a1_notation/column/
from_str.rs1use 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}