1#![allow(non_snake_case)]23use std::cmp::Ordering;45use jrsonnet_evaluator::{6 error::Result,7 function::{builtin, FuncVal},8 operator::evaluate_compare_op,9 throw,10 val::{equals, ArrValue},11 Thunk, Val,12};13use jrsonnet_parser::BinaryOpType;1415use crate::eval_on_empty;1617#[derive(Copy, Clone)]18enum SortKeyType {19 Number,20 String,21 Unknown,22}2324#[derive(PartialEq)]25struct NonNaNf64(f64);26impl PartialOrd for NonNaNf64 {27 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {28 Some(self.cmp(other))29 }30}31impl Eq for NonNaNf64 {}32impl Ord for NonNaNf64 {33 fn cmp(&self, other: &Self) -> std::cmp::Ordering {34 self.0.partial_cmp(&other.0).expect("non nan")35 }36}3738fn get_sort_type<T>(values: &[T], key_getter: impl Fn(&T) -> &Val) -> Result<SortKeyType> {39 let mut sort_type = SortKeyType::Unknown;40 for i in values.iter() {41 let i = key_getter(i);42 match (i, sort_type) {43 (Val::Str(_), SortKeyType::Unknown) => sort_type = SortKeyType::String,44 (Val::Num(_), SortKeyType::Unknown) => sort_type = SortKeyType::Number,45 (Val::Str(_), SortKeyType::String) | (Val::Num(_), SortKeyType::Number) => {}46 (Val::Str(_) | Val::Num(_), _) => {47 throw!("sort elements should have the same types")48 }49 _ => {}50 }51 }52 Ok(sort_type)53}5455fn sort_identity(mut values: Vec<Val>) -> Result<Vec<Val>> {56 57 let sort_type = get_sort_type(&values, |k| k)?;58 match sort_type {59 SortKeyType::Number => values.sort_unstable_by_key(|v| match v {60 Val::Num(n) => NonNaNf64(*n),61 _ => unreachable!(),62 }),63 SortKeyType::String => values.sort_unstable_by_key(|v| match v {64 Val::Str(s) => s.clone(),65 _ => unreachable!(),66 }),67 SortKeyType::Unknown => {68 let mut err = None;69 70 71 values.sort_unstable_by(|a, b| match evaluate_compare_op(a, b, BinaryOpType::Lt) {72 Ok(ord) => ord,73 Err(e) if err.is_none() => {74 let _ = err.insert(e);75 Ordering::Equal76 }77 Err(_) => Ordering::Equal,78 });79 if let Some(err) = err {80 return Err(err);81 }82 }83 };84 Ok(values)85}8687fn sort_keyf(values: ArrValue, keyf: FuncVal) -> Result<Vec<Thunk<Val>>> {88 89 let mut vk = Vec::with_capacity(values.len());90 for value in values.iter_lazy() {91 vk.push((92 value.clone(),93 keyf.evaluate_simple(&(value.clone(),), false)?,94 ));95 }96 let sort_type = get_sort_type(&vk, |v| &v.1)?;97 match sort_type {98 SortKeyType::Number => vk.sort_by_key(|v| match v.1 {99 Val::Num(n) => NonNaNf64(n),100 _ => unreachable!(),101 }),102 SortKeyType::String => vk.sort_by_key(|v| match &v.1 {103 Val::Str(s) => s.clone(),104 _ => unreachable!(),105 }),106 SortKeyType::Unknown => {107 let mut err = None;108 109 110 vk.sort_by(111 |(_a, ak), (_b, bk)| match evaluate_compare_op(ak, bk, BinaryOpType::Lt) {112 Ok(ord) => ord,113 Err(e) if err.is_none() => {114 let _ = err.insert(e);115 Ordering::Equal116 }117 Err(_) => Ordering::Equal,118 },119 );120 if let Some(err) = err {121 return Err(err);122 }123 }124 };125 Ok(vk.into_iter().map(|v| v.0).collect())126}127128129pub fn sort(values: ArrValue, key_getter: FuncVal) -> Result<ArrValue> {130 if values.len() <= 1 {131 return Ok(values);132 }133 if key_getter.is_identity() {134 Ok(ArrValue::eager(sort_identity(135 values.iter().collect::<Result<Vec<Val>>>()?,136 )?))137 } else {138 Ok(ArrValue::lazy(sort_keyf(values, key_getter)?))139 }140}141142#[builtin]143pub fn builtin_sort(arr: ArrValue, keyF: Option<FuncVal>) -> Result<ArrValue> {144 super::sort::sort(arr, keyF.unwrap_or_else(FuncVal::identity))145}146147fn uniq_identity(arr: Vec<Val>) -> Result<Vec<Val>> {148 let mut out = Vec::new();149 let mut last = arr[0].clone();150 out.push(last.clone());151 for next in arr.into_iter().skip(1) {152 if !equals(&last, &next)? {153 out.push(next.clone());154 }155 last = next;156 }157 Ok(out)158}159160fn uniq_keyf(arr: ArrValue, keyf: FuncVal) -> Result<Vec<Thunk<Val>>> {161 let mut out = Vec::new();162 let last_value = arr.get_lazy(0).unwrap();163 let mut last_key = keyf.evaluate_simple(&(last_value.clone(),), false)?;164 out.push(last_value);165166 for next in arr.iter_lazy().skip(1) {167 let next_key = keyf.evaluate_simple(&(next.clone(),), false)?;168 if !equals(&last_key, &next_key)? {169 out.push(next.clone());170 }171 last_key = next_key;172 }173 Ok(out)174}175176#[builtin]177#[allow(non_snake_case)]178pub fn builtin_uniq(arr: ArrValue, keyF: Option<FuncVal>) -> Result<ArrValue> {179 if arr.len() <= 1 {180 return Ok(arr);181 }182 let keyF = keyF.unwrap_or(FuncVal::identity());183 if keyF.is_identity() {184 Ok(ArrValue::eager(uniq_identity(185 arr.iter().collect::<Result<Vec<Val>>>()?,186 )?))187 } else {188 Ok(ArrValue::lazy(uniq_keyf(arr, keyF)?))189 }190}191192#[builtin]193#[allow(non_snake_case)]194pub fn builtin_set(arr: ArrValue, keyF: Option<FuncVal>) -> Result<ArrValue> {195 if arr.len() <= 1 {196 return Ok(arr);197 }198 let keyF = keyF.unwrap_or(FuncVal::identity());199 if keyF.is_identity() {200 let arr = arr.iter().collect::<Result<Vec<Val>>>()?;201 let arr = sort_identity(arr)?;202 let arr = uniq_identity(arr)?;203 Ok(ArrValue::eager(arr))204 } else {205 let arr = sort_keyf(arr, keyF.clone())?;206 let arr = uniq_keyf(ArrValue::lazy(arr), keyF)?;207 Ok(ArrValue::lazy(arr))208 }209}210211fn eval_keyf(val: Val, key_f: &Option<FuncVal>) -> Result<Val> {212 if let Some(key_f) = key_f {213 key_f.evaluate_simple(&(val,), false)214 } else {215 Ok(val)216 }217}218219fn array_top1(arr: ArrValue, key_f: Option<FuncVal>, ordering: Ordering) -> Result<Val> {220 let mut iter = arr.iter();221 let mut min = iter.next().expect("not empty")?;222 let mut min_key = eval_keyf(min.clone(), &key_f)?;223 for item in iter {224 let cur = item?;225 let cur_key = eval_keyf(cur.clone(), &key_f)?;226 if evaluate_compare_op(&cur_key, &min_key, BinaryOpType::Lt)? == ordering {227 min = cur;228 min_key = cur_key;229 }230 }231 Ok(min)232}233234#[builtin]235pub fn builtin_min_array(236 arr: ArrValue,237 keyF: Option<FuncVal>,238 onEmpty: Option<Thunk<Val>>,239) -> Result<Val> {240 if arr.is_empty() {241 return eval_on_empty(onEmpty);242 }243 array_top1(arr, keyF, Ordering::Less)244}245#[builtin]246pub fn builtin_max_array(247 arr: ArrValue,248 keyF: Option<FuncVal>,249 onEmpty: Option<Thunk<Val>>,250) -> Result<Val> {251 if arr.is_empty() {252 return eval_on_empty(onEmpty);253 }254 array_top1(arr, keyF, Ordering::Greater)255}