1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use std::any::TypeId;
use std::ops::{Index, IndexMut};

use crate::algebraic_type::AlgebraicType;
use crate::algebraic_type_ref::AlgebraicTypeRef;
use crate::{de::Deserialize, ser::Serialize};
use crate::{ArrayType, BuiltinType, TypeInSpace};

#[derive(Debug, Clone, Deserialize, Serialize)]
#[sats(crate = crate)]
pub struct Typespace {
    pub types: Vec<AlgebraicType>,
}

impl Default for Typespace {
    fn default() -> Self {
        Self::new(Vec::new())
    }
}

impl Index<AlgebraicTypeRef> for Typespace {
    type Output = AlgebraicType;

    fn index(&self, index: AlgebraicTypeRef) -> &Self::Output {
        &self.types[index.0 as usize]
    }
}
impl IndexMut<AlgebraicTypeRef> for Typespace {
    fn index_mut(&mut self, index: AlgebraicTypeRef) -> &mut Self::Output {
        &mut self.types[index.0 as usize]
    }
}

impl Typespace {
    pub const fn new(types: Vec<AlgebraicType>) -> Self {
        Self { types }
    }

    pub fn get(&self, r: AlgebraicTypeRef) -> Option<&AlgebraicType> {
        self.types.get(r.0 as usize)
    }

    /// Inserts an `AlgebraicType` into the typespace
    /// and returns an `AlgebraicTypeRef` that refers to the inserted `AlgebraicType`.
    ///
    /// This allows for self referential,
    /// recursive or other complex types to be declared in the typespace.
    ///
    /// You can also use this to later change the meaning of the returned `AlgebraicTypeRef`
    /// when you cannot provide the full definition of the type yet.
    pub fn add(&mut self, ty: AlgebraicType) -> AlgebraicTypeRef {
        let i = self.types.len();
        self.types.push(ty);
        AlgebraicTypeRef(i as u32)
    }

    pub fn with_type<'a, T: ?Sized>(&'a self, ty: &'a T) -> TypeInSpace<'a, T> {
        TypeInSpace::new(self, ty)
    }
}

pub trait SpacetimeType {
    fn make_type<S: TypespaceBuilder>(typespace: &mut S) -> AlgebraicType;
}

pub use spacetimedb_bindings_macro::SpacetimeType;

pub trait TypespaceBuilder {
    fn add(
        &mut self,
        typeid: TypeId,
        name: Option<&'static str>,
        make_ty: impl FnOnce(&mut Self) -> AlgebraicType,
    ) -> AlgebraicType;
}

macro_rules! impl_primitives {
    ($($t:ty => $x:ident,)*) => {
        $(
            impl SpacetimeType for $t {
                fn make_type<S: TypespaceBuilder>(_ts: &mut S) -> AlgebraicType {
                    AlgebraicType::$x
                }
            }
        )*
    };
}

impl_primitives! {
    bool => Bool,
    u8 => U8,
    i8 => I8,
    u16 => U16,
    i16 => I16,
    u32 => U32,
    i32 => I32,
    u64 => U64,
    i64 => I64,
    u128 => U128,
    i128 => I128,
    f32 => F32,
    f64 => F64,
    String => String,
}

impl SpacetimeType for () {
    fn make_type<S: TypespaceBuilder>(_ts: &mut S) -> AlgebraicType {
        AlgebraicType::UNIT_TYPE
    }
}
impl SpacetimeType for &str {
    fn make_type<S: TypespaceBuilder>(_ts: &mut S) -> AlgebraicType {
        AlgebraicType::String
    }
}

impl<T: SpacetimeType> SpacetimeType for Vec<T> {
    fn make_type<S: TypespaceBuilder>(typespace: &mut S) -> AlgebraicType {
        AlgebraicType::Builtin(BuiltinType::Array(ArrayType {
            elem_ty: Box::new(T::make_type(typespace)),
        }))
    }
}

impl<T: SpacetimeType> SpacetimeType for Option<T> {
    fn make_type<S: TypespaceBuilder>(typespace: &mut S) -> AlgebraicType {
        AlgebraicType::make_option_type(T::make_type(typespace))
    }
}