Skip to content

Commit cb42ed8

Browse files
adamsitnikbartonjsjkotas
authored
Creating new TypeName without reparsing + usage in NRBF (#103713)
Co-authored-by: Jeremy Barton <jbarton@microsoft.com> Co-authored-by: Jan Kotas <jkotas@microsoft.com>
1 parent 6086fe1 commit cb42ed8

18 files changed

+568
-218
lines changed

src/libraries/System.Formats.Nrbf/src/Resources/Strings.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,4 +159,7 @@
159159
<data name="NotSupported_NonZeroOffsets" xml:space="preserve">
160160
<value>Only arrays with zero offsets are supported.</value>
161161
</data>
162+
<data name="Serialization_InvalidAssemblyName" xml:space="preserve">
163+
<value>Invalid assembly name: `{0}`.</value>
164+
</data>
162165
</root>

src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySingleObjectRecord.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,12 @@ namespace System.Formats.Nrbf;
1616
/// </remarks>
1717
internal sealed class ArraySingleObjectRecord : SZArrayRecord<object?>
1818
{
19-
private static TypeName? s_typeName;
20-
2119
private ArraySingleObjectRecord(ArrayInfo arrayInfo) : base(arrayInfo) => Records = [];
2220

2321
public override SerializationRecordType RecordType => SerializationRecordType.ArraySingleObject;
2422

2523
public override TypeName TypeName
26-
=> s_typeName ??= TypeName.Parse(("System.Object[], " + TypeNameExtensions.CoreLibAssemblyName).AsSpan());
24+
=> TypeNameHelpers.GetPrimitiveSZArrayTypeName(TypeNameHelpers.ObjectPrimitiveType);
2725

2826
private List<SerializationRecord> Records { get; }
2927

src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySinglePrimitiveRecord.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ namespace System.Formats.Nrbf;
2424
internal sealed class ArraySinglePrimitiveRecord<T> : SZArrayRecord<T>
2525
where T : unmanaged
2626
{
27-
private static TypeName? s_typeName;
28-
2927
internal ArraySinglePrimitiveRecord(ArrayInfo arrayInfo, IReadOnlyList<T> values) : base(arrayInfo)
3028
{
3129
Values = values;
@@ -35,8 +33,7 @@ internal ArraySinglePrimitiveRecord(ArrayInfo arrayInfo, IReadOnlyList<T> values
3533
public override SerializationRecordType RecordType => SerializationRecordType.ArraySinglePrimitive;
3634

3735
/// <inheritdoc />
38-
public override TypeName TypeName
39-
=> s_typeName ??= TypeName.Parse((typeof(T[]).FullName + "," + TypeNameExtensions.CoreLibAssemblyName).AsSpan());
36+
public override TypeName TypeName => TypeNameHelpers.GetPrimitiveSZArrayTypeName(TypeNameHelpers.GetPrimitiveType<T>());
4037

4138
internal IReadOnlyList<T> Values { get; }
4239

src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySingleStringRecord.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,12 @@ namespace System.Formats.Nrbf;
1616
/// </remarks>
1717
internal sealed class ArraySingleStringRecord : SZArrayRecord<string?>
1818
{
19-
private static TypeName? s_typeName;
20-
2119
private ArraySingleStringRecord(ArrayInfo arrayInfo) : base(arrayInfo) => Records = [];
2220

2321
public override SerializationRecordType RecordType => SerializationRecordType.ArraySingleString;
2422

2523
/// <inheritdoc />
26-
public override TypeName TypeName
27-
=> s_typeName ??= TypeName.Parse(("System.String[], " + TypeNameExtensions.CoreLibAssemblyName).AsSpan());
24+
public override TypeName TypeName => TypeNameHelpers.GetPrimitiveSZArrayTypeName(PrimitiveType.String);
2825

2926
private List<SerializationRecord> Records { get; }
3027

src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryLibraryRecord.cs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Diagnostics;
5+
using System.Formats.Nrbf.Utils;
56
using System.IO;
67
using System.Reflection.Metadata;
78

@@ -15,7 +16,13 @@ namespace System.Formats.Nrbf;
1516
/// </remarks>
1617
internal sealed class BinaryLibraryRecord : SerializationRecord
1718
{
18-
private BinaryLibraryRecord(SerializationRecordId libraryId, string libraryName)
19+
private BinaryLibraryRecord(SerializationRecordId libraryId, string rawLibraryName)
20+
{
21+
Id = libraryId;
22+
RawLibraryName = rawLibraryName;
23+
}
24+
25+
private BinaryLibraryRecord(SerializationRecordId libraryId, AssemblyNameInfo libraryName)
1926
{
2027
Id = libraryId;
2128
LibraryName = libraryName;
@@ -32,11 +39,27 @@ public override TypeName TypeName
3239
}
3340
}
3441

35-
internal string LibraryName { get; }
42+
internal string? RawLibraryName { get; }
43+
44+
internal AssemblyNameInfo? LibraryName { get; }
3645

3746
/// <inheritdoc />
3847
public override SerializationRecordId Id { get; }
3948

40-
internal static BinaryLibraryRecord Decode(BinaryReader reader)
41-
=> new(SerializationRecordId.Decode(reader), reader.ReadString());
49+
internal static BinaryLibraryRecord Decode(BinaryReader reader, PayloadOptions options)
50+
{
51+
SerializationRecordId id = SerializationRecordId.Decode(reader);
52+
string rawName = reader.ReadString();
53+
54+
if (AssemblyNameInfo.TryParse(rawName.AsSpan(), out AssemblyNameInfo? assemblyNameInfo))
55+
{
56+
return new BinaryLibraryRecord(id, assemblyNameInfo);
57+
}
58+
else if (!options.UndoTruncatedTypeNames)
59+
{
60+
ThrowHelper.ThrowInvalidAssemblyName(rawName);
61+
}
62+
63+
return new BinaryLibraryRecord(id, rawName);
64+
}
4265
}

src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MemberTypeInfo.cs

Lines changed: 20 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -142,63 +142,26 @@ internal TypeName GetArrayTypeName(ArrayInfo arrayInfo)
142142
{
143143
(BinaryType binaryType, object? additionalInfo) = Infos[0];
144144

145-
switch (binaryType)
145+
TypeName elementTypeName = binaryType switch
146146
{
147-
case BinaryType.String:
148-
return typeof(string).BuildCoreLibArrayTypeName(arrayInfo.Rank);
149-
case BinaryType.StringArray:
150-
return typeof(string[]).BuildCoreLibArrayTypeName(arrayInfo.Rank);
151-
case BinaryType.Object:
152-
return typeof(object).BuildCoreLibArrayTypeName(arrayInfo.Rank);
153-
case BinaryType.ObjectArray:
154-
return typeof(object[]).BuildCoreLibArrayTypeName(arrayInfo.Rank);
155-
case BinaryType.Primitive:
156-
Type primitiveType = ((PrimitiveType)additionalInfo!) switch
157-
{
158-
PrimitiveType.Boolean => typeof(bool),
159-
PrimitiveType.Byte => typeof(byte),
160-
PrimitiveType.Char => typeof(char),
161-
PrimitiveType.Decimal => typeof(decimal),
162-
PrimitiveType.Double => typeof(double),
163-
PrimitiveType.Int16 => typeof(short),
164-
PrimitiveType.Int32 => typeof(int),
165-
PrimitiveType.Int64 => typeof(long),
166-
PrimitiveType.SByte => typeof(sbyte),
167-
PrimitiveType.Single => typeof(float),
168-
PrimitiveType.TimeSpan => typeof(TimeSpan),
169-
PrimitiveType.DateTime => typeof(DateTime),
170-
PrimitiveType.UInt16 => typeof(ushort),
171-
PrimitiveType.UInt32 => typeof(uint),
172-
_ => typeof(ulong),
173-
};
174-
175-
return primitiveType.BuildCoreLibArrayTypeName(arrayInfo.Rank);
176-
case BinaryType.PrimitiveArray:
177-
Type primitiveArrayType = ((PrimitiveType)additionalInfo!) switch
178-
{
179-
PrimitiveType.Boolean => typeof(bool[]),
180-
PrimitiveType.Byte => typeof(byte[]),
181-
PrimitiveType.Char => typeof(char[]),
182-
PrimitiveType.Decimal => typeof(decimal[]),
183-
PrimitiveType.Double => typeof(double[]),
184-
PrimitiveType.Int16 => typeof(short[]),
185-
PrimitiveType.Int32 => typeof(int[]),
186-
PrimitiveType.Int64 => typeof(long[]),
187-
PrimitiveType.SByte => typeof(sbyte[]),
188-
PrimitiveType.Single => typeof(float[]),
189-
PrimitiveType.TimeSpan => typeof(TimeSpan[]),
190-
PrimitiveType.DateTime => typeof(DateTime[]),
191-
PrimitiveType.UInt16 => typeof(ushort[]),
192-
PrimitiveType.UInt32 => typeof(uint[]),
193-
_ => typeof(ulong[]),
194-
};
195-
196-
return primitiveArrayType.BuildCoreLibArrayTypeName(arrayInfo.Rank);
197-
case BinaryType.SystemClass:
198-
return ((TypeName)additionalInfo!).BuildArrayTypeName(arrayInfo.Rank);
199-
default:
200-
Debug.Assert(binaryType is BinaryType.Class, "The parsers should reject other inputs");
201-
return (((ClassTypeInfo)additionalInfo!).TypeName).BuildArrayTypeName(arrayInfo.Rank);
202-
}
147+
BinaryType.String => TypeNameHelpers.GetPrimitiveTypeName(PrimitiveType.String),
148+
BinaryType.StringArray => TypeNameHelpers.GetPrimitiveSZArrayTypeName(PrimitiveType.String),
149+
BinaryType.Primitive => TypeNameHelpers.GetPrimitiveTypeName((PrimitiveType)additionalInfo!),
150+
BinaryType.PrimitiveArray => TypeNameHelpers.GetPrimitiveSZArrayTypeName((PrimitiveType)additionalInfo!),
151+
BinaryType.Object => TypeNameHelpers.GetPrimitiveTypeName(TypeNameHelpers.ObjectPrimitiveType),
152+
BinaryType.ObjectArray => TypeNameHelpers.GetPrimitiveSZArrayTypeName(TypeNameHelpers.ObjectPrimitiveType),
153+
BinaryType.SystemClass => (TypeName)additionalInfo!,
154+
BinaryType.Class => ((ClassTypeInfo)additionalInfo!).TypeName,
155+
_ => throw new ArgumentOutOfRangeException(paramName: nameof(binaryType), actualValue: binaryType, message: null)
156+
};
157+
158+
// In general, arrayRank == 1 may have two different meanings:
159+
// - [] is a single-dimensional array with a zero lower bound (SZArray),
160+
// - [*] is a single-dimensional array with an arbitrary lower bound (variable bound array).
161+
// Variable bound arrays are not supported by design, so in our case it's always SZArray.
162+
// That is why we don't call TypeName.MakeArrayTypeName(1) because it would create [*] instead of [] name.
163+
return arrayInfo.Rank == 1
164+
? elementTypeName.MakeSZArrayTypeName()
165+
: elementTypeName.MakeArrayTypeName(arrayInfo.Rank);
203166
}
204167
}

src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NrbfDecoder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ private static SerializationRecord DecodeNext(BinaryReader reader, RecordMap rec
226226
SerializationRecordType.ArraySinglePrimitive => DecodeArraySinglePrimitiveRecord(reader),
227227
SerializationRecordType.ArraySingleString => ArraySingleStringRecord.Decode(reader),
228228
SerializationRecordType.BinaryArray => BinaryArrayRecord.Decode(reader, recordMap, options),
229-
SerializationRecordType.BinaryLibrary => BinaryLibraryRecord.Decode(reader),
229+
SerializationRecordType.BinaryLibrary => BinaryLibraryRecord.Decode(reader, options),
230230
SerializationRecordType.BinaryObjectString => BinaryObjectStringRecord.Decode(reader),
231231
SerializationRecordType.ClassWithId => ClassWithIdRecord.Decode(reader, recordMap),
232232
SerializationRecordType.ClassWithMembersAndTypes => ClassWithMembersAndTypesRecord.Decode(reader, recordMap, options),

src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/PrimitiveTypeRecordOfT.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ namespace System.Formats.Nrbf;
2525
[DebuggerDisplay("{Value}")]
2626
public abstract class PrimitiveTypeRecord<T> : PrimitiveTypeRecord
2727
{
28-
private static TypeName? s_typeName;
29-
3028
private protected PrimitiveTypeRecord(T value) => Value = value;
3129

3230
/// <summary>
@@ -36,8 +34,7 @@ public abstract class PrimitiveTypeRecord<T> : PrimitiveTypeRecord
3634
public new T Value { get; }
3735

3836
/// <inheritdoc />
39-
public override TypeName TypeName
40-
=> s_typeName ??= TypeName.Parse(typeof(T).FullName.AsSpan()).WithCoreLibAssemblyName();
37+
public override TypeName TypeName => TypeNameHelpers.GetPrimitiveTypeName(TypeNameHelpers.GetPrimitiveType<T>());
4138

4239
internal override object? GetValue() => Value;
4340
}

src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SystemClassWithMembersAndTypesRecord.cs

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,25 +38,30 @@ internal override (AllowedRecordTypes allowed, PrimitiveType primitiveType) GetN
3838
// to get a single primitive value!
3939
internal SerializationRecord TryToMapToUserFriendly()
4040
{
41+
if (!TypeName.IsSimple)
42+
{
43+
return this;
44+
}
45+
4146
if (MemberValues.Count == 1)
4247
{
4348
if (HasMember("m_value"))
4449
{
4550
return MemberValues[0] switch
4651
{
4752
// there can be a value match, but no TypeName match
48-
bool value when TypeName.FullName == typeof(bool).FullName => Create(value),
49-
byte value when TypeName.FullName == typeof(byte).FullName => Create(value),
50-
sbyte value when TypeName.FullName == typeof(sbyte).FullName => Create(value),
51-
char value when TypeName.FullName == typeof(char).FullName => Create(value),
52-
short value when TypeName.FullName == typeof(short).FullName => Create(value),
53-
ushort value when TypeName.FullName == typeof(ushort).FullName => Create(value),
54-
int value when TypeName.FullName == typeof(int).FullName => Create(value),
55-
uint value when TypeName.FullName == typeof(uint).FullName => Create(value),
56-
long value when TypeName.FullName == typeof(long).FullName => Create(value),
57-
ulong value when TypeName.FullName == typeof(ulong).FullName => Create(value),
58-
float value when TypeName.FullName == typeof(float).FullName => Create(value),
59-
double value when TypeName.FullName == typeof(double).FullName => Create(value),
53+
bool value when TypeNameMatches(typeof(bool)) => Create(value),
54+
byte value when TypeNameMatches(typeof(byte)) => Create(value),
55+
sbyte value when TypeNameMatches(typeof(sbyte)) => Create(value),
56+
char value when TypeNameMatches(typeof(char)) => Create(value),
57+
short value when TypeNameMatches(typeof(short)) => Create(value),
58+
ushort value when TypeNameMatches(typeof(ushort)) => Create(value),
59+
int value when TypeNameMatches(typeof(int)) => Create(value),
60+
uint value when TypeNameMatches(typeof(uint)) => Create(value),
61+
long value when TypeNameMatches(typeof(long)) => Create(value),
62+
ulong value when TypeNameMatches(typeof(ulong)) => Create(value),
63+
float value when TypeNameMatches(typeof(float)) => Create(value),
64+
double value when TypeNameMatches(typeof(double)) => Create(value),
6065
_ => this
6166
};
6267
}
@@ -65,12 +70,12 @@ internal SerializationRecord TryToMapToUserFriendly()
6570
return MemberValues[0] switch
6671
{
6772
// there can be a value match, but no TypeName match
68-
long value when TypeName.FullName == typeof(IntPtr).FullName => Create(new IntPtr(value)),
69-
ulong value when TypeName.FullName == typeof(UIntPtr).FullName => Create(new UIntPtr(value)),
73+
long value when TypeNameMatches(typeof(IntPtr)) => Create(new IntPtr(value)),
74+
ulong value when TypeNameMatches(typeof(UIntPtr)) => Create(new UIntPtr(value)),
7075
_ => this
7176
};
7277
}
73-
else if (HasMember("_ticks") && MemberValues[0] is long ticks && TypeName.FullName == typeof(TimeSpan).FullName)
78+
else if (HasMember("_ticks") && MemberValues[0] is long ticks && TypeNameMatches(typeof(TimeSpan)))
7479
{
7580
return Create(new TimeSpan(ticks));
7681
}

src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/ThrowHelper.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ internal static void ThrowInvalidValue(object value)
1414
internal static void ThrowInvalidReference()
1515
=> throw new SerializationException(SR.Serialization_InvalidReference);
1616

17+
internal static void ThrowInvalidTypeName(string name)
18+
=> throw new SerializationException(SR.Format(SR.Serialization_InvalidTypeName, name));
19+
1720
internal static void ThrowUnexpectedNullRecordCount()
1821
=> throw new SerializationException(SR.Serialization_UnexpectedNullRecordCount);
1922

@@ -23,6 +26,9 @@ internal static void ThrowMaxArrayLength(long limit, long actual)
2326
internal static void ThrowArrayContainedNulls()
2427
=> throw new SerializationException(SR.Serialization_ArrayContainedNulls);
2528

29+
internal static void ThrowInvalidAssemblyName(string rawName)
30+
=> throw new SerializationException(SR.Format(SR.Serialization_InvalidAssemblyName, rawName));
31+
2632
internal static void ThrowEndOfStreamException()
2733
=> throw new EndOfStreamException();
2834

0 commit comments

Comments
 (0)