11//! Emitting model items (structs, enums, aliases) as token streams.
22
33use proc_macro2:: TokenStream ;
4+ use quote:: format_ident;
45use quote:: quote;
56
67use crate :: emit:: doc_attr;
78use crate :: emit:: emit_type;
89use crate :: error:: Result ;
910use crate :: ir:: Alias ;
11+ use crate :: ir:: DefaultValue ;
1012use crate :: ir:: Deprecation ;
1113use crate :: ir:: Enum ;
1214use crate :: ir:: EnumKind ;
1315use crate :: ir:: Field ;
1416use crate :: ir:: ForeignDerives ;
1517use crate :: ir:: Item ;
18+ use crate :: ir:: RustType ;
1619use crate :: ir:: StringVariant ;
1720use crate :: ir:: Struct ;
1821use crate :: ir:: UnionVariant ;
22+ use crate :: naming:: RustIdent ;
1923
2024/// The full derive set for one generated model: its serde traits, plus which of
2125/// `Debug`, `Clone`, `PartialEq` the model can carry.
@@ -169,9 +173,23 @@ pub(crate) fn emit_struct(strukt: &Struct, derives: ModelDerives) -> Result<Toke
169173 let has_serde = serde. serialize || serde. deserialize ;
170174
171175 let mut fields = Vec :: with_capacity ( strukt. fields . len ( ) ) ;
176+ let mut defaults = Vec :: new ( ) ;
172177 for field in & strukt. fields {
173- fields. push ( emit_field ( field, has_serde) ?) ;
178+ fields. push ( emit_field ( field, serde, & strukt. name ) ?) ;
179+ // Only the `Deserialize` derive reads `default`, so only it calls these
180+ // functions. Emitted beside any other derive set, they are dead code.
181+ if let ( Some ( value) , true ) = ( & field. default , serde. deserialize ) {
182+ defaults. push ( emit_default_fn ( field, value) ?) ;
183+ }
174184 }
185+ // serde needs a path to call. An associated function keeps these out of the
186+ // crate root, where every generated type lives. Field names are unique
187+ // within a struct, so the names built from them are too.
188+ let defaults = if defaults. is_empty ( ) {
189+ quote ! { }
190+ } else {
191+ quote ! { impl #name { #( #defaults) * } }
192+ } ;
175193
176194 let additional = match & strukt. additional_properties {
177195 Some ( element) => {
@@ -210,13 +228,75 @@ pub(crate) fn emit_struct(strukt: &Struct, derives: ModelDerives) -> Result<Toke
210228 #( #fields) *
211229 #additional
212230 }
231+
232+ #defaults
233+ } ) ;
234+ }
235+
236+ /// The name that serde calls to fill an absent property.
237+ fn default_fn_name ( field : & Field ) -> proc_macro2:: Ident {
238+ return format_ident ! ( "default_{}" , field. name. logical( ) ) ;
239+ }
240+
241+ /// Render the associated function behind `#[serde(default = "..")]`.
242+ fn emit_default_fn ( field : & Field , value : & DefaultValue ) -> Result < TokenStream > {
243+ let name = default_fn_name ( field) ;
244+ let ty = emit_type ( & field. ty ) ?;
245+ let expr = emit_default_value ( value, & field. ty ) ?;
246+ let doc = doc_attr ( & Some ( format ! (
247+ "The `default` the document gives `{}`." ,
248+ field. name. logical( )
249+ ) ) ) ;
250+ return Ok ( quote ! {
251+ #doc
252+ fn #name( ) -> #ty {
253+ #expr
254+ }
213255 } ) ;
214256}
215257
258+ /// Render a default as an expression of the field type.
259+ fn emit_default_value ( value : & DefaultValue , ty : & RustType ) -> Result < TokenStream > {
260+ match ty {
261+ RustType :: Option ( inner) => {
262+ let inner = emit_default_value ( value, inner) ?;
263+ return Ok ( quote ! { Some ( #inner) } ) ;
264+ }
265+ RustType :: Boxed ( inner) => {
266+ let inner = emit_default_value ( value, inner) ?;
267+ return Ok ( quote ! { Box :: new( #inner) } ) ;
268+ }
269+ _ => { }
270+ }
271+ let expr = match value {
272+ DefaultValue :: Str ( text) => quote ! { #text. to_owned( ) } ,
273+ // No suffix, so one arm serves both `i32` and `i64`. A whole number
274+ // still reads as a float where the field is one.
275+ DefaultValue :: Int ( number) => {
276+ let literal = proc_macro2:: Literal :: i64_unsuffixed ( * number) ;
277+ quote ! { #literal }
278+ }
279+ DefaultValue :: Float ( number) => {
280+ let literal = proc_macro2:: Literal :: f64_unsuffixed ( * number) ;
281+ quote ! { #literal }
282+ }
283+ DefaultValue :: Bool ( flag) => quote ! { #flag } ,
284+ DefaultValue :: Variant ( variant) => {
285+ let owner = emit_type ( ty) ?;
286+ let variant = variant. to_token ( ) ;
287+ quote ! { #owner:: #variant }
288+ }
289+ // The return type pins this to the right empty collection.
290+ DefaultValue :: Empty => quote ! { Default :: default ( ) } ,
291+ } ;
292+ return Ok ( expr) ;
293+ }
294+
216295/// Render a single struct field. When the struct derives no serde trait,
217296/// `#[serde(..)]` attributes are suppressed — without a serde derive macro in
218297/// scope they are orphaned and fail to compile.
219- fn emit_field ( field : & Field , has_serde : bool ) -> Result < TokenStream > {
298+ fn emit_field ( field : & Field , serde : SerdeDerives , owner : & RustIdent ) -> Result < TokenStream > {
299+ let has_serde = serde. serialize || serde. deserialize ;
220300 let name = field. name . to_token ( ) ;
221301 let ty = emit_type ( & field. ty ) ?;
222302 let doc = doc_attr ( & field. doc ) ;
@@ -233,6 +313,12 @@ fn emit_field(field: &Field, has_serde: bool) -> Result<TokenStream> {
233313 if omit_empty && field. ty . is_option ( ) {
234314 metas. push ( quote ! { skip_serializing_if = "Option::is_none" } ) ;
235315 }
316+ if field. default . is_some ( ) && serde. deserialize {
317+ // `to_token` keeps any `r#` prefix. A path without it does not
318+ // compile.
319+ let path = format ! ( "{}::{}" , owner. to_token( ) , default_fn_name( field) ) ;
320+ metas. push ( quote ! { default = #path } ) ;
321+ }
236322 }
237323 let serde_attr = if !has_serde || metas. is_empty ( ) {
238324 quote ! { }
@@ -324,3 +410,86 @@ fn emit_alias(alias: &Alias) -> Result<TokenStream> {
324410 pub type #name = #ty;
325411 } ) ;
326412}
413+
414+ #[ cfg( test) ]
415+ mod tests {
416+ use super :: * ;
417+ use crate :: naming:: Case ;
418+ use crate :: naming:: to_ident;
419+
420+ /// One struct, `Widget`, with one field that carries a `default`.
421+ fn widget_with_a_default ( ) -> Struct {
422+ return Struct {
423+ name : to_ident ( "Widget" , Case :: Pascal ) ,
424+ doc : None ,
425+ deprecated : None ,
426+ fields : vec ! [ Field {
427+ name: to_ident( "count" , Case :: Snake ) ,
428+ rename: None ,
429+ doc: None ,
430+ deprecated: None ,
431+ ty: RustType :: I64 ,
432+ required: false ,
433+ omit_empty: None ,
434+ serde_skip: false ,
435+ default : Some ( DefaultValue :: Int ( 10 ) ) ,
436+ } ] ,
437+ additional_properties : None ,
438+ deny_unknown_fields : false ,
439+ } ;
440+ }
441+
442+ fn rendered ( serde : SerdeDerives ) -> String {
443+ let derives = ModelDerives {
444+ serde,
445+ foreign : ForeignDerives {
446+ debug : true ,
447+ clone : true ,
448+ partial_eq : true ,
449+ } ,
450+ } ;
451+ return emit_struct ( & widget_with_a_default ( ) , derives)
452+ . expect ( "this struct renders" )
453+ . to_string ( ) ;
454+ }
455+
456+ /// Only the `Deserialize` derive reads `default`. Beside any other derive
457+ /// set the function has no caller, and the generated crate warns.
458+ #[ test]
459+ fn a_default_function_needs_the_deserialize_derive ( ) {
460+ let cases = [
461+ (
462+ SerdeDerives {
463+ serialize : true ,
464+ deserialize : true ,
465+ } ,
466+ true ,
467+ ) ,
468+ (
469+ SerdeDerives {
470+ serialize : false ,
471+ deserialize : true ,
472+ } ,
473+ true ,
474+ ) ,
475+ (
476+ SerdeDerives {
477+ serialize : true ,
478+ deserialize : false ,
479+ } ,
480+ false ,
481+ ) ,
482+ (
483+ SerdeDerives {
484+ serialize : false ,
485+ deserialize : false ,
486+ } ,
487+ false ,
488+ ) ,
489+ ] ;
490+ for ( serde, is_emitted) in cases {
491+ let code = rendered ( serde) ;
492+ assert_eq ! ( code. contains( "default_count" ) , is_emitted, "{code}" ) ;
493+ }
494+ }
495+ }
0 commit comments