Skip to content

Add FrozenDictionary and FrozenSet serialization support#187

Merged
dameng324 merged 4 commits into
mainfrom
copilot/add-frozen-collections-support
May 16, 2026
Merged

Add FrozenDictionary and FrozenSet serialization support#187
dameng324 merged 4 commits into
mainfrom
copilot/add-frozen-collections-support

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 15, 2026

Adds FrozenDictionary<TKey, TValue> and FrozenSet<T> as supported collection types, following the same patterns as their Immutable* counterparts.

Changes

  • src/LightProto/Parser/FrozenDictionary.csFrozenDictionaryProtoWriter<TKey, TValue> and FrozenDictionaryProtoReader<TKey, TValue>, guarded by #if NET8_0_OR_GREATER. Reader wraps DictionaryProtoReader and converts via .ToFrozenDictionary(); empty value is FrozenDictionary<TKey, TValue>.Empty.
  • src/LightProto/Parser/FrozenSet.csFrozenSetProtoWriter<T> and FrozenSetProtoReader<TItem>, guarded by #if NET8_0_OR_GREATER. Reader wraps ArrayProtoReader and converts via .ToFrozenSet(); empty value is FrozenSet<TItem>.Empty.
  • tests/LightProto.Tests/Parsers/FrozenDictionaryTests.cs — Test coverage mirroring ImmutableDictionaryTests, gated on NET8_0_OR_GREATER.
  • tests/LightProto.Tests/Parsers/FrozenSetTests.cs — Test coverage mirroring ImmutableHashSetTests, gated on NET8_0_OR_GREATER.
  • PublicAPI/net/PublicAPI.Unshipped.txt — New public API declarations added to the net surface only (not netstandard2.0).

No generator changes required — the existing codegen path already handles these types.

Usage

[ProtoContract]
public partial record Message
{
    [ProtoMember(1)]
    public FrozenDictionary<int, string> MapProperty { get; set; } = FrozenDictionary<int, string>.Empty;

    [ProtoMember(2)]
    public FrozenSet<int> SetProperty { get; set; } = FrozenSet<int>.Empty;
}

Copilot AI linked an issue May 15, 2026 that may be closed by this pull request
@codacy-production
Copy link
Copy Markdown

codacy-production Bot commented May 15, 2026

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 4 complexity · 3 duplication

Metric Results
Complexity 4
Duplication 3

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

Copilot AI changed the title [WIP] Add frozen collections support for FrozenDictionary and FrozenSet Add FrozenDictionary serialization support May 15, 2026
Copilot AI requested a review from dameng324 May 15, 2026 13:17
@dameng324
Copy link
Copy Markdown
Owner

@copilot FrozenSet should be supported as well.

Agent-Logs-Url: https://github.com/dameng324/LightProto/sessions/5be79ed4-03b6-47e6-944d-cd19255da29b

Co-authored-by: dameng324 <4465571+dameng324@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 15, 2026

@copilot FrozenSet should be supported as well.

