/// <summary>
        /// Builds a deserializer for the Confluent wire format.
        /// </summary>
        /// <param name="id">
        /// A schema ID that all payloads must be serialized with. If a received schema ID does not
        /// match this ID, <see cref="InvalidDataException" /> will be thrown.
        /// </param>
        /// <param name="schema">
        /// The schema to build the Avro deserializer from.
        /// </param>
        protected virtual IDeserializer <T> Build <T>(int id, string schema)
        {
            var deserialize = _deserializerBuilder.BuildDelegate <T>(_schemaReader.Read(schema));

            return(new DelegateDeserializer <T>(stream =>
            {
                var bytes = new byte[4];

                if (stream.ReadByte() != 0x00 || stream.Read(bytes, 0, bytes.Length) != bytes.Length)
                {
                    throw new InvalidDataException("Data does not conform to the Confluent wire format.");
                }

                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(bytes);
                }

                var received = BitConverter.ToInt32(bytes, 0);

                if (received != id)
                {
                    throw new InvalidDataException($"The received schema ({received}) does not match the specified schema ({id}).");
                }

                return deserialize(stream);
            }));
        }
        /// <summary>
        /// Deserialize a message. (See <see cref="IAsyncDeserializer{T}.DeserializeAsync(ReadOnlyMemory{byte}, bool, SerializationContext)" />.)
        /// </summary>
        public virtual async Task <T> DeserializeAsync(ReadOnlyMemory <byte> data, bool isNull, SerializationContext context)
        {
            using (var stream = new MemoryStream(data.ToArray(), false))
            {
                var bytes = new byte[4];

                if (stream.ReadByte() != 0x00 || stream.Read(bytes, 0, bytes.Length) != bytes.Length)
                {
                    throw new InvalidDataException("Data does not conform to the Confluent wire format.");
                }

                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(bytes);
                }

                var @delegate = await(_cache.GetOrAdd(BitConverter.ToInt32(bytes, 0), async id =>
                {
                    var json   = await _resolve(id).ConfigureAwait(false);
                    var schema = _schemaReader.Read(json);

                    return(_deserializerBuilder.BuildDelegate <T>(schema));
                })).ConfigureAwait(false);

                return(@delegate(stream));
            }
        }
        /// <summary>
        /// Serialize a message. (See <see cref="IAsyncSerializer{T}.SerializeAsync(T, SerializationContext)" />.)
        /// </summary>
        public virtual async Task <byte[]> SerializeAsync(T data, SerializationContext context)
        {
            var serialize = await(_cache.GetOrAdd(_subjectNameBuilder(context), async subject =>
            {
                int id;
                Action <T, Stream> @delegate;

                try
                {
                    var existing = await _resolve(subject).ConfigureAwait(false);
                    var schema   = _schemaReader.Read(existing.SchemaString);

                    @delegate = _serializerBuilder.BuildDelegate <T>(schema);
                    id        = existing.Id;
                }
                catch (Exception e) when(_registerAutomatically && (
                                             (e is SchemaRegistryException sre && sre.ErrorCode == 40401) ||
                                             (e is UnsupportedTypeException)
                                             ))
                {
                    var schema = _schemaBuilder.BuildSchema <T>();
                    var json   = _schemaWriter.Write(schema);

                    @delegate = _serializerBuilder.BuildDelegate <T>(schema);
                    id        = await _register(subject, json).ConfigureAwait(false);
                }

                var bytes = BitConverter.GetBytes(id);

                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(bytes);
                }

                return(value =>
                {
                    var stream = new MemoryStream();

                    using (stream)
                    {
                        stream.WriteByte(0x00);
                        stream.Write(bytes, 0, bytes.Length);

                        @delegate(value, stream);
                    }

                    return stream.ToArray();
                });
            })).ConfigureAwait(false);

            return(serialize(data));
        }
        /// <summary>
        /// Builds a serializer for the Confluent wire format.
        /// </summary>
        /// <param name="id">
        /// A schema ID to include in each serialized payload.
        /// </param>
        /// <param name="schema">
        /// The schema to build the Avro serializer from.
        /// </param>
        protected virtual ISerializer <T> Build <T>(int id, string schema)
        {
            var bytes = BitConverter.GetBytes(id);

            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(bytes);
            }

            var serialize = _serializerBuilder.BuildDelegate <T>(_schemaReader.Read(schema));

            return(new DelegateSerializer <T>((data, stream) =>
            {
                stream.WriteByte(0x00);
                stream.Write(bytes, 0, bytes.Length);

                serialize(data, stream);
            }));
        }