a1_notation/column/
from_str.rs

1use crate::{Column, Error, ALPHA};
2use std::str::FromStr;
3
4impl FromStr for Column {
5    type Err = Error;
6
7    fn from_str(s: &str) -> Result<Self, Self::Err> {
8        let mut absolute = false;
9        let ys = if let Some(without_abs) = s.strip_prefix('$') {
10            absolute = true;
11            without_abs
12        } else {
13            s
14        };
15
16        let mut x = 0;
17        for ch in ys.chars() {
18            let uch = ch.to_ascii_uppercase();
19            if let Some(ch_index) = ALPHA.iter().position(|&c| c == uch) {
20                x = x * 26 + ch_index + 1;
21            } else {
22                return Err(Error::parse_error(
23                    ch,
24                    format!("Invalid character in A1 notation: {s}"),
25                ));
26            }
27        }
28
29        Ok(Self { absolute, x: x - 1 })
30    }
31}
32
33#[cfg(test)]
34mod tests {
35    use super::*;
36
37    #[test]
38    fn from_str_ok() {
39        let a = Column::from_str("A").unwrap();
40        assert_eq!(a.x, 0);
41        assert!(!a.absolute);
42
43        let z = Column::from_str("Z").unwrap();
44        assert_eq!(z.x, 25);
45        assert!(!z.absolute);
46    }
47
48    #[test]
49    fn from_str_ok_absolute() {
50        let a = Column::from_str("$A").unwrap();
51        assert_eq!(a.x, 0);
52        assert!(a.absolute);
53
54        let z = Column::from_str("$Z").unwrap();
55        assert_eq!(z.x, 25);
56        assert!(z.absolute);
57    }
58
59    #[test]
60    fn from_str_err() {
61        assert!(Column::from_str("123").is_err());
62        assert!(Column::from_str("<foo>").is_err());
63    }
64}