at_parser_rs/parser.rs
1use crate::context::AtContext;
2use crate::{AtError, AtResult, Args};
3
4/*
5AT Command Forms:
6- AT+CMD (execution)
7- AT+CMD? (query)
8- AT+CMD=? (test)
9- AT+CMD=... (set with arguments)
10 */
11
12/// Represents the different forms an AT command can take
13enum AtForm<'a> {
14 /// Execute command without parameters (AT+CMD)
15 Exec,
16 /// Query the current state (AT+CMD?)
17 Query,
18 /// Test command availability or get valid ranges (AT+CMD=?)
19 Test,
20 /// Set command with arguments (AT+CMD=args)
21 Set(Args<'a>),
22}
23
24/// The main AT command parser
25/// Generic over T which must implement AtContext trait
26pub struct AtParser<'a, T>
27where
28 T: AtContext {
29 /// Array of registered commands with their name and handler
30 pub commands: &'a mut [(&'static str, &'a mut T)],
31}
32
33impl<'a, T> AtParser<'a, T>
34where
35 T: AtContext {
36
37 /// Create a new empty parser
38 pub fn new() -> Self {
39 Self { commands: & mut [] }
40 }
41
42 /// Register commands that this parser will handle
43 pub fn set_commands(&mut self, commands: &'a mut [(&'static str, &'a mut T)]) {
44 self.commands = commands;
45 }
46
47 /// Parse and execute an AT command string
48 ///
49 /// # Arguments
50 /// * `input` - The raw AT command string (e.g., "AT+CMD?")
51 ///
52 /// # Returns
53 /// * `Ok(&str)` - Success response from the command handler
54 /// * `Err(AtError)` - Error if parsing fails or command is not found
55 pub fn execute(&mut self, input: &str) -> AtResult<'static> {
56 let input = input.trim();
57 let (name, form) = parse(input)?;
58
59 // Find the command handler
60 let (_, module) = self.commands
61 .iter_mut()
62 .find(|(n, _)| *n == name)
63 .ok_or(AtError::UnknownCommand)?;
64
65 // Dispatch to the appropriate handler method
66 match form {
67 AtForm::Exec => module.exec(),
68 AtForm::Query => module.query(),
69 AtForm::Test => module.test(),
70 AtForm::Set(args) => module.set(args),
71 }
72 }
73}
74
75/// Parse an AT command string into its name and form
76///
77/// # Arguments
78/// * `input` - The command string to parse
79///
80/// # Returns
81/// A tuple of (command_name, command_form)
82fn parse<'a>(input: &'a str) -> Result<(&'a str, AtForm<'a>), AtError> {
83 let input = input.trim();
84
85 // Check suffixes to determine command form
86 if let Some(cmd) = input.strip_suffix("=?") {
87 Ok((cmd, AtForm::Test))
88 } else if let Some(cmd) = input.strip_suffix('?') {
89 Ok((cmd, AtForm::Query))
90 } else if let Some((cmd, args)) = input.split_once('=') {
91 Ok((cmd, AtForm::Set(Args { raw: args })))
92 } else {
93 Ok((input, AtForm::Exec))
94 }
95}