Done — added FrozenSet<T> support in commit 6ed06b3 following the same ImmutableHashSet pattern (FrozenSetProtoWriter<T> and FrozenSetProtoReader<TItem>, both guarded by #if NET8_0_OR_GREATER).

Copilot AI changed the title Add FrozenDictionary serialization support Add FrozenDictionary and FrozenSet serialization support May 15, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented May 16, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.40%. Comparing base (7a23ce5) to head (d702bf3).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #187      +/-   ##
==========================================
+ Coverage   95.36%   95.40%   +0.04%     
==========================================
  Files         121      123       +2     
  Lines        3061     3093      +32     
  Branches      423      425       +2     
==========================================
+ Hits         2919     2951      +32     
  Misses         76       76              
  Partials       66       66              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions

This comment has been minimized.

Register FrozenSet<> and FrozenDictionary<,> parsers (NET8+) and add necessary using. Extend non-generic serializer tests to handle FrozenSet/FrozenDictionary: add them to AOT-unsupported value providers, introduce a non-generic AOT helper that accepts an explicit Type and obtains reader/writer via Serializer.GetProtoReader/GetProtoWriter, and update non-generic serialize calls to pass the writer. Add SkipAot empty-deserialize tests for FrozenSet and FrozenDictionary. Conditional compilation is used to only enable parser registration on .NET 8 or greater.
@github-actions
Copy link
Copy Markdown


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 7763 2.67GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.300
  [Host]    : .NET 8.0.27 (8.0.27, 8.0.2726.22922), X64 RyuJIT x86-64-v3
  .NET 10.0 : .NET 10.0.8 (10.0.8, 10.0.826.23019), X64 RyuJIT x86-64-v3
  .NET 8.0  : .NET 8.0.27 (8.0.27, 8.0.2726.22922), X64 RyuJIT x86-64-v3
  .NET 9.0  : .NET 9.0.16 (9.0.16, 9.0.1626.22923), X64 RyuJIT x86-64-v3


Method Job Runtime Mean Error StdDev Ratio Allocated Alloc Ratio
Deserialize_ProtoBuf_net .NET 10.0 .NET 10.0 754.2 μs 3.25 μs 2.71 μs 1.25 562 KB 0.98
Deserialize_GoogleProtoBuf .NET 10.0 .NET 10.0 622.2 μs 9.19 μs 8.15 μs 1.03 648.7 KB 1.13
Deserialize_LightProto .NET 10.0 .NET 10.0 601.9 μs 2.89 μs 2.56 μs 1.00 574.8 KB 1.00
Deserialize_ProtoBuf_net .NET 8.0 .NET 8.0 895.6 μs 3.89 μs 3.45 μs 1.47 562 KB 0.98
Deserialize_GoogleProtoBuf .NET 8.0 .NET 8.0 791.4 μs 1.79 μs 1.59 μs 1.30 648.7 KB 1.13
Deserialize_LightProto .NET 8.0 .NET 8.0 608.5 μs 2.84 μs 2.52 μs 1.00 574.8 KB 1.00
Deserialize_ProtoBuf_net .NET 9.0 .NET 9.0 811.4 μs 2.22 μs 1.86 μs 1.28 562 KB 0.98
Deserialize_GoogleProtoBuf .NET 9.0 .NET 9.0 686.5 μs 1.11 μs 0.99 μs 1.09 648.7 KB 1.13
Deserialize_LightProto .NET 9.0 .NET 9.0 631.7 μs 2.96 μs 2.62 μs 1.00 574.8 KB 1.00

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 7763 2.67GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.300
  [Host]    : .NET 8.0.27 (8.0.27, 8.0.2726.22922), X64 RyuJIT x86-64-v3
  .NET 10.0 : .NET 10.0.8 (10.0.8, 10.0.826.23019), X64 RyuJIT x86-64-v3
  .NET 8.0  : .NET 8.0.27 (8.0.27, 8.0.2726.22922), X64 RyuJIT x86-64-v3
  .NET 9.0  : .NET 9.0.16 (9.0.16, 9.0.1626.22923), X64 RyuJIT x86-64-v3


Method Job Runtime Mean Error StdDev Ratio RatioSD Allocated Alloc Ratio
Serialize_ProtoBuf_net .NET 10.0 .NET 10.0 1,060.7 μs 1.38 μs 1.29 μs 1.51 0.00 526.4 KB 1.03
Serialize_GoogleProtoBuf .NET 10.0 .NET 10.0 785.4 μs 2.00 μs 1.77 μs 1.12 0.00 512.95 KB 1.00
Serialize_LightProto .NET 10.0 .NET 10.0 704.1 μs 2.52 μs 2.23 μs 1.00 0.00 512.92 KB 1.00
Serialize_ProtoBuf_net .NET 8.0 .NET 8.0 1,016.3 μs 2.65 μs 2.48 μs 1.31 0.00 526.4 KB 1.03
Serialize_GoogleProtoBuf .NET 8.0 .NET 8.0 807.5 μs 1.93 μs 1.81 μs 1.04 0.00 512.95 KB 1.00
Serialize_LightProto .NET 8.0 .NET 8.0 773.5 μs 2.57 μs 2.15 μs 1.00 0.00 512.92 KB 1.00
Serialize_ProtoBuf_net .NET 9.0 .NET 9.0 980.7 μs 8.03 μs 7.51 μs 1.30 0.02 526.4 KB 1.03
Serialize_GoogleProtoBuf .NET 9.0 .NET 9.0 804.8 μs 5.67 μs 5.03 μs 1.07 0.01 512.95 KB 1.00
Serialize_LightProto .NET 9.0 .NET 9.0 751.7 μs 8.32 μs 7.79 μs 1.00 0.01 512.92 KB 1.00

@dameng324 dameng324 marked this pull request as ready for review May 16, 2026 08:05
Copilot AI review requested due to automatic review settings May 16, 2026 08:05
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds runtime serialization/deserialization support for .NET 8+ System.Collections.Frozen collections (FrozenDictionary<TKey,TValue> and FrozenSet<T>) to the LightProto runtime, mirroring the existing Immutable* collection parser patterns, and wires them into the dynamic (non-generic) serializer path.

Changes:

  • Introduces FrozenDictionaryProtoReader/Writer and FrozenSetProtoReader/Writer under #if NET8_0_OR_GREATER.
  • Registers FrozenSet<> / FrozenDictionary<,> in Serializer.Dynamically (NET8+ only) so non-generic APIs can resolve these parsers.
  • Adds NET8+ test coverage for both new parsers and extends non-generic serializer tests to include Frozen collection cases.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/LightProto/Parser/FrozenDictionary.cs Adds FrozenDictionary parser reader/writer (NET8+).
src/LightProto/Parser/FrozenSet.cs Adds FrozenSet parser reader/writer (NET8+).
src/LightProto/Serializer.Dynamically.cs Registers Frozen parsers (NET8+), enabling non-generic dynamic resolution.
src/LightProto/PublicAPI/net/PublicAPI.Unshipped.txt Declares the new public parser types on the net API surface.
tests/LightProto.Tests/Parsers/FrozenDictionaryTests.cs Adds NET8+ tests for FrozenDictionary parsing behavior.
tests/LightProto.Tests/Parsers/FrozenSetTests.cs Adds NET8+ tests for FrozenSet parsing behavior.
tests/LightProto.Tests/NonGenericSerializerTests.cs Adds Frozen types to non-generic test data and refactors to pass explicit writers for serialization.
Comments suppressed due to low confidence (1)

tests/LightProto.Tests/NonGenericSerializerTests.cs:715

  • In LightProto_SerializeDeserialize_NonGeneric_AOT_WithType, reader is retrieved but never used. This also means the deserialization path still calls the DeserializeNonGeneric(Type, ...) overloads that internally call GetProtoReader(type) (dynamic-code path) instead of using the AOT-friendly overloads that accept an IProtoReader. Consider removing the unused local or (preferably) using DeserializeNonGeneric(..., reader) overloads in the local DeserializedFrom* functions for consistency with the writer changes and to avoid unnecessary dynamic parsing work.
    async Task LightProto_SerializeDeserialize_NonGeneric_AOT_WithType(object value, Type type)
    {
        var reader = Serializer.GetProtoReader(type);
        var writer = Serializer.GetProtoWriter(type);
        var bytes1 = SerializeToArray();

Comment thread src/LightProto/Serializer.Dynamically.cs
Comment thread tests/LightProto.Tests/NonGenericSerializerTests.cs
@dameng324 dameng324 merged commit adec778 into main May 16, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Frozen** collections support

3 participants