1pub mod de;
2pub mod ser;
3
4use crate::{AlgebraicType, ArrayValue, ProductValue, SumValue};
5use core::mem;
6use core::ops::{Bound, RangeBounds};
7use derive_more::From;
8use enum_as_inner::EnumAsInner;
9
10pub use ethnum::{i256, u256};
11
12pub type F32 = decorum::Total<f32>;
14
15pub type F64 = decorum::Total<f64>;
17
18#[derive(EnumAsInner, Debug, Clone, Eq, PartialEq, Ord, PartialOrd, From)]
28pub enum AlgebraicValue {
29 Min,
33
34 Sum(SumValue),
43 Product(ProductValue),
50 Array(ArrayValue),
56 Bool(bool),
58 I8(i8),
60 U8(u8),
62 I16(i16),
64 U16(u16),
66 I32(i32),
68 U32(u32),
70 I64(i64),
72 U64(u64),
74 I128(Packed<i128>),
78 U128(Packed<u128>),
82 I256(Box<i256>),
86 U256(Box<u256>),
90 F32(F32),
97 F64(F64),
104 String(Box<str>),
108
109 Max,
113}
114
115#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
117#[repr(Rust, packed)]
118pub struct Packed<T>(pub T);
119
120impl<T> From<T> for Packed<T> {
121 fn from(value: T) -> Self {
122 Self(value)
123 }
124}
125
126#[allow(non_snake_case)]
127impl AlgebraicValue {
128 pub fn take(&mut self) -> Self {
130 mem::replace(self, Self::U8(0))
131 }
132
133 #[inline]
135 pub fn as_bytes(&self) -> Option<&[u8]> {
136 match self {
137 Self::Array(ArrayValue::U8(a)) => Some(a),
138 _ => None,
139 }
140 }
141
142 pub fn unit() -> Self {
146 Self::product([])
147 }
148
149 #[inline]
151 pub const fn Bytes(v: Box<[u8]>) -> Self {
152 Self::Array(ArrayValue::U8(v))
153 }
154
155 pub fn into_bytes(self) -> Result<Box<[u8]>, Self> {
157 match self {
158 Self::Array(ArrayValue::U8(v)) => Ok(v),
159 _ => Err(self),
160 }
161 }
162
163 pub fn into_option(self) -> Result<Option<Self>, Self> {
165 match self {
166 AlgebraicValue::Sum(sum_value) => match sum_value.tag {
167 0 => Ok(Some(*sum_value.value)),
168 1 => Ok(None),
169 _ => Err(AlgebraicValue::Sum(sum_value)),
170 },
171 _ => Err(self),
172 }
173 }
174
175 #[inline]
179 pub fn OptionSome(v: Self) -> Self {
180 Self::sum(0, v)
181 }
182
183 #[inline]
187 pub fn OptionNone() -> Self {
188 Self::sum(1, Self::unit())
189 }
190
191 pub fn into_result(self) -> Result<Result<Self, Self>, Self> {
193 match self {
194 AlgebraicValue::Sum(sum_value) => match sum_value.tag {
195 0 => Ok(Ok(*sum_value.value)),
196 1 => Ok(Err(*sum_value.value)),
197 _ => Err(AlgebraicValue::Sum(sum_value)),
198 },
199 _ => Err(self),
200 }
201 }
202
203 #[inline]
207 pub fn ResultOk(v: Self) -> Self {
208 Self::sum(0, v)
209 }
210
211 #[inline]
215 pub fn ResultErr(v: Self) -> Self {
216 Self::sum(1, v)
217 }
218
219 pub fn sum(tag: u8, value: Self) -> Self {
221 Self::Sum(SumValue::new(tag, value))
222 }
223
224 pub fn enum_simple(tag: u8) -> Self {
227 Self::Sum(SumValue::new_simple(tag))
228 }
229
230 pub fn product(elements: impl Into<ProductValue>) -> Self {
232 Self::Product(elements.into())
233 }
234
235 pub(crate) fn type_of_product(x: &ProductValue) -> Option<AlgebraicType> {
237 let mut elems = Vec::with_capacity(x.elements.len());
238 for elem in &*x.elements {
239 elems.push(elem.type_of()?.into());
240 }
241 Some(AlgebraicType::product(elems.into_boxed_slice()))
242 }
243
244 pub fn type_of(&self) -> Option<AlgebraicType> {
261 match self {
262 Self::Sum(_) => None,
263 Self::Product(x) => Self::type_of_product(x),
264 Self::Array(x) => x.type_of().map(Into::into),
265 Self::Bool(_) => Some(AlgebraicType::Bool),
266 Self::I8(_) => Some(AlgebraicType::I8),
267 Self::U8(_) => Some(AlgebraicType::U8),
268 Self::I16(_) => Some(AlgebraicType::I16),
269 Self::U16(_) => Some(AlgebraicType::U16),
270 Self::I32(_) => Some(AlgebraicType::I32),
271 Self::U32(_) => Some(AlgebraicType::U32),
272 Self::I64(_) => Some(AlgebraicType::I64),
273 Self::U64(_) => Some(AlgebraicType::U64),
274 Self::I128(_) => Some(AlgebraicType::I128),
275 Self::U128(_) => Some(AlgebraicType::U128),
276 Self::I256(_) => Some(AlgebraicType::I256),
277 Self::U256(_) => Some(AlgebraicType::U256),
278 Self::F32(_) => Some(AlgebraicType::F32),
279 Self::F64(_) => Some(AlgebraicType::F64),
280 Self::String(_) => Some(AlgebraicType::String),
281 AlgebraicValue::Min | AlgebraicValue::Max => None,
282 }
283 }
284
285 pub fn is_numeric_zero(&self) -> bool {
289 match *self {
290 Self::I8(x) => x == 0,
291 Self::U8(x) => x == 0,
292 Self::I16(x) => x == 0,
293 Self::U16(x) => x == 0,
294 Self::I32(x) => x == 0,
295 Self::U32(x) => x == 0,
296 Self::I64(x) => x == 0,
297 Self::U64(x) => x == 0,
298 Self::I128(x) => x.0 == 0,
299 Self::U128(x) => x.0 == 0,
300 Self::I256(ref x) => **x == i256::ZERO,
301 Self::U256(ref x) => **x == u256::ZERO,
302 Self::F32(x) => x == 0.0,
303 Self::F64(x) => x == 0.0,
304 _ => false,
305 }
306 }
307
308 pub fn from_i128(ty: &AlgebraicType, value: i128) -> Option<Self> {
312 let val = match ty {
313 AlgebraicType::I8 => (value as i8).into(),
314 AlgebraicType::I16 => (value as i16).into(),
315 AlgebraicType::I32 => (value as i32).into(),
316 AlgebraicType::I64 => (value as i64).into(),
317 AlgebraicType::I128 => value.into(),
318 AlgebraicType::I256 => i256::from(value).into(),
319
320 AlgebraicType::U8 => (value as u8).into(),
321 AlgebraicType::U16 => (value as u16).into(),
322 AlgebraicType::U32 => (value as u32).into(),
323 AlgebraicType::U64 => (value as u64).into(),
324 AlgebraicType::U128 => (value as u128).into(),
325 AlgebraicType::U256 => (u256::from(value as u128)).into(),
326
327 _ => return None,
328 };
329 Some(val)
330 }
331}
332
333impl<T: Into<AlgebraicValue>> From<Option<T>> for AlgebraicValue {
334 fn from(value: Option<T>) -> Self {
335 match value {
336 None => AlgebraicValue::OptionNone(),
337 Some(x) => AlgebraicValue::OptionSome(x.into()),
338 }
339 }
340}
341
342impl RangeBounds<AlgebraicValue> for &AlgebraicValue {
345 fn start_bound(&self) -> Bound<&AlgebraicValue> {
346 Bound::Included(self)
347 }
348 fn end_bound(&self) -> Bound<&AlgebraicValue> {
349 Bound::Included(self)
350 }
351}
352
353impl RangeBounds<AlgebraicValue> for AlgebraicValue {
354 fn start_bound(&self) -> Bound<&AlgebraicValue> {
355 Bound::Included(self)
356 }
357 fn end_bound(&self) -> Bound<&AlgebraicValue> {
358 Bound::Included(self)
359 }
360}
361
362#[cfg(test)]
363mod tests {
364 use crate::satn::Satn;
365 use crate::{AlgebraicType, AlgebraicValue, ArrayValue, Typespace, ValueWithType, WithTypespace};
366
367 fn in_space<'a, T: crate::Value>(ts: &'a Typespace, ty: &'a T::Type, val: &'a T) -> ValueWithType<'a, T> {
368 WithTypespace::new(ts, ty).with_value(val)
369 }
370
371 #[test]
372 fn unit() {
373 let val = AlgebraicValue::unit();
374 let unit = AlgebraicType::unit();
375 let typespace = Typespace::new(vec![]);
376 assert_eq!(in_space(&typespace, &unit, &val).to_satn(), "()");
377 }
378
379 #[test]
380 fn product_value() {
381 let product_type = AlgebraicType::product([("foo", AlgebraicType::I32)]);
382 let typespace = Typespace::new(vec![]);
383 let product_value = AlgebraicValue::product([AlgebraicValue::I32(42)]);
384 assert_eq!(
385 "(foo = 42)",
386 in_space(&typespace, &product_type, &product_value).to_satn(),
387 );
388 }
389
390 #[test]
391 fn option_some() {
392 let option = AlgebraicType::option(AlgebraicType::never());
393 let sum_value = AlgebraicValue::OptionNone();
394 let typespace = Typespace::new(vec![]);
395 assert_eq!("(none = ())", in_space(&typespace, &option, &sum_value).to_satn(),);
396 }
397
398 #[test]
399 fn result() {
400 let result = AlgebraicType::result(AlgebraicType::U8, AlgebraicType::String);
401 let ok = AlgebraicValue::ResultOk(AlgebraicValue::U8(42));
402 let typespace = Typespace::new(vec![]);
403 assert_eq!("(ok = 42)", in_space(&typespace, &result, &ok).to_satn(),);
404
405 let err = AlgebraicValue::ResultErr(AlgebraicValue::String("error".into()));
406 assert_eq!("(err = \"error\")", in_space(&typespace, &result, &err).to_satn(),);
407 }
408
409 #[test]
410 fn primitive() {
411 let u8 = AlgebraicType::U8;
412 let value = AlgebraicValue::U8(255);
413 let typespace = Typespace::new(vec![]);
414 assert_eq!(in_space(&typespace, &u8, &value).to_satn(), "255");
415 }
416
417 #[test]
418 fn array() {
419 let array = AlgebraicType::array(AlgebraicType::U8);
420 let value = AlgebraicValue::Array(ArrayValue::Sum([].into()));
421 let typespace = Typespace::new(vec![]);
422 assert_eq!(in_space(&typespace, &array, &value).to_satn(), "[]");
423 }
424
425 #[test]
426 fn array_of_values() {
427 let array = AlgebraicType::array(AlgebraicType::U8);
428 let value = AlgebraicValue::Array([3u8].into());
429 let typespace = Typespace::new(vec![]);
430 assert_eq!(in_space(&typespace, &array, &value).to_satn(), "0x03");
431 }
432}