synthphonia/text/formatting/
weekday.rs

1use std::collections::HashSet;
2
3use chrono::NaiveTime;
4use regex::Regex;
5
6use crate::forward::enumeration::Enumerator1;
7use crate::utils::F64;
8use crate::value::{ConstValue, Value};
9use chrono::Timelike;
10use crate::{ impl_name, impl_op1, parser::config::Config};
11
12use crate::galloc::{AllocForExactSizeIter, TryAllocForExactSizeIter};
13
14use super::FormattingOp;
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
16pub struct FormatWeekday(usize, Option<bool>);
17
18impl FormatWeekday {
19    pub fn from_config(config: &Config) -> Self {
20        Self(
21            config.get_usize("cost").unwrap_or(1),
22            config.get_bool("abbv"),
23        )
24    }
25}
26impl FormatWeekday {
27    pub fn name() -> &'static str {
28        "weekday.fmt"
29    }
30}
31impl std::fmt::Display for FormatWeekday {
32    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33        if let Some(abbv) = self.1 {
34            write!(f, "weekday.fmt #abbv:{}", abbv)
35        } else {
36            write!(f, "weekday.fmt")
37        }
38    }
39}
40
41impl Default for FormatWeekday {
42    fn default() -> Self {
43        Self::from_config(&Default::default())
44    }
45}
46
47impl Enumerator1 for FormatWeekday {
48    fn enumerate(&self, this: &'static crate::expr::ops::Op1Enum, exec: &'static crate::forward::executor::Executor, opnt: [usize; 1]) -> Result<(), ()> { Ok(()) }
49}
50
51
52impl crate::expr::ops::Op1 for FormatWeekday {
53    fn cost(&self) -> usize {
54        self.0
55    }
56    fn try_eval(&self, a1: crate::value::Value) -> (bool, crate::value::Value) {
57        match a1 {
58            crate::value::Value::Int(s1) => {
59                let a = s1.iter().map(|&s1| {
60                    if !(1..=7).contains(&s1) { return ""; }
61                    let weekday_abbv = ["", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
62                    let weekday_full = ["", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
63                    
64                    if let Some(true) = self.1 {
65                        weekday_abbv[s1 as usize]
66                    } else {
67                        weekday_full[s1 as usize]
68                    }
69                }).galloc_scollect();
70                (true, a.into())
71            }
72            _ => (false, Value::Null),
73        }
74    }
75}
76
77lazy_static::lazy_static!{
78    static ref REGEX: Regex = {
79        let weekday_literal = r"Sun(day)?|Mon(day)?|Tue(sday)?|Wed(nesday)?|Thu(r|rsday)?|Fri(day)?|Sat(urday)?";
80        Regex::new(format!(r"^{weekday_literal}").as_str()).unwrap()
81    };
82}
83
84impl FormattingOp for FormatWeekday {
85    fn format(&self, input: &'static str) -> Option<(Self, crate::value::ConstValue, &'static str)> {
86        let weekdays = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
87        let weekday_abbv = HashSet::from(["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]);
88        let weekday_full = HashSet::from(["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]);
89        if let Some(caps) = REGEX.captures(input) {
90            if caps.get(0).is_some() {
91                let m = caps.get(0).unwrap().as_str();
92                let weekday = weekdays.iter().enumerate().find(|(i, s)| ***s == caps.get(0).unwrap().as_str()[0..3]).unwrap().0 as u32 + 1;
93                let abbv = if weekday_abbv.contains(m) { Some(true) } else if weekday_full.contains(m) { Some(false) } else { None } ;
94                return Some((*self, weekday.into(), &input[caps.get(0).unwrap().as_str().len()..]))
95            }
96        }
97        None
98    }
99
100    fn union(self, other: Self) -> Option<Self> {
101        Some(Self(1, conflict(self.1, other.1)?))
102    }
103
104    fn bad_value() -> crate::value::ConstValue {
105        crate::value::ConstValue::Int(0.into())
106    }
107}
108
109fn conflict(a: Option<bool>, b: Option<bool>) -> Option<Option<bool>> {
110    match (a, b) {
111        (Some(x), Some(y)) if x != y => { None }
112        (Some(x), _) | (None, Some(x)) => { Some(Some(x)) }
113        (None, None) => { Some(None) }
114    }
115}