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