From 75ba1879ee56dd0239ddd58e99cfc1f37b2f5036 Mon Sep 17 00:00:00 2001 From: Gekctek Date: Fri, 25 Oct 2024 13:12:25 -0700 Subject: [PATCH 1/4] CandiTypeDef + Raw candid values --- README.md | 10 +- src/Candid/API.xml | 14 + src/Candid/Mapping/IResolvableTypeInfo.cs | 41 ++- src/Candid/Mapping/MapperAttributes.cs | 21 ++ src/Candid/Mapping/Mappers/RawCandidMapper.cs | 32 +++ src/Candid/Mapping/Mappers/RecordMapper.cs | 55 ++-- src/Candid/Mapping/Mappers/VariantMapper.cs | 92 ++++--- src/Candid/Models/Principal.cs | 4 +- src/Candid/Models/Types/Compound.cs | 7 +- src/Candid/README.md | 23 +- test/Candid.Tests/CandidConverterTests.cs | 254 ++++++++++++++++++ 11 files changed, 476 insertions(+), 77 deletions(-) create mode 100644 src/Candid/Mapping/Mappers/RawCandidMapper.cs diff --git a/README.md b/README.md index f97a021f..5a6a2377 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,6 @@ Collection of Internet Computer Protocol (ICP) libraries for .NET/Blazor/Unity ## See each individual project README for more in depth guides - # 🎮 Unity Integration - Download latest `agent.unitypackage` from: https://github.com/edjCase/ICP.NET/releases @@ -20,7 +19,9 @@ Collection of Internet Computer Protocol (ICP) libraries for .NET/Blazor/Unity - Start coding 💻 # 📡 Generating a client for a canister + You can specify all the models and api calls yourself, but this is a tool to automatically generate a client and models based on the canister or .did file + - Prerequisite: Have .Net 6 installed (https://dotnet.microsoft.com/en-us/download/dotnet) - Navigate to directory of .Net project ``` @@ -87,9 +88,13 @@ You can specify all the models and api calls yourself, but this is a tool to aut - SHIP IT! 🚀 # Breaking change migrations + ## 3.x.x => 4.x.x + The big change here was around variant classes and their attributes. Before the option types were defined by the attribute on each enum member, but in 4.x.x it changed to using method return types and having not type information in attributes. Also the VariantAttribute now gets the enum type from the Tag property vs the attribute + ### Version 3 + ``` [Variant(typeof(MyVariantTag))] // Required to flag as variant and define options with enum public class MyVariant @@ -109,7 +114,9 @@ public enum MyVariantTag Option2 } ``` + ### Version 4 + ``` [Variant] // Required to flag as variant public class MyVariant @@ -136,6 +143,7 @@ public enum MyVariantTag Option2 } ``` + # Candid Related Links - [IC Http Interface Spec](https://smartcontracts.org/docs/current/references/ic-interface-spec) diff --git a/src/Candid/API.xml b/src/Candid/API.xml index 2c9bf130..cc66e008 100644 --- a/src/Candid/API.xml +++ b/src/Candid/API.xml @@ -500,6 +500,20 @@ The tag of the variant option + + + An attribute to put on a raw candid value to specify its type. + This is REQUIRED for any raw candid values + + + + + The candid type definition for the raw value + + + + The candid type definition in string format https://github.com/dfinity/candid/blob/master/spec/Candid.md#core-grammar + A model representing a candid arg. Used as the list of arguments for a function diff --git a/src/Candid/Mapping/IResolvableTypeInfo.cs b/src/Candid/Mapping/IResolvableTypeInfo.cs index d1a42a1d..ad29cb29 100644 --- a/src/Candid/Mapping/IResolvableTypeInfo.cs +++ b/src/Candid/Mapping/IResolvableTypeInfo.cs @@ -2,6 +2,7 @@ using EdjCase.ICP.Candid.Models; using EdjCase.ICP.Candid.Models.Types; using EdjCase.ICP.Candid.Models.Values; +using EdjCase.ICP.Candid.Parsers; using System; using System.Collections; using System.Collections.Generic; @@ -335,6 +336,11 @@ private static IResolvableTypeInfo BuildTypeInfo(Type objType) return BuildVariant(objType, variantAttribute); } + if (typeof(CandidValue).IsAssignableFrom(objType)) + { + // If RawCandidValueAttribute is on the property, then it will never reach here + throw new InvalidOperationException("Raw candid values must have the `CandidTypeDefAttribute` on the property"); + } // Assume anything else is a record return BuildRecord(objType); @@ -519,7 +525,7 @@ private static IResolvableTypeInfo BuildVariant(Type objType, VariantAttribute a t => t ); - var optionTypes = new Dictionary(); + var optionTypes = new Dictionary(); foreach (MethodInfo classMethod in objType.GetMethods(BindingFlags.Instance | BindingFlags.Public)) { CandidTag tag; @@ -539,7 +545,9 @@ private static IResolvableTypeInfo BuildVariant(Type objType, VariantAttribute a CandidOptionalAttribute? optionalAttribute = classMethod.GetCustomAttribute(); bool useOptionalOverride = optionalAttribute != null; - optionTypes.Add(tag, (classMethod.ReturnType, useOptionalOverride)); + CandidTypeDefAttribute? rawCandidTypeAttribute = classMethod.GetCustomAttribute(); + + optionTypes.Add(tag, (classMethod.ReturnType, useOptionalOverride, rawCandidTypeAttribute?.Type)); } foreach (PropertyInfo property in properties) { @@ -566,14 +574,15 @@ private static IResolvableTypeInfo BuildVariant(Type objType, VariantAttribute a } CandidOptionalAttribute? optionalAttribute = property.GetCustomAttribute(); bool useOptionalOverride = optionalAttribute != null; - if (!optionTypes.TryGetValue(tag, out (Type, bool) optionType)) + CandidTypeDefAttribute? rawCandidTypeAttribute = property.GetCustomAttribute(); + if (!optionTypes.TryGetValue(tag, out (Type, bool, CandidType?) optionType)) { // Add if not already added by a method - optionTypes.Add(tag, (property.PropertyType, useOptionalOverride)); + optionTypes.Add(tag, (property.PropertyType, useOptionalOverride, rawCandidTypeAttribute?.Type)); } else { - if (optionType != (property.PropertyType, useOptionalOverride)) + if (optionType != (property.PropertyType, useOptionalOverride, rawCandidTypeAttribute?.Type)) { throw new Exception($"Conflict: Variant '{objType.FullName}' defines a property '{property.Name}' and a method with different types for an option"); } @@ -589,19 +598,21 @@ private static IResolvableTypeInfo BuildVariant(Type objType, VariantAttribute a MemberInfo enumOption = variantTagProperty.PropertyType.GetMember(tagName.Name).First(); Type? optionType = null; bool useOptionalOverride = false; - if (optionTypes.TryGetValue(tagName, out (Type Type, bool UseOptionalOverride) o)) + CandidType? candidType = null; + if (optionTypes.TryGetValue(tagName, out (Type Type, bool UseOptionalOverride, CandidType? CandidType) o)) { optionType = o.Type; useOptionalOverride = o.UseOptionalOverride; + candidType = o.CandidType; } var tagAttribute = enumOption.GetCustomAttribute(); CandidTag tag = tagAttribute?.Tag ?? tagName; - return (tag, new VariantMapper.Option(tagEnum, optionType, useOptionalOverride)); + return (tag, new VariantMapper.Option(tagEnum, optionType, useOptionalOverride, candidType)); }) .ToDictionary(k => k.Item1, k => k.Item2); List dependencies = options.Values - .Where(v => v.Type != null) + .Where(v => v.Type != null && v.CandidType == null) .Select(v => v.Type!) .Distinct() .ToList(); @@ -617,7 +628,7 @@ private static IResolvableTypeInfo BuildVariant(Type objType, VariantAttribute a { return new CandidPrimitiveType(PrimitiveType.Null); } - return resolvedDependencies[o.Value.Type]; + return o.Value.CandidType ?? resolvedDependencies[o.Value.Type]; } ); var type = new CandidVariantType(optionCandidTypes); @@ -673,10 +684,15 @@ private static IResolvableTypeInfo BuildRecord(Type objType) } CandidOptionalAttribute? optionalAttribute = property.GetCustomAttribute(); bool useOptionalOverride = optionalAttribute != null; - PropertyMetaData propertyMetaData = new(property, useOptionalOverride); + + CandidTypeDefAttribute? rawCandidValueAttribute = property.GetCustomAttribute(); + + + PropertyMetaData propertyMetaData = new(property, useOptionalOverride, rawCandidValueAttribute?.Type); propertyMetaDataMap.Add(tag, propertyMetaData); } List dependencies = propertyMetaDataMap + .Where(p => p.Value.CandidType is null) .Select(p => p.Value.PropertyInfo.PropertyType) .ToList(); return new ComplexTypeInfo(objType, dependencies, (resolvedMappings) => @@ -686,7 +702,7 @@ private static IResolvableTypeInfo BuildRecord(Type objType) p => p.Key, p => { - CandidType type = resolvedMappings[p.Value.PropertyInfo.PropertyType]; + CandidType type = p.Value.CandidType ?? resolvedMappings[p.Value.PropertyInfo.PropertyType]; if (p.Value.UseOptionalOverride) { // Property is really optional type @@ -704,7 +720,8 @@ private static IResolvableTypeInfo BuildRecord(Type objType) } internal record PropertyMetaData( PropertyInfo PropertyInfo, - bool UseOptionalOverride + bool UseOptionalOverride, + CandidType? CandidType ); diff --git a/src/Candid/Mapping/MapperAttributes.cs b/src/Candid/Mapping/MapperAttributes.cs index 55e13a58..382637f0 100644 --- a/src/Candid/Mapping/MapperAttributes.cs +++ b/src/Candid/Mapping/MapperAttributes.cs @@ -1,4 +1,6 @@ using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid.Models.Types; +using EdjCase.ICP.Candid.Parsers; using System; namespace EdjCase.ICP.Candid.Mapping @@ -117,4 +119,23 @@ public VariantOptionAttribute(string tag) : this(CandidTag.FromName(tag)) } } + + /// + /// An attribute to specify the candid type definition for a value + /// This is REQUIRED for any raw candid values + /// + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method)] + public class CandidTypeDefAttribute : Attribute + { + /// + /// The candid type definition for the value + /// + public CandidType Type { get; } + + /// The candid type definition in string format https://github.com/dfinity/candid/blob/master/spec/Candid.md#core-grammar + public CandidTypeDefAttribute(string typeDef) + { + this.Type = CandidTextParser.Parse(typeDef); + } + } } diff --git a/src/Candid/Mapping/Mappers/RawCandidMapper.cs b/src/Candid/Mapping/Mappers/RawCandidMapper.cs new file mode 100644 index 00000000..4dfd9174 --- /dev/null +++ b/src/Candid/Mapping/Mappers/RawCandidMapper.cs @@ -0,0 +1,32 @@ +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid.Models.Types; +using EdjCase.ICP.Candid.Models.Values; +using System; + +namespace EdjCase.ICP.Candid.Mapping.Mappers +{ + internal class RawCandidMapper : ICandidValueMapper + { + public CandidType CandidType { get; } + + public RawCandidMapper(CandidType candidType) + { + this.CandidType = candidType ?? throw new ArgumentNullException(nameof(candidType)); + } + + public object Map(CandidValue value, CandidConverter converter) + { + return value; + } + + public CandidValue Map(object value, CandidConverter converter) + { + return (CandidValue)value; + } + + public CandidType? GetMappedCandidType(Type type) + { + return this.CandidType; + } + } +} \ No newline at end of file diff --git a/src/Candid/Mapping/Mappers/RecordMapper.cs b/src/Candid/Mapping/Mappers/RecordMapper.cs index 04c18f2c..64b5ae6a 100644 --- a/src/Candid/Mapping/Mappers/RecordMapper.cs +++ b/src/Candid/Mapping/Mappers/RecordMapper.cs @@ -30,23 +30,31 @@ public object Map(CandidValue value, CandidConverter converter) if (record.Fields.TryGetValue(tag, out CandidValue fieldCandidValue)) { Type t = property.PropertyInfo.PropertyType; - if (t.IsGenericType - && t.GetGenericTypeDefinition() == typeof(Nullable<>)) + if (typeof(CandidValue).IsAssignableFrom(t)) { - // Get T of Nullable - t = t.GetGenericArguments()[0]; - } - if (property.UseOptionalOverride - && fieldCandidValue is CandidOptional o - && o.Value.IsNull()) - { - // If not using OptionalValue and the value is opt null, - // that is the same as setting to null, so just skip - fieldValue = null; + // If the property is a candid value, just set it + fieldValue = fieldCandidValue; } else { - fieldValue = converter.ToObject(t, fieldCandidValue); + if (t.IsGenericType + && t.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + // Get T of Nullable + t = t.GetGenericArguments()[0]; + } + if (property.UseOptionalOverride + && fieldCandidValue is CandidOptional o + && o.Value.IsNull()) + { + // If not using OptionalValue and the value is opt null, + // that is the same as setting to null, so just skip + fieldValue = null; + } + else + { + fieldValue = converter.ToObject(t, fieldCandidValue); + } } if (fieldValue != null) @@ -79,18 +87,25 @@ public CandidValue Map(object value, CandidConverter converter) foreach ((CandidTag tag, PropertyMetaData property) in this.Properties) { object? propValue = property.PropertyInfo.GetValue(value); - CandidValue v; - if (propValue == null) + CandidValue v; if (propValue is CandidValue cv) { - v = new CandidOptional(null); + // If the property is a candid value, just set it + v = cv; } else { - v = converter.FromObject(propValue); - if (property.UseOptionalOverride) + if (propValue == null) + { + v = new CandidOptional(null); + } + else { - // Wrap in candid optional if has override [CandidOptional] - v = new CandidOptional(v); + v = converter.FromObject(propValue); + if (property.UseOptionalOverride) + { + // Wrap in candid optional if has override [CandidOptional] + v = new CandidOptional(v); + } } } fields.Add(tag, v); diff --git a/src/Candid/Mapping/Mappers/VariantMapper.cs b/src/Candid/Mapping/Mappers/VariantMapper.cs index 7803027e..0e31c1e5 100644 --- a/src/Candid/Mapping/Mappers/VariantMapper.cs +++ b/src/Candid/Mapping/Mappers/VariantMapper.cs @@ -35,47 +35,55 @@ public VariantMapper( public object Map(CandidValue value, CandidConverter converter) { CandidVariant variant = value.AsVariant(); - object obj = Activator.CreateInstance(this.Type, nonPublic: true); if (!this.Options.TryGetValue(variant.Tag, out Option optionInfo)) { throw new Exception($"Could not map candid variant to type '{this.Type}'. Type is missing option '{variant.Tag}'"); } - object? variantValue; - if (optionInfo.Type != null) + if (typeof(CandidValue).IsAssignableFrom(optionInfo.Type)) { - if (optionInfo.UseOptionalOverride && variant.Value is CandidOptional o) + // If the type is a candid value, just set it + variantValue = variant.Value; + } + else + { + if (optionInfo.Type != null) { - // If UseOptionalOverride, then unwrap the inner value - if (o.Value.IsNull()) + if (optionInfo.UseOptionalOverride && variant.Value is CandidOptional o) { - // If null, no need to convert - variantValue = null; + // If UseOptionalOverride, then unwrap the inner value + if (o.Value.IsNull()) + { + // If null, no need to convert + variantValue = null; + } + else + { + Type t = optionInfo.Type; + if (t.IsGenericType + && t.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + // Get T of Nullable + t = t.GetGenericArguments()[0]; + } + // Use inner value + variantValue = converter.ToObject(t, o.Value); + } } else { - Type t = optionInfo.Type; - if (t.IsGenericType - && t.GetGenericTypeDefinition() == typeof(Nullable<>)) - { - // Get T of Nullable - t = t.GetGenericArguments()[0]; - } - // Use inner value - variantValue = converter.ToObject(t, o.Value); + // Treat like normal + variantValue = converter.ToObject(optionInfo.Type, variant.Value); } } else { - // Treat like normal - variantValue = converter.ToObject(optionInfo.Type, variant.Value); + variantValue = null; } } - else - { - variantValue = null; - } + + object obj = Activator.CreateInstance(this.Type, nonPublic: true); this.TypeProperty.SetValue(obj, optionInfo.EnumValue); this.ValueProperty.SetValue(obj, variantValue); return obj; @@ -94,24 +102,32 @@ public CandidValue Map(object obj, CandidConverter converter) CandidValue innerValue; - if(optionInfo.Type == null) + if (innerObj is CandidValue value) { - // If typeless, always set to null - innerValue = CandidValue.Null(); - } - else if (innerObj == null) - { - // If null and has a type, should always be a null opt - innerValue = new CandidOptional(null); + // If the object is a candid value, just use it + innerValue = value; } else { - // Convert - innerValue = converter.FromObject(innerObj); - if (optionInfo.UseOptionalOverride) + if (optionInfo.Type == null) + { + // If typeless, always set to null + innerValue = CandidValue.Null(); + } + else if (innerObj == null) + { + // If null and has a type, should always be a null opt + innerValue = new CandidOptional(null); + } + else { - // Wrap in candid optional - innerValue = new CandidOptional(innerValue); + // Convert + innerValue = converter.FromObject(innerObj); + if (optionInfo.UseOptionalOverride) + { + // Wrap in candid optional + innerValue = new CandidOptional(innerValue); + } } } return new CandidVariant(innerTag, innerValue); @@ -127,12 +143,14 @@ public class Option public Enum EnumValue { get; } public Type? Type { get; } public bool UseOptionalOverride { get; } + public CandidType? CandidType { get; } - public Option(Enum enumValue, Type? type, bool useOptionalOverride) + public Option(Enum enumValue, Type? type, bool useOptionalOverride, CandidType? candidType) { this.EnumValue = enumValue ?? throw new ArgumentNullException(nameof(enumValue)); this.Type = type; this.UseOptionalOverride = useOptionalOverride; + this.CandidType = candidType; } } } diff --git a/src/Candid/Models/Principal.cs b/src/Candid/Models/Principal.cs index e0492f26..486f101a 100644 --- a/src/Candid/Models/Principal.cs +++ b/src/Candid/Models/Principal.cs @@ -133,7 +133,7 @@ public byte[] ToLedgerAccount(byte[]? subAccount) .Concat(subAccount).ToArray(); // Compute the SHA224 hash - SHA224 sha224 = new (); + SHA224 sha224 = new(); byte[] hash = sha224.GenerateDigest(data); // Compute the CRC32 checksum @@ -248,7 +248,7 @@ public byte[] ComputeHash(IHashFunction hashFunction) /// public bool Equals(Principal? other) { - if (other == null) + if (other is null) { return false; } diff --git a/src/Candid/Models/Types/Compound.cs b/src/Candid/Models/Types/Compound.cs index 3906e0bb..c69e5c63 100644 --- a/src/Candid/Models/Types/Compound.cs +++ b/src/Candid/Models/Types/Compound.cs @@ -69,7 +69,7 @@ internal override void EncodeInnerTypes(CompoundTypeTable compoundTypeTable, IBu LEB128.EncodeSigned(fieldsOrOptions.Count, destination); // Encode field/option count - foreach(var f in fieldsOrOptions.OrderBy(f => f.Key)) + foreach (var f in fieldsOrOptions.OrderBy(f => f.Key)) { LEB128.EncodeUnsigned(f.Key.Id, destination); // Encode key f.Value.Encode(compoundTypeTable, destination); // Encode value @@ -88,13 +88,14 @@ public override bool Equals(object? obj) bool exactType = this.GetType() == obj?.GetType(); if (exactType && obj is CandidRecordOrVariantType def) { - if (fieldsOrOptions.Count != fieldsOrOptions.Count) + Dictionary otherFieldsOrOptions = def.GetFieldsOrOptions(); + if (fieldsOrOptions.Count != otherFieldsOrOptions.Count) { return false; } foreach ((CandidTag fLabel, CandidType fDef) in fieldsOrOptions) { - if (!fieldsOrOptions.TryGetValue(fLabel, out CandidType? otherFDef)) + if (!otherFieldsOrOptions.TryGetValue(fLabel, out CandidType? otherFDef)) { return false; } diff --git a/src/Candid/README.md b/src/Candid/README.md index 7c685df5..c32841b4 100644 --- a/src/Candid/README.md +++ b/src/Candid/README.md @@ -197,6 +197,22 @@ public class MyRecord } ``` +## Raw Candid Types + +If you want to use the raw candid forms for the value, then the candid type definition must be specified with the CandidTypeDefAttribute +The definition is in text form of candid (like in a \*.did file) as seen here https://github.com/dfinity/candid/blob/master/spec/Candid.md#core-grammar +The text form is used because attributes cannot have an object type, so cannot accept the CandidType class + +NOTE: func and service do not have a compatible type that is not the raw candid form, so they must have the CandidTypeDefAttribute + +``` +public class MyRecord +{ + [CandidTypeDef("() -> ()")] + public CandidFunc Callback { get; set; } +} +``` + ## Defining Other Types ```cs @@ -219,9 +235,12 @@ bool -> Bool Principal -> Principal List -> Vec T T[] -> Vec T -CandidFunc -> Func OptionalValue -> Opt T EmptyValue -> Empty ReservedValue -> Reserved NullValue -> Null -``` \ No newline at end of file +* CandidFunc -> Func +* CandidService -> Service + +* Raw types require the [CandidTypeDef("...")] attribute +``` diff --git a/test/Candid.Tests/CandidConverterTests.cs b/test/Candid.Tests/CandidConverterTests.cs index 51f0346d..825843d3 100644 --- a/test/Candid.Tests/CandidConverterTests.cs +++ b/test/Candid.Tests/CandidConverterTests.cs @@ -546,6 +546,260 @@ public void CustomOptionalValue() this.Test(raw, candid, (a, b) => a.ValueOrDefault == b.ValueOrDefault); } + public class AllRawTypes + { +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. + [CandidTypeDef("bool")] + public CandidPrimitive Bool { get; set; } + [CandidTypeDef("nat")] + public CandidPrimitive Nat { get; set; } + [CandidTypeDef("int")] + public CandidPrimitive Int { get; set; } + [CandidTypeDef("nat8")] + public CandidPrimitive Nat8 { get; set; } + [CandidTypeDef("nat16")] + public CandidPrimitive Nat16 { get; set; } + [CandidTypeDef("nat32")] + public CandidPrimitive Nat32 { get; set; } + [CandidTypeDef("nat64")] + public CandidPrimitive Nat64 { get; set; } + [CandidTypeDef("int8")] + public CandidPrimitive Int8 { get; set; } + [CandidTypeDef("int16")] + public CandidPrimitive Int16 { get; set; } + [CandidTypeDef("int32")] + public CandidPrimitive Int32 { get; set; } + [CandidTypeDef("int64")] + public CandidPrimitive Int64 { get; set; } + [CandidTypeDef("float32")] + public CandidPrimitive Float32 { get; set; } + [CandidTypeDef("float64")] + public CandidPrimitive Float64 { get; set; } + [CandidTypeDef("text")] + public CandidPrimitive Text { get; set; } + [CandidTypeDef("null")] + public CandidPrimitive Null { get; set; } + [CandidTypeDef("reserved")] + public CandidPrimitive Reserved { get; set; } + [CandidTypeDef("empty")] + public CandidPrimitive Empty { get; set; } + [CandidTypeDef("principal")] + public CandidPrimitive Principal { get; set; } + [CandidTypeDef("service { test : () -> () }")] + public CandidService Service { get; set; } + [CandidTypeDef("() -> ()")] + public CandidFunc Func { get; set; } + [CandidTypeDef("opt text")] + public CandidOptional Opt { get; set; } + [CandidTypeDef("vec text")] + public CandidVector Vec { get; set; } + [CandidTypeDef("record { text4 : text }")] + public CandidRecord Rec { get; set; } + [CandidTypeDef("variant { text5 : text }")] + public CandidVariant Var { get; set; } +#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. + } + + [Fact] + public void AllRawTypes__Record__NoMapping() + { + var raw = new AllRawTypes + { + Bool = CandidValue.Bool(true), + Nat = CandidValue.Nat(1), + Int = CandidValue.Int(-1), + Nat8 = CandidValue.Nat8(2), + Nat16 = CandidValue.Nat16(2), + Nat32 = CandidValue.Nat32(2), + Nat64 = CandidValue.Nat64(2), + Int8 = CandidValue.Int8(2), + Int16 = CandidValue.Int16(2), + Int32 = CandidValue.Int32(2), + Int64 = CandidValue.Int64(2), + Float32 = CandidValue.Float32(3.14f), + Float64 = CandidValue.Float64(-3.14f), + Text = CandidValue.Text("text"), + Null = CandidValue.Null(), + Reserved = CandidValue.Reserved(), + Empty = CandidValue.Empty(), + Principal = CandidValue.Principal(Models.Principal.FromText("rrkah-fqaaa-aaaaa-aaaaq-cai")), + Service = new CandidService(Models.Principal.FromText("rrkah-fqaaa-aaaaa-aaaaq-cai")), + Func = new CandidFunc(new CandidService(Models.Principal.FromText("rrkah-fqaaa-aaaaa-aaaaq-cai")), "test"), + Opt = new CandidOptional(CandidValue.Text("text2")), + Vec = new CandidVector(new CandidValue[] { CandidValue.Text("text3") }), + Rec = new CandidRecord(new Dictionary + { + ["text4"] = CandidValue.Text("text4") + }), + Var = new CandidVariant("text5", CandidValue.Text("text5")) + }; + + var candidValue = new CandidRecord(new Dictionary + { + ["Bool"] = raw.Bool, + ["Nat"] = raw.Nat, + ["Int"] = raw.Int, + ["Nat8"] = raw.Nat8, + ["Nat16"] = raw.Nat16, + ["Nat32"] = raw.Nat32, + ["Nat64"] = raw.Nat64, + ["Int8"] = raw.Int8, + ["Int16"] = raw.Int16, + ["Int32"] = raw.Int32, + ["Int64"] = raw.Int64, + ["Float32"] = raw.Float32, + ["Float64"] = raw.Float64, + ["Text"] = raw.Text, + ["Null"] = raw.Null, + ["Reserved"] = raw.Reserved, + ["Empty"] = raw.Empty, + ["Principal"] = raw.Principal, + ["Service"] = raw.Service, + ["Func"] = raw.Func, + ["Opt"] = raw.Opt, + ["Vec"] = raw.Vec, + ["Rec"] = raw.Rec, + ["Var"] = raw.Var + }); + var funcType = new CandidFuncType(new List(), new List(), new List()); + var candidType = new CandidRecordType(new Dictionary + { + ["Bool"] = CandidType.Bool(), + ["Nat"] = CandidType.Nat(), + ["Int"] = CandidType.Int(), + ["Nat8"] = CandidType.Nat8(), + ["Nat16"] = CandidType.Nat16(), + ["Nat32"] = CandidType.Nat32(), + ["Nat64"] = CandidType.Nat64(), + ["Int8"] = CandidType.Int8(), + ["Int16"] = CandidType.Int16(), + ["Int32"] = CandidType.Int32(), + ["Int64"] = CandidType.Int64(), + ["Float32"] = CandidType.Float32(), + ["Float64"] = CandidType.Float64(), + ["Text"] = CandidType.Text(), + ["Null"] = CandidType.Null(), + ["Reserved"] = CandidType.Reserved(), + ["Empty"] = CandidType.Empty(), + ["Principal"] = CandidType.Principal(), + ["Service"] = new CandidServiceType(new Dictionary + { + [CandidId.Create("test")] = funcType + }), + ["Func"] = funcType, + ["Opt"] = new CandidOptionalType(CandidType.Text()), + ["Vec"] = new CandidVectorType(CandidType.Text()), + ["Rec"] = new CandidRecordType(new Dictionary + { + ["text4"] = CandidType.Text() + }), + ["Var"] = new CandidVariantType(new Dictionary + { + ["text5"] = CandidType.Text() + }) + }); + var candid = new CandidTypedValue(candidValue, candidType); + + this.Test(raw, candid, (a, b) => + { + return a.Bool == b.Bool + && a.Nat == b.Nat + && a.Int == b.Int + && a.Nat8 == b.Nat8 + && a.Nat16 == b.Nat16 + && a.Nat32 == b.Nat32 + && a.Nat64 == b.Nat64 + && a.Int8 == b.Int8 + && a.Int16 == b.Int16 + && a.Int32 == b.Int32 + && a.Int64 == b.Int64 + && a.Float32 == b.Float32 + && a.Float64 == b.Float64 + && a.Text == b.Text + && a.Null == b.Null + && a.Reserved == b.Reserved + && a.Empty == b.Empty + && a.Principal == b.Principal + && a.Service == b.Service + && a.Func == b.Func + && a.Opt == b.Opt + && a.Vec == b.Vec + && a.Rec == b.Rec + && a.Var == b.Var; + }); + } + + [Variant] + public class RawVariant + { + [VariantTagProperty] + public RawVariantTag Tag { get; set; } + [VariantValueProperty] + public object? Value { get; set; } + + [CandidTypeDef("() -> ()")] + public CandidFunc AsFunc() + { + return (CandidFunc)this.Value!; + } + + [CandidTypeDef("opt text")] + public CandidOptional AsOptional() + { + return (CandidOptional)this.Value!; + } + } + public enum RawVariantTag + { + Func, + Optional + } + + [Fact] + public void RawVariant__NoMapping() + { + var value1 = new CandidFunc(new CandidService(Models.Principal.FromText("rrkah-fqaaa-aaaaa-aaaaq-cai")), "test"); + var raw = new RawVariant + { + Tag = RawVariantTag.Func, + Value = value1 + }; + var candidValue = new CandidVariant("Func", value1); + var candidType = new CandidVariantType(new Dictionary + { + ["Func"] = new CandidFuncType(new List(), new List(), new List()), + ["Optional"] = new CandidOptionalType(CandidType.Text()) + }); + var candidTypedValue = new CandidTypedValue(candidValue, candidType); + + var value2 = new CandidOptional(CandidValue.Text("text")); + var raw2 = new RawVariant + { + Tag = RawVariantTag.Optional, + Value = value2 + }; + + var candidValue2 = new CandidVariant("Optional", value2); + var candidTypedValue2 = new CandidTypedValue(candidValue2, candidType); + + + CandidTypedValue actualTypedCandid = CandidConverter.Default.FromTypedObject(raw); + Assert.Equal(candidTypedValue, actualTypedCandid); + + RawVariant actual = CandidConverter.Default.ToObject(candidValue); + Assert.NotNull(actual); + Assert.Equal(raw.Tag, actual.Tag); + Assert.Equal(raw.Value, actual.Value); + + CandidTypedValue actualTypedCandid2 = CandidConverter.Default.FromTypedObject(raw2); + Assert.Equal(candidTypedValue2, actualTypedCandid2); + + RawVariant actual2 = CandidConverter.Default.ToObject(candidValue2); + Assert.NotNull(actual2); + Assert.Equal(raw2.Tag, actual2.Tag); + Assert.Equal(raw2.Value, actual2.Value); + } + private void Test(T raw, CandidTypedValue candid, Func areEqual) where T : notnull From 0947ed50afc24a7f6dfdec59c7f22e89e86e3000 Mon Sep 17 00:00:00 2001 From: Gekctek Date: Sat, 26 Oct 2024 15:30:18 -0700 Subject: [PATCH 2/4] Adding CandidTypeDefinition to client generator --- src/Candid/API.xml | 12 ++-- src/Candid/Mapping/IResolvableTypeInfo.cs | 8 +-- src/Candid/Mapping/MapperAttributes.cs | 8 +-- src/Candid/Parsers/CandidTextParser.cs | 2 + src/Candid/README.md | 8 +-- src/ClientGenerator/ClientCodeGenerator.cs | 4 +- src/ClientGenerator/RoslynTypeResolver.cs | 30 ++++++++++ src/ClientGenerator/SourceCodeType.cs | 13 ++++- src/ClientGenerator/TypeName.cs | 43 ++++++++++++++- test/Candid.Tests/Candid.Tests.csproj | 14 ++--- test/Candid.Tests/CandidConverterTests.cs | 52 +++++++++--------- .../Generators/ClientGeneratorTests.cs | 3 +- .../Generators/Files/FuncType.did | 7 +++ ...ies_False_OverrideOptionalValue_False.snap | 55 +++++++++++++++++++ ...ties_False_OverrideOptionalValue_True.snap | 55 +++++++++++++++++++ ...ties_True_OverrideOptionalValue_False.snap | 55 +++++++++++++++++++ ...rties_True_OverrideOptionalValue_True.snap | 55 +++++++++++++++++++ ...ies_False_OverrideOptionalValue_False.snap | 54 ++++++++++++++++++ ...ties_False_OverrideOptionalValue_True.snap | 54 ++++++++++++++++++ ...ties_True_OverrideOptionalValue_False.snap | 54 ++++++++++++++++++ ...rties_True_OverrideOptionalValue_True.snap | 54 ++++++++++++++++++ ...ies_False_OverrideOptionalValue_False.snap | 55 +++++++++++++++++++ ...ties_False_OverrideOptionalValue_True.snap | 55 +++++++++++++++++++ ...ties_True_OverrideOptionalValue_False.snap | 55 +++++++++++++++++++ ...rties_True_OverrideOptionalValue_True.snap | 55 +++++++++++++++++++ ...ies_False_OverrideOptionalValue_False.snap | 54 ++++++++++++++++++ ...ties_False_OverrideOptionalValue_True.snap | 54 ++++++++++++++++++ ...ties_True_OverrideOptionalValue_False.snap | 54 ++++++++++++++++++ ...rties_True_OverrideOptionalValue_True.snap | 54 ++++++++++++++++++ ...ies_False_OverrideOptionalValue_False.snap | 55 +++++++++++++++++++ ...ties_False_OverrideOptionalValue_True.snap | 55 +++++++++++++++++++ ...ties_True_OverrideOptionalValue_False.snap | 55 +++++++++++++++++++ ...rties_True_OverrideOptionalValue_True.snap | 55 +++++++++++++++++++ ...ies_False_OverrideOptionalValue_False.snap | 54 ++++++++++++++++++ ...ties_False_OverrideOptionalValue_True.snap | 54 ++++++++++++++++++ ...ties_True_OverrideOptionalValue_False.snap | 54 ++++++++++++++++++ ...rties_True_OverrideOptionalValue_True.snap | 54 ++++++++++++++++++ ...ies_False_OverrideOptionalValue_False.snap | 55 +++++++++++++++++++ ...ties_False_OverrideOptionalValue_True.snap | 55 +++++++++++++++++++ ...ties_True_OverrideOptionalValue_False.snap | 55 +++++++++++++++++++ ...rties_True_OverrideOptionalValue_True.snap | 55 +++++++++++++++++++ ...ies_False_OverrideOptionalValue_False.snap | 54 ++++++++++++++++++ ...ties_False_OverrideOptionalValue_True.snap | 54 ++++++++++++++++++ ...ties_True_OverrideOptionalValue_False.snap | 54 ++++++++++++++++++ ...rties_True_OverrideOptionalValue_True.snap | 54 ++++++++++++++++++ 45 files changed, 1889 insertions(+), 59 deletions(-) create mode 100644 test/Candid.Tests/Generators/Files/FuncType.did create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_False.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_True.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_False.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_True.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_False.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_True.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_False.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_True.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_False.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_True.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_False.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_True.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_False.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_True.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_False.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_True.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_False.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_True.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_False.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_True.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_False.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_True.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_False.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_True.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_False.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_True.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_False.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_True.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_False.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_True.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_False.snap create mode 100644 test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_True.snap diff --git a/src/Candid/API.xml b/src/Candid/API.xml index cc66e008..6d65f8ca 100644 --- a/src/Candid/API.xml +++ b/src/Candid/API.xml @@ -500,19 +500,19 @@ The tag of the variant option - + - An attribute to put on a raw candid value to specify its type. + An attribute to specify the candid type definition for a value This is REQUIRED for any raw candid values - + - The candid type definition for the raw value + The candid type definition for the value - - The candid type definition in string format https://github.com/dfinity/candid/blob/master/spec/Candid.md#core-grammar + + The candid type definition in string format https://github.com/dfinity/candid/blob/master/spec/Candid.md#core-grammar diff --git a/src/Candid/Mapping/IResolvableTypeInfo.cs b/src/Candid/Mapping/IResolvableTypeInfo.cs index ad29cb29..3c7b6ed8 100644 --- a/src/Candid/Mapping/IResolvableTypeInfo.cs +++ b/src/Candid/Mapping/IResolvableTypeInfo.cs @@ -339,7 +339,7 @@ private static IResolvableTypeInfo BuildTypeInfo(Type objType) if (typeof(CandidValue).IsAssignableFrom(objType)) { // If RawCandidValueAttribute is on the property, then it will never reach here - throw new InvalidOperationException("Raw candid values must have the `CandidTypeDefAttribute` on the property"); + throw new InvalidOperationException("Raw candid values must have the `CandidTypeDefinitionAttribute` on the property"); } // Assume anything else is a record @@ -545,7 +545,7 @@ private static IResolvableTypeInfo BuildVariant(Type objType, VariantAttribute a CandidOptionalAttribute? optionalAttribute = classMethod.GetCustomAttribute(); bool useOptionalOverride = optionalAttribute != null; - CandidTypeDefAttribute? rawCandidTypeAttribute = classMethod.GetCustomAttribute(); + CandidTypeDefinitionAttribute? rawCandidTypeAttribute = classMethod.GetCustomAttribute(); optionTypes.Add(tag, (classMethod.ReturnType, useOptionalOverride, rawCandidTypeAttribute?.Type)); } @@ -574,7 +574,7 @@ private static IResolvableTypeInfo BuildVariant(Type objType, VariantAttribute a } CandidOptionalAttribute? optionalAttribute = property.GetCustomAttribute(); bool useOptionalOverride = optionalAttribute != null; - CandidTypeDefAttribute? rawCandidTypeAttribute = property.GetCustomAttribute(); + CandidTypeDefinitionAttribute? rawCandidTypeAttribute = property.GetCustomAttribute(); if (!optionTypes.TryGetValue(tag, out (Type, bool, CandidType?) optionType)) { // Add if not already added by a method @@ -685,7 +685,7 @@ private static IResolvableTypeInfo BuildRecord(Type objType) CandidOptionalAttribute? optionalAttribute = property.GetCustomAttribute(); bool useOptionalOverride = optionalAttribute != null; - CandidTypeDefAttribute? rawCandidValueAttribute = property.GetCustomAttribute(); + CandidTypeDefinitionAttribute? rawCandidValueAttribute = property.GetCustomAttribute(); PropertyMetaData propertyMetaData = new(property, useOptionalOverride, rawCandidValueAttribute?.Type); diff --git a/src/Candid/Mapping/MapperAttributes.cs b/src/Candid/Mapping/MapperAttributes.cs index 382637f0..bcb7a43e 100644 --- a/src/Candid/Mapping/MapperAttributes.cs +++ b/src/Candid/Mapping/MapperAttributes.cs @@ -125,17 +125,17 @@ public VariantOptionAttribute(string tag) : this(CandidTag.FromName(tag)) /// This is REQUIRED for any raw candid values /// [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method)] - public class CandidTypeDefAttribute : Attribute + public class CandidTypeDefinitionAttribute : Attribute { /// /// The candid type definition for the value /// public CandidType Type { get; } - /// The candid type definition in string format https://github.com/dfinity/candid/blob/master/spec/Candid.md#core-grammar - public CandidTypeDefAttribute(string typeDef) + /// The candid type definition in string format https://github.com/dfinity/candid/blob/master/spec/Candid.md#core-grammar + public CandidTypeDefinitionAttribute(string definition) { - this.Type = CandidTextParser.Parse(typeDef); + this.Type = CandidTextParser.Parse(definition); } } } diff --git a/src/Candid/Parsers/CandidTextParser.cs b/src/Candid/Parsers/CandidTextParser.cs index 05723a4d..c422d8b8 100644 --- a/src/Candid/Parsers/CandidTextParser.cs +++ b/src/Candid/Parsers/CandidTextParser.cs @@ -48,6 +48,7 @@ private static CandidType ParseType(CandidTextTokenHelper helper) case CandidTextTokenType.OpenParenthesis: return GetFunc(helper, null); case CandidTextTokenType.OpenCurlyBrace: + // TODO service type return GetRecord(helper, null); case CandidTextTokenType.OpenBracket: return GetVec(helper, null); @@ -99,6 +100,7 @@ private static CandidFuncType GetFunc(CandidTextTokenHelper helper, CandidId? re if (helper.CurrentToken.Type == CandidTextTokenType.SemiColon || helper.CurrentToken.Type == CandidTextTokenType.CloseCurlyBrace) { + helper.MoveNext(); break; } string rawMode = helper.CurrentToken.GetTextValueOrThrow(); diff --git a/src/Candid/README.md b/src/Candid/README.md index c32841b4..2848793c 100644 --- a/src/Candid/README.md +++ b/src/Candid/README.md @@ -199,16 +199,16 @@ public class MyRecord ## Raw Candid Types -If you want to use the raw candid forms for the value, then the candid type definition must be specified with the CandidTypeDefAttribute +If you want to use the raw candid forms for the value, then the candid type definition must be specified with the CandidTypeDefinitionAttribute The definition is in text form of candid (like in a \*.did file) as seen here https://github.com/dfinity/candid/blob/master/spec/Candid.md#core-grammar The text form is used because attributes cannot have an object type, so cannot accept the CandidType class -NOTE: func and service do not have a compatible type that is not the raw candid form, so they must have the CandidTypeDefAttribute +NOTE: func and service do not have a compatible type that is not the raw candid form, so they must have the CandidTypeDefinitionAttribute ``` public class MyRecord { - [CandidTypeDef("() -> ()")] + [CandidTypeDefinition("() -> ()")] public CandidFunc Callback { get; set; } } ``` @@ -242,5 +242,5 @@ NullValue -> Null * CandidFunc -> Func * CandidService -> Service -* Raw types require the [CandidTypeDef("...")] attribute +* Raw types require the [CandidTypeDefinition("...")] attribute ``` diff --git a/src/ClientGenerator/ClientCodeGenerator.cs b/src/ClientGenerator/ClientCodeGenerator.cs index c2923ae9..6ee0c06a 100644 --- a/src/ClientGenerator/ClientCodeGenerator.cs +++ b/src/ClientGenerator/ClientCodeGenerator.cs @@ -73,7 +73,7 @@ ClientGenerationOptions options ) { var nameHelper = new NameHelper(options.KeepCandidCase); - HashSet aliasedTypeIds = new (); + HashSet aliasedTypeIds = new(); // Mapping of A => Type // where candid is: type A = Type; Dictionary declaredTypes = service.DeclaredTypes @@ -168,7 +168,7 @@ out bool hasAliasReference case CandidFuncType f: { hasAliasReference = false; - return new NonGenericSourceCodeType(typeof(CandidFunc)); + return new RawCandidType(f); } case CandidPrimitiveType p: { diff --git a/src/ClientGenerator/RoslynTypeResolver.cs b/src/ClientGenerator/RoslynTypeResolver.cs index 504a4176..a68bbffb 100644 --- a/src/ClientGenerator/RoslynTypeResolver.cs +++ b/src/ClientGenerator/RoslynTypeResolver.cs @@ -13,6 +13,7 @@ using System.Threading.Tasks; using EdjCase.ICP.Candid; using Org.BouncyCastle.Asn1.Cms; +using EdjCase.ICP.Candid.Models.Types; namespace EdjCase.ICP.ClientGenerator { @@ -77,6 +78,11 @@ Stack parentTypeIds { switch (type) { + case RawCandidType t: + { + CandidTypeTypeName typeName = new(t.CandidType); + return new ResolvedType(typeName); + } case NonGenericSourceCodeType c: { var cType = new SimpleTypeName( @@ -503,6 +509,14 @@ private List GenerateVariantProperties( { attributeSyntaxList.Add(this.GenerateAttribute(AttributeInfo.FromType())); } + CandidType? candidType = o.Type!.Name.GetCandidType(); + if (candidType != null) + { + // [CandidTypeDefinition("{typeDefinition}")] + string candidTypeDefinition = CandidTextGenerator.Generate(candidType, indentType: CandidTextGenerator.IndentType.None); + attributeSyntaxList.Add(this.GenerateAttribute(AttributeInfo.FromType(candidTypeDefinition))); + } + List accessors = new() { // Add getter @@ -849,6 +863,14 @@ bool optionalOverridden // Add '?' if applicible returnTypeName = new NullableTypeName(returnTypeName); } + CandidType? candidType = returnTypeName.GetCandidType(); + if (candidType != null) + { + // [CandidTypeDefinition("{typeDefinition}")] + attributes ??= new List(); + string candidTypeDefinition = CandidTextGenerator.Generate(candidType, indentType: CandidTextGenerator.IndentType.None); + attributes.Add(AttributeInfo.FromType(candidTypeDefinition)); + } return this.GenerateMethod( body: body, @@ -981,6 +1003,14 @@ Stack parentTypeIds // Add '?' if applicible typeName = new NullableTypeName(typeName); } + CandidType? candidType = typeName.GetCandidType(); + if (candidType != null) + { + // [CandidTypeDefinition("{typeDefinition}")] + string candidTypeDefinition = CandidTextGenerator.Generate(candidType, indentType: CandidTextGenerator.IndentType.None); + attributes.Add(AttributeInfo.FromType(candidTypeDefinition)); + } + // public {fieldType} {fieldName} {{ get; set; }} diff --git a/src/ClientGenerator/SourceCodeType.cs b/src/ClientGenerator/SourceCodeType.cs index a32ca80f..162a276a 100644 --- a/src/ClientGenerator/SourceCodeType.cs +++ b/src/ClientGenerator/SourceCodeType.cs @@ -11,6 +11,17 @@ internal abstract class SourceCodeType } + internal class RawCandidType : SourceCodeType + { + public Candid.Models.Types.CandidType CandidType { get; } + public override bool IsPredefinedType { get; } = true; + + public RawCandidType(Candid.Models.Types.CandidType candidType) + { + this.CandidType = candidType ?? throw new ArgumentNullException(nameof(candidType)); + } + } + internal class NonGenericSourceCodeType : SourceCodeType { public Type Type { get; } @@ -71,7 +82,7 @@ public DictionarySourceCodeType(SourceCodeType keyType, SourceCodeType valueType { this.KeyType = keyType; this.ValueType = valueType; - this.IsPredefinedType= usePredefined; + this.IsPredefinedType = usePredefined; } } diff --git a/src/ClientGenerator/TypeName.cs b/src/ClientGenerator/TypeName.cs index 43e73d6a..1b796668 100644 --- a/src/ClientGenerator/TypeName.cs +++ b/src/ClientGenerator/TypeName.cs @@ -1,4 +1,6 @@ using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid.Models.Types; +using EdjCase.ICP.Candid.Models.Values; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System; @@ -65,6 +67,44 @@ public override TypeSyntax ToTypeSyntax(bool featureNullable, bool resolveAliase } } + internal class CandidTypeTypeName : TypeName + { + public override bool IsDefaultNullable => false; + public CandidType CandidType { get; } + + public CandidTypeTypeName(CandidType candidType) + { + this.CandidType = candidType; + } + + public override string BuildName(bool featureNullable, bool includeNamespace, bool resolveAliases) + { + Type candidValueType; + switch (this.CandidType) + { + case CandidFuncType f: + candidValueType = typeof(CandidFunc); + break; + default: + throw new NotImplementedException("RawCandidType type not implemented: " + this.CandidType); + } + if (!includeNamespace || candidValueType.Namespace == null) + { + return candidValueType.Name; + } + return candidValueType.Namespace + "." + candidValueType.Name; + } + + public override TypeSyntax ToTypeSyntax(bool featureNullable, bool resolveAliases) + { + string typeName = this.BuildName(featureNullable, includeNamespace: true, resolveAliases: resolveAliases); + return SyntaxFactory.IdentifierName(typeName); + } + + public override CandidType? GetCandidType() => this.CandidType; + + } + internal class SimpleTypeName : TypeName { public override bool IsDefaultNullable { get; } @@ -244,7 +284,7 @@ public override TypeSyntax ToTypeSyntax(bool featureNullable, bool resolveAliase public override string BuildName(bool featureNullable, bool includeNamespace, bool resolveAliases) { string innerName = this.InnerType.BuildName(featureNullable, includeNamespace, resolveAliases); - return featureNullable ? innerName + "?" : innerName; + return featureNullable ? innerName + "?" : innerName; } } @@ -319,6 +359,7 @@ public override TypeSyntax ToTypeSyntax(bool featureNullable, bool resolveAliase internal abstract class TypeName { + public virtual CandidType? GetCandidType() => null; public abstract string BuildName(bool featureNullable, bool includeNamespace, bool resolveAliases = false); public abstract TypeSyntax ToTypeSyntax(bool featureNullable, bool resolveAliases = false); public abstract bool IsDefaultNullable { get; } diff --git a/test/Candid.Tests/Candid.Tests.csproj b/test/Candid.Tests/Candid.Tests.csproj index d00baa61..e5d69294 100644 --- a/test/Candid.Tests/Candid.Tests.csproj +++ b/test/Candid.Tests/Candid.Tests.csproj @@ -11,17 +11,11 @@ - - - - + - - - - + @@ -49,8 +43,8 @@ - - + + diff --git a/test/Candid.Tests/CandidConverterTests.cs b/test/Candid.Tests/CandidConverterTests.cs index 825843d3..f538ecd3 100644 --- a/test/Candid.Tests/CandidConverterTests.cs +++ b/test/Candid.Tests/CandidConverterTests.cs @@ -549,53 +549,53 @@ public void CustomOptionalValue() public class AllRawTypes { #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. - [CandidTypeDef("bool")] + [CandidTypeDefinition("bool")] public CandidPrimitive Bool { get; set; } - [CandidTypeDef("nat")] + [CandidTypeDefinition("nat")] public CandidPrimitive Nat { get; set; } - [CandidTypeDef("int")] + [CandidTypeDefinition("int")] public CandidPrimitive Int { get; set; } - [CandidTypeDef("nat8")] + [CandidTypeDefinition("nat8")] public CandidPrimitive Nat8 { get; set; } - [CandidTypeDef("nat16")] + [CandidTypeDefinition("nat16")] public CandidPrimitive Nat16 { get; set; } - [CandidTypeDef("nat32")] + [CandidTypeDefinition("nat32")] public CandidPrimitive Nat32 { get; set; } - [CandidTypeDef("nat64")] + [CandidTypeDefinition("nat64")] public CandidPrimitive Nat64 { get; set; } - [CandidTypeDef("int8")] + [CandidTypeDefinition("int8")] public CandidPrimitive Int8 { get; set; } - [CandidTypeDef("int16")] + [CandidTypeDefinition("int16")] public CandidPrimitive Int16 { get; set; } - [CandidTypeDef("int32")] + [CandidTypeDefinition("int32")] public CandidPrimitive Int32 { get; set; } - [CandidTypeDef("int64")] + [CandidTypeDefinition("int64")] public CandidPrimitive Int64 { get; set; } - [CandidTypeDef("float32")] + [CandidTypeDefinition("float32")] public CandidPrimitive Float32 { get; set; } - [CandidTypeDef("float64")] + [CandidTypeDefinition("float64")] public CandidPrimitive Float64 { get; set; } - [CandidTypeDef("text")] + [CandidTypeDefinition("text")] public CandidPrimitive Text { get; set; } - [CandidTypeDef("null")] + [CandidTypeDefinition("null")] public CandidPrimitive Null { get; set; } - [CandidTypeDef("reserved")] + [CandidTypeDefinition("reserved")] public CandidPrimitive Reserved { get; set; } - [CandidTypeDef("empty")] + [CandidTypeDefinition("empty")] public CandidPrimitive Empty { get; set; } - [CandidTypeDef("principal")] + [CandidTypeDefinition("principal")] public CandidPrimitive Principal { get; set; } - [CandidTypeDef("service { test : () -> () }")] + [CandidTypeDefinition("service { test : () -> () }")] public CandidService Service { get; set; } - [CandidTypeDef("() -> ()")] + [CandidTypeDefinition("() -> ()")] public CandidFunc Func { get; set; } - [CandidTypeDef("opt text")] + [CandidTypeDefinition("opt text")] public CandidOptional Opt { get; set; } - [CandidTypeDef("vec text")] + [CandidTypeDefinition("vec text")] public CandidVector Vec { get; set; } - [CandidTypeDef("record { text4 : text }")] + [CandidTypeDefinition("record { text4 : text }")] public CandidRecord Rec { get; set; } - [CandidTypeDef("variant { text5 : text }")] + [CandidTypeDefinition("variant { text5 : text }")] public CandidVariant Var { get; set; } #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. } @@ -737,13 +737,13 @@ public class RawVariant [VariantValueProperty] public object? Value { get; set; } - [CandidTypeDef("() -> ()")] + [CandidTypeDefinition("() -> ()")] public CandidFunc AsFunc() { return (CandidFunc)this.Value!; } - [CandidTypeDef("opt text")] + [CandidTypeDefinition("opt text")] public CandidOptional AsOptional() { return (CandidOptional)this.Value!; diff --git a/test/Candid.Tests/Generators/ClientGeneratorTests.cs b/test/Candid.Tests/Generators/ClientGeneratorTests.cs index 3d254e47..0f5c5527 100644 --- a/test/Candid.Tests/Generators/ClientGeneratorTests.cs +++ b/test/Candid.Tests/Generators/ClientGeneratorTests.cs @@ -23,6 +23,7 @@ public class ClientGeneratorTests [InlineData("Dex")] [InlineData("AnonymousTuples")] [InlineData("DuplicatePropertyNames")] + [InlineData("FuncType")] public void GenerateClients(string serviceName) { string fileText = GetFileText(serviceName + ".did"); @@ -81,7 +82,7 @@ bool variantsUseProperties outputDirectory: "./", purgeOutputDirectory: true, noFolders: noFolders, - featureNullable: featureNullable, + featureNullable: featureNullable, variantsUseProperties: variantsUseProperties, keepCandidCase: keepCandidCase, overrideOptionalValue: overrideOptionalValue, diff --git a/test/Candid.Tests/Generators/Files/FuncType.did b/test/Candid.Tests/Generators/Files/FuncType.did new file mode 100644 index 00000000..45a61a03 --- /dev/null +++ b/test/Candid.Tests/Generators/Files/FuncType.did @@ -0,0 +1,7 @@ +type Result = { + callback : () -> (); +}; + +service : () -> { + a : () -> (Result) query; +}; diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_False.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_False.snap new file mode 100644 index 00000000..1535f04f --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_False.snap @@ -0,0 +1,55 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task A() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test.Models +{ + public class Result + { + [CandidName("callback")] + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc Callback { get; set; } + + public Result(CandidFunc callback) + { + this.Callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_True.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_True.snap new file mode 100644 index 00000000..1535f04f --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_True.snap @@ -0,0 +1,55 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task A() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test.Models +{ + public class Result + { + [CandidName("callback")] + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc Callback { get; set; } + + public Result(CandidFunc callback) + { + this.Callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_False.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_False.snap new file mode 100644 index 00000000..1535f04f --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_False.snap @@ -0,0 +1,55 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task A() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test.Models +{ + public class Result + { + [CandidName("callback")] + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc Callback { get; set; } + + public Result(CandidFunc callback) + { + this.Callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_True.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_True.snap new file mode 100644 index 00000000..1535f04f --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_True.snap @@ -0,0 +1,55 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task A() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test.Models +{ + public class Result + { + [CandidName("callback")] + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc Callback { get; set; } + + public Result(CandidFunc callback) + { + this.Callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_False.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_False.snap new file mode 100644 index 00000000..8c31bf53 --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_False.snap @@ -0,0 +1,54 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task a() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test.Models +{ + public class Result + { + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc callback { get; set; } + + public Result(CandidFunc callback) + { + this.callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_True.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_True.snap new file mode 100644 index 00000000..8c31bf53 --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_True.snap @@ -0,0 +1,54 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task a() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test.Models +{ + public class Result + { + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc callback { get; set; } + + public Result(CandidFunc callback) + { + this.callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_False.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_False.snap new file mode 100644 index 00000000..8c31bf53 --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_False.snap @@ -0,0 +1,54 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task a() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test.Models +{ + public class Result + { + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc callback { get; set; } + + public Result(CandidFunc callback) + { + this.callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_True.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_True.snap new file mode 100644 index 00000000..8c31bf53 --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_False_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_True.snap @@ -0,0 +1,54 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task a() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test.Models +{ + public class Result + { + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc callback { get; set; } + + public Result(CandidFunc callback) + { + this.callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_False.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_False.snap new file mode 100644 index 00000000..1e6b5e50 --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_False.snap @@ -0,0 +1,55 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter? Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter? converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task A() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test.Models +{ + public class Result + { + [CandidName("callback")] + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc Callback { get; set; } + + public Result(CandidFunc callback) + { + this.Callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_True.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_True.snap new file mode 100644 index 00000000..1e6b5e50 --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_True.snap @@ -0,0 +1,55 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter? Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter? converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task A() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test.Models +{ + public class Result + { + [CandidName("callback")] + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc Callback { get; set; } + + public Result(CandidFunc callback) + { + this.Callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_False.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_False.snap new file mode 100644 index 00000000..1e6b5e50 --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_False.snap @@ -0,0 +1,55 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter? Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter? converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task A() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test.Models +{ + public class Result + { + [CandidName("callback")] + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc Callback { get; set; } + + public Result(CandidFunc callback) + { + this.Callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_True.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_True.snap new file mode 100644 index 00000000..1e6b5e50 --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_True.snap @@ -0,0 +1,55 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter? Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter? converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task A() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test.Models +{ + public class Result + { + [CandidName("callback")] + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc Callback { get; set; } + + public Result(CandidFunc callback) + { + this.Callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_False.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_False.snap new file mode 100644 index 00000000..01ada2dd --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_False.snap @@ -0,0 +1,54 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter? Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter? converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task a() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test.Models +{ + public class Result + { + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc callback { get; set; } + + public Result(CandidFunc callback) + { + this.callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_True.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_True.snap new file mode 100644 index 00000000..01ada2dd --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_True.snap @@ -0,0 +1,54 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter? Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter? converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task a() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test.Models +{ + public class Result + { + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc callback { get; set; } + + public Result(CandidFunc callback) + { + this.callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_False.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_False.snap new file mode 100644 index 00000000..01ada2dd --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_False.snap @@ -0,0 +1,54 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter? Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter? converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task a() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test.Models +{ + public class Result + { + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc callback { get; set; } + + public Result(CandidFunc callback) + { + this.callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_True.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_True.snap new file mode 100644 index 00000000..01ada2dd --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_False_Nullable_True_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_True.snap @@ -0,0 +1,54 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter? Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter? converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task a() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test.Models +{ + public class Result + { + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc callback { get; set; } + + public Result(CandidFunc callback) + { + this.callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_False.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_False.snap new file mode 100644 index 00000000..fd402d60 --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_False.snap @@ -0,0 +1,55 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task A() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test +{ + public class Result + { + [CandidName("callback")] + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc Callback { get; set; } + + public Result(CandidFunc callback) + { + this.Callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_True.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_True.snap new file mode 100644 index 00000000..fd402d60 --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_True.snap @@ -0,0 +1,55 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task A() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test +{ + public class Result + { + [CandidName("callback")] + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc Callback { get; set; } + + public Result(CandidFunc callback) + { + this.Callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_False.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_False.snap new file mode 100644 index 00000000..fd402d60 --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_False.snap @@ -0,0 +1,55 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task A() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test +{ + public class Result + { + [CandidName("callback")] + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc Callback { get; set; } + + public Result(CandidFunc callback) + { + this.Callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_True.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_True.snap new file mode 100644 index 00000000..fd402d60 --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_True.snap @@ -0,0 +1,55 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task A() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test +{ + public class Result + { + [CandidName("callback")] + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc Callback { get; set; } + + public Result(CandidFunc callback) + { + this.Callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_False.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_False.snap new file mode 100644 index 00000000..6ea78ea5 --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_False.snap @@ -0,0 +1,54 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task a() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test +{ + public class Result + { + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc callback { get; set; } + + public Result(CandidFunc callback) + { + this.callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_True.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_True.snap new file mode 100644 index 00000000..6ea78ea5 --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_True.snap @@ -0,0 +1,54 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task a() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test +{ + public class Result + { + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc callback { get; set; } + + public Result(CandidFunc callback) + { + this.callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_False.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_False.snap new file mode 100644 index 00000000..6ea78ea5 --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_False.snap @@ -0,0 +1,54 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task a() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test +{ + public class Result + { + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc callback { get; set; } + + public Result(CandidFunc callback) + { + this.callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_True.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_True.snap new file mode 100644 index 00000000..6ea78ea5 --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_False_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_True.snap @@ -0,0 +1,54 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task a() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test +{ + public class Result + { + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc callback { get; set; } + + public Result(CandidFunc callback) + { + this.callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_False.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_False.snap new file mode 100644 index 00000000..c494782a --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_False.snap @@ -0,0 +1,55 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter? Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter? converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task A() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test +{ + public class Result + { + [CandidName("callback")] + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc Callback { get; set; } + + public Result(CandidFunc callback) + { + this.Callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_True.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_True.snap new file mode 100644 index 00000000..c494782a --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_False_VariantsUseProperties_False_OverrideOptionalValue_True.snap @@ -0,0 +1,55 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter? Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter? converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task A() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test +{ + public class Result + { + [CandidName("callback")] + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc Callback { get; set; } + + public Result(CandidFunc callback) + { + this.Callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_False.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_False.snap new file mode 100644 index 00000000..c494782a --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_False.snap @@ -0,0 +1,55 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter? Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter? converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task A() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test +{ + public class Result + { + [CandidName("callback")] + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc Callback { get; set; } + + public Result(CandidFunc callback) + { + this.Callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_True.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_True.snap new file mode 100644 index 00000000..c494782a --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_False_VariantsUseProperties_True_OverrideOptionalValue_True.snap @@ -0,0 +1,55 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter? Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter? converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task A() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test +{ + public class Result + { + [CandidName("callback")] + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc Callback { get; set; } + + public Result(CandidFunc callback) + { + this.Callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_False.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_False.snap new file mode 100644 index 00000000..d52868ad --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_False.snap @@ -0,0 +1,54 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter? Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter? converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task a() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test +{ + public class Result + { + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc callback { get; set; } + + public Result(CandidFunc callback) + { + this.callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_True.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_True.snap new file mode 100644 index 00000000..d52868ad --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_True_VariantsUseProperties_False_OverrideOptionalValue_True.snap @@ -0,0 +1,54 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter? Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter? converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task a() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test +{ + public class Result + { + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc callback { get; set; } + + public Result(CandidFunc callback) + { + this.callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_False.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_False.snap new file mode 100644 index 00000000..d52868ad --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_False.snap @@ -0,0 +1,54 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter? Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter? converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task a() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test +{ + public class Result + { + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc callback { get; set; } + + public Result(CandidFunc callback) + { + this.callback = callback; + } + + public Result() + { + } + } +} diff --git a/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_True.snap b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_True.snap new file mode 100644 index 00000000..d52868ad --- /dev/null +++ b/test/Candid.Tests/Generators/__snapshots__/FuncType_NoFolders_True_Nullable_True_KeepCandidCase_True_VariantsUseProperties_True_OverrideOptionalValue_True.snap @@ -0,0 +1,54 @@ +using EdjCase.ICP.Agent.Agents; +using EdjCase.ICP.Candid.Models; +using EdjCase.ICP.Candid; +using System.Threading.Tasks; +using Test; +using EdjCase.ICP.Agent.Responses; + +namespace Test +{ + public class FuncTypeApiClient + { + public IAgent Agent { get; } + public Principal CanisterId { get; } + public CandidConverter? Converter { get; } + + public FuncTypeApiClient(IAgent agent, Principal canisterId, CandidConverter? converter = default) + { + this.Agent = agent; + this.CanisterId = canisterId; + this.Converter = converter; + } + + public async Task a() + { + CandidArg arg = CandidArg.FromCandid(); + QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "a", arg); + CandidArg reply = response.ThrowOrGetReply(); + return reply.ToObjects(this.Converter); + } + } +} + +Type File: 'Result' + +using EdjCase.ICP.Candid.Mapping; +using EdjCase.ICP.Candid.Models.Values; + +namespace Test +{ + public class Result + { + [CandidTypeDefinition("( ) -> ( )")] + public CandidFunc callback { get; set; } + + public Result(CandidFunc callback) + { + this.callback = callback; + } + + public Result() + { + } + } +} From 28d3b65d047c0c21f7f8db63e35c44725052899c Mon Sep 17 00:00:00 2001 From: Gekctek Date: Sat, 26 Oct 2024 16:20:48 -0700 Subject: [PATCH 3/4] Fixing tests --- src/Candid/Mapping/IResolvableTypeInfo.cs | 12 +++++++++--- test/Candid.Tests/CandidConverterTests.cs | 3 +-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Candid/Mapping/IResolvableTypeInfo.cs b/src/Candid/Mapping/IResolvableTypeInfo.cs index 3c7b6ed8..8b2daf52 100644 --- a/src/Candid/Mapping/IResolvableTypeInfo.cs +++ b/src/Candid/Mapping/IResolvableTypeInfo.cs @@ -333,7 +333,7 @@ private static IResolvableTypeInfo BuildTypeInfo(Type objType) VariantAttribute? variantAttribute = objType.GetCustomAttribute(); if (variantAttribute != null) { - return BuildVariant(objType, variantAttribute); + return BuildVariant(objType); } if (typeof(CandidValue).IsAssignableFrom(objType)) @@ -487,7 +487,7 @@ private static IResolvableTypeInfo BuildEnumVariant(Type enumType) return new ResolvedTypeInfo(enumType, candidType, mapper); } - private static IResolvableTypeInfo BuildVariant(Type objType, VariantAttribute attribute) + private static IResolvableTypeInfo BuildVariant(Type objType) { List properties = objType .GetProperties(BindingFlags.Instance | BindingFlags.Public) @@ -628,7 +628,13 @@ private static IResolvableTypeInfo BuildVariant(Type objType, VariantAttribute a { return new CandidPrimitiveType(PrimitiveType.Null); } - return o.Value.CandidType ?? resolvedDependencies[o.Value.Type]; + CandidType type = o.Value.CandidType ?? resolvedDependencies[o.Value.Type]; + if (o.Value.UseOptionalOverride) + { + // Property is really optional type + type = new CandidOptionalType(type); + } + return type; } ); var type = new CandidVariantType(optionCandidTypes); diff --git a/test/Candid.Tests/CandidConverterTests.cs b/test/Candid.Tests/CandidConverterTests.cs index f538ecd3..c5a920d8 100644 --- a/test/Candid.Tests/CandidConverterTests.cs +++ b/test/Candid.Tests/CandidConverterTests.cs @@ -372,10 +372,9 @@ public class OptOverrideVariant return (string)this.Value!; } - [CandidOptional] public int? AsInt() { - return (int)this.Value!; + return (int?)this.Value!; } } From c289e6406bbe563a381b9200cf2c4586abac2d25 Mon Sep 17 00:00:00 2001 From: Gekctek Date: Sat, 26 Oct 2024 16:58:08 -0700 Subject: [PATCH 4/4] Fixing tests --- src/Candid/Mapping/IResolvableTypeInfo.cs | 21 +++++++++++++++++++-- src/Candid/Mapping/Mappers/RecordMapper.cs | 9 ++------- src/Candid/Mapping/Mappers/VariantMapper.cs | 20 +++++++++++++++++++- test/Candid.Tests/CandidConverterTests.cs | 5 ++++- 4 files changed, 44 insertions(+), 11 deletions(-) diff --git a/src/Candid/Mapping/IResolvableTypeInfo.cs b/src/Candid/Mapping/IResolvableTypeInfo.cs index 8b2daf52..d926c43c 100644 --- a/src/Candid/Mapping/IResolvableTypeInfo.cs +++ b/src/Candid/Mapping/IResolvableTypeInfo.cs @@ -724,11 +724,28 @@ private static IResolvableTypeInfo BuildRecord(Type objType) } } + internal record PropertyMetaData( PropertyInfo PropertyInfo, bool UseOptionalOverride, CandidType? CandidType - ); - + ) + { + private bool? isGenericNullableCache; + public bool IsGenericNullable + { + get + { + { + if (!this.isGenericNullableCache.HasValue) + { + this.isGenericNullableCache = this.PropertyInfo.PropertyType.IsGenericType + && this.PropertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>); + } + return this.isGenericNullableCache.Value; + } + } + } + }; } diff --git a/src/Candid/Mapping/Mappers/RecordMapper.cs b/src/Candid/Mapping/Mappers/RecordMapper.cs index 64b5ae6a..a10e1688 100644 --- a/src/Candid/Mapping/Mappers/RecordMapper.cs +++ b/src/Candid/Mapping/Mappers/RecordMapper.cs @@ -37,12 +37,6 @@ public object Map(CandidValue value, CandidConverter converter) } else { - if (t.IsGenericType - && t.GetGenericTypeDefinition() == typeof(Nullable<>)) - { - // Get T of Nullable - t = t.GetGenericArguments()[0]; - } if (property.UseOptionalOverride && fieldCandidValue is CandidOptional o && o.Value.IsNull()) @@ -101,9 +95,10 @@ public CandidValue Map(object value, CandidConverter converter) else { v = converter.FromObject(propValue); - if (property.UseOptionalOverride) + if (property.UseOptionalOverride || property.IsGenericNullable) { // Wrap in candid optional if has override [CandidOptional] + // or is Nullable<> (Nullable gives just T if setting the value) v = new CandidOptional(v); } } diff --git a/src/Candid/Mapping/Mappers/VariantMapper.cs b/src/Candid/Mapping/Mappers/VariantMapper.cs index 0e31c1e5..108a1b31 100644 --- a/src/Candid/Mapping/Mappers/VariantMapper.cs +++ b/src/Candid/Mapping/Mappers/VariantMapper.cs @@ -123,7 +123,7 @@ public CandidValue Map(object obj, CandidConverter converter) { // Convert innerValue = converter.FromObject(innerObj); - if (optionInfo.UseOptionalOverride) + if (optionInfo.UseOptionalOverride || optionInfo.IsGenericNullable) { // Wrap in candid optional innerValue = new CandidOptional(innerValue); @@ -152,6 +152,24 @@ public Option(Enum enumValue, Type? type, bool useOptionalOverride, CandidType? this.UseOptionalOverride = useOptionalOverride; this.CandidType = candidType; } + + + private bool? isGenericNullableCache; + + public bool IsGenericNullable + { + get + { + { + if (!this.isGenericNullableCache.HasValue) + { + this.isGenericNullableCache = this.Type != null && this.Type.IsGenericType + && this.Type.GetGenericTypeDefinition() == typeof(Nullable<>); + } + return this.isGenericNullableCache.Value; + } + } + } } } } diff --git a/test/Candid.Tests/CandidConverterTests.cs b/test/Candid.Tests/CandidConverterTests.cs index c5a920d8..870746fd 100644 --- a/test/Candid.Tests/CandidConverterTests.cs +++ b/test/Candid.Tests/CandidConverterTests.cs @@ -169,6 +169,10 @@ public class VariantValueClass public object? Value { get; set; } + public string AsV2() + { + return (string)this.Value!; + } public int AsV3() { return (int)this.Value!; @@ -313,7 +317,6 @@ public class OptOverride [CandidOptional] public string? OptValue { get; set; } - [CandidOptional] public int? OptIntValue { get; set; } public OptionalValue OptValue2 { get; set; } = OptionalValue.NoValue(); }