Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_jdat/src/int.rs

19.0 KiB, 7 runs

created by r1870400018:469, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1use crate::{
2 prelude::*,
3};
4
5use oxedyne_fe2o3_core::{
6 prelude::*,
7 rand::Rand,
8};
9
10
11pub trait DaticleInteger {
12 fn int_kind(&self) -> DatIntKind;
13 fn as_dat(self) -> Dat;
14 fn to_vec(&self) -> Vec<u8>;
15 fn is_signed(&self) -> bool;
16 fn fmt_hex(&self) -> String;
17 fn fmt_oct(&self) -> String;
18 fn fmt_bin(&self) -> String;
19 fn fmt_dec(&self) -> String;
20 fn min_size(&self) -> Self;
21}
22
23#[derive(Clone, Copy, Debug, Eq, PartialEq)]
24pub enum DatInt {
25 U8(u8),
26 U16(u16),
27 U32(u32),
28 U64(u64),
29 U128(u128),
30 BU32(B32), // Big endian, i.e. largest byte first, interpreted as unsigned.
31 I8(i8),
32 I16(i16),
33 I32(i32),
34 I64(i64),
35 I128(i128),
36}
37
38#[derive(Clone, Debug)]
39pub enum DatIntKind {
40 U8,
41 U16,
42 U32,
43 U64,
44 U128,
45 BU32,
46 I8,
47 I16,
48 I32,
49 I64,
50 I128,
51}
52
53impl From<u8> for DatInt {
54 fn from(n: u8) -> Self {
55 Self::U8(n)
56 }
57}
58
59impl From<u16> for DatInt {
60 fn from(n: u16) -> Self {
61 Self::U16(n)
62 }
63}
64
65impl From<u32> for DatInt {
66 fn from(n: u32) -> Self {
67 Self::U32(n)
68 }
69}
70
71impl From<u64> for DatInt {
72 fn from(n: u64) -> Self {
73 Self::U64(n)
74 }
75}
76
77impl From<u128> for DatInt {
78 fn from(n: u128) -> Self {
79 Self::U128(n)
80 }
81}
82
83impl From<usize> for DatInt {
84 fn from(n: usize) -> Self {
85 Self::U128(n as u128)
86 }
87}
88
89impl From<[u8; 32]> for DatInt {
90 fn from(a: [u8; 32]) -> Self {
91 Self::BU32(B32(a))
92 }
93}
94
95impl From<B32> for DatInt {
96 fn from(a: B32) -> Self {
97 Self::BU32(a)
98 }
99}
100
101impl From<i8> for DatInt {
102 fn from(n: i8) -> Self {
103 Self::I8(n)
104 }
105}
106
107impl From<i16> for DatInt {
108 fn from(n: i16) -> Self {
109 Self::I16(n)
110 }
111}
112
113impl From<i32> for DatInt {
114 fn from(n: i32) -> Self {
115 Self::I32(n)
116 }
117}
118
119impl From<i64> for DatInt {
120 fn from(n: i64) -> Self {
121 Self::I64(n)
122 }
123}
124
125impl From<i128> for DatInt {
126 fn from(n: i128) -> Self {
127 Self::I128(n)
128 }
129}
130
131impl From<isize> for DatInt {
132 fn from(n: isize) -> Self {
133 Self::I128(n as i128)
134 }
135}
136
137impl DaticleInteger for DatInt {
138
139 fn int_kind(&self) -> DatIntKind {
140 match self {
141 Self::U8(_) => DatIntKind::U8,
142 Self::U16(_) => DatIntKind::U16,
143 Self::U32(_) => DatIntKind::U32,
144 Self::U64(_) => DatIntKind::U64,
145 Self::U128(_) => DatIntKind::U128,
146 Self::BU32(_) => DatIntKind::BU32,
147 Self::I8(_) => DatIntKind::I8,
148 Self::I16(_) => DatIntKind::I16,
149 Self::I32(_) => DatIntKind::I32,
150 Self::I64(_) => DatIntKind::I64,
151 Self::I128(_) => DatIntKind::I128,
152 }
153 }
154
155 fn as_dat(self) -> Dat {
156 match self {
157 Self::U8(n) => Dat::U8(n),
158 Self::U16(n) => Dat::U16(n),
159 Self::U32(n) => Dat::U32(n),
160 Self::U64(n) => Dat::U64(n),
161 Self::U128(n) => Dat::U128(n),
162 Self::BU32(b) => Dat::B32(b),
163 Self::I8(n) => Dat::I8(n),
164 Self::I16(n) => Dat::I16(n),
165 Self::I32(n) => Dat::I32(n),
166 Self::I64(n) => Dat::I64(n),
167 Self::I128(n) => Dat::I128(n),
168 }
169 }
170
171 fn to_vec(&self) -> Vec<u8> {
172 match self {
173 Self::U8(n) => n.to_be_bytes().to_vec(),
174 Self::U16(n) => n.to_be_bytes().to_vec(),
175 Self::U32(n) => n.to_be_bytes().to_vec(),
176 Self::U64(n) => n.to_be_bytes().to_vec(),
177 Self::U128(n) => n.to_be_bytes().to_vec(),
178 Self::BU32(a) => a.to_vec(),
179 Self::I8(n) => n.to_be_bytes().to_vec(),
180 Self::I16(n) => n.to_be_bytes().to_vec(),
181 Self::I32(n) => n.to_be_bytes().to_vec(),
182 Self::I64(n) => n.to_be_bytes().to_vec(),
183 Self::I128(n) => n.to_be_bytes().to_vec(),
184 }
185 }
186
187 fn is_signed(&self) -> bool {
188 match self {
189 Self::U8(_) |
190 Self::U16(_) |
191 Self::U32(_) |
192 Self::U64(_) |
193 Self::U128(_) |
194 Self::BU32(_) => false,
195 Self::I8(_) |
196 Self::I16(_) |
197 Self::I32(_) |
198 Self::I64(_) |
199 Self::I128(_) => true,
200 }
201 }
202
203 fn fmt_hex(&self) -> String {
204 match self {
205 Self::U8(n) => fmt!("0x{:02x}", n),
206 Self::U16(n) => fmt!("0x{:04x}", n),
207 Self::U32(n) => fmt!("0x{:08x}", n),
208 Self::U64(n) => fmt!("0x{:016x}", n),
209 Self::U128(n) => fmt!("0x{:032x}", n),
210 Self::BU32(a) =>
211 a.iter().map(|b| format!("0x{:02x}", b)).collect::<Vec<_>>().join(", "),
212 Self::I8(n) => {
213 let sign = if *n < 0 { "-" } else { "" };
214 let a = match n.checked_abs() {
215 Some(a) => a as u8,
216 None => i8::MAX as u8 + 1,
217 };
218 fmt!("{}0x{:02x}", sign, a)
219 },
220 Self::I16(n) => {
221 let sign = if *n < 0 { "-" } else { "" };
222 let a = match n.checked_abs() {
223 Some(a) => a as u16,
224 None => i16::MAX as u16 + 1,
225 };
226 fmt!("{}0x{:04x}", sign, a)
227 },
228 Self::I32(n) => {
229 let sign = if *n < 0 { "-" } else { "" };
230 let a = match n.checked_abs() {
231 Some(a) => a as u32,
232 None => i32::MAX as u32 + 1,
233 };
234 fmt!("{}0x{:08x}", sign, a)
235 },
236 Self::I64(n) => {
237 let sign = if *n < 0 { "-" } else { "" };
238 let a = match n.checked_abs() {
239 Some(a) => a as u64,
240 None => i64::MAX as u64 + 1,
241 };
242 fmt!("{}0x{:016x}", sign, a)
243 },
244 Self::I128(n) => {
245 let sign = if *n < 0 { "-" } else { "" };
246 let a = match n.checked_abs() {
247 Some(a) => a as u128,
248 None => i128::MAX as u128 + 1,
249 };
250 fmt!("{}0x{:032x}", sign, a)
251 },
252 }
253 }
254
255 fn fmt_oct(&self) -> String {
256 match self {
257 Self::U8(n) => fmt!("0o{:o}", n),
258 Self::U16(n) => fmt!("0o{:o}", n),
259 Self::U32(n) => fmt!("0o{:o}", n),
260 Self::U64(n) => fmt!("0o{:o}", n),
261 Self::U128(n) => fmt!("0o{:o}", n),
262 Self::BU32(a) =>
263 a.iter().map(|b| format!("0o{:03x}", b)).collect::<Vec<_>>().join(", "),
264 Self::I8(n) => {
265 let sign = if *n < 0 { "-" } else { "" };
266 let a = match n.checked_abs() {
267 Some(a) => a as u8,
268 None => i8::MAX as u8 + 1,
269 };
270 fmt!("{}0o{:o}", sign, a)
271 },
272 Self::I16(n) => {
273 let sign = if *n < 0 { "-" } else { "" };
274 let a = match n.checked_abs() {
275 Some(a) => a as u16,
276 None => i16::MAX as u16 + 1,
277 };
278 fmt!("{}0o{:o}", sign, a)
279 },
280 Self::I32(n) => {
281 let sign = if *n < 0 { "-" } else { "" };
282 let a = match n.checked_abs() {
283 Some(a) => a as u32,
284 None => i32::MAX as u32 + 1,
285 };
286 fmt!("{}0o{:o}", sign, a)
287 },
288 Self::I64(n) => {
289 let sign = if *n < 0 { "-" } else { "" };
290 let a = match n.checked_abs() {
291 Some(a) => a as u64,
292 None => i64::MAX as u64 + 1,
293 };
294 fmt!("{}0o{:o}", sign, a)
295 },
296 Self::I128(n) => {
297 let sign = if *n < 0 { "-" } else { "" };
298 let a = match n.checked_abs() {
299 Some(a) => a as u128,
300 None => i128::MAX as u128 + 1,
301 };
302 fmt!("{}0o{:o}", sign, a)
303 },
304 }
305 }
306
307 fn fmt_bin(&self) -> String {
308 let (s, sign) = match self {
309 Self::U8(n) => (
310 n.to_be_bytes().iter().map(|b| fmt!("{:08b}", b)).collect::<Vec<_>>().join("_"),
311 "",
312 ),
313 Self::U16(n) => (
314 n.to_be_bytes().iter().map(|b| fmt!("{:08b}", b)).collect::<Vec<_>>().join("_"),
315 "",
316 ),
317 Self::U32(n) => (
318 n.to_be_bytes().iter().map(|b| fmt!("{:08b}", b)).collect::<Vec<_>>().join("_"),
319 "",
320 ),
321 Self::U64(n) => (
322 n.to_be_bytes().iter().map(|b| fmt!("{:08b}", b)).collect::<Vec<_>>().join("_"),
323 "",
324 ),
325 Self::U128(n) => (
326 n.to_be_bytes().iter().map(|b| fmt!("{:08b}", b)).collect::<Vec<_>>().join("_"),
327 "",
328 ),
329 Self::BU32(a) => (
330 a.iter().map(|b| fmt!("{:08b}", b)).collect::<Vec<_>>().join("_"),
331 "",
332 ),
333 Self::I8(n) => (
334 (
335 match n.checked_abs() {
336 Some(a) => a as u8,
337 None => i8::MAX as u8 + 1,
338 }
339 ).to_be_bytes().iter().map(|b| fmt!("{:08b}", b)).collect::<Vec<_>>().join("_"),
340 if *n < 0 { "-" } else { "" },
341 ),
342 Self::I16(n) => (
343 (
344 match n.checked_abs() {
345 Some(a) => a as u16,
346 None => i16::MAX as u16 + 1,
347 }
348 ).to_be_bytes().iter().map(|b| fmt!("{:08b}", b)).collect::<Vec<_>>().join("_"),
349 if *n < 0 { "-" } else { "" },
350 ),
351 Self::I32(n) => (
352 (
353 match n.checked_abs() {
354 Some(a) => a as u32,
355 None => i32::MAX as u32 + 1,
356 }
357 ).to_be_bytes().iter().map(|b| fmt!("{:08b}", b)).collect::<Vec<_>>().join("_"),
358 if *n < 0 { "-" } else { "" },
359 ),
360 Self::I64(n) => (
361 (
362 match n.checked_abs() {
363 Some(a) => a as u64,
364 None => i64::MAX as u64 + 1,
365 }
366 ).to_be_bytes().iter().map(|b| fmt!("{:08b}", b)).collect::<Vec<_>>().join("_"),
367 if *n < 0 { "-" } else { "" },
368 ),
369 Self::I128(n) => (
370 (
371 match n.checked_abs() {
372 Some(a) => a as u128,
373 None => i128::MAX as u128 + 1,
374 }
375 ).to_be_bytes().iter().map(|b| fmt!("{:08b}", b)).collect::<Vec<_>>().join("_"),
376 if *n < 0 { "-" } else { "" },
377 ),
378 };
379 fmt!("{}0b{}", sign, s)
380 }
381
382 fn fmt_dec(&self) -> String {
383 match self {
384 Self::U8(n) => n.to_string(),
385 Self::U16(n) => n.to_string(),
386 Self::U32(n) => n.to_string(),
387 Self::U64(n) => n.to_string(),
388 Self::U128(n) => n.to_string(),
389 Self::BU32(a) => a.iter().map(|b| b.to_string()).collect::<Vec<_>>().join(", "),
390 Self::I8(n) => n.to_string(),
391 Self::I16(n) => n.to_string(),
392 Self::I32(n) => n.to_string(),
393 Self::I64(n) => n.to_string(),
394 Self::I128(n) => n.to_string(),
395 }
396 }
397
398 /// Re-wrap the integer into the variant with the smallest binary representation. Positive
399 /// integers get represented as uint variants, regardless of the original `DatIntKind`. If a zero
400 /// is originally a signed int, the result will be an I8.
401 fn min_size(&self) -> Self {
402 match self {
403 Self::U8(n) => Self::min_size_uint(*n as u128),
404 Self::U16(n) => Self::min_size_uint(*n as u128),
405 Self::U32(n) => Self::min_size_uint(*n as u128),
406 Self::U64(n) => Self::min_size_uint(*n as u128),
407 Self::U128(n) => Self::min_size_uint(*n as u128),
408
409 Self::I8(n) => if *n <= 0 {
410 Self::min_size_int(*n as i128)
411 } else {
412 Self::min_size_uint(n.abs() as u128)
413 },
414 Self::I16(n) => if *n <= 0 {
415 Self::min_size_int(*n as i128)
416 } else {
417 Self::min_size_uint(n.abs() as u128)
418 },
419 Self::I32(n) => if *n <= 0 {
420 Self::min_size_int(*n as i128)
421 } else {
422 Self::min_size_uint(n.abs() as u128)
423 },
424 Self::I64(n) => if *n <= 0 {
425 Self::min_size_int(*n as i128)
426 } else {
427 Self::min_size_uint(n.abs() as u128)
428 },
429 Self::I128(n) => if *n <= 0 {
430 Self::min_size_int(*n as i128)
431 } else {
432 Self::min_size_uint(n.abs() as u128)
433 },
434
435 Self::BU32(byts) => {
436 // Count the number of leading zero bytes:
437 let mut count: usize = 0;
438 for byt in **byts {
439 if byt == 0 {
440 count += 1;
441 } else {
442 break;
443 }
444 }
445 // If the top 16 most significant are zero, we can use a u128.
446 // If the top 16 + 8 = 24 most significant are zero, we can use a u64.
447 // If the top 16 + 8 + 4 = 28 most significant are zero, we can use a u32.
448 // If the top 16 + 8 + 4 + 2 = 30 most significant are zero, we can use a u16.
449 // If the top 16 + 8 + 4 + 2 + 1 = 31 most significant are zero, we can use a u8.
450 if count >= 31 {
451 let mut a = [0u8; 1];
452 a.copy_from_slice(&byts[31..]);
453 Self::U8(u8::from_be_bytes(a))
454 } else if count >= 30 {
455 let mut a = [0u8; 2];
456 a.copy_from_slice(&byts[30..]);
457 Self::U16(u16::from_be_bytes(a))
458 } else if count >= 28 {
459 let mut a = [0u8; 4];
460 a.copy_from_slice(&byts[28..]);
461 Self::U32(u32::from_be_bytes(a))
462 } else if count >= 24 {
463 let mut a = [0u8; 8];
464 a.copy_from_slice(&byts[24..]);
465 Self::U64(u64::from_be_bytes(a))
466 } else if count >= 16 {
467 let mut a = [0u8; 16];
468 a.copy_from_slice(&byts[16..]);
469 Self::U128(u128::from_be_bytes(a))
470 } else {
471 *self
472 }
473 },
474 }
475 }
476}
477
478impl DatInt {
479
480 const U8_MAX_AS_U128: u128 = u8::MAX as u128;
481 const U16_MAX_AS_U128: u128 = u16::MAX as u128;
482 const U32_MAX_AS_U128: u128 = u32::MAX as u128;
483 const U64_MAX_AS_U128: u128 = u64::MAX as u128;
484
485 pub fn min_size_uint(n: u128) -> Self {
486 if n <= Self::U8_MAX_AS_U128 {
487 Self::U8(n as u8)
488 } else if n <= Self::U16_MAX_AS_U128 {
489 Self::U16(n as u16)
490 } else if n <= Self::U32_MAX_AS_U128 {
491 Self::U32(n as u32)
492 } else if n <= Self::U64_MAX_AS_U128 {
493 Self::U64(n as u64)
494 } else {
495 Self::U128(n)
496 }
497 }
498
499 const I8_MAX_AS_I128: i128 = i8::MAX as i128;
500 const I16_MAX_AS_I128: i128 = i16::MAX as i128;
501 const I32_MAX_AS_I128: i128 = i32::MAX as i128;
502 const I64_MAX_AS_I128: i128 = i64::MAX as i128;
503
504 const I8_MIN_AS_I128: i128 = i8::MIN as i128;
505 const I16_MIN_AS_I128: i128 = i16::MIN as i128;
506 const I32_MIN_AS_I128: i128 = i32::MIN as i128;
507 const I64_MIN_AS_I128: i128 = i64::MIN as i128;
508
509 /// The narrowest signed variant that holds `n`. Signedness is the caller's
510 /// choice and not the value's: a small positive number arrives here as `I8`
511 /// rather than `U8`, so the sign the caller meant survives the round trip
512 /// through `Dat`.
513 pub fn min_size_int(n: i128) -> Self {
514 if Self::I8_MIN_AS_I128 <= n && n <= Self::I8_MAX_AS_I128 {
515 Self::I8(n as i8)
516 } else if Self::I16_MIN_AS_I128 <= n && n <= Self::I16_MAX_AS_I128 {
517 Self::I16(n as i16)
518 } else if Self::I32_MIN_AS_I128 <= n && n <= Self::I32_MAX_AS_I128 {
519 Self::I32(n as i32)
520 } else if Self::I64_MIN_AS_I128 <= n && n <= Self::I64_MAX_AS_I128 {
521 Self::I64(n as i64)
522 } else {
523 Self::I128(n)
524 }
525 }
526}
527
528impl ToDat for DatInt {
529 fn to_dat(&self) -> Outcome<Dat> {
530 Ok(match self {
531 Self::U8(n) => Dat::U8(*n),
532 Self::U16(n) => Dat::U16(*n),
533 Self::U32(n) => Dat::U32(*n),
534 Self::U64(n) => Dat::U64(*n),
535 Self::U128(n) => Dat::U128(*n),
536 Self::BU32(b) => Dat::B32(*b),
537 Self::I8(n) => Dat::I8(*n),
538 Self::I16(n) => Dat::I16(*n),
539 Self::I32(n) => Dat::I32(*n),
540 Self::I64(n) => Dat::I64(*n),
541 Self::I128(n) => Dat::I128(*n),
542 })
543 }
544}
545
546impl DatIntKind {
547
548 pub fn rand(&self) -> DatInt {
549 match self {
550 Self::U8 => DatInt::U8(Rand::rand_u8()),
551 Self::U16 => DatInt::U16(Rand::rand_u16()),
552 Self::U32 => DatInt::U32(Rand::rand_u32()),
553 Self::U64 => DatInt::U64(Rand::rand_u64()),
554 Self::U128 => DatInt::U128(Rand::rand_u128()),
555 Self::BU32 => {
556 let mut b = [0; 32];
557 Rand::fill_u8(&mut b);
558 DatInt::BU32(B32(b))
559 },
560 Self::I8 => DatInt::I8(Rand::rand_u8() as i8),
561 Self::I16 => DatInt::I16(Rand::rand_u16() as i16),
562 Self::I32 => DatInt::I32(Rand::rand_u32() as i32),
563 Self::I64 => DatInt::I64(Rand::rand_u64() as i64),
564 Self::I128 => DatInt::I128(Rand::rand_u128() as i128),
565 }
566 }
567}
568
569#[cfg(test)]
570mod tests {
571 use super::*;
572
573 #[test]
574 fn min_size_int_narrows_within_the_signed_kinds() {
575 // Positive values stay signed, so the unsigned variants are never reached.
576 assert_eq!(DatInt::min_size_int(0), DatInt::I8(0));
577 assert_eq!(DatInt::min_size_int(127), DatInt::I8(127));
578 assert_eq!(DatInt::min_size_int(128), DatInt::I16(128));
579 // Each boundary belongs to the narrower of the two kinds it separates.
580 assert_eq!(DatInt::min_size_int(-128), DatInt::I8(-128));
581 assert_eq!(DatInt::min_size_int(-129), DatInt::I16(-129));
582 assert_eq!(DatInt::min_size_int(i64::MAX as i128), DatInt::I64(i64::MAX));
583 assert_eq!(
584 DatInt::min_size_int(i64::MAX as i128 + 1),
585 DatInt::I128(i64::MAX as i128 + 1),
586 );
587 }
588}