use crate::dbs; use crate::dbs::Executor; use crate::dbs::Options; use crate::dbs::Runtime; use crate::err::Error; use crate::sql::comment::mightbespace; use crate::sql::common::commas; use crate::sql::number::Number; use crate::sql::strand::Strand; use crate::sql::value::{value, Value}; use nom::bytes::complete::tag; use nom::combinator::opt; use nom::multi::separated_list0; use nom::IResult; use serde::ser::SerializeStruct; use serde::{Deserialize, Serialize}; use std::fmt; use std::ops; #[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Deserialize)] pub struct Array { pub value: Vec, } impl From> for Array { fn from(v: Vec) -> Self { Array { value: v, } } } impl From> for Array { fn from(v: Vec) -> Self { Array { value: v.into_iter().map(|x| x.into()).collect(), } } } impl From> for Array { fn from(v: Vec) -> Self { Array { value: v.into_iter().map(|x| x.into()).collect(), } } } impl From>> for Array { fn from(v: Vec>) -> Self { Array { value: v.into_iter().map(|x| x.into()).collect(), } } } impl<'a> From> for Array { fn from(v: Vec<&str>) -> Self { Array { value: v.into_iter().map(|v| Value::from(v)).collect(), } } } impl Array { pub fn len(&self) -> usize { self.value.len() } pub fn as_ints(self) -> Vec { self.value.into_iter().map(|v| v.as_int()).collect() } pub fn as_floats(self) -> Vec { self.value.into_iter().map(|v| v.as_float()).collect() } pub fn as_numbers(self) -> Vec { self.value.into_iter().map(|v| v.as_number()).collect() } pub fn as_strands(self) -> Vec { self.value.into_iter().map(|v| v.as_strand()).collect() } pub fn as_point(mut self) -> [f64; 2] { match self.len() { 0 => [0.0, 0.0], 1 => [self.value.remove(0).as_float(), 0.0], _ => [self.value.remove(0).as_float(), self.value.remove(0).as_float()], } } } impl fmt::Display for Array { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "[{}]", self.value.iter().map(|ref v| format!("{}", v)).collect::>().join(", ") ) } } impl dbs::Process for Array { fn process( &self, ctx: &Runtime, opt: &Options, exe: &mut Executor, doc: Option<&Value>, ) -> Result { self.value .iter() .map(|v| match v.process(ctx, opt, exe, doc) { Ok(v) => Ok(v), Err(e) => Err(e), }) .collect::, _>>() .map(|v| { Value::Array(Array { value: v, }) }) } } impl Serialize for Array { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { if serializer.is_human_readable() { serializer.serialize_some(&self.value) } else { let mut val = serializer.serialize_struct("Array", 1)?; val.serialize_field("value", &self.value)?; val.end() } } } // ------------------------------ impl ops::Add for Array { type Output = Self; fn add(mut self, other: Value) -> Self { if self.value.iter().position(|x| *x == other).is_none() { self.value.push(other) } self } } impl ops::Add for Array { type Output = Self; fn add(mut self, other: Self) -> Self { for v in other.value { if self.value.iter().position(|x| *x == v).is_none() { self.value.push(v) } } self } } // ------------------------------ impl ops::Sub for Array { type Output = Self; fn sub(mut self, other: Value) -> Self { if let Some(p) = self.value.iter().position(|x| *x == other) { self.value.remove(p); } self } } impl ops::Sub for Array { type Output = Self; fn sub(mut self, other: Self) -> Self { for v in other.value { if let Some(p) = self.value.iter().position(|x| *x == v) { self.value.remove(p); } } self } } // ------------------------------ pub trait Uniq { fn uniq(self) -> Vec; } impl Uniq for Vec { fn uniq(mut self) -> Vec { for x in (0..self.len()).rev() { for y in (x + 1..self.len()).rev() { if self[x] == self[y] { self.remove(y); } } } self } } // ------------------------------ pub trait Union { fn union(self, other: Vec) -> Vec; } impl Union for Vec { fn union(mut self, mut other: Vec) -> Vec { self.append(&mut other); self.uniq() } } // ------------------------------ pub trait Combine { fn combine(self, other: Vec) -> Vec>; } impl Combine for Vec { fn combine(self, other: Vec) -> Vec> { let mut out = Vec::new(); for a in self.iter() { for b in other.iter() { if a != b { out.push(vec![a.clone(), b.clone()]); } } } out } } // ------------------------------ pub trait Concat { fn concat(self, other: Vec) -> Vec>; } impl Concat for Vec { fn concat(self, other: Vec) -> Vec> { let mut out = Vec::new(); for a in self.iter() { for b in other.iter() { out.push(vec![a.clone(), b.clone()]); } } out } } // ------------------------------ pub trait Intersect { fn intersect(self, other: Vec) -> Vec; } impl Intersect for Vec { fn intersect(self, other: Vec) -> Vec { let mut out = Vec::new(); let mut other: Vec<_> = other.into_iter().collect(); for a in self.into_iter() { if let Some(pos) = other.iter().position(|b| a == *b) { out.push(a); other.remove(pos); } } out } } // ------------------------------ pub trait Difference { fn difference(self, other: Vec) -> Vec; } impl Difference for Vec { fn difference(self, other: Vec) -> Vec { let mut out = Vec::new(); let mut other: Vec<_> = other.into_iter().collect(); for a in self.into_iter() { if let Some(pos) = other.iter().position(|b| a == *b) { other.remove(pos); } else { out.push(a); } } out.append(&mut other); out } } // ------------------------------ pub fn array(i: &str) -> IResult<&str, Array> { let (i, _) = tag("[")(i)?; let (i, _) = mightbespace(i)?; let (i, v) = separated_list0(commas, item)(i)?; let (i, _) = mightbespace(i)?; let (i, _) = opt(tag(","))(i)?; let (i, _) = mightbespace(i)?; let (i, _) = tag("]")(i)?; Ok(( i, Array { value: v, }, )) } fn item(i: &str) -> IResult<&str, Value> { let (i, v) = value(i)?; Ok((i, v)) } #[cfg(test)] mod tests { use super::*; #[test] fn array_normal() { let sql = "[1,2,3]"; let res = array(sql); assert!(res.is_ok()); let out = res.unwrap().1; assert_eq!("[1, 2, 3]", format!("{}", out)); assert_eq!(out.value.len(), 3); } #[test] fn array_commas() { let sql = "[1,2,3,]"; let res = array(sql); assert!(res.is_ok()); let out = res.unwrap().1; assert_eq!("[1, 2, 3]", format!("{}", out)); assert_eq!(out.value.len(), 3); } #[test] fn array_expression() { let sql = "[1,2,3+1]"; let res = array(sql); assert!(res.is_ok()); let out = res.unwrap().1; assert_eq!("[1, 2, 3 + 1]", format!("{}", out)); assert_eq!(out.value.len(), 3); } }