log4rs-rolling-file 0.2.0

A rolling file appender for log4rs
Documentation
use serde::de::{Deserializer, Visitor, Error};
use std::ascii::AsciiExt;

#[derive(Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Config {
    #[serde(deserialize_with = "deserialize_limit")]
    pub limit: u64,
}

fn deserialize_limit<D>(d: &mut D) -> Result<u64, D::Error>
    where D: Deserializer
{
    struct V;

    impl Visitor for V {
        type Value = u64;

        fn visit_u64<E>(&mut self, v: u64) -> Result<u64, E>
            where E: Error
        {
            Ok(v)
        }

        fn visit_i64<E>(&mut self, v: i64) -> Result<u64, E>
            where E: Error
        {
            if v < 0 {
                return Err(E::invalid_value("must be non-negative"));
            }

            Ok(v as u64)
        }

        fn visit_str<E>(&mut self, v: &str) -> Result<u64, E>
            where E: Error
        {
            let (number, unit) = match v.find(|c: char| !c.is_digit(10)) {
                Some(n) => (v[..n].trim(), Some(v[n..].trim())),
                None => (v.trim(), None),
            };

            let number = match number.parse::<u64>() {
                Ok(n) => n,
                Err(e) => return Err(E::invalid_value(&e.to_string())),
            };

            let unit = match unit {
                Some(u) => u,
                None => return Ok(number),
            };

            let number = if unit.eq_ignore_ascii_case("b") {
                Some(number)
            } else if unit.eq_ignore_ascii_case("kb") || unit.eq_ignore_ascii_case("kib") {
                number.checked_mul(1024)
            } else if unit.eq_ignore_ascii_case("mb") || unit.eq_ignore_ascii_case("mib") {
                number.checked_mul(1024 * 1024)
            } else if unit.eq_ignore_ascii_case("gb") || unit.eq_ignore_ascii_case("gib") {
                number.checked_mul(1024 * 1024 * 1024)
            } else if unit.eq_ignore_ascii_case("tb") || unit.eq_ignore_ascii_case("tib") {
                number.checked_mul(1024 * 1024 * 1024 * 1024)
            } else {
                return Err(E::invalid_value(&format!("invalid unit `{}`", unit)));
            };

            match number {
                Some(n) => Ok(n),
                None => Err(E::invalid_value("value overflowed")),
            }
        }
    }

    d.deserialize(V)
}