planck_pack_core/
radix.rs1use crate::error::DecodeError;
2use crate::traits::Packable;
3
4impl Packable for bool {
7 const RADIX: u128 = 2;
8
9 fn to_ordinal(&self) -> u128 {
10 *self as u128
11 }
12
13 fn from_ordinal(ord: u128) -> Result<Self, DecodeError> {
14 match ord {
15 0 => Ok(false),
16 1 => Ok(true),
17 _ => Err(DecodeError::OrdinalOutOfRange {
18 ordinal: ord,
19 radix: 2,
20 }),
21 }
22 }
23}
24
25impl Packable for () {
28 const RADIX: u128 = 1;
29
30 fn to_ordinal(&self) -> u128 {
31 0
32 }
33
34 fn from_ordinal(ord: u128) -> Result<Self, DecodeError> {
35 if ord == 0 {
36 Ok(())
37 } else {
38 Err(DecodeError::OrdinalOutOfRange {
39 ordinal: ord,
40 radix: 1,
41 })
42 }
43 }
44}
45
46macro_rules! impl_packable_unsigned {
49 ($ty:ty, $radix:expr) => {
50 impl Packable for $ty {
51 const RADIX: u128 = $radix;
52
53 fn to_ordinal(&self) -> u128 {
54 *self as u128
55 }
56
57 fn from_ordinal(ord: u128) -> Result<Self, DecodeError> {
58 if ord < $radix {
59 Ok(ord as $ty)
60 } else {
61 Err(DecodeError::OrdinalOutOfRange {
62 ordinal: ord,
63 radix: $radix,
64 })
65 }
66 }
67 }
68 };
69}
70
71impl_packable_unsigned!(u8, 256);
72impl_packable_unsigned!(u16, 65536);
73impl_packable_unsigned!(u32, 1 << 32);
74impl_packable_unsigned!(u64, 1 << 64);
75
76macro_rules! impl_packable_signed {
79 ($ty:ty, $unsigned:ty, $radix:expr, $offset:expr) => {
80 impl Packable for $ty {
81 const RADIX: u128 = $radix;
82
83 fn to_ordinal(&self) -> u128 {
84 (*self as $unsigned) as u128
85 }
86
87 fn from_ordinal(ord: u128) -> Result<Self, DecodeError> {
88 if ord < $radix {
89 Ok((ord as $unsigned) as $ty)
90 } else {
91 Err(DecodeError::OrdinalOutOfRange {
92 ordinal: ord,
93 radix: $radix,
94 })
95 }
96 }
97 }
98 };
99}
100
101impl_packable_signed!(i8, u8, 256, 128);
102impl_packable_signed!(i16, u16, 65536, 32768);
103impl_packable_signed!(i32, u32, 1 << 32, 1 << 31);
104impl_packable_signed!(i64, u64, 1 << 64, 1 << 63);
105
106impl<T: Packable> Packable for Option<T> {
109 const RADIX: u128 = T::RADIX + 1;
110
111 fn to_ordinal(&self) -> u128 {
112 match self {
113 None => 0,
114 Some(v) => v.to_ordinal() + 1,
115 }
116 }
117
118 fn from_ordinal(ord: u128) -> Result<Self, DecodeError> {
119 if ord == 0 {
120 Ok(None)
121 } else if ord <= T::RADIX {
122 Ok(Some(T::from_ordinal(ord - 1)?))
123 } else {
124 Err(DecodeError::OrdinalOutOfRange {
125 ordinal: ord,
126 radix: Self::RADIX,
127 })
128 }
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135
136 #[test]
137 fn bool_round_trip() {
138 assert_eq!(bool::from_ordinal(false.to_ordinal()).unwrap(), false);
139 assert_eq!(bool::from_ordinal(true.to_ordinal()).unwrap(), true);
140 assert!(bool::from_ordinal(2).is_err());
141 }
142
143 #[test]
144 fn u8_round_trip() {
145 for v in 0..=255u8 {
146 assert_eq!(u8::from_ordinal(v.to_ordinal()).unwrap(), v);
147 }
148 assert!(u8::from_ordinal(256).is_err());
149 }
150
151 #[test]
152 fn i8_round_trip() {
153 for v in i8::MIN..=i8::MAX {
154 assert_eq!(i8::from_ordinal(v.to_ordinal()).unwrap(), v);
155 }
156 }
157
158 #[test]
159 fn option_round_trip() {
160 let none: Option<bool> = None;
161 assert_eq!(Option::<bool>::from_ordinal(none.to_ordinal()).unwrap(), None);
162 assert_eq!(
163 Option::<bool>::from_ordinal(Some(true).to_ordinal()).unwrap(),
164 Some(true)
165 );
166 assert_eq!(Option::<bool>::RADIX, 3);
167 }
168
169 #[test]
170 fn unit_round_trip() {
171 assert_eq!(<()>::from_ordinal(().to_ordinal()).unwrap(), ());
172 assert!(<()>::from_ordinal(1).is_err());
173 }
174}