use crate::iter::ConcatIterator;
use crate::parser::{comment, tabspaces};
use combine::parser::char::{alpha_num, char, digit, newline, spaces};
use combine::parser::combinator::attempt;
use combine::sep_end_by;
use combine::stream::Stream;
use combine::token;
use combine::{between, choice, eof, many, many1, sep_by1};
#[allow(non_camel_case_types)]
type number = u64;
#[derive(Default, Debug, PartialEq, Clone)]
struct NodeaggSubRange {
start: number,
stop: number,
}
impl NodeaggSubRange {
fn iter(&self) -> impl Iterator<Item = number> {
self.start..=self.stop
}
}
#[derive(Default, Debug, PartialEq, Clone)]
struct NodeaggSubNumber(number);
impl NodeaggSubNumber {
fn iter(&self) -> impl Iterator<Item = number> {
std::iter::once(self.0)
}
}
#[derive(Debug, PartialEq, Clone)]
enum NodeaggSubArrayElementKind {
Range(NodeaggSubRange),
Number(NodeaggSubNumber),
}
#[derive(Debug, PartialEq, Clone)]
struct NodeaggSubArrayElement {
width: usize,
inner: NodeaggSubArrayElementKind,
}
impl NodeaggSubArrayElement {
fn iter(&self) -> Box<dyn Iterator<Item = number> + '_> {
match &self.inner {
NodeaggSubArrayElementKind::Range(v) => Box::new(v.iter()),
NodeaggSubArrayElementKind::Number(v) => Box::new(v.iter()),
}
}
}
#[derive(Default, Debug, PartialEq, Clone)]
struct NodeaggSubArray {
values: Vec<NodeaggSubArrayElement>,
}
impl Extend<NodeaggSubArrayElement> for NodeaggSubArray {
fn extend<T: IntoIterator<Item = NodeaggSubArrayElement>>(&mut self, iter: T) {
self.values.extend(iter);
}
}
impl NodeaggSubArray {
fn iter(&self) -> Box<dyn Iterator<Item = String> + '_> {
let width = self.values.iter().map(|x| x.width).max().unwrap();
Box::new(
(ConcatIterator {
itrs: self.values.iter().map(|e| e.iter()).collect::<Vec<_>>(),
})
.map(move |x| format!("{0:0>1$}", x, width)),
)
}
}
#[derive(Debug, PartialEq, Clone)]
enum NodeaggSubExpr {
NodeaggSub(String),
Array(NodeaggSubArray),
}
#[derive(Default, Debug, Clone, PartialEq)]
struct NodeaggBaseExpr(Vec<NodeaggSubExpr>);
impl Extend<NodeaggSubExpr> for NodeaggBaseExpr {
fn extend<T: IntoIterator<Item = NodeaggSubExpr>>(&mut self, iter: T) {
self.0.extend(iter);
}
}
impl NodeaggSubExpr {
pub fn iter(&self) -> Box<dyn Iterator<Item = String> + '_> {
match self {
NodeaggSubExpr::NodeaggSub(s) => Box::new(std::iter::once(s.clone())),
NodeaggSubExpr::Array(a) => a.iter(),
}
}
}
impl NodeaggBaseExpr {
pub fn iter(&self) -> Box<dyn Iterator<Item = String> + '_> {
use itertools::Itertools;
if self.0.len() == 0 {
Box::new(std::iter::empty::<String>())
} else {
Box::new(
self.0
.iter()
.clone()
.map(|e| e.iter().map(|s| s.to_string()).collect::<Vec<String>>())
.multi_cartesian_product()
.map(|v| {
v.iter()
.map(|s| s.to_string())
.collect::<Vec<String>>()
.join("")
}),
)
}
}
}
#[derive(Default, Debug, Clone)]
pub(crate) struct NodeaggExpr(Vec<NodeaggBaseExpr>);
impl Extend<NodeaggBaseExpr> for NodeaggExpr {
fn extend<T: IntoIterator<Item = NodeaggBaseExpr>>(&mut self, iter: T) {
self.0.extend(iter);
}
}
impl NodeaggExpr {
pub(crate) fn iter(&self) -> itertools::Unique<ConcatIterator<'_, String>> {
use itertools::Itertools;
(ConcatIterator {
itrs: self.0.iter().map(|e| e.iter()).collect::<Vec<_>>(),
})
.unique()
}
}
parser! {
fn nodeagg_sub_expr[Input]()(Input) -> NodeaggSubExpr
where [Input: Stream<Token = char>]
{
use std::cmp::max;
let word = many1(alpha_num().or(char('.')).or(char('-')));
let number = many1(digit()).map(|t: String|
NodeaggSubArrayElement {
width: t.len(),
inner: NodeaggSubArrayElementKind::Number (
NodeaggSubNumber(t.parse::<number>().unwrap())
)}
);
let range = (many1(digit()), char('-'), many1(digit())).map(|t: (String, _, String)|
NodeaggSubArrayElement {
width: max(t.0.len(), t.2.len()),
inner: NodeaggSubArrayElementKind::Range (
NodeaggSubRange {
start: t.0.parse::<number>().unwrap(),
stop: t.2.parse::<number>().unwrap(),
})}
);
let comma_list = sep_by1::<NodeaggSubArray, _, _, _>(
attempt(range).or(number)
, char(','));
let array = between(char('['), char(']'), comma_list);
choice((
word.map(NodeaggSubExpr::NodeaggSub),
array.map(NodeaggSubExpr::Array),
))
}
}
parser! {
fn nodeagg_base_expr[Input]()(Input) -> NodeaggBaseExpr
where [Input: Stream<Token = char>]
{
many(nodeagg_sub_expr()).skip(tabspaces())
}
}
parser! {
pub(crate) fn nodeagg_expr[Input]()(Input) -> NodeaggExpr
where [Input: Stream<Token = char>]
{
spaces().with(sep_end_by(nodeagg_base_expr().skip(comment()),
(token(',').or(newline())).skip(tabspaces()).skip(comment())
)).skip(tabspaces().skip(comment()).with(eof()))
}}
#[cfg(test)]
mod tests {
use super::*;
use combine::EasyParser;
use combine::Parser;
impl From<Vec<NodeaggSubExpr>> for NodeaggBaseExpr {
fn from(item: Vec<NodeaggSubExpr>) -> Self {
NodeaggBaseExpr(item)
}
}
impl From<NodeaggExpr> for Vec<NodeaggBaseExpr> {
fn from(item: NodeaggExpr) -> Self {
item.0
}
}
impl From<Vec<NodeaggBaseExpr>> for NodeaggExpr {
fn from(item: Vec<NodeaggBaseExpr>) -> Self {
NodeaggExpr(item)
}
}
impl PartialEq for NodeaggExpr {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
#[test]
fn _nodeagg_sub_expr() {
assert!(nodeagg_sub_expr().parse("").is_err());
assert_eq!(
nodeagg_sub_expr().parse("node"),
Ok((NodeaggSubExpr::NodeaggSub("node".to_string()), ""))
);
assert_eq!(
nodeagg_sub_expr().parse("123"),
Ok((NodeaggSubExpr::NodeaggSub("123".to_string()), ""))
);
assert!(nodeagg_sub_expr().parse("[]").is_err());
assert!(nodeagg_sub_expr().parse("[1]").is_ok());
assert!(nodeagg_sub_expr().parse("[01,02]").is_ok());
assert!(nodeagg_sub_expr().parse("[01-02]").is_ok());
assert_eq!(
nodeagg_sub_expr()
.parse("[1,2,3-4]")
.unwrap()
.0
.iter()
.collect::<String>()
.len(),
4
);
}
#[test]
fn _nodeagg_base_expr() {
assert_eq!(nodeagg_base_expr().parse(""), Ok((vec![].into(), "")));
assert_eq!(
nodeagg_base_expr().parse("123"),
Ok((
vec![NodeaggSubExpr::NodeaggSub("123".to_string())].into(),
""
))
);
assert_eq!(
nodeagg_base_expr().parse("node "),
Ok((
vec![NodeaggSubExpr::NodeaggSub("node".to_string())].into(),
""
))
);
assert!(nodeagg_base_expr().parse("[]").is_err());
assert!(nodeagg_base_expr().parse("[1]").is_ok());
assert!(nodeagg_base_expr().parse("node1,node2").is_ok());
assert!(nodeagg_base_expr().parse("[1,2]").is_ok());
assert!(nodeagg_base_expr().parse("[1-2]").is_ok());
assert!(nodeagg_base_expr().parse("anode[01-02]").is_ok());
}
#[test]
fn _nodeagg_expr() {
assert_eq!(
nodeagg_expr().easy_parse("node1,node2"),
Ok((
vec![
nodeagg_base_expr().parse("node1").unwrap().0,
nodeagg_base_expr().parse("node2").unwrap().0
]
.into(),
""
))
);
assert_eq!(
nodeagg_expr()
.parse("anode[01-02],bnode2")
.unwrap()
.0
.iter()
.collect::<Vec<_>>(),
vec!["anode01", "anode02", "bnode2"]
);
assert!(nodeagg_expr().parse("node1, node2").is_ok());
assert!(nodeagg_expr().parse(" node1,node2").is_ok());
assert!(nodeagg_expr().parse("node1,node2 ").is_ok());
assert!(nodeagg_expr().parse("node1\nnode2").is_ok());
assert!(nodeagg_expr().parse("node1 a").is_err());
}
}