difftreelog
feat array unification
in: master
11 files changed
bindings/jsonnet/src/val_make.rsdiffbeforeafterboth50/// 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}555556/// Make a `JsonnetJsonValue` representing an object.56/// Make a `JsonnetJsonValue` representing an object.bindings/jsonnet/src/val_modify.rsdiffbeforeafterboth24 }24 }252526 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 }crates/jrsonnet-evaluator/src/arr/mod.rsdiffbeforeafterboth6};6};778use jrsonnet_gcmodule::{Cc, cc_dyn};8use jrsonnet_gcmodule::{Cc, cc_dyn};9use jrsonnet_interner::IBytes;10use jrsonnet_ir::Expr;9use jrsonnet_ir::Expr;111012use crate::{Context, Result, Thunk, Val, function::NativeFn, typed::IntoUntyped};11use crate::{Context, Result, Thunk, Val, function::NativeFn, typed::IntoUntyped};353436impl ArrValue {35impl ArrValue {37 pub fn empty() -> Self {36 pub fn empty() -> Self {38 Self::new(RangeArray::empty())37 Self::new(())39 }38 }403941 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 }4445 pub fn lazy(thunks: Vec<Thunk<Val>>) -> Self {46 Self::new(LazyArray(thunks))47 }4849 pub fn eager(values: Vec<Val>) -> Self {50 Self::new(EagerArray(values))51 }524353 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 }564757 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 };887689 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 }978598 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 choice100 const ARR_EXTEND_THRESHOLD: usize = 1000;101102 if a.is_empty() {87 if a.is_empty() {103 b88 b104 } else if b.is_empty() {89 } else if b.is_empty() {105 a90 a106 } 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 }12095121 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 }167142168 /// 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 }174146175 /// 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 values177 ///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 }182153183 /// 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 }198199 /// 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 None205 }206 }207169208 /// 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 }217218 /// Is this vec supports `.get_cheap()?`219 pub fn is_cheap(&self) -> bool {220 self.0.is_cheap()221 }222179223 pub fn as_any(&self) -> &dyn Any {180 pub fn as_any(&self) -> &dyn Any {224 &self.0181 &self.0225 }182 }226}183}227impl From<Vec<Val>> for ArrValue {184impl<T> From<T> for ArrValue185where186 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 ArrValue193where194 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 }246247 fn get(&self, index: usize) -> Result<Option<Val>> {248 self.0.get(index)249 }250251 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {252 self.0.get_lazy(index)253 }254255 fn get_cheap(&self, index: usize) -> Option<Val> {256 self.0.get_cheap(index)257 }258259 fn is_cheap(&self) -> bool {260 self.0.is_cheap()261 }262}263200crates/jrsonnet-evaluator/src/arr/spec.rsdiffbeforeafterboth1use 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};283use 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>;253026 fn is_cheap(&self) -> bool;31 fn is_cheap(&self) -> bool {32 false33 }27}34}35trait ArrayCheap {36 fn get(&self, index: usize) -> Option<Val>;37 fn len(&self) -> usize;38}39impl<T> ArrayLike for T40where41 T: Any + Trace + Debug + ArrayCheap,42{43 fn len(&self) -> usize {44 <T as ArrayCheap>::len(self)45 }4647 fn get(&self, index: usize) -> Result<Option<Val>> {48 Ok(<T as ArrayCheap>::get(self, index))49 }5051 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {52 <T as ArrayCheap>::get(self, index).map(Thunk::evaluated)53 }5455 fn is_cheap(&self) -> bool {56 true57 }58}5960impl ArrayCheap for () {61 fn len(&self) -> usize {62 063 }64 fn get(&self, _index: usize) -> Option<Val> {65 None66 }67}286829#[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 }549455 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}629963#[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 }6970 fn get(&self, index: usize) -> Result<Option<Val>> {106 fn get(&self, index: usize) -> Option<Val> {71 Ok(self.get_cheap(index))72 }7374 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {75 self.get_cheap(index).map(Thunk::evaluated)76 }7778 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 true83 }84}109}8511086#[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 }9293 fn get(&self, index: usize) -> Result<Option<Val>> {115 fn get(&self, index: usize) -> Option<Val> {94 Ok(self.get_cheap(index))95 }9697 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {98 self.get_cheap(index).map(Thunk::evaluated)99 }100101 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 true106 }107}118}108119109#[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 None196 }197 fn is_cheap(&self) -> bool {205 fn is_cheap(&self) -> bool {198 false206 false199 }207 }275 self.len283 self.len276 }284 }277285278 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}289290290#[derive(Trace, Debug)]291pub struct LazyArray(pub Vec<Thunk<Val>>);292impl ArrayLike for LazyArray {291impl<T> ArrayLike for Vec<T>292where293 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 }299296 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> {306303 None304 }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 }311308 fn is_cheap(&self) -> bool {312 fn is_cheap(&self) -> bool {309 false313 !T::provides_lazy()310 }314 }311}315}312313#[derive(Trace, Debug)]314pub struct EagerArray(pub Vec<Val>);315impl ArrayLike for EagerArray {316 fn len(&self) -> usize {317 self.0.len()318 }319320 fn get(&self, index: usize) -> Result<Option<Val>> {321 Ok(self.0.get(index).cloned())322 }323324 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {325 self.0.get(index).cloned().map(Thunk::evaluated)326 }327328 fn get_cheap(&self, index: usize) -> Option<Val> {329 self.0.get(index).cloned()330 }331 fn is_cheap(&self) -> bool {332 true333 }334}335316336/// Inclusive range type317/// Inclusive range type337#[derive(Debug, Trace, PartialEq, Eq)]318#[derive(Debug, Trace, PartialEq, Eq)]364 }345 }365}346}366367impl 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() == 0373 }374375 fn get(&self, index: usize) -> Result<Option<Val>> {376 Ok(self.get_cheap(index))377 }378379 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {380 self.get_cheap(index).map(Thunk::evaluated)381 }382383 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}390355403 self.0.get_lazy(self.0.len() - index - 1)368 self.0.get_lazy(self.0.len() - index - 1)404 }369 }405370406 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 }513514 fn get_cheap(&self, _index: usize) -> Option<Val> {515 None516 }517 fn is_cheap(&self) -> bool {518 false519 }520}475}521476522#[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}538539impl ArrayLike for RepeatedArray {540 fn len(&self) -> usize {541 self.total_len542 }543544 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}499500impl ArrayLike for RepeatedArray {501 fn len(&self) -> usize {502 self.total_len503 }550504551 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 }557511558 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 }516564 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}568521569#[derive(Trace, Debug)]522#[derive(Trace, Debug)]570pub struct PickObjectValues {523pub struct PickObjectValues {584 }537 }585538586 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 }592545593 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 }597598 fn get_cheap(&self, _index: usize) -> Option<Val> {599 None600 }601550602 fn is_cheap(&self) -> bool {551 fn is_cheap(&self) -> bool {603 false552 false628 }577 }629578630 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 }642591643 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 still646 // lazy-evaluated595 // lazy-evaluated647 Some(Thunk::evaluated(596 Some(Thunk::evaluated(653 ))602 ))654 }603 }655656 fn get_cheap(&self, _index: usize) -> Option<Val> {657 None658 }659604660 fn is_cheap(&self) -> bool {605 fn is_cheap(&self) -> bool {661 false606 falsecrates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth70 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);156156528 #[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());532532533 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 }crates/jrsonnet-evaluator/src/integrations/serde.rsdiffbeforeafterboth1use std::borrow::Cow;1use std::borrow::Cow;223use 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};121213use 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};171790 where90 where91 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 }959596 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 }132132133 Ok(Val::Arr(ArrValue::eager(out)))133 Ok(Val::arr(out))134 }134 }135135136 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 }271271272 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 }510510511 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 }514514515 fn serialize_none(self) -> Result<Val> {515 fn serialize_none(self) -> Result<Val> {crates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth667use 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 &T87where88 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>168where169 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 true176 }177178 fn into_lazy_untyped(inner: Self) -> Thunk<Val> {179 // Avoid lazy mapping180 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}160187161fn 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}766818767pub 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}782838811impl 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 {crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth137137138impl<T> Thunk<T>138impl<T> Thunk<T>139where139where140 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>163where163where164 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 where355 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}705708706impl From<IStr> for Val {709impl From<IStr> for Val {crates/jrsonnet-stdlib/src/arrays.rsdiffbeforeafterboth34 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}262262468 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();crates/jrsonnet-stdlib/src/sets.rsdiffbeforeafterboth292930#[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();353960 }64 }61 }65 }62 }66 }63 Ok(ArrValue::lazy(out))67 Ok(out)64}68}656966#[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();7179103 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}108116109#[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();114126154 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}159171crates/jrsonnet-stdlib/src/sort.rsdiffbeforeafterboth113 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}123123162 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}172172180 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