1use std::fmt::{self, Display, Formatter, Write};
23use std::hash::Hash;
24
25use amplify::Wrapper;
26
27use crate::STRICT_TYPES_LIB;
28
29#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)]
30#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))]
31pub struct Primitive(u8);
32
33impl Primitive {
34 pub const U8: Primitive = Primitive::unsigned(1);
35 pub const U16: Primitive = Primitive::unsigned(2);
36 pub const U24: Primitive = Primitive::unsigned(3);
37 pub const U32: Primitive = Primitive::unsigned(4);
38 pub const U40: Primitive = Primitive::unsigned(5);
39 pub const U48: Primitive = Primitive::unsigned(6);
40 pub const U56: Primitive = Primitive::unsigned(7);
41 pub const U64: Primitive = Primitive::unsigned(8);
42 pub const U128: Primitive = Primitive::unsigned(16);
43 pub const U160: Primitive = Primitive::unsigned(20);
44 pub const U256: Primitive = Primitive::unsigned(32);
45 pub const U512: Primitive = Primitive::unsigned(64);
46 pub const U1024: Primitive = Primitive::unsigned(128);
47
48 pub const I8: Primitive = Primitive::signed(1);
49 pub const I16: Primitive = Primitive::signed(2);
50 pub const I24: Primitive = Primitive::signed(3);
51 pub const I32: Primitive = Primitive::signed(4);
52 pub const I40: Primitive = Primitive::signed(5);
53 pub const I48: Primitive = Primitive::signed(6);
54 pub const I56: Primitive = Primitive::signed(7);
55 pub const I64: Primitive = Primitive::signed(8);
56 pub const I128: Primitive = Primitive::signed(16);
57 pub const I256: Primitive = Primitive::signed(32);
58 pub const I512: Primitive = Primitive::signed(64);
59 pub const I1024: Primitive = Primitive::signed(128);
60
61 pub const N8: Primitive = Primitive::non_zero(1);
62 pub const N16: Primitive = Primitive::non_zero(2);
63 pub const N24: Primitive = Primitive::non_zero(3);
64 pub const N32: Primitive = Primitive::non_zero(4);
65 pub const N48: Primitive = Primitive::non_zero(6);
66 pub const N64: Primitive = Primitive::non_zero(8);
67 pub const N128: Primitive = Primitive::non_zero(16);
68
69 pub const F16: Primitive = Primitive::float(2);
70 pub const F32: Primitive = Primitive::float(4);
71 pub const F64: Primitive = Primitive::float(8);
72 pub const F80: Primitive = Primitive::float(10);
73 pub const F128: Primitive = Primitive::float(16);
74 pub const F256: Primitive = Primitive::float(32);
75
76 pub const UNIT: Primitive = Primitive(0x00);
77 pub const BYTE: Primitive = Primitive(0x40);
78 pub const RESERVED: Primitive = Primitive(0x80);
79 pub const F16B: Primitive = Primitive(0xC0);
80
81 pub const FLOAT_RESERVED_1: Primitive = Primitive(0xC1);
82 pub const FLOAT_RESERVED_2: Primitive = Primitive(0xC3);
83 pub const FLOAT_RESERVED_3: Primitive = Primitive(0xC5);
84 pub const FLOAT_RESERVED_4: Primitive = Primitive(0xC6);
85 pub const FLOAT_RESERVED_5: Primitive = Primitive(0xC7);
86 pub const FLOAT_RESERVED_6: Primitive = Primitive(0xC9);
87 pub const FLOAT_RESERVED_7: Primitive = Primitive(0xCB);
88 pub const FLOAT_RESERVED_8: Primitive = Primitive(0xCC);
89 pub const FLOAT_RESERVED_9: Primitive = Primitive(0xCD);
90 pub const FLOAT_RESERVED_10: Primitive = Primitive(0xCE);
91 pub const FLOAT_RESERVED_11: Primitive = Primitive(0xCF);
92 pub const FLOAT_RESERVED_12: Primitive = Primitive(0xD1);
93 pub const FLOAT_RESERVED_13: Primitive = Primitive(0xD2);
94 pub const FLOAT_RESERVED_14: Primitive = Primitive(0xD3);
95 pub const FLOAT_RESERVED_15: Primitive = Primitive(0xD4);
96 pub const FLOAT_RESERVED_16: Primitive = Primitive(0xD5);
97 pub const FLOAT_RESERVED_17: Primitive = Primitive(0xD6);
98 pub const FLOAT_RESERVED_18: Primitive = Primitive(0xD7);
99 pub const FLOAT_RESERVED_19: Primitive = Primitive(0xD8);
100 pub const FLOAT_RESERVED_20: Primitive = Primitive(0xD9);
101 pub const FLOAT_RESERVED_21: Primitive = Primitive(0xDA);
102 pub const FLOAT_RESERVED_22: Primitive = Primitive(0xDB);
103 pub const FLOAT_RESERVED_23: Primitive = Primitive(0xDC);
104 pub const FLOAT_RESERVED_24: Primitive = Primitive(0xDE);
105 pub const FLOAT_RESERVED_25: Primitive = Primitive(0xDF);
106
107 pub const FLOAT_RESERVED_26: Primitive = Primitive(0xE1);
108 pub const FLOAT_RESERVED_27: Primitive = Primitive(0xE2);
109 pub const FLOAT_RESERVED_28: Primitive = Primitive(0xE3);
110 pub const FLOAT_RESERVED_29: Primitive = Primitive(0xE4);
111 pub const FLOAT_RESERVED_30: Primitive = Primitive(0xE5);
112 pub const FLOAT_RESERVED_31: Primitive = Primitive(0xE6);
113 pub const FLOAT_RESERVED_32: Primitive = Primitive(0xE7);
114 pub const FLOAT_RESERVED_33: Primitive = Primitive(0xE8);
115 pub const FLOAT_RESERVED_34: Primitive = Primitive(0xE9);
116 pub const FLOAT_RESERVED_35: Primitive = Primitive(0xEA);
117 pub const FLOAT_RESERVED_36: Primitive = Primitive(0xEB);
118 pub const FLOAT_RESERVED_37: Primitive = Primitive(0xEC);
119 pub const FLOAT_RESERVED_38: Primitive = Primitive(0xEE);
120 pub const FLOAT_RESERVED_39: Primitive = Primitive(0xEF);
121
122 pub const FLOAT_RESERVED_40: Primitive = Primitive(0xF0);
123 pub const FLOAT_RESERVED_41: Primitive = Primitive(0xF1);
124 pub const FLOAT_RESERVED_42: Primitive = Primitive(0xF2);
125 pub const FLOAT_RESERVED_43: Primitive = Primitive(0xF3);
126 pub const FLOAT_RESERVED_44: Primitive = Primitive(0xF4);
127 pub const FLOAT_RESERVED_45: Primitive = Primitive(0xF5);
128 pub const FLOAT_RESERVED_46: Primitive = Primitive(0xF6);
129 pub const FLOAT_RESERVED_47: Primitive = Primitive(0xF7);
130 pub const FLOAT_RESERVED_48: Primitive = Primitive(0xF8);
131 pub const FLOAT_RESERVED_49: Primitive = Primitive(0xF9);
132 pub const FLOAT_RESERVED_50: Primitive = Primitive(0xFA);
133 pub const FLOAT_RESERVED_51: Primitive = Primitive(0xFB);
134 pub const FLOAT_RESERVED_52: Primitive = Primitive(0xFC);
135 pub const FLOAT_RESERVED_53: Primitive = Primitive(0xFE);
136 pub const FLOAT_RESERVED_54: Primitive = Primitive(0xFF);
137
138 pub const fn unsigned(bytes: u16) -> Self {
139 Primitive(
140 NumInfo {
141 ty: NumCls::Unsigned,
142 size: NumSize::from_bytes(bytes),
143 }
144 .into_code(),
145 )
146 }
147
148 pub const fn signed(bytes: u16) -> Self {
149 Primitive(
150 NumInfo {
151 ty: NumCls::Signed,
152 size: NumSize::from_bytes(bytes),
153 }
154 .into_code(),
155 )
156 }
157
158 pub const fn non_zero(bytes: u16) -> Self {
159 Primitive(
160 NumInfo {
161 ty: NumCls::NonZero,
162 size: NumSize::from_bytes(bytes),
163 }
164 .into_code(),
165 )
166 }
167
168 pub const fn float(bytes: u16) -> Self {
169 Primitive(
170 NumInfo {
171 ty: NumCls::Float,
172 size: NumSize::from_bytes(bytes),
173 }
174 .into_code(),
175 )
176 }
177
178 pub const fn from_code(code: u8) -> Self { Primitive(code) }
179 pub const fn into_code(self) -> u8 { self.0 }
180
181 pub const fn info(self) -> NumInfo { NumInfo::from_code(self.0) }
182
183 pub const fn byte_size(self) -> u16 { self.info().byte_size() }
184}
185
186impl Display for Primitive {
187 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
188 match *self {
189 Primitive::UNIT => return f.write_str("()"),
190 Primitive::BYTE => return f.write_str("Byte"),
191 Primitive::F16B => return f.write_str("F16b"),
192 Primitive::RESERVED => unreachable!("reserved primitive value"),
193 _ => {}
194 }
195
196 let info = self.info();
197 f.write_char(match info.ty {
198 NumCls::Unsigned => 'U',
199 NumCls::Signed => 'I',
200 NumCls::NonZero => 'N',
201 NumCls::Float => 'F',
202 })?;
203
204 write!(f, "{}", info.byte_size() * 8)
205 }
206}
207
208impl_strict_newtype!(Primitive, STRICT_TYPES_LIB);
209
210#[derive(Copy, Clone, PartialEq, Eq, Debug)]
212pub struct NumInfo {
213 pub ty: NumCls,
215 pub size: NumSize,
217}
218
219impl NumInfo {
220 pub const fn from_code(id: u8) -> Self {
221 NumInfo {
222 ty: NumCls::from_code(id),
223 size: NumSize::from_code(id),
224 }
225 }
226
227 pub const fn into_code(self) -> u8 { self.ty.into_code() | self.size.into_code() }
228
229 pub const fn byte_size(self) -> u16 { self.size.byte_size() }
230}
231
232#[derive(Copy, Clone, PartialEq, Eq, Debug)]
233pub struct NumSize(NumSizeInner);
234
235impl NumSize {
236 pub(super) const fn from_bytes(bytes: u16) -> Self {
237 NumSize(if bytes < 0x20 {
238 NumSizeInner::Bytes(bytes as u8)
239 } else if bytes % 16 != 0 {
240 unreachable!()
241 } else {
242 NumSizeInner::Factored((bytes / 16 - 2) as u8)
243 })
244 }
245
246 pub(super) const fn from_code(id: u8) -> Self {
247 let code = id & 0x1F;
248 NumSize(match (id & 0x20) / 0x20 {
249 0 if id == Primitive::BYTE.0 => NumSizeInner::Bytes(1),
250 0 if id == Primitive::F16B.0 => NumSizeInner::Bytes(2),
251 0 => NumSizeInner::Bytes(code),
252 1 => NumSizeInner::Factored(code),
253 _ => unreachable!(),
254 })
255 }
256
257 pub(super) const fn into_code(self) -> u8 {
258 match self.0 {
259 NumSizeInner::Bytes(bytes) => bytes,
260 NumSizeInner::Factored(factor) => factor | 0x20,
261 }
262 }
263
264 pub const fn byte_size(self) -> u16 {
265 match self.0 {
266 NumSizeInner::Bytes(bytes) => bytes as u16,
267 NumSizeInner::Factored(factor) => 16 * (factor as u16 + 2),
268 }
269 }
270}
271
272#[derive(Copy, Clone, PartialEq, Eq, Debug)]
274enum NumSizeInner {
275 Bytes(u8),
277 Factored(u8),
281}
282
283#[derive(Copy, Clone, PartialEq, Eq, Debug)]
285#[repr(u8)]
286pub enum NumCls {
287 Unsigned = 0x00,
288 Signed = 0x40,
289 NonZero = 0x80,
290 Float = 0xC0,
291}
292
293impl NumCls {
294 pub const fn from_code(id: u8) -> Self {
295 match id & 0xC0 {
296 x if x == NumCls::Unsigned as u8 => NumCls::Unsigned,
297 x if x == NumCls::Signed as u8 => NumCls::Signed,
298 x if x == NumCls::NonZero as u8 => NumCls::NonZero,
299 x if x == NumCls::Float as u8 => NumCls::Float,
300 _ => unreachable!(),
301 }
302 }
303
304 pub const fn into_code(self) -> u8 { self as u8 }
305}
306
307#[cfg(test)]
308mod test {
309 use crate::Primitive;
310
311 #[test]
312 fn unsigned_byte_size() {
313 assert_eq!(Primitive::U8.byte_size(), 1);
314 assert_eq!(Primitive::U16.byte_size(), 2);
315 assert_eq!(Primitive::U24.byte_size(), 3);
316 assert_eq!(Primitive::U32.byte_size(), 4);
317 assert_eq!(Primitive::U40.byte_size(), 5);
318 assert_eq!(Primitive::U48.byte_size(), 6);
319 assert_eq!(Primitive::U56.byte_size(), 7);
320 assert_eq!(Primitive::U64.byte_size(), 8);
321 assert_eq!(Primitive::U128.byte_size(), 16);
322 assert_eq!(Primitive::U160.byte_size(), 20);
323 assert_eq!(Primitive::U256.byte_size(), 32);
324 assert_eq!(Primitive::U512.byte_size(), 64);
325 assert_eq!(Primitive::U1024.byte_size(), 128);
326 }
327
328 #[test]
329 fn signed_byte_size() {
330 assert_eq!(Primitive::I8.byte_size(), 1);
331 assert_eq!(Primitive::I16.byte_size(), 2);
332 assert_eq!(Primitive::I24.byte_size(), 3);
333 assert_eq!(Primitive::I32.byte_size(), 4);
334 assert_eq!(Primitive::I40.byte_size(), 5);
335 assert_eq!(Primitive::I48.byte_size(), 6);
336 assert_eq!(Primitive::I56.byte_size(), 7);
337 assert_eq!(Primitive::I64.byte_size(), 8);
338 assert_eq!(Primitive::I128.byte_size(), 16);
339 assert_eq!(Primitive::I256.byte_size(), 32);
340 assert_eq!(Primitive::I512.byte_size(), 64);
341 assert_eq!(Primitive::I1024.byte_size(), 128);
342 }
343
344 #[test]
345 fn nonzero_byte_size() {
346 assert_eq!(Primitive::N8.byte_size(), 1);
347 assert_eq!(Primitive::N16.byte_size(), 2);
348 assert_eq!(Primitive::N24.byte_size(), 3);
349 assert_eq!(Primitive::N32.byte_size(), 4);
350 assert_eq!(Primitive::N48.byte_size(), 6);
351 assert_eq!(Primitive::N64.byte_size(), 8);
352 assert_eq!(Primitive::N128.byte_size(), 16);
353 }
354
355 #[test]
356 fn float_byte_size() {
357 assert_eq!(Primitive::F16.byte_size(), 2);
358 assert_eq!(Primitive::F16B.byte_size(), 2);
359 assert_eq!(Primitive::F32.byte_size(), 4);
360 assert_eq!(Primitive::F64.byte_size(), 8);
361 assert_eq!(Primitive::F80.byte_size(), 10);
362 assert_eq!(Primitive::F128.byte_size(), 16);
363 assert_eq!(Primitive::F256.byte_size(), 32);
364 }
365
366 #[test]
367 fn spec_byte_size() {
368 assert_eq!(Primitive::UNIT.byte_size(), 0);
369 assert_eq!(Primitive::BYTE.byte_size(), 1);
370 }
371}