| // This file is part of ICU4X. For terms of use, please see the file |
| // called LICENSE at the top level of the ICU4X source tree |
| // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). |
| |
| use zerovec::ule::AsULE; |
| use zerovec::ule::EncodeAsVarULE; |
| use zerovec::*; |
| |
| #[repr(C, packed)] |
| #[derive(ule::ULE, Copy, Clone)] |
| pub struct FooULE { |
| a: u8, |
| b: <u32 as AsULE>::ULE, |
| c: <char as AsULE>::ULE, |
| } |
| |
| #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
| struct Foo { |
| a: u8, |
| b: u32, |
| c: char, |
| } |
| |
| impl AsULE for Foo { |
| type ULE = FooULE; |
| fn to_unaligned(self) -> FooULE { |
| FooULE { |
| a: self.a, |
| b: self.b.to_unaligned(), |
| c: self.c.to_unaligned(), |
| } |
| } |
| |
| fn from_unaligned(other: FooULE) -> Self { |
| Self { |
| a: other.a, |
| b: AsULE::from_unaligned(other.b), |
| c: AsULE::from_unaligned(other.c), |
| } |
| } |
| } |
| |
| #[repr(C, packed)] |
| #[derive(ule::VarULE)] |
| pub struct RelationULE { |
| /// This maps to (AndOr, Polarity, Operand), |
| /// with the first bit mapping to AndOr (1 == And), the second bit |
| /// to Polarity (1 == Positive), and the remaining bits to Operand |
| /// encoded via Operand::encode. It is unsound for the Operand bits to |
| /// not be a valid encoded Operand. |
| andor_polarity_operand: u8, |
| modulo: <u32 as AsULE>::ULE, |
| range_list: ZeroSlice<Foo>, |
| } |
| |
| #[derive(Clone, PartialEq, Debug)] |
| pub struct Relation<'a> { |
| andor_polarity_operand: u8, |
| modulo: u32, |
| range_list: ZeroVec<'a, Foo>, |
| } |
| |
| unsafe impl EncodeAsVarULE<RelationULE> for Relation<'_> { |
| fn encode_var_ule_as_slices<R>(&self, cb: impl FnOnce(&[&[u8]]) -> R) -> R { |
| cb(&[ |
| &[self.andor_polarity_operand], |
| ule::ULE::as_byte_slice(&[self.modulo.to_unaligned()]), |
| self.range_list.as_bytes(), |
| ]) |
| } |
| } |
| |
| impl RelationULE { |
| pub fn as_relation(&self) -> Relation { |
| Relation { |
| andor_polarity_operand: self.andor_polarity_operand, |
| modulo: u32::from_unaligned(self.modulo), |
| range_list: self.range_list.as_zerovec(), |
| } |
| } |
| } |
| |
| const TEST_SLICE: &[Foo] = &[ |
| Foo { |
| a: 101, |
| b: 924, |
| c: '⸘', |
| }, |
| Foo { |
| a: 217, |
| b: 4228, |
| c: 'ə', |
| }, |
| Foo { |
| a: 117, |
| b: 9090, |
| c: 'ø', |
| }, |
| ]; |
| |
| const TEST_SLICE2: &[Foo] = &[ |
| Foo { |
| a: 92, |
| b: 4, |
| c: 'å', |
| }, |
| Foo { |
| a: 9, |
| b: 49993, |
| c: '±', |
| }, |
| ]; |
| fn test_zerovec() { |
| let zerovec: ZeroVec<Foo> = TEST_SLICE.iter().copied().collect(); |
| |
| assert_eq!(zerovec, TEST_SLICE); |
| |
| let bytes = zerovec.as_bytes(); |
| let reparsed: ZeroVec<Foo> = ZeroVec::parse_byte_slice(bytes).expect("Parsing should succeed"); |
| |
| assert_eq!(reparsed, TEST_SLICE); |
| } |
| |
| fn test_varzerovec() { |
| let relation1 = Relation { |
| andor_polarity_operand: 1, |
| modulo: 5004, |
| range_list: TEST_SLICE.iter().copied().collect(), |
| }; |
| let relation2 = Relation { |
| andor_polarity_operand: 5, |
| modulo: 909, |
| range_list: TEST_SLICE2.iter().copied().collect(), |
| }; |
| |
| let relations = &[relation1, relation2]; |
| |
| let vzv = VarZeroVec::<_>::from(relations); |
| |
| for (ule, stack) in vzv.iter().zip(relations.iter()) { |
| assert_eq!(*stack, ule.as_relation()); |
| } |
| |
| let bytes = vzv.as_bytes(); |
| |
| let recovered: VarZeroVec<RelationULE> = |
| VarZeroVec::parse_byte_slice(bytes).expect("Parsing should succeed"); |
| |
| for (ule, stack) in recovered.iter().zip(relations.iter()) { |
| assert_eq!(*stack, ule.as_relation()); |
| } |
| } |
| |
| fn main() { |
| test_zerovec(); |
| test_varzerovec(); |
| } |