feat: add display UI with splash screen, dashboard, and RSSI sparkline
Implement full SSD1306 OLED display support: - Splash screen on boot (1.5s) with project name, version, board - Dashboard showing radio state, config, counters, RSSI/SNR - RSSI history sparkline (64-sample ring buffer, 2px-wide bars) - DisplayOn/DisplayOff host commands routed via dedicated channel - Pure render functions against generic DrawTarget (no hardware coupling) - Display on/off control bypasses radio task entirely Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
17624 files changed
+4564928
-38
No files matched your search
+97
@@ -0,0 +1,97 @@
|
||||
use crate::de::Error;
|
||||
|
||||
pub(crate) struct ArrayDeserializer {
|
||||
input: Vec<crate::Item>,
|
||||
span: Option<std::ops::Range<usize>>,
|
||||
}
|
||||
|
||||
impl ArrayDeserializer {
|
||||
pub(crate) fn new(input: Vec<crate::Item>, span: Option<std::ops::Range<usize>>) -> Self {
|
||||
Self { input, span }
|
||||
}
|
||||
}
|
||||
|
||||
// Note: this is wrapped by `ValueDeserializer` and any trait methods
|
||||
// implemented here need to be wrapped there
|
||||
impl<'de> serde::Deserializer<'de> for ArrayDeserializer {
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_seq(ArraySeqAccess::new(self.input))
|
||||
}
|
||||
|
||||
fn deserialize_struct<V>(
|
||||
self,
|
||||
name: &'static str,
|
||||
fields: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
if serde_spanned::__unstable::is_spanned(name, fields) {
|
||||
if let Some(span) = self.span.clone() {
|
||||
return visitor.visit_map(super::SpannedDeserializer::new(self, span));
|
||||
}
|
||||
}
|
||||
|
||||
self.deserialize_any(visitor)
|
||||
}
|
||||
|
||||
serde::forward_to_deserialize_any! {
|
||||
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
|
||||
bytes byte_buf map option unit newtype_struct
|
||||
ignored_any unit_struct tuple_struct tuple enum identifier
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::de::IntoDeserializer<'_, Error> for ArrayDeserializer {
|
||||
type Deserializer = Self;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Array {
|
||||
pub(crate) fn into_deserializer(self) -> ArrayDeserializer {
|
||||
ArrayDeserializer::new(self.values, self.span)
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ArrayOfTables {
|
||||
pub(crate) fn into_deserializer(self) -> ArrayDeserializer {
|
||||
ArrayDeserializer::new(self.values, self.span)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ArraySeqAccess {
|
||||
iter: std::vec::IntoIter<crate::Item>,
|
||||
}
|
||||
|
||||
impl ArraySeqAccess {
|
||||
pub(crate) fn new(input: Vec<crate::Item>) -> Self {
|
||||
Self {
|
||||
iter: input.into_iter(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::de::SeqAccess<'de> for ArraySeqAccess {
|
||||
type Error = Error;
|
||||
|
||||
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
|
||||
where
|
||||
T: serde::de::DeserializeSeed<'de>,
|
||||
{
|
||||
match self.iter.next() {
|
||||
Some(v) => seed
|
||||
.deserialize(crate::de::ValueDeserializer::new(v))
|
||||
.map(Some),
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
use serde::de::value::BorrowedStrDeserializer;
|
||||
use serde::de::IntoDeserializer;
|
||||
|
||||
use crate::de::Error;
|
||||
|
||||
pub(crate) struct DatetimeDeserializer {
|
||||
date: Option<crate::Datetime>,
|
||||
}
|
||||
|
||||
impl DatetimeDeserializer {
|
||||
pub(crate) fn new(date: crate::Datetime) -> Self {
|
||||
Self { date: Some(date) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::de::MapAccess<'de> for DatetimeDeserializer {
|
||||
type Error = Error;
|
||||
|
||||
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error>
|
||||
where
|
||||
K: serde::de::DeserializeSeed<'de>,
|
||||
{
|
||||
if self.date.is_some() {
|
||||
seed.deserialize(BorrowedStrDeserializer::new(
|
||||
toml_datetime::__unstable::FIELD,
|
||||
))
|
||||
.map(Some)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error>
|
||||
where
|
||||
V: serde::de::DeserializeSeed<'de>,
|
||||
{
|
||||
if let Some(date) = self.date.take() {
|
||||
seed.deserialize(date.to_string().into_deserializer())
|
||||
} else {
|
||||
panic!("next_value_seed called before next_key_seed")
|
||||
}
|
||||
}
|
||||
}
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
use serde::de::IntoDeserializer;
|
||||
|
||||
use super::Error;
|
||||
|
||||
pub(crate) struct KeyDeserializer {
|
||||
span: Option<std::ops::Range<usize>>,
|
||||
key: crate::Key,
|
||||
}
|
||||
|
||||
impl KeyDeserializer {
|
||||
pub(crate) fn new(key: crate::Key, span: Option<std::ops::Range<usize>>) -> Self {
|
||||
KeyDeserializer { span, key }
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDeserializer<'_, Error> for KeyDeserializer {
|
||||
type Deserializer = Self;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::de::Deserializer<'de> for KeyDeserializer {
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.key.into_deserializer().deserialize_any(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_enum<V>(
|
||||
self,
|
||||
name: &str,
|
||||
variants: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
let _ = name;
|
||||
let _ = variants;
|
||||
visitor.visit_enum(self)
|
||||
}
|
||||
|
||||
fn deserialize_struct<V>(
|
||||
self,
|
||||
name: &'static str,
|
||||
fields: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
if serde_spanned::__unstable::is_spanned(name, fields) {
|
||||
if let Some(span) = self.span.clone() {
|
||||
return visitor.visit_map(super::SpannedDeserializer::new(self.key.get(), span));
|
||||
}
|
||||
}
|
||||
self.deserialize_any(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_newtype_struct<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_newtype_struct(self)
|
||||
}
|
||||
|
||||
serde::forward_to_deserialize_any! {
|
||||
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
|
||||
bytes byte_buf map option unit
|
||||
ignored_any unit_struct tuple_struct tuple identifier
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::de::EnumAccess<'de> for KeyDeserializer {
|
||||
type Error = Error;
|
||||
type Variant = UnitOnly<Self::Error>;
|
||||
|
||||
fn variant_seed<T>(self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error>
|
||||
where
|
||||
T: serde::de::DeserializeSeed<'de>,
|
||||
{
|
||||
seed.deserialize(self).map(unit_only)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct UnitOnly<E> {
|
||||
marker: std::marker::PhantomData<E>,
|
||||
}
|
||||
|
||||
fn unit_only<T, E>(t: T) -> (T, UnitOnly<E>) {
|
||||
(
|
||||
t,
|
||||
UnitOnly {
|
||||
marker: std::marker::PhantomData,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
impl<'de, E> serde::de::VariantAccess<'de> for UnitOnly<E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
type Error = E;
|
||||
|
||||
fn unit_variant(self) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value, Self::Error>
|
||||
where
|
||||
T: serde::de::DeserializeSeed<'de>,
|
||||
{
|
||||
Err(serde::de::Error::invalid_type(
|
||||
serde::de::Unexpected::UnitVariant,
|
||||
&"newtype variant",
|
||||
))
|
||||
}
|
||||
|
||||
fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
Err(serde::de::Error::invalid_type(
|
||||
serde::de::Unexpected::UnitVariant,
|
||||
&"tuple variant",
|
||||
))
|
||||
}
|
||||
|
||||
fn struct_variant<V>(
|
||||
self,
|
||||
_fields: &'static [&'static str],
|
||||
_visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
Err(serde::de::Error::invalid_type(
|
||||
serde::de::Unexpected::UnitVariant,
|
||||
&"struct variant",
|
||||
))
|
||||
}
|
||||
}
|
||||
+327
@@ -0,0 +1,327 @@
|
||||
//! Deserializing TOML into Rust structures.
|
||||
//!
|
||||
//! This module contains all the Serde support for deserializing TOML documents into Rust structures.
|
||||
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
mod array;
|
||||
mod datetime;
|
||||
mod key;
|
||||
mod spanned;
|
||||
mod table;
|
||||
mod table_enum;
|
||||
mod value;
|
||||
|
||||
use array::ArrayDeserializer;
|
||||
use datetime::DatetimeDeserializer;
|
||||
use key::KeyDeserializer;
|
||||
use spanned::SpannedDeserializer;
|
||||
use table_enum::TableEnumDeserializer;
|
||||
|
||||
pub use value::ValueDeserializer;
|
||||
|
||||
/// Errors that can occur when deserializing a type.
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct Error {
|
||||
inner: crate::TomlError,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub(crate) fn custom<T>(msg: T, span: Option<std::ops::Range<usize>>) -> Self
|
||||
where
|
||||
T: std::fmt::Display,
|
||||
{
|
||||
Error {
|
||||
inner: crate::TomlError::custom(msg.to_string(), span),
|
||||
}
|
||||
}
|
||||
|
||||
/// Add key while unwinding
|
||||
pub fn add_key(&mut self, key: String) {
|
||||
self.inner.add_key(key);
|
||||
}
|
||||
|
||||
/// What went wrong
|
||||
pub fn message(&self) -> &str {
|
||||
self.inner.message()
|
||||
}
|
||||
|
||||
/// The start/end index into the original document where the error occurred
|
||||
pub fn span(&self) -> Option<std::ops::Range<usize>> {
|
||||
self.inner.span()
|
||||
}
|
||||
|
||||
pub(crate) fn set_span(&mut self, span: Option<std::ops::Range<usize>>) {
|
||||
self.inner.set_span(span);
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::de::Error for Error {
|
||||
fn custom<T>(msg: T) -> Self
|
||||
where
|
||||
T: std::fmt::Display,
|
||||
{
|
||||
Error::custom(msg, None)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.inner.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.inner.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::TomlError> for Error {
|
||||
fn from(e: crate::TomlError) -> Error {
|
||||
Self { inner: e }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for crate::TomlError {
|
||||
fn from(e: Error) -> crate::TomlError {
|
||||
e.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {}
|
||||
|
||||
/// Convert a TOML [documents][crate::DocumentMut] into `T`.
|
||||
#[cfg(feature = "parse")]
|
||||
pub fn from_str<T>(s: &'_ str) -> Result<T, Error>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
let de = Deserializer::parse(s)?;
|
||||
T::deserialize(de)
|
||||
}
|
||||
|
||||
/// Convert a TOML [documents][crate::DocumentMut] into `T`.
|
||||
#[cfg(feature = "parse")]
|
||||
pub fn from_slice<T>(s: &'_ [u8]) -> Result<T, Error>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
let s = std::str::from_utf8(s).map_err(|e| Error::custom(e, None))?;
|
||||
from_str(s)
|
||||
}
|
||||
|
||||
/// Convert a [`DocumentMut`][crate::DocumentMut] into `T`.
|
||||
pub fn from_document<T>(d: impl Into<Deserializer>) -> Result<T, Error>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
let deserializer = d.into();
|
||||
T::deserialize(deserializer)
|
||||
}
|
||||
|
||||
/// Deserialization for TOML [documents][crate::DocumentMut].
|
||||
pub struct Deserializer<S = String> {
|
||||
root: crate::Item,
|
||||
raw: Option<S>,
|
||||
}
|
||||
|
||||
impl Deserializer {
|
||||
/// Deserialization implementation for TOML.
|
||||
#[deprecated(since = "0.22.6", note = "Replaced with `Deserializer::from`")]
|
||||
pub fn new(input: crate::DocumentMut) -> Self {
|
||||
Self::from(input)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parse")]
|
||||
impl<S: AsRef<str>> Deserializer<S> {
|
||||
/// Parse a TOML document
|
||||
pub fn parse(raw: S) -> Result<Self, Error> {
|
||||
crate::ImDocument::parse(raw)
|
||||
.map(Self::from)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::DocumentMut> for Deserializer {
|
||||
fn from(doc: crate::DocumentMut) -> Self {
|
||||
let crate::DocumentMut { root, .. } = doc;
|
||||
Self { root, raw: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> From<crate::ImDocument<S>> for Deserializer<S> {
|
||||
fn from(doc: crate::ImDocument<S>) -> Self {
|
||||
let crate::ImDocument { root, raw, .. } = doc;
|
||||
let raw = Some(raw);
|
||||
Self { root, raw }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parse")]
|
||||
impl std::str::FromStr for Deserializer {
|
||||
type Err = Error;
|
||||
|
||||
/// Parses a document from a &str
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let doc: crate::ImDocument<_> = s.parse().map_err(Error::from)?;
|
||||
Ok(Deserializer::from(doc))
|
||||
}
|
||||
}
|
||||
|
||||
// Note: this is wrapped by `toml::de::Deserializer` and any trait methods
|
||||
// implemented here need to be wrapped there
|
||||
impl<'de, S: Into<String>> serde::Deserializer<'de> for Deserializer<S> {
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
let raw = self.raw;
|
||||
self.root
|
||||
.into_deserializer()
|
||||
.deserialize_any(visitor)
|
||||
.map_err(|mut e: Self::Error| {
|
||||
e.inner.set_raw(raw.map(|r| r.into()));
|
||||
e
|
||||
})
|
||||
}
|
||||
|
||||
// `None` is interpreted as a missing field so be sure to implement `Some`
|
||||
// as a present field.
|
||||
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
let raw = self.raw;
|
||||
self.root
|
||||
.into_deserializer()
|
||||
.deserialize_option(visitor)
|
||||
.map_err(|mut e: Self::Error| {
|
||||
e.inner.set_raw(raw.map(|r| r.into()));
|
||||
e
|
||||
})
|
||||
}
|
||||
|
||||
fn deserialize_newtype_struct<V>(
|
||||
self,
|
||||
name: &'static str,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
let raw = self.raw;
|
||||
self.root
|
||||
.into_deserializer()
|
||||
.deserialize_newtype_struct(name, visitor)
|
||||
.map_err(|mut e: Self::Error| {
|
||||
e.inner.set_raw(raw.map(|r| r.into()));
|
||||
e
|
||||
})
|
||||
}
|
||||
|
||||
fn deserialize_struct<V>(
|
||||
self,
|
||||
name: &'static str,
|
||||
fields: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
let raw = self.raw;
|
||||
self.root
|
||||
.into_deserializer()
|
||||
.deserialize_struct(name, fields, visitor)
|
||||
.map_err(|mut e: Self::Error| {
|
||||
e.inner.set_raw(raw.map(|r| r.into()));
|
||||
e
|
||||
})
|
||||
}
|
||||
|
||||
// Called when the type to deserialize is an enum, as opposed to a field in the type.
|
||||
fn deserialize_enum<V>(
|
||||
self,
|
||||
name: &'static str,
|
||||
variants: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
let raw = self.raw;
|
||||
self.root
|
||||
.into_deserializer()
|
||||
.deserialize_enum(name, variants, visitor)
|
||||
.map_err(|mut e: Self::Error| {
|
||||
e.inner.set_raw(raw.map(|r| r.into()));
|
||||
e
|
||||
})
|
||||
}
|
||||
|
||||
serde::forward_to_deserialize_any! {
|
||||
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
|
||||
bytes byte_buf map unit
|
||||
ignored_any unit_struct tuple_struct tuple identifier
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::de::IntoDeserializer<'_, Error> for Deserializer {
|
||||
type Deserializer = Deserializer;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::de::IntoDeserializer<'_, Error> for crate::DocumentMut {
|
||||
type Deserializer = Deserializer;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer {
|
||||
Deserializer::from(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::de::IntoDeserializer<'_, Error> for crate::ImDocument<String> {
|
||||
type Deserializer = Deserializer;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer {
|
||||
Deserializer::from(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn validate_struct_keys(
|
||||
table: &crate::table::KeyValuePairs,
|
||||
fields: &'static [&'static str],
|
||||
) -> Result<(), Error> {
|
||||
let extra_fields = table
|
||||
.keys()
|
||||
.filter_map(|key| {
|
||||
if !fields.contains(&key.get()) {
|
||||
Some(key.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if extra_fields.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::custom(
|
||||
format!(
|
||||
"unexpected keys in table: {}, available keys: {}",
|
||||
extra_fields
|
||||
.iter()
|
||||
.map(|k| k.get())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
fields.join(", "),
|
||||
),
|
||||
extra_fields[0].span(),
|
||||
))
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
use serde::de::value::BorrowedStrDeserializer;
|
||||
use serde::de::IntoDeserializer as _;
|
||||
|
||||
use super::Error;
|
||||
|
||||
pub(crate) struct SpannedDeserializer<'de, T: serde::de::IntoDeserializer<'de, Error>> {
|
||||
phantom_data: std::marker::PhantomData<&'de ()>,
|
||||
start: Option<usize>,
|
||||
end: Option<usize>,
|
||||
value: Option<T>,
|
||||
}
|
||||
|
||||
impl<'de, T> SpannedDeserializer<'de, T>
|
||||
where
|
||||
T: serde::de::IntoDeserializer<'de, Error>,
|
||||
{
|
||||
pub(crate) fn new(value: T, span: std::ops::Range<usize>) -> Self {
|
||||
Self {
|
||||
phantom_data: Default::default(),
|
||||
start: Some(span.start),
|
||||
end: Some(span.end),
|
||||
value: Some(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T> serde::de::MapAccess<'de> for SpannedDeserializer<'de, T>
|
||||
where
|
||||
T: serde::de::IntoDeserializer<'de, Error>,
|
||||
{
|
||||
type Error = Error;
|
||||
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error>
|
||||
where
|
||||
K: serde::de::DeserializeSeed<'de>,
|
||||
{
|
||||
if self.start.is_some() {
|
||||
seed.deserialize(BorrowedStrDeserializer::new(
|
||||
serde_spanned::__unstable::START_FIELD,
|
||||
))
|
||||
.map(Some)
|
||||
} else if self.end.is_some() {
|
||||
seed.deserialize(BorrowedStrDeserializer::new(
|
||||
serde_spanned::__unstable::END_FIELD,
|
||||
))
|
||||
.map(Some)
|
||||
} else if self.value.is_some() {
|
||||
seed.deserialize(BorrowedStrDeserializer::new(
|
||||
serde_spanned::__unstable::VALUE_FIELD,
|
||||
))
|
||||
.map(Some)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error>
|
||||
where
|
||||
V: serde::de::DeserializeSeed<'de>,
|
||||
{
|
||||
if let Some(start) = self.start.take() {
|
||||
seed.deserialize(start.into_deserializer())
|
||||
} else if let Some(end) = self.end.take() {
|
||||
seed.deserialize(end.into_deserializer())
|
||||
} else if let Some(value) = self.value.take() {
|
||||
seed.deserialize(value.into_deserializer())
|
||||
} else {
|
||||
panic!("next_value_seed called before next_key_seed")
|
||||
}
|
||||
}
|
||||
}
|
||||
+214
@@ -0,0 +1,214 @@
|
||||
use serde::de::IntoDeserializer;
|
||||
|
||||
use crate::de::Error;
|
||||
|
||||
pub(crate) struct TableDeserializer {
|
||||
span: Option<std::ops::Range<usize>>,
|
||||
items: crate::table::KeyValuePairs,
|
||||
}
|
||||
|
||||
// Note: this is wrapped by `Deserializer` and `ValueDeserializer` and any trait methods
|
||||
// implemented here need to be wrapped there
|
||||
impl<'de> serde::Deserializer<'de> for TableDeserializer {
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_map(TableMapAccess::new(self))
|
||||
}
|
||||
|
||||
// `None` is interpreted as a missing field so be sure to implement `Some`
|
||||
// as a present field.
|
||||
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_some(self)
|
||||
}
|
||||
|
||||
fn deserialize_newtype_struct<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_newtype_struct(self)
|
||||
}
|
||||
|
||||
fn deserialize_struct<V>(
|
||||
self,
|
||||
name: &'static str,
|
||||
fields: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
if serde_spanned::__unstable::is_spanned(name, fields) {
|
||||
if let Some(span) = self.span.clone() {
|
||||
return visitor.visit_map(super::SpannedDeserializer::new(self, span));
|
||||
}
|
||||
}
|
||||
|
||||
self.deserialize_any(visitor)
|
||||
}
|
||||
|
||||
// Called when the type to deserialize is an enum, as opposed to a field in the type.
|
||||
fn deserialize_enum<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variants: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
if self.items.is_empty() {
|
||||
Err(Error::custom(
|
||||
"wanted exactly 1 element, found 0 elements",
|
||||
self.span,
|
||||
))
|
||||
} else if self.items.len() != 1 {
|
||||
Err(Error::custom(
|
||||
"wanted exactly 1 element, more than 1 element",
|
||||
self.span,
|
||||
))
|
||||
} else {
|
||||
visitor.visit_enum(TableMapAccess::new(self))
|
||||
}
|
||||
}
|
||||
|
||||
serde::forward_to_deserialize_any! {
|
||||
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
|
||||
bytes byte_buf map unit
|
||||
ignored_any unit_struct tuple_struct tuple identifier
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDeserializer<'_, Error> for TableDeserializer {
|
||||
type Deserializer = TableDeserializer;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Table {
|
||||
pub(crate) fn into_deserializer(self) -> TableDeserializer {
|
||||
TableDeserializer {
|
||||
span: self.span(),
|
||||
items: self.items,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::InlineTable {
|
||||
pub(crate) fn into_deserializer(self) -> TableDeserializer {
|
||||
TableDeserializer {
|
||||
span: self.span(),
|
||||
items: self.items,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct TableMapAccess {
|
||||
iter: indexmap::map::IntoIter<crate::Key, crate::Item>,
|
||||
span: Option<std::ops::Range<usize>>,
|
||||
value: Option<(crate::Key, crate::Item)>,
|
||||
}
|
||||
|
||||
impl TableMapAccess {
|
||||
pub(crate) fn new(input: TableDeserializer) -> Self {
|
||||
Self {
|
||||
iter: input.items.into_iter(),
|
||||
span: input.span,
|
||||
value: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::de::MapAccess<'de> for TableMapAccess {
|
||||
type Error = Error;
|
||||
|
||||
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
|
||||
where
|
||||
K: serde::de::DeserializeSeed<'de>,
|
||||
{
|
||||
match self.iter.next() {
|
||||
Some((k, v)) => {
|
||||
let key_span = k.span();
|
||||
let ret = seed
|
||||
.deserialize(super::KeyDeserializer::new(k.clone(), key_span.clone()))
|
||||
.map(Some)
|
||||
.map_err(|mut e: Self::Error| {
|
||||
if e.span().is_none() {
|
||||
e.set_span(key_span);
|
||||
}
|
||||
e
|
||||
});
|
||||
self.value = Some((k, v));
|
||||
ret
|
||||
}
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::DeserializeSeed<'de>,
|
||||
{
|
||||
match self.value.take() {
|
||||
Some((k, v)) => {
|
||||
let span = v.span().or_else(|| k.span());
|
||||
seed.deserialize(crate::de::ValueDeserializer::new(v))
|
||||
.map_err(|mut e: Self::Error| {
|
||||
if e.span().is_none() {
|
||||
e.set_span(span);
|
||||
}
|
||||
e.add_key(k.get().to_owned());
|
||||
e
|
||||
})
|
||||
}
|
||||
None => {
|
||||
panic!("no more values in next_value_seed, internal error in ValueDeserializer")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::de::EnumAccess<'de> for TableMapAccess {
|
||||
type Error = Error;
|
||||
type Variant = super::TableEnumDeserializer;
|
||||
|
||||
fn variant_seed<V>(mut self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
|
||||
where
|
||||
V: serde::de::DeserializeSeed<'de>,
|
||||
{
|
||||
let (key, value) = match self.iter.next() {
|
||||
Some(pair) => pair,
|
||||
None => {
|
||||
return Err(Error::custom(
|
||||
"expected table with exactly 1 entry, found empty table",
|
||||
self.span,
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let val = seed
|
||||
.deserialize(key.into_deserializer())
|
||||
.map_err(|mut e: Self::Error| {
|
||||
if e.span().is_none() {
|
||||
e.set_span(key.span());
|
||||
}
|
||||
e
|
||||
})?;
|
||||
|
||||
let variant = super::TableEnumDeserializer::new(value);
|
||||
|
||||
Ok((val, variant))
|
||||
}
|
||||
}
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
use crate::de::Error;
|
||||
|
||||
/// Deserializes table values into enum variants.
|
||||
pub(crate) struct TableEnumDeserializer {
|
||||
value: crate::Item,
|
||||
}
|
||||
|
||||
impl TableEnumDeserializer {
|
||||
pub(crate) fn new(value: crate::Item) -> Self {
|
||||
TableEnumDeserializer { value }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::de::VariantAccess<'de> for TableEnumDeserializer {
|
||||
type Error = Error;
|
||||
|
||||
fn unit_variant(self) -> Result<(), Self::Error> {
|
||||
match self.value {
|
||||
crate::Item::ArrayOfTables(values) => {
|
||||
if values.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::custom("expected empty array", values.span()))
|
||||
}
|
||||
}
|
||||
crate::Item::Value(crate::Value::Array(values)) => {
|
||||
if values.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::custom("expected empty table", values.span()))
|
||||
}
|
||||
}
|
||||
crate::Item::Table(values) => {
|
||||
if values.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::custom("expected empty table", values.span()))
|
||||
}
|
||||
}
|
||||
crate::Item::Value(crate::Value::InlineTable(values)) => {
|
||||
if values.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::custom("expected empty table", values.span()))
|
||||
}
|
||||
}
|
||||
e => Err(Error::custom(
|
||||
format!("expected table, found {}", e.type_name()),
|
||||
e.span(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
|
||||
where
|
||||
T: serde::de::DeserializeSeed<'de>,
|
||||
{
|
||||
seed.deserialize(super::ValueDeserializer::new(self.value))
|
||||
}
|
||||
|
||||
fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
match self.value {
|
||||
crate::Item::ArrayOfTables(values) => {
|
||||
let values_span = values.span();
|
||||
let tuple_values = values.values.into_iter().collect::<Vec<_>>();
|
||||
|
||||
if tuple_values.len() == len {
|
||||
serde::de::Deserializer::deserialize_seq(
|
||||
super::ArrayDeserializer::new(tuple_values, values_span),
|
||||
visitor,
|
||||
)
|
||||
} else {
|
||||
Err(Error::custom(
|
||||
format!("expected tuple with length {len}"),
|
||||
values_span,
|
||||
))
|
||||
}
|
||||
}
|
||||
crate::Item::Value(crate::Value::Array(values)) => {
|
||||
let values_span = values.span();
|
||||
let tuple_values = values.values.into_iter().collect::<Vec<_>>();
|
||||
|
||||
if tuple_values.len() == len {
|
||||
serde::de::Deserializer::deserialize_seq(
|
||||
super::ArrayDeserializer::new(tuple_values, values_span),
|
||||
visitor,
|
||||
)
|
||||
} else {
|
||||
Err(Error::custom(
|
||||
format!("expected tuple with length {len}"),
|
||||
values_span,
|
||||
))
|
||||
}
|
||||
}
|
||||
crate::Item::Table(values) => {
|
||||
let values_span = values.span();
|
||||
let tuple_values: Result<Vec<_>, _> = values
|
||||
.items
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, (key, value))| match key.get().parse::<usize>() {
|
||||
Ok(key_index) if key_index == index => Ok(value),
|
||||
Ok(_) | Err(_) => Err(Error::custom(
|
||||
format!("expected table key `{}`, but was `{}`", index, key.get()),
|
||||
key.span(),
|
||||
)),
|
||||
})
|
||||
.collect();
|
||||
let tuple_values = tuple_values?;
|
||||
|
||||
if tuple_values.len() == len {
|
||||
serde::de::Deserializer::deserialize_seq(
|
||||
super::ArrayDeserializer::new(tuple_values, values_span),
|
||||
visitor,
|
||||
)
|
||||
} else {
|
||||
Err(Error::custom(
|
||||
format!("expected tuple with length {len}"),
|
||||
values_span,
|
||||
))
|
||||
}
|
||||
}
|
||||
crate::Item::Value(crate::Value::InlineTable(values)) => {
|
||||
let values_span = values.span();
|
||||
let tuple_values: Result<Vec<_>, _> = values
|
||||
.items
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, (key, value))| match key.get().parse::<usize>() {
|
||||
Ok(key_index) if key_index == index => Ok(value),
|
||||
Ok(_) | Err(_) => Err(Error::custom(
|
||||
format!("expected table key `{}`, but was `{}`", index, key.get()),
|
||||
key.span(),
|
||||
)),
|
||||
})
|
||||
.collect();
|
||||
let tuple_values = tuple_values?;
|
||||
|
||||
if tuple_values.len() == len {
|
||||
serde::de::Deserializer::deserialize_seq(
|
||||
super::ArrayDeserializer::new(tuple_values, values_span),
|
||||
visitor,
|
||||
)
|
||||
} else {
|
||||
Err(Error::custom(
|
||||
format!("expected tuple with length {len}"),
|
||||
values_span,
|
||||
))
|
||||
}
|
||||
}
|
||||
e => Err(Error::custom(
|
||||
format!("expected table, found {}", e.type_name()),
|
||||
e.span(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn struct_variant<V>(
|
||||
self,
|
||||
fields: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
serde::de::Deserializer::deserialize_struct(
|
||||
super::ValueDeserializer::new(self.value).with_struct_key_validation(),
|
||||
"", // TODO: this should be the variant name
|
||||
fields,
|
||||
visitor,
|
||||
)
|
||||
}
|
||||
}
|
||||
+257
@@ -0,0 +1,257 @@
|
||||
use serde::de::IntoDeserializer as _;
|
||||
|
||||
use crate::de::DatetimeDeserializer;
|
||||
use crate::de::Error;
|
||||
|
||||
/// Deserialization implementation for TOML [values][crate::Value].
|
||||
///
|
||||
/// Can be created either directly from TOML strings, using [`std::str::FromStr`],
|
||||
/// or from parsed [values][crate::Value] using [`serde::de::IntoDeserializer::into_deserializer`].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # #[cfg(feature = "parse")] {
|
||||
/// # #[cfg(feature = "display")] {
|
||||
/// use serde::Deserialize;
|
||||
///
|
||||
/// #[derive(Deserialize)]
|
||||
/// struct Config {
|
||||
/// title: String,
|
||||
/// owner: Owner,
|
||||
/// }
|
||||
///
|
||||
/// #[derive(Deserialize)]
|
||||
/// struct Owner {
|
||||
/// name: String,
|
||||
/// }
|
||||
///
|
||||
/// let value = r#"{ title = 'TOML Example', owner = { name = 'Lisa' } }"#;
|
||||
/// let deserializer = value.parse::<toml_edit::de::ValueDeserializer>().unwrap();
|
||||
/// let config = Config::deserialize(deserializer).unwrap();
|
||||
/// assert_eq!(config.title, "TOML Example");
|
||||
/// assert_eq!(config.owner.name, "Lisa");
|
||||
/// # }
|
||||
/// # }
|
||||
/// ```
|
||||
pub struct ValueDeserializer {
|
||||
input: crate::Item,
|
||||
validate_struct_keys: bool,
|
||||
}
|
||||
|
||||
impl ValueDeserializer {
|
||||
pub(crate) fn new(input: crate::Item) -> Self {
|
||||
Self {
|
||||
input,
|
||||
validate_struct_keys: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn with_struct_key_validation(mut self) -> Self {
|
||||
self.validate_struct_keys = true;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
// Note: this is wrapped by `toml::de::ValueDeserializer` and any trait methods
|
||||
// implemented here need to be wrapped there
|
||||
impl<'de> serde::Deserializer<'de> for ValueDeserializer {
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
let span = self.input.span();
|
||||
match self.input {
|
||||
crate::Item::None => visitor.visit_none(),
|
||||
crate::Item::Value(crate::Value::String(v)) => visitor.visit_string(v.into_value()),
|
||||
crate::Item::Value(crate::Value::Integer(v)) => visitor.visit_i64(v.into_value()),
|
||||
crate::Item::Value(crate::Value::Float(v)) => visitor.visit_f64(v.into_value()),
|
||||
crate::Item::Value(crate::Value::Boolean(v)) => visitor.visit_bool(v.into_value()),
|
||||
crate::Item::Value(crate::Value::Datetime(v)) => {
|
||||
visitor.visit_map(DatetimeDeserializer::new(v.into_value()))
|
||||
}
|
||||
crate::Item::Value(crate::Value::Array(v)) => {
|
||||
v.into_deserializer().deserialize_any(visitor)
|
||||
}
|
||||
crate::Item::Value(crate::Value::InlineTable(v)) => {
|
||||
v.into_deserializer().deserialize_any(visitor)
|
||||
}
|
||||
crate::Item::Table(v) => v.into_deserializer().deserialize_any(visitor),
|
||||
crate::Item::ArrayOfTables(v) => v.into_deserializer().deserialize_any(visitor),
|
||||
}
|
||||
.map_err(|mut e: Self::Error| {
|
||||
if e.span().is_none() {
|
||||
e.set_span(span);
|
||||
}
|
||||
e
|
||||
})
|
||||
}
|
||||
|
||||
// `None` is interpreted as a missing field so be sure to implement `Some`
|
||||
// as a present field.
|
||||
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
let span = self.input.span();
|
||||
visitor.visit_some(self).map_err(|mut e: Self::Error| {
|
||||
if e.span().is_none() {
|
||||
e.set_span(span);
|
||||
}
|
||||
e
|
||||
})
|
||||
}
|
||||
|
||||
fn deserialize_newtype_struct<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
let span = self.input.span();
|
||||
visitor
|
||||
.visit_newtype_struct(self)
|
||||
.map_err(|mut e: Self::Error| {
|
||||
if e.span().is_none() {
|
||||
e.set_span(span);
|
||||
}
|
||||
e
|
||||
})
|
||||
}
|
||||
|
||||
fn deserialize_struct<V>(
|
||||
self,
|
||||
name: &'static str,
|
||||
fields: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
if serde_spanned::__unstable::is_spanned(name, fields) {
|
||||
if let Some(span) = self.input.span() {
|
||||
return visitor.visit_map(super::SpannedDeserializer::new(self, span));
|
||||
}
|
||||
}
|
||||
|
||||
if name == toml_datetime::__unstable::NAME && fields == [toml_datetime::__unstable::FIELD] {
|
||||
let span = self.input.span();
|
||||
if let crate::Item::Value(crate::Value::Datetime(d)) = self.input {
|
||||
return visitor
|
||||
.visit_map(DatetimeDeserializer::new(d.into_value()))
|
||||
.map_err(|mut e: Self::Error| {
|
||||
if e.span().is_none() {
|
||||
e.set_span(span);
|
||||
}
|
||||
e
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if self.validate_struct_keys {
|
||||
let span = self.input.span();
|
||||
match &self.input {
|
||||
crate::Item::Table(values) => super::validate_struct_keys(&values.items, fields),
|
||||
crate::Item::Value(crate::Value::InlineTable(values)) => {
|
||||
super::validate_struct_keys(&values.items, fields)
|
||||
}
|
||||
_ => Ok(()),
|
||||
}
|
||||
.map_err(|mut e: Self::Error| {
|
||||
if e.span().is_none() {
|
||||
e.set_span(span);
|
||||
}
|
||||
e
|
||||
})?;
|
||||
}
|
||||
|
||||
self.deserialize_any(visitor)
|
||||
}
|
||||
|
||||
// Called when the type to deserialize is an enum, as opposed to a field in the type.
|
||||
fn deserialize_enum<V>(
|
||||
self,
|
||||
name: &'static str,
|
||||
variants: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
let span = self.input.span();
|
||||
match self.input {
|
||||
crate::Item::Value(crate::Value::String(v)) => {
|
||||
visitor.visit_enum(v.into_value().into_deserializer())
|
||||
}
|
||||
crate::Item::Value(crate::Value::InlineTable(v)) => {
|
||||
if v.is_empty() {
|
||||
Err(Error::custom(
|
||||
"wanted exactly 1 element, found 0 elements",
|
||||
v.span(),
|
||||
))
|
||||
} else if v.len() != 1 {
|
||||
Err(Error::custom(
|
||||
"wanted exactly 1 element, more than 1 element",
|
||||
v.span(),
|
||||
))
|
||||
} else {
|
||||
v.into_deserializer()
|
||||
.deserialize_enum(name, variants, visitor)
|
||||
}
|
||||
}
|
||||
crate::Item::Table(v) => v
|
||||
.into_deserializer()
|
||||
.deserialize_enum(name, variants, visitor),
|
||||
e => Err(Error::custom("wanted string or table", e.span())),
|
||||
}
|
||||
.map_err(|mut e: Self::Error| {
|
||||
if e.span().is_none() {
|
||||
e.set_span(span);
|
||||
}
|
||||
e
|
||||
})
|
||||
}
|
||||
|
||||
serde::forward_to_deserialize_any! {
|
||||
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
|
||||
bytes byte_buf map unit
|
||||
ignored_any unit_struct tuple_struct tuple identifier
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::de::IntoDeserializer<'_, Error> for ValueDeserializer {
|
||||
type Deserializer = Self;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::de::IntoDeserializer<'_, Error> for crate::Value {
|
||||
type Deserializer = ValueDeserializer;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer {
|
||||
ValueDeserializer::new(crate::Item::Value(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Item {
|
||||
pub(crate) fn into_deserializer(self) -> ValueDeserializer {
|
||||
ValueDeserializer::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parse")]
|
||||
impl std::str::FromStr for ValueDeserializer {
|
||||
type Err = Error;
|
||||
|
||||
/// Parses a value from a &str
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let value = s.parse::<crate::Value>().map_err(Error::from)?;
|
||||
Ok(value.into_deserializer())
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user