struct_reflection/lib.rs
1use std::marker::PhantomData;
2
3pub use struct_reflection_derive::StructReflection;
4
5pub trait StructReflection {
6 fn struct_reflection() -> Option<Vec<String>>;
7}
8
9pub trait StructReflectionHelper {
10 fn struct_reflection() -> Option<Vec<String>>;
11}
12
13/// Implementation of StructReflectionHelper for any type that implements StructReflection.
14/// This bridges the two traits, allowing types with #[derive(StructReflection)] to work
15/// in contexts that require StructReflectionHelper.
16impl<T: StructReflection> StructReflectionHelper for T {
17 fn struct_reflection() -> Option<Vec<String>> {
18 T::struct_reflection()
19 }
20}
21
22impl<T: StructReflectionHelper, const N: usize> StructReflectionHelper for [T; N] {
23 fn struct_reflection() -> Option<Vec<String>> {
24 match T::struct_reflection() {
25 Some(inner_fields) => {
26 let mut fields = Vec::new();
27
28 for i in 0..N {
29 for field in &inner_fields {
30 fields.push(format!("{i}__{field}"));
31 }
32 }
33
34 Some(fields)
35 }
36 None => Some((0..N).map(|i| i.to_string()).collect()),
37 }
38 }
39}
40
41// Note on Option<T> implementation:
42//
43// Ideally, we would handle Option<T> differently based on T:
44// - For primitives: return a single "optional" field
45// - For structs: return internal fields with "__optional" suffix
46//
47// This isn't currently possible in stable Rust due to trait coherence rules
48// and lack of specialization. As a compromise, we use a simplified implementation
49// that treats all Option<T> the same way, regardless of what T is.
50//
51// This might be improved in future versions when Rust's type system evolves.
52impl<T> StructReflectionHelper for Option<T> {
53 fn struct_reflection() -> Option<Vec<String>> {
54 // Simple implementation that always returns "optional"
55 Some(vec!["optional".to_string()])
56 }
57}
58
59impl<T> StructReflectionHelper for PhantomData<T> {
60 fn struct_reflection() -> Option<Vec<String>> {
61 None
62 }
63}