/// <summary>
    /// Read the value for an unknown key as bytes.
    /// Used to preserve unknown keys during deserialization.
    /// Requires the message option preserveunknown=true.
    /// </summary>
    public static byte[] ReadValueBytes(CitoStream stream, Key key)
    {
        byte[] b;
        int    offset = 0;

        switch (key.GetWireType())
        {
        case Wire.Fixed32:
            b = new byte[4];
            while (offset < 4)
            {
                offset += stream.Read(b, offset, 4 - offset);
            }
            return(b);

        case Wire.Fixed64:
            b = new byte[8];
            while (offset < 8)
            {
                offset += stream.Read(b, offset, 8 - offset);
            }
            return(b);

        case Wire.LengthDelimited:
            //Read and include length in value buffer
            int length          = ProtocolParser.ReadUInt32(stream);
            CitoMemoryStream ms = new CitoMemoryStream();
            {
                //TODO: pass b directly to MemoryStream constructor or skip usage of it completely
                ProtocolParser.WriteUInt32(ms, length);
                b = new byte[length + ms.Length()];
                byte[] arr = ms.ToArray();
                for (int i = 0; i < ProtoPlatform.ArrayLength(arr); i++)
                {
                    b[i] = arr[i];
                }
                offset = ms.Length();
            }

            //Read data into buffer
            while (offset < ProtoPlatform.ArrayLength(b))
            {
                offset += stream.Read(b, offset, ProtoPlatform.ArrayLength(b) - offset);
            }
            return(b);

        case Wire.Varint:
            return(ProtocolParser.ReadVarIntBytes(stream));

        default:
#if !CITO
            throw new NotImplementedException("Unknown wire type: " + key.GetWireType());
#else
            return(null);
#endif
        }
    }
    /// <summary>
    /// Reads a length delimited byte array
    /// </summary>
    public static byte[] ReadBytes(CitoStream stream)
    {
        //VarInt length
        int length = ReadUInt32(stream);

        //Bytes
        byte[] buffer = new byte[length];
        int    read   = 0;

        while (read < length)
        {
            int r = stream.Read(buffer, read, length - read);
            if (r == 0)
#if !CITO
            { throw new InvalidDataException("Expected " + (length - read) + " got " + read); }
#else
            { return(null); }
#endif
            read += r;
        }
        return(buffer);
    }
    /// <summary>
    /// Read the value for an unknown key as bytes.
    /// Used to preserve unknown keys during deserialization.
    /// Requires the message option preserveunknown=true.
    /// </summary>
    public static byte[] ReadValueBytes(CitoStream stream, Key key)
    {
        byte[] b;
        int offset = 0;

        switch (key.GetWireType())
        {
            case Wire.Fixed32:
                b = new byte[4];
                while (offset < 4)
                    offset += stream.Read(b, offset, 4 - offset);
                return b;
            case Wire.Fixed64:
                b = new byte[8];
                while (offset < 8)
                    offset += stream.Read(b, offset, 8 - offset);
                return b;
            case Wire.LengthDelimited:
                //Read and include length in value buffer
                int length = ProtocolParser.ReadUInt32(stream);
                CitoMemoryStream ms = new CitoMemoryStream();
                {
                    //TODO: pass b directly to MemoryStream constructor or skip usage of it completely
                    ProtocolParser.WriteUInt32(ms, length);
                    b = new byte[length + ms.Length()];
                    byte[] arr = ms.ToArray();
                    for (int i = 0; i < ProtoPlatform.ArrayLength(arr); i++)
                    {
                        b[i] = arr[i];
                    }
                    offset = ms.Length();
                }

                //Read data into buffer
                while (offset < ProtoPlatform.ArrayLength(b))
                    offset += stream.Read(b, offset, ProtoPlatform.ArrayLength(b) - offset);
                return b;
            case Wire.Varint:
                return ProtocolParser.ReadVarIntBytes(stream);
            default:
        #if !CITO
                throw new NotImplementedException("Unknown wire type: " + key.GetWireType());
        #else
                return null;
        #endif
        }
    }
    /// <summary>
    /// Reads a length delimited byte array
    /// </summary>
    public static byte[] ReadBytes(CitoStream stream)
    {
        //VarInt length
        int length = ReadUInt32(stream);

        //Bytes
        byte[] buffer = new byte[length];
        int read = 0;
        while (read < length)
        {
            int r = stream.Read(buffer, read, length - read);
            if (r == 0)
        #if !CITO
                throw new InvalidDataException("Expected " + (length - read) + " got " + read);
        #else
            return null;
        #endif
            read += r;
        }
        return buffer;
    }