deft 0.15.0

Cross platform ui framework
use crate::mrc::{Mrc, MrcWeak, UpgradeError};
use std::any::Any;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};

pub struct StateId<T> {
    id: u32,
    _phantom: PhantomData<T>,
}

pub struct StateManager {
    next_id: u32,
    states: HashMap<u32, Box<dyn Any>>,
}

pub enum StateData<T> {
    Hosting(MrcWeak<T>),
    SelfManaged(Mrc<T>),
}

pub struct State<T> {
    id: u32,
    store: StateData<T>,
}

impl<T> PartialEq for State<T> {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

impl<T> Clone for State<T> {
    fn clone(&self) -> Self {
        let weak = match &self.store {
            StateData::Hosting(d) => d.clone(),
            StateData::SelfManaged(d) => d.as_weak(),
        };
        Self {
            id: self.id,
            store: StateData::Hosting(weak),
        }
    }
}

impl<T> State<T> {
    pub fn invalid() -> State<T> {
        State {
            id: 0,
            store: StateData::Hosting(MrcWeak::new()),
        }
    }
    pub fn upgrade_mut(&self) -> Result<StateMutRef<'_, T>, UpgradeError> {
        match &self.store {
            StateData::Hosting(d) => {
                let data = d.upgrade()?;
                Ok(StateMutRef {
                    state_data: &self.store,
                    data,
                })
            }
            StateData::SelfManaged(d) => Ok(StateMutRef {
                state_data: &self.store,
                data: d.clone(),
            }),
        }
    }
}

pub struct StateMutRef<'a, T> {
    state_data: &'a StateData<T>,
    data: Mrc<T>,
}

impl<'a, T> Deref for StateMutRef<'a, T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.data
    }
}

impl<'a, T> DerefMut for StateMutRef<'a, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.data
    }
}

impl StateManager {
    pub fn new() -> StateManager {
        Self {
            next_id: 1,
            states: Default::default(),
        }
    }

    pub fn new_state<T: 'static>(&mut self, state: T) -> State<T> {
        let id = self.next_id;
        self.next_id += 1;

        let data = Mrc::new(state);
        let weak = data.as_weak();
        self.states.insert(id, Box::new(data));
        State {
            id,
            store: StateData::Hosting(weak),
        }
    }

    pub fn new_self_managed_state<T: 'static>(&mut self, state: T) -> State<T> {
        let id = self.next_id;
        self.next_id += 1;

        let data = Mrc::new(state);
        State {
            id,
            store: StateData::SelfManaged(data),
        }
    }

    pub fn remove_state<T>(&mut self, state: &State<T>) {
        self.states.remove(&state.id);
    }

    pub fn get_state<T: 'static>(&self, id: u32) -> Option<State<T>> {
        if let Some(data) = self.states.get(&id) {
            let raw_data = data.deref();
            if let Some(r) = raw_data.downcast_ref::<Mrc<T>>() {
                return Some(State {
                    id,
                    store: StateData::Hosting(r.as_weak()),
                });
            }
        }
        None
    }
}

#[cfg(test)]
pub mod tests {
    use crate::state::StateManager;

    struct MyState {
        num: u32,
    }
    #[test]
    fn test_upgrade_mut() {
        let mut sm = StateManager::new();
        let my_state = MyState { num: 162534 };
        let state = sm.new_state(my_state);

        {
            let state_mut_ref = state.upgrade_mut().unwrap();
            assert_eq!(162534, state_mut_ref.num);
        }

        sm.remove_state(&state);
        let upgrade_result = state.upgrade_mut();
        assert!(upgrade_result.is_err());
    }
}