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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
pub use spacetimedb_sats::buffer;
pub mod data_key;
pub use spacetimedb_sats::de;
pub mod error;
pub mod hash;
#[cfg(feature = "serde")]
pub mod name;
pub mod primary_key;
pub use spacetimedb_sats::ser;
pub mod type_def {
    pub use spacetimedb_sats::{
        AlgebraicType as TypeDef, ProductType as TupleDef, ProductTypeElement as ElementDef, SumType as EnumDef,
    };
}
pub mod type_value {
    pub use spacetimedb_sats::{AlgebraicValue as TypeValue, ProductValue as TupleValue};
}
#[cfg(feature = "serde")]
pub mod recovery;
pub mod version;
pub use spacetimedb_sats::bsatn;

pub use data_key::DataKey;
pub use hash::Hash;
pub use primary_key::PrimaryKey;
pub use type_def::*;
pub use type_value::{TupleValue, TypeValue};

pub use spacetimedb_sats as sats;

pub const SCHEMA_FORMAT_VERSION: u16 = 1;

#[macro_export]
macro_rules! abi_versions {
    ($mac:ident) => {
        $mac! {
            V0 => (0, 0),
            V0_3_3 => (1, 1),
        }
    };
}

extern crate self as spacetimedb_lib;

#[derive(Debug, Clone, de::Deserialize, ser::Serialize)]
pub struct TableDef {
    pub name: String,
    pub data: sats::AlgebraicTypeRef,
    /// must be sorted!
    pub unique_columns: Vec<u8>,
}

#[derive(Debug, Clone, de::Deserialize, ser::Serialize)]
pub struct ReducerDef {
    pub name: Option<Box<str>>,
    pub args: Vec<ElementDef>,
}

impl ReducerDef {
    pub fn encode(&self, writer: &mut impl buffer::BufWriter) {
        bsatn::to_writer(writer, self).unwrap()
    }

    pub fn serialize_args<'a>(ty: sats::TypeInSpace<'a, Self>, value: &'a TupleValue) -> impl ser::Serialize + 'a {
        ReducerArgsWithSchema { value, ty }
    }

    pub fn deserialize(
        ty: sats::TypeInSpace<'_, Self>,
    ) -> impl for<'de> de::DeserializeSeed<'de, Output = TupleValue> + '_ {
        ReducerDeserialize(ty)
    }
}

struct ReducerDeserialize<'a>(sats::TypeInSpace<'a, ReducerDef>);

impl<'de> de::DeserializeSeed<'de> for ReducerDeserialize<'_> {
    type Output = TupleValue;

    fn deserialize<D: de::Deserializer<'de>>(self, deserializer: D) -> Result<Self::Output, D::Error> {
        deserializer.deserialize_product(self)
    }
}

impl<'de> de::ProductVisitor<'de> for ReducerDeserialize<'_> {
    type Output = TupleValue;

    fn product_name(&self) -> Option<&str> {
        self.0.ty().name.as_deref()
    }
    fn product_len(&self) -> usize {
        self.0.ty().args.len()
    }
    fn product_kind(&self) -> de::ProductKind {
        de::ProductKind::ReducerArgs
    }

    fn visit_seq_product<A: de::SeqProductAccess<'de>>(self, tup: A) -> Result<Self::Output, A::Error> {
        de::visit_seq_product(self.0.map(|r| &*r.args), &self, tup)
    }

    fn visit_named_product<A: de::NamedProductAccess<'de>>(self, tup: A) -> Result<Self::Output, A::Error> {
        de::visit_named_product(self.0.map(|r| &*r.args), &self, tup)
    }
}

struct ReducerArgsWithSchema<'a> {
    value: &'a TupleValue,
    ty: sats::TypeInSpace<'a, ReducerDef>,
}

impl ser::Serialize for ReducerArgsWithSchema<'_> {
    fn serialize<S: ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        use itertools::Itertools;
        use ser::SerializeSeqProduct;
        let mut seq = serializer.serialize_seq_product(self.value.elements.len())?;
        for (value, elem) in self.value.elements.iter().zip_eq(&self.ty.ty().args) {
            seq.serialize_element(&self.ty.with(&elem.algebraic_type).with_value(value))?;
        }
        seq.end()
    }
}

#[derive(Debug, Clone, enum_as_inner::EnumAsInner)]
pub enum EntityDef {
    Table(TableDef),
    Reducer(ReducerDef),
}

#[derive(Debug, Clone)]
pub enum ModuleItemDef {
    Entity(EntityDef),
    TypeAlias(sats::AlgebraicTypeRef),
}

// use std::fmt;
//
// #[cfg(feature = "serde")]
// use serde::de::Expected as SerdeExpected;
// #[cfg(not(feature = "serde"))]
// use Sized as SerdeExpected;
// fn fmt_fn(f: impl Fn(&mut fmt::Formatter) -> fmt::Result) -> impl fmt::Display + fmt::Debug + SerdeExpected {
//     struct FDisplay<F>(F);
//     impl<F: Fn(&mut fmt::Formatter) -> fmt::Result> fmt::Display for FDisplay<F> {
//         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
//             (self.0)(f)
//         }
//     }
//     impl<F: Fn(&mut fmt::Formatter) -> fmt::Result> fmt::Debug for FDisplay<F> {
//         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
//             (self.0)(f)
//         }
//     }
//     #[cfg(feature = "serde")]
//     impl<F: Fn(&mut fmt::Formatter) -> fmt::Result> serde::de::Expected for FDisplay<F> {
//         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
//             (self.0)(f)
//         }
//     }
//     FDisplay(f)
// }