Skip to content

Reduce record usage in published projects #48907

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 31 commits into from
Jul 22, 2023
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
bd3ca9d
Convert CollectionModelBinder to class
david-acker Jun 18, 2023
b50f5a6
Convert AltSvcHeader to class
david-acker Jun 18, 2023
6f40f74
Convert InternalHeader to class
david-acker Jun 18, 2023
f331a08
Convert OnRegistrationClose to struct
david-acker Jun 18, 2023
923930d
Convert UnacknowledgedRenderBatch to class
david-acker Jun 19, 2023
1967540
Convert OptionsRecord to struct
david-acker Jun 19, 2023
7d44f3a
Convert BrowserOptions to class
david-acker Jun 19, 2023
2073db0
Convert LogEntry to class
david-acker Jun 19, 2023
94f0d01
Convert BodyDescriptorInfo to class
david-acker Jun 19, 2023
b5cc7ee
Convert RouteParameter to class
david-acker Jun 19, 2023
b9bec97
Convert InternalAccessTokenResult to struct
david-acker Jun 19, 2023
d075af9
Clean up spacing
david-acker Jun 20, 2023
188177a
Convert DfaBuilderWorkerWorkItem to struct
david-acker Jun 20, 2023
8d89d8d
Fix property names
david-acker Jun 20, 2023
94f9d51
Set properties to init
david-acker Jun 20, 2023
ae3478f
Clean up
david-acker Jun 20, 2023
5cd5788
Convert ComponentTypeInfoCacheEntry to class
david-acker Jun 21, 2023
384164c
Convert FormDataConverterReadParameters to class
david-acker Jun 21, 2023
5cfb980
Convert ComponentIdAndDepth to struct
david-acker Jun 21, 2023
eeee9c9
Convert MethodInfoData to struct
david-acker Jun 21, 2023
3cb6eaa
Convert BrowserTab to class
david-acker Jun 21, 2023
e67bb69
Revert unrelated changes
david-acker Jun 21, 2023
d56ac8e
Convert NamedEvent to struct
david-acker Jun 22, 2023
288b841
Merge main
david-acker Jun 22, 2023
8841a6d
Revert submodule changes
david-acker Jun 22, 2023
15aee55
Merge branch 'main' into reduce-record-usage
david-acker Jun 30, 2023
8446029
Add Deconstruct to ComponentTypeInfoCacheEntry
david-acker Jul 1, 2023
dffaa71
Merge remote-tracking branch 'origin/main' into reduce-record-usage
david-acker Jul 7, 2023
2f2fd2a
Seal InternalHeader
david-acker Jul 11, 2023
c6e4900
Merge remote-tracking branch 'origin/main' into reduce-record-usage
david-acker Jul 21, 2023
07d4abb
Convert FormDataConverterReadParameters to struct
david-acker Jul 21, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions src/Components/Components/src/ComponentFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,26 @@ void Initialize(IServiceProvider serviceProvider, IComponent component)
}

// Tracks information about a specific component type that ComponentFactory uses
private record class ComponentTypeInfoCacheEntry(
IComponentRenderMode? ComponentTypeRenderMode,
Action<IServiceProvider, IComponent> PerformPropertyInjection);
private sealed class ComponentTypeInfoCacheEntry
{
public IComponentRenderMode? ComponentTypeRenderMode { get; }

public Action<IServiceProvider, IComponent> PerformPropertyInjection { get; }

public ComponentTypeInfoCacheEntry(
IComponentRenderMode? componentTypeRenderMode,
Action<IServiceProvider, IComponent> performPropertyInjection)
{
ComponentTypeRenderMode = componentTypeRenderMode;
PerformPropertyInjection = performPropertyInjection;
}

public void Deconstruct(
out IComponentRenderMode? componentTypeRenderMode,
out Action<IServiceProvider, IComponent> performPropertyInjection)
{
componentTypeRenderMode = ComponentTypeRenderMode;
performPropertyInjection = PerformPropertyInjection;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -245,5 +245,16 @@ private void WriteComponentHtml(int componentId, TextWriter output, bool allowBo
}
}

private readonly record struct ComponentIdAndDepth(int ComponentId, int Depth);
private readonly struct ComponentIdAndDepth
{
public int ComponentId { get; }

public int Depth { get; }

public ComponentIdAndDepth(int componentId, int depth)
{
ComponentId = componentId;
Depth = depth;
}
}
}
46 changes: 45 additions & 1 deletion src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,51 @@ private static string GetContextBaseUri(HttpRequest request)
return result.EndsWith('/') ? result : result += "/";
}

