config_struct/enums.rs
1use std::path::Path;
2
3use crate::{
4 error::{Error, GenerationError},
5 files,
6 format::Format,
7 generation,
8 options::{EnumOptions},
9 validation,
10};
11
12/// Generate Rust source code defining an enum based on a map-like config file.
13///
14/// The enum variants are based on the keys of the map. The format of the
15/// config file will be auto-detected from its extension.
16///
17/// # Examples
18/// ```rust,no_run
19/// # fn main() -> Result<(), config_struct::Error> {
20/// let code = config_struct::generate_enum("map.toml", &Default::default())?;
21/// assert!(code.contains("pub struct Key"));
22/// # Ok(())
23/// # }
24/// ```
25pub fn generate_enum<P: AsRef<Path>>(
26 filepath: P,
27 options: &EnumOptions,
28) -> Result<String, Error> {
29 let path = filepath.as_ref();
30 let source = std::fs::read_to_string(path)?;
31 let output = generate_enum_from_source_with_filepath(&source, options, Some(path))?;
32
33 Ok(output)
34}
35
36/// Generate Rust source code defining an enum from a config string containing
37/// a map-like structure. The variants of the enum are based on the keys of
38/// the map.
39///
40/// The format must be specified in the provided options.
41///
42/// # Examples
43/// ```rust
44/// # fn main() -> Result<(), config_struct::Error> {
45/// use config_struct::{EnumOptions, Format};
46///
47/// let code = config_struct::generate_enum_from_source(
48/// "[KeyOne]\n[KeyTwo]\n",
49/// &EnumOptions {
50/// format: Some(Format::Toml),
51/// ..Default::default()
52/// })?;
53/// eprintln!("CODE : {}", code);
54///
55/// assert!(code.contains("pub enum Key"));
56/// assert!(code.contains("KeyOne"));
57/// assert!(code.contains("KeyTwo"));
58/// # Ok(())
59/// # }
60/// ```
61pub fn generate_enum_from_source<S: AsRef<str>>(
62 source: S,
63 options: &EnumOptions,
64) -> Result<String, GenerationError> {
65 generate_enum_from_source_with_filepath(source.as_ref(), options, None)
66}
67
68fn generate_enum_from_source_with_filepath(
69 source: &str,
70 options: &EnumOptions,
71 filepath: Option<&Path>,
72) -> Result<String, GenerationError> {
73 options.validate()?;
74
75 let format = match options.format {
76 Some(format) => format,
77 None => match filepath {
78 Some(path) => Format::from_filename(path)?,
79 None => return Err(GenerationError::UnknownInputFormat("<none>".into())),
80 }
81 };
82
83 let keys: Vec<String> = match format {
84 #[cfg(feature = "json-parsing")]
85 Format::Json => crate::json_parsing::parse_map_keys(source)?,
86
87 #[cfg(feature = "ron-parsing")]
88 Format::Ron => crate::ron_parsing::parse_map_keys(source)?,
89
90 #[cfg(feature = "toml-parsing")]
91 Format::Toml => crate::toml_parsing::parse_map_keys(source)?,
92
93 #[cfg(feature = "yaml-parsing")]
94 Format::Yaml => crate::yaml_parsing::parse_map_keys(source)?,
95 };
96
97 // TODO: Refactor
98 // TODO: Validate other identifiers
99 {
100 for key in &keys {
101 if !validation::valid_identifier(key) {
102 return Err(GenerationError::InvalidVariantName(key.into()))
103 }
104 }
105 }
106
107 let enum_code = generation::generate_enum(&keys, options);
108
109 Ok(enum_code)
110}
111
112/// Generate a Rust module containing an enum definition based on a
113/// given config file containing a map-like structure. The variants
114/// of the enum are based on the keys of the map.
115///
116/// The format of the config is auto-detected from its filename
117/// extension.
118///
119/// # Examples
120///
121/// ```rust,no_run
122/// # fn main() -> Result<(), config_struct::Error> {
123/// use config_struct::EnumOptions;
124///
125/// config_struct::create_enum("map.toml", "src/keys.rs", &EnumOptions::default())?;
126/// # Ok(())
127/// # }
128/// ```
129pub fn create_enum<SrcPath: AsRef<Path>, DstPath: AsRef<Path>>(
130 filepath: SrcPath,
131 destination: DstPath,
132 options: &EnumOptions,
133) -> Result<(), Error> {
134 let output = generate_enum(filepath, options)?;
135 files::ensure_destination(destination.as_ref(), options.create_dirs)?;
136 files::write_destination(destination.as_ref(), output, options.write_only_if_changed)?;
137
138 Ok(())
139}
140
141/// Generate a Rust module containing an enum definition based on a
142/// config string containing a map-like structure. The variants
143/// of the enum are based on the keys of the map.
144///
145/// The format of the config must be provided in the options.
146///
147/// # Examples
148///
149/// ```rust,no_run
150/// # fn main() -> Result<(), config_struct::Error> {
151/// use config_struct::{Format, StructOptions};
152///
153/// config_struct::create_struct_from_source(
154/// "number = 100 # This is valid TOML.",
155/// "src/config.rs",
156/// &StructOptions {
157/// format: Some(Format::Toml),
158/// ..Default::default()
159/// })?;
160/// # Ok(())
161/// # }
162/// ```
163pub fn create_enum_from_source<S: AsRef<str>, P: AsRef<Path>>(
164 source: S,
165 destination: P,
166 options: &EnumOptions,
167) -> Result<(), Error> {
168 let output = generate_enum_from_source(source, options)?;
169 files::ensure_destination(destination.as_ref(), options.create_dirs)?;
170 files::write_destination(destination.as_ref(), output, options.write_only_if_changed)?;
171
172 Ok(())
173}