dyn_derive 0.3.4

Inherit and derive object-unsafe traits for dynamic Rust.
Documentation
use std::collections::HashMap;
use std::fmt::Debug;

use dyn_derive::*;
use dyn_std::Instance;

#[dyn_trait]
pub trait Error: Debug + PartialEq {}

#[dyn_trait]
pub trait Value<#[dynamic] E: Error>: Debug + Clone + PartialEq {
    fn new(v: i32) -> Result<Self, E>;
    fn get(&self) -> i32;
    fn set(&mut self, v: i32) -> Result<(), E>;
}

#[dyn_trait]
pub trait Context<#[dynamic] E: Error, #[dynamic] V: Value<E>> {
    fn get(&self, name: &str) -> Option<V>;
    fn set(&mut self, name: &str, value: V);
    fn extend(&mut self, store: HashMap<String, V>);
}

#[derive(Debug, PartialEq)]
struct MyError;

impl ErrorFactory for MyError {}

#[derive(Debug, Clone, PartialEq)]
struct MyValue(u32);

impl ValueFactory<MyError> for MyValue {
    fn new(v: i32) -> Result<Self, MyError> {
        if v < 0 {
            Err(MyError)
        } else {
            Ok(Self(v as u32))
        }
    }

    fn get(&self) -> i32 {
        self.0 as i32
    }

    fn set(&mut self, v: i32) -> Result<(), MyError> {
        if v < 0 {
            Err(MyError)
        } else {
            self.0 = v as u32;
            Ok(())
        }
    }
}

pub struct MyContext {
    store: HashMap<String, MyValue>,
}

impl MyContext {
    pub fn new() -> Self {
        Self {
            store: Default::default(),
        }
    }
}

impl ContextFactory<MyError, MyValue> for MyContext {
    fn get(&self, name: &str) -> Option<MyValue> {
        self.store.get(name).cloned()
    }

    fn set(&mut self, name: &str, value: MyValue) {
        self.store.insert(name.to_string(), value);
    }

    fn extend(&mut self, store: HashMap<String, MyValue>) {
        self.store.extend(store)
    }
}

#[test]
fn main() {
    let ctx: &mut dyn Context = &mut Instance::new(MyContext::new());
    let value: &mut dyn Value = &mut Instance::new(MyValue::new(42).unwrap());
    assert_eq!(value.get(), 42);
    assert_eq!(value.set(514), Ok(()));
    assert_eq!(value.get(), 514);
    assert_eq!(value.set(-1), Err(Box::new(Instance::new(MyError)) as Box<dyn Error>));
    assert_eq!(value.get(), 514);
    ctx.set("x", Box::new(Instance::new(MyValue::new(114).unwrap())));
    let value = ctx.get("x").unwrap();
    assert_eq!(value.get(), 114);
}