use std::convert::{TryFrom, TryInto}; use std::io::Cursor; use deku::prelude::*; use deku::reader::Reader; use deku::writer::Writer; /// General smoke tests for ctx /// TODO: These should be divided into smaller units #[test] fn test_ctx_struct() { #[derive(PartialEq, Debug, DekuRead, DekuWrite)] #[deku(ctx = "a: u8, b: u8")] struct SubTypeNeedCtx { #[deku( reader = "(u8::from_reader_with_ctx(deku::reader,()).map(|c|(a+b+c) as usize))", writer = "(|c|{u8::to_writer(&(c-a-b), deku::writer, ())})(self.i as u8)" )] i: usize, } #[derive(PartialEq, Debug, DekuRead, DekuWrite)] struct FieldLevelCtxStruct { a: u8, b: u8, #[deku(ctx = "a + 1, *b")] c: SubTypeNeedCtx, } let test_data = [0x01_u8, 0x02, 0x03]; let ret_read = FieldLevelCtxStruct::try_from(test_data.as_slice()).unwrap(); assert_eq!( ret_read, FieldLevelCtxStruct { a: 0x01, b: 0x02, c: SubTypeNeedCtx { i: 0x01 + 1 + 0x02 + 0x03 } // (a + 1) + b + c } ); let ret_write: Vec = ret_read.try_into().unwrap(); assert_eq!(ret_write, test_data) } #[test] fn test_top_level_ctx_enum() { #[derive(PartialEq, Debug, DekuRead, DekuWrite)] #[deku(id_type = "u8", ctx = "a: u8, b: u8")] enum TopLevelCtxEnum { #[deku(id = "1")] VariantA( #[deku( reader = "(u8::from_reader_with_ctx(deku::reader,()).map(|c|(a+b+c)))", writer = "(|c|{u8::to_writer(&(c-a-b), deku::writer, ())})(field_0)" )] u8, ), } let test_data = [0x01_u8, 0x03]; let ret_read = TopLevelCtxEnum::from_reader_with_ctx( &mut Reader::new(&mut Cursor::new(test_data)), (1, 2), ) .unwrap(); assert_eq!(ret_read, TopLevelCtxEnum::VariantA(0x06)); let mut out_buf = vec![]; let mut cursor = Cursor::new(&mut out_buf); let mut writer = Writer::new(&mut cursor); ret_read.to_writer(&mut writer, (1, 2)).unwrap(); assert_eq!(out_buf.to_vec(), &test_data[..]); } #[test] fn test_top_level_ctx_enum_default() { #[derive(PartialEq, Debug, DekuRead, DekuWrite)] #[deku(id_type = "u8", ctx = "a: u8, b: u8", ctx_default = "1,2")] enum TopLevelCtxEnumDefault { #[deku(id = "1")] VariantA( #[deku( reader = "(u8::from_reader_with_ctx(deku::reader, ()).map(|c|(a+b+c)))", writer = "(|c|{u8::to_writer(&(c-a-b), deku::writer, ())})(field_0)" )] u8, ), } let expected = TopLevelCtxEnumDefault::VariantA(0x06); let test_data = [0x01_u8, 0x03]; // Use default let ret_read = TopLevelCtxEnumDefault::try_from(test_data.as_slice()).unwrap(); assert_eq!(expected, ret_read); let ret_write: Vec = ret_read.try_into().unwrap(); assert_eq!(test_data.to_vec(), ret_write); // Use context let ret_read = TopLevelCtxEnumDefault::from_reader_with_ctx( &mut Reader::new(&mut Cursor::new(test_data)), (1, 2), ) .unwrap(); assert_eq!(ret_read, TopLevelCtxEnumDefault::VariantA(0x06)); let mut out_buf = vec![]; let mut cursor = Cursor::new(&mut out_buf); let mut writer = Writer::new(&mut cursor); ret_read.to_writer(&mut writer, (1, 2)).unwrap(); assert_eq!(test_data.to_vec(), out_buf.to_vec()); } #[test] fn test_struct_enum_ctx_id() { #[derive(PartialEq, Debug, DekuRead, DekuWrite)] #[deku(ctx = "my_id: u8, data: usize", id = "my_id, data")] enum EnumId { #[deku(id = "(1, 1)")] VarA(u8), #[deku(id = "(2, 2)")] VarB, #[deku(id = "(2, 3)")] VarC(u8), #[deku(id_pat = "_")] VarAll(u8), } #[derive(PartialEq, Debug, DekuRead, DekuWrite)] #[deku(ctx = "my_id: u8", id = "my_id")] enum EnumJustId { #[deku(id = "1")] VarA(u8), #[deku(id = "2")] VarB, } #[derive(PartialEq, Debug, DekuRead, DekuWrite)] struct StructEnumId { my_id: u8, #[deku(bytes = 1)] data: usize, #[deku(ctx = "*my_id, *data")] enum_from_id: EnumId, #[deku(ctx = "*my_id")] enum_from_just_id: EnumJustId, } // VarA let test_data = [0x01_u8, 0x01, 0xab, 0xab]; let ret_read = StructEnumId::try_from(test_data.as_slice()).unwrap(); assert_eq!( StructEnumId { my_id: 0x01, data: 0x01, enum_from_id: EnumId::VarA(0xab), enum_from_just_id: EnumJustId::VarA(0xab), }, ret_read ); let ret_write: Vec = ret_read.try_into().unwrap(); assert_eq!(ret_write, test_data); // VarB let test_data = [0x02_u8, 0x02]; let ret_read = StructEnumId::try_from(test_data.as_slice()).unwrap(); assert_eq!( StructEnumId { my_id: 0x02, data: 0x02, enum_from_id: EnumId::VarB, enum_from_just_id: EnumJustId::VarB, }, ret_read ); let ret_write: Vec = ret_read.try_into().unwrap(); assert_eq!(ret_write, test_data); // VarC let test_data = [0x02_u8, 0x03, 0xcc]; let mut cursor = Cursor::new(test_data); let (_, ret_read) = StructEnumId::from_reader((&mut cursor, 0)).unwrap(); assert_eq!( StructEnumId { my_id: 0x02, data: 0x03, enum_from_id: EnumId::VarC(0xcc), enum_from_just_id: EnumJustId::VarB, }, ret_read ); let ret_write: Vec = ret_read.try_into().unwrap(); assert_eq!(ret_write, test_data); // VarPat let test_data = [0x02_u8, 0xff, 0xcc]; let mut cursor = Cursor::new(test_data); let (_, ret_read) = StructEnumId::from_reader((&mut cursor, 0)).unwrap(); assert_eq!( StructEnumId { my_id: 0x02, data: 0xff, enum_from_id: EnumId::VarAll(0xcc), enum_from_just_id: EnumJustId::VarB, }, ret_read ); let ret_write: Vec = ret_read.try_into().unwrap(); assert_eq!(ret_write, test_data); } #[test] fn test_ctx_default_struct() { #[derive(PartialEq, Debug, DekuRead, DekuWrite)] #[deku(ctx = "a: u8, b: u8", ctx_default = "1, 2")] struct TopLevelCtxStructDefault { #[deku(cond = "a == 1")] a: Option, #[deku(cond = "b == 1")] b: Option, } let expected = TopLevelCtxStructDefault { a: Some(0xff), b: None, }; let test_data = [0xffu8]; // Use default let ret_read = TopLevelCtxStructDefault::try_from(test_data.as_slice()).unwrap(); assert_eq!(expected, ret_read); let ret_write: Vec = ret_read.try_into().unwrap(); assert_eq!(ret_write, test_data); // Use context let ret_read = TopLevelCtxStructDefault::from_reader_with_ctx( &mut Reader::new(&mut Cursor::new(test_data)), (1, 2), ) .unwrap(); assert_eq!(expected, ret_read); let mut out_buf = vec![]; let mut cursor = Cursor::new(&mut out_buf); let mut writer = Writer::new(&mut cursor); ret_read.to_writer(&mut writer, (1, 2)).unwrap(); assert_eq!(test_data.to_vec(), out_buf.to_vec()); } #[test] fn test_enum_endian_ctx() { #[derive(PartialEq, Debug, DekuRead, DekuWrite)] #[deku(id_type = "u32", endian = "endian", ctx = "endian: deku::ctx::Endian")] enum EnumTypeEndianCtx { #[deku(id = "0xDEADBEEF")] VarA(u8), } #[derive(PartialEq, Debug, DekuRead, DekuWrite)] struct EnumTypeEndian { #[deku(endian = "big")] t: EnumTypeEndianCtx, } let test_data = [0xdeu8, 0xad, 0xbe, 0xef, 0xff]; let ret_read = EnumTypeEndian::try_from(test_data.as_slice()).unwrap(); assert_eq!( EnumTypeEndian { t: EnumTypeEndianCtx::VarA(0xff) }, ret_read ); let ret_write: Vec = ret_read.try_into().unwrap(); assert_eq!(ret_write, test_data) }