pub trait Scripter {
    fn name() -> &'static str;
fn script_type() -> ScriptType;
fn hooks() -> &'static [&'static str];
fn version_requirement() -> VersionReq; fn read<H: Hook>() -> H { ... }
fn write<H: Hook>(output: &<H as Hook>::Output) { ... }
fn execute(func: &mut dyn FnMut(&str)) -> Result<(), Error> { ... } }
Expand description

Trait that should be implemented on a script abstraction struct
This concerns ScriptType::OneShot and ScriptType::Daemon
The implementer should provide Scripter::script_type, Scripter::name, Scripter::hooks and Scripter::version_requirement
The struct should call Scripter::execute


// The hook should usually be on a common api crate.
#[derive(serde::Serialize, serde::Deserialize)]
struct MyHook;
impl Hook for MyHook {
   const NAME: &'static str = "MyHook";
   type Output = ();
}

struct MyScript;
impl MyScript {
   fn run(&mut self, hook: &str) {
       let _hook: MyHook = Self::read();
       eprintln!("hook: {} was triggered", hook);
   }
}
impl Scripter for MyScript {
   fn name() -> &'static str {
       "MyScript"
   }
   fn script_type() -> ScriptType {
       ScriptType::OneShot
   }
   fn hooks() -> &'static [&'static str] {
       &[MyHook::NAME]
   }
   fn version_requirement() -> VersionReq {
       VersionReq::parse(">=0.1.0").expect("version requirement is correct")
   }
}

fn main() {
   let mut my_script = MyScript;
   MyScript::execute(&mut |hook_name|MyScript::run(&mut my_script, hook_name));
}

Required methods

The name of the script

The script type Daemon/OneShot

The hooks that the script is interested in

The version requirement of the program that the script will run against, when running the script with Scripter::execute it will use this version to check if there is an incompatibility between the script and the program

Provided methods

Read a hook from stdin

Write a value to stdout
It takes the hook as a type argument in-order to make sure that the output provided correspond to the hook’s expected output

This function is the script entry point.

  1. It handles the initial greeting and exiting if the script type is ScriptType::OneShot
  2. It handles receiving hooks, the user is expected to provide a function that acts on a hook name, the user function should use the hook name to read the actual hook from stdin using Scripter::read

Example of a user function:


fn run(hook_name: &str) {
    match hook_name {
        MyHook::NAME => {
            let hook: MyHook = MyScript::read();
            let output = todo!(); // prepare the corresponding hook output
            MyScript::write::<MyHook>(&output);
        }
        _ => unreachable!()
    }
}

Implementors