difftreelog
perf move std.object[Keys]Values[All] to native
in: master
6 files changed
crates/jrsonnet-evaluator/src/arr/spec.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/arr/spec.rs
+++ b/crates/jrsonnet-evaluator/src/arr/spec.rs
@@ -9,8 +9,9 @@
error::ErrorKind::InfiniteRecursionDetected,
evaluate,
function::FuncVal,
+ typed::Typed,
val::{StrValue, ThunkValue},
- Context, Error, Result, Thunk, Val,
+ Context, Error, ObjValue, Result, Thunk, Val,
};
pub trait ArrayLike: Any + Trace + Debug {
@@ -576,3 +577,103 @@
self.data.is_cheap()
}
}
+
+#[derive(Trace, Debug)]
+pub struct PickObjectValues {
+ obj: ObjValue,
+ keys: Vec<IStr>,
+}
+
+impl PickObjectValues {
+ pub fn new(obj: ObjValue, keys: Vec<IStr>) -> Self {
+ Self { obj, keys }
+ }
+}
+
+impl ArrayLike for PickObjectValues {
+ fn len(&self) -> usize {
+ self.keys.len()
+ }
+
+ fn get(&self, index: usize) -> Result<Option<Val>> {
+ let Some(key) = self.keys.get(index) else {
+ return Ok(None);
+ };
+ Ok(Some(self.obj.get_or_bail(key.clone())?))
+ }
+
+ fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {
+ let Some(key) = self.keys.get(index) else {
+ return None;
+ };
+ Some(self.obj.get_lazy_or_bail(key.clone()))
+ }
+
+ fn get_cheap(&self, _index: usize) -> Option<Val> {
+ None
+ }
+
+ fn is_cheap(&self) -> bool {
+ false
+ }
+}
+
+#[derive(Trace, Debug)]
+pub struct PickObjectKeyValues {
+ obj: ObjValue,
+ keys: Vec<IStr>,
+}
+
+impl PickObjectKeyValues {
+ pub fn new(obj: ObjValue, keys: Vec<IStr>) -> Self {
+ Self { obj, keys }
+ }
+}
+
+#[derive(Typed)]
+pub struct KeyValue {
+ key: IStr,
+ value: Thunk<Val>,
+}
+
+impl ArrayLike for PickObjectKeyValues {
+ fn len(&self) -> usize {
+ self.keys.len()
+ }
+
+ fn get(&self, index: usize) -> Result<Option<Val>> {
+ let Some(key) = self.keys.get(index) else {
+ return Ok(None);
+ };
+ Ok(Some(
+ KeyValue::into_untyped(KeyValue {
+ key: key.clone(),
+ value: Thunk::evaluated(self.obj.get_or_bail(key.clone())?),
+ })
+ .expect("convertible"),
+ ))
+ }
+
+ fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {
+ let Some(key) = self.keys.get(index) else {
+ return None;
+ };
+ // Nothing can fail in the key part, yet value is still
+ // lazy-evaluated
+ Some(Thunk::evaluated(
+ KeyValue::into_untyped(KeyValue {
+ key: key.clone(),
+ value: self.obj.get_lazy_or_bail(key.clone()),
+ })
+ .expect("convertible"),
+ ))
+ }
+
+ fn get_cheap(&self, _index: usize) -> Option<Val> {
+ None
+ }
+
+ fn is_cheap(&self) -> bool {
+ false
+ }
+}
crates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/obj.rs
+++ b/crates/jrsonnet-evaluator/src/obj.rs
@@ -12,12 +12,13 @@
use rustc_hash::FxHashMap;
use crate::{
- error::{Error, ErrorKind::*},
+ arr::{PickObjectKeyValues, PickObjectValues},
+ error::{suggest_object_fields, Error, ErrorKind::*},
function::CallLocation,
gc::{GcHashMap, GcHashSet, TraceBox},
operator::evaluate_add_op,
tb, throw,
- val::ThunkValue,
+ val::{ArrValue, ThunkValue},
MaybeUnbound, Result, State, Thunk, Unbound, Val,
};
@@ -398,6 +399,14 @@
self.0.get_for(key, this)
}
+ pub fn get_or_bail(&self, key: IStr) -> Result<Val> {
+ let Some(value) = self.get(key.clone())? else {
+ let suggestions = suggest_object_fields(self, key.clone());
+ throw!(NoSuchField(key, suggestions))
+ };
+ Ok(value)
+ }
+
fn get_raw(&self, key: IStr, this: ObjValue) -> Result<Option<Val>> {
self.0.get_for_uncached(key, this)
}
@@ -452,6 +461,25 @@
key,
}))
}
+ pub fn get_lazy_or_bail(&self, key: IStr) -> Thunk<Val> {
+ #[derive(Trace)]
+ struct ThunkGet {
+ obj: ObjValue,
+ key: IStr,
+ }
+ impl ThunkValue for ThunkGet {
+ type Output = Val;
+
+ fn get(self: Box<Self>) -> Result<Self::Output> {
+ Ok(self.obj.get_or_bail(self.key)?)
+ }
+ }
+
+ Thunk::new(ThunkGet {
+ obj: self.clone(),
+ key,
+ })
+ }
pub fn ptr_eq(a: &Self, b: &Self) -> bool {
Cc::ptr_eq(&a.0, &b.0)
}
@@ -529,6 +557,51 @@
preserve_order,
)
}
+ pub fn values_ex(
+ &self,
+ include_hidden: bool,
+ #[cfg(feature = "exp-preserve-order")] preserve_order: bool,
+ ) -> ArrValue {
+ ArrValue::new(PickObjectValues::new(
+ self.clone(),
+ self.fields_ex(
+ include_hidden,
+ #[cfg(feature = "exp-preserve-order")]
+ preserve_order,
+ ),
+ ))
+ }
+ pub fn values(&self, #[cfg(feature = "exp-preserve-order")] preserve_order: bool) -> ArrValue {
+ self.values_ex(
+ false,
+ #[cfg(feature = "exp-preserve-order")]
+ preserve_order,
+ )
+ }
+ pub fn key_values_ex(
+ &self,
+ include_hidden: bool,
+ #[cfg(feature = "exp-preserve-order")] preserve_order: bool,
+ ) -> ArrValue {
+ ArrValue::new(PickObjectKeyValues::new(
+ self.clone(),
+ self.fields_ex(
+ include_hidden,
+ #[cfg(feature = "exp-preserve-order")]
+ preserve_order,
+ ),
+ ))
+ }
+ pub fn key_values(
+ &self,
+ #[cfg(feature = "exp-preserve-order")] preserve_order: bool,
+ ) -> ArrValue {
+ self.key_values_ex(
+ false,
+ #[cfg(feature = "exp-preserve-order")]
+ preserve_order,
+ )
+ }
}
impl OopObject {
crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth1use std::{1use std::{2 cell::RefCell,2 cell::RefCell,3 fmt::{self, Debug, Display},3 fmt::{self, Debug, Display},4 hash::Hasher,5 mem::replace,4 mem::replace,6 rc::Rc,5 rc::Rc,7};6};879use jrsonnet_gcmodule::{Cc, Trace};8use jrsonnet_gcmodule::{Cc, Trace};10use jrsonnet_interner::IStr;9use jrsonnet_interner::IStr;11use jrsonnet_types::ValType;10use jrsonnet_types::ValType;12use rustc_hash::FxHasher;131114pub use crate::arr::{ArrValue, ArrayLike};12pub use crate::arr::{ArrValue, ArrayLike};15use crate::{13use crate::{50 pub fn errored(e: Error) -> Self {48 pub fn errored(e: Error) -> Self {51 Self(Cc::new(RefCell::new(ThunkInner::Errored(e))))49 Self(Cc::new(RefCell::new(ThunkInner::Errored(e))))52 }50 }51 pub fn result(res: Result<T, Error>) -> Self {52 match res {53 Ok(o) => Self::evaluated(o),54 Err(e) => Self::errored(e),55 }56 }53}57}545855impl<T> Thunk<T>59impl<T> Thunk<T>crates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/lib.rs
+++ b/crates/jrsonnet-stdlib/src/lib.rs
@@ -138,6 +138,10 @@
("base64DecodeBytes", builtin_base64_decode_bytes::INST),
// Objects
("objectFieldsEx", builtin_object_fields_ex::INST),
+ ("objectValues", builtin_object_values::INST),
+ ("objectValuesAll", builtin_object_values_all::INST),
+ ("objectKeysValues", builtin_object_keys_values::INST),
+ ("objectKeysValuesAll", builtin_object_keys_values_all::INST),
("objectHasEx", builtin_object_has_ex::INST),
("objectRemoveKey", builtin_object_remove_key::INST),
// Manifest
crates/jrsonnet-stdlib/src/objects.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/objects.rs
+++ b/crates/jrsonnet-stdlib/src/objects.rs
@@ -1,6 +1,6 @@
use jrsonnet_evaluator::{
function::builtin,
- val::{StrValue, Val},
+ val::{ArrValue, StrValue, Val},
IStr, ObjValue, ObjValueBuilder,
};
@@ -23,6 +23,82 @@
.collect::<Vec<_>>()
}
+pub fn builtin_object_values_ex(
+ o: ObjValue,
+ include_hidden: bool,
+ #[cfg(feature = "exp-preserve-order")] preserve_order: Option<bool>,
+) -> ArrValue {
+ #[cfg(feature = "exp-preserve-order")]
+ let preserve_order = preserve_order.unwrap_or(false);
+ o.values_ex(
+ include_hidden,
+ #[cfg(feature = "exp-preserve-order")]
+ preserve_order,
+ )
+}
+#[builtin]
+pub fn builtin_object_values(
+ o: ObjValue,
+ #[cfg(feature = "exp-preserve-order")] preserve_order: Option<bool>,
+) -> ArrValue {
+ builtin_object_values_ex(
+ o,
+ false,
+ #[cfg(feature = "exp-preserve-order")]
+ preserve_order,
+ )
+}
+#[builtin]
+pub fn builtin_object_values_all(
+ o: ObjValue,
+ #[cfg(feature = "exp-preserve-order")] preserve_order: Option<bool>,
+) -> ArrValue {
+ builtin_object_values_ex(
+ o,
+ true,
+ #[cfg(feature = "exp-preserve-order")]
+ preserve_order,
+ )
+}
+
+pub fn builtin_object_keys_values_ex(
+ o: ObjValue,
+ include_hidden: bool,
+ #[cfg(feature = "exp-preserve-order")] preserve_order: Option<bool>,
+) -> ArrValue {
+ #[cfg(feature = "exp-preserve-order")]
+ let preserve_order = preserve_order.unwrap_or(false);
+ o.key_values_ex(
+ include_hidden,
+ #[cfg(feature = "exp-preserve-order")]
+ preserve_order,
+ )
+}
+#[builtin]
+pub fn builtin_object_keys_values(
+ o: ObjValue,
+ #[cfg(feature = "exp-preserve-order")] preserve_order: Option<bool>,
+) -> ArrValue {
+ builtin_object_keys_values_ex(
+ o,
+ false,
+ #[cfg(feature = "exp-preserve-order")]
+ preserve_order,
+ )
+}
+#[builtin]
+pub fn builtin_object_keys_values_all(
+ o: ObjValue,
+ #[cfg(feature = "exp-preserve-order")] preserve_order: Option<bool>,
+) -> ArrValue {
+ builtin_object_keys_values_ex(
+ o,
+ true,
+ #[cfg(feature = "exp-preserve-order")]
+ preserve_order,
+ )
+}
+
#[builtin]
pub fn builtin_object_has_ex(obj: ObjValue, fname: IStr, hidden: bool) -> bool {
obj.has_field_ex(fname, hidden)
crates/jrsonnet-stdlib/src/std.jsonnetdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/std.jsonnet
+++ b/crates/jrsonnet-stdlib/src/std.jsonnet
@@ -268,18 +268,6 @@
objectHasAll(o, f)::
std.objectHasEx(o, f, true),
- objectValues(o)::
- [o[k] for k in std.objectFields(o)],
-
- objectValuesAll(o)::
- [o[k] for k in std.objectFieldsAll(o)],
-
- objectKeysValues(o)::
- [{ key: k, value: o[k] } for k in std.objectFields(o)],
-
- objectKeysValuesAll(o)::
- [{ key: k, value: o[k] } for k in std.objectFieldsAll(o)],
-
resolvePath(f, r)::
local arr = std.split(f, '/');
std.join('/', std.makeArray(std.length(arr) - 1, function(i) arr[i]) + [r]),