1pub mod fmt;
2pub mod map_notation;
3
4use crate::algebraic_value::de::{ValueDeserializeError, ValueDeserializer};
5use crate::algebraic_value::ser::value_serialize;
6use crate::de::Deserialize;
7use crate::meta_type::MetaType;
8use crate::product_type::{CONNECTION_ID_TAG, IDENTITY_TAG, TIMESTAMP_TAG, TIME_DURATION_TAG};
9use crate::sum_type::{OPTION_NONE_TAG, OPTION_SOME_TAG};
10use crate::typespace::Typespace;
11use crate::{i256, u256};
12use crate::{AlgebraicTypeRef, AlgebraicValue, ArrayType, ProductType, SpacetimeType, SumType, SumTypeVariant};
13use derive_more::From;
14use enum_as_inner::EnumAsInner;
15
16#[derive(EnumAsInner, Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, SpacetimeType, From)]
23#[sats(crate = crate)]
24pub enum AlgebraicType {
25 Ref(AlgebraicTypeRef),
31 Sum(SumType),
58 Product(ProductType),
84 Array(ArrayType),
87 String,
93 Bool,
95 I8,
97 U8,
99 I16,
101 U16,
103 I32,
105 U32,
107 I64,
109 U64,
111 I128,
113 U128,
115 I256,
117 U256,
119 F32,
121 F64,
123}
124
125impl MetaType for AlgebraicType {
126 fn meta_type() -> Self {
132 AlgebraicType::sum([
133 ("ref", AlgebraicTypeRef::meta_type()),
134 ("sum", SumType::meta_type()),
135 ("product", ProductType::meta_type()),
136 ("array", ArrayType::meta_type()),
137 ("string", AlgebraicType::unit()),
138 ("bool", AlgebraicType::unit()),
139 ("i8", AlgebraicType::unit()),
140 ("u8", AlgebraicType::unit()),
141 ("i16", AlgebraicType::unit()),
142 ("u16", AlgebraicType::unit()),
143 ("i32", AlgebraicType::unit()),
144 ("u32", AlgebraicType::unit()),
145 ("i64", AlgebraicType::unit()),
146 ("u64", AlgebraicType::unit()),
147 ("i128", AlgebraicType::unit()),
148 ("u128", AlgebraicType::unit()),
149 ("i256", AlgebraicType::unit()),
150 ("u256", AlgebraicType::unit()),
151 ("f32", AlgebraicType::unit()),
152 ("f64", AlgebraicType::unit()),
153 ])
154 }
155}
156
157impl Default for AlgebraicType {
159 fn default() -> Self {
160 Self::ZERO_REF
161 }
162}
163
164impl AlgebraicType {
165 pub const ZERO_REF: Self = Self::Ref(AlgebraicTypeRef(0));
167
168 pub fn is_connection_id(&self) -> bool {
172 matches!(self, Self::Product(p) if p.is_connection_id())
173 }
174
175 pub fn is_identity(&self) -> bool {
177 matches!(self, Self::Product(p) if p.is_identity())
178 }
179
180 pub fn is_timestamp(&self) -> bool {
182 matches!(self, Self::Product(p) if p.is_timestamp())
183 }
184
185 pub fn is_time_duration(&self) -> bool {
187 matches!(self, Self::Product(p) if p.is_time_duration())
188 }
189
190 pub fn is_schedule_at(&self) -> bool {
192 matches!(self, Self::Sum(p) if p.is_schedule_at())
193 }
194
195 pub fn is_unit(&self) -> bool {
197 matches!(self, Self::Product(p) if p.is_unit())
198 }
199
200 pub fn is_never(&self) -> bool {
202 matches!(self, Self::Sum(p) if p.is_empty())
203 }
204
205 pub fn is_option(&self) -> bool {
207 matches!(self, Self::Sum(p) if p.is_option())
208 }
209
210 pub fn as_option(&self) -> Option<&AlgebraicType> {
213 self.as_sum()?.as_option()
214 }
215
216 pub fn is_scalar_or_string(&self) -> bool {
218 self.is_scalar() || self.is_string()
219 }
220
221 pub fn is_scalar(&self) -> bool {
228 self.is_bool() || self.is_integer() || self.is_float()
229 }
230
231 pub fn is_signed(&self) -> bool {
233 matches!(
234 self,
235 Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128 | Self::I256
236 )
237 }
238
239 pub fn is_unsigned(&self) -> bool {
241 matches!(
242 self,
243 Self::U8 | Self::U16 | Self::U32 | Self::U64 | Self::U128 | Self::U256
244 )
245 }
246
247 pub fn is_integer(&self) -> bool {
249 self.is_signed() || self.is_unsigned()
250 }
251
252 pub fn is_float(&self) -> bool {
254 matches!(self, Self::F32 | Self::F64)
255 }
256
257 pub fn unit() -> Self {
259 let fs: [AlgebraicType; 0] = [];
260 Self::product(fs)
261 }
262
263 pub fn never() -> Self {
265 let vs: [SumTypeVariant; 0] = [];
266 Self::sum(vs)
267 }
268
269 pub fn bytes() -> Self {
271 Self::array(Self::U8)
272 }
273
274 pub fn is_bytes(&self) -> bool {
276 self.as_array().is_some_and(|ty| ty.elem_ty.is_u8())
277 }
278
279 pub fn contains_refs(&self) -> bool {
281 match self {
282 AlgebraicType::Ref(_) => true,
283 AlgebraicType::Product(ProductType { elements }) => {
284 elements.iter().any(|elem| elem.algebraic_type.contains_refs())
285 }
286 AlgebraicType::Sum(SumType { variants }) => {
287 variants.iter().any(|variant| variant.algebraic_type.contains_refs())
288 }
289 AlgebraicType::Array(array) => array.elem_ty.contains_refs(),
290 _ => false,
291 }
292 }
293
294 pub fn sum<S: Into<SumType>>(sum: S) -> Self {
296 AlgebraicType::Sum(sum.into())
297 }
298
299 pub fn product<P: Into<ProductType>>(prod: P) -> Self {
301 AlgebraicType::Product(prod.into())
302 }
303
304 pub fn option(some_type: Self) -> Self {
306 Self::sum([(OPTION_SOME_TAG, some_type), (OPTION_NONE_TAG, AlgebraicType::unit())])
307 }
308
309 pub fn array(ty: Self) -> Self {
311 ArrayType { elem_ty: Box::new(ty) }.into()
312 }
313
314 pub fn identity() -> Self {
316 AlgebraicType::product([(IDENTITY_TAG, AlgebraicType::U256)])
317 }
318
319 pub fn connection_id() -> Self {
321 AlgebraicType::product([(CONNECTION_ID_TAG, AlgebraicType::U128)])
322 }
323
324 pub fn timestamp() -> Self {
326 AlgebraicType::product([(TIMESTAMP_TAG, AlgebraicType::I64)])
327 }
328
329 pub fn time_duration() -> Self {
331 AlgebraicType::product([(TIME_DURATION_TAG, AlgebraicType::I64)])
332 }
333
334 pub fn simple_enum<'a>(var_names: impl Iterator<Item = &'a str>) -> Self {
336 Self::sum(var_names.into_iter().map(SumTypeVariant::unit).collect::<Box<[_]>>())
337 }
338
339 pub fn as_value(&self) -> AlgebraicValue {
340 value_serialize(self)
341 }
342
343 pub fn from_value(value: &AlgebraicValue) -> Result<Self, ValueDeserializeError> {
344 Self::deserialize(ValueDeserializer::from_ref(value))
345 }
346
347 #[inline]
348 pub fn min_value(&self) -> Option<AlgebraicValue> {
350 match *self {
351 Self::I8 => Some(i8::MIN.into()),
352 Self::U8 => Some(u8::MIN.into()),
353 Self::I16 => Some(i16::MIN.into()),
354 Self::U16 => Some(u16::MIN.into()),
355 Self::I32 => Some(i32::MIN.into()),
356 Self::U32 => Some(u32::MIN.into()),
357 Self::I64 => Some(i64::MIN.into()),
358 Self::U64 => Some(u64::MIN.into()),
359 Self::I128 => Some(i128::MIN.into()),
360 Self::U128 => Some(u128::MIN.into()),
361 Self::I256 => Some(i256::MIN.into()),
362 Self::U256 => Some(u256::MIN.into()),
363 Self::F32 => Some(f32::MIN.into()),
364 Self::F64 => Some(f64::MIN.into()),
365 _ => None,
366 }
367 }
368
369 #[inline]
370 pub fn max_value(&self) -> Option<AlgebraicValue> {
372 match *self {
373 Self::I8 => Some(i8::MAX.into()),
374 Self::U8 => Some(u8::MAX.into()),
375 Self::I16 => Some(i16::MAX.into()),
376 Self::U16 => Some(u16::MAX.into()),
377 Self::I32 => Some(i32::MAX.into()),
378 Self::U32 => Some(u32::MAX.into()),
379 Self::I64 => Some(i64::MAX.into()),
380 Self::U64 => Some(u64::MAX.into()),
381 Self::I128 => Some(i128::MAX.into()),
382 Self::U128 => Some(u128::MAX.into()),
383 Self::I256 => Some(i256::MAX.into()),
384 Self::U256 => Some(u256::MAX.into()),
385 Self::F32 => Some(f32::MAX.into()),
386 Self::F64 => Some(f64::MAX.into()),
387 _ => None,
388 }
389 }
390
391 pub fn is_special(&self) -> bool {
395 match self {
396 AlgebraicType::Product(product) => product.is_special(),
397 AlgebraicType::Sum(sum) => sum.is_special(),
398 _ => false,
399 }
400 }
401
402 pub fn is_valid_for_client_type_definition(&self) -> bool {
411 if self.is_special() {
413 return false;
414 }
415 match self {
416 AlgebraicType::Sum(sum) => sum
417 .variants
418 .iter()
419 .all(|variant| variant.algebraic_type.is_valid_for_client_type_use()),
420 AlgebraicType::Product(product) => product
421 .elements
422 .iter()
423 .all(|elem| elem.algebraic_type.is_valid_for_client_type_use()),
424 _ => false,
425 }
426 }
427
428 pub fn is_valid_for_client_type_use(&self) -> bool {
440 match self {
441 AlgebraicType::Sum(sum) => {
442 if let Some(wrapped) = sum.as_option() {
443 wrapped.is_valid_for_client_type_use()
444 } else {
445 sum.is_special() || sum.is_empty()
446 }
447 }
448 AlgebraicType::Product(product) => product.is_special() || product.is_unit(),
449 AlgebraicType::Array(array) => array.elem_ty.is_valid_for_client_type_use(),
450 AlgebraicType::Ref(_) => true,
451 _ => true,
452 }
453 }
454
455 pub fn type_check(&self, value: &AlgebraicValue, typespace: &Typespace) -> bool {
456 match (self, value) {
457 (_, AlgebraicValue::Min | AlgebraicValue::Max) => true,
458 (AlgebraicType::Ref(r), _) => {
459 if let Some(resolved_ty) = typespace.get(*r) {
460 resolved_ty.type_check(value, typespace)
461 } else {
462 false
463 }
464 }
465 (AlgebraicType::Sum(sum_ty), AlgebraicValue::Sum(sv)) => sum_ty.type_check(sv, typespace),
466 (AlgebraicType::Product(product_ty), AlgebraicValue::Product(pv)) => product_ty.type_check(pv, typespace),
467 (AlgebraicType::Array(array_ty), AlgebraicValue::Array(arr)) => array_ty.type_check(arr, typespace),
468
469 (AlgebraicType::String, AlgebraicValue::String(_))
470 | (AlgebraicType::Bool, AlgebraicValue::Bool(_))
471 | (AlgebraicType::I8, AlgebraicValue::I8(_))
472 | (AlgebraicType::U8, AlgebraicValue::U8(_))
473 | (AlgebraicType::I16, AlgebraicValue::I16(_))
474 | (AlgebraicType::U16, AlgebraicValue::U16(_))
475 | (AlgebraicType::I32, AlgebraicValue::I32(_))
476 | (AlgebraicType::U32, AlgebraicValue::U32(_))
477 | (AlgebraicType::I64, AlgebraicValue::I64(_))
478 | (AlgebraicType::U64, AlgebraicValue::U64(_))
479 | (AlgebraicType::I128, AlgebraicValue::I128(_))
480 | (AlgebraicType::U128, AlgebraicValue::U128(_))
481 | (AlgebraicType::I256, AlgebraicValue::I256(_))
482 | (AlgebraicType::U256, AlgebraicValue::U256(_))
483 | (AlgebraicType::F32, AlgebraicValue::F32(_))
484 | (AlgebraicType::F64, AlgebraicValue::F64(_)) => true,
485 _ => false,
486 }
487 }
488}
489#[cfg(test)]
490mod tests {
491 use super::AlgebraicType;
492 use crate::meta_type::MetaType;
493 use crate::satn::Satn;
494 use crate::{
495 algebraic_type::fmt::fmt_algebraic_type, algebraic_type::map_notation::fmt_algebraic_type as fmt_map,
496 algebraic_type_ref::AlgebraicTypeRef, typespace::Typespace,
497 };
498 use crate::{product, AlgebraicValue, ValueWithType, WithTypespace};
499
500 #[test]
501 fn never() {
502 assert_eq!("(|)", fmt_algebraic_type(&AlgebraicType::never()).to_string());
503 }
504
505 #[test]
506 fn never_map() {
507 assert_eq!("{ ty_: Sum }", fmt_map(&AlgebraicType::never()).to_string());
508 }
509
510 #[test]
511 fn unit() {
512 assert_eq!("()", fmt_algebraic_type(&AlgebraicType::unit()).to_string());
513 }
514
515 #[test]
516 fn unit_map() {
517 assert_eq!("{ ty_: Product }", fmt_map(&AlgebraicType::unit()).to_string());
518 }
519
520 #[test]
521 fn primitive() {
522 assert_eq!("U8", fmt_algebraic_type(&AlgebraicType::U8).to_string());
523 }
524
525 #[test]
526 fn primitive_map() {
527 assert_eq!("{ ty_: U8 }", fmt_map(&AlgebraicType::U8).to_string());
528 }
529
530 #[test]
531 fn option() {
532 let option = AlgebraicType::option(AlgebraicType::never());
533 assert_eq!("(some: (|) | none: ())", fmt_algebraic_type(&option).to_string());
534 }
535
536 #[test]
537 fn option_map() {
538 let option = AlgebraicType::option(AlgebraicType::never());
539 assert_eq!(
540 "{ ty_: Sum, some: { ty_: Sum }, none: { ty_: Product } }",
541 fmt_map(&option).to_string()
542 );
543 }
544
545 #[test]
546 fn algebraic_type() {
547 let algebraic_type = AlgebraicType::meta_type();
548 assert_eq!(
549 "(\
550 ref: U32 \
551 | sum: (variants: Array<(\
552 name: (some: String | none: ()), \
553 algebraic_type: &0\
554 )>) \
555 | product: (elements: Array<(\
556 name: (some: String | none: ()), \
557 algebraic_type: &0\
558 )>) \
559 | array: &0 \
560 | string: () \
561 | bool: () \
562 | i8: () | u8: () \
563 | i16: () | u16: () \
564 | i32: () | u32: () \
565 | i64: () | u64: () \
566 | i128: () | u128: () \
567 | i256: () | u256: () \
568 | f32: () | f64: ()\
569 )",
570 fmt_algebraic_type(&algebraic_type).to_string()
571 );
572 }
573
574 #[test]
575 fn algebraic_type_map() {
576 let algebraic_type = AlgebraicType::meta_type();
577 assert_eq!(
578 "{ \
579 ty_: Sum, \
580 ref: { ty_: U32 }, \
581 sum: { \
582 ty_: Product, \
583 variants: { \
584 ty_: Array, \
585 0: { \
586 ty_: Product, \
587 name: { ty_: Sum, some: { ty_: String }, none: { ty_: Product } }, \
588 algebraic_type: { ty_: Ref, 0: 0 } \
589 } \
590 } \
591 }, \
592 product: { \
593 ty_: Product, \
594 elements: { \
595 ty_: Array, \
596 0: { \
597 ty_: Product, \
598 name: { ty_: Sum, some: { ty_: String }, none: { ty_: Product } }, \
599 algebraic_type: { ty_: Ref, 0: 0 } \
600 } \
601 } \
602 }, \
603 array: { ty_: Ref, 0: 0 }, \
604 string: { ty_: Product }, \
605 bool: { ty_: Product }, \
606 i8: { ty_: Product }, u8: { ty_: Product }, \
607 i16: { ty_: Product }, u16: { ty_: Product }, \
608 i32: { ty_: Product }, u32: { ty_: Product }, \
609 i64: { ty_: Product }, u64: { ty_: Product }, \
610 i128: { ty_: Product }, u128: { ty_: Product }, \
611 i256: { ty_: Product }, u256: { ty_: Product }, \
612 f32: { ty_: Product }, f64: { ty_: Product } \
613 }",
614 fmt_map(&algebraic_type).to_string()
615 );
616 }
617
618 #[test]
619 fn nested_products_and_sums() {
620 let builtin = AlgebraicType::U8;
621 let product = AlgebraicType::product([("thing", AlgebraicType::U8)]);
622 let sum = AlgebraicType::sum([builtin.clone(), builtin.clone(), product]);
623 let next = AlgebraicType::product([
624 (Some("test"), builtin.clone()),
625 (None, sum),
626 (None, builtin),
627 (Some("never"), AlgebraicType::never()),
628 ]);
629 assert_eq!(
630 "(test: U8, 1: (U8 | U8 | (thing: U8)), 2: U8, never: (|))",
631 fmt_algebraic_type(&next).to_string()
632 );
633 }
634
635 fn in_space<'a, T: crate::Value>(ts: &'a Typespace, ty: &'a T::Type, val: &'a T) -> ValueWithType<'a, T> {
636 WithTypespace::new(ts, ty).with_value(val)
637 }
638
639 #[test]
640 fn option_as_value() {
641 let option = AlgebraicType::option(AlgebraicType::never());
642 let algebraic_type = AlgebraicType::meta_type();
643 let typespace = Typespace::new(vec![algebraic_type]);
644 let at_ref = AlgebraicType::Ref(AlgebraicTypeRef(0));
645 assert_eq!(
646 r#"(sum = (variants = [(name = (some = "some"), algebraic_type = (sum = (variants = []))), (name = (some = "none"), algebraic_type = (product = (elements = [])))]))"#,
647 in_space(&typespace, &at_ref, &option.as_value()).to_satn()
648 );
649 }
650
651 #[test]
652 fn algebraic_type_as_value() {
653 let algebraic_type = AlgebraicType::meta_type();
654 let typespace = Typespace::new(vec![algebraic_type.clone()]);
655 let at_ref = AlgebraicType::Ref(AlgebraicTypeRef(0));
656
657 let ref0 = "algebraic_type = (ref = 0)";
658 let unit = "algebraic_type = (product = (elements = []))";
659 let aggr_elems_ty = format!(
660 "algebraic_type = (array = (product = (elements = [\
661 (\
662 name = (some = \"name\"), \
663 algebraic_type = (sum = (variants = [\
664 (name = (some = \"some\"), algebraic_type = (string = ())), \
665 (name = (some = \"none\"), {unit})\
666 ]))\
667 ), \
668 (name = (some = \"algebraic_type\"), {ref0})\
669 ])))"
670 );
671
672 assert_eq!(
673 format!(
674 "(\
675 sum = (\
676 variants = [\
677 (name = (some = \"ref\"), algebraic_type = (u32 = ())), \
678 (\
679 name = (some = \"sum\"), \
680 algebraic_type = (product = (elements = [\
681 (name = (some = \"variants\"), {aggr_elems_ty})\
682 ]))\
683 ), \
684 (\
685 name = (some = \"product\"), \
686 algebraic_type = (product = (elements = [\
687 (name = (some = \"elements\"), {aggr_elems_ty})\
688 ]))\
689 ), \
690 (name = (some = \"array\"), {ref0}), \
691 (name = (some = \"string\"), {unit}), \
692 (name = (some = \"bool\"), {unit}), \
693 (name = (some = \"i8\"), {unit}), \
694 (name = (some = \"u8\"), {unit}), \
695 (name = (some = \"i16\"), {unit}), \
696 (name = (some = \"u16\"), {unit}), \
697 (name = (some = \"i32\"), {unit}), \
698 (name = (some = \"u32\"), {unit}), \
699 (name = (some = \"i64\"), {unit}), \
700 (name = (some = \"u64\"), {unit}), \
701 (name = (some = \"i128\"), {unit}), \
702 (name = (some = \"u128\"), {unit}), \
703 (name = (some = \"i256\"), {unit}), \
704 (name = (some = \"u256\"), {unit}), \
705 (name = (some = \"f32\"), {unit}), \
706 (name = (some = \"f64\"), {unit})\
707 ]\
708 )\
709 )"
710 ),
711 in_space(&typespace, &at_ref, &algebraic_type.as_value()).to_satn()
712 );
713 }
714
715 #[test]
716 fn option_from_value() {
717 let option = AlgebraicType::option(AlgebraicType::never());
718 AlgebraicType::from_value(&option.as_value()).expect("No errors.");
719 }
720
721 #[test]
722 fn builtin_from_value() {
723 let u8 = AlgebraicType::U8;
724 AlgebraicType::from_value(&u8.as_value()).expect("No errors.");
725 }
726
727 #[test]
728 fn algebraic_type_from_value() {
729 let algebraic_type = AlgebraicType::meta_type();
730 AlgebraicType::from_value(&algebraic_type.as_value()).expect("No errors.");
731 }
732
733 #[test]
734 fn special_types_are_special() {
735 assert!(AlgebraicType::identity().is_identity());
736 assert!(AlgebraicType::identity().is_special());
737 assert!(AlgebraicType::connection_id().is_connection_id());
738 assert!(AlgebraicType::connection_id().is_special());
739 assert!(AlgebraicType::timestamp().is_timestamp());
740 assert!(AlgebraicType::timestamp().is_special());
741 assert!(AlgebraicType::time_duration().is_special());
742 assert!(AlgebraicType::time_duration().is_time_duration());
743 }
744
745 #[test]
746 fn type_check() {
747 let av = AlgebraicValue::sum(1, AlgebraicValue::from(product![0u16, 1u32]));
748 let at = AlgebraicType::sum([
749 ("a", AlgebraicType::U8),
750 ("b", AlgebraicType::product([AlgebraicType::U16, AlgebraicType::U32])),
751 ]);
752
753 at.type_check(&av, Typespace::EMPTY);
754 }
755}