Skip to content

Commit

Permalink
Add more info to TypeInfo (#178)
Browse files Browse the repository at this point in the history
Adding FieldCount allows users to enumerate the field info for each
field in the TypeInfo. Retrieving the System.Type is an experimental API
needed for the command line Serde implementation. This API might become
permanent if it's cheap enough and there are no better options.
  • Loading branch information
agocke authored Jul 6, 2024
1 parent f9db8d4 commit 94efd9d
Showing 1 changed file with 29 additions and 20 deletions.
49 changes: 29 additions & 20 deletions src/serde/TypeInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
Expand All @@ -18,8 +19,23 @@ namespace Serde;
/// </summary>
public sealed class TypeInfo
{
// The field names are sorted by the Utf8 representation of the field name.
private readonly ImmutableArray<(ReadOnlyMemory<byte> Utf8Name, int Index)> _nameToIndex;
private readonly ImmutableArray<PrivateFieldInfo> _indexToInfo;

/// <summary>
/// Holds information for a field or property in the given type.
/// </summary>
private readonly record struct PrivateFieldInfo(
string StringName,
int Utf8NameIndex,
IList<CustomAttributeData> CustomAttributesData,
Type FieldType);

public string TypeName { get; }

public int FieldCount => _nameToIndex.Length;

public enum TypeKind
{
Primitive,
Expand All @@ -43,6 +59,9 @@ public int TryGetIndex(Utf8Span utf8FieldName)
return mapIndex < 0 ? IDeserializeType.IndexNotFound : _nameToIndex[mapIndex].Index;
}

[Experimental("SerdeExperimentalFieldType")]
public Type GetFieldType(int index) => _indexToInfo[index].FieldType;

public IList<CustomAttributeData> GetCustomAttributeData(int index)
{
return _indexToInfo[index].CustomAttributesData;
Expand Down Expand Up @@ -72,13 +91,19 @@ public static TypeInfo Create(
for (int index = 0; index < fields.Length; index++)
{
var (serializeName, memberInfo) = fields[index];
if (memberInfo is null)
var fieldType = memberInfo switch
{
throw new ArgumentNullException(serializeName);
}
FieldInfo info => info.FieldType,
PropertyInfo propertyInfo => propertyInfo.PropertyType,
_ => throw new ArgumentException("MemberInfo must be a FieldInfo or PropertyInfo", nameof(memberInfo))
};

nameToIndexBuilder.Add((s_utf8.GetBytes(serializeName), index));
var fieldInfo = new PrivateFieldInfo(serializeName, -1, memberInfo.GetCustomAttributesData());
var fieldInfo = new PrivateFieldInfo(
serializeName,
-1,
memberInfo.GetCustomAttributesData(),
fieldType);
indexToInfoBuilder.Add(fieldInfo);
}

Expand All @@ -94,20 +119,6 @@ public static TypeInfo Create(
return new TypeInfo(typeName, typeKind, nameToIndexBuilder.ToImmutable(), indexToInfoBuilder.ToImmutable());
}

#region Private implementation details

// The field names are sorted by the Utf8 representation of the field name.
private readonly ImmutableArray<(ReadOnlyMemory<byte> Utf8Name, int Index)> _nameToIndex;
private readonly ImmutableArray<PrivateFieldInfo> _indexToInfo;

/// <summary>
/// Holds information for a field or property in the given type.
/// </summary>
private readonly record struct PrivateFieldInfo(
string StringName,
int Utf8NameIndex,
IList<CustomAttributeData> CustomAttributesData);

private static readonly UTF8Encoding s_utf8 = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);

private TypeInfo(
Expand Down Expand Up @@ -165,6 +176,4 @@ private static int BinarySearch(ref (ReadOnlyMemory<byte> Utf8Name, int) spanSta
// is `lo` at this point.
return ~lo;
}

#endregion // Private implementation details
}

0 comments on commit 94efd9d

Please sign in to comment.