git.delta.rocks / jrsonnet / refs/commits / f0c8338d487d

difftreelog

refactor split TypedObj derives

oqrkzkryYaroslav Bolyukin2026-03-22parent: #bd50dd1.patch.diff
in: master

5 files changed

modifiedcrates/jrsonnet-evaluator/src/arr/spec.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/arr/spec.rs
+++ b/crates/jrsonnet-evaluator/src/arr/spec.rs
@@ -609,7 +609,7 @@
 	}
 }
 
-#[derive(Typed)]
+#[derive(Typed, IntoUntyped)]
 pub struct KeyValue {
 	key: IStr,
 	value: Thunk<Val>,
modifiedcrates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/typed/conversions.rs
+++ b/crates/jrsonnet-evaluator/src/typed/conversions.rs
@@ -2,7 +2,6 @@
 
 use jrsonnet_gcmodule::Trace;
 use jrsonnet_interner::{IBytes, IStr};
-pub use jrsonnet_macros::Typed;
 use jrsonnet_types::{ComplexValType, ValType};
 
 use crate::{
@@ -14,6 +13,19 @@
 	ObjValue, ObjValueBuilder, Result, ResultExt, Thunk, Val,
 };
 
+#[doc(hidden)]
+pub mod __typed_macro_prelude {
+	pub use ::jrsonnet_evaluator::{
+		error::{ErrorKind, Result as JrResult},
+		typed::{
+			CheckType, ComplexValType, FromUntyped, IntoUntyped, ParseTypedObj, SerializeTypedObj,
+			Typed,
+		},
+		IStr, ObjValue, ObjValueBuilder, State, Val,
+	};
+}
+pub use jrsonnet_macros::{FromUntyped, IntoUntyped, Typed};
+
 #[derive(Trace)]
 struct ThunkFromUntyped<K: Trace>(PhantomData<fn() -> K>);
 impl<K> ThunkMapper<Val> for ThunkFromUntyped<K>
@@ -49,9 +61,11 @@
 	}
 }
 
-pub trait TypedObj: Typed {
-	fn serialize(self, out: &mut ObjValueBuilder) -> Result<()>;
+pub trait ParseTypedObj: Typed {
 	fn parse(obj: &ObjValue) -> Result<Self>;
+}
+pub trait SerializeTypedObj: Typed {
+	fn serialize(self, out: &mut ObjValueBuilder) -> Result<()>;
 	fn into_object(self) -> Result<ObjValue> {
 		let mut builder = ObjValueBuilder::new();
 		self.serialize(&mut builder)?;
modifiedcrates/jrsonnet-macros/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-macros/src/lib.rs
+++ b/crates/jrsonnet-macros/src/lib.rs
@@ -13,7 +13,7 @@
 	LitStr, Meta, Pat, Path, PathArguments, Result, ReturnType, Token, Type,
 };
 
-use self::typed::derive_typed_inner;
+use self::typed::{derive_from_untyped_inner, derive_into_untyped_inner, derive_typed_inner};
 
 mod names;
 mod typed;
@@ -451,6 +451,24 @@
 		Err(e) => e.to_compile_error().into(),
 	}
 }
