Skip to content

Commit

Permalink
Document + Refactor SATS (#66)
Browse files Browse the repository at this point in the history
* Document most of SATS

* sats: simplify Serialize impls

* sats: simplify Deserialize impls

* improve sats::de docs

* document sats::bsatn

* simplify sats fmt/map notation

* value serializer: docs + opt

* docs/refactor sats::algebraic_value::{ser,de}

* sats: document serde conversions

* cargo fmt

* small fixes

* fix tests

* fix serde feature

* sats: address pheobe's review

* fix doc comment

* fix test failure

* Remove unusued import

* Fix a borrowing issue introduced by the merge of master

The definitions of these were tweaked in some way, I think,
such that references to them are no longer automatically 'static?

---------

Co-authored-by: George Kulakowski <george@clockworklabs.io>
  • Loading branch information
Centril and kulakowski authored Jul 27, 2023
1 parent 97ca22d commit c3526ee
Show file tree
Hide file tree
Showing 69 changed files with 2,832 additions and 2,223 deletions.
10 changes: 2 additions & 8 deletions crates/bindings-macro/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,7 @@ pub(crate) fn derive_satstype(ty: &SatsType<'_>, gen_type_alias: bool) -> TokenS
algebraic_type: <#ty as spacetimedb::SpacetimeType>::make_type(__typespace),
})
});
quote!(spacetimedb::sats::AlgebraicType::Product(
spacetimedb::sats::ProductType {
elements: vec![#(#fields),*],
}
))
quote!(spacetimedb::sats::AlgebraicType::product(vec![#(#fields),*]))
}
SatsTypeData::Sum(variants) => {
let unit = syn::Type::Tuple(syn::TypeTuple {
Expand All @@ -154,9 +150,7 @@ pub(crate) fn derive_satstype(ty: &SatsType<'_>, gen_type_alias: bool) -> TokenS
algebraic_type: <#ty as spacetimedb::SpacetimeType>::make_type(__typespace),
})
});
quote!(spacetimedb::sats::AlgebraicType::Sum(spacetimedb::sats::SumType {
variants: vec![#(#variants),*],
}))
quote!(spacetimedb::sats::AlgebraicType::sum(vec![#(#variants),*]))
// todo!()
} // syn::Data::Union(u) => return Err(syn::Error::new(u.union_token.span, "unions not supported")),
};
Expand Down
19 changes: 4 additions & 15 deletions crates/bindings/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ mod timestamp;

use spacetimedb_lib::buffer::{BufReader, BufWriter, Cursor, DecodeError};
pub use spacetimedb_lib::de::{Deserialize, DeserializeOwned};
use spacetimedb_lib::sats::{impl_deserialize, impl_serialize, impl_st};
pub use spacetimedb_lib::ser::Serialize;
use spacetimedb_lib::{bsatn, ColumnIndexAttribute, IndexType, PrimaryKey, ProductType, ProductValue};
use std::cell::RefCell;
Expand Down Expand Up @@ -691,21 +692,9 @@ impl<R> Clone for ScheduleToken<R> {
}
impl<R> Copy for ScheduleToken<R> {}

impl<R> Serialize for ScheduleToken<R> {
fn serialize<S: spacetimedb_lib::ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.id.serialize(serializer)
}
}
impl<'de, R> Deserialize<'de> for ScheduleToken<R> {
fn deserialize<D: spacetimedb_lib::de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
u64::deserialize(deserializer).map(Self::new)
}
}
impl<R> SpacetimeType for ScheduleToken<R> {
fn make_type<S: spacetimedb_lib::sats::typespace::TypespaceBuilder>(_ts: &mut S) -> spacetimedb_lib::AlgebraicType {
spacetimedb_lib::AlgebraicType::U64
}
}
impl_serialize!([R] ScheduleToken<R>, (self, ser) => self.id.serialize(ser));
impl_deserialize!([R] ScheduleToken<R>, de => u64::deserialize(de).map(Self::new));
impl_st!([R] ScheduleToken<R>, _ts => spacetimedb_lib::AlgebraicType::U64);

impl<R> ScheduleToken<R> {
/// Wrap the ID under which a reducer is scheduled in a [`ScheduleToken`].
Expand Down
27 changes: 11 additions & 16 deletions crates/bindings/src/rt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use crate::{sys, ReducerContext, ScheduleToken, SpacetimeType, TableType, Timest
use spacetimedb_lib::auth::{StAccess, StTableType};
use spacetimedb_lib::de::{self, Deserialize, SeqProductAccess};
use spacetimedb_lib::sats::typespace::TypespaceBuilder;
use spacetimedb_lib::sats::{AlgebraicType, AlgebraicTypeRef, ProductTypeElement};
use spacetimedb_lib::ser::{self, Serialize, SerializeSeqProduct};
use spacetimedb_lib::sats::{impl_deserialize, impl_serialize, AlgebraicType, AlgebraicTypeRef, ProductTypeElement};
use spacetimedb_lib::ser::{Serialize, SerializeSeqProduct};
use spacetimedb_lib::{bsatn, Identity, MiscModuleExport, ModuleDef, ReducerDef, TableDef, TypeAlias};
use sys::Buffer;

Expand Down Expand Up @@ -319,20 +319,15 @@ impl_reducer!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V,

/// Provides deserialization and serialization for any type `A: Args`.
struct SerDeArgs<A>(A);
impl<'de, A: Args<'de>> Deserialize<'de> for SerDeArgs<A> {
fn deserialize<D: de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
deserializer
.deserialize_product(ArgsVisitor { _marker: PhantomData })
.map(Self)
}
}
impl<'de, A: Args<'de>> Serialize for SerDeArgs<A> {
fn serialize<S: ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut prod = serializer.serialize_seq_product(A::LEN)?;
self.0.serialize_seq_product(&mut prod)?;
prod.end()
}
}
impl_deserialize!(
[A: Args<'de>] SerDeArgs<A>,
de => de.deserialize_product(ArgsVisitor { _marker: PhantomData }).map(Self)
);
impl_serialize!(['de, A: Args<'de>] SerDeArgs<A>, (self, ser) => {
let mut prod = ser.serialize_seq_product(A::LEN)?;
self.0.serialize_seq_product(&mut prod)?;
prod.end()
});

/// Returns a timestamp that is `duration` from now.
#[track_caller]
Expand Down
23 changes: 4 additions & 19 deletions crates/bindings/src/timestamp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
use std::ops::{Add, Sub};
use std::time::Duration;

use spacetimedb_lib::de::Deserialize;
use spacetimedb_lib::ser::Serialize;
use spacetimedb_lib::sats::{impl_deserialize, impl_serialize, impl_st};

scoped_tls::scoped_thread_local! {
static CURRENT_TIMESTAMP: Timestamp
Expand Down Expand Up @@ -90,20 +89,6 @@ impl Sub<Duration> for Timestamp {
}
}

impl crate::SpacetimeType for Timestamp {
fn make_type<S: spacetimedb_lib::sats::typespace::TypespaceBuilder>(_ts: &mut S) -> spacetimedb_lib::AlgebraicType {
spacetimedb_lib::AlgebraicType::U64
}
}

impl<'de> Deserialize<'de> for Timestamp {
fn deserialize<D: spacetimedb_lib::de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
u64::deserialize(deserializer).map(|micros_since_epoch| Self { micros_since_epoch })
}
}

impl Serialize for Timestamp {
fn serialize<S: spacetimedb_lib::ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.micros_since_epoch.serialize(serializer)
}
}
impl_st!([] Timestamp, _ts => spacetimedb_lib::AlgebraicType::U64);
impl_deserialize!([] Timestamp, de => u64::deserialize(de).map(|m| Self { micros_since_epoch: m }));
impl_serialize!([] Timestamp, (self, ser) => self.micros_since_epoch.serialize(ser));
3 changes: 2 additions & 1 deletion crates/cli/src/edit_distance.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
Copyright, The Rust project developers.
Some parts copyright, The Rust project developers.
See https://github.com/rust-lang/rust/blob/8882507bc7dbad0cc0548204eb8777e51ac92332/COPYRIGHT
for the parts where MIT / Apache-2.0 applies.
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
Expand Down
12 changes: 2 additions & 10 deletions crates/cli/src/subcommands/generate/csharp.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use super::util::fmt_fn;

use std::fmt::{self, Write};

use convert_case::{Case, Casing};
Expand Down Expand Up @@ -259,16 +261,6 @@ fn csharp_typename(ctx: &GenCtx, typeref: AlgebraicTypeRef) -> &str {
ctx.names[typeref.idx()].as_deref().expect("tuples should have names")
}

fn fmt_fn(f: impl Fn(&mut fmt::Formatter) -> fmt::Result) -> impl fmt::Display {
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)
}
}
FDisplay(f)
}

