1use std::{2 any::Any,3 fmt::{self},4 num::NonZeroU32,5 rc::Rc,6};78use jrsonnet_gcmodule::{Cc, cc_dyn};9use jrsonnet_ir::Expr;1011use crate::{Context, Result, Thunk, Val, function::NativeFn, typed::IntoUntyped};1213mod spec;14pub use spec::{ArrayLike, *};1516cc_dyn!(17 #[doc = "Represents a Jsonnet array value."]18 #[derive(Clone)]19 ArrValue,20 ArrayLike,21 pub fn new() {...}22);23impl fmt::Debug for ArrValue {24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {25 self.0.fmt(f)26 }27}2829pub trait ArrayLikeIter<T>: Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator {}30impl<I, T> ArrayLikeIter<T> for I where31 I: Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator32{33}3435impl ArrValue {36 pub fn empty() -> Self {37 Self::new(())38 }3940 pub fn expr(ctx: Context, exprs: Rc<Vec<Expr>>) -> Self {41 Self::new(ExprArray::new(ctx, exprs))42 }4344 pub fn repeated(data: Self, repeats: usize) -> Option<Self> {45 Some(Self::new(RepeatedArray::new(data, repeats)?))46 }4748 #[must_use]49 pub fn map(self, mapper: NativeFn!((Val) -> Val)) -> Self {50 Self::new(<MappedArray>::new(self, ArrayMapper::Plain(mapper)))51 }5253 #[must_use]54 pub fn map_with_index(self, mapper: NativeFn!((u32, Val) -> Val)) -> Self {55 Self::new(<MappedArray>::new(self, ArrayMapper::WithIndex(mapper)))56 }5758 pub fn filter(self, filter: NativeFn!((Thunk<Val>) -> bool)) -> Result<Self> {59 60 'eager: {61 let mut out = Vec::new();62 for i in self.iter() {63 let Ok(i) = i else {64 break 'eager;65 };66 if filter.call(IntoUntyped::into_lazy_untyped(i.clone()))? {67 out.push(i);68 }69 }70 return Ok(Self::new(out));71 };7273 let mut out = Vec::new();74 for i in self.iter_lazy() {75 if filter.call(i.clone())? {76 out.push(i);77 }78 }79 Ok(Self::new(out))80 }8182 pub fn extended(a: Self, b: Self) -> Self {83 if a.is_empty() {84 b85 } else if b.is_empty() {86 a87 } else {88 Self::new(ExtendedArray::new(a, b))89 }90 }9192 pub fn range_exclusive(a: i32, b: i32) -> Self {93 Self::new(RangeArray::new_exclusive(a, b))94 }95 pub fn range_inclusive(a: i32, b: i32) -> Self {96 Self::new(RangeArray::new_inclusive(a, b))97 }9899 #[must_use]100 pub fn slice(self, index: Option<i32>, end: Option<i32>, step: Option<NonZeroU32>) -> Self {101 let get_idx = |pos: Option<i32>, len: usize, default| match pos {102 #[expect(103 clippy::cast_sign_loss,104 reason = "abs value is used, len is limited to u31"105 )]106 Some(v) if v < 0 => len.saturating_sub((-v) as usize),107 #[expect(clippy::cast_sign_loss, reason = "abs value is used")]108 Some(v) => (v as usize).min(len),109 None => default,110 };111 let index = get_idx(index, self.len(), 0);112 let end = get_idx(end, self.len(), self.len());113 let step = step.unwrap_or_else(|| NonZeroU32::new(1).expect("1 != 0"));114115 if index >= end {116 return Self::empty();117 }118119 Self::new(SliceArray {120 inner: self,121 #[expect(clippy::cast_possible_truncation, reason = "len is limited to u31")]122 from: index as u32,123 #[expect(clippy::cast_possible_truncation, reason = "len is limited to u31")]124 to: end as u32,125 step: step.get(),126 })127 }128129 130 pub fn len(&self) -> usize {131 self.0.len()132 }133134 135 pub fn is_empty(&self) -> bool {136 self.0.is_empty()137 }138139 pub fn is_cheap(&self) -> bool {140 self.0.is_cheap()141 }142143 144 145 146 pub fn get(&self, index: usize) -> Result<Option<Val>> {147 self.0.get(index)148 }149150 151 152 153 pub fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {154 self.0.get_lazy(index)155 }156157 pub fn iter(&self) -> impl ArrayLikeIter<Result<Val>> + '_ {158 (0..self.len()).map(|i| self.get(i).transpose().expect("length checked"))159 }160161 162 pub fn iter_lazy(&self) -> impl ArrayLikeIter<Thunk<Val>> + '_ {163 (0..self.len()).map(|i| self.get_lazy(i).expect("length checked"))164 }165166 167 #[must_use]168 pub fn reversed(self) -> Self {169 Self::new(ReverseArray(self))170 }171172 pub fn ptr_eq(a: &Self, b: &Self) -> bool {173 Cc::ptr_eq(&a.0, &b.0)174 }175176 pub fn as_any(&self) -> &dyn Any {177 &self.0178 }179}180impl<T> From<T> for ArrValue181where182 T: ArrayLike,183{184 fn from(value: T) -> Self {185 Self::new(value)186 }187}188impl<I> FromIterator<I> for ArrValue189where190 Vec<I>: ArrayLike,191{192 fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self {193 Self::new(iter.into_iter().collect::<Vec<_>>())194 }195}