duckling 0.4.0

A Rust port of Facebook's Duckling library for parsing natural language into structured data
Documentation
use crate::dimensions::numeral::helpers::is_natural;
use crate::pattern::{dim, predicate, regex};
use crate::types::{DimensionKind, Rule, TokenData};

use super::DurationData;

fn duration_data(td: &TokenData) -> Option<&DurationData> {
    match td {
        TokenData::Duration(d) => Some(d),
        _ => None,
    }
}

pub fn rules() -> Vec<Rule> {
    vec![
        Rule {
            name: "half of an hour".to_string(),
            pattern: vec![regex("(mitja hora|dos quarts)")],
            production: Box::new(|_| {
                Some(TokenData::Duration(DurationData::new(
                    30,
                    crate::dimensions::time_grain::Grain::Minute,
                )))
            }),
        },
        Rule {
            name: "quarter of an hour".to_string(),
            pattern: vec![regex("((1 |un )?quarts?|1/4) d'hora")],
            production: Box::new(|_| {
                Some(TokenData::Duration(DurationData::new(
                    15,
                    crate::dimensions::time_grain::Grain::Minute,
                )))
            }),
        },
        Rule {
            name: "three-quarters of an hour".to_string(),
            pattern: vec![regex("((tres|3) quarts|3/4)( d'hor([a]|(es)))?")],
            production: Box::new(|_| {
                Some(TokenData::Duration(DurationData::new(
                    45,
                    crate::dimensions::time_grain::Grain::Minute,
                )))
            }),
        },
        Rule {
            name: "composite <duration>".to_string(),
            pattern: vec![
                predicate(is_natural),
                dim(DimensionKind::TimeGrain),
                dim(DimensionKind::Duration),
            ],
            production: Box::new(|nodes| {
                let v = match &nodes[0].token_data {
                    TokenData::Numeral(n) => n.value as i64,
                    _ => return None,
                };
                let g = match &nodes[1].token_data {
                    TokenData::TimeGrain(g) => *g,
                    _ => return None,
                };
                let dd = duration_data(&nodes[2].token_data)?;
                if g <= dd.grain {
                    return None;
                }
                Some(TokenData::Duration(DurationData::new(v, g).combine(dd)?))
            }),
        },
        Rule {
            name: "composite <duration> (with and)".to_string(),
            pattern: vec![
                predicate(is_natural),
                dim(DimensionKind::TimeGrain),
                regex("i"),
                dim(DimensionKind::Duration),
            ],
            production: Box::new(|nodes| {
                let v = match &nodes[0].token_data {
                    TokenData::Numeral(n) => n.value as i64,
                    _ => return None,
                };
                let g = match &nodes[1].token_data {
                    TokenData::TimeGrain(g) => *g,
                    _ => return None,
                };
                let dd = duration_data(&nodes[3].token_data)?;
                if g <= dd.grain {
                    return None;
                }
                Some(TokenData::Duration(DurationData::new(v, g).combine(dd)?))
            }),
        },
    ]
}