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