goods 0.5.3

Asset manager for good assets
Documentation
use {
    crate::{
        asset::Asset,
        channel::{Receiver, Sender, Setter},
    },
    alloc::{boxed::Box, vec::Vec},
    core::any::{Any, TypeId},
    hashbrown::hash_map::{Entry, HashMap},
    maybe_sync::{dyn_maybe_send, MaybeSend, Mutex},
};

pub(crate) trait AnyProcess<C>: MaybeSend {
    fn run(self: Box<Self>, ctx: &mut C);
}

pub(crate) struct Process<A: Asset> {
    pub(crate) repr: A::Repr,
    pub(crate) setter: Setter<A::BuildFuture>,
}

impl<A> AnyProcess<A::Context> for Process<A>
where
    A: Asset,
{
    fn run(self: Box<Self>, ctx: &mut A::Context) {
        self.setter.set(A::build(self.repr, ctx))
    }
}

struct Processes<C> {
    receiver: Receiver<Box<dyn AnyProcess<C>>>,
}

pub(crate) struct Processor {
    processes: Mutex<HashMap<TypeId, Box<dyn_maybe_send!(Any)>>>,
}

impl Processor {
    pub(crate) fn new() -> Self {
        Processor {
            processes: Mutex::new(HashMap::new()),
        }
    }

    pub(crate) fn sender<A>(&self) -> Sender<Box<dyn AnyProcess<A::Context>>>
    where
        A: Asset,
    {
        let mut lock = self.processes.lock();
        match lock.entry(TypeId::of::<A::Context>()) {
            Entry::Vacant(entry) => {
                let receiver = Receiver::new();
                let sender = receiver.sender();
                entry.insert(Box::new(Processes::<A::Context> { receiver }));
                sender
            }
            Entry::Occupied(entry) => Any::downcast_ref::<Processes<A::Context>>(&*entry.get())
                .unwrap()
                .receiver
                .sender(),
        }
    }

    pub(crate) fn run<C: 'static>(&self, ctx: &mut C) {
        let lock = self.processes.lock();
        if let Some(processes) = lock.get(&TypeId::of::<C>()) {
            let processes = Any::downcast_ref::<Processes<C>>(&**processes).unwrap();
            let mut received = Vec::new();
            processes.receiver.recv(&mut received);
            for received in received {
                received.run(ctx);
            }
        }
    }
}