1use crate::ast::*;
3
4#[derive(Debug, Clone)]
5pub enum ScalarError {
6 IncorrectSign,
8 OutOfBounds,
10 UnsupportedPtrSize,
11}
12pub type ScalarResult<T> = std::result::Result<T, ScalarError>;
14
15macro_rules! from_le_bytes {
16 ($m:ident, $b:ident, [$(($i_ty: ty, $i:ident, $s:ident, $n_ty:ty, $t:ty)),*]) => {
17 match $m {
18 $(
19 IntegerTy::$s(<$i_ty>::$i) => {
20 let n = size_of::<$n_ty>();
21 let b: [u8; _] = $b[0..n].try_into().unwrap();
22 ScalarValue::$s(<$i_ty>::$i, <$n_ty>::from_le_bytes(b) as $t)
23 }
24 )*
25 }
26 }
27}
28
29impl ScalarValue {
30 fn ptr_size_max(ptr_size: ByteCount, signed: bool) -> ScalarResult<u128> {
31 match ptr_size {
32 2 => Ok(if signed {
33 i16::MAX as u128
34 } else {
35 u16::MAX as u128
36 }),
37 4 => Ok(if signed {
38 i32::MAX as u128
39 } else {
40 u32::MAX as u128
41 }),
42 8 => Ok(if signed {
43 i64::MAX as u128
44 } else {
45 u64::MAX as u128
46 }),
47 _ => Err(ScalarError::UnsupportedPtrSize),
48 }
49 }
50
51 fn ptr_size_min(ptr_size: ByteCount, signed: bool) -> ScalarResult<i128> {
52 match ptr_size {
53 2 => Ok(if signed {
54 i16::MIN as i128
55 } else {
56 u16::MIN as i128
57 }),
58 4 => Ok(if signed {
59 i32::MIN as i128
60 } else {
61 u32::MIN as i128
62 }),
63 8 => Ok(if signed {
64 i64::MIN as i128
65 } else {
66 u64::MIN as i128
67 }),
68 _ => Err(ScalarError::UnsupportedPtrSize),
69 }
70 }
71
72 pub fn get_integer_ty(&self) -> IntegerTy {
73 match self {
74 ScalarValue::Signed(ty, _) => IntegerTy::Signed(*ty),
75 ScalarValue::Unsigned(ty, _) => IntegerTy::Unsigned(*ty),
76 }
77 }
78
79 pub fn is_int(&self) -> bool {
80 matches!(self, ScalarValue::Signed(_, _))
81 }
82
83 pub fn is_uint(&self) -> bool {
84 matches!(self, ScalarValue::Unsigned(_, _))
85 }
86
87 pub fn as_uint(&self) -> ScalarResult<u128> {
91 match self {
92 ScalarValue::Unsigned(_, v) => Ok(*v),
93 _ => Err(ScalarError::IncorrectSign),
94 }
95 }
96
97 pub fn uint_is_in_bounds(ptr_size: ByteCount, ty: UIntTy, v: u128) -> bool {
98 match ty {
99 UIntTy::Usize => v <= Self::ptr_size_max(ptr_size, false).unwrap(),
100 UIntTy::U8 => v <= (u8::MAX as u128),
101 UIntTy::U16 => v <= (u16::MAX as u128),
102 UIntTy::U32 => v <= (u32::MAX as u128),
103 UIntTy::U64 => v <= (u64::MAX as u128),
104 UIntTy::U128 => true,
105 }
106 }
107
108 pub fn from_unchecked_uint(ty: UIntTy, v: u128) -> ScalarValue {
109 ScalarValue::Unsigned(ty, v)
110 }
111
112 pub fn from_uint(ptr_size: ByteCount, ty: UIntTy, v: u128) -> ScalarResult<ScalarValue> {
113 if !ScalarValue::uint_is_in_bounds(ptr_size, ty, v) {
114 trace!("Not in bounds for {:?}: {}", ty, v);
115 Err(ScalarError::OutOfBounds)
116 } else {
117 Ok(ScalarValue::from_unchecked_uint(ty, v))
118 }
119 }
120
121 pub fn as_int(&self) -> ScalarResult<i128> {
125 match self {
126 ScalarValue::Signed(_, v) => Ok(*v),
127 _ => Err(ScalarError::IncorrectSign),
128 }
129 }
130
131 pub fn int_is_in_bounds(ptr_size: ByteCount, ty: IntTy, v: i128) -> bool {
132 match ty {
133 IntTy::Isize => {
134 v >= Self::ptr_size_min(ptr_size, true).unwrap()
135 && v <= Self::ptr_size_max(ptr_size, true).unwrap() as i128
136 }
137 IntTy::I8 => v >= (i8::MIN as i128) && v <= (i8::MAX as i128),
138 IntTy::I16 => v >= (i16::MIN as i128) && v <= (i16::MAX as i128),
139 IntTy::I32 => v >= (i32::MIN as i128) && v <= (i32::MAX as i128),
140 IntTy::I64 => v >= (i64::MIN as i128) && v <= (i64::MAX as i128),
141 IntTy::I128 => true,
142 }
143 }
144
145 pub fn from_unchecked_int(ty: IntTy, v: i128) -> ScalarValue {
146 ScalarValue::Signed(ty, v)
147 }
148
149 pub fn to_bits(&self) -> u128 {
151 match *self {
152 ScalarValue::Unsigned(_, v) => v,
153 ScalarValue::Signed(_, v) => u128::from_le_bytes(v.to_le_bytes()),
154 }
155 }
156
157 pub fn from_le_bytes(ty: IntegerTy, bytes: [u8; 16]) -> Self {
162 from_le_bytes!(
163 ty,
164 bytes,
165 [
166 (IntTy, Isize, Signed, isize, i128),
167 (IntTy, I8, Signed, i8, i128),
168 (IntTy, I16, Signed, i16, i128),
169 (IntTy, I32, Signed, i32, i128),
170 (IntTy, I64, Signed, i64, i128),
171 (IntTy, I128, Signed, i128, i128),
172 (UIntTy, Usize, Unsigned, usize, u128),
173 (UIntTy, U8, Unsigned, u8, u128),
174 (UIntTy, U16, Unsigned, u16, u128),
175 (UIntTy, U32, Unsigned, u32, u128),
176 (UIntTy, U64, Unsigned, u64, u128),
177 (UIntTy, U128, Unsigned, u128, u128)
178 ]
179 )
180 }
181
182 pub fn from_bits(ty: IntegerTy, bits: u128) -> Self {
183 let bytes = bits.to_le_bytes();
184 Self::from_le_bytes(ty, bytes)
185 }
186
187 pub fn from_int(ptr_size: ByteCount, ty: IntTy, v: i128) -> ScalarResult<ScalarValue> {
191 if !ScalarValue::int_is_in_bounds(ptr_size, ty, v) {
192 Err(ScalarError::OutOfBounds)
193 } else {
194 Ok(ScalarValue::from_unchecked_int(ty, v))
195 }
196 }
197
198 pub fn to_constant(self) -> ConstantExpr {
199 let literal_ty = match self {
200 ScalarValue::Signed(int_ty, _) => LiteralTy::Int(int_ty),
201 ScalarValue::Unsigned(uint_ty, _) => LiteralTy::UInt(uint_ty),
202 };
203 ConstantExpr {
204 value: RawConstantExpr::Literal(Literal::Scalar(self)),
205 ty: TyKind::Literal(literal_ty).into_ty(),
206 }
207 }
208}
209
210pub(crate) mod scalar_value_ser_de {
212 use std::{marker::PhantomData, str::FromStr};
213
214 use serde::de::{Deserializer, Error};
215
216 pub fn serialize<S, V>(val: &V, serializer: S) -> Result<S::Ok, S::Error>
217 where
218 S: serde::ser::Serializer,
219 V: ToString,
220 {
221 serializer.serialize_str(&val.to_string())
222 }
223
224 pub fn deserialize<'de, D, V>(deserializer: D) -> Result<V, D::Error>
225 where
226 D: Deserializer<'de>,
227 V: FromStr,
228 {
229 struct Visitor<V> {
230 _val: PhantomData<V>,
231 }
232 impl<'de, V> serde::de::Visitor<'de> for Visitor<V>
233 where
234 V: FromStr,
235 {
236 type Value = V;
237 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
238 write!(f, "ScalarValue value")
239 }
240 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
241 where
242 E: Error,
243 {
244 v.parse()
245 .map_err(|_| E::custom("Could not parse 128 bit integer!"))
246 }
247 }
248 deserializer.deserialize_str(Visitor { _val: PhantomData })
249 }
250}
251
252#[cfg(test)]
253mod test {
254 use super::*;
255
256 #[test]
257 fn test_big_endian_scalars() -> ScalarResult<()> {
258 let u128 = 0x12345678901234567890123456789012u128;
259 let le_bytes = u128.to_le_bytes();
260
261 let le_scalar = ScalarValue::from_le_bytes(IntegerTy::Unsigned(UIntTy::U128), le_bytes);
262 assert_eq!(le_scalar, ScalarValue::Unsigned(UIntTy::U128, u128));
263
264 let i64 = 0x1234567890123456i64;
265 let le_bytes = (i64 as i128).to_le_bytes();
266 let le_scalar = ScalarValue::from_le_bytes(IntegerTy::Signed(IntTy::I64), le_bytes);
267 assert_eq!(le_scalar, ScalarValue::Signed(IntTy::I64, i64 as i128));
268
269 Ok(())
270 }
271}