use crate::{ConfSerde, ConfSerdeContext, IdentString, InnerError};
use core::fmt;
use serde::de::{Deserialize, DeserializeSeed, Deserializer};
#[doc(hidden)]
pub trait NextValueProducer<'de>: Sized {
type Error: serde::de::Error;
fn next_value_seed<S>(self, seed: S) -> Result<S::Value, Self::Error>
where
S: DeserializeSeed<'de>;
fn next_value<V>(self) -> Result<V, Self::Error>
where
V: Deserialize<'de>,
{
self.next_value_seed(core::marker::PhantomData)
}
}
impl<'de, MA> NextValueProducer<'de> for &mut MA
where
MA: serde::de::MapAccess<'de>,
{
type Error = MA::Error;
fn next_value_seed<S>(self, seed: S) -> Result<S::Value, Self::Error>
where
S: DeserializeSeed<'de>,
{
MA::next_value_seed(self, seed)
}
}
#[doc(hidden)]
pub trait InitializationStateMachine<'de>: Sized {
type Value;
fn wants_key(&self, key: &str) -> bool;
fn next<NVP>(self, key: &str, next_value_producer: NVP) -> Self
where
NVP: NextValueProducer<'de>;
fn finalize(self) -> Result<Self::Value, Vec<InnerError>>;
fn needs_finalize(&self) -> bool;
}
#[doc(hidden)]
pub struct AsVisitor<M> {
pub machine: M,
pub expecting_fn: fn(&mut fmt::Formatter) -> fmt::Result,
}
impl<'de, M> serde::de::Visitor<'de> for AsVisitor<M>
where
M: InitializationStateMachine<'de>,
{
type Value = Result<M::Value, Vec<InnerError>>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
(self.expecting_fn)(f)
}
fn visit_map<MA>(self, mut map_access: MA) -> Result<Self::Value, MA::Error>
where
MA: serde::de::MapAccess<'de>,
{
let Self { mut machine, .. } = self;
while let Some(key) = map_access.next_key::<IdentString>()? {
machine = machine.next(key.as_str(), &mut map_access);
}
Ok(machine.finalize())
}
}
pub struct ConfSerdeSeed<'a, V> {
ctxt: ConfSerdeContext<'a>,
_marker: core::marker::PhantomData<fn() -> V>,
}
impl<'a, V> From<ConfSerdeContext<'a>> for ConfSerdeSeed<'a, V> {
fn from(ctxt: ConfSerdeContext<'a>) -> Self {
Self {
ctxt,
_marker: Default::default(),
}
}
}
impl<'de, 'a, V> DeserializeSeed<'de> for ConfSerdeSeed<'a, V>
where
V: ConfSerde,
{
type Value = Result<V, Vec<InnerError>>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
let struct_name = V::STRUCT_NAME;
let expecting_fn = V::expecting;
let doc_name = self.ctxt.document_name;
let machine = V::ISM::<'a>::from(self.ctxt);
let visitor = AsVisitor {
machine,
expecting_fn,
};
let deserialize_result = if let Some(keys) = V::STRUCT_KEYS {
deserializer.deserialize_struct(struct_name, keys, visitor)
} else {
deserializer.deserialize_map(visitor)
};
Ok(match deserialize_result {
Ok(result) => result,
Err(err) => Err(vec![InnerError::serde(doc_name, struct_name, err)]),
})
}
}
#[doc(hidden)]
pub struct PrefixStrippingStateMachine<'a, M> {
prefix: &'a str,
inner: M,
}
impl<'a, M> PrefixStrippingStateMachine<'a, M> {
pub fn new(prefix: &'a str, inner: M) -> Self {
Self { prefix, inner }
}
}
impl<'de, 'a, M> InitializationStateMachine<'de> for PrefixStrippingStateMachine<'a, M>
where
M: InitializationStateMachine<'de>,
{
type Value = M::Value;
fn wants_key(&self, key: &str) -> bool {
if let Some(stripped_key) = key.strip_prefix(self.prefix) {
self.inner.wants_key(stripped_key)
} else {
false
}
}
fn next<NVP>(self, key: &str, next_value_producer: NVP) -> Self
where
NVP: NextValueProducer<'de>,
{
let stripped_key = key.strip_prefix(self.prefix).unwrap_or_else(|| {
panic!("key '{}' does not start with prefix '{}'", key, self.prefix)
});
Self {
prefix: self.prefix,
inner: self.inner.next(stripped_key, next_value_producer),
}
}
fn finalize(self) -> Result<Self::Value, Vec<InnerError>> {
self.inner.finalize()
}
fn needs_finalize(&self) -> bool {
self.inner.needs_finalize()
}
}
#[doc(hidden)]
pub struct OptionalStateMachine<M> {
inner: M,
received_key: bool,
}
impl<M> OptionalStateMachine<M> {
pub fn new(inner: M) -> Self {
Self {
inner,
received_key: false,
}
}
}
impl<'de, M> InitializationStateMachine<'de> for OptionalStateMachine<M>
where
M: InitializationStateMachine<'de>,
{
type Value = Option<M::Value>;
fn wants_key(&self, key: &str) -> bool {
self.inner.wants_key(key)
}
fn next<NVP>(self, key: &str, next_value_producer: NVP) -> Self
where
NVP: NextValueProducer<'de>,
{
Self {
inner: self.inner.next(key, next_value_producer),
received_key: true,
}
}
fn finalize(self) -> Result<Self::Value, Vec<InnerError>> {
if self.needs_finalize() {
self.inner.finalize().map(Some)
} else {
Ok(None)
}
}
fn needs_finalize(&self) -> bool {
self.received_key || self.inner.needs_finalize()
}
}