1 | use crate::{Error, Length, LengthUnit, Stream}; |
2 | |
3 | /// List of all SVG directional positions. |
4 | #[derive (Clone, Copy, PartialEq, Eq, Debug)] |
5 | pub 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 | |
18 | impl 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 | |
42 | impl 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 | |
56 | impl 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 | |
72 | impl<'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)] |
110 | mod 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 | |