private record struct NamedEvent(ulong EventHandlerId, int ComponentId, string EventNameId);
private readonly struct NamedEvent : IEquatable<NamedEvent>
{
public ulong EventHandlerId { get; }

public int ComponentId { get; }

public string EventNameId { get; }

public NamedEvent(ulong eventHandlerId, int componentId, string eventNameId)
{
EventHandlerId = eventHandlerId;
ComponentId = componentId;
EventNameId = eventNameId;
}

public static bool operator ==(NamedEvent left, NamedEvent right)
{
return left.EventHandlerId == right.EventHandlerId
&& left.ComponentId == right.ComponentId
&& left.EventNameId == right.EventNameId;
}

public static bool operator !=(NamedEvent left, NamedEvent right)
{
return !(left == right);
}

public bool Equals(NamedEvent other)
{
return this == other;
}

public override int GetHashCode()
{
return HashCode.Combine(EventHandlerId, ComponentId, EventNameId);
}

public override bool Equals(object? obj)
{
return obj is NamedEvent namedEvent
&& namedEvent.EventHandlerId == EventHandlerId
&& namedEvent.ComponentId == ComponentId
&& namedEvent.EventNameId == EventNameId;
}
}

private sealed class FormCollectionReadOnlyDictionary : IReadOnlyDictionary<string, StringValues>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,34 +160,34 @@ static MethodInfoData GetMethodInfoData(MethodInfo methodInfo)
var declaringType = methodInfo.DeclaringType;
if (declaringType is null)
{
return new(IsSingleArgumentIndexer: false);
return new(isSingleArgumentIndexer: false);
}

// Check whether GetDefaultMembers() (if present in CoreCLR) would return a member of this type. Compiler
// names the indexer property, if any, in a generated [DefaultMember] attribute for the containing type.
var defaultMember = declaringType.GetCustomAttribute<DefaultMemberAttribute>(inherit: true);
if (defaultMember is null)
{
return new(IsSingleArgumentIndexer: false);
return new(isSingleArgumentIndexer: false);
}

// Find default property (the indexer) and confirm its getter is the method in this expression.
var runtimeProperties = declaringType.GetRuntimeProperties();
if (runtimeProperties is null)
{
return new(IsSingleArgumentIndexer: false);
return new(isSingleArgumentIndexer: false);
}

foreach (var property in runtimeProperties)
{
if (string.Equals(defaultMember.MemberName, property.Name, StringComparison.Ordinal) &&
property.GetMethod == methodInfo)
{
return new(IsSingleArgumentIndexer: true);
return new(isSingleArgumentIndexer: true);
}
}

return new(IsSingleArgumentIndexer: false);
return new(isSingleArgumentIndexer: false);
}
}

Expand Down Expand Up @@ -297,5 +297,13 @@ private static void FormatConstantValue(ConstantExpression constantExpression, r
}
}

private record struct MethodInfoData(bool IsSingleArgumentIndexer);
private readonly struct MethodInfoData
{
public bool IsSingleArgumentIndexer { get; }

public MethodInfoData(bool isSingleArgumentIndexer)
{
IsSingleArgumentIndexer = isSingleArgumentIndexer;
}
}
}
34 changes: 25 additions & 9 deletions src/Components/WebAssembly/Server/src/TargetPickerUi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -425,13 +425,29 @@ private async Task<IEnumerable<BrowserTab>> GetOpenedBrowserTabs()
return JsonSerializer.Deserialize<BrowserTab[]>(jsonResponse, JsonOptions)!;
}

