| 
					
				 | 
			
			
				@@ -29,36 +29,122 @@ namespace Grpc.Core 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         readonly Func<T, byte[]> serializer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         readonly Func<byte[], T> deserializer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        readonly Action<T, SerializationContext> contextualSerializer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        readonly Func<DeserializationContext, T> contextualDeserializer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// Initializes a new marshaller. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Initializes a new marshaller from simple serialize/deserialize functions. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <param name="serializer">Function that will be used to serialize messages.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <param name="deserializer">Function that will be used to deserialize messages.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public Marshaller(Func<T, byte[]> serializer, Func<byte[], T> deserializer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            this.serializer = GrpcPreconditions.CheckNotNull(serializer, "serializer"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            this.deserializer = GrpcPreconditions.CheckNotNull(deserializer, "deserializer"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.serializer = GrpcPreconditions.CheckNotNull(serializer, nameof(serializer)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.deserializer = GrpcPreconditions.CheckNotNull(deserializer, nameof(deserializer)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.contextualSerializer = EmulateContextualSerializer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.contextualDeserializer = EmulateContextualDeserializer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// Gets the serializer function. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Initializes a new marshaller from serialize/deserialize fuctions that can access serialization and deserialization 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// context. Compared to the simple serializer/deserializer functions, using the contextual version provides more 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// flexibility and can lead to increased efficiency (and better performance). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Note: This constructor is part of an experimental API that can change or be removed without any prior notice. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public Func<T, byte[]> Serializer 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="serializer">Function that will be used to serialize messages.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="deserializer">Function that will be used to deserialize messages.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public Marshaller(Action<T, SerializationContext> serializer, Func<DeserializationContext, T> deserializer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            get 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return this.serializer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.contextualSerializer = GrpcPreconditions.CheckNotNull(serializer, nameof(serializer)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.contextualDeserializer = GrpcPreconditions.CheckNotNull(deserializer, nameof(deserializer)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.serializer = EmulateSimpleSerializer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.deserializer = EmulateSimpleDeserializer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Gets the serializer function. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public Func<T, byte[]> Serializer => this.serializer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// Gets the deserializer function. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public Func<byte[], T> Deserializer 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public Func<byte[], T> Deserializer => this.deserializer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Gets the serializer function. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Note: experimental API that can change or be removed without any prior notice. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public Action<T, SerializationContext> ContextualSerializer => this.contextualSerializer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Gets the serializer function. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Note: experimental API that can change or be removed without any prior notice. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public Func<DeserializationContext, T> ContextualDeserializer => this.contextualDeserializer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // for backward compatibility, emulate the simple serializer using the contextual one 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private byte[] EmulateSimpleSerializer(T msg) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            get 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // TODO(jtattermusch): avoid the allocation by passing a thread-local instance 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var context = new EmulatedSerializationContext(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.contextualSerializer(msg, context); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return context.GetPayload(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // for backward compatibility, emulate the simple deserializer using the contextual one 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private T EmulateSimpleDeserializer(byte[] payload) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // TODO(jtattermusch): avoid the allocation by passing a thread-local instance 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var context = new EmulatedDeserializationContext(payload); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return this.contextualDeserializer(context); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // for backward compatibility, emulate the contextual serializer using the simple one 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private void EmulateContextualSerializer(T message, SerializationContext context) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var payload = this.serializer(message); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            context.Complete(payload); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // for backward compatibility, emulate the contextual deserializer using the simple one 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private T EmulateContextualDeserializer(DeserializationContext context) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return this.deserializer(context.PayloadAsNewBuffer()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        internal class EmulatedSerializationContext : SerializationContext 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            bool isComplete; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            byte[] payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            public override void Complete(byte[] payload) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                GrpcPreconditions.CheckState(!isComplete); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                this.isComplete = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                this.payload = payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            internal byte[] GetPayload() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return this.payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        internal class EmulatedDeserializationContext : DeserializationContext 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            readonly byte[] payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            public EmulatedDeserializationContext(byte[] payload) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                this.payload = payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            public override int? PayloadLength => payload?.Length; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            public override byte[] PayloadAsNewBuffer() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return this.deserializer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 |