diff --git a/crates/bindings-csharp/BSATN.Codegen/Type.cs b/crates/bindings-csharp/BSATN.Codegen/Type.cs index 4bfbf45ec7e..c2142f16535 100644 --- a/crates/bindings-csharp/BSATN.Codegen/Type.cs +++ b/crates/bindings-csharp/BSATN.Codegen/Type.cs @@ -84,6 +84,12 @@ public static TypeUse Parse(ISymbol member, ITypeSymbol typeSymbol, DiagReporter ), INamedTypeSymbol named => named.OriginalDefinition.ToString() switch { + "SpacetimeDB.Result" or "SpacetimeDB.Result" => new ResultUse( + type, + typeInfo, + Parse(member, named.TypeArguments[0], diag), + Parse(member, named.TypeArguments[1], diag) + ), "System.Collections.Generic.List" => new ListUse( type, typeInfo, @@ -101,6 +107,14 @@ public static TypeUse Parse(ISymbol member, ITypeSymbol typeSymbol, DiagReporter }; } + /// + /// Get the name of the BSATN struct for this type. + /// + public virtual string to_bsatn_string() + { + return this.BSATNName; + } + /// /// Get a statement that declares outVar and assigns (inVar1 logically-equals inVar2) to it. /// logically-equals: @@ -133,6 +147,40 @@ public abstract string EqualsStatement( public abstract string GetHashCodeStatement(string inVar, string outVar, int level = 0); } +/// +/// A use of a Result type. +/// +public sealed record ResultUse : TypeUse +{ + public TypeUse Ok { get; } + public TypeUse Err { get; } + + public string TypeName { get; } + + public ResultUse(string typeName, string typeInfo, TypeUse ok, TypeUse err) + : base(typeName, typeInfo) + { + Ok = ok; + Err = err; + TypeName = typeName; + } + + public override string to_bsatn_string() + { + return $"{TypeName}.BSATN<{Ok.BSATNName}, {Err.BSATNName}>"; + } + + public override string EqualsStatement( + string inVar1, + string inVar2, + string outVar, + int level = 0 + ) => $"var {outVar} = {inVar1} == {inVar2};"; + + public override string GetHashCodeStatement(string inVar, string outVar, int level = 0) => + $"var {outVar} = {inVar}.GetHashCode();"; +} + /// /// A use of an enum type. /// (This is a C# enum, not one of our tagged enums.) @@ -348,7 +396,7 @@ IEnumerable members return string.Join( "\n ", members.Select(m => - $"{visStr} static readonly {m.Type.BSATNName} {m.Name}{TypeUse.BsatnFieldSuffix} = new();" + $"{visStr} static readonly {m.Type.to_bsatn_string()} {m.Name}{TypeUse.BsatnFieldSuffix} = new();" ) ); } diff --git a/crates/bindings-csharp/BSATN.Runtime/BSATN/AlgebraicType.cs b/crates/bindings-csharp/BSATN.Runtime/BSATN/AlgebraicType.cs index 603feae5c78..862c40fa43a 100644 --- a/crates/bindings-csharp/BSATN.Runtime/BSATN/AlgebraicType.cs +++ b/crates/bindings-csharp/BSATN.Runtime/BSATN/AlgebraicType.cs @@ -49,4 +49,8 @@ Unit F64 // Special AlgebraicType that can be recognised by the SpacetimeDB `generate` CLI as an Option. internal static AlgebraicType MakeOption(AlgebraicType someType) => new Sum([new("some", someType), new("none", Unit)]); + + // Special AlgebraicType that can be recognised by the SpacetimeDB `generate` CLI as a Result. + internal static AlgebraicType MakeResult(AlgebraicType okType, AlgebraicType errType) => + new Sum([new("ok", okType), new("err", errType)]); } diff --git a/crates/bindings-csharp/BSATN.Runtime/Builtins.cs b/crates/bindings-csharp/BSATN.Runtime/Builtins.cs index a3478d18023..6817dc20bbd 100644 --- a/crates/bindings-csharp/BSATN.Runtime/Builtins.cs +++ b/crates/bindings-csharp/BSATN.Runtime/Builtins.cs @@ -605,3 +605,77 @@ public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) => // --- / customized --- } } + +public partial record Result : TaggedEnum<(T Ok, E Err)> +{ + public static implicit operator Result(T value) => new Ok(value); + + public static implicit operator Result(E error) => new Err(error); + + public TResult Match(Func onOk, Func onErr) => + this switch + { + Ok(var v) => onOk(v), + Err(var e) => onErr(e), + _ => throw new InvalidOperationException("Unknown Result variant."), + }; + + // ----- auto-generated ----- + + private Result() { } + + internal enum @enum : byte + { + Ok, + Err, + } + + public sealed record Ok(T Value) : Result; + + public sealed record Err(E Error) : Result; + + private enum Variant : byte + { + Ok = 0, + Err = 1, + } + + public readonly struct BSATN : IReadWrite> + where OkRW : struct, IReadWrite + where ErrRW : struct, IReadWrite + { + private static readonly SpacetimeDB.BSATN.Enum<@enum> __enumTag = new(); + private static readonly OkRW okRW = new(); + private static readonly ErrRW errRW = new(); + + public Result Read(BinaryReader reader) => + __enumTag.Read(reader) switch + { + @enum.Ok => new Ok(okRW.Read(reader)), + @enum.Err => new Err(errRW.Read(reader)), + _ => throw new InvalidOperationException(), + }; + + public void Write(BinaryWriter writer, Result value) + { + switch (value) + { + case Ok(var v): + __enumTag.Write(writer, @enum.Ok); + okRW.Write(writer, v); + break; + + case Err(var e): + __enumTag.Write(writer, @enum.Err); + errRW.Write(writer, e); + break; + } + } + + public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) => + AlgebraicType.MakeResult( + okRW.GetAlgebraicType(registrar), + errRW.GetAlgebraicType(registrar) + ); + } +} diff --git a/crates/bindings-csharp/Codegen/Module.cs b/crates/bindings-csharp/Codegen/Module.cs index 9988f7b027c..e0876c2392a 100644 --- a/crates/bindings-csharp/Codegen/Module.cs +++ b/crates/bindings-csharp/Codegen/Module.cs @@ -1168,7 +1168,7 @@ public Scope.Extensions GenerateSchedule() using var writer = new BinaryWriter(stream); {{string.Join( "\n", - Args.Select(a => $"new {a.Type.BSATNName}().Write(writer, {a.Name});") + Args.Select(a => $"new {a.Type.to_bsatn_string()}().Write(writer, {a.Name});") )}} SpacetimeDB.Internal.IReducer.VolatileNonatomicScheduleImmediate(nameof({{Name}}), stream); } @@ -1239,7 +1239,7 @@ public string GenerateClass() var result = {{FullName}}((SpacetimeDB.ProcedureContext)ctx{{invocationArgs}}); using var output = new MemoryStream(); using var writer = new BinaryWriter(output); - new {{ReturnType.BSATNName}}().Write(writer, result); + new {{ReturnType.to_bsatn_string()}}().Write(writer, result); return output.ToArray(); """; @@ -1283,7 +1283,7 @@ public Scope.Extensions GenerateSchedule() using var writer = new BinaryWriter(stream); {{string.Join( "\n", - Args.Select(a => $"new {a.Type.BSATNName}().Write(writer, {a.Name});") + Args.Select(a => $"new {a.Type.to_bsatn_string()}().Write(writer, {a.Name});") )}} SpacetimeDB.Internal.IProcedure.VolatileNonatomicScheduleImmediate(nameof({{Name}}), stream); } diff --git a/crates/bindings-typescript/src/index.ts b/crates/bindings-typescript/src/index.ts index 6e8c97d64e7..bac8310e3b0 100644 --- a/crates/bindings-typescript/src/index.ts +++ b/crates/bindings-typescript/src/index.ts @@ -9,4 +9,5 @@ export * from './lib/timestamp'; export * from './lib/util'; export * from './lib/identity'; export * from './lib/option'; +export * from './lib/result'; export * from './sdk'; diff --git a/crates/bindings-typescript/src/lib/algebraic_type.ts b/crates/bindings-typescript/src/lib/algebraic_type.ts index 82a95287eee..99a5da6623e 100644 --- a/crates/bindings-typescript/src/lib/algebraic_type.ts +++ b/crates/bindings-typescript/src/lib/algebraic_type.ts @@ -439,6 +439,36 @@ export const SumType = { } else { writer.writeByte(1); } + } else if ( + ty.variants.length == 2 && + ty.variants[0].name === 'ok' && + ty.variants[1].name === 'err' + ) { + let variantName: 'ok' | 'err'; + let innerValue: any; + let index: number; + if ('ok' in value) { + variantName = 'ok'; + innerValue = value.ok; + index = 0; + } else { + variantName = 'err'; + innerValue = value.err; + index = 1; + } + + if (index < 0) { + throw `Result serialization error: variant '${variantName}' not found in ${JSON.stringify(ty)}`; + } + + writer.writeU8(index); + + AlgebraicType.serializeValue( + writer, + ty.variants[index].algebraicType, + innerValue, + typespace + ); } else { const variant = value['tag']; const index = ty.variants.findIndex(v => v.name === variant); @@ -479,6 +509,28 @@ export const SumType = { } else { throw `Can't deserialize an option type, couldn't find ${tag} tag`; } + } else if ( + ty.variants.length == 2 && + ty.variants[0].name === 'ok' && + ty.variants[1].name === 'err' + ) { + if (tag === 0) { + const value = AlgebraicType.deserializeValue( + reader, + ty.variants[0].algebraicType, + typespace + ); + return { ok: value }; + } else if (tag === 1) { + const value = AlgebraicType.deserializeValue( + reader, + ty.variants[1].algebraicType, + typespace + ); + return { err: value }; + } else { + throw `Can't deserialize a result type, couldn't find ${tag} tag`; + } } else { const variant = ty.variants[tag]; const value = AlgebraicType.deserializeValue( diff --git a/crates/bindings-typescript/src/lib/result.ts b/crates/bindings-typescript/src/lib/result.ts new file mode 100644 index 00000000000..5ea0d682048 --- /dev/null +++ b/crates/bindings-typescript/src/lib/result.ts @@ -0,0 +1,36 @@ +import { AlgebraicType } from './algebraic_type'; + +export type ResultAlgebraicType< + T extends AlgebraicType = AlgebraicType, + E extends AlgebraicType = AlgebraicType, +> = { + tag: 'Sum'; + value: { + variants: [ + { name: 'ok'; algebraicType: T }, + { name: 'err'; algebraicType: E }, + ]; + }; +}; + +export const Result: { + getAlgebraicType< + T extends AlgebraicType = AlgebraicType, + E extends AlgebraicType = AlgebraicType, + >( + okType: T, + errType: E + ): ResultAlgebraicType; +} = { + getAlgebraicType< + T extends AlgebraicType = AlgebraicType, + E extends AlgebraicType = AlgebraicType, + >(okType: T, errType: E): ResultAlgebraicType { + return AlgebraicType.Sum({ + variants: [ + { name: 'ok', algebraicType: okType }, + { name: 'err', algebraicType: errType }, + ], + }); + }, +}; diff --git a/crates/bindings-typescript/src/lib/schema.ts b/crates/bindings-typescript/src/lib/schema.ts index 51a0edae5e7..b249ea4549a 100644 --- a/crates/bindings-typescript/src/lib/schema.ts +++ b/crates/bindings-typescript/src/lib/schema.ts @@ -16,6 +16,7 @@ import { type InferSpacetimeTypeOfTypeBuilder, type RowObj, type VariantsObj, + ResultBuilder, } from './type_builders'; import type { UntypedTableDef } from './table'; import { @@ -203,6 +204,11 @@ export function registerTypesRecursively< return new OptionBuilder( registerTypesRecursively(typeBuilder.value) ) as any; + } else if (typeBuilder instanceof ResultBuilder) { + return new ResultBuilder( + registerTypesRecursively(typeBuilder.ok), + registerTypesRecursively(typeBuilder.err) + ) as any; } else if (typeBuilder instanceof ArrayBuilder) { return new ArrayBuilder( registerTypesRecursively(typeBuilder.element) diff --git a/crates/bindings-typescript/src/lib/type_builders.ts b/crates/bindings-typescript/src/lib/type_builders.ts index 371b7ee8942..a4749fe3002 100644 --- a/crates/bindings-typescript/src/lib/type_builders.ts +++ b/crates/bindings-typescript/src/lib/type_builders.ts @@ -4,6 +4,7 @@ import type BinaryWriter from './binary_writer'; import { ConnectionId, type ConnectionIdAlgebraicType } from './connection_id'; import { Identity, type IdentityAlgebraicType } from './identity'; import { Option, type OptionAlgebraicType } from './option'; +import { Result, type ResultAlgebraicType } from './result'; import ScheduleAt, { type ScheduleAtAlgebraicType } from './schedule_at'; import type { CoerceRow } from './table'; import { TimeDuration, type TimeDurationAlgebraicType } from './time_duration'; @@ -1211,6 +1212,57 @@ export class OptionBuilder> } } +export class ResultBuilder< + Ok extends TypeBuilder, + Err extends TypeBuilder, + > + extends TypeBuilder< + InferTypeOfTypeBuilder | InferTypeOfTypeBuilder, + ResultAlgebraicType< + InferSpacetimeTypeOfTypeBuilder, + InferSpacetimeTypeOfTypeBuilder + > + > + implements + Defaultable< + InferTypeOfTypeBuilder | InferTypeOfTypeBuilder, + ResultAlgebraicType< + InferSpacetimeTypeOfTypeBuilder, + InferSpacetimeTypeOfTypeBuilder + > + > +{ + ok: Ok; + err: Err; + + constructor(ok: Ok, err: Err) { + super(Result.getAlgebraicType(ok.algebraicType, err.algebraicType)); + this.ok = ok; + this.err = err; + } + default( + value: InferTypeOfTypeBuilder | InferTypeOfTypeBuilder + ): ResultColumnBuilder< + Ok, + Err, + SetField< + DefaultMetadata, + 'defaultValue', + InferTypeOfTypeBuilder | InferTypeOfTypeBuilder + > + > { + return new ResultColumnBuilder< + Ok, + Err, + SetField< + DefaultMetadata, + 'defaultValue', + InferTypeOfTypeBuilder | InferTypeOfTypeBuilder + > + >(this, set(defaultMetadata, { defaultValue: value })); + } +} + export class ProductBuilder extends TypeBuilder< ObjectType, @@ -2653,6 +2705,54 @@ export class OptionColumnBuilder< } } +export class ResultColumnBuilder< + Ok extends TypeBuilder, + Err extends TypeBuilder, + M extends ColumnMetadata< + InferTypeOfTypeBuilder | InferTypeOfTypeBuilder + > = DefaultMetadata, + > + extends ColumnBuilder< + InferTypeOfTypeBuilder | InferTypeOfTypeBuilder, + ResultAlgebraicType< + InferSpacetimeTypeOfTypeBuilder, + InferSpacetimeTypeOfTypeBuilder + >, + M + > + implements + Defaultable< + InferTypeOfTypeBuilder | InferTypeOfTypeBuilder, + ResultAlgebraicType< + InferSpacetimeTypeOfTypeBuilder, + InferSpacetimeTypeOfTypeBuilder + > + > +{ + constructor(typeBuilder: TypeBuilder, metadata: M) { + super(typeBuilder, metadata); + } + + default( + value: InferTypeOfTypeBuilder | InferTypeOfTypeBuilder + ): ResultColumnBuilder< + Ok, + Err, + SetField< + M, + 'defaultValue', + InferTypeOfTypeBuilder | InferTypeOfTypeBuilder + > + > { + return new ResultColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { + defaultValue: value, + }) + ); + } +} + export class ProductColumnBuilder< Elements extends ElementsObj, M extends ColumnMetadata> = DefaultMetadata, @@ -3291,6 +3391,20 @@ export const t = { return new OptionBuilder(value); }, + /** + * This is a convenience method for creating a column with the {@link Result} type. + * You can create a column of the same type by constructing an enum with an `ok` and `err` variant. + * @param ok The type of the value contained in the `ok` variant of the `Result`. + * @param err The type of the value contained in the `err` variant of the `Result`. + * @returns A new {@link ResultBuilder} instance with the {@link Result} type. + */ + result, Err extends TypeBuilder>( + ok: Ok, + err: Err + ): ResultBuilder { + return new ResultBuilder(ok, err); + }, + /** * This is a convenience method for creating a column with the {@link Identity} type. * You can create a column of the same type by constructing an `object` with a single `__identity__` element. diff --git a/crates/codegen/src/csharp.rs b/crates/codegen/src/csharp.rs index c07265a6d69..d7ba9560c8c 100644 --- a/crates/codegen/src/csharp.rs +++ b/crates/codegen/src/csharp.rs @@ -1103,6 +1103,12 @@ fn ty_fmt<'a>(module: &'a ModuleDef, ty: &'a AlgebraicTypeUse) -> impl fmt::Disp AlgebraicTypeUse::TimeDuration => f.write_str("SpacetimeDB.TimeDuration"), AlgebraicTypeUse::Unit => f.write_str("SpacetimeDB.Unit"), AlgebraicTypeUse::Option(inner_ty) => write!(f, "{}?", ty_fmt(module, inner_ty)), + AlgebraicTypeUse::Result { ok_ty, err_ty } => write!( + f, + "SpacetimeDB.Result<{}, {}>", + ty_fmt(module, ok_ty), + ty_fmt(module, err_ty) + ), AlgebraicTypeUse::Array(elem_ty) => write!(f, "System.Collections.Generic.List<{}>", ty_fmt(module, elem_ty)), AlgebraicTypeUse::String => f.write_str("string"), AlgebraicTypeUse::Ref(r) => f.write_str(&type_ref_name(module, *r)), @@ -1137,6 +1143,12 @@ fn ty_fmt_with_ns<'a>(module: &'a ModuleDef, ty: &'a AlgebraicTypeUse, namespace AlgebraicTypeUse::TimeDuration => f.write_str("SpacetimeDB.TimeDuration"), AlgebraicTypeUse::Unit => f.write_str("SpacetimeDB.Unit"), AlgebraicTypeUse::Option(inner_ty) => write!(f, "{}?", ty_fmt_with_ns(module, inner_ty, namespace)), + AlgebraicTypeUse::Result { ok_ty, err_ty } => write!( + f, + "SpacetimeDB.Result<{}, {}>", + ty_fmt_with_ns(module, ok_ty, namespace), + ty_fmt_with_ns(module, err_ty, namespace) + ), AlgebraicTypeUse::Array(elem_ty) => write!( f, "System.Collections.Generic.List<{}>", @@ -1189,6 +1201,8 @@ fn default_init(ctx: &TypespaceForGenerate, ty: &AlgebraicTypeUse) -> Option<&'s | AlgebraicTypeUse::ConnectionId | AlgebraicTypeUse::Timestamp | AlgebraicTypeUse::TimeDuration => None, + // Result is a struct, initialized to the "Ok with default T" variant. + AlgebraicTypeUse::Result { .. } => None, AlgebraicTypeUse::Never => unimplemented!("never types are not yet supported in C# output"), } } diff --git a/crates/codegen/src/rust.rs b/crates/codegen/src/rust.rs index 9bcb427298c..6057a29cf28 100644 --- a/crates/codegen/src/rust.rs +++ b/crates/codegen/src/rust.rs @@ -621,6 +621,13 @@ pub fn write_type(module: &ModuleDef, out: &mut W, ty: &AlgebraicTypeU write_type(module, out, inner_ty)?; write!(out, ">")?; } + AlgebraicTypeUse::Result { ok_ty, err_ty } => { + write!(out, "Result::<")?; + write_type(module, out, ok_ty)?; + write!(out, ", ")?; + write_type(module, out, err_ty)?; + write!(out, ">")?; + } AlgebraicTypeUse::Primitive(prim) => match prim { PrimitiveType::Bool => write!(out, "bool")?, PrimitiveType::I8 => write!(out, "i8")?, diff --git a/crates/codegen/src/typescript.rs b/crates/codegen/src/typescript.rs index 254506a8f98..8f6fcdf242b 100644 --- a/crates/codegen/src/typescript.rs +++ b/crates/codegen/src/typescript.rs @@ -728,6 +728,13 @@ fn write_type_builder(module: &ModuleDef, out: &mut W, ty: &AlgebraicT write_type_builder(module, out, inner_ty)?; write!(out, ")")?; } + AlgebraicTypeUse::Result { ok_ty, err_ty } => { + write!(out, "__t.result(")?; + write_type_builder(module, out, ok_ty)?; + write!(out, ", ")?; + write_type_builder(module, out, err_ty)?; + write!(out, ")")?; + } AlgebraicTypeUse::Primitive(prim) => match prim { PrimitiveType::Bool => write!(out, "__t.bool()")?, PrimitiveType::I8 => write!(out, "__t.i8()")?, @@ -840,7 +847,7 @@ fn needs_parens_within_array(ty: &AlgebraicTypeUse) -> bool { | AlgebraicTypeUse::String => { false } - AlgebraicTypeUse::ScheduleAt | AlgebraicTypeUse::Option(_) => { + AlgebraicTypeUse::ScheduleAt | AlgebraicTypeUse::Option(_) | AlgebraicTypeUse::Result { .. } => { true } } @@ -868,6 +875,11 @@ pub fn write_type( write_type(module, out, inner_ty, ref_prefix, ref_suffix)?; write!(out, " | undefined")?; } + AlgebraicTypeUse::Result { ok_ty, err_ty } => { + write_type(module, out, ok_ty, ref_prefix, ref_suffix)?; + write!(out, " | ")?; + write_type(module, out, err_ty, ref_prefix, ref_suffix)?; + } AlgebraicTypeUse::Primitive(prim) => match prim { PrimitiveType::Bool => write!(out, "boolean")?, PrimitiveType::I8 => write!(out, "number")?, diff --git a/crates/codegen/src/unrealcpp.rs b/crates/codegen/src/unrealcpp.rs index 2fe7abd60e7..cd93321e458 100644 --- a/crates/codegen/src/unrealcpp.rs +++ b/crates/codegen/src/unrealcpp.rs @@ -4473,6 +4473,9 @@ fn should_pass_by_value_in_delegate(_module: &ModuleDef, ty: &AlgebraicTypeUse) AlgebraicTypeUse::Ref(_) => false, AlgebraicTypeUse::Array(_) => false, // Arrays use const references AlgebraicTypeUse::Option(inner) => should_pass_by_value_in_delegate(_module, inner), + AlgebraicTypeUse::Result { ok_ty, err_ty } => { + should_pass_by_value_in_delegate(_module, ok_ty) && should_pass_by_value_in_delegate(_module, err_ty) + } AlgebraicTypeUse::ScheduleAt => false, AlgebraicTypeUse::Never => false, } @@ -4520,6 +4523,9 @@ fn is_blueprintable(module: &ModuleDef, ty: &AlgebraicTypeUse) -> bool { } } AlgebraicTypeUse::Option(inner) => is_blueprintable(module, inner), + AlgebraicTypeUse::Result { ok_ty, err_ty } => { + is_blueprintable(module, ok_ty) && is_blueprintable(module, err_ty) + } AlgebraicTypeUse::Never => false, } } @@ -4553,6 +4559,9 @@ fn is_type_blueprintable_for_delegates(module: &ModuleDef, ty: &AlgebraicTypeUse } } AlgebraicTypeUse::Option(inner) => is_type_blueprintable_for_delegates(module, inner), + AlgebraicTypeUse::Result { ok_ty, err_ty } => { + is_type_blueprintable_for_delegates(module, ok_ty) && is_type_blueprintable_for_delegates(module, err_ty) + } AlgebraicTypeUse::Never => false, } } @@ -4991,6 +5000,14 @@ fn cpp_ty_fmt_impl<'a>( } } + // Result use the generated result types + AlgebraicTypeUse::Result { ok_ty, err_ty } => { + let ok_type = cpp_ty_fmt_impl(module, ok_ty, module_name).to_string(); + let err_type = cpp_ty_fmt_impl(module, err_ty, module_name).to_string(); + + write!(f, "FSpacetimeDBResult<{ok_type}, {err_type}>") + } + AlgebraicTypeUse::Never => unreachable!("never type"), }) } @@ -5028,6 +5045,8 @@ fn cpp_ty_init_fmt_impl<'a>(ty: &'a AlgebraicTypeUse) -> impl fmt::Display + 'a AlgebraicTypeUse::Ref(_r) => f.write_str(""), // Options use the generated optional types AlgebraicTypeUse::Option(_inner) => f.write_str(""), + // Result use the generated result types + AlgebraicTypeUse::Result { ok_ty: _, err_ty: _ } => f.write_str(""), AlgebraicTypeUse::Never => unreachable!("never type"), }) } @@ -5055,6 +5074,13 @@ fn collect_includes_for_type( // Also collect includes for the inner type collect_includes_for_type(module, inner, out, module_name); } + Result { ok_ty, err_ty } => { + // Add the result type header + out.insert("Types/Result.h".to_string()); + // Also collect includes for the ok and err types + collect_includes_for_type(module, ok_ty, out, module_name); + collect_includes_for_type(module, err_ty, out, module_name); + } Array(inner) => { collect_includes_for_type(module, inner, out, module_name); } diff --git a/crates/lib/tests/serde.rs b/crates/lib/tests/serde.rs index dfc6eef0957..661cc94116d 100644 --- a/crates/lib/tests/serde.rs +++ b/crates/lib/tests/serde.rs @@ -70,6 +70,10 @@ fn test_json_mappings() { enumm([("Hash", AlgebraicType::bytes()), ("Unit", AlgebraicType::unit())]).into(), ), ("and_peggy", AlgebraicType::option(AlgebraicType::F64)), + ( + "result", + AlgebraicType::result(AlgebraicType::U32, AlgebraicType::String), + ), ("identity", Identity::get_type()), ]); @@ -80,6 +84,7 @@ fn test_json_mappings() { "baz": ["heyyyyyy", "hooo"], "quux": { "Hash": "54a3e6d2b0959deaacf102292b1cbd6fcbb8cf237f73306e27ed82c3153878aa" }, "and_peggy": { "some": 3.141592653589793238426 }, + "result": { "ok": 1 }, "identity": ["0x0"] } "#; // all of those ^^^^^^ digits are from memory @@ -92,6 +97,7 @@ fn test_json_mappings() { "baz": ["it's 🥶°C"], "quux": { "Unit": [] }, "and_peggy": null, + "result": { "err": "sorry" }, "identity": ["0x0"] } "#; diff --git a/crates/lib/tests/snapshots/serde__json_mappings-2.snap b/crates/lib/tests/snapshots/serde__json_mappings-2.snap index db77cada11d..659a82a5a1b 100644 --- a/crates/lib/tests/snapshots/serde__json_mappings-2.snap +++ b/crates/lib/tests/snapshots/serde__json_mappings-2.snap @@ -1,6 +1,6 @@ --- source: crates/lib/tests/serde.rs -expression: "de_json({\n \"foo\": 5654,\n \"bar\": [1, 15, 44],\n \"baz\": [\"it's 🥶°C\"],\n \"quux\": { \"Unit\": [] },\n \"and_peggy\": null,\n \"identity\": [\"0x0\"]\n})" +expression: "de_json({\n \"foo\": 5654,\n \"bar\": [1, 15, 44],\n \"baz\": [\"it's 🥶°C\"],\n \"quux\": { \"Unit\": [] },\n \"and_peggy\": null,\n \"result\": { \"err\": \"sorry\" },\n \"identity\": [\"0x0\"]\n})" --- ( foo = 5654, @@ -14,6 +14,9 @@ expression: "de_json({\n \"foo\": 5654,\n \"bar\": [1, 15, 44],\n \"baz and_peggy = ( none = (), ), + result = ( + err = "sorry", + ), identity = ( __identity__ = 0, ), diff --git a/crates/lib/tests/snapshots/serde__json_mappings.snap b/crates/lib/tests/snapshots/serde__json_mappings.snap index 4bd8dcf4986..5f48e829bdd 100644 --- a/crates/lib/tests/snapshots/serde__json_mappings.snap +++ b/crates/lib/tests/snapshots/serde__json_mappings.snap @@ -1,6 +1,6 @@ --- source: crates/lib/tests/serde.rs -expression: "de_json({\n \"foo\": 42,\n \"bar\": \"404040FFFF0A48656C6C6F\",\n \"baz\": [\"heyyyyyy\", \"hooo\"],\n \"quux\": { \"Hash\": \"54a3e6d2b0959deaacf102292b1cbd6fcbb8cf237f73306e27ed82c3153878aa\" },\n \"and_peggy\": { \"some\": 3.141592653589793238426 },\n \"identity\": [\"0x0\"]\n})" +expression: "de_json({\n \"foo\": 42,\n \"bar\": \"404040FFFF0A48656C6C6F\",\n \"baz\": [\"heyyyyyy\", \"hooo\"],\n \"quux\": { \"Hash\": \"54a3e6d2b0959deaacf102292b1cbd6fcbb8cf237f73306e27ed82c3153878aa\" },\n \"and_peggy\": { \"some\": 3.141592653589793238426 },\n \"result\": { \"ok\": 1 },\n \"identity\": [\"0x0\"]\n})" --- ( foo = 42, @@ -15,6 +15,9 @@ expression: "de_json({\n \"foo\": 42,\n \"bar\": \"404040FFFF0A48656C6C6F\ and_peggy = ( some = 3.141592653589793, ), + result = ( + ok = 1, + ), identity = ( __identity__ = 0, ), diff --git a/crates/pg/src/encoder.rs b/crates/pg/src/encoder.rs index f5a6ed990ed..dc07f70c9e5 100644 --- a/crates/pg/src/encoder.rs +++ b/crates/pg/src/encoder.rs @@ -239,6 +239,15 @@ mod tests { let row = run(schema, value).await; assert_eq!(row, "\0\0\0\u{b}{\"some\": 1}\0\0\0\u{c}{\"none\": {}}"); + let result = AlgebraicType::result(AlgebraicType::I64, AlgebraicType::String); + let schema = ProductType::from([result.clone(), result.clone()]); + let value = product![ + AlgebraicValue::sum(0, AlgebraicValue::I64(1)), // Ok(1) + AlgebraicValue::sum(1, AlgebraicValue::String("error".into())), // Err("error") + ]; + let row = run(schema, value).await; + assert_eq!(row, "\0\0\0\t{\"ok\": 1}\0\0\0\u{10}{\"err\": \"error\"}"); + let color = AlgebraicType::Sum([SumTypeVariant::new_named(AlgebraicType::I64, "Gray")].into()); let nested = AlgebraicType::option(color.clone()); let schema = ProductType::from([color, nested]); diff --git a/crates/sats/src/algebraic_type.rs b/crates/sats/src/algebraic_type.rs index e42ba015639..8e0e1922af5 100644 --- a/crates/sats/src/algebraic_type.rs +++ b/crates/sats/src/algebraic_type.rs @@ -6,7 +6,7 @@ use crate::algebraic_value::ser::value_serialize; use crate::de::Deserialize; use crate::meta_type::MetaType; use crate::product_type::{CONNECTION_ID_TAG, IDENTITY_TAG, TIMESTAMP_TAG, TIME_DURATION_TAG}; -use crate::sum_type::{OPTION_NONE_TAG, OPTION_SOME_TAG}; +use crate::sum_type::{OPTION_NONE_TAG, OPTION_SOME_TAG, RESULT_ERR_TAG, RESULT_OK_TAG}; use crate::typespace::Typespace; use crate::{i256, u256}; use crate::{AlgebraicTypeRef, AlgebraicValue, ArrayType, ProductType, SpacetimeType, SumType, SumTypeVariant}; @@ -213,6 +213,17 @@ impl AlgebraicType { self.as_sum()?.as_option() } + /// Returns whether this type is a result type. + pub fn is_result(&self) -> bool { + matches!(self, Self::Sum(p) if p.is_result()) + } + + /// If this type is the standard result type, returns the types of the `ok` and `err` variants. + /// Otherwise, returns `None`. + pub fn as_result(&self) -> Option<(&AlgebraicType, &AlgebraicType)> { + self.as_sum()?.as_result() + } + /// Returns whether this type is scalar or a string type. pub fn is_scalar_or_string(&self) -> bool { self.is_scalar() || self.is_string() @@ -306,6 +317,12 @@ impl AlgebraicType { Self::sum([(OPTION_SOME_TAG, some_type), (OPTION_NONE_TAG, AlgebraicType::unit())]) } + /// Returns a structural result type where `ok_type` is the type for the `ok` variant + /// and `err_type` is the type for the `err` variant. + pub fn result(ok_type: Self, err_type: Self) -> Self { + Self::sum([(RESULT_OK_TAG, ok_type), (RESULT_ERR_TAG, err_type)]) + } + /// Returns an unsized array type where the element type is `ty`. pub fn array(ty: Self) -> Self { ArrayType { elem_ty: Box::new(ty) }.into() @@ -432,7 +449,7 @@ impl AlgebraicType { /// - a reference /// - a special, known type /// - a non-compound type like `U8`, `I32`, `F64`, etc. - /// - or a map, array, or option built from types that satisfy [`AlgebraicType::is_valid_for_client_type_use`] + /// - or a map, array, option, or result built from types that satisfy [`AlgebraicType::is_valid_for_client_type_use`] /// /// This method does not actually follow `Ref`s to check the types they point to, /// it only checks the structure of the type. @@ -441,6 +458,8 @@ impl AlgebraicType { AlgebraicType::Sum(sum) => { if let Some(wrapped) = sum.as_option() { wrapped.is_valid_for_client_type_use() + } else if let Some((ok_ty, err_ty)) = sum.as_result() { + ok_ty.is_valid_for_client_type_use() && err_ty.is_valid_for_client_type_use() } else { sum.is_special() || sum.is_empty() } @@ -542,6 +561,21 @@ mod tests { ); } + #[test] + fn result() { + let result = AlgebraicType::result(AlgebraicType::U8, AlgebraicType::String); + assert_eq!("(ok: U8 | err: String)", fmt_algebraic_type(&result).to_string()); + } + + #[test] + fn result_map() { + let result = AlgebraicType::result(AlgebraicType::U8, AlgebraicType::String); + assert_eq!( + "{ ty_: Sum, ok: { ty_: U8 }, err: { ty_: String } }", + fmt_map(&result).to_string() + ); + } + #[test] fn algebraic_type() { let algebraic_type = AlgebraicType::meta_type(); @@ -648,6 +682,18 @@ mod tests { ); } + #[test] + fn result_as_value() { + let result = AlgebraicType::result(AlgebraicType::U8, AlgebraicType::String); + let algebraic_type = AlgebraicType::meta_type(); + let typespace = Typespace::new(vec![algebraic_type]); + let at_ref = AlgebraicType::Ref(AlgebraicTypeRef(0)); + assert_eq!( + r#"(sum = (variants = [(name = (some = "ok"), algebraic_type = (u8 = ())), (name = (some = "err"), algebraic_type = (string = ()))]))"#, + in_space(&typespace, &at_ref, &result.as_value()).to_satn() + ); + } + #[test] fn algebraic_type_as_value() { let algebraic_type = AlgebraicType::meta_type(); @@ -718,6 +764,12 @@ mod tests { AlgebraicType::from_value(&option.as_value()).expect("No errors."); } + #[test] + fn result_from_value() { + let result = AlgebraicType::result(AlgebraicType::U8, AlgebraicType::String); + AlgebraicType::from_value(&result.as_value()).expect("No errors."); + } + #[test] fn builtin_from_value() { let u8 = AlgebraicType::U8; diff --git a/crates/sats/src/algebraic_value.rs b/crates/sats/src/algebraic_value.rs index 5b0859beeea..6fb94c1457e 100644 --- a/crates/sats/src/algebraic_value.rs +++ b/crates/sats/src/algebraic_value.rs @@ -188,6 +188,34 @@ impl AlgebraicValue { Self::sum(1, Self::unit()) } + /// Converts `self` into an `Result`, if applicable. + pub fn into_result(self) -> Result { + match self { + AlgebraicValue::Sum(sum_value) => match sum_value.tag { + 0 => Ok(*sum_value.value), + 1 => Err(*sum_value.value), + _ => Err(AlgebraicValue::Sum(sum_value)), + }, + _ => Err(self), + } + } + + /// Returns an [`AlgebraicValue`] for ` Ok: v`. + /// + /// The `Ok` variant is assigned the tag `0`. + #[inline] + pub fn ResultOk(v: Self) -> Self { + Self::sum(0, v) + } + + /// Returns an [`AlgebraicValue`] for ` Err: v`. + /// + /// The `Err` variant is assigned the tag `1`. + #[inline] + pub fn ResultErr(v: Self) -> Self { + Self::sum(1, v) + } + /// Returns an [`AlgebraicValue`] representing a sum value with `tag` and `value`. pub fn sum(tag: u8, value: Self) -> Self { Self::Sum(SumValue::new(tag, value)) @@ -343,6 +371,17 @@ mod tests { assert_eq!("(none = ())", in_space(&typespace, &option, &sum_value).to_satn(),); } + #[test] + fn result() { + let result = AlgebraicType::result(AlgebraicType::U8, AlgebraicType::String); + let ok = AlgebraicValue::ResultOk(AlgebraicValue::U8(42)); + let typespace = Typespace::new(vec![]); + assert_eq!("(ok = 42)", in_space(&typespace, &result, &ok).to_satn(),); + + let err = AlgebraicValue::ResultErr(AlgebraicValue::String("error".into())); + assert_eq!("(err = \"error\")", in_space(&typespace, &result, &err).to_satn(),); + } + #[test] fn primitive() { let u8 = AlgebraicType::U8; diff --git a/crates/sats/src/proptest.rs b/crates/sats/src/proptest.rs index f0344520714..da30690c3de 100644 --- a/crates/sats/src/proptest.rs +++ b/crates/sats/src/proptest.rs @@ -232,7 +232,7 @@ fn generate_ref(typespace_len: u32) -> BoxedStrategy { } /// Generate a type valid to be used to generate a type *use* in a client module. -/// That is, a ref, non-compound type, a special type, or an array, map, or option of the same. +/// That is, a ref, non-compound type, a special type, or an array, map, option, result of the same. fn generate_type_valid_for_client_use() -> impl Strategy { let leaf = prop_oneof![ generate_non_compound_algebraic_type(), @@ -246,6 +246,7 @@ fn generate_type_valid_for_client_use() -> impl Strategy prop_oneof![ gen_element.clone().prop_map(AlgebraicType::array), gen_element.clone().prop_map(AlgebraicType::option), + gen_element.clone().prop_map(|x| AlgebraicType::result(x.clone(), x)), ] }) } diff --git a/crates/sats/src/sum_type.rs b/crates/sats/src/sum_type.rs index 7bb26e0bb5f..4d9afca349c 100644 --- a/crates/sats/src/sum_type.rs +++ b/crates/sats/src/sum_type.rs @@ -12,6 +12,10 @@ pub const SCHEDULE_AT_TIME_TAG: &str = "Time"; pub const OPTION_SOME_TAG: &str = "some"; /// The tag used for the `none` variant of the special `option` sum type. pub const OPTION_NONE_TAG: &str = "none"; +/// The tag used for the `ok` variant of the special `result` sum type. +pub const RESULT_OK_TAG: &str = "ok"; +/// The tag used for the `err` variant of the special `result` sum type. +pub const RESULT_ERR_TAG: &str = "err"; /// A structural sum type. /// @@ -119,6 +123,55 @@ impl SumType { self.as_option().is_some() } + /// Check whether this sum type is a structural result type. + /// + /// A structural result type has `ok(T)` as its first variant and `err(E)` as its second. + /// That is, `{ ok(T), err(E) }` or `ok: T | err: E` depending on your notation. + /// Note that `ok` and `err` are lowercase, unlike Rust's `Result`. + /// Order matters, and a result type with these variants in the opposite order will not be recognized. + /// + /// If the type does look like a structural result type, returns the types `T` and `E`. + pub fn as_result(&self) -> Option<(&AlgebraicType, &AlgebraicType)> { + match &*self.variants { + [first, second] if Self::are_variants_result(first, second) => { + Some((&first.algebraic_type, &second.algebraic_type)) + } + _ => None, + } + } + + /// Check whether this sum type is a structural result type. + /// + /// A structural result type has `ok(T)` as its first variant and `err(E)` as its second. + /// That is, `{ ok(T), err(E) }` or `ok: T | err: E` depending on your notation. + /// Note that `ok` and `err` are lowercase, unlike Rust's `Result`. + /// Order matters, and a result type with these variants in the opposite order will not be recognized. + /// + /// If the type does look like a structural result type, returns the types `T` and `E`. + pub fn as_result_mut(&mut self) -> Option<(&mut AlgebraicType, &mut AlgebraicType)> { + match &mut *self.variants { + [first, second] if Self::are_variants_result(first, second) => { + Some((&mut first.algebraic_type, &mut second.algebraic_type)) + } + _ => None, + } + } + + fn are_variants_result(first: &SumTypeVariant, second: &SumTypeVariant) -> bool { + first.has_name(RESULT_OK_TAG) && second.has_name(RESULT_ERR_TAG) + } + + /// Check whether this sum type is a structural result type. + /// + /// A structural result type has `ok(T)` as its first variant and `err(E)` as its second. + /// That is, `{ ok(T), err(E) }` or `ok: T | err: E` depending on your notation. + /// Note that `ok` and `err` are lowercase, unlike Rust's `Result`. + /// + /// Order matters, and a result type with these variants in the opposite order will not be recognized. + pub fn is_result(&self) -> bool { + self.as_result().is_some() + } + /// Return whether this sum type is empty, that is, has no variants. pub fn is_empty(&self) -> bool { self.variants.is_empty() @@ -139,9 +192,9 @@ impl SumType { } } - /// Returns whether this sum type is a special known type, currently `Option` or `ScheduleAt`. + /// Returns whether this sum type is a special known type, currently `Option`, `ScheduleAt`, or `Result`. pub fn is_special(&self) -> bool { - self.is_option() || self.is_schedule_at() + self.is_option() || self.is_schedule_at() || self.is_result() } /// Returns whether this sum type is like on in C without data attached to the variants. diff --git a/crates/sats/src/typespace.rs b/crates/sats/src/typespace.rs index f7d0978d660..3f75f17c8de 100644 --- a/crates/sats/src/typespace.rs +++ b/crates/sats/src/typespace.rs @@ -290,6 +290,7 @@ pub trait GroundSpacetimeType { /// - `String` and `&str`, utf-8 string data /// - `()`, the unit type /// - `Option where T: SpacetimeType` +/// - `Result where T: SpacetimeType, E: SpacetimeType` /// - `Vec where T: SpacetimeType` /// /// (Storing collections in rows of a database table is a form of [denormalization](https://en.wikipedia.org/wiki/Denormalization).) @@ -427,6 +428,16 @@ impl_st!([] bytes::Bytes, AlgebraicType::bytes()); #[cfg(feature = "bytestring")] impl_st!([] bytestring::ByteString, AlgebraicType::String); +impl SpacetimeType for Result +where + T: SpacetimeType, + E: SpacetimeType, +{ + fn make_type(typespace: &mut S) -> AlgebraicType { + AlgebraicType::result(T::make_type(typespace), E::make_type(typespace)) + } +} + #[cfg(test)] mod tests { use crate::proptest::generate_typespace_valid_for_codegen; @@ -466,5 +477,18 @@ mod tests { assert_not_valid(AlgebraicType::option(AlgebraicType::array(AlgebraicType::option( bad_inner_1.clone(), )))); + + assert_not_valid(AlgebraicType::result(bad_inner_1.clone(), AlgebraicType::U8)); + assert_not_valid(AlgebraicType::result(AlgebraicType::U8, bad_inner_2.clone())); + + assert_not_valid(AlgebraicType::result( + AlgebraicType::array(AlgebraicType::result(bad_inner_1.clone(), AlgebraicType::U8)), + AlgebraicType::U8, + )); + + assert_not_valid(AlgebraicType::result( + AlgebraicType::U8, + AlgebraicType::array(AlgebraicType::result(AlgebraicType::U8, bad_inner_2.clone())), + )); } } diff --git a/crates/schema/src/type_for_generate.rs b/crates/schema/src/type_for_generate.rs index 6c2a259f080..a915b999b0a 100644 --- a/crates/schema/src/type_for_generate.rs +++ b/crates/schema/src/type_for_generate.rs @@ -281,6 +281,12 @@ pub enum AlgebraicTypeUse { /// A standard structural option type. Option(Arc), + /// A standard structural result type. + Result { + ok_ty: Arc, + err_ty: Arc, + }, + /// The special `ScheduleAt` type. ScheduleAt, @@ -329,6 +335,10 @@ impl AlgebraicTypeUse { AlgebraicTypeUse::Ref(ref_) => f(*ref_), AlgebraicTypeUse::Array(elem_ty) => elem_ty._for_each_ref(f), AlgebraicTypeUse::Option(elem_ty) => elem_ty._for_each_ref(f), + AlgebraicTypeUse::Result { ok_ty, err_ty } => { + ok_ty._for_each_ref(f); + err_ty._for_each_ref(f); + } _ => {} } } @@ -398,6 +408,12 @@ impl TypespaceForGenerateBuilder<'_> { let elem_ty = self.parse_use(elem_ty)?; let interned = self.intern_use(elem_ty); Ok(AlgebraicTypeUse::Option(interned)) + } else if let Some((ok_ty, err_ty)) = ty.as_result() { + let ok = self.parse_use(ok_ty)?; + let err = self.parse_use(err_ty)?; + let ok_ty = self.intern_use(ok); + let err_ty = self.intern_use(err); + Ok(AlgebraicTypeUse::Result { ok_ty, err_ty }) } else if ty.is_schedule_at() { Ok(AlgebraicTypeUse::ScheduleAt) } else { @@ -708,11 +724,19 @@ mod tests { let ref1 = t.add(AlgebraicType::array(AlgebraicType::Ref(def))); let ref2 = t.add(AlgebraicType::option(AlgebraicType::Ref(ref1))); let ref3 = t.add(AlgebraicType::Ref(ref2)); + let ref4 = t.add(AlgebraicType::result( + AlgebraicType::Ref(ref3), + AlgebraicType::Ref(ref2), + )); let expected_0 = AlgebraicTypeUse::Ref(def); let expected_1 = AlgebraicTypeUse::Array(Arc::new(expected_0.clone())); let expected_2 = AlgebraicTypeUse::Option(Arc::new(expected_1.clone())); let expected_3 = expected_2.clone(); + let expected_4 = AlgebraicTypeUse::Result { + ok_ty: Arc::new(expected_3.clone()), + err_ty: Arc::new(expected_2.clone()), + }; let mut for_generate_forward = TypespaceForGenerate::builder(&t, [def]); for_generate_forward.add_definition(def).unwrap(); @@ -720,13 +744,16 @@ mod tests { let use1 = for_generate_forward.parse_use(&ref1.into()).unwrap(); let use2 = for_generate_forward.parse_use(&ref2.into()).unwrap(); let use3 = for_generate_forward.parse_use(&ref3.into()).unwrap(); + let use4 = for_generate_forward.parse_use(&ref4.into()).unwrap(); assert_eq!(use0, expected_0); assert_eq!(use1, expected_1); assert_eq!(use2, expected_2); assert_eq!(use3, expected_3); + assert_eq!(use4, expected_4); let mut for_generate_backward = TypespaceForGenerate::builder(&t, [def]); + let use4 = for_generate_backward.parse_use(&ref4.into()).unwrap(); let use3 = for_generate_forward.parse_use(&ref3.into()).unwrap(); let use2 = for_generate_forward.parse_use(&ref2.into()).unwrap(); let use1 = for_generate_forward.parse_use(&ref1.into()).unwrap(); @@ -737,6 +764,7 @@ mod tests { assert_eq!(use1, expected_1); assert_eq!(use2, expected_2); assert_eq!(use3, expected_3); + assert_eq!(use4, expected_4); } #[test] diff --git a/modules/sdk-test-cs/Lib.cs b/modules/sdk-test-cs/Lib.cs index b17daa81ad4..f1e6b78c02f 100644 --- a/modules/sdk-test-cs/Lib.cs +++ b/modules/sdk-test-cs/Lib.cs @@ -767,6 +767,86 @@ public static void insert_option_every_primitive_struct( ctx.Db.option_every_primitive_struct.Insert(new OptionEveryPrimitiveStruct { s = s }); } + [Table(Name = "result_i32_string", Public = true)] + public partial struct ResultI32String + { + public Result r; + } + + [Reducer] + public static void insert_result_i32_string(ReducerContext ctx, Result r) + { + ctx.Db.result_i32_string.Insert(new ResultI32String { r = r }); + } + + [Table(Name = "result_string_i32", Public = true)] + public partial struct ResultStringI32 + { + public Result r; + } + + [Reducer] + public static void insert_result_string_i32(ReducerContext ctx, Result r) + { + ctx.Db.result_string_i32.Insert(new ResultStringI32 { r = r }); + } + + [Table(Name = "result_identity_string", Public = true)] + public partial struct ResultIdentityString + { + public Result r; + } + + [Reducer] + public static void insert_result_identity_string(ReducerContext ctx, Result r) + { + ctx.Db.result_identity_string.Insert(new ResultIdentityString { r = r }); + } + + [Table(Name = "result_simple_enum_i32", Public = true)] + public partial struct ResultSimpleEnumI32 + { + public Result r; + } + + [Reducer] + public static void insert_result_simple_enum_i32(ReducerContext ctx, Result r) + { + ctx.Db.result_simple_enum_i32.Insert(new ResultSimpleEnumI32 { r = r }); + } + + [Table(Name = "result_every_primitive_struct_string", Public = true)] + public partial struct ResultEveryPrimitiveStructString + { + public Result r; + } + + [Reducer] + public static void insert_result_every_primitive_struct_string( + ReducerContext ctx, + Result r + ) + { + ctx.Db.result_every_primitive_struct_string.Insert( + new ResultEveryPrimitiveStructString { r = r } + ); + } + + [Table(Name = "result_vec_i32_string", Public = true)] + public partial struct ResultVecI32String + { + public Result, string> r; + } + + [Reducer] + public static void insert_result_vec_i32_string( + ReducerContext ctx, + Result, string> r + ) + { + ctx.Db.result_vec_i32_string.Insert(new ResultVecI32String { r = r }); + } + [SpacetimeDB.Table(Name = "option_vec_option_i32", Public = true)] public partial struct OptionVecOptionI32 { diff --git a/modules/sdk-test-cs/sdk-test-cs.sln b/modules/sdk-test-cs/sdk-test-cs.sln new file mode 100644 index 00000000000..651c824c299 --- /dev/null +++ b/modules/sdk-test-cs/sdk-test-cs.sln @@ -0,0 +1,24 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.2.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "sdk-test-cs", "sdk-test-cs.csproj", "{A8BDE7A4-453D-5B7A-BB1B-A86E6E17160F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A8BDE7A4-453D-5B7A-BB1B-A86E6E17160F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A8BDE7A4-453D-5B7A-BB1B-A86E6E17160F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A8BDE7A4-453D-5B7A-BB1B-A86E6E17160F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A8BDE7A4-453D-5B7A-BB1B-A86E6E17160F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {34AFEE93-AA55-4929-BAB6-14A94C3A0DD4} + EndGlobalSection +EndGlobal diff --git a/modules/sdk-test-ts/src/index.ts b/modules/sdk-test-ts/src/index.ts index 76bc93e1748..fd521ef5135 100644 --- a/modules/sdk-test-ts/src/index.ts +++ b/modules/sdk-test-ts/src/index.ts @@ -316,6 +316,40 @@ const optionTables = [ ), ] as const; +// Tables for Result values. +const resultTables = [ + tbl( + 'result_i32_string', + { insert: 'insert_result_i32_string' }, + { r: t.result(t.i32(), t.string()) } + ), + tbl( + 'result_string_i32', + { insert: 'insert_result_string_i32' }, + { r: t.result(t.string(), t.i32()) } + ), + tbl( + 'result_identity_string', + { insert: 'insert_result_identity_string' }, + { r: t.result(t.identity(), t.string()) } + ), + tbl( + 'result_simple_enum_i32', + { insert: 'insert_result_simple_enum_i32' }, + { r: t.result(SimpleEnum, t.i32()) } + ), + tbl( + 'result_every_primitive_struct_string', + { insert: 'insert_result_every_primitive_struct_string' }, + { r: t.result(EveryPrimitiveStruct, t.string()) } + ), + tbl( + 'result_vec_i32_string', + { insert: 'insert_result_vec_i32_string' }, + { r: t.result(t.array(t.i32()), t.string()) } + ), +] as const; + // Tables mapping a unique, but non-pk, key to a boring i32 payload. // This allows us to test delete events, and the semantically correct absence of update events. const uniqueTables = [ @@ -717,6 +751,7 @@ const allTables = [ ...singleValTables, ...vecTables, ...optionTables, + ...resultTables, ...uniqueTables, ...pkTables, ...weirdTables, diff --git a/modules/sdk-test/src/lib.rs b/modules/sdk-test/src/lib.rs index c4dda5aeae3..81a62e324af 100644 --- a/modules/sdk-test/src/lib.rs +++ b/modules/sdk-test/src/lib.rs @@ -335,6 +335,16 @@ define_tables! { OptionVecOptionI32 { insert insert_option_vec_option_i32 } v Option>>; } +// Tables holding a Result of various types. +define_tables! { + ResultI32String { insert insert_result_i32_string } r Result; + ResultStringI32 { insert insert_result_string_i32 } r Result; + ResultIdentityString { insert insert_result_identity_string } r Result; + ResultSimpleEnumI32 { insert insert_result_simple_enum_i32 } r Result; + ResultEveryPrimitiveStructString { insert insert_result_every_primitive_struct_string } r Result; + ResultVecI32String { insert insert_result_vec_i32_string } r Result, String>; +} + // Tables mapping a unique, but non-pk, key to a boring i32 payload. // This allows us to test delete events, and the semantically correct absence of update events. define_tables! { diff --git a/sdks/rust/tests/test-client/src/module_bindings/insert_result_every_primitive_struct_string_reducer.rs b/sdks/rust/tests/test-client/src/module_bindings/insert_result_every_primitive_struct_string_reducer.rs new file mode 100644 index 00000000000..cc02e7ac327 --- /dev/null +++ b/sdks/rust/tests/test-client/src/module_bindings/insert_result_every_primitive_struct_string_reducer.rs @@ -0,0 +1,118 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +use super::every_primitive_struct_type::EveryPrimitiveStruct; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub(super) struct InsertResultEveryPrimitiveStructStringArgs { + pub r: Result, +} + +impl From for super::Reducer { + fn from(args: InsertResultEveryPrimitiveStructStringArgs) -> Self { + Self::InsertResultEveryPrimitiveStructString { r: args.r } + } +} + +impl __sdk::InModule for InsertResultEveryPrimitiveStructStringArgs { + type Module = super::RemoteModule; +} + +pub struct InsertResultEveryPrimitiveStructStringCallbackId(__sdk::CallbackId); + +#[allow(non_camel_case_types)] +/// Extension trait for access to the reducer `insert_result_every_primitive_struct_string`. +/// +/// Implemented for [`super::RemoteReducers`]. +pub trait insert_result_every_primitive_struct_string { + /// Request that the remote module invoke the reducer `insert_result_every_primitive_struct_string` to run as soon as possible. + /// + /// This method returns immediately, and errors only if we are unable to send the request. + /// The reducer will run asynchronously in the future, + /// and its status can be observed by listening for [`Self::on_insert_result_every_primitive_struct_string`] callbacks. + fn insert_result_every_primitive_struct_string(&self, r: Result) + -> __sdk::Result<()>; + /// Register a callback to run whenever we are notified of an invocation of the reducer `insert_result_every_primitive_struct_string`. + /// + /// Callbacks should inspect the [`__sdk::ReducerEvent`] contained in the [`super::ReducerEventContext`] + /// to determine the reducer's status. + /// + /// The returned [`InsertResultEveryPrimitiveStructStringCallbackId`] can be passed to [`Self::remove_on_insert_result_every_primitive_struct_string`] + /// to cancel the callback. + fn on_insert_result_every_primitive_struct_string( + &self, + callback: impl FnMut(&super::ReducerEventContext, &Result) + Send + 'static, + ) -> InsertResultEveryPrimitiveStructStringCallbackId; + /// Cancel a callback previously registered by [`Self::on_insert_result_every_primitive_struct_string`], + /// causing it not to run in the future. + fn remove_on_insert_result_every_primitive_struct_string( + &self, + callback: InsertResultEveryPrimitiveStructStringCallbackId, + ); +} + +impl insert_result_every_primitive_struct_string for super::RemoteReducers { + fn insert_result_every_primitive_struct_string( + &self, + r: Result, + ) -> __sdk::Result<()> { + self.imp.call_reducer( + "insert_result_every_primitive_struct_string", + InsertResultEveryPrimitiveStructStringArgs { r }, + ) + } + fn on_insert_result_every_primitive_struct_string( + &self, + mut callback: impl FnMut(&super::ReducerEventContext, &Result) + Send + 'static, + ) -> InsertResultEveryPrimitiveStructStringCallbackId { + InsertResultEveryPrimitiveStructStringCallbackId(self.imp.on_reducer( + "insert_result_every_primitive_struct_string", + Box::new(move |ctx: &super::ReducerEventContext| { + let super::ReducerEventContext { + event: + __sdk::ReducerEvent { + reducer: super::Reducer::InsertResultEveryPrimitiveStructString { r }, + .. + }, + .. + } = ctx + else { + unreachable!() + }; + callback(ctx, r) + }), + )) + } + fn remove_on_insert_result_every_primitive_struct_string( + &self, + callback: InsertResultEveryPrimitiveStructStringCallbackId, + ) { + self.imp + .remove_on_reducer("insert_result_every_primitive_struct_string", callback.0) + } +} + +#[allow(non_camel_case_types)] +#[doc(hidden)] +/// Extension trait for setting the call-flags for the reducer `insert_result_every_primitive_struct_string`. +/// +/// Implemented for [`super::SetReducerFlags`]. +/// +/// This type is currently unstable and may be removed without a major version bump. +pub trait set_flags_for_insert_result_every_primitive_struct_string { + /// Set the call-reducer flags for the reducer `insert_result_every_primitive_struct_string` to `flags`. + /// + /// This type is currently unstable and may be removed without a major version bump. + fn insert_result_every_primitive_struct_string(&self, flags: __ws::CallReducerFlags); +} + +impl set_flags_for_insert_result_every_primitive_struct_string for super::SetReducerFlags { + fn insert_result_every_primitive_struct_string(&self, flags: __ws::CallReducerFlags) { + self.imp + .set_call_reducer_flags("insert_result_every_primitive_struct_string", flags); + } +} diff --git a/sdks/rust/tests/test-client/src/module_bindings/insert_result_i_32_string_reducer.rs b/sdks/rust/tests/test-client/src/module_bindings/insert_result_i_32_string_reducer.rs new file mode 100644 index 00000000000..0ebbc51d558 --- /dev/null +++ b/sdks/rust/tests/test-client/src/module_bindings/insert_result_i_32_string_reducer.rs @@ -0,0 +1,102 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub(super) struct InsertResultI32StringArgs { + pub r: Result, +} + +impl From for super::Reducer { + fn from(args: InsertResultI32StringArgs) -> Self { + Self::InsertResultI32String { r: args.r } + } +} + +impl __sdk::InModule for InsertResultI32StringArgs { + type Module = super::RemoteModule; +} + +pub struct InsertResultI32StringCallbackId(__sdk::CallbackId); + +#[allow(non_camel_case_types)] +/// Extension trait for access to the reducer `insert_result_i32_string`. +/// +/// Implemented for [`super::RemoteReducers`]. +pub trait insert_result_i_32_string { + /// Request that the remote module invoke the reducer `insert_result_i32_string` to run as soon as possible. + /// + /// This method returns immediately, and errors only if we are unable to send the request. + /// The reducer will run asynchronously in the future, + /// and its status can be observed by listening for [`Self::on_insert_result_i_32_string`] callbacks. + fn insert_result_i_32_string(&self, r: Result) -> __sdk::Result<()>; + /// Register a callback to run whenever we are notified of an invocation of the reducer `insert_result_i32_string`. + /// + /// Callbacks should inspect the [`__sdk::ReducerEvent`] contained in the [`super::ReducerEventContext`] + /// to determine the reducer's status. + /// + /// The returned [`InsertResultI32StringCallbackId`] can be passed to [`Self::remove_on_insert_result_i_32_string`] + /// to cancel the callback. + fn on_insert_result_i_32_string( + &self, + callback: impl FnMut(&super::ReducerEventContext, &Result) + Send + 'static, + ) -> InsertResultI32StringCallbackId; + /// Cancel a callback previously registered by [`Self::on_insert_result_i_32_string`], + /// causing it not to run in the future. + fn remove_on_insert_result_i_32_string(&self, callback: InsertResultI32StringCallbackId); +} + +impl insert_result_i_32_string for super::RemoteReducers { + fn insert_result_i_32_string(&self, r: Result) -> __sdk::Result<()> { + self.imp + .call_reducer("insert_result_i32_string", InsertResultI32StringArgs { r }) + } + fn on_insert_result_i_32_string( + &self, + mut callback: impl FnMut(&super::ReducerEventContext, &Result) + Send + 'static, + ) -> InsertResultI32StringCallbackId { + InsertResultI32StringCallbackId(self.imp.on_reducer( + "insert_result_i32_string", + Box::new(move |ctx: &super::ReducerEventContext| { + let super::ReducerEventContext { + event: + __sdk::ReducerEvent { + reducer: super::Reducer::InsertResultI32String { r }, + .. + }, + .. + } = ctx + else { + unreachable!() + }; + callback(ctx, r) + }), + )) + } + fn remove_on_insert_result_i_32_string(&self, callback: InsertResultI32StringCallbackId) { + self.imp.remove_on_reducer("insert_result_i32_string", callback.0) + } +} + +#[allow(non_camel_case_types)] +#[doc(hidden)] +/// Extension trait for setting the call-flags for the reducer `insert_result_i32_string`. +/// +/// Implemented for [`super::SetReducerFlags`]. +/// +/// This type is currently unstable and may be removed without a major version bump. +pub trait set_flags_for_insert_result_i_32_string { + /// Set the call-reducer flags for the reducer `insert_result_i32_string` to `flags`. + /// + /// This type is currently unstable and may be removed without a major version bump. + fn insert_result_i_32_string(&self, flags: __ws::CallReducerFlags); +} + +impl set_flags_for_insert_result_i_32_string for super::SetReducerFlags { + fn insert_result_i_32_string(&self, flags: __ws::CallReducerFlags) { + self.imp.set_call_reducer_flags("insert_result_i32_string", flags); + } +} diff --git a/sdks/rust/tests/test-client/src/module_bindings/insert_result_identity_string_reducer.rs b/sdks/rust/tests/test-client/src/module_bindings/insert_result_identity_string_reducer.rs new file mode 100644 index 00000000000..8de7d62c464 --- /dev/null +++ b/sdks/rust/tests/test-client/src/module_bindings/insert_result_identity_string_reducer.rs @@ -0,0 +1,102 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub(super) struct InsertResultIdentityStringArgs { + pub r: Result<__sdk::Identity, String>, +} + +impl From for super::Reducer { + fn from(args: InsertResultIdentityStringArgs) -> Self { + Self::InsertResultIdentityString { r: args.r } + } +} + +impl __sdk::InModule for InsertResultIdentityStringArgs { + type Module = super::RemoteModule; +} + +pub struct InsertResultIdentityStringCallbackId(__sdk::CallbackId); + +#[allow(non_camel_case_types)] +/// Extension trait for access to the reducer `insert_result_identity_string`. +/// +/// Implemented for [`super::RemoteReducers`]. +pub trait insert_result_identity_string { + /// Request that the remote module invoke the reducer `insert_result_identity_string` to run as soon as possible. + /// + /// This method returns immediately, and errors only if we are unable to send the request. + /// The reducer will run asynchronously in the future, + /// and its status can be observed by listening for [`Self::on_insert_result_identity_string`] callbacks. + fn insert_result_identity_string(&self, r: Result<__sdk::Identity, String>) -> __sdk::Result<()>; + /// Register a callback to run whenever we are notified of an invocation of the reducer `insert_result_identity_string`. + /// + /// Callbacks should inspect the [`__sdk::ReducerEvent`] contained in the [`super::ReducerEventContext`] + /// to determine the reducer's status. + /// + /// The returned [`InsertResultIdentityStringCallbackId`] can be passed to [`Self::remove_on_insert_result_identity_string`] + /// to cancel the callback. + fn on_insert_result_identity_string( + &self, + callback: impl FnMut(&super::ReducerEventContext, &Result<__sdk::Identity, String>) + Send + 'static, + ) -> InsertResultIdentityStringCallbackId; + /// Cancel a callback previously registered by [`Self::on_insert_result_identity_string`], + /// causing it not to run in the future. + fn remove_on_insert_result_identity_string(&self, callback: InsertResultIdentityStringCallbackId); +} + +impl insert_result_identity_string for super::RemoteReducers { + fn insert_result_identity_string(&self, r: Result<__sdk::Identity, String>) -> __sdk::Result<()> { + self.imp + .call_reducer("insert_result_identity_string", InsertResultIdentityStringArgs { r }) + } + fn on_insert_result_identity_string( + &self, + mut callback: impl FnMut(&super::ReducerEventContext, &Result<__sdk::Identity, String>) + Send + 'static, + ) -> InsertResultIdentityStringCallbackId { + InsertResultIdentityStringCallbackId(self.imp.on_reducer( + "insert_result_identity_string", + Box::new(move |ctx: &super::ReducerEventContext| { + let super::ReducerEventContext { + event: + __sdk::ReducerEvent { + reducer: super::Reducer::InsertResultIdentityString { r }, + .. + }, + .. + } = ctx + else { + unreachable!() + }; + callback(ctx, r) + }), + )) + } + fn remove_on_insert_result_identity_string(&self, callback: InsertResultIdentityStringCallbackId) { + self.imp.remove_on_reducer("insert_result_identity_string", callback.0) + } +} + +#[allow(non_camel_case_types)] +#[doc(hidden)] +/// Extension trait for setting the call-flags for the reducer `insert_result_identity_string`. +/// +/// Implemented for [`super::SetReducerFlags`]. +/// +/// This type is currently unstable and may be removed without a major version bump. +pub trait set_flags_for_insert_result_identity_string { + /// Set the call-reducer flags for the reducer `insert_result_identity_string` to `flags`. + /// + /// This type is currently unstable and may be removed without a major version bump. + fn insert_result_identity_string(&self, flags: __ws::CallReducerFlags); +} + +impl set_flags_for_insert_result_identity_string for super::SetReducerFlags { + fn insert_result_identity_string(&self, flags: __ws::CallReducerFlags) { + self.imp.set_call_reducer_flags("insert_result_identity_string", flags); + } +} diff --git a/sdks/rust/tests/test-client/src/module_bindings/insert_result_simple_enum_i_32_reducer.rs b/sdks/rust/tests/test-client/src/module_bindings/insert_result_simple_enum_i_32_reducer.rs new file mode 100644 index 00000000000..908f257c1df --- /dev/null +++ b/sdks/rust/tests/test-client/src/module_bindings/insert_result_simple_enum_i_32_reducer.rs @@ -0,0 +1,104 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +use super::simple_enum_type::SimpleEnum; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub(super) struct InsertResultSimpleEnumI32Args { + pub r: Result, +} + +impl From for super::Reducer { + fn from(args: InsertResultSimpleEnumI32Args) -> Self { + Self::InsertResultSimpleEnumI32 { r: args.r } + } +} + +impl __sdk::InModule for InsertResultSimpleEnumI32Args { + type Module = super::RemoteModule; +} + +pub struct InsertResultSimpleEnumI32CallbackId(__sdk::CallbackId); + +#[allow(non_camel_case_types)] +/// Extension trait for access to the reducer `insert_result_simple_enum_i32`. +/// +/// Implemented for [`super::RemoteReducers`]. +pub trait insert_result_simple_enum_i_32 { + /// Request that the remote module invoke the reducer `insert_result_simple_enum_i32` to run as soon as possible. + /// + /// This method returns immediately, and errors only if we are unable to send the request. + /// The reducer will run asynchronously in the future, + /// and its status can be observed by listening for [`Self::on_insert_result_simple_enum_i_32`] callbacks. + fn insert_result_simple_enum_i_32(&self, r: Result) -> __sdk::Result<()>; + /// Register a callback to run whenever we are notified of an invocation of the reducer `insert_result_simple_enum_i32`. + /// + /// Callbacks should inspect the [`__sdk::ReducerEvent`] contained in the [`super::ReducerEventContext`] + /// to determine the reducer's status. + /// + /// The returned [`InsertResultSimpleEnumI32CallbackId`] can be passed to [`Self::remove_on_insert_result_simple_enum_i_32`] + /// to cancel the callback. + fn on_insert_result_simple_enum_i_32( + &self, + callback: impl FnMut(&super::ReducerEventContext, &Result) + Send + 'static, + ) -> InsertResultSimpleEnumI32CallbackId; + /// Cancel a callback previously registered by [`Self::on_insert_result_simple_enum_i_32`], + /// causing it not to run in the future. + fn remove_on_insert_result_simple_enum_i_32(&self, callback: InsertResultSimpleEnumI32CallbackId); +} + +impl insert_result_simple_enum_i_32 for super::RemoteReducers { + fn insert_result_simple_enum_i_32(&self, r: Result) -> __sdk::Result<()> { + self.imp + .call_reducer("insert_result_simple_enum_i32", InsertResultSimpleEnumI32Args { r }) + } + fn on_insert_result_simple_enum_i_32( + &self, + mut callback: impl FnMut(&super::ReducerEventContext, &Result) + Send + 'static, + ) -> InsertResultSimpleEnumI32CallbackId { + InsertResultSimpleEnumI32CallbackId(self.imp.on_reducer( + "insert_result_simple_enum_i32", + Box::new(move |ctx: &super::ReducerEventContext| { + let super::ReducerEventContext { + event: + __sdk::ReducerEvent { + reducer: super::Reducer::InsertResultSimpleEnumI32 { r }, + .. + }, + .. + } = ctx + else { + unreachable!() + }; + callback(ctx, r) + }), + )) + } + fn remove_on_insert_result_simple_enum_i_32(&self, callback: InsertResultSimpleEnumI32CallbackId) { + self.imp.remove_on_reducer("insert_result_simple_enum_i32", callback.0) + } +} + +#[allow(non_camel_case_types)] +#[doc(hidden)] +/// Extension trait for setting the call-flags for the reducer `insert_result_simple_enum_i32`. +/// +/// Implemented for [`super::SetReducerFlags`]. +/// +/// This type is currently unstable and may be removed without a major version bump. +pub trait set_flags_for_insert_result_simple_enum_i_32 { + /// Set the call-reducer flags for the reducer `insert_result_simple_enum_i32` to `flags`. + /// + /// This type is currently unstable and may be removed without a major version bump. + fn insert_result_simple_enum_i_32(&self, flags: __ws::CallReducerFlags); +} + +impl set_flags_for_insert_result_simple_enum_i_32 for super::SetReducerFlags { + fn insert_result_simple_enum_i_32(&self, flags: __ws::CallReducerFlags) { + self.imp.set_call_reducer_flags("insert_result_simple_enum_i32", flags); + } +} diff --git a/sdks/rust/tests/test-client/src/module_bindings/insert_result_string_i_32_reducer.rs b/sdks/rust/tests/test-client/src/module_bindings/insert_result_string_i_32_reducer.rs new file mode 100644 index 00000000000..bd344f18972 --- /dev/null +++ b/sdks/rust/tests/test-client/src/module_bindings/insert_result_string_i_32_reducer.rs @@ -0,0 +1,102 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub(super) struct InsertResultStringI32Args { + pub r: Result, +} + +impl From for super::Reducer { + fn from(args: InsertResultStringI32Args) -> Self { + Self::InsertResultStringI32 { r: args.r } + } +} + +impl __sdk::InModule for InsertResultStringI32Args { + type Module = super::RemoteModule; +} + +pub struct InsertResultStringI32CallbackId(__sdk::CallbackId); + +#[allow(non_camel_case_types)] +/// Extension trait for access to the reducer `insert_result_string_i32`. +/// +/// Implemented for [`super::RemoteReducers`]. +pub trait insert_result_string_i_32 { + /// Request that the remote module invoke the reducer `insert_result_string_i32` to run as soon as possible. + /// + /// This method returns immediately, and errors only if we are unable to send the request. + /// The reducer will run asynchronously in the future, + /// and its status can be observed by listening for [`Self::on_insert_result_string_i_32`] callbacks. + fn insert_result_string_i_32(&self, r: Result) -> __sdk::Result<()>; + /// Register a callback to run whenever we are notified of an invocation of the reducer `insert_result_string_i32`. + /// + /// Callbacks should inspect the [`__sdk::ReducerEvent`] contained in the [`super::ReducerEventContext`] + /// to determine the reducer's status. + /// + /// The returned [`InsertResultStringI32CallbackId`] can be passed to [`Self::remove_on_insert_result_string_i_32`] + /// to cancel the callback. + fn on_insert_result_string_i_32( + &self, + callback: impl FnMut(&super::ReducerEventContext, &Result) + Send + 'static, + ) -> InsertResultStringI32CallbackId; + /// Cancel a callback previously registered by [`Self::on_insert_result_string_i_32`], + /// causing it not to run in the future. + fn remove_on_insert_result_string_i_32(&self, callback: InsertResultStringI32CallbackId); +} + +impl insert_result_string_i_32 for super::RemoteReducers { + fn insert_result_string_i_32(&self, r: Result) -> __sdk::Result<()> { + self.imp + .call_reducer("insert_result_string_i32", InsertResultStringI32Args { r }) + } + fn on_insert_result_string_i_32( + &self, + mut callback: impl FnMut(&super::ReducerEventContext, &Result) + Send + 'static, + ) -> InsertResultStringI32CallbackId { + InsertResultStringI32CallbackId(self.imp.on_reducer( + "insert_result_string_i32", + Box::new(move |ctx: &super::ReducerEventContext| { + let super::ReducerEventContext { + event: + __sdk::ReducerEvent { + reducer: super::Reducer::InsertResultStringI32 { r }, + .. + }, + .. + } = ctx + else { + unreachable!() + }; + callback(ctx, r) + }), + )) + } + fn remove_on_insert_result_string_i_32(&self, callback: InsertResultStringI32CallbackId) { + self.imp.remove_on_reducer("insert_result_string_i32", callback.0) + } +} + +#[allow(non_camel_case_types)] +#[doc(hidden)] +/// Extension trait for setting the call-flags for the reducer `insert_result_string_i32`. +/// +/// Implemented for [`super::SetReducerFlags`]. +/// +/// This type is currently unstable and may be removed without a major version bump. +pub trait set_flags_for_insert_result_string_i_32 { + /// Set the call-reducer flags for the reducer `insert_result_string_i32` to `flags`. + /// + /// This type is currently unstable and may be removed without a major version bump. + fn insert_result_string_i_32(&self, flags: __ws::CallReducerFlags); +} + +impl set_flags_for_insert_result_string_i_32 for super::SetReducerFlags { + fn insert_result_string_i_32(&self, flags: __ws::CallReducerFlags) { + self.imp.set_call_reducer_flags("insert_result_string_i32", flags); + } +} diff --git a/sdks/rust/tests/test-client/src/module_bindings/insert_result_vec_i_32_string_reducer.rs b/sdks/rust/tests/test-client/src/module_bindings/insert_result_vec_i_32_string_reducer.rs new file mode 100644 index 00000000000..0423867f021 --- /dev/null +++ b/sdks/rust/tests/test-client/src/module_bindings/insert_result_vec_i_32_string_reducer.rs @@ -0,0 +1,102 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub(super) struct InsertResultVecI32StringArgs { + pub r: Result, String>, +} + +impl From for super::Reducer { + fn from(args: InsertResultVecI32StringArgs) -> Self { + Self::InsertResultVecI32String { r: args.r } + } +} + +impl __sdk::InModule for InsertResultVecI32StringArgs { + type Module = super::RemoteModule; +} + +pub struct InsertResultVecI32StringCallbackId(__sdk::CallbackId); + +#[allow(non_camel_case_types)] +/// Extension trait for access to the reducer `insert_result_vec_i32_string`. +/// +/// Implemented for [`super::RemoteReducers`]. +pub trait insert_result_vec_i_32_string { + /// Request that the remote module invoke the reducer `insert_result_vec_i32_string` to run as soon as possible. + /// + /// This method returns immediately, and errors only if we are unable to send the request. + /// The reducer will run asynchronously in the future, + /// and its status can be observed by listening for [`Self::on_insert_result_vec_i_32_string`] callbacks. + fn insert_result_vec_i_32_string(&self, r: Result, String>) -> __sdk::Result<()>; + /// Register a callback to run whenever we are notified of an invocation of the reducer `insert_result_vec_i32_string`. + /// + /// Callbacks should inspect the [`__sdk::ReducerEvent`] contained in the [`super::ReducerEventContext`] + /// to determine the reducer's status. + /// + /// The returned [`InsertResultVecI32StringCallbackId`] can be passed to [`Self::remove_on_insert_result_vec_i_32_string`] + /// to cancel the callback. + fn on_insert_result_vec_i_32_string( + &self, + callback: impl FnMut(&super::ReducerEventContext, &Result, String>) + Send + 'static, + ) -> InsertResultVecI32StringCallbackId; + /// Cancel a callback previously registered by [`Self::on_insert_result_vec_i_32_string`], + /// causing it not to run in the future. + fn remove_on_insert_result_vec_i_32_string(&self, callback: InsertResultVecI32StringCallbackId); +} + +impl insert_result_vec_i_32_string for super::RemoteReducers { + fn insert_result_vec_i_32_string(&self, r: Result, String>) -> __sdk::Result<()> { + self.imp + .call_reducer("insert_result_vec_i32_string", InsertResultVecI32StringArgs { r }) + } + fn on_insert_result_vec_i_32_string( + &self, + mut callback: impl FnMut(&super::ReducerEventContext, &Result, String>) + Send + 'static, + ) -> InsertResultVecI32StringCallbackId { + InsertResultVecI32StringCallbackId(self.imp.on_reducer( + "insert_result_vec_i32_string", + Box::new(move |ctx: &super::ReducerEventContext| { + let super::ReducerEventContext { + event: + __sdk::ReducerEvent { + reducer: super::Reducer::InsertResultVecI32String { r }, + .. + }, + .. + } = ctx + else { + unreachable!() + }; + callback(ctx, r) + }), + )) + } + fn remove_on_insert_result_vec_i_32_string(&self, callback: InsertResultVecI32StringCallbackId) { + self.imp.remove_on_reducer("insert_result_vec_i32_string", callback.0) + } +} + +#[allow(non_camel_case_types)] +#[doc(hidden)] +/// Extension trait for setting the call-flags for the reducer `insert_result_vec_i32_string`. +/// +/// Implemented for [`super::SetReducerFlags`]. +/// +/// This type is currently unstable and may be removed without a major version bump. +pub trait set_flags_for_insert_result_vec_i_32_string { + /// Set the call-reducer flags for the reducer `insert_result_vec_i32_string` to `flags`. + /// + /// This type is currently unstable and may be removed without a major version bump. + fn insert_result_vec_i_32_string(&self, flags: __ws::CallReducerFlags); +} + +impl set_flags_for_insert_result_vec_i_32_string for super::SetReducerFlags { + fn insert_result_vec_i_32_string(&self, flags: __ws::CallReducerFlags) { + self.imp.set_call_reducer_flags("insert_result_vec_i32_string", flags); + } +} diff --git a/sdks/rust/tests/test-client/src/module_bindings/mod.rs b/sdks/rust/tests/test-client/src/module_bindings/mod.rs index a3fd6ab9c2f..b2ce77a4731 100644 --- a/sdks/rust/tests/test-client/src/module_bindings/mod.rs +++ b/sdks/rust/tests/test-client/src/module_bindings/mod.rs @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 1.8.0 (commit 798b1c7909306e832723f507f7a3c97d6abc610d). +// This was generated using spacetimedb cli version 1.10.0 (commit b5f3ce8c2dad6817d52ac14a03ea49bf638a2e17). #![allow(unused, clippy::all)] use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; @@ -117,6 +117,12 @@ pub mod insert_pk_u_32_two_reducer; pub mod insert_pk_u_64_reducer; pub mod insert_pk_u_8_reducer; pub mod insert_primitives_as_strings_reducer; +pub mod insert_result_every_primitive_struct_string_reducer; +pub mod insert_result_i_32_string_reducer; +pub mod insert_result_identity_string_reducer; +pub mod insert_result_simple_enum_i_32_reducer; +pub mod insert_result_string_i_32_reducer; +pub mod insert_result_vec_i_32_string_reducer; pub mod insert_table_holds_table_reducer; pub mod insert_unique_bool_reducer; pub mod insert_unique_connection_id_reducer; @@ -262,6 +268,18 @@ pub mod pk_u_64_table; pub mod pk_u_64_type; pub mod pk_u_8_table; pub mod pk_u_8_type; +pub mod result_every_primitive_struct_string_table; +pub mod result_every_primitive_struct_string_type; +pub mod result_i_32_string_table; +pub mod result_i_32_string_type; +pub mod result_identity_string_table; +pub mod result_identity_string_type; +pub mod result_simple_enum_i_32_table; +pub mod result_simple_enum_i_32_type; +pub mod result_string_i_32_table; +pub mod result_string_i_32_type; +pub mod result_vec_i_32_string_table; +pub mod result_vec_i_32_string_type; pub mod scheduled_table_table; pub mod scheduled_table_type; pub mod send_scheduled_message_reducer; @@ -595,6 +613,25 @@ pub use insert_pk_u_8_reducer::{insert_pk_u_8, set_flags_for_insert_pk_u_8, Inse pub use insert_primitives_as_strings_reducer::{ insert_primitives_as_strings, set_flags_for_insert_primitives_as_strings, InsertPrimitivesAsStringsCallbackId, }; +pub use insert_result_every_primitive_struct_string_reducer::{ + insert_result_every_primitive_struct_string, set_flags_for_insert_result_every_primitive_struct_string, + InsertResultEveryPrimitiveStructStringCallbackId, +}; +pub use insert_result_i_32_string_reducer::{ + insert_result_i_32_string, set_flags_for_insert_result_i_32_string, InsertResultI32StringCallbackId, +}; +pub use insert_result_identity_string_reducer::{ + insert_result_identity_string, set_flags_for_insert_result_identity_string, InsertResultIdentityStringCallbackId, +}; +pub use insert_result_simple_enum_i_32_reducer::{ + insert_result_simple_enum_i_32, set_flags_for_insert_result_simple_enum_i_32, InsertResultSimpleEnumI32CallbackId, +}; +pub use insert_result_string_i_32_reducer::{ + insert_result_string_i_32, set_flags_for_insert_result_string_i_32, InsertResultStringI32CallbackId, +}; +pub use insert_result_vec_i_32_string_reducer::{ + insert_result_vec_i_32_string, set_flags_for_insert_result_vec_i_32_string, InsertResultVecI32StringCallbackId, +}; pub use insert_table_holds_table_reducer::{ insert_table_holds_table, set_flags_for_insert_table_holds_table, InsertTableHoldsTableCallbackId, }; @@ -780,6 +817,18 @@ pub use pk_u_64_table::*; pub use pk_u_64_type::PkU64; pub use pk_u_8_table::*; pub use pk_u_8_type::PkU8; +pub use result_every_primitive_struct_string_table::*; +pub use result_every_primitive_struct_string_type::ResultEveryPrimitiveStructString; +pub use result_i_32_string_table::*; +pub use result_i_32_string_type::ResultI32String; +pub use result_identity_string_table::*; +pub use result_identity_string_type::ResultIdentityString; +pub use result_simple_enum_i_32_table::*; +pub use result_simple_enum_i_32_type::ResultSimpleEnumI32; +pub use result_string_i_32_table::*; +pub use result_string_i_32_type::ResultStringI32; +pub use result_vec_i_32_string_table::*; +pub use result_vec_i_32_string_type::ResultVecI32String; pub use scheduled_table_table::*; pub use scheduled_table_type::ScheduledTable; pub use send_scheduled_message_reducer::{ @@ -1290,6 +1339,24 @@ pub enum Reducer { InsertPrimitivesAsStrings { s: EveryPrimitiveStruct, }, + InsertResultEveryPrimitiveStructString { + r: Result, + }, + InsertResultI32String { + r: Result, + }, + InsertResultIdentityString { + r: Result<__sdk::Identity, String>, + }, + InsertResultSimpleEnumI32 { + r: Result, + }, + InsertResultStringI32 { + r: Result, + }, + InsertResultVecI32String { + r: Result, String>, + }, InsertTableHoldsTable { a: OneU8, b: VecU8, @@ -1694,6 +1761,12 @@ impl __sdk::Reducer for Reducer { Reducer::InsertPkU64 { .. } => "insert_pk_u64", Reducer::InsertPkU8 { .. } => "insert_pk_u8", Reducer::InsertPrimitivesAsStrings { .. } => "insert_primitives_as_strings", + Reducer::InsertResultEveryPrimitiveStructString { .. } => "insert_result_every_primitive_struct_string", + Reducer::InsertResultI32String { .. } => "insert_result_i32_string", + Reducer::InsertResultIdentityString { .. } => "insert_result_identity_string", + Reducer::InsertResultSimpleEnumI32 { .. } => "insert_result_simple_enum_i32", + Reducer::InsertResultStringI32 { .. } => "insert_result_string_i32", + Reducer::InsertResultVecI32String { .. } => "insert_result_vec_i32_string", Reducer::InsertTableHoldsTable { .. } => "insert_table_holds_table", Reducer::InsertUniqueBool { .. } => "insert_unique_bool", Reducer::InsertUniqueConnectionId { .. } => "insert_unique_connection_id", @@ -2304,6 +2377,32 @@ impl TryFrom<__ws::ReducerCallInfo<__ws::BsatnFormat>> for Reducer { insert_primitives_as_strings_reducer::InsertPrimitivesAsStringsArgs, >("insert_primitives_as_strings", &value.args)? .into()), + "insert_result_every_primitive_struct_string" => { + Ok(__sdk::parse_reducer_args::< + insert_result_every_primitive_struct_string_reducer::InsertResultEveryPrimitiveStructStringArgs, + >("insert_result_every_primitive_struct_string", &value.args)? + .into()) + } + "insert_result_i32_string" => Ok(__sdk::parse_reducer_args::< + insert_result_i_32_string_reducer::InsertResultI32StringArgs, + >("insert_result_i32_string", &value.args)? + .into()), + "insert_result_identity_string" => Ok(__sdk::parse_reducer_args::< + insert_result_identity_string_reducer::InsertResultIdentityStringArgs, + >("insert_result_identity_string", &value.args)? + .into()), + "insert_result_simple_enum_i32" => Ok(__sdk::parse_reducer_args::< + insert_result_simple_enum_i_32_reducer::InsertResultSimpleEnumI32Args, + >("insert_result_simple_enum_i32", &value.args)? + .into()), + "insert_result_string_i32" => Ok(__sdk::parse_reducer_args::< + insert_result_string_i_32_reducer::InsertResultStringI32Args, + >("insert_result_string_i32", &value.args)? + .into()), + "insert_result_vec_i32_string" => Ok(__sdk::parse_reducer_args::< + insert_result_vec_i_32_string_reducer::InsertResultVecI32StringArgs, + >("insert_result_vec_i32_string", &value.args)? + .into()), "insert_table_holds_table" => Ok(__sdk::parse_reducer_args::< insert_table_holds_table_reducer::InsertTableHoldsTableArgs, >("insert_table_holds_table", &value.args)? @@ -2822,6 +2921,12 @@ pub struct DbUpdate { pk_u_32_two: __sdk::TableUpdate, pk_u_64: __sdk::TableUpdate, pk_u_8: __sdk::TableUpdate, + result_every_primitive_struct_string: __sdk::TableUpdate, + result_i_32_string: __sdk::TableUpdate, + result_identity_string: __sdk::TableUpdate, + result_simple_enum_i_32: __sdk::TableUpdate, + result_string_i_32: __sdk::TableUpdate, + result_vec_i_32_string: __sdk::TableUpdate, scheduled_table: __sdk::TableUpdate, table_holds_table: __sdk::TableUpdate, unique_bool: __sdk::TableUpdate, @@ -3032,6 +3137,24 @@ impl TryFrom<__ws::DatabaseUpdate<__ws::BsatnFormat>> for DbUpdate { .pk_u_64 .append(pk_u_64_table::parse_table_update(table_update)?), "pk_u8" => db_update.pk_u_8.append(pk_u_8_table::parse_table_update(table_update)?), + "result_every_primitive_struct_string" => db_update.result_every_primitive_struct_string.append( + result_every_primitive_struct_string_table::parse_table_update(table_update)?, + ), + "result_i32_string" => db_update + .result_i_32_string + .append(result_i_32_string_table::parse_table_update(table_update)?), + "result_identity_string" => db_update + .result_identity_string + .append(result_identity_string_table::parse_table_update(table_update)?), + "result_simple_enum_i32" => db_update + .result_simple_enum_i_32 + .append(result_simple_enum_i_32_table::parse_table_update(table_update)?), + "result_string_i32" => db_update + .result_string_i_32 + .append(result_string_i_32_table::parse_table_update(table_update)?), + "result_vec_i32_string" => db_update + .result_vec_i_32_string + .append(result_vec_i_32_string_table::parse_table_update(table_update)?), "scheduled_table" => db_update .scheduled_table .append(scheduled_table_table::parse_table_update(table_update)?), @@ -3282,6 +3405,20 @@ impl __sdk::DbUpdate for DbUpdate { diff.pk_u_8 = cache .apply_diff_to_table::("pk_u8", &self.pk_u_8) .with_updates_by_pk(|row| &row.n); + diff.result_every_primitive_struct_string = cache.apply_diff_to_table::( + "result_every_primitive_struct_string", + &self.result_every_primitive_struct_string, + ); + diff.result_i_32_string = + cache.apply_diff_to_table::("result_i32_string", &self.result_i_32_string); + diff.result_identity_string = + cache.apply_diff_to_table::("result_identity_string", &self.result_identity_string); + diff.result_simple_enum_i_32 = + cache.apply_diff_to_table::("result_simple_enum_i32", &self.result_simple_enum_i_32); + diff.result_string_i_32 = + cache.apply_diff_to_table::("result_string_i32", &self.result_string_i_32); + diff.result_vec_i_32_string = + cache.apply_diff_to_table::("result_vec_i32_string", &self.result_vec_i_32_string); diff.scheduled_table = cache .apply_diff_to_table::("scheduled_table", &self.scheduled_table) .with_updates_by_pk(|row| &row.scheduled_id); @@ -3401,6 +3538,12 @@ pub struct AppliedDiff<'r> { pk_u_32_two: __sdk::TableAppliedDiff<'r, PkU32Two>, pk_u_64: __sdk::TableAppliedDiff<'r, PkU64>, pk_u_8: __sdk::TableAppliedDiff<'r, PkU8>, + result_every_primitive_struct_string: __sdk::TableAppliedDiff<'r, ResultEveryPrimitiveStructString>, + result_i_32_string: __sdk::TableAppliedDiff<'r, ResultI32String>, + result_identity_string: __sdk::TableAppliedDiff<'r, ResultIdentityString>, + result_simple_enum_i_32: __sdk::TableAppliedDiff<'r, ResultSimpleEnumI32>, + result_string_i_32: __sdk::TableAppliedDiff<'r, ResultStringI32>, + result_vec_i_32_string: __sdk::TableAppliedDiff<'r, ResultVecI32String>, scheduled_table: __sdk::TableAppliedDiff<'r, ScheduledTable>, table_holds_table: __sdk::TableAppliedDiff<'r, TableHoldsTable>, unique_bool: __sdk::TableAppliedDiff<'r, UniqueBool>, @@ -3532,6 +3675,28 @@ impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> { callbacks.invoke_table_row_callbacks::("pk_u32_two", &self.pk_u_32_two, event); callbacks.invoke_table_row_callbacks::("pk_u64", &self.pk_u_64, event); callbacks.invoke_table_row_callbacks::("pk_u8", &self.pk_u_8, event); + callbacks.invoke_table_row_callbacks::( + "result_every_primitive_struct_string", + &self.result_every_primitive_struct_string, + event, + ); + callbacks.invoke_table_row_callbacks::("result_i32_string", &self.result_i_32_string, event); + callbacks.invoke_table_row_callbacks::( + "result_identity_string", + &self.result_identity_string, + event, + ); + callbacks.invoke_table_row_callbacks::( + "result_simple_enum_i32", + &self.result_simple_enum_i_32, + event, + ); + callbacks.invoke_table_row_callbacks::("result_string_i32", &self.result_string_i_32, event); + callbacks.invoke_table_row_callbacks::( + "result_vec_i32_string", + &self.result_vec_i_32_string, + event, + ); callbacks.invoke_table_row_callbacks::("scheduled_table", &self.scheduled_table, event); callbacks.invoke_table_row_callbacks::("table_holds_table", &self.table_holds_table, event); callbacks.invoke_table_row_callbacks::("unique_bool", &self.unique_bool, event); @@ -4365,6 +4530,12 @@ impl __sdk::SpacetimeModule for RemoteModule { pk_u_32_two_table::register_table(client_cache); pk_u_64_table::register_table(client_cache); pk_u_8_table::register_table(client_cache); + result_every_primitive_struct_string_table::register_table(client_cache); + result_i_32_string_table::register_table(client_cache); + result_identity_string_table::register_table(client_cache); + result_simple_enum_i_32_table::register_table(client_cache); + result_string_i_32_table::register_table(client_cache); + result_vec_i_32_string_table::register_table(client_cache); scheduled_table_table::register_table(client_cache); table_holds_table_table::register_table(client_cache); unique_bool_table::register_table(client_cache); diff --git a/sdks/rust/tests/test-client/src/module_bindings/result_every_primitive_struct_string_table.rs b/sdks/rust/tests/test-client/src/module_bindings/result_every_primitive_struct_string_table.rs new file mode 100644 index 00000000000..39f27548639 --- /dev/null +++ b/sdks/rust/tests/test-client/src/module_bindings/result_every_primitive_struct_string_table.rs @@ -0,0 +1,99 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use super::every_primitive_struct_type::EveryPrimitiveStruct; +use super::result_every_primitive_struct_string_type::ResultEveryPrimitiveStructString; +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +/// Table handle for the table `result_every_primitive_struct_string`. +/// +/// Obtain a handle from the [`ResultEveryPrimitiveStructStringTableAccess::result_every_primitive_struct_string`] method on [`super::RemoteTables`], +/// like `ctx.db.result_every_primitive_struct_string()`. +/// +/// Users are encouraged not to explicitly reference this type, +/// but to directly chain method calls, +/// like `ctx.db.result_every_primitive_struct_string().on_insert(...)`. +pub struct ResultEveryPrimitiveStructStringTableHandle<'ctx> { + imp: __sdk::TableHandle, + ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, +} + +#[allow(non_camel_case_types)] +/// Extension trait for access to the table `result_every_primitive_struct_string`. +/// +/// Implemented for [`super::RemoteTables`]. +pub trait ResultEveryPrimitiveStructStringTableAccess { + #[allow(non_snake_case)] + /// Obtain a [`ResultEveryPrimitiveStructStringTableHandle`], which mediates access to the table `result_every_primitive_struct_string`. + fn result_every_primitive_struct_string(&self) -> ResultEveryPrimitiveStructStringTableHandle<'_>; +} + +impl ResultEveryPrimitiveStructStringTableAccess for super::RemoteTables { + fn result_every_primitive_struct_string(&self) -> ResultEveryPrimitiveStructStringTableHandle<'_> { + ResultEveryPrimitiveStructStringTableHandle { + imp: self + .imp + .get_table::("result_every_primitive_struct_string"), + ctx: std::marker::PhantomData, + } + } +} + +pub struct ResultEveryPrimitiveStructStringInsertCallbackId(__sdk::CallbackId); +pub struct ResultEveryPrimitiveStructStringDeleteCallbackId(__sdk::CallbackId); + +impl<'ctx> __sdk::Table for ResultEveryPrimitiveStructStringTableHandle<'ctx> { + type Row = ResultEveryPrimitiveStructString; + type EventContext = super::EventContext; + + fn count(&self) -> u64 { + self.imp.count() + } + fn iter(&self) -> impl Iterator + '_ { + self.imp.iter() + } + + type InsertCallbackId = ResultEveryPrimitiveStructStringInsertCallbackId; + + fn on_insert( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> ResultEveryPrimitiveStructStringInsertCallbackId { + ResultEveryPrimitiveStructStringInsertCallbackId(self.imp.on_insert(Box::new(callback))) + } + + fn remove_on_insert(&self, callback: ResultEveryPrimitiveStructStringInsertCallbackId) { + self.imp.remove_on_insert(callback.0) + } + + type DeleteCallbackId = ResultEveryPrimitiveStructStringDeleteCallbackId; + + fn on_delete( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> ResultEveryPrimitiveStructStringDeleteCallbackId { + ResultEveryPrimitiveStructStringDeleteCallbackId(self.imp.on_delete(Box::new(callback))) + } + + fn remove_on_delete(&self, callback: ResultEveryPrimitiveStructStringDeleteCallbackId) { + self.imp.remove_on_delete(callback.0) + } +} + +#[doc(hidden)] +pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { + let _table = + client_cache.get_or_make_table::("result_every_primitive_struct_string"); +} + +#[doc(hidden)] +pub(super) fn parse_table_update( + raw_updates: __ws::TableUpdate<__ws::BsatnFormat>, +) -> __sdk::Result<__sdk::TableUpdate> { + __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { + __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") + .with_cause(e) + .into() + }) +} diff --git a/sdks/rust/tests/test-client/src/module_bindings/result_every_primitive_struct_string_type.rs b/sdks/rust/tests/test-client/src/module_bindings/result_every_primitive_struct_string_type.rs new file mode 100644 index 00000000000..27dd840464a --- /dev/null +++ b/sdks/rust/tests/test-client/src/module_bindings/result_every_primitive_struct_string_type.rs @@ -0,0 +1,17 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +use super::every_primitive_struct_type::EveryPrimitiveStruct; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub struct ResultEveryPrimitiveStructString { + pub r: Result, +} + +impl __sdk::InModule for ResultEveryPrimitiveStructString { + type Module = super::RemoteModule; +} diff --git a/sdks/rust/tests/test-client/src/module_bindings/result_i_32_string_table.rs b/sdks/rust/tests/test-client/src/module_bindings/result_i_32_string_table.rs new file mode 100644 index 00000000000..b18d8c228a1 --- /dev/null +++ b/sdks/rust/tests/test-client/src/module_bindings/result_i_32_string_table.rs @@ -0,0 +1,95 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use super::result_i_32_string_type::ResultI32String; +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +/// Table handle for the table `result_i32_string`. +/// +/// Obtain a handle from the [`ResultI32StringTableAccess::result_i_32_string`] method on [`super::RemoteTables`], +/// like `ctx.db.result_i_32_string()`. +/// +/// Users are encouraged not to explicitly reference this type, +/// but to directly chain method calls, +/// like `ctx.db.result_i_32_string().on_insert(...)`. +pub struct ResultI32StringTableHandle<'ctx> { + imp: __sdk::TableHandle, + ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, +} + +#[allow(non_camel_case_types)] +/// Extension trait for access to the table `result_i32_string`. +/// +/// Implemented for [`super::RemoteTables`]. +pub trait ResultI32StringTableAccess { + #[allow(non_snake_case)] + /// Obtain a [`ResultI32StringTableHandle`], which mediates access to the table `result_i32_string`. + fn result_i_32_string(&self) -> ResultI32StringTableHandle<'_>; +} + +impl ResultI32StringTableAccess for super::RemoteTables { + fn result_i_32_string(&self) -> ResultI32StringTableHandle<'_> { + ResultI32StringTableHandle { + imp: self.imp.get_table::("result_i32_string"), + ctx: std::marker::PhantomData, + } + } +} + +pub struct ResultI32StringInsertCallbackId(__sdk::CallbackId); +pub struct ResultI32StringDeleteCallbackId(__sdk::CallbackId); + +impl<'ctx> __sdk::Table for ResultI32StringTableHandle<'ctx> { + type Row = ResultI32String; + type EventContext = super::EventContext; + + fn count(&self) -> u64 { + self.imp.count() + } + fn iter(&self) -> impl Iterator + '_ { + self.imp.iter() + } + + type InsertCallbackId = ResultI32StringInsertCallbackId; + + fn on_insert( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> ResultI32StringInsertCallbackId { + ResultI32StringInsertCallbackId(self.imp.on_insert(Box::new(callback))) + } + + fn remove_on_insert(&self, callback: ResultI32StringInsertCallbackId) { + self.imp.remove_on_insert(callback.0) + } + + type DeleteCallbackId = ResultI32StringDeleteCallbackId; + + fn on_delete( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> ResultI32StringDeleteCallbackId { + ResultI32StringDeleteCallbackId(self.imp.on_delete(Box::new(callback))) + } + + fn remove_on_delete(&self, callback: ResultI32StringDeleteCallbackId) { + self.imp.remove_on_delete(callback.0) + } +} + +#[doc(hidden)] +pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { + let _table = client_cache.get_or_make_table::("result_i32_string"); +} + +#[doc(hidden)] +pub(super) fn parse_table_update( + raw_updates: __ws::TableUpdate<__ws::BsatnFormat>, +) -> __sdk::Result<__sdk::TableUpdate> { + __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { + __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") + .with_cause(e) + .into() + }) +} diff --git a/sdks/rust/tests/test-client/src/module_bindings/result_i_32_string_type.rs b/sdks/rust/tests/test-client/src/module_bindings/result_i_32_string_type.rs new file mode 100644 index 00000000000..8eb0d4c5856 --- /dev/null +++ b/sdks/rust/tests/test-client/src/module_bindings/result_i_32_string_type.rs @@ -0,0 +1,15 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub struct ResultI32String { + pub r: Result, +} + +impl __sdk::InModule for ResultI32String { + type Module = super::RemoteModule; +} diff --git a/sdks/rust/tests/test-client/src/module_bindings/result_identity_string_table.rs b/sdks/rust/tests/test-client/src/module_bindings/result_identity_string_table.rs new file mode 100644 index 00000000000..8a3d9d78b3e --- /dev/null +++ b/sdks/rust/tests/test-client/src/module_bindings/result_identity_string_table.rs @@ -0,0 +1,95 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use super::result_identity_string_type::ResultIdentityString; +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +/// Table handle for the table `result_identity_string`. +/// +/// Obtain a handle from the [`ResultIdentityStringTableAccess::result_identity_string`] method on [`super::RemoteTables`], +/// like `ctx.db.result_identity_string()`. +/// +/// Users are encouraged not to explicitly reference this type, +/// but to directly chain method calls, +/// like `ctx.db.result_identity_string().on_insert(...)`. +pub struct ResultIdentityStringTableHandle<'ctx> { + imp: __sdk::TableHandle, + ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, +} + +#[allow(non_camel_case_types)] +/// Extension trait for access to the table `result_identity_string`. +/// +/// Implemented for [`super::RemoteTables`]. +pub trait ResultIdentityStringTableAccess { + #[allow(non_snake_case)] + /// Obtain a [`ResultIdentityStringTableHandle`], which mediates access to the table `result_identity_string`. + fn result_identity_string(&self) -> ResultIdentityStringTableHandle<'_>; +} + +impl ResultIdentityStringTableAccess for super::RemoteTables { + fn result_identity_string(&self) -> ResultIdentityStringTableHandle<'_> { + ResultIdentityStringTableHandle { + imp: self.imp.get_table::("result_identity_string"), + ctx: std::marker::PhantomData, + } + } +} + +pub struct ResultIdentityStringInsertCallbackId(__sdk::CallbackId); +pub struct ResultIdentityStringDeleteCallbackId(__sdk::CallbackId); + +impl<'ctx> __sdk::Table for ResultIdentityStringTableHandle<'ctx> { + type Row = ResultIdentityString; + type EventContext = super::EventContext; + + fn count(&self) -> u64 { + self.imp.count() + } + fn iter(&self) -> impl Iterator + '_ { + self.imp.iter() + } + + type InsertCallbackId = ResultIdentityStringInsertCallbackId; + + fn on_insert( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> ResultIdentityStringInsertCallbackId { + ResultIdentityStringInsertCallbackId(self.imp.on_insert(Box::new(callback))) + } + + fn remove_on_insert(&self, callback: ResultIdentityStringInsertCallbackId) { + self.imp.remove_on_insert(callback.0) + } + + type DeleteCallbackId = ResultIdentityStringDeleteCallbackId; + + fn on_delete( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> ResultIdentityStringDeleteCallbackId { + ResultIdentityStringDeleteCallbackId(self.imp.on_delete(Box::new(callback))) + } + + fn remove_on_delete(&self, callback: ResultIdentityStringDeleteCallbackId) { + self.imp.remove_on_delete(callback.0) + } +} + +#[doc(hidden)] +pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { + let _table = client_cache.get_or_make_table::("result_identity_string"); +} + +#[doc(hidden)] +pub(super) fn parse_table_update( + raw_updates: __ws::TableUpdate<__ws::BsatnFormat>, +) -> __sdk::Result<__sdk::TableUpdate> { + __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { + __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") + .with_cause(e) + .into() + }) +} diff --git a/sdks/rust/tests/test-client/src/module_bindings/result_identity_string_type.rs b/sdks/rust/tests/test-client/src/module_bindings/result_identity_string_type.rs new file mode 100644 index 00000000000..e242fbc4d06 --- /dev/null +++ b/sdks/rust/tests/test-client/src/module_bindings/result_identity_string_type.rs @@ -0,0 +1,15 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub struct ResultIdentityString { + pub r: Result<__sdk::Identity, String>, +} + +impl __sdk::InModule for ResultIdentityString { + type Module = super::RemoteModule; +} diff --git a/sdks/rust/tests/test-client/src/module_bindings/result_simple_enum_i_32_table.rs b/sdks/rust/tests/test-client/src/module_bindings/result_simple_enum_i_32_table.rs new file mode 100644 index 00000000000..4c2a65d9f66 --- /dev/null +++ b/sdks/rust/tests/test-client/src/module_bindings/result_simple_enum_i_32_table.rs @@ -0,0 +1,96 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use super::result_simple_enum_i_32_type::ResultSimpleEnumI32; +use super::simple_enum_type::SimpleEnum; +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +/// Table handle for the table `result_simple_enum_i32`. +/// +/// Obtain a handle from the [`ResultSimpleEnumI32TableAccess::result_simple_enum_i_32`] method on [`super::RemoteTables`], +/// like `ctx.db.result_simple_enum_i_32()`. +/// +/// Users are encouraged not to explicitly reference this type, +/// but to directly chain method calls, +/// like `ctx.db.result_simple_enum_i_32().on_insert(...)`. +pub struct ResultSimpleEnumI32TableHandle<'ctx> { + imp: __sdk::TableHandle, + ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, +} + +#[allow(non_camel_case_types)] +/// Extension trait for access to the table `result_simple_enum_i32`. +/// +/// Implemented for [`super::RemoteTables`]. +pub trait ResultSimpleEnumI32TableAccess { + #[allow(non_snake_case)] + /// Obtain a [`ResultSimpleEnumI32TableHandle`], which mediates access to the table `result_simple_enum_i32`. + fn result_simple_enum_i_32(&self) -> ResultSimpleEnumI32TableHandle<'_>; +} + +impl ResultSimpleEnumI32TableAccess for super::RemoteTables { + fn result_simple_enum_i_32(&self) -> ResultSimpleEnumI32TableHandle<'_> { + ResultSimpleEnumI32TableHandle { + imp: self.imp.get_table::("result_simple_enum_i32"), + ctx: std::marker::PhantomData, + } + } +} + +pub struct ResultSimpleEnumI32InsertCallbackId(__sdk::CallbackId); +pub struct ResultSimpleEnumI32DeleteCallbackId(__sdk::CallbackId); + +impl<'ctx> __sdk::Table for ResultSimpleEnumI32TableHandle<'ctx> { + type Row = ResultSimpleEnumI32; + type EventContext = super::EventContext; + + fn count(&self) -> u64 { + self.imp.count() + } + fn iter(&self) -> impl Iterator + '_ { + self.imp.iter() + } + + type InsertCallbackId = ResultSimpleEnumI32InsertCallbackId; + + fn on_insert( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> ResultSimpleEnumI32InsertCallbackId { + ResultSimpleEnumI32InsertCallbackId(self.imp.on_insert(Box::new(callback))) + } + + fn remove_on_insert(&self, callback: ResultSimpleEnumI32InsertCallbackId) { + self.imp.remove_on_insert(callback.0) + } + + type DeleteCallbackId = ResultSimpleEnumI32DeleteCallbackId; + + fn on_delete( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> ResultSimpleEnumI32DeleteCallbackId { + ResultSimpleEnumI32DeleteCallbackId(self.imp.on_delete(Box::new(callback))) + } + + fn remove_on_delete(&self, callback: ResultSimpleEnumI32DeleteCallbackId) { + self.imp.remove_on_delete(callback.0) + } +} + +#[doc(hidden)] +pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { + let _table = client_cache.get_or_make_table::("result_simple_enum_i32"); +} + +#[doc(hidden)] +pub(super) fn parse_table_update( + raw_updates: __ws::TableUpdate<__ws::BsatnFormat>, +) -> __sdk::Result<__sdk::TableUpdate> { + __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { + __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") + .with_cause(e) + .into() + }) +} diff --git a/sdks/rust/tests/test-client/src/module_bindings/result_simple_enum_i_32_type.rs b/sdks/rust/tests/test-client/src/module_bindings/result_simple_enum_i_32_type.rs new file mode 100644 index 00000000000..e5a4725035d --- /dev/null +++ b/sdks/rust/tests/test-client/src/module_bindings/result_simple_enum_i_32_type.rs @@ -0,0 +1,17 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +use super::simple_enum_type::SimpleEnum; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub struct ResultSimpleEnumI32 { + pub r: Result, +} + +impl __sdk::InModule for ResultSimpleEnumI32 { + type Module = super::RemoteModule; +} diff --git a/sdks/rust/tests/test-client/src/module_bindings/result_string_i_32_table.rs b/sdks/rust/tests/test-client/src/module_bindings/result_string_i_32_table.rs new file mode 100644 index 00000000000..ea6b2c3c1aa --- /dev/null +++ b/sdks/rust/tests/test-client/src/module_bindings/result_string_i_32_table.rs @@ -0,0 +1,95 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use super::result_string_i_32_type::ResultStringI32; +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +/// Table handle for the table `result_string_i32`. +/// +/// Obtain a handle from the [`ResultStringI32TableAccess::result_string_i_32`] method on [`super::RemoteTables`], +/// like `ctx.db.result_string_i_32()`. +/// +/// Users are encouraged not to explicitly reference this type, +/// but to directly chain method calls, +/// like `ctx.db.result_string_i_32().on_insert(...)`. +pub struct ResultStringI32TableHandle<'ctx> { + imp: __sdk::TableHandle, + ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, +} + +#[allow(non_camel_case_types)] +/// Extension trait for access to the table `result_string_i32`. +/// +/// Implemented for [`super::RemoteTables`]. +pub trait ResultStringI32TableAccess { + #[allow(non_snake_case)] + /// Obtain a [`ResultStringI32TableHandle`], which mediates access to the table `result_string_i32`. + fn result_string_i_32(&self) -> ResultStringI32TableHandle<'_>; +} + +impl ResultStringI32TableAccess for super::RemoteTables { + fn result_string_i_32(&self) -> ResultStringI32TableHandle<'_> { + ResultStringI32TableHandle { + imp: self.imp.get_table::("result_string_i32"), + ctx: std::marker::PhantomData, + } + } +} + +pub struct ResultStringI32InsertCallbackId(__sdk::CallbackId); +pub struct ResultStringI32DeleteCallbackId(__sdk::CallbackId); + +impl<'ctx> __sdk::Table for ResultStringI32TableHandle<'ctx> { + type Row = ResultStringI32; + type EventContext = super::EventContext; + + fn count(&self) -> u64 { + self.imp.count() + } + fn iter(&self) -> impl Iterator + '_ { + self.imp.iter() + } + + type InsertCallbackId = ResultStringI32InsertCallbackId; + + fn on_insert( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> ResultStringI32InsertCallbackId { + ResultStringI32InsertCallbackId(self.imp.on_insert(Box::new(callback))) + } + + fn remove_on_insert(&self, callback: ResultStringI32InsertCallbackId) { + self.imp.remove_on_insert(callback.0) + } + + type DeleteCallbackId = ResultStringI32DeleteCallbackId; + + fn on_delete( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> ResultStringI32DeleteCallbackId { + ResultStringI32DeleteCallbackId(self.imp.on_delete(Box::new(callback))) + } + + fn remove_on_delete(&self, callback: ResultStringI32DeleteCallbackId) { + self.imp.remove_on_delete(callback.0) + } +} + +#[doc(hidden)] +pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { + let _table = client_cache.get_or_make_table::("result_string_i32"); +} + +#[doc(hidden)] +pub(super) fn parse_table_update( + raw_updates: __ws::TableUpdate<__ws::BsatnFormat>, +) -> __sdk::Result<__sdk::TableUpdate> { + __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { + __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") + .with_cause(e) + .into() + }) +} diff --git a/sdks/rust/tests/test-client/src/module_bindings/result_string_i_32_type.rs b/sdks/rust/tests/test-client/src/module_bindings/result_string_i_32_type.rs new file mode 100644 index 00000000000..463e9a8996b --- /dev/null +++ b/sdks/rust/tests/test-client/src/module_bindings/result_string_i_32_type.rs @@ -0,0 +1,15 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub struct ResultStringI32 { + pub r: Result, +} + +impl __sdk::InModule for ResultStringI32 { + type Module = super::RemoteModule; +} diff --git a/sdks/rust/tests/test-client/src/module_bindings/result_vec_i_32_string_table.rs b/sdks/rust/tests/test-client/src/module_bindings/result_vec_i_32_string_table.rs new file mode 100644 index 00000000000..201e7e778d6 --- /dev/null +++ b/sdks/rust/tests/test-client/src/module_bindings/result_vec_i_32_string_table.rs @@ -0,0 +1,95 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use super::result_vec_i_32_string_type::ResultVecI32String; +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +/// Table handle for the table `result_vec_i32_string`. +/// +/// Obtain a handle from the [`ResultVecI32StringTableAccess::result_vec_i_32_string`] method on [`super::RemoteTables`], +/// like `ctx.db.result_vec_i_32_string()`. +/// +/// Users are encouraged not to explicitly reference this type, +/// but to directly chain method calls, +/// like `ctx.db.result_vec_i_32_string().on_insert(...)`. +pub struct ResultVecI32StringTableHandle<'ctx> { + imp: __sdk::TableHandle, + ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, +} + +#[allow(non_camel_case_types)] +/// Extension trait for access to the table `result_vec_i32_string`. +/// +/// Implemented for [`super::RemoteTables`]. +pub trait ResultVecI32StringTableAccess { + #[allow(non_snake_case)] + /// Obtain a [`ResultVecI32StringTableHandle`], which mediates access to the table `result_vec_i32_string`. + fn result_vec_i_32_string(&self) -> ResultVecI32StringTableHandle<'_>; +} + +impl ResultVecI32StringTableAccess for super::RemoteTables { + fn result_vec_i_32_string(&self) -> ResultVecI32StringTableHandle<'_> { + ResultVecI32StringTableHandle { + imp: self.imp.get_table::("result_vec_i32_string"), + ctx: std::marker::PhantomData, + } + } +} + +pub struct ResultVecI32StringInsertCallbackId(__sdk::CallbackId); +pub struct ResultVecI32StringDeleteCallbackId(__sdk::CallbackId); + +impl<'ctx> __sdk::Table for ResultVecI32StringTableHandle<'ctx> { + type Row = ResultVecI32String; + type EventContext = super::EventContext; + + fn count(&self) -> u64 { + self.imp.count() + } + fn iter(&self) -> impl Iterator + '_ { + self.imp.iter() + } + + type InsertCallbackId = ResultVecI32StringInsertCallbackId; + + fn on_insert( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> ResultVecI32StringInsertCallbackId { + ResultVecI32StringInsertCallbackId(self.imp.on_insert(Box::new(callback))) + } + + fn remove_on_insert(&self, callback: ResultVecI32StringInsertCallbackId) { + self.imp.remove_on_insert(callback.0) + } + + type DeleteCallbackId = ResultVecI32StringDeleteCallbackId; + + fn on_delete( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> ResultVecI32StringDeleteCallbackId { + ResultVecI32StringDeleteCallbackId(self.imp.on_delete(Box::new(callback))) + } + + fn remove_on_delete(&self, callback: ResultVecI32StringDeleteCallbackId) { + self.imp.remove_on_delete(callback.0) + } +} + +#[doc(hidden)] +pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { + let _table = client_cache.get_or_make_table::("result_vec_i32_string"); +} + +#[doc(hidden)] +pub(super) fn parse_table_update( + raw_updates: __ws::TableUpdate<__ws::BsatnFormat>, +) -> __sdk::Result<__sdk::TableUpdate> { + __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { + __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") + .with_cause(e) + .into() + }) +} diff --git a/sdks/rust/tests/test-client/src/module_bindings/result_vec_i_32_string_type.rs b/sdks/rust/tests/test-client/src/module_bindings/result_vec_i_32_string_type.rs new file mode 100644 index 00000000000..cc6c0a71b6c --- /dev/null +++ b/sdks/rust/tests/test-client/src/module_bindings/result_vec_i_32_string_type.rs @@ -0,0 +1,15 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub struct ResultVecI32String { + pub r: Result, String>, +} + +impl __sdk::InModule for ResultVecI32String { + type Module = super::RemoteModule; +} diff --git a/smoketests/tests/pg_wire.py b/smoketests/tests/pg_wire.py index 24402e2ec9f..233bba1e3b5 100644 --- a/smoketests/tests/pg_wire.py +++ b/smoketests/tests/pg_wire.py @@ -92,6 +92,19 @@ class SqlFormat(Smoketest): ints: TInts, } +#[derive(Clone)] +#[spacetimedb::table(name = t_enums)] +pub struct TEnums { + bool_opt: Option, + bool_result: Result, + action: Action, +} + +#[spacetimedb::table(name = t_enums_tuple)] +pub struct TEnumsTuple { + tuple: TEnums, +} + #[spacetimedb::reducer] pub fn test(ctx: &ReducerContext) { let tuple = TInts { @@ -141,6 +154,15 @@ class SqlFormat(Smoketest): se: TSimpleEnum { id: 2, action: Action::Active }, ints, }); + + let tuple = TEnums { + bool_opt: Some(true), + bool_result: Ok(false), + action: Action::Active, + }; + + ctx.db.t_enums().insert(tuple.clone()); + ctx.db.t_enums_tuple().insert(TEnumsTuple { tuple }); } """ @@ -234,7 +256,19 @@ def test_sql_format(self): -----------------------------------+-------------------------------------+--------------------------------------------------------------------------------------------------------- {"id": 1, "color": {"Gray": 128}} | {"id": 2, "action": {"Active": {}}} | {"i8": -25, "i16": -3224, "i32": -23443, "i64": -2344353, "i128": -234434897853, "i256": -234434897853} (1 row)""") - + self.assertSql(token,"SELECT * FROM t_enums", """\ +bool_opt | bool_result | action +----------------+---------------+-------- + {"some": true} | {"ok": false} | Active +(1 row) +""") + self.assertSql(token,"SELECT * FROM t_enums_tuple", """\ +tuple +-------------------------------------------------------------------------------------- + {"bool_opt": {"some": true}, "bool_result": {"ok": false}, "action": {"Active": {}}} +(1 row) +""") + def test_sql_conn(self): """This test is designed to test connecting to the database and executing queries using `psycopg2`""" token = self.read_token() diff --git a/smoketests/tests/sql.py b/smoketests/tests/sql.py index c90d63c3661..1b33fbc5460 100644 --- a/smoketests/tests/sql.py +++ b/smoketests/tests/sql.py @@ -4,7 +4,7 @@ class SqlFormat(Smoketest): MODULE_CODE = """ use spacetimedb::sats::{i256, u256}; -use spacetimedb::{table, ConnectionId, Identity, ReducerContext, Table, Timestamp, TimeDuration}; +use spacetimedb::{table, ConnectionId, Identity, ReducerContext, Table, Timestamp, TimeDuration, SpacetimeType }; #[derive(Copy, Clone)] #[spacetimedb::table(name = t_ints)] @@ -57,6 +57,25 @@ class SqlFormat(Smoketest): tuple: TOthers } +#[derive(SpacetimeType, Debug, Clone, Copy)] +pub enum Action { + Inactive, + Active, +} + +#[derive(Clone)] +#[spacetimedb::table(name = t_enums)] +pub struct TEnums { + bool_opt: Option, + bool_result: Result, + action: Action, +} + +#[spacetimedb::table(name = t_enums_tuple)] +pub struct TEnumsTuple { + tuple: TEnums, +} + #[spacetimedb::reducer] pub fn test(ctx: &ReducerContext) { let tuple = TInts { @@ -94,6 +113,15 @@ class SqlFormat(Smoketest): }; ctx.db.t_others().insert(tuple.clone()); ctx.db.t_others_tuple().insert(TOthersTuple { tuple }); + + let tuple = TEnums { + bool_opt: Some(true), + bool_result: Ok(false), + action: Action::Active, + }; + + ctx.db.t_enums().insert(tuple.clone()); + ctx.db.t_enums_tuple().insert(TEnumsTuple { tuple }); } """ @@ -138,4 +166,14 @@ def test_sql_format(self): tuple ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- (bool = true, f32 = 594806.56, f64 = -3454353.345389043, str = "This is spacetimedb", bytes = 0x01020304050607, identity = 0x0000000000000000000000000000000000000000000000000000000000000001, connection_id = 0x00000000000000000000000000000000, timestamp = 1970-01-01T00:00:00+00:00, duration = +0.000000) +""") + self.assertSql("SELECT * FROM t_enums", """\ + bool_opt | bool_result | action +---------------+--------------+--------------- + (some = true) | (ok = false) | (Active = ()) +""") + self.assertSql("SELECT * FROM t_enums_tuple", """\ + tuple +-------------------------------------------------------------------------------- + (bool_opt = (some = true), bool_result = (ok = false), action = (Active = ())) """)