difftreelog
feat derive(Typed) for struct
in: master
9 files changed
Cargo.lockdiffbeforeafterboth707071[[package]]71[[package]]72name = "clap"72name = "clap"73version = "3.0.0-beta.2"73version = "3.1.8"74source = "git+https://github.com/clap-rs/clap?rev=f0c5ea5e1503de5c8e74d8c047a799cf51498e83#f0c5ea5e1503de5c8e74d8c047a799cf51498e83"74source = "registry+https://github.com/rust-lang/crates.io-index"75checksum = "71c47df61d9e16dc010b55dba1952a57d8c215dbb533fd13cdd13369aac73b1c"75dependencies = [76dependencies = [76 "atty",77 "atty",77 "bitflags",78 "bitflags",82 "strsim",83 "strsim",83 "termcolor",84 "termcolor",84 "textwrap",85 "textwrap",85 "vec_map",86]86]878788[[package]]88[[package]]89name = "clap_derive"89name = "clap_complete"90version = "3.0.0-beta.2"90version = "3.1.1"91source = "git+https://github.com/clap-rs/clap?rev=f0c5ea5e1503de5c8e74d8c047a799cf51498e83#f0c5ea5e1503de5c8e74d8c047a799cf51498e83"91source = "registry+https://github.com/rust-lang/crates.io-index"92checksum = "df6f3613c0a3cddfd78b41b10203eb322cb29b600cbdf808a7d3db95691b8e25"92dependencies = [93dependencies = [93 "heck",94 "clap",94 "proc-macro-error",95 "proc-macro2",96 "quote",97 "syn",98]95]9996100[[package]]97[[package]]101name = "clap_generate"98name = "clap_derive"102version = "3.0.0-beta.2"99version = "3.1.7"103source = "git+https://github.com/clap-rs/clap?rev=f0c5ea5e1503de5c8e74d8c047a799cf51498e83#f0c5ea5e1503de5c8e74d8c047a799cf51498e83"100source = "registry+https://github.com/rust-lang/crates.io-index"101checksum = "a3aab4734e083b809aaf5794e14e756d1c798d2c69c7f7de7a09a2f5214993c1"104dependencies = [102dependencies = [105 "clap",103 "heck",104 "proc-macro-error",105 "proc-macro2",106 "quote",107 "syn",106]108]107109108[[package]]110[[package]]148150149[[package]]151[[package]]150name = "heck"152name = "heck"151version = "0.3.3"153version = "0.4.0"152source = "registry+https://github.com/rust-lang/crates.io-index"154source = "registry+https://github.com/rust-lang/crates.io-index"153checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"155checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"154dependencies = [155 "unicode-segmentation",156]157156158[[package]]157[[package]]159name = "hermit-abi"158name = "hermit-abi"185version = "0.4.2"184version = "0.4.2"186dependencies = [185dependencies = [187 "clap",186 "clap",188 "clap_generate",187 "clap_complete",189 "gcmodule",188 "gcmodule",190 "jrsonnet-cli",189 "jrsonnet-cli",191 "jrsonnet-evaluator",190 "jrsonnet-evaluator",214 "bincode",213 "bincode",215 "gcmodule",214 "gcmodule",216 "jrsonnet-interner",215 "jrsonnet-interner",216 "jrsonnet-macros",217 "jrsonnet-parser",217 "jrsonnet-parser",218 "jrsonnet-stdlib",218 "jrsonnet-stdlib",219 "jrsonnet-types",219 "jrsonnet-types",235 "serde",235 "serde",236]236]237238[[package]]239name = "jrsonnet-macros"240version = "0.4.2"241dependencies = [242 "proc-macro2",243 "quote",244 "syn",245]237246238[[package]]247[[package]]239name = "jrsonnet-parser"248name = "jrsonnet-parser"300source = "registry+https://github.com/rust-lang/crates.io-index"309source = "registry+https://github.com/rust-lang/crates.io-index"301checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"310checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"311312[[package]]313name = "memchr"314version = "2.4.1"315source = "registry+https://github.com/rust-lang/crates.io-index"316checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"302317303[[package]]318[[package]]304name = "mimalloc-sys"319name = "mimalloc-sys"321336322[[package]]337[[package]]323name = "os_str_bytes"338name = "os_str_bytes"324version = "3.1.0"339version = "6.0.0"325source = "registry+https://github.com/rust-lang/crates.io-index"340source = "registry+https://github.com/rust-lang/crates.io-index"326checksum = "6acbef58a60fe69ab50510a55bc8cdd4d6cf2283d27ad338f54cb52747a9cf2d"341checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"342dependencies = [343 "memchr",344]327345328[[package]]346[[package]]329name = "parking_lot"347name = "parking_lot"357375358[[package]]376[[package]]359name = "peg"377name = "peg"360version = "0.7.0"378version = "0.8.0"361source = "registry+https://github.com/rust-lang/crates.io-index"379source = "registry+https://github.com/rust-lang/crates.io-index"362checksum = "07c0b841ea54f523f7aa556956fbd293bcbe06f2e67d2eb732b7278aaf1d166a"380checksum = "af728fe826811af3b38c37e93de6d104485953ea373d656eebae53d6987fcd2c"363dependencies = [381dependencies = [364 "peg-macros",382 "peg-macros",365 "peg-runtime",383 "peg-runtime",366]384]367385368[[package]]386[[package]]369name = "peg-macros"387name = "peg-macros"370version = "0.7.0"388version = "0.8.0"371source = "registry+https://github.com/rust-lang/crates.io-index"389source = "registry+https://github.com/rust-lang/crates.io-index"372checksum = "b5aa52829b8decbef693af90202711348ab001456803ba2a98eb4ec8fb70844c"390checksum = "4536be147b770b824895cbad934fccce8e49f14b4c4946eaa46a6e4a12fcdc16"373dependencies = [391dependencies = [374 "peg-runtime",392 "peg-runtime",375 "proc-macro2",393 "proc-macro2",378396379[[package]]397[[package]]380name = "peg-runtime"398name = "peg-runtime"381version = "0.7.0"399version = "0.8.0"382source = "registry+https://github.com/rust-lang/crates.io-index"400source = "registry+https://github.com/rust-lang/crates.io-index"383checksum = "c719dcf55f09a3a7e764c6649ab594c18a177e3599c467983cdf644bfc0a4088"401checksum = "f9b0efd3ba03c3a409d44d60425f279ec442bcf0b9e63ff4e410da31c8b0f69f"384402385[[package]]403[[package]]386name = "proc-macro-error"404name = "proc-macro-error"536554537[[package]]555[[package]]538name = "textwrap"556name = "textwrap"539version = "0.14.2"557version = "0.15.0"540source = "registry+https://github.com/rust-lang/crates.io-index"558source = "registry+https://github.com/rust-lang/crates.io-index"541checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"559checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"542dependencies = [543 "unicode-width",544]545560546[[package]]561[[package]]547name = "thiserror"562name = "thiserror"563 "syn",578 "syn",564]579]565566[[package]]567name = "unicode-segmentation"568version = "1.8.0"569source = "registry+https://github.com/rust-lang/crates.io-index"570checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"571580572[[package]]581[[package]]573name = "unicode-width"582name = "unicode-width"581source = "registry+https://github.com/rust-lang/crates.io-index"590source = "registry+https://github.com/rust-lang/crates.io-index"582checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"591checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"583584[[package]]585name = "vec_map"586version = "0.8.2"587source = "registry+https://github.com/rust-lang/crates.io-index"588checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"589592590[[package]]593[[package]]591name = "version_check"594name = "version_check"crates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth179 }179 }180}180}181181182pub type Result<V> = std::result::Result<V, LocError>;182pub type Result<V, E = LocError> = std::result::Result<V, E>;183183184#[macro_export]184#[macro_export]185macro_rules! throw {185macro_rules! throw {crates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth8};8};9use gcmodule::Trace;9use gcmodule::Trace;10use jrsonnet_interner::IStr;10use jrsonnet_interner::IStr;11pub use jrsonnet_macros::builtin;11use jrsonnet_parser::{ArgsDesc, ExprLocation, LocExpr, ParamsDesc};12use jrsonnet_parser::{ArgsDesc, ExprLocation, LocExpr, ParamsDesc};12use std::{borrow::Cow, collections::HashMap, convert::TryFrom};13use std::{borrow::Cow, collections::HashMap, convert::TryFrom};1314377 pub has_default: bool,378 pub has_default: bool,378}379}379380381/// Do not implement it directly, instead use #[builtin] macro380pub trait Builtin: Trace {382pub trait Builtin: Trace {381 fn name(&self) -> &str;383 fn name(&self) -> &str;382 fn params(&self) -> &[BuiltinParam];384 fn params(&self) -> &[BuiltinParam];crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth174 pub(crate) static EVAL_STATE: RefCell<Option<EvaluationState>> = RefCell::new(None)174 pub(crate) static EVAL_STATE: RefCell<Option<EvaluationState>> = RefCell::new(None)175}175}176pub(crate) fn with_state<T>(f: impl FnOnce(&EvaluationState) -> T) -> T {176pub(crate) fn with_state<T>(f: impl FnOnce(&EvaluationState) -> T) -> T {177 EVAL_STATE.with(|s| f(s.borrow().as_ref().unwrap()))177 EVAL_STATE.with(|s| {178 f(s.borrow().as_ref().expect(179 "missing evaluation state, some functions should be called inside of run_in_state call",180 ))181 })178}182}179pub fn push_frame<T>(183pub fn push_frame<T>(180 e: Option<&ExprLocation>,184 e: Option<&ExprLocation>,728 }732 }729733730 macro_rules! eval {734 macro_rules! eval {731 ($str: expr) => {735 ($str: expr) => {{732 EvaluationState::default()736 let evaluator = EvaluationState::default();733 .with_stdlib()737 evaluator.with_stdlib();734 .evaluate_snippet_raw(PathBuf::from("raw.jsonnet").into(), $str.into())738 evaluator.run_in_state(|| {739 evaluator740 .evaluate_snippet_raw(PathBuf::from("raw.jsonnet").into(), $str.into())735 .unwrap()741 .unwrap()742 })736 };743 }};737 }744 }738 macro_rules! eval_json {745 macro_rules! eval_json {739 ($str: expr) => {{746 ($str: expr) => {{1266 assert_eval!(r#"std.assertEqual(std.count(["a", "b", "a"], "a"), 2)"#);1273 assert_eval!(r#"std.assertEqual(std.count(["a", "b", "a"], "a"), 2)"#);1267 }1274 }12751276 mod derive_typed {1277 use crate::{typed::Typed, EvaluationState};1278 use std::path::PathBuf;12791280 #[derive(Typed, PartialEq, Debug)]1281 struct MyTyped {1282 a: u32,1283 b: String,1284 }12851286 #[test]1287 fn test() {1288 let es = EvaluationState::default();1289 let val = eval!("{a: 14, b: 'Hello, world!'}");1290 let typed = es.run_in_state(|| MyTyped::try_from(val).unwrap());12911292 assert_eq!(1293 typed,1294 MyTyped {1295 a: 14,1296 b: "Hello, world!".to_string()1297 }1298 );1299 es.settings_mut().globals.insert(1300 "mytyped".into(),1301 es.run_in_state(|| typed.try_into()).unwrap(),1302 );13031304 let v = es1305 .evaluate_snippet_raw(1306 PathBuf::from("raw.jsonnet").into(),1307 "1308 mytyped == {a: 14, b: 'Hello, world!'}1309 "1310 .into(),1311 )1312 .unwrap()1313 .as_bool()1314 .unwrap();1315 assert!(v)1316 }1317 }1268}1318}12691319crates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth1use std::convert::{TryFrom, TryInto};1use std::convert::{TryFrom, TryInto};223use jrsonnet_interner::IStr;3use jrsonnet_interner::IStr;4pub use jrsonnet_macros::Typed;4use jrsonnet_types::{ComplexValType, ValType};5use jrsonnet_types::{ComplexValType, ValType};566use crate::{7use crate::{crates/jrsonnet-evaluator/src/typed/mod.rsdiffbeforeafterboth8 push_description_frame, Val,8 push_description_frame, Val,9};9};10use gcmodule::Trace;10use gcmodule::Trace;11use jrsonnet_types::{ComplexValType, ValType};11pub use jrsonnet_types::{ComplexValType, ValType};12use thiserror::Error;12use thiserror::Error;1314#[macro_export]15macro_rules! unwrap_type {16 ($desc:expr, $value:expr, $typ:expr => $match:path) => {{17 use $crate::{push_frame, typed::CheckType};18 push_frame(None, $desc, || Ok($typ.check(&$value)?))?;19 match $value {20 $match(v) => v,21 _ => unreachable!(),22 }23 }};24}251326#[derive(Debug, Error, Clone, Trace)]14#[derive(Debug, Error, Clone, Trace)]27pub enum TypeError {15pub enum TypeError {136impl Display for ValuePathItem {124impl Display for ValuePathItem {137 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {125 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {138 match self {126 match self {139 Self::Field(name) => write!(f, ".{}", name)?,127 Self::Field(name) => write!(f, ".{:?}", name)?,140 Self::Index(idx) => write!(f, "[{}]", idx)?,128 Self::Index(idx) => write!(f, "[{}]", idx)?,141 }129 }142 Ok(())130 Ok(())crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth91 Normal(Cc<FuncDesc>),91 Normal(Cc<FuncDesc>),92 /// Standard library function92 /// Standard library function93 StaticBuiltin(#[skip_trace] &'static dyn StaticBuiltin),93 StaticBuiltin(#[skip_trace] &'static dyn StaticBuiltin),9494 /// User-provided function95 Builtin(Cc<TraceBox<dyn Builtin>>),95 Builtin(Cc<TraceBox<dyn Builtin>>),96}96}979798impl Debug for FuncVal {98impl Debug for FuncVal {99 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {99 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {100 match self {100 match self {101 Self::Normal(arg0) => f.debug_tuple("Normal").field(arg0).finish(),101 Self::Normal(arg0) => f.debug_tuple("Normal").field(arg0).finish(),102 Self::StaticBuiltin(arg0) => f.debug_tuple("Intrinsic").field(&arg0.name()).finish(),102 Self::StaticBuiltin(arg0) => {103 f.debug_tuple("StaticBuiltin").field(&arg0.name()).finish()104 }103 Self::Builtin(arg0) => f.debug_tuple("Intrinsic").field(&arg0.name()).finish(),105 Self::Builtin(arg0) => f.debug_tuple("Builtin").field(&arg0.name()).finish(),104 }106 }105 }107 }106}108}338}340}339341340impl Val {342impl Val {343 pub fn as_bool(&self) -> Option<bool> {344 match self {345 Val::Bool(v) => Some(*v),346 _ => None,347 }348 }349 pub fn as_null(&self) -> Option<()> {350 match self {351 Val::Null => Some(()),352 _ => None,353 }354 }355 pub fn as_str(&self) -> Option<IStr> {356 match self {357 Val::Str(s) => Some(s.clone()),358 _ => None,359 }360 }361 pub fn as_num(&self) -> Option<f64> {362 match self {363 Val::Num(n) => Some(*n),364 _ => None,365 }366 }367 pub fn as_arr(&self) -> Option<ArrValue> {368 match self {369 Val::Arr(a) => Some(a.clone()),370 _ => None,371 }372 }373 pub fn as_obj(&self) -> Option<ObjValue> {374 match self {375 Val::Obj(o) => Some(o.clone()),376 _ => None,377 }378 }379 pub fn as_func(&self) -> Option<FuncVal> {380 match self {381 Val::Func(f) => Some(f.clone()),382 _ => None,383 }384 }385341 /// Creates `Val::Num` after checking for numeric overflow.386 /// Creates `Val::Num` after checking for numeric overflow.342 /// As numbers are `f64`, we can just check for their finity.387 /// As numbers are `f64`, we can just check for their finity.crates/jrsonnet-macros/src/lib.rsdiffbeforeafterboth1use quote::{quote, quote_spanned};1use quote::{quote, quote_spanned};2use syn::{2use syn::{3 parenthesized, parse::Parse, parse_macro_input, punctuated::Punctuated, spanned::Spanned,3 parenthesized, parse::Parse, parse_macro_input, punctuated::Punctuated, spanned::Spanned,4 token::Comma, FnArg, GenericArgument, Ident, ItemFn, Pat, PatType, Path, PathArguments, Token,4 token::Comma, DeriveInput, FnArg, GenericArgument, Ident, ItemFn, Pat, PatType, Path,5 Type,5 PathArguments, Token, Type,6};6};77255 .into()255 .into()256}256}257258#[proc_macro_derive(Typed)]259pub fn derive_typed(item: proc_macro::TokenStream) -> proc_macro::TokenStream {260 let input = parse_macro_input!(item as DeriveInput);261 let data = match &input.data {262 syn::Data::Struct(s) => s,263 _ => {264 return syn::Error::new(input.span(), "only structs supported")265 .to_compile_error()266 .into()267 }268 };269270 let ident = &input.ident;271272 let fields_def = data.fields.iter().map(|f| {273 let name = f274 .ident275 .as_ref()276 .expect("only named fields supported")277 .to_string();278 let ty = &f.ty;279 quote! {280 (#name, #ty::TYPE),281 }282 });283 let fields_parse = data.fields.iter().map(|f| {284 let ident = f.ident.as_ref().unwrap();285 let name = ident.to_string();286 let ty = &f.ty;287 quote! {288 #ident: #ty::try_from(obj.get(#name.into())?.expect("shape is correct"))?,289 }290 });291 let fields_serialize = data.fields.iter().map(|f| {292 let ident = f.ident.as_ref().unwrap();293 let name = ident.to_string();294 quote! {295 out.member(#name.into()).value(self.#ident.try_into()?);296 }297 });298 let field_count = data.fields.len();299300 quote! {301 const _: () = {302 use ::jrsonnet_evaluator::{303 typed::{ComplexValType, Typed, CheckType},304 Val,305 error::LocError,306 obj::ObjValueBuilder,307 };308309 const ITEMS: [(&'static str, &'static ComplexValType); #field_count] = [310 #(#fields_def)*311 ];312 impl Typed for #ident {313 const TYPE: &'static ComplexValType = &ComplexValType::ObjectRef(&ITEMS);314 }315316 impl TryFrom<Val> for #ident {317 type Error = LocError;318 fn try_from(value: Val) -> Result<Self, Self::Error> {319 <Self as Typed>::TYPE.check(&value)?;320 let obj = value.as_obj().expect("shape is correct");321322 Ok(Self {323 #(#fields_parse)*324 })325 }326 }327 impl TryInto<Val> for #ident {328 type Error = LocError;329 fn try_into(self) -> Result<Val, Self::Error> {330 let mut out = ObjValueBuilder::new();331 #(#fields_serialize)*332 Ok(Val::Obj(out.build()))333 }334 }335 ()336 };337 }338 .into()339}257340crates/jrsonnet-types/src/lib.rsdiffbeforeafterboth122 BoundedNumber(Option<f64>, Option<f64>),122 BoundedNumber(Option<f64>, Option<f64>),123 Array(Box<ComplexValType>),123 Array(Box<ComplexValType>),124 ArrayRef(&'static ComplexValType),124 ArrayRef(&'static ComplexValType),125 ObjectRef(&'static [(&'static str, ComplexValType)]),125 ObjectRef(&'static [(&'static str, &'static ComplexValType)]),126 Union(Vec<ComplexValType>),126 Union(Vec<ComplexValType>),127 UnionRef(&'static [&'static ComplexValType]),127 UnionRef(&'static [&'static ComplexValType]),128 Sum(Vec<ComplexValType>),128 Sum(Vec<ComplexValType>),