1- use crate :: args:: { PartialArg , SerdeContainerArgs , SerdeFieldArgs , SerdeRenameArg } ;
1+ use crate :: args:: {
2+ PartialArg , SerdeContainerArgs , SerdeFieldArgs , SerdeIoDirection , SerdeRenameArg ,
3+ } ;
24use crate :: container:: ContainerArgs ;
35use crate :: field_value:: FieldValue ;
46use crate :: utils:: { ImplResult , preserve_str_literal, to_type_string} ;
57use darling:: { FromAttributes , FromMeta } ;
6- use quote:: ToTokens ;
8+ use proc_macro2:: { Literal , TokenStream } ;
9+ use quote:: { ToTokens , TokenStreamExt , quote} ;
710use std:: ops:: Deref ;
811use std:: rc:: Rc ;
912use syn:: { Attribute , Expr , ExprPath , Field as NativeField , FieldMutability , Ident , Visibility } ;
@@ -154,37 +157,13 @@ impl Field {
154157 fn validate_args ( & self ) {
155158 #[ cfg( feature = "env" ) ]
156159 {
157- // env
158- if self . args . env . as_ref ( ) . is_some_and ( |key| key. is_empty ( ) ) {
159- panic ! ( "Attribute `env` cannot be empty." ) ;
160- }
161-
162- if self . args . env . is_some ( ) && self . args . env_prefix . is_some ( ) {
163- panic ! ( "Cannot use `env` and `env_prefix` together." ) ;
164- }
165-
166160 // env_prefix
167- if self
168- . args
169- . env_prefix
170- . as_ref ( )
171- . is_some_and ( |key| key. is_empty ( ) )
172- {
173- panic ! ( "Attribute `env_prefix` cannot be empty." ) ;
174- }
175-
176161 if self . args . env_prefix . is_some ( ) && self . args . nested . is_none ( ) {
177162 panic ! ( "Cannot use `env_prefix` without `nested`." ) ;
178163 }
179164 }
180165
181166 // nested
182- if self . args . nested . is_some ( ) {
183- #[ cfg( feature = "env" ) ]
184- if self . args . env . is_some ( ) {
185- panic ! ( "Cannot use `env` with `nested`, use `env_prefix` instead?" ) ;
186- }
187- }
188167
189168 #[ cfg( feature = "env" ) ]
190169 {
@@ -194,6 +173,83 @@ impl Field {
194173 }
195174 }
196175 }
176+
177+ #[ cfg( not( feature = "env" ) ) ]
178+ pub fn get_env_var ( & self ) -> Option < String > {
179+ None
180+ }
181+
182+ #[ cfg( feature = "env" ) ]
183+ pub fn get_env_var ( & self ) -> Option < String > {
184+ if self . args . env . is_some ( ) && self . args . env_prefix . is_some ( ) {
185+ panic ! ( "Cannot use `env` and `env_prefix` together." ) ;
186+ }
187+
188+ if let Some ( env_key) = & self . args . env {
189+ if env_key. is_empty ( ) {
190+ panic ! ( "Attribute `env` cannot be empty." ) ;
191+ }
192+
193+ if self . is_nested ( ) {
194+ panic ! ( "Cannot use `env` with `nested`, use `env_prefix` instead?" ) ;
195+ }
196+
197+ return Some ( env_key. to_owned ( ) ) ;
198+ }
199+
200+ if let Some ( env_prefix) = & self . container_args . env_prefix {
201+ if env_prefix. is_empty ( ) {
202+ panic ! ( "Attribute `env_prefix` cannot be empty." ) ;
203+ }
204+
205+ return Some ( format ! ( "{env_prefix}{}" , self . get_name( ) ) . to_uppercase ( ) ) ;
206+ }
207+
208+ None
209+ }
210+
211+ pub fn get_key ( & self ) -> TokenStream {
212+ self . ident
213+ . as_ref ( )
214+ . map ( |name| quote ! { #name } )
215+ . unwrap_or_else ( || {
216+ let index = Index ( self . index ) ;
217+
218+ quote ! { #index }
219+ } )
220+ }
221+
222+ pub fn get_name ( & self ) -> String {
223+ let dir = SerdeIoDirection :: From ;
224+
225+ if let Some ( name) = self . args . rename . as_ref ( ) . and_then ( |rn| rn. get_name ( dir) ) {
226+ return name. into ( ) ;
227+ }
228+
229+ if let Some ( name) = self
230+ . serde_args
231+ . rename
232+ . as_ref ( )
233+ . and_then ( |rn| rn. get_name ( dir) )
234+ {
235+ return name. into ( ) ;
236+ }
237+
238+ self . ident
239+ . as_ref ( )
240+ . expect ( "Name only usable on named fields!" )
241+ . to_string ( )
242+ }
243+
244+ pub fn is_nested ( & self ) -> bool {
245+ self . args
246+ . nested
247+ . as_ref ( )
248+ . is_some_and ( |nested| match nested {
249+ FieldNestedArg :: Detect ( inner) => * inner,
250+ FieldNestedArg :: Ident ( _) => true ,
251+ } )
252+ }
197253}
198254
199255// impl ToTokens for Field {
@@ -223,4 +279,34 @@ impl Field {
223279 pub fn impl_partial_default_value ( & self ) -> ImplResult {
224280 self . value . impl_partial_default_value ( & self . args )
225281 }
282+
283+ #[ cfg( not( feature = "env" ) ) ]
284+ pub fn impl_partial_env_value ( & self ) -> ImplResult {
285+ ImplResult :: skipped ( )
286+ }
287+
288+ #[ cfg( feature = "env" ) ]
289+ pub fn impl_partial_env_value ( & self ) -> ImplResult {
290+ if self . is_nested ( ) {
291+ return self . value . impl_partial_env_value ( & self . args , "" ) ;
292+ }
293+
294+ let Some ( env_key) = self . get_env_var ( ) else {
295+ if self . args . parse_env . is_some ( ) {
296+ panic ! ( "Cannot use `parse_env` without `env` or a parent `env_prefix`." ) ;
297+ }
298+
299+ return ImplResult :: skipped ( ) ;
300+ } ;
301+
302+ self . value . impl_partial_env_value ( & self . args , & env_key)
303+ }
304+ }
305+
306+ struct Index ( usize ) ;
307+
308+ impl ToTokens for Index {
309+ fn to_tokens ( & self , tokens : & mut TokenStream ) {
310+ tokens. append ( Literal :: usize_unsuffixed ( self . 0 ) ) ;
311+ }
226312}
0 commit comments