Skip to content
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

Serialization Simplification #171

Merged
merged 29 commits into from
Oct 31, 2023
Merged

Serialization Simplification #171

merged 29 commits into from
Oct 31, 2023

Conversation

mtmk
Copy link
Collaborator

@mtmk mtmk commented Oct 26, 2023

https://github.com/nats-io/nats.net.v2/blob/serialization-proposal/docs/documentation/serialization.md

  • Simplified INatsSerializer interface (using IBufferWriter)
  • Replace default JSON serializer with JSON context aware serializers
  • Enable trim warnings (AOT)
  • Native AOT test
  • Serialization docs

resolves #92 - NativeAOT support
resolves #137 - Reconsider serialization approach

IBufferWriter is part of the standard runtime and since we're
not using the property introduced by our interface ICountableBuffer
(which extends IBufferWriter)there is no reason to keep that
dependency on the public interface.
@mtmk mtmk self-assigned this Oct 27, 2023
* Simplified INatsSerializer a little more. (Serialize method's return
  value wasn't used)

* Removed the default JSON serializer which was serializing any object
  using reflection. Reflection isn't possible with native AOT. This
  also makes serialization more explicit.

* Added a UTF8 primitives serializer in the default serializer chain
  to cover simple use cases like sending strings or ints.

* Added JSON serializer contexts for JS, Obj and Services models.
@mtmk mtmk changed the title [WIP] Serialization proposal Serialization Simplification Oct 30, 2023
@mtmk mtmk marked this pull request as ready for review October 30, 2023 20:50
@mtmk mtmk requested a review from caleblloyd October 30, 2023 20:50
Copy link
Contributor

@jasper-d jasper-d left a comment

Choose a reason for hiding this comment

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

I've only taken a quick look because I'm vacationing and have unfortunately little time right now. Left a few comments but nothing major.

I think this is an improvement. But I'm still not convinced that the non-generic ISerializer is the best interface, both in terms of discoverability of the serialization API and performance.

src/NATS.Client.Core/INatsSerializer.cs Outdated Show resolved Hide resolved

var span = bufferWriter.GetSpan(128);

// int
Copy link
Contributor

Choose a reason for hiding this comment

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

How were the supported types chosen? int and double seem kinda arbitrary.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Somewhat is. Ideally I wanted to support all types Utf8Parser supports.

Copy link
Collaborator

Choose a reason for hiding this comment

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

That is a neat idea, I like the idea of supporting all of the Utf8Formatter/Parser types

throw new NatsException($"Can't serialize {typeof(T)}");
}

Next.Serialize(bufferWriter, value);
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the use case for this chaining? To have composition support for serializers I presume?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, composition and reuse. Though I realized it doesn't need to be enforced by the interface. So I removed the Next property from the interface and it really is an optional convention now.

{
Utf8JsonWriter writer;
if (_jsonWriter == null)
if (_context.GetTypeInfo(typeof(T)) is JsonTypeInfo<T> jsonTypeInfo)
Copy link
Contributor

Choose a reason for hiding this comment

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

A minor downside of the non-generic INatsSerializer is that it requires a dictionary lookup for the JsonTypeInfo<T> as opposed to a generic serializer where the required type info object would be known.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We could have a generic interface where we chain multiple types when used in connection options.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I gave this a go but there is way too much change. I'll leave it to another PR.

src/NATS.Client.Core/Internal/FixedArrayBufferWriter.cs Outdated Show resolved Hide resolved
src/NATS.Client.Core/NatsBufferWriter.cs Outdated Show resolved Hide resolved
src/NATS.Client.Core/NatsBufferWriter.cs Outdated Show resolved Hide resolved
src/NATS.Client.Core/NatsBufferWriter.cs Outdated Show resolved Hide resolved
@mtmk
Copy link
Collaborator Author

mtmk commented Oct 30, 2023

Thank you @jasper-d very helpful. Already commited your suggestions. Will have a look at your other comments tomorrow. Have a nice vacation 🍹

Also removed method inlining on getters (based on Jasper's advice:
Presumably JIT should always inline simple field accesses and the
other getters look like they are likely inlined without
AggressiveInlining when on a hot path.)

Thank you @jasper-d
Note that chaining serializers is implemented by convention and doesn't need
to be enforced by the INatsSerializer interface since the next serializer
would not be exposed to external users of the interface.
Copy link
Collaborator

@caleblloyd caleblloyd left a comment

Choose a reason for hiding this comment

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

I like the approach!

What about people who don't care about trimming/AOT? Should we offer a regular JSON Serializer that doesn't depend on defining a JSON Context? Could that be in the same assembly or would we need to move it out to another assembly that does not have <IsTrimmable>true</IsTrimmable>


var span = bufferWriter.GetSpan(128);

// int
Copy link
Collaborator

Choose a reason for hiding this comment

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

That is a neat idea, I like the idea of supporting all of the Utf8Formatter/Parser types

@mtmk
Copy link
Collaborator Author

mtmk commented Oct 31, 2023

would we need to move it out to another assembly that does not have <IsTrimmable>true</IsTrimmable>

I think so. NATS.Client.Core.Serializers.Json or something?

@caleblloyd
Copy link
Collaborator

I think so. NATS.Client.Core.Serializers.Json or something?

Yes, if it would introduce problems with AOT we should definitely isolate it somewhere like that

Copy link
Collaborator

@caleblloyd caleblloyd left a comment

Choose a reason for hiding this comment

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

LGTM!

@mtmk mtmk merged commit a000cb0 into main Oct 31, 2023
9 checks passed
@mtmk mtmk deleted the serialization-proposal branch October 31, 2023 19:53
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.

Reconsider serialization approach NativeAOT support?
3 participants