use crate::extruct_from::Model;
use proc_macro2::TokenStream;
use quote::quote;
pub(crate) type Rust = TokenStream;
pub(crate) fn codegen(model: Model) -> Rust {
let Model {
substruct,
superstruct_name,
fields,
} = model;
let substruct_name = substruct.ident.clone();
let assignments: Vec<_> = fields
.into_iter()
.map(|f| quote! { #f: value.#f.into()})
.collect();
quote!(
#substruct
impl std::convert::From<#superstruct_name> for #substruct_name {
fn from(value: #superstruct_name) -> Self {
Self {
#(#assignments,)*
}
}
}
impl extruct::ExtructedFrom<#superstruct_name> for #substruct_name {}
)
}
#[cfg(test)]
mod tests {
use super::*;
use syn::{parse::Parse, parse_quote, ItemImpl, ItemStruct};
struct StructDefAndImplBlock {
struct_def: ItemStruct,
#[allow(dead_code)]
impl_blocks: [ItemImpl; 2],
}
impl Parse for StructDefAndImplBlock {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let struct_def: ItemStruct = input.parse()?;
let impl_block1: ItemImpl = input.parse()?;
let impl_block2: ItemImpl = input.parse()?;
Ok(Self {
struct_def,
impl_blocks: [impl_block1, impl_block2],
})
}
}
#[test]
fn output_is_struct_def_and_impl_block() {
let substruct: ItemStruct = parse_quote!(
struct SomeStruct {
first: String,
second: u32,
}
);
let model = Model {
substruct: substruct.clone(),
superstruct_name: parse_quote!(AnotherStruct),
fields: vec![parse_quote!(first), parse_quote!(second)],
};
let rust = codegen(model);
let parsed = syn::parse2::<StructDefAndImplBlock>(rust).unwrap();
assert_eq!(parsed.struct_def, substruct);
}
}