use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
pub struct Output {
pub inner_func: TokenStream2,
pub func_declare_start: TokenStream2,
pub func_output_start: TokenStream2,
pub func_declare_body: TokenStream2,
pub func_output_end: TokenStream2,
pub func_declare_end: TokenStream2,
}
impl From<Output> for TokenStream {
fn from(val: Output) -> Self {
let Output {
inner_func,
func_declare_start,
func_output_start,
func_declare_body,
func_output_end,
func_declare_end,
} = val;
let ts2 = quote! {
#inner_func
#func_declare_start {
#func_output_start
#func_declare_body
#func_output_end
#func_declare_end
}
};
ts2.into()
}
}
#[cfg(test)]
mod tests {
use super::*;
use quote::quote;
#[test]
fn test_output_creation() {
let output = Output {
inner_func: quote! { fn __test__() {} },
func_declare_start: quote! { fn test() },
func_output_start: quote! { println!("start"); },
func_declare_body: quote! { let output = __test__(); },
func_output_end: quote! { println!("end"); },
func_declare_end: quote! { output },
};
assert!(!output.inner_func.is_empty());
assert!(!output.func_declare_start.is_empty());
assert!(!output.func_output_start.is_empty());
assert!(!output.func_declare_body.is_empty());
assert!(!output.func_output_end.is_empty());
assert!(!output.func_declare_end.is_empty());
}
#[test]
fn test_output_from_conversion() {
let output = Output {
inner_func: quote! { fn __test__() { 42 } },
func_declare_start: quote! { fn test() -> i32 },
func_output_start: quote! { println!("entering test"); },
func_declare_body: quote! { let output = __test__(); },
func_output_end: quote! { println!("exiting test"); },
func_declare_end: quote! { output },
};
let _: Output = output;
}
#[test]
fn test_output_with_empty_components() {
let output = Output {
inner_func: quote! { fn __empty__() {} },
func_declare_start: quote! { fn empty() },
func_output_start: quote! {},
func_declare_body: quote! { let output = __empty__(); },
func_output_end: quote! {},
func_declare_end: quote! { output },
};
assert!(output.func_output_start.is_empty());
assert!(output.func_output_end.is_empty());
assert!(!output.inner_func.is_empty());
}
#[test]
fn test_output_with_complex_logging() {
let output = Output {
inner_func: quote! {
fn __complex_func__(x: i32, y: String) -> Result<i32, String> {
if x > 0 { Ok(x) } else { Err(y) }
}
},
func_declare_start: quote! {
fn complex_func(x: i32, y: String) -> Result<i32, String>
},
func_output_start: quote! {
log::debug!("complex_func [in ]: x:{}, y:{}", format!("{:?}", x), format!("{:?}", y));
},
func_declare_body: quote! {
let __x_value__ = format!("{:?}", x);
let __y_value__ = format!("{:?}", y);
let output = __complex_func__(x, y);
},
func_output_end: quote! {
log::debug!("complex_func [out]: return:{}", format!("{:?}", output));
},
func_declare_end: quote! { output },
};
assert!(!output.inner_func.is_empty());
assert!(!output.func_declare_start.is_empty());
assert!(!output.func_output_start.is_empty());
assert!(!output.func_declare_body.is_empty());
assert!(!output.func_output_end.is_empty());
assert!(!output.func_declare_end.is_empty());
}
#[test]
fn test_output_structure_integrity() {
let output = Output {
inner_func: quote! { fn __test__() -> i32 { 42 } },
func_declare_start: quote! { fn test() -> i32 },
func_output_start: quote! { println!("start"); },
func_declare_body: quote! { let output = __test__(); },
func_output_end: quote! { println!("end"); },
func_declare_end: quote! { output },
};
assert!(!output.inner_func.is_empty());
assert!(!output.func_declare_start.is_empty());
assert!(!output.func_output_start.is_empty());
assert!(!output.func_declare_body.is_empty());
assert!(!output.func_output_end.is_empty());
assert!(!output.func_declare_end.is_empty());
}
}