diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index 2e4958b73ff5..ae92511fd56d 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -45,7 +45,7 @@ use dep::protocol_types::{ PRIVATE_LOG_SIZE_IN_FIELDS, PUBLIC_DISPATCH_SELECTOR, }, messaging::l2_to_l1_message::L2ToL1Message, - traits::Empty, + traits::{Empty, FromField, Hash}, }; // When finished, one can call .finish() to convert back to the abi diff --git a/noir-projects/aztec-nr/aztec/src/context/public_context.nr b/noir-projects/aztec-nr/aztec/src/context/public_context.nr index ccb3526e65d7..b1aa80192a7a 100644 --- a/noir-projects/aztec-nr/aztec/src/context/public_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/public_context.nr @@ -5,7 +5,7 @@ use crate::hash::{ use dep::protocol_types::abis::function_selector::FunctionSelector; use dep::protocol_types::address::{AztecAddress, EthAddress}; use dep::protocol_types::constants::MAX_FIELD_VALUE; -use dep::protocol_types::traits::{Deserialize, Empty, Serialize}; +use dep::protocol_types::traits::{Empty, Packable, Serialize}; pub struct PublicContext { pub args_hash: Option, @@ -219,9 +219,9 @@ impl PublicContext { pub fn storage_read(self, storage_slot: Field) -> T where - T: Deserialize, + T: Packable, { - T::deserialize(self.raw_storage_read(storage_slot)) + T::unpack(self.raw_storage_read(storage_slot)) } pub fn raw_storage_write(_self: Self, storage_slot: Field, values: [Field; N]) { @@ -233,9 +233,9 @@ impl PublicContext { pub fn storage_write(self, storage_slot: Field, value: T) where - T: Serialize, + T: Packable, { - self.raw_storage_write(storage_slot, value.serialize()); + self.raw_storage_write(storage_slot, value.pack()); } } diff --git a/noir-projects/aztec-nr/aztec/src/context/unconstrained_context.nr b/noir-projects/aztec-nr/aztec/src/context/unconstrained_context.nr index 5a2c5f765ab6..a50105824fa5 100644 --- a/noir-projects/aztec-nr/aztec/src/context/unconstrained_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/unconstrained_context.nr @@ -2,7 +2,7 @@ use crate::oracle::{ execution::{get_block_number, get_chain_id, get_contract_address, get_version}, storage::storage_read, }; -use dep::protocol_types::{address::AztecAddress, traits::Deserialize}; +use dep::protocol_types::{address::AztecAddress, traits::Packable}; pub struct UnconstrainedContext { block_number: u32, @@ -62,8 +62,8 @@ impl UnconstrainedContext { pub unconstrained fn storage_read(self, storage_slot: Field) -> T where - T: Deserialize, + T: Packable, { - T::deserialize(self.raw_storage_read(storage_slot)) + T::unpack(self.raw_storage_read(storage_slot)) } } diff --git a/noir-projects/aztec-nr/aztec/src/oracle/storage.nr b/noir-projects/aztec-nr/aztec/src/oracle/storage.nr index 67e86790e43d..98909a8209ca 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/storage.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/storage.nr @@ -1,4 +1,4 @@ -use dep::protocol_types::{address::AztecAddress, traits::Deserialize}; +use dep::protocol_types::{address::AztecAddress, traits::{Packable, ToField}}; #[oracle(storageRead)] unconstrained fn storage_read_oracle( @@ -27,14 +27,14 @@ pub unconstrained fn storage_read( block_number: u32, ) -> T where - T: Deserialize, + T: Packable, { - T::deserialize(raw_storage_read(address, storage_slot, block_number)) + T::unpack(raw_storage_read(address, storage_slot, block_number)) } mod tests { use crate::oracle::storage::{raw_storage_read, storage_read}; - use dep::protocol_types::address::AztecAddress; + use dep::protocol_types::{address::AztecAddress, traits::{FromField, Packable}}; use crate::test::mocks::mock_struct::MockStruct; use std::test::OracleMock; @@ -47,7 +47,7 @@ mod tests { unconstrained fn test_raw_storage_read() { let written = MockStruct { a: 13, b: 42 }; - let _ = OracleMock::mock("storageRead").returns(written.serialize()); + let _ = OracleMock::mock("storageRead").returns(written.pack()); let read: [Field; 2] = raw_storage_read(address, slot, block_number); assert_eq(read[0], 13); @@ -58,7 +58,7 @@ mod tests { unconstrained fn test_storage_read() { let written = MockStruct { a: 13, b: 42 }; - let _ = OracleMock::mock("storageRead").returns(written.serialize()); + let _ = OracleMock::mock("storageRead").returns(written.pack()); let read: MockStruct = storage_read(address, slot, block_number); assert_eq(read.a, 13); diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr index 96809aa86869..af8402a86c2c 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr @@ -1,11 +1,9 @@ use crate::{ context::{PrivateContext, PublicContext, UnconstrainedContext}, + history::public_storage::PublicStorageHistoricalRead, state_vars::storage::Storage, }; -use dep::protocol_types::{ - constants::INITIALIZATION_SLOT_SEPARATOR, - traits::{Deserialize, Serialize}, -}; +use dep::protocol_types::{constants::INITIALIZATION_SLOT_SEPARATOR, traits::Packable}; /// Stores an immutable value in public state which can be read from public, private and unconstrained execution /// contexts. @@ -18,7 +16,7 @@ pub struct PublicImmutable { impl Storage for PublicImmutable where - T: Serialize + Deserialize, + T: Packable, { fn get_storage_slot(self) -> Field { self.storage_slot @@ -38,9 +36,9 @@ impl PublicImmutable { // docs:end:public_immutable_struct_new } -impl PublicImmutable +impl PublicImmutable where - T: Serialize + Deserialize, + T: Packable, { // docs:start:public_immutable_struct_write pub fn initialize(self, value: T) { @@ -63,22 +61,22 @@ where // docs:end:public_immutable_struct_read } -impl PublicImmutable +impl PublicImmutable where - T: Serialize + Deserialize, + T: Packable, { pub unconstrained fn read(self) -> T { self.context.storage_read(self.storage_slot) } } -impl PublicImmutable +impl PublicImmutable where - T: Serialize + Deserialize, + T: Packable, { pub fn read(self) -> T { let header = self.context.get_block_header(); - let mut fields = [0; T_SERIALIZED_LEN]; + let mut fields = [0; T_PACKED_LEN]; for i in 0..fields.len() { fields[i] = header.public_storage_historical_read( @@ -86,6 +84,6 @@ where (*self.context).this_address(), ); } - T::deserialize(fields) + T::unpack(fields) } } diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr index cf9bf5890403..f2890f27f64d 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr @@ -1,6 +1,6 @@ use crate::context::{PublicContext, UnconstrainedContext}; use crate::state_vars::storage::Storage; -use dep::protocol_types::traits::{Deserialize, Serialize}; +use dep::protocol_types::traits::Packable; // docs:start:public_mutable_struct pub struct PublicMutable { @@ -11,7 +11,7 @@ pub struct PublicMutable { impl Storage for PublicMutable where - T: Serialize + Deserialize, + T: Packable, { fn get_storage_slot(self) -> Field { self.storage_slot @@ -31,9 +31,9 @@ impl PublicMutable { // docs:end:public_mutable_struct_new } -impl PublicMutable +impl PublicMutable where - T: Serialize + Deserialize, + T: Packable, { // docs:start:public_mutable_struct_read pub fn read(self) -> T { @@ -48,9 +48,9 @@ where // docs:end:public_mutable_struct_write } -impl PublicMutable +impl PublicMutable where - T: Deserialize, + T: Packable, { pub unconstrained fn read(self) -> T { self.context.storage_read(self.storage_slot) diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable.nr index 34ace291116d..46a5da870043 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable.nr @@ -225,12 +225,12 @@ where // scheduled. Therefore, the hints must then correspond to uninitialized scheduled changes. assert_eq( value_change_hint, - ScheduledValueChange::deserialize(zeroed()), + ScheduledValueChange::unpack(zeroed()), "Non-zero value change for zero hash", ); assert_eq( delay_change_hint, - ScheduledDelayChange::deserialize(zeroed()), + ScheduledDelayChange::unpack(zeroed()), "Non-zero delay change for zero hash", ); }; @@ -242,8 +242,7 @@ where value_change: ScheduledValueChange, delay_change: ScheduledDelayChange, ) -> Field { - let concatenated: [Field; 4] = - array_concat(value_change.serialize(), delay_change.serialize()); + let concatenated: [Field; 4] = array_concat(value_change.pack(), delay_change.pack()); poseidon2_hash(concatenated) } } diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change.nr b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change.nr index 29808aef30a3..d325dbd0a0f0 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change.nr @@ -1,4 +1,4 @@ -use dep::protocol_types::traits::{Deserialize, Serialize}; +use dep::protocol_types::traits::Packable; use std::cmp::min; mod test; @@ -125,8 +125,8 @@ impl ScheduledDelayChange { } } -impl Serialize<1> for ScheduledDelayChange { - fn serialize(self) -> [Field; 1] { +impl Packable<1> for ScheduledDelayChange { + fn pack(self) -> [Field; 1] { // We pack all three u32 values into a single U128, which is made up of two u64 limbs. // Low limb: [ pre_inner: u32 | post_inner: u32 ] // High limb: [ empty | pre_is_some: u8 | post_is_some: u8 | block_of_change: u32 ] @@ -141,10 +141,8 @@ impl Serialize<1> for ScheduledDelayChange Deserialize<1> for ScheduledDelayChange { - fn deserialize(input: [Field; 1]) -> Self { + fn unpack(input: [Field; 1]) -> Self { let packed = U128::from_integer(input[0]); // We use division and modulo to clear the bits that correspond to other values when unpacking. diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change/test.nr b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change/test.nr index 17a9e5e94e6c..5cbeb1e583c1 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change/test.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change/test.nr @@ -6,7 +6,7 @@ unconstrained fn assert_equal_after_conversion(original: ScheduledDelayChange = - ScheduledDelayChange::deserialize((original).serialize()); + ScheduledDelayChange::unpack(original.pack()); assert_eq(original, converted); // This also tests the Eq impl assert_eq(original.pre, converted.pre); @@ -81,7 +81,7 @@ unconstrained fn get_non_initial_delay_change( } unconstrained fn get_initial_delay_change() -> ScheduledDelayChange { - ScheduledDelayChange::deserialize([0]) + ScheduledDelayChange::unpack([0]) } #[test] diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_value_change.nr b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_value_change.nr index 2bc6a2527985..eeb55c46e760 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_value_change.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_value_change.nr @@ -1,4 +1,4 @@ -use dep::protocol_types::traits::{Deserialize, FromField, Serialize, ToField}; +use dep::protocol_types::traits::{FromField, Packable, ToField}; use std::cmp::min; mod test; @@ -133,20 +133,15 @@ impl ScheduledValueChange { } } -impl Serialize<3> for ScheduledValueChange +impl Packable<3> for ScheduledValueChange where - T: ToField, + T: ToField + FromField, { - fn serialize(self) -> [Field; 3] { + fn pack(self) -> [Field; 3] { [self.pre.to_field(), self.post.to_field(), self.block_of_change.to_field()] } -} -impl Deserialize<3> for ScheduledValueChange -where - T: FromField, -{ - fn deserialize(input: [Field; 3]) -> Self { + fn unpack(input: [Field; 3]) -> Self { Self { pre: FromField::from_field(input[0]), post: FromField::from_field(input[1]), diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_value_change/test.nr b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_value_change/test.nr index 4677830d013e..179089945abd 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_value_change/test.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_value_change/test.nr @@ -3,13 +3,13 @@ use crate::state_vars::shared_mutable::scheduled_value_change::ScheduledValueCha global TEST_DELAY: u32 = 200; #[test] -unconstrained fn test_serde() { +unconstrained fn test_packable() { let pre = 1; let post = 2; let block_of_change = 50; let original = ScheduledValueChange::new(pre, post, block_of_change); - let converted = ScheduledValueChange::deserialize((original).serialize()); + let converted = ScheduledValueChange::unpack((original).pack()); assert_eq(original, converted); // This also tests the Eq impl assert_eq(original.pre, converted.pre); diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/test.nr b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/test.nr index f3ec3434abf3..8983b35e44ae 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/test.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/test.nr @@ -296,7 +296,7 @@ unconstrained fn test_get_current_value_in_private_bad_value_hints() { env.contract_address().to_field(), private_state_var.get_value_change_storage_slot(), schedule_block_number, 3, )) - .returns(mocked.serialize()) + .returns(mocked.pack()) .times(1); let _ = private_state_var.get_current_value(); @@ -319,7 +319,7 @@ unconstrained fn test_get_current_value_in_private_bad_delay_hints() { env.contract_address().to_field(), private_state_var.get_delay_change_storage_slot(), schedule_block_number, 1, )) - .returns(mocked.serialize()) + .returns(mocked.pack()) .times(1); let _ = private_state_var.get_current_value(); @@ -338,7 +338,7 @@ unconstrained fn test_get_current_value_in_private_bad_zero_hash_value_hints() { env.contract_address().to_field(), state_var.get_value_change_storage_slot(), historical_block_number, 3, )) - .returns(mocked.serialize()) + .returns(mocked.pack()) .times(1); let _ = state_var.get_current_value(); @@ -358,7 +358,7 @@ unconstrained fn test_get_current_value_in_private_bad_zero_hash_delay_hints() { env.contract_address().to_field(), state_var.get_delay_change_storage_slot(), historical_block_number, 1, )) - .returns(mocked.serialize()) + .returns(mocked.pack()) .times(1); let _ = state_var.get_current_value(); diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/storage.nr b/noir-projects/aztec-nr/aztec/src/state_vars/storage.nr index 3539ce0c78cc..3ea02e3ad886 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/storage.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/storage.nr @@ -1,8 +1,8 @@ -use dep::protocol_types::traits::{Deserialize, Serialize}; +use dep::protocol_types::traits::Packable; pub trait Storage where - T: Serialize + Deserialize, + T: Packable, { fn get_storage_slot(self) -> Field; } diff --git a/noir-projects/aztec-nr/aztec/src/test/mocks/mock_struct.nr b/noir-projects/aztec-nr/aztec/src/test/mocks/mock_struct.nr index 2adfcda5a5ba..4677b23fb14e 100644 --- a/noir-projects/aztec-nr/aztec/src/test/mocks/mock_struct.nr +++ b/noir-projects/aztec-nr/aztec/src/test/mocks/mock_struct.nr @@ -1,4 +1,4 @@ -use dep::protocol_types::traits::{Deserialize, Serialize}; +use dep::protocol_types::traits::{Deserialize, Packable, Serialize}; pub(crate) struct MockStruct { pub(crate) a: Field, @@ -29,8 +29,24 @@ impl Deserialize<2> for MockStruct { } } +impl Packable<2> for MockStruct { + fn pack(self) -> [Field; 2] { + [self.a, self.b] + } + + fn unpack(fields: [Field; 2]) -> Self { + Self { a: fields[0], b: fields[1] } + } +} + #[test] unconstrained fn test_serde() { let val = MockStruct::new(5, 6); assert_eq(val, MockStruct::deserialize(val.serialize())); } + +#[test] +unconstrained fn test_packable() { + let val = MockStruct::new(5, 6); + assert_eq(val, MockStruct::unpack(val.pack())); +} diff --git a/noir-projects/aztec-nr/compressed-string/src/field_compressed_string.nr b/noir-projects/aztec-nr/compressed-string/src/field_compressed_string.nr index 41b391c260c5..2c1c40613ace 100644 --- a/noir-projects/aztec-nr/compressed-string/src/field_compressed_string.nr +++ b/noir-projects/aztec-nr/compressed-string/src/field_compressed_string.nr @@ -1,4 +1,4 @@ -use dep::aztec::protocol_types::{traits::{Deserialize, Serialize}, utils::field::field_from_bytes}; +use dep::aztec::protocol_types::{traits::Packable, utils::field::field_from_bytes}; // A Fixedsize Compressed String. // Essentially a special version of Compressed String for practical use. @@ -6,14 +6,12 @@ pub struct FieldCompressedString { value: Field, } -impl Serialize<1> for FieldCompressedString { - fn serialize(self) -> [Field; 1] { +impl Packable<1> for FieldCompressedString { + fn pack(self) -> [Field; 1] { [self.value] } -} -impl Deserialize<1> for FieldCompressedString { - fn deserialize(input: [Field; 1]) -> Self { + fn unpack(input: [Field; 1]) -> Self { Self { value: input[0] } } } diff --git a/noir-projects/noir-contracts/contracts/amm_contract/src/config.nr b/noir-projects/noir-contracts/contracts/amm_contract/src/config.nr index c83648c4a395..5efdd982624e 100644 --- a/noir-projects/noir-contracts/contracts/amm_contract/src/config.nr +++ b/noir-projects/noir-contracts/contracts/amm_contract/src/config.nr @@ -1,4 +1,4 @@ -use dep::aztec::protocol_types::{address::AztecAddress, traits::{Deserialize, Serialize}}; +use dep::aztec::protocol_types::{address::AztecAddress, traits::{FromField, Packable, ToField}}; global CONFIG_LENGTH: u32 = 3; @@ -11,15 +11,12 @@ pub struct Config { pub liquidity_token: AztecAddress, } -// Note: I could not get #[derive(Serialize)] to work so I had to implement it manually. -impl Serialize for Config { - fn serialize(self: Self) -> [Field; CONFIG_LENGTH] { +impl Packable for Config { + fn pack(self: Self) -> [Field; CONFIG_LENGTH] { [self.token0.to_field(), self.token1.to_field(), self.liquidity_token.to_field()] } -} -impl Deserialize for Config { - fn deserialize(fields: [Field; CONFIG_LENGTH]) -> Self { + fn unpack(fields: [Field; CONFIG_LENGTH]) -> Self { Self { token0: AztecAddress::from_field(fields[0]), token1: AztecAddress::from_field(fields[1]), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/lib.nr b/noir-projects/noir-protocol-circuits/crates/types/src/lib.nr index 4a3ccfc32d03..c5c37d539cb1 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/lib.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/lib.nr @@ -16,6 +16,7 @@ pub mod hash; pub mod poseidon2; pub mod traits; pub mod type_serialization; +pub mod type_packing; pub mod content_commitment; pub mod block_header; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/type_packing.nr b/noir-projects/noir-protocol-circuits/crates/types/src/type_packing.nr new file mode 100644 index 000000000000..ffcc62eb32bf --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/types/src/type_packing.nr @@ -0,0 +1,176 @@ +use crate::traits::{Packable, ToField}; + +global BOOL_PACKED_LEN: u32 = 1; +global U8_PACKED_LEN: u32 = 1; +global U16_PACKED_LEN: u32 = 1; +global U32_PACKED_LEN: u32 = 1; +global U64_PACKED_LEN: u32 = 1; +global U128_PACKED_LEN: u32 = 1; +global FIELD_PACKED_LEN: u32 = 1; +global I8_PACKED_LEN: u32 = 1; +global I16_PACKED_LEN: u32 = 1; +global I32_PACKED_LEN: u32 = 1; +global I64_PACKED_LEN: u32 = 1; + +impl Packable for bool { + fn pack(self) -> [Field; BOOL_PACKED_LEN] { + [self as Field] + } + + fn unpack(fields: [Field; BOOL_PACKED_LEN]) -> bool { + fields[0] as bool + } +} + +impl Packable for u8 { + fn pack(self) -> [Field; U8_PACKED_LEN] { + [self as Field] + } + + fn unpack(fields: [Field; U8_PACKED_LEN]) -> Self { + fields[0] as u8 + } +} + +impl Packable for u16 { + fn pack(self) -> [Field; U16_PACKED_LEN] { + [self as Field] + } + + fn unpack(fields: [Field; U16_PACKED_LEN]) -> Self { + fields[0] as u16 + } +} + +impl Packable for u32 { + fn pack(self) -> [Field; U32_PACKED_LEN] { + [self as Field] + } + + fn unpack(fields: [Field; U32_PACKED_LEN]) -> Self { + fields[0] as u32 + } +} + +impl Packable for u64 { + fn pack(self) -> [Field; U64_PACKED_LEN] { + [self as Field] + } + + fn unpack(fields: [Field; U64_PACKED_LEN]) -> Self { + fields[0] as u64 + } +} + +impl Packable for U128 { + fn pack(self) -> [Field; U128_PACKED_LEN] { + [self.to_field()] + } + + fn unpack(fields: [Field; U128_PACKED_LEN]) -> Self { + U128::from_u64s_le(fields[0] as u64, fields[1] as u64) + } +} + +impl Packable for Field { + fn pack(self) -> [Field; FIELD_PACKED_LEN] { + [self] + } + + fn unpack(fields: [Field; FIELD_PACKED_LEN]) -> Self { + fields[0] + } +} + +impl Packable for i8 { + fn pack(self) -> [Field; I8_PACKED_LEN] { + [self as Field] + } + + fn unpack(fields: [Field; I8_PACKED_LEN]) -> Self { + fields[0] as i8 + } +} + +impl Packable for i16 { + fn pack(self) -> [Field; I16_PACKED_LEN] { + [self as Field] + } + + fn unpack(fields: [Field; I16_PACKED_LEN]) -> Self { + fields[0] as i16 + } +} + +impl Packable for i32 { + fn pack(self) -> [Field; I32_PACKED_LEN] { + [self as Field] + } + + fn unpack(fields: [Field; I32_PACKED_LEN]) -> Self { + fields[0] as i32 + } +} + +impl Packable for i64 { + fn pack(self) -> [Field; I64_PACKED_LEN] { + [self as Field] + } + + fn unpack(fields: [Field; I64_PACKED_LEN]) -> Self { + fields[0] as i64 + } +} + +impl Packable for [T; N] +where + T: Packable, +{ + fn pack(self) -> [Field; N * M] { + let mut result: [Field; N * M] = std::mem::zeroed(); + let mut serialized: [Field; M] = std::mem::zeroed(); + for i in 0..N { + serialized = self[i].pack(); + for j in 0..M { + result[i * M + j] = serialized[j]; + } + } + result + } + + fn unpack(fields: [Field; N * M]) -> Self { + let mut reader = crate::utils::reader::Reader::new(fields); + let mut result: [T; N] = std::mem::zeroed(); + reader.read_struct_array::(Packable::unpack, result) + } +} + +#[test] +fn test_u16_packing() { + let a: u16 = 10; + assert_eq(a, u16::unpack(a.pack())); +} + +#[test] +fn test_i8_packing() { + let a: i8 = -10; + assert_eq(a, i8::unpack(a.pack())); +} + +#[test] +fn test_i16_packing() { + let a: i16 = -10; + assert_eq(a, i16::unpack(a.pack())); +} + +#[test] +fn test_i32_packing() { + let a: i32 = -10; + assert_eq(a, i32::unpack(a.pack())); +} + +#[test] +fn test_i64_packing() { + let a: i64 = -10; + assert_eq(a, i64::unpack(a.pack())); +}