@@ -20,18 +20,18 @@ use once_cell::sync::Lazy;
2020#[ cfg( any( feature = "dist-client" ,  feature = "dist-server" ) ) ]  
2121use  serde:: ser:: Serializer ; 
2222use  serde:: { 
23-     de:: { DeserializeOwned ,  Deserializer } , 
23+     de:: { self ,   DeserializeOwned ,  Deserializer } , 
2424    Deserialize ,  Serialize , 
2525} ; 
2626#[ cfg( test) ]  
2727use  serial_test:: serial; 
28- use  std:: collections:: HashMap ; 
2928use  std:: env; 
3029use  std:: io:: { Read ,  Write } ; 
3130use  std:: path:: { Path ,  PathBuf } ; 
3231use  std:: result:: Result  as  StdResult ; 
3332use  std:: str:: FromStr ; 
3433use  std:: sync:: Mutex ; 
34+ use  std:: { collections:: HashMap ,  fmt} ; 
3535
3636pub  use  crate :: cache:: PreprocessorCacheModeConfig ; 
3737use  crate :: errors:: * ; 
@@ -69,8 +69,50 @@ fn default_toolchain_cache_size() -> u64 {
6969    TEN_GIGS 
7070} 
7171
72+ struct  StringOrU64Visitor ; 
73+ 
74+ impl < ' de >  de:: Visitor < ' de >  for  StringOrU64Visitor  { 
75+     type  Value  = u64 ; 
76+ 
77+     fn  expecting ( & self ,  formatter :  & mut  fmt:: Formatter < ' _ > )  -> fmt:: Result  { 
78+         formatter. write_str ( "a string with size suffix (like '20G') or a u64" ) 
79+     } 
80+ 
81+     fn  visit_str < E > ( self ,  value :  & str )  -> StdResult < Self :: Value ,  E > 
82+     where 
83+         E :  de:: Error , 
84+     { 
85+         parse_size ( value) . ok_or_else ( || E :: custom ( format ! ( "Invalid size value: {}" ,  value) ) ) 
86+     } 
87+ 
88+     fn  visit_u64 < E > ( self ,  value :  u64 )  -> StdResult < Self :: Value ,  E > 
89+     where 
90+         E :  de:: Error , 
91+     { 
92+         Ok ( value) 
93+     } 
94+ 
95+     fn  visit_i64 < E > ( self ,  value :  i64 )  -> StdResult < Self :: Value ,  E > 
96+     where 
97+         E :  de:: Error , 
98+     { 
99+         if  value < 0  { 
100+             Err ( E :: custom ( "negative values not supported" ) ) 
101+         }  else  { 
102+             Ok ( value as  u64 ) 
103+         } 
104+     } 
105+ } 
106+ 
107+ fn  deserialize_size_from_str < ' de ,  D > ( deserializer :  D )  -> StdResult < u64 ,  D :: Error > 
108+ where 
109+     D :  Deserializer < ' de > , 
110+ { 
111+     deserializer. deserialize_any ( StringOrU64Visitor ) 
112+ } 
113+ 
72114pub  fn  parse_size ( val :  & str )  -> Option < u64 >  { 
73-     let  multiplier = match  val. chars ( ) . last ( )  { 
115+     let  multiplier = match  val. chars ( ) . last ( ) . map ( |v| v . to_ascii_uppercase ( ) )  { 
74116        Some ( 'K' )  => 1024 , 
75117        Some ( 'M' )  => 1024  *  1024 , 
76118        Some ( 'G' )  => 1024  *  1024  *  1024 , 
@@ -150,7 +192,7 @@ pub struct AzureCacheConfig {
150192#[ serde( default ) ]  
151193pub  struct  DiskCacheConfig  { 
152194    pub  dir :  PathBuf , 
153-     // TODO: use  deserialize_with to allow human-readable sizes in toml 
195+     # [ serde ( deserialize_with =  "deserialize_size_from_str" ) ] 
154196    pub  size :  u64 , 
155197    pub  preprocessor_cache_mode :  PreprocessorCacheModeConfig , 
156198    pub  rw_mode :  CacheModeConfig , 
@@ -517,6 +559,7 @@ pub struct DistConfig {
517559    pub  scheduler_url :  Option < String > , 
518560    pub  cache_dir :  PathBuf , 
519561    pub  toolchains :  Vec < DistToolchainConfig > , 
562+     #[ serde( deserialize_with = "deserialize_size_from_str" ) ]  
520563    pub  toolchain_cache_size :  u64 , 
521564    pub  rewrite_includes_only :  bool , 
522565} 
@@ -1211,6 +1254,7 @@ fn test_parse_size() {
12111254    assert_eq ! ( None ,  parse_size( "bogus value" ) ) ; 
12121255    assert_eq ! ( Some ( 100 ) ,  parse_size( "100" ) ) ; 
12131256    assert_eq ! ( Some ( 2048 ) ,  parse_size( "2K" ) ) ; 
1257+     assert_eq ! ( Some ( 2048 ) ,  parse_size( "2k" ) ) ; 
12141258    assert_eq ! ( Some ( 10  *  1024  *  1024 ) ,  parse_size( "10M" ) ) ; 
12151259    assert_eq ! ( Some ( TEN_GIGS ) ,  parse_size( "10G" ) ) ; 
12161260    assert_eq ! ( Some ( 1024  *  TEN_GIGS ) ,  parse_size( "10T" ) ) ; 
@@ -1644,3 +1688,33 @@ fn server_toml_parse() {
16441688        } 
16451689    ) 
16461690} 
1691+ 
1692+ #[ test]  
1693+ fn  human_units_parse ( )  { 
1694+     const  CONFIG_STR :  & str  = r#" 
1695+ [dist] 
1696+ toolchain_cache_size = "5g" 
1697+ 
1698+ [cache.disk] 
1699+ size = "7g" 
1700+ "# ; 
1701+ 
1702+     let  file_config:  FileConfig  = toml:: from_str ( CONFIG_STR ) . expect ( "Is valid toml." ) ; 
1703+     assert_eq ! ( 
1704+         file_config, 
1705+         FileConfig  { 
1706+             cache:  CacheConfigs  { 
1707+                 disk:  Some ( DiskCacheConfig  { 
1708+                     size:  7  *  1024  *  1024  *  1024 , 
1709+                     ..Default :: default ( ) 
1710+                 } ) , 
1711+                 ..Default :: default ( ) 
1712+             } , 
1713+             dist:  DistConfig  { 
1714+                 toolchain_cache_size:  5  *  1024  *  1024  *  1024 , 
1715+                 ..Default :: default ( ) 
1716+             } , 
1717+             server_startup_timeout_ms:  None , 
1718+         } 
1719+     ) ; 
1720+ } 
0 commit comments