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