Skip to main content

console_entry_config/
console_entry_config.rs

1//! A simple console example that lets the user pick from a few different
2//! scenarios that have set configurations that are relevant to the scenario.
3//! This is meant to be a quick way to see how different configurations can be
4//! used in different contexts within the same project.
5//! Run with: `cargo run --example console_entry_config`
6
7use std::io::{self, BufRead, Write};
8
9use partial_date::models::{
10    Century, ComponentOrder, Config, DateComponent, DayConfig, IsExpected, MonthConfig,
11    SlidingWindowPivot, TwoDigitYearExpansion, YearConfig,
12};
13
14fn main() {
15    println!("Partial Date Extraction Examples");
16    println!("===============================\n");
17
18    println!("Welcome to this interactive console example of how the library can be used!");
19
20    let stdin = io::stdin();
21    let mut stdout = io::stdout();
22    'scenario: loop {
23        println!("Select a scenario:");
24        println!("  1) StrictDMY");
25        println!("  2) AllHistoricalDates");
26        println!("  3) IndustrialRevolutionDates");
27        println!("  4) ChildrenBirthdays");
28        println!("  (quit to exit)");
29        print!("> ");
30        stdout.flush().unwrap();
31        let mut choice = String::new();
32        stdin.lock().read_line(&mut choice).unwrap();
33        let config_preset = match choice.trim() {
34            "1" => PreDefinedConfigs::StrictDMY,
35            "2" => PreDefinedConfigs::AllHistoricalDates,
36            "3" => PreDefinedConfigs::IndustrialRevolutionDates,
37            "4" => PreDefinedConfigs::ChildrenBirthdays,
38            "quit" => break 'scenario,
39            _ => {
40                println!("Unknown option.\n");
41                continue 'scenario;
42            }
43        };
44        loop {
45            print!("Enter a date (or 'back' / 'quit'): ");
46            stdout.flush().unwrap();
47            let mut input = String::new();
48            stdin.lock().read_line(&mut input).unwrap();
49            match input.trim() {
50                "quit" => break 'scenario,
51                "back" => break,
52                text => {
53                    let result = partial_date::extract::extract(partial_date::models::Input {
54                        utterance: text.to_string(),
55                        config: Some(config_preset.get_config()),
56                    });
57                    println!("  Day:   {:?}", result.day.value);
58                    println!("  Month: {:?}", result.month.number);
59                    println!("  Year:  {:?}\n", result.year.value);
60                }
61            }
62        }
63    }
64    println!("Goodbye!");
65}
66
67pub enum PreDefinedConfigs {
68    StrictDMY,
69    AllHistoricalDates,
70    IndustrialRevolutionDates,
71    ChildrenBirthdays,
72}
73
74impl PreDefinedConfigs {
75    pub fn get_config(&self) -> Config {
76        match self {
77            // Strictly day-first numeric dates with all three components
78            // required. Letter-O substitution is disabled since this scenario
79            // expects clean numeric input only.
80            PreDefinedConfigs::StrictDMY => Config::default()
81                .with_day(
82                    DayConfig::default()
83                        .with_expected(IsExpected::Yes),
84                )
85                .with_month(
86                    MonthConfig::default()
87                        .with_expected(IsExpected::Yes)
88                )
89                .with_year(
90                    YearConfig::default()
91                        .with_range(1, 3000)
92                        .with_expected(IsExpected::Yes)
93                        .with_two_digit_expansion(TwoDigitYearExpansion::Literal),
94                )
95                .with_component_order(
96                    ComponentOrder::new(
97                        DateComponent::Day,
98                        DateComponent::Month,
99                        DateComponent::Year,
100                    )
101                    .unwrap(),
102                )
103                .with_letter_o_substitution(false),
104
105            // Wide ranging historical dates that cannot use 2-digit year
106            // expansion as there is no way to know which centuries the dates
107            // will be from. Minimal assumptions about the data when there is
108            // a lot of uncertainty.
109            PreDefinedConfigs::AllHistoricalDates => Config::default().with_year(
110                YearConfig::default()
111                    .with_range(1, 3000)
112                    .with_expected(IsExpected::Yes)
113                    .with_two_digit_expansion(TwoDigitYearExpansion::Literal),
114            ),
115
116            // Constrains the year range to the Industrial Revolution period and
117            // uses a sliding window for 2-digit years centred on 1800.
118            // Component order matches Great Britain's common DD/MM/YYYY format.
119            PreDefinedConfigs::IndustrialRevolutionDates => Config::default()
120                .with_year(
121                    YearConfig::default()
122                        .with_range(1760, 1840)
123                        .with_expected(IsExpected::Yes)
124                        .with_two_digit_expansion(TwoDigitYearExpansion::SlidingWindow {
125                            earliest_year: 1750,
126                            pivot: SlidingWindowPivot::new(50),
127                        }),
128                )
129                .with_component_order(
130                    ComponentOrder::new(
131                        DateComponent::Day,
132                        DateComponent::Month,
133                        DateComponent::Year,
134                    )
135                    .unwrap(),
136                ),
137
138            // Children under 18 — birth years must be in the 2000s and not in
139            // the future. Always(Century(2000)) maps all 2-digit values to the
140            // 2000s; the max of 2026 rejects future years.
141            PreDefinedConfigs::ChildrenBirthdays => Config::default().with_year(
142                YearConfig::default()
143                    .with_range(2000, 2026)
144                    .with_expected(IsExpected::Yes)
145                    .with_two_digit_expansion(TwoDigitYearExpansion::Always(Century::new(2000)))
146                    .with_single_digit_expansion(true),
147            ),
148        }
149    }
150}