Sindbad~EG File Manager
use std::collections::HashMap;
use crate::image::write::channels::{WritableChannels, ChannelsWriter};
use crate::meta::attribute::{LevelMode, ChannelList, Text, TextSlice, ChannelInfo};
use crate::meta::header::Header;
use crate::image::read::layers::{ReadChannels, ChannelsReader};
use crate::block::{BlockIndex, UncompressedBlock};
use crate::block::lines::{collect_uncompressed_block_from_lines, LineIndex};
use std::io::{Cursor, Read};
use crate::error::{Result, UnitResult};
use crate::block::chunk::TileCoordinates;
use crate::prelude::SmallVec;
pub struct ChannelGroups<ChannelGroup> {
channel_group: Option<ChannelGroup>,
children: HashMap<Text, Self>
}
impl<ChannelGroup> ChannelGroups<ChannelGroup> {
// pub fn visit_groups_mut(&mut self, visitor: impl Fn(&mut Channels)) {
// }
pub fn groups(&self) -> SmallVec<[&ChannelGroup; 12]> {
let children = self.children.iter().flat_map(|group| group.groups());
self.channel_group.iter().chain(children).collect()
}
pub fn lookup_group(&self, group_name: &TextSlice) -> Option<&ChannelGroup> {
let dot_index = group_name.iter().position('.');
if let Some(dot_index) = dot_index {
let group_name = &group_name[.. dot_index];
let child_name = &group_name[dot_index + 1 ..];
self.children.get(group_name)
.and_then(|child| child.lookup(child_name))
}
else {
self.channel_group.lookup(name)
}
}
/*pub fn insert_group(&mut self, full_name: &TextSlice, value: ChannelGroup) {
let dot_index = full_name.iter().position('.');
if let Some(dot_index) = dot_index {
let group_name = &group_name[.. dot_index];
let name_rest = &group_name[dot_index + 1 ..];
self.children.entry(Text::from_slice_unchecked(group_name))
.or_insert(|| );
// self.children.insert(Text::from_slice_unchecked(group_name), value)
// .and_then(|child| child.lookup(name_rest));
}
else {
self.channel_group.lookup(name);
}
}*/
pub fn map<T>(self, mapper: impl FnMut(ChannelGroup) -> T) -> ChannelGroups<T> {
ChannelGroups {
children: self.channel_group.iter().map(&mapper).collect(),
channel_group: self.channel_group.map(mapper),
}
}
}
pub fn parse_channel_list_groups<T>(channels: impl Iterator<Item=(Text, T)>)
-> ChannelGroups<SmallVec<(Text, T)>>
{
fn insert_into_groups(groups: &mut ChannelGroups<SmallVec<(Text, T)>>, name: Text, value: T) {
let dot_index = name.as_slice().iter().position('.');
if let Some(dot_index) = dot_index {
// insert into child group
let group_name = Text::from_slice_unchecked(&name.as_slice()[.. dot_index]);
let child_channel = Text::from_slice_unchecked(&name.as_slice()[dot_index + 1 ..]);
let child_group = groups.children.entry(group_name)
.or_insert(ChannelGroups { channel_group: None, children: Default::default() });
insert_into_groups(child_group, child_channel, value);
}
else {
// insert directly into group
if groups.channel_group.is_none() {
groups.channel_group = Some(SmallVec::new());
}
groups.channel_group.unwrap().push(value);
}
}
let mut result = ChannelGroups { channel_group: None, children: HashMap::default() };
for (name, value) in channels { insert_into_groups(&mut result, name, value); }
result
}
impl<'slf, ChannelGroup> WritableChannels<'slf> for ChannelGroups<ChannelGroup>
where ChannelGroup: WritableChannels<'slf>
{
fn infer_channel_list(&self) -> ChannelList {
// TODO what about empty groups with NO channels??
let child_channels = self.children.iter().flat_map(|(group_name, child)| {
let mut child_channels = child.infer_channel_list().list;
for channel in &mut child_channels { channel.name.push_front(group_name) };
child_channels
});
let mut own_channels = self.channel_group
.map(|chans| chans.infer_channel_list().list)
.unwrap_or_default();
own_channels.extend(child_channels);
own_channels.sort_unstable(); // TODO only once at end
ChannelList::new(own_channels) // might be empty, but will be checked in MetaData::validate()
}
fn level_mode(&self) -> LevelMode {
fn find_mode_or_none(channels: &Self) -> Option<LevelMode> {
channels.channel_group.map(WritableChannels::level_mode).or_else(|| {
channels.children.iter().map(find_mode_or_none).next()
})
}
let mode = find_mode_or_none(self)
.expect("empty channel groups (check failed)"); // TODO only happens for empty channels, right? panic maybe?
if let Some(chans) = self.channel_group.as_ref() {
debug_assert_eq!(chans.level_mode(), mode, "level mode must be equal for all legacy channel groups")
}
debug_assert!(
self.children.values()
.flat_map(find_mode_or_none)
.all(|child_mode| child_mode == mode),
"level mode must be equal for all legacy channel groups"
);
mode
}
type Writer = GroupChannelsWriter<'slf, ChannelGroup>;
fn create_writer(&'slf self, header: &Header) -> Self::Writer {
let channels = header.channels.list.iter()
.map(|channel_info|{
// hashmap order is not guaranteed? so look up each channel group manually instead of generating new
let channels = self.lookup_group(channel_info.name.as_slice())
.expect("channels not found bug");
channels.create_writer(header) // channel_info.name.clone()
})
.collect();
GroupChannelsWriter { channels_list: channels }
}
}
struct GroupChannelsWriter<'c, ChannelGroupWriter> {
channels_list: Vec<&'c ChannelGroupWriter>,
}
impl<'c, Channels> ChannelsWriter for GroupChannelsWriter<'c, Channels> where Channels: ChannelsWriter {
fn extract_uncompressed_block(&self, header: &Header, block: BlockIndex) -> Vec<u8> {
let mut blocks_per_channel: Vec<Cursor<Vec<u8>>> = self
.channels_list.iter()
.map(|channels| Cursor::new(channels.extract_uncompressed_block(header, block)))
.collect();
UncompressedBlock::uncompressed_block_from_lines(header, block, |line|{
let channel_reader = &mut blocks_per_channel[line.location.channel]; // TODO subsampling
// read from specific channel into total byte block
// this assumes that the lines in the callback are iterated in strictly increasing order
// because each channel reader is consumed
channel_reader.read_exact(line.value)
.expect("collecting grouped channel byte block failed");
})
}
}
struct ReadChannelGroups<ReadChannelGroup> {
read_channels: ReadChannelGroup
}
struct ChannelGroupsReader<ChannelGroupReader> {
channels: ChannelGroups<usize>,
indexed_channels: Vec<ChannelGroupReader>,
}
impl<'s, ReadChannelGroup> ReadChannels<'s> for ReadChannelGroups<ReadChannelGroup>
where ReadChannelGroup: ReadChannels<'s>
{
type Reader = ChannelGroupsReader<ReadChannelGroup::Reader>;
fn create_channels_reader(&'s self, header: &Header) -> Result<Self::Reader> {
let swap = |(a,b)| (b,a);
let channel_groups = parse_channel_list_groups(
header.channels.list.iter().enumerate().map(swap)
);
let mut indexed_channels = Vec::new();
let channel_groups = channel_groups.map(|channels| {
let mut channels_header = header.clone(); // TODO no clone?
channels_header.channels = ChannelList::new(channels.iter().map(|(name, index)|{
let mut channel_info = header.channels.list[index].clone();
channel_info.name = name;
channel_info
}).collect()); // FIXME does not comply to `header.chunk_count` and that stuff?? change ReadChannels fn signature?
indexed_channels.push(self.read_channels.create_channels_reader(&channels_header));
// FIXME this is not the original order indexed_channels.len() - 1
indexed_channels[]
});
Ok(ChannelGroupsReader {
channels: channel_groups,
indexed_channels,
})
/*Ok(ChannelGroupsReader {
channels: header.channels.list.iter().map(|channel| {
let mut channels_header = header.clone();
let reader = self.read_channels.create_channels_reader(&channels_header);
(channels_header, reader)
}).collect(),
})*/
}
}
impl<ChannelGroupReader> ChannelsReader for ChannelGroupsReader<ChannelGroupReader> where ChannelGroupReader: ChannelsReader {
type Channels = ChannelGroups<ChannelGroupReader::Channels>;
fn filter_block(&self, tile: (usize, &TileCoordinates)) -> bool {
self.indexed_channels.iter().any(|channel| channel.filter_block(tile))
}
fn read_block(&mut self, header: &Header, block: UncompressedBlock) -> UnitResult {
block.for_lines(|line|{
})
}
fn into_channels(self) -> Self::Channels {
}
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists