1use std::{collections::HashMap, sync::Arc};
2
3use crate::{
4 command::{fn_handler, Factory, Handler},
5 context::{Context, GroupContext},
6 State,
7};
8
9#[derive(Default)]
10pub struct Group {
13 commands: HashMap<String, Box<Handler>>,
14 children: HashMap<String, Self>,
15 state: State,
16}
17
18impl Group {
19 #[must_use]
20 pub fn new() -> Self {
22 Self {
23 commands: HashMap::new(),
24 children: HashMap::new(),
25 state: State::default(),
26 }
27 }
28
29 #[inline]
30 #[must_use]
31 pub fn state<T>(self, state: T) -> Self
33 where
34 T: Send + Sync + 'static,
35 {
36 self.state.set(state);
37 self
38 }
39
40 #[inline]
41 #[must_use]
42 pub fn freeze_state(mut self) -> Self {
44 self.state.freeze();
45 self
46 }
47
48 #[inline]
49 #[must_use]
50 pub fn command<S, F, I, R>(mut self, name: S, handler: F) -> Self
52 where
53 S: Into<String>,
54 F: Factory<I, R> + 'static,
55 {
56 self.commands
57 .insert(name.into(), Box::new(fn_handler(handler)));
58 self
59 }
60
61 #[inline]
62 #[must_use]
63 pub fn group<S>(mut self, name: S, child: Self) -> Self
65 where
66 S: Into<String>,
67 {
68 self.children.insert(name.into(), child);
69 self
70 }
71}
72
73pub(crate) struct InternalGroup {
74 commands: HashMap<String, Box<Handler>>,
75 children: HashMap<String, Self>,
76 pub(crate) state: Arc<State>,
77}
78
79impl InternalGroup {
80 #[allow(clippy::too_many_arguments)]
81 pub(crate) fn handle(
82 &self,
83 context: Context,
84 acm: &crate::ArmaContextManager,
85 function: &str,
86 output: *mut libc::c_char,
87 size: libc::size_t,
88 args: Option<*mut *mut i8>,
89 count: Option<libc::c_int>,
90 ) -> libc::c_int {
91 if let Some((group, function)) = function.split_once(':') {
92 self.children.get(group).map_or(1, |group| {
93 group.handle(context, acm, function, output, size, args, count)
94 })
95 } else if let Some(handler) = self.commands.get(function) {
96 (handler.handler)(
97 context.with_group(GroupContext::new(self.state.clone())),
98 acm,
99 output,
100 size,
101 args,
102 count,
103 )
104 } else {
105 1
106 }
107 }
108}
109
110impl From<Group> for InternalGroup {
111 fn from(group: Group) -> Self {
112 let children = group
113 .children
114 .into_iter()
115 .map(|(name, group)| (name, Self::from(group)))
116 .collect();
117 Self {
118 commands: group.commands,
119 children,
120 state: Arc::new(group.state),
121 }
122 }
123}