difftreelog
doc: review issues
in: master
19 files changed
bindings/jsonnet/src/import.rsdiffbeforeafterboth939394/// # Safety94/// # Safety95///95///96/// Caller should pass correct callback function96/// It should be safe to call `cb` using valid values with passed `ctx`97#[no_mangle]97#[no_mangle]98pub unsafe extern "C" fn jsonnet_import_callback(98pub unsafe extern "C" fn jsonnet_import_callback(99 vm: &State,99 vm: &State,109109110/// # Safety110/// # Safety111///111///112/// Caller should pass correct path: it should contain correct utf-8, and be \0-terminated112/// `path` should be a NUL-terminated string113#[no_mangle]113#[no_mangle]114pub unsafe extern "C" fn jsonnet_jpath_add(vm: &State, v: *const c_char) {114pub unsafe extern "C" fn jsonnet_jpath_add(vm: &State, path: *const c_char) {115 let cstr = CStr::from_ptr(v);115 let cstr = CStr::from_ptr(path);116 let path = PathBuf::from(cstr.to_str().unwrap());116 let path = PathBuf::from(cstr.to_str().unwrap());117 let any_resolver = vm.import_resolver();117 let any_resolver = vm.import_resolver();118 let resolver = any_resolver118 let resolver = any_resolverbindings/jsonnet/src/lib.rsdiffbeforeafterboth41 let str = OsStr::from_bytes(input.to_bytes());41 let str = OsStr::from_bytes(input.to_bytes());42 Cow::Borrowed(Path::new(str))42 Cow::Borrowed(Path::new(str))43 }43 }44 #[cfg(target_family = "windows")]44 #[cfg(not(target_family = "unix"))]45 {45 {46 use std::os::windows::ffi::OsStringExt;47 let str = input.to_str().expect("input is not utf8");46 let string = input.to_str().expect("bad utf-8");48 let wide = str.encode_utf16().collect::<Vec<_>>();49 let wide = OsString::from_wide(&wide);50 Cow::Owned(PathBuf::new(wide))47 Cow::Borrowed(string.as_ref())51 }48 }52 #[cfg(not(any(target_family = "unix", target_family = "windows")))]53 {54 compile_error!("unsupported os")55 }56}49}575058unsafe fn unparse_path(input: &Path) -> Cow<CStr> {51unsafe fn unparse_path(input: &Path) -> Cow<CStr> {62 let str = CString::new(input.as_os_str().as_bytes()).expect("input has zero byte in it");55 let str = CString::new(input.as_os_str().as_bytes()).expect("input has zero byte in it");63 Cow::Owned(str)56 Cow::Owned(str)64 }57 }65 #[cfg(not(any(target_family = "unix", target_family = "windows")))]58 #[cfg(not(target_family = "unix"))]66 {59 {60 let str = input.as_os_str().to_str().expect("bad utf-8");67 compile_error!("unsupported os")61 let cstr = CString::new(str).expect("input has NUL inside");62 Cow::Owned(cstr)68 }63 }69}64}7065169///164///170/// # Safety165/// # Safety171///166///172/// `filename` should be a \0-terminated string167/// `filename` should be a NUL-terminated string173#[no_mangle]168#[no_mangle]174pub unsafe extern "C" fn jsonnet_evaluate_file(169pub unsafe extern "C" fn jsonnet_evaluate_file(175 vm: &State,170 vm: &State,200///195///201/// # Safety196/// # Safety202///197///203/// `filename`, `snippet` should be a \0-terminated strings198/// `filename`, `snippet` should be a NUL-terminated strings204#[no_mangle]199#[no_mangle]205pub unsafe extern "C" fn jsonnet_evaluate_snippet(200pub unsafe extern "C" fn jsonnet_evaluate_snippet(206 vm: &State,201 vm: &State,bindings/jsonnet/src/native.rsdiffbeforeafterboth65/// # Safety65/// # Safety66///66///67/// `vm` should be a vm allocated by `jsonnet_make`67/// `vm` should be a vm allocated by `jsonnet_make`68/// `name` should be a NUL-terminated string68/// `cb` should be a correct function pointer69/// `cb` should be a function pointer69/// `raw_params` should point to a NULL-terminated string array70/// `raw_params` should point to a NULL-terminated array of NUL-terminated strings70/// `name`, `raw_params` elements should be a \0-terminated strings71#[no_mangle]71#[no_mangle]72pub unsafe extern "C" fn jsonnet_native_callback(72pub unsafe extern "C" fn jsonnet_native_callback(73 vm: &State,73 vm: &State,bindings/jsonnet/src/val_make.rsdiffbeforeafterboth12///12///13/// # Safety13/// # Safety14///14///15/// `v` should be a \0-terminated string15/// `v` should be a NUL-terminated string16#[no_mangle]16#[no_mangle]17pub unsafe extern "C" fn jsonnet_json_make_string(_vm: &State, val: *const c_char) -> *mut Val {17pub unsafe extern "C" fn jsonnet_json_make_string(_vm: &State, val: *const c_char) -> *mut Val {18 let val = CStr::from_ptr(val);18 let val = CStr::from_ptr(val);bindings/jsonnet/src/val_modify.rsdiffbeforeafterboth11///11///12/// # Safety12/// # Safety13///13///14/// `arr` should be correct pointer to array value allocated by make_array, or returned by other library call14/// `arr` should be a pointer to array value allocated by make_array, or returned by other library call15/// `val` should be correct pointer to value allocated using this library15/// `val` should be a pointer to value allocated using this library16#[no_mangle]16#[no_mangle]17pub unsafe extern "C" fn jsonnet_json_array_append(_vm: &State, arr: &mut Val, val: &Val) {17pub unsafe extern "C" fn jsonnet_json_array_append(_vm: &State, arr: &mut Val, val: &Val) {18 match arr {18 match arr {35///35///36/// # Safety36/// # Safety37///37///38/// `obj` should be a valid pointer to object value allocated by `make_object`, or returned by other library call38/// `obj` should be a pointer to object value allocated by `make_object`, or returned by other library call39/// `name` should be \0-terminated string39/// `name` should be NUL-terminated string40#[no_mangle]40#[no_mangle]41pub unsafe extern "C" fn jsonnet_json_object_append(41pub unsafe extern "C" fn jsonnet_json_object_append(42 _vm: &State,42 _vm: &State,bindings/jsonnet/src/vars_tlas.rsdiffbeforeafterboth445use jrsonnet_evaluator::State;5use jrsonnet_evaluator::State;667/// Bind a Jsonnet external var to the given string.7/// Binds a Jsonnet external variable to the given string.8///8///9/// Argument values are copied so memory should be managed by caller.9/// Argument values are copied so memory should be managed by the caller.10///10///11/// # Safety11/// # Safety12///12///13/// Caller should pass correct pointers as `name` and `code`, they need to be \0-terminated strings13/// `name`, `code` should be a NUL-terminated strings14#[no_mangle]14#[no_mangle]15pub unsafe extern "C" fn jsonnet_ext_var(vm: &State, name: *const c_char, value: *const c_char) {15pub unsafe extern "C" fn jsonnet_ext_var(vm: &State, name: *const c_char, value: *const c_char) {16 let name = CStr::from_ptr(name);16 let name = CStr::from_ptr(name);27 )27 )28}28}292930/// Bind a Jsonnet external var to the given code.30/// Binds a Jsonnet external variable to the given code.31///31///32/// Argument values are copied so memory should be managed by caller.32/// Argument values are copied so memory should be managed by the caller.33///33///34/// # Safety34/// # Safety35///35///36/// Caller should pass correct pointers as `name` and `code`, they need to be \0-terminated strings36/// `name`, `code` should be a NUL-terminated strings37#[no_mangle]37#[no_mangle]38pub unsafe extern "C" fn jsonnet_ext_code(vm: &State, name: *const c_char, code: *const c_char) {38pub unsafe extern "C" fn jsonnet_ext_code(vm: &State, name: *const c_char, code: *const c_char) {39 let name = CStr::from_ptr(name);39 let name = CStr::from_ptr(name);51 .expect("can't parse ext code")51 .expect("can't parse ext code")52}52}535354/// Bind a string top-level argument for a top-level parameter.54/// Binds a top-level string argument for a top-level parameter.55///55///56/// Argument values are copied so memory should be managed by caller.56/// Argument values are copied so memory should be managed by the caller.57///57///58/// # Safety58/// # Safety59///59///60/// Caller should pass correct pointers as `name` and `value`, they need to be \0-terminated strings60/// `name`, `value` should be a NUL-terminated strings61#[no_mangle]61#[no_mangle]62pub unsafe extern "C" fn jsonnet_tla_var(vm: &State, name: *const c_char, value: *const c_char) {62pub unsafe extern "C" fn jsonnet_tla_var(vm: &State, name: *const c_char, value: *const c_char) {63 let name = CStr::from_ptr(name);63 let name = CStr::from_ptr(name);68 )68 )69}69}707071/// Bind a code top-level argument for a top-level parameter.71/// Binds a top-level code argument for a top-level parameter.72///72///73/// Argument values are copied so memory should be managed by caller.73/// Argument values are copied so memory should be managed by the caller.74///74///75/// # Safety75/// # Safety76///76///77/// Caller should pass correct pointers as `name` and `code`, they need to be \0-terminated strings77/// `name`, `code` should be a NUL-terminated strings78#[no_mangle]78#[no_mangle]79pub unsafe extern "C" fn jsonnet_tla_code(vm: &State, name: *const c_char, code: *const c_char) {79pub unsafe extern "C" fn jsonnet_tla_code(vm: &State, name: *const c_char, code: *const c_char) {80 let name = CStr::from_ptr(name);80 let name = CStr::from_ptr(name);crates/jrsonnet-evaluator/src/ctx.rsdiffbeforeafterboth20 }20 }21}21}222223/// Context keeps information about current lexical code location24///25/// This information includes local variables, top-level object (`$`), current object (`this`), and super object (`super`)23#[derive(Debug, Clone, Trace)]26#[derive(Debug, Clone, Trace)]24pub struct Context(Cc<ContextInternals>);27pub struct Context(Cc<ContextInternals>);25impl Context {28impl Context {160 extend: Some(parent),163 extend: Some(parent),161 }164 }162 }165 }166 /// # Panics167 /// If `name` is already bound163 pub fn bind(&mut self, name: IStr, value: Thunk<Val>) -> &mut Self {168 pub fn bind(&mut self, name: IStr, value: Thunk<Val>) -> &mut Self {164 self.bindings.insert(name, value);169 let old = self.bindings.insert(name, value);170 assert!(old.is_none(), "variable bound twice in single context call");165 self171 self166 }172 }167 pub fn build(self) -> Context {173 pub fn build(self) -> Context {crates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth676768type FunctionSignature = Vec<(Option<IStr>, bool)>;68type FunctionSignature = Vec<(Option<IStr>, bool)>;696970/// Possible errors71#[allow(missing_docs)]70#[derive(Error, Debug, Clone, Trace)]72#[derive(Error, Debug, Clone, Trace)]73#[non_exhaustive]71pub enum Error {74pub enum Error {72 #[error("intrinsic not found: {0}")]75 #[error("intrinsic not found: {0}")]73 IntrinsicNotFound(IStr),76 IntrinsicNotFound(IStr),217 }220 }218}221}219222223/// Single stack trace frame220#[derive(Clone, Debug, Trace)]224#[derive(Clone, Debug, Trace)]221pub struct StackTraceElement {225pub struct StackTraceElement {226 /// Source of this frame227 /// Some frames only act as description, without attached source222 pub location: Option<ExprLocation>,228 pub location: Option<ExprLocation>,229 /// Frame description223 pub desc: String,230 pub desc: String,224}231}225#[derive(Debug, Clone, Trace)]232#[derive(Debug, Clone, Trace)]crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth269 }269 }270 }270 }271 let this = builder.build();271 let this = builder.build();272 let _ctx = ctx272 fctx.fill(ctx.extend(GcHashMap::new(), None, None, Some(this.clone())));273 .extend(GcHashMap::new(), None, None, Some(this.clone()))274 .into_future(fctx);275 Ok(this)273 Ok(this)276}274}277275356 ctx: Context,354 ctx: Context,357 value: &LocExpr,355 value: &LocExpr,358 args: &ArgsDesc,356 args: &ArgsDesc,359 loc: CallLocation,357 loc: CallLocation<'_>,360 tailstrict: bool,358 tailstrict: bool,361) -> Result<Val> {359) -> Result<Val> {362 let value = evaluate(s.clone(), ctx.clone(), value)?;360 let value = evaluate(s.clone(), ctx.clone(), value)?;602 }600 }603 Slice(value, desc) => {601 Slice(value, desc) => {604 fn parse_idx<T: Typed>(602 fn parse_idx<T: Typed>(605 loc: CallLocation,603 loc: CallLocation<'_>,606 s: State,604 s: State,607 ctx: &Context,605 ctx: &Context,608 expr: &Option<LocExpr>,606 expr: &Option<LocExpr>,crates/jrsonnet-evaluator/src/function/builtin.rsdiffbeforeafterboth28 &self,29 s: State,30 ctx: Context,31 loc: CallLocation<'_>,32 args: &dyn ArgsLike,33 ) -> Result<Val>;28}34}80 &self,81 s: State,82 ctx: Context,83 _loc: CallLocation<'_>,84 args: &dyn ArgsLike,85 ) -> Result<Val> {74 let args = parse_builtin_call(s.clone(), ctx, &self.params, args, true)?;86 let args = parse_builtin_call(s.clone(), ctx, &self.params, args, true)?;crates/jrsonnet-evaluator/src/function/mod.rsdiffbeforeafterboth18pub mod native;18pub mod native;19pub mod parse;19pub mod parse;202021/// Function callsite location.22/// Either from other jsonnet code, specified by expression location, or from native (without location).21#[derive(Clone, Copy)]23#[derive(Clone, Copy)]22pub struct CallLocation<'l>(pub Option<&'l ExprLocation>);24pub struct CallLocation<'l>(pub Option<&'l ExprLocation>);23impl<'l> CallLocation<'l> {25impl<'l> CallLocation<'l> {26 /// Construct new location for calls coming from specified jsonnet expression location.24 pub const fn new(loc: &'l ExprLocation) -> Self {27 pub const fn new(loc: &'l ExprLocation) -> Self {25 Self(Some(loc))28 Self(Some(loc))26 }29 }27}30}28impl CallLocation<'static> {31impl CallLocation<'static> {32 /// Construct new location for calls coming from native code.29 pub const fn native() -> Self {33 pub const fn native() -> Self {30 Self(None)34 Self(None)31 }35 }32}36}333734/// Function implemented in jsonnet38/// Represents Jsonnet function defined in code.35#[derive(Debug, PartialEq, Trace)]39#[derive(Debug, PartialEq, Trace)]36pub struct FuncDesc {40pub struct FuncDesc {37 /// In expressions like41 /// # Example42 ///43 /// In expressions like this, deducted to `a`, unspecified otherwise.38 /// ```jsonnet44 /// ```jsonnet39 /// local a = function() ...45 /// local a = function() ...40 /// local a() ...46 /// local a() ...41 /// { a: function() ... }47 /// { a: function() ... }42 /// { a() = ... }48 /// { a() = ... }43 /// ```49 /// ```44 ///45 /// Deducted to `a`, unspecified otherwise46 pub name: IStr,50 pub name: IStr,47 /// Context, in which this function was evaluated51 /// Context, in which this function was evaluated.48 ///52 ///53 /// # Example49 /// I.e in54 /// In50 /// ```jsonnet55 /// ```jsonnet51 /// local a = 2;56 /// local a = 2;52 /// function() ...57 /// function() ...53 /// ```58 /// ```54 /// context will contain `a`59 /// context will contain `a`.55 pub ctx: Context,60 pub ctx: Context,566162 /// Function parameter definition57 pub params: ParamsDesc,63 pub params: ParamsDesc,64 /// Function body58 pub body: LocExpr,65 pub body: LocExpr,59}66}60impl FuncDesc {67impl FuncDesc {82 }89 }83}90}849185/// Any possible function value, including plain functions and user-provided builtins92/// Represents a Jsonnet function value, including plain functions and user-provided builtins.86#[allow(clippy::module_name_repetitions)]93#[allow(clippy::module_name_repetitions)]87#[derive(Trace, Clone)]94#[derive(Trace, Clone)]88pub enum FuncVal {95pub enum FuncVal {89 /// std.id96 /// Identity function, kept this way for comparsions.90 Id,97 Id,91 /// Plain function implemented in jsonnet98 /// Plain function implemented in jsonnet.92 Normal(Cc<FuncDesc>),99 Normal(Cc<FuncDesc>),93 /// Standard library function100 /// Standard library function.94 StaticBuiltin(#[trace(skip)] &'static dyn StaticBuiltin),101 StaticBuiltin(#[trace(skip)] &'static dyn StaticBuiltin),95 /// User-provided function102 /// User-provided function.96 Builtin(Cc<TraceBox<dyn Builtin>>),103 Builtin(Cc<TraceBox<dyn Builtin>>),97}104}98105110}117}111118112impl FuncVal {119impl FuncVal {113 pub fn into_native<D: NativeDesc>(self) -> D::Value {120 /// Amount of non-default required arguments114 D::into_native(self)115 }116 pub fn params_len(&self) -> usize {121 pub fn params_len(&self) -> usize {117 match self {122 match self {118 Self::Id => 1,123 Self::Id => 1,121 Self::Builtin(i) => i.params().iter().filter(|p| !p.has_default).count(),126 Self::Builtin(i) => i.params().iter().filter(|p| !p.has_default).count(),122 }127 }123 }128 }129 /// Function name, as defined in code.124 pub fn name(&self) -> IStr {130 pub fn name(&self) -> IStr {125 match self {131 match self {126 Self::Id => "id".into(),132 Self::Id => "id".into(),129 Self::Builtin(builtin) => builtin.name().into(),135 Self::Builtin(builtin) => builtin.name().into(),130 }136 }131 }137 }138 /// Call function using arguments evaluated in specified `call_ctx` [`Context`].139 ///140 /// If `tailstrict` is specified - then arguments will be evaluated before being passed to function body.132 pub fn evaluate(141 pub fn evaluate(133 &self,142 &self,134 s: State,143 s: State,135 call_ctx: Context,144 call_ctx: Context,136 loc: CallLocation,145 loc: CallLocation<'_>,137 args: &dyn ArgsLike,146 args: &dyn ArgsLike,138 tailstrict: bool,147 tailstrict: bool,139 ) -> Result<Val> {148 ) -> Result<Val> {156 Self::Builtin(b) => b.call(s, call_ctx, loc, args),165 Self::Builtin(b) => b.call(s, call_ctx, loc, args),157 }166 }158 }167 }168 /// Helper method, which calls [`Self::evaluate`] with sensible defaults for native code.159 pub fn evaluate_simple(&self, s: State, args: &dyn ArgsLike) -> Result<Val> {169 pub fn evaluate_simple(&self, s: State, args: &dyn ArgsLike) -> Result<Val> {160 self.evaluate(s, Context::default(), CallLocation::native(), args, true)170 self.evaluate(s, Context::default(), CallLocation::native(), args, true)161 }171 }162172 /// Convert jsonnet function to plain `Fn` value.173 pub fn into_native<D: NativeDesc>(self) -> D::Value {174 D::into_native(self)175 }176177 /// Is this function an indentity function.178 ///179 /// Currently only works for builtin `std.id`, aka `Self::Id` value, `function(x) x` defined by jsonnet will not count as identity.163 pub const fn is_identity(&self) -> bool {180 pub const fn is_identity(&self) -> bool {164 matches!(self, Self::Id)181 matches!(self, Self::Id)165 }182 }183 /// Identity function value.166 pub const fn identity() -> Self {184 pub const fn identity() -> Self {167 Self::Id185 Self::Id168 }186 }crates/jrsonnet-evaluator/src/gc.rsdiffbeforeafterboth22}22}232324impl<T: ?Sized + Trace> Trace for TraceBox<T> {24impl<T: ?Sized + Trace> Trace for TraceBox<T> {25 fn trace(&self, tracer: &mut Tracer) {25 fn trace(&self, tracer: &mut Tracer<'_>) {26 self.0.trace(tracer);26 self.0.trace(tracer);27 }27 }282892where92where93 V: Trace,93 V: Trace,94{94{95 fn trace(&self, tracer: &mut jrsonnet_gcmodule::Tracer) {95 fn trace(&self, tracer: &mut Tracer<'_>) {96 for v in &self.0 {96 for v in &self.0 {97 v.trace(tracer);97 v.trace(tracer);98 }98 }133 K: Trace,133 K: Trace,134 V: Trace,134 V: Trace,135{135{136 fn trace(&self, tracer: &mut jrsonnet_gcmodule::Tracer) {136 fn trace(&self, tracer: &mut Tracer<'_>) {137 for (k, v) in &self.0 {137 for (k, v) in &self.0 {138 k.trace(tracer);138 k.trace(tracer);139 v.trace(tracer);139 v.trace(tracer);crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth1//! jsonnet interpreter implementation23#![deny(unsafe_op_in_unsafe_fn)]1#![warn(clippy::all, clippy::nursery, clippy::pedantic)]4#![warn(5 clippy::all,6 clippy::nursery,7 clippy::pedantic,8 // missing_docs,9 elided_lifetimes_in_paths,10 explicit_outlives_requirements,11 noop_method_call,12 single_use_lifetimes,13 variant_size_differences,14 rustdoc::all15)]2#![allow(16#![allow(3 macro_expanded_macro_exports_accessed_by_absolute_paths,17 macro_expanded_macro_exports_accessed_by_absolute_paths,67use trace::{CompactFormat, TraceFormat};81use trace::{CompactFormat, TraceFormat};68pub use val::{ManifestFormat, Thunk, Val};82pub use val::{ManifestFormat, Thunk, Val};698384/// Thunk without bound `super`/`this`85/// object inheritance may be overriden multiple times, and will be fixed only on field read70pub trait Unbound: Trace {86pub trait Unbound: Trace {87 /// Type of value after object context is bound71 type Bound;88 type Bound;89 /// Create value bound to specified object context72 fn bind(&self, s: State, sup: Option<ObjValue>, this: Option<ObjValue>) -> Result<Self::Bound>;90 fn bind(&self, s: State, sup: Option<ObjValue>, this: Option<ObjValue>) -> Result<Self::Bound>;73}91}749293/// Object fields may, or may not depend on `this`/`super`, this enum allows cheaper reuse of object-independent fields for native code94/// Standard jsonnet fields are always unbound75#[derive(Clone, Trace)]95#[derive(Clone, Trace)]76pub enum LazyBinding {96pub enum MaybeUnbound {97 /// Value needs to be bound to `this`/`super`77 Bindable(Cc<TraceBox<dyn Unbound<Bound = Thunk<Val>>>>),98 Unbound(Cc<TraceBox<dyn Unbound<Bound = Thunk<Val>>>>),99 /// Value is object-independent78 Bound(Thunk<Val>),100 Bound(Thunk<Val>),79}101}8010281impl Debug for LazyBinding {103impl Debug for MaybeUnbound {82 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {83 write!(f, "LazyBinding")105 write!(f, "MaybeUnbound")84 }106 }85}107}86impl LazyBinding {108impl MaybeUnbound {109 /// Attach object context to value, if required87 pub fn evaluate(110 pub fn evaluate(88 &self,111 &self,89 s: State,112 s: State,90 sup: Option<ObjValue>,113 sup: Option<ObjValue>,91 this: Option<ObjValue>,114 this: Option<ObjValue>,92 ) -> Result<Thunk<Val>> {115 ) -> Result<Thunk<Val>> {93 match self {116 match self {94 Self::Bindable(v) => v.bind(s, sup, this),117 Self::Unbound(v) => v.bind(s, sup, this),95 Self::Bound(v) => Ok(v.clone()),118 Self::Bound(v) => Ok(v.clone()),96 }119 }97 }120 }98}121}99122100/// During import, this trait will be called to create initial context for file123/// During import, this trait will be called to create initial context for file.101/// It may initialize global variables, stdlib for example124/// It may initialize global variables, stdlib for example.102pub trait ContextInitializer {125pub trait ContextInitializer {126 /// Initialize default file context.103 fn initialize(&self, state: State, for_file: Source) -> Context;127 fn initialize(&self, state: State, for_file: Source) -> Context;104128 /// Allows upcasting from abstract to concrete context initializer.129 /// jrsonnet by itself doesn't use this method, it is allowed for it to panic.105 fn as_any(&self) -> &dyn Any;130 fn as_any(&self) -> &dyn Any;106}131}107132116 }141 }117}142}118143144/// Dynamically reconfigurable evaluation settings119pub struct EvaluationSettings {145pub struct EvaluationSettings {120 /// Limits recursion by limiting the number of stack frames146 /// Limits recursion by limiting the number of stack frames121 pub max_stack: usize,147 pub max_stack: usize,401 /// Executes code creating a new stack frame427 /// Executes code creating a new stack frame402 pub fn push<T>(428 pub fn push<T>(403 &self,429 &self,404 e: CallLocation,430 e: CallLocation<'_>,405 frame_desc: impl FnOnce() -> String,431 frame_desc: impl FnOnce() -> String,406 f: impl FnOnce() -> Result<T>,432 f: impl FnOnce() -> Result<T>,407 ) -> Result<T> {433 ) -> Result<T> {547573548/// Internals574/// Internals549impl State {575impl State {550 // fn data(&self) -> Ref<EvaluationData> {551 // self.0.data.borrow()552 // }553 fn data_mut(&self) -> RefMut<EvaluationData> {576 fn data_mut(&self) -> RefMut<'_, EvaluationData> {554 self.0.data.borrow_mut()577 self.0.data.borrow_mut()555 }578 }556 pub fn settings(&self) -> Ref<EvaluationSettings> {579 pub fn settings(&self) -> Ref<'_, EvaluationSettings> {557 self.0.settings.borrow()580 self.0.settings.borrow()558 }581 }559 pub fn settings_mut(&self) -> RefMut<EvaluationSettings> {582 pub fn settings_mut(&self) -> RefMut<'_, EvaluationSettings> {560 self.0.settings.borrow_mut()583 self.0.settings.borrow_mut()561 }584 }562}585}623 pub fn resolve(&self, path: impl AsRef<Path>) -> Result<SourcePath> {646 pub fn resolve(&self, path: impl AsRef<Path>) -> Result<SourcePath> {624 self.import_resolver().resolve(path.as_ref())647 self.import_resolver().resolve(path.as_ref())625 }648 }626 pub fn import_resolver(&self) -> Ref<dyn ImportResolver> {649 pub fn import_resolver(&self) -> Ref<'_, dyn ImportResolver> {627 Ref::map(self.settings(), |s| &*s.import_resolver)650 Ref::map(self.settings(), |s| &*s.import_resolver)628 }651 }629 pub fn set_import_resolver(&self, resolver: Box<dyn ImportResolver>) {652 pub fn set_import_resolver(&self, resolver: Box<dyn ImportResolver>) {630 self.settings_mut().import_resolver = resolver;653 self.settings_mut().import_resolver = resolver;631 }654 }632 pub fn context_initializer(&self) -> Ref<dyn ContextInitializer> {655 pub fn context_initializer(&self) -> Ref<'_, dyn ContextInitializer> {633 Ref::map(self.settings(), |s| &*s.context_initializer)656 Ref::map(self.settings(), |s| &*s.context_initializer)634 }657 }635658640 self.settings_mut().manifest_format = format;663 self.settings_mut().manifest_format = format;641 }664 }642665643 pub fn trace_format(&self) -> Ref<dyn TraceFormat> {666 pub fn trace_format(&self) -> Ref<'_, dyn TraceFormat> {644 Ref::map(self.settings(), |s| &*s.trace_format)667 Ref::map(self.settings(), |s| &*s.trace_format)645 }668 }646 pub fn set_trace_format(&self, format: Box<dyn TraceFormat>) {669 pub fn set_trace_format(&self, format: Box<dyn TraceFormat>) {crates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth15 function::CallLocation,15 function::CallLocation,16 gc::{GcHashMap, GcHashSet, TraceBox},16 gc::{GcHashMap, GcHashSet, TraceBox},17 operator::evaluate_add_op,17 operator::evaluate_add_op,18 throw, LazyBinding, Result, State, Thunk, Unbound, Val,18 throw, MaybeUnbound, Result, State, Thunk, Unbound, Val,19};19};202021#[cfg(not(feature = "exp-preserve-order"))]21#[cfg(not(feature = "exp-preserve-order"))]100 pub add: bool,100 pub add: bool,101 pub visibility: Visibility,101 pub visibility: Visibility,102 original_index: FieldIndex,102 original_index: FieldIndex,103 pub invoke: LazyBinding,103 pub invoke: MaybeUnbound,104 pub location: Option<ExprLocation>,104 pub location: Option<ExprLocation>,105}105}106106208 new.insert(key, value);208 new.insert(key, value);209 Self::new(Some(self), Cc::new(new), Cc::new(Vec::new()))209 Self::new(Some(self), Cc::new(new), Cc::new(Vec::new()))210 }210 }211 pub fn extend_field(&mut self, name: IStr) -> ObjMemberBuilder<ExtendBuilder> {211 pub fn extend_field(&mut self, name: IStr) -> ObjMemberBuilder<ExtendBuilder<'_>> {212 ObjMemberBuilder::new(ExtendBuilder(self), name, FieldIndex::default())212 ObjMemberBuilder::new(ExtendBuilder(self), name, FieldIndex::default())213 }213 }214214239 }239 }240240241 /// Run callback for every field found in object241 /// Run callback for every field found in object242 ///243 /// Returns true if ended prematurely242 pub(crate) fn enum_fields(244 pub(crate) fn enum_fields(243 &self,245 &self,244 depth: SuperDepth,246 depth: SuperDepth,500 self.assertions.push(assertion);502 self.assertions.push(assertion);501 self503 self502 }504 }503 pub fn member(&mut self, name: IStr) -> ObjMemberBuilder<ValueBuilder> {505 pub fn member(&mut self, name: IStr) -> ObjMemberBuilder<ValueBuilder<'_>> {504 let field_index = self.next_field_index;506 let field_index = self.next_field_index;505 self.next_field_index = self.next_field_index.next();507 self.next_field_index = self.next_field_index.next();506 ObjMemberBuilder::new(ValueBuilder(self), name, field_index)508 ObjMemberBuilder::new(ValueBuilder(self), name, field_index)558 self.location = Some(location);560 self.location = Some(location);559 self561 self560 }562 }561 fn build_member(self, binding: LazyBinding) -> (Kind, IStr, ObjMember) {563 fn build_member(self, binding: MaybeUnbound) -> (Kind, IStr, ObjMember) {562 (564 (563 self.kind,565 self.kind,564 self.name,566 self.name,574}576}575577576pub struct ValueBuilder<'v>(&'v mut ObjValueBuilder);578pub struct ValueBuilder<'v>(&'v mut ObjValueBuilder);577impl<'v> ObjMemberBuilder<ValueBuilder<'v>> {579impl ObjMemberBuilder<ValueBuilder<'_>> {578 pub fn value(self, s: State, value: Val) -> Result<()> {580 pub fn value(self, s: State, value: Val) -> Result<()> {579 self.binding(s, LazyBinding::Bound(Thunk::evaluated(value)))581 self.binding(s, MaybeUnbound::Bound(Thunk::evaluated(value)))580 }582 }581 pub fn bindable(583 pub fn bindable(582 self,584 self,583 s: State,585 s: State,584 bindable: TraceBox<dyn Unbound<Bound = Thunk<Val>>>,586 bindable: TraceBox<dyn Unbound<Bound = Thunk<Val>>>,585 ) -> Result<()> {587 ) -> Result<()> {586 self.binding(s, LazyBinding::Bindable(Cc::new(bindable)))588 self.binding(s, MaybeUnbound::Unbound(Cc::new(bindable)))587 }589 }588 pub fn binding(self, s: State, binding: LazyBinding) -> Result<()> {590 pub fn binding(self, s: State, binding: MaybeUnbound) -> Result<()> {589 let (receiver, name, member) = self.build_member(binding);591 let (receiver, name, member) = self.build_member(binding);590 let location = member.location.clone();592 let location = member.location.clone();591 let old = receiver.0.map.insert(name.clone(), member);593 let old = receiver.0.map.insert(name.clone(), member);601}603}602604603pub struct ExtendBuilder<'v>(&'v mut ObjValue);605pub struct ExtendBuilder<'v>(&'v mut ObjValue);604impl<'v> ObjMemberBuilder<ExtendBuilder<'v>> {606impl ObjMemberBuilder<ExtendBuilder<'_>> {605 pub fn value(self, value: Val) {607 pub fn value(self, value: Val) {606 self.binding(LazyBinding::Bound(Thunk::evaluated(value)));608 self.binding(MaybeUnbound::Bound(Thunk::evaluated(value)));607 }609 }608 pub fn bindable(self, bindable: TraceBox<dyn Unbound<Bound = Thunk<Val>>>) {610 pub fn bindable(self, bindable: TraceBox<dyn Unbound<Bound = Thunk<Val>>>) {609 self.binding(LazyBinding::Bindable(Cc::new(bindable)));611 self.binding(MaybeUnbound::Unbound(Cc::new(bindable)));610 }612 }611 pub fn binding(self, binding: LazyBinding) {613 pub fn binding(self, binding: MaybeUnbound) {612 let (receiver, name, member) = self.build_member(binding);614 let (receiver, name, member) = self.build_member(binding);613 let new = receiver.0.clone();615 let new = receiver.0.clone();614 *receiver.0 = new.extend_with_raw_member(name, member);616 *receiver.0 = new.extend_with_raw_member(name, member);crates/jrsonnet-evaluator/src/stdlib/format.rsdiffbeforeafterboth363637type ParseResult<'t, T> = std::result::Result<(T, &'t str), FormatError>;37type ParseResult<'t, T> = std::result::Result<(T, &'t str), FormatError>;383839pub fn try_parse_mapping_key(str: &str) -> ParseResult<&str> {39pub fn try_parse_mapping_key(str: &str) -> ParseResult<'_, &str> {40 if str.is_empty() {40 if str.is_empty() {41 return Err(TruncatedFormatCode);41 return Err(TruncatedFormatCode);42 }42 }96 pub sign: bool,96 pub sign: bool,97}97}989899pub fn try_parse_cflags(str: &str) -> ParseResult<CFlags> {99pub fn try_parse_cflags(str: &str) -> ParseResult<'_, CFlags> {100 if str.is_empty() {100 if str.is_empty() {101 return Err(TruncatedFormatCode);101 return Err(TruncatedFormatCode);102 }102 }125 Star,125 Star,126 Fixed(usize),126 Fixed(usize),127}127}128pub fn try_parse_field_width(str: &str) -> ParseResult<Width> {128pub fn try_parse_field_width(str: &str) -> ParseResult<'_, Width> {129 if str.is_empty() {129 if str.is_empty() {130 return Err(TruncatedFormatCode);130 return Err(TruncatedFormatCode);131 }131 }146 Ok((Width::Fixed(out), &str[digits..]))146 Ok((Width::Fixed(out), &str[digits..]))147}147}148148149pub fn try_parse_precision(str: &str) -> ParseResult<Option<Width>> {149pub fn try_parse_precision(str: &str) -> ParseResult<'_, Option<Width>> {150 if str.is_empty() {150 if str.is_empty() {151 return Err(TruncatedFormatCode);151 return Err(TruncatedFormatCode);152 }152 }159}159}160160161// Only skips161// Only skips162pub fn try_parse_length_modifier(str: &str) -> ParseResult<()> {162pub fn try_parse_length_modifier(str: &str) -> ParseResult<'_, ()> {163 if str.is_empty() {163 if str.is_empty() {164 return Err(TruncatedFormatCode);164 return Err(TruncatedFormatCode);165 }165 }191 caps: bool,191 caps: bool,192}192}193193194pub fn parse_conversion_type(str: &str) -> ParseResult<ConvType> {194pub fn parse_conversion_type(str: &str) -> ParseResult<'_, ConvType> {195 if str.is_empty() {195 if str.is_empty() {196 return Err(TruncatedFormatCode);196 return Err(TruncatedFormatCode);197 }197 }226 convtype: ConvTypeV,226 convtype: ConvTypeV,227 caps: bool,227 caps: bool,228}228}229pub fn parse_code(str: &str) -> ParseResult<Code> {229pub fn parse_code(str: &str) -> ParseResult<'_, Code<'_>> {230 if str.is_empty() {230 if str.is_empty() {231 return Err(TruncatedFormatCode);231 return Err(TruncatedFormatCode);232 }232 }255 String(&'s str),255 String(&'s str),256 Code(Code<'s>),256 Code(Code<'s>),257}257}258pub fn parse_codes(mut str: &str) -> Result<Vec<Element>> {258pub fn parse_codes(mut str: &str) -> Result<Vec<Element<'_>>> {259 let mut bytes = str.as_bytes();259 let mut bytes = str.as_bytes();260 let mut out = vec![];260 let mut out = vec![];261 let mut offset = 0;261 let mut offset = 0;475 s: State,475 s: State,476 out: &mut String,476 out: &mut String,477 value: &Val,477 value: &Val,478 code: &Code,478 code: &Code<'_>,479 width: usize,479 width: usize,480 precision: Option<usize>,480 precision: Option<usize>,481) -> Result<()> {481) -> Result<()> {crates/jrsonnet-evaluator/src/stdlib/manifest.rsdiffbeforeafterboth116 || {116 || {117 let value = obj.get(s.clone(), field.clone())?.unwrap();117 let value = obj.get(s.clone(), field.clone())?.unwrap();118 manifest_json_ex_buf(s.clone(), &value, buf, cur_padding, options)?;118 manifest_json_ex_buf(s.clone(), &value, buf, cur_padding, options)?;119 Ok(Val::Null)119 Ok(())120 },120 },121 )?;121 )?;122 }122 }crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth186 }186 }187}187}188188189/// Represents a Jsonnet array value.189#[derive(Debug, Clone, Trace)]190#[derive(Debug, Clone, Trace)]190// may contrain other ArrValue191// may contrain other ArrValue191#[trace(tracking(force))]192#[trace(tracking(force))]192pub enum ArrValue {193pub enum ArrValue {194 /// Layout optimized byte array.193 Bytes(#[trace(skip)] IBytes),195 Bytes(#[trace(skip)] IBytes),196 /// Every element is lazy evaluated.194 Lazy(Cc<Vec<Thunk<Val>>>),197 Lazy(Cc<Vec<Thunk<Val>>>),198 /// Every field is already evaluated.195 Eager(Cc<Vec<Val>>),199 Eager(Cc<Vec<Val>>),200 /// Concatenation of two arrays of any kind.196 Extended(Box<(Self, Self)>),201 Extended(Box<(Self, Self)>),202 /// Represents a integer array in form `[start, start + 1, ... end - 1, end]`.203 /// This kind of arrays is generated by `std.range(start, end)` call, and used for loops.197 Range(i32, i32),204 Range(i32, i32),205 /// Sliced array view.198 Slice(Box<Slice>),206 Slice(Box<Slice>),207 /// Reversed array view.208 /// Returned by `std.reverse(other)` call199 Reversed(Box<Self>),209 Reversed(Box<Self>),200}210}201211237 }))247 }))238 }248 }239249250 /// Array length.240 pub fn len(&self) -> usize {251 pub fn len(&self) -> usize {241 match self {252 match self {242 Self::Bytes(i) => i.len(),253 Self::Bytes(i) => i.len(),249 }260 }250 }261 }251262263 /// Is array contains no elements?252 pub fn is_empty(&self) -> bool {264 pub fn is_empty(&self) -> bool {253 self.len() == 0265 self.len() == 0254 }266 }255267268 /// Get array element by index, evaluating it, if it is lazy.269 ///270 /// Returns `None` on out-of-bounds condition.256 pub fn get(&self, s: State, index: usize) -> Result<Option<Val>> {271 pub fn get(&self, s: State, index: usize) -> Result<Option<Val>> {257 match self {272 match self {258 Self::Bytes(i) => i273 Self::Bytes(i) => i297 }312 }298 }313 }299314315 /// Get array element by index, without evaluation.316 ///317 /// Returns `None` on out-of-bounds condition.300 pub fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {318 pub fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {301 match self {319 match self {302 Self::Bytes(i) => i320 Self::Bytes(i) => i337 }355 }338 }356 }339357358 /// Evaluate all array elements, returning new array.340 pub fn evaluated(&self, s: State) -> Result<Cc<Vec<Val>>> {359 pub fn evaluated(&self, s: State) -> Result<Cc<Vec<Val>>> {341 Ok(match self {360 Ok(match self {342 Self::Bytes(i) => {361 Self::Bytes(i) => {389 })408 })390 }409 }391410411 /// Iterate over elements, evaluating them.392 pub fn iter(&self, s: State) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {412 pub fn iter(&self, s: State) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {393 (0..self.len()).map(move |idx| match self {413 (0..self.len()).map(move |idx| match self {394 Self::Bytes(b) => Ok(Val::Num(f64::from(b[idx]))),414 Self::Bytes(b) => Ok(Val::Num(f64::from(b[idx]))),400 })420 })401 }421 }402422423 /// Iterate over elements, returning lazy values.403 pub fn iter_lazy(&self) -> impl DoubleEndedIterator<Item = Thunk<Val>> + '_ {424 pub fn iter_lazy(&self) -> impl DoubleEndedIterator<Item = Thunk<Val>> + '_ {404 (0..self.len()).map(move |idx| match self {425 (0..self.len()).map(move |idx| match self {405 Self::Bytes(b) => Thunk::evaluated(Val::Num(f64::from(b[idx]))),426 Self::Bytes(b) => Thunk::evaluated(Val::Num(f64::from(b[idx]))),411 })432 })412 }433 }413434435 /// Return a reversed view on current array.414 #[must_use]436 #[must_use]415 pub fn reversed(self) -> Self {437 pub fn reversed(self) -> Self {416 Self::Reversed(Box::new(self))438 Self::Reversed(Box::new(self))417 }439 }418440441 /// Return a new array, produced by passing every element of current array to specified callback function.419 pub fn map(self, s: State, mapper: impl Fn(Val) -> Result<Val>) -> Result<Self> {442 pub fn map(self, s: State, mapper: impl Fn(Val) -> Result<Val>) -> Result<Self> {420 let mut out = Vec::with_capacity(self.len());443 let mut out = Vec::with_capacity(self.len());421444426 Ok(Self::Eager(Cc::new(out)))449 Ok(Self::Eager(Cc::new(out)))427 }450 }428451452 /// Return a new array, produced from current array by removing every value, for which specified callback function returns false.429 pub fn filter(self, s: State, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {453 pub fn filter(self, s: State, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {430 let mut out = Vec::with_capacity(self.len());454 let mut out = Vec::with_capacity(self.len());431455460 }484 }461}485}462486487/// Represents a Jsonnet value, which can be spliced or indexed (string or array).463#[allow(clippy::module_name_repetitions)]488#[allow(clippy::module_name_repetitions)]464pub enum IndexableVal {489pub enum IndexableVal {490 /// String.465 Str(IStr),491 Str(IStr),492 /// Array.466 Arr(ArrValue),493 Arr(ArrValue),467}494}468impl IndexableVal {495impl IndexableVal {496 /// Slice the value.497 ///498 /// # Implementation499 ///500 /// For strings, will create a copy of specified interval.501 ///502 /// For arrays, nothing will be copied on this call, instead [`ArrValue::Slice`] view will be returned.469 pub fn slice(503 pub fn slice(470 self,504 self,471 index: Option<BoundedUsize<0, { i32::MAX as usize }>>,505 index: Option<BoundedUsize<0, { i32::MAX as usize }>>,511 }545 }512}546}513547548/// Represents any valid Jsonnet value.514#[derive(Debug, Clone, Trace)]549#[derive(Debug, Clone, Trace)]515pub enum Val {550pub enum Val {551 /// Represents a Jsonnet boolean.516 Bool(bool),552 Bool(bool),553 /// Represents a Jsonnet null value.517 Null,554 Null,555 /// Represents a Jsonnet string.518 Str(IStr),556 Str(IStr),557 /// Represents a Jsonnet number.558 /// Should be finite, and not NaN559 /// This restriction isn't enforced by enum, as enum field can't be marked as private519 Num(f64),560 Num(f64),561 /// Represents a Jsonnet array.520 Arr(ArrValue),562 Arr(ArrValue),563 /// Represents a Jsonnet object.521 Obj(ObjValue),564 Obj(ObjValue),565 /// Represents a Jsonnet function.522 Func(FuncVal),566 Func(FuncVal),523}567}524568crates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth52 builder.with_super(eval);52 builder.with_super(eval);535354 for (name, builtin) in [54 for (name, builtin) in [55 ("length".into(), builtin_length::INST),55 ("length", builtin_length::INST),56 // Types56 // Types57 ("type".into(), builtin_type::INST),57 ("type", builtin_type::INST),58 ("isString".into(), builtin_is_string::INST),58 ("isString", builtin_is_string::INST),59 ("isNumber".into(), builtin_is_number::INST),59 ("isNumber", builtin_is_number::INST),60 ("isBoolean".into(), builtin_is_boolean::INST),60 ("isBoolean", builtin_is_boolean::INST),61 ("isObject".into(), builtin_is_object::INST),61 ("isObject", builtin_is_object::INST),62 ("isArray".into(), builtin_is_array::INST),62 ("isArray", builtin_is_array::INST),63 ("isFunction".into(), builtin_is_function::INST),63 ("isFunction", builtin_is_function::INST),64 // Arrays64 // Arrays65 ("makeArray".into(), builtin_make_array::INST),65 ("makeArray", builtin_make_array::INST),66 ("slice".into(), builtin_slice::INST),66 ("slice", builtin_slice::INST),67 ("map".into(), builtin_map::INST),67 ("map", builtin_map::INST),68 ("flatMap".into(), builtin_flatmap::INST),68 ("flatMap", builtin_flatmap::INST),69 ("filter".into(), builtin_filter::INST),69 ("filter", builtin_filter::INST),70 ("foldl".into(), builtin_foldl::INST),70 ("foldl", builtin_foldl::INST),71 ("foldr".into(), builtin_foldr::INST),71 ("foldr", builtin_foldr::INST),72 ("range".into(), builtin_range::INST),72 ("range", builtin_range::INST),73 ("join".into(), builtin_join::INST),73 ("join", builtin_join::INST),74 ("reverse".into(), builtin_reverse::INST),74 ("reverse", builtin_reverse::INST),75 ("any".into(), builtin_any::INST),75 ("any", builtin_any::INST),76 ("all".into(), builtin_all::INST),76 ("all", builtin_all::INST),77 ("member".into(), builtin_member::INST),77 ("member", builtin_member::INST),78 ("count".into(), builtin_count::INST),78 ("count", builtin_count::INST),79 // Math79 // Math80 ("modulo".into(), builtin_modulo::INST),80 ("modulo", builtin_modulo::INST),81 ("floor".into(), builtin_floor::INST),81 ("floor", builtin_floor::INST),82 ("ceil".into(), builtin_ceil::INST),82 ("ceil", builtin_ceil::INST),83 ("log".into(), builtin_log::INST),83 ("log", builtin_log::INST),84 ("pow".into(), builtin_pow::INST),84 ("pow", builtin_pow::INST),85 ("sqrt".into(), builtin_sqrt::INST),85 ("sqrt", builtin_sqrt::INST),86 ("sin".into(), builtin_sin::INST),86 ("sin", builtin_sin::INST),87 ("cos".into(), builtin_cos::INST),87 ("cos", builtin_cos::INST),88 ("tan".into(), builtin_tan::INST),88 ("tan", builtin_tan::INST),89 ("asin".into(), builtin_asin::INST),89 ("asin", builtin_asin::INST),90 ("acos".into(), builtin_acos::INST),90 ("acos", builtin_acos::INST),91 ("atan".into(), builtin_atan::INST),91 ("atan", builtin_atan::INST),92 ("exp".into(), builtin_exp::INST),92 ("exp", builtin_exp::INST),93 ("mantissa".into(), builtin_mantissa::INST),93 ("mantissa", builtin_mantissa::INST),94 ("exponent".into(), builtin_exponent::INST),94 ("exponent", builtin_exponent::INST),95 // Operator95 // Operator96 ("mod".into(), builtin_mod::INST),96 ("mod", builtin_mod::INST),97 ("primitiveEquals".into(), builtin_primitive_equals::INST),97 ("primitiveEquals", builtin_primitive_equals::INST),98 ("equals".into(), builtin_equals::INST),98 ("equals", builtin_equals::INST),99 ("format".into(), builtin_format::INST),99 ("format", builtin_format::INST),100 // Sort100 // Sort101 ("sort".into(), builtin_sort::INST),101 ("sort", builtin_sort::INST),102 // Hash102 // Hash103 ("md5".into(), builtin_md5::INST),103 ("md5", builtin_md5::INST),104 // Encoding104 // Encoding105 ("encodeUTF8".into(), builtin_encode_utf8::INST),105 ("encodeUTF8", builtin_encode_utf8::INST),106 ("decodeUTF8".into(), builtin_decode_utf8::INST),106 ("decodeUTF8", builtin_decode_utf8::INST),107 ("base64".into(), builtin_base64::INST),107 ("base64", builtin_base64::INST),108 ("base64Decode".into(), builtin_base64_decode::INST),108 ("base64Decode", builtin_base64_decode::INST),109 (109 ("base64DecodeBytes", builtin_base64_decode_bytes::INST),110 "base64DecodeBytes".into(),111 builtin_base64_decode_bytes::INST,112 ),113 // Objects110 // Objects114 ("objectFieldsEx".into(), builtin_object_fields_ex::INST),111 ("objectFieldsEx", builtin_object_fields_ex::INST),115 ("objectHasEx".into(), builtin_object_has_ex::INST),112 ("objectHasEx", builtin_object_has_ex::INST),116 // Manifest113 // Manifest117 ("escapeStringJson".into(), builtin_escape_string_json::INST),114 ("escapeStringJson", builtin_escape_string_json::INST),118 ("manifestJsonEx".into(), builtin_manifest_json_ex::INST),115 ("manifestJsonEx", builtin_manifest_json_ex::INST),119 ("manifestYamlDoc".into(), builtin_manifest_yaml_doc::INST),116 ("manifestYamlDoc", builtin_manifest_yaml_doc::INST),120 // Parsing117 // Parsing121 ("parseJson".into(), builtin_parse_json::INST),118 ("parseJson", builtin_parse_json::INST),122 ("parseYaml".into(), builtin_parse_yaml::INST),119 ("parseYaml", builtin_parse_yaml::INST),123 // Misc120 // Misc124 ("codepoint".into(), builtin_codepoint::INST),121 ("codepoint", builtin_codepoint::INST),125 ("substr".into(), builtin_substr::INST),122 ("substr", builtin_substr::INST),126 ("char".into(), builtin_char::INST),123 ("char", builtin_char::INST),127 ("strReplace".into(), builtin_str_replace::INST),124 ("strReplace", builtin_str_replace::INST),128 ("splitLimit".into(), builtin_splitlimit::INST),125 ("splitLimit", builtin_splitlimit::INST),129 ("asciiUpper".into(), builtin_ascii_upper::INST),126 ("asciiUpper", builtin_ascii_upper::INST),130 ("asciiLower".into(), builtin_ascii_lower::INST),127 ("asciiLower", builtin_ascii_lower::INST),131 ("findSubstr".into(), builtin_find_substr::INST),128 ("findSubstr", builtin_find_substr::INST),132 ("startsWith".into(), builtin_starts_with::INST),129 ("startsWith", builtin_starts_with::INST),133 ("endsWith".into(), builtin_ends_with::INST),130 ("endsWith", builtin_ends_with::INST),134 ]131 ]135 .iter()132 .iter()136 .cloned()133 .cloned()137 {134 {138 builder135 builder139 .member(name)136 .member(name.into())140 .hide()137 .hide()141 .value(s.clone(), Val::Func(FuncVal::StaticBuiltin(builtin)))138 .value(s.clone(), Val::Func(FuncVal::StaticBuiltin(builtin)))142 .expect("no conflict");139 .expect("no conflict");tests/src/lib.rsdiffbeforeafterboth11//! See tests/, suite/ and golden/ directories for tests22