From d6055b5ac4f3ff5016bc4881cf1cc109a22c40ba Mon Sep 17 00:00:00 2001 From: Igor Tolmachev Date: Sun, 16 Jun 2024 21:36:13 +0900 Subject: Implement serialize --- src/archive.rs | 2 +- src/error.rs | 35 +++-- src/structs/error.rs | 29 +++++ src/structs/mod.rs | 13 +- src/structs/ser.rs | 339 +++++++++++++++++++++++++++++++++++++++++++++++- src/structs/settings.rs | 110 ++++++++++++++++ src/structs/tests.rs | 88 +++++++++++++ src/zip/driver.rs | 4 +- src/zip/error.rs | 8 +- src/zip/mod.rs | 1 + 10 files changed, 611 insertions(+), 18 deletions(-) create mode 100644 src/structs/error.rs create mode 100644 src/structs/settings.rs create mode 100644 src/structs/tests.rs (limited to 'src') diff --git a/src/archive.rs b/src/archive.rs index a422f9e..fe03a12 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -3,7 +3,7 @@ use crate::ArchiveResult; use std::io::{Read, Write}; pub struct Archive { - pub(crate) driver: D, + pub driver: D, } impl Archive diff --git a/src/error.rs b/src/error.rs index 6d7aba4..9252762 100644 --- a/src/error.rs +++ b/src/error.rs @@ -2,25 +2,27 @@ use std::error::Error; use std::fmt::Display; use std::io; -pub type ArchiveResult = Result>; +pub type ArchiveResult = Result>; #[derive(Debug)] pub enum ArchiveError { - IO(io::Error), - Driver { name: &'static str, error: E }, + IO { error: io::Error }, + Serde { message: String }, + Archivator { module: String, error: E }, } impl From for ArchiveError { fn from(value: io::Error) -> Self { - Self::IO(value) + Self::IO { error: value } } } impl Display for ArchiveError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - ArchiveError::IO(error) => write!(f, "{error}"), - ArchiveError::Driver { name, error } => write!(f, "{name}: {error}"), + Self::IO { error } => writeln!(f, "IO: {error}"), + Self::Serde { message } => writeln!(f, "Serde: {message}"), + Self::Archivator { module, error } => writeln!(f, "{module}: {error}"), } } } @@ -28,8 +30,25 @@ impl Display for ArchiveError { impl Error for ArchiveError { fn source(&self) -> Option<&(dyn Error + 'static)> { match self { - Self::IO(error) => Some(error), - _ => None, + Self::IO { error } => Some(error), + Self::Serde { .. } => None, + Self::Archivator { module, error } => None, + } + } +} + +impl serde::ser::Error for ArchiveError { + fn custom(msg: T) -> Self { + Self::Serde { + message: msg.to_string(), + } + } +} + +impl serde::de::Error for ArchiveError { + fn custom(msg: T) -> Self { + Self::Serde { + message: msg.to_string(), } } } diff --git a/src/structs/error.rs b/src/structs/error.rs new file mode 100644 index 0000000..b9d765d --- /dev/null +++ b/src/structs/error.rs @@ -0,0 +1,29 @@ +use crate::{ArchiveError, ArchiveResult}; +use std::error::Error; +use std::fmt::Display; + +pub type StructResult = ArchiveResult; + +#[derive(Debug)] +pub enum StructError { + IncorrectEnumVariant, +} + +impl From for ArchiveError { + fn from(value: StructError) -> Self { + Self::Archivator { + module: "Struct serializer".to_string(), + error: value, + } + } +} + +impl Display for StructError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + StructError::IncorrectEnumVariant => write!(f, "Can't cast enum variant type"), + } + } +} + +impl Error for StructError {} diff --git a/src/structs/mod.rs b/src/structs/mod.rs index d7e9daa..feb37dd 100644 --- a/src/structs/mod.rs +++ b/src/structs/mod.rs @@ -1,2 +1,11 @@ -mod de; -mod ser; +pub mod de; +mod error; +pub mod ser; +mod settings; + +pub use error::{StructError, StructResult}; +pub use ser::ArchiveSerializer; +pub use settings::{ByteOrder, Settings, VariantIndexType}; + +#[cfg(test)] +mod tests; diff --git a/src/structs/ser.rs b/src/structs/ser.rs index a3fe291..8aa95a5 100644 --- a/src/structs/ser.rs +++ b/src/structs/ser.rs @@ -1,6 +1,343 @@ +use crate::structs::{Settings, StructError, StructResult}; use crate::ArchiveError; use serde::{ser, Serialize}; pub struct ArchiveSerializer { - bin: Vec, + bytes: Vec, + settings: Settings, +} + +impl ArchiveSerializer { + pub fn new(settings: Settings) -> Self { + Self { + bytes: Vec::new(), + settings, + } + } + + pub fn to_bytes(self) -> Vec { + self.bytes + } +} + +impl ser::Serializer for &mut ArchiveSerializer { + type Ok = (); + type Error = ArchiveError; + + type SerializeSeq = Self; + type SerializeTuple = Self; + type SerializeTupleStruct = Self; + type SerializeTupleVariant = Self; + type SerializeMap = Self; + type SerializeStruct = Self; + type SerializeStructVariant = Self; + + fn serialize_bool(self, v: bool) -> StructResult<()> { + self.bytes.push(v as u8); + Ok(()) + } + + fn serialize_i8(self, v: i8) -> StructResult<()> { + self.bytes.push(v as u8); + Ok(()) + } + + fn serialize_i16(self, v: i16) -> StructResult<()> { + self.bytes.append(&mut self.settings.byte_order.i16(v)); + Ok(()) + } + + fn serialize_i32(self, v: i32) -> StructResult<()> { + self.bytes.append(&mut self.settings.byte_order.i32(v)); + Ok(()) + } + + fn serialize_i64(self, v: i64) -> StructResult<()> { + self.bytes.append(&mut self.settings.byte_order.i64(v)); + Ok(()) + } + + fn serialize_u8(self, v: u8) -> StructResult<()> { + self.bytes.push(v); + Ok(()) + } + + fn serialize_u16(self, v: u16) -> StructResult<()> { + self.bytes.append(&mut self.settings.byte_order.u16(v)); + Ok(()) + } + + fn serialize_u32(self, v: u32) -> StructResult<()> { + self.bytes.append(&mut self.settings.byte_order.u32(v)); + Ok(()) + } + + fn serialize_u64(self, v: u64) -> StructResult<()> { + self.bytes.append(&mut self.settings.byte_order.u64(v)); + Ok(()) + } + + fn serialize_f32(self, v: f32) -> StructResult<()> { + self.bytes.append(&mut self.settings.byte_order.f32(v)); + Ok(()) + } + + fn serialize_f64(self, v: f64) -> StructResult<()> { + self.bytes.append(&mut self.settings.byte_order.f64(v)); + Ok(()) + } + + fn serialize_char(self, v: char) -> StructResult<()> { + self.bytes.push(v as u8); + Ok(()) + } + + fn serialize_str(self, v: &str) -> StructResult<()> { + self.bytes.append(&mut v.as_bytes().to_vec()); + Ok(()) + } + + fn serialize_bytes(self, v: &[u8]) -> StructResult<()> { + self.bytes.append(&mut v.to_vec()); + Ok(()) + } + + fn serialize_none(self) -> StructResult<()> { + Ok(()) + } + + fn serialize_some(self, value: &T) -> StructResult<()> + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + fn serialize_unit(self) -> StructResult<()> { + Ok(()) + } + + fn serialize_unit_struct(self, _name: &'static str) -> StructResult<()> { + self.serialize_unit() + } + + fn serialize_unit_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + ) -> StructResult<()> { + self.bytes.append( + &mut self + .settings + .variant_index_type + .cast(variant_index, &self.settings.byte_order)?, + ); + Ok(()) + } + + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> StructResult<()> + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + value: &T, + ) -> StructResult<()> + where + T: ?Sized + Serialize, + { + self.bytes.append( + &mut self + .settings + .variant_index_type + .cast(variant_index, &self.settings.byte_order)?, + ); + value.serialize(self) + } + + fn serialize_seq(self, _len: Option) -> StructResult { + Ok(self) + } + + fn serialize_tuple(self, _len: usize) -> StructResult { + Ok(self) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> StructResult { + Ok(self) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> StructResult { + self.bytes.append( + &mut self + .settings + .variant_index_type + .cast(variant_index, &self.settings.byte_order)?, + ); + Ok(self) + } + + fn serialize_map(self, _len: Option) -> StructResult { + Ok(self) + } + + fn serialize_struct( + self, + _name: &'static str, + _len: usize, + ) -> StructResult { + Ok(self) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> StructResult { + self.bytes.append( + &mut self + .settings + .variant_index_type + .cast(variant_index, &self.settings.byte_order)?, + ); + Ok(self) + } +} + +impl ser::SerializeSeq for &mut ArchiveSerializer { + type Ok = (); + type Error = ArchiveError; + + fn serialize_element(&mut self, value: &T) -> StructResult<()> + where + T: ?Sized + Serialize, + { + value.serialize(&mut **self) + } + + fn end(self) -> StructResult<()> { + Ok(()) + } +} + +impl ser::SerializeTuple for &mut ArchiveSerializer { + type Ok = (); + type Error = ArchiveError; + + fn serialize_element(&mut self, value: &T) -> StructResult<()> + where + T: ?Sized + Serialize, + { + value.serialize(&mut **self) + } + + fn end(self) -> StructResult<()> { + Ok(()) + } +} + +impl ser::SerializeTupleStruct for &mut ArchiveSerializer { + type Ok = (); + type Error = ArchiveError; + + fn serialize_field(&mut self, value: &T) -> StructResult<()> + where + T: ?Sized + Serialize, + { + value.serialize(&mut **self) + } + + fn end(self) -> StructResult<()> { + Ok(()) + } +} + +impl ser::SerializeTupleVariant for &mut ArchiveSerializer { + type Ok = (); + type Error = ArchiveError; + + fn serialize_field(&mut self, value: &T) -> StructResult<()> + where + T: ?Sized + Serialize, + { + value.serialize(&mut **self) + } + + fn end(self) -> StructResult<()> { + Ok(()) + } +} + +impl ser::SerializeMap for &mut ArchiveSerializer { + type Ok = (); + type Error = ArchiveError; + + fn serialize_key(&mut self, key: &T) -> StructResult<()> + where + T: ?Sized + Serialize, + { + key.serialize(&mut **self) + } + + fn serialize_value(&mut self, value: &T) -> StructResult<()> + where + T: ?Sized + Serialize, + { + value.serialize(&mut **self) + } + + fn end(self) -> StructResult<()> { + Ok(()) + } +} + +impl ser::SerializeStruct for &mut ArchiveSerializer { + type Ok = (); + type Error = ArchiveError; + + fn serialize_field(&mut self, _key: &'static str, value: &T) -> StructResult<()> + where + T: ?Sized + Serialize, + { + value.serialize(&mut **self) + } + + fn end(self) -> StructResult<()> { + Ok(()) + } +} + +impl ser::SerializeStructVariant for &mut ArchiveSerializer { + type Ok = (); + type Error = ArchiveError; + + fn serialize_field(&mut self, _key: &'static str, value: &T) -> StructResult<()> + where + T: ?Sized + Serialize, + { + value.serialize(&mut **self) + } + + fn end(self) -> StructResult<()> { + Ok(()) + } } diff --git a/src/structs/settings.rs b/src/structs/settings.rs new file mode 100644 index 0000000..63c4d3a --- /dev/null +++ b/src/structs/settings.rs @@ -0,0 +1,110 @@ +use crate::structs::{ArchiveSerializer, StructError, StructResult}; +use serde::Serialize; + +pub enum ByteOrder { + Le, + Be, + Ne, +} + +pub enum VariantIndexType { + U8, + U16, + U32, + U64, + I8, + I16, + I32, + I64, +} + +macro_rules! impl_byte_order { + ($($n:ident),+) => { + impl ByteOrder {$( + pub fn $n(&self, num: $n) -> Vec { + match self { + ByteOrder::Le => num.to_le_bytes().to_vec(), + ByteOrder::Be => num.to_be_bytes().to_vec(), + ByteOrder::Ne => num.to_ne_bytes().to_vec(), + } + } + )+} + }; +} +impl_byte_order!(u8, u16, u32, u64, i8, i16, i32, i64, f32, f64); + +impl VariantIndexType { + pub fn cast(&self, num: u32, byte_order: &ByteOrder) -> StructResult> { + Ok(match self { + VariantIndexType::U8 => byte_order.u8(num + .try_into() + .map_err(|_| StructError::IncorrectEnumVariant)?), + VariantIndexType::U16 => byte_order.u16( + num.try_into() + .map_err(|_| StructError::IncorrectEnumVariant)?, + ), + VariantIndexType::U32 => byte_order.u32( + num.try_into() + .map_err(|_| StructError::IncorrectEnumVariant)?, + ), + VariantIndexType::U64 => byte_order.u64( + num.try_into() + .map_err(|_| StructError::IncorrectEnumVariant)?, + ), + VariantIndexType::I8 => byte_order.i8(num + .try_into() + .map_err(|_| StructError::IncorrectEnumVariant)?), + VariantIndexType::I16 => byte_order.i16( + num.try_into() + .map_err(|_| StructError::IncorrectEnumVariant)?, + ), + VariantIndexType::I32 => byte_order.i32( + num.try_into() + .map_err(|_| StructError::IncorrectEnumVariant)?, + ), + VariantIndexType::I64 => byte_order.i64( + num.try_into() + .map_err(|_| StructError::IncorrectEnumVariant)?, + ), + }) + } +} + +pub struct Settings { + pub(crate) byte_order: ByteOrder, + pub(crate) variant_index_type: VariantIndexType, +} + +impl Settings { + pub fn new(byte_order: ByteOrder, variant_index_type: VariantIndexType) -> Self { + Self { + byte_order, + variant_index_type, + } + } + + pub fn byte_order(mut self, order: ByteOrder) -> Self { + self.byte_order = order; + self + } + + pub fn variant_index_type(mut self, index_type: VariantIndexType) -> Self { + self.variant_index_type = index_type; + self + } + + pub fn serialize(self, object: &impl Serialize) -> StructResult> { + let mut serializer = ArchiveSerializer::new(self); + object.serialize(&mut serializer)?; + Ok(serializer.to_bytes()) + } +} + +impl Default for Settings { + fn default() -> Self { + Self { + byte_order: ByteOrder::Le, + variant_index_type: VariantIndexType::U32, + } + } +} diff --git a/src/structs/tests.rs b/src/structs/tests.rs new file mode 100644 index 0000000..0fa5347 --- /dev/null +++ b/src/structs/tests.rs @@ -0,0 +1,88 @@ +use crate::structs::{ByteOrder, Settings, VariantIndexType}; +use serde::Serialize; + +#[derive(Serialize)] +struct Struct<'a> { + u8: u8, + u16: u16, + u32: u32, + u64: u64, + u8arr: [u8; 3], + tuple: (u16, u8), + str: &'a str, +} + +#[derive(Serialize)] +enum Enum<'a> { + Unit, + Type(u16), + Tuple(u16, &'a str), + Struct { u32: u32, u64: u64 }, +} + +#[test] +fn struct_serialize_test() { + let object = Struct { + u8: 42, + u16: 26, + u32: 69, + u64: 11, + u8arr: [37, 74, 111], + tuple: (24, 13), + str: "yes", + }; + + let bytes = Settings::default() + .byte_order(ByteOrder::Le) + .serialize(&object) + .unwrap(); + assert_eq!( + bytes, + //u8|-u16--|----u32-----|----------u64-----------|[0]-[1]--[2]|.0 --.1---|-y----e----s| + [42, 26, 0, 69, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 37, 74, 111, 24, 0, 13, 121, 101, 115] + ); + + let bytes = Settings::default() + .byte_order(ByteOrder::Be) + .serialize(&object) + .unwrap(); + assert_eq!( + bytes, + //u8|-u16--|----u32-----|----------u64-----------|[0]-[1]--[2]|.0 --.1---|-y----e----s| + [42, 0, 26, 0, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 11, 37, 74, 111, 0, 24, 13, 121, 101, 115] + ); +} + +#[test] +fn enum_serialize_test() { + let bytes = Settings::default() + .byte_order(ByteOrder::Le) + .variant_index_type(VariantIndexType::U8) + .serialize(&Enum::Unit) + .unwrap(); + assert_eq!(bytes, [0]); + + let bytes = Settings::default() + .byte_order(ByteOrder::Le) + .variant_index_type(VariantIndexType::U16) + .serialize(&Enum::Type(42)) + .unwrap(); + assert_eq!(bytes, [1, 0, 42, 0]); + + let bytes = Settings::default() + .byte_order(ByteOrder::Le) + .variant_index_type(VariantIndexType::U32) + .serialize(&Enum::Tuple(26, "yes")) + .unwrap(); + assert_eq!(bytes, [2, 0, 0, 0, 26, 0, 121, 101, 115]); + + let bytes = Settings::default() + .byte_order(ByteOrder::Be) + .variant_index_type(VariantIndexType::U64) + .serialize(&Enum::Struct { u32: 69, u64: 37 }) + .unwrap(); + assert_eq!( + bytes, + [0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 37] + ); +} diff --git a/src/zip/driver.rs b/src/zip/driver.rs index 313bf8d..d575509 100644 --- a/src/zip/driver.rs +++ b/src/zip/driver.rs @@ -4,7 +4,7 @@ use crate::zip::structs::{EOCDR64Locator, CDR, EOCDR, EOCDR64}; use crate::zip::ZipFile; use std::collections::HashMap as Map; use std::fs::File; -use std::io::{Cursor, Read, Seek, SeekFrom, Write}; +use std::io::{Read, Seek, SeekFrom, Write}; pub struct Zip { io: IO, @@ -43,7 +43,7 @@ impl ArchiveRead for Zip { }; let eocdr: EOCDR = bincode::deserialize(&buf).map_err(|_| ZipError::InvalidEOCDR)?; let comment = { - let mut buf = vec![0; eocdr.comment_len as usize]; + let mut buf: Vec = vec![0; eocdr.comment_len as usize]; io.read(&mut buf)?; String::from_utf8(buf).map_err(|_| ZipError::InvalidArchiveComment)? }; diff --git a/src/zip/error.rs b/src/zip/error.rs index ad1989a..18bbb22 100644 --- a/src/zip/error.rs +++ b/src/zip/error.rs @@ -2,7 +2,7 @@ use crate::{ArchiveError, ArchiveResult}; use std::error::Error; use std::fmt::Display; -pub type ZipResult = ArchiveResult; +pub type ZipResult = ArchiveResult; #[derive(Debug)] pub enum ZipError { @@ -22,10 +22,10 @@ pub enum ZipError { impl From for ArchiveError { fn from(value: ZipError) -> Self { - return ArchiveError::Driver { - name: "Zip", + Self::Archivator { + module: "Zip".to_string(), error: value, - }; + } } } diff --git a/src/zip/mod.rs b/src/zip/mod.rs index 612a946..5aeca97 100644 --- a/src/zip/mod.rs +++ b/src/zip/mod.rs @@ -4,4 +4,5 @@ mod file; mod structs; pub use driver::Zip; +pub use error::ZipError; pub use file::ZipFile; -- cgit v1.2.3