synthphonia/text/formatting/
int.rs

1use std::cmp::max;
2
3use itertools::Format;
4use regex::Regex;
5
6use crate::forward::enumeration::Enumerator1;
7use crate::value::{ConstValue, Value};
8use crate::{ impl_name, impl_op1, parser::config::Config};
9
10use crate::galloc::{AllocForExactSizeIter, AllocForStr};
11
12use super::FormattingOp;
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14pub struct FormatInt(usize, usize);
15
16impl FormatInt {
17    pub fn from_config(config: &Config) -> Self {
18        Self(config.get_usize("cost").unwrap_or(1), config.get_usize("width").unwrap_or(1))
19    }
20    pub fn format_single(&self, value: i64) -> String {
21        if self.1 > 0 {
22            format!("{:0left$}", value, left= self.1)
23        } else { format!("{}", value) }
24    }
25    pub fn get_format(input: &str) -> Self {
26        let startzero = input.starts_with("+0") || input.starts_with("-0") || input.starts_with("0");
27        let before_dot = if startzero { input.len() } else { 0 };
28        Self(1, before_dot)
29    }
30}
31
32impl FormatInt {
33    pub fn name() ->  &'static str {
34        "int.fmt"
35    }
36}
37
38impl std::fmt::Display for FormatInt {
39    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40        write!(f, "int.fmt #left:{}", self.1)
41    }
42}
43
44impl Default for FormatInt {
45    fn default() -> Self {
46        Self::from_config(&Default::default())
47    }
48}
49
50impl Enumerator1 for FormatInt {
51    fn enumerate(&self, this: &'static crate::expr::ops::Op1Enum, exec: &'static crate::forward::executor::Executor, opnt: [usize; 1]) -> Result<(), ()> { Ok(()) }
52}
53
54crate::impl_formatop!(FormatInt, Int, |this: &FormatInt| this.0);
55
56fn conflict(a: usize, b: usize) -> Option<usize> {
57    if a > 0 && b > 0 && a != b { return None; }
58    Some(max(a, b))
59}
60
61impl FormattingOp for FormatInt {
62    fn format(&self, input: &'static str) -> Option<(Self, crate::value::ConstValue, &'static str)> {
63        let regex = Regex::new(r"^ *(\-|\+)? *\d+".to_string().as_str()).unwrap();
64        if let Some(a) = regex.find(input) {
65            let cv: ConstValue = a.as_str().parse::<i64>().ok()?.into();
66            Some((FormatInt::get_format(a.as_str()), cv, &input[a.as_str().len()..]))
67        } else { None }
68    }
69
70    fn union(self, other: Self) -> Option<Self> {
71        Some(Self(1, conflict(self.1, other.1)?))
72    }
73
74    fn bad_value() -> crate::value::ConstValue {
75        crate::value::ConstValue::Int(0)
76    }
77}