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