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

Custom type mapping (cs::type attribute) #674

Closed
bernardnormier opened this issue Dec 4, 2021 · 6 comments
Closed

Custom type mapping (cs::type attribute) #674

bernardnormier opened this issue Dec 4, 2021 · 6 comments
Assignees
Labels
proposal Proposal for a new feature or significant update

Comments

@bernardnormier
Copy link
Member

You define a type in Slice but the C# mapping from slicec-cs is not quite what you want. This is a proposal to address this issue and give you complete freedom to map any Slice-defined type to the type of your choice.

For example:

  1. we define Slice struct EndpointData and want to map it to record class Endpoint in C#
    We already have the code that encodes an Endpoint into an EndpointData and decodes an EndpointData into an Endpoint. We just want to "plug it in" slicec-cs to get Endpoint instead of EndpointData for mapped parameters, fields etc.

  2. we define Fields as:

typealias Fields = dictionary<varint, sequence<byte>>;

It's mapped to IDictionary<int, IList<byte>>, but we'd rather map it to ImmutableDictionary<int, ReadOnlyMemory<byte>>.

Proposed solution

The cs::type attribute is a typealias attribute that specifies the mapped type. The provided string is then generated verbatim by the Slice compiler.

For example:

module IceRpc::Slice::Internal
{
    struct EndpointData { ... }
    
    typealias Endpoint = [cs::type("IceRpc.Endpoint")] EndpointData;
}

then all parameters, data members etc of type (IceRpc::Slice::Internal::)Endpoint in Slice definitions are mapped to IceRpc.Endpoint in C#.

The Slice compiler then uses: IceRpc.Slice.Internal.EndpointDecoderExtensions.DecodeEndpoint to decode an Endpoint from a SliceDecoder and IceRpc.Slice.Internal.EndpointEncoderExtensions.EncodeEndpoint to encode an endpoint.

More generally, for

module M
{
     typealias A = [cs::type("...")] S;
}

The Slice compiler uses M.ADecoderExtensions.DecodeA to decode an A and M.AEncoderExtensions.EncodeA to encode an A.

For Fields:

module IceRpc 
{
    typealias Fields = 
        [cs:type("System.Immutable.ImmutableDictionary<int, System.ReadOnlyMemory<byte>>")] 
        dictionary<int, sequence<byte>>; 
}

and the encoder/decoder methods are IceRpc.FieldsDecoderExtensions.DecodeFields and IceRpc.FieldsEncoderExtensionsEncodeFields.

This proposal relies on typealias (obviously), and with proposal, the specified custom mapped type is used all the time:

  • for outgoing and incoming parameters
  • for data members and sequence/dictionary elements
@bernardnormier bernardnormier added the proposal Proposal for a new feature or significant update label Dec 4, 2021
@pepone
Copy link
Member

pepone commented Jan 10, 2022

If I understand this correctly the extension methods are placed in the namespace where the typealias is defined?

@pepone
Copy link
Member

pepone commented Jan 10, 2022

The cs::type attribute is a typealias attribute that specifies the mapped type.

I think we currently don't distinguish typelias from other types. I don't think we can currently have an attribute that apply only to typealias, @InsertCreativityHere can you clarify

@InsertCreativityHere
Copy link
Member

InsertCreativityHere commented Jan 10, 2022

I think we currently don't distinguish typelias from other types

This is correct.
The idea behind type-aliases is that they're for convenience when writing your Slice definition.
After parsing is complete, everywhere where a type-alias was used is replaced with the actual underlying type.

For example:

typealias MyType = [cs:type("foo")] sequence<int>;
class C {
    my_data: MyType,
}

After parsing, this will become:

typealias MyType = sequence<int>;
class C {
    my_data: [cs:type("foo")] sequence<int>,
}

There is currently no way to tell whether a type was originally from an alias or not.
To implement this proposal we'd need to add either
A) Add an extra field to TypeRef which stores a Option<TypeAlias> that we could check to if an alias was used
B) Change the parser to no longer "parse out" aliases.

@pepone
Copy link
Member

pepone commented Feb 2, 2022

so should we go with the solution proposed in icerpc/slicec#73 (comment) and make cs:type a compact struct attribute?

@pepone pepone self-assigned this Feb 3, 2022
@bernardnormier
Copy link
Member Author

so should we go with the solution proposed in zeroc-ice/icerpc#73 (comment) and make cs:type a compact struct attribute?

yes

@bernardnormier
Copy link
Member Author

Fixed by #782.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
proposal Proposal for a new feature or significant update
Projects
None yet
Development

No branches or pull requests

3 participants