difftreelog
refactor move arrays to use dyn ArrayLike
in: master
8 files changed
crates/jrsonnet-evaluator/src/arr/mod.rsdiffbeforeafterboth1use std::rc::Rc;1use std::any::Any;223use jrsonnet_gcmodule::{Cc, Trace};3use jrsonnet_gcmodule::{Cc, Trace};4use jrsonnet_interner::IBytes;4use jrsonnet_interner::IBytes;5use jrsonnet_parser::LocExpr;5use jrsonnet_parser::LocExpr;667use crate::{function::FuncVal, Context, Result, Thunk, Val};7use crate::{function::FuncVal, gc::TraceBox, tb, Context, Result, Thunk, Val};889mod spec;9mod spec;10pub use spec::ArrayLike;10use spec::*;11pub(crate) use spec::*;111212/// Represents a Jsonnet array value.13/// Represents a Jsonnet array value.13#[derive(Debug, Clone, Trace)]14#[derive(Debug, Clone, Trace)]14// may contrain other ArrValue15// may contrain other ArrValue15#[trace(tracking(force))]16#[trace(tracking(force))]16pub enum ArrValue {17pub struct ArrValue(Cc<TraceBox<dyn ArrayLike>>);17 /// Layout optimized byte array.18 Bytes(BytesArray),19 /// Layout optimized char array.20 Chars(CharArray),21 /// Every element is lazy evaluated.22 Lazy(LazyArray),23 /// Every element is defined somewhere in source code24 Expr(ExprArray),25 /// Every field is already evaluated.26 Eager(EagerArray),27 /// Concatenation of two arrays of any kind.28 Extended(Cc<ExtendedArray>),29 /// Represents a integer array in form `[start, start + 1, ... end - 1, end]`.30 /// This kind of arrays is generated by `std.range(start, end)` call, and used for loops.31 Range(RangeArray),32 /// Sliced array view.33 Slice(Cc<SliceArray>),34 /// Reversed array view.35 /// Returned by `std.reverse(other)` call36 Reverse(Cc<ReverseArray>),37 /// Returned by `std.map` call38 Mapped(MappedArray),39 /// Returned by `std.repeat` call40 Repeated(RepeatedArray),41}421843pub trait ArrayLikeIter<T>: Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator {}19pub trait ArrayLikeIter<T>: Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator {}44impl<I, T> ArrayLikeIter<T> for I where20impl<I, T> ArrayLikeIter<T> for I where47}23}482449impl ArrValue {25impl ArrValue {26 pub fn new(v: impl ArrayLike) -> Self {27 Self(Cc::new(tb!(v)))28 }50 pub fn empty() -> Self {29 pub fn empty() -> Self {51 Self::Range(RangeArray::empty())30 Self::new(RangeArray::empty())52 }31 }533254 pub fn expr(ctx: Context, exprs: impl IntoIterator<Item = LocExpr>) -> Self {33 pub fn expr(ctx: Context, exprs: impl IntoIterator<Item = LocExpr>) -> Self {55 Self::Expr(ExprArray::new(ctx, exprs))34 Self::new(ExprArray::new(ctx, exprs))56 }35 }573658 pub fn lazy(thunks: Cc<Vec<Thunk<Val>>>) -> Self {37 pub fn lazy(thunks: Vec<Thunk<Val>>) -> Self {59 Self::Lazy(LazyArray(thunks))38 Self::new(LazyArray(thunks))60 }39 }614062 pub fn eager(values: Vec<Val>) -> Self {41 pub fn eager(values: Vec<Val>) -> Self {63 Self::Eager(EagerArray(Cc::new(values)))42 Self::new(EagerArray(values))64 }43 }654466 pub fn repeated(data: ArrValue, repeats: usize) -> Option<Self> {45 pub fn repeated(data: ArrValue, repeats: usize) -> Option<Self> {67 Some(Self::Repeated(RepeatedArray::new(data, repeats)?))46 Some(Self::new(RepeatedArray::new(data, repeats)?))68 }47 }694870 pub fn bytes(bytes: IBytes) -> Self {49 pub fn bytes(bytes: IBytes) -> Self {71 Self::Bytes(BytesArray(bytes))50 Self::new(BytesArray(bytes))72 }51 }73 pub fn chars(chars: impl Iterator<Item = char>) -> Self {52 pub fn chars(chars: impl Iterator<Item = char>) -> Self {74 Self::Chars(CharArray(Rc::new(chars.collect())))53 Self::new(CharArray(chars.collect()))75 }54 }765577 #[must_use]56 #[must_use]78 pub fn map(self, mapper: FuncVal) -> Self {57 pub fn map(self, mapper: FuncVal) -> Self {79 Self::Mapped(MappedArray::new(self, mapper))58 Self::new(MappedArray::new(self, mapper))80 }59 }816082 pub fn filter(self, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {61 pub fn filter(self, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {100 } else if b.is_empty() {79 } else if b.is_empty() {101 a80 a102 } else if a.len() + b.len() > ARR_EXTEND_THRESHOLD {81 } else if a.len() + b.len() > ARR_EXTEND_THRESHOLD {103 Self::Extended(Cc::new(ExtendedArray::new(a, b)))82 Self::new(ExtendedArray::new(a, b))104 } else if let (Some(a), Some(b)) = (a.iter_cheap(), b.iter_cheap()) {83 } else if let (Some(a), Some(b)) = (a.iter_cheap(), b.iter_cheap()) {105 let mut out = Vec::with_capacity(a.len() + b.len());84 let mut out = Vec::with_capacity(a.len() + b.len());106 out.extend(a);85 out.extend(a);110 let mut out = Vec::with_capacity(a.len() + b.len());89 let mut out = Vec::with_capacity(a.len() + b.len());111 out.extend(a.iter_lazy());90 out.extend(a.iter_lazy());112 out.extend(b.iter_lazy());91 out.extend(b.iter_lazy());113 Self::lazy(Cc::new(out))92 Self::lazy(out)114 }93 }115 }94 }11695117 pub fn range_exclusive(a: i32, b: i32) -> Self {96 pub fn range_exclusive(a: i32, b: i32) -> Self {118 Self::Range(RangeArray::new_exclusive(a, b))97 Self::new(RangeArray::new_exclusive(a, b))119 }98 }120 pub fn range_inclusive(a: i32, b: i32) -> Self {99 pub fn range_inclusive(a: i32, b: i32) -> Self {121 Self::Range(RangeArray::new_inclusive(a, b))100 Self::new(RangeArray::new_inclusive(a, b))122 }101 }123102124 #[must_use]103 #[must_use]136 if from >= to || step == 0 {115 if from >= to || step == 0 {137 return None;116 return None;138 }117 }139 // match self {140 // ArrValue::Slice(slice) => {141 // return Some(Self::Slice(Cc::new(SliceArray {142 // inner: slice.inner.clone(),143 // from: slice.from + slice.step * (from as u32),144 // to: slice.from + (to as u32) * slice.step,145 // step: slice.step * step as u32,146 // })))147 // }148 // _ => {}149 // }150118151 Some(Self::Slice(Cc::new(SliceArray {119 Some(Self::new(SliceArray {152 inner: self,120 inner: self,153 from: from as u32,121 from: from as u32,154 to: to as u32,122 to: to as u32,155 step: step as u32,123 step: step as u32,156 })))124 }))157 }125 }158126159 /// Array length.127 /// Array length.160 pub fn len(&self) -> usize {128 pub fn len(&self) -> usize {161 pass!(self.len())129 self.0.len()162 }130 }163131164 /// Is array contains no elements?132 /// Is array contains no elements?165 pub fn is_empty(&self) -> bool {133 pub fn is_empty(&self) -> bool {166 pass!(self.is_empty())134 self.0.is_empty()167 }135 }168136169 /// Get array element by index, evaluating it, if it is lazy.137 /// Get array element by index, evaluating it, if it is lazy.170 ///138 ///171 /// Returns `None` on out-of-bounds condition.139 /// Returns `None` on out-of-bounds condition.172 pub fn get(&self, index: usize) -> Result<Option<Val>> {140 pub fn get(&self, index: usize) -> Result<Option<Val>> {173 pass!(self.get(index))141 self.0.get(index)174 }142 }175143176 /// Returns None if get is either non cheap, or out of bounds144 /// Returns None if get is either non cheap, or out of bounds177 fn get_cheap(&self, index: usize) -> Option<Val> {145 fn get_cheap(&self, index: usize) -> Option<Val> {178 pass!(self.get_cheap(index))146 self.0.get_cheap(index)179 }147 }180148181 /// Get array element by index, without evaluation.149 /// Get array element by index, without evaluation.182 ///150 ///183 /// Returns `None` on out-of-bounds condition.151 /// Returns `None` on out-of-bounds condition.184 pub fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {152 pub fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {185 pass!(self.get_lazy(index))153 self.0.get_lazy(index)186 }154 }187155188 pub fn iter(&self) -> impl ArrayLikeIter<Result<Val>> + '_ {156 pub fn iter(&self) -> impl ArrayLikeIter<Result<Val>> + '_ {205 /// Return a reversed view on current array.173 /// Return a reversed view on current array.206 #[must_use]174 #[must_use]207 pub fn reversed(self) -> Self {175 pub fn reversed(self) -> Self {208 Self::Reverse(Cc::new(ReverseArray(self)))176 Self::new(ReverseArray(self))209 }177 }210178211 pub fn ptr_eq(a: &Self, b: &Self) -> bool {179 pub fn ptr_eq(a: &Self, b: &Self) -> bool {212 match (a, b) {213 (ArrValue::Bytes(a), ArrValue::Bytes(b)) => a.0 == b.0,214 (ArrValue::Lazy(a), ArrValue::Lazy(b)) => Cc::ptr_eq(&a.0, &b.0),215 (ArrValue::Expr(a), ArrValue::Expr(b)) => Cc::ptr_eq(&a.0, &b.0),180 Cc::ptr_eq(&a.0, &b.0)216 (ArrValue::Eager(a), ArrValue::Eager(b)) => Cc::ptr_eq(&a.0, &b.0),217 (ArrValue::Extended(a), ArrValue::Extended(b)) => Cc::ptr_eq(a, b),218 (ArrValue::Range(a), ArrValue::Range(b)) => a == b,219 _ => false,220 }221 }181 }222182223 /// Is this vec supports `.get_cheap()?`183 /// Is this vec supports `.get_cheap()?`224 pub fn is_cheap(&self) -> bool {184 pub fn is_cheap(&self) -> bool {225 match self {226 ArrValue::Eager(_) | ArrValue::Range(..) | ArrValue::Bytes(_) | ArrValue::Chars(_) => {227 true228 }229 ArrValue::Extended(v) => v.a.is_cheap() && v.b.is_cheap(),230 ArrValue::Slice(r) => r.inner.is_cheap(),231 ArrValue::Reverse(i) => i.0.is_cheap(),185 self.0.is_cheap()232 ArrValue::Repeated(v) => v.is_cheap(),233 ArrValue::Expr(_) | ArrValue::Lazy(_) | ArrValue::Mapped(_) => false,234 }235 }186 }187188 pub fn as_any(&self) -> &dyn Any {189 &self.0190 }236}191}237impl From<Vec<Val>> for ArrValue {192impl From<Vec<Val>> for ArrValue {238 fn from(value: Vec<Val>) -> Self {193 fn from(value: Vec<Val>) -> Self {241}196}242impl From<Vec<Thunk<Val>>> for ArrValue {197impl From<Vec<Thunk<Val>>> for ArrValue {243 fn from(value: Vec<Thunk<Val>>) -> Self {198 fn from(value: Vec<Thunk<Val>>) -> Self {244 Self::lazy(Cc::new(value))199 Self::lazy(value)245 }200 }246}201}247impl FromIterator<Val> for ArrValue {202impl FromIterator<Val> for ArrValue {248 fn from_iter<T: IntoIterator<Item = Val>>(iter: T) -> Self {203 fn from_iter<T: IntoIterator<Item = Val>>(iter: T) -> Self {249 Self::eager(iter.into_iter().collect())204 Self::eager(iter.into_iter().collect())250 }205 }251}206}207impl ArrayLike for ArrValue {208 fn len(&self) -> usize {209 self.0.len()210 }211212 fn get(&self, index: usize) -> Result<Option<Val>> {213 self.0.get(index)214 }215216 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {217 self.0.get_lazy(index)218 }219220 fn get_cheap(&self, index: usize) -> Option<Val> {221 self.0.get_cheap(index)222 }223224 fn is_cheap(&self) -> bool {225 self.0.is_cheap()226 }227}252228253#[cfg(target_pointer_width = "64")]229#[cfg(target_pointer_width = "64")]254static_assertions::assert_eq_size!(ArrValue, [u8; 16]);230static_assertions::assert_eq_size!(ArrValue, [u8; 8]);255231crates/jrsonnet-evaluator/src/arr/spec.rsdiffbeforeafterboth1use std::{cell::RefCell, iter, mem::replace, rc::Rc};1use std::{any::Any, cell::RefCell, fmt::Debug, iter, mem::replace};223use jrsonnet_gcmodule::{Cc, Trace};3use jrsonnet_gcmodule::{Cc, Trace};4use jrsonnet_interner::{IBytes, IStr};4use jrsonnet_interner::{IBytes, IStr};13 Context, Error, Result, Thunk, Val,13 Context, Error, Result, Thunk, Val,14};14};151516pub trait ArrayLike: Sized + Into<ArrValue> {16pub trait ArrayLike: Any + Trace + Debug {17 fn len(&self) -> usize;17 fn len(&self) -> usize;18 fn is_empty(&self) -> bool {18 fn is_empty(&self) -> bool {19 self.len() == 019 self.len() == 022 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>>;22 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>>;23 fn get_cheap(&self, index: usize) -> Option<Val>;23 fn get_cheap(&self, index: usize) -> Option<Val>;242425 fn reverse(self) -> ArrValue {25 fn is_cheap(&self) -> bool;26 ArrValue::Reverse(Cc::new(ReverseArray(self.into())))27 }28}26}292730#[derive(Debug, Clone, Trace)]28#[derive(Debug, Trace)]31pub struct SliceArray {29pub struct SliceArray {32 pub(crate) inner: ArrValue,30 pub(crate) inner: ArrValue,33 pub(crate) from: u32,31 pub(crate) from: u32,62 )60 )63 }61 }64}62}65impl ArrayLike for SliceArray {63impl ArrayLike for SliceArray {66 fn len(&self) -> usize {64 fn len(&self) -> usize {67 iter::repeat(())65 iter::repeat(())68 .take((self.to - self.from) as usize)66 .take((self.to - self.from) as usize)81 fn get_cheap(&self, index: usize) -> Option<Val> {79 fn get_cheap(&self, index: usize) -> Option<Val> {82 self.iter_cheap()?.nth(index)80 self.iter_cheap()?.nth(index)83 }81 }84}85impl From<SliceArray> for ArrValue {86 fn from(value: SliceArray) -> Self {82 fn is_cheap(&self) -> bool {87 Self::Slice(Cc::new(value))83 self.inner.is_cheap()88 }84 }89}85}908691#[derive(Trace, Debug, Clone)]87#[derive(Trace, Debug)]92pub struct CharArray(pub Rc<Vec<char>>);88pub struct CharArray(pub Vec<char>);93impl ArrayLike for CharArray {89impl ArrayLike for CharArray {94 fn len(&self) -> usize {90 fn len(&self) -> usize {95 self.0.len()91 self.0.len()96 }92 }108 .get(index)104 .get(index)109 .map(|v| Val::Str(StrValue::Flat(IStr::from(*v))))105 .map(|v| Val::Str(StrValue::Flat(IStr::from(*v))))110 }106 }111}112impl From<CharArray> for ArrValue {113 fn from(value: CharArray) -> Self {107 fn is_cheap(&self) -> bool {114 ArrValue::Chars(value)108 true115 }109 }116}110}117111118#[derive(Trace, Debug, Clone)]112#[derive(Trace, Debug)]119pub struct BytesArray(pub IBytes);113pub struct BytesArray(pub IBytes);120impl ArrayLike for BytesArray {114impl ArrayLike for BytesArray {121 fn len(&self) -> usize {115 fn len(&self) -> usize {122 self.0.len()116 self.0.len()123 }117 }133 fn get_cheap(&self, index: usize) -> Option<Val> {127 fn get_cheap(&self, index: usize) -> Option<Val> {134 self.0.get(index).map(|v| Val::Num(f64::from(*v)))128 self.0.get(index).map(|v| Val::Num(f64::from(*v)))135 }129 }136}137impl From<BytesArray> for ArrValue {138 fn from(value: BytesArray) -> Self {130 fn is_cheap(&self) -> bool {139 ArrValue::Bytes(value)131 true140 }132 }141}133}142134143#[derive(Debug, Trace, Clone)]135#[derive(Debug, Trace, Clone)]144enum ArrayThunk<T: 'static + Trace> {136enum ArrayThunk<T: 'static + Trace> {148 Pending,140 Pending,149}141}150142151#[derive(Debug, Trace)]143#[derive(Debug, Trace, Clone)]152pub struct ExprArrayInner {144pub struct ExprArray {153 ctx: Context,145 ctx: Context,154 cached: RefCell<Vec<ArrayThunk<LocExpr>>>,146 cached: Cc<RefCell<Vec<ArrayThunk<LocExpr>>>>,155}147}156#[derive(Debug, Trace, Clone)]157pub struct ExprArray(pub Cc<ExprArrayInner>);158impl ExprArray {148impl ExprArray {159 pub fn new(ctx: Context, items: impl IntoIterator<Item = LocExpr>) -> Self {149 pub fn new(ctx: Context, items: impl IntoIterator<Item = LocExpr>) -> Self {160 Self(Cc::new(ExprArrayInner {150 Self {161 ctx,151 ctx,162 cached: RefCell::new(items.into_iter().map(ArrayThunk::Waiting).collect()),152 cached: Cc::new(RefCell::new(153 items.into_iter().map(ArrayThunk::Waiting).collect(),163 }))154 )),155 }164 }156 }165}157}166impl ArrayLike for ExprArray {158impl ArrayLike for ExprArray {167 fn len(&self) -> usize {159 fn len(&self) -> usize {168 self.0.cached.borrow().len()160 self.cached.borrow().len()169 }161 }170 fn get(&self, index: usize) -> Result<Option<Val>> {162 fn get(&self, index: usize) -> Result<Option<Val>> {171 if index >= self.len() {163 if index >= self.len() {172 return Ok(None);164 return Ok(None);173 }165 }174 match &self.0.cached.borrow()[index] {166 match &self.cached.borrow()[index] {175 ArrayThunk::Computed(c) => return Ok(Some(c.clone())),167 ArrayThunk::Computed(c) => return Ok(Some(c.clone())),176 ArrayThunk::Errored(e) => return Err(e.clone()),168 ArrayThunk::Errored(e) => return Err(e.clone()),177 ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),169 ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),178 ArrayThunk::Waiting(..) => {}170 ArrayThunk::Waiting(..) => {}179 };171 };180172181 let ArrayThunk::Waiting(expr) =173 let ArrayThunk::Waiting(expr) =182 replace(&mut self.0.cached.borrow_mut()[index], ArrayThunk::Pending)174 replace(&mut self.cached.borrow_mut()[index], ArrayThunk::Pending)183 else {175 else {184 unreachable!()176 unreachable!()185 };177 };186178187 let new_value = match evaluate(self.0.ctx.clone(), &expr) {179 let new_value = match evaluate(self.ctx.clone(), &expr) {188 Ok(v) => v,180 Ok(v) => v,189 Err(e) => {181 Err(e) => {190 self.0.cached.borrow_mut()[index] = ArrayThunk::Errored(e.clone());182 self.cached.borrow_mut()[index] = ArrayThunk::Errored(e.clone());191 return Err(e);183 return Err(e);192 }184 }193 };185 };194 self.0.cached.borrow_mut()[index] = ArrayThunk::Computed(new_value.clone());186 self.cached.borrow_mut()[index] = ArrayThunk::Computed(new_value.clone());195 Ok(Some(new_value))187 Ok(Some(new_value))196 }188 }197 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {189 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {215 if index >= self.len() {207 if index >= self.len() {216 return None;208 return None;217 }209 }218 match &self.0.cached.borrow()[index] {210 match &self.cached.borrow()[index] {219 ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),211 ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),220 ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),212 ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),221 ArrayThunk::Waiting(_) | ArrayThunk::Pending => {}213 ArrayThunk::Waiting(_) | ArrayThunk::Pending => {}229 fn get_cheap(&self, _index: usize) -> Option<Val> {221 fn get_cheap(&self, _index: usize) -> Option<Val> {230 None222 None231 }223 }224 fn is_cheap(&self) -> bool {225 false226 }232}227}233impl From<ExprArray> for ArrValue {234 fn from(value: ExprArray) -> Self {235 Self::Expr(value)236 }237}238228239#[derive(Trace, Debug, Clone)]229#[derive(Trace, Debug)]240pub struct ExtendedArray {230pub struct ExtendedArray {241 pub a: ArrValue,231 pub a: ArrValue,242 pub b: ArrValue,232 pub b: ArrValue,292 self.1282 self.1293 }283 }294}284}295impl ArrayLike for ExtendedArray {285impl ArrayLike for ExtendedArray {296 fn get(&self, index: usize) -> Result<Option<Val>> {286 fn get(&self, index: usize) -> Result<Option<Val>> {297 if self.split > index {287 if self.split > index {298 self.a.get(index)288 self.a.get(index)319 self.b.get_cheap(index - self.split)309 self.b.get_cheap(index - self.split)320 }310 }321 }311 }322}323impl From<ExtendedArray> for ArrValue {324 fn from(value: ExtendedArray) -> Self {312 fn is_cheap(&self) -> bool {325 Self::Extended(Cc::new(value))313 self.a.is_cheap() && self.b.is_cheap()326 }314 }327}315}328316329#[derive(Trace, Debug, Clone)]317#[derive(Trace, Debug)]330pub struct LazyArray(pub Cc<Vec<Thunk<Val>>>);318pub struct LazyArray(pub Vec<Thunk<Val>>);331impl ArrayLike for LazyArray {319impl ArrayLike for LazyArray {332 fn len(&self) -> usize {320 fn len(&self) -> usize {333 self.0.len()321 self.0.len()334 }322 }344 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {332 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {345 self.0.get(index).cloned()333 self.0.get(index).cloned()346 }334 }347}348impl From<LazyArray> for ArrValue {349 fn from(value: LazyArray) -> Self {335 fn is_cheap(&self) -> bool {350 Self::Lazy(value)336 false351 }337 }352}338}353339354#[derive(Trace, Debug, Clone)]340#[derive(Trace, Debug)]355pub struct EagerArray(pub Cc<Vec<Val>>);341pub struct EagerArray(pub Vec<Val>);356impl ArrayLike for EagerArray {342impl ArrayLike for EagerArray {357 fn len(&self) -> usize {343 fn len(&self) -> usize {358 self.0.len()344 self.0.len()359 }345 }369 fn get_cheap(&self, index: usize) -> Option<Val> {355 fn get_cheap(&self, index: usize) -> Option<Val> {370 self.0.get(index).cloned()356 self.0.get(index).cloned()371 }357 }372}373impl From<EagerArray> for ArrValue {374 fn from(value: EagerArray) -> Self {358 fn is_cheap(&self) -> bool {375 Self::Eager(value)359 true376 }360 }377}361}378362379/// Inclusive range type363/// Inclusive range type380#[derive(Debug, Trace, Clone, PartialEq, Eq)]364#[derive(Debug, Trace, PartialEq, Eq)]381pub struct RangeArray {365pub struct RangeArray {382 start: i32,366 start: i32,383 end: i32,367 end: i32,403 }387 }404}388}405389406impl ArrayLike for RangeArray {390impl ArrayLike for RangeArray {407 fn len(&self) -> usize {391 fn len(&self) -> usize {408 self.range().len()392 self.range().len()409 }393 }422 fn get_cheap(&self, index: usize) -> Option<Val> {406 fn get_cheap(&self, index: usize) -> Option<Val> {423 self.range().nth(index).map(|i| Val::Num(f64::from(i)))407 self.range().nth(index).map(|i| Val::Num(f64::from(i)))424 }408 }425}426impl From<RangeArray> for ArrValue {427 fn from(value: RangeArray) -> Self {409 fn is_cheap(&self) -> bool {428 Self::Range(value)410 true429 }411 }430}412}431413432#[derive(Debug, Trace, Clone)]414#[derive(Debug, Trace)]433pub struct ReverseArray(pub ArrValue);415pub struct ReverseArray(pub ArrValue);434impl ArrayLike for ReverseArray {416impl ArrayLike for ReverseArray {435 fn len(&self) -> usize {417 fn len(&self) -> usize {447 fn get_cheap(&self, index: usize) -> Option<Val> {429 fn get_cheap(&self, index: usize) -> Option<Val> {448 self.0.get_cheap(self.0.len() - index - 1)430 self.0.get_cheap(self.0.len() - index - 1)449 }431 }450 fn reverse(self) -> ArrValue {432 fn is_cheap(&self) -> bool {451 self.0433 self.0.is_cheap()452 }434 }453}435}454impl From<ReverseArray> for ArrValue {455 fn from(value: ReverseArray) -> Self {456 Self::Reverse(Cc::new(value))457 }458}459436460#[derive(Trace, Debug)]437#[derive(Trace, Debug, Clone)]461pub struct MappedArrayInner {438pub struct MappedArray {462 inner: ArrValue,439 inner: ArrValue,463 cached: RefCell<Vec<ArrayThunk<()>>>,440 cached: Cc<RefCell<Vec<ArrayThunk<()>>>>,464 mapper: FuncVal,441 mapper: FuncVal,465}442}466#[derive(Trace, Debug, Clone)]467pub struct MappedArray(Cc<MappedArrayInner>);468impl MappedArray {443impl MappedArray {469 pub fn new(inner: ArrValue, mapper: FuncVal) -> Self {444 pub fn new(inner: ArrValue, mapper: FuncVal) -> Self {470 let len = inner.len();445 let len = inner.len();471 Self(Cc::new(MappedArrayInner {446 Self {472 inner,447 inner,473 cached: RefCell::new(vec![ArrayThunk::Waiting(()); len]),448 cached: Cc::new(RefCell::new(vec![ArrayThunk::Waiting(()); len])),474 mapper,449 mapper,475 }))450 }476 }451 }477}452}478impl ArrayLike for MappedArray {453impl ArrayLike for MappedArray {479 fn len(&self) -> usize {454 fn len(&self) -> usize {480 self.0.cached.borrow().len()455 self.cached.borrow().len()481 }456 }482457483 fn get(&self, index: usize) -> Result<Option<Val>> {458 fn get(&self, index: usize) -> Result<Option<Val>> {484 if index >= self.len() {459 if index >= self.len() {485 return Ok(None);460 return Ok(None);486 }461 }487 match &self.0.cached.borrow()[index] {462 match &self.cached.borrow()[index] {488 ArrayThunk::Computed(c) => return Ok(Some(c.clone())),463 ArrayThunk::Computed(c) => return Ok(Some(c.clone())),489 ArrayThunk::Errored(e) => return Err(e.clone()),464 ArrayThunk::Errored(e) => return Err(e.clone()),490 ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),465 ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),491 ArrayThunk::Waiting(..) => {}466 ArrayThunk::Waiting(..) => {}492 };467 };493468494 let ArrayThunk::Waiting(_) =469 let ArrayThunk::Waiting(_) =495 replace(&mut self.0.cached.borrow_mut()[index], ArrayThunk::Pending)470 replace(&mut self.cached.borrow_mut()[index], ArrayThunk::Pending)496 else {471 else {497 unreachable!()472 unreachable!()498 };473 };499474500 let val = self475 let val = self501 .0502 .inner476 .inner503 .get(index)477 .get(index)504 .transpose()478 .transpose()505 .expect("index checked")479 .expect("index checked")506 .and_then(|r| self.0.mapper.evaluate_simple(&(r,), false));480 .and_then(|r| self.mapper.evaluate_simple(&(r,), false));507481508 let new_value = match val {482 let new_value = match val {509 Ok(v) => v,483 Ok(v) => v,510 Err(e) => {484 Err(e) => {511 self.0.cached.borrow_mut()[index] = ArrayThunk::Errored(e.clone());485 self.cached.borrow_mut()[index] = ArrayThunk::Errored(e.clone());512 return Err(e);486 return Err(e);513 }487 }514 };488 };515 self.0.cached.borrow_mut()[index] = ArrayThunk::Computed(new_value.clone());489 self.cached.borrow_mut()[index] = ArrayThunk::Computed(new_value.clone());516 Ok(Some(new_value))490 Ok(Some(new_value))517 }491 }518 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {492 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {536 if index >= self.len() {510 if index >= self.len() {537 return None;511 return None;538 }512 }539 match &self.0.cached.borrow()[index] {513 match &self.cached.borrow()[index] {540 ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),514 ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),541 ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),515 ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),542 ArrayThunk::Waiting(_) | ArrayThunk::Pending => {}516 ArrayThunk::Waiting(_) | ArrayThunk::Pending => {}551 fn get_cheap(&self, _index: usize) -> Option<Val> {525 fn get_cheap(&self, _index: usize) -> Option<Val> {552 None526 None553 }527 }528 fn is_cheap(&self) -> bool {529 false530 }554}531}555impl From<MappedArray> for ArrValue {556 fn from(value: MappedArray) -> Self {557 Self::Mapped(value)558 }559}560532561#[derive(Trace, Debug)]533#[derive(Trace, Debug)]562pub struct RepeatedArrayInner {534pub struct RepeatedArray {563 data: ArrValue,535 data: ArrValue,564 repeats: usize,536 repeats: usize,565 total_len: usize,537 total_len: usize,566}538}567#[derive(Trace, Debug, Clone)]568pub struct RepeatedArray(Cc<RepeatedArrayInner>);569impl RepeatedArray {539impl RepeatedArray {570 pub fn new(data: ArrValue, repeats: usize) -> Option<Self> {540 pub fn new(data: ArrValue, repeats: usize) -> Option<Self> {571 let total_len = data.len().checked_mul(repeats)?;541 let total_len = data.len().checked_mul(repeats)?;572 Some(Self(Cc::new(RepeatedArrayInner {542 Some(Self {573 data,543 data,574 repeats,544 repeats,575 total_len,545 total_len,576 })))546 })577 }547 }578 pub fn is_cheap(&self) -> bool {579 self.0.data.is_cheap()580 }581}548}582549583impl ArrayLike for RepeatedArray {550impl ArrayLike for RepeatedArray {584 fn len(&self) -> usize {551 fn len(&self) -> usize {585 self.0.total_len552 self.total_len586 }553 }587554588 fn get(&self, index: usize) -> Result<Option<Val>> {555 fn get(&self, index: usize) -> Result<Option<Val>> {589 if index > self.0.total_len {556 if index > self.total_len {590 return Ok(None);557 return Ok(None);591 }558 }592 self.0.data.get(index % self.0.data.len())559 self.data.get(index % self.data.len())593 }560 }594561595 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {562 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {596 if index > self.0.total_len {563 if index > self.total_len {597 return None;564 return None;598 }565 }599 self.0.data.get_lazy(index % self.0.data.len())566 self.data.get_lazy(index % self.data.len())600 }567 }601568602 fn get_cheap(&self, index: usize) -> Option<Val> {569 fn get_cheap(&self, index: usize) -> Option<Val> {603 if index > self.0.total_len {570 if index > self.total_len {604 return None;571 return None;605 }572 }606 self.0.data.get_cheap(index % self.0.data.len())573 self.data.get_cheap(index % self.data.len())607 }574 }575 fn is_cheap(&self) -> bool {576 self.data.is_cheap()577 }608}578}609impl From<RepeatedArray> for ArrValue {610 fn from(value: RepeatedArray) -> Self {611 Self::Repeated(value)612 }613}614615macro_rules! pass {616 ($t:ident.$m:ident($($ident:ident),*)) => {617 match $t {618 Self::Bytes(e) => e.$m($($ident)*),619 Self::Chars(e) => e.$m($($ident)*),620 Self::Expr(e) => e.$m($($ident)*),621 Self::Lazy(e) => e.$m($($ident)*),622 Self::Eager(e) => e.$m($($ident)*),623 Self::Range(e) => e.$m($($ident)*),624 Self::Slice(e) => e.$m($($ident)*),625 Self::Extended(e) => e.$m($($ident)*),626 Self::Reverse(e) => e.$m($($ident)*),627 Self::Mapped(e) => e.$m($($ident)*),628 Self::Repeated(e) => e.$m($($ident)*),629 }630 };631}632pub(super) use pass;633579crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth573 evaluate(self.ctx, &self.item)573 evaluate(self.ctx, &self.item)574 }574 }575 }575 }576 Val::Arr(ArrValue::lazy(Cc::new(vec![Thunk::new(ArrayElement {576 Val::Arr(ArrValue::lazy(vec![Thunk::new(ArrayElement {577 ctx,577 ctx,578 item: items[0].clone(),578 item: items[0].clone(),579 })])))579 })]))580 } else {580 } else {581 Val::Arr(ArrValue::expr(ctx, items.iter().cloned()))581 Val::Arr(ArrValue::expr(ctx, items.iter().cloned()))582 }582 }crates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth17 operator::evaluate_add_op,17 operator::evaluate_add_op,18 tb, throw,18 tb, throw,19 val::ThunkValue,19 val::ThunkValue,20 MaybeUnbound, Result, ResultExt, State, Thunk, Unbound, Val,20 MaybeUnbound, Result, State, Thunk, Unbound, Val,21};21};222223#[cfg(not(feature = "exp-preserve-order"))]23#[cfg(not(feature = "exp-preserve-order"))]crates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth6use jrsonnet_types::{ComplexValType, ValType};6use jrsonnet_types::{ComplexValType, ValType};778use crate::{8use crate::{9 arr::ArrValue,9 arr::{ArrValue, BytesArray},10 error::Result,10 error::Result,11 function::{native::NativeDesc, FuncDesc, FuncVal},11 function::{native::NativeDesc, FuncDesc, FuncVal},12 throw,12 throw,434 }434 }435435436 fn from_untyped(value: Val) -> Result<Self> {436 fn from_untyped(value: Val) -> Result<Self> {437 if let Val::Arr(ArrValue::Bytes(bytes)) = value {437 match &value {438 Val::Arr(a) => {439 if let Some(bytes) = a.as_any().downcast_ref::<BytesArray>() {440 return Ok(bytes.0.as_slice().into());438 return Ok(bytes.0);441 };439 }440 <Self as Typed>::TYPE.check(&value)?;442 <Self as Typed>::TYPE.check(&value)?;441 match value {443 // Any::downcast_ref::<ByteArray>(&a);442 Val::Arr(a) => {443 let mut out = Vec::with_capacity(a.len());444 let mut out = Vec::with_capacity(a.len());444 for e in a.iter() {445 for e in a.iter() {445 let r = e?;446 let r = e?;446 out.push(u8::from_untyped(r)?);447 out.push(u8::from_untyped(r)?);447 }448 }448 Ok(out.as_slice().into())449 Ok(out.as_slice().into())449 }450 }450 _ => unreachable!(),451 _ => {451 }452 <Self as Typed>::TYPE.check(&value)?;453 unreachable!()454 }455 }452 }456 }453}457}454458crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth9use jrsonnet_interner::IStr;9use jrsonnet_interner::IStr;10use jrsonnet_types::ValType;10use jrsonnet_types::ValType;111112pub use crate::arr::ArrValue;12pub use crate::arr::{ArrValue, ArrayLike};13use crate::{13use crate::{14 error::{Error, ErrorKind::*},14 error::{Error, ErrorKind::*},15 function::FuncVal,15 function::FuncVal,crates/jrsonnet-stdlib/src/sets.rsdiffbeforeafterboth7 val::ArrValue,7 val::ArrValue,8 Thunk, Val,8 Thunk, Val,9};9};10use jrsonnet_gcmodule::Cc;11use jrsonnet_parser::BinaryOpType;10use jrsonnet_parser::BinaryOpType;121113#[builtin]12#[builtin]70 }69 }71 };70 };72 }71 }73 Ok(ArrValue::lazy(Cc::new(out)))72 Ok(ArrValue::lazy(out))74}73}7574crates/jrsonnet-stdlib/src/sort.rsdiffbeforeafterboth10 val::{equals, ArrValue},10 val::{equals, ArrValue},11 Thunk, Val,11 Thunk, Val,12};12};13use jrsonnet_gcmodule::Cc;14use jrsonnet_parser::BinaryOpType;13use jrsonnet_parser::BinaryOpType;151416use crate::eval_on_empty;15use crate::eval_on_empty;136 values.iter().collect::<Result<Vec<Val>>>()?,135 values.iter().collect::<Result<Vec<Val>>>()?,137 )?))136 )?))138 } else {137 } else {139 Ok(ArrValue::lazy(Cc::new(sort_keyf(values, key_getter)?)))138 Ok(ArrValue::lazy(sort_keyf(values, key_getter)?))140 }139 }141}140}142141186 arr.iter().collect::<Result<Vec<Val>>>()?,185 arr.iter().collect::<Result<Vec<Val>>>()?,187 )?))186 )?))188 } else {187 } else {189 Ok(ArrValue::lazy(Cc::new(uniq_keyf(arr, keyF)?)))188 Ok(ArrValue::lazy(uniq_keyf(arr, keyF)?))190 }189 }191}190}192191204 Ok(ArrValue::eager(arr))203 Ok(ArrValue::eager(arr))205 } else {204 } else {206 let arr = sort_keyf(arr, keyF.clone())?;205 let arr = sort_keyf(arr, keyF.clone())?;207 let arr = uniq_keyf(ArrValue::lazy(Cc::new(arr)), keyF)?;206 let arr = uniq_keyf(ArrValue::lazy(arr), keyF)?;208 Ok(ArrValue::lazy(Cc::new(arr)))207 Ok(ArrValue::lazy(arr))209 }208 }210}209}211210