use std::marker::PhantomData;
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum HandleResult<Item, HandlerIndex> {
Passed(Item),
Consumed(HandlerIndex),
}
pub type DynOutputHandler<Item> = dyn FnMut(Item) -> Option<Item> + Send + Sync;
pub struct FlowHandlerList<Item> {
handlers: Vec<Box<DynOutputHandler<Item>>>,
_marker: PhantomData<Item>,
}
impl<Item> std::fmt::Debug for FlowHandlerList<Item> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "FlowHandlerList(num={})", self.handlers.len())
}
}
impl<Item> FlowHandlerList<Item> {
pub fn new() -> Self {
Self::from_vec(vec![])
}
pub fn from_vec(vec: Vec<Box<DynOutputHandler<Item>>>) -> Self {
Self {
handlers: vec,
_marker: PhantomData,
}
}
pub fn handle(&mut self, mut item: Item) -> HandleResult<Item, usize> {
for (index, handler) in self.handlers.iter_mut().enumerate() {
match handler(item) {
Some(new_item) => item = new_item,
None => return HandleResult::Consumed(index),
}
}
HandleResult::Passed(item)
}
pub fn get_handler(&self, index: usize) -> Option<&DynOutputHandler<Item>> {
self.handlers.get(index).map(Box::as_ref)
}
pub fn add_handler(
&mut self,
handler: impl FnMut(Item) -> Option<Item> + Send + Sync + 'static,
) {
self.handlers.push(Box::new(handler))
}
}
impl<Item> Default for FlowHandlerList<Item> {
fn default() -> Self {
Self::new()
}
}
#[macro_export]
macro_rules! flow_handler_list {
[ $($handler:expr),* $(,)? ] => {
FlowHandlerList::from_vec(
vec![$(Box::new($handler)),*]
)
};
}
#[cfg(test)]
mod tests {
use super::*;
use nar_dev_utils::*;
use HandleResult::*;
#[test]
fn test_flow_handler_list() {
let handler1 = Some;
let handler2 = |x| Some(x + 1);
let handler3 = |x| if x > 1 { Some(x) } else { None };
let mut list = FlowHandlerList::new();
asserts! {
list.add_handler(handler1) => (),
list.handle(0) =>Passed(0),
list.add_handler(handler2) => (),
list.handle(0) => Passed(1),
list.add_handler(handler3) => (),
list.handle(0) => Consumed(2), list.handle(1) => Passed(2), }
let mut list = flow_handler_list![
Some,
|x: usize| Some(x + 1),
|x| Some(dbg!(x)),
|x: usize| Some(x - 1),
];
asserts! {
list.handle(0) => Passed(0)
}
}
#[test]
fn test_navm_output() {
use narsese::conversion::string::impl_lexical::shortcuts::*;
use navm::output::*;
let answer = Output::ANSWER {
content_raw: "<A --> B>.".into(),
narsese: Some(nse!(<A --> B>.)), };
let out = Output::OUT {
content_raw: "<A --> C>".into(),
narsese: Some(nse!(<A --> C>.)),
};
let mut list = flow_handler_list![
|out: Output| Some(dbg!(out)),
|out| match out {
Output::ANSWER {
content_raw,
narsese,
} => {
println!("截获到回答:{content_raw:?} | {narsese:?}");
None
}
_ => Some(out),
},
|out| {
println!("这是其它输出:{out:?}");
Some(out)
},
];
asserts! {
list.handle(answer) => Consumed(1),
list.handle(out.clone()) => Passed(out),
}
}
}