1use jrsonnet_gcmodule::{Cc, Trace};2use jrsonnet_interner::IBytes;3use jrsonnet_parser::LocExpr;45use crate::{function::FuncVal, Context, Result, Thunk, Val};67mod spec;8use spec::*;91011#[derive(Debug, Clone, Trace)]1213#[trace(tracking(force))]14pub enum ArrValue {15 16 Bytes(BytesArray),17 18 Lazy(LazyArray),19 20 Expr(ExprArray),21 22 Eager(EagerArray),23 24 Extended(Cc<ExtendedArray>),25 26 27 Range(RangeArray),28 29 Slice(Cc<SliceArray>),30 31 32 Reverse(Cc<ReverseArray>),33 34 Mapped(MappedArray),35 36 Repeated(RepeatedArray),37}3839pub trait ArrayLikeIter<T>: Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator {}40impl<I, T> ArrayLikeIter<T> for I where41 I: Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator42{43}4445impl ArrValue {46 pub fn empty() -> Self {47 Self::Range(RangeArray::empty())48 }4950 pub fn expr(ctx: Context, exprs: impl IntoIterator<Item = LocExpr>) -> Self {51 Self::Expr(ExprArray::new(ctx, exprs))52 }5354 pub fn lazy(thunks: Cc<Vec<Thunk<Val>>>) -> Self {55 Self::Lazy(LazyArray(thunks))56 }5758 pub fn eager(values: Cc<Vec<Val>>) -> Self {59 Self::Eager(EagerArray(values))60 }6162 pub fn repeated(data: ArrValue, repeats: usize) -> Option<Self> {63 Some(Self::Repeated(RepeatedArray::new(data, repeats)?))64 }6566 pub fn bytes(bytes: IBytes) -> Self {67 Self::Bytes(BytesArray(bytes))68 }6970 #[must_use]71 pub fn map(self, mapper: FuncVal) -> Self {72 Self::Mapped(MappedArray::new(self, mapper))73 }7475 pub fn filter(self, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {76 77 let mut out = Vec::new();78 for i in self.iter() {79 let i = i?;80 if filter(&i)? {81 out.push(i);82 };83 }84 Ok(Self::eager(Cc::new(out)))85 }8687 pub fn extended(a: ArrValue, b: ArrValue) -> Self {88 89 const ARR_EXTEND_THRESHOLD: usize = 100;9091 if a.is_empty() {92 b93 } else if b.is_empty() {94 a95 } else if a.len() + b.len() > ARR_EXTEND_THRESHOLD {96 Self::Extended(Cc::new(ExtendedArray::new(a, b)))97 } else if let (Some(a), Some(b)) = (a.iter_cheap(), b.iter_cheap()) {98 let mut out = Vec::with_capacity(a.len() + b.len());99 out.extend(a);100 out.extend(b);101 Self::eager(Cc::new(out))102 } else {103 let mut out = Vec::with_capacity(a.len() + b.len());104 out.extend(a.iter_lazy());105 out.extend(b.iter_lazy());106 Self::lazy(Cc::new(out))107 }108 }109110 pub fn range_exclusive(a: i32, b: i32) -> Self {111 Self::Range(RangeArray::new_exclusive(a, b))112 }113 pub fn range_inclusive(a: i32, b: i32) -> Self {114 Self::Range(RangeArray::new_inclusive(a, b))115 }116117 #[must_use]118 pub fn slice(119 self,120 from: Option<usize>,121 to: Option<usize>,122 step: Option<usize>,123 ) -> Option<Self> {124 let len = self.len();125 let from = from.unwrap_or(0);126 let to = to.unwrap_or(len).min(len);127 let step = step.unwrap_or(1);128 if from >= to || step == 0 {129 return None;130 }131132 Some(Self::Slice(Cc::new(SliceArray {133 inner: self,134 from: from as u32,135 to: to as u32,136 step: step as u32,137 })))138 }139140 141 pub fn len(&self) -> usize {142 pass!(self.len())143 }144145 146 pub fn is_empty(&self) -> bool {147 pass!(self.is_empty())148 }149150 151 152 153 pub fn get(&self, index: usize) -> Result<Option<Val>> {154 pass!(self.get(index))155 }156157 158 fn get_cheap(&self, index: usize) -> Option<Val> {159 pass!(self.get_cheap(index))160 }161162 163 164 165 pub fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {166 pass!(self.get_lazy(index))167 }168169 #[cfg(feature = "nightly")]170 pub fn iter(&self) -> UnknownArrayIter<'_> {171 pass_iter_call!(self.iter => UnknownArrayIter)172 }173 #[cfg(not(feature = "nightly"))]174 pub fn iter(&self) -> impl ArrayLikeIter<Result<Val>> + '_ {175 (0..self.len()).map(|i| self.get(i).transpose().expect("length checked"))176 }177178 179 #[cfg(feature = "nightly")]180 pub fn iter_lazy(&self) -> UnknownArrayIterLazy<'_> {181 pass_iter_call!(self.iter_lazy => UnknownArrayIterLazy)182 }183 #[cfg(not(feature = "nightly"))]184 pub fn iter_lazy(&self) -> impl ArrayLikeIter<Thunk<Val>> + '_ {185 (0..self.len()).map(|i| self.get_lazy(i).expect("length checked"))186 }187188 #[cfg(feature = "nightly")]189 pub fn iter_cheap(&self) -> Option<UnknownArrayIterCheap<'_>> {190 macro_rules! question {191 ($v:expr) => {192 $v?193 };194 }195 Some(pass_iter_call!(self.iter_cheap in question => UnknownArrayIterCheap))196 }197198 #[cfg(not(feature = "nightly"))]199 pub fn iter_cheap(&self) -> Option<impl ArrayLikeIter<Val> + '_> {200 if self.is_cheap() {201 Some((0..self.len()).map(|i| self.get_cheap(i).expect("length and is_cheap checked")))202 } else {203 None204 }205 }206207 208 #[must_use]209 pub fn reversed(self) -> Self {210 Self::Reverse(Cc::new(ReverseArray(self)))211 }212213 pub fn ptr_eq(a: &Self, b: &Self) -> bool {214 match (a, b) {215 (ArrValue::Bytes(a), ArrValue::Bytes(b)) => a.0 == b.0,216 (ArrValue::Lazy(a), ArrValue::Lazy(b)) => Cc::ptr_eq(&a.0, &b.0),217 (ArrValue::Expr(a), ArrValue::Expr(b)) => Cc::ptr_eq(&a.0, &b.0),218 (ArrValue::Eager(a), ArrValue::Eager(b)) => Cc::ptr_eq(&a.0, &b.0),219 (ArrValue::Extended(a), ArrValue::Extended(b)) => Cc::ptr_eq(a, b),220 (ArrValue::Range(a), ArrValue::Range(b)) => a == b,221 _ => false,222 }223 }224225 pub fn is_cheap(&self) -> bool {226 match self {227 ArrValue::Eager(_) | ArrValue::Range(..) | ArrValue::Bytes(_) => true,228 ArrValue::Extended(v) => v.a.is_cheap() && v.b.is_cheap(),229 ArrValue::Slice(r) => r.inner.is_cheap(),230 ArrValue::Reverse(i) => i.0.is_cheap(),231 ArrValue::Repeated(v) => v.is_cheap(),232 ArrValue::Expr(_) | ArrValue::Lazy(_) | ArrValue::Mapped(_) => false,233 }234 }235}236impl From<Vec<Val>> for ArrValue {237 fn from(value: Vec<Val>) -> Self {238 Self::eager(Cc::new(value))239 }240}241impl From<Vec<Thunk<Val>>> for ArrValue {242 fn from(value: Vec<Thunk<Val>>) -> Self {243 Self::lazy(Cc::new(value))244 }245}246247#[cfg(target_pointer_width = "64")]248static_assertions::assert_eq_size!(ArrValue, [u8; 16]);