diff --git a/crates/cli/src/subcommands/call.rs b/crates/cli/src/subcommands/call.rs index 997a9b5be4..5a6d697b5e 100644 --- a/crates/cli/src/subcommands/call.rs +++ b/crates/cli/src/subcommands/call.rs @@ -9,7 +9,7 @@ use itertools::Either; use serde_json::Value; use spacetimedb::db::AlgebraicType; use spacetimedb_lib::de::serde::deserialize_from; -use spacetimedb_lib::sats::{AlgebraicTypeRef, BuiltinType, Typespace}; +use spacetimedb_lib::sats::{AlgebraicTypeRef, Typespace}; use spacetimedb_lib::{Address, ProductTypeElement}; use std::fmt::Write; use std::iter; @@ -86,7 +86,7 @@ pub async fn exec(mut config: Config, args: &ArgMatches) -> Result<(), Error> { .unwrap_or_default() .zip(describe_reducer.schema.elements.iter()) .map(|(argument, element)| match &element.algebraic_type { - AlgebraicType::Builtin(BuiltinType::String) if !argument.starts_with('\"') || !argument.ends_with('\"') => { + AlgebraicType::String if !argument.starts_with('\"') || !argument.ends_with('\"') => { format!("\"{}\"", argument) } _ => argument.to_string(), diff --git a/crates/cli/src/subcommands/generate/csharp.rs b/crates/cli/src/subcommands/generate/csharp.rs index 8913bb6b52..0fb96da5f4 100644 --- a/crates/cli/src/subcommands/generate/csharp.rs +++ b/crates/cli/src/subcommands/generate/csharp.rs @@ -3,120 +3,50 @@ use super::util::fmt_fn; use std::fmt::{self, Write}; use convert_case::{Case, Casing}; -use spacetimedb_lib::sats::{ - AlgebraicType, AlgebraicType::Builtin, AlgebraicTypeRef, ArrayType, BuiltinType, MapType, ProductType, SumType, -}; +use spacetimedb_lib::sats::{AlgebraicType, AlgebraicTypeRef, ArrayType, ProductType, SumType}; use spacetimedb_lib::{ColumnIndexAttribute, ProductTypeElement, ReducerDef, TableDef}; use super::code_indenter::CodeIndenter; use super::{GenCtx, GenItem, INDENT}; -enum MaybePrimitive<'a> { - Primitive(&'static str), - Array(&'a ArrayType), - Map(&'a MapType), -} - -fn maybe_primitive(b: &BuiltinType) -> MaybePrimitive { - MaybePrimitive::Primitive(match b { - BuiltinType::Bool => "bool", - BuiltinType::I8 => "sbyte", - BuiltinType::U8 => "byte", - BuiltinType::I16 => "short", - BuiltinType::U16 => "ushort", - BuiltinType::I32 => "int", - BuiltinType::U32 => "uint", - BuiltinType::I64 => "long", - BuiltinType::U64 => "ulong", - // BuiltinType::I128 => "int128", Not a supported type in csharp - // BuiltinType::U128 => "uint128", Not a supported type in csharp - BuiltinType::I128 => panic!("i128 not supported for csharp"), - BuiltinType::U128 => panic!("i128 not supported for csharp"), - BuiltinType::String => "string", - BuiltinType::F32 => "float", - BuiltinType::F64 => "double", - BuiltinType::Array(ty) => return MaybePrimitive::Array(ty), - BuiltinType::Map(m) => return MaybePrimitive::Map(m), - }) -} - fn ty_fmt<'a>(ctx: &'a GenCtx, ty: &'a AlgebraicType, namespace: &'a str) -> impl fmt::Display + 'a { fmt_fn(move |f| match ty { AlgebraicType::Sum(sum_type) => { // This better be an option type - if let Some(inner_ty) = sum_type.as_option() { - match inner_ty { - Builtin(b) => match b { - BuiltinType::Bool - | BuiltinType::I8 - | BuiltinType::U8 - | BuiltinType::I16 - | BuiltinType::U16 - | BuiltinType::I32 - | BuiltinType::U32 - | BuiltinType::I64 - | BuiltinType::U64 - | BuiltinType::I128 - | BuiltinType::U128 - | BuiltinType::F32 - | BuiltinType::F64 => { - // This has to be a nullable type. - write!(f, "{}?", ty_fmt(ctx, inner_ty, namespace)) - } - _ => { - write!(f, "{}", ty_fmt(ctx, inner_ty, namespace)) - } - }, - _ => { - write!(f, "{}", ty_fmt(ctx, inner_ty, namespace)) - } - } - } else { - unimplemented!() + let Some(inner_ty) = sum_type.as_option() else { + unimplemented!(); + }; + + write!(f, "{}", ty_fmt(ctx, inner_ty, namespace))?; + if inner_ty.is_scalar() { + // This has to be a nullable type. + f.write_char('?')?; } + Ok(()) } - AlgebraicType::Product(prod) => { - // The only type that is allowed here is the identity type. All other types should fail. - if prod.is_identity() { - write!(f, "SpacetimeDB.Identity") - } else if prod.is_address() { - write!(f, "SpacetimeDB.Address") - } else { - unimplemented!() - } - } - AlgebraicType::Builtin(b) => match maybe_primitive(b) { - MaybePrimitive::Primitive(p) => f.write_str(p), - MaybePrimitive::Array(ArrayType { elem_ty }) if **elem_ty == AlgebraicType::U8 => f.write_str("byte[]"), - MaybePrimitive::Array(ArrayType { elem_ty }) => { - write!( - f, - "System.Collections.Generic.List<{}>", - ty_fmt(ctx, elem_ty, namespace) - ) - } - MaybePrimitive::Map(ty) => { - write!( - f, - "System.Collections.Generic.Dictionary<{}, {}>", - ty_fmt(ctx, &ty.ty, namespace), - ty_fmt(ctx, &ty.key_ty, namespace) - ) - } - }, + ty if ty.is_identity() => write!(f, "SpacetimeDB.Identity"), + ty if ty.is_address() => write!(f, "SpacetimeDB.Address"), + AlgebraicType::Product(_) => unimplemented!(), + ty if ty.is_bytes() => f.write_str("byte[]"), + AlgebraicType::Array(arr) => write!( + f, + "System.Collections.Generic.List<{}>", + ty_fmt(ctx, &arr.elem_ty, namespace) + ), + AlgebraicType::Map(ty) => write!( + f, + "System.Collections.Generic.SortedDictionary<{}, {}>", + ty_fmt(ctx, &ty.ty, namespace), + ty_fmt(ctx, &ty.key_ty, namespace) + ), + ty if ty.is_scalar_or_string() => f.write_str(maybe_primitive(ty).unwrap().1), AlgebraicType::Ref(r) => { let name = csharp_typename(ctx, *r); - match &ctx.typespace.types[r.idx()] { - AlgebraicType::Sum(sum_type) => { - if is_enum(sum_type) { - let parts: Vec<&str> = name.split('.').collect(); - if parts.len() >= 2 { - let enum_namespace = parts[0]; - let enum_name = parts[1]; - write!(f, "{namespace}.{enum_namespace}.Types.{enum_name}") - } else { - write!(f, "{}.{}", namespace, name) - } + match &ctx.typespace[*r] { + AlgebraicType::Sum(sum_type) if sum_type.is_simple_enum() => { + let mut ps = name.split('.'); + if let Some((e_ns, e_name)) = ps.next().zip(ps.next()) { + write!(f, "{namespace}.{e_ns}.Types.{e_name}") } else { write!(f, "{}.{}", namespace, name) } @@ -126,24 +56,30 @@ fn ty_fmt<'a>(ctx: &'a GenCtx, ty: &'a AlgebraicType, namespace: &'a str) -> imp } } } + _ => unreachable!(), }) } -fn convert_builtintype<'a>( +fn convert_type<'a>( ctx: &'a GenCtx, vecnest: usize, - b: &'a BuiltinType, + ty: &'a AlgebraicType, value: impl fmt::Display + 'a, namespace: &'a str, ) -> impl fmt::Display + 'a { - fmt_fn(move |f| match maybe_primitive(b) { - MaybePrimitive::Primitive(_) => { - write!(f, "{value}.As{b:?}()") - } - MaybePrimitive::Array(ArrayType { elem_ty }) if **elem_ty == AlgebraicType::U8 => { - write!(f, "{value}.AsBytes()") - } - MaybePrimitive::Array(ArrayType { elem_ty }) => { + fmt_fn(move |f| match ty { + ty if ty.is_identity() => write!( + f, + "SpacetimeDB.Identity.From({}.AsProductValue().elements[0].AsBytes())", + value + ), + ty if ty.is_address() => write!( + f, + "(SpacetimeDB.Address)SpacetimeDB.Address.From({}.AsProductValue().elements[0].AsBytes())", + value + ), + ty if ty.is_bytes() => write!(f, "{value}.AsBytes()"), + AlgebraicType::Array(ArrayType { elem_ty }) => { let csharp_type = ty_fmt(ctx, elem_ty, namespace); writeln!( f, @@ -166,70 +102,18 @@ fn convert_builtintype<'a>( writeln!(f, "\treturn vec{vecnest};")?; write!(f, "}}))()") } - MaybePrimitive::Map(_) => todo!(), - }) -} - -fn convert_type<'a>( - ctx: &'a GenCtx, - vecnest: usize, - ty: &'a AlgebraicType, - value: impl fmt::Display + 'a, - namespace: &'a str, -) -> impl fmt::Display + 'a { - fmt_fn(move |f| match ty { - AlgebraicType::Product(product) => { - if product.is_identity() { - write!( - f, - "SpacetimeDB.Identity.From({}.AsProductValue().elements[0].AsBytes())", - value - ) - } else if product.is_address() { - write!( - f, - "(SpacetimeDB.Address)SpacetimeDB.Address.From({}.AsProductValue().elements[0].AsBytes())", - value - ) - } else { - unimplemented!() - } - } + AlgebraicType::Product(_) | AlgebraicType::Map(_) => todo!(), AlgebraicType::Sum(sum_type) => { if let Some(inner_ty) = sum_type.as_option() { match inner_ty { - Builtin(ty) => match ty { - BuiltinType::Bool - | BuiltinType::I8 - | BuiltinType::U8 - | BuiltinType::I16 - | BuiltinType::U16 - | BuiltinType::I32 - | BuiltinType::U32 - | BuiltinType::I64 - | BuiltinType::U64 - | BuiltinType::I128 - | BuiltinType::U128 - | BuiltinType::F32 - | BuiltinType::F64 => write!( - f, - "{}.AsSumValue().tag == 1 ? null : new {}?({}.AsSumValue().value{})", - value, - ty_fmt(ctx, inner_ty, namespace), - value, - &convert_type(ctx, vecnest, inner_ty, "", namespace), - ), - _ => fmt::Display::fmt( - &convert_type( - ctx, - vecnest, - inner_ty, - format_args!("{}.AsSumValue().tag == 1 ? null : {}.AsSumValue().value", value, value), - namespace, - ), - f, - ), - }, + ty if ty.is_scalar() => write!( + f, + "{}.AsSumValue().tag == 1 ? null : new {}?({}.AsSumValue().value{})", + value, + ty_fmt(ctx, inner_ty, namespace), + value, + &convert_type(ctx, vecnest, inner_ty, "", namespace), + ), _ => fmt::Display::fmt( &convert_type( ctx, @@ -245,13 +129,11 @@ fn convert_type<'a>( unimplemented!() } } - AlgebraicType::Builtin(b) => fmt::Display::fmt(&convert_builtintype(ctx, vecnest, b, &value, namespace), f), AlgebraicType::Ref(r) => { let name = csharp_typename(ctx, *r); - let algebraic_type = &ctx.typespace.types[r.idx()]; - match algebraic_type { + match &ctx.typespace[*r] { AlgebraicType::Sum(sum) => { - if is_enum(sum) { + if sum.is_simple_enum() { let split: Vec<&str> = name.split('.').collect(); if split.len() >= 2 { assert_eq!( @@ -278,6 +160,9 @@ fn convert_type<'a>( } } } + ty if ty.is_scalar() => write!(f, "{value}.As{ty:?}()"), + AlgebraicType::String => write!(f, "{value}.AsString()"), + _ => unreachable!(), }) } @@ -296,43 +181,34 @@ fn convert_algebraic_type<'a>(ctx: &'a GenCtx, ty: &'a AlgebraicType, namespace: fmt_fn(move |f| match ty { AlgebraicType::Product(product_type) => write!(f, "{}", convert_product_type(ctx, product_type, namespace)), AlgebraicType::Sum(sum_type) => write!(f, "{}", convert_sum_type(ctx, sum_type, namespace)), - AlgebraicType::Builtin(b) => match maybe_primitive(b) { - MaybePrimitive::Primitive(_) => { - write!( - f, - "SpacetimeDB.SATS.AlgebraicType.CreatePrimitiveType(SpacetimeDB.SATS.BuiltinType.Type.{:?})", - b - ) - } - MaybePrimitive::Array(ArrayType { elem_ty }) => write!( - f, - "SpacetimeDB.SATS.AlgebraicType.CreateArrayType({})", - convert_algebraic_type(ctx, elem_ty, namespace) - ), - MaybePrimitive::Map(_) => todo!(), - }, + AlgebraicType::Array(arr) => write!( + f, + "SpacetimeDB.SATS.AlgebraicType.CreateArrayType({})", + convert_algebraic_type(ctx, &arr.elem_ty, namespace) + ), + AlgebraicType::Map(map) => write!( + f, + "SpacetimeDB.SATS.AlgebraicType.CreateArrayType({}, {})", + convert_algebraic_type(ctx, &map.key_ty, namespace), + convert_algebraic_type(ctx, &map.ty, namespace), + ), + ty if ty.is_scalar_or_string() => write!(f, "SpacetimeDB.SATS.AlgebraicType.create{ty:?}Type()"), AlgebraicType::Ref(r) => { let name = csharp_typename(ctx, *r); - match &ctx.typespace.types[r.idx()] { - AlgebraicType::Sum(sum_type) => { - if is_enum(sum_type) { - let parts: Vec<&str> = name.split('.').collect(); - if parts.len() >= 2 { - let enum_namespace = parts[0]; - let enum_name = parts[1]; - write!(f, "{namespace}.{enum_namespace}.GetAlgebraicTypeFor{enum_name}()") - } else { - write!(f, "{}", convert_sum_type(ctx, sum_type, namespace)) - } + match &ctx.typespace[*r] { + AlgebraicType::Sum(sum_type) if sum_type.is_simple_enum() => { + let mut ps = name.split('.'); + if let Some((e_ns, e_name)) = ps.next().zip(ps.next()) { + write!(f, "{namespace}.{e_ns}.GetAlgebraicTypeFor{e_name}()") } else { - unimplemented!() + write!(f, "{}", convert_sum_type(ctx, sum_type, namespace)) } } - _ => { - write!(f, "{}.{}.GetAlgebraicType()", namespace, name) - } + AlgebraicType::Sum(_) => unimplemented!(), + _ => write!(f, "{}.{}.GetAlgebraicType()", namespace, name), } } + _ => unreachable!(), }) } @@ -384,23 +260,8 @@ fn convert_sum_type<'a>(ctx: &'a GenCtx, sum_type: &'a SumType, namespace: &'a s }) } -pub fn is_enum(sum_type: &SumType) -> bool { - for variant in sum_type.clone().variants { - match variant.algebraic_type { - AlgebraicType::Product(product) => { - if product.elements.is_empty() { - continue; - } - } - _ => return false, - } - } - - true -} - pub fn autogen_csharp_sum(ctx: &GenCtx, name: &str, sum_type: &SumType, namespace: &str) -> String { - if is_enum(sum_type) { + if sum_type.is_simple_enum() { autogen_csharp_enum(ctx, name, sum_type, namespace) } else { unimplemented!(); @@ -419,8 +280,8 @@ pub fn autogen_csharp_enum(ctx: &GenCtx, name: &str, sum_type: &SumType, namespa panic!("Enum names cannot contain more than one namespace prefix. Example: MyNamespace.MyEnum"); } - sum_namespace = Some(split[0].to_string().to_case(Case::Pascal)); - sum_type_name = split[1].to_string().to_case(Case::Pascal); + sum_namespace = Some(split[0].to_case(Case::Pascal)); + sum_type_name = split[1].to_case(Case::Pascal); sum_full_enum_type_name = format!("{}.Types.{}", sum_namespace.clone().unwrap(), sum_type_name); } @@ -465,7 +326,7 @@ pub fn autogen_csharp_enum(ctx: &GenCtx, name: &str, sum_type: &SumType, namespa writeln!(output, "{{").unwrap(); { indent_scope!(output); - for variant in &sum_type.variants { + for variant in &*sum_type.variants { let variant_name = variant .name .as_ref() @@ -498,7 +359,7 @@ pub fn autogen_csharp_enum(ctx: &GenCtx, name: &str, sum_type: &SumType, namespa .unwrap(); } None => { - for variant in &sum_type.variants { + for variant in &*sum_type.variants { let variant_name = variant .name .as_ref() @@ -594,7 +455,7 @@ fn autogen_csharp_product_table_common( { indent_scope!(output); - for field in &product_type.elements { + for field in &*product_type.elements { let field_name = field .name .as_ref() @@ -602,14 +463,12 @@ fn autogen_csharp_product_table_common( .replace("r#", ""); writeln!(output, "[Newtonsoft.Json.JsonProperty(\"{field_name}\")]").unwrap(); match &field.algebraic_type { - Builtin(BuiltinType::Array(ArrayType { elem_ty: array_type })) => { - if let Builtin(BuiltinType::U8) = **array_type { - writeln!( - output, - "[Newtonsoft.Json.JsonConverter(typeof(SpacetimeDB.ByteArrayConverter))]" - ) - .unwrap(); - } + ty if ty.is_bytes() => { + writeln!( + output, + "[Newtonsoft.Json.JsonConverter(typeof(SpacetimeDB.ByteArrayConverter))]" + ) + .unwrap(); } AlgebraicType::Sum(sum) => { if sum.as_option().is_some() { @@ -619,9 +478,8 @@ fn autogen_csharp_product_table_common( } } AlgebraicType::Ref(type_ref) => { - let ref_type = &ctx.typespace.types[type_ref.idx()]; - if let AlgebraicType::Sum(sum_type) = ref_type { - if is_enum(sum_type) { + if let AlgebraicType::Sum(sum_type) = &ctx.typespace[*type_ref] { + if sum_type.is_simple_enum() { writeln!(output, "[SpacetimeDB.Enum]").unwrap(); } else { unimplemented!() @@ -912,6 +770,30 @@ fn indented_block(output: &mut CodeIndenter, f: impl FnOnce(&mut Code res } +fn maybe_primitive(ty: &AlgebraicType) -> Option<(&'static str, &'static str)> { + match ty { + AlgebraicType::Bool => Some(("Bool", "bool")), + AlgebraicType::I8 => Some(("I8", "sbyte")), + AlgebraicType::U8 => Some(("U8", "byte")), + AlgebraicType::I16 => Some(("I16", "short")), + AlgebraicType::U16 => Some(("U16", "ushort")), + AlgebraicType::I32 => Some(("I32", "int")), + AlgebraicType::U32 => Some(("U32", "uint")), + AlgebraicType::I64 => Some(("I64", "long")), + AlgebraicType::U64 => Some(("U64", "ulong")), + AlgebraicType::I128 => Some(("I128", "byte[]")), + AlgebraicType::U128 => Some(("U128", "byte[]")), + AlgebraicType::String => Some(("String", "string")), + AlgebraicType::F32 => Some(("F32", "float")), + AlgebraicType::F64 => Some(("F64", "double")), + AlgebraicType::Array(_) + | AlgebraicType::Ref(_) + | AlgebraicType::Map(_) + | AlgebraicType::Sum(_) + | AlgebraicType::Product(_) => None, + } +} + fn autogen_csharp_access_funcs_for_struct( output: &mut CodeIndenter, struct_name_pascal_case: &str, @@ -964,50 +846,31 @@ fn autogen_csharp_access_funcs_for_struct( let csharp_field_name_pascal = field_name.replace("r#", "").to_case(Case::Pascal); let (field_type, csharp_field_type, is_option) = match field_type { - AlgebraicType::Product(product) => { - if product.is_identity() { - ("Identity".into(), "SpacetimeDB.Identity".into(), false) - } else if product.is_address() { - ("Address".into(), "SpacetimeDB.Address".into(), false) - } else { - // TODO: We don't allow filtering on tuples right now, - // it's possible we may consider it for the future. - continue; - } - } + ty if ty.is_identity() => ("Identity", "SpacetimeDB.Identity".into(), false), + ty if ty.is_address() => ("Address", "SpacetimeDB.Address".into(), false), + + // Do allow filtering for byte arrays. + ty if ty.is_bytes() => ("Bytes", "byte[]".into(), false), + AlgebraicType::Sum(sum) => { - if let Some(Builtin(b)) = sum.as_option() { - match maybe_primitive(b) { - MaybePrimitive::Primitive(ty) => (format!("{:?}", b), format!("{}?", ty), true), - _ => { - continue; - } - } + if let Some((ft, cft)) = sum.as_option().and_then(maybe_primitive) { + (ft, format!("{cft}?"), true) } else { continue; } } - AlgebraicType::Ref(_) => { - // TODO: We don't allow filtering on enums or tuples right now; + AlgebraicType::Product(_) | AlgebraicType::Ref(_) | AlgebraicType::Array(_) | AlgebraicType::Map(_) => { + // TODO: We don't allow filtering on enums, tuples, arrays, or maps right now; // it's possible we may consider it for the future. + // For maps, it would be nice to be able to say, + // give me all entries where this vec contains this value, + // which we can do. continue; } - AlgebraicType::Builtin(b) => match maybe_primitive(b) { - MaybePrimitive::Primitive(ty) => (format!("{:?}", b), ty.into(), false), - MaybePrimitive::Array(ArrayType { elem_ty }) => { - if let Some(BuiltinType::U8) = elem_ty.as_builtin() { - // Do allow filtering for byte arrays - ("Bytes".into(), "byte[]".into(), false) - } else { - // TODO: We don't allow filtering based on an array type, but we might want other functionality here in the future. - continue; - } - } - MaybePrimitive::Map(_) => { - // TODO: It would be nice to be able to say, give me all entries where this vec contains this value, which we can do. - continue; - } - }, + ty => { + let (ft, cft) = maybe_primitive(ty).unwrap(); + (ft, cft.into(), false) + } }; let filter_return_type = fmt_fn(|f| { @@ -1276,26 +1139,19 @@ pub fn autogen_csharp_reducer(ctx: &GenCtx, reducer: &ReducerDef, namespace: &st json_args.push_str(&arg_name); } } - AlgebraicType::Product(_) => { - json_args.push_str(arg_name.as_str()); - } - Builtin(_) => { - json_args.push_str(arg_name.as_str()); + ty if ty.is_product() || ty.is_array() || ty.is_scalar_or_string() => { + json_args.push_str(&arg_name); } - AlgebraicType::Ref(type_ref) => { - let ref_type = &ctx.typespace.types[type_ref.idx()]; - if let AlgebraicType::Sum(sum_type) = ref_type { - if is_enum(sum_type) { - json_args.push_str( - format!("new SpacetimeDB.EnumWrapper<{}>({})", arg_type_str, arg_name).as_str(), - ); - } else { - unimplemented!() - } - } else { - json_args.push_str(arg_name.as_str()); + AlgebraicType::Map(_) => todo!(), + AlgebraicType::Ref(type_ref) => match &ctx.typespace[*type_ref] { + AlgebraicType::Sum(sum) if sum.is_simple_enum() => { + json_args + .push_str(format!("new SpacetimeDB.EnumWrapper<{}>({})", arg_type_str, arg_name).as_str()); } - } + AlgebraicType::Sum(_) => unimplemented!(), + _ => json_args.push_str(&arg_name), + }, + _ => unreachable!(), } if arg_i > 0 { diff --git a/crates/cli/src/subcommands/generate/mod.rs b/crates/cli/src/subcommands/generate/mod.rs index 3a2eb7ada2..2a60679d19 100644 --- a/crates/cli/src/subcommands/generate/mod.rs +++ b/crates/cli/src/subcommands/generate/mod.rs @@ -264,8 +264,7 @@ impl GenItem { let name = name.to_case(Case::Snake); Some((name + ".py", code)) } - AlgebraicType::Builtin(_) => todo!(), - AlgebraicType::Ref(_) => todo!(), + _ => todo!(), }, GenItem::Reducer(reducer) => { let code = python::autogen_python_reducer(ctx, reducer); @@ -293,8 +292,7 @@ impl GenItem { let name = name.to_case(Case::Snake); Some((name + ".ts", code)) } - AlgebraicType::Builtin(_) => todo!(), - AlgebraicType::Ref(_) => todo!(), + _ => todo!(), }, GenItem::Reducer(reducer) => { let code = typescript::autogen_typescript_reducer(ctx, reducer); @@ -320,8 +318,7 @@ impl GenItem { let code = csharp::autogen_csharp_tuple(ctx, name, prod, namespace); Some((name.clone() + ".cs", code)) } - AlgebraicType::Builtin(_) => todo!(), - AlgebraicType::Ref(_) => todo!(), + _ => todo!(), }, GenItem::Reducer(reducer) => { let code = csharp::autogen_csharp_reducer(ctx, reducer, namespace); diff --git a/crates/cli/src/subcommands/generate/python.rs b/crates/cli/src/subcommands/generate/python.rs index c6b2f834df..1556ba59a8 100644 --- a/crates/cli/src/subcommands/generate/python.rs +++ b/crates/cli/src/subcommands/generate/python.rs @@ -2,97 +2,47 @@ use super::util::fmt_fn; use convert_case::{Case, Casing}; use spacetimedb_lib::{ - sats::{AlgebraicType::Builtin, AlgebraicTypeRef, ArrayType, BuiltinType, MapType}, + sats::{AlgebraicTypeRef, ArrayType}, AlgebraicType, ColumnIndexAttribute, ProductType, ProductTypeElement, ReducerDef, SumType, TableDef, }; use std::fmt::{self, Write}; -use super::{code_indenter::CodeIndenter, csharp::is_enum, GenCtx, GenItem}; +use super::{code_indenter::CodeIndenter, GenCtx, GenItem}; -enum MaybePrimitive<'a> { - Primitive(&'static str), - Array(&'a ArrayType), - Map(&'a MapType), -} - -fn maybe_primitive(b: &BuiltinType) -> MaybePrimitive { - MaybePrimitive::Primitive(match b { - BuiltinType::Bool => "bool", - BuiltinType::I8 => "int", - BuiltinType::U8 => "int", - BuiltinType::I16 => "int", - BuiltinType::U16 => "int", - BuiltinType::I32 => "int", - BuiltinType::U32 => "int", - BuiltinType::I64 => "int", - BuiltinType::U64 => "int", - BuiltinType::I128 => "int", - BuiltinType::U128 => "int", - BuiltinType::String => "str", - BuiltinType::F32 => "float", - BuiltinType::F64 => "float", - BuiltinType::Array(ty) => return MaybePrimitive::Array(ty), - BuiltinType::Map(m) => return MaybePrimitive::Map(m), - }) -} - -fn convert_builtintype<'a>( - ctx: &'a GenCtx, - vecnest: usize, - b: &'a BuiltinType, - value: impl fmt::Display + 'a, - ref_prefix: &'a str, -) -> impl fmt::Display + 'a { - fmt_fn(move |f| match maybe_primitive(b) { - MaybePrimitive::Primitive(p) => { - write!(f, "{p}({value})") - } - MaybePrimitive::Array(ArrayType { elem_ty }) if **elem_ty == AlgebraicType::U8 => { - write!(f, "bytes.fromhex({value})") - } - MaybePrimitive::Array(ArrayType { elem_ty }) => { - let convert_type = convert_type(ctx, vecnest + 1, elem_ty, "item", ref_prefix); - write!(f, "[{convert_type} for item in {value}]") - } - MaybePrimitive::Map(_) => unimplemented!(), - }) -} - -fn convert_type<'a>( - ctx: &'a GenCtx, - vecnest: usize, - ty: &'a AlgebraicType, - value: impl fmt::Display + 'a, - ref_prefix: &'a str, -) -> impl fmt::Display + 'a { +fn convert_type<'a>(ctx: &'a GenCtx, ty: &'a AlgebraicType, value: impl fmt::Display + 'a) -> impl fmt::Display + 'a { fmt_fn(move |f| match ty { - AlgebraicType::Product(product) => { - if product.is_identity() { - write!(f, "Identity.from_string({value}[0])") - } else { - unimplemented!() - } - } + ty if ty.is_identity() => write!(f, "Identity.from_string({value}[0])"), AlgebraicType::Sum(sum_type) => match sum_type.as_option() { Some(inner_ty) => write!( f, "{} if '0' in {value} else None", - convert_type(ctx, vecnest, inner_ty, format!("{value}['0']"), ref_prefix), + convert_type(ctx, inner_ty, format!("{value}['0']")), ), None => unimplemented!(), }, - AlgebraicType::Builtin(b) => fmt::Display::fmt(&convert_builtintype(ctx, vecnest, b, &value, ref_prefix), f), + ty if ty.is_bytes() => write!(f, "bytes.fromhex({value})"), + AlgebraicType::Array(ArrayType { elem_ty }) => { + let convert_type = convert_type(ctx, elem_ty, "item"); + write!(f, "[{convert_type} for item in {value}]") + } + AlgebraicType::Product(_) | AlgebraicType::Map(_) => unimplemented!(), + AlgebraicType::Bool => write!(f, "bool({value})"), + ty if ty.is_int() => write!(f, "int({value})"), + ty if ty.is_float() => write!(f, "float({value})"), + AlgebraicType::String => write!(f, "str({value})"), AlgebraicType::Ref(r) => { let name = python_typename(ctx, *r); - let algebraic_type = &ctx.typespace.types[r.idx()]; - match algebraic_type { + match &ctx.typespace[*r] { // for enums in json this comes over as a dictionary where the key is actually the enum index - AlgebraicType::Sum(sum_type) if is_enum(sum_type) => write!(f, "{name}(int(next(iter({value})))+1)"), + AlgebraicType::Sum(sum_type) if sum_type.is_simple_enum() => { + write!(f, "{name}(int(next(iter({value})))+1)") + } _ => { write!(f, "{name}({value})") } } } + _ => unreachable!(), }) } @@ -103,33 +53,26 @@ fn python_typename(ctx: &GenCtx, typeref: AlgebraicTypeRef) -> &str { fn ty_fmt<'a>(ctx: &'a GenCtx, ty: &'a AlgebraicType, ref_prefix: &'a str) -> impl fmt::Display + 'a { fmt_fn(move |f| match ty { - AlgebraicType::Sum(_sum_type) => { - unimplemented!() - } - AlgebraicType::Product(prod) => { - // The only type that is allowed here is the identity type. All other types should fail. - if prod.is_identity() { - write!(f, "Identity") - } else { - unimplemented!() - } + // The only product type allowed here is Identity. + // All other types should fail. + AlgebraicType::Product(prod) if prod.is_identity() => write!(f, "Identity"), + AlgebraicType::Sum(_) | AlgebraicType::Product(_) => unimplemented!(), + ty if ty.is_bytes() => f.write_str("bytes"), + AlgebraicType::Array(ArrayType { elem_ty }) => { + write!(f, "List[{}]", ty_fmt(ctx, elem_ty, ref_prefix)) } - AlgebraicType::Builtin(b) => match maybe_primitive(b) { - MaybePrimitive::Primitive(p) => f.write_str(p), - MaybePrimitive::Array(ArrayType { elem_ty }) if **elem_ty == AlgebraicType::U8 => f.write_str("bytes"), - MaybePrimitive::Array(ArrayType { elem_ty }) => { - write!(f, "List[{}]", ty_fmt(ctx, elem_ty, ref_prefix)) - } - MaybePrimitive::Map(ty) => { - write!( - f, - "Dict[{}, {}]", - ty_fmt(ctx, &ty.ty, ref_prefix), - ty_fmt(ctx, &ty.key_ty, ref_prefix) - ) - } - }, + AlgebraicType::Map(ty) => write!( + f, + "Dict[{}, {}]", + ty_fmt(ctx, &ty.ty, ref_prefix), + ty_fmt(ctx, &ty.key_ty, ref_prefix) + ), + AlgebraicType::Bool => f.write_str("bool"), + ty if ty.is_int() => f.write_str("int"), + ty if ty.is_float() => f.write_str("float"), + AlgebraicType::String => f.write_str("str"), AlgebraicType::Ref(r) => write!(f, "{}{}", ref_prefix, python_typename(ctx, *r)), + _ => unreachable!(), }) } @@ -151,7 +94,7 @@ pub fn autogen_python_table(ctx: &GenCtx, table: &TableDef) -> String { autogen_python_product_table_common(ctx, &table.name, tuple, Some(&table.column_attrs)) } -fn generate_imports(ctx: &GenCtx, elements: &Vec, imports: &mut Vec) { +fn generate_imports(ctx: &GenCtx, elements: &[ProductTypeElement], imports: &mut Vec) { for field in elements { _generate_imports(ctx, &field.algebraic_type, imports); } @@ -159,14 +102,11 @@ fn generate_imports(ctx: &GenCtx, elements: &Vec, imports: & fn _generate_imports(ctx: &GenCtx, ty: &AlgebraicType, imports: &mut Vec) { match ty { - Builtin(b) => match b { - BuiltinType::Array(ArrayType { elem_ty }) => _generate_imports(ctx, elem_ty, imports), - BuiltinType::Map(map_type) => { - _generate_imports(ctx, &map_type.key_ty, imports); - _generate_imports(ctx, &map_type.ty, imports); - } - _ => {} - }, + AlgebraicType::Array(ArrayType { elem_ty }) => _generate_imports(ctx, elem_ty, imports), + AlgebraicType::Map(map_type) => { + _generate_imports(ctx, &map_type.key_ty, imports); + _generate_imports(ctx, &map_type.ty, imports); + } AlgebraicType::Sum(sum_type) => { if let Some(inner_ty) = sum_type.as_option() { _generate_imports(ctx, inner_ty, imports) @@ -179,6 +119,7 @@ fn _generate_imports(ctx: &GenCtx, ty: &AlgebraicType, imports: &mut Vec let import = format!("from .{filename} import {class_name}"); imports.push(import); } + // Products, scalars, and strings. _ => {} } } @@ -303,19 +244,7 @@ fn autogen_python_product_table_common( // TODO: We don't allow filtering on enums or tuples right now, its possible we may consider it for the future. continue; } - AlgebraicType::Builtin(b) => match maybe_primitive(b) { - MaybePrimitive::Array(ArrayType { elem_ty }) => { - if elem_ty.as_builtin().is_none() { - // TODO: We don't allow filtering based on an array type, but we might want other functionality here in the future. - continue; - } - } - MaybePrimitive::Map(_) => { - // TODO: It would be nice to be able to say, give me all entries where this vec contains this value, which we can do. - continue; - } - _ => (), - }, + _ => unreachable!(), }; let field_name = field @@ -361,7 +290,7 @@ fn autogen_python_product_table_common( writeln!( output, "self.data[\"{python_field_name}\"] = {}", - convert_type(ctx, 0, field_type, format_args!("data[{idx}]"), "") + convert_type(ctx, field_type, format_args!("data[{idx}]")) ) .unwrap() } @@ -384,17 +313,13 @@ fn autogen_python_product_table_common( AlgebraicType::Sum(sum_type) if sum_type.as_option().is_some() => { reducer_args.push(format!("{{'0': [self.{}]}}", python_field_name)) } - AlgebraicType::Sum(_) => unimplemented!(), - AlgebraicType::Product(_) => { - reducer_args.push(format!("self.{python_field_name}")); - } - Builtin(_) => { + AlgebraicType::Sum(_) | AlgebraicType::Map(_) => unimplemented!(), + ty if ty.is_product() || ty.is_array() || ty.is_scalar_or_string() => { reducer_args.push(format!("self.{python_field_name}")); } AlgebraicType::Ref(type_ref) => { - let ref_type = &ctx.typespace.types[type_ref.idx()]; - if let AlgebraicType::Sum(sum_type) = ref_type { - if is_enum(sum_type) { + if let AlgebraicType::Sum(sum_type) = &ctx.typespace[*type_ref] { + if sum_type.is_simple_enum() { reducer_args.push(format!("{{str({}.value): []}}", python_field_name)) } else { unimplemented!() @@ -403,6 +328,7 @@ fn autogen_python_product_table_common( reducer_args.push(format!("self.{python_field_name}.encode()")); } } + _ => unreachable!(), } } let reducer_args_str = reducer_args.join(", "); @@ -422,7 +348,7 @@ fn autogen_python_product_table_common( } pub fn autogen_python_sum(ctx: &GenCtx, name: &str, sum_type: &SumType) -> String { - if is_enum(sum_type) { + if sum_type.is_simple_enum() { autogen_python_enum(ctx, name, sum_type) } else { unimplemented!() @@ -463,64 +389,35 @@ pub fn autogen_python_tuple(ctx: &GenCtx, name: &str, tuple: &ProductType) -> St autogen_python_product_table_common(ctx, name, tuple, None) } -fn encode_builtintype<'a>( - ctx: &'a GenCtx, - vecnest: usize, - b: &'a BuiltinType, - value: impl fmt::Display + 'a, - ref_prefix: &'a str, -) -> impl fmt::Display + 'a { - fmt_fn(move |f| match maybe_primitive(b) { - MaybePrimitive::Primitive(_) => { - write!(f, "{value}") - } - MaybePrimitive::Array(ArrayType { elem_ty }) if **elem_ty == AlgebraicType::U8 => { - write!(f, "{value}.hex()") - } - MaybePrimitive::Array(ArrayType { elem_ty }) => { - let convert_type = encode_type(ctx, vecnest + 1, elem_ty, "item", ref_prefix); - write!(f, "[{convert_type} for item in {value}]") - } - MaybePrimitive::Map(_) => unimplemented!(), - }) -} - pub fn encode_type<'a>( ctx: &'a GenCtx, - vecnest: usize, ty: &'a AlgebraicType, value: impl fmt::Display + 'a, - ref_prefix: &'a str, ) -> impl fmt::Display + 'a { fmt_fn(move |f| match ty { - AlgebraicType::Product(product) => { - if product.is_identity() { - write!(f, "Identity.from_string({value})") - } else if product.is_address() { - write!(f, "Address.from_string({value})") - } else { - unimplemented!() - } - } + ty if ty.is_address() => write!(f, "Address.from_string({value})"), + ty if ty.is_identity() => write!(f, "Identity.from_string({value})"), AlgebraicType::Sum(sum_type) => match sum_type.as_option() { Some(inner_ty) => write!( f, "{{'0': {}}} if value is not None else {{}}", - encode_type(ctx, vecnest, inner_ty, format!("{value}"), ref_prefix), + encode_type(ctx, inner_ty, format!("{value}")), ), None => unimplemented!(), }, - AlgebraicType::Builtin(b) => fmt::Display::fmt(&encode_builtintype(ctx, vecnest, b, &value, ref_prefix), f), - AlgebraicType::Ref(r) => { - let algebraic_type = &ctx.typespace.types[r.idx()]; - match algebraic_type { - // for enums in json this comes over as a dictionary where the key is actually the enum index - AlgebraicType::Sum(sum_type) if is_enum(sum_type) => write!(f, "{{str({value}.value-1): []}}"), - _ => { - write!(f, "{value}.encode()") - } - } + ty if ty.is_bytes() => write!(f, "{value}.hex()"), + AlgebraicType::Array(ArrayType { elem_ty }) => { + let convert_type = encode_type(ctx, elem_ty, "item"); + write!(f, "[{convert_type} for item in {value}]") } + AlgebraicType::Map(_) | AlgebraicType::Product(_) => unimplemented!(), + ty if ty.is_scalar_or_string() => write!(f, "{value}"), + AlgebraicType::Ref(r) => match &ctx.typespace[*r] { + // for enums in json this comes over as a dictionary where the key is actually the enum index + AlgebraicType::Sum(sum_type) if sum_type.is_simple_enum() => write!(f, "{{str({value}.value-1): []}}"), + _ => write!(f, "{value}.encode()"), + }, + _ => unreachable!(), }) } @@ -549,11 +446,7 @@ pub fn autogen_python_reducer(ctx: &GenCtx, reducer: &ReducerDef) -> String { writeln!(output).unwrap(); let mut imports = Vec::new(); - generate_imports( - ctx, - &reducer.args.clone().into_iter().collect::>(), - &mut imports, - ); + generate_imports(ctx, &reducer.args, &mut imports); for import in imports { writeln!(output, "{import}").unwrap(); @@ -613,7 +506,7 @@ pub fn autogen_python_reducer(ctx: &GenCtx, reducer: &ReducerDef) -> String { writeln!( output, "{python_field_name} = {}", - encode_type(ctx, 0, field_type, format_args!("{python_field_name}"), "") + encode_type(ctx, field_type, format_args!("{python_field_name}")) ) .unwrap(); } @@ -655,7 +548,7 @@ pub fn autogen_python_reducer(ctx: &GenCtx, reducer: &ReducerDef) -> String { let field_type = &arg.algebraic_type; decode_strs.push(format!( "{}", - convert_type(ctx, 0, field_type, format_args!("data[{idx}]"), "") + convert_type(ctx, field_type, format_args!("data[{idx}]")) )); } diff --git a/crates/cli/src/subcommands/generate/rust.rs b/crates/cli/src/subcommands/generate/rust.rs index 7369c0d693..4570223a46 100644 --- a/crates/cli/src/subcommands/generate/rust.rs +++ b/crates/cli/src/subcommands/generate/rust.rs @@ -2,8 +2,7 @@ use super::code_indenter::CodeIndenter; use super::{GenCtx, GenItem}; use convert_case::{Case, Casing}; use spacetimedb_lib::sats::{ - AlgebraicType, AlgebraicTypeRef, ArrayType, BuiltinType, MapType, ProductType, ProductTypeElement, SumType, - SumTypeVariant, + AlgebraicType, AlgebraicTypeRef, ArrayType, ProductType, ProductTypeElement, SumType, SumTypeVariant, }; use spacetimedb_lib::{ColumnIndexAttribute, ReducerDef, TableDef}; use std::collections::HashSet; @@ -14,33 +13,6 @@ type Indenter = CodeIndenter; /// Pairs of (module_name, TypeName). type Imports = HashSet<(String, String)>; -enum MaybePrimitive<'a> { - Primitive(&'a str), - Array(&'a ArrayType), - Map(&'a MapType), -} - -fn maybe_primitive(b: &BuiltinType) -> MaybePrimitive { - MaybePrimitive::Primitive(match b { - BuiltinType::Bool => "bool", - BuiltinType::I8 => "i8", - BuiltinType::U8 => "u8", - BuiltinType::I16 => "i16", - BuiltinType::U16 => "u16", - BuiltinType::I32 => "i32", - BuiltinType::U32 => "u32", - BuiltinType::I64 => "i64", - BuiltinType::U64 => "u64", - BuiltinType::I128 => "i128", - BuiltinType::U128 => "u128", - BuiltinType::String => "String", - BuiltinType::F32 => "f32", - BuiltinType::F64 => "f64", - BuiltinType::Array(ty) => return MaybePrimitive::Array(ty), - BuiltinType::Map(m) => return MaybePrimitive::Map(m), - }) -} - fn write_type_ctx(ctx: &GenCtx, out: &mut Indenter, ty: &AlgebraicType) { write_type(&|r| type_name(ctx, r), out, ty) } @@ -62,12 +34,8 @@ pub fn write_type(ctx: &impl Fn(AlgebraicTypeRef) -> String, out: &mut }); } } - AlgebraicType::Product(p) if p.is_identity() => { - write!(out, "Identity").unwrap(); - } - AlgebraicType::Product(p) if p.is_address() => { - write!(out, "Address").unwrap(); - } + ty if ty.is_identity() => write!(out, "Identity").unwrap(), + ty if ty.is_address() => write!(out, "Address").unwrap(), AlgebraicType::Product(ProductType { elements }) => { print_comma_sep_braced(out, elements, |out: &mut W, elem: &ProductTypeElement| { if let Some(name) = &elem.name { @@ -76,29 +44,40 @@ pub fn write_type(ctx: &impl Fn(AlgebraicTypeRef) -> String, out: &mut write_type(ctx, out, &elem.algebraic_type); }); } - AlgebraicType::Builtin(b) => match maybe_primitive(b) { - MaybePrimitive::Primitive(p) => write!(out, "{}", p).unwrap(), - MaybePrimitive::Array(ArrayType { elem_ty }) => { - write!(out, "Vec::<").unwrap(); - write_type(ctx, out, elem_ty); - write!(out, ">").unwrap(); - } - MaybePrimitive::Map(ty) => { - // TODO: Should `BuiltinType::Map` translate to `HashMap`? This requires - // that any map-key type implement `Hash`. We'll have to derive hash - // on generated types, and notably, `HashMap` is not itself `Hash`, - // so any type that holds a `Map` cannot derive `Hash` and cannot - // key a `Map`. - // UPDATE: No, `AlgebraicType::Map` is supposed to be `BTreeMap`. Fix this. - // This will require deriving `Ord` for generated types, - // and is likely to be a big headache. - write!(out, "HashMap::<").unwrap(); - write_type(ctx, out, &ty.key_ty); - write!(out, ", ").unwrap(); - write_type(ctx, out, &ty.ty); - write!(out, ">").unwrap(); - } - }, + AlgebraicType::Array(ArrayType { elem_ty }) => { + write!(out, "Vec::<").unwrap(); + write_type(ctx, out, elem_ty); + write!(out, ">").unwrap(); + } + AlgebraicType::Map(ty) => { + // TODO: Should `AlgebraicType::Map` translate to `HashMap`? This requires + // that any map-key type implement `Hash`. We'll have to derive hash + // on generated types, and notably, `HashMap` is not itself `Hash`, + // so any type that holds a `Map` cannot derive `Hash` and cannot + // key a `Map`. + // UPDATE: No, `AlgebraicType::Map` is supposed to be `BTreeMap`. Fix this. + // This will require deriving `Ord` for generated types, + // and is likely to be a big headache. + write!(out, "HashMap::<").unwrap(); + write_type(ctx, out, &ty.key_ty); + write!(out, ", ").unwrap(); + write_type(ctx, out, &ty.ty); + write!(out, ">").unwrap(); + } + AlgebraicType::Bool => write!(out, "bool").unwrap(), + AlgebraicType::I8 => write!(out, "i8").unwrap(), + AlgebraicType::U8 => write!(out, "u8").unwrap(), + AlgebraicType::I16 => write!(out, "i16").unwrap(), + AlgebraicType::U16 => write!(out, "u16").unwrap(), + AlgebraicType::I32 => write!(out, "i32").unwrap(), + AlgebraicType::U32 => write!(out, "u32").unwrap(), + AlgebraicType::I64 => write!(out, "i64").unwrap(), + AlgebraicType::U64 => write!(out, "u64").unwrap(), + AlgebraicType::I128 => write!(out, "i128").unwrap(), + AlgebraicType::U128 => write!(out, "u128").unwrap(), + AlgebraicType::String => write!(out, "String").unwrap(), + AlgebraicType::F32 => write!(out, "f32").unwrap(), + AlgebraicType::F64 => write!(out, "f64").unwrap(), AlgebraicType::Ref(r) => { write!(out, "{}", ctx(*r)).unwrap(); } @@ -225,7 +204,7 @@ pub fn autogen_rust_sum(ctx: &GenCtx, name: &str, sum_type: &SumType) -> String out.delimited_block( "{", |out| { - for variant in &sum_type.variants { + for variant in &*sum_type.variants { write_enum_variant(ctx, out, variant); out.newline(); } @@ -1104,12 +1083,11 @@ fn module_name(name: &str) -> String { fn generate_imports(ctx: &GenCtx, imports: &mut Imports, ty: &AlgebraicType) { match ty { - AlgebraicType::Builtin(BuiltinType::Array(ArrayType { elem_ty })) => generate_imports(ctx, imports, elem_ty), - AlgebraicType::Builtin(BuiltinType::Map(map_type)) => { + AlgebraicType::Array(ArrayType { elem_ty }) => generate_imports(ctx, imports, elem_ty), + AlgebraicType::Map(map_type) => { generate_imports(ctx, imports, &map_type.key_ty); generate_imports(ctx, imports, &map_type.ty); } - AlgebraicType::Builtin(_) => (), AlgebraicType::Ref(r) => { let type_name = type_name(ctx, *r); let module_name = module_name(&type_name); @@ -1117,8 +1095,9 @@ fn generate_imports(ctx: &GenCtx, imports: &mut Imports, ty: &AlgebraicType) { } // Recurse into variants of anonymous sum types, e.g. for `Option`, import `T`. AlgebraicType::Sum(s) => generate_imports_variants(ctx, imports, &s.variants), + // Products, scalars, and strings. // Do we need to generate imports for fields of anonymous product types? - _ => (), + _ => {} } } diff --git a/crates/cli/src/subcommands/generate/typescript.rs b/crates/cli/src/subcommands/generate/typescript.rs index 95844c9832..d1c3d05e65 100644 --- a/crates/cli/src/subcommands/generate/typescript.rs +++ b/crates/cli/src/subcommands/generate/typescript.rs @@ -4,40 +4,13 @@ use std::fmt::{self, Write}; use convert_case::{Case, Casing}; use spacetimedb_lib::sats::{ - AlgebraicType, AlgebraicType::Builtin, AlgebraicTypeRef, ArrayType, BuiltinType, MapType, ProductType, - ProductTypeElement, SumType, SumTypeVariant, + AlgebraicType, AlgebraicTypeRef, ArrayType, ProductType, ProductTypeElement, SumType, SumTypeVariant, }; use spacetimedb_lib::{ColumnIndexAttribute, ReducerDef, TableDef}; use super::code_indenter::CodeIndenter; use super::{GenCtx, GenItem, INDENT}; -enum MaybePrimitive<'a> { - Primitive(&'static str), - Array(&'a ArrayType), - Map(&'a MapType), -} - -fn maybe_primitive(b: &BuiltinType) -> MaybePrimitive { - MaybePrimitive::Primitive(match b { - BuiltinType::Bool => "boolean", - BuiltinType::I8 - | BuiltinType::U8 - | BuiltinType::I16 - | BuiltinType::U16 - | BuiltinType::I32 - | BuiltinType::U32 - | BuiltinType::I64 - | BuiltinType::U64 - | BuiltinType::F32 - | BuiltinType::F64 => "number", - BuiltinType::I128 | BuiltinType::U128 => "BigInt", - BuiltinType::String => "string", - BuiltinType::Array(ty) => return MaybePrimitive::Array(ty), - BuiltinType::Map(m) => return MaybePrimitive::Map(m), - }) -} - fn ty_fmt<'a>(ctx: &'a GenCtx, ty: &'a AlgebraicType, ref_prefix: &'a str) -> impl fmt::Display + 'a { fmt_fn(move |f| match ty { AlgebraicType::Sum(sum_type) => { @@ -47,132 +20,48 @@ fn ty_fmt<'a>(ctx: &'a GenCtx, ty: &'a AlgebraicType, ref_prefix: &'a str) -> im unimplemented!() } } - AlgebraicType::Product(prod) => { - // The only type that is allowed here is the identity type. All other types should fail. - if prod.is_identity() { - write!(f, "Identity") - } else if prod.is_address() { - write!(f, "Address") - } else { - unimplemented!() - } + ty if ty.is_identity() => write!(f, "Identity"), + ty if ty.is_address() => write!(f, "Address"), + AlgebraicType::Product(_) => unimplemented!(), + ty if ty.is_bytes() => f.write_str("Uint8Array"), + AlgebraicType::Array(ArrayType { elem_ty }) => { + write!(f, "{}[]", ty_fmt(ctx, elem_ty, ref_prefix)) } - AlgebraicType::Builtin(b) => match maybe_primitive(b) { - MaybePrimitive::Primitive(p) => f.write_str(p), - MaybePrimitive::Array(ArrayType { elem_ty }) if **elem_ty == AlgebraicType::U8 => f.write_str("Uint8Array"), - MaybePrimitive::Array(ArrayType { elem_ty }) => { - write!(f, "{}[]", ty_fmt(ctx, elem_ty, ref_prefix)) - } - MaybePrimitive::Map(ty) => { - write!( - f, - "Map<{}, {}>", - ty_fmt(ctx, &ty.ty, ref_prefix), - ty_fmt(ctx, &ty.key_ty, ref_prefix) - ) - } - }, + AlgebraicType::Map(map_type) => write!( + f, + "Map<{}, {}>", + ty_fmt(ctx, &map_type.ty, ref_prefix), + ty_fmt(ctx, &map_type.key_ty, ref_prefix) + ), + AlgebraicType::Bool => f.write_str("boolean"), + AlgebraicType::I128 | AlgebraicType::U128 => f.write_str("BigInt"), + AlgebraicType::String => f.write_str("string"), + ty if ty.is_int() => f.write_str("number"), AlgebraicType::Ref(r) => write!(f, "{}{}", ref_prefix, typescript_typename(ctx, *r)), - }) -} -fn typescript_as_type(b: &BuiltinType) -> &str { - match b { - BuiltinType::Bool => "Boolean", - BuiltinType::I8 => "Number", - BuiltinType::U8 => "Number", - BuiltinType::I16 => "Number", - BuiltinType::U16 => "Number", - BuiltinType::I32 => "Number", - BuiltinType::U32 => "Number", - BuiltinType::I64 => "Number", - BuiltinType::U64 => "Number", - BuiltinType::I128 => "BigInt", - BuiltinType::U128 => "BigInt", - BuiltinType::F32 => "Number", - BuiltinType::F64 => "Number", - BuiltinType::String => "String", - BuiltinType::Array(_) => "Array", - BuiltinType::Map(_) => "Map", - } -} -fn convert_builtintype<'a>( - ctx: &'a GenCtx, - vecnest: usize, - b: &'a BuiltinType, - value: impl fmt::Display + 'a, - ref_prefix: &'a str, -) -> impl fmt::Display + 'a { - fmt_fn(move |f| match maybe_primitive(b) { - MaybePrimitive::Primitive(_) => { - let typescript_as_type = typescript_as_type(b); - write!(f, "{value}.as{typescript_as_type}()") - } - MaybePrimitive::Array(ArrayType { elem_ty }) if **elem_ty == AlgebraicType::U8 => { - write!(f, "{value}.asBytes()") - } - MaybePrimitive::Array(ArrayType { elem_ty }) => { - let typescript_type = ty_fmt(ctx, elem_ty, ref_prefix); - writeln!( - f, - "{value}.asArray().map(el => {}) as {typescript_type}[];", - convert_type(ctx, vecnest + 1, elem_ty, "el", ref_prefix) - ) - } - MaybePrimitive::Map(_) => todo!(), + _ => unreachable!(), }) } fn convert_type<'a>( ctx: &'a GenCtx, - vecnest: usize, ty: &'a AlgebraicType, value: impl fmt::Display + 'a, ref_prefix: &'a str, ) -> impl fmt::Display + 'a { fmt_fn(move |f| match ty { - AlgebraicType::Product(product) => { - if product.is_identity() { - write!(f, "new Identity({}.asProductValue().elements[0].asBytes())", value) - } else if product.is_address() { - write!(f, "new Address({}.asProductValue().elements[0].asBytes())", value) - } else { - unimplemented!() - } - } + ty if ty.is_identity() => write!(f, "new Identity({}.asProductValue().elements[0].asBytes())", value), + ty if ty.is_address() => write!(f, "new Address({}.asProductValue().elements[0].asBytes())", value), + AlgebraicType::Product(_) => unimplemented!(), AlgebraicType::Sum(sum_type) => { if let Some(inner_ty) = sum_type.as_option() { match inner_ty { - Builtin(ty) => match ty { - BuiltinType::Bool - | BuiltinType::I8 - | BuiltinType::U8 - | BuiltinType::I16 - | BuiltinType::U16 - | BuiltinType::I32 - | BuiltinType::U32 - | BuiltinType::I64 - | BuiltinType::U64 - | BuiltinType::I128 - | BuiltinType::U128 - | BuiltinType::F32 - | BuiltinType::F64 => write!( - f, - "{}.asSumValue().tag == 1 ? null : {}.asSumValue().value{}", - value, - value, - &convert_type(ctx, vecnest, inner_ty, "", ref_prefix), - ), - _ => fmt::Display::fmt( - &convert_type( - ctx, - vecnest, - inner_ty, - format_args!("{value}.asSumValue().tag == 1 ? null : {value}.asSumValue().value"), - ref_prefix - ), - f, - ), - }, + ty if ty.is_scalar() => write!( + f, + "{}.asSumValue().tag == 1 ? null : {}.asSumValue().value{}", + value, + value, + &convert_type(ctx, inner_ty, "", ref_prefix), + ), AlgebraicType::Ref(_) => fmt::Display::fmt( &format!( "function() {{ const value = {}.asSumValue().tag == 1 ? null : {}.asSumValue().value; return value ? {} : null; }}()", @@ -180,7 +69,6 @@ fn convert_type<'a>( value, convert_type( ctx, - vecnest, inner_ty, "value", ref_prefix @@ -191,7 +79,6 @@ fn convert_type<'a>( _ => fmt::Display::fmt( &convert_type( ctx, - vecnest, inner_ty, format_args!("{value}.asSumValue().tag == 1 ? null : {value}.asSumValue().value"), ref_prefix @@ -203,11 +90,25 @@ fn convert_type<'a>( unimplemented!() } } - AlgebraicType::Builtin(b) => fmt::Display::fmt(&convert_builtintype(ctx, vecnest, b, &value, ref_prefix), f), + ty if ty.is_bytes() => write!(f, "{value}.asBytes()"), + AlgebraicType::Array(ArrayType { elem_ty }) => { + let typescript_type = ty_fmt(ctx, elem_ty, ref_prefix); + writeln!( + f, + "{value}.asArray().map(el => {}) as {typescript_type}[];", + convert_type(ctx, elem_ty, "el", ref_prefix) + ) + } + AlgebraicType::Map(_) => write!(f, "{value}.asMap()"), + AlgebraicType::Bool => write!(f, "{value}.asBool()"), + AlgebraicType::I128 | AlgebraicType::U128 => write!(f, "{value}.asBigInt()"), + ty if ty.is_int() => write!(f, "{value}.asNumber()"), + AlgebraicType::String => write!(f, "{value}.asString()"), AlgebraicType::Ref(r) => { let name = typescript_typename(ctx, *r); write!(f, "{ref_prefix}{name}.fromValue({value})",) } + _ => unreachable!(), }) } @@ -233,18 +134,20 @@ fn convert_algebraic_type<'a>(ctx: &'a GenCtx, ty: &'a AlgebraicType, ref_prefix fmt_fn(move |f| match ty { AlgebraicType::Product(product_type) => write!(f, "{}", convert_product_type(ctx, product_type, ref_prefix)), AlgebraicType::Sum(sum_type) => write!(f, "{}", convert_sum_type(ctx, sum_type, ref_prefix)), - AlgebraicType::Builtin(b) => match maybe_primitive(b) { - MaybePrimitive::Primitive(_) => { - write!(f, "AlgebraicType.createPrimitiveType(BuiltinType.Type.{b:?})") - } - MaybePrimitive::Array(ArrayType { elem_ty }) => write!( - f, - "AlgebraicType.createArrayType({})", - convert_algebraic_type(ctx, elem_ty, ref_prefix) - ), - MaybePrimitive::Map(_) => todo!(), - }, + AlgebraicType::Array(ArrayType { elem_ty }) => write!( + f, + "AlgebraicType.createArrayType({})", + convert_algebraic_type(ctx, elem_ty, ref_prefix) + ), + AlgebraicType::Map(map) => write!( + f, + "AlgebraicType.createMapType({}, {})", + convert_algebraic_type(ctx, &map.key_ty, ref_prefix), + convert_algebraic_type(ctx, &map.ty, ref_prefix), + ), + ty if ty.is_scalar_or_string() => write!(f, "AlgebraicType.create{ty:?}Type()"), AlgebraicType::Ref(r) => write!(f, "{ref_prefix}{}.getAlgebraicType()", typescript_typename(ctx, *r)), + _ => unreachable!(), }) } @@ -295,13 +198,8 @@ fn serialize_type<'a>( prefix: &'a str, ) -> impl fmt::Display + 'a { fmt_fn(move |f| match ty { - AlgebraicType::Product(prod) => { - if prod.is_identity() { - write!(f, "Array.from({value}.toUint8Array())") - } else { - unimplemented!() - } - } + ty if ty.is_identity() => write!(f, "Array.from({value}.toUint8Array())"), + AlgebraicType::Product(_) => unimplemented!(), AlgebraicType::Sum(sum_type) => { if let Some(inner_ty) = sum_type.as_option() { write!( @@ -313,16 +211,17 @@ fn serialize_type<'a>( unimplemented!() } } - AlgebraicType::Builtin(BuiltinType::Array(ArrayType { elem_ty })) => match &**elem_ty { - Builtin(BuiltinType::U8) => write!(f, "Array.from({value})"), - Builtin(_) => write!(f, "{value}"), - t => write!(f, "{value}.map(el => {})", serialize_type(ctx, t, "el", prefix)), + AlgebraicType::Array(ArrayType { elem_ty }) => match &**elem_ty { + ty if ty.is_u8() => write!(f, "Array.from({value})"), + ty if ty.is_scalar_or_string() => write!(f, "{value}"), + ty => write!(f, "{value}.map(el => {})", serialize_type(ctx, ty, "el", prefix)), }, - AlgebraicType::Builtin(_) => write!(f, "{value}"), + ty if ty.is_map() || ty.is_scalar_or_string() => write!(f, "{value}"), AlgebraicType::Ref(r) => { let typename = typescript_typename(ctx, *r); write!(f, "{prefix}{typename}.serialize({value})",) } + _ => unreachable!(), }) } @@ -342,7 +241,7 @@ pub fn autogen_typescript_sum(ctx: &GenCtx, name: &str, sum_type: &SumType) -> S writeln!(output, "// @ts-ignore").unwrap(); writeln!( output, - "import {{ __SPACETIMEDB__, AlgebraicType, SumTypeVariant, BuiltinType, AlgebraicValue }} from \"@clockworklabs/spacetimedb-sdk\";" + "import {{ __SPACETIMEDB__, AlgebraicType, SumTypeVariant, AlgebraicValue }} from \"@clockworklabs/spacetimedb-sdk\";" ) .unwrap(); @@ -486,7 +385,7 @@ pub fn autogen_typescript_sum(ctx: &GenCtx, name: &str, sum_type: &SumType) -> S } _ => format!( "{{ tag: \"{variant_name}\", value: {} }}", - convert_type(ctx, 0, field_type, "sumValue.value", "__") + convert_type(ctx, field_type, "sumValue.value", "__") ), }; writeln!(output, "\treturn {result};").unwrap(); @@ -574,7 +473,7 @@ pub fn autogen_typescript_table(ctx: &GenCtx, table: &TableDef) -> String { autogen_typescript_product_table_common(ctx, &table.name, tuple, Some(&table.column_attrs)) } -fn generate_imports(ctx: &GenCtx, elements: &Vec, imports: &mut Vec, prefix: Option<&str>) { +fn generate_imports(ctx: &GenCtx, elements: &[ProductTypeElement], imports: &mut Vec, prefix: Option<&str>) { for field in elements { _generate_imports(ctx, &field.algebraic_type, imports, prefix); } @@ -583,7 +482,7 @@ fn generate_imports(ctx: &GenCtx, elements: &Vec, imports: & // TODO: refactor to allow passing both elements and variants fn generate_imports_variants( ctx: &GenCtx, - variants: &Vec, + variants: &[SumTypeVariant], imports: &mut Vec, prefix: Option<&str>, ) { @@ -594,14 +493,11 @@ fn generate_imports_variants( fn _generate_imports(ctx: &GenCtx, ty: &AlgebraicType, imports: &mut Vec, prefix: Option<&str>) { match ty { - Builtin(b) => match b { - BuiltinType::Array(ArrayType { elem_ty }) => _generate_imports(ctx, elem_ty, imports, prefix), - BuiltinType::Map(map_type) => { - _generate_imports(ctx, &map_type.key_ty, imports, prefix); - _generate_imports(ctx, &map_type.ty, imports, prefix); - } - _ => (), - }, + AlgebraicType::Array(ArrayType { elem_ty }) => _generate_imports(ctx, elem_ty, imports, prefix), + AlgebraicType::Map(map_type) => { + _generate_imports(ctx, &map_type.key_ty, imports, prefix); + _generate_imports(ctx, &map_type.ty, imports, prefix); + } AlgebraicType::Ref(r) => { let class_name = typescript_typename(ctx, *r).to_string(); let filename = typescript_filename(ctx, *r); @@ -645,7 +541,7 @@ fn autogen_typescript_product_table_common( writeln!(output).unwrap(); writeln!(output, "// @ts-ignore").unwrap(); - writeln!(output, "import {{ __SPACETIMEDB__, AlgebraicType, ProductType, BuiltinType, ProductTypeElement, SumType, SumTypeVariant, IDatabaseTable, AlgebraicValue, ReducerEvent, Identity, Address }} from \"@clockworklabs/spacetimedb-sdk\";").unwrap(); + writeln!(output, "import {{ __SPACETIMEDB__, AlgebraicType, ProductType, ProductTypeElement, SumType, SumTypeVariant, IDatabaseTable, AlgebraicValue, ReducerEvent, Identity, Address }} from \"@clockworklabs/spacetimedb-sdk\";").unwrap(); let mut imports = Vec::new(); generate_imports(ctx, &product_type.elements, &mut imports, None); @@ -928,7 +824,7 @@ fn autogen_typescript_product_value_to_struct( writeln!( output, "let __{typescript_field_name} = {};", - convert_type(ctx, 0, field_type, format_args!("productValue.elements[{idx}]"), "") + convert_type(ctx, field_type, format_args!("productValue.elements[{idx}]"), "") ) .unwrap(); } @@ -992,36 +888,27 @@ fn autogen_typescript_access_funcs_for_struct( let typescript_field_name_camel = field_name.replace("r#", "").to_case(Case::Camel); let typescript_field_type = match field_type { - AlgebraicType::Product(product) => { - if product.is_identity() { - "Identity" - } else if product.is_address() { - "Address" - } else { - // TODO: We don't allow filtering on tuples right now, its possible we may consider it for the future. - continue; - } - } - AlgebraicType::Ref(_) | AlgebraicType::Sum(_) => { - // TODO: We don't allow filtering on enums or tuples right now, its possible we may consider it for the future. + AlgebraicType::Bool => "boolean", + AlgebraicType::I128 | AlgebraicType::U128 => "BigInt", + ty if ty.is_int() => "number", + AlgebraicType::String => "string", + ty if ty.is_identity() => "Identity", + ty if ty.is_address() => "Address", + // Do allow filtering for byte arrays. + ty if ty.is_bytes() => "Uint8Array", + AlgebraicType::Product(_) + | AlgebraicType::Sum(_) + | AlgebraicType::Ref(_) + | AlgebraicType::Array(_) + | AlgebraicType::Map(_) => { + // TODO: We don't allow filtering on enums, tuples, arrays, or maps right now, + // its possible we may consider it for the future. + // For maps, it would be nice to be able to say, + // give me all entries where this vec contains this value, + // which we can do. continue; } - AlgebraicType::Builtin(b) => match maybe_primitive(b) { - MaybePrimitive::Primitive(ty) => ty, - MaybePrimitive::Array(ArrayType { elem_ty }) => { - if let Some(BuiltinType::U8) = elem_ty.as_builtin() { - // Do allow filtering for byte arrays - "Uint8Array" - } else { - // TODO: We don't allow filtering based on an array type, but we might want other functionality here in the future. - continue; - } - } - MaybePrimitive::Map(_) => { - // TODO: It would be nice to be able to say, give me all entries where this vec contains this value, which we can do. - continue; - } - }, + _ => unreachable!(), }; let filter_return_type = fmt_fn(|f| { @@ -1150,7 +1037,7 @@ pub fn autogen_typescript_reducer(ctx: &GenCtx, reducer: &ReducerDef) -> String writeln!(output).unwrap(); writeln!(output, "// @ts-ignore").unwrap(); - writeln!(output, "import {{ __SPACETIMEDB__, AlgebraicType, ProductType, BuiltinType, ProductTypeElement, IDatabaseTable, AlgebraicValue, ReducerArgsAdapter, SumTypeVariant, Serializer, Identity, Address, ReducerEvent }} from \"@clockworklabs/spacetimedb-sdk\";").unwrap(); + writeln!(output, "import {{ __SPACETIMEDB__, AlgebraicType, ProductType, ProductTypeElement, IDatabaseTable, AlgebraicValue, ReducerArgsAdapter, SumTypeVariant, Serializer, Identity, Address, ReducerEvent }} from \"@clockworklabs/spacetimedb-sdk\";").unwrap(); let mut imports = Vec::new(); generate_imports( @@ -1253,7 +1140,7 @@ pub fn autogen_typescript_reducer(ctx: &GenCtx, reducer: &ReducerDef) -> String writeln!( output, "let {arg_name} = {};", - convert_type(ctx, 0, ty, format_args!("{arg_name}Value"), "") + convert_type(ctx, ty, format_args!("{arg_name}Value"), "") ) .unwrap(); diff --git a/crates/sats/src/algebraic_type.rs b/crates/sats/src/algebraic_type.rs index 1602e8c6be..098b640ac1 100644 --- a/crates/sats/src/algebraic_type.rs +++ b/crates/sats/src/algebraic_type.rs @@ -5,7 +5,7 @@ use crate::algebraic_value::de::{ValueDeserializeError, ValueDeserializer}; use crate::algebraic_value::ser::ValueSerializer; use crate::meta_type::MetaType; use crate::{de::Deserialize, ser::Serialize, MapType}; -use crate::{AlgebraicTypeRef, AlgebraicValue, ArrayType, BuiltinType, ProductType, SumType, SumTypeVariant}; +use crate::{AlgebraicTypeRef, AlgebraicValue, ArrayType, ProductType, SumType, SumTypeVariant}; use derive_more::From; use enum_as_inner::EnumAsInner; @@ -55,6 +55,12 @@ use enum_as_inner::EnumAsInner; #[derive(EnumAsInner, Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, From)] #[sats(crate = crate)] pub enum AlgebraicType { + /// A type where the definition is given by the typing context (`Typespace`). + /// In other words, this is defined by a pointer to another `AlgebraicType`. + /// + /// This should not be conflated with reference and pointer types in languages like Rust, + /// In other words, this is not `&T` or `*const T`. + Ref(AlgebraicTypeRef), /// A structural sum type. /// /// Unlike most languages, sums in SATs are *[structural]* and not nominal. @@ -104,62 +110,126 @@ pub enum AlgebraicType { /// /// [structural]: https://en.wikipedia.org/wiki/Structural_type_system Product(ProductType), - /// A bulltin type, e.g., `bool`. - Builtin(BuiltinType), - /// A type where the definition is given by the typing context (`Typespace`). - /// In other words, this is defined by a pointer to another `AlgebraicType`. + /// The type of array values where elements are of a base type `elem_ty`. + /// Values [`AlgebraicValue::Array(array)`](crate::AlgebraicValue::Array) will have this type. + Array(ArrayType), + /// The type of map values consisting of a key type `key_ty` and value `ty`. + /// Values [`AlgebraicValue::Map(map)`](crate::AlgebraicValue::Map) will have this type. + /// The order of entries in a map value is observable. + Map(Box), + /// The bool type. Values [`AlgebraicValue::Bool(b)`](crate::AlgebraicValue::Bool) will have this type. + Bool, + /// The `I8` type. Values [`AlgebraicValue::I8(v)`](crate::AlgebraicValue::I8) will have this type. + I8, + /// The `U8` type. Values [`AlgebraicValue::U8(v)`](crate::AlgebraicValue::U8) will have this type. + U8, + /// The `I16` type. Values [`AlgebraicValue::I16(v)`](crate::AlgebraicValue::I16) will have this type. + I16, + /// The `U16` type. Values [`AlgebraicValue::U16(v)`](crate::AlgebraicValue::U16) will have this type. + U16, + /// The `I32` type. Values [`AlgebraicValue::I32(v)`](crate::AlgebraicValue::I32) will have this type. + I32, + /// The `U32` type. Values [`AlgebraicValue::U32(v)`](crate::AlgebraicValue::U32) will have this type. + U32, + /// The `I64` type. Values [`AlgebraicValue::I64(v)`](crate::AlgebraicValue::I64) will have this type. + I64, + /// The `U64` type. Values [`AlgebraicValue::U64(v)`](crate::AlgebraicValue::U64) will have this type. + U64, + /// The `I128` type. Values [`AlgebraicValue::I128(v)`](crate::AlgebraicValue::I128) will have this type. + I128, + /// The `U128` type. Values [`AlgebraicValue::U128(v)`](crate::AlgebraicValue::U128) will have this type. + U128, + /// The `F32` type. Values [`AlgebraicValue::F32(v)`](crate::AlgebraicValue::F32) will have this type. + F32, + /// The `F64` type. Values [`AlgebraicValue::F64(v)`](crate::AlgebraicValue::F64) will have this type. + F64, + /// The UTF-8 encoded `String` type. + /// Values [`AlgebraicValue::String(s)`](crate::AlgebraicValue::String) will have this type. /// - /// This should not be conflated with reference and pointer types in languages like Rust, - /// In other words, this is not `&T` or `*const T`. - Ref(AlgebraicTypeRef), + /// This type exists for convenience and because it is easy to just use Rust's `String` (UTF-8) + /// as opposed to rolling your own equivalent byte-array based UTF-8 encoding. + String, +} + +impl MetaType for AlgebraicType { + /// This is a static function that constructs the type of `AlgebraicType` + /// and returns it as an `AlgebraicType`. + /// + /// This could alternatively be implemented + /// as a regular AlgebraicValue or as a static variable. + fn meta_type() -> Self { + AlgebraicType::sum([ + SumTypeVariant::new_named(AlgebraicTypeRef::meta_type(), "ref"), + SumTypeVariant::new_named(SumType::meta_type(), "sum"), + SumTypeVariant::new_named(ProductType::meta_type(), "product"), + SumTypeVariant::new_named(ArrayType::meta_type(), "array"), + SumTypeVariant::new_named(MapType::meta_type(), "map"), + SumTypeVariant::unit("bool"), + SumTypeVariant::unit("i8"), + SumTypeVariant::unit("u8"), + SumTypeVariant::unit("i16"), + SumTypeVariant::unit("u16"), + SumTypeVariant::unit("i32"), + SumTypeVariant::unit("u32"), + SumTypeVariant::unit("i64"), + SumTypeVariant::unit("u64"), + SumTypeVariant::unit("i128"), + SumTypeVariant::unit("u128"), + SumTypeVariant::unit("f32"), + SumTypeVariant::unit("f64"), + SumTypeVariant::unit("string"), + ]) + } } -#[allow(non_upper_case_globals)] impl AlgebraicType { /// The first type in the typespace. pub const ZERO_REF: Self = Self::Ref(AlgebraicTypeRef(0)); - /// The built-in Bool type. - pub const Bool: Self = Self::Builtin(BuiltinType::Bool); - - /// The built-in signed 8-bit integer type. - pub const I8: Self = Self::Builtin(BuiltinType::I8); - - /// The built-in unsigned 8-bit integer type. - pub const U8: Self = Self::Builtin(BuiltinType::U8); - - /// The built-in signed 16-bit integer type. - pub const I16: Self = Self::Builtin(BuiltinType::I16); - - /// The built-in unsigned 16-bit integer type. - pub const U16: Self = Self::Builtin(BuiltinType::U16); - - /// The built-in signed 32-bit integer type. - pub const I32: Self = Self::Builtin(BuiltinType::I32); - - /// The built-in unsigned 32-bit integer type. - pub const U32: Self = Self::Builtin(BuiltinType::U32); + /// Returns whether this type is the conventional address type. + pub fn is_address(&self) -> bool { + matches!(self, Self::Product(p) if p.is_address()) + } - /// The built-in signed 64-bit integer type. - pub const I64: Self = Self::Builtin(BuiltinType::I64); + /// Returns whether this type is the conventional identity type. + pub fn is_identity(&self) -> bool { + matches!(self, Self::Product(p) if p.is_identity()) + } - /// The built-in unsigned 64-bit integer type. - pub const U64: Self = Self::Builtin(BuiltinType::U64); + /// Returns whether this type is scalar or a string type. + pub fn is_scalar_or_string(&self) -> bool { + self.is_scalar() || self.is_string() + } - /// The built-in signed 128-bit integer type. - pub const I128: Self = Self::Builtin(BuiltinType::I128); + /// Returns whether this type is one which holds a scalar value. + /// + /// A scalar value is one not made up of other values, i.e., not composite. + /// These are all integer and float values, + /// i.e., integer and float types are scalar. + /// References to other types, i.e., [`AlgebraicType::Ref`]s are not scalar. + pub fn is_scalar(&self) -> bool { + self.is_bool() || self.is_int() || self.is_float() + } - /// The built-in unsigned 128-bit integer type. - pub const U128: Self = Self::Builtin(BuiltinType::U128); + /// Returns whether the type is a signed integer type. + pub fn is_signed(&self) -> bool { + matches!(self, Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128) + } - /// The built-in 32-bit floating point type. - pub const F32: Self = Self::Builtin(BuiltinType::F32); + /// Returns whether the type is an unsigned integer type. + pub fn is_unsigned(&self) -> bool { + matches!(self, Self::U8 | Self::U16 | Self::U32 | Self::U64 | Self::U128) + } - /// The built-in 64-bit floating point type. - pub const F64: Self = Self::Builtin(BuiltinType::F64); + /// Returns whether the type is an integer type. + pub fn is_int(&self) -> bool { + self.is_signed() || self.is_unsigned() + } - /// The built-in string type. - pub const String: Self = Self::Builtin(BuiltinType::String); + /// Returns whether the type is a float type. + pub fn is_float(&self) -> bool { + matches!(self, Self::F32 | Self::F64) + } /// The canonical 0-element unit type. pub fn unit() -> Self { @@ -172,25 +242,7 @@ impl AlgebraicType { let vs: [SumTypeVariant; 0] = []; Self::sum(vs) } -} -impl MetaType for AlgebraicType { - /// This is a static function that constructs the type of `AlgebraicType` - /// and returns it as an `AlgebraicType`. - /// - /// This could alternatively be implemented - /// as a regular AlgebraicValue or as a static variable. - fn meta_type() -> Self { - AlgebraicType::sum([ - ("sum", SumType::meta_type()), - ("product", ProductType::meta_type()), - ("builtin", BuiltinType::meta_type()), - ("ref", AlgebraicTypeRef::meta_type()), - ]) - } -} - -impl AlgebraicType { /// A type representing an array of `U8`s. pub fn bytes() -> Self { Self::array(Self::U8) @@ -198,7 +250,7 @@ impl AlgebraicType { /// Returns whether this type is `AlgebraicType::bytes()`. pub fn is_bytes(&self) -> bool { - matches!(self, AlgebraicType::Builtin(BuiltinType::Array(ArrayType { elem_ty })) + matches!(self, AlgebraicType::Array(ArrayType { elem_ty }) if **elem_ty == AlgebraicType::U8 ) } @@ -342,7 +394,7 @@ mod tests { fn algebraic_type() { let algebraic_type = AlgebraicType::meta_type(); assert_eq!( - "(sum: (variants: Array<(name: (some: String | none: ()), algebraic_type: &0)>) | product: (elements: Array<(name: (some: String | none: ()), algebraic_type: &0)>) | builtin: (bool: () | i8: () | u8: () | i16: () | u16: () | i32: () | u32: () | i64: () | u64: () | i128: () | u128: () | f32: () | f64: () | string: () | array: &0 | map: (key_ty: &0, ty: &0)) | ref: U32)", + "(ref: U32 | sum: (variants: Array<(name: (some: String | none: ()), algebraic_type: &0)>) | product: (elements: Array<(name: (some: String | none: ()), algebraic_type: &0)>) | array: &0 | map: (key_ty: &0, ty: &0) | bool: () | i8: () | u8: () | i16: () | u16: () | i32: () | u32: () | i64: () | u64: () | i128: () | u128: () | f32: () | f64: () | string: ())", fmt_algebraic_type(&algebraic_type).to_string() ); } @@ -351,7 +403,7 @@ mod tests { fn algebraic_type_map() { let algebraic_type = AlgebraicType::meta_type(); assert_eq!( - "{ ty_: Sum, sum: { ty_: Product, variants: { ty_: Array, 0: { ty_: Product, name: { ty_: Sum, some: { ty_: String }, none: { ty_: Product } }, algebraic_type: { ty_: Ref, 0: 0 } } } }, product: { ty_: Product, elements: { ty_: Array, 0: { ty_: Product, name: { ty_: Sum, some: { ty_: String }, none: { ty_: Product } }, algebraic_type: { ty_: Ref, 0: 0 } } } }, builtin: { ty_: Sum, bool: { ty_: Product }, i8: { ty_: Product }, u8: { ty_: Product }, i16: { ty_: Product }, u16: { ty_: Product }, i32: { ty_: Product }, u32: { ty_: Product }, i64: { ty_: Product }, u64: { ty_: Product }, i128: { ty_: Product }, u128: { ty_: Product }, f32: { ty_: Product }, f64: { ty_: Product }, string: { ty_: Product }, array: { ty_: Ref, 0: 0 }, map: { ty_: Product, key_ty: { ty_: Ref, 0: 0 }, ty: { ty_: Ref, 0: 0 } } }, ref: { ty_: U32 } }", + "{ ty_: Sum, ref: { ty_: U32 }, sum: { ty_: Product, variants: { ty_: Array, 0: { ty_: Product, name: { ty_: Sum, some: { ty_: String }, none: { ty_: Product } }, algebraic_type: { ty_: Ref, 0: 0 } } } }, product: { ty_: Product, elements: { ty_: Array, 0: { ty_: Product, name: { ty_: Sum, some: { ty_: String }, none: { ty_: Product } }, algebraic_type: { ty_: Ref, 0: 0 } } } }, array: { ty_: Ref, 0: 0 }, map: { ty_: Product, key_ty: { ty_: Ref, 0: 0 }, ty: { ty_: Ref, 0: 0 } }, bool: { ty_: Product }, i8: { ty_: Product }, u8: { ty_: Product }, i16: { ty_: Product }, u16: { ty_: Product }, i32: { ty_: Product }, u32: { ty_: Product }, i64: { ty_: Product }, u64: { ty_: Product }, i128: { ty_: Product }, u128: { ty_: Product }, f32: { ty_: Product }, f64: { ty_: Product }, string: { ty_: Product } }", fmt_map(&algebraic_type).to_string() ); } @@ -395,10 +447,7 @@ mod tests { let algebraic_type = AlgebraicType::meta_type(); let typespace = Typespace::new(vec![algebraic_type]); let at_ref = AlgebraicType::Ref(AlgebraicTypeRef(0)); - assert_eq!( - "(builtin = (u8 = ()))", - in_space(&typespace, &at_ref, &array.as_value()).to_satn() - ); + assert_eq!("(u8 = ())", in_space(&typespace, &at_ref, &array.as_value()).to_satn()); } #[test] @@ -407,7 +456,7 @@ mod tests { let typespace = Typespace::new(vec![algebraic_type.clone()]); let at_ref = AlgebraicType::Ref(AlgebraicTypeRef(0)); assert_eq!( - r#"(sum = (variants = [(name = (some = "sum"), algebraic_type = (product = (elements = [(name = (some = "variants"), algebraic_type = (builtin = (array = (product = (elements = [(name = (some = "name"), algebraic_type = (sum = (variants = [(name = (some = "some"), algebraic_type = (builtin = (string = ()))), (name = (some = "none"), algebraic_type = (product = (elements = [])))]))), (name = (some = "algebraic_type"), algebraic_type = (ref = 0))])))))]))), (name = (some = "product"), algebraic_type = (product = (elements = [(name = (some = "elements"), algebraic_type = (builtin = (array = (product = (elements = [(name = (some = "name"), algebraic_type = (sum = (variants = [(name = (some = "some"), algebraic_type = (builtin = (string = ()))), (name = (some = "none"), algebraic_type = (product = (elements = [])))]))), (name = (some = "algebraic_type"), algebraic_type = (ref = 0))])))))]))), (name = (some = "builtin"), algebraic_type = (sum = (variants = [(name = (some = "bool"), algebraic_type = (product = (elements = []))), (name = (some = "i8"), algebraic_type = (product = (elements = []))), (name = (some = "u8"), algebraic_type = (product = (elements = []))), (name = (some = "i16"), algebraic_type = (product = (elements = []))), (name = (some = "u16"), algebraic_type = (product = (elements = []))), (name = (some = "i32"), algebraic_type = (product = (elements = []))), (name = (some = "u32"), algebraic_type = (product = (elements = []))), (name = (some = "i64"), algebraic_type = (product = (elements = []))), (name = (some = "u64"), algebraic_type = (product = (elements = []))), (name = (some = "i128"), algebraic_type = (product = (elements = []))), (name = (some = "u128"), algebraic_type = (product = (elements = []))), (name = (some = "f32"), algebraic_type = (product = (elements = []))), (name = (some = "f64"), algebraic_type = (product = (elements = []))), (name = (some = "string"), algebraic_type = (product = (elements = []))), (name = (some = "array"), algebraic_type = (ref = 0)), (name = (some = "map"), algebraic_type = (product = (elements = [(name = (some = "key_ty"), algebraic_type = (ref = 0)), (name = (some = "ty"), algebraic_type = (ref = 0))])))]))), (name = (some = "ref"), algebraic_type = (builtin = (u32 = ())))]))"#, + r#"(sum = (variants = [(name = (some = "ref"), algebraic_type = (u32 = ())), (name = (some = "sum"), algebraic_type = (product = (elements = [(name = (some = "variants"), algebraic_type = (array = (product = (elements = [(name = (some = "name"), algebraic_type = (sum = (variants = [(name = (some = "some"), algebraic_type = (string = ())), (name = (some = "none"), algebraic_type = (product = (elements = [])))]))), (name = (some = "algebraic_type"), algebraic_type = (ref = 0))]))))]))), (name = (some = "product"), algebraic_type = (product = (elements = [(name = (some = "elements"), algebraic_type = (array = (product = (elements = [(name = (some = "name"), algebraic_type = (sum = (variants = [(name = (some = "some"), algebraic_type = (string = ())), (name = (some = "none"), algebraic_type = (product = (elements = [])))]))), (name = (some = "algebraic_type"), algebraic_type = (ref = 0))]))))]))), (name = (some = "array"), algebraic_type = (ref = 0)), (name = (some = "map"), algebraic_type = (product = (elements = [(name = (some = "key_ty"), algebraic_type = (ref = 0)), (name = (some = "ty"), algebraic_type = (ref = 0))]))), (name = (some = "bool"), algebraic_type = (product = (elements = []))), (name = (some = "i8"), algebraic_type = (product = (elements = []))), (name = (some = "u8"), algebraic_type = (product = (elements = []))), (name = (some = "i16"), algebraic_type = (product = (elements = []))), (name = (some = "u16"), algebraic_type = (product = (elements = []))), (name = (some = "i32"), algebraic_type = (product = (elements = []))), (name = (some = "u32"), algebraic_type = (product = (elements = []))), (name = (some = "i64"), algebraic_type = (product = (elements = []))), (name = (some = "u64"), algebraic_type = (product = (elements = []))), (name = (some = "i128"), algebraic_type = (product = (elements = []))), (name = (some = "u128"), algebraic_type = (product = (elements = []))), (name = (some = "f32"), algebraic_type = (product = (elements = []))), (name = (some = "f64"), algebraic_type = (product = (elements = []))), (name = (some = "string"), algebraic_type = (product = (elements = [])))]))"#, in_space(&typespace, &at_ref, &algebraic_type.as_value()).to_satn() ); } diff --git a/crates/sats/src/algebraic_type/fmt.rs b/crates/sats/src/algebraic_type/fmt.rs index fe45b5902e..8bf8e4ef9e 100644 --- a/crates/sats/src/algebraic_type/fmt.rs +++ b/crates/sats/src/algebraic_type/fmt.rs @@ -1,5 +1,5 @@ use super::{AlgebraicType, ProductType, SumType}; -use crate::{de::fmt_fn, BuiltinType}; +use crate::de::fmt_fn; use fmt_algebraic_type as fmt; use std::fmt::Display; @@ -17,22 +17,22 @@ pub fn fmt_algebraic_type(ty: &AlgebraicType) -> impl '_ + Display { AlgebraicType::Ref(r) => write!(f, "{}", r), AlgebraicType::Sum(ty) => write!(f, "{}", fmt_sum_type(ty)), AlgebraicType::Product(ty) => write!(f, "{}", fmt_product_type(ty)), - AlgebraicType::Builtin(BuiltinType::Array(a)) => write!(f, "Array<{}>", fmt(&a.elem_ty)), - AlgebraicType::Builtin(BuiltinType::Map(m)) => write!(f, "Map<{}, {}>", fmt(&m.key_ty), fmt(&m.ty)), - &AlgebraicType::Bool => write!(f, "Bool"), - &AlgebraicType::I8 => write!(f, "I8"), - &AlgebraicType::U8 => write!(f, "U8"), - &AlgebraicType::I16 => write!(f, "I16"), - &AlgebraicType::U16 => write!(f, "U16"), - &AlgebraicType::I32 => write!(f, "I32"), - &AlgebraicType::U32 => write!(f, "U32"), - &AlgebraicType::I64 => write!(f, "I64"), - &AlgebraicType::U64 => write!(f, "U64"), - &AlgebraicType::I128 => write!(f, "I128"), - &AlgebraicType::U128 => write!(f, "U128"), - &AlgebraicType::F32 => write!(f, "F32"), - &AlgebraicType::F64 => write!(f, "F64"), - &AlgebraicType::String => write!(f, "String"), + AlgebraicType::Array(a) => write!(f, "Array<{}>", fmt(&a.elem_ty)), + AlgebraicType::Map(m) => write!(f, "Map<{}, {}>", fmt(&m.key_ty), fmt(&m.ty)), + AlgebraicType::Bool => write!(f, "Bool"), + AlgebraicType::I8 => write!(f, "I8"), + AlgebraicType::U8 => write!(f, "U8"), + AlgebraicType::I16 => write!(f, "I16"), + AlgebraicType::U16 => write!(f, "U16"), + AlgebraicType::I32 => write!(f, "I32"), + AlgebraicType::U32 => write!(f, "U32"), + AlgebraicType::I64 => write!(f, "I64"), + AlgebraicType::U64 => write!(f, "U64"), + AlgebraicType::I128 => write!(f, "I128"), + AlgebraicType::U128 => write!(f, "U128"), + AlgebraicType::F32 => write!(f, "F32"), + AlgebraicType::F64 => write!(f, "F64"), + AlgebraicType::String => write!(f, "String"), }) } diff --git a/crates/sats/src/algebraic_type/map_notation.rs b/crates/sats/src/algebraic_type/map_notation.rs index b1edb5ed3d..3951a16838 100644 --- a/crates/sats/src/algebraic_type/map_notation.rs +++ b/crates/sats/src/algebraic_type/map_notation.rs @@ -1,4 +1,4 @@ -use crate::{de::fmt_fn, AlgebraicType, BuiltinType::*}; +use crate::{de::fmt_fn, AlgebraicType}; use std::fmt; /// Wraps an algebraic `ty` in a `Display` impl using a object/map JSON-like notation. @@ -29,21 +29,21 @@ pub fn fmt_algebraic_type(ty: &AlgebraicType) -> impl '_ + fmt::Display { } write!(f, " }}") } - AlgebraicType::Builtin(Array(ty)) => write!(f, "{{ ty_: Array, 0: {} }}", fmt(&ty.elem_ty)), - AlgebraicType::Builtin(Map(map)) => write!(f, "{{ ty_: Map, 0: {}, 1: {} }}", fmt(&map.key_ty), fmt(&map.ty)), - &AlgebraicType::Bool => write!(f, "{{ ty_: Bool }}"), - &AlgebraicType::I8 => write!(f, "{{ ty_: I8 }}"), - &AlgebraicType::U8 => write!(f, "{{ ty_: U8 }}"), - &AlgebraicType::I16 => write!(f, "{{ ty_: I16 }}"), - &AlgebraicType::U16 => write!(f, "{{ ty_: U16 }}"), - &AlgebraicType::I32 => write!(f, "{{ ty_: I32 }}"), - &AlgebraicType::U32 => write!(f, "{{ ty_: U32 }}"), - &AlgebraicType::I64 => write!(f, "{{ ty_: I64 }}"), - &AlgebraicType::U64 => write!(f, "{{ ty_: U64 }}"), - &AlgebraicType::I128 => write!(f, "{{ ty_: I128 }}"), - &AlgebraicType::U128 => write!(f, "{{ ty_: U128 }}"), - &AlgebraicType::F32 => write!(f, "{{ ty_: F32 }}"), - &AlgebraicType::F64 => write!(f, "{{ ty_: F64 }}"), - &AlgebraicType::String => write!(f, "{{ ty_: String }}"), + AlgebraicType::Array(ty) => write!(f, "{{ ty_: Array, 0: {} }}", fmt(&ty.elem_ty)), + AlgebraicType::Map(map) => write!(f, "{{ ty_: Map, 0: {}, 1: {} }}", fmt(&map.key_ty), fmt(&map.ty)), + AlgebraicType::Bool => write!(f, "{{ ty_: Bool }}"), + AlgebraicType::I8 => write!(f, "{{ ty_: I8 }}"), + AlgebraicType::U8 => write!(f, "{{ ty_: U8 }}"), + AlgebraicType::I16 => write!(f, "{{ ty_: I16 }}"), + AlgebraicType::U16 => write!(f, "{{ ty_: U16 }}"), + AlgebraicType::I32 => write!(f, "{{ ty_: I32 }}"), + AlgebraicType::U32 => write!(f, "{{ ty_: U32 }}"), + AlgebraicType::I64 => write!(f, "{{ ty_: I64 }}"), + AlgebraicType::U64 => write!(f, "{{ ty_: U64 }}"), + AlgebraicType::I128 => write!(f, "{{ ty_: I128 }}"), + AlgebraicType::U128 => write!(f, "{{ ty_: U128 }}"), + AlgebraicType::F32 => write!(f, "{{ ty_: F32 }}"), + AlgebraicType::F64 => write!(f, "{{ ty_: F64 }}"), + AlgebraicType::String => write!(f, "{{ ty_: String }}"), }) } diff --git a/crates/sats/src/builtin_type.rs b/crates/sats/src/builtin_type.rs deleted file mode 100644 index ac59c5ba46..0000000000 --- a/crates/sats/src/builtin_type.rs +++ /dev/null @@ -1,87 +0,0 @@ -use crate::algebraic_value::de::{ValueDeserializeError, ValueDeserializer}; -use crate::algebraic_value::ser::ValueSerializer; -use crate::meta_type::MetaType; -use crate::{de::Deserialize, ser::Serialize}; -use crate::{AlgebraicType, AlgebraicValue, ArrayType, MapType, SumTypeVariant}; -use enum_as_inner::EnumAsInner; - -/// Represents the built-in types in SATS. -/// -/// Some of these types are nominal in our otherwise structural type system. -#[derive(EnumAsInner, Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] -#[sats(crate = crate)] -pub enum BuiltinType { - /// The bool type. Values [`BuiltinValue::Bool(b)`](crate::BuiltinValue::Bool) will have this type. - Bool, - /// The `I8` type. Values [`BuiltinValue::I8(v)`](crate::BuiltinValue::I8) will have this type. - I8, - /// The `U8` type. Values [`BuiltinValue::U8(v)`](crate::BuiltinValue::U8) will have this type. - U8, - /// The `I16` type. Values [`BuiltinValue::I16(v)`](crate::BuiltinValue::I16) will have this type. - I16, - /// The `U16` type. Values [`BuiltinValue::U16(v)`](crate::BuiltinValue::U16) will have this type. - U16, - /// The `I32` type. Values [`BuiltinValue::I32(v)`](crate::BuiltinValue::I32) will have this type. - I32, - /// The `U32` type. Values [`BuiltinValue::U32(v)`](crate::BuiltinValue::U32) will have this type. - U32, - /// The `I64` type. Values [`BuiltinValue::I64(v)`](crate::BuiltinValue::I64) will have this type. - I64, - /// The `U64` type. Values [`BuiltinValue::U64(v)`](crate::BuiltinValue::U64) will have this type. - U64, - /// The `I128` type. Values [`BuiltinValue::I128(v)`](crate::BuiltinValue::I128) will have this type. - I128, - /// The `U128` type. Values [`BuiltinValue::U128(v)`](crate::BuiltinValue::U128) will have this type. - U128, - /// The `F32` type. Values [`BuiltinValue::F32(v)`](crate::BuiltinValue::F32) will have this type. - F32, - /// The `F64` type. Values [`BuiltinValue::F64(v)`](crate::BuiltinValue::F64) will have this type. - F64, - /// The UTF-8 encoded `String` type. - /// Values [`BuiltinValue::String(s)`](crate::BuiltinValue::String) will have this type. - /// - /// This type exists for convenience and because it is easy to just use Rust's `String` (UTF-8) - /// as opposed to rolling your own equivalent byte-array based UTF-8 encoding. - String, - /// The type of array values where elements are of a base type `elem_ty`. - /// Values [`BuiltinValue::Array(array)`](crate::BuiltinValue::Array) will have this type. - Array(ArrayType), - /// The type of map values consisting of a key type `key_ty` and value `ty`. - /// Values [`BuiltinValue::Map(map)`](crate::BuiltinValue::Map) will have this type. - /// The order of entries in a map value is observable. - Map(Box), -} - -impl MetaType for BuiltinType { - fn meta_type() -> AlgebraicType { - // TODO: sats(rename_all = "lowercase"), otherwise json won't work. - AlgebraicType::sum([ - SumTypeVariant::unit("bool"), - SumTypeVariant::unit("i8"), - SumTypeVariant::unit("u8"), - SumTypeVariant::unit("i16"), - SumTypeVariant::unit("u16"), - SumTypeVariant::unit("i32"), - SumTypeVariant::unit("u32"), - SumTypeVariant::unit("i64"), - SumTypeVariant::unit("u64"), - SumTypeVariant::unit("i128"), - SumTypeVariant::unit("u128"), - SumTypeVariant::unit("f32"), - SumTypeVariant::unit("f64"), - SumTypeVariant::unit("string"), - SumTypeVariant::new_named(ArrayType::meta_type(), "array"), - SumTypeVariant::new_named(MapType::meta_type(), "map"), - ]) - } -} - -impl BuiltinType { - pub fn as_value(&self) -> AlgebraicValue { - self.serialize(ValueSerializer).unwrap_or_else(|x| match x {}) - } - - pub fn from_value(value: &AlgebraicValue) -> Result { - Self::deserialize(ValueDeserializer::from_ref(value)) - } -} diff --git a/crates/sats/src/convert.rs b/crates/sats/src/convert.rs index 31e864d9dd..fd8a0ddf74 100644 --- a/crates/sats/src/convert.rs +++ b/crates/sats/src/convert.rs @@ -1,4 +1,4 @@ -use crate::{AlgebraicType, AlgebraicValue, ArrayType, BuiltinType, MapType, ProductType, ProductValue}; +use crate::{AlgebraicType, AlgebraicValue, MapType, ProductType, ProductValue}; use spacetimedb_primitives::{ColId, ConstraintId, IndexId, SequenceId, TableId}; impl crate::Value for AlgebraicValue { @@ -23,15 +23,9 @@ impl From for ProductType { } } -impl From for AlgebraicType { - fn from(x: ArrayType) -> Self { - BuiltinType::Array(x).into() - } -} - impl From for AlgebraicType { fn from(x: MapType) -> Self { - BuiltinType::Map(Box::new(x)).into() + Box::new(x).into() } } diff --git a/crates/sats/src/de/impls.rs b/crates/sats/src/de/impls.rs index 365e7172f0..5c9f5ead3a 100644 --- a/crates/sats/src/de/impls.rs +++ b/crates/sats/src/de/impls.rs @@ -302,8 +302,8 @@ impl<'de> DeserializeSeed<'de> for WithTypespace<'_, AlgebraicType> { AlgebraicType::Ref(r) => self.resolve(*r).deserialize(de), AlgebraicType::Sum(sum) => self.with(sum).deserialize(de).map(Into::into), AlgebraicType::Product(prod) => self.with(prod).deserialize(de).map(Into::into), - AlgebraicType::Builtin(crate::BuiltinType::Array(ty)) => self.with(ty).deserialize(de).map(Into::into), - AlgebraicType::Builtin(crate::BuiltinType::Map(ty)) => self.with(&**ty).deserialize(de).map(Into::into), + AlgebraicType::Array(ty) => self.with(ty).deserialize(de).map(Into::into), + AlgebraicType::Map(ty) => self.with(&**ty).deserialize(de).map(Into::into), &AlgebraicType::Bool => bool::deserialize(de).map(Into::into), &AlgebraicType::I8 => i8::deserialize(de).map(Into::into), &AlgebraicType::U8 => u8::deserialize(de).map(Into::into), @@ -435,10 +435,10 @@ impl<'de> DeserializeSeed<'de> for WithTypespace<'_, ArrayType> { AlgebraicType::Product(ty) => deserializer .deserialize_array_seed(BasicVecVisitor, self.with(ty)) .map(ArrayValue::Product), - AlgebraicType::Builtin(crate::BuiltinType::Array(ty)) => deserializer + AlgebraicType::Array(ty) => deserializer .deserialize_array_seed(BasicVecVisitor, self.with(ty)) .map(ArrayValue::Array), - AlgebraicType::Builtin(crate::BuiltinType::Map(ty)) => deserializer + AlgebraicType::Map(ty) => deserializer .deserialize_array_seed(BasicVecVisitor, self.with(&**ty)) .map(ArrayValue::Map), &AlgebraicType::Bool => de_array(deserializer, ArrayValue::Bool), diff --git a/crates/sats/src/lib.rs b/crates/sats/src/lib.rs index 242d663fa9..35a4866e89 100644 --- a/crates/sats/src/lib.rs +++ b/crates/sats/src/lib.rs @@ -5,7 +5,6 @@ pub mod array_type; pub mod array_value; pub mod bsatn; pub mod buffer; -pub mod builtin_type; pub mod convert; pub mod de; pub mod map_type; @@ -27,7 +26,6 @@ pub use algebraic_type_ref::AlgebraicTypeRef; pub use algebraic_value::{AlgebraicValue, F32, F64}; pub use array_type::ArrayType; pub use array_value::ArrayValue; -pub use builtin_type::BuiltinType; pub use map_type::MapType; pub use map_value::MapValue; pub use product_type::ProductType; diff --git a/crates/sats/src/resolve_refs.rs b/crates/sats/src/resolve_refs.rs index d57f98f2a8..abe167fc7e 100644 --- a/crates/sats/src/resolve_refs.rs +++ b/crates/sats/src/resolve_refs.rs @@ -1,6 +1,6 @@ use crate::{ - AlgebraicType, AlgebraicTypeRef, ArrayType, BuiltinType, MapType, ProductType, ProductTypeElement, SumType, - SumTypeVariant, WithTypespace, + AlgebraicType, AlgebraicTypeRef, ArrayType, MapType, ProductType, ProductTypeElement, SumType, SumTypeVariant, + WithTypespace, }; /// Resolver for [`AlgebraicTypeRef`]s within a structure. @@ -68,8 +68,8 @@ impl ResolveRefs for AlgebraicType { Self::Ref(r) => this.with(r)._resolve_refs(state), Self::Sum(sum) => this.with(sum)._resolve_refs(state).map(Into::into), Self::Product(prod) => this.with(prod)._resolve_refs(state).map(Into::into), - Self::Builtin(BuiltinType::Array(ty)) => this.with(ty)._resolve_refs(state).map(Into::into), - Self::Builtin(BuiltinType::Map(m)) => this.with(&**m)._resolve_refs(state).map(Into::into), + Self::Array(ty) => this.with(ty)._resolve_refs(state).map(Into::into), + Self::Map(m) => this.with(&**m)._resolve_refs(state).map(Into::into), // These types are plain and cannot have refs in them. x => Some(x.clone()), } diff --git a/crates/sats/src/ser/impls.rs b/crates/sats/src/ser/impls.rs index f5f25d3620..2a2423f6af 100644 --- a/crates/sats/src/ser/impls.rs +++ b/crates/sats/src/ser/impls.rs @@ -147,8 +147,8 @@ impl_serialize!([] ValueWithType<'_, AlgebraicValue>, (self, ser) => { } (AlgebraicValue::Sum(val), AlgebraicType::Sum(ty)) => self.with(ty, val).serialize(ser), (AlgebraicValue::Product(val), AlgebraicType::Product(ty)) => self.with(ty, val).serialize(ser), - (AlgebraicValue::Array(val), AlgebraicType::Builtin(crate::BuiltinType::Array(ty))) => self.with(ty, val).serialize(ser), - (AlgebraicValue::Map(val), AlgebraicType::Builtin(crate::BuiltinType::Map(ty))) => self.with(&**ty, val).serialize(ser), + (AlgebraicValue::Array(val), AlgebraicType::Array(ty)) => self.with(ty, val).serialize(ser), + (AlgebraicValue::Map(val), AlgebraicType::Map(ty)) => self.with(&**ty, val).serialize(ser), (AlgebraicValue::Bool(v), &AlgebraicType::Bool) => ser.serialize_bool(*v), (AlgebraicValue::I8(v), &AlgebraicType::I8) => ser.serialize_i8(*v), (AlgebraicValue::U8(v), &AlgebraicType::U8) => ser.serialize_u8(*v), @@ -196,7 +196,7 @@ impl_serialize!([] ValueWithType<'_, ProductValue>, (self, ser) => { impl_serialize!([] ValueWithType<'_, ArrayValue>, (self, ser) => match (self.value(), &*self.ty().elem_ty) { (ArrayValue::Sum(v), AlgebraicType::Sum(ty)) => self.with(ty, v).serialize(ser), (ArrayValue::Product(v), AlgebraicType::Product(ty)) => self.with(ty, v).serialize(ser), - (ArrayValue::Map(v), AlgebraicType::Builtin(crate::BuiltinType::Map(m))) => self.with(&**m, v).serialize(ser), + (ArrayValue::Map(v), AlgebraicType::Map(m)) => self.with(&**m, v).serialize(ser), (ArrayValue::Bool(v), &AlgebraicType::Bool) => v.serialize(ser), (ArrayValue::I8(v), &AlgebraicType::I8) => v.serialize(ser), (ArrayValue::U8(v), &AlgebraicType::U8) => v.serialize(ser), @@ -211,7 +211,7 @@ impl_serialize!([] ValueWithType<'_, ArrayValue>, (self, ser) => match (self.val (ArrayValue::F32(v), &AlgebraicType::F32) => v.serialize(ser), (ArrayValue::F64(v), &AlgebraicType::F64) => v.serialize(ser), (ArrayValue::String(v), &AlgebraicType::String) => v.serialize(ser), - (ArrayValue::Array(v), AlgebraicType::Builtin(crate::BuiltinType::Array(ty))) => self.with(ty, v).serialize(ser), + (ArrayValue::Array(v), AlgebraicType::Array(ty)) => self.with(ty, v).serialize(ser), (val, _) if val.is_empty() => ser.serialize_array(0)?.end(), (val, ty) => panic!("mismatched value and schema: {val:?} {ty:?}"), }); diff --git a/crates/sqltest/src/space.rs b/crates/sqltest/src/space.rs index fe773c9d72..325b70a664 100644 --- a/crates/sqltest/src/space.rs +++ b/crates/sqltest/src/space.rs @@ -9,7 +9,7 @@ use spacetimedb_lib::identity::AuthCtx; use spacetimedb_lib::relation::MemTable; use spacetimedb_sats::meta_type::MetaType; use spacetimedb_sats::satn::Satn; -use spacetimedb_sats::{AlgebraicType, AlgebraicValue, BuiltinType}; +use spacetimedb_sats::{AlgebraicType, AlgebraicValue}; use sqllogictest::{AsyncDB, ColumnType, DBOutput}; use std::fs; use std::io::Write; @@ -31,7 +31,7 @@ impl ColumnType for Kind { fn to_char(&self) -> char { match self.0 { - AlgebraicType::Builtin(BuiltinType::Map(_)) | AlgebraicType::Builtin(BuiltinType::Array(_)) => '?', + AlgebraicType::Map(_) | AlgebraicType::Array(_) => '?', AlgebraicType::I8 | AlgebraicType::U8 | AlgebraicType::U16