spacetimedb_lib/db/
default_element_ordering.rs

1//! This module defines the default ordering for fields of a `ProductType` and variants of a `SumType`.
2//!
3//! - In ABI version 8, the default ordering was not applied.
4//! - In ABI version 9, the default ordering is applied to all types in a spacetime module, unless they explicitly declare a custom ordering.
5
6use spacetimedb_sats::{ProductType, ProductTypeElement, SumType, SumTypeVariant};
7
8/// A label for a field of a `ProductType` or a variant of a `SumType`.
9///
10/// The ordering on this type defines the default ordering for the fields of a `ProductType` and the variants of a `SumType`.
11#[derive(PartialEq, Eq, PartialOrd, Ord)]
12pub enum ElementLabel<'a> {
13    /// An unnamed field with a position.
14    /// The unnamed fields in a type do not necessarily have contiguous positions.
15    Unnamed(usize),
16    /// A named field.
17    /// Names are required to be unique within the product type.
18    Named(&'a str),
19}
20
21impl<'a> From<(usize, &'a ProductTypeElement)> for ElementLabel<'a> {
22    fn from((i, element): (usize, &'a ProductTypeElement)) -> Self {
23        match &element.name {
24            Some(name) => ElementLabel::Named(&name[..]),
25            None => ElementLabel::Unnamed(i),
26        }
27    }
28}
29impl<'a> From<(usize, &'a SumTypeVariant)> for ElementLabel<'a> {
30    fn from((i, element): (usize, &'a SumTypeVariant)) -> Self {
31        match &element.name {
32            Some(name) => ElementLabel::Named(&name[..]),
33            None => ElementLabel::Unnamed(i),
34        }
35    }
36}
37
38/// Checks if a sum type has the default ordering.
39///
40/// Not a recursive check.
41pub fn sum_type_has_default_ordering(ty: &SumType) -> bool {
42    ty.variants.iter().enumerate().map(ElementLabel::from).is_sorted()
43}
44
45/// Checks if a product type has the default ordering.
46///
47/// Not a recursive check.
48pub fn product_type_has_default_ordering(ty: &ProductType) -> bool {
49    ty.elements.iter().enumerate().map(ElementLabel::from).is_sorted()
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55
56    #[test]
57    fn test_element_label_comparison() {
58        let a = ElementLabel::Unnamed(0);
59        let b = ElementLabel::Unnamed(2);
60        let c = ElementLabel::Named("apples");
61        let d = ElementLabel::Named("oranges");
62        let e = ElementLabel::Named("oranges_tomorrow");
63
64        assert!(a == a);
65        assert!(a < b);
66        assert!(a < c);
67        assert!(a < d);
68        assert!(a < e);
69
70        assert!(b > a);
71        assert!(b == b);
72        assert!(b < c);
73        assert!(b < d);
74        assert!(b < e);
75
76        assert!(c > a);
77        assert!(c > b);
78        assert!(c == c);
79        assert!(c < d);
80        assert!(c < e);
81
82        assert!(d > a);
83        assert!(d > b);
84        assert!(d > c);
85        assert!(d == d);
86        assert!(d < e);
87
88        assert!(e > a);
89        assert!(e > b);
90        assert!(e > c);
91        assert!(e > d);
92        assert!(e == e);
93    }
94}