#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct MemorySize(usize);
impl MemorySize {
pub fn bytes(bytes: usize) -> MemorySize {
MemorySize(bytes)
}
pub fn kb(kb: usize) -> MemorySize {
MemorySize(kb * 1024)
}
pub fn mb(mb: usize) -> MemorySize {
MemorySize(mb * 1024 * 1024)
}
pub fn gb(gb: usize) -> MemorySize {
MemorySize(gb * 1024 * 1024 * 1024)
}
pub fn to_bytes(self) -> usize {
match self {
MemorySize(bytes) => bytes,
}
}
}
impl_interpolatable_value!(MemorySize);
impl fmt::Display for MemorySize {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let bytes = self.to_bytes();
if bytes == 0 {
write!(f, "0")
} else if bytes % (1024*1024*1024) == 0 {
write!(f, "{}g", bytes / (1024*1024*1024))
} else if bytes % (1024*1024) == 0 {
write!(f, "{}m", bytes / (1024*1024))
} else if bytes % 1024 == 0 {
write!(f, "{}k", bytes / 1024)
} else {
write!(f, "{}", bytes)
}
}
}
impl FromStr for MemorySize {
type Err = InvalidValueError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
lazy_static! {
static ref MEM_SIZE: Regex =
Regex::new("^([0-9]+)([bkmg])?$").unwrap();
}
let caps = try!(MEM_SIZE.captures(s).ok_or_else(|| {
InvalidValueError::new("memory size", s)
}));
let value: usize = caps.at(1).unwrap().parse().unwrap();
match caps.at(2) {
None | Some("b") => Ok(MemorySize::bytes(value)),
Some("k") => Ok(MemorySize::kb(value)),
Some("m") => Ok(MemorySize::mb(value)),
Some("g") => Ok(MemorySize::gb(value)),
_ => unreachable!("Unexpected error parsing MemorySize <{}>", s),
}
}
}
#[test]
fn memory_size_supports_string_serialization() {
let pairs = vec!(
(MemorySize::bytes(0), "0"),
(MemorySize::bytes(1), "1"),
(MemorySize::bytes(1023), "1023"),
(MemorySize::bytes(1024), "1k"),
(MemorySize::kb(1), "1k"),
(MemorySize::bytes(1025), "1025"),
(MemorySize::mb(1), "1m"),
(MemorySize::gb(1), "1g"),
);
for (mem_sz, s) in pairs {
assert_eq!(mem_sz.to_string(), s);
assert_eq!(mem_sz, MemorySize::from_str(s).unwrap());
}
assert_eq!(MemorySize::bytes(10), MemorySize::from_str("10b").unwrap());
}