triblespace_core/inline/encodings/
iu256.rs1use crate::inline::Encodes;
2use crate::id::ExclusiveId;
3use crate::id::Id;
4use crate::id_hex;
5use crate::macros::entity;
6use crate::metadata;
7use crate::metadata::MetaDescribe;
8use crate::trible::Fragment;
9use crate::inline::TryFromInline;
10use crate::inline::Inline;
11use crate::inline::InlineEncoding;
12use std::convert::Infallible;
13use std::num::TryFromIntError;
14
15use ethnum;
16
17pub struct U256LE;
19
20pub struct U256BE;
22
23pub struct I256LE;
25
26pub struct I256BE;
28
29pub type I256 = I256BE;
32
33pub type U256 = U256BE;
36
37impl MetaDescribe for U256LE {
38 fn describe() -> Fragment {
39 let id: Id = id_hex!("49E70B4DBD84DC7A3E0BDDABEC8A8C6E");
40 #[allow(unused_mut)]
41 let mut tribles = entity! {
42 ExclusiveId::force_ref(&id) @
43 metadata::name: "u256le",
44 metadata::description: "Unsigned 256-bit integer stored in little-endian byte order. The full 32 bytes are dedicated to the magnitude.\n\nUse for large counters, identifiers, or domain-specific fixed-width numbers that exceed u128. Prefer U256BE when bytewise ordering or protocol encoding matters.\n\nIf a smaller width suffices, prefer U64 or U128 in your schema to reduce storage and improve readability.",
45 metadata::tag: metadata::KIND_INLINE_ENCODING,
46 };
47
48 #[cfg(feature = "wasm")]
49 {
50 tribles += entity! { ExclusiveId::force_ref(&id) @
51 metadata::value_formatter: wasm_formatter::U256_LE_WASM,
52 };
53 }
54 tribles
55 }
56}
57impl InlineEncoding for U256LE {
58 type ValidationError = Infallible;
59 type Encoding = Self;
60}
61impl MetaDescribe for U256BE {
62 fn describe() -> Fragment {
63 let id: Id = id_hex!("DC3CFB719B05F019FB8101A6F471A982");
64 #[allow(unused_mut)]
65 let mut tribles = entity! {
66 ExclusiveId::force_ref(&id) @
67 metadata::name: "u256be",
68 metadata::description: "Unsigned 256-bit integer stored in big-endian byte order. Bytewise comparisons align with numeric order.\n\nUse when ordering or network serialization matters. Prefer U256LE for local storage or interop with little-endian APIs.\n\nIf you do not need the full 256-bit range, smaller integer schemas are easier to handle and faster to encode.",
69 metadata::tag: metadata::KIND_INLINE_ENCODING,
70 };
71
72 #[cfg(feature = "wasm")]
73 {
74 tribles += entity! { ExclusiveId::force_ref(&id) @
75 metadata::value_formatter: wasm_formatter::U256_BE_WASM,
76 };
77 }
78 tribles
79 }
80}
81impl InlineEncoding for U256BE {
82 type ValidationError = Infallible;
83 type Encoding = Self;
84}
85impl MetaDescribe for I256LE {
86 fn describe() -> Fragment {
87 let id: Id = id_hex!("DB94325A37D96037CBFC6941A4C3B66D");
88 #[allow(unused_mut)]
89 let mut tribles = entity! {
90 ExclusiveId::force_ref(&id) @
91 metadata::name: "i256le",
92 metadata::description: "Signed 256-bit integer stored in little-endian twos-complement. This enables extremely large signed ranges in a fixed width.\n\nUse for large signed quantities such as balances or offsets beyond i128. Prefer I256BE when bytewise ordering or external protocols require big-endian.\n\nIf values fit within i64 or i128, smaller schemas are more compact and easier to interoperate with.",
93 metadata::tag: metadata::KIND_INLINE_ENCODING,
94 };
95
96 #[cfg(feature = "wasm")]
97 {
98 tribles += entity! { ExclusiveId::force_ref(&id) @
99 metadata::value_formatter: wasm_formatter::I256_LE_WASM,
100 };
101 }
102 tribles
103 }
104}
105impl InlineEncoding for I256LE {
106 type ValidationError = Infallible;
107 type Encoding = Self;
108}
109impl MetaDescribe for I256BE {
110 fn describe() -> Fragment {
111 let id: Id = id_hex!("CE3A7839231F1EB390E9E8E13DAED782");
112 #[allow(unused_mut)]
113 let mut tribles = entity! {
114 ExclusiveId::force_ref(&id) @
115 metadata::name: "i256be",
116 metadata::description: "Signed 256-bit integer stored in big-endian twos-complement. This variant is convenient for protocol encoding and deterministic ordering.\n\nUse for interoperability or stable bytewise comparisons across systems. Prefer I256LE for local storage or when endianness does not matter.\n\nAs with any signed integer, consider whether the sign bit has semantic meaning and avoid mixing signed and unsigned ranges.",
117 metadata::tag: metadata::KIND_INLINE_ENCODING,
118 };
119
120 #[cfg(feature = "wasm")]
121 {
122 tribles += entity! { ExclusiveId::force_ref(&id) @
123 metadata::value_formatter: wasm_formatter::I256_BE_WASM,
124 };
125 }
126 tribles
127 }
128}
129impl InlineEncoding for I256BE {
130 type ValidationError = Infallible;
131 type Encoding = Self;
132}
133
134#[cfg(feature = "wasm")]
135mod wasm_formatter {
136 use core::fmt::Write;
137
138 use triblespace_core_macros::value_formatter;
139
140 #[value_formatter(const_wasm = U256_LE_WASM)]
141 pub(crate) fn u256_le(raw: &[u8; 32], out: &mut impl Write) -> Result<(), u32> {
142 fn div_mod10(limbs: &mut [u64; 4]) -> u8 {
143 let mut rem: u128 = 0;
144 for limb in limbs.iter_mut() {
145 let n = (rem << 64) | (*limb as u128);
146 *limb = (n / 10) as u64;
147 rem = n % 10;
148 }
149 rem as u8
150 }
151
152 fn is_zero(limbs: &[u64; 4]) -> bool {
153 limbs.iter().all(|&limb| limb == 0)
154 }
155
156 let mut buf = [0u8; 8];
157 buf.copy_from_slice(&raw[0..8]);
158 let w0 = u64::from_le_bytes(buf);
159 buf.copy_from_slice(&raw[8..16]);
160 let w1 = u64::from_le_bytes(buf);
161 buf.copy_from_slice(&raw[16..24]);
162 let w2 = u64::from_le_bytes(buf);
163 buf.copy_from_slice(&raw[24..32]);
164 let w3 = u64::from_le_bytes(buf);
165
166 let mut limbs = [w3, w2, w1, w0];
167 if is_zero(&limbs) {
168 out.write_char('0').map_err(|_| 1u32)?;
169 return Ok(());
170 }
171
172 let mut digits = [0u8; 78];
173 let mut len = 0usize;
174 while !is_zero(&limbs) {
175 let digit = div_mod10(&mut limbs);
176 digits[len] = b'0' + digit;
177 len += 1;
178 }
179
180 for &digit in digits[..len].iter().rev() {
181 out.write_char(digit as char).map_err(|_| 1u32)?;
182 }
183
184 Ok(())
185 }
186
187 #[value_formatter(const_wasm = U256_BE_WASM)]
188 pub(crate) fn u256_be(raw: &[u8; 32], out: &mut impl Write) -> Result<(), u32> {
189 fn div_mod10(limbs: &mut [u64; 4]) -> u8 {
190 let mut rem: u128 = 0;
191 for limb in limbs.iter_mut() {
192 let n = (rem << 64) | (*limb as u128);
193 *limb = (n / 10) as u64;
194 rem = n % 10;
195 }
196 rem as u8
197 }
198
199 fn is_zero(limbs: &[u64; 4]) -> bool {
200 limbs.iter().all(|&limb| limb == 0)
201 }
202
203 let mut buf = [0u8; 8];
204 buf.copy_from_slice(&raw[0..8]);
205 let w0 = u64::from_be_bytes(buf);
206 buf.copy_from_slice(&raw[8..16]);
207 let w1 = u64::from_be_bytes(buf);
208 buf.copy_from_slice(&raw[16..24]);
209 let w2 = u64::from_be_bytes(buf);
210 buf.copy_from_slice(&raw[24..32]);
211 let w3 = u64::from_be_bytes(buf);
212
213 let mut limbs = [w0, w1, w2, w3];
214 if is_zero(&limbs) {
215 out.write_char('0').map_err(|_| 1u32)?;
216 return Ok(());
217 }
218
219 let mut digits = [0u8; 78];
220 let mut len = 0usize;
221 while !is_zero(&limbs) {
222 let digit = div_mod10(&mut limbs);
223 digits[len] = b'0' + digit;
224 len += 1;
225 }
226
227 for &digit in digits[..len].iter().rev() {
228 out.write_char(digit as char).map_err(|_| 1u32)?;
229 }
230
231 Ok(())
232 }
233
234 #[value_formatter(const_wasm = I256_LE_WASM)]
235 pub(crate) fn i256_le(raw: &[u8; 32], out: &mut impl Write) -> Result<(), u32> {
236 fn div_mod10(limbs: &mut [u64; 4]) -> u8 {
237 let mut rem: u128 = 0;
238 for limb in limbs.iter_mut() {
239 let n = (rem << 64) | (*limb as u128);
240 *limb = (n / 10) as u64;
241 rem = n % 10;
242 }
243 rem as u8
244 }
245
246 fn is_zero(limbs: &[u64; 4]) -> bool {
247 limbs.iter().all(|&limb| limb == 0)
248 }
249
250 fn twos_complement(limbs: &mut [u64; 4]) {
251 for limb in limbs.iter_mut() {
252 *limb = !*limb;
253 }
254
255 let mut carry: u128 = 1;
256 for limb in limbs.iter_mut().rev() {
257 let sum = (*limb as u128) + carry;
258 *limb = sum as u64;
259 carry = sum >> 64;
260 if carry == 0 {
261 break;
262 }
263 }
264 }
265
266 let mut buf = [0u8; 8];
267 buf.copy_from_slice(&raw[0..8]);
268 let w0 = u64::from_le_bytes(buf);
269 buf.copy_from_slice(&raw[8..16]);
270 let w1 = u64::from_le_bytes(buf);
271 buf.copy_from_slice(&raw[16..24]);
272 let w2 = u64::from_le_bytes(buf);
273 buf.copy_from_slice(&raw[24..32]);
274 let w3 = u64::from_le_bytes(buf);
275
276 let mut limbs = [w3, w2, w1, w0];
277 let negative = (limbs[0] & (1u64 << 63)) != 0;
278 if negative {
279 twos_complement(&mut limbs);
280 }
281
282 if is_zero(&limbs) {
283 out.write_char('0').map_err(|_| 1u32)?;
284 return Ok(());
285 }
286
287 let mut digits = [0u8; 78];
288 let mut len = 0usize;
289 while !is_zero(&limbs) {
290 let digit = div_mod10(&mut limbs);
291 digits[len] = b'0' + digit;
292 len += 1;
293 }
294
295 if negative {
296 out.write_char('-').map_err(|_| 1u32)?;
297 }
298
299 for &digit in digits[..len].iter().rev() {
300 out.write_char(digit as char).map_err(|_| 1u32)?;
301 }
302
303 Ok(())
304 }
305
306 #[value_formatter(const_wasm = I256_BE_WASM)]
307 pub(crate) fn i256_be(raw: &[u8; 32], out: &mut impl Write) -> Result<(), u32> {
308 fn div_mod10(limbs: &mut [u64; 4]) -> u8 {
309 let mut rem: u128 = 0;
310 for limb in limbs.iter_mut() {
311 let n = (rem << 64) | (*limb as u128);
312 *limb = (n / 10) as u64;
313 rem = n % 10;
314 }
315 rem as u8
316 }
317
318 fn is_zero(limbs: &[u64; 4]) -> bool {
319 limbs.iter().all(|&limb| limb == 0)
320 }
321
322 fn twos_complement(limbs: &mut [u64; 4]) {
323 for limb in limbs.iter_mut() {
324 *limb = !*limb;
325 }
326
327 let mut carry: u128 = 1;
328 for limb in limbs.iter_mut().rev() {
329 let sum = (*limb as u128) + carry;
330 *limb = sum as u64;
331 carry = sum >> 64;
332 if carry == 0 {
333 break;
334 }
335 }
336 }
337
338 let mut buf = [0u8; 8];
339 buf.copy_from_slice(&raw[0..8]);
340 let w0 = u64::from_be_bytes(buf);
341 buf.copy_from_slice(&raw[8..16]);
342 let w1 = u64::from_be_bytes(buf);
343 buf.copy_from_slice(&raw[16..24]);
344 let w2 = u64::from_be_bytes(buf);
345 buf.copy_from_slice(&raw[24..32]);
346 let w3 = u64::from_be_bytes(buf);
347
348 let mut limbs = [w0, w1, w2, w3];
349 let negative = (limbs[0] & (1u64 << 63)) != 0;
350 if negative {
351 twos_complement(&mut limbs);
352 }
353
354 if is_zero(&limbs) {
355 out.write_char('0').map_err(|_| 1u32)?;
356 return Ok(());
357 }
358
359 let mut digits = [0u8; 78];
360 let mut len = 0usize;
361 while !is_zero(&limbs) {
362 let digit = div_mod10(&mut limbs);
363 digits[len] = b'0' + digit;
364 len += 1;
365 }
366
367 if negative {
368 out.write_char('-').map_err(|_| 1u32)?;
369 }
370
371 for &digit in digits[..len].iter().rev() {
372 out.write_char(digit as char).map_err(|_| 1u32)?;
373 }
374
375 Ok(())
376 }
377}
378
379impl Encodes<ethnum::U256> for U256BE
380{
381 type Output = Inline<U256BE>;
382 fn encode(source: ethnum::U256) -> Inline<U256BE> {
383 Inline::new(source.to_be_bytes())
384 }
385}
386
387impl TryFromInline<'_, U256BE> for ethnum::U256 {
388 type Error = Infallible;
389 fn try_from_inline(v: &Inline<U256BE>) -> Result<Self, Infallible> {
390 Ok(ethnum::U256::from_be_bytes(v.raw))
391 }
392}
393
394impl Encodes<ethnum::U256> for U256LE
395{
396 type Output = Inline<U256LE>;
397 fn encode(source: ethnum::U256) -> Inline<U256LE> {
398 Inline::new(source.to_le_bytes())
399 }
400}
401
402impl TryFromInline<'_, U256LE> for ethnum::U256 {
403 type Error = Infallible;
404 fn try_from_inline(v: &Inline<U256LE>) -> Result<Self, Infallible> {
405 Ok(ethnum::U256::from_le_bytes(v.raw))
406 }
407}
408
409impl Encodes<ethnum::I256> for I256BE
410{
411 type Output = Inline<I256BE>;
412 fn encode(source: ethnum::I256) -> Inline<I256BE> {
413 Inline::new(source.to_be_bytes())
414 }
415}
416
417impl TryFromInline<'_, I256BE> for ethnum::I256 {
418 type Error = Infallible;
419 fn try_from_inline(v: &Inline<I256BE>) -> Result<Self, Infallible> {
420 Ok(ethnum::I256::from_be_bytes(v.raw))
421 }
422}
423
424impl Encodes<ethnum::I256> for I256LE
425{
426 type Output = Inline<I256LE>;
427 fn encode(source: ethnum::I256) -> Inline<I256LE> {
428 Inline::new(source.to_le_bytes())
429 }
430}
431
432impl TryFromInline<'_, I256LE> for ethnum::I256 {
433 type Error = Infallible;
434 fn try_from_inline(v: &Inline<I256LE>) -> Result<Self, Infallible> {
435 Ok(ethnum::I256::from_le_bytes(v.raw))
436 }
437}
438
439impl Encodes<u8> for U256LE
440{
441 type Output = Inline<U256LE>;
442 fn encode(source: u8) -> Inline<U256LE> {
443 Inline::new(ethnum::U256::new(source.into()).to_le_bytes())
444 }
445}
446
447impl Encodes<u16> for U256LE
448{
449 type Output = Inline<U256LE>;
450 fn encode(source: u16) -> Inline<U256LE> {
451 Inline::new(ethnum::U256::new(source.into()).to_le_bytes())
452 }
453}
454
455impl Encodes<u32> for U256LE
456{
457 type Output = Inline<U256LE>;
458 fn encode(source: u32) -> Inline<U256LE> {
459 Inline::new(ethnum::U256::new(source.into()).to_le_bytes())
460 }
461}
462
463impl Encodes<u64> for U256LE
464{
465 type Output = Inline<U256LE>;
466 fn encode(source: u64) -> Inline<U256LE> {
467 Inline::new(ethnum::U256::new(source.into()).to_le_bytes())
468 }
469}
470
471impl Encodes<u128> for U256LE
472{
473 type Output = Inline<U256LE>;
474 fn encode(source: u128) -> Inline<U256LE> {
475 Inline::new(ethnum::U256::new(source).to_le_bytes())
476 }
477}
478
479impl Encodes<u8> for U256BE
480{
481 type Output = Inline<U256BE>;
482 fn encode(source: u8) -> Inline<U256BE> {
483 Inline::new(ethnum::U256::new(source.into()).to_be_bytes())
484 }
485}
486
487impl Encodes<u16> for U256BE
488{
489 type Output = Inline<U256BE>;
490 fn encode(source: u16) -> Inline<U256BE> {
491 Inline::new(ethnum::U256::new(source.into()).to_be_bytes())
492 }
493}
494
495impl Encodes<u32> for U256BE
496{
497 type Output = Inline<U256BE>;
498 fn encode(source: u32) -> Inline<U256BE> {
499 Inline::new(ethnum::U256::new(source.into()).to_be_bytes())
500 }
501}
502
503impl Encodes<u64> for U256BE
504{
505 type Output = Inline<U256BE>;
506 fn encode(source: u64) -> Inline<U256BE> {
507 Inline::new(ethnum::U256::new(source.into()).to_be_bytes())
508 }
509}
510
511impl Encodes<u128> for U256BE
512{
513 type Output = Inline<U256BE>;
514 fn encode(source: u128) -> Inline<U256BE> {
515 Inline::new(ethnum::U256::new(source).to_be_bytes())
516 }
517}
518
519impl Encodes<i8> for I256LE
520{
521 type Output = Inline<I256LE>;
522 fn encode(source: i8) -> Inline<I256LE> {
523 Inline::new(ethnum::I256::new(source.into()).to_le_bytes())
524 }
525}
526
527impl Encodes<i16> for I256LE
528{
529 type Output = Inline<I256LE>;
530 fn encode(source: i16) -> Inline<I256LE> {
531 Inline::new(ethnum::I256::new(source.into()).to_le_bytes())
532 }
533}
534
535impl Encodes<i32> for I256LE
536{
537 type Output = Inline<I256LE>;
538 fn encode(source: i32) -> Inline<I256LE> {
539 Inline::new(ethnum::I256::new(source.into()).to_le_bytes())
540 }
541}
542
543impl Encodes<i64> for I256LE
544{
545 type Output = Inline<I256LE>;
546 fn encode(source: i64) -> Inline<I256LE> {
547 Inline::new(ethnum::I256::new(source.into()).to_le_bytes())
548 }
549}
550
551impl Encodes<i128> for I256LE
552{
553 type Output = Inline<I256LE>;
554 fn encode(source: i128) -> Inline<I256LE> {
555 Inline::new(ethnum::I256::new(source).to_le_bytes())
556 }
557}
558
559impl Encodes<i8> for I256BE
560{
561 type Output = Inline<I256BE>;
562 fn encode(source: i8) -> Inline<I256BE> {
563 Inline::new(ethnum::I256::new(source.into()).to_be_bytes())
564 }
565}
566
567impl Encodes<i32> for I256BE
568{
569 type Output = Inline<I256BE>;
570 fn encode(source: i32) -> Inline<I256BE> {
571 Inline::new(ethnum::I256::new(source.into()).to_be_bytes())
572 }
573}
574
575impl Encodes<i64> for I256BE
576{
577 type Output = Inline<I256BE>;
578 fn encode(source: i64) -> Inline<I256BE> {
579 Inline::new(ethnum::I256::new(source.into()).to_be_bytes())
580 }
581}
582
583impl Encodes<i128> for I256BE
584{
585 type Output = Inline<I256BE>;
586 fn encode(source: i128) -> Inline<I256BE> {
587 Inline::new(ethnum::I256::new(source).to_be_bytes())
588 }
589}
590
591macro_rules! impl_try_from_u256 {
594 ($schema:ty, $wide:ty, $($narrow:ty),+) => {
595 $(
596 impl TryFromInline<'_, $schema> for $narrow {
597 type Error = TryFromIntError;
598 fn try_from_inline(v: &Inline<$schema>) -> Result<Self, Self::Error> {
599 let wide: $wide = v.from_inline();
600 <$narrow>::try_from(wide)
601 }
602 }
603 )+
604 };
605}
606
607impl_try_from_u256!(U256BE, ethnum::U256, u8, u16, u32, u64, u128);
608impl_try_from_u256!(U256LE, ethnum::U256, u8, u16, u32, u64, u128);
609impl_try_from_u256!(I256BE, ethnum::I256, i8, i16, i32, i64, i128);
610impl_try_from_u256!(I256LE, ethnum::I256, i8, i16, i32, i64, i128);
611
612#[cfg(test)]
613mod tests {
614 use super::*;
615 use crate::inline::{IntoInline, TryFromInline};
616 use proptest::prelude::*;
617
618 fn arb_u256() -> impl Strategy<Value = ethnum::U256> {
619 prop::array::uniform32(any::<u8>()).prop_map(ethnum::U256::from_be_bytes)
620 }
621
622 fn arb_i256() -> impl Strategy<Value = ethnum::I256> {
623 prop::array::uniform32(any::<u8>()).prop_map(ethnum::I256::from_be_bytes)
624 }
625
626 proptest! {
629 #[test]
630 fn u256be_ethnum_roundtrip(input in arb_u256()) {
631 let value: Inline<U256BE> = input.to_inline();
632 let output: ethnum::U256 = value.from_inline();
633 prop_assert_eq!(input, output);
634 }
635
636 #[test]
637 fn u256be_u128_roundtrip(input: u128) {
638 let value: Inline<U256BE> = input.to_inline();
639 let output = u128::try_from_inline(&value).expect("fits in u128");
640 prop_assert_eq!(input, output);
641 }
642
643 #[test]
644 fn u256be_u64_roundtrip(input: u64) {
645 let value: Inline<U256BE> = input.to_inline();
646 let output = u64::try_from_inline(&value).expect("fits in u64");
647 prop_assert_eq!(input, output);
648 }
649
650 #[test]
651 fn u256be_u32_roundtrip(input: u32) {
652 let value: Inline<U256BE> = input.to_inline();
653 let output = u32::try_from_inline(&value).expect("fits in u32");
654 prop_assert_eq!(input, output);
655 }
656
657 #[test]
658 fn u256be_u16_roundtrip(input: u16) {
659 let value: Inline<U256BE> = input.to_inline();
660 let output = u16::try_from_inline(&value).expect("fits in u16");
661 prop_assert_eq!(input, output);
662 }
663
664 #[test]
665 fn u256be_u8_roundtrip(input: u8) {
666 let value: Inline<U256BE> = input.to_inline();
667 let output = u8::try_from_inline(&value).expect("fits in u8");
668 prop_assert_eq!(input, output);
669 }
670
671 #[test]
672 fn u256be_validates(input in arb_u256()) {
673 let value: Inline<U256BE> = input.to_inline();
674 prop_assert!(U256BE::validate(value).is_ok());
675 }
676
677 #[test]
678 fn u256be_order_preservation(a in arb_u256(), b in arb_u256()) {
679 let va: Inline<U256BE> = a.to_inline();
680 let vb: Inline<U256BE> = b.to_inline();
681 prop_assert_eq!(a.cmp(&b), va.raw.cmp(&vb.raw));
682 }
683
684 #[test]
685 fn u256be_widening_u64_u128(input: u64) {
686 let v64: Inline<U256BE> = input.to_inline();
687 let v128: Inline<U256BE> = (input as u128).to_inline();
688 prop_assert_eq!(v64.raw, v128.raw);
689 }
690
691 #[test]
692 fn u256be_widening_u32_u128(input: u32) {
693 let v32: Inline<U256BE> = input.to_inline();
694 let v128: Inline<U256BE> = (input as u128).to_inline();
695 prop_assert_eq!(v32.raw, v128.raw);
696 }
697
698 #[test]
701 fn u256le_ethnum_roundtrip(input in arb_u256()) {
702 let value: Inline<U256LE> = input.to_inline();
703 let output: ethnum::U256 = value.from_inline();
704 prop_assert_eq!(input, output);
705 }
706
707 #[test]
708 fn u256le_u128_roundtrip(input: u128) {
709 let value: Inline<U256LE> = input.to_inline();
710 let output = u128::try_from_inline(&value).expect("fits in u128");
711 prop_assert_eq!(input, output);
712 }
713
714 #[test]
715 fn u256le_u64_roundtrip(input: u64) {
716 let value: Inline<U256LE> = input.to_inline();
717 let output = u64::try_from_inline(&value).expect("fits in u64");
718 prop_assert_eq!(input, output);
719 }
720
721 #[test]
722 fn u256le_validates(input in arb_u256()) {
723 let value: Inline<U256LE> = input.to_inline();
724 prop_assert!(U256LE::validate(value).is_ok());
725 }
726
727 #[test]
728 fn u256_le_and_be_differ(input in arb_u256().prop_filter("non-zero", |v| *v != ethnum::U256::ZERO)) {
729 let le_val: Inline<U256LE> = input.to_inline();
730 let be_val: Inline<U256BE> = input.to_inline();
731 prop_assert_ne!(le_val.raw, be_val.raw);
732 }
733
734 #[test]
737 fn i256be_ethnum_roundtrip(input in arb_i256()) {
738 let value: Inline<I256BE> = input.to_inline();
739 let output: ethnum::I256 = value.from_inline();
740 prop_assert_eq!(input, output);
741 }
742
743 #[test]
744 fn i256be_i128_roundtrip(input: i128) {
745 let value: Inline<I256BE> = input.to_inline();
746 let output = i128::try_from_inline(&value).expect("fits in i128");
747 prop_assert_eq!(input, output);
748 }
749
750 #[test]
751 fn i256be_i64_roundtrip(input: i64) {
752 let value: Inline<I256BE> = input.to_inline();
753 let output = i64::try_from_inline(&value).expect("fits in i64");
754 prop_assert_eq!(input, output);
755 }
756
757 #[test]
758 fn i256be_i32_roundtrip(input: i32) {
759 let value: Inline<I256BE> = input.to_inline();
760 let output = i32::try_from_inline(&value).expect("fits in i32");
761 prop_assert_eq!(input, output);
762 }
763
764 #[test]
765 fn i256be_i8_roundtrip(input: i8) {
766 let value: Inline<I256BE> = input.to_inline();
767 let output = i8::try_from_inline(&value).expect("fits in i8");
768 prop_assert_eq!(input, output);
769 }
770
771 #[test]
772 fn i256be_validates(input in arb_i256()) {
773 let value: Inline<I256BE> = input.to_inline();
774 prop_assert!(I256BE::validate(value).is_ok());
775 }
776
777 #[test]
783 fn i256le_ethnum_roundtrip(input in arb_i256()) {
784 let value: Inline<I256LE> = input.to_inline();
785 let output: ethnum::I256 = value.from_inline();
786 prop_assert_eq!(input, output);
787 }
788
789 #[test]
790 fn i256le_i128_roundtrip(input: i128) {
791 let value: Inline<I256LE> = input.to_inline();
792 let output = i128::try_from_inline(&value).expect("fits in i128");
793 prop_assert_eq!(input, output);
794 }
795
796 #[test]
797 fn i256le_i64_roundtrip(input: i64) {
798 let value: Inline<I256LE> = input.to_inline();
799 let output = i64::try_from_inline(&value).expect("fits in i64");
800 prop_assert_eq!(input, output);
801 }
802
803 #[test]
804 fn i256le_validates(input in arb_i256()) {
805 let value: Inline<I256LE> = input.to_inline();
806 prop_assert!(I256LE::validate(value).is_ok());
807 }
808
809 #[test]
810 fn i256_le_and_be_differ(input in arb_i256().prop_filter("non-zero", |v| *v != ethnum::I256::ZERO)) {
811 let le_val: Inline<I256LE> = input.to_inline();
812 let be_val: Inline<I256BE> = input.to_inline();
813 prop_assert_ne!(le_val.raw, be_val.raw);
814 }
815 }
816
817 #[test]
820 fn u256be_narrowing_overflow() {
821 let input = ethnum::U256::from(u128::MAX) + ethnum::U256::ONE;
822 let value: Inline<U256BE> = input.to_inline();
823 assert!(u128::try_from_inline(&value).is_err());
824 }
825
826 #[test]
827 fn i256be_narrowing_overflow_positive() {
828 let input = ethnum::I256::from(i128::MAX) + ethnum::I256::ONE;
829 let value: Inline<I256BE> = input.to_inline();
830 assert!(i128::try_from_inline(&value).is_err());
831 }
832
833 #[test]
834 fn i256be_narrowing_overflow_negative() {
835 let input = ethnum::I256::from(i128::MIN) - ethnum::I256::ONE;
836 let value: Inline<I256BE> = input.to_inline();
837 assert!(i128::try_from_inline(&value).is_err());
838 }
839}