Skip to content

Commit

Permalink
Fixing optionalValue that arent inline mapping (#109)
Browse files Browse the repository at this point in the history
  • Loading branch information
Gekctek committed Oct 9, 2023
1 parent 7025e86 commit c6eae59
Show file tree
Hide file tree
Showing 17 changed files with 179 additions and 65 deletions.
8 changes: 6 additions & 2 deletions samples/Sample.Shared/Address/SelfRef.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@ namespace Sample.Shared.AddressBook
{
public class SelfRef : OptionalValue<SelfRef.SelfRefValue>
{
protected SelfRef()
public SelfRef()
{
}

public SelfRef(SelfRef.SelfRefValue value) : base(value)
{
}

public class SelfRefValue : List<SelfRef>
{
protected SelfRefValue()
public SelfRefValue()
{
}
}
Expand Down
6 changes: 5 additions & 1 deletion samples/Sample.Shared/ICRC1Ledger/Models/Account.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ public Account()

public class SubaccountInfo : OptionalValue<Subaccount>
{
protected SubaccountInfo()
public SubaccountInfo()
{
}

public SubaccountInfo(Subaccount value) : base(value)
{
}
}
Expand Down
6 changes: 5 additions & 1 deletion samples/Sample.Shared/ICRC1Ledger/Models/Allowance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ public Allowance()

public class ExpiresAtInfo : OptionalValue<Timestamp>
{
protected ExpiresAtInfo()
public ExpiresAtInfo()
{
}

public ExpiresAtInfo(Timestamp value) : base(value)
{
}
}
Expand Down
12 changes: 10 additions & 2 deletions samples/Sample.Shared/ICRC1Ledger/Models/Approve.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,22 @@ public Approve()

public class CreatedAtTimeInfo : OptionalValue<Timestamp>
{
protected CreatedAtTimeInfo()
public CreatedAtTimeInfo()
{
}

public CreatedAtTimeInfo(Timestamp value) : base(value)
{
}
}

public class ExpiresAtInfo : OptionalValue<Timestamp>
{
protected ExpiresAtInfo()
public ExpiresAtInfo()
{
}

public ExpiresAtInfo(Timestamp value) : base(value)
{
}
}
Expand Down
12 changes: 10 additions & 2 deletions samples/Sample.Shared/ICRC1Ledger/Models/ApproveArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,22 @@ public ApproveArgs()

public class CreatedAtTimeInfo : OptionalValue<Timestamp>
{
protected CreatedAtTimeInfo()
public CreatedAtTimeInfo()
{
}

public CreatedAtTimeInfo(Timestamp value) : base(value)
{
}
}

public class ExpiresAtInfo : OptionalValue<Timestamp>
{
protected ExpiresAtInfo()
public ExpiresAtInfo()
{
}

public ExpiresAtInfo(Timestamp value) : base(value)
{
}
}
Expand Down
2 changes: 1 addition & 1 deletion samples/Sample.Shared/ICRC1Ledger/Models/BlockRange.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public BlockRange()

public class BlocksInfo : List<Block>
{
protected BlocksInfo()
public BlocksInfo()
{
}
}
Expand Down
6 changes: 5 additions & 1 deletion samples/Sample.Shared/ICRC1Ledger/Models/Burn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ public Burn()

public class CreatedAtTimeInfo : OptionalValue<Timestamp>
{
protected CreatedAtTimeInfo()
public CreatedAtTimeInfo()
{
}

public CreatedAtTimeInfo(Timestamp value) : base(value)
{
}
}
Expand Down
4 changes: 2 additions & 2 deletions samples/Sample.Shared/ICRC1Ledger/Models/GetBlocksResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ public GetBlocksResponse()

public class BlocksInfo : List<Block>
{
protected BlocksInfo()
public BlocksInfo()
{
}
}

public class ArchivedBlocksInfo : List<GetBlocksResponse.ArchivedBlocksInfo.ArchivedBlocksInfoElement>
{
protected ArchivedBlocksInfo()
public ArchivedBlocksInfo()
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public GetTransactionsResponse()

public class ArchivedTransactionsInfo : List<GetTransactionsResponse.ArchivedTransactionsInfo.ArchivedTransactionsInfoElement>
{
protected ArchivedTransactionsInfo()
public ArchivedTransactionsInfo()
{
}

Expand Down
6 changes: 5 additions & 1 deletion samples/Sample.Shared/ICRC1Ledger/Models/Mint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ public Mint()

public class CreatedAtTimeInfo : OptionalValue<Timestamp>
{
protected CreatedAtTimeInfo()
public CreatedAtTimeInfo()
{
}

public CreatedAtTimeInfo(Timestamp value) : base(value)
{
}
}
Expand Down
6 changes: 5 additions & 1 deletion samples/Sample.Shared/ICRC1Ledger/Models/Transfer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ public Transfer()

public class CreatedAtTimeInfo : OptionalValue<Timestamp>
{
protected CreatedAtTimeInfo()
public CreatedAtTimeInfo()
{
}

public CreatedAtTimeInfo(Timestamp value) : base(value)
{
}
}
Expand Down
18 changes: 15 additions & 3 deletions samples/Sample.Shared/ICRC1Ledger/Models/TransferArg.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,33 @@ public TransferArg()

public class FromSubaccountInfo : OptionalValue<Subaccount>
{
protected FromSubaccountInfo()
public FromSubaccountInfo()
{
}

public FromSubaccountInfo(Subaccount value) : base(value)
{
}
}

public class FeeInfo : OptionalValue<Tokens>
{
protected FeeInfo()
public FeeInfo()
{
}

public FeeInfo(Tokens value) : base(value)
{
}
}

public class CreatedAtTimeInfo : OptionalValue<Timestamp>
{
protected CreatedAtTimeInfo()
public CreatedAtTimeInfo()
{
}

public CreatedAtTimeInfo(Timestamp value) : base(value)
{
}
}
Expand Down
18 changes: 15 additions & 3 deletions samples/Sample.Shared/ICRC1Ledger/Models/TransferFromArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,21 +48,33 @@ public TransferFromArgs()

public class SpenderSubaccountInfo : OptionalValue<Subaccount>
{
protected SpenderSubaccountInfo()
public SpenderSubaccountInfo()
{
}

public SpenderSubaccountInfo(Subaccount value) : base(value)
{
}
}

public class FeeInfo : OptionalValue<Tokens>
{
protected FeeInfo()
public FeeInfo()
{
}

public FeeInfo(Tokens value) : base(value)
{
}
}

public class CreatedAtTimeInfo : OptionalValue<Timestamp>
{
protected CreatedAtTimeInfo()
public CreatedAtTimeInfo()
{
}

public CreatedAtTimeInfo(Timestamp value) : base(value)
{
}
}
Expand Down
2 changes: 1 addition & 1 deletion samples/Sample.Shared/ICRC1Ledger/Models/Value.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ private void ValidateTag(ValueTag tag)

public class ArrayInfo : List<Value>
{
protected ArrayInfo()
public ArrayInfo()
{
}
}
Expand Down
77 changes: 48 additions & 29 deletions src/Candid/Mapping/IResolvableTypeInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -276,32 +276,23 @@ private static IResolvableTypeInfo BuildTypeInfo(Type objType)
return BuildEnumVariant(objType);
}

// Generics
if (objType.IsGenericType)
if (ImplementsType(objType, typeof(OptionalValue<>), out Type? optionalType))
{
Type genericTypeDefinition = objType.GetGenericTypeDefinition();
if (genericTypeDefinition == typeof(OptionalValue<>))
{
return BuildOpt(objType);
}
if (objType.Name.StartsWith("ValueTuple"))
{
return BuildTuple(objType, objType.GenericTypeArguments);
}
if(genericTypeDefinition == typeof(Nullable<>))
{
return BuildNullableStruct(objType);
}
return BuildOpt(objType, optionalType.GenericTypeArguments[0]);
}
if (IsImplementationOfGenericType(objType, typeof(IDictionary<, >), out Type? dictInterface))
if (ImplementsType(objType, typeof(Nullable<>), out Type? nullableType))
{
return BuildNullableStruct(objType, nullableType.GenericTypeArguments[0]);
}
if (ImplementsType(objType, typeof(IDictionary<,>), out Type? dictInterface))
{
return BuildDictVector(
objType,
dictInterface.GenericTypeArguments[0],
dictInterface.GenericTypeArguments[1]
);
}
if (IsImplementationOfGenericType(objType, typeof(IList<>), out Type? listInterface))
if (ImplementsType(objType, typeof(IList<>), out Type? listInterface))
{
Type innerType = listInterface.GenericTypeArguments[0];
return BuildVector(
Expand All @@ -319,6 +310,10 @@ private static IResolvableTypeInfo BuildTypeInfo(Type objType)
}
);
}
if (objType.IsGenericType && objType.Name.StartsWith("ValueTuple"))
{
return BuildTuple(objType, objType.GenericTypeArguments);
}

if (objType == typeof(NullValue))
{
Expand All @@ -344,11 +339,39 @@ private static IResolvableTypeInfo BuildTypeInfo(Type objType)
// Assume anything else is a record
return BuildRecord(objType);
}
private static bool IsImplementationOfGenericType(Type type, Type genericInterface, [NotNullWhen(true)] out Type? @interface)
private static bool ImplementsType(Type type, Type implementationType, [NotNullWhen(true)] out Type? actualType)
{
if (implementationType.IsInterface)
{
actualType = type.GetInterfaces()
.FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == implementationType);
return actualType != null;
}
else
{
if (implementationType.IsGenericTypeDefinition)
{
actualType = FindImplementationsOfGeneric(type, implementationType);
return actualType != null;
}
actualType = implementationType;
return implementationType.IsAssignableFrom(type);
}
}

static Type? FindImplementationsOfGeneric(Type type, Type genericTypeDef)
{
@interface = type.GetInterfaces()
.FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == genericInterface);
return @interface != null;
Type currentType = type;
while (currentType != null && currentType != typeof(object))
{
if (currentType.IsGenericType && currentType.GetGenericTypeDefinition() == genericTypeDef)
{
return currentType;
}

currentType = currentType.BaseType;
}
return null;
}

private static IResolvableTypeInfo BuildStruct<T>(CandidType candidType, T value, Func<CandidValue> valueGetter)
Expand All @@ -373,26 +396,22 @@ private static IResolvableTypeInfo BuildPrimitive(
return new ResolvedTypeInfo(objType, type, mapper);
}

private static IResolvableTypeInfo BuildNullableStruct(Type objType)
private static IResolvableTypeInfo BuildNullableStruct(Type objType, Type innerType)
{
Type innerType = objType.GenericTypeArguments[0];

var dependencies = new List<Type> { innerType };
return new ComplexTypeInfo(objType, dependencies, (resolvedDependencies) =>
{
CandidType innerCandidType = resolvedDependencies[innerType];
return (new OptMapper(innerCandidType, innerType), new CandidOptionalType(innerCandidType));
return (new OptMapper(objType, innerCandidType, innerType), new CandidOptionalType(innerCandidType));
});
}
private static IResolvableTypeInfo BuildOpt(Type objType)
private static IResolvableTypeInfo BuildOpt(Type objType, Type innerType)
{
Type innerType = objType.GenericTypeArguments[0];

var dependencies = new List<Type> { innerType };
return new ComplexTypeInfo(objType, dependencies, (resolvedDependencies) =>
{
CandidType innerCandidType = resolvedDependencies[innerType];
return (new OptMapper(innerCandidType, innerType), new CandidOptionalType(innerCandidType));
return (new OptMapper(objType, innerCandidType, innerType), new CandidOptionalType(innerCandidType));
});
}

Expand Down
3 changes: 2 additions & 1 deletion src/Candid/Mapping/Mappers/OptMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ internal class OptMapper : ICandidValueMapper
private MethodInfo valueGetFunc;

public OptMapper(
Type type,
CandidType innerCandidType,
Type innerType
)
{
this.InnerCandidType = innerCandidType ?? throw new ArgumentNullException(nameof(innerCandidType));
this.InnerType = innerType ?? throw new ArgumentNullException(nameof(innerType));
this.Type = typeof(OptionalValue<>).MakeGenericType(innerType);
this.Type = type;
this.CandidType = new CandidOptionalType(this.InnerCandidType);
this.hasValueProp = this.Type.GetProperty(nameof(OptionalValue<object>.HasValue));
this.valueGetFunc = this.Type.GetMethod(nameof(OptionalValue<object>.GetValueOrThrow));
Expand Down
Loading

0 comments on commit c6eae59

Please sign in to comment.