use std::{collections::BTreeMap, fmt};
use crate::{
dynamic::{
unknown::UnknownFieldSet,
value::{SetFieldError, Value},
},
field::{FieldDescriptor, Kind},
oneof::OneofDescriptor,
};
#[derive(Clone, Debug, PartialEq)]
pub(crate) enum ValueOrUnknown {
Value(Value),
Unknown(UnknownFieldSet),
Taken,
}
#[derive(Clone, Default, Debug, PartialEq)]
pub(crate) struct DynamicMessageFieldSet {
pub(crate) fields: BTreeMap<u32, ValueOrUnknown>,
}
impl DynamicMessageFieldSet {
pub(crate) fn get_value(&self, number: u32) -> Option<&Value> {
match self.fields.get(&number) {
Some(ValueOrUnknown::Value(v)) => Some(v),
_ => None,
}
}
pub(crate) fn get_value_mut(&mut self, number: u32) -> Option<&mut Value> {
match self.fields.get_mut(&number) {
Some(ValueOrUnknown::Value(v)) => Some(v),
_ => None,
}
}
pub(crate) fn iter_known(&self) -> impl Iterator<Item = (u32, &Value)> + '_ {
self.fields.iter().filter_map(|(n, v)| match v {
ValueOrUnknown::Value(val) => Some((*n, val)),
_ => None,
})
}
pub(crate) fn iter_unknown(&self) -> impl Iterator<Item = (u32, &UnknownFieldSet)> + '_ {
self.fields.iter().filter_map(|(n, v)| match v {
ValueOrUnknown::Unknown(set) => Some((*n, set)),
_ => None,
})
}
pub(crate) fn iter_in_order(&self) -> impl Iterator<Item = (u32, &ValueOrUnknown)> + '_ {
self.fields.iter().map(|(n, v)| (*n, v))
}
pub(crate) fn has_value(&self, number: u32) -> bool {
matches!(self.fields.get(&number), Some(ValueOrUnknown::Value(_)))
}
pub(crate) fn set(&mut self, field: &FieldDescriptor, value: Value) {
debug_assert!(
value.is_valid_for_field(field),
"DynamicMessageFieldSet::set: value {value:?} not valid for field {}",
field.full_name(),
);
self.clear_oneof_siblings(field);
self.fields
.insert(field.number(), ValueOrUnknown::Value(value));
}
pub(crate) fn try_set(
&mut self,
field: &FieldDescriptor,
value: Value,
) -> Result<(), SetFieldError> {
if !value.is_valid_for_field(field) {
return Err(SetFieldError::InvalidType {
field: field.clone(),
value: Box::new(value),
});
}
self.clear_oneof_siblings(field);
self.fields
.insert(field.number(), ValueOrUnknown::Value(value));
Ok(())
}
pub(crate) fn clear(&mut self, field: &FieldDescriptor) {
self.clear_oneof_siblings(field);
self.fields.remove(&field.number());
}
fn clear_oneof_siblings(&mut self, field: &FieldDescriptor) {
let Some(oneof) = field.containing_oneof() else {
return;
};
let self_number = field.number();
for sibling in oneof.fields() {
let n = sibling.number();
if n == self_number {
continue;
}
self.fields.remove(&n);
}
}
pub(crate) fn add_unknown(&mut self, number: u32, field: buffa::UnknownField) {
match self.fields.entry(number) {
std::collections::btree_map::Entry::Occupied(mut occ) => match occ.get_mut() {
ValueOrUnknown::Unknown(set) => set.push(field),
ValueOrUnknown::Value(_) | ValueOrUnknown::Taken => {
let mut set = UnknownFieldSet::new();
set.push(field);
occ.insert(ValueOrUnknown::Unknown(set));
}
},
std::collections::btree_map::Entry::Vacant(vac) => {
let mut set = UnknownFieldSet::new();
set.push(field);
vac.insert(ValueOrUnknown::Unknown(set));
}
}
}
pub(crate) fn drain_unknown(&mut self) -> Vec<(u32, UnknownFieldSet)> {
let numbers: Vec<u32> = self
.fields
.iter()
.filter_map(|(n, v)| match v {
ValueOrUnknown::Unknown(_) => Some(*n),
_ => None,
})
.collect();
let mut out = Vec::with_capacity(numbers.len());
for n in numbers {
if let Some(slot) = self.fields.get_mut(&n) {
let taken = std::mem::replace(slot, ValueOrUnknown::Taken);
if let ValueOrUnknown::Unknown(set) = taken {
out.push((n, set));
}
}
}
self.fields
.retain(|_, v| !matches!(v, ValueOrUnknown::Taken));
out
}
pub(crate) fn is_empty(&self) -> bool {
self.fields
.values()
.all(|v| matches!(v, ValueOrUnknown::Taken))
}
}
#[allow(dead_code, reason = "extension support follow-up will add second impl")]
pub(crate) trait FieldDescriptorLike: fmt::Debug {
fn number(&self) -> u32;
fn kind(&self) -> Kind;
fn is_list(&self) -> bool;
fn is_map(&self) -> bool;
fn is_packed(&self) -> bool;
fn is_packable(&self) -> bool;
fn supports_presence(&self) -> bool;
fn containing_oneof(&self) -> Option<OneofDescriptor>;
fn default_value(&self) -> Value;
fn is_default_value(&self, value: &Value) -> bool;
fn is_valid(&self, value: &Value) -> bool;
}
impl FieldDescriptorLike for FieldDescriptor {
fn number(&self) -> u32 {
FieldDescriptor::number(self)
}
fn kind(&self) -> Kind {
FieldDescriptor::kind(self)
}
fn is_list(&self) -> bool {
FieldDescriptor::is_list(self)
}
fn is_map(&self) -> bool {
FieldDescriptor::is_map(self)
}
fn is_packed(&self) -> bool {
FieldDescriptor::is_packed(self)
}
fn is_packable(&self) -> bool {
FieldDescriptor::is_packable(self)
}
fn supports_presence(&self) -> bool {
FieldDescriptor::supports_presence(self)
}
fn containing_oneof(&self) -> Option<OneofDescriptor> {
FieldDescriptor::containing_oneof(self)
}
fn default_value(&self) -> Value {
Value::default_value_for_field(self)
}
fn is_default_value(&self, value: &Value) -> bool {
if self.is_list() || self.is_map() {
return matches!(value, Value::List(l) if l.is_empty())
|| matches!(value, Value::Map(m) if m.is_empty());
}
value.is_default(&FieldDescriptor::kind(self))
}
fn is_valid(&self, value: &Value) -> bool {
Value::is_valid_for_field(value, self)
}
}