Skip to content

Commit c2e593d

Browse files
authored
fix: infallible structs in derive macro (#58)
* fix: infallible structs in derive macro * lint: clippy
1 parent c0a2c0e commit c2e593d

File tree

4 files changed

+46
-13
lines changed

4 files changed

+46
-13
lines changed

from-env-derive/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "init4-from-env-derive"
33

44
description = "A derive macro for `init4_bin_base::FromEnv`"
5-
version = "0.1.1"
5+
version = "0.1.2"
66
edition = "2021"
77
rust-version = "1.81"
88
authors = ["init4", "James Prestwich"]
@@ -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.3"
23+
init4-bin-base = "0.9"

from-env-derive/src/field.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ impl Field {
114114
return field_name.clone();
115115
}
116116

117-
let n = format!("field_{}", idx);
117+
let n = format!("field_{idx}");
118118
syn::parse_str::<Ident>(&n)
119119
.map_err(|_| syn::Error::new(self.span, "Failed to create field name"))
120120
.unwrap()
@@ -199,7 +199,7 @@ impl Field {
199199
})
200200
}
201201

202-
pub(crate) fn expand_item_from_env(&self, err_ident: &Ident, idx: usize) -> TokenStream {
202+
pub(crate) fn expand_item_from_env(&self, err_ident: &syn::Path, idx: usize) -> TokenStream {
203203
// Produces code fo the following form:
204204
// ```rust
205205
// // EITHER

from-env-derive/src/lib.rs

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,15 +102,23 @@ impl Input {
102102
}
103103
}
104104

105-
fn error_ident(&self) -> syn::Ident {
105+
fn error_ident(&self) -> syn::Path {
106+
if self.is_infallible() {
107+
return syn::parse_str("::std::convert::Infallible").unwrap();
108+
}
109+
106110
let error_name = format!("{}EnvError", self.ident);
107-
syn::parse_str::<syn::Ident>(&error_name)
111+
syn::parse_str::<syn::Path>(&error_name)
108112
.map_err(|_| {
109113
syn::Error::new(self.ident.span(), "Failed to parse error ident").to_compile_error()
110114
})
111115
.unwrap()
112116
}
113117

118+
fn is_infallible(&self) -> bool {
119+
self.error_variants().is_empty()
120+
}
121+
114122
fn error_variants(&self) -> Vec<TokenStream> {
115123
self.fields
116124
.iter()
@@ -152,6 +160,10 @@ impl Input {
152160
let error_variant_displays = self.error_variant_displays();
153161
let error_variant_sources = self.expand_variant_sources();
154162

163+
if error_variants.is_empty() {
164+
return Default::default();
165+
}
166+
155167
quote! {
156168
#[doc = "Generated error type for [`FromEnv`] for"]
157169
#[doc = #struct_name_str]
@@ -195,6 +207,7 @@ impl Input {
195207
fn expand_impl(&self) -> TokenStream {
196208
let env_item_info = self.env_item_info();
197209
let struct_name = &self.ident;
210+
198211
let error_ident = self.error_ident();
199212

200213
let item_from_envs = self.item_from_envs();
@@ -226,16 +239,25 @@ impl Input {
226239

227240
fn expand_mod(&self) -> TokenStream {
228241
// let expanded_impl = expand_impl(input);
229-
let expanded_error = self.expand_error();
230242
let expanded_impl = self.expand_impl();
231243
let crate_name = &self.crate_name;
232-
let error_ident = self.error_ident();
233244

234245
let mod_ident =
235246
syn::parse_str::<syn::Ident>(&format!("__from_env_impls_{}", self.ident)).unwrap();
236247

248+
let expanded_error = self.expand_error();
249+
250+
let use_err = if !expanded_error.is_empty() {
251+
let error_ident = self.error_ident();
252+
quote! {
253+
pub use #mod_ident::#error_ident;
254+
}
255+
} else {
256+
quote! {}
257+
};
258+
237259
quote! {
238-
pub use #mod_ident::#error_ident;
260+
#use_err
239261
mod #mod_ident {
240262
use super::*;
241263
use #crate_name::utils::from_env::{FromEnv, FromEnvErr, FromEnvVar, EnvItemInfo};

from-env-derive/tests/macro.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
use init4_from_env_derive::FromEnv;
22

3+
// Compile check for a struct with no fallible fields (and therefore no
4+
// associated env error).
5+
#[derive(Debug, FromEnv)]
6+
pub struct InfallibleConfig {
7+
#[from_env(var = "INTERNAL", desc = "An infallible string", infallible)]
8+
pub internal: String,
9+
10+
#[from_env(var = "INTERNAL_COW", desc = "An infallible Cow<str>", infallible)]
11+
pub internal_cow: std::borrow::Cow<'static, str>,
12+
}
13+
314
#[derive(FromEnv, Debug)]
415
pub struct FromEnvTest {
516
/// This is a guy named tony
@@ -81,10 +92,10 @@ mod test {
8192
}
8293

8394
fn assert_contains(vec: &Vec<&'static EnvItemInfo>, item: &EnvItemInfo) {
84-
let item = vec.iter().find(|i| i.var == item.var).unwrap();
85-
assert_eq!(item.var, item.var);
86-
assert_eq!(item.description, item.description);
87-
assert_eq!(item.optional, item.optional);
95+
let i = vec.iter().find(|i| i.var == item.var).unwrap();
96+
assert_eq!(i.var, item.var);
97+
assert_eq!(i.description, item.description);
98+
assert_eq!(i.optional, item.optional);
8899
}
89100

90101
#[test]

0 commit comments

Comments
 (0)