klavier_core/
text_input.rs

1use std::{num::{ParseFloatError, ParseIntError}, str::FromStr};
2
3use crate::{duration, location::{parse_location, Location}, percent::PercentU16, rhythm, tempo::TempoValue, velocity::Velocity};
4
5#[derive(Debug)]
6pub struct Validated<T>(pub T);
7
8#[inline]
9pub fn from_str<T, E>(s: &str) -> Result<Validated<T>, E> 
10  where Validated<T>: FromStr<Err = E>
11{
12    Validated::<T>::from_str(s)
13}
14
15#[derive(Debug)]
16pub struct TextInput<T, E> {
17    validated: Result<Validated<T>, E>,
18    buffer: String,
19}
20
21impl<T, E> TextInput<T, E>
22    where Validated<T>: FromStr<Err = E>
23{
24    pub fn from_string(s: String) -> Self {
25        let validated: Result<Validated<T>, E> = from_str(&s);
26        Self { validated, buffer: s }
27    }
28
29    pub fn mutate<R, M>(&mut self, mutator: M) -> R
30      where M: FnOnce(&mut String) -> R
31    {
32        let r = (mutator)(&mut self.buffer);
33        self.validated = from_str(&self.buffer);
34        r
35    }
36
37    #[inline]
38    pub fn input(&self) -> &str {
39        &self.buffer
40    }
41
42    #[inline]
43    pub fn validate(&self) -> &Result<Validated<T>, E> {
44        &self.validated
45    }
46}
47
48pub enum LocationParseError {
49    InvalidFormat,
50}
51
52impl FromStr for Validated<Option<Location>> {
53    type Err = LocationParseError;
54
55    fn from_str(s: &str) -> Result<Self, Self::Err> {
56        if s.is_empty() {
57            Ok(Validated(None))
58        } else {
59            match parse_location(s) {
60                Some(loc) => Ok(Validated(Some(loc))),
61                None => Err(LocationParseError::InvalidFormat),
62            }
63        }
64    }
65}
66
67impl FromStr for Validated<Option<i16>> {
68    type Err = ParseIntError;
69    
70    fn from_str(s: &str) -> Result<Self, Self::Err> {
71        if s.is_empty() {
72            Ok(Validated(None))
73        } else {
74            s.parse::<i16>().map(|i| Validated(Some(i)))
75        }
76    }
77}
78
79impl FromStr for Validated<Option<TempoValue>> {
80    type Err = ParseIntError;
81    
82    fn from_str(s: &str) -> Result<Self, Self::Err> {
83        if s.is_empty() {
84            Ok(Validated(None))
85        } else {
86            s.parse::<u16>().map(|u| Validated(Some(TempoValue::new(u))))
87        }
88    }
89}
90
91impl FromStr for Validated<Option<Velocity>> {
92    type Err = ParseIntError;
93
94    fn from_str(s: &str) -> Result<Self, Self::Err> {
95        if s.is_empty() {
96            Ok(Validated(None))
97        } else {
98            s.parse::<u8>().map(|u| Validated(Some(Velocity::new(u))))
99        }
100    }
101}
102
103impl FromStr for Validated<Option<rhythm::Numerator>> {
104    type Err = rhythm::NumeratorError;
105
106    fn from_str(s: &str) -> Result<Self, Self::Err> {
107        if s.is_empty() {
108            Ok(Validated(None))
109        } else {
110            rhythm::Numerator::from_str(s).map(|n| Validated(Some(n)))
111        }
112    }
113}
114
115#[derive(Debug)]
116pub enum DurationDenominatorError {
117    ParseIntError,
118    InvalidValue,
119}
120
121impl FromStr for Validated<Option<duration::Denominator>> {
122    type Err = DurationDenominatorError;
123
124    fn from_str(s: &str) -> Result<Self, Self::Err> {
125        if s.is_empty() {
126            Ok(Validated(None))
127        } else {
128            match s.parse::<u8>() {
129                Ok(u) => match duration::Denominator::from_value(u) {
130                    Some(d) => Ok(Validated(Some(d))),
131                    None => Err(DurationDenominatorError::InvalidValue),
132                }
133                Err(_) => Err(DurationDenominatorError::ParseIntError)
134            }
135        }
136    }
137}
138
139impl FromStr for Validated<Option<PercentU16>> {
140    type Err = ParseFloatError;
141
142    fn from_str(s: &str) -> Result<Self, Self::Err> {
143        if s.is_empty() {
144            Ok(Validated(None))
145        } else {
146            match s.parse::<f32>() {
147                Ok(pct) => Ok(Validated(Some(pct.into()))),
148                Err(e) => Err(e),
149            }
150        }
151    }
152}