silo 0.1.0

多引擎融合框架 - 整合 Bevy、Godot 和 Unity 的跨引擎通信调度平台
Documentation
use bytes::Bytes;
use serde::{Deserialize, Serialize};
use std::{
    cell::RefCell,
    collections::HashMap,
    rc::Rc,
    sync::atomic::{AtomicU64, Ordering},
};
use tokio::sync::mpsc::UnboundedSender;

pub struct App {
    pub world: u64,
    tx: UnboundedSender<crate::base::Message>,
    events: RefCell<HashMap<String, Vec<(AppOnEvent, AppEventSource)>>>,
    next_id: AtomicU64,
}

impl App {
    pub fn on<T: for<'a> Deserialize<'a> + 'static>(
        &self,
        f: Box<dyn Fn(T) + 'static>,
        source: AppEventSource,
    ) where
        T: Default,
    {
        self.events
            .borrow_mut()
            .entry(std::any::type_name::<T>().to_string())
            .or_default()
            .push((
                Box::new(move |v| {
                    let mut de = serde_cbor::de::Deserializer::from_slice(v);
                    if let Ok(event) = T::deserialize(&mut de) {
                        f(event)
                    }
                }),
                source,
            ))
    }

    pub fn emit(&self, t: &String, b: &Bytes) {
        let binding = self.events.borrow();
        let events = binding.get(t).clone();
        if let Some(events) = events {
            for (invoke, _) in events {
                invoke(b);
            }
        }
    }

    pub fn off<T>(&self, source: AppEventSource) {
        let t = std::any::type_name::<T>().to_string();
        if let Some(vs) = self.events.borrow_mut().get_mut(&t) {
            vs.retain(|(_, s)| *s != source);
        }
    }

    pub fn invoke<T: Serialize>(&self, event: &T) {
        if let Ok(v) = serde_cbor::to_vec(event) {
            let _ = self
                .tx
                .send(crate::base::Message::Event(crate::base::Event::Invoke {
                    t: std::any::type_name::<T>().to_string(),
                    v: Bytes::from(v),
                    world: self.world,
                }));
        }
    }

    pub fn invoke_to_world<T: Serialize>(&self, event: &T, world: u64) {
        if let Ok(v) = serde_cbor::to_vec(event) {
            let _ = self
                .tx
                .send(crate::base::Message::Event(crate::base::Event::Invoke {
                    t: std::any::type_name::<T>().to_string(),
                    v: Bytes::from(v),
                    world,
                }));
        }
    }

    pub fn create(&self, skin: &crate::view::Skin) -> Rc<Page> {
        let id = self.next_id.fetch_add(1, Ordering::SeqCst) + 1;
        let p = Rc::new(Page { id: id });
        let _ = self
            .tx
            .send(crate::base::Message::Event(crate::base::Event::Spawn {
                id,
                t: std::any::type_name::<Page>().to_string(),
                world: self.world,
            }));
        let _ = self
            .tx
            .send(crate::base::Message::Event(crate::base::Event::Change {
                id,
                t: std::any::type_name::<crate::view::Skin>().to_string(),
                v: Bytes::from(serde_cbor::to_vec(skin).unwrap()),
                world: self.world,
            }));
        p
    }
}

pub struct Page {
    pub id: u64,
}

#[derive(Debug, Serialize, Deserialize, Default)]
pub struct PageEvent<T> {
    pub id: u64,
    pub event: T,
}

impl Page {
    pub fn on<T: for<'a> Deserialize<'a> + 'static>(
        &self,
        app: Rc<App>,
        f: Box<dyn Fn(T) + 'static>,
    ) where
        T: Default,
    {
        let id = self.id;
        app.on::<PageEvent<T>>(
            Box::new(move |v| {
                if v.id == id {
                    f(v.event);
                }
            }),
            AppEventSource::Page(self.id),
        );
    }

    pub fn off<T>(&self, app: Rc<App>) {
        app.off::<PageEvent<T>>(AppEventSource::Page(self.id));
    }

    pub fn close(&self, app: Rc<App>) {
        let _ = app
            .tx
            .send(crate::base::Message::Event(crate::base::Event::Despawn {
                id: self.id,
                world: app.world,
            }));
    }

    pub fn set<T: Serialize>(&self, app: Rc<App>, data: &T) {
        if let Ok(v) = serde_cbor::to_vec(data) {
            let _ = app
                .tx
                .send(crate::base::Message::Event(crate::base::Event::Change {
                    id: self.id,
                    t: std::any::type_name::<T>().to_string(),
                    v: Bytes::from(v),
                    world: app.world,
                }));
        }
    }

    pub fn invoke<T: Serialize>(&self, app: Rc<App>, event: &T) {
        app.invoke(&PageEvent {
            id: self.id,
            event: event,
        });
    }
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub enum AppEventSource {
    App,
    Page(u64),
    User(u64),
}

pub type AppOnEvent = Box<dyn Fn(&Bytes) + 'static>;

pub async fn run<F>(world: u64, f: fn(Rc<App>) -> F)
where
    F: std::future::Future<Output = ()> + 'static,
{
    let mut ch = crate::base::RUNTIME.chan();
    let app = Rc::new(App {
        world: world,
        tx: ch.tx,
        events: RefCell::new(HashMap::new()),
        next_id: AtomicU64::new(0),
    });

    let run_task = tokio::task::spawn_local({
        let app = app.clone();
        let f = f;
        async move {
            f(app).await;
        }
    });

    let recv_task = tokio::task::spawn_local({
        let app = app.clone();
        let world = world;
        async move {
            while let Some(e) = ch.rx.recv().await {
                match e {
                    crate::base::Message::Event(event) => match event {
                        crate::base::Event::Invoke { t, v, world: w } => {
                            if w == world {
                                app.emit(&t, &v);
                            }
                        }
                        _ => {}
                    },
                    _ => {}
                }
            }
        }
    });

    tokio::select! {
        _ = run_task => {},
        _ = recv_task => {},
    }
}