use std::sync::Arc;
use sim_citizen_derive::non_citizen;
use sim_kernel::{Cx, Expr, Object, ObjectCompat, Result, Symbol, Value};
use crate::SkillCard;
pub trait SkillEventSink {
fn emit(&mut self, cx: &mut Cx, event: Value) -> Result<()>;
}
pub trait SkillTransport: Send + Sync {
fn id(&self) -> &str;
fn kind(&self) -> &str;
fn discover(&self, cx: &mut Cx) -> Result<Vec<SkillCard>>;
fn call(
&self,
cx: &mut Cx,
card: &SkillCard,
args: Value,
events: Option<&mut dyn SkillEventSink>,
) -> Result<Value>;
fn health(&self, cx: &mut Cx) -> Result<Value>;
}
#[derive(Clone)]
#[non_citizen(
reason = "live skill transport handle; transport metadata is carried by skill/Card descriptor",
kind = "handle"
)]
pub struct SkillTransportValue {
transport: Arc<dyn SkillTransport>,
}
impl SkillTransportValue {
pub fn new(transport: Arc<dyn SkillTransport>) -> Self {
Self { transport }
}
pub fn transport(&self) -> Arc<dyn SkillTransport> {
self.transport.clone()
}
}
impl Object for SkillTransportValue {
fn display(&self, _cx: &mut Cx) -> Result<String> {
Ok(format!(
"#<skill-transport {}:{}>",
self.transport.kind(),
self.transport.id()
))
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
impl ObjectCompat for SkillTransportValue {
fn as_expr(&self, cx: &mut Cx) -> Result<Expr> {
self.as_table(cx)?.object().as_expr(cx)
}
fn as_table(&self, cx: &mut Cx) -> Result<Value> {
cx.factory().table(vec![
(
Symbol::new("kind"),
cx.factory().symbol(Symbol::new("skill/transport"))?,
),
(
Symbol::new("id"),
cx.factory().string(self.transport.id().to_owned())?,
),
(
Symbol::new("transport-kind"),
cx.factory().string(self.transport.kind().to_owned())?,
),
])
}
}
pub fn skill_transport_value(cx: &mut Cx, transport: Arc<dyn SkillTransport>) -> Result<Value> {
cx.factory()
.opaque(Arc::new(SkillTransportValue::new(transport)))
}