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