From 87048610bbfa45d7e2a1e265dd6bbccf8e931961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 12 Nov 2024 14:53:33 +0100 Subject: [PATCH] impls: add Result, Cow, RwLock, Mutex, Cell, RefCell --- CHANGELOG.md | 3 +- miniconf/Cargo.toml | 2 +- miniconf/src/impls.rs | 644 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 639 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a056e316..f7a75c3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -* `std` and `alloc` features and `Tree*` impls for `Box`, `Rc`, `Arc` +* `std` and `alloc` features and `Tree*` impls for `Box`, `Rc`, `Arc`, `Cow`, `Mutex`, + `RwLock`, `Cell`, `RefCell` ## [0.17.0](https://github.com/quartiq/miniconf/compare/v0.16.3...v0.17.0) - 2024-10-25 diff --git a/miniconf/Cargo.toml b/miniconf/Cargo.toml index c6a9edb5..713d56dc 100644 --- a/miniconf/Cargo.toml +++ b/miniconf/Cargo.toml @@ -23,7 +23,7 @@ postcard = { version = "1.0.8", optional = true } thiserror = { version = "2", default-features = false } [features] -default = ["derive"] +default = ["derive", "std"] json-core = ["dep:serde-json-core"] postcard = ["dep:postcard"] derive = ["dep:miniconf_derive", "serde/derive"] diff --git a/miniconf/src/impls.rs b/miniconf/src/impls.rs index cfbd5ca5..6c400e61 100644 --- a/miniconf/src/impls.rs +++ b/miniconf/src/impls.rs @@ -1,3 +1,4 @@ +use core::cell::{Cell, RefCell}; use core::{any::Any, num::NonZero}; use serde::{Deserializer, Serializer}; @@ -240,11 +241,265 @@ impl TreeAny for Option { ///////////////////////////////////////////////////////////////////////////////////////// +const RESULT_LOOKUP: KeyLookup = KeyLookup { + len: NonZero::::MIN.saturating_add(1), + names: Some(&["Ok", "Err"]), +}; + +impl TreeKey for Result { + #[inline] + fn traverse_all() -> Result { + W::internal() + .merge(&T::traverse_all()?, Some(0), &RESULT_LOOKUP)? + .merge(&E::traverse_all()?, Some(1), &RESULT_LOOKUP) + } + + #[inline] + fn traverse_by_key(mut keys: K, func: F) -> Result> + where + K: Keys, + F: FnMut(usize, Option<&'static str>, NonZero) -> Result<(), G>, + { + Error::increment_result(match keys.next(&RESULT_LOOKUP)? { + 0 => T::traverse_by_key(keys, func), + 1 => E::traverse_by_key(keys, func), + _ => unreachable!(), + }) + } +} + +impl TreeSerialize for Result { + #[inline] + fn serialize_by_key(&self, mut keys: K, ser: S) -> Result> + where + K: Keys, + S: Serializer, + { + Error::increment_result(match (keys.next(&RESULT_LOOKUP)?, self) { + (0, Ok(value)) => value.serialize_by_key(keys, ser), + (1, Err(value)) => value.serialize_by_key(keys, ser), + _ => Err(Traversal::Absent(0).into()), + }) + } +} + +impl<'de, T: TreeDeserialize<'de>, E: TreeDeserialize<'de>> TreeDeserialize<'de> for Result { + #[inline] + fn deserialize_by_key(&mut self, mut keys: K, de: D) -> Result> + where + K: Keys, + D: Deserializer<'de>, + { + Error::increment_result(match (keys.next(&RESULT_LOOKUP)?, self) { + (0, Ok(value)) => value.deserialize_by_key(keys, de), + (1, Err(value)) => value.deserialize_by_key(keys, de), + _ => Err(Traversal::Absent(0).into()), + }) + } +} + +impl TreeAny for Result { + #[inline] + fn ref_any_by_key(&self, mut keys: K) -> Result<&dyn Any, Traversal> + where + K: Keys, + { + match (keys.next(&RESULT_LOOKUP)?, self) { + (0, Ok(value)) => value.ref_any_by_key(keys), + (1, Err(value)) => value.ref_any_by_key(keys), + _ => Err(Traversal::Absent(0)), + } + .map_err(Traversal::increment) + } + + #[inline] + fn mut_any_by_key(&mut self, mut keys: K) -> Result<&mut dyn Any, Traversal> + where + K: Keys, + { + match (keys.next(&RESULT_LOOKUP)?, self) { + (0, Ok(value)) => value.mut_any_by_key(keys), + (1, Err(value)) => value.mut_any_by_key(keys), + _ => Err(Traversal::Absent(0)), + } + .map_err(Traversal::increment) + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +impl TreeKey for Cell { + #[inline] + fn traverse_all() -> Result { + T::traverse_all() + } + + #[inline] + fn traverse_by_key(keys: K, func: F) -> Result> + where + K: Keys, + F: FnMut(usize, Option<&'static str>, NonZero) -> Result<(), E>, + { + T::traverse_by_key(keys, func) + } +} + +impl TreeSerialize for Cell { + #[inline] + fn serialize_by_key(&self, keys: K, ser: S) -> Result> + where + K: Keys, + S: Serializer, + { + self.get().serialize_by_key(keys, ser) + } +} + +impl<'de, T: TreeDeserialize<'de>> TreeDeserialize<'de> for Cell { + #[inline] + fn deserialize_by_key(&mut self, keys: K, de: D) -> Result> + where + K: Keys, + D: Deserializer<'de>, + { + self.get_mut().deserialize_by_key(keys, de) + } +} + +impl TreeAny for Cell { + #[inline] + fn ref_any_by_key(&self, _keys: K) -> Result<&dyn Any, Traversal> + where + K: Keys, + { + Err(Traversal::Access(0, "Can't leak out of Cell")) + } + + #[inline] + fn mut_any_by_key(&mut self, keys: K) -> Result<&mut dyn Any, Traversal> + where + K: Keys, + { + self.get_mut().mut_any_by_key(keys) + } +} + +impl TreeAny for &Cell { + #[inline] + fn ref_any_by_key(&self, _keys: K) -> Result<&dyn Any, Traversal> + where + K: Keys, + { + Err(Traversal::Access(0, "Can't leak out of Cell")) + } + + #[inline] + fn mut_any_by_key(&mut self, _keys: K) -> Result<&mut dyn Any, Traversal> + where + K: Keys, + { + Err(Traversal::Access(0, "Can't leak out of Cell")) + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +impl TreeKey for RefCell { + #[inline] + fn traverse_all() -> Result { + T::traverse_all() + } + + #[inline] + fn traverse_by_key(keys: K, func: F) -> Result> + where + K: Keys, + F: FnMut(usize, Option<&'static str>, NonZero) -> Result<(), E>, + { + T::traverse_by_key(keys, func) + } +} + +impl TreeSerialize for RefCell { + #[inline] + fn serialize_by_key(&self, keys: K, ser: S) -> Result> + where + K: Keys, + S: Serializer, + { + self.try_borrow() + .or(Err(Traversal::Access(0, "Borrowed")))? + .serialize_by_key(keys, ser) + } +} + +impl<'de, T: TreeDeserialize<'de>> TreeDeserialize<'de> for &RefCell { + #[inline] + fn deserialize_by_key(&mut self, keys: K, de: D) -> Result> + where + K: Keys, + D: Deserializer<'de>, + { + self.try_borrow_mut() + .or(Err(Traversal::Access(0, "Borrowed")))? + .deserialize_by_key(keys, de) + } +} + +impl<'de, T: TreeDeserialize<'de>> TreeDeserialize<'de> for RefCell { + #[inline] + fn deserialize_by_key(&mut self, keys: K, de: D) -> Result> + where + K: Keys, + D: Deserializer<'de>, + { + self.get_mut().deserialize_by_key(keys, de) + } +} + +impl TreeAny for RefCell { + #[inline] + fn ref_any_by_key(&self, _keys: K) -> Result<&dyn Any, Traversal> + where + K: Keys, + { + Err(Traversal::Access(0, "Can't leak out of RefCell")) + } + + #[inline] + fn mut_any_by_key(&mut self, keys: K) -> Result<&mut dyn Any, Traversal> + where + K: Keys, + { + self.get_mut().mut_any_by_key(keys) + } +} + +impl TreeAny for &RefCell { + #[inline] + fn ref_any_by_key(&self, _keys: K) -> Result<&dyn Any, Traversal> + where + K: Keys, + { + Err(Traversal::Access(0, "Can't leak out of RefCell")) + } + + #[inline] + fn mut_any_by_key(&mut self, _keys: K) -> Result<&mut dyn Any, Traversal> + where + K: Keys, + { + Err(Traversal::Access(0, "Can't leak out of RefCell")) + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + #[cfg(feature = "alloc")] -mod alloc { +mod _alloc { use super::*; extern crate alloc; - use alloc::{boxed::Box, rc::Rc}; + use alloc::{borrow::Cow, boxed::Box, rc, rc::Rc, sync, sync::Arc}; impl TreeKey for Box { #[inline] @@ -304,6 +559,64 @@ mod alloc { ///////////////////////////////////////////////////////////////////////////////////////// + impl<'a, T: TreeKey + Clone> TreeKey for Cow<'a, T> { + #[inline] + fn traverse_all() -> Result { + T::traverse_all() + } + + #[inline] + fn traverse_by_key(keys: K, func: F) -> Result> + where + K: Keys, + F: FnMut(usize, Option<&'static str>, NonZero) -> Result<(), E>, + { + T::traverse_by_key(keys, func) + } + } + + impl<'a, T: TreeSerialize + Clone> TreeSerialize for Cow<'a, T> { + #[inline] + fn serialize_by_key(&self, keys: K, ser: S) -> Result> + where + K: Keys, + S: Serializer, + { + (**self).serialize_by_key(keys, ser) + } + } + + impl<'a, 'de, T: TreeDeserialize<'de> + Clone> TreeDeserialize<'de> for Cow<'a, T> { + #[inline] + fn deserialize_by_key(&mut self, keys: K, de: D) -> Result> + where + K: Keys, + D: Deserializer<'de>, + { + self.to_mut().deserialize_by_key(keys, de) + } + } + + impl<'a, T: TreeAny + Clone> TreeAny for Cow<'a, T> { + #[inline] + fn ref_any_by_key(&self, keys: K) -> Result<&dyn Any, Traversal> + where + K: Keys, + { + (**self).ref_any_by_key(keys) + } + + #[inline] + fn mut_any_by_key(&mut self, keys: K) -> Result<&mut dyn Any, Traversal> + where + K: Keys, + { + self.to_mut().mut_any_by_key(keys) + } + } + + ///////////////////////////////////////////////////////////////////////////////////////// + impl TreeKey for Rc { #[inline] fn traverse_all() -> Result { @@ -363,14 +676,70 @@ mod alloc { .mut_any_by_key(keys) } } -} -///////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////// -#[cfg(feature = "std")] -mod sync { - use super::*; - use std::sync::Arc; + impl TreeKey for rc::Weak { + #[inline] + fn traverse_all() -> Result { + T::traverse_all() + } + + #[inline] + fn traverse_by_key(keys: K, func: F) -> Result> + where + K: Keys, + F: FnMut(usize, Option<&'static str>, NonZero) -> Result<(), E>, + { + T::traverse_by_key(keys, func) + } + } + + impl TreeSerialize for rc::Weak { + #[inline] + fn serialize_by_key(&self, keys: K, ser: S) -> Result> + where + K: Keys, + S: Serializer, + { + self.upgrade() + .ok_or(Traversal::Access(0, "Dropped"))? + .serialize_by_key(keys, ser) + } + } + + impl<'de, T: TreeDeserialize<'de>> TreeDeserialize<'de> for rc::Weak { + #[inline] + fn deserialize_by_key(&mut self, keys: K, de: D) -> Result> + where + K: Keys, + D: Deserializer<'de>, + { + self.upgrade() + .ok_or(Traversal::Access(0, "Dropped"))? + .deserialize_by_key(keys, de) + } + } + + impl TreeAny for rc::Weak { + #[inline] + fn ref_any_by_key(&self, _keys: K) -> Result<&dyn Any, Traversal> + where + K: Keys, + { + Err(Traversal::Access(0, "Can't leak out of Weak")) + } + + #[inline] + fn mut_any_by_key(&mut self, _keys: K) -> Result<&mut dyn Any, Traversal> + where + K: Keys, + { + Err(Traversal::Access(0, "Can't leak out of Weak")) + } + } + + ///////////////////////////////////////////////////////////////////////////////////////// impl TreeKey for Arc { #[inline] @@ -431,4 +800,263 @@ mod sync { .mut_any_by_key(keys) } } + + ///////////////////////////////////////////////////////////////////////////////////////// + + impl TreeKey for sync::Weak { + #[inline] + fn traverse_all() -> Result { + T::traverse_all() + } + + #[inline] + fn traverse_by_key(keys: K, func: F) -> Result> + where + K: Keys, + F: FnMut(usize, Option<&'static str>, NonZero) -> Result<(), E>, + { + T::traverse_by_key(keys, func) + } + } + + impl TreeSerialize for sync::Weak { + #[inline] + fn serialize_by_key(&self, keys: K, ser: S) -> Result> + where + K: Keys, + S: Serializer, + { + self.upgrade() + .ok_or(Traversal::Access(0, "Dropped"))? + .serialize_by_key(keys, ser) + } + } + + impl<'de, T: TreeDeserialize<'de>> TreeDeserialize<'de> for sync::Weak { + #[inline] + fn deserialize_by_key(&mut self, keys: K, de: D) -> Result> + where + K: Keys, + D: Deserializer<'de>, + { + self.upgrade() + .ok_or(Traversal::Access(0, "Dropped"))? + .deserialize_by_key(keys, de) + } + } + + impl TreeAny for sync::Weak { + #[inline] + fn ref_any_by_key(&self, _keys: K) -> Result<&dyn Any, Traversal> + where + K: Keys, + { + Err(Traversal::Access(0, "Can't leak out of Weak")) + } + + #[inline] + fn mut_any_by_key(&mut self, _keys: K) -> Result<&mut dyn Any, Traversal> + where + K: Keys, + { + Err(Traversal::Access(0, "Can't leak out of Weak")) + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "std")] +mod _std { + use super::*; + use std::sync::{Mutex, RwLock}; + + impl TreeKey for Mutex { + #[inline] + fn traverse_all() -> Result { + T::traverse_all() + } + + #[inline] + fn traverse_by_key(keys: K, func: F) -> Result> + where + K: Keys, + F: FnMut(usize, Option<&'static str>, NonZero) -> Result<(), E>, + { + T::traverse_by_key(keys, func) + } + } + + impl TreeSerialize for Mutex { + #[inline] + fn serialize_by_key(&self, keys: K, ser: S) -> Result> + where + K: Keys, + S: Serializer, + { + self.lock() + .or(Err(Traversal::Access(0, "Poisoned")))? + .serialize_by_key(keys, ser) + } + } + + impl<'de, T: TreeDeserialize<'de>> TreeDeserialize<'de> for &Mutex { + #[inline] + fn deserialize_by_key(&mut self, keys: K, de: D) -> Result> + where + K: Keys, + D: Deserializer<'de>, + { + (*self) + .lock() + .or(Err(Traversal::Access(0, "Poisoned")))? + .deserialize_by_key(keys, de) + } + } + + impl<'de, T: TreeDeserialize<'de>> TreeDeserialize<'de> for Mutex { + #[inline] + fn deserialize_by_key(&mut self, keys: K, de: D) -> Result> + where + K: Keys, + D: Deserializer<'de>, + { + self.get_mut() + .or(Err(Traversal::Access(0, "Poisoned")))? + .deserialize_by_key(keys, de) + } + } + + impl TreeAny for Mutex { + #[inline] + fn ref_any_by_key(&self, _keys: K) -> Result<&dyn Any, Traversal> + where + K: Keys, + { + Err(Traversal::Access(0, "Can't leak out of Mutex")) + } + + #[inline] + fn mut_any_by_key(&mut self, keys: K) -> Result<&mut dyn Any, Traversal> + where + K: Keys, + { + self.get_mut() + .or(Err(Traversal::Access(0, "Poisoned")))? + .mut_any_by_key(keys) + } + } + + impl TreeAny for &Mutex { + #[inline] + fn ref_any_by_key(&self, _keys: K) -> Result<&dyn Any, Traversal> + where + K: Keys, + { + Err(Traversal::Access(0, "Can't leak out of Mutex")) + } + + #[inline] + fn mut_any_by_key(&mut self, _keys: K) -> Result<&mut dyn Any, Traversal> + where + K: Keys, + { + Err(Traversal::Access(0, "Can't leak out of Mutex")) + } + } + + ///////////////////////////////////////////////////////////////////////////////////////// + + impl TreeKey for RwLock { + #[inline] + fn traverse_all() -> Result { + T::traverse_all() + } + + #[inline] + fn traverse_by_key(keys: K, func: F) -> Result> + where + K: Keys, + F: FnMut(usize, Option<&'static str>, NonZero) -> Result<(), E>, + { + T::traverse_by_key(keys, func) + } + } + + impl TreeSerialize for RwLock { + #[inline] + fn serialize_by_key(&self, keys: K, ser: S) -> Result> + where + K: Keys, + S: Serializer, + { + self.read() + .or(Err(Traversal::Access(0, "Locked")))? + .serialize_by_key(keys, ser) + } + } + + impl<'de, T: TreeDeserialize<'de>> TreeDeserialize<'de> for &RwLock { + #[inline] + fn deserialize_by_key(&mut self, keys: K, de: D) -> Result> + where + K: Keys, + D: Deserializer<'de>, + { + self.write() + .or(Err(Traversal::Access(0, "Locked")))? + .deserialize_by_key(keys, de) + } + } + + impl<'de, T: TreeDeserialize<'de>> TreeDeserialize<'de> for RwLock { + #[inline] + fn deserialize_by_key(&mut self, keys: K, de: D) -> Result> + where + K: Keys, + D: Deserializer<'de>, + { + self.get_mut() + .or(Err(Traversal::Access(0, "Poisoned")))? + .deserialize_by_key(keys, de) + } + } + + impl TreeAny for RwLock { + #[inline] + fn ref_any_by_key(&self, _keys: K) -> Result<&dyn Any, Traversal> + where + K: Keys, + { + Err(Traversal::Access(0, "Can't leak out of RwLock")) + } + + #[inline] + fn mut_any_by_key(&mut self, keys: K) -> Result<&mut dyn Any, Traversal> + where + K: Keys, + { + self.get_mut() + .or(Err(Traversal::Access(0, "Poisoned")))? + .mut_any_by_key(keys) + } + } + + impl TreeAny for &RwLock { + #[inline] + fn ref_any_by_key(&self, _keys: K) -> Result<&dyn Any, Traversal> + where + K: Keys, + { + Err(Traversal::Access(0, "Can't leak out of RwLock")) + } + + #[inline] + fn mut_any_by_key(&mut self, _keys: K) -> Result<&mut dyn Any, Traversal> + where + K: Keys, + { + Err(Traversal::Access(0, "Can't leak out of RwLock")) + } + } }