1use std::{2 any::Any,3 fmt::{self},4 num::NonZeroU32,5 rc::Rc,6};78use jrsonnet_gcmodule::{Cc, cc_dyn};910use crate::{Context, Result, Thunk, Val, analyze::LExpr, function::NativeFn, typed::IntoUntyped};1112mod spec;13pub use spec::{ArrayLike, *};1415cc_dyn!(16 #[doc = "Represents a Jsonnet array value."]17 #[derive(Clone)]18 ArrValue,19 ArrayLike,20 pub fn new() {...}21);22impl fmt::Debug for ArrValue {23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {24 self.0.fmt(f)25 }26}2728pub trait ArrayLikeIter<T>: Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator {}29impl<I, T> ArrayLikeIter<T> for I where30 I: Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator31{32}3334impl ArrValue {35 pub fn empty() -> Self {36 Self::new(())37 }3839 pub fn expr(ctx: Context, exprs: Rc<Vec<LExpr>>) -> Self {40 Self::new(ExprArray::new(ctx, exprs))41 }4243 pub fn repeated(data: Self, repeats: u32) -> Option<Self> {44 Some(Self::new(RepeatedArray::new(data, repeats)?))45 }4647 pub fn make(len: u32, cb: NativeFn!((u32,)->Val)) -> Self {48 Self::new(MakeArray::new(len, cb))49 }5051 #[must_use]52 pub fn map(self, mapper: NativeFn!((Val) -> Val)) -> Self {53 Self::new(<MappedArray>::new(self, ArrayMapper::Plain(mapper)))54 }5556 #[must_use]57 pub fn map_with_index(self, mapper: NativeFn!((u32, Val) -> Val)) -> Self {58 Self::new(<MappedArray>::new(self, ArrayMapper::WithIndex(mapper)))59 }6061 pub fn filter(self, filter: NativeFn!((Thunk<Val>) -> bool)) -> Result<Self> {62 63 'eager: {64 let mut out = Vec::new();65 for i in self.iter() {66 let Ok(i) = i else {67 break 'eager;68 };69 if filter.call(IntoUntyped::into_lazy_untyped(i.clone()))? {70 out.push(i);71 }72 }73 return Ok(Self::new(out));74 };7576 let mut out = Vec::new();77 for i in self.iter_lazy() {78 if filter.call(i.clone())? {79 out.push(i);80 }81 }82 Ok(Self::new(out))83 }8485 pub fn extended(a: Self, b: Self) -> Option<Self> {86 Some(if a.is_empty() {87 b88 } else if b.is_empty() {89 a90 } else {91 Self::new(ExtendedArray::new(a, b)?)92 })93 }9495 pub fn range_exclusive(a: i32, b: i32) -> Self {96 Self::new(RangeArray::new_exclusive(a, b))97 }98 pub fn range_inclusive(a: i32, b: i32) -> Self {99 Self::new(RangeArray::new_inclusive(a, b))100 }101102 #[must_use]103 pub fn slice(self, index: Option<i32>, end: Option<i32>, step: Option<NonZeroU32>) -> Self {104 let get_idx = |pos: Option<i32>, len: u32, default| match pos {105 #[expect(106 clippy::cast_sign_loss,107 reason = "abs value is used, len is limited to u31"108 )]109 Some(v) if v < 0 => len.saturating_add_signed(v),110 #[expect(clippy::cast_sign_loss, reason = "abs value is used")]111 Some(v) => (v as u32).min(len),112 None => default,113 };114 let index = get_idx(index, self.len(), 0);115 let end = get_idx(end, self.len(), self.len());116 let step = step.unwrap_or_else(|| NonZeroU32::new(1).expect("1 != 0"));117118 if index >= end {119 return Self::empty();120 }121122 Self::new(SliceArray {123 inner: self,124 #[expect(clippy::cast_possible_truncation, reason = "len is limited to u31")]125 from: index as u32,126 #[expect(clippy::cast_possible_truncation, reason = "len is limited to u31")]127 to: end as u32,128 step: step.get(),129 })130 }131132 133 pub fn len(&self) -> u32 {134 self.0.len()135 }136137 138 pub fn is_empty(&self) -> bool {139 self.0.is_empty()140 }141142 pub fn is_cheap(&self) -> bool {143 self.0.is_cheap()144 }145146 147 148 149 pub fn get(&self, index: u32) -> Result<Option<Val>> {150 self.0.get(index)151 }152153 154 155 156 pub fn get_lazy(&self, index: u32) -> Option<Thunk<Val>> {157 self.0.get_lazy(index)158 }159160 pub fn iter(&self) -> impl ArrayLikeIter<Result<Val>> + '_ {161 (0..self.len()).map(|i| self.get(i).transpose().expect("length checked"))162 }163164 165 pub fn iter_lazy(&self) -> impl ArrayLikeIter<Thunk<Val>> + '_ {166 (0..self.len()).map(|i| self.get_lazy(i).expect("length checked"))167 }168169 170 #[must_use]171 pub fn reversed(self) -> Self {172 Self::new(ReverseArray(self))173 }174175 pub fn ptr_eq(a: &Self, b: &Self) -> bool {176 Cc::ptr_eq(&a.0, &b.0)177 }178179 pub fn as_any(&self) -> &dyn Any {180 &self.0181 }182}183impl<T> From<T> for ArrValue184where185 T: ArrayLike,186{187 fn from(value: T) -> Self {188 Self::new(value)189 }190}191impl<I> FromIterator<I> for ArrValue192where193 Vec<I>: ArrayLike,194{195 fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self {196 Self::new(iter.into_iter().collect::<Vec<_>>())197 }198}