File tree 3 files changed +58
-5
lines changed
3 files changed +58
-5
lines changed Original file line number Diff line number Diff line change @@ -66,15 +66,18 @@ pub fn from_env_with_parser<T, E: std::error::Error + Send + Sync + 'static>(
66
66
parse : fn ( & str ) -> Result < T , E > ,
67
67
) -> Result < Option < T > , Error > {
68
68
let v = get_env_var ! ( key, field) ;
69
- parse ( & v)
70
- . map ( Some )
71
- . map_err ( |err| {
69
+ let is_empty = v. is_empty ( ) ;
70
+ match parse ( & v) {
71
+ Ok ( v) => Ok ( Some ( v) ) ,
72
+ Err ( _) if is_empty => Ok ( None ) ,
73
+ Err ( err) => Err (
72
74
ErrorInner :: EnvParseError {
73
75
field : field. to_owned ( ) ,
74
76
key : key. to_owned ( ) ,
75
77
err : Box :: new ( err) ,
76
78
} . into ( )
77
- } )
79
+ ) ,
80
+ }
78
81
}
79
82
80
83
pub fn from_env_with_deserializer < T > (
@@ -83,9 +86,11 @@ pub fn from_env_with_deserializer<T>(
83
86
deserialize : fn ( crate :: env:: Deserializer ) -> Result < T , crate :: env:: DeError > ,
84
87
) -> Result < Option < T > , Error > {
85
88
let s = get_env_var ! ( key, field) ;
89
+ let is_empty = s. is_empty ( ) ;
86
90
87
91
match deserialize ( crate :: env:: Deserializer :: new ( s) ) {
88
92
Ok ( v) => Ok ( Some ( v) ) ,
93
+ Err ( _) if is_empty => Ok ( None ) ,
89
94
Err ( e) => Err ( ErrorInner :: EnvDeserialization {
90
95
key : key. into ( ) ,
91
96
field : field. into ( ) ,
Original file line number Diff line number Diff line change @@ -337,6 +337,9 @@ pub use crate::{
337
337
/// Assigns an environment variable to this field. In [`Partial::from_env`], the
338
338
/// variable is checked and deserialized into the field if present.
339
339
///
340
+ /// If the env var is set to an empty string and if the field fails to
341
+ /// parse/deserialize from it, it is treated as unset.
342
+ ///
340
343
/// ### `parse_env`
341
344
///
342
345
/// ```ignore
Original file line number Diff line number Diff line change 1
1
use serde:: Deserialize ;
2
- use confique:: { Config } ;
2
+ use confique:: { Config , Partial } ;
3
+ use pretty_assertions:: assert_eq;
3
4
4
5
#[ derive( Debug , Deserialize ) ]
5
6
enum Foo { A , B , C }
@@ -17,3 +18,47 @@ fn enum_env() {
17
18
let conf = Conf :: builder ( ) . env ( ) . load ( ) ;
18
19
assert ! ( matches!( conf, Ok ( Conf { foo: Foo :: B } ) ) ) ;
19
20
}
21
+
22
+ fn my_parser ( s : & str ) -> Result < u32 , impl std:: error:: Error > {
23
+ s. trim ( ) . parse ( )
24
+ }
25
+
26
+ #[ test]
27
+ fn empty_error_is_unset ( ) {
28
+ #[ derive( Config ) ]
29
+ #[ config( partial_attr( derive( PartialEq , Debug ) ) ) ]
30
+ #[ allow( dead_code) ]
31
+ struct Conf {
32
+ #[ config( env = "EMPTY_ERROR_IS_UNSET_FOO" ) ]
33
+ foo : u32 ,
34
+
35
+ #[ config( env = "EMPTY_ERROR_IS_UNSET_BAR" , parse_env = my_parser) ]
36
+ bar : u32 ,
37
+
38
+ #[ config( env = "EMPTY_ERROR_IS_UNSET_BAZ" ) ]
39
+ baz : String ,
40
+ }
41
+
42
+ type Partial = <Conf as Config >:: Partial ;
43
+
44
+ std:: env:: set_var ( "EMPTY_ERROR_IS_UNSET_FOO" , "" ) ;
45
+ assert_eq ! ( Partial :: from_env( ) . unwrap( ) , Partial {
46
+ foo: None ,
47
+ bar: None ,
48
+ baz: None ,
49
+ } ) ;
50
+
51
+ std:: env:: set_var ( "EMPTY_ERROR_IS_UNSET_BAR" , "" ) ;
52
+ assert_eq ! ( Partial :: from_env( ) . unwrap( ) , Partial {
53
+ foo: None ,
54
+ bar: None ,
55
+ baz: None ,
56
+ } ) ;
57
+
58
+ std:: env:: set_var ( "EMPTY_ERROR_IS_UNSET_BAZ" , "" ) ;
59
+ assert_eq ! ( Partial :: from_env( ) . unwrap( ) , Partial {
60
+ foo: None ,
61
+ bar: None ,
62
+ baz: Some ( "" . into( ) ) ,
63
+ } ) ;
64
+ }
You can’t perform that action at this time.
0 commit comments