Skip to main content

substrate_data/schema/plain/
ints.rs

1//! The schemas of integers: checked against their type's range, bit-packed in lists.
2
3use crate::binary::{Decoder, Writer};
4use crate::frame::{Packer, Unpacker};
5use crate::model::borrowed::ValueRef;
6use crate::model::value::Value;
7use crate::schema::{Expected, Reader, Schema, Shape};
8
9/// What a schema needs of an integer type: its range, and the `i64` and
10/// bit-packed forms it is carried in, both ways, without a lossy cast.
11trait Int: Copy + Sized {
12    /// Its range, as the shape says it (`u64` and `usize` up to `i64::MAX`).
13    fn range() -> (i64, i64);
14    /// As the model's `i64` (a 64-bit unsigned number: the `i64` of its bits).
15    fn to_i64(self) -> i64;
16    /// From the model's `i64`, if it fits.
17    fn of_i64(n: i64) -> Option<Self>;
18    /// As a bit-packed list's bits: a signed number zigzagged.
19    fn to_bits(self) -> u64;
20    /// From a bit-packed list's bits, if it fits.
21    fn of_bits(v: u64) -> Option<Self>;
22}
23
24macro_rules! signed {
25    ($($t:ty),*) => {$(
26        impl Int for $t {
27            fn range() -> (i64, i64) {
28                (i64::from(<$t>::MIN), i64::from(<$t>::MAX))
29            }
30            fn to_i64(self) -> i64 {
31                i64::from(self)
32            }
33            fn of_i64(n: i64) -> Option<Self> {
34                Self::try_from(n).ok()
35            }
36            fn to_bits(self) -> u64 {
37                crate::binary::zigzag(i64::from(self))
38            }
39            fn of_bits(v: u64) -> Option<Self> {
40                Self::try_from(crate::binary::unzigzag(v)).ok()
41            }
42        }
43    )*};
44}
45signed!(i8, i16, i32, i64);
46
47macro_rules! unsigned {
48    ($($t:ty),*) => {$(
49        impl Int for $t {
50            fn range() -> (i64, i64) {
51                (0, i64::from(<$t>::MAX))
52            }
53            fn to_i64(self) -> i64 {
54                i64::from(self)
55            }
56            fn of_i64(n: i64) -> Option<Self> {
57                Self::try_from(n).ok()
58            }
59            fn to_bits(self) -> u64 {
60                u64::from(self)
61            }
62            fn of_bits(v: u64) -> Option<Self> {
63                Self::try_from(v).ok()
64            }
65        }
66    )*};
67}
68unsigned!(u8, u16, u32);
69
70impl Int for u64 {
71    fn range() -> (i64, i64) {
72        (0, i64::MAX)
73    }
74    fn to_i64(self) -> i64 {
75        i64::from_ne_bytes(self.to_ne_bytes())
76    }
77    fn of_i64(n: i64) -> Option<Self> {
78        Some(u64::from_ne_bytes(n.to_ne_bytes()))
79    }
80    fn to_bits(self) -> u64 {
81        self
82    }
83    fn of_bits(v: u64) -> Option<Self> {
84        Some(v)
85    }
86}
87
88impl Int for usize {
89    fn range() -> (i64, i64) {
90        (0, i64::MAX)
91    }
92    fn to_i64(self) -> i64 {
93        u64::try_from(self).unwrap_or(u64::MAX).to_i64()
94    }
95    fn of_i64(n: i64) -> Option<Self> {
96        Self::try_from(u64::of_i64(n)?).ok()
97    }
98    fn to_bits(self) -> u64 {
99        u64::try_from(self).unwrap_or(u64::MAX)
100    }
101    fn of_bits(v: u64) -> Option<Self> {
102        Self::try_from(v).ok()
103    }
104}
105
106macro_rules! int_schema {
107    ($($t:ty),*) => {$(
108        impl Schema for $t {
109            fn shape() -> Shape {
110                let (min, max) = <$t as Int>::range();
111                Shape::Int { min, max }
112            }
113            fn read(v: &ValueRef<'_>, cx: &mut Reader<'_>) -> Option<Self> {
114                let Some(n) = v.as_i64() else {
115                    cx.expected(Expected::Integer, v);
116                    return None;
117                };
118                <$t as Int>::of_i64(n).or_else(|| {
119                    cx.problem(format!("{n} is out of range ({}..={})", <$t>::MIN, <$t>::MAX));
120                    None
121                })
122            }
123            fn write(&self) -> Value {
124                Value::Int(self.to_i64())
125            }
126            fn encode(&self, w: &mut Writer) {
127                w.int(self.to_i64());
128            }
129            fn decode(d: &mut Decoder<'_>) -> Option<Self> {
130                d.int().and_then(<$t as Int>::of_i64)
131            }
132            fn pack(&self, p: &mut Packer) {
133                p.put_i(self.to_i64());
134            }
135            fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
136                u.int().and_then(<$t as Int>::of_i64)
137            }
138            fn pack_list(items: &[Self], p: &mut Packer) {
139                p.put_uints(items.len(), items.iter().map(|&n| n.to_bits()));
140            }
141            fn unpack_list(u: &mut Unpacker<'_>) -> Option<Vec<Self>> {
142                u.uints(<$t as Int>::of_bits)
143            }
144            fn encode_list(items: &[Self], w: &mut Writer) {
145                w.ints(items.iter().map(|&n| n.to_i64()));
146            }
147            fn decode_list(d: &mut Decoder<'_>) -> Option<Vec<Self>> {
148                let n = d.ints()?;
149                let mut out = Vec::with_capacity(n);
150                for _ in 0..n {
151                    out.push(<$t as Int>::of_i64(d.packed_int()?)?);
152                }
153                Some(out)
154            }
155        }
156    )*};
157}
158int_schema!(i8, i16, i32, i64, u8, u16, u32, u64, usize);