difftreelog
refactor use PreparedFunction for NativeFn
in: master
9 files changed
crates/jrsonnet-evaluator/src/arr/mod.rsdiffbeforeafterboth8use jrsonnet_interner::IBytes;9use jrsonnet_interner::IBytes;9use jrsonnet_parser::{Expr, Spanned};10use jrsonnet_parser::{Expr, Spanned};101111use crate::{function::FuncVal, Context, Result, Thunk, Val};12use crate::{typed::NativeFn, Context, Result, Thunk, Val};121313mod spec;14mod spec;14pub use spec::{ArrayLike, *};15pub use spec::{ArrayLike, *};61 }62 }626363 #[must_use]64 #[must_use]64 pub fn map(self, mapper: FuncVal) -> Self {65 pub fn map(self, mapper: NativeFn!((Val) -> Val)) -> Self {65 Self::new(<MappedArray<false>>::new(self, mapper))66 Self::new(<MappedArray>::new(self, ArrayMapper::Plain(mapper)))66 }67 }676868 #[must_use]69 #[must_use]69 pub fn map_with_index(self, mapper: FuncVal) -> Self {70 pub fn map_with_index(self, mapper: NativeFn!((u32, Val) -> Val)) -> Self {70 Self::new(<MappedArray<true>>::new(self, mapper))71 Self::new(<MappedArray>::new(self, ArrayMapper::WithIndex(mapper)))71 }72 }727373 pub fn filter(self, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {74 pub fn filter(self, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {crates/jrsonnet-evaluator/src/arr/spec.rsdiffbeforeafterboth6use jrsonnet_parser::{Expr, Spanned};6use jrsonnet_parser::{Expr, Spanned};778use super::ArrValue;8use super::ArrValue;9use crate::typed::NativeFn;10use crate::val::NumValue;9use crate::{11use crate::{10 error::ErrorKind::InfiniteRecursionDetected, evaluate, function::FuncVal, typed::Typed,12 error::ErrorKind::InfiniteRecursionDetected, evaluate, typed::Typed, val::ThunkValue, Context,11 val::ThunkValue, Context, Error, ObjValue, Result, Thunk, Val,13 Error, ObjValue, Result, Thunk, Val,12};14};1315404 }406 }405}407}408409#[derive(Trace, Clone, Debug)]410pub enum ArrayMapper {411 Plain(NativeFn!((Val) -> Val)),412 WithIndex(NativeFn!((u32, Val) -> Val)),413}406414407#[derive(Trace, Debug, Clone)]415#[derive(Trace, Debug, Clone)]408pub struct MappedArray<const WITH_INDEX: bool> {416pub struct MappedArray {409 inner: ArrValue,417 inner: ArrValue,410 cached: Cc<RefCell<Vec<ArrayThunk>>>,418 cached: Cc<RefCell<Vec<ArrayThunk>>>,411 mapper: FuncVal,419 mapper: ArrayMapper,412}420}413impl<const WITH_INDEX: bool> MappedArray<WITH_INDEX> {421impl MappedArray {414 pub fn new(inner: ArrValue, mapper: FuncVal) -> Self {422 pub fn new(inner: ArrValue, mapper: ArrayMapper) -> Self {415 let len = inner.len();423 let len = inner.len();416 Self {424 Self {417 inner,425 inner,420 }428 }421 }429 }422 fn evaluate(&self, index: usize, value: Val) -> Result<Val> {430 fn evaluate(&self, index: usize, value: Val) -> Result<Val> {423 if WITH_INDEX {424 self.mapper.evaluate_simple(&(index, value), false)431 match &self.mapper {425 } else {432 ArrayMapper::Plain(f) => f.call(value),426 self.mapper.evaluate_simple(&(value,), false)433 ArrayMapper::WithIndex(f) => f.call(index as u32, value),427 }434 }428 }435 }429}436}430impl<const WITH_INDEX: bool> ArrayLike for MappedArray<WITH_INDEX> {437impl ArrayLike for MappedArray {431 fn len(&self) -> usize {438 fn len(&self) -> usize {432 self.cached.borrow().len()439 self.cached.borrow().len()433 }440 }468 }475 }469 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {476 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {470 #[derive(Trace)]477 #[derive(Trace)]471 struct MappedArrayThunk<const WITH_INDEX: bool> {478 struct MappedArrayThunk {472 arr: MappedArray<WITH_INDEX>,479 arr: MappedArray,473 index: usize,480 index: usize,474 }481 }475 impl<const WITH_INDEX: bool> ThunkValue for MappedArrayThunk<WITH_INDEX> {482 impl ThunkValue for MappedArrayThunk {476 type Output = Val;483 type Output = Val;477484478 fn get(&self) -> Result<Self::Output> {485 fn get(&self) -> Result<Self::Output> {crates/jrsonnet-evaluator/src/function/mod.rsdiffbeforeafterboth8use jrsonnet_parser::{Destruct, Expr, ExprParams, Span, Spanned};8use jrsonnet_parser::{Destruct, Expr, ExprParams, Span, Spanned};9910use self::{10use self::{11 arglike::OptionalContext,12 builtin::{Builtin, StaticBuiltin},11 builtin::{Builtin, StaticBuiltin},13 native::NativeDesc,14 parse::{parse_builtin_call, parse_default_function_call, parse_function_call},12 parse::{parse_builtin_call, parse_default_function_call, parse_function_call},15 prepared::{parse_prepared_builtin_call, parse_prepared_function_call, PreparedCall},13 prepared::{parse_prepared_builtin_call, parse_prepared_function_call, PreparedCall},16};14};17use crate::{15use crate::{18 bail, error::ErrorKind::*, evaluate, evaluate_trivial, function::builtin::BuiltinFunc, Context,16 bail, error::ErrorKind::*, evaluate, evaluate_trivial, function::builtin::BuiltinFunc, Context,19 ContextBuilder, Result, Thunk, Val,17 Result, Thunk, Val,20};18};211922pub mod arglike;20pub mod arglike;200 }198 }201 }199 }202 }200 }203 pub fn evaluate_simple<A: ArgsLike + OptionalContext>(204 &self,205 args: &A,206 tailstrict: bool,207 ) -> Result<Val> {208 self.evaluate(209 ContextBuilder::new().build(),210 CallLocation::native(),211 args,212 tailstrict,213 )214 }215201216 pub(crate) fn evaluate_prepared(202 pub(crate) fn evaluate_prepared(217 &self,203 &self,247 }233 }248 }234 }249 }235 }250 /// Convert jsonnet function to plain `Fn` value.251 pub fn into_native<D: NativeDesc>(self) -> D::Value {252 D::into_native(self)253 }254236255 /// Is this function an indentity function.237 /// Is this function an indentity function.256 ///238 ///crates/jrsonnet-evaluator/src/function/native.rsdiffbeforeafterboth1use super::{1use super::PreparedFuncVal;2 arglike::{ArgLike, OptionalContext},3 FuncVal,4};5use crate::{typed::Typed, Result};2use crate::{typed::Typed, CallLocation, Result, Thunk};67pub trait NativeDesc {8 type Value;9 fn into_native(val: FuncVal) -> Self::Value;10}11macro_rules! impl_native_desc {12 ($($gen:ident)*) => {13 impl<$($gen,)* O> NativeDesc for (($($gen,)*), O)14 where15 $($gen: ArgLike + OptionalContext,)*16 O: Typed,17 {18 type Value = Box<dyn Fn($($gen,)*) -> Result<O>>;1920 #[allow(non_snake_case)]21 fn into_native(val: FuncVal) -> Self::Value {22 Box::new(move |$($gen),*| {23 let val = val.evaluate_simple(24 &($($gen,)*),25 false,26 )?;27 O::from_untyped(val)28 })29 }30 }31 };32 ($($cur:ident)* @ $c:ident $($rest:ident)*) => {33 impl_native_desc!($($cur)*);34 impl_native_desc!($($cur)* $c @ $($rest)*);35 };36 ($($cur:ident)* @) => {37 impl_native_desc!($($cur)*);38 }39}4041impl_native_desc! {42 @ A B C D E F G H I J K L43}443crates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth8use crate::{8use crate::{9 arr::{ArrValue, BytesArray},9 arr::{ArrValue, BytesArray},10 bail,10 bail,11 function::{native::NativeDesc, FuncDesc, FuncVal},11 function::{CallLocation, FuncDesc, FuncVal, PreparedFuncVal},12 typed::CheckType,12 typed::CheckType,13 val::{IndexableVal, NumValue, StrValue, ThunkMapper},13 val::{IndexableVal, NumValue, StrValue, ThunkMapper},14 ObjValue, ObjValueBuilder, Result, ResultExt, Thunk, Val,14 ObjValue, ObjValueBuilder, Result, ResultExt, Thunk, Val,675 }675 }676}676}677677678#[derive(Debug, Trace, Clone)]678pub struct NativeFn<D: NativeDesc>(D::Value);679pub struct NativeFn<D: 'static>(pub(crate) PreparedFuncVal, PhantomData<D>);679impl<D: NativeDesc> Deref for NativeFn<D> {680macro_rules! impl_native_desc {680 type Target = D::Value;681 ($i:expr; $($gen:ident)*) => {681682 fn deref(&self) -> &Self::Target {683 &self.0684 }685}686impl<D: NativeDesc> Typed for NativeFn<D> {682 impl<$($gen,)* O> NativeFn<($($gen,)* O,)>683 where684 $($gen: Typed,)*685 O: Typed,686 {687 pub fn call(688 &self,689 $($gen: $gen,)*690 ) -> Result<O> {691 let val = self.0.call(692 CallLocation::native(),693 &[$(Typed::into_lazy_untyped($gen),)*],694 &[],695 )?;696 O::from_untyped(val)697 }698 }699 impl<$($gen,)* O> Typed for NativeFn<($($gen,)* O,)> {687 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);700 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);688701689 fn into_untyped(_typed: Self) -> Result<Val> {702 fn into_untyped(_typed: Self) -> Result<Val> {690 bail!("can only convert functions from jsonnet to native")703 bail!("can only convert functions from jsonnet to native")691 }704 }692705693 fn from_untyped(untyped: Val) -> Result<Self> {706 fn from_untyped(untyped: Val) -> Result<Self> {707 let func = FuncVal::from_untyped(untyped)?;694 Ok(Self(708 Ok(Self(695 untyped696 .as_func()697 .expect("shape is checked")698 .into_native::<D>(),709 PreparedFuncVal::new(func, $i, &[])?,710 PhantomData,699 ))711 ))700 }712 }701}713 }714 };715 ($i:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {716 impl_native_desc!($i; $($cur)*);717 impl_native_desc!($i + 1; $($cur)* $c @ $($rest)*);718 };719 ($i:expr; $($cur:ident)* @) => {720 impl_native_desc!($i; $($cur)*);721 }722}723724impl_native_desc! {725 0; @ A B C D E F G H I J K L726}727728mod native_macro {729 #[macro_export]730 macro_rules! NativeFn {731 (($($t:ty),* $(,)?) -> $res:ty) => {732 NativeFn<($($t,)* $res)>733 }734 }735}736pub use crate::NativeFn;702737703impl Typed for NumValue {738impl Typed for NumValue {704 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Num);739 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Num);crates/jrsonnet-macros/src/lib.rsdiffbeforeafterboth3use proc_macro2::TokenStream;3use proc_macro2::TokenStream;4use quote::{quote, quote_spanned};4use quote::{quote, quote_spanned};5use syn::{5use syn::{6 parenthesized,7 parse::{Parse, ParseStream},8 parse_macro_input,9 punctuated::Punctuated,10 spanned::Spanned,11 token::{self, Comma},6 Attribute, DeriveInput, Error, Expr, ExprClosure, FnArg, GenericArgument, Ident, ItemFn, LitStr, Meta, Pat, Path, PathArguments, Result, ReturnType, Token, Type, parenthesized, parse::{Parse, ParseStream}, parse_macro_input, punctuated::Punctuated, spanned::Spanned, token::{self, Comma}12 Attribute, DeriveInput, Error, Expr, ExprClosure, FnArg, GenericArgument, Ident, ItemFn,13 LitStr, Meta, Pat, Path, PathArguments, Result, ReturnType, Token, Type,7};14};815crates/jrsonnet-stdlib/src/arrays.rsdiffbeforeafterboth23 return Ok(ArrValue::empty());23 return Ok(ArrValue::empty());24 }24 }25 func.evaluate_trivial().map_or_else(25 func.evaluate_trivial().map_or_else(26 // TODO: Different mapped array impl avoiding allocating unnecessary vals26 || Ok(ArrValue::range_exclusive(0, *sz).map(func)),27 || Ok(ArrValue::range_exclusive(0, *sz).map(Typed::from_untyped(Val::Func(func))?)),27 |trivial| {28 |trivial| {28 let mut out = Vec::with_capacity(*sz as usize);29 let mut out = Vec::with_capacity(*sz as usize);29 for _ in 0..*sz {30 for _ in 0..*sz {58}59}596060#[builtin]61#[builtin]61pub fn builtin_map(func: FuncVal, arr: IndexableVal) -> ArrValue {62pub fn builtin_map(func: NativeFn!((Val) -> Val), arr: IndexableVal) -> ArrValue {62 let arr = arr.to_array();63 let arr = arr.to_array();63 arr.map(func)64 arr.map(func)64}65}656666#[builtin]67#[builtin]67pub fn builtin_map_with_index(func: FuncVal, arr: IndexableVal) -> ArrValue {68pub fn builtin_map_with_index(func: NativeFn!((u32, Val) -> Val), arr: IndexableVal) -> ArrValue {68 let arr = arr.to_array();69 let arr = arr.to_array();69 arr.map_with_index(func)70 arr.map_with_index(func)70}71}717272#[builtin]73#[builtin]73pub fn builtin_map_with_key(func: FuncVal, obj: ObjValue) -> Result<ObjValue> {74pub fn builtin_map_with_key(75 func: NativeFn!((IStr, Val) -> Val),76 obj: ObjValue,77) -> Result<ObjValue> {74 let mut out = ObjValueBuilder::new();78 let mut out = ObjValueBuilder::new();80 true,84 true,81 ) {85 ) {82 let v = v?;86 let v = v?;83 out.field(k.clone())87 out.field(k.clone()).value(func.call(k, v)?);84 .value(func.evaluate_simple(&(k, v), false)?);85 }88 }86 Ok(out.build())89 Ok(out.build())87}90}889189#[builtin]92#[builtin]90pub fn builtin_flatmap(93pub fn builtin_flatmap(91 func: NativeFn<((Either![String, Val],), Val)>,94 func: NativeFn!((Either![String, Val]) -> Val),92 arr: IndexableVal,95 arr: IndexableVal,93) -> Result<IndexableVal> {96) -> Result<IndexableVal> {94 use std::fmt::Write;97 use std::fmt::Write;95 match arr {98 match arr {96 IndexableVal::Str(str) => {99 IndexableVal::Str(str) => {97 let mut out = String::new();100 let mut out = String::new();98 for c in str.chars() {101 for c in str.chars() {99 match func(Either2::A(c.to_string()))? {102 match func.call(Either2::A(c.to_string()))? {100 Val::Str(o) => write!(out, "{o}").unwrap(),103 Val::Str(o) => write!(out, "{o}").unwrap(),101 Val::Null => {},104 Val::Null => {}102 _ => bail!("in std.join all items should be strings"),105 _ => bail!("in std.join all items should be strings"),103 }106 }104 }107 }108 let mut out = Vec::new();111 let mut out = Vec::new();109 for el in a.iter() {112 for el in a.iter() {110 let el = el?;113 let el = el?;111 match func(Either2::B(el))? {114 match func.call(Either2::B(el))? {112 Val::Arr(o) => {115 Val::Arr(o) => {113 for oe in o.iter() {116 for oe in o.iter() {114 out.push(oe?);117 out.push(oe?);115 }118 }116 }119 }117 Val::Null => {},120 Val::Null => {}118 _ => bail!("in std.join all items should be arrays"),121 _ => bail!("in std.join all items should be arrays"),119 }122 }120 }123 }123 }126 }124}127}128129type FilterFunc = NativeFn!((Val) -> bool);125130126#[builtin]131#[builtin]127pub fn builtin_filter(func: FuncVal, arr: ArrValue) -> Result<ArrValue> {132pub fn builtin_filter(func: FilterFunc, arr: ArrValue) -> Result<ArrValue> {128 arr.filter(|val| bool::from_untyped(func.evaluate_simple(&(val.clone(),), false)?))133 arr.filter(|val| func.call(val.clone()))129}134}130135131#[builtin]136#[builtin]132pub fn builtin_filter_map(137pub fn builtin_filter_map(133 filter_func: FuncVal,138 filter_func: FilterFunc,134 map_func: FuncVal,139 map_func: NativeFn!((Val) -> Val),135 arr: ArrValue,140 arr: ArrValue,136) -> Result<ArrValue> {141) -> Result<ArrValue> {137 Ok(builtin_filter(filter_func, arr)?.map(map_func))142 Ok(builtin_filter(filter_func, arr)?.map(map_func))138}143}139144140#[builtin]145#[builtin]141pub fn builtin_foldl(func: FuncVal, arr: Either![ArrValue, IStr], init: Val) -> Result<Val> {146pub fn builtin_foldl(147 func: NativeFn!((Val, Either![Val, char]) -> Val),148 arr: Either![ArrValue, IStr],149 init: Val,150) -> Result<Val> {142 let mut acc = init;151 let mut acc = init;143 match arr {152 match arr {144 Either2::A(arr) => {153 Either2::A(arr) => {145 for i in arr.iter() {154 for i in arr.iter() {146 acc = func.evaluate_simple(&(acc, i?), false)?;155 acc = func.call(acc, Either2::A(i?))?;147 }156 }148 }157 }149 Either2::B(arr) => {158 Either2::B(arr) => {150 for i in arr.chars() {159 for c in arr.chars() {151 acc = func.evaluate_simple(&(acc, Val::string(i)), false)?;160 acc = func.call(acc, Either2::B(c))?;152 }161 }153 }162 }154 }163 }155 Ok(acc)164 Ok(acc)156}165}157166158#[builtin]167#[builtin]159pub fn builtin_foldr(func: FuncVal, arr: Either![ArrValue, IStr], init: Val) -> Result<Val> {168pub fn builtin_foldr(169 func: NativeFn!((Either![Val, char], Val) -> Val),170 arr: Either![ArrValue, IStr],171 init: Val,172) -> Result<Val> {160 let mut acc = init;173 let mut acc = init;161 match arr {174 match arr {162 Either2::A(arr) => {175 Either2::A(arr) => {163 for i in arr.iter().rev() {176 for i in arr.iter().rev() {164 acc = func.evaluate_simple(&(i?, acc), false)?;177 acc = func.call(Either2::A(i?), acc)?;165 }178 }166 }179 }167 Either2::B(arr) => {180 Either2::B(arr) => {168 for i in arr.chars().rev() {181 for c in arr.chars().rev() {169 acc = func.evaluate_simple(&(Val::string(i), acc), false)?;182 acc = func.call(Either2::B(c), acc)?;170 }183 }171 }184 }172 }185 }crates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth38mod compat;38mod compat;39mod encoding;39mod encoding;40mod hash;40mod hash;41mod keyf;41mod manifest;42mod manifest;42mod math;43mod math;43mod misc;44mod misc;50mod sort;51mod sort;51mod strings;52mod strings;52mod types;53mod types;53mod keyf;545455#[allow(clippy::too_many_lines)]55#[allow(clippy::too_many_lines)]56pub fn stdlib_uncached(settings: Cc<RefCell<Settings>>) -> ObjValue {56pub fn stdlib_uncached(settings: Cc<RefCell<Settings>>) -> ObjValue {tests/tests/as_native.rsdiffbeforeafterbothno changes