svgtypes/
directional_position.rs
1use crate::{Error, Length, LengthUnit, Stream};
5
6#[derive(Clone, Copy, PartialEq, Eq, Debug)]
8pub enum DirectionalPosition {
9 Top,
11 Center,
13 Bottom,
15 Right,
17 Left,
19}
20
21impl DirectionalPosition {
22 #[inline]
24 pub fn is_horizontal(&self) -> bool {
25 matches!(
26 self,
27 DirectionalPosition::Center | DirectionalPosition::Left | DirectionalPosition::Right
28 )
29 }
30
31 #[inline]
33 pub fn is_vertical(&self) -> bool {
34 matches!(
35 self,
36 DirectionalPosition::Center | DirectionalPosition::Top | DirectionalPosition::Bottom
37 )
38 }
39}
40
41impl From<DirectionalPosition> for Length {
42 fn from(value: DirectionalPosition) -> Self {
43 match value {
44 DirectionalPosition::Left | DirectionalPosition::Top => {
45 Length::new(0.0, LengthUnit::Percent)
46 }
47 DirectionalPosition::Right | DirectionalPosition::Bottom => {
48 Length::new(100.0, LengthUnit::Percent)
49 }
50 DirectionalPosition::Center => Length::new(50.0, LengthUnit::Percent),
51 }
52 }
53}
54
55impl std::str::FromStr for DirectionalPosition {
56 type Err = Error;
57
58 #[inline]
59 fn from_str(text: &str) -> Result<Self, Error> {
60 let mut s = Stream::from(text);
61 let dir_pos = s.parse_directional_position()?;
62
63 if !s.at_end() {
64 return Err(Error::UnexpectedData(s.calc_char_pos()));
65 }
66
67 Ok(dir_pos)
68 }
69}
70
71impl Stream<'_> {
72 pub fn parse_directional_position(&mut self) -> Result<DirectionalPosition, Error> {
74 self.skip_spaces();
75
76 if self.starts_with(b"left") {
77 self.advance(4);
78 Ok(DirectionalPosition::Left)
79 } else if self.starts_with(b"right") {
80 self.advance(5);
81 Ok(DirectionalPosition::Right)
82 } else if self.starts_with(b"top") {
83 self.advance(3);
84 Ok(DirectionalPosition::Top)
85 } else if self.starts_with(b"bottom") {
86 self.advance(6);
87 Ok(DirectionalPosition::Bottom)
88 } else if self.starts_with(b"center") {
89 self.advance(6);
90 Ok(DirectionalPosition::Center)
91 } else {
92 Err(Error::InvalidString(
93 vec![
94 self.slice_tail().to_string(),
95 "left".to_string(),
96 "right".to_string(),
97 "top".to_string(),
98 "bottom".to_string(),
99 "center".to_string(),
100 ],
101 self.calc_char_pos(),
102 ))
103 }
104 }
105}
106
107#[rustfmt::skip]
108#[cfg(test)]
109mod tests {
110 use super::*;
111 use std::str::FromStr;
112
113 macro_rules! test_p {
114 ($name:ident, $text:expr, $result:expr) => (
115 #[test]
116 fn $name() {
117 assert_eq!(DirectionalPosition::from_str($text).unwrap(), $result);
118 }
119 )
120 }
121
122 test_p!(parse_1, "left", DirectionalPosition::Left);
123 test_p!(parse_2, "right", DirectionalPosition::Right);
124 test_p!(parse_3, "center", DirectionalPosition::Center);
125 test_p!(parse_4, "top", DirectionalPosition::Top);
126 test_p!(parse_5, "bottom", DirectionalPosition::Bottom);
127
128 #[test]
129 fn parse_6() {
130 let mut s = Stream::from("left,");
131 assert_eq!(s.parse_directional_position().unwrap(), DirectionalPosition::Left);
132 }
133
134 #[test]
135 fn parse_7() {
136 let mut s = Stream::from("left ,");
137 assert_eq!(s.parse_directional_position().unwrap(), DirectionalPosition::Left);
138 }
139
140 #[test]
141 fn parse_16() {
142 let mut s = Stream::from("left center");
143 assert_eq!(s.parse_directional_position().unwrap(), DirectionalPosition::Left);
144 }
145
146 #[test]
147 fn err_1() {
148 let mut s = Stream::from("something");
149 assert_eq!(s.parse_directional_position().unwrap_err().to_string(),
150 "expected 'left', 'right', 'top', 'bottom', 'center' not 'something' at position 1");
151 }
152}