• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #region Copyright notice and license
2 
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #endregion
18 
19 using System;
20 using Grpc.Core.Utils;
21 
22 namespace Grpc.Core
23 {
24     /// <summary>
25     /// Encapsulates the logic for serializing and deserializing messages.
26     /// </summary>
27     public class Marshaller<T>
28     {
29         readonly Func<T, byte[]> serializer;
30         readonly Func<byte[], T> deserializer;
31 
32         readonly Action<T, SerializationContext> contextualSerializer;
33         readonly Func<DeserializationContext, T> contextualDeserializer;
34 
35         /// <summary>
36         /// Initializes a new marshaller from simple serialize/deserialize functions.
37         /// </summary>
38         /// <param name="serializer">Function that will be used to serialize messages.</param>
39         /// <param name="deserializer">Function that will be used to deserialize messages.</param>
Marshaller(Func<T, byte[]> serializer, Func<byte[], T> deserializer)40         public Marshaller(Func<T, byte[]> serializer, Func<byte[], T> deserializer)
41         {
42             this.serializer = GrpcPreconditions.CheckNotNull(serializer, nameof(serializer));
43             this.deserializer = GrpcPreconditions.CheckNotNull(deserializer, nameof(deserializer));
44             // contextual serialization/deserialization is emulated to make the marshaller
45             // usable with the grpc library (required for backward compatibility).
46             this.contextualSerializer = EmulateContextualSerializer;
47             this.contextualDeserializer = EmulateContextualDeserializer;
48         }
49 
50         /// <summary>
51         /// Initializes a new marshaller from serialize/deserialize fuctions that can access serialization and deserialization
52         /// context. Compared to the simple serializer/deserializer functions, using the contextual version provides more
53         /// flexibility and can lead to increased efficiency (and better performance).
54         /// Note: This constructor is part of an experimental API that can change or be removed without any prior notice.
55         /// </summary>
56         /// <param name="serializer">Function that will be used to serialize messages.</param>
57         /// <param name="deserializer">Function that will be used to deserialize messages.</param>
Marshaller(Action<T, SerializationContext> serializer, Func<DeserializationContext, T> deserializer)58         public Marshaller(Action<T, SerializationContext> serializer, Func<DeserializationContext, T> deserializer)
59         {
60             this.contextualSerializer = GrpcPreconditions.CheckNotNull(serializer, nameof(serializer));
61             this.contextualDeserializer = GrpcPreconditions.CheckNotNull(deserializer, nameof(deserializer));
62             // gRPC only uses contextual serializer/deserializer internally, so emulating the legacy
63             // (de)serializer is not necessary.
64             this.serializer = (msg) => { throw new NotImplementedException(); };
65             this.deserializer = (payload) => { throw new NotImplementedException(); };
66         }
67 
68         /// <summary>
69         /// Gets the serializer function.
70         /// </summary>
71         public Func<T, byte[]> Serializer => this.serializer;
72 
73         /// <summary>
74         /// Gets the deserializer function.
75         /// </summary>
76         public Func<byte[], T> Deserializer => this.deserializer;
77 
78         /// <summary>
79         /// Gets the serializer function.
80         /// Note: experimental API that can change or be removed without any prior notice.
81         /// </summary>
82         public Action<T, SerializationContext> ContextualSerializer => this.contextualSerializer;
83 
84         /// <summary>
85         /// Gets the serializer function.
86         /// Note: experimental API that can change or be removed without any prior notice.
87         /// </summary>
88         public Func<DeserializationContext, T> ContextualDeserializer => this.contextualDeserializer;
89 
90         // for backward compatibility, emulate the contextual serializer using the simple one
EmulateContextualSerializer(T message, SerializationContext context)91         private void EmulateContextualSerializer(T message, SerializationContext context)
92         {
93             var payload = this.serializer(message);
94             context.Complete(payload);
95         }
96 
97         // for backward compatibility, emulate the contextual deserializer using the simple one
EmulateContextualDeserializer(DeserializationContext context)98         private T EmulateContextualDeserializer(DeserializationContext context)
99         {
100             return this.deserializer(context.PayloadAsNewBuffer());
101         }
102     }
103 
104     /// <summary>
105     /// Utilities for creating marshallers.
106     /// </summary>
107     public static class Marshallers
108     {
109         /// <summary>
110         /// Creates a marshaller from specified serializer and deserializer.
111         /// </summary>
Create(Func<T, byte[]> serializer, Func<byte[], T> deserializer)112         public static Marshaller<T> Create<T>(Func<T, byte[]> serializer, Func<byte[], T> deserializer)
113         {
114             return new Marshaller<T>(serializer, deserializer);
115         }
116 
117         /// <summary>
118         /// Creates a marshaller from specified contextual serializer and deserializer.
119         /// Note: This method is part of an experimental API that can change or be removed without any prior notice.
120         /// </summary>
Create(Action<T, SerializationContext> serializer, Func<DeserializationContext, T> deserializer)121         public static Marshaller<T> Create<T>(Action<T, SerializationContext> serializer, Func<DeserializationContext, T> deserializer)
122         {
123             return new Marshaller<T>(serializer, deserializer);
124         }
125 
126         /// <summary>
127         /// Returns a marshaller for <c>string</c> type. This is useful for testing.
128         /// </summary>
129         public static Marshaller<string> StringMarshaller
130         {
131             get
132             {
133                 return new Marshaller<string>(System.Text.Encoding.UTF8.GetBytes,
134                                               System.Text.Encoding.UTF8.GetString);
135             }
136         }
137     }
138 }
139