Skip to content

Commit a888c16

Browse files
authored
feat: handle human size prefixes (#2405)
* handle lower case size prefixes * feat: support human-readable sizes for sizes * lint * add test * improve test * fix linting
1 parent 333131e commit a888c16

File tree

1 file changed

+78
-4
lines changed

1 file changed

+78
-4
lines changed

src/config.rs

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,18 @@ use once_cell::sync::Lazy;
2020
#[cfg(any(feature = "dist-client", feature = "dist-server"))]
2121
use serde::ser::Serializer;
2222
use serde::{
23-
de::{DeserializeOwned, Deserializer},
23+
de::{self, DeserializeOwned, Deserializer},
2424
Deserialize, Serialize,
2525
};
2626
#[cfg(test)]
2727
use serial_test::serial;
28-
use std::collections::HashMap;
2928
use std::env;
3029
use std::io::{Read, Write};
3130
use std::path::{Path, PathBuf};
3231
use std::result::Result as StdResult;
3332
use std::str::FromStr;
3433
use std::sync::Mutex;
34+
use std::{collections::HashMap, fmt};
3535

3636
pub use crate::cache::PreprocessorCacheModeConfig;
3737
use 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+
72114
pub 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)]
151193
pub 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

Comments
 (0)