From 098d931f0d92480fbe938f936cf3e6731516d3d5 Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Thu, 15 Aug 2024 17:45:07 +0200 Subject: [PATCH] fix: #[derive(Typed)] should lazily process Thunks Fixes: https://github.com/CertainLach/jrsonnet/issues/172 --- crates/jrsonnet-evaluator/src/obj.rs | 4 ++-- crates/jrsonnet-macros/src/lib.rs | 32 +++++++++++++++++++++------- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/crates/jrsonnet-evaluator/src/obj.rs b/crates/jrsonnet-evaluator/src/obj.rs index e00b8d2..106359e 100644 --- a/crates/jrsonnet-evaluator/src/obj.rs +++ b/crates/jrsonnet-evaluator/src/obj.rs @@ -957,9 +957,9 @@ impl ObjMemberBuilder> { /// Tries to insert value, returns an error if it was already defined pub fn try_value(self, value: impl Into) -> Result<()> { - self.thunk(Thunk::evaluated(value.into())) + self.try_thunk(Thunk::evaluated(value.into())) } - pub fn thunk(self, value: impl Into>) -> Result<()> { + pub fn try_thunk(self, value: impl Into>) -> Result<()> { self.binding(MaybeUnbound::Bound(value.into())) } pub fn bindable(self, bindable: impl Unbound) -> Result<()> { diff --git a/crates/jrsonnet-macros/src/lib.rs b/crates/jrsonnet-macros/src/lib.rs index c154e7f..20a22f1 100644 --- a/crates/jrsonnet-macros/src/lib.rs +++ b/crates/jrsonnet-macros/src/lib.rs @@ -477,6 +477,7 @@ struct TypedField { ident: Ident, ty: Type, is_option: bool, + is_lazy: bool, } impl TypedField { fn parse(field: &syn::Field) -> Result { @@ -503,11 +504,14 @@ impl TypedField { )); } + let is_lazy = type_is_path(&ty, "Thunk").is_some(); + Ok(Self { attr, ident, ty, is_option, + is_lazy, }) } /// None if this field is flattened in jsonnet output @@ -596,21 +600,33 @@ impl TypedField { } else { quote! {} }; - if self.is_option { + let value = if self.is_lazy { quote! { - if let Some(value) = self.#ident { - out.field(#name) - #hide - #add - .try_value(<#ty as Typed>::into_untyped(value)?)?; - } + out.field(#name) + #hide + #add + .try_thunk(<#ty as Typed>::into_lazy_untyped(value))?; } } else { quote! { out.field(#name) #hide #add - .try_value(<#ty as Typed>::into_untyped(self.#ident)?)?; + .try_value(<#ty as Typed>::into_untyped(value)?)?; + } + }; + if self.is_option { + quote! { + if let Some(value) = self.#ident { + #value + } + } + } else { + quote! { + { + let value = self.#ident; + #value + } } } },