Build fn child unwrap; some tests.

This commit is contained in:
Jesse Brault 2025-09-04 19:27:26 -05:00
parent 4d70765d17
commit 59165f6235

View File

@ -1,5 +1,6 @@
use crate::spec::{ use crate::spec::{
BuildBooleanOn, ChildSpec, SingleChildToBuild, StructBuildSpec, VecChildToBuild, BuildBooleanOn, ChildSpec, SingleBooleanChildToBuild, SingleChildToBuild,
SingleTypeChildToBuild, StructBuildSpec, VecChild, VecChildToBuild,
}; };
use convert_case::{Case, Casing}; use convert_case::{Case, Casing};
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
@ -9,33 +10,45 @@ pub fn make_build_fn_name(s: &str) -> String {
format!("build_{}", s.to_case(Case::Snake)) format!("build_{}", s.to_case(Case::Snake))
} }
fn make_vec_child_holder(vec_child: &VecChild) -> TokenStream {
let (child_ident, child_type_ident) = match vec_child.build() {
VecChildToBuild::Type(vec_type_child) => (
format_ident!("{}", vec_type_child.var_name()),
format_ident!("{}", vec_type_child.build()),
),
};
quote! {
let mut #child_ident: Vec<Box<#child_type_ident>> = vec![]
}
}
fn make_single_type_child_holder(single_type_child: &SingleTypeChildToBuild) -> TokenStream {
let child_ident = format_ident!("{}", single_type_child.var_name());
let child_type_ident = format_ident!("{}", single_type_child.build());
quote! {
let mut #child_ident: Option<Box<#child_type_ident>> = None
}
}
fn make_single_boolean_child_holder(
single_boolean_child: &SingleBooleanChildToBuild,
) -> TokenStream {
let child_ident = format_ident!("{}", single_boolean_child.var_name());
quote! {
let mut #child_ident: bool = false
}
}
fn make_child_holder(child_spec: &ChildSpec) -> Option<TokenStream> { fn make_child_holder(child_spec: &ChildSpec) -> Option<TokenStream> {
match child_spec { match child_spec {
ChildSpec::SkipChild(_) => None, ChildSpec::SkipChild(_) => None,
ChildSpec::VecChild(vec_child) => { ChildSpec::VecChild(vec_child) => Some(make_vec_child_holder(vec_child)),
let (child_ident, child_type_ident) = match vec_child.build() {
VecChildToBuild::Type(vec_type_child) => (
format_ident!("{}", vec_type_child.var_name()),
format_ident!("{}", vec_type_child.build()),
),
};
Some(quote! {
let mut #child_ident: Vec<Box<#child_type_ident>> = vec![]
})
}
ChildSpec::SingleChild(single_child) => match single_child.build() { ChildSpec::SingleChild(single_child) => match single_child.build() {
SingleChildToBuild::Type(single_type_child) => { SingleChildToBuild::Type(single_type_child) => {
let child_ident = format_ident!("{}", single_type_child.var_name()); Some(make_single_type_child_holder(single_type_child))
let child_type_ident = format_ident!("{}", single_type_child.build());
Some(quote! {
let mut #child_ident: Option<Box<#child_type_ident>> = None;
})
} }
SingleChildToBuild::Boolean(boolean_child) => { SingleChildToBuild::Boolean(boolean_child) => {
let child_ident = format_ident!("{}", boolean_child.var_name()); Some(make_single_boolean_child_holder(boolean_child))
Some(quote! {
let #child_ident: bool = false
})
} }
}, },
} }
@ -95,32 +108,32 @@ fn make_child_arg(child_spec: &ChildSpec) -> Option<TokenStream> {
ChildSpec::SkipChild(_) => None, ChildSpec::SkipChild(_) => None,
ChildSpec::VecChild(vec_child) => { ChildSpec::VecChild(vec_child) => {
let child_ident = match vec_child.build() { let child_ident = match vec_child.build() {
VecChildToBuild::Type(vec_type_child) => format_ident!("{}", vec_type_child.var_name()) VecChildToBuild::Type(vec_type_child) => {
format_ident!("{}", vec_type_child.var_name())
}
}; };
Some(quote! { #child_ident }) Some(quote! { #child_ident })
}, }
ChildSpec::SingleChild(single_child) => { ChildSpec::SingleChild(single_child) => match single_child.build() {
match single_child.build() { SingleChildToBuild::Type(single_type_child) => {
SingleChildToBuild::Type(single_type_child) => { let child_ident = format_ident!("{}", single_type_child.var_name());
let child_ident = format_ident!("{}", single_type_child.var_name()); if single_type_child.optional() {
if single_type_child.optional() {
Some(quote! { #child_ident })
} else if let Some(or_else) = single_type_child.or_else() {
let child_type_ident = format_ident!("{}", single_type_child.build());
let or_else_ident = format_ident!("{}", or_else);
Some(quote! {
#child_ident.unwrap_or_else(|| Box::new(#child_type_ident::#or_else_ident()))
})
} else {
Some(quote! { #child_ident.unwrap() })
}
},
SingleChildToBuild::Boolean(single_boolean_child) => {
let child_ident = format_ident!("{}", single_boolean_child.var_name());
Some(quote! { #child_ident }) Some(quote! { #child_ident })
} else if let Some(or_else) = single_type_child.or_else() {
let child_type_ident = format_ident!("{}", single_type_child.build());
let or_else_ident = format_ident!("{}", or_else);
Some(quote! {
#child_ident.unwrap_or_else(|| Box::new(#child_type_ident::#or_else_ident()))
})
} else {
Some(quote! { #child_ident.unwrap() })
} }
} }
} SingleChildToBuild::Boolean(single_boolean_child) => {
let child_ident = format_ident!("{}", single_boolean_child.var_name());
Some(quote! { #child_ident })
}
},
} }
} }
@ -180,3 +193,54 @@ pub fn make_struct_build_fn(build_spec: &StructBuildSpec) -> TokenStream {
} }
} }
} }
#[cfg(test)]
mod tests {
use super::*;
use crate::spec::VecTypeChildToBuild;
#[test]
fn vec_child_holder() {
let vec_child = VecChild::new(
"test_child",
"Test",
VecChildToBuild::Type(VecTypeChildToBuild::new(
"TestType",
"test_child",
"build_test_child",
)),
);
assert_eq!(
make_vec_child_holder(&vec_child).to_string(),
quote! {
let mut test_child: Vec<Box<TestType>> = vec![]
}
.to_string()
);
}
#[test]
fn single_type_child_holder() {
let single_type_child = SingleTypeChildToBuild::from_build_or_rule("TestType", None, false);
assert_eq!(
make_single_type_child_holder(&single_type_child).to_string(),
quote! {
let mut test_type: Option<Box<TestType>> = None
}
.to_string()
);
}
#[test]
fn single_boolean_child_holder() {
let single_boolean_child =
SingleBooleanChildToBuild::new("test_child", BuildBooleanOn::RulePresent);
assert_eq!(
make_single_boolean_child_holder(&single_boolean_child).to_string(),
quote! {
let mut test_child: bool = false
}
.to_string()
);
}
}