private sealed record BrowserTab
(
string Id,
string Type,
string Url,
string Title,
string DevtoolsFrontendUrl,
string WebSocketDebuggerUrl
);
private sealed class BrowserTab
{
public string Id { get; }
public string Type { get; }
public string Url { get; }
public string Title { get; }
public string DevtoolsFrontendUrl { get; }
public string WebSocketDebuggerUrl { get; }

public BrowserTab(
string id,
string type,
string url,
string title,
string devtoolsFrontendUrl,
string webSocketDebuggerUrl)
{
Id = id;
Type = type;
Url = url;
Title = title;
DevtoolsFrontendUrl = devtoolsFrontendUrl;
WebSocketDebuggerUrl = webSocketDebuggerUrl;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,32 @@ public override void Write(Utf8JsonWriter writer, InteractiveRequestOptions valu
InteractiveRequestOptionsSerializerContext.Default.OptionsRecord);
}

internal record struct OptionsRecord(
[property: JsonInclude] string ReturnUrl,
[property: JsonInclude] IEnumerable<string> Scopes,
[property: JsonInclude] InteractionType Interaction,
[property: JsonInclude] Dictionary<string, object>? AdditionalRequestParameters);
internal readonly struct OptionsRecord
{
[JsonInclude]
public string ReturnUrl { get; init; }

[JsonInclude]
public IEnumerable<string> Scopes { get; init; }

[JsonInclude]
public InteractionType Interaction { get; init; }

[JsonInclude]
public Dictionary<string, object>? AdditionalRequestParameters { get; init; }

public OptionsRecord(
string returnUrl,
IEnumerable<string> scopes,
InteractionType interaction,
Dictionary<string, object>? additionalRequestParameters)
{
ReturnUrl = returnUrl;
Scopes = scopes;
Interaction = interaction;
AdditionalRequestParameters = additionalRequestParameters;
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,4 +255,16 @@ internal class RemoteAuthenticationServiceJavaScriptLoggingOptions
}

// Internal for testing purposes
internal record struct InternalAccessTokenResult([property: JsonConverter(typeof(JsonStringEnumConverter<AccessTokenResultStatus>))] AccessTokenResultStatus Status, AccessToken Token);
internal readonly struct InternalAccessTokenResult
{
[JsonConverter(typeof(JsonStringEnumConverter<AccessTokenResultStatus>))]
public AccessTokenResultStatus Status { get; init; }

public AccessToken Token { get; init; }

public InternalAccessTokenResult(AccessTokenResultStatus status, AccessToken token)
{
Status = status;
Token = token;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,10 @@ public void NotifyRenderCompleted(long batchId)
nextUnacknowledgedBatch.CompletionSource.SetResult();
}

private sealed record UnacknowledgedRenderBatch
private sealed class UnacknowledgedRenderBatch
{
public long BatchId { get; init; }

public TaskCompletionSource CompletionSource { get; init; }
}
}
60 changes: 47 additions & 13 deletions src/Grpc/JsonTranscoding/src/Shared/ServiceDescriptorHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -428,11 +428,11 @@ public static Dictionary<string, RouteParameter> ResolveRouteParameterDescriptor
{
// A repeating field isn't a message type. The JSON parser will parse using the containing
// type to get the repeating collection.
return new BodyDescriptorInfo(responseBodyDescriptor.ContainingType, responseBodyDescriptor, IsDescriptorRepeated: true, propertyInfo);
return new BodyDescriptorInfo(responseBodyDescriptor.ContainingType, responseBodyDescriptor, isDescriptorRepeated: true, propertyInfo);
}
else
{
return new BodyDescriptorInfo(responseBodyDescriptor.MessageType, responseBodyDescriptor, IsDescriptorRepeated: false, propertyInfo);
return new BodyDescriptorInfo(responseBodyDescriptor.MessageType, responseBodyDescriptor, isDescriptorRepeated: false, propertyInfo);
}
}
else
Expand All @@ -444,7 +444,7 @@ public static Dictionary<string, RouteParameter> ResolveRouteParameterDescriptor
requestParameter = methodInfo.GetParameters().SingleOrDefault(p => p.Name == "request");
}