+#[proc_macro_derive(IntoUntyped, attributes(typed))]
+pub fn derive_into_untyped(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
+	let input = parse_macro_input!(item as DeriveInput);
+
+	match derive_into_untyped_inner(input) {
+		Ok(v) => v.into(),
+		Err(e) => e.to_compile_error().into(),
+	}
+}
+#[proc_macro_derive(FromUntyped, attributes(typed))]
+pub fn derive_from_untyped(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
+	let input = parse_macro_input!(item as DeriveInput);
+
+	match derive_from_untyped_inner(input) {
+		Ok(v) => v.into(),
+		Err(e) => e.to_compile_error().into(),
+	}
+}
 
 struct FormatInput {
 	formatting: LitStr,
modifiedcrates/jrsonnet-macros/src/typed.rsdiffbeforeafterboth
287 }287 }
288}288}
289289
290pub fn derive_typed_inner(input: DeriveInput) -> Result<TokenStream> {
291 let syn::Data::Struct(data) = &input.data else {
292 return Err(Error::new(input.span(), "only structs supported"));
293 };
294
295 let ident = &input.ident;
296 let fields = data
297 .fields
298 .iter()
299 .map(TypedField::parse)
300 .collect::<Result<Vec<_>>>()?;
301
302 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
303
304 let fields = fields
305 .iter()
306 .filter_map(TypedField::expand_field)
307 .collect::<Vec<_>>();
308 Ok(quote! {
309 const _: () = {
310 use ::jrsonnet_evaluator::typed::__typed_macro_prelude::*;
311
312 impl #impl_generics Typed for #ident #ty_generics #where_clause {
313 const TYPE: &'static ComplexValType = &ComplexValType::ObjectRef(&[
314 #(#fields,)*
315 ]);
316 }
317 };
318 })
319}
320pub fn derive_into_untyped_inner(input: DeriveInput) -> Result<TokenStream> {
321 let syn::Data::Struct(data) = &input.data else {
322 return Err(Error::new(input.span(), "only structs supported"));
323 };
324
325 let ident = &input.ident;
326 let fields = data
327 .fields
328 .iter()
329 .map(TypedField::parse)
330 .collect::<Result<Vec<_>>>()?;
331
332 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
333
334 let capacity = fields.len();
335
336 let mut names = Names::default();
337
338 let fields_serialize = fields
339 .iter()
340 .map(|f| f.expand_serialize(&mut names))
341 .collect::<Vec<_>>();
342
343 let names_expanded = names.expand();
344 Ok(quote! {
345 const _: () = {
346 use ::jrsonnet_evaluator::typed::__typed_macro_prelude::*;
347
348 impl #impl_generics IntoUntyped for #ident #ty_generics #where_clause {
349 fn into_untyped(value: Self) -> JrResult<Val> {
350 let mut out = ObjValueBuilder::with_capacity(#capacity);
351 value.serialize(&mut out)?;
352 Ok(Val::Obj(out.build()))
353 }
354 }
355
356 #names_expanded
357
358 impl #impl_generics SerializeTypedObj for #ident #ty_generics #where_clause {
359 fn serialize(self, out: &mut ObjValueBuilder) -> JrResult<()> {
360 NAMES.with(|__names| {
361 #(#fields_serialize)*
362
363 Ok(())
364 })
365 }
366 }
367 };
368 })
369}
290pub fn derive_typed_inner(input: DeriveInput) -> Result<TokenStream> {370pub fn derive_from_untyped_inner(input: DeriveInput) -> Result<TokenStream> {
291 let syn::Data::Struct(data) = &input.data else {371 let syn::Data::Struct(data) = &input.data else {
292 return Err(Error::new(input.span(), "only structs supported"));372 return Err(Error::new(input.span(), "only structs supported"));
293 };373 };
301381
302 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();382 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
303
304 let capacity = fields.len();
305
306 let typed = {
307 let fields = fields
308 .iter()
309 .filter_map(TypedField::expand_field)
310 .collect::<Vec<_>>();
311 quote! {
312 impl #impl_generics Typed for #ident #ty_generics #where_clause {
313 const TYPE: &'static ComplexValType = &ComplexValType::ObjectRef(&[
314 #(#fields,)*
315 ]);
316 }
317
318 impl #impl_generics FromUntyped for #ident #ty_generics #where_clause {
319 fn from_untyped(value: Val) -> JrResult<Self> {
320 let obj = value.as_obj().expect("shape is correct");
321 Self::parse(&obj)
322 }
323 }
324
325 impl #impl_generics IntoUntyped for #ident #ty_generics #where_clause {
326 fn into_untyped(value: Self) -> JrResult<Val> {
327 let mut out = ObjValueBuilder::with_capacity(#capacity);
328 value.serialize(&mut out)?;
329 Ok(Val::Obj(out.build()))
330 }
331 }
332 }
333 };
334383
335 let mut names = Names::default();384 let mut names = Names::default();
336385
337 let fields_parse = fields386 let fields_parse = fields
338 .iter()387 .iter()
339 .map(|f| f.expand_parse(&mut names))388 .map(|f| f.expand_parse(&mut names))
340 .collect::<Vec<_>>();389 .collect::<Vec<_>>();
341 let fields_serialize = fields
342 .iter()
343 .map(|f| f.expand_serialize(&mut names))
344 .collect::<Vec<_>>();
345390
346 let names_expanded = names.expand();391 let names_expanded = names.expand();
347 Ok(quote! {392 Ok(quote! {
348 const _: () = {393 const _: () = {
349 use ::jrsonnet_evaluator::{394 use ::jrsonnet_evaluator::typed::__typed_macro_prelude::*;
350 typed::{ComplexValType, Typed, IntoUntyped, FromUntyped, TypedObj, CheckType},
351 Val, State,
352 error::{ErrorKind, Result as JrResult},
353 ObjValueBuilder, ObjValue, IStr,
354 };
355
356 #typed
357
358 #names_expanded
359395
360 impl #impl_generics TypedObj for #ident #ty_generics #where_clause {396 impl #impl_generics FromUntyped for #ident #ty_generics #where_clause {
361 fn serialize(self, out: &mut ObjValueBuilder) -> JrResult<()> {397 fn from_untyped(value: Val) -> JrResult<Self> {
362 NAMES.with(|__names| {398 let obj = value.as_obj().expect("shape is correct");
363 #(#fields_serialize)*399 Self::parse(&obj)
364
365 Ok(())
366 })
367 }400 }
401 }
402
403 #names_expanded
404
405 impl #impl_generics ParseTypedObj for #ident #ty_generics #where_clause {
368 fn parse(obj: &ObjValue) -> JrResult<Self> {406 fn parse(obj: &ObjValue) -> JrResult<Self> {
369 NAMES.with(|__names| Ok(Self {407 NAMES.with(|__names| Ok(Self {
370 #(#fields_parse)*408 #(#fields_parse)*
371 }))409 }))
372 }410 }
373 }411 }
374 };412 };
375 })413 })
376}414}
modifiedcrates/jrsonnet-stdlib/src/manifest/ini.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/manifest/ini.rs
+++ b/crates/jrsonnet-stdlib/src/manifest/ini.rs
@@ -82,7 +82,7 @@
 	Ok(())
 }
 
-#[derive(Typed)]
+#[derive(Typed, FromUntyped)]
 struct IniObj {
 	main: Option<ObjValue>,
 	// TODO: Preserve section order?