fn is_option_type(ty: &SumType) -> bool {
if ty.variants.len() != 2 {
return false;
Expand Down
1 change: 1 addition & 0 deletions crates/cli/src/subcommands/generate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod csharp;
pub mod python;
pub mod rust;
pub mod typescript;
mod util;

const INDENT: &str = "\t";

Expand Down
12 changes: 2 additions & 10 deletions crates/cli/src/subcommands/generate/python.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use super::util::fmt_fn;

use convert_case::{Case, Casing};
use spacetimedb_lib::{
sats::{AlgebraicType::Builtin, AlgebraicTypeRef, ArrayType, BuiltinType, MapType},
Expand Down Expand Up @@ -137,16 +139,6 @@ fn python_filename(ctx: &GenCtx, typeref: AlgebraicTypeRef) -> String {
.to_case(Case::Snake)
}

fn fmt_fn(f: impl Fn(&mut fmt::Formatter) -> fmt::Result) -> impl fmt::Display {
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)
}
}
FDisplay(f)
}

fn is_option_type(ty: &SumType) -> bool {
if ty.variants.len() != 2 {
return false;
Expand Down
12 changes: 2 additions & 10 deletions crates/cli/src/subcommands/generate/typescript.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use super::util::fmt_fn;

use std::fmt::{self, Write};

use convert_case::{Case, Casing};
Expand Down Expand Up @@ -227,16 +229,6 @@ fn typescript_filename(ctx: &GenCtx, typeref: AlgebraicTypeRef) -> String {
.to_case(Case::Snake)
}

fn fmt_fn(f: impl Fn(&mut fmt::Formatter) -> fmt::Result) -> impl fmt::Display {
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)
}
}
FDisplay(f)
}

