scpi/parser/expression/
numeric_list.rs1use crate::error::{Error, ErrorCode};
7
8type Number<'a> = crate::parser::tokenizer::Token<'a>;
9
10#[derive(Clone, PartialEq, Eq, Debug)]
11pub enum Token<'a> {
12 Numeric(Number<'a>),
13 NumericRange(Number<'a>, Number<'a>),
14}
15
16#[derive(Clone)]
18pub struct NumericList<'a> {
19 pub tokenizer: crate::parser::tokenizer::Tokenizer<'a>,
20 pub first: bool,
21}
22
23impl<'a> NumericList<'a> {
24 pub fn new(s: &'a [u8]) -> NumericList<'a> {
25 NumericList {
26 tokenizer: crate::parser::tokenizer::Tokenizer::new(s),
27 first: true,
28 }
29 }
30
31 fn read_numeric_data(&mut self) -> Result<Token<'a>, ErrorCode> {
32 let begin: Number = self.tokenizer.read_nrf()?;
33 if let Some(c) = self.tokenizer.chars.clone().next() {
34 if *c == b':' {
36 self.tokenizer.chars.next();
37 let end = self.tokenizer.read_nrf()?;
38 return Ok(Token::NumericRange(begin, end));
39 }
40 }
41
42 Ok(Token::Numeric(begin))
43 }
44}
45
46impl<'a> Iterator for NumericList<'a> {
47 type Item = Result<Token<'a>, Error>;
48
49 fn next(&mut self) -> Option<Self::Item> {
50 let char = self.tokenizer.chars.clone().next()?;
52
53 Some(match char {
54 b',' if !self.first => {
55 self.tokenizer.chars.next().unwrap();
56 self.read_numeric_data().map_err(|err| {
57 Error::new(ErrorCode::InvalidExpression).extended(err.get_message())
58 })
59 }
60 x if x.is_ascii_digit() || *x == b'-' || *x == b'+' && self.first => {
61 self.first = false;
62 self.read_numeric_data().map_err(|err| {
63 Error::new(ErrorCode::InvalidExpression).extended(err.get_message())
64 })
65 }
66 _ => Err(Error::new(ErrorCode::InvalidExpression).extended(b"Invalid character")),
67 })
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 extern crate std;
76
77 #[test]
78 fn test_numeric_data() {
79 let spec = NumericList::new(b"2").read_numeric_data();
80 assert_eq!(
81 spec,
82 Ok(Token::Numeric(Number::DecimalNumericProgramData(b"2")))
83 );
84 let range = NumericList::new(b"2:5").read_numeric_data();
85 assert_eq!(
86 range,
87 Ok(Token::NumericRange(
88 Number::DecimalNumericProgramData(b"2"),
89 Number::DecimalNumericProgramData(b"5")
90 ))
91 );
92 let specfail = NumericList::new(b"2::5").read_numeric_data();
93 assert_eq!(specfail, Err(ErrorCode::NumericDataError));
94 }
95
96 #[test]
97 fn test_numeric_list() {
98 let mut expr = NumericList::new(b"3.1415,1.1:3.9e6");
99 assert_eq!(
100 expr.next().unwrap(),
101 Ok(Token::Numeric(Number::DecimalNumericProgramData(b"3.1415")))
102 );
103 assert_eq!(
104 expr.next().unwrap(),
105 Ok(Token::NumericRange(
106 Number::DecimalNumericProgramData(b"1.1"),
107 Number::DecimalNumericProgramData(b"3.9e6")
108 ))
109 );
110 assert_eq!(expr.next(), None);
111 }
112
113 #[test]
114 fn test_numeric_leading() {
115 let mut expr = NumericList::new(b",1,2:5");
116 assert_eq!(
117 expr.next().unwrap(),
118 Err(Error::new(ErrorCode::InvalidExpression).extended(b"Invalid character"))
119 );
120 }
121
122 #[test]
123 fn test_numeric_repeated() {
124 let mut expr = NumericList::new(b"1,,2:5");
125 assert_eq!(
126 expr.next().unwrap(),
127 Ok(Token::Numeric(Number::DecimalNumericProgramData(b"1")))
128 );
129 assert_eq!(
130 expr.next().unwrap(),
131 Err(Error::new(ErrorCode::InvalidExpression)
132 .extended(ErrorCode::NumericDataError.get_message()))
133 );
134 }
135}