Skip to main content

toml_scaffold/
lib.rs

1mod field_path;
2mod format;
3mod schema;
4
5pub use field_path::FieldPath;
6use schemars::JsonSchema;
7use serde::Serialize;
8pub use toml_scaffold_macros::TomlScaffold;
9
10/// Trait for generating TOML scaffold files with comments from doc strings.
11pub trait TomlScaffold: Serialize + JsonSchema {
12    /// Returns format preferences for fields (field_path -> format_type)
13    fn format_preferences() -> std::collections::HashMap<FieldPath, String> {
14        std::collections::HashMap::new()
15    }
16
17    /// Generates a TOML scaffold string with comments from struct field doc comments.
18    fn to_scaffold(&self) -> Result<String, toml::ser::Error> {
19        // Serialize struct to TOML value
20        let value = toml::Value::try_from(&self)?;
21
22        // Extract schema metadata (comments, field info)
23        let schema = schemars::schema_for!(Self);
24        let mut schema_info = schema::extract_schema_info(&schema, &FieldPath::new());
25
26        // Apply format preferences
27        schema_info.formats.extend(Self::format_preferences());
28
29        // Format TOML with comments from schema
30        let result = format::format_with_comments(
31            &value,
32            &schema_info.comments,
33            &schema_info.all_fields,
34            &schema_info.optional_fields,
35            &schema_info.formats,
36            &FieldPath::new(),
37        );
38
39        // Rule 14: Always end file with a single newline
40        Ok(format!("{}\n", result.trim_end()))
41    }
42}
43
44// Implementations for built-in types that return empty format preferences
45macro_rules! impl_toml_scaffold_empty {
46    ($($ty:ty),* $(,)?) => {
47        $(
48            impl TomlScaffold for $ty {
49                fn format_preferences() -> std::collections::HashMap<FieldPath, String> {
50                    std::collections::HashMap::new()
51                }
52            }
53        )*
54    };
55}
56
57// Primitives
58impl_toml_scaffold_empty!(
59    String, &str, bool, char, i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32,
60    f64,
61);
62
63// Common types
64impl_toml_scaffold_empty!(serde_json::Value, std::path::PathBuf,);
65
66// Generic collections
67impl<T: TomlScaffold> TomlScaffold for Vec<T> {
68    fn format_preferences() -> std::collections::HashMap<FieldPath, String> {
69        std::collections::HashMap::new()
70    }
71}
72
73impl<T: TomlScaffold> TomlScaffold for Option<T> {
74    fn format_preferences() -> std::collections::HashMap<FieldPath, String> {
75        std::collections::HashMap::new()
76    }
77}
78
79impl<K: Serialize + JsonSchema, V: TomlScaffold> TomlScaffold for std::collections::HashMap<K, V> {
80    fn format_preferences() -> std::collections::HashMap<FieldPath, String> {
81        std::collections::HashMap::new()
82    }
83}
84
85impl<K: Serialize + JsonSchema, V: TomlScaffold> TomlScaffold for std::collections::BTreeMap<K, V> {
86    fn format_preferences() -> std::collections::HashMap<FieldPath, String> {
87        std::collections::HashMap::new()
88    }
89}
90
91impl<T: TomlScaffold> TomlScaffold for std::collections::HashSet<T> {
92    fn format_preferences() -> std::collections::HashMap<FieldPath, String> {
93        std::collections::HashMap::new()
94    }
95}
96
97impl<T: TomlScaffold> TomlScaffold for std::collections::BTreeSet<T> {
98    fn format_preferences() -> std::collections::HashMap<FieldPath, String> {
99        std::collections::HashMap::new()
100    }
101}
102
103impl<T: TomlScaffold> TomlScaffold for Box<T> {
104    fn format_preferences() -> std::collections::HashMap<FieldPath, String> {
105        std::collections::HashMap::new()
106    }
107}