difftreelog
refactor split TypedObj derives
in: master
5 files changed
crates/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>,
crates/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)?;
crates/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,
crates/jrsonnet-macros/src/typed.rsdiffbeforeafterboth--- a/crates/jrsonnet-macros/src/typed.rs
+++ b/crates/jrsonnet-macros/src/typed.rs
@@ -301,26 +301,49 @@
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
- let capacity = fields.len();
+ let fields = fields
+ .iter()
+ .filter_map(TypedField::expand_field)
+ .collect::<Vec<_>>();
+ Ok(quote! {
+ const _: () = {
+ use ::jrsonnet_evaluator::typed::__typed_macro_prelude::*;
- let typed = {
- let fields = fields
- .iter()
- .filter_map(TypedField::expand_field)
- .collect::<Vec<_>>();
- quote! {
impl #impl_generics Typed for #ident #ty_generics #where_clause {
const TYPE: &'static ComplexValType = &ComplexValType::ObjectRef(&[
#(#fields,)*
]);
}
+ };
+ })
+}
+pub fn derive_into_untyped_inner(input: DeriveInput) -> Result<TokenStream> {
+ let syn::Data::Struct(data) = &input.data else {
+ return Err(Error::new(input.span(), "only structs supported"));
+ };
+
+ let ident = &input.ident;
+ let fields = data
+ .fields
+ .iter()
+ .map(TypedField::parse)
+ .collect::<Result<Vec<_>>>()?;
+
+ let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
+
+ let capacity = fields.len();
+
+ let mut names = Names::default();
+
+ let fields_serialize = fields
+ .iter()
+ .map(|f| f.expand_serialize(&mut names))
+ .collect::<Vec<_>>();
- impl #impl_generics FromUntyped for #ident #ty_generics #where_clause {
- fn from_untyped(value: Val) -> JrResult<Self> {
- let obj = value.as_obj().expect("shape is correct");
- Self::parse(&obj)
- }
- }
+ let names_expanded = names.expand();
+ Ok(quote! {
+ const _: () = {
+ use ::jrsonnet_evaluator::typed::__typed_macro_prelude::*;
impl #impl_generics IntoUntyped for #ident #ty_generics #where_clause {
fn into_untyped(value: Self) -> JrResult<Val> {
@@ -329,42 +352,57 @@
Ok(Val::Obj(out.build()))
}
}
- }
+
+ #names_expanded
+
+ impl #impl_generics SerializeTypedObj for #ident #ty_generics #where_clause {
+ fn serialize(self, out: &mut ObjValueBuilder) -> JrResult<()> {
+ NAMES.with(|__names| {
+ #(#fields_serialize)*
+
+ Ok(())
+ })
+ }
+ }
+ };
+ })
+}
+pub fn derive_from_untyped_inner(input: DeriveInput) -> Result<TokenStream> {
+ let syn::Data::Struct(data) = &input.data else {
+ return Err(Error::new(input.span(), "only structs supported"));
};
+ let ident = &input.ident;
+ let fields = data
+ .fields
+ .iter()
+ .map(TypedField::parse)
+ .collect::<Result<Vec<_>>>()?;
+
+ let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
+
let mut names = Names::default();
let fields_parse = fields
.iter()
.map(|f| f.expand_parse(&mut names))
- .collect::<Vec<_>>();
- let fields_serialize = fields
- .iter()
- .map(|f| f.expand_serialize(&mut names))
.collect::<Vec<_>>();
let names_expanded = names.expand();
Ok(quote! {
const _: () = {
- use ::jrsonnet_evaluator::{
- typed::{ComplexValType, Typed, IntoUntyped, FromUntyped, TypedObj, CheckType},
- Val, State,
- error::{ErrorKind, Result as JrResult},
- ObjValueBuilder, ObjValue, IStr,
- };
+ use ::jrsonnet_evaluator::typed::__typed_macro_prelude::*;
- #typed
+ impl #impl_generics FromUntyped for #ident #ty_generics #where_clause {
+ fn from_untyped(value: Val) -> JrResult<Self> {
+ let obj = value.as_obj().expect("shape is correct");
+ Self::parse(&obj)
+ }
+ }
#names_expanded
- impl #impl_generics TypedObj for #ident #ty_generics #where_clause {
- fn serialize(self, out: &mut ObjValueBuilder) -> JrResult<()> {
- NAMES.with(|__names| {
- #(#fields_serialize)*
-
- Ok(())
- })
- }
+ impl #impl_generics ParseTypedObj for #ident #ty_generics #where_clause {
fn parse(obj: &ObjValue) -> JrResult<Self> {
NAMES.with(|__names| Ok(Self {
#(#fields_parse)*
crates/jrsonnet-stdlib/src/manifest/ini.rsdiffbeforeafterboth1use std::collections::BTreeMap;23use jrsonnet_evaluator::{4 manifest::{ManifestFormat, ToStringFormat},5 typed::{FromUntyped, Typed},6 ObjValue, Result, ResultExt, Val,7};8use jrsonnet_parser::IStr;910pub struct IniFormat {11 #[cfg(feature = "exp-preserve-order")]12 preserve_order: bool,13 final_newline: bool,14}1516impl IniFormat {17 pub fn std(#[cfg(feature = "exp-preserve-order")] preserve_order: bool) -> Self {18 Self {19 #[cfg(feature = "exp-preserve-order")]20 preserve_order,21 final_newline: true,22 }23 }24 pub fn cli(#[cfg(feature = "exp-preserve-order")] preserve_order: bool) -> Self {25 Self {26 #[cfg(feature = "exp-preserve-order")]27 preserve_order,28 final_newline: false,29 }30 }31}3233impl ManifestFormat for IniFormat {34 fn manifest_buf(&self, val: Val, buf: &mut String) -> Result<()> {35 manifest_ini_obj(36 self,37 IniObj::from_untyped(val).description("ini object structure")?,38 buf,39 )40 }41}4243fn manifest_ini_body(44 #[cfg(feature = "exp-preserve-order")] format: &IniFormat,45 body: ObjValue,46 out: &mut String,47) -> Result<()> {48 for (i, (key, value)) in body49 .iter(50 #[cfg(feature = "exp-preserve-order")]51 format.preserve_order,52 )53 .enumerate()54 {55 if i != 0 || !out.is_empty() {56 out.push('\n');57 }58 let value = value.with_description(|| format!("field <{key}> evaluation"))?;59 let manifest_desc = || format!("field <{key}> manifestification");60 if let Some(arr) = value.as_arr() {61 for (i, ele) in arr.iter().enumerate() {62 if i != 0 {63 out.push('\n');64 }65 let ele = ele66 .with_description(|| format!("elem <{i}> evaluation"))67 .with_description(manifest_desc)?;68 out.push_str(&key);69 out.push_str(" = ");70 ToStringFormat71 .manifest_buf(ele, out)72 .with_description(manifest_desc)?;73 }74 } else {75 out.push_str(&key);76 out.push_str(" = ");77 ToStringFormat78 .manifest_buf(value, out)79 .with_description(manifest_desc)?;80 }81 }82 Ok(())83}8485#[derive(Typed)]86struct IniObj {87 main: Option<ObjValue>,88 // TODO: Preserve section order?89 sections: BTreeMap<IStr, ObjValue>,90}9192fn manifest_ini_obj(format: &IniFormat, obj: IniObj, out: &mut String) -> Result<()> {93 if let Some(main) = obj.main {94 manifest_ini_body(95 #[cfg(feature = "exp-preserve-order")]96 format,97 main,98 out,99 )100 .description("<main> manifestification")?;101 }102 for (i, (section, val)) in obj.sections.into_iter().enumerate() {103 if i != 0 || !out.is_empty() {104 out.push('\n');105 }106 out.push('[');107 out.push_str(§ion);108 out.push(']');109 manifest_ini_body(110 #[cfg(feature = "exp-preserve-order")]111 format,112 val,113 out,114 )115 .with_description(|| format!("<{section}> section manifestification"))?;116 }117 if format.final_newline {118 out.push('\n');119 }120 Ok(())121}1use std::collections::BTreeMap;23use jrsonnet_evaluator::{4 manifest::{ManifestFormat, ToStringFormat},5 typed::{FromUntyped, Typed},6 ObjValue, Result, ResultExt, Val,7};8use jrsonnet_parser::IStr;910pub struct IniFormat {11 #[cfg(feature = "exp-preserve-order")]12 preserve_order: bool,13 final_newline: bool,14}1516impl IniFormat {17 pub fn std(#[cfg(feature = "exp-preserve-order")] preserve_order: bool) -> Self {18 Self {19 #[cfg(feature = "exp-preserve-order")]20 preserve_order,21 final_newline: true,22 }23 }24 pub fn cli(#[cfg(feature = "exp-preserve-order")] preserve_order: bool) -> Self {25 Self {26 #[cfg(feature = "exp-preserve-order")]27 preserve_order,28 final_newline: false,29 }30 }31}3233impl ManifestFormat for IniFormat {34 fn manifest_buf(&self, val: Val, buf: &mut String) -> Result<()> {35 manifest_ini_obj(36 self,37 IniObj::from_untyped(val).description("ini object structure")?,38 buf,39 )40 }41}4243fn manifest_ini_body(44 #[cfg(feature = "exp-preserve-order")] format: &IniFormat,45 body: ObjValue,46 out: &mut String,47) -> Result<()> {48 for (i, (key, value)) in body49 .iter(50 #[cfg(feature = "exp-preserve-order")]51 format.preserve_order,52 )53 .enumerate()54 {55 if i != 0 || !out.is_empty() {56 out.push('\n');57 }58 let value = value.with_description(|| format!("field <{key}> evaluation"))?;59 let manifest_desc = || format!("field <{key}> manifestification");60 if let Some(arr) = value.as_arr() {61 for (i, ele) in arr.iter().enumerate() {62 if i != 0 {63 out.push('\n');64 }65 let ele = ele66 .with_description(|| format!("elem <{i}> evaluation"))67 .with_description(manifest_desc)?;68 out.push_str(&key);69 out.push_str(" = ");70 ToStringFormat71 .manifest_buf(ele, out)72 .with_description(manifest_desc)?;73 }74 } else {75 out.push_str(&key);76 out.push_str(" = ");77 ToStringFormat78 .manifest_buf(value, out)79 .with_description(manifest_desc)?;80 }81 }82 Ok(())83}8485#[derive(Typed, FromUntyped)]86struct IniObj {87 main: Option<ObjValue>,88 // TODO: Preserve section order?89 sections: BTreeMap<IStr, ObjValue>,90}9192fn manifest_ini_obj(format: &IniFormat, obj: IniObj, out: &mut String) -> Result<()> {93 if let Some(main) = obj.main {94 manifest_ini_body(95 #[cfg(feature = "exp-preserve-order")]96 format,97 main,98 out,99 )100 .description("<main> manifestification")?;101 }102 for (i, (section, val)) in obj.sections.into_iter().enumerate() {103 if i != 0 || !out.is_empty() {104 out.push('\n');105 }106 out.push('[');107 out.push_str(§ion);108 out.push(']');109 manifest_ini_body(110 #[cfg(feature = "exp-preserve-order")]111 format,112 val,113 out,114 )115 .with_description(|| format!("<{section}> section manifestification"))?;116 }117 if format.final_newline {118 out.push('\n');119 }120 Ok(())121}