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