gedcomx_date 0.1.0

Gedcomx Date Parser
Documentation
use super::super::Duration;
use nom::bytes::complete::tag;
use nom::character::complete::digit1;
use nom::combinator::{map_res, opt};
use nom::sequence::{terminated, Tuple};
use nom::IResult;
use std::str;

fn u32_digit(i: &str) -> IResult<&str, u32> {
    map_res(digit1, |s: &str| s.parse::<u32>())(i)
}

pub fn duration(i: &str) -> IResult<&str, Duration> {
    let p = tag("P");
    let year = opt(terminated(u32_digit, tag("Y")));
    let month = opt(terminated(u32_digit, tag("M")));
    let day = opt(terminated(u32_digit, tag("D")));

    let (remaining, (_, y, m, d, dt)) = (p, year, month, day, opt(duration_time)).parse(i)?;
    let duration_time = dt.unwrap_or((0, 0, 0));
    Ok((
        remaining,
        Duration {
            years: y.unwrap_or(0),
            months: m.unwrap_or(0),
            days: d.unwrap_or(0),
            hours: duration_time.0,
            minutes: duration_time.1,
            seconds: duration_time.2,
        },
    ))
}

fn duration_time(i: &str) -> IResult<&str, (u32, u32, u32)> {
    let t = tag("T");
    let hour = opt(terminated(u32_digit, tag("H")));
    let minute = opt(terminated(u32_digit, tag("M")));
    let second = opt(terminated(u32_digit, tag("S")));

    let (remaining, (_, h, m, s)) = (t, hour, minute, second).parse(i)?;
    Ok((remaining, (h.unwrap_or(0), m.unwrap_or(0), s.unwrap_or(0))))
}

#[cfg(test)]
mod tests {
    use super::super::super::Duration;
    use super::{duration, duration_time};

    #[test]
    fn test_duration_time() {
        assert_eq!(Ok(("", (10, 10, 10))), duration_time("T10H10M10S"));

        assert_eq!(Ok(("", (10, 10, 0))), duration_time("T10H10M0S"));

        assert_eq!(Ok(("", (10, 0, 0))), duration_time("T10H0S"));

        assert_eq!(Ok(("", (0, 0, 200))), duration_time("T200S"));

        assert!(duration_time("10H10M10S").is_err());
        assert!(duration_time("10H10S10M").is_err());
    }

    #[test]
    fn test_duration() {
        assert_eq!(
            Ok((
                "",
                Duration {
                    years: 10,
                    months: 20,
                    days: 30,
                    hours: 10,
                    minutes: 20,
                    seconds: 30,
                }
            )),
            duration("P10Y20M30DT10H20M30S")
        );

        assert_eq!(
            Ok((
                "",
                Duration {
                    years: 10,
                    months: 0,
                    days: 0,
                    hours: 10,
                    minutes: 0,
                    seconds: 0,
                }
            )),
            duration("P10YT10H0S")
        );

        assert_eq!(
            Ok((
                "",
                Duration {
                    years: 0,
                    months: 0,
                    days: 0,
                    hours: 0,
                    minutes: 1000,
                    seconds: 0,
                }
            )),
            duration("PT1000M0S")
        );

        assert_eq!(
            Ok((
                "",
                Duration {
                    years: 10,
                    months: 0,
                    days: 0,
                    hours: 0,
                    minutes: 0,
                    seconds: 0,
                }
            )),
            duration("P10YT0S")
        );

        assert_eq!(
            Ok((
                "",
                Duration {
                    years: 0,
                    months: 10,
                    days: 0,
                    hours: 0,
                    minutes: 0,
                    seconds: 0,
                }
            )),
            duration("P10MT0S")
        );

        assert_eq!(
            Ok((
                "",
                Duration {
                    years: 0,
                    months: 0,
                    days: 0,
                    hours: 0,
                    minutes: 10,
                    seconds: 0,
                }
            )),
            duration("PT10M0S")
        );

        assert!(duration("YT1000M").is_err());
    }
}