1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
use byteorder::{LittleEndian, WriteBytesExt}; use failure::{format_err, Error}; use crate::model::{owned::OwnedBuf, TableType}; mod configuration; mod entry; pub use self::{ configuration::ConfigurationBuf, entry::{ComplexEntry, Entry, EntryHeader, SimpleEntry}, }; #[derive(Debug)] pub struct TableTypeBuf { id: u8, config: ConfigurationBuf, entries: Vec<Entry>, } impl TableTypeBuf { pub fn new(id: u8, config: ConfigurationBuf) -> Self { Self { id, config, entries: Vec::new(), } } pub fn add_entry(&mut self, entry: Entry) { self.entries.push(entry); } } impl OwnedBuf for TableTypeBuf { fn get_token(&self) -> u16 { 0x201 } fn get_body_data(&self) -> Result<Vec<u8>, Error> { let mut out = Vec::new(); let mut i = 0; let mut entries_body = Vec::new(); for e in &self.entries { let current_entry = e.to_vec()?; if e.is_empty() { out.write_u32::<LittleEndian>(0xFFFF_FFFF)?; } else { out.write_u32::<LittleEndian>(i)?; i += current_entry.len() as u32; } entries_body.extend(¤t_entry); } out.extend(&entries_body); Ok(out) } fn get_header(&self) -> Result<Vec<u8>, Error> { let mut out = Vec::new(); let vec_config = self.config.to_vec()?; let header_size = (5 * 4) + vec_config.len() as u32; out.write_u32::<LittleEndian>(u32::from(self.id))?; out.write_u32::<LittleEndian>(self.entries.len() as u32)?; out.write_u32::<LittleEndian>(header_size + (self.entries.len() as u32 * 4))?; out.extend(&vec_config); Ok(out) } } impl TableType for TableTypeBuf { type Configuration = ConfigurationBuf; fn get_id(&self) -> Result<u8, Error> { Ok(self.id) } fn get_amount(&self) -> Result<u32, Error> { Ok(self.entries.len() as u32) } fn get_configuration(&self) -> Result<Self::Configuration, Error> { Ok(self.config.clone()) } fn get_entry(&self, index: u32) -> Result<Entry, Error> { self.entries .get(index as usize) .cloned() .ok_or_else(|| format_err!("entry out of bound")) } } #[cfg(test)] mod tests { use super::{ComplexEntry, ConfigurationBuf, Entry, SimpleEntry, TableTypeBuf}; use crate::{ chunks::TableTypeWrapper, model::{owned::OwnedBuf, TableType}, raw_chunks, test::compare_chunks, }; #[test] fn it_can_generate_a_chunk_with_the_given_data() { let mut table_type = TableTypeBuf::new(5, ConfigurationBuf::default()); let entry = Entry::Simple(SimpleEntry::new(1, 2, 3, 4)); let sub_entry = SimpleEntry::new(5, 6, 7, 8); let sub_entry2 = SimpleEntry::new(9, 0, 1, 2); let entry2 = Entry::Complex(ComplexEntry::new(10, 11, 12, vec![sub_entry, sub_entry2])); let entry3 = Entry::Simple(SimpleEntry::new(20, 21, 22, 23)); table_type.add_entry(entry); table_type.add_entry(entry2); table_type.add_entry(entry3); assert_eq!(5, table_type.get_id().unwrap()); assert_eq!(3, table_type.get_amount().unwrap()); assert_eq!( 10, table_type.get_entry(1).unwrap().complex().unwrap().get_id() ) } #[test] fn identity() { let wrapper = TableTypeWrapper::new(raw_chunks::EXAMPLE_TABLE_TYPE, 68); let _ = wrapper.get_entries(); let owned = wrapper.to_buffer().unwrap(); let new_raw = owned.to_vec().unwrap(); compare_chunks(&new_raw, &raw_chunks::EXAMPLE_TABLE_TYPE); } #[test] fn identity_with_mixed_complex_and_simple_entries() { let wrapper = TableTypeWrapper::new(raw_chunks::EXAMPLE_TABLE_TYPE_WITH_COMPLEX, 76); let _ = wrapper.get_entries(); let owned = wrapper.to_buffer().unwrap(); let new_raw = owned.to_vec().unwrap(); compare_chunks(&new_raw, &raw_chunks::EXAMPLE_TABLE_TYPE_WITH_COMPLEX); } }