synthphonia/text/formatting/
weekday.rs1use 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}