1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use crate::{Address, Column, Error, RangeOrCell, Result, Row};
use std::str::FromStr;

fn parse_str(a1: &str) -> Result<RangeOrCell> {
    if let Some((l, r)) = a1.split_once(':') {
        if l.chars().all(|c| c == '$' || c.is_ascii_digit())
            && r.chars().all(|c| c == '$' || c.is_ascii_digit())
        {
            Ok(RangeOrCell::RowRange {
                from: Row::from_str(l)?,
                to: Row::from_str(r)?,
            })
        } else if l.chars().all(|c| c == '$' || c.is_ascii_alphabetic())
            && r.chars().all(|c| c == '$' || c.is_ascii_alphabetic())
        {
            Ok(RangeOrCell::ColumnRange {
                from: Column::from_str(l)?,
                to: Column::from_str(r)?,
            })
        } else {
            Ok(RangeOrCell::Range {
                from: Address::from_str(l)?,
                to: Address::from_str(r)?,
            })
        }
    } else {
        Ok(RangeOrCell::Cell(Address::from_str(a1)?))
    }
}

impl FromStr for RangeOrCell {
    type Err = Error;

    fn from_str(a1: &str) -> Result<Self> {
        let range_strs: Vec<&str> = a1.split(',').collect();

        let count = range_strs.len();
        if count > 1 {
            let mut ranges = vec![];
            for range_str in range_strs {
                ranges.push(parse_str(range_str)?);
            }

            Ok(RangeOrCell::NonContiguous(ranges))
        } else if let Some(s) = range_strs.first() {
            parse_str(s)
        } else {
            Err(Error::parse_error(a1, "No valid A1 references found"))
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::*;
    use std::str::FromStr;

    #[test]
    fn from_str_cell() {
        assert_eq!(
            RangeOrCell::Cell(Address::new(0, 0)),
            RangeOrCell::from_str("A1").unwrap()
        );
    }

    #[test]
    fn from_str_non_contiguous() {
        assert_eq!(
            RangeOrCell::NonContiguous(vec![
                RangeOrCell::Cell(Address::new(0, 0)),
                RangeOrCell::Cell(Address::new(1, 1)),
                RangeOrCell::Range {
                    from: Address::new(0, 0),
                    to: Address::new(2, 2),
                },
            ]),
            RangeOrCell::from_str("A1,B2,A1:C3").unwrap()
        );
    }

    #[test]
    fn from_str_range() {
        assert_eq!(
            RangeOrCell::Range {
                from: Address::new(0, 0),
                to: Address::new(2, 2),
            },
            RangeOrCell::from_str("A1:C3").unwrap()
        );
    }

    #[test]
    fn from_str_row_range() {
        assert_eq!(
            RangeOrCell::RowRange {
                from: Row::new(0),
                to: Row::new(5),
            },
            RangeOrCell::from_str("1:6").unwrap()
        );
    }

    #[test]
    fn from_str_column_range() {
        assert_eq!(
            RangeOrCell::ColumnRange {
                from: Column::new(0),
                to: Column::new(2),
            },
            RangeOrCell::from_str("A:C").unwrap()
        );
    }
}