use std::borrow::Cow;
use std::collections::BTreeMap;
use std::collections::HashMap;
use oxiproto_core::wire::UnknownFields;
use super::descriptor::{Cardinality, FieldDescriptor, Kind, MessageDescriptor};
use super::value::Value;
#[derive(Clone, Debug, PartialEq)]
pub struct DynamicMessage {
pub(crate) desc: MessageDescriptor,
pub(crate) fields: BTreeMap<u32, Value>,
pub(crate) unknown: UnknownFields,
}
impl DynamicMessage {
pub fn new(desc: MessageDescriptor) -> Self {
Self {
desc,
fields: BTreeMap::new(),
unknown: UnknownFields::new(),
}
}
pub fn descriptor(&self) -> MessageDescriptor {
self.desc.clone()
}
pub fn unknown_fields(&self) -> &UnknownFields {
&self.unknown
}
pub fn unknown_fields_mut(&mut self) -> &mut UnknownFields {
&mut self.unknown
}
pub fn has_field(&self, field: &FieldDescriptor) -> bool {
match self.fields.get(&field.number()) {
None => false,
Some(v) => !is_field_value_default(field, v),
}
}
pub fn get_field(&self, field: &FieldDescriptor) -> Cow<'_, Value> {
match self.fields.get(&field.number()) {
Some(v) => Cow::Borrowed(v),
None => Cow::Owned(default_value_for(field)),
}
}
pub fn set_field(&mut self, field: &FieldDescriptor, value: Value) {
if let Some(oneof) = field.containing_oneof() {
for sibling in oneof.fields() {
if sibling.number() != field.number() {
self.fields.remove(&sibling.number());
}
}
}
self.fields.insert(field.number(), value);
}
pub fn clear_field(&mut self, field: &FieldDescriptor) {
self.fields.remove(&field.number());
}
pub fn get_field_by_name(&self, name: &str) -> Option<Cow<'_, Value>> {
let field = self.desc.get_field_by_name(name)?;
Some(self.get_field(&field))
}
pub fn set_field_by_name(&mut self, name: &str, value: Value) -> bool {
match self.desc.get_field_by_name(name) {
Some(field) => {
self.set_field(&field, value);
true
}
None => false,
}
}
pub fn which_oneof(&self, oneof_name: &str) -> Option<FieldDescriptor> {
let oneof = self.desc.oneofs().find(|o| o.name() == oneof_name)?;
let set_field = oneof
.fields()
.find(|f| self.fields.contains_key(&f.number()));
set_field
}
pub fn iter_fields(&self) -> impl Iterator<Item = (FieldDescriptor, &Value)> + '_ {
self.fields
.iter()
.filter_map(move |(&number, value)| self.desc.get_field(number).map(|f| (f, value)))
}
}
pub(crate) fn default_value_for(field: &FieldDescriptor) -> Value {
if field.is_map() {
return Value::Map(HashMap::new());
}
if matches!(field.cardinality(), Cardinality::Repeated) {
return Value::List(Vec::new());
}
default_scalar_value(field.kind())
}
pub(crate) fn default_scalar_value(kind: Kind) -> Value {
match kind {
Kind::Double => Value::F64(0.0),
Kind::Float => Value::F32(0.0),
Kind::Int32 | Kind::Sint32 | Kind::Sfixed32 => Value::I32(0),
Kind::Int64 | Kind::Sint64 | Kind::Sfixed64 => Value::I64(0),
Kind::Uint32 | Kind::Fixed32 => Value::U32(0),
Kind::Uint64 | Kind::Fixed64 => Value::U64(0),
Kind::Bool => Value::Bool(false),
Kind::String => Value::String(String::new()),
Kind::Bytes => Value::Bytes(Vec::new()),
Kind::Enum(_) => Value::EnumNumber(0),
Kind::Message(_) | Kind::Group(_) => Value::List(Vec::new()),
}
}
pub(crate) fn is_field_value_default(field: &FieldDescriptor, value: &Value) -> bool {
match field.cardinality() {
Cardinality::Repeated => match value {
Value::List(l) => l.is_empty(),
Value::Map(m) => m.is_empty(),
_ => false,
},
Cardinality::Optional | Cardinality::Required => {
if matches!(field.kind(), Kind::Message(_) | Kind::Group(_)) {
return !matches!(value, Value::Message(_));
}
value.is_default()
}
}
}