difftreelog
test basic interop checks
in: master
7 files changed
crates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth1use std::{1use std::{2 fmt::Debug,2 path::{Path, PathBuf},3 path::{Path, PathBuf},3 rc::Rc,4 rc::Rc,4};5};166#[derive(Debug, Clone, Trace)]167#[derive(Debug, Clone, Trace)]167pub struct StackTrace(pub Vec<StackTraceElement>);168pub struct StackTrace(pub Vec<StackTraceElement>);168169169#[derive(Debug, Clone, Trace)]170#[derive(Clone, Trace)]170pub struct LocError(Box<(Error, StackTrace)>);171pub struct LocError(Box<(Error, StackTrace)>);171impl LocError {172impl LocError {172 pub fn new(e: Error) -> Self {173 pub fn new(e: Error) -> Self {186 &mut (self.0).1187 &mut (self.0).1187 }188 }188}189}190impl Debug for LocError {191 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {192 writeln!(f, "{}", self.0 .0)?;193 for el in self.0 .1 .0.iter() {194 writeln!(f, "\t{:?}", el)?;195 }196 Ok(())197 }198}189199190pub type Result<V, E = LocError> = std::result::Result<V, E>;200pub type Result<V, E = LocError> = std::result::Result<V, E>;191201crates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth169 }168 }170}169}170171impl ArgsLike for [(); 0] {172 fn unnamed_len(&self) -> usize {173 0174 }175176 fn unnamed_iter(177 &self,178 _s: State,179 _ctx: Context,180 _tailstrict: bool,181 _handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,182 ) -> Result<()> {183 Ok(())184 }185186 fn named_iter(187 &self,188 _s: State,189 _ctx: Context,190 _tailstrict: bool,191 _handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,192 ) -> Result<()> {193 Ok(())194 }195196 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}197}171198172impl<A: ArgLike> ArgsLike for [(IStr, A)] {199impl<A: ArgLike> ArgsLike for [(IStr, A)] {173 fn unnamed_len(&self) -> usize {200 fn unnamed_len(&self) -> usize {crates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth14};14};151516pub trait TypedObj: Typed {16pub trait TypedObj: Typed {17 fn serialize(self, out: &mut ObjValueBuilder) -> Result<()>;17 fn serialize(self, s: State, out: &mut ObjValueBuilder) -> Result<()>;18 fn parse(obj: &ObjValue) -> Result<Self>;18 fn parse(obj: &ObjValue, s: State) -> Result<Self>;19 fn into_object(self) -> Result<ObjValue> {19 fn into_object(self, s: State) -> Result<ObjValue> {20 let mut builder = ObjValueBuilder::new();20 let mut builder = ObjValueBuilder::new();21 self.serialize(&mut builder)?;21 self.serialize(s, &mut builder)?;22 Ok(builder.build())22 Ok(builder.build())23 }23 }24}24}crates/jrsonnet-evaluator/tests/builtin.rsdiffbeforeafterbothno changes
crates/jrsonnet-evaluator/tests/common.rsdiffbeforeafterbothno changes
crates/jrsonnet-evaluator/tests/typed_obj.rsdiffbeforeafterbothno changes
crates/jrsonnet-macros/src/lib.rsdiffbeforeafterboth6 parse_macro_input,6 parse_macro_input,7 punctuated::Punctuated,7 punctuated::Punctuated,8 spanned::Spanned,8 spanned::Spanned,9 token::Comma,9 token::{self, Comma},10 Attribute, DeriveInput, Error, FnArg, GenericArgument, Ident, ItemFn, LitStr, Pat, Path,10 Attribute, DeriveInput, Error, FnArg, GenericArgument, Ident, ItemFn, LitStr, Pat, Path,11 PathArguments, Result, ReturnType, Token, Type,11 PathArguments, Result, ReturnType, Token, Type,12};12};90 syn::custom_keyword!(fields);90 syn::custom_keyword!(fields);91 syn::custom_keyword!(rename);91 syn::custom_keyword!(rename);92 syn::custom_keyword!(flatten);92 syn::custom_keyword!(flatten);93 syn::custom_keyword!(ok);93}94}949595struct EmptyAttr;96struct EmptyAttr;135}136}136137137impl ArgInfo {138impl ArgInfo {138 fn parse(arg: &FnArg) -> Result<Self> {139 fn parse(name: &str, arg: &FnArg) -> Result<Self> {139 let arg = match arg {140 let arg = match arg {140 FnArg::Receiver(_) => unreachable!(),141 FnArg::Receiver(_) => unreachable!(),141 FnArg::Typed(a) => a,142 FnArg::Typed(a) => a,149 return Ok(Self::State);150 return Ok(Self::State);150 } else if type_is_path(ty, "CallLocation").is_some() {151 } else if type_is_path(ty, "CallLocation").is_some() {151 return Ok(Self::Location);152 return Ok(Self::Location);152 } else if type_is_path(ty, "Self").is_some() {153 } else if type_is_path(ty, "LazyVal").is_some() {153 return Ok(Self::This);154 } else if type_is_path(ty, "LazyVal").is_some() {155 return Ok(Self::Lazy {154 return Ok(Self::Lazy {156 is_option: false,155 is_option: false,157 name: ident.to_string(),156 name: ident.to_string(),158 });157 });159 }158 }159160 match &ty as &Type {161 Type::Reference(r) if type_is_path(&r.elem, &name).is_some() => return Ok(Self::This),162 _ => {}163 }160164161 let (is_option, ty) = if let Some(ty) = extract_type_from_option(ty)? {165 let (is_option, ty) = if let Some(ty) = extract_type_from_option(ty)? {162 if type_is_path(ty, "LazyVal").is_some() {166 if type_is_path(ty, "LazyVal").is_some() {230 return Err(Error::new(result.span(), "return value should be result"));234 return Err(Error::new(result.span(), "return value should be result"));231 };235 };232236237 let name = fun.sig.ident.to_string();233 let args = fun238 let args = fun234 .sig239 .sig235 .inputs240 .inputs236 .iter()241 .iter()237 .map(ArgInfo::parse)242 .map(|arg| ArgInfo::parse(&name, arg))238 .collect::<Result<Vec<_>>>()?;243 .collect::<Result<Vec<_>>>()?;239244240 let params_desc = args.iter().flat_map(|a| match a {245 let params_desc = args.iter().flat_map(|a| match a {343 }348 }344 const _: () = {349 const _: () = {345 use ::jrsonnet_evaluator::{350 use ::jrsonnet_evaluator::{346 State,351 State, Val,347 function::{Builtin, CallLocation, StaticBuiltin, BuiltinParam, ArgsLike, parse_builtin_call},352 function::{Builtin, CallLocation, StaticBuiltin, BuiltinParam, ArgsLike, parse_builtin_call},348 error::Result, Context,353 error::Result, Context, typed::Typed,349 parser::ExprLocation,354 parser::ExprLocation,350 };355 };351 const PARAMS: &'static [BuiltinParam] = &[356 const PARAMS: &'static [BuiltinParam] = &[379struct TypedAttr {384struct TypedAttr {380 rename: Option<String>,385 rename: Option<String>,381 flatten: bool,386 flatten: bool,387 /// flatten(ok) strategy for flattened optionals388 /// field would be None in case of any parsing error (as in serde)389 flatten_ok: bool,382}390}383impl Parse for TypedAttr {391impl Parse for TypedAttr {384 fn parse(input: ParseStream) -> syn::Result<Self> {392 fn parse(input: ParseStream) -> syn::Result<Self> {399 } else if lookahead.peek(kw::flatten) {407 } else if lookahead.peek(kw::flatten) {400 input.parse::<kw::flatten>()?;408 input.parse::<kw::flatten>()?;401 out.flatten = true;409 out.flatten = true;410 if input.peek(token::Paren) {411 let content;412 parenthesized!(content in input);413 let lookahead = content.lookahead1();414 if lookahead.peek(kw::ok) {415 content.parse::<kw::ok>()?;416 out.flatten_ok = true;417 } else {418 return Err(lookahead.error());419 }420 }402 } else if input.is_empty() {421 } else if input.is_empty() {403 break;422 break;404 } else {423 } else {417 }436 }418}437}419438420struct TypedField<'f>(&'f syn::Field, TypedAttr);439struct TypedField {440 attr: TypedAttr,441 ident: Ident,442 ty: Type,443 is_option: bool,444}421impl<'f> TypedField<'f> {445impl TypedField {422 fn try_new(field: &'f syn::Field) -> Result<Self> {446 fn parse(field: &syn::Field) -> Result<Self> {423 let attr = parse_attr::<TypedAttr, _>(&field.attrs, "typed")?.unwrap_or_default();447 let attr = parse_attr::<TypedAttr, _>(&field.attrs, "typed")?.unwrap_or_default();424 if field.ident.is_none() {448 let ident = if let Some(ident) = field.ident.clone() {449 ident450 } else {425 return Err(Error::new(451 return Err(Error::new(426 field.span(),452 field.span(),427 "this field should appear in output object, but it has no visible name",453 "this field should appear in output object, but it has no visible name",428 ));454 ));429 }455 };456 let (is_option, ty) = if let Some(ty) = extract_type_from_option(&field.ty)? {457 (true, ty.clone())458 } else {459 (false, field.ty.clone())460 };461 if is_option && attr.flatten {462 if !attr.flatten_ok {463 return Err(Error::new(464 field.span(),465 "strategy should be set when flattening Option",466 ));467 }468 } else {469 if attr.flatten_ok {470 return Err(Error::new(471 field.span(),472 "flatten(ok) is only useable on optional fields",473 ));474 }475 }430 Ok(Self(field, attr))476 Ok(Self {477 attr,478 ident,479 ty,480 is_option,481 })431 }482 }432 fn ident(&self) -> Ident {433 self.0434 .ident435 .clone()436 .expect("constructor disallows fields without name")437 }438 /// None if this field is flattened in jsonnet output483 /// None if this field is flattened in jsonnet output439 fn name(&self) -> Option<String> {484 fn name(&self) -> Option<String> {440 if self.1.flatten {485 if self.attr.flatten {441 return None;486 return None;442 }487 }443 Some(488 Some(444 self.1489 self.attr445 .rename490 .rename446 .clone()491 .clone()447 .unwrap_or_else(|| self.ident().to_string()),492 .unwrap_or_else(|| self.ident.to_string()),448 )493 )449 }494 }450495451 fn expand_field(&self) -> Option<TokenStream> {496 fn expand_field(&self) -> Option<TokenStream> {452 if self.is_option() {497 if self.is_option {453 return None;498 return None;454 }499 }455 let name = self.name()?;500 let name = self.name()?;456 let ty = &self.0.ty;501 let ty = &self.ty;457 Some(quote! {502 Some(quote! {458 (#name, <#ty>::TYPE)503 (#name, <#ty>::TYPE)459 })504 })460 }505 }461 fn expand_parse(&self) -> TokenStream {506 fn expand_parse(&self) -> TokenStream {462 let ident = self.ident();507 let ident = &self.ident;463 let ty = &self.0.ty;508 let ty = &self.ty;464 if self.1.flatten {509 if self.attr.flatten {465 // optional flatten is handled in same way as serde510 // optional flatten is handled in same way as serde466 return if self.is_option() {511 return if self.is_option {467 quote! {512 quote! {468 #ident: <#ty>::parse(&obj).ok(),513 #ident: <#ty>::parse(&obj, s.clone()).ok(),469 }514 }470 } else {515 } else {471 quote! {516 quote! {472 #ident: <#ty>::parse(&obj)?,517 #ident: <#ty>::parse(&obj, s.clone())?,473 }518 }474 };519 };475 };520 };476521477 let name = self.name().unwrap();522 let name = self.name().unwrap();478 let value = if let Some(ty) = self.as_option() {523 let value = if self.is_option {479 quote! {524 quote! {480 if let Some(value) = obj.get(#name.into())? {525 if let Some(value) = obj.get(s.clone(), #name.into())? {481 Some(<#ty>::try_from(vakue)?)526 Some(<#ty>::from_untyped(value, s.clone())?)482 } else {527 } else {483 None528 None484 }529 }485 }530 }486 } else {531 } else {487 quote! {532 quote! {488 <#ty>::try_from(obj.get(#name.into())?.ok_or_else(|| Error::NoSuchField(#name.into()))?)?533 <#ty>::from_untyped(obj.get(s.clone(), #name.into())?.ok_or_else(|| Error::NoSuchField(#name.into()))?, s.clone())?489 }534 }490 };535 };491536492 quote! {537 quote! {493 #ident: #value,538 #ident: #value,494 }539 }495 }540 }496 fn expand_serialize(&self) -> TokenStream {541 fn expand_serialize(&self) -> Result<TokenStream> {497 let ident = self.ident();542 let ident = &self.ident;543 let ty = &self.ty;498 if let Some(name) = self.name() {544 Ok(if let Some(name) = self.name() {499 if self.is_option() {545 if self.is_option {500 quote! {546 quote! {501 if let Some(value) = self.#ident {547 if let Some(value) = self.#ident {502 out.member(#name.into()).value(value.try_into()?)?;548 out.member(#name.into()).value(s.clone(), <#ty>::into_untyped(value, s.clone())?)?;503 }549 }504 }550 }505 } else {551 } else {506 quote! {552 quote! {507 out.member(#name.into()).value(self.#ident.try_into()?)?;553 out.member(#name.into()).value(s.clone(), <#ty>::into_untyped(self.#ident, s.clone())?)?;508 }554 }509 }555 }510 } else if self.is_option() {556 } else if self.is_option {511 quote! {557 quote! {512 if let Some(value) = self.#ident {558 if let Some(value) = self.#ident {513 value.serialize(out)?;559 value.serialize(s.clone(), out)?;514 }560 }515 }561 }516 } else {562 } else {517 quote! {563 quote! {518 self.#ident.serialize(out)?;564 self.#ident.serialize(s.clone(), out)?;519 }565 }520 }566 })521 }567 }522523 fn as_option(&self) -> Option<&Type> {524 extract_type_from_option(&self.0.ty).unwrap()525 }526 fn is_option(&self) -> bool {527 self.as_option().is_some()528 }529}568}530569531#[proc_macro_derive(Typed, attributes(typed))]570#[proc_macro_derive(Typed, attributes(typed))]548 let fields = data587 let fields = data549 .fields588 .fields550 .iter()589 .iter()551 .map(TypedField::try_new)590 .map(TypedField::parse)552 .collect::<Result<Vec<_>>>()?;591 .collect::<Result<Vec<_>>>()?;553592554 let typed = {593 let typed = {566605567 fn from_untyped(value: Val, s: State) -> Result<Self> {606 fn from_untyped(value: Val, s: State) -> Result<Self> {568 let obj = value.as_obj().expect("shape is correct");607 let obj = value.as_obj().expect("shape is correct");569 Self::parse(&obj)608 Self::parse(&obj, s)570 }609 }571610572 fn into_untyped(value: Self, s: State) -> Result<Val> {611 fn into_untyped(value: Self, s: State) -> Result<Val> {573 let mut out = ObjValueBuilder::new();612 let mut out = ObjValueBuilder::new();574 value.serialize(&mut out)?;613 value.serialize(s, &mut out)?;575 Ok(Val::Obj(out.build()))614 Ok(Val::Obj(out.build()))576 }615 }577616583 let fields_serialize = fields.iter().map(TypedField::expand_serialize);622 let fields_serialize = fields623 .iter()624 .map(TypedField::expand_serialize)625 .collect::<Result<Vec<_>>>()?;584626585 Ok(quote! {627 Ok(quote! {586 const _: () = {628 const _: () = {587 use ::jrsonnet_evaluator::{629 use ::jrsonnet_evaluator::{588 typed::{ComplexValType, Typed, TypedObj, CheckType},630 typed::{ComplexValType, Typed, TypedObj, CheckType},589 Val,631 Val, State,590 error::{LocError, Error},632 error::{LocError, Error, Result},591 ObjValueBuilder, ObjValue,633 ObjValueBuilder, ObjValue,592 };634 };593635594 #typed636 #typed595637596 impl #ident {638 impl TypedObj for #ident {597 fn serialize(self, out: &mut ObjValueBuilder) -> Result<(), LocError> {639 fn serialize(self, s: State, out: &mut ObjValueBuilder) -> Result<(), LocError> {598 #(#fields_serialize)*640 #(#fields_serialize)*599641600 Ok(())642 Ok(())601 }643 }602 fn parse(obj: &ObjValue) -> Result<Self, LocError> {644 fn parse(obj: &ObjValue, s: State) -> Result<Self, LocError> {603 Ok(Self {645 Ok(Self {604 #(#fields_parse)*646 #(#fields_parse)*605 })647 })