macro_rules! indent_scope {
($x:ident) => {
let mut $x = $x.indented(1);
Expand Down
14 changes: 14 additions & 0 deletions crates/cli/src/subcommands/generate/util.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//! Various utility functions that the generate modules have in common.

use std::fmt::{Display, Formatter, Result};

/// Turns a closure `f: Fn(&mut Formatter) -> Result` into `fmt::Display`.
pub(super) fn fmt_fn(f: impl Fn(&mut Formatter) -> Result) -> impl Display {
struct FDisplay<F>(F);
impl<F: Fn(&mut Formatter) -> Result> Display for FDisplay<F> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
(self.0)(f)
}
}
FDisplay(f)
}
4 changes: 2 additions & 2 deletions crates/client-api/src/routes/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use spacetimedb_lib::name;
use spacetimedb_lib::name::DomainName;
use spacetimedb_lib::name::DomainParsingError;
use spacetimedb_lib::name::PublishOp;
use spacetimedb_lib::sats::TypeInSpace;
use spacetimedb_lib::sats::WithTypespace;

use crate::auth::{
SpacetimeAuth, SpacetimeAuthHeader, SpacetimeEnergyUsed, SpacetimeExecutionDurationMicros, SpacetimeIdentity,
Expand Down Expand Up @@ -201,7 +201,7 @@ async fn extract_db_call_info(
})
}

