git.delta.rocks / jrsonnet / refs/commits / 6f6b79fd0e0d

difftreelog

feat array unification

kxktrsumYaroslav Bolyukin2026-04-25parent: #953b3d0.patch.diff
in: master

11 files changed

modifiedbindings/jsonnet/src/val_make.rsdiffbeforeafterboth
50/// Assign elements with [`jsonnet_json_array_append`].50/// Assign elements with [`jsonnet_json_array_append`].
51#[no_mangle]51#[no_mangle]
52pub extern "C" fn jsonnet_json_make_array(_vm: &VM) -> *mut Val {52pub extern "C" fn jsonnet_json_make_array(_vm: &VM) -> *mut Val {
53 Box::into_raw(Box::new(Val::Arr(ArrValue::eager(Vec::new()))))53 Box::into_raw(Box::new(Val::arr(())))
54}54}
5555
56/// Make a `JsonnetJsonValue` representing an object.56/// Make a `JsonnetJsonValue` representing an object.
modifiedbindings/jsonnet/src/val_modify.rsdiffbeforeafterboth
24 }24 }
2525
26 new.push(Thunk::evaluated(val.clone()));26 new.push(Thunk::evaluated(val.clone()));
27 *arr = Val::Arr(ArrValue::lazy(new));27 *arr = Val::arr(new);
28 }28 }
29 _ => panic!("should receive array"),29 _ => panic!("should receive array"),
30 }30 }
modifiedcrates/jrsonnet-evaluator/src/arr/mod.rsdiffbeforeafterboth
6};6};
77
8use jrsonnet_gcmodule::{Cc, cc_dyn};8use jrsonnet_gcmodule::{Cc, cc_dyn};
9use jrsonnet_interner::IBytes;
10use jrsonnet_ir::Expr;9use jrsonnet_ir::Expr;
1110
12use crate::{Context, Result, Thunk, Val, function::NativeFn, typed::IntoUntyped};11use crate::{Context, Result, Thunk, Val, function::NativeFn, typed::IntoUntyped};
3534
36impl ArrValue {35impl ArrValue {
37 pub fn empty() -> Self {36 pub fn empty() -> Self {
38 Self::new(RangeArray::empty())37 Self::new(())
39 }38 }
4039
41 pub fn expr(ctx: Context, exprs: Rc<Vec<Expr>>) -> Self {40 pub fn expr(ctx: Context, exprs: Rc<Vec<Expr>>) -> Self {
42 Self::new(ExprArray::new(ctx, exprs))41 Self::new(ExprArray::new(ctx, exprs))
43 }42 }
44
45 pub fn lazy(thunks: Vec<Thunk<Val>>) -> Self {
46 Self::new(LazyArray(thunks))
47 }
48
49 pub fn eager(values: Vec<Val>) -> Self {
50 Self::new(EagerArray(values))
51 }
5243
53 pub fn repeated(data: Self, repeats: usize) -> Option<Self> {44 pub fn repeated(data: Self, repeats: usize) -> Option<Self> {
54 Some(Self::new(RepeatedArray::new(data, repeats)?))45 Some(Self::new(RepeatedArray::new(data, repeats)?))
55 }46 }
5647
57 pub fn bytes(bytes: IBytes) -> Self {
58 Self::new(BytesArray(bytes))
59 }
60 pub fn chars(chars: impl Iterator<Item = char>) -> Self {48 pub fn chars(chars: impl Iterator<Item = char>) -> Self {
61 Self::new(CharArray(chars.collect()))49 Self::new(CharArray(chars.collect()))
62 }50 }
83 out.push(i);71 out.push(i);
84 }72 }
85 }73 }
86 return Ok(Self::eager(out));74 return Ok(Self::new(out));
87 };75 };
8876
89 let mut out = Vec::new();77 let mut out = Vec::new();
92 out.push(i);80 out.push(i);
93 }81 }
94 }82 }
95 Ok(Self::lazy(out))83 Ok(Self::new(out))
96 }84 }
9785
98 pub fn extended(a: Self, b: Self) -> Self {86 pub fn extended(a: Self, b: Self) -> Self {
99 // TODO: benchmark for an optimal value, currently just a arbitrary choice
100 const ARR_EXTEND_THRESHOLD: usize = 1000;
101
102 if a.is_empty() {87 if a.is_empty() {
103 b88 b
104 } else if b.is_empty() {89 } else if b.is_empty() {
105 a90 a
106 } else if a.len() + b.len() > ARR_EXTEND_THRESHOLD {91 } else {
107 Self::new(ExtendedArray::new(a, b))92 Self::new(ExtendedArray::new(a, b))
108 } else if let (Some(a), Some(b)) = (a.iter_cheap(), b.iter_cheap()) {93 }
109 let mut out = Vec::with_capacity(a.len() + b.len());
110 out.extend(a);
111 out.extend(b);
112 Self::eager(out)
113 } else {
114 let mut out = Vec::with_capacity(a.len() + b.len());
115 out.extend(a.iter_lazy());
116 out.extend(b.iter_lazy());
117 Self::lazy(out)
118 }
119 }94 }
12095
121 pub fn range_exclusive(a: i32, b: i32) -> Self {96 pub fn range_exclusive(a: i32, b: i32) -> Self {
165 self.0.is_empty()140 self.0.is_empty()
166 }141 }
167142
168 /// Get array element by index, evaluating it, if it is lazy.
169 ///
170 /// Returns `None` on out-of-bounds condition.
171 pub fn get(&self, index: usize) -> Result<Option<Val>> {143 pub fn is_cheap(&self) -> bool {
172 self.0.get(index)144 self.0.is_cheap()
173 }145 }
174146
175 /// Returns None if get is either non cheap, or out of bounds147 /// Get array element by index, evaluating it, if it is lazy.
176 /// Note that non-cheap access includes errorable values
177 ///148 ///
178 /// Prefer it to `get_lazy`, but use `get` when you can.149 /// Returns `None` on out-of-bounds condition.
179 fn get_cheap(&self, index: usize) -> Option<Val> {150 pub fn get(&self, index: usize) -> Result<Option<Val>> {
180 self.0.get_cheap(index)151 self.0.get(index)
181 }152 }
182153
183 /// Get array element by index, without evaluation.154 /// Get array element by index, without evaluation.
196 (0..self.len()).map(|i| self.get_lazy(i).expect("length checked"))167 (0..self.len()).map(|i| self.get_lazy(i).expect("length checked"))
197 }168 }
198
199 /// Prefer it over `iter_lazy`, but do not use it where `iter` will do.
200 pub fn iter_cheap(&self) -> Option<impl ArrayLikeIter<Val> + '_> {
201 if self.is_cheap() {
202 Some((0..self.len()).map(|i| self.get_cheap(i).expect("length and is_cheap checked")))
203 } else {
204 None
205 }
206 }
207169
208 /// Return a reversed view on current array.170 /// Return a reversed view on current array.
209 #[must_use]171 #[must_use]
215 Cc::ptr_eq(&a.0, &b.0)177 Cc::ptr_eq(&a.0, &b.0)
216 }178 }
217
218 /// Is this vec supports `.get_cheap()?`
219 pub fn is_cheap(&self) -> bool {
220 self.0.is_cheap()
221 }
222179
223 pub fn as_any(&self) -> &dyn Any {180 pub fn as_any(&self) -> &dyn Any {
224 &self.0181 &self.0
225 }182 }
226}183}
227impl From<Vec<Val>> for ArrValue {184impl<T> From<T> for ArrValue
185where
186 T: ArrayLike,
187{
228 fn from(value: Vec<Val>) -> Self {188 fn from(value: T) -> Self {
229 Self::eager(value)189 Self::new(value)
230 }190 }
231}191}
232impl From<Vec<Thunk<Val>>> for ArrValue {
233 fn from(value: Vec<Thunk<Val>>) -> Self {
234 Self::lazy(value)
235 }
236}
237impl FromIterator<Val> for ArrValue {192impl<I> FromIterator<I> for ArrValue
193where
194 Vec<I>: ArrayLike,
195{
238 fn from_iter<T: IntoIterator<Item = Val>>(iter: T) -> Self {196 fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self {
239 Self::eager(iter.into_iter().collect())197 Self::new(iter.into_iter().collect::<Vec<_>>())
240 }198 }
241}199}
242impl ArrayLike for ArrValue {
243 fn len(&self) -> usize {
244 self.0.len()
245 }
246
247 fn get(&self, index: usize) -> Result<Option<Val>> {
248 self.0.get(index)
249 }
250
251 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {
252 self.0.get_lazy(index)
253 }
254
255 fn get_cheap(&self, index: usize) -> Option<Val> {
256 self.0.get_cheap(index)
257 }
258
259 fn is_cheap(&self) -> bool {
260 self.0.is_cheap()
261 }
262}
263200
modifiedcrates/jrsonnet-evaluator/src/arr/spec.rsdiffbeforeafterboth
1use std::{any::Any, cell::RefCell, fmt::Debug, mem::replace, rc::Rc};1use std::{
2 any::Any,
3 cell::RefCell,
4 fmt::{self, Debug},
5 mem::replace,
6 rc::Rc,
7};
28
3use jrsonnet_gcmodule::{Cc, Trace};9use jrsonnet_gcmodule::{Cc, Trace};
21 }27 }
22 fn get(&self, index: usize) -> Result<Option<Val>>;28 fn get(&self, index: usize) -> Result<Option<Val>>;
23 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>>;29 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>>;
24 fn get_cheap(&self, index: usize) -> Option<Val>;
2530
26 fn is_cheap(&self) -> bool;31 fn is_cheap(&self) -> bool {
32 false
33 }
27}34}
35trait ArrayCheap {
36 fn get(&self, index: usize) -> Option<Val>;
37 fn len(&self) -> usize;
38}
39impl<T> ArrayLike for T
40where
41 T: Any + Trace + Debug + ArrayCheap,
42{
43 fn len(&self) -> usize {
44 <T as ArrayCheap>::len(self)
45 }
46
47 fn get(&self, index: usize) -> Result<Option<Val>> {
48 Ok(<T as ArrayCheap>::get(self, index))
49 }
50
51 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {
52 <T as ArrayCheap>::get(self, index).map(Thunk::evaluated)
53 }
54
55 fn is_cheap(&self) -> bool {
56 true
57 }
58}
59
60impl ArrayCheap for () {
61 fn len(&self) -> usize {
62 0
63 }
64 fn get(&self, _index: usize) -> Option<Val> {
65 None
66 }
67}
2868
29#[derive(Debug, Trace)]69#[derive(Debug, Trace)]
30pub struct SliceArray {70pub struct SliceArray {
52 self.inner.get_lazy(self.map_idx(index))92 self.inner.get_lazy(self.map_idx(index))
53 }93 }
5494
55 fn get_cheap(&self, index: usize) -> Option<Val> {
56 self.inner.get_cheap(self.map_idx(index))
57 }
58 fn is_cheap(&self) -> bool {95 fn is_cheap(&self) -> bool {
59 self.inner.is_cheap()96 self.inner.is_cheap()
60 }97 }
61}98}
6299
63#[derive(Trace, Debug)]100#[derive(Trace, Debug)]
64pub struct CharArray(pub Vec<char>);101pub struct CharArray(pub Vec<char>);
65impl ArrayLike for CharArray {102impl ArrayCheap for CharArray {
66 fn len(&self) -> usize {103 fn len(&self) -> usize {
67 self.0.len()104 self.0.as_slice().len()
68 }105 }
69
70 fn get(&self, index: usize) -> Result<Option<Val>> {106 fn get(&self, index: usize) -> Option<Val> {
71 Ok(self.get_cheap(index))
72 }
73
74 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {
75 self.get_cheap(index).map(Thunk::evaluated)
76 }
77
78 fn get_cheap(&self, index: usize) -> Option<Val> {
79 self.0.get(index).map(|v| Val::string(*v))107 self.0.as_slice().get(index).map(|v| Val::string(*v))
80 }108 }
81 fn is_cheap(&self) -> bool {
82 true
83 }
84}109}
85110
86#[derive(Trace, Debug)]
87pub struct BytesArray(pub IBytes);
88impl ArrayLike for BytesArray {111impl ArrayCheap for IBytes {
89 fn len(&self) -> usize {112 fn len(&self) -> usize {
90 self.0.len()113 self.as_slice().len()
91 }114 }
92
93 fn get(&self, index: usize) -> Result<Option<Val>> {115 fn get(&self, index: usize) -> Option<Val> {
94 Ok(self.get_cheap(index))
95 }
96
97 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {
98 self.get_cheap(index).map(Thunk::evaluated)
99 }
100
101 fn get_cheap(&self, index: usize) -> Option<Val> {
102 self.0.get(index).map(|v| Val::Num((*v).into()))116 self.as_slice().get(index).map(|v| Val::Num((*v).into()))
103 }117 }
104 fn is_cheap(&self) -> bool {
105 true
106 }
107}118}
108119
109#[derive(Debug, Trace, Clone)]120#[derive(Debug, Trace, Clone)]
191 index,202 index,
192 }))203 }))
193 }204 }
194 fn get_cheap(&self, _index: usize) -> Option<Val> {
195 None
196 }
197 fn is_cheap(&self) -> bool {205 fn is_cheap(&self) -> bool {
198 false206 false
199 }207 }
275 self.len283 self.len
276 }284 }
277285
278 fn get_cheap(&self, index: usize) -> Option<Val> {
279 if self.split > index {
280 self.a.get_cheap(index)
281 } else {
282 self.b.get_cheap(index - self.split)
283 }
284 }
285 fn is_cheap(&self) -> bool {286 fn is_cheap(&self) -> bool {
286 self.a.is_cheap() && self.b.is_cheap()287 self.a.is_cheap() && self.b.is_cheap()
287 }288 }
288}289}
289290
290#[derive(Trace, Debug)]
291pub struct LazyArray(pub Vec<Thunk<Val>>);
292impl ArrayLike for LazyArray {291impl<T> ArrayLike for Vec<T>
292where
293 T: IntoUntyped + Trace + fmt::Debug,
294 for<'a> &'a T: IntoUntyped,
295{
293 fn len(&self) -> usize {296 fn len(&self) -> usize {
294 self.0.len()297 self.as_slice().len()
295 }298 }
299
296 fn get(&self, index: usize) -> Result<Option<Val>> {300 fn get(&self, index: usize) -> Result<Option<Val>> {
297 let Some(v) = self.0.get(index) else {301 let Some(elem) = self.as_slice().get(index) else {
298 return Ok(None);302 return Ok(None);
299 };303 };
300 v.evaluate().map(Some)304 IntoUntyped::into_untyped(elem).map(Some)
301 }305 }
302 fn get_cheap(&self, _index: usize) -> Option<Val> {306
303 None
304 }
305 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {307 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {
306 self.0.get(index).cloned()308 let elem = self.as_slice().get(index)?;
309 Some(IntoUntyped::into_lazy_untyped(elem))
307 }310 }
311
308 fn is_cheap(&self) -> bool {312 fn is_cheap(&self) -> bool {
309 false313 !T::provides_lazy()
310 }314 }
311}315}
312
313#[derive(Trace, Debug)]
314pub struct EagerArray(pub Vec<Val>);
315impl ArrayLike for EagerArray {
316 fn len(&self) -> usize {
317 self.0.len()
318 }
319
320 fn get(&self, index: usize) -> Result<Option<Val>> {
321 Ok(self.0.get(index).cloned())
322 }
323
324 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {
325 self.0.get(index).cloned().map(Thunk::evaluated)
326 }
327
328 fn get_cheap(&self, index: usize) -> Option<Val> {
329 self.0.get(index).cloned()
330 }
331 fn is_cheap(&self) -> bool {
332 true
333 }
334}
335316
336/// Inclusive range type317/// Inclusive range type
337#[derive(Debug, Trace, PartialEq, Eq)]318#[derive(Debug, Trace, PartialEq, Eq)]
364 }345 }
365}346}
366
367impl ArrayLike for RangeArray {347impl ArrayCheap for RangeArray {
368 fn len(&self) -> usize {
369 self.size()
370 }
371 fn is_empty(&self) -> bool {
372 self.size() == 0
373 }
374
375 fn get(&self, index: usize) -> Result<Option<Val>> {
376 Ok(self.get_cheap(index))
377 }
378
379 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {
380 self.get_cheap(index).map(Thunk::evaluated)
381 }
382
383 fn get_cheap(&self, index: usize) -> Option<Val> {348 fn get(&self, index: usize) -> Option<Val> {
384 self.range().nth(index).map(|i| Val::Num(i.into()))349 self.range().nth(index).map(|i| Val::Num(i.into()))
385 }350 }
386 fn is_cheap(&self) -> bool {351 fn len(&self) -> usize {
387 true352 self.size()
388 }353 }
389}354}
390355
403 self.0.get_lazy(self.0.len() - index - 1)368 self.0.get_lazy(self.0.len() - index - 1)
404 }369 }
405370
406 fn get_cheap(&self, index: usize) -> Option<Val> {
407 self.0.get_cheap(self.0.len() - index - 1)
408 }
409 fn is_cheap(&self) -> bool {371 fn is_cheap(&self) -> bool {
410 self.0.is_cheap()372 self.0.is_cheap()
411 }373 }
511 }))473 }))
512 }474 }
513
514 fn get_cheap(&self, _index: usize) -> Option<Val> {
515 None
516 }
517 fn is_cheap(&self) -> bool {
518 false
519 }
520}475}
521476
522#[derive(Trace, Debug)]477#[derive(Trace, Debug)]
525 repeats: usize,480 repeats: usize,
526 total_len: usize,481 total_len: usize,
527}482}
528impl RepeatedArray {483impl RepeatedArray {
529 pub fn new(data: ArrValue, repeats: usize) -> Option<Self> {484 pub fn new(data: ArrValue, repeats: usize) -> Option<Self> {
530 let total_len = data.len().checked_mul(repeats)?;485 let total_len = data.len().checked_mul(repeats)?;
531 Some(Self {486 Some(Self {
534 total_len,489 total_len,
535 })490 })
536 }491 }
537}
538
539impl ArrayLike for RepeatedArray {
540 fn len(&self) -> usize {
541 self.total_len
542 }
543
544 fn get(&self, index: usize) -> Result<Option<Val>> {492 fn map_idx(&self, index: usize) -> Option<usize> {
545 if index > self.total_len {493 if index > self.total_len {
546 return Ok(None);494 return None;
547 }495 }
548 self.data.get(index % self.data.len())496 Some(index % self.data.len())
549 }497 }
498}
499
500impl ArrayLike for RepeatedArray {
501 fn len(&self) -> usize {
502 self.total_len
503 }
550504
551 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {505 fn get(&self, index: usize) -> Result<Option<Val>> {
552 if index > self.total_len {506 let Some(idx) = self.map_idx(index) else {
553 return None;507 return Ok(None);
554 }508 };
555 self.data.get_lazy(index % self.data.len())509 self.data.get(idx)
556 }510 }
557511
558 fn get_cheap(&self, index: usize) -> Option<Val> {512 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {
559 if index > self.total_len {513 let idx = self.map_idx(index)?;
560 return None;
561 }
562 self.data.get_cheap(index % self.data.len())514 self.data.get_lazy(idx)
563 }515 }
516
564 fn is_cheap(&self) -> bool {517 fn is_cheap(&self) -> bool {
565 self.data.is_cheap()518 self.data.is_cheap()
566 }519 }
567}520}
568521
569#[derive(Trace, Debug)]522#[derive(Trace, Debug)]
570pub struct PickObjectValues {523pub struct PickObjectValues {
584 }537 }
585538
586 fn get(&self, index: usize) -> Result<Option<Val>> {539 fn get(&self, index: usize) -> Result<Option<Val>> {
587 let Some(key) = self.keys.get(index) else {540 let Some(key) = self.keys.as_slice().get(index) else {
588 return Ok(None);541 return Ok(None);
589 };542 };
590 Ok(Some(self.obj.get_or_bail(key.clone())?))543 Ok(Some(self.obj.get_or_bail(key.clone())?))
591 }544 }
592545
593 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {546 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {
594 let key = self.keys.get(index)?;547 let key = self.keys.as_slice().get(index)?;
595 Some(self.obj.get_lazy_or_bail(key.clone()))548 Some(self.obj.get_lazy_or_bail(key.clone()))
596 }549 }
597
598 fn get_cheap(&self, _index: usize) -> Option<Val> {
599 None
600 }
601550
602 fn is_cheap(&self) -> bool {551 fn is_cheap(&self) -> bool {
603 false552 false
628 }577 }
629578
630 fn get(&self, index: usize) -> Result<Option<Val>> {579 fn get(&self, index: usize) -> Result<Option<Val>> {
631 let Some(key) = self.keys.get(index) else {580 let Some(key) = self.keys.as_slice().get(index) else {
632 return Ok(None);581 return Ok(None);
633 };582 };
634 Ok(Some(583 Ok(Some(
641 }590 }
642591
643 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {592 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {
644 let key = self.keys.get(index)?;593 let key = self.keys.as_slice().get(index)?;
645 // Nothing can fail in the key part, yet value is still594 // Nothing can fail in the key part, yet value is still
646 // lazy-evaluated595 // lazy-evaluated
647 Some(Thunk::evaluated(596 Some(Thunk::evaluated(
653 ))602 ))
654 }603 }
655
656 fn get_cheap(&self, _index: usize) -> Option<Val> {
657 None
658 }
659604
660 fn is_cheap(&self) -> bool {605 fn is_cheap(&self) -> bool {
661 false606 false
modifiedcrates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth
70 if n.iter().any(|e| !is_trivial(e)) {70 if n.iter().any(|e| !is_trivial(e)) {
71 return None;71 return None;
72 }72 }
73 Val::Arr(ArrValue::eager(73 Val::Arr(
74 n.iter()74 n.iter()
75 .map(evaluate_trivial)75 .map(evaluate_trivial)
76 .map(|e| e.expect("checked trivial"))76 .map(|e| e.expect("checked trivial"))
77 .collect(),77 .collect(),
78 ))78 )
79 }79 }
80 _ => return None,80 _ => return None,
81 })81 })
145 let fctx = Pending::new();145 let fctx = Pending::new();
146 let mut new_bindings = FxHashMap::with_capacity(into.binds_len());146 let mut new_bindings = FxHashMap::with_capacity(into.binds_len());
147 let obj = obj.clone();147 let obj = obj.clone();
148 let value = Thunk::evaluated(Val::Arr(ArrValue::lazy(vec![148 let value = Thunk::evaluated(Val::arr(vec![
149 Thunk::evaluated(Val::string(field.clone())),149 Thunk::evaluated(Val::string(field.clone())),
150 Thunk!(move || obj.get(field).transpose().expect(150 obj.get_lazy(field).transpose().expect(
151 "field exists, as field name was obtained from object.fields()",151 "field exists, as field name was obtained from object.fields()",
152 )),152 ),
153 ])));153 ]));
154 destruct(into, value, fctx.clone(), &mut new_bindings)?;154 destruct(into, value, fctx.clone(), &mut new_bindings)?;
155 let ctx = ctx.clone().extend_bindings(new_bindings).into_future(fctx);155 let ctx = ctx.clone().extend_bindings(new_bindings).into_future(fctx);
156156
528 #[cfg(feature = "exp-null-coaelse")]528 #[cfg(feature = "exp-null-coaelse")]
529 None if part.null_coaelse => return Ok(Val::Null),529 None if part.null_coaelse => return Ok(Val::Null),
530 None => {530 None => {
531 let suggestions = suggest_object_fields(&v, key.clone().into_flat());531 let suggestions = suggest_object_fields(&v, key.into_flat());
532532
533 return Err(Error::from(NoSuchField(533 return Err(Error::from(NoSuchField(
534 key.clone().into_flat(),534 key.clone().into_flat(),
628 }628 }
629 Arr(items) => {629 Arr(items) => {
630 if items.is_empty() {630 if items.is_empty() {
631 Val::Arr(ArrValue::empty())631 Val::arr(())
632 } else {632 } else {
633 Val::Arr(ArrValue::expr(ctx, items.clone()))633 Val::Arr(ArrValue::expr(ctx, items.clone()))
634 }634 }
640 out.push(Thunk!(move || evaluate(ctx, &expr)));640 out.push(Thunk!(move || evaluate(ctx, &expr)));
641 Ok(())641 Ok(())
642 })?;642 })?;
643 Val::Arr(ArrValue::lazy(out))643 Val::arr(out)
644 }644 }
645 Obj(body) => Val::Obj(evaluate_object(None, ctx, body)?),645 Obj(body) => Val::Obj(evaluate_object(None, ctx, body)?),
646 ObjExtend(a, b) => {646 ObjExtend(a, b) => {
718 || s.import_resolved(resolved_path),718 || s.import_resolved(resolved_path),
719 )?,719 )?,
720 ImportKind::Str => Val::string(s.import_resolved_str(resolved_path)?),720 ImportKind::Str => Val::string(s.import_resolved_str(resolved_path)?),
721 ImportKind::Bin => {721 ImportKind::Bin => Val::arr(s.import_resolved_bin(resolved_path)?),
722 Val::Arr(ArrValue::bytes(s.import_resolved_bin(resolved_path)?))
723 }
724 }) as Result<Val>722 }) as Result<Val>
725 })?723 })?
726 }724 }
modifiedcrates/jrsonnet-evaluator/src/integrations/serde.rsdiffbeforeafterboth
1use std::borrow::Cow;1use std::borrow::Cow;
22
3use jrsonnet_interner::IStr;3use jrsonnet_interner::{IBytes, IStr};
4use serde::{4use serde::{
5 Deserialize, Serialize, Serializer,5 Deserialize, Serialize, Serializer,
6 de::{self, Visitor},6 de::{self, Visitor},
11};11};
1212
13use crate::{13use crate::{
14 Error as JrError, ObjValue, ObjValueBuilder, Result, Val, arr::ArrValue, in_description_frame,14 Error as JrError, ObjValue, ObjValueBuilder, Result, Val, in_description_frame, runtime_error,
15 runtime_error, val::NumValue,15 val::NumValue,
16};16};
1717
90 where90 where
91 E: de::Error,91 E: de::Error,
92 {92 {
93 Ok(Val::Arr(ArrValue::bytes(v.into())))93 Ok(Val::arr(IBytes::from(v)))
94 }94 }
9595
96 fn visit_none<E>(self) -> Result<Self::Value, E>96 fn visit_none<E>(self) -> Result<Self::Value, E>
130 out.push(val);130 out.push(val);
131 }131 }
132132
133 Ok(Val::Arr(ArrValue::eager(out)))133 Ok(Val::arr(out))
134 }134 }
135135
136 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>136 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
270 }270 }
271271
272 fn end(self) -> Result<Val> {272 fn end(self) -> Result<Val> {
273 let inner = Val::Arr(ArrValue::eager(self.data));273 let inner = Val::arr(self.data);
274 if let Some(variant) = self.variant {274 if let Some(variant) = self.variant {
275 let mut out = ObjValue::builder_with_capacity(1);275 let mut out = ObjValue::builder_with_capacity(1);
276 out.field(variant).value(inner);276 out.field(variant).value(inner);
509 }509 }
510510
511 fn serialize_bytes(self, v: &[u8]) -> Result<Val> {511 fn serialize_bytes(self, v: &[u8]) -> Result<Val> {
512 Ok(Val::Arr(ArrValue::bytes(v.into())))512 Ok(Val::arr(IBytes::from(v)))
513 }513 }
514514
515 fn serialize_none(self) -> Result<Val> {515 fn serialize_none(self) -> Result<Val> {
modifiedcrates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth
66
7use crate::{7use crate::{
8 ObjValue, ObjValueBuilder, Result, ResultExt, Thunk, Val,8 ObjValue, ObjValueBuilder, Result, ResultExt, Thunk, Val,
9 arr::{ArrValue, BytesArray},9 arr::ArrValue,
10 bail,10 bail,
11 function::FuncVal,11 function::FuncVal,
12 typed::CheckType,12 typed::CheckType,
83pub trait Typed: Sized {83pub trait Typed: Sized {
84 const TYPE: &'static ComplexValType;84 const TYPE: &'static ComplexValType;
85}85}
86impl<T> Typed for &T
87where
88 T: Typed,
89{
90 const TYPE: &'static ComplexValType = <&T as Typed>::TYPE;
91}
86pub trait IntoUntyped: Typed {92pub trait IntoUntyped: Typed {
87 // Whatever caller should use `into_lazy_untyped` instead of `into_untyped`93 // Whatever caller should use `into_lazy_untyped` instead of `into_untyped`
88 fn provides_lazy() -> bool {94 fn provides_lazy() -> bool {
157 inner.map(<ThunkIntoUntyped<T>>::default())164 inner.map(<ThunkIntoUntyped<T>>::default())
158 }165 }
159}166}
167impl<T> IntoUntyped for &Thunk<T>
168where
169 T: IntoUntyped + Trace + Clone,
170{
171 fn into_untyped(typed: Self) -> Result<Val> {
172 T::into_untyped(typed.evaluate()?)
173 }
174 fn provides_lazy() -> bool {
175 true
176 }
177
178 fn into_lazy_untyped(inner: Self) -> Thunk<Val> {
179 // Avoid lazy mapping
180 let inner = match try_cast_thunk_val(inner.clone()) {
181 Ok(v) => return v,
182 Err(e) => e,
183 };
184 inner.map(<ThunkIntoUntyped<T>>::default())
185 }
186}
160187
161fn try_cast_thunk_t<T: 'static>(typed: Thunk<Val>) -> Result<Thunk<T>, Thunk<Val>> {188fn try_cast_thunk_t<T: 'static>(typed: Thunk<Val>) -> Result<Thunk<T>, Thunk<Val>> {
162 if TypeId::of::<T>() == TypeId::of::<Val>() {189 if TypeId::of::<T>() == TypeId::of::<Val>() {
221 }248 }
222 }249 }
223 }250 }
224 impl IntoUntyped for $ty {251 impl IntoUntyped for &$ty {
252 fn into_untyped(value: Self) -> Result<Val> {
253 Ok(Val::Num((*value).into()))
254 }
255 }
256 impl IntoUntyped for $ty {
225 fn into_untyped(value: Self) -> Result<Val> {257 fn into_untyped(value: Self) -> Result<Val> {
226 Ok(Val::Num(value.into()))258 Ok(Val::Num(value.into()))
227 }259 }
305impl Typed for f64 {337impl Typed for f64 {
306 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Num);338 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Num);
307}339}
340impl IntoUntyped for &f64 {
341 fn into_untyped(value: Self) -> Result<Val> {
342 Ok(Val::try_num(*value)?)
343 }
344}
308impl IntoUntyped for f64 {345impl IntoUntyped for f64 {
309 fn into_untyped(value: Self) -> Result<Val> {346 fn into_untyped(value: Self) -> Result<Val> {
310 Ok(Val::try_num(value)?)347 Ok(Val::try_num(value)?)
324impl Typed for PositiveF64 {361impl Typed for PositiveF64 {
325 const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(0.0), None);362 const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(0.0), None);
326}363}
327impl IntoUntyped for PositiveF64 {364impl IntoUntyped for &PositiveF64 {
328 fn into_untyped(value: Self) -> Result<Val> {365 fn into_untyped(value: Self) -> Result<Val> {
329 Ok(Val::try_num(value.0)?)366 Ok(Val::try_num(value.0)?)
330 }367 }
538impl Typed for Val {575impl Typed for Val {
539 const TYPE: &'static ComplexValType = &ComplexValType::Any;576 const TYPE: &'static ComplexValType = &ComplexValType::Any;
540}577}
578impl IntoUntyped for &Val {
579 fn into_untyped(typed: Self) -> Result<Val> {
580 Ok(typed.clone())
581 }
582}
541impl IntoUntyped for Val {583impl IntoUntyped for Val {
542 fn into_untyped(typed: Self) -> Result<Val> {584 fn into_untyped(typed: Self) -> Result<Val> {
543 Ok(typed)585 Ok(typed)
567 const TYPE: &'static ComplexValType =609 const TYPE: &'static ComplexValType =
568 &ComplexValType::ArrayRef(&ComplexValType::BoundedNumber(Some(0.0), Some(255.0)));610 &ComplexValType::ArrayRef(&ComplexValType::BoundedNumber(Some(0.0), Some(255.0)));
569}611}
570impl IntoUntyped for IBytes {612impl IntoUntyped for &IBytes {
571 fn into_untyped(value: Self) -> Result<Val> {613 fn into_untyped(value: Self) -> Result<Val> {
572 Ok(Val::Arr(ArrValue::bytes(value)))614 Ok(Val::arr(value.clone()))
573 }615 }
574}616}
617impl IntoUntyped for IBytes {
618 fn into_untyped(value: Self) -> Result<Val> {
619 Ok(Val::arr(value))
620 }
621}
575impl FromUntyped for IBytes {622impl FromUntyped for IBytes {
576 fn from_untyped(value: Val) -> Result<Self> {623 fn from_untyped(value: Val) -> Result<Self> {
577 let Val::Arr(a) = &value else {624 let Val::Arr(a) = &value else {
578 <Self as Typed>::TYPE.check(&value)?;625 <Self as Typed>::TYPE.check(&value)?;
579 unreachable!()626 unreachable!()
580 };627 };
581 if let Some(bytes) = a.as_any().downcast_ref::<BytesArray>() {628 if let Some(bytes) = a.as_any().downcast_ref::<IBytes>() {
582 return Ok(bytes.0.as_slice().into());629 return Ok(bytes.clone());
583 }630 }
584 <Self as Typed>::TYPE.check(&value)?;631 <Self as Typed>::TYPE.check(&value)?;
585 // Any::downcast_ref::<ByteArray>(&a);632 // Any::downcast_ref::<ByteArray>(&a);
596impl Typed for M1 {643impl Typed for M1 {
597 const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(-1.0), Some(-1.0));644 const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(-1.0), Some(-1.0));
598}645}
599impl IntoUntyped for M1 {646impl IntoUntyped for &M1 {
600 fn into_untyped(_: Self) -> Result<Val> {647 fn into_untyped(_: Self) -> Result<Val> {
601 Ok(Val::Num(NumValue::new(-1.0).expect("finite")))648 Ok(Val::Num(NumValue::new(-1.0).expect("finite")))
602 }649 }
728impl Typed for bool {775impl Typed for bool {
729 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Bool);776 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Bool);
730}777}
778impl IntoUntyped for &bool {
779 fn into_untyped(value: Self) -> Result<Val> {
780 Ok(Val::Bool(*value))
781 }
782}
731impl IntoUntyped for bool {783impl IntoUntyped for bool {
732 fn into_untyped(value: Self) -> Result<Val> {784 fn into_untyped(value: Self) -> Result<Val> {
733 Ok(Val::Bool(value))785 Ok(Val::Bool(value))
764 }816 }
765}817}
766818
767pub struct Null;
768impl Typed for Null {819impl Typed for () {
769 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Null);820 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Null);
770}821}
771impl IntoUntyped for Null {822impl IntoUntyped for &() {
823 fn into_untyped((): Self) -> Result<Val> {
824 Ok(Val::Null)
825 }
826}
827impl IntoUntyped for () {
772 fn into_untyped(_: Self) -> Result<Val> {828 fn into_untyped((): Self) -> Result<Val> {
773 Ok(Val::Null)829 Ok(Val::Null)
774 }830 }
775}831}
776impl FromUntyped for Null {832impl FromUntyped for () {
777 fn from_untyped(value: Val) -> Result<Self> {833 fn from_untyped(value: Val) -> Result<Self> {
778 <Self as Typed>::TYPE.check(&value)?;834 <Self as Typed>::TYPE.check(&value)?;
779 Ok(Self)835 Ok(())
780 }836 }
781}837}
782838
811impl Typed for NumValue {867impl Typed for NumValue {
812 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Num);868 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Num);
813}869}
814impl IntoUntyped for NumValue {870impl IntoUntyped for &NumValue {
815 fn into_untyped(typed: Self) -> Result<Val> {871 fn into_untyped(typed: Self) -> Result<Val> {
816 Ok(Val::Num(typed))872 Ok(Val::Num(*typed))
817 }873 }
818}874}
819impl FromUntyped for NumValue {875impl FromUntyped for NumValue {
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
137137
138impl<T> Thunk<T>138impl<T> Thunk<T>
139where139where
140 T: Clone + Trace,140 T: Trace,
141{141{
142 pub fn force(&self) -> Result<()> {142 pub fn force(&self) -> Result<()> {
143 self.evaluate()?;143 self.evaluate()?;
161}161}
162impl<Input> Thunk<Input>162impl<Input> Thunk<Input>
163where163where
164 Input: Trace + Clone,164 Input: Trace,
165{165{
166 pub fn map<M>(self, mapper: M) -> Thunk<M::Output>166 pub fn map<M>(self, mapper: M) -> Thunk<M::Output>
167 where167 where
355 Self::Tree(Rc::new((a, b, len)))355 Self::Tree(Rc::new((a, b, len)))
356 }356 }
357 }357 }
358 pub fn into_flat(self) -> IStr {358 pub fn into_flat(&self) -> IStr {
359 #[cold]359 #[cold]
360 fn write_buf(s: &StrValue, out: &mut String) {360 fn write_buf(s: &StrValue, out: &mut String) {
361 match s {361 match s {
367 }367 }
368 }368 }
369 match self {369 match self {
370 Self::Flat(f) => f,370 Self::Flat(f) => f.clone(),
371 Self::Tree(_) => {371 Self::Tree(_) => {
372 let mut buf = String::with_capacity(self.len());372 let mut buf = String::with_capacity(self.len());
373 write_buf(&self, &mut buf);373 write_buf(self, &mut buf);
374 buf.into()374 buf.into()
375 }375 }
376 }376 }
701 {701 {
702 Ok(Self::Num(num.try_into()?))702 Ok(Self::Num(num.try_into()?))
703 }703 }
704 pub fn arr(a: impl ArrayLike) -> Self {
705 Self::Arr(ArrValue::new(a))
706 }
704}707}
705708
706impl From<IStr> for Val {709impl From<IStr> for Val {
modifiedcrates/jrsonnet-stdlib/src/arrays.rsdiffbeforeafterboth
34 for _ in 0..*sz {34 for _ in 0..*sz {
35 out.push(trivial.clone());35 out.push(trivial.clone());
36 }36 }
37 Ok(ArrValue::eager(out))37 Ok(ArrValue::new(out))
38 },38 },
39 )39 )
40}40}
256pub fn builtin_lines(arr: ArrValue) -> Result<IndexableVal> {256pub fn builtin_lines(arr: ArrValue) -> Result<IndexableVal> {
257 builtin_join(257 builtin_join(
258 IndexableVal::Str("\n".into()),258 IndexableVal::Str("\n".into()),
259 ArrValue::extended(arr, ArrValue::eager(vec![Val::string("")])),259 ArrValue::extended(arr, ArrValue::new(vec![Val::string("")])),
260 )260 )
261}261}
262262
468 out.push(ele);468 out.push(ele);
469 }469 }
470 }470 }
471 Val::Arr(ArrValue::eager(out))471 Val::arr(out)
472 }472 }
473 Val::Obj(o) => {473 Val::Obj(o) => {
474 let mut out = ObjValueBuilder::new();474 let mut out = ObjValueBuilder::new();
modifiedcrates/jrsonnet-stdlib/src/sets.rsdiffbeforeafterboth
2929
30#[builtin]30#[builtin]
31#[allow(non_snake_case, clippy::redundant_closure)]31#[allow(non_snake_case, clippy::redundant_closure)]
32pub fn builtin_set_inter(a: ArrValue, b: ArrValue, #[default] keyF: KeyF) -> Result<ArrValue> {32pub fn builtin_set_inter(
33 a: ArrValue,
34 b: ArrValue,
35 #[default] keyF: KeyF,
36) -> Result<Vec<Thunk<Val>>> {
33 let mut a = a.iter_lazy();37 let mut a = a.iter_lazy();
34 let mut b = b.iter_lazy();38 let mut b = b.iter_lazy();
3539
60 }64 }
61 }65 }
62 }66 }
63 Ok(ArrValue::lazy(out))67 Ok(out)
64}68}
6569
66#[builtin]70#[builtin]
67#[allow(non_snake_case, clippy::redundant_closure)]71#[allow(non_snake_case, clippy::redundant_closure)]
68pub fn builtin_set_diff(a: ArrValue, b: ArrValue, #[default] keyF: KeyF) -> Result<ArrValue> {72pub fn builtin_set_diff(
73 a: ArrValue,
74 b: ArrValue,
75 #[default] keyF: KeyF,
76) -> Result<Vec<Thunk<Val>>> {
69 let mut a = a.iter_lazy();77 let mut a = a.iter_lazy();
70 let mut b = b.iter_lazy();78 let mut b = b.iter_lazy();
7179
103 av = a.next();111 av = a.next();
104 ak = av.clone().map(keyF).transpose()?;112 ak = av.clone().map(keyF).transpose()?;
105 }113 }
106 Ok(ArrValue::lazy(out))114 Ok(out)
107}115}
108116
109#[builtin]117#[builtin]
110#[allow(non_snake_case, clippy::redundant_closure)]118#[allow(non_snake_case, clippy::redundant_closure)]
111pub fn builtin_set_union(a: ArrValue, b: ArrValue, #[default] keyF: KeyF) -> Result<ArrValue> {119pub fn builtin_set_union(
120 a: ArrValue,
121 b: ArrValue,
122 #[default] keyF: KeyF,
123) -> Result<Vec<Thunk<Val>>> {
112 let mut a = a.iter_lazy();124 let mut a = a.iter_lazy();
113 let mut b = b.iter_lazy();125 let mut b = b.iter_lazy();
114126
154 bv = b.next();166 bv = b.next();
155 bk = bv.clone().map(keyF).transpose()?;167 bk = bv.clone().map(keyF).transpose()?;
156 }168 }
157 Ok(ArrValue::lazy(out))169 Ok(out)
158}170}
159171
modifiedcrates/jrsonnet-stdlib/src/sort.rsdiffbeforeafterboth
113 return Ok(values);113 return Ok(values);
114 }114 }
115 if key_getter.is_identity() {115 if key_getter.is_identity() {
116 Ok(ArrValue::eager(sort_identity(116 Ok(ArrValue::new(sort_identity(
117 values.iter().collect::<Result<Vec<Val>>>()?,117 values.iter().collect::<Result<Vec<Val>>>()?,
118 )?))118 )?))
119 } else {119 } else {
120 Ok(ArrValue::lazy(sort_keyf(values, key_getter)?))120 Ok(ArrValue::new(sort_keyf(values, key_getter)?))
121 }121 }
122}122}
123123
162 return Ok(arr);162 return Ok(arr);
163 }163 }
164 if keyF.is_identity() {164 if keyF.is_identity() {
165 Ok(ArrValue::eager(uniq_identity(165 Ok(ArrValue::new(uniq_identity(
166 arr.iter().collect::<Result<Vec<Val>>>()?,166 arr.iter().collect::<Result<Vec<Val>>>()?,
167 )?))167 )?))
168 } else {168 } else {
169 Ok(ArrValue::lazy(uniq_keyf(arr, keyF)?))169 Ok(ArrValue::new(uniq_keyf(arr, keyF)?))
170 }170 }
171}171}
172172
180 let arr = arr.iter().collect::<Result<Vec<Val>>>()?;180 let arr = arr.iter().collect::<Result<Vec<Val>>>()?;
181 let arr = sort_identity(arr)?;181 let arr = sort_identity(arr)?;
182 let arr = uniq_identity(arr)?;182 let arr = uniq_identity(arr)?;
183 Ok(ArrValue::eager(arr))183 Ok(ArrValue::new(arr))
184 } else {184 } else {
185 let arr = sort_keyf(arr, keyF.clone())?;185 let arr = sort_keyf(arr, keyF.clone())?;
186 let arr = uniq_keyf(ArrValue::lazy(arr), keyF)?;186 let arr = uniq_keyf(ArrValue::new(arr), keyF)?;
187 Ok(ArrValue::lazy(arr))187 Ok(ArrValue::new(arr))
188 }188 }
189}189}
190190