return new BodyDescriptorInfo(methodDescriptor.InputType, FieldDescriptor: null, IsDescriptorRepeated: false, ParameterInfo: requestParameter);
return new BodyDescriptorInfo(methodDescriptor.InputType, fieldDescriptor: null, isDescriptorRepeated: false, parameterInfo: requestParameter);
}
}

Expand Down Expand Up @@ -562,12 +562,32 @@ private static bool IsCustomType(MessageDescriptor messageDescriptor)
return false;
}

public sealed record BodyDescriptorInfo(
MessageDescriptor Descriptor,
FieldDescriptor? FieldDescriptor,
bool IsDescriptorRepeated,
PropertyInfo? PropertyInfo = null,
ParameterInfo? ParameterInfo = null);
public sealed class BodyDescriptorInfo
{
public MessageDescriptor Descriptor { get; }

public FieldDescriptor? FieldDescriptor { get; }

public bool IsDescriptorRepeated { get; }

public PropertyInfo? PropertyInfo { get; }

public ParameterInfo? ParameterInfo { get; }

public BodyDescriptorInfo(
MessageDescriptor descriptor,
FieldDescriptor? fieldDescriptor,
bool isDescriptorRepeated,
PropertyInfo? propertyInfo = null,
ParameterInfo? parameterInfo = null)
{
Descriptor = descriptor;
FieldDescriptor = fieldDescriptor;
IsDescriptorRepeated = isDescriptorRepeated;
PropertyInfo = propertyInfo;
ParameterInfo = parameterInfo;
}
}

public static string FormatUnderscoreName(string input, bool pascalCase, bool preservePeriod)
{
Expand Down Expand Up @@ -626,7 +646,21 @@ public static string FormatUnderscoreName(string input, bool pascalCase, bool pr
}
}

internal record RouteParameter(
List<FieldDescriptor> DescriptorsPath,
HttpRouteVariable RouteVariable,
string JsonPath);
internal sealed class RouteParameter
{
public List<FieldDescriptor> DescriptorsPath { get; }

public HttpRouteVariable RouteVariable { get; }

public string JsonPath { get; }

public RouteParameter(
List<FieldDescriptor> descriptorsPath,
HttpRouteVariable routeVariable,
string jsonPath)
{
DescriptorsPath = descriptorsPath;
RouteVariable = routeVariable;
JsonPath = jsonPath;
}
}
23 changes: 22 additions & 1 deletion src/Http/Routing/src/Matching/DfaMatcherBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -987,5 +987,26 @@ private static bool TryGetRequiredValue(RoutePattern routePattern, RoutePatternP
return !RouteValueEqualityComparer.Default.Equals(value, string.Empty);
}

private readonly record struct DfaBuilderWorkerWorkItem(RouteEndpoint Endpoint, int PrecedenceDigit, List<DfaNode> Parents);
public readonly struct DfaBuilderWorkerWorkItem
{
public RouteEndpoint Endpoint { get; }

public int PrecedenceDigit { get; }

public List<DfaNode> Parents { get; }

public DfaBuilderWorkerWorkItem(RouteEndpoint endpoint, int precedenceDigit, List<DfaNode> parents)
{
Endpoint = endpoint;
PrecedenceDigit = precedenceDigit;
Parents = parents;
}

public void Deconstruct(out RouteEndpoint endpoint, out int precedenceDigit, out List<DfaNode> parents)
{
endpoint = Endpoint;
precedenceDigit = PrecedenceDigit;
parents = Parents;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -409,9 +409,16 @@ internal async Task<CollectionResult> BindComplexCollectionFromIndexes(
}

// Internal for testing.
internal sealed record CollectionResult(IEnumerable<TElement?> Model)
internal sealed class CollectionResult
{
public IEnumerable<TElement?> Model { get; }

public IValidationStrategy? ValidationStrategy { get; init; }

public CollectionResult(IEnumerable<TElement?> model)
{
Model = model;
}
}

/// <summary>
Expand Down
Loading