use crate::error::{Error, ErrorCode};
use core::convert::TryFrom;
use core::slice::Iter;
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct ChannelSpec<'a>(&'a [u8], usize);
impl<'a> IntoIterator for ChannelSpec<'a> {
type Item = Result<isize, ErrorCode>;
type IntoIter = ChannelSpecIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
ChannelSpecIterator {
chars: self.0.iter(),
}
}
}
impl<'a> ChannelSpec<'a> {
pub fn dimension(&self) -> usize {
self.1
}
pub fn len(&self) -> usize {
self.dimension()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Token<'a> {
ChannelSpec(ChannelSpec<'a>),
ChannelRange(ChannelSpec<'a>, ChannelSpec<'a>),
ModuleChannel(&'a [u8], &'a [u8]),
PathName(&'a [u8]),
}
pub struct ChannelSpecIterator<'a> {
chars: Iter<'a, u8>,
}
impl<'a> Iterator for ChannelSpecIterator<'a> {
type Item = Result<isize, ErrorCode>;
fn next(&mut self) -> Option<Self::Item> {
let x = self.chars.clone().next()?;
Some({
if *x == b'!' {
self.chars.next();
}
lexical_core::parse_partial(self.chars.as_slice())
.map(|(n, len)| {
self.chars.nth(len - 1).unwrap();
n
})
.map_err(|_| ErrorCode::ExpressionError)
})
}
}
impl<'a> TryFrom<ChannelSpec<'a>> for isize {
type Error = Error;
fn try_from(value: ChannelSpec) -> Result<Self, Self::Error> {
if value.dimension() == 1 {
let i: isize = value
.into_iter()
.next()
.unwrap_or(Err(ErrorCode::ExpressionError))?;
Ok(i)
} else {
Err(Error::new(ErrorCode::InvalidExpression).extended(b"Unexpected channel dimension"))
}
}
}
impl<'a> TryFrom<ChannelSpec<'a>> for usize {
type Error = Error;
fn try_from(value: ChannelSpec) -> Result<Self, Self::Error> {
let i: isize = value.try_into()?;
i.try_into()
.map_err(|_| ErrorCode::IllegalParameterValue.into())
}
}
impl<'a> TryFrom<ChannelSpec<'a>> for (isize, isize) {
type Error = Error;
fn try_from(value: ChannelSpec) -> Result<Self, Self::Error> {
if value.dimension() == 2 {
let i1: isize = value
.into_iter()
.next()
.unwrap_or(Err(ErrorCode::ExpressionError))?;
let i2: isize = value
.into_iter()
.next()
.unwrap_or(Err(ErrorCode::ExpressionError))?;
Ok((i1, i2))
} else {
Err(Error::new(ErrorCode::ExpressionError).extended(b"Unexpected channel dimension"))
}
}
}
impl<'a> TryFrom<ChannelSpec<'a>> for (usize, usize) {
type Error = Error;
fn try_from(value: ChannelSpec) -> Result<Self, Self::Error> {
let (i1, i2): (isize, isize) = value.try_into()?;
Ok((
i1.try_into()
.map_err(|_| Error::new(ErrorCode::IllegalParameterValue))?,
i2.try_into()
.map_err(|_| Error::new(ErrorCode::IllegalParameterValue))?,
))
}
}
impl<'a> TryFrom<ChannelSpec<'a>> for (isize, isize, isize) {
type Error = Error;
fn try_from(value: ChannelSpec) -> Result<Self, Self::Error> {
if value.dimension() == 3 {
let i1: isize = value
.into_iter()
.next()
.unwrap_or(Err(ErrorCode::ExpressionError))?;
let i2: isize = value
.into_iter()
.next()
.unwrap_or(Err(ErrorCode::ExpressionError))?;
let i3: isize = value
.into_iter()
.next()
.unwrap_or(Err(ErrorCode::ExpressionError))?;
Ok((i1, i2, i3))
} else {
Err(Error::new(ErrorCode::ExpressionError).extended(b"Unexpected channel dimension"))
}
}
}
impl<'a> TryFrom<ChannelSpec<'a>> for (usize, usize, usize) {
type Error = Error;
fn try_from(value: ChannelSpec) -> Result<Self, Self::Error> {
let (i1, i2, i3): (isize, isize, isize) = value.try_into()?;
Ok((
i1.try_into()
.map_err(|_| Error::new(ErrorCode::IllegalParameterValue))?,
i2.try_into()
.map_err(|_| Error::new(ErrorCode::IllegalParameterValue))?,
i3.try_into()
.map_err(|_| Error::new(ErrorCode::IllegalParameterValue))?,
))
}
}
#[derive(Clone)]
pub struct ChannelList<'a> {
pub chars: Iter<'a, u8>,
pub first: bool,
}
impl<'a> ChannelList<'a> {
pub fn new(expr: &'a [u8]) -> Option<Self> {
let mut iter = expr.iter();
if let Some(x) = iter.next() {
if *x == b'@' {
Some(ChannelList {
chars: iter.clone(),
first: true,
})
} else {
None
}
} else {
None
}
}
fn read_channel_spec(&mut self) -> Result<(&'a [u8], usize), ErrorCode> {
let mut dim = 1usize;
let s = self.chars.as_slice();
while self.chars.clone().next().map_or(false, |ch| {
ch.is_ascii_digit() || *ch == b'-' || *ch == b'+' || *ch == b'!'
}) {
if let Some(x) = self.chars.next() {
if *x == b'!' {
dim += 1;
}
}
}
let s = &s[0..s.len() - self.chars.as_slice().len()];
if s.is_empty() {
Err(ErrorCode::InvalidExpression)
} else {
Ok((s, dim))
}
}
fn read_channel_range(&mut self) -> Result<Token<'a>, ErrorCode> {
let (begin, dim1) = self.read_channel_spec()?;
if let Some(x) = self.chars.clone().next() {
if *x == b':' {
self.chars.next();
let (end, dim2) = self.read_channel_spec()?;
if dim1 != dim2 {
return Err(ErrorCode::InvalidExpression);
}
return Ok(Token::ChannelRange(
ChannelSpec(begin, dim1),
ChannelSpec(end, dim2),
));
}
}
Ok(Token::ChannelSpec(ChannelSpec(begin, dim1)))
}
fn read_channel_path(&mut self, x: u8) -> Result<Token<'a>, ErrorCode> {
let s = self.chars.as_slice();
if let crate::parser::tokenizer::Token::StringProgramData(s) =
crate::parser::tokenizer::Tokenizer::new(s).read_string_data(x, true)?
{
self.chars.nth(s.len() + 1); Ok(Token::PathName(s))
} else {
Err(ErrorCode::InvalidExpression)
}
}
}
impl<'a> Iterator for ChannelList<'a> {
type Item = Result<Token<'a>, ErrorCode>;
fn next(&mut self) -> Option<Self::Item> {
let mut x = self.chars.clone().next()?;
if *x == b',' {
if self.first {
return Some(Err(ErrorCode::InvalidExpression));
}
self.chars.next().unwrap();
x = self.chars.clone().next()?;
}
self.first = false;
Some(match x {
x if x.is_ascii_digit() || *x == b'+' || *x == b'-' => self.read_channel_range(),
x if *x == b'"' || *x == b'\'' => self.read_channel_path(*x),
_ => Err(ErrorCode::InvalidExpression),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
extern crate std;
#[test]
fn test_channel_list() {
let mut expr = ChannelList::new(b"@1!12,3!4:5!6,'POTATO'").unwrap();
let spec = expr.next().unwrap().unwrap();
assert_eq!(spec, Token::ChannelSpec(ChannelSpec(b"1!12", 2)));
if let Token::ChannelSpec(spec) = spec {
let mut spec_iter = spec.into_iter();
assert_eq!(Some(Ok(1)), spec_iter.next());
assert_eq!(Some(Ok(12)), spec_iter.next());
assert_eq!(None, spec_iter.next());
} else {
panic!("Not a channel spec")
}
let range = expr.next().unwrap().unwrap();
assert_eq!(
range,
Token::ChannelRange(ChannelSpec(b"3!4", 2), ChannelSpec(b"5!6", 2))
);
if let Token::ChannelRange(begin, end) = range {
let mut begin_iter = begin.into_iter();
assert_eq!(Some(Ok(3)), begin_iter.next());
assert_eq!(Some(Ok(4)), begin_iter.next());
assert_eq!(None, begin_iter.next());
let mut end_iter = end.into_iter();
assert_eq!(Some(Ok(5)), end_iter.next());
assert_eq!(Some(Ok(6)), end_iter.next());
assert_eq!(None, end_iter.next());
} else {
panic!("Not a channel range")
}
assert_eq!(expr.next(), Some(Ok(Token::PathName(b"POTATO"))));
assert_eq!(expr.next(), None);
}
}