Skip to content

Commit 62f540a

Browse files
committed
feat: skip for derive
1 parent 31f9889 commit 62f540a

File tree

5 files changed

+56
-6
lines changed

5 files changed

+56
-6
lines changed

from-env-derive/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ syn = { version = "2.0.100", features = ["full", "parsing"] }
2020
proc-macro = true
2121

2222
[dev-dependencies]
23-
init4-bin-base = "0.2"
23+
init4-bin-base = "0.3"

from-env-derive/src/field.rs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use heck::ToPascalCase;
22
use proc_macro2::TokenStream;
33
use quote::quote;
4-
use syn::{Ident, LitStr, spanned::Spanned};
4+
use syn::{spanned::Spanned, Ident, LitStr};
55

66
/// A parsed Field of a struct
77
pub(crate) struct Field {
@@ -11,6 +11,7 @@ pub(crate) struct Field {
1111

1212
optional: bool,
1313
infallible: bool,
14+
skip: bool,
1415
desc: Option<String>,
1516

1617
_attrs: Vec<syn::Attribute>,
@@ -26,13 +27,18 @@ impl TryFrom<&syn::Field> for Field {
2627
let mut env_var = None;
2728
let mut infallible = false;
2829
let mut desc = None;
30+
let mut skip = false;
2931

3032
field
3133
.attrs
3234
.iter()
3335
.filter(|attr| attr.path().is_ident("from_env"))
3436
.for_each(|attr| {
3537
let _ = attr.parse_nested_meta(|meta| {
38+
if meta.path.is_ident("skip") {
39+
skip = true;
40+
return Ok(());
41+
}
3642
if meta.path.is_ident("optional") {
3743
optional = true;
3844
return Ok(());
@@ -68,6 +74,7 @@ impl TryFrom<&syn::Field> for Field {
6874
field_name,
6975
field_type,
7076
optional,
77+
skip,
7178
infallible,
7279
desc,
7380
_attrs: field
@@ -115,7 +122,7 @@ impl Field {
115122

116123
/// Produces the name of the enum variant for the field
117124
pub(crate) fn enum_variant_name(&self, idx: usize) -> Option<TokenStream> {
118-
if self.infallible {
125+
if self.skip || self.infallible {
119126
return None;
120127
}
121128

@@ -143,10 +150,16 @@ impl Field {
143150

144151
/// Produces the a line for the `inventory` function
145152
/// of the form
146-
/// items.push(...);
153+
/// items.push(...); // (if this is a FromEnvVar)
154+
/// or
155+
/// items.extend(...); // (if this is a FromEnv)
147156
/// or
148-
/// items.extend(...);
157+
/// // nothing if this is a skip
149158
pub(crate) fn expand_env_item_info(&self) -> TokenStream {
159+
if self.skip {
160+
return quote! {};
161+
}
162+
150163
let description = self.desc.clone().unwrap_or_default();
151164
let optional = self.optional;
152165

@@ -197,10 +210,20 @@ impl Field {
197210

198211
// // OR
199212
// let field_name = FromEnv::from_env().map_err()?;
213+
214+
// // OR
215+
// let field_name = Default::default();
216+
200217
//```
201218
let variant = self.enum_variant_name(idx);
202219
let field_name = self.field_name(idx);
203220

221+
if self.skip {
222+
return quote! {
223+
let #field_name = Default::default();
224+
};
225+
}
226+
204227
let fn_invoc = if let Some(ref env_var) = self.env_var {
205228
quote! { FromEnvVar::from_env_var(#env_var) }
206229
} else {

from-env-derive/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use proc_macro::TokenStream as Ts;
22
use proc_macro2::TokenStream;
33
use quote::quote;
4-
use syn::{DeriveInput, parse_macro_input};
4+
use syn::{parse_macro_input, DeriveInput};
55

66
mod field;
77
use field::Field;
@@ -61,6 +61,8 @@ pub fn derive(input: Ts) -> Ts {
6161
tuple_like,
6262
};
6363

64+
eprintln!("{}", input.expand_mod());
65+
6466
input.expand_mod().into()
6567
}
6668

from-env-derive/tests/macro.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ pub struct FromEnvTest {
2525
desc = "Oliver is an Option<String>"
2626
)]
2727
pub oliver: Option<String>,
28+
29+
#[from_env(skip)]
30+
memo: std::sync::OnceLock<String>,
2831
}
2932

3033
#[derive(Debug, FromEnv)]
@@ -36,6 +39,13 @@ pub struct Nested {
3639
pub from_env_test: FromEnvTest,
3740
}
3841

42+
impl FromEnvTest {
43+
/// Get the memoized value
44+
pub fn get_memo(&self) -> &str {
45+
self.memo.get_or_init(|| "hello world".to_string())
46+
}
47+
}
48+
3949
#[cfg(test)]
4050
mod test {
4151
use super::*;

src/utils/from_env.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,21 @@ use std::{convert::Infallible, env::VarError, num::ParseIntError, str::FromStr};
1212
/// occur when trying to create an instance of the struct from environment
1313
/// variables. This error type is used in the `FromEnv` trait implementation.
1414
///
15+
/// ## Attributes
16+
///
17+
/// The macro supports the following attributes:
18+
/// - `var = ""`: The name of the environment variable. This is required if the
19+
/// prop implements [`FromEnvVar`].
20+
/// - `desc`: A description of the environment variable. This is required if
21+
/// the prop implements [`FromEnvVar`].
22+
/// - `optional`: Marks the prop as optional. This is currently only used in the
23+
/// `fn inventory` function, and is informational.
24+
/// - `infallible`: Marks the prop as infallible. This means that the prop
25+
/// cannot fail to be parsed after the environment variable is loaded.
26+
/// - `skip`: Marks the prop as skipped. This means that the prop will not be
27+
/// loaded from the environment, and will be generated via
28+
/// `Default::default()` instead.
29+
///
1530
/// ## Conditions of use
1631
///
1732
/// There are a few usage requirements:

0 commit comments

Comments
 (0)