/// <summary> /// Returns the constructed form of the provided generic type. /// </summary> public static IdSpan GetConstructed(this TypeConverter formatter, IdSpan unconstructed, params Type[] typeArguments) { var typeString = unconstructed.AsSpan(); var indicatorIndex = typeString.IndexOf((byte)GenericTypeIndicator); var arityString = typeString.Slice(indicatorIndex + 1); if (indicatorIndex < 0 || arityString.IndexOf((byte)StartArgument) >= 0) { throw new InvalidOperationException("Cannot construct an already-constructed type"); } if (!Utf8Parser.TryParse(arityString, out int arity, out var len) || len < arityString.Length || typeArguments.Length != arity) { throw new InvalidOperationException($"Insufficient number of type arguments, {typeArguments.Length}, provided while constructing type \"{unconstructed}\""); } var typeSpecs = new TypeSpec[typeArguments.Length]; for (var i = 0; i < typeArguments.Length; i++) { typeSpecs[i] = RuntimeTypeNameParser.Parse(formatter.Format(typeArguments[i])); } var constructed = new ConstructedGenericTypeSpec(new NamedTypeSpec(null, unconstructed.ToStringUtf8(), typeArguments.Length), typeSpecs).Format(); return(IdSpan.Create(constructed)); }
/// <summary> /// Returns the type arguments for the provided constructed generic type string. /// </summary> public static Type[] GetArguments(this TypeConverter formatter, IdSpan constructed) { var str = constructed.AsSpan(); var index = str.IndexOf((byte)StartArgument); if (index <= 0) { return(Array.Empty <Type>()); } var safeString = "safer" + str.Slice(str.IndexOf((byte)GenericTypeIndicator)).GetUtf8String(); var parsed = RuntimeTypeNameParser.Parse(safeString); if (!(parsed is ConstructedGenericTypeSpec spec)) { throw new InvalidOperationException($"Unable to correctly parse grain type {constructed}"); } var result = new Type[spec.Arguments.Length]; for (var i = 0; i < result.Length; i++) { var arg = spec.Arguments[i]; var formattedArg = arg.Format(); result[i] = formatter.Parse(formattedArg); if (result[i] is null) { throw new InvalidOperationException($"Unable to parse argument \"{formattedArg}\" as a type for grain type \"{constructed}\""); } } return(result); }
private static (TypeSpec Type, string Assembly) HandleNamedType(NamedTypeSpec type, string assemblyName, Func <QualifiedType, QualifiedType> replaceTypeName) { var nsQualified = type.GetNamespaceQualifiedName(); var names = replaceTypeName(new QualifiedType(assembly: assemblyName, type: nsQualified)); if (!string.Equals(nsQualified, names.Type, StringComparison.Ordinal)) { // Change the type name and potentially the assembly. var resultType = RuntimeTypeNameParser.Parse(names.Type); if (!(resultType is NamedTypeSpec)) { throw new InvalidOperationException($"Replacement type name, \"{names.Type}\", can not deviate from the original type structure of the input, \"{nsQualified}\""); } return(resultType, names.Assembly); } else if (!string.Equals(assemblyName, names.Assembly, StringComparison.Ordinal)) { // Only change the assembly; return(type, names.Assembly); } else if (type.ContainingType is object) { // Give the user an opportunity to change the parent, including the assembly. var replacementParent = ApplyInner(type.ContainingType, assemblyName, replaceTypeName); if (ReferenceEquals(replacementParent.Type, type.ContainingType)) { // No change to the type. return(type, replacementParent.Assembly); } // The parent type changed. var typedReplacement = (NamedTypeSpec)replacementParent.Type; return(new NamedTypeSpec(typedReplacement, type.Name, type.Arity), replacementParent.Assembly); } else { return(type, names.Assembly); } }