1use std::{2 any::Any,3 fmt::{self},4 num::NonZeroU32,5 rc::Rc,6};78use jrsonnet_gcmodule::{Cc, cc_dyn};910use crate::{11 Context, Result, Thunk, Val,12 analyze::{ClosureShape, LExpr},13 function::NativeFn,14 typed::IntoUntyped,15};1617mod spec;18pub use spec::{ArrayLike, *};1920cc_dyn!(21 #[doc = "Represents a Jsonnet array value."]22 #[derive(Clone)]23 ArrValue,24 ArrayLike,25 pub fn new() {...}26);27impl fmt::Debug for ArrValue {28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {29 self.0.fmt(f)30 }31}3233pub trait ArrayLikeIter<T>: Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator {}34impl<I, T> ArrayLikeIter<T> for I where35 I: Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator36{37}3839impl ArrValue {40 pub fn empty() -> Self {41 Self::new(())42 }4344 pub fn expr(ctx: Context, shape: &ClosureShape, exprs: Rc<Vec<LExpr>>) -> Self {45 Self::new(ExprArray::new(ctx, shape, exprs))46 }4748 pub fn repeated(data: Self, repeats: u32) -> Option<Self> {49 Some(Self::new(RepeatedArray::new(data, repeats)?))50 }5152 pub fn make(len: u32, cb: NativeFn!((u32,)->Val)) -> Self {53 Self::new(MakeArray::new(len, cb))54 }5556 #[must_use]57 pub fn map(self, mapper: NativeFn!((Val) -> Val)) -> Self {58 Self::new(<MappedArray>::new(self, ArrayMapper::Plain(mapper)))59 }6061 #[must_use]62 pub fn map_with_index(self, mapper: NativeFn!((u32, Val) -> Val)) -> Self {63 Self::new(<MappedArray>::new(self, ArrayMapper::WithIndex(mapper)))64 }6566 pub fn filter(self, filter: NativeFn!((Thunk<Val>) -> bool)) -> Result<Self> {67 68 'eager: {69 let mut out = Vec::new();70 for i in self.iter() {71 let Ok(i) = i else {72 break 'eager;73 };74 if filter.call(IntoUntyped::into_lazy_untyped(i.clone()))? {75 out.push(i);76 }77 }78 return Ok(Self::new(out));79 };8081 let mut out = Vec::new();82 for i in self.iter_lazy() {83 if filter.call(i.clone())? {84 out.push(i);85 }86 }87 Ok(Self::new(out))88 }8990 pub fn extended(a: Self, b: Self) -> Option<Self> {91 Some(if a.is_empty() {92 b93 } else if b.is_empty() {94 a95 } else {96 Self::new(ExtendedArray::new(a, b)?)97 })98 }99100 pub fn range_exclusive(a: i32, b: i32) -> Self {101 Self::new(RangeArray::new_exclusive(a, b))102 }103 pub fn range_inclusive(a: i32, b: i32) -> Self {104 Self::new(RangeArray::new_inclusive(a, b))105 }106107 #[must_use]108 pub fn slice(self, index: Option<i32>, end: Option<i32>, step: Option<NonZeroU32>) -> Self {109 let get_idx = |pos: Option<i32>, len: u32, default| match pos {110 #[expect(111 clippy::cast_sign_loss,112 reason = "abs value is used, len is limited to u31"113 )]114 Some(v) if v < 0 => len.saturating_add_signed(v),115 #[expect(clippy::cast_sign_loss, reason = "abs value is used")]116 Some(v) => (v as u32).min(len),117 None => default,118 };119 let index = get_idx(index, self.len(), 0);120 let end = get_idx(end, self.len(), self.len());121 let step = step.unwrap_or_else(|| NonZeroU32::new(1).expect("1 != 0"));122123 if index >= end {124 return Self::empty();125 }126127 Self::new(SliceArray {128 inner: self,129 #[expect(clippy::cast_possible_truncation, reason = "len is limited to u31")]130 from: index as u32,131 #[expect(clippy::cast_possible_truncation, reason = "len is limited to u31")]132 to: end as u32,133 step: step.get(),134 })135 }136137 138 pub fn len(&self) -> u32 {139 self.0.len()140 }141142 143 pub fn is_empty(&self) -> bool {144 self.0.is_empty()145 }146147 pub fn is_cheap(&self) -> bool {148 self.0.is_cheap()149 }150151 152 153 154 pub fn get(&self, index: u32) -> Result<Option<Val>> {155 self.0.get(index)156 }157158 159 160 161 pub fn get_lazy(&self, index: u32) -> Option<Thunk<Val>> {162 self.0.get_lazy(index)163 }164165 pub fn iter(&self) -> impl ArrayLikeIter<Result<Val>> + '_ {166 (0..self.len()).map(|i| self.get(i).transpose().expect("length checked"))167 }168169 170 pub fn iter_lazy(&self) -> impl ArrayLikeIter<Thunk<Val>> + '_ {171 (0..self.len()).map(|i| self.get_lazy(i).expect("length checked"))172 }173174 175 #[must_use]176 pub fn reversed(self) -> Self {177 Self::new(ReverseArray(self))178 }179180 pub fn ptr_eq(a: &Self, b: &Self) -> bool {181 Cc::ptr_eq(&a.0, &b.0)182 }183184 pub fn as_any(&self) -> &dyn Any {185 &self.0186 }187}188impl<T> From<T> for ArrValue189where190 T: ArrayLike,191{192 fn from(value: T) -> Self {193 Self::new(value)194 }195}196impl<I> FromIterator<I> for ArrValue197where198 Vec<I>: ArrayLike,199{200 fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self {201 Self::new(iter.into_iter().collect::<Vec<_>>())202 }203}