1#[allow(unused_imports)]
59use figment::providers::{Data, Format};
60use figment::Provider;
61use serde::de::DeserializeOwned;
62
63#[allow(unused_macros)]
64macro_rules! impl_format {
65 ($name:ident $NAME:literal/$string:literal: $func:expr, $E:ty, $doc:expr) => (
66 #[doc = $doc]
67 pub struct $name;
68
69 impl Format for $name {
70 type Error = $E;
71
72 const NAME: &'static str = $NAME;
73
74 fn from_str<'de, T: DeserializeOwned>(s: &'de str) -> Result<T, $E> {
75 $func(s)
76 }
77 }
78 );
79
80 ($name:ident $NAME:literal/$string:literal: $func:expr, $E:ty) => (
81 impl_format!($name $NAME/$string: $func, $E, concat!(
82 "A ", $NAME, " [`Format`] [`Data`] provider.",
83 "\n\n",
84 "Static constructor methods on `", stringify!($name), "` return a
85 [`Data`] value with a generic marker of [`", stringify!($name), "`].
86 Thus, further use occurs via methods on [`Data`].",
87 "\n```\n",
88 "\nuse figment::providers::Format;",
89 "\nuse figment_json5::{", stringify!($name), "};",
90 "\n\n// Source directly from a source string...",
91 "\nlet provider = ", stringify!($name), r#"::string("source-string");"#,
92 "\n\n// Or read from a file on disk.",
93 "\nlet provider = ", stringify!($name), r#"::file("path-to-file");"#,
94 "\n\n// Or configured as nested (via Data::nested()):",
95 "\nlet provider = ", stringify!($name), r#"::file("path-to-file").nested();"#,
96 "\n```",
97 "\n\nSee also [`", stringify!($func), "`] for parsing details."
98 ));
99 )
100}
101
102impl_format!(Json5 "JSON5"/"json5": json5::from_str, json5::Error);
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107 use crate::Json5;
108 use figment::Figment;
109 use serde::Deserialize;
110
111 #[test]
112 fn test_json5() {
113 #[derive(Deserialize)]
114 struct Config {
115 name: String,
116 description: String,
117
118 #[serde(rename = "leadingDecimalPoint")]
119 leading_decimal_point: f64,
120
121 #[serde(rename = "andTrailing")]
122 and_trailing: f64,
123
124 #[serde(rename = "positiveSign")]
125 positive_sign: i32,
126
127 age: u32,
128 }
129
130 let config = r#"
131 {
132 // Allow comments
133 "name": "powerumc",
134 "age": 0x28, // Allow hexadecimal numbers
135 "description": "This is a \
136test config", // Allow multiline strings
137 "leadingDecimalPoint": .8675309,
138 "andTrailing": 8675309.,
139 "positiveSign": +1,
140 "address": "Seoul", // Allow trailing commas
141 }
142 "#;
143
144 let config: Config = Figment::new()
145 .merge(Json5::string(config))
146 .extract()
147 .unwrap();
148
149 assert_eq!(config.name, "powerumc");
150 assert_eq!(config.description, "This is a test config");
151 assert_eq!(config.leading_decimal_point, 0.8675309);
152 assert_eq!(config.and_trailing, 8675309.0);
153 assert_eq!(config.positive_sign, 1);
154 assert_eq!(config.age, 40);
155 }
156}