arma_rs/
group.rs

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)]
10/// A group of commands.
11/// Called from Arma using `[group]:[command]`.
12pub struct Group {
13    commands: HashMap<String, Box<Handler>>,
14    children: HashMap<String, Self>,
15    state: State,
16}
17
18impl Group {
19    #[must_use]
20    /// Creates a new group
21    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    /// Add a new state value to the group if it has not be added already
32    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    /// Freeze the group's state, preventing the state from changing, allowing for faster reads
43    pub fn freeze_state(mut self) -> Self {
44        self.state.freeze();
45        self
46    }
47
48    #[inline]
49    #[must_use]
50    /// Add a command to the group
51    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    /// Add a group to the group
64    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}