difftreelog
Merge remote-tracking branch 'origin/master' into gcmodule
in: master
7 files changed
crates/jrsonnet-evaluator/src/builtin/manifest.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/builtin/manifest.rs
+++ b/crates/jrsonnet-evaluator/src/builtin/manifest.rs
@@ -19,6 +19,8 @@
pub struct ManifestJsonOptions<'s> {
pub padding: &'s str,
pub mtype: ManifestType,
+ pub newline: &'s str,
+ pub key_val_sep: &'s str,
}
pub fn manifest_json_ex(val: &Val, options: &ManifestJsonOptions<'_>) -> Result<String> {
@@ -49,7 +51,7 @@
buf.push('[');
if !items.is_empty() {
if mtype != ManifestType::ToString && mtype != ManifestType::Minify {
- buf.push('\n');
+ buf.push_str(options.newline);
}
let old_len = cur_padding.len();
@@ -60,7 +62,7 @@
if mtype == ManifestType::ToString {
buf.push(' ');
} else if mtype != ManifestType::Minify {
- buf.push('\n');
+ buf.push_str(options.newline);
}
}
buf.push_str(cur_padding);
@@ -69,7 +71,7 @@
cur_padding.truncate(old_len);
if mtype != ManifestType::ToString && mtype != ManifestType::Minify {
- buf.push('\n');
+ buf.push_str(options.newline);
buf.push_str(cur_padding);
}
} else if mtype == ManifestType::Std {
@@ -86,7 +88,7 @@
let fields = obj.fields();
if !fields.is_empty() {
if mtype != ManifestType::ToString && mtype != ManifestType::Minify {
- buf.push('\n');
+ buf.push_str(options.newline);
}
let old_len = cur_padding.len();
@@ -97,12 +99,12 @@
if mtype == ManifestType::ToString {
buf.push(' ');
} else if mtype != ManifestType::Minify {
- buf.push('\n');
+ buf.push_str(options.newline);
}
}
buf.push_str(cur_padding);
escape_string_json_buf(&field, buf);
- buf.push_str(": ");
+ buf.push_str(options.key_val_sep);
push_description_frame(
|| format!("field <{}> manifestification", field.clone()),
|| {
@@ -115,7 +117,7 @@
cur_padding.truncate(old_len);
if mtype != ManifestType::ToString && mtype != ManifestType::Minify {
- buf.push('\n');
+ buf.push_str(options.newline);
buf.push_str(cur_padding);
}
} else if mtype == ManifestType::Std {
crates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/builtin/mod.rs
+++ b/crates/jrsonnet-evaluator/src/builtin/mod.rs
@@ -1,6 +1,5 @@
use crate::function::StaticBuiltin;
-use crate::typed::{Any, Null, PositiveF64, VecVal, M1};
-use crate::{self as jrsonnet_evaluator, Either, ObjValue};
+use crate::typed::{Any, PositiveF64, VecVal, M1};
use crate::{
builtin::manifest::{manifest_yaml_ex, ManifestYamlOptions},
equals,
@@ -10,6 +9,7 @@
typed::{Either2, Either4},
with_state, ArrValue, Context, FuncVal, IndexableVal, Val,
};
+use crate::{Either, ObjValue};
use format::{format_arr, format_obj};
use gcmodule::Cc;
use jrsonnet_interner::IStr;
@@ -145,7 +145,7 @@
fn builtin_length(x: Either![IStr, VecVal, ObjValue, Cc<FuncVal>]) -> Result<usize> {
use Either4::*;
Ok(match x {
- A(x) => x.len(),
+ A(x) => x.chars().count(),
B(x) => x.0.len(),
C(x) => x
.fields_visibility()
@@ -566,12 +566,21 @@
}
#[jrsonnet_macros::builtin]
-fn builtin_manifest_json_ex(value: Any, indent: IStr) -> Result<String> {
+fn builtin_manifest_json_ex(
+ value: Any,
+ indent: IStr,
+ newline: Option<IStr>,
+ key_val_sep: Option<IStr>,
+) -> Result<String> {
+ let newline = newline.as_deref().unwrap_or("\n");
+ let key_val_sep = key_val_sep.as_deref().unwrap_or(": ");
manifest_json_ex(
&value.0,
&ManifestJsonOptions {
padding: &indent,
mtype: ManifestType::Std,
+ newline,
+ key_val_sep,
},
)
}
crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -5,6 +5,9 @@
clippy::ptr_arg
)]
+// For jrsonnet-macros
+extern crate self as jrsonnet_evaluator;
+
mod builtin;
mod ctx;
mod dynamic;
@@ -976,6 +979,14 @@
}
#[test]
+ fn json_minified() {
+ assert_json!(
+ r#"std.manifestJsonMinified({a:3, b:4, c:6})"#,
+ r#""{\"a\":3,\"b\":4,\"c\":6}""#
+ );
+ }
+
+ #[test]
fn parse_json() {
assert_json!(
r#"std.parseJson('{"a": -1,"b": 1,"c": 3.141,"d": []}')"#,
crates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/typed/conversions.rs
+++ b/crates/jrsonnet-evaluator/src/typed/conversions.rs
@@ -19,7 +19,7 @@
($($ty:ty)*) => {$(
impl Typed for $ty {
const TYPE: &'static ComplexValType =
- &ComplexValType::BoundedNumber(Some(<$ty>::MIN as f64), Some(<$ty>::MAX as f64));
+ &ComplexValType::BoundedNumber(Some(Self::MIN as f64), Some(Self::MAX as f64));
}
impl TryFrom<Val> for $ty {
type Error = LocError;
crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -400,6 +400,8 @@
&ManifestJsonOptions {
padding: "",
mtype: ManifestType::ToString,
+ newline: "\n",
+ key_val_sep: ": ",
},
)?
.into(),
@@ -484,6 +486,8 @@
} else {
ManifestType::Manifest
},
+ newline: "\n",
+ key_val_sep: ": ",
},
)
.map(|s| s.into())
@@ -496,6 +500,8 @@
&ManifestJsonOptions {
padding: &" ".repeat(padding),
mtype: ManifestType::Std,
+ newline: "\n",
+ key_val_sep: ": ",
},
)
.map(|s| s.into())
crates/jrsonnet-macros/src/lib.rsdiffbeforeafterboth1use quote::quote;2use syn::{3 parse_macro_input, FnArg, GenericArgument, ItemFn, Pat, PatType, Path, PathArguments, Type,4};56fn is_location_arg(t: &PatType) -> bool {7 t.attrs.iter().any(|a| a.path.is_ident("location"))8}910trait RetainHad<T> {11 fn retain_had(&mut self, h: impl FnMut(&T) -> bool) -> bool;12}13impl<T> RetainHad<T> for Vec<T> {14 fn retain_had(&mut self, h: impl FnMut(&T) -> bool) -> bool {15 let before = self.len();16 self.retain(h);17 let after = self.len();18 before != after19 }20}2122fn extract_type_from_option(ty: &Type) -> Option<&Type> {23 fn path_is_option(path: &Path) -> bool {24 path.leading_colon.is_none()25 && path.segments.len() == 126 && path.segments.iter().next().unwrap().ident == "Option"27 }2829 match ty {30 Type::Path(typepath) if typepath.qself.is_none() && path_is_option(&typepath.path) => {31 // Get the first segment of the path (there is only one, in fact: "Option"):32 let type_params = &typepath.path.segments.iter().next().unwrap().arguments;33 // It should have only on angle-bracketed param ("<String>"):34 let generic_arg = match type_params {35 PathArguments::AngleBracketed(params) => params.args.iter().next().unwrap(),36 _ => panic!("missing option generic"),37 };38 // This argument must be a type:39 match generic_arg {40 GenericArgument::Type(ty) => Some(ty),41 _ => panic!("option generic should be a type"),42 }43 }44 _ => None,45 }46}4748#[proc_macro_attribute]49pub fn builtin(50 _attr: proc_macro::TokenStream,51 item: proc_macro::TokenStream,52) -> proc_macro::TokenStream {53 // syn::ItemFn::parse(input)54 let mut fun: ItemFn = parse_macro_input!(item);5556 let result = match fun.sig.output {57 syn::ReturnType::Default => panic!("builtin should return something"),58 syn::ReturnType::Type(_, ref ty) => ty.clone(),59 };6061 let params = fun62 .sig63 .inputs64 .iter()65 .map(|i| match i {66 FnArg::Receiver(_) => unreachable!(),67 FnArg::Typed(t) => t,68 })69 .filter(|a| !is_location_arg(a))70 .map(|t| {71 let ident = match &t.pat as &Pat {72 Pat::Ident(i) => i.ident.to_string(),73 _ => panic!("only idents supported yet"),74 };75 let optional = extract_type_from_option(&t.ty).is_some();76 quote! {77 BuiltinParam {78 name: std::borrow::Cow::Borrowed(#ident),79 has_default: #optional,80 }81 }82 })83 .collect::<Vec<_>>();8485 let args = fun86 .sig87 .inputs88 .iter_mut()89 .map(|i| match i {90 FnArg::Receiver(_) => unreachable!(),91 FnArg::Typed(t) => t,92 })93 .map(|t| {94 let is_location = t.attrs.retain_had(|a| !a.path.is_ident("location"));95 if is_location {96 quote! {{97 loc98 }}99 } else {100 let ident = match &t.pat as &Pat {101 Pat::Ident(i) => i.ident.to_string(),102 _ => panic!("only idents supported yet"),103 };104 let ty = &t.ty;105 if let Some(opt_ty) = extract_type_from_option(&t.ty) {106 quote! {{107 if let Some(value) = parsed.get(#ident) {108 Some(jrsonnet_evaluator::push_description_frame(109 || format!("argument <{}> evaluation", #ident),110 || <#opt_ty>::try_from(value.evaluate()?),111 )?)112 } else {113 None114 }115 }}116 } else {117 quote! {{118 let value = parsed.get(#ident).unwrap();119120 jrsonnet_evaluator::push_description_frame(121 || format!("argument <{}> evaluation", #ident),122 || <#ty>::try_from(value.evaluate()?),123 )?124 }}125 }126 }127 })128 .collect::<Vec<_>>();129130 let name = &fun.sig.ident;131 let vis = &fun.vis;132 (quote! {133 #fun134 #[doc(hidden)]135 #[allow(non_camel_case_types)]136 #[derive(Clone, Copy, gcmodule::Trace)]137 #vis struct #name {}138 const _: () = {139 use jrsonnet_evaluator::function::{Builtin, StaticBuiltin, BuiltinParam, ArgsLike};140 const PARAMS: &'static [BuiltinParam] = &[141 #(#params),*142 ];143144 impl #name {145 pub const INST: &'static dyn StaticBuiltin = &#name {};146 }147 impl StaticBuiltin for #name {}148 impl Builtin for #name149 where150 Self: 'static151 {152 fn name(&self) -> &str {153 stringify!(#name)154 }155 fn params(&self) -> &[BuiltinParam] {156 PARAMS157 }158 fn call(&self, context: Context, loc: Option<&ExprLocation>, args: &dyn ArgsLike) -> Result<Val> {159 let parsed = jrsonnet_evaluator::function::parse_builtin_call(context, &PARAMS, args, false)?;160161 let result: #result = #name(#(#args),*);162 let result = result?;163 result.try_into()164 }165 }166 };167 })168 .into()169}1use quote::quote;2use syn::{3 parse_macro_input, FnArg, GenericArgument, ItemFn, Pat, PatType, Path, PathArguments, Type,4};56fn is_location_arg(t: &PatType) -> bool {7 t.attrs.iter().any(|a| a.path.is_ident("location"))8}910trait RetainHad<T> {11 fn retain_had(&mut self, h: impl FnMut(&T) -> bool) -> bool;12}13impl<T> RetainHad<T> for Vec<T> {14 fn retain_had(&mut self, h: impl FnMut(&T) -> bool) -> bool {15 let before = self.len();16 self.retain(h);17 let after = self.len();18 before != after19 }20}2122fn extract_type_from_option(ty: &Type) -> Option<&Type> {23 fn path_is_option(path: &Path) -> bool {24 path.leading_colon.is_none()25 && path.segments.len() == 126 && path.segments.iter().next().unwrap().ident == "Option"27 }2829 match ty {30 Type::Path(typepath) if typepath.qself.is_none() && path_is_option(&typepath.path) => {31 // Get the first segment of the path (there is only one, in fact: "Option"):32 let type_params = &typepath.path.segments.iter().next().unwrap().arguments;33 // It should have only on angle-bracketed param ("<String>"):34 let generic_arg = match type_params {35 PathArguments::AngleBracketed(params) => params.args.iter().next().unwrap(),36 _ => panic!("missing option generic"),37 };38 // This argument must be a type:39 match generic_arg {40 GenericArgument::Type(ty) => Some(ty),41 _ => panic!("option generic should be a type"),42 }43 }44 _ => None,45 }46}4748#[proc_macro_attribute]49pub fn builtin(50 _attr: proc_macro::TokenStream,51 item: proc_macro::TokenStream,52) -> proc_macro::TokenStream {53 // syn::ItemFn::parse(input)54 let mut fun: ItemFn = parse_macro_input!(item);5556 let result = match fun.sig.output {57 syn::ReturnType::Default => panic!("builtin should return something"),58 syn::ReturnType::Type(_, ref ty) => ty.clone(),59 };6061 let params = fun62 .sig63 .inputs64 .iter()65 .map(|i| match i {66 FnArg::Receiver(_) => unreachable!(),67 FnArg::Typed(t) => t,68 })69 .filter(|a| !is_location_arg(a))70 .map(|t| {71 let ident = match &t.pat as &Pat {72 Pat::Ident(i) => i.ident.to_string(),73 _ => panic!("only idents supported yet"),74 };75 let optional = extract_type_from_option(&t.ty).is_some();76 quote! {77 BuiltinParam {78 name: std::borrow::Cow::Borrowed(#ident),79 has_default: #optional,80 }81 }82 })83 .collect::<Vec<_>>();8485 let args = fun86 .sig87 .inputs88 .iter_mut()89 .map(|i| match i {90 FnArg::Receiver(_) => unreachable!(),91 FnArg::Typed(t) => t,92 })93 .map(|t| {94 let is_location = t.attrs.retain_had(|a| !a.path.is_ident("location"));95 if is_location {96 quote! {{97 loc98 }}99 } else {100 let ident = match &t.pat as &Pat {101 Pat::Ident(i) => i.ident.to_string(),102 _ => panic!("only idents supported yet"),103 };104 let ty = &t.ty;105 if let Some(opt_ty) = extract_type_from_option(&t.ty) {106 quote! {{107 if let Some(value) = parsed.get(#ident) {108 Some(::jrsonnet_evaluator::push_description_frame(109 || format!("argument <{}> evaluation", #ident),110 || <#opt_ty>::try_from(value.evaluate()?),111 )?)112 } else {113 None114 }115 }}116 } else {117 quote! {{118 let value = parsed.get(#ident).unwrap();119120 ::jrsonnet_evaluator::push_description_frame(121 || format!("argument <{}> evaluation", #ident),122 || <#ty>::try_from(value.evaluate()?),123 )?124 }}125 }126 }127 })128 .collect::<Vec<_>>();129130 let name = &fun.sig.ident;131 let vis = &fun.vis;132 (quote! {133 #fun134 #[doc(hidden)]135 #[allow(non_camel_case_types)]136 #[derive(Clone, Copy, gcmodule::Trace)]137 #vis struct #name {}138 const _: () = {139 use ::jrsonnet_evaluator::function::{Builtin, StaticBuiltin, BuiltinParam, ArgsLike};140 const PARAMS: &'static [BuiltinParam] = &[141 #(#params),*142 ];143144 impl #name {145 pub const INST: &'static dyn StaticBuiltin = &#name {};146 }147 impl StaticBuiltin for #name {}148 impl Builtin for #name149 where150 Self: 'static151 {152 fn name(&self) -> &str {153 stringify!(#name)154 }155 fn params(&self) -> &[BuiltinParam] {156 PARAMS157 }158 fn call(&self, context: Context, loc: Option<&ExprLocation>, args: &dyn ArgsLike) -> Result<Val> {159 let parsed = ::jrsonnet_evaluator::function::parse_builtin_call(context, &PARAMS, args, false)?;160161 let result: #result = #name(#(#args),*);162 let result = result?;163 result.try_into()164 }165 }166 };167 })168 .into()169}crates/jrsonnet-stdlib/src/std.jsonnetdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/std.jsonnet
+++ b/crates/jrsonnet-stdlib/src/std.jsonnet
@@ -373,6 +373,8 @@
manifestJson(value):: std.manifestJsonEx(value, ' ') tailstrict,
+ manifestJsonMinified(value):: std.manifestJsonEx(value, '', '', ':'),
+
manifestJsonEx:: $intrinsic(manifestJsonEx),
manifestYamlDoc:: $intrinsic(manifestYamlDoc),
@@ -530,6 +532,9 @@
else
patch,
+ get(o, f, default = null, inc_hidden = true)::
+ if std.objectHasEx(o, f, inc_hidden) then o[f] else default,
+
objectFields(o)::
std.objectFieldsEx(o, false),