dynconfig 0.1.2

Dynamically change fields of a struct based on a path.
Documentation
//! <style>
//! .rustdoc-hidden { display: none; }
//! </style>
#![doc = include_str!("../README.md")]
#![cfg_attr(dynconfig_nightly, feature(doc_cfg))]
#![forbid(unsafe_code)]
#![no_std]
extern crate alloc;
extern crate self as dynconfig;

#[cfg(feature = "std")]
extern crate std;

mod error;
mod path;
mod value;

pub mod pair;

pub use self::error::Error;
pub use self::path::Path;
pub use self::value::Value;

#[allow(missing_docs)]
pub type Result<T, E = Error> = core::result::Result<T, E>;

#[cfg(feature = "derive")]
#[doc(inline)]
pub use dynconfig_derive::Dynconfig;

/// An item whose values can be dynamically updated.
pub trait Dynconfig: Sized {
    /// Set the `path.next()` field of `self` to `value`.
    ///
    /// This method takes a [`Path`] and a `value`. `path` is the full path of
    /// the field we wish to update (example: `foo.bar.x`) and `value` the new
    /// (unparsed) value of that field.
    ///
    /// # Implementors
    ///
    /// [`Path`] is an [`Iterator`] over all components of the field path.
    /// Implementations are supposed to (usually) only ever take the next
    /// component from `path` and then pass the same `path` down to the
    /// corresponding field.
    ///
    /// # Example
    ///
    /// ```rust
    /// # use dynconfig::{Dynconfig, Path, Result, Error};
    /// struct Foo {
    ///     x: u32,
    ///     y: usize,
    ///     z: f32,
    /// }
    ///
    /// impl Dynconfig for Foo {
    ///     fn set(&mut self, path: &mut Path<'_>, value: &str) -> Result<()> {
    ///         match path.next() {
    ///             Some("x") => self.x.set(path, value),
    ///             Some("y") => self.y.set(path, value),
    ///             Some("z") => self.z.set(path, value),
    ///             Some(x) => Err(Error::unknown_field(x)),
    ///             None => Ok(())
    ///         }
    ///     }
    /// }
    ///
    /// let mut foo = Foo { x: 42, y: 0, z: -1.0 };
    ///
    /// assert_eq!(foo.x, 42);
    /// foo.set(&mut Path::new("x"), "54").unwrap();
    /// assert_eq!(foo.x, 54);
    /// ```
    fn set(&mut self, path: &mut Path<'_>, value: &str) -> Result<()>;
}

impl<T> Dynconfig for T
where
    T: Value,
{
    fn set(&mut self, _: &mut Path<'_>, value: &str) -> Result<()> {
        Value::update(self, value)
    }
}

#[doc(inline)]
pub use self::pair::Pair;
#[doc(inline)]
pub use self::pair::parse;

/// Shorthand for calling [`Dynconfig::set`] with `pair`.
///
/// Equivalent to: [`pair.set_on(x)`](Pair::set_on).
#[inline]
pub fn set<T>(x: &mut T, pair: Pair<'_>) -> Result<()>
where
    T: Dynconfig,
{
    pair.set_on(x)
}

/// Shorthand for calling [`Dynconfig::set`] with many values.
///
/// This function is short-circuiting.
///
/// # Example
///
/// ```rust
/// # use dynconfig::{Dynconfig, Path};
/// #[derive(Default, Dynconfig)]
/// struct Foo {
///     x: u32,
///     y: usize,
///     z: f32,
/// }
///
/// let mut foo = Foo::default();
///
/// dynconfig::set_many(&mut foo,
///     [
///         ("x", "42"),
///         ("y", "34"),
///         ("z", "-1"),
///     ]
///     .into_iter()
///     .map(|(path, value)| (Path::new(path), value))
///     .map(Into::into)
/// ).unwrap();
/// ```
pub fn set_many<'a, T, I>(x: &mut T, iter: I) -> Result<()>
where
    T: Dynconfig,
    I: IntoIterator<Item = Pair<'a>>,
{
    iter.into_iter().try_for_each(|pair| set(x, pair))
}