Skip to content

Commit 922b464

Browse files
committed
Add settings.
1 parent 3809dce commit 922b464

10 files changed

Lines changed: 316 additions & 6 deletions

crates/core/src/container.rs

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::args::{PartialArg, SerdeContainerArgs, SerdeRenameArg};
22
use crate::field::Field;
3-
use crate::utils::{ImplResult, is_inheritable_attribute};
3+
use crate::utils::{ImplResult, is_inheritable_attribute, to_type_string};
44
use crate::variant::Variant;
55
use darling::FromDeriveInput;
66
use proc_macro2::TokenStream;
@@ -226,10 +226,75 @@ impl Container {
226226
}
227227
}
228228

229-
// TODO
230229
pub fn impl_full_settings(&self) -> TokenStream {
230+
let mut settings = vec![];
231+
232+
match &self.inner {
233+
ContainerInner::NamedStruct { fields } | ContainerInner::UnnamedStruct { fields } => {
234+
for field in fields {
235+
let name = if field.ident.is_some() {
236+
field.get_name()
237+
} else {
238+
field.index.to_string()
239+
};
240+
let env_key = if let Some(value) = field.get_env_var() {
241+
quote! { .env(#value) }
242+
} else {
243+
quote! {}
244+
};
245+
let nested = if field.is_nested() {
246+
let value = field.value.get_inner_type();
247+
quote! { .nested(#value::settings()) }
248+
} else {
249+
quote! {}
250+
};
251+
let type_alias = to_type_string(field.value.ty.to_token_stream());
252+
253+
settings.push(quote! {
254+
(#name.into(), ConfigSetting::new(#type_alias)
255+
#env_key
256+
#nested
257+
),
258+
});
259+
}
260+
}
261+
ContainerInner::UnnamedEnum { variants } => {
262+
for variant in variants {
263+
let name = variant.get_name();
264+
let type_alias = to_type_string(
265+
variant
266+
.values
267+
.iter()
268+
.map(|v| v.ty.to_token_stream())
269+
.collect::<Vec<_>>()
270+
.into_iter()
271+
.collect::<TokenStream>(),
272+
);
273+
274+
settings.push(quote! {
275+
(#name.into(), ConfigSetting::new(#type_alias)),
276+
});
277+
}
278+
}
279+
ContainerInner::UnitEnum { variants } => {
280+
for variant in variants {
281+
let name = variant.get_name();
282+
283+
settings.push(quote! {
284+
(#name.into(), ConfigSetting::new(#name)),
285+
});
286+
}
287+
}
288+
};
289+
231290
quote! {
232-
fn settings() -> schematic::ConfigSettingMap {}
291+
fn settings() -> schematic::ConfigSettingMap {
292+
use schematic::ConfigSetting;
293+
294+
std::collections::BTreeMap::from_iter([
295+
#(#settings)*
296+
])
297+
}
233298
}
234299
}
235300

crates/core/src/variant.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use crate::args::{NestedArg, PartialArg, SerdeContainerArgs, SerdeFieldArgs, SerdeRenameArg};
1+
use crate::args::{
2+
NestedArg, PartialArg, SerdeContainerArgs, SerdeFieldArgs, SerdeIoDirection, SerdeRenameArg,
3+
};
24
use crate::container::ContainerArgs;
35
use crate::utils::ImplResult;
46
use crate::variant_value::VariantValue;
@@ -124,6 +126,25 @@ impl Variant {
124126
}
125127
}
126128

129+
pub fn get_name(&self) -> String {
130+
let dir = SerdeIoDirection::From;
131+
132+
if let Some(name) = self.args.rename.as_ref().and_then(|rn| rn.get_name(dir)) {
133+
return name.into();
134+
}
135+
136+
if let Some(name) = self
137+
.serde_args
138+
.rename
139+
.as_ref()
140+
.and_then(|rn| rn.get_name(dir))
141+
{
142+
return name.into();
143+
}
144+
145+
self.ident.to_string()
146+
}
147+
127148
pub fn is_default(&self) -> bool {
128149
self.args.default
129150
}

crates/core/tests/container_test.rs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
mod utils;
2+
13
use schematic_core::args::*;
24
use schematic_core::container::Container;
5+
use starbase_sandbox::assert_snapshot;
36
use syn::parse_quote;
7+
use utils::pretty;
48

59
mod container {
610
use super::*;
@@ -133,3 +137,98 @@ mod container {
133137
);
134138
}
135139
}
140+
141+
mod settings {
142+
use super::*;
143+
144+
mod named_struct {
145+
use super::*;
146+
147+
#[test]
148+
fn supports() {
149+
let container = Container::from(parse_quote! {
150+
#[derive(Config)]
151+
struct Example {
152+
a: String,
153+
b: i32,
154+
#[setting(env = "C_VAR")]
155+
c: bool,
156+
d: Option<String>,
157+
e: Vec<u8>,
158+
f: std::collections::HashMap<String, String>,
159+
#[setting(nested)]
160+
g: NestedExample,
161+
}
162+
});
163+
164+
assert_snapshot!(pretty(container.impl_full_settings()));
165+
}
166+
}
167+
168+
mod unnamed_struct {
169+
use super::*;
170+
171+
#[test]
172+
fn supports() {
173+
let container = Container::from(parse_quote! {
174+
#[derive(Config)]
175+
struct Example(
176+
String,
177+
i32,
178+
#[setting(env = "C_VAR")]
179+
bool,
180+
Option<String>,
181+
Vec<u8>,
182+
std::collections::HashMap<String, String>,
183+
#[setting(nested)]
184+
NestedExample,
185+
);
186+
});
187+
188+
assert_snapshot!(pretty(container.impl_full_settings()));
189+
}
190+
}
191+
192+
mod named_enum {
193+
// N/A
194+
}
195+
196+
mod unnamed_enum {
197+
use super::*;
198+
199+
#[test]
200+
fn supports() {
201+
let container = Container::from(parse_quote! {
202+
#[derive(Config)]
203+
enum Example {
204+
A(String),
205+
B(i32),
206+
C(bool),
207+
D(Option<String>),
208+
E(Vec<u8>),
209+
F(std::collections::HashMap<String, String>),
210+
#[setting(nested)]
211+
G(NestedExample),
212+
}
213+
});
214+
215+
assert_snapshot!(pretty(container.impl_full_settings()));
216+
}
217+
}
218+
219+
mod unit_enum {
220+
use super::*;
221+
222+
#[test]
223+
fn supports() {
224+
let container = Container::from(parse_quote! {
225+
#[derive(Config)]
226+
enum Example {
227+
A, B, C
228+
}
229+
});
230+
231+
assert_snapshot!(pretty(container.impl_full_settings()));
232+
}
233+
}
234+
}

crates/core/tests/setting_transform_test.rs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,47 @@ mod setting_transform {
9797
}
9898

9999
mod unnamed_enum {
100-
// N/A
100+
use super::*;
101+
102+
#[test]
103+
fn accepts_func_ref() {
104+
let container = Container::from(parse_quote! {
105+
#[derive(Config)]
106+
enum Example {
107+
#[setting(transform = func_ref)]
108+
A(String)
109+
}
110+
});
111+
let field = container.inner.get_variants()[0];
112+
113+
assert!(field.args.transform.is_some());
114+
}
115+
116+
#[test]
117+
fn accepts_string() {
118+
let container = Container::from(parse_quote! {
119+
#[derive(Config)]
120+
enum Example {
121+
#[setting(transform = "func_ref")]
122+
A(String)
123+
}
124+
});
125+
let field = container.inner.get_variants()[0];
126+
127+
assert!(field.args.transform.is_some());
128+
}
129+
130+
#[test]
131+
#[should_panic(expected = "UnexpectedType")]
132+
fn errors_invalid_type() {
133+
Container::from(parse_quote! {
134+
#[derive(Config)]
135+
enum Example {
136+
#[setting(transform = 123)]
137+
A(String)
138+
}
139+
});
140+
}
101141
}
102142

103143
mod unit_enum {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
source: crates/core/tests/container_test.rs
3+
expression: pretty(container.impl_full_settings())
4+
---
5+
fn settings() -> schematic::ConfigSettingMap {
6+
use schematic::ConfigSetting;
7+
std::collections::BTreeMap::from_iter([
8+
("a".into(), ConfigSetting::new("String")),
9+
("b".into(), ConfigSetting::new("i32")),
10+
("c".into(), ConfigSetting::new("bool").env("C_VAR")),
11+
("d".into(), ConfigSetting::new("Option<String>")),
12+
("e".into(), ConfigSetting::new("Vec<u8>")),
13+
("f".into(), ConfigSetting::new("std::collections::HashMap<String, String>")),
14+
(
15+
"g".into(),
16+
ConfigSetting::new("NestedExample").nested(NestedExample::settings()),
17+
),
18+
])
19+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
source: crates/core/tests/container_test.rs
3+
expression: pretty(container.impl_full_settings())
4+
---
5+
fn settings() -> schematic::ConfigSettingMap {
6+
use schematic::ConfigSetting;
7+
std::collections::BTreeMap::from_iter([
8+
("A".into(), ConfigSetting::new("A")),
9+
("B".into(), ConfigSetting::new("B")),
10+
("C".into(), ConfigSetting::new("C")),
11+
])
12+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
source: crates/core/tests/container_test.rs
3+
expression: pretty(container.impl_full_settings())
4+
---
5+
fn settings() -> schematic::ConfigSettingMap {
6+
use schematic::ConfigSetting;
7+
std::collections::BTreeMap::from_iter([
8+
("A".into(), ConfigSetting::new("String")),
9+
("B".into(), ConfigSetting::new("i32")),
10+
("C".into(), ConfigSetting::new("bool")),
11+
("D".into(), ConfigSetting::new("Option<String>")),
12+
("E".into(), ConfigSetting::new("Vec<u8>")),
13+
("F".into(), ConfigSetting::new("std::collections::HashMap<String, String>")),
14+
("G".into(), ConfigSetting::new("NestedExample")),
15+
])
16+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
source: crates/core/tests/container_test.rs
3+
expression: pretty(container.impl_full_settings())
4+
---
5+
fn settings() -> schematic::ConfigSettingMap {
6+
use schematic::ConfigSetting;
7+
std::collections::BTreeMap::from_iter([
8+
("0".into(), ConfigSetting::new("String")),
9+
("1".into(), ConfigSetting::new("i32")),
10+
("2".into(), ConfigSetting::new("bool").env("C_VAR")),
11+
("3".into(), ConfigSetting::new("Option<String>")),
12+
("4".into(), ConfigSetting::new("Vec<u8>")),
13+
("5".into(), ConfigSetting::new("std::collections::HashMap<String, String>")),
14+
(
15+
"6".into(),
16+
ConfigSetting::new("NestedExample").nested(NestedExample::settings()),
17+
),
18+
])
19+
}

crates/schematic/src/config/configs.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,4 +131,24 @@ pub struct ConfigSetting {
131131
pub type_alias: String,
132132
}
133133

134+
impl ConfigSetting {
135+
pub fn new(type_alias: impl AsRef<str>) -> Self {
136+
Self {
137+
env_key: None,
138+
nested: None,
139+
type_alias: type_alias.as_ref().to_string(),
140+
}
141+
}
142+
143+
pub fn env(mut self, env_key: impl AsRef<str>) -> Self {
144+
self.env_key = Some(env_key.as_ref().to_string());
145+
self
146+
}
147+
148+
pub fn nested(mut self, nested: ConfigSettingMap) -> Self {
149+
self.nested = Some(nested);
150+
self
151+
}
152+
}
153+
134154
pub type ConfigSettingMap = BTreeMap<String, ConfigSetting>;

crates/schematic/tests/variants_test.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use schematic::*;
22
use serial_test::serial;
33
use std::collections::HashMap;
4-
use std::env;
54

65
fn test_list<T>(_: &[String], _: &T, context: &Context, _: bool) -> ValidateResult {
76
if context.fail {

0 commit comments

Comments
 (0)