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::{i256, u256};
11use crate::{AlgebraicTypeRef, AlgebraicValue, ArrayType, ProductType, SpacetimeType, SumType, SumTypeVariant};
12use derive_more::From;
13use enum_as_inner::EnumAsInner;
14
15#[derive(EnumAsInner, Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, SpacetimeType, From)]
22#[sats(crate = crate)]
23pub enum AlgebraicType {
24 Ref(AlgebraicTypeRef),
30 Sum(SumType),
57 Product(ProductType),
83 Array(ArrayType),
86 String,
92 Bool,
94 I8,
96 U8,
98 I16,
100 U16,
102 I32,
104 U32,
106 I64,
108 U64,
110 I128,
112 U128,
114 I256,
116 U256,
118 F32,
120 F64,
122}
123
124impl MetaType for AlgebraicType {
125 fn meta_type() -> Self {
131 AlgebraicType::sum([
132 ("ref", AlgebraicTypeRef::meta_type()),
133 ("sum", SumType::meta_type()),
134 ("product", ProductType::meta_type()),
135 ("array", ArrayType::meta_type()),
136 ("string", AlgebraicType::unit()),
137 ("bool", AlgebraicType::unit()),
138 ("i8", AlgebraicType::unit()),
139 ("u8", AlgebraicType::unit()),
140 ("i16", AlgebraicType::unit()),
141 ("u16", AlgebraicType::unit()),
142 ("i32", AlgebraicType::unit()),
143 ("u32", AlgebraicType::unit()),
144 ("i64", AlgebraicType::unit()),
145 ("u64", AlgebraicType::unit()),
146 ("i128", AlgebraicType::unit()),
147 ("u128", AlgebraicType::unit()),
148 ("i256", AlgebraicType::unit()),
149 ("u256", AlgebraicType::unit()),
150 ("f32", AlgebraicType::unit()),
151 ("f64", AlgebraicType::unit()),
152 ])
153 }
154}
155
156impl Default for AlgebraicType {
158 fn default() -> Self {
159 Self::ZERO_REF
160 }
161}
162
163impl AlgebraicType {
164 pub const ZERO_REF: Self = Self::Ref(AlgebraicTypeRef(0));
166
167 pub fn is_connection_id(&self) -> bool {
171 matches!(self, Self::Product(p) if p.is_connection_id())
172 }
173
174 pub fn is_identity(&self) -> bool {
176 matches!(self, Self::Product(p) if p.is_identity())
177 }
178
179 pub fn is_timestamp(&self) -> bool {
181 matches!(self, Self::Product(p) if p.is_timestamp())
182 }
183
184 pub fn is_time_duration(&self) -> bool {
186 matches!(self, Self::Product(p) if p.is_time_duration())
187 }
188
189 pub fn is_schedule_at(&self) -> bool {
191 matches!(self, Self::Sum(p) if p.is_schedule_at())
192 }
193
194 pub fn is_unit(&self) -> bool {
196 matches!(self, Self::Product(p) if p.is_unit())
197 }
198
199 pub fn is_never(&self) -> bool {
201 matches!(self, Self::Sum(p) if p.is_empty())
202 }
203
204 pub fn as_option(&self) -> Option<&AlgebraicType> {
207 self.as_sum()?.as_option()
208 }
209
210 pub fn is_scalar_or_string(&self) -> bool {
212 self.is_scalar() || self.is_string()
213 }
214
215 pub fn is_scalar(&self) -> bool {
222 self.is_bool() || self.is_integer() || self.is_float()
223 }
224
225 pub fn is_signed(&self) -> bool {
227 matches!(
228 self,
229 Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128 | Self::I256
230 )
231 }
232
233 pub fn is_unsigned(&self) -> bool {
235 matches!(
236 self,
237 Self::U8 | Self::U16 | Self::U32 | Self::U64 | Self::U128 | Self::U256
238 )
239 }
240
241 pub fn is_integer(&self) -> bool {
243 self.is_signed() || self.is_unsigned()
244 }
245
246 pub fn is_float(&self) -> bool {
248 matches!(self, Self::F32 | Self::F64)
249 }
250
251 pub fn unit() -> Self {
253 let fs: [AlgebraicType; 0] = [];
254 Self::product(fs)
255 }
256
257 pub fn never() -> Self {
259 let vs: [SumTypeVariant; 0] = [];
260 Self::sum(vs)
261 }
262
263 pub fn bytes() -> Self {
265 Self::array(Self::U8)
266 }
267
268 pub fn is_bytes(&self) -> bool {
270 self.as_array().is_some_and(|ty| ty.elem_ty.is_u8())
271 }
272
273 pub fn contains_refs(&self) -> bool {
275 match self {
276 AlgebraicType::Ref(_) => true,
277 AlgebraicType::Product(ProductType { elements }) => {
278 elements.iter().any(|elem| elem.algebraic_type.contains_refs())
279 }
280 AlgebraicType::Sum(SumType { variants }) => {
281 variants.iter().any(|variant| variant.algebraic_type.contains_refs())
282 }
283 AlgebraicType::Array(array) => array.elem_ty.contains_refs(),
284 _ => false,
285 }
286 }
287
288 pub fn sum<S: Into<SumType>>(sum: S) -> Self {
290 AlgebraicType::Sum(sum.into())
291 }
292
293 pub fn product<P: Into<ProductType>>(prod: P) -> Self {
295 AlgebraicType::Product(prod.into())
296 }
297
298 pub fn option(some_type: Self) -> Self {
300 Self::sum([(OPTION_SOME_TAG, some_type), (OPTION_NONE_TAG, AlgebraicType::unit())])
301 }
302
303 pub fn array(ty: Self) -> Self {
305 ArrayType { elem_ty: Box::new(ty) }.into()
306 }
307
308 pub fn identity() -> Self {
310 AlgebraicType::product([(IDENTITY_TAG, AlgebraicType::U256)])
311 }
312
313 pub fn connection_id() -> Self {
315 AlgebraicType::product([(CONNECTION_ID_TAG, AlgebraicType::U128)])
316 }
317
318 pub fn timestamp() -> Self {
320 AlgebraicType::product([(TIMESTAMP_TAG, AlgebraicType::I64)])
321 }
322
323 pub fn time_duration() -> Self {
325 AlgebraicType::product([(TIME_DURATION_TAG, AlgebraicType::I64)])
326 }
327
328 pub fn simple_enum<'a>(var_names: impl Iterator<Item = &'a str>) -> Self {
330 Self::sum(var_names.into_iter().map(SumTypeVariant::unit).collect::<Box<[_]>>())
331 }
332
333 pub fn as_value(&self) -> AlgebraicValue {
334 value_serialize(self)
335 }
336
337 pub fn from_value(value: &AlgebraicValue) -> Result<Self, ValueDeserializeError> {
338 Self::deserialize(ValueDeserializer::from_ref(value))
339 }
340
341 #[inline]
342 pub fn min_value(&self) -> Option<AlgebraicValue> {
344 match *self {
345 Self::I8 => Some(i8::MIN.into()),
346 Self::U8 => Some(u8::MIN.into()),
347 Self::I16 => Some(i16::MIN.into()),
348 Self::U16 => Some(u16::MIN.into()),
349 Self::I32 => Some(i32::MIN.into()),
350 Self::U32 => Some(u32::MIN.into()),
351 Self::I64 => Some(i64::MIN.into()),
352 Self::U64 => Some(u64::MIN.into()),
353 Self::I128 => Some(i128::MIN.into()),
354 Self::U128 => Some(u128::MIN.into()),
355 Self::I256 => Some(i256::MIN.into()),
356 Self::U256 => Some(u256::MIN.into()),
357 Self::F32 => Some(f32::MIN.into()),
358 Self::F64 => Some(f64::MIN.into()),
359 _ => None,
360 }
361 }
362
363 #[inline]
364 pub fn max_value(&self) -> Option<AlgebraicValue> {
366 match *self {
367 Self::I8 => Some(i8::MAX.into()),
368 Self::U8 => Some(u8::MAX.into()),
369 Self::I16 => Some(i16::MAX.into()),
370 Self::U16 => Some(u16::MAX.into()),
371 Self::I32 => Some(i32::MAX.into()),
372 Self::U32 => Some(u32::MAX.into()),
373 Self::I64 => Some(i64::MAX.into()),
374 Self::U64 => Some(u64::MAX.into()),
375 Self::I128 => Some(i128::MAX.into()),
376 Self::U128 => Some(u128::MAX.into()),
377 Self::I256 => Some(i256::MAX.into()),
378 Self::U256 => Some(u256::MAX.into()),
379 Self::F32 => Some(f32::MAX.into()),
380 Self::F64 => Some(f64::MAX.into()),
381 _ => None,
382 }
383 }
384
385 pub fn is_special(&self) -> bool {
389 match self {
390 AlgebraicType::Product(product) => product.is_special(),
391 AlgebraicType::Sum(sum) => sum.is_special(),
392 _ => false,
393 }
394 }
395
396 pub fn is_valid_for_client_type_definition(&self) -> bool {
405 if self.is_special() {
407 return false;
408 }
409 match self {
410 AlgebraicType::Sum(sum) => sum
411 .variants
412 .iter()
413 .all(|variant| variant.algebraic_type.is_valid_for_client_type_use()),
414 AlgebraicType::Product(product) => product
415 .elements
416 .iter()
417 .all(|elem| elem.algebraic_type.is_valid_for_client_type_use()),
418 _ => false,
419 }
420 }
421
422 pub fn is_valid_for_client_type_use(&self) -> bool {
434 match self {
435 AlgebraicType::Sum(sum) => {
436 if let Some(wrapped) = sum.as_option() {
437 wrapped.is_valid_for_client_type_use()
438 } else {
439 sum.is_special() || sum.is_empty()
440 }
441 }
442 AlgebraicType::Product(product) => product.is_special() || product.is_unit(),
443 AlgebraicType::Array(array) => array.elem_ty.is_valid_for_client_type_use(),
444 AlgebraicType::Ref(_) => true,
445 _ => true,
446 }
447 }
448}
449
450#[cfg(test)]
451mod tests {
452 use super::AlgebraicType;
453 use crate::meta_type::MetaType;
454 use crate::satn::Satn;
455 use crate::{
456 algebraic_type::fmt::fmt_algebraic_type, algebraic_type::map_notation::fmt_algebraic_type as fmt_map,
457 algebraic_type_ref::AlgebraicTypeRef, typespace::Typespace,
458 };
459 use crate::{ValueWithType, WithTypespace};
460
461 #[test]
462 fn never() {
463 assert_eq!("(|)", fmt_algebraic_type(&AlgebraicType::never()).to_string());
464 }
465
466 #[test]
467 fn never_map() {
468 assert_eq!("{ ty_: Sum }", fmt_map(&AlgebraicType::never()).to_string());
469 }
470
471 #[test]
472 fn unit() {
473 assert_eq!("()", fmt_algebraic_type(&AlgebraicType::unit()).to_string());
474 }
475
476 #[test]
477 fn unit_map() {
478 assert_eq!("{ ty_: Product }", fmt_map(&AlgebraicType::unit()).to_string());
479 }
480
481 #[test]
482 fn primitive() {
483 assert_eq!("U8", fmt_algebraic_type(&AlgebraicType::U8).to_string());
484 }
485
486 #[test]
487 fn primitive_map() {
488 assert_eq!("{ ty_: U8 }", fmt_map(&AlgebraicType::U8).to_string());
489 }
490
491 #[test]
492 fn option() {
493 let option = AlgebraicType::option(AlgebraicType::never());
494 assert_eq!("(some: (|) | none: ())", fmt_algebraic_type(&option).to_string());
495 }
496
497 #[test]
498 fn option_map() {
499 let option = AlgebraicType::option(AlgebraicType::never());
500 assert_eq!(
501 "{ ty_: Sum, some: { ty_: Sum }, none: { ty_: Product } }",
502 fmt_map(&option).to_string()
503 );
504 }
505
506 #[test]
507 fn algebraic_type() {
508 let algebraic_type = AlgebraicType::meta_type();
509 assert_eq!(
510 "(\
511 ref: U32 \
512 | sum: (variants: Array<(\
513 name: (some: String | none: ()), \
514 algebraic_type: &0\
515 )>) \
516 | product: (elements: Array<(\
517 name: (some: String | none: ()), \
518 algebraic_type: &0\
519 )>) \
520 | array: &0 \
521 | string: () \
522 | bool: () \
523 | i8: () | u8: () \
524 | i16: () | u16: () \
525 | i32: () | u32: () \
526 | i64: () | u64: () \
527 | i128: () | u128: () \
528 | i256: () | u256: () \
529 | f32: () | f64: ()\
530 )",
531 fmt_algebraic_type(&algebraic_type).to_string()
532 );
533 }
534
535 #[test]
536 fn algebraic_type_map() {
537 let algebraic_type = AlgebraicType::meta_type();
538 assert_eq!(
539 "{ \
540 ty_: Sum, \
541 ref: { ty_: U32 }, \
542 sum: { \
543 ty_: Product, \
544 variants: { \
545 ty_: Array, \
546 0: { \
547 ty_: Product, \
548 name: { ty_: Sum, some: { ty_: String }, none: { ty_: Product } }, \
549 algebraic_type: { ty_: Ref, 0: 0 } \
550 } \
551 } \
552 }, \
553 product: { \
554 ty_: Product, \
555 elements: { \
556 ty_: Array, \
557 0: { \
558 ty_: Product, \
559 name: { ty_: Sum, some: { ty_: String }, none: { ty_: Product } }, \
560 algebraic_type: { ty_: Ref, 0: 0 } \
561 } \
562 } \
563 }, \
564 array: { ty_: Ref, 0: 0 }, \
565 string: { ty_: Product }, \
566 bool: { ty_: Product }, \
567 i8: { ty_: Product }, u8: { ty_: Product }, \
568 i16: { ty_: Product }, u16: { ty_: Product }, \
569 i32: { ty_: Product }, u32: { ty_: Product }, \
570 i64: { ty_: Product }, u64: { ty_: Product }, \
571 i128: { ty_: Product }, u128: { ty_: Product }, \
572 i256: { ty_: Product }, u256: { ty_: Product }, \
573 f32: { ty_: Product }, f64: { ty_: Product } \
574 }",
575 fmt_map(&algebraic_type).to_string()
576 );
577 }
578
579 #[test]
580 fn nested_products_and_sums() {
581 let builtin = AlgebraicType::U8;
582 let product = AlgebraicType::product([("thing", AlgebraicType::U8)]);
583 let sum = AlgebraicType::sum([builtin.clone(), builtin.clone(), product]);
584 let next = AlgebraicType::product([
585 (Some("test"), builtin.clone()),
586 (None, sum),
587 (None, builtin),
588 (Some("never"), AlgebraicType::never()),
589 ]);
590 assert_eq!(
591 "(test: U8, 1: (U8 | U8 | (thing: U8)), 2: U8, never: (|))",
592 fmt_algebraic_type(&next).to_string()
593 );
594 }
595
596 fn in_space<'a, T: crate::Value>(ts: &'a Typespace, ty: &'a T::Type, val: &'a T) -> ValueWithType<'a, T> {
597 WithTypespace::new(ts, ty).with_value(val)
598 }
599
600 #[test]
601 fn option_as_value() {
602 let option = AlgebraicType::option(AlgebraicType::never());
603 let algebraic_type = AlgebraicType::meta_type();
604 let typespace = Typespace::new(vec![algebraic_type]);
605 let at_ref = AlgebraicType::Ref(AlgebraicTypeRef(0));
606 assert_eq!(
607 r#"(sum = (variants = [(name = (some = "some"), algebraic_type = (sum = (variants = []))), (name = (some = "none"), algebraic_type = (product = (elements = [])))]))"#,
608 in_space(&typespace, &at_ref, &option.as_value()).to_satn()
609 );
610 }
611
612 #[test]
613 fn algebraic_type_as_value() {
614 let algebraic_type = AlgebraicType::meta_type();
615 let typespace = Typespace::new(vec![algebraic_type.clone()]);
616 let at_ref = AlgebraicType::Ref(AlgebraicTypeRef(0));
617
618 let ref0 = "algebraic_type = (ref = 0)";
619 let unit = "algebraic_type = (product = (elements = []))";
620 let aggr_elems_ty = format!(
621 "algebraic_type = (array = (product = (elements = [\
622 (\
623 name = (some = \"name\"), \
624 algebraic_type = (sum = (variants = [\
625 (name = (some = \"some\"), algebraic_type = (string = ())), \
626 (name = (some = \"none\"), {unit})\
627 ]))\
628 ), \
629 (name = (some = \"algebraic_type\"), {ref0})\
630 ])))"
631 );
632
633 assert_eq!(
634 format!(
635 "(\
636 sum = (\
637 variants = [\
638 (name = (some = \"ref\"), algebraic_type = (u32 = ())), \
639 (\
640 name = (some = \"sum\"), \
641 algebraic_type = (product = (elements = [\
642 (name = (some = \"variants\"), {aggr_elems_ty})\
643 ]))\
644 ), \
645 (\
646 name = (some = \"product\"), \
647 algebraic_type = (product = (elements = [\
648 (name = (some = \"elements\"), {aggr_elems_ty})\
649 ]))\
650 ), \
651 (name = (some = \"array\"), {ref0}), \
652 (name = (some = \"string\"), {unit}), \
653 (name = (some = \"bool\"), {unit}), \
654 (name = (some = \"i8\"), {unit}), \
655 (name = (some = \"u8\"), {unit}), \
656 (name = (some = \"i16\"), {unit}), \
657 (name = (some = \"u16\"), {unit}), \
658 (name = (some = \"i32\"), {unit}), \
659 (name = (some = \"u32\"), {unit}), \
660 (name = (some = \"i64\"), {unit}), \
661 (name = (some = \"u64\"), {unit}), \
662 (name = (some = \"i128\"), {unit}), \
663 (name = (some = \"u128\"), {unit}), \
664 (name = (some = \"i256\"), {unit}), \
665 (name = (some = \"u256\"), {unit}), \
666 (name = (some = \"f32\"), {unit}), \
667 (name = (some = \"f64\"), {unit})\
668 ]\
669 )\
670 )"
671 ),
672 in_space(&typespace, &at_ref, &algebraic_type.as_value()).to_satn()
673 );
674 }
675
676 #[test]
677 fn option_from_value() {
678 let option = AlgebraicType::option(AlgebraicType::never());
679 AlgebraicType::from_value(&option.as_value()).expect("No errors.");
680 }
681
682 #[test]
683 fn builtin_from_value() {
684 let u8 = AlgebraicType::U8;
685 AlgebraicType::from_value(&u8.as_value()).expect("No errors.");
686 }
687
688 #[test]
689 fn algebraic_type_from_value() {
690 let algebraic_type = AlgebraicType::meta_type();
691 AlgebraicType::from_value(&algebraic_type.as_value()).expect("No errors.");
692 }
693
694 #[test]
695 fn special_types_are_special() {
696 assert!(AlgebraicType::identity().is_identity());
697 assert!(AlgebraicType::identity().is_special());
698 assert!(AlgebraicType::connection_id().is_connection_id());
699 assert!(AlgebraicType::connection_id().is_special());
700 assert!(AlgebraicType::timestamp().is_timestamp());
701 assert!(AlgebraicType::timestamp().is_special());
702 assert!(AlgebraicType::time_duration().is_special());
703 assert!(AlgebraicType::time_duration().is_time_duration());
704 }
705}