@@ -110,6 +110,19 @@ pub mod tracing;
110
110
/// Logging flags to `#[command(flatten)]` into your CLI
111
111
#[ derive( clap:: Args , Debug , Clone , Copy , Default , PartialEq , Eq ) ]
112
112
#[ command( about = None , long_about = None ) ]
113
+ #[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
114
+ #[ cfg_attr(
115
+ feature = "serde" ,
116
+ serde(
117
+ from = "VerbosityFilter" ,
118
+ into = "VerbosityFilter" ,
119
+ bound( serialize = "L: Clone" )
120
+ )
121
+ ) ]
122
+ #[ cfg_attr(
123
+ feature = "serde" ,
124
+ doc = r#"This type serializes to a string representation of the log level, e.g. `"Debug"`"#
125
+ ) ]
113
126
pub struct Verbosity < L : LogLevel = ErrorLevel > {
114
127
#[ arg(
115
128
long,
@@ -245,6 +258,7 @@ pub trait LogLevel {
245
258
///
246
259
/// Used to calculate the log level and filter.
247
260
#[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
261
+ #[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
248
262
pub enum VerbosityFilter {
249
263
Off ,
250
264
Error ,
@@ -532,4 +546,65 @@ mod test {
532
546
}
533
547
}
534
548
}
549
+
550
+ #[ cfg( feature = "serde" ) ]
551
+ #[ cfg( test) ]
552
+ mod serde_tests {
553
+ use super :: * ;
554
+
555
+ use clap:: Parser ;
556
+ use serde:: { Deserialize , Serialize } ;
557
+
558
+ #[ derive( Debug , Parser , Serialize , Deserialize ) ]
559
+ struct Cli {
560
+ meaning_of_life : u8 ,
561
+ #[ command( flatten) ]
562
+ verbosity : Verbosity < InfoLevel > ,
563
+ }
564
+
565
+ #[ test]
566
+ fn serialize_toml ( ) {
567
+ let cli = Cli {
568
+ meaning_of_life : 42 ,
569
+ verbosity : Verbosity :: new ( 2 , 1 ) ,
570
+ } ;
571
+ let toml = toml:: to_string ( & cli) . unwrap ( ) ;
572
+ assert_eq ! ( toml, "meaning_of_life = 42\n verbosity = \" Debug\" \n " ) ;
573
+ }
574
+
575
+ #[ test]
576
+ fn deserialize_toml ( ) {
577
+ let toml = "meaning_of_life = 42\n verbosity = \" Debug\" \n " ;
578
+ let cli: Cli = toml:: from_str ( toml) . unwrap ( ) ;
579
+ assert_eq ! ( cli. meaning_of_life, 42 ) ;
580
+ assert_eq ! ( cli. verbosity. filter( ) , VerbosityFilter :: Debug ) ;
581
+ }
582
+
583
+ /// Tests that the `Verbosity` can be serialized and deserialized correctly from an a token.
584
+ #[ test]
585
+ fn serde_round_trips ( ) {
586
+ use serde_test:: { assert_tokens, Token } ;
587
+
588
+ for ( filter, variant) in [
589
+ ( VerbosityFilter :: Off , "Off" ) ,
590
+ ( VerbosityFilter :: Error , "Error" ) ,
591
+ ( VerbosityFilter :: Warn , "Warn" ) ,
592
+ ( VerbosityFilter :: Info , "Info" ) ,
593
+ ( VerbosityFilter :: Debug , "Debug" ) ,
594
+ ( VerbosityFilter :: Trace , "Trace" ) ,
595
+ ] {
596
+ let tokens = & [ Token :: UnitVariant {
597
+ name : "VerbosityFilter" ,
598
+ variant,
599
+ } ] ;
600
+
601
+ // `assert_tokens` checks both serialization and deserialization.
602
+ assert_tokens ( & Verbosity :: < OffLevel > :: from ( filter) , tokens) ;
603
+ assert_tokens ( & Verbosity :: < ErrorLevel > :: from ( filter) , tokens) ;
604
+ assert_tokens ( & Verbosity :: < WarnLevel > :: from ( filter) , tokens) ;
605
+ assert_tokens ( & Verbosity :: < InfoLevel > :: from ( filter) , tokens) ;
606
+ assert_tokens ( & Verbosity :: < DebugLevel > :: from ( filter) , tokens) ;
607
+ assert_tokens ( & Verbosity :: < TraceLevel > :: from ( filter) , tokens) ;
608
+ }
609
+ }
535
610
}
0 commit comments