use std::ops::Bound;
use anyhow::Result;
use reblessive::tree::Stk;
use super::args::Optional;
use crate::ctx::FrozenContext;
use crate::dbs::Options;
use crate::doc::CursorDoc;
use crate::err::Error;
use crate::val::range::TypedRange;
use crate::val::{Closure, Set, Value};
pub fn add((mut set, value): (Set, Value)) -> Result<Value> {
match value {
Value::Array(arr) => {
for v in arr.0 {
set.insert(v);
}
Ok(set.into())
}
Value::Set(other) => {
for v in other.0 {
set.insert(v);
}
Ok(set.into())
}
value => {
set.insert(value);
Ok(set.into())
}
}
}
pub fn remove((mut set, value): (Set, Value)) -> Result<Value> {
match value {
Value::Array(arr) => {
for v in arr.0 {
set.remove(&v);
}
Ok(set.into())
}
Value::Set(other) => {
for v in other.0 {
set.remove(&v);
}
Ok(set.into())
}
value => {
set.remove(&value);
Ok(set.into())
}
}
}
pub fn union((set1, set2): (Set, Set)) -> Result<Value> {
Ok(set1.union(&set2).into())
}
pub fn intersect((set1, set2): (Set, Set)) -> Result<Value> {
Ok(set1.intersection(&set2).into())
}
pub fn difference((set1, set2): (Set, Set)) -> Result<Value> {
Ok(set1.symmetric_difference(&set2).into())
}
pub fn complement((set1, set2): (Set, Set)) -> Result<Value> {
Ok(set1.complement(&set2).into())
}
pub fn len((set,): (Set,)) -> Result<Value> {
Ok(set.len().into())
}
pub fn is_empty((set,): (Set,)) -> Result<Value> {
Ok(set.is_empty().into())
}
pub fn contains((set, value): (Set, Value)) -> Result<Value> {
Ok(set.contains(&value).into())
}
pub async fn all(
(stk, ctx, opt, doc): (&mut Stk, &FrozenContext, Option<&Options>, Option<&CursorDoc>),
(set, Optional(check)): (Set, Optional<Value>),
) -> Result<Value> {
Ok(match check {
Some(Value::Closure(closure)) => {
if let Some(opt) = opt {
for arg in set {
if closure.invoke(stk, ctx, opt, doc, vec![arg]).await?.is_truthy() {
continue;
} else {
return Ok(Value::Bool(false));
}
}
Value::Bool(true)
} else {
Value::None
}
}
Some(value) => set.iter().all(|v: &Value| *v == value).into(),
None => set.iter().all(Value::is_truthy).into(),
})
}
pub async fn any(
(stk, ctx, opt, doc): (&mut Stk, &FrozenContext, Option<&Options>, Option<&CursorDoc>),
(set, Optional(check)): (Set, Optional<Value>),
) -> Result<Value> {
Ok(match check {
Some(Value::Closure(closure)) => {
if let Some(opt) = opt {
for arg in set {
if closure.invoke(stk, ctx, opt, doc, vec![arg]).await?.is_truthy() {
return Ok(Value::Bool(true));
} else {
continue;
}
}
Value::Bool(false)
} else {
Value::None
}
}
Some(value) => set.contains(&value).into(),
None => set.iter().any(Value::is_truthy).into(),
})
}
pub fn at((set, i): (Set, i64)) -> Result<Value> {
let mut idx = i;
if idx < 0 {
idx += set.len() as i64;
}
if idx < 0 {
return Ok(Value::None);
}
Ok(set.iter().nth(idx as usize).cloned().unwrap_or(Value::None))
}
pub async fn filter(
(stk, ctx, opt, doc): (&mut Stk, &FrozenContext, Option<&Options>, Option<&CursorDoc>),
(set, check): (Set, Value),
) -> Result<Value> {
Ok(match check {
Value::Closure(closure) => {
if let Some(opt) = opt {
let mut res = Set::new();
for arg in set {
if closure.invoke(stk, ctx, opt, doc, vec![arg.clone()]).await?.is_truthy() {
res.insert(arg);
}
}
res.into()
} else {
Value::None
}
}
value => set.into_iter().filter(|v: &Value| *v == value).collect::<Set>().into(),
})
}
pub async fn find(
(stk, ctx, opt, doc): (&mut Stk, &FrozenContext, Option<&Options>, Option<&CursorDoc>),
(set, value): (Set, Value),
) -> Result<Value> {
Ok(match value {
Value::Closure(closure) => {
if let Some(opt) = opt {
for arg in set {
if closure.invoke(stk, ctx, opt, doc, vec![arg.clone()]).await?.is_truthy() {
return Ok(arg);
}
}
Value::None
} else {
Value::None
}
}
value => set.into_iter().find(|v: &Value| *v == value).unwrap_or(Value::None),
})
}
pub fn first((set,): (Set,)) -> Result<Value> {
Ok(set.iter().next().cloned().unwrap_or(Value::None))
}
pub fn flatten((set,): (Set,)) -> Result<Value> {
Ok(set.flatten().into())
}
pub async fn fold(
(stk, ctx, opt, doc): (&mut Stk, &FrozenContext, Option<&Options>, Option<&CursorDoc>),
(set, init, mapper): (Set, Value, Box<Closure>),
) -> Result<Value> {
if let Some(opt) = opt {
let mut accum = init;
for val in set {
accum = mapper.invoke(stk, ctx, opt, doc, vec![accum, val]).await?
}
Ok(accum)
} else {
Ok(Value::None)
}
}
pub fn join((set, sep): (Set, String)) -> Result<Value> {
Ok(set.into_iter().map(Value::into_raw_string).collect::<Vec<_>>().join(&sep).into())
}
pub fn last((set,): (Set,)) -> Result<Value> {
Ok(set.iter().last().cloned().unwrap_or(Value::None))
}
pub async fn map(
(stk, ctx, opt, doc): (&mut Stk, &FrozenContext, Option<&Options>, Option<&CursorDoc>),
(set, mapper): (Set, Box<Closure>),
) -> Result<Value> {
if let Some(opt) = opt {
let mut res = Set::new();
for arg in set {
res.insert(mapper.invoke(stk, ctx, opt, doc, vec![arg]).await?);
}
Ok(res.into())
} else {
Ok(Value::None)
}
}
pub fn max((set,): (Set,)) -> Result<Value> {
Ok(set.into_iter().max().unwrap_or(Value::None))
}
pub fn min((set,): (Set,)) -> Result<Value> {
Ok(set.into_iter().min().unwrap_or(Value::None))
}
pub async fn reduce(
(stk, ctx, opt, doc): (&mut Stk, &FrozenContext, Option<&Options>, Option<&CursorDoc>),
(set, mapper): (Set, Box<Closure>),
) -> Result<Value> {
if let Some(opt) = opt {
match set.len() {
0 => Ok(Value::None),
1 => {
let Some(val) = set.into_iter().next() else {
return Err(Error::InvalidFunctionArguments {
name: String::from("set::reduce"),
message: String::from("Iterator should have an item at this point"),
}
.into());
};
Ok(val)
}
_ => {
let mut iter = set.into_iter();
let Some(mut accum) = iter.next() else {
return Ok(Value::None);
};
for val in iter {
accum = mapper.invoke(stk, ctx, opt, doc, vec![accum, val]).await?;
}
Ok(accum)
}
}
} else {
Ok(Value::None)
}
}
pub fn slice(
(set, Optional(range_start), Optional(end)): (Set, Optional<Value>, Optional<i64>),
) -> Result<Value> {
let Some(range_start) = range_start else {
return Ok(set.into());
};
let range = if let Some(end) = end {
let start =
range_start.coerce_to::<i64>().map_err(|e| Error::InvalidFunctionArguments {
name: String::from("set::slice"),
message: format!("Argument 1 was the wrong type. {e}"),
})?;
TypedRange {
start: Bound::Included(start),
end: Bound::Excluded(end),
}
} else if let Value::Range(range) = range_start {
range.coerce_to_typed::<i64>().map_err(|e| Error::InvalidFunctionArguments {
name: String::from("set::slice"),
message: format!("Range was the wrong type. {e}"),
})?
} else {
let start =
range_start.coerce_to::<i64>().map_err(|e| Error::InvalidFunctionArguments {
name: String::from("set::slice"),
message: format!("Argument 1 was the wrong type. {e}"),
})?;
TypedRange {
start: Bound::Included(start),
end: Bound::Unbounded,
}
};
let set_len = set.len() as i64;
let start = match range.start {
Bound::Included(x) => {
if x < 0 {
set_len.saturating_add(x).max(0) as usize
} else {
x as usize
}
}
Bound::Excluded(x) => {
if x < 0 {
set_len.saturating_add(x).saturating_add(1).max(0) as usize
} else {
x.saturating_add(1) as usize
}
}
Bound::Unbounded => 0,
};
if start >= set.len() {
return Ok(Value::Set(Set::new()));
}
let end = match range.end {
Bound::Included(x) => {
if x < 0 {
set_len.saturating_add(x).max(0) as usize
} else {
x as usize
}
}
Bound::Excluded(x) => {
if x < 0 {
let end = set_len.saturating_add(x).saturating_sub(1);
if end < start as i64 {
return Ok(Value::Set(Set::new()));
}
end as usize
} else {
if x <= start as i64 {
return Ok(Value::Set(Set::new()));
}
x.saturating_sub(1) as usize
}
}
Bound::Unbounded => usize::MAX,
};
if end < start {
return Ok(Value::Set(Set::new()));
}
let mut result = Set::new();
for (i, value) in set.into_iter().enumerate() {
if i >= start && i <= end {
result.insert(value);
} else if i > end {
break;
}
}
Ok(result.into())
}