use core::iter::Peekable;
pub mod command;
use command::Command;
use crate::error::{Error, ErrorCode, Result};
use crate::parser::parameters::Parameters;
use crate::parser::response::Formatter;
use crate::parser::tokenizer::{Token, Tokenizer};
use crate::{Context, Device};
pub mod prelude {
pub use super::{
command::{Command, CommandTypeMeta},
Node::{self, Branch, Leaf},
};
pub use crate::{
error::{Error, ErrorCode},
parser::{
format::*,
parameters::Parameters,
response::{Formatter, ResponseData, ResponseUnit},
tokenizer::{Token, Tokenizer},
},
Context, Device,
};
}
pub enum Node<'a, D> {
Leaf {
name: &'static [u8],
default: bool,
handler: &'a dyn Command<D>,
},
Branch {
name: &'static [u8],
default: bool,
sub: &'a [Node<'a, D>],
},
}
impl<'a, D> Node<'a, D> {
pub const fn leaf(name: &'static [u8], handler: &'a dyn Command<D>) -> Self {
Self::Leaf {
name,
default: false,
handler,
}
}
pub const fn default_leaf(name: &'static [u8], handler: &'a dyn Command<D>) -> Self {
Self::Leaf {
name,
default: true,
handler,
}
}
pub const fn branch(name: &'static [u8], sub: &'a [Node<'a, D>]) -> Self {
Self::Branch {
name,
default: false,
sub,
}
}
pub const fn default_branch(name: &'static [u8], sub: &'a [Node<'a, D>]) -> Self {
Self::Branch {
name,
default: true,
sub,
}
}
pub const fn root(sub: &'a [Node<'a, D>]) -> Self {
Self::Branch {
name: b"",
default: false,
sub,
}
}
}
#[macro_export]
macro_rules! Leaf {
($name:literal => $handler:expr) => {
$crate::tree::Node::Leaf {
name: $name,
default: false,
handler: $handler,
}
};
(default $name:literal => $handler:expr) => {
$crate::tree::Node::Leaf {
name: $name,
default: true,
handler: $handler,
}
};
}
#[macro_export]
macro_rules! Branch {
($name:literal; $($child:expr),+) => {
$crate::tree::Node::Branch {
name: $name,
default: false,
sub: &[
$($child),+
],
}
};
($name:literal => $handler:expr; $($child:expr),+) => {
$crate::tree::Node::Branch {
name: $name,
default: false,
sub: &[
Leaf!{default b"" => $handler },
$($child),+
],
}
};
(default $name:literal; $($child:expr),+) => {
$crate::tree::Node::Branch {
name: $name,
default: true,
sub: &[
$($child),+
],
}
};
}
#[macro_export]
macro_rules! Root {
($($child:expr),+) => {
$crate::tree::Node::Branch {
name: b"",
default: false,
sub: &[
$($child),+
],
}
};
}
impl<'a, D> Node<'a, D> {
pub fn name(&self) -> &'static [u8] {
match self {
Self::Leaf { name, .. } => name,
Self::Branch { name, .. } => name,
}
}
}
impl<'a, D> Node<'a, D>
where
D: Device,
{
pub fn run<FMT>(
&self,
command: &[u8],
device: &mut D,
context: &mut Context,
response: &mut FMT,
) -> Result<()>
where
FMT: Formatter,
{
let mut tokenizer = Tokenizer::new(command).peekable();
let res = self.run_tokens(device, context, &mut tokenizer, response);
if let Err(err) = &res {
device.handle_error(*err);
}
res
}
pub(crate) fn run_tokens<FMT>(
&self,
device: &mut D,
context: &mut Context,
tokens: &mut Peekable<Tokenizer>,
response: &mut FMT,
) -> Result<()>
where
FMT: Formatter,
{
let mut leaf = self;
response.message_start()?;
loop {
match tokens.peek() {
Some(Ok(Token::HeaderMnemonicSeparator)) => {
leaf = self;
tokens.next();
self.exec(&mut leaf, device, context, tokens, response)?;
}
Some(Ok(Token::ProgramMnemonic(s))) => {
if s.starts_with(b"*") {
let mut _x = self;
self.exec(&mut _x, device, context, tokens, response)?;
} else {
leaf.exec(&mut leaf, device, context, tokens, response)?;
}
}
None => break Ok(()),
Some(Err(err)) => break Err(Error::new(*err)),
Some(_) => break Err(ErrorCode::SyntaxError.into()),
}
match tokens.next() {
None => {
if !response.is_empty() {
response.message_end()?;
}
break Ok(());
}
Some(Ok(Token::ProgramMessageUnitSeparator)) => {
continue;
}
Some(Ok(tok)) => {
if tok.is_data() || tok == Token::ProgramDataSeparator {
break Err(ErrorCode::ParameterNotAllowed.into());
} else {
break Err(ErrorCode::SyntaxError.into());
}
}
Some(Err(err)) => break Err(Error::new(err)),
}
}
}
pub(crate) fn exec<FMT>(
&'a self,
leaf: &mut &'a Node<'a, D>,
device: &mut D,
context: &mut Context,
tokens: &mut Peekable<Tokenizer>,
response: &mut FMT,
) -> Result<()>
where
FMT: Formatter,
{
let next = match tokens.peek() {
Some(Ok(tok)) => Some(tok),
Some(Err(err)) => return Err(Error::new(*err)),
None => None,
};
match self {
Node::Leaf { handler, .. } => {
match next {
Some(Token::ProgramHeaderSeparator | Token::ProgramMessageUnitSeparator)
| None => {
tokens.next_if(|t| matches!(t, Ok(Token::ProgramHeaderSeparator)));
handler.event(device, context, Parameters::with(tokens))
}
Some(Token::HeaderQuerySuffix) => {
tokens.next();
tokens.next_if(|t| matches!(t, Ok(Token::ProgramHeaderSeparator)));
let response_unit = response.response_unit()?;
handler.query(device, context, Parameters::with(tokens), response_unit)
}
Some(Token::HeaderMnemonicSeparator | Token::ProgramMnemonic(..)) => {
Err(ErrorCode::UndefinedHeader.into())
}
Some(_) => Err(ErrorCode::SyntaxError.into()),
}
}
Node::Branch { sub, .. } => {
match next {
Some(Token::HeaderMnemonicSeparator | Token::ProgramMnemonic(..)) => {
tokens.next_if(|t| matches!(t, Ok(Token::HeaderMnemonicSeparator)));
let mnemonic = match tokens.peek() {
Some(Ok(mnemonic @ Token::ProgramMnemonic(..))) => mnemonic,
Some(Err(err)) => return Err((*err).into()),
_ => return Err(ErrorCode::CommandHeaderError.into()),
};
*leaf = self;
for child in *sub {
if mnemonic.match_program_header(child.name()) {
tokens.next(); return child.exec(leaf, device, context, tokens, response);
}
}
if let Some(child) = sub
.iter()
.find(|child| matches!(child, Node::Branch { default: true, .. }))
{
child.exec(leaf, device, context, tokens, response)
} else {
Err(ErrorCode::UndefinedHeader.into())
}
}
Some(
Token::ProgramHeaderSeparator
| Token::ProgramMessageUnitSeparator
| Token::HeaderQuerySuffix,
)
| None => {
if let Some(default_leaf) = sub
.iter()
.find(|child| matches!(child, Node::Leaf { default: true, .. }))
{
default_leaf.exec(leaf, device, context, tokens, response)
} else if let Some(default_branch) = sub
.iter()
.find(|child| matches!(child, Node::Branch { default: true, .. }))
{
default_branch.exec(leaf, device, context, tokens, response)
} else {
Err(ErrorCode::UndefinedHeader.into())
}
}
Some(_) => Err(ErrorCode::SyntaxError.into()),
}
}
}
}
}