Skip to main content

classicube_sys\command/
owned_chat_command.rs

1use core::{ffi::CStr, ptr};
2
3use crate::{
4    COMMAND_FLAG_SINGLEPLAYER_ONLY, ChatCommand,
5    bindings::{Commands_Register, cc_string},
6    std_types::{Box, CString, Vec, c_int},
7};
8
9pub struct OwnedChatCommand {
10    pub name: Box<CStr>,
11    pub help: Vec<Box<CStr>>,
12    pub command: Box<ChatCommand>,
13}
14
15impl OwnedChatCommand {
16    /// # Panics
17    ///
18    /// Panics if `name` or any entry in `help` contains an interior NUL byte.
19    pub fn new(
20        name: &str,
21        execute: unsafe extern "C" fn(args: *const cc_string, argsCount: c_int),
22        singleplayer_only: bool,
23        mut help: Vec<&str>,
24    ) -> Self {
25        let name = CString::new(name).unwrap().into_boxed_c_str();
26
27        let help: Vec<Box<CStr>> = help
28            .drain(..)
29            .map(|s| CString::new(s).unwrap().into_boxed_c_str())
30            .collect();
31
32        let help_array = [
33            #[expect(
34                clippy::get_first,
35                reason = "consistent indexing across the 5-slot array"
36            )]
37            help.get(0).map_or(ptr::null(), |cs| cs.as_ptr()),
38            help.get(1).map_or(ptr::null(), |cs| cs.as_ptr()),
39            help.get(2).map_or(ptr::null(), |cs| cs.as_ptr()),
40            help.get(3).map_or(ptr::null(), |cs| cs.as_ptr()),
41            help.get(4).map_or(ptr::null(), |cs| cs.as_ptr()),
42        ];
43
44        #[expect(
45            clippy::cast_possible_truncation,
46            reason = "COMMAND_FLAG_SINGLEPLAYER_ONLY fits in the flags u8"
47        )]
48        let flags = if singleplayer_only {
49            COMMAND_FLAG_SINGLEPLAYER_ONLY as _
50        } else {
51            0
52        };
53
54        let command = Box::new(ChatCommand {
55            name: name.as_ptr(),
56            Execute: Some(execute),
57            flags,
58            help: help_array,
59            next: ptr::null_mut(),
60        });
61
62        Self {
63            name,
64            help,
65            command,
66        }
67    }
68
69    pub fn register(&mut self) {
70        let OwnedChatCommand { command, .. } = self;
71
72        unsafe {
73            Commands_Register(command.as_mut());
74        }
75    }
76}
77
78// #[test]
79// fn test_owned_chat_command() {
80//     extern "C" fn c_command_callback(_args: *const crate::String, _args_count: c_int) {}
81//     let mut cmd = OwnedChatCommand::new("Roll", c_command_callback, false, vec![]);
82//     cmd.as_mut().register();
83// }