blizz-fsm 3.0.0-beta.3

Generic state machine engine for sequential state processing
Documentation
use serde_json::Value;
use std::sync::Arc;

/// A boxed closure that expands a submitted value into continuation states.
pub type AdvanceFn<S> = Box<dyn FnOnce(&str) -> Vec<Box<S>>>;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Branch {
  Next,
  JumpTo(&'static str),
  Finish,
}

/// Arc-wrapped predicate that maps accumulated answers to a [`Branch`].
#[derive(Clone)]
pub struct BranchFn(Arc<dyn Fn(&Value) -> Branch>);

impl std::fmt::Debug for BranchFn {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    f.debug_tuple("BranchFn").field(&"<closure>").finish()
  }
}

impl BranchFn {
  pub fn new(f: impl Fn(&Value) -> Branch + 'static) -> Self {
    Self(Arc::new(f))
  }

  pub fn call(&self, value: &Value) -> Branch {
    (self.0)(value)
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use serde_json::json;

  #[test]
  fn branch_fn_call_returns_branch() {
    let bf = BranchFn::new(|_| Branch::Next);
    assert_eq!(bf.call(&json!({})), Branch::Next);
  }

  #[test]
  fn branch_fn_debug_formats() {
    let bf = BranchFn::new(|_| Branch::Finish);
    let s = format!("{bf:?}");
    assert!(s.contains("BranchFn"));
  }
}