Skip to content

Commit 827ca1d

Browse files
committed
Test default values.
1 parent 3938e83 commit 827ca1d

File tree

29 files changed

+841
-329
lines changed

29 files changed

+841
-329
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
##### Config
1212

13+
- Added support for unnamed tuple and newtype structs. Unnamed fields within the struct support
14+
`#[setting]`.
1315
- Added support for `#[setting(nested = NestedConfig)]` on fields, where the nested config name can
1416
be explicitly defined if we fail to detect it. This is useful for extremely complex/composed
1517
types.

crates/core/src/container.rs

Lines changed: 61 additions & 13 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::{impl_struct_default, is_inheritable_attribute};
3+
use crate::utils::{ImplResult, is_inheritable_attribute};
44
use crate::variant::Variant;
55
use darling::FromDeriveInput;
66
use proc_macro2::TokenStream;
@@ -10,11 +10,7 @@ use syn::{Attribute, Data, DeriveInput, ExprPath, Fields, Ident, Visibility};
1010

1111
// #[config()], #[schematic()]
1212
#[derive(Debug, Default, FromDeriveInput)]
13-
#[darling(
14-
default,
15-
attributes(config, schematic),
16-
supports(struct_named, enum_any)
17-
)]
13+
#[darling(default, attributes(config, schematic), supports(struct_any, enum_any))]
1814
pub struct ContainerArgs {
1915
// config
2016
pub allow_unknown_fields: bool,
@@ -208,25 +204,34 @@ impl Container {
208204
}
209205

210206
pub fn impl_partial_default_values(&self) -> TokenStream {
207+
let mut requires_internal = false;
208+
211209
let inner = match &self.inner {
212210
ContainerInner::NamedStruct { fields } => {
213211
let mut rows = vec![];
214212

215213
for field in fields {
216-
if let Some(value) = field.impl_partial_default_value() {
214+
let res = field.impl_partial_default_value();
215+
216+
if !res.no_value {
217217
let name = field.ident.as_ref().unwrap();
218+
let value = res.value;
218219

219220
rows.push(quote! {
220221
#name: #value,
221222
});
222223
}
224+
225+
if res.requires_internal {
226+
requires_internal = true;
227+
}
223228
}
224229

225230
if rows.is_empty() {
226231
return quote! {};
227232
}
228233

229-
let default_row = impl_struct_default(rows.len() != fields.len());
234+
let default_row = ImplResult::impl_struct_default(rows.len() != fields.len());
230235

231236
quote! {
232237
Ok(Some(Self {
@@ -240,14 +245,21 @@ impl Container {
240245
let mut all_none = true;
241246

242247
for field in fields {
243-
if let Some(value) = field.impl_partial_default_value() {
248+
let res = field.impl_partial_default_value();
249+
250+
if res.no_value {
251+
rows.push(quote! { None });
252+
} else {
244253
all_none = false;
254+
let value = res.value;
245255

246256
rows.push(quote! {
247257
#value
248258
});
249-
} else {
250-
rows.push(quote! { None })
259+
}
260+
261+
if res.requires_internal {
262+
requires_internal = true;
251263
}
252264
}
253265

@@ -261,12 +273,48 @@ impl Container {
261273
)))
262274
}
263275
}
264-
ContainerInner::Enum { .. } => todo!(),
265-
ContainerInner::UnitEnum { .. } => todo!(),
276+
ContainerInner::Enum { variants } | ContainerInner::UnitEnum { variants } => {
277+
let default_variants = variants
278+
.iter()
279+
.filter(|v| v.is_default())
280+
.collect::<Vec<_>>();
281+
282+
if default_variants.len() > 1 {
283+
panic!("Only 1 variant may be marked as default.");
284+
}
285+
286+
match default_variants.get(0) {
287+
Some(default_variant) => {
288+
let res = default_variant.impl_partial_default_value();
289+
290+
if res.requires_internal {
291+
requires_internal = true;
292+
}
293+
294+
if res.no_value {
295+
quote! {
296+
Ok(None)
297+
}
298+
} else {
299+
let value = res.value;
300+
301+
quote! {
302+
Ok(Some(Self::#value))
303+
}
304+
}
305+
}
306+
None => quote! {
307+
Ok(None)
308+
},
309+
}
310+
}
266311
};
267312

313+
let internal = ImplResult::impl_use_internal(requires_internal);
314+
268315
quote! {
269316
fn default_values(context: &Self::Context) -> std::result::Result<Option<Self>, schematic::ConfigError> {
317+
#internal
270318
#inner
271319
}
272320
}

crates/core/src/field.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
use crate::args::{PartialArg, SerdeContainerArgs, SerdeFieldArgs, SerdeRenameArg};
22
use crate::container::ContainerArgs;
33
use crate::field_value::FieldValue;
4-
use crate::utils::{preserve_str_literal, to_type_string};
4+
use crate::utils::{ImplResult, preserve_str_literal, to_type_string};
55
use darling::{FromAttributes, FromMeta};
6-
use proc_macro2::TokenStream;
76
use quote::ToTokens;
87
use std::ops::Deref;
98
use std::rc::Rc;
@@ -221,7 +220,7 @@ impl Field {
221220
// }
222221

223222
impl Field {
224-
pub fn impl_partial_default_value(&self) -> Option<TokenStream> {
223+
pub fn impl_partial_default_value(&self) -> ImplResult {
225224
self.value.impl_partial_default_value(&self.args)
226225
}
227226
}

crates/core/src/field_value.rs

Lines changed: 83 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use crate::field::{FieldArgs, FieldNestedArg};
2-
use crate::utils::to_type_string;
3-
use proc_macro2::TokenStream;
2+
use crate::utils::{ImplResult, to_type_string};
43
use quote::{ToTokens, format_ident, quote};
54
use syn::{Expr, GenericArgument, Ident, Lit, PathArguments, PathSegment, Type};
65

@@ -19,6 +18,7 @@ pub enum Layer {
1918

2019
#[derive(Debug)]
2120
pub struct FieldValue {
21+
pub inner_ty: Option<Type>,
2222
pub layers: Vec<Layer>,
2323
pub nested: bool,
2424
pub nested_ident: Option<Ident>,
@@ -30,7 +30,6 @@ impl FieldValue {
3030
pub fn new(ty: Type, nested_arg: Option<&FieldNestedArg>) -> Self {
3131
let mut nested = false;
3232
let mut nested_ident = None;
33-
let mut layers = vec![];
3433
let ty_string = to_type_string(ty.to_token_stream());
3534

3635
// Determine nested state
@@ -52,30 +51,37 @@ impl FieldValue {
5251
};
5352
}
5453

55-
// Extract type information
56-
if let Some(custom_ident) =
57-
extract_type_information(&ty, &mut layers, nested && nested_ident.is_none())
58-
{
59-
nested_ident = Some(custom_ident);
60-
}
61-
62-
if nested_ident.is_none() && nested {
63-
panic!(
64-
"Unable to extract the nested configuration identifier from `{ty_string}`. Try explicitly passing the identifier with `nested = ConfigName`."
65-
)
66-
}
67-
68-
let value = Self {
54+
let mut value = FieldValue {
55+
inner_ty: None,
6956
nested,
7057
nested_ident,
71-
layers,
58+
layers: vec![],
7259
ty_string,
7360
ty,
7461
};
62+
value.extract_type_information();
63+
value
64+
}
7565

76-
// dbg!(&value);
66+
pub fn extract_type_information(&mut self) {
67+
extract_type_information(&self.ty, &mut self.layers, |ty, segment| {
68+
self.inner_ty = Some(ty.to_owned());
7769

78-
value
70+
if self.nested && self.nested_ident.is_none() {
71+
self.nested_ident = Some(segment.ident.clone());
72+
}
73+
});
74+
75+
if self.nested && self.nested_ident.is_none() {
76+
panic!(
77+
"Unable to extract the nested configuration identifier from `{}`. Try explicitly passing the identifier with `nested = ConfigName`.",
78+
self.ty_string
79+
)
80+
}
81+
}
82+
83+
pub fn get_inner_type(&self) -> &Type {
84+
self.inner_ty.as_ref().unwrap_or(&self.ty)
7985
}
8086

8187
pub fn is_outer_option_wrapped(&self) -> bool {
@@ -84,11 +90,14 @@ impl FieldValue {
8490
.is_some_and(|wrapper| *wrapper == Layer::Option)
8591
}
8692

87-
pub fn impl_partial_default_value(&self, field_args: &FieldArgs) -> Option<TokenStream> {
93+
pub fn impl_partial_default_value(&self, field_args: &FieldArgs) -> ImplResult {
8894
if self.is_outer_option_wrapped() {
89-
return None;
95+
return ImplResult::skipped();
9096
};
9197

98+
let mut res = ImplResult::default();
99+
let mut wrap_with_some = false;
100+
92101
// Extract the inner value first
93102
let mut value = if let Some(nested_ident) = &self.nested_ident {
94103
if field_args.default.is_some() {
@@ -99,18 +108,32 @@ impl FieldValue {
99108
<#nested_ident as schematic::PartialConfig>::default_values(content)?
100109
}
101110
} else if let Some(expr) = &field_args.default {
111+
let ty = self.get_inner_type();
112+
102113
match expr {
103114
Expr::Array(_) | Expr::Call(_) | Expr::Macro(_) | Expr::Tuple(_) => {
115+
wrap_with_some = true;
116+
104117
quote! { #expr }
105118
}
106119
Expr::Path(func) => {
107-
quote! { schematic::internal::handle_default_result(#func(context))? }
120+
res.requires_internal = true;
121+
122+
quote! { handle_default_result(#func(context))? }
108123
}
109124
Expr::Lit(lit) => match &lit.lit {
110-
Lit::Str(string) => quote! {
111-
schematic::internal::handle_default_result(std::convert::TryFrom::try_from(#string))?
112-
},
113-
other => quote! { #other },
125+
Lit::Str(string) => {
126+
res.requires_internal = true;
127+
128+
quote! {
129+
handle_default_result(#ty::try_from(#string))?
130+
}
131+
}
132+
other => {
133+
wrap_with_some = true;
134+
135+
quote! { #other }
136+
}
114137
},
115138
invalid => {
116139
panic!(
@@ -119,40 +142,52 @@ impl FieldValue {
119142
}
120143
}
121144
} else {
145+
wrap_with_some = true;
146+
122147
quote! {
123148
Default::default()
124149
}
125150
};
126151

127152
// Then wrap with each layer
128-
for layer in self.layers.iter().rev() {
129-
value = match layer {
130-
Layer::Arc => quote! { Arc::new(#value) },
131-
Layer::Box => quote! { Box::new(#value) },
132-
Layer::Option => quote! { Some(#value) },
133-
Layer::Rc => quote! { Rc::new(#value) },
134-
Layer::Map(name) | Layer::Set(name) | Layer::Vec(name) | Layer::Unknown(name) => {
135-
let collection = format_ident!("{name}");
136-
137-
quote! { #collection::default() }
138-
}
139-
};
153+
if !self.layers.is_empty() {
154+
wrap_with_some = true;
155+
156+
for layer in self.layers.iter().rev() {
157+
value = match layer {
158+
Layer::Arc => quote! { Arc::new(#value) },
159+
Layer::Box => quote! { Box::new(#value) },
160+
Layer::Option => quote! { Some(#value) },
161+
Layer::Rc => quote! { Rc::new(#value) },
162+
Layer::Map(name)
163+
| Layer::Set(name)
164+
| Layer::Vec(name)
165+
| Layer::Unknown(name) => {
166+
let collection = format_ident!("{name}");
167+
168+
quote! { #collection::default() }
169+
}
170+
};
171+
}
140172
}
141173

142-
Some(quote! {
143-
Some(#value)
144-
})
174+
if wrap_with_some {
175+
value = quote! { Some(#value) };
176+
}
177+
178+
res.value = value;
179+
res
145180
}
146181
}
147182

148183
fn extract_type_information(
149184
ty: &Type,
150185
layers: &mut Vec<Layer>,
151-
nested_ident: bool,
152-
) -> Option<Ident> {
186+
mut on_last: impl FnMut(&Type, &PathSegment),
187+
) {
153188
// We don't need to traverse other types, just paths
154189
let Type::Path(ty_path) = ty else {
155-
return None;
190+
return;
156191
};
157192

158193
// Extract the last segment of the path, for example `Option`,
@@ -162,25 +197,22 @@ fn extract_type_information(
162197
match &last_segment.arguments {
163198
// We've reached the final segment
164199
PathArguments::None => {
165-
if nested_ident {
166-
return Some(last_segment.ident.clone());
167-
}
200+
on_last(ty, last_segment);
168201
}
169202

170203
// Attempt to drill deeper down
171204
PathArguments::AngleBracketed(args) => {
172205
extract_layer(last_segment, layers);
173206

174207
if let Some(GenericArgument::Type(inner_ty)) = args.args.last() {
175-
return extract_type_information(inner_ty, layers, nested_ident);
208+
extract_type_information(inner_ty, layers, on_last);
209+
return;
176210
}
177211
}
178212

179213
// What to do here, anything?
180214
PathArguments::Parenthesized(_) => {}
181215
};
182-
183-
None
184216
}
185217

186218
fn extract_layer(last_segment: &PathSegment, layers: &mut Vec<Layer>) {

0 commit comments

Comments
 (0)