yogurt/dispatcher/
builder.rs

1use super::{ExecContext, NodeType};
2use crate::argument::parser::ArgumentParser;
3use crate::argument::Argument;
4use crate::{Command, Dispatcher, Error, Result};
5use std::fmt::Debug;
6
7#[allow(clippy::type_complexity)]
8pub struct CommandBuilder<C: Debug, O> {
9    children: Vec<Command<C, O>>,
10    node: NodeType,
11    exec: Option<fn(&mut ExecContext<C>) -> Result<O>>,
12}
13
14impl<C: Debug, O> CommandBuilder<C, O> {
15    pub fn literal(name: impl Into<String>) -> Self {
16        Self {
17            children: vec![],
18            node: NodeType::Literal(name.into()),
19            exec: None,
20        }
21    }
22
23    pub fn argument(parser: impl ArgumentParser, name: impl Into<String>, required: bool) -> Self {
24        Self::argument_validator(parser.validator(), name, required)
25    }
26
27    pub fn argument_validator(
28        validator: fn(&str) -> bool,
29        name: impl Into<String>,
30        required: bool,
31    ) -> Self {
32        Self {
33            children: vec![],
34            exec: None,
35            node: NodeType::Argument(Argument::new(validator, name.into(), required)),
36        }
37    }
38
39    pub fn exec(mut self, exec: fn(&mut ExecContext<C>) -> Result<O>) -> Self {
40        self.exec = Some(exec);
41        self
42    }
43
44    pub fn child(mut self, child: impl Into<Command<C, O>>) -> Self {
45        self.children.push(child.into());
46        self
47    }
48
49    pub fn build(self) -> Command<C, O> {
50        let (mut literals, arguments): (Vec<_>, Vec<_>) =
51            self.children.into_iter().partition(|c| c.is_literal());
52        literals.extend(arguments);
53        Command {
54            children: literals,
55            node: self.node,
56            exec: self.exec,
57        }
58    }
59}
60
61pub struct DispatcherBuilder<C: Debug, O, B> {
62    root: CommandBuilder<C, O>,
63    prefix: Option<String>,
64    context_factory: Option<fn(&B) -> C>,
65    base_context: Option<B>,
66}
67
68impl<C: Debug, O, B> DispatcherBuilder<C, O, B> {
69    pub fn new() -> Self {
70        Self {
71            root: CommandBuilder::literal(""),
72            prefix: None,
73            context_factory: None,
74            base_context: None,
75        }
76    }
77
78    pub fn prefix(mut self, prefix: impl Into<String>) -> Self {
79        self.prefix = Some(prefix.into());
80        self
81    }
82
83    pub fn context_factory(mut self, factory: fn(&B) -> C) -> Self {
84        self.context_factory = Some(factory);
85        self
86    }
87
88    pub fn base_context(mut self, context: B) -> Self {
89        self.base_context = Some(context);
90        self
91    }
92
93    pub fn child(mut self, child: impl Into<Command<C, O>>) -> Self {
94        self.root.children.push(child.into());
95        self
96    }
97
98    pub fn build(self) -> Result<Dispatcher<C, O, B>> {
99        Ok(Dispatcher {
100            root: self.root.build(),
101            prefix: self.prefix.unwrap_or_default(),
102            context_factory: self.context_factory.ok_or(Error::IncompleteBuilder)?,
103            base_context: self.base_context.ok_or(Error::IncompleteBuilder)?,
104        })
105    }
106}
107
108impl<C: Debug, O, B> Default for DispatcherBuilder<C, O, B> {
109    fn default() -> Self {
110        Self {
111            root: CommandBuilder::literal(""),
112            prefix: None,
113            context_factory: None,
114            base_context: None,
115        }
116    }
117}