use std::collections::HashMap;
use chronon_core::{ChrononError, Result};
use crate::descriptor::{InvokeFn, ScriptDescriptor};
struct StoredScript {
name: String,
invoke: InvokeFn,
signature_json: String,
signature_hash: u64,
}
pub struct ScriptRegistry {
scripts: HashMap<String, StoredScript>,
}
impl Default for ScriptRegistry {
fn default() -> Self {
Self::new()
}
}
impl ScriptRegistry {
pub fn new() -> Self {
Self {
scripts: HashMap::new(),
}
}
pub fn from_inventory() -> Self {
let mut registry = Self::new();
registry.register_from_inventory();
registry
}
pub fn register_from_inventory(&mut self) {
for desc in quark::inventory::iter::<ScriptDescriptor> {
self.register(ScriptDescriptor::with_signature(
desc.name,
desc.invoke,
desc.signature_json,
desc.signature_hash,
));
}
}
pub fn register(&mut self, desc: ScriptDescriptor) {
self.scripts.insert(
desc.name.to_string(),
StoredScript {
name: desc.name.to_string(),
invoke: desc.invoke,
signature_json: desc.signature_json.to_string(),
signature_hash: desc.signature_hash,
},
);
}
pub fn get(&self, name: &str) -> Option<ScriptDescriptorRef<'_>> {
self.scripts.get(name).map(|s| ScriptDescriptorRef {
name: s.name.as_str(),
invoke: s.invoke,
signature_json: s.signature_json.as_str(),
signature_hash: s.signature_hash,
})
}
pub fn get_or_err(&self, name: &str) -> Result<ScriptDescriptorRef<'_>> {
self.get(name)
.ok_or_else(|| ChrononError::ScriptNotFound(name.to_string()))
}
pub fn len(&self) -> usize {
self.scripts.len()
}
pub fn is_empty(&self) -> bool {
self.scripts.is_empty()
}
pub fn contains(&self, name: &str) -> bool {
self.scripts.contains_key(name)
}
pub fn list(&self) -> Vec<ScriptDescriptorRef<'_>> {
let mut v: Vec<_> = self.scripts.values().map(stored_to_ref).collect();
v.sort_by_key(|d| d.name);
v
}
}
#[derive(Clone, Copy)]
pub struct ScriptDescriptorRef<'a> {
pub name: &'a str,
pub invoke: InvokeFn,
pub signature_json: &'a str,
pub signature_hash: u64,
}
fn stored_to_ref(s: &StoredScript) -> ScriptDescriptorRef<'_> {
ScriptDescriptorRef {
name: s.name.as_str(),
invoke: s.invoke,
signature_json: s.signature_json.as_str(),
signature_hash: s.signature_hash,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::descriptor::ScriptDescriptor;
use chronon_core::{Result, ScriptContext};
use serde_json::Value;
use std::future::Future;
use std::pin::Pin;
fn stub_invoke(
_ctx: Box<dyn ScriptContext>,
_params: Value,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send>> {
Box::pin(async { Ok(()) })
}
#[test]
fn register_and_lookup() {
let mut reg = ScriptRegistry::new();
reg.register(ScriptDescriptor::new("hello", stub_invoke));
assert!(reg.contains("hello"));
assert_eq!(reg.len(), 1);
}
}