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