From: Ian Jackson Date: Tue, 17 Nov 2020 18:42:34 +0000 (+0000) Subject: wip toml X-Git-Tag: otter-0.2.0~501 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=4fcd2cdfc407d0363ea0dc17079d80a314b72439;p=otter.git wip toml Signed-off-by: Ian Jackson --- diff --git a/src/lib.rs b/src/lib.rs index 8bf731e7..95f54306 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,4 +27,5 @@ pub mod shapelib; pub mod tz; pub mod accounts; pub mod config; +pub mod toml; #[path="slotmap-slot-idx.rs"] pub mod slotmap_slot_idx; diff --git a/src/toml.rs b/src/toml.rs new file mode 100644 index 00000000..8a605624 --- /dev/null +++ b/src/toml.rs @@ -0,0 +1,85 @@ +// Copyright 2020 Ian Jackson +// SPDX-License-Identifier: AGPL-3.0-or-later +// There is NO WARRANTY. + +use std::fmt::{self, Display}; +use std::iter::Peekable; + +use fehler::throws; +use serde::de::{Deserializer, DeserializeSeed, MapAccess, SeqAccess, Visitor}; +use thiserror::Error; + +#[derive(Error,Debug)] +enum Error { + Custom(Box), +} + +impl Display for Error { + #[throws(fmt::Error)] + fn fmt(&self, f: &mut fmt::Formatter) { + type E = Error; + match self { + E::Custom(x) => write!(f, "toml::TomlDe::Error::Custom:{}", x)?, + } + } +} + +impl serde::de::Error for Error { + fn custom(x: X) -> Self { Error::Custom(Box::new(x)) } +} + +pub struct TomlDe<'de>(pub &'de toml::Value); + +struct SA<'de> (&'de [toml::Value]); + +impl<'de> SeqAccess<'de> for SA<'de> { + type Error = Error; + #[throws(Error)] + fn next_element_seed> + (&mut self, seed: T) -> Option + { + let elem = (self.0).next()?; + Some(seed.deserialize(elem)?) + } + fn size_hint(&self) -> Option { + Some(self.0.len()) + } +} + +struct MA<'de> (Peekable>); + +impl<'de> MapAccess<'de> for MA<'de> { + type Error = Error; + #[throws(Error)] + fn next_key_seed> + (&mut self, seed: K) -> Option + { + let (k, _v) = self.0.peek()?; + Some(seed.deserialize(k)?) + } + #[throws(Error)] + fn next_value_seed> + (&mut self, seed: V) -> V::Value + { + let (_k, v) = self.0.next().unwrap(); + seed.deserialize(v)? + } +} + +#[throws(Error)] +fn visit<'de, V: Visitor<'de>>(v: &V, tv: &toml::Value) -> V::Value { + type TV = toml::Value; + match tv { + TV::String(s) => v.visit_borrowed_str(s)?, + TV::Array(a) => v.visit_seq(SA(a.as_slice()))?, + TV::Table(t) => v.visit_table(MA(t.iter().peekable()))?, + } +} + +impl<'de> Deserializer<'de> for TomlDe<'de> { + type Error = Error; + #[throws(Error)] + fn deserialize_any>(self, visitor: V) -> V::Value { + visit(visitor, &self.0); + } +}