use serde_json::Value;
use crate::error::{ChrononError, Result};
pub trait ScriptContext: Send {
fn label(&self) -> &str;
fn actor_json(&self) -> &Value;
}
pub trait ContextFactory: Send + Sync {
fn build(&self, actor_json: &Value) -> Result<Box<dyn ScriptContext>>;
}
#[derive(Debug, thiserror::Error)]
#[error("identity error: {0}")]
pub struct IdentityError(pub String);
impl From<IdentityError> for ChrononError {
fn from(value: IdentityError) -> Self {
Self::Internal(value.0)
}
}
#[derive(Debug, Default)]
pub struct NoOpScriptContext {
actor_json: Value,
}
impl ScriptContext for NoOpScriptContext {
fn label(&self) -> &'static str {
"noop"
}
fn actor_json(&self) -> &Value {
&self.actor_json
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct NoOpContextFactory;
impl ContextFactory for NoOpContextFactory {
fn build(&self, _actor_json: &Value) -> Result<Box<dyn ScriptContext>> {
Ok(Box::new(NoOpScriptContext::default()))
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct JsonScriptContextFactory;
struct JsonContext {
actor_json: Value,
label: String,
}
impl ScriptContext for JsonContext {
fn label(&self) -> &str {
&self.label
}
fn actor_json(&self) -> &Value {
&self.actor_json
}
}
impl ContextFactory for JsonScriptContextFactory {
fn build(&self, actor_json: &Value) -> Result<Box<dyn ScriptContext>> {
Ok(Box::new(JsonContext {
actor_json: actor_json.clone(),
label: actor_json.to_string(),
}))
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
struct TestContext {
label: String,
actor_json: Value,
}
impl ScriptContext for TestContext {
fn label(&self) -> &str {
&self.label
}
fn actor_json(&self) -> &Value {
&self.actor_json
}
}
struct TestFactory;
impl ContextFactory for TestFactory {
fn build(&self, actor_json: &Value) -> Result<Box<dyn ScriptContext>> {
if actor_json.get("System").is_some() {
Ok(Box::new(TestContext {
label: "system".into(),
actor_json: actor_json.clone(),
}))
} else {
Err(IdentityError("missing System".into()).into())
}
}
}
#[test]
fn factory_builds_context() {
let factory = TestFactory;
let actor = json!({"System": {"operation": "t"}});
let ctx = factory.build(&actor).expect("ok");
assert_eq!(ctx.label(), "system");
assert_eq!(ctx.actor_json(), &actor);
}
#[test]
fn json_factory_stores_actor_json() {
let factory = JsonScriptContextFactory;
let actor = json!({"user": "alice"});
let ctx = factory.build(&actor).expect("ok");
assert_eq!(ctx.actor_json(), &actor);
assert!(ctx.label().contains("alice"));
}
}