use std::fmt;
pub trait Context: Default + Clone + fmt::Display + fmt::Debug + Send + Sync + 'static {
fn update(self, replacements: Self) -> Self;
fn is_empty(&self) -> bool;
}
#[derive(Default, Copy, Clone, Debug)]
pub struct NoContext;
impl fmt::Display for NoContext {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
Ok(())
}
}
impl Context for NoContext {
fn update(self, _replacements: Self) -> Self {
self
}
fn is_empty(&self) -> bool {
true
}
}
#[derive(Default, Clone, Debug)]
pub struct AdhocContext {
data: indexmap::IndexMap<&'static str, Box<dyn AdhocValue>>,
}
impl AdhocContext {
pub fn new() -> Self {
Default::default()
}
pub fn insert<V>(mut self, key: &'static str, value: V) -> Self
where
V: AdhocValue + Clone,
{
self.data.insert(key, Box::new(value));
self
}
}
impl fmt::Display for AdhocContext {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (k, v) in self.data.iter() {
writeln!(f, "{}: {}", k, v)?;
}
Ok(())
}
}
impl Context for AdhocContext {
fn update(mut self, replacements: Self) -> Self {
self.data.extend(replacements.data);
self
}
fn is_empty(&self) -> bool {
self.data.is_empty()
}
}
pub trait AdhocValue: fmt::Display + fmt::Debug + Send + Sync + 'static {
fn clone_box(&self) -> Box<dyn AdhocValue>;
}
impl<V> AdhocValue for V
where
V: Clone + fmt::Display + fmt::Debug + Send + Sync + 'static,
{
fn clone_box(&self) -> Box<dyn AdhocValue> {
Box::new(self.clone())
}
}
impl Clone for Box<dyn AdhocValue> {
fn clone(&self) -> Box<dyn AdhocValue> {
self.clone_box()
}
}
#[cfg(test)]
mod test {
use super::*;
use static_assertions::*;
#[test]
fn no_context() {
assert_impl_all!(
NoContext: Default,
Copy,
Clone,
fmt::Debug,
fmt::Display,
Context
);
}
#[test]
fn adhoc_context() {
assert_impl_all!(NoContext: Default, Clone, fmt::Debug, fmt::Display, Context);
}
}