diff --git a/src/v1.rs b/src/v1.rs index 07bc82d..42a0567 100644 --- a/src/v1.rs +++ b/src/v1.rs @@ -249,8 +249,8 @@ struct EventChunkHeader{ // first time I've managed to write BinRead generics without this stupid T::Args<'a>:Required thing blocking me fn read_data_into_events<'a,R:BinReaderExt,T>(data:&mut R,events:&mut Vec,num_events:usize)->binrw::BinResult<()> where - T:binrw::BinRead, - T::Args<'a>:binrw::__private::Required, + T:binrw::BinRead, + T::Args<'a>:binrw::__private::Required, { // there is only supposed to be at most one of each type of event chunk per block, so no need to amortize. events.reserve_exact(num_events); @@ -259,10 +259,26 @@ where } Ok(()) } +fn read_data_into_events_amortized<'a,R:BinReaderExt,T>(data:&mut R,events:&mut Vec,num_events:usize)->binrw::BinResult<()> +where + T:binrw::BinRead, + T::Args<'a>:binrw::__private::Required, +{ + // this is used when reading multiple blocks into a single object, so amortize the allocation cost. + events.reserve(num_events); + for _ in 0..num_events{ + events.push(data.read_le()?); + } + Ok(()) +} impl Block{ - fn read(mut data:R)->binrw::BinResult{ + fn read(data:R)->binrw::BinResult{ let mut block=Block::default(); + Block::read_into(data,&mut block)?; + Ok(block) + } + fn read_into(mut data:R,block:&mut Block)->binrw::BinResult<()>{ // well... this looks error prone while let Ok(event_chunk_header)=data.read_le::(){ match event_chunk_header.event_type{ @@ -276,7 +292,23 @@ impl Block{ EventType::Setting=>read_data_into_events(&mut data,&mut block.setting_events,event_chunk_header.num_events as usize)?, } } - Ok(block) + Ok(()) + } + fn read_into_amortized(mut data:R,block:&mut Block)->binrw::BinResult<()>{ + // sad code duplication + while let Ok(event_chunk_header)=data.read_le::(){ + match event_chunk_header.event_type{ + EventType::Input=>read_data_into_events_amortized(&mut data,&mut block.input_events,event_chunk_header.num_events as usize)?, + EventType::Output=>read_data_into_events_amortized(&mut data,&mut block.output_events,event_chunk_header.num_events as usize)?, + EventType::Sound=>read_data_into_events_amortized(&mut data,&mut block.sound_events,event_chunk_header.num_events as usize)?, + EventType::World=>read_data_into_events_amortized(&mut data,&mut block.world_events,event_chunk_header.num_events as usize)?, + EventType::Gravity=>read_data_into_events_amortized(&mut data,&mut block.gravity_events,event_chunk_header.num_events as usize)?, + EventType::Run=>read_data_into_events_amortized(&mut data,&mut block.run_events,event_chunk_header.num_events as usize)?, + EventType::Camera=>read_data_into_events_amortized(&mut data,&mut block.camera_events,event_chunk_header.num_events as usize)?, + EventType::Setting=>read_data_into_events_amortized(&mut data,&mut block.setting_events,event_chunk_header.num_events as usize)?, + } + } + Ok(()) } } @@ -306,6 +338,16 @@ pub struct TimedBlockId{ pub time:f64, pub block_id:BlockId, } +impl PartialEq for TimedBlockId{ + fn eq(&self,other:&Self)->bool{ + self.time.eq(&other.time) + } +} +impl PartialOrd for TimedBlockId{ + fn partial_cmp(&self,other:&Self)->Option{ + self.time.partial_cmp(&other.time) + } +} #[binrw] #[brw(little)] @@ -337,6 +379,41 @@ impl FileHeader{ } } +struct MergeIter,It1:Iterator>{ + it0:It0, + it1:It1, + item0:Option, + item1:Option, +} +impl,It1:Iterator> MergeIter{ + fn new(mut it0:It0,mut it1:It1)->Self{ + Self{ + item0:it0.next(), + item1:it1.next(), + it0, + it1, + } + } +} +impl,It1:Iterator> Iterator for MergeIter{ + type Item=T; + fn next(&mut self)->Option{ + match (&self.item0,&self.item1){ + (None,None)=>None, + (Some(_),None)=>core::mem::replace(&mut self.item0,self.it0.next()), + (None,Some(_))=>core::mem::replace(&mut self.item1,self.it1.next()), + (Some(item0),Some(item1))=>match item0.partial_cmp(item1){ + Some(core::cmp::Ordering::Less) + |Some(core::cmp::Ordering::Equal) + |None + =>core::mem::replace(&mut self.item0,self.it0.next()), + Some(core::cmp::Ordering::Greater) + =>core::mem::replace(&mut self.item1,self.it1.next()), + }, + } + } +} + pub struct File{ pub header:FileHeader, pub data:FileData, @@ -348,6 +425,18 @@ impl File{ data:FileData{data}, }) } + pub fn read_all(&mut self)->Result{ + let block_iter=MergeIter::new( + self.header.offline_blocks_timeline.iter(), + self.header.realtime_blocks_timeline.iter(), + ); + let mut big_block=Block::default(); + for &TimedBlockId{time:_,block_id} in block_iter{ + let block_info=self.header.block_info(block_id)?; + self.data.read_block_info_into(block_info,&mut big_block)?; + } + Ok(big_block) + } } pub struct FileData{ @@ -366,4 +455,9 @@ impl FileData{ let block=Block::read(data).map_err(Error::InvalidData)?; Ok(block) } + pub fn read_block_info_into(&mut self,block_info:BlockInfo,block:&mut Block)->Result<(),Error>{ + let data=self.block_reader(block_info)?; + Block::read_into_amortized(data,block).map_err(Error::InvalidData)?; + Ok(()) + } }