topcoat_runtime/surrogate/
integer.rs1use ref_cast::RefCast;
2use serde::{Deserialize, Serialize, de, ser::SerializeStruct};
3
4use crate::{BoolSurrogate, impl_surrogate, impl_surrogate_mut, impl_surrogate_ref};
5
6#[derive(Deserialize)]
7#[serde(deny_unknown_fields)]
8struct Integer {
9 t: String,
10 bits: u32,
11 v: String,
12}
13
14macro_rules! integer_op {
15 ($surrogate:ident, $trait:ident, $method:ident, $checked:ident) => {
16 impl core::ops::$trait for $surrogate {
17 type Output = Self;
18
19 #[inline]
20 #[track_caller]
21 fn $method(self, rhs: Self) -> Self {
22 Self(
23 self.0
24 .$checked(rhs.0)
25 .expect(concat!("invalid integer ", stringify!($method),)),
26 )
27 }
28 }
29 };
30}
31
32macro_rules! integer_cmp {
33 ($surrogate:ident, $method:ident, $op:tt) => {
34 impl $surrogate {
35 #[inline]
36 pub fn $method(&self, rhs: &Self) -> BoolSurrogate {
37 BoolSurrogate::new(self.0 $op rhs.0)
38 }
39 }
40 };
41}
42
43macro_rules! integer_surrogate {
44 ($real:ident, $surrogate:ident) => {
45 #[doc = concat!("A `", stringify!($real), "` in a runtime expression.")]
46 #[derive(Debug, Clone, Copy, RefCast)]
49 #[repr(transparent)]
50 pub struct $surrogate($real);
51
52 impl $surrogate {
53 #[inline]
54 pub(crate) const fn new(value: $real) -> Self {
55 Self(value)
56 }
57 }
58
59 impl_surrogate!($real, $surrogate);
60 impl_surrogate_ref!($real, $surrogate);
61 impl_surrogate_mut!($real, $surrogate);
62
63 impl std::fmt::Display for $surrogate {
64 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65 self.0.fmt(f)
66 }
67 }
68
69 impl Serialize for $surrogate {
70 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
71 where
72 S: serde::Serializer,
73 {
74 let mut value = serializer.serialize_struct("Integer", 3)?;
75 value.serialize_field("t", stringify!($real))?;
76 value.serialize_field("bits", &$real::BITS)?;
77 value.serialize_field("v", &self.0.to_string())?;
78 value.end()
79 }
80 }
81
82 impl<'de> Deserialize<'de> for $surrogate {
83 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
84 where
85 D: serde::Deserializer<'de>,
86 {
87 let value = Integer::deserialize(deserializer)?;
88 if value.t != stringify!($real) {
89 return Err(de::Error::invalid_value(
90 de::Unexpected::Str(&value.t),
91 &stringify!($real),
92 ));
93 }
94 if value.bits != $real::BITS {
95 return Err(de::Error::custom("integer width does not match the server"));
96 }
97 let integer: $real = value.v.parse().map_err(de::Error::custom)?;
98 if value.v != integer.to_string() {
99 return Err(de::Error::custom("expected a canonical decimal integer"));
100 }
101 Ok(Self(integer))
102 }
103 }
104
105 integer_op!($surrogate, Add, add, checked_add);
106 integer_op!($surrogate, Sub, sub, checked_sub);
107 integer_op!($surrogate, Mul, mul, checked_mul);
108 integer_op!($surrogate, Div, div, checked_div);
109 integer_op!($surrogate, Rem, rem, checked_rem);
110
111 integer_cmp!($surrogate, eq, ==);
112 integer_cmp!($surrogate, ne, !=);
113 integer_cmp!($surrogate, gt, >);
114 integer_cmp!($surrogate, lt, <);
115 integer_cmp!($surrogate, ge, >=);
116 integer_cmp!($surrogate, le, <=);
117 };
118}
119
120macro_rules! signed_integer_surrogate {
121 ($real:ident, $surrogate:ident) => {
122 integer_surrogate!($real, $surrogate);
123
124 impl core::ops::Neg for $surrogate {
125 type Output = Self;
126
127 #[inline]
128 #[track_caller]
129 fn neg(self) -> Self {
130 Self(self.0.checked_neg().expect("integer negation overflow"))
131 }
132 }
133 };
134}
135
136integer_surrogate!(u8, U8Surrogate);
137integer_surrogate!(u16, U16Surrogate);
138integer_surrogate!(u32, U32Surrogate);
139integer_surrogate!(u64, U64Surrogate);
140integer_surrogate!(u128, U128Surrogate);
141integer_surrogate!(usize, UsizeSurrogate);
142signed_integer_surrogate!(i8, I8Surrogate);
143signed_integer_surrogate!(i16, I16Surrogate);
144signed_integer_surrogate!(i32, I32Surrogate);
145signed_integer_surrogate!(i64, I64Surrogate);
146signed_integer_surrogate!(i128, I128Surrogate);
147signed_integer_surrogate!(isize, IsizeSurrogate);
148
149#[cfg(test)]
150mod tests {
151 use serde_json::json;
152
153 use super::*;
154
155 macro_rules! integer_tests {
156 ($real:ident, $surrogate:ident) => {
157 #[test]
158 fn $real() {
159 for value in [$real::MIN, 0, 1, $real::MAX] {
160 let wire = serde_json::to_value($surrogate::new(value)).unwrap();
161 assert_eq!(wire, json!({
162 "t": stringify!($real), "bits": $real::BITS, "v": value.to_string(),
163 }));
164 let decoded: $surrogate = serde_json::from_value(wire).unwrap();
165 assert_eq!(decoded.0, value);
166 assert_eq!(decoded.to_string(), value.to_string());
167 }
168 for digits in ["", "-0", "+1", "01", "1.0", "1e3", " 1", "1 ", "0xff"] {
169 assert!(serde_json::from_value::<$surrogate>(json!({
170 "t": stringify!($real), "bits": $real::BITS, "v": digits,
171 })).is_err());
172 }
173 for wire in [
174 json!({ "t": "f64", "bits": $real::BITS, "v": "1" }),
175 json!({ "t": stringify!($real), "bits": $real::BITS / 2, "v": "1" }),
176 json!({ "t": stringify!($real), "bits": $real::BITS, "v": 1 }),
177 json!({ "t": stringify!($real), "v": "1" }),
178 json!({ "t": stringify!($real), "bits": $real::BITS, "v": "1", "extra": true }),
179 json!({ "t": stringify!($real), "bits": $real::BITS, "v": format!("{}0", $real::MAX) }),
180 ] {
181 assert!(serde_json::from_value::<$surrogate>(wire).is_err());
182 }
183 }
184 };
185 }
186
187 integer_tests!(u8, U8Surrogate);
188 integer_tests!(u16, U16Surrogate);
189 integer_tests!(u32, U32Surrogate);
190 integer_tests!(u64, U64Surrogate);
191 integer_tests!(u128, U128Surrogate);
192 integer_tests!(usize, UsizeSurrogate);
193 integer_tests!(i8, I8Surrogate);
194 integer_tests!(i16, I16Surrogate);
195 integer_tests!(i32, I32Surrogate);
196 integer_tests!(i64, I64Surrogate);
197 integer_tests!(i128, I128Surrogate);
198 integer_tests!(isize, IsizeSurrogate);
199}