use prost_reflect::{FieldDescriptor, Kind, MessageDescriptor};
use serde::de::value::StringDeserializer;
use serde::de::{self, DeserializeSeed, Deserializer, IntoDeserializer, MapAccess, Visitor};
use std::fmt;
#[derive(Debug, Default)]
pub(super) struct Presence {
names: String,
entries: Vec<Entry>,
matched: Vec<bool>,
whole: bool,
}
#[derive(Debug)]
struct Entry {
depth: u32,
start: u32,
end: u32,
held: Held,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Held {
Whole,
Object,
Fields,
}
impl Presence {
pub(super) fn for_body(len: usize) -> Self {
Self {
names: String::with_capacity(len.min(512)),
entries: Vec::with_capacity((len / 6).min(64)),
matched: Vec::new(),
whole: false,
}
}
pub(super) fn clear(&mut self) {
self.names.clear();
self.entries.clear();
self.whole = false;
}
pub(super) fn record_whole(&mut self) {
self.whole = true;
}
fn record(&mut self, depth: usize, key: &str, held: Held) {
let start = self.names.len();
self.names.push_str(key);
self.entries.push(Entry {
depth: u32::try_from(depth).expect("fewer than 2^32 nesting levels"),
start: u32::try_from(start).expect("keys shorter than 4 GiB"),
end: u32::try_from(self.names.len()).expect("keys shorter than 4 GiB"),
held,
});
}
pub(super) fn record_path(&mut self, path: &[FieldDescriptor], fields: bool) {
for (depth, field) in path.iter().enumerate() {
let held = if fields || depth + 1 < path.len() {
Held::Fields
} else {
Held::Whole
};
self.record(depth, field.name(), held);
}
}
fn mark_object(&mut self) {
if let Some(entry) = self.entries.last_mut() {
entry.held = Held::Object;
}
}
pub(super) fn blocks(&mut self, path: &[FieldDescriptor]) -> bool {
if self.whole {
return true;
}
self.matched.clear();
for entry in &self.entries {
let depth = entry.depth as usize;
self.matched.truncate(depth);
let parent = depth == 0 || self.matched.get(depth - 1) == Some(&true);
let key = &self.names[entry.start as usize..entry.end as usize];
let field = path
.get(depth)
.filter(|field| parent && (key == field.name() || key == field.json_name()));
if let Some(field) = field {
let whole = match entry.held {
Held::Whole => true,
Held::Object => {
matches!(field.kind(), Kind::Message(message) if has_special_json(&message))
}
Held::Fields => false,
};
if depth + 1 == path.len() || whole {
return true;
}
}
let hit = field.is_some();
self.matched.resize(depth, false);
self.matched.push(hit);
}
false
}
}
pub(crate) fn has_special_json(message: &MessageDescriptor) -> bool {
matches!(
message.full_name(),
"google.protobuf.Any"
| "google.protobuf.Timestamp"
| "google.protobuf.Duration"
| "google.protobuf.Struct"
| "google.protobuf.FloatValue"
| "google.protobuf.DoubleValue"
| "google.protobuf.Int32Value"
| "google.protobuf.Int64Value"
| "google.protobuf.UInt32Value"
| "google.protobuf.UInt64Value"
| "google.protobuf.BoolValue"
| "google.protobuf.StringValue"
| "google.protobuf.BytesValue"
| "google.protobuf.FieldMask"
| "google.protobuf.ListValue"
| "google.protobuf.Value"
| "google.protobuf.Empty"
)
}
pub(super) struct Recording<'p, D> {
inner: D,
presence: &'p mut Presence,
depth: usize,
}
impl<'p, D> Recording<'p, D> {
pub(super) fn root(inner: D, presence: &'p mut Presence) -> Self {
Self {
inner,
presence,
depth: 0,
}
}
}
macro_rules! forward {
($($method:ident($($arg:ident: $ty:ty),*);)*) => {$(
fn $method<V: Visitor<'de>>(self, $($arg: $ty,)* visitor: V) -> Result<V::Value, D::Error> {
self.inner.$method($($arg,)* visitor)
}
)*};
}
impl<'de, D: Deserializer<'de>> Deserializer<'de> for Recording<'_, D> {
type Error = D::Error;
fn deserialize_option<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, D::Error> {
let Self {
inner,
presence,
depth,
} = self;
inner.deserialize_option(OptionVisitor {
visitor,
presence,
depth,
})
}
fn deserialize_map<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, D::Error> {
let Self {
inner,
presence,
depth,
} = self;
inner.deserialize_map(MapVisitor {
visitor,
presence,
depth,
})
}
forward! {
deserialize_any();
deserialize_bool();
deserialize_i8();
deserialize_i16();
deserialize_i32();
deserialize_i64();
deserialize_i128();
deserialize_u8();
deserialize_u16();
deserialize_u32();
deserialize_u64();
deserialize_u128();
deserialize_f32();
deserialize_f64();
deserialize_char();
deserialize_str();
deserialize_string();
deserialize_bytes();
deserialize_byte_buf();
deserialize_unit();
deserialize_unit_struct(name: &'static str);
deserialize_newtype_struct(name: &'static str);
deserialize_seq();
deserialize_tuple(len: usize);
deserialize_tuple_struct(name: &'static str, len: usize);
deserialize_struct(name: &'static str, fields: &'static [&'static str]);
deserialize_enum(name: &'static str, variants: &'static [&'static str]);
deserialize_identifier();
deserialize_ignored_any();
}
fn is_human_readable(&self) -> bool {
self.inner.is_human_readable()
}
}
struct OptionVisitor<'p, V> {
visitor: V,
presence: &'p mut Presence,
depth: usize,
}
impl<'de, V: Visitor<'de>> Visitor<'de> for OptionVisitor<'_, V> {
type Value = V::Value;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.visitor.expecting(f)
}
fn visit_none<E: de::Error>(self) -> Result<V::Value, E> {
self.visitor.visit_none()
}
fn visit_unit<E: de::Error>(self) -> Result<V::Value, E> {
self.visitor.visit_unit()
}
fn visit_some<D: Deserializer<'de>>(self, inner: D) -> Result<V::Value, D::Error> {
self.visitor.visit_some(Recording {
inner,
presence: self.presence,
depth: self.depth,
})
}
}
struct MapVisitor<'p, V> {
visitor: V,
presence: &'p mut Presence,
depth: usize,
}
impl<'de, V: Visitor<'de>> Visitor<'de> for MapVisitor<'_, V> {
type Value = V::Value;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.visitor.expecting(f)
}
fn visit_map<A: MapAccess<'de>>(self, inner: A) -> Result<V::Value, A::Error> {
if self.depth > 0 {
self.presence.mark_object();
}
self.visitor.visit_map(RecordingMap {
inner,
presence: self.presence,
depth: self.depth,
})
}
}
struct RecordingMap<'p, A> {
inner: A,
presence: &'p mut Presence,
depth: usize,
}
impl<'de, A: MapAccess<'de>> MapAccess<'de> for RecordingMap<'_, A> {
type Error = A::Error;
fn next_key_seed<K: DeserializeSeed<'de>>(
&mut self,
seed: K,
) -> Result<Option<K::Value>, A::Error> {
let Some(key) = self.inner.next_key::<String>()? else {
return Ok(None);
};
self.presence.record(self.depth, &key, Held::Whole);
let key: StringDeserializer<A::Error> = key.into_deserializer();
seed.deserialize(key).map(Some)
}
fn next_value_seed<S: DeserializeSeed<'de>>(&mut self, seed: S) -> Result<S::Value, A::Error> {
self.inner.next_value_seed(RecordingSeed {
seed,
presence: self.presence,
depth: self.depth + 1,
})
}
fn size_hint(&self) -> Option<usize> {
self.inner.size_hint()
}
}
struct RecordingSeed<'p, S> {
seed: S,
presence: &'p mut Presence,
depth: usize,
}
impl<'de, S: DeserializeSeed<'de>> DeserializeSeed<'de> for RecordingSeed<'_, S> {
type Value = S::Value;
fn deserialize<D: Deserializer<'de>>(self, inner: D) -> Result<S::Value, D::Error> {
self.seed.deserialize(Recording {
inner,
presence: self.presence,
depth: self.depth,
})
}
}
pub(super) struct OneEntry<'k, D> {
pub(super) key: &'k str,
pub(super) value: D,
}
impl<'de, D: Deserializer<'de>> Deserializer<'de> for OneEntry<'_, D> {
type Error = D::Error;
fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, D::Error> {
visitor.visit_map(OneEntryAccess {
key: Some(self.key),
value: Some(self.value),
})
}
serde::forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any
}
}
struct OneEntryAccess<'k, D> {
key: Option<&'k str>,
value: Option<D>,
}
impl<'de, D: Deserializer<'de>> MapAccess<'de> for OneEntryAccess<'_, D> {
type Error = D::Error;
fn next_key_seed<K: DeserializeSeed<'de>>(
&mut self,
seed: K,
) -> Result<Option<K::Value>, D::Error> {
match self.key.take() {
Some(key) => seed
.deserialize(de::value::StrDeserializer::<D::Error>::new(key))
.map(Some),
None => Ok(None),
}
}
fn next_value_seed<S: DeserializeSeed<'de>>(&mut self, seed: S) -> Result<S::Value, D::Error> {
let value = self
.value
.take()
.expect("serde reads a value only after its key");
seed.deserialize(value)
}
fn size_hint(&self) -> Option<usize> {
Some(usize::from(self.key.is_some()))
}
}