use crate::ctx::Context; use crate::dbs::Options; use crate::dbs::Transaction; use crate::err::Error; use crate::sql::comment::mightbespace; use crate::sql::common::commas; use crate::sql::error::IResult; use crate::sql::fmt::{pretty_indent, Fmt, Pretty}; use crate::sql::number::Number; use crate::sql::operation::Operation; use crate::sql::serde::is_internal_serialization; use crate::sql::strand::Strand; use crate::sql::value::{value, Value}; use nom::character::complete::char; use nom::combinator::opt; use nom::multi::separated_list0; use serde::{Deserialize, Serialize}; use std::collections::HashSet; use std::fmt::{self, Display, Formatter, Write}; use std::ops; use std::ops::Deref; use std::ops::DerefMut; #[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Deserialize, Hash)] pub struct Array(pub Vec); impl From for Array { fn from(v: Value) -> Self { vec![v].into() } } impl From> for Array { fn from(v: Vec) -> Self { Self(v) } } impl From> for Array { fn from(v: Vec) -> Self { Self(v.into_iter().map(Value::from).collect()) } } impl From> for Array { fn from(v: Vec<&str>) -> Self { Self(v.into_iter().map(Value::from).collect()) } } impl From> for Array { fn from(v: Vec) -> Self { Self(v.into_iter().map(Value::from).collect()) } } impl From> for Array { fn from(v: Vec) -> Self { Self(v.into_iter().map(Value::from).collect()) } } impl From> for Array { fn from(v: Vec) -> Self { Self(v.into_iter().map(Value::from).collect()) } } impl From for Vec { fn from(s: Array) -> Self { s.0 } } impl Deref for Array { type Target = Vec; fn deref(&self) -> &Self::Target { &self.0 } } impl DerefMut for Array { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } impl IntoIterator for Array { type Item = Value; type IntoIter = std::vec::IntoIter; fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } } impl Array { pub fn new() -> Self { Self::default() } pub fn with_capacity(len: usize) -> Self { Self(Vec::with_capacity(len)) } pub fn as_ints(self) -> Vec { self.0.into_iter().map(|v| v.as_int()).collect() } pub fn as_floats(self) -> Vec { self.0.into_iter().map(|v| v.as_float()).collect() } pub fn as_numbers(self) -> Vec { self.0.into_iter().map(|v| v.as_number()).collect() } pub fn as_strands(self) -> Vec { self.0.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.0.remove(0).as_float(), 0.0], _ => [self.0.remove(0).as_float(), self.0.remove(0).as_float()], } } } impl Array { pub(crate) async fn compute( &self, ctx: &Context<'_>, opt: &Options, txn: &Transaction, doc: Option<&Value>, ) -> Result { let mut x = Self::with_capacity(self.len()); for v in self.iter() { match v.compute(ctx, opt, txn, doc).await { Ok(v) => x.push(v), Err(e) => return Err(e), }; } Ok(Value::Array(x)) } } impl Display for Array { fn fmt(&self, f: &mut Formatter) -> fmt::Result { let mut f = Pretty::from(f); f.write_char('[')?; let indent = pretty_indent(); write!(f, "{}", Fmt::pretty_comma_separated(self.as_slice()))?; drop(indent); f.write_char(']') } } impl Serialize for Array { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { if is_internal_serialization() { serializer.serialize_newtype_struct("Array", &self.0) } else { serializer.serialize_some(&self.0) } } } // ------------------------------ impl ops::Add for Array { type Output = Self; fn add(mut self, other: Value) -> Self { if !self.0.iter().any(|x| *x == other) { self.0.push(other) } self } } impl ops::Add for Array { type Output = Self; fn add(mut self, other: Self) -> Self { for v in other.0 { if !self.0.iter().any(|x| *x == v) { self.0.push(v) } } self } } // ------------------------------ impl ops::Sub for Array { type Output = Self; fn sub(mut self, other: Value) -> Self { if let Some(p) = self.0.iter().position(|x| *x == other) { self.0.remove(p); } self } } impl ops::Sub for Array { type Output = Self; fn sub(mut self, other: Self) -> Self { for v in other.0 { if let Some(p) = self.0.iter().position(|x| *x == v) { self.0.remove(p); } } self } } // ------------------------------ pub trait Abolish { fn abolish(&mut self, f: F) where F: FnMut(usize) -> bool; } impl Abolish for Vec { fn abolish(&mut self, mut f: F) where F: FnMut(usize) -> bool, { let mut i = 0; // FIXME: use drain_filter once stabilized (https://github.com/rust-lang/rust/issues/43244) // to avoid negation of the predicate return value. self.retain(|_| { let retain = !f(i); i += 1; retain }); } } // ------------------------------ pub trait Combine { fn combine(self, other: T) -> T; } impl Combine for Array { fn combine(self, other: Self) -> Array { let mut out = Self::with_capacity(self.len().saturating_mul(other.len())); for a in self.iter() { for b in other.iter() { out.push(vec![a.clone(), b.clone()].into()); } } out } } // ------------------------------ pub trait Complement { fn complement(self, other: T) -> T; } impl Complement for Array { fn complement(self, other: Self) -> Array { let mut out = Array::new(); for v in self.into_iter() { if !other.contains(&v) { out.push(v) } } out } } // ------------------------------ pub trait Concat { fn concat(self, other: T) -> T; } impl Concat for Array { fn concat(mut self, mut other: Array) -> Array { self.append(&mut other); self } } // ------------------------------ pub trait Difference { fn difference(self, other: T) -> T; } impl Difference for Array { fn difference(self, mut other: Array) -> Array { let mut out = Array::new(); for v in self.into_iter() { if let Some(pos) = other.iter().position(|w| v == *w) { other.remove(pos); } else { out.push(v); } } out.append(&mut other); out } } // ------------------------------ pub trait Flatten { fn flatten(self) -> T; } impl Flatten for Array { fn flatten(self) -> Array { let mut out = Array::new(); for v in self.into_iter() { match v { Value::Array(mut a) => out.append(&mut a), _ => out.push(v), } } out } } // ------------------------------ pub trait Intersect { fn intersect(self, other: T) -> T; } impl Intersect for Array { fn intersect(self, mut other: Self) -> Self { let mut out = Self::new(); for v in self.0.into_iter() { if let Some(pos) = other.iter().position(|w| v == *w) { other.remove(pos); out.push(v); } } out } } // ------------------------------ pub trait Union { fn union(self, other: T) -> T; } impl Union for Array { fn union(mut self, mut other: Self) -> Array { self.append(&mut other); self.uniq() } } // ------------------------------ pub trait Uniq { fn uniq(self) -> T; } impl Uniq for Array { fn uniq(mut self) -> Array { let mut set: HashSet<&Value> = HashSet::new(); let mut to_remove: Vec = Vec::new(); for (i, item) in self.iter().enumerate() { if !set.insert(item) { to_remove.push(i); } } for i in to_remove.iter().rev() { self.remove(*i); } self } } // ------------------------------ pub fn array(i: &str) -> IResult<&str, Array> { let (i, _) = char('[')(i)?; let (i, _) = mightbespace(i)?; let (i, v) = separated_list0(commas, item)(i)?; let (i, _) = mightbespace(i)?; let (i, _) = opt(char(','))(i)?; let (i, _) = mightbespace(i)?; let (i, _) = char(']')(i)?; Ok((i, Array(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_empty() { let sql = "[]"; let res = array(sql); assert!(res.is_ok()); let out = res.unwrap().1; assert_eq!("[]", format!("{}", out)); assert_eq!(out.0.len(), 0); } #[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.0.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.0.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.0.len(), 3); } #[test] fn array_fnc_uniq_normal() { let sql = "[1,2,1,3,3,4]"; let res = array(sql); assert!(res.is_ok()); let out = res.unwrap().1.uniq(); assert_eq!("[1, 2, 3, 4]", format!("{}", out)); assert_eq!(out.0.len(), 4); } }