use oxiproto_core::wire::{
zigzag_decode32, zigzag_decode64, zigzag_encode32, zigzag_encode64, DecodeBuffer, EncodeBuffer,
Tag, UnknownFields, WireType,
};
use super::descriptor::{Cardinality, FieldDescriptor, Kind, MessageDescriptor};
use super::dynamic::{default_scalar_value, is_field_value_default, DynamicMessage};
use super::value::{MapKey, Value};
use crate::ReflectError;
impl DynamicMessage {
pub fn encode_to_vec(&self) -> Result<Vec<u8>, ReflectError> {
let mut buf = EncodeBuffer::new();
self.encode(&mut buf)?;
Ok(buf.into_vec())
}
pub fn encode(&self, buf: &mut EncodeBuffer) -> Result<(), ReflectError> {
for (field, value) in self.iter_fields() {
if is_field_value_default(&field, value) {
continue;
}
encode_field(buf, &field, value)?;
}
self.unknown.encode_to(buf);
Ok(())
}
pub fn decode(desc: MessageDescriptor, bytes: &[u8]) -> Result<Self, ReflectError> {
let mut msg = DynamicMessage::new(desc);
let mut dec = DecodeBuffer::new(bytes);
decode_into(&mut msg, &mut dec)?;
Ok(msg)
}
}
fn decode_into(msg: &mut DynamicMessage, dec: &mut DecodeBuffer<'_>) -> Result<(), ReflectError> {
while !dec.is_empty() {
let tag = dec.read_tag().map_err(wire_err)?;
let desc = msg.descriptor();
match desc.get_field(tag.field_number) {
Some(field) => decode_known_field(msg, &field, tag, dec)?,
None => decode_unknown_field(&mut msg.unknown, tag, dec)?,
}
}
Ok(())
}
fn decode_known_field(
msg: &mut DynamicMessage,
field: &FieldDescriptor,
tag: Tag,
dec: &mut DecodeBuffer<'_>,
) -> Result<(), ReflectError> {
if field.is_map() {
return decode_map_entry(msg, field, tag, dec);
}
match field.cardinality() {
Cardinality::Repeated => decode_repeated(msg, field, tag, dec),
Cardinality::Optional | Cardinality::Required => {
let value = decode_single_value(field, tag, dec)?;
msg.set_field(field, value);
Ok(())
}
}
}
fn decode_repeated(
msg: &mut DynamicMessage,
field: &FieldDescriptor,
tag: Tag,
dec: &mut DecodeBuffer<'_>,
) -> Result<(), ReflectError> {
if tag.wire_type == WireType::Len && field.kind().is_packable() {
let payload = dec.read_length_delimited().map_err(wire_err)?;
let mut inner = DecodeBuffer::new(payload);
let mut decoded = Vec::new();
while !inner.is_empty() {
decoded.push(decode_scalar_from(field.kind(), &mut inner)?);
}
append_to_list(msg, field, decoded);
return Ok(());
}
let value = decode_single_value(field, tag, dec)?;
append_to_list(msg, field, vec![value]);
Ok(())
}
fn append_to_list(msg: &mut DynamicMessage, field: &FieldDescriptor, mut elems: Vec<Value>) {
let entry = msg
.fields
.entry(field.number())
.or_insert_with(|| Value::List(Vec::new()));
match entry {
Value::List(list) => list.append(&mut elems),
other => {
let mut list = Vec::new();
list.append(&mut elems);
*other = Value::List(list);
}
}
}
fn decode_single_value(
field: &FieldDescriptor,
tag: Tag,
dec: &mut DecodeBuffer<'_>,
) -> Result<Value, ReflectError> {
match field.kind() {
Kind::Group(_) => Err(group_unsupported()),
Kind::Message(idx) => {
if tag.wire_type != WireType::Len {
return Err(ReflectError::Field(format!(
"message field '{}' expected length-delimited wire type, got {}",
field.name(),
tag.wire_type
)));
}
let payload = dec.read_length_delimited().map_err(wire_err)?;
let nested_desc = MessageDescriptor {
pool: field.pool.clone(),
index: idx,
};
let nested = DynamicMessage::decode(nested_desc, payload)?;
Ok(Value::Message(Box::new(nested)))
}
kind => decode_scalar_with_tag(kind, tag, dec, field),
}
}
fn decode_scalar_with_tag(
kind: Kind,
tag: Tag,
dec: &mut DecodeBuffer<'_>,
field: &FieldDescriptor,
) -> Result<Value, ReflectError> {
let expected = scalar_wire_type(kind)?;
if tag.wire_type != expected {
return Err(ReflectError::Field(format!(
"field '{}' expected wire type {expected}, got {}",
field.name(),
tag.wire_type
)));
}
decode_scalar_from(kind, dec)
}
fn decode_scalar_from(kind: Kind, dec: &mut DecodeBuffer<'_>) -> Result<Value, ReflectError> {
let value = match kind {
Kind::Double => Value::F64(dec.read_double().map_err(wire_err)?),
Kind::Float => Value::F32(dec.read_float().map_err(wire_err)?),
Kind::Int32 => Value::I32(dec.read_varint().map_err(wire_err)? as i32),
Kind::Int64 => Value::I64(dec.read_varint().map_err(wire_err)? as i64),
Kind::Uint32 => {
let v = dec.read_varint().map_err(wire_err)?;
Value::U32(v as u32)
}
Kind::Uint64 => Value::U64(dec.read_varint().map_err(wire_err)?),
Kind::Sint32 => {
let raw = dec.read_varint().map_err(wire_err)? as u32;
Value::I32(zigzag_decode32(raw))
}
Kind::Sint64 => {
let raw = dec.read_varint().map_err(wire_err)?;
Value::I64(zigzag_decode64(raw))
}
Kind::Fixed32 => Value::U32(dec.read_fixed32().map_err(wire_err)?),
Kind::Fixed64 => Value::U64(dec.read_fixed64().map_err(wire_err)?),
Kind::Sfixed32 => Value::I32(dec.read_fixed32().map_err(wire_err)? as i32),
Kind::Sfixed64 => Value::I64(dec.read_fixed64().map_err(wire_err)? as i64),
Kind::Bool => Value::Bool(dec.read_varint().map_err(wire_err)? != 0),
Kind::String => Value::String(dec.read_string().map_err(wire_err)?.to_owned()),
Kind::Bytes => Value::Bytes(dec.read_length_delimited().map_err(wire_err)?.to_vec()),
Kind::Enum(_) => Value::EnumNumber(dec.read_varint().map_err(wire_err)? as i32),
Kind::Message(_) | Kind::Group(_) => {
return Err(ReflectError::Field(
"message/group kind is not a scalar".to_owned(),
))
}
};
Ok(value)
}
fn decode_map_entry(
msg: &mut DynamicMessage,
field: &FieldDescriptor,
tag: Tag,
dec: &mut DecodeBuffer<'_>,
) -> Result<(), ReflectError> {
if tag.wire_type != WireType::Len {
return Err(ReflectError::Field(format!(
"map field '{}' expected length-delimited entries, got {}",
field.name(),
tag.wire_type
)));
}
let payload = dec.read_length_delimited().map_err(wire_err)?;
let key_field = field
.map_entry_key_field()
.ok_or_else(|| ReflectError::Field("map field missing entry key field".to_owned()))?;
let value_field = field
.map_entry_value_field()
.ok_or_else(|| ReflectError::Field("map field missing entry value field".to_owned()))?;
let mut key_val = default_scalar_value(key_field.kind());
let mut val_val = match value_field.kind() {
Kind::Message(idx) => {
let nested_desc = MessageDescriptor {
pool: value_field.pool.clone(),
index: idx,
};
Value::Message(Box::new(DynamicMessage::new(nested_desc)))
}
other => default_scalar_value(other),
};
let mut entry_dec = DecodeBuffer::new(payload);
while !entry_dec.is_empty() {
let entry_tag = entry_dec.read_tag().map_err(wire_err)?;
match entry_tag.field_number {
1 => key_val = decode_single_value(&key_field, entry_tag, &mut entry_dec)?,
2 => val_val = decode_single_value(&value_field, entry_tag, &mut entry_dec)?,
_ => entry_dec
.skip_field(entry_tag.wire_type)
.map_err(wire_err)?,
}
}
let map_key = value_to_map_key(&key_val).ok_or_else(|| {
ReflectError::Field(format!(
"map field '{}' has an unsupported key type",
field.name()
))
})?;
let entry = msg
.fields
.entry(field.number())
.or_insert_with(|| Value::Map(std::collections::HashMap::new()));
match entry {
Value::Map(map) => {
map.insert(map_key, val_val);
}
other => {
let mut map = std::collections::HashMap::new();
map.insert(map_key, val_val);
*other = Value::Map(map);
}
}
Ok(())
}
fn decode_unknown_field(
unknown: &mut UnknownFields,
tag: Tag,
dec: &mut DecodeBuffer<'_>,
) -> Result<(), ReflectError> {
match tag.wire_type {
WireType::Varint => {
let v = dec.read_varint().map_err(wire_err)?;
unknown.push_varint(tag.field_number, v);
}
WireType::I64 => {
let v = dec.read_fixed64().map_err(wire_err)?;
unknown.push_fixed64(tag.field_number, v);
}
WireType::I32 => {
let v = dec.read_fixed32().map_err(wire_err)?;
unknown.push_fixed32(tag.field_number, v);
}
WireType::Len => {
let payload = dec.read_length_delimited().map_err(wire_err)?;
unknown.push_length_delimited(tag.field_number, payload.to_vec());
}
WireType::SGroup | WireType::EGroup => return Err(group_unsupported()),
}
Ok(())
}
fn encode_field(
buf: &mut EncodeBuffer,
field: &FieldDescriptor,
value: &Value,
) -> Result<(), ReflectError> {
if field.is_map() {
return encode_map(buf, field, value);
}
match field.cardinality() {
Cardinality::Repeated => encode_repeated(buf, field, value),
Cardinality::Optional | Cardinality::Required => {
encode_single(buf, field, value, field.number())
}
}
}
fn encode_repeated(
buf: &mut EncodeBuffer,
field: &FieldDescriptor,
value: &Value,
) -> Result<(), ReflectError> {
let list = match value {
Value::List(l) => l,
_ => {
return Err(ReflectError::Field(format!(
"repeated field '{}' holds a non-list value",
field.name()
)))
}
};
if list.is_empty() {
return Ok(());
}
if field.is_packed() && field.kind().is_packable() {
let mut payload = EncodeBuffer::new();
for elem in list {
encode_scalar_payload(&mut payload, field.kind(), elem, field)?;
}
buf.write_tag(field.number(), WireType::Len)
.map_err(wire_err)?;
buf.write_length_delimited(payload.as_bytes());
} else {
for elem in list {
encode_single(buf, field, elem, field.number())?;
}
}
Ok(())
}
fn encode_map(
buf: &mut EncodeBuffer,
field: &FieldDescriptor,
value: &Value,
) -> Result<(), ReflectError> {
let map = match value {
Value::Map(m) => m,
_ => {
return Err(ReflectError::Field(format!(
"map field '{}' holds a non-map value",
field.name()
)))
}
};
let key_field = field
.map_entry_key_field()
.ok_or_else(|| ReflectError::Field("map field missing entry key field".to_owned()))?;
let value_field = field
.map_entry_value_field()
.ok_or_else(|| ReflectError::Field("map field missing entry value field".to_owned()))?;
for (k, v) in map {
let key_value = k.to_value();
let mut entry = EncodeBuffer::new();
encode_single(&mut entry, &key_field, &key_value, 1)?;
encode_single(&mut entry, &value_field, v, 2)?;
buf.write_tag(field.number(), WireType::Len)
.map_err(wire_err)?;
buf.write_length_delimited(entry.as_bytes());
}
Ok(())
}
fn encode_single(
buf: &mut EncodeBuffer,
field: &FieldDescriptor,
value: &Value,
field_number: u32,
) -> Result<(), ReflectError> {
match field.kind() {
Kind::Group(_) => Err(group_unsupported()),
Kind::Message(_) => {
let nested = match value {
Value::Message(m) => m,
_ => {
return Err(ReflectError::Field(format!(
"message field '{}' holds a non-message value",
field.name()
)))
}
};
let payload = nested.encode_to_vec()?;
buf.write_tag(field_number, WireType::Len)
.map_err(wire_err)?;
buf.write_length_delimited(&payload);
Ok(())
}
kind => {
let wt = scalar_wire_type(kind)?;
buf.write_tag(field_number, wt).map_err(wire_err)?;
encode_scalar_payload(buf, kind, value, field)
}
}
}
fn encode_scalar_payload(
buf: &mut EncodeBuffer,
kind: Kind,
value: &Value,
field: &FieldDescriptor,
) -> Result<(), ReflectError> {
match kind {
Kind::Double => buf.write_double(expect_f64(value, field)?),
Kind::Float => buf.write_float(expect_f32(value, field)?),
Kind::Int32 => buf.write_varint_i32(expect_i32(value, field)?),
Kind::Int64 => buf.write_varint_i64(expect_i64(value, field)?),
Kind::Uint32 => buf.write_varint32(expect_u32(value, field)?),
Kind::Uint64 => buf.write_varint(expect_u64(value, field)?),
Kind::Sint32 => buf.write_varint32(zigzag_encode32(expect_i32(value, field)?)),
Kind::Sint64 => buf.write_varint(zigzag_encode64(expect_i64(value, field)?)),
Kind::Fixed32 => buf.write_fixed32(expect_u32(value, field)?),
Kind::Fixed64 => buf.write_fixed64(expect_u64(value, field)?),
Kind::Sfixed32 => buf.write_fixed32(expect_i32(value, field)? as u32),
Kind::Sfixed64 => buf.write_fixed64(expect_i64(value, field)? as u64),
Kind::Bool => buf.write_bool(expect_bool(value, field)?),
Kind::String => buf.write_string(expect_str(value, field)?),
Kind::Bytes => buf.write_length_delimited(expect_bytes(value, field)?),
Kind::Enum(_) => buf.write_varint_i32(expect_enum(value, field)?),
Kind::Message(_) | Kind::Group(_) => {
return Err(ReflectError::Field(
"message/group kind has no scalar payload".to_owned(),
))
}
}
Ok(())
}
fn scalar_wire_type(kind: Kind) -> Result<WireType, ReflectError> {
let wt = match kind {
Kind::Int32
| Kind::Int64
| Kind::Uint32
| Kind::Uint64
| Kind::Sint32
| Kind::Sint64
| Kind::Bool
| Kind::Enum(_) => WireType::Varint,
Kind::Fixed64 | Kind::Sfixed64 | Kind::Double => WireType::I64,
Kind::Fixed32 | Kind::Sfixed32 | Kind::Float => WireType::I32,
Kind::String | Kind::Bytes => WireType::Len,
Kind::Message(_) | Kind::Group(_) => {
return Err(ReflectError::Field(
"message/group kind has no scalar wire type".to_owned(),
))
}
};
Ok(wt)
}
fn value_to_map_key(value: &Value) -> Option<MapKey> {
match value {
Value::String(s) => Some(MapKey::String(s.clone())),
Value::I32(v) => Some(MapKey::I32(*v)),
Value::I64(v) => Some(MapKey::I64(*v)),
Value::U32(v) => Some(MapKey::U32(*v)),
Value::U64(v) => Some(MapKey::U64(*v)),
Value::Bool(v) => Some(MapKey::Bool(*v)),
_ => None,
}
}
fn group_unsupported() -> ReflectError {
ReflectError::Field("protobuf groups (wire types 3/4) are unsupported".to_owned())
}
fn wire_err(e: oxiproto_core::wire::WireError) -> ReflectError {
ReflectError::Field(format!("wire format error: {e}"))
}
fn type_mismatch(field: &FieldDescriptor, expected: &str) -> ReflectError {
ReflectError::Field(format!(
"field '{}' expected a {expected} value",
field.name()
))
}
fn expect_f64(value: &Value, field: &FieldDescriptor) -> Result<f64, ReflectError> {
value.as_f64().ok_or_else(|| type_mismatch(field, "f64"))
}
fn expect_f32(value: &Value, field: &FieldDescriptor) -> Result<f32, ReflectError> {
value.as_f32().ok_or_else(|| type_mismatch(field, "f32"))
}
fn expect_i32(value: &Value, field: &FieldDescriptor) -> Result<i32, ReflectError> {
value.as_i32().ok_or_else(|| type_mismatch(field, "i32"))
}
fn expect_i64(value: &Value, field: &FieldDescriptor) -> Result<i64, ReflectError> {
value.as_i64().ok_or_else(|| type_mismatch(field, "i64"))
}
fn expect_u32(value: &Value, field: &FieldDescriptor) -> Result<u32, ReflectError> {
value.as_u32().ok_or_else(|| type_mismatch(field, "u32"))
}
fn expect_u64(value: &Value, field: &FieldDescriptor) -> Result<u64, ReflectError> {
value.as_u64().ok_or_else(|| type_mismatch(field, "u64"))
}
fn expect_bool(value: &Value, field: &FieldDescriptor) -> Result<bool, ReflectError> {
value.as_bool().ok_or_else(|| type_mismatch(field, "bool"))
}
fn expect_str<'a>(value: &'a Value, field: &FieldDescriptor) -> Result<&'a str, ReflectError> {
value.as_str().ok_or_else(|| type_mismatch(field, "string"))
}
fn expect_bytes<'a>(value: &'a Value, field: &FieldDescriptor) -> Result<&'a [u8], ReflectError> {
value
.as_bytes()
.ok_or_else(|| type_mismatch(field, "bytes"))
}
fn expect_enum(value: &Value, field: &FieldDescriptor) -> Result<i32, ReflectError> {
value
.as_enum_number()
.or_else(|| value.as_i32())
.ok_or_else(|| type_mismatch(field, "enum number"))
}