fn entity_description_json(description: TypeInSpace<EntityDef>, expand: bool) -> Option<Value> {
fn entity_description_json(description: WithTypespace<EntityDef>, expand: bool) -> Option<Value> {
let typ = DescribedEntityType::from_entitydef(description.ty()).as_str();
let len = match description.ty() {
EntityDef::Table(t) => description.resolve(t.data).ty().as_product()?.elements.len(),
Expand Down
2 changes: 1 addition & 1 deletion crates/core/src/db/datastore/locking_tx_datastore/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2094,7 +2094,7 @@ mod tests {

StColumnRow { table_id: 1, col_id: 0, col_name: "table_id".to_string(), col_type: AlgebraicType::U32, is_autoinc: false },
StColumnRow { table_id: 1, col_id: 1, col_name: "col_id".to_string(), col_type: AlgebraicType::U32, is_autoinc: false },
StColumnRow { table_id: 1, col_id: 2, col_name: "col_type".to_string(), col_type: AlgebraicType::make_array_type(AlgebraicType::U8), is_autoinc: false },
StColumnRow { table_id: 1, col_id: 2, col_name: "col_type".to_string(), col_type: AlgebraicType::array(AlgebraicType::U8), is_autoinc: false },
StColumnRow { table_id: 1, col_id: 3, col_name: "col_name".to_string(), col_type: AlgebraicType::String, is_autoinc: false },
StColumnRow { table_id: 1, col_id: 4, col_name: "is_autoinc".to_string(), col_type: AlgebraicType::Bool, is_autoinc: false },

Expand Down
6 changes: 3 additions & 3 deletions crates/core/src/host/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use spacetimedb_lib::de::serde::SeedWrapper;
use spacetimedb_lib::de::DeserializeSeed;
use spacetimedb_lib::{bsatn, Hash, Identity};
use spacetimedb_lib::{ProductValue, ReducerDef};
use spacetimedb_sats::TypeInSpace;
use spacetimedb_sats::WithTypespace;

mod host_controller;
pub(crate) mod module_host;
Expand Down Expand Up @@ -35,13 +35,13 @@ pub enum ReducerArgs {
}

impl ReducerArgs {
fn into_tuple(self, schema: TypeInSpace<'_, ReducerDef>) -> Result<ArgsTuple, InvalidReducerArguments> {
fn into_tuple(self, schema: WithTypespace<'_, ReducerDef>) -> Result<ArgsTuple, InvalidReducerArguments> {
self._into_tuple(schema).map_err(|err| InvalidReducerArguments {
err,
reducer: schema.ty().name.clone(),
})
}
fn _into_tuple(self, schema: TypeInSpace<'_, ReducerDef>) -> anyhow::Result<ArgsTuple> {
fn _into_tuple(self, schema: WithTypespace<'_, ReducerDef>) -> anyhow::Result<ArgsTuple> {
Ok(match self {
ReducerArgs::Json(json) => ArgsTuple {
tuple: from_json_seed(&json, SeedWrapper(ReducerDef::deserialize(schema)))?,
Expand Down
10 changes: 5 additions & 5 deletions crates/core/src/host/module_host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::protobuf::client_api::{table_row_operation, SubscriptionUpdate, Table
use crate::subscription::module_subscription_actor::ModuleSubscriptionManager;
use indexmap::IndexMap;
use spacetimedb_lib::{ReducerDef, TableDef};
use spacetimedb_sats::{ProductValue, TypeInSpace, Typespace};
use spacetimedb_sats::{ProductValue, Typespace, WithTypespace};
use std::collections::HashMap;
use std::convert::Infallible;
use std::sync::Arc;
Expand Down Expand Up @@ -560,18 +560,18 @@ impl Catalog {
&self.0.typespace
}

pub fn get(&self, name: &str) -> Option<TypeInSpace<'_, EntityDef>> {
pub fn get(&self, name: &str) -> Option<WithTypespace<'_, EntityDef>> {
self.0.catalog.get(name).map(|ty| self.0.typespace.with_type(ty))
}
pub fn get_reducer(&self, name: &str) -> Option<TypeInSpace<'_, ReducerDef>> {
pub fn get_reducer(&self, name: &str) -> Option<WithTypespace<'_, ReducerDef>> {
let schema = self.get(name)?;
Some(schema.with(schema.ty().as_reducer()?))
}
pub fn get_table(&self, name: &str) -> Option<TypeInSpace<'_, TableDef>> {
pub fn get_table(&self, name: &str) -> Option<WithTypespace<'_, TableDef>> {
let schema = self.get(name)?;
Some(schema.with(schema.ty().as_table()?))
}
pub fn iter(&self) -> impl Iterator<Item = (&str, TypeInSpace<'_, EntityDef>)> + '_ {
pub fn iter(&self) -> impl Iterator<Item = (&str, WithTypespace<'_, EntityDef>)> + '_ {
self.0
.catalog
.iter()
Expand Down
14 changes: 4 additions & 10 deletions crates/core/src/host/timestamp.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::time::{Duration, SystemTime};

use spacetimedb_sats::{impl_deserialize, impl_serialize};

#[derive(Copy, Clone, PartialEq, Eq, Debug, serde::Serialize)]
#[serde(transparent)]
#[repr(transparent)]
Expand All @@ -24,13 +26,5 @@ impl Timestamp {
}
}

impl<'de> spacetimedb_sats::de::Deserialize<'de> for Timestamp {
fn deserialize<D: spacetimedb_lib::de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
u64::deserialize(deserializer).map(Self)
}
}
impl spacetimedb_sats::ser::Serialize for Timestamp {
fn serialize<S: spacetimedb_lib::ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.0.serialize(serializer)
}
}
impl_deserialize!([] Timestamp, de => u64::deserialize(de).map(Self));
impl_serialize!([] Timestamp, (self, ser) => self.0.serialize(ser));
31 changes: 13 additions & 18 deletions crates/core/src/sql/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,24 +276,23 @@ fn extract_field(table: &From, of: &SqlExpr) -> Result<Option<ProductTypeElement
/// When `field` is `None`, the type is inferred to an integer or float depending on if a `.` separator is present.
/// The `is_long` parameter decides whether to parse as a 64-bit type or a 32-bit one.
fn infer_number(field: Option<&ProductTypeElement>, value: &str, is_long: bool) -> Result<AlgebraicValue, ErrorVm> {
let ty = match field {
match field {
None => {
if value.contains('.') {
let ty = if value.contains('.') {
if is_long {
&AlgebraicType::F64
AlgebraicType::F64
} else {
&AlgebraicType::F32
AlgebraicType::F32
}
} else if is_long {
&AlgebraicType::I64
AlgebraicType::I64
} else {
&AlgebraicType::I32
}
AlgebraicType::I32
};
parse(value, &ty)
}
Some(f) => &f.algebraic_type,
};

parse(value, ty)
Some(f) => parse(value, &f.algebraic_type),
}
}

/// Compiles a [SqlExpr] expression into a [ColumnOp]
Expand Down Expand Up @@ -743,20 +742,16 @@ fn column_def_type(named: &String, is_null: bool, data_type: &DataType) -> Resul
DataType::Real => AlgebraicType::F32,
DataType::Double => AlgebraicType::F64,
DataType::Boolean => AlgebraicType::Bool,
DataType::Array(Some(ty)) => AlgebraicType::make_array_type(column_def_type(named, false, ty)?),
DataType::Enum(values) => AlgebraicType::make_simple_enum(values.iter().map(|x| x.as_str())),
DataType::Array(Some(ty)) => AlgebraicType::array(column_def_type(named, false, ty)?),
DataType::Enum(values) => AlgebraicType::simple_enum(values.iter().map(|x| x.as_str())),
x => {
return Err(PlanError::Unsupported {
feature: format!("Column {} of type {}", named, x),
})
}
};

Ok(if is_null {
AlgebraicType::make_option_type(ty)
} else {
ty
})
Ok(if is_null { AlgebraicType::option(ty) } else { ty })
}

/// Extract the column attributes into [ColumnIndexAttribute]
Expand Down
Loading

0 comments on commit c3526ee

Please sign in to comment.