1 | // Copyright 2023 the SVG Types Authors |
2 | // SPDX-License-Identifier: Apache-2.0 OR MIT |
3 | |
4 | use crate::{Error, Length, LengthUnit, Stream}; |
5 | |
6 | /// List of all SVG directional positions. |
7 | #[derive (Clone, Copy, PartialEq, Eq, Debug)] |
8 | pub enum DirectionalPosition { |
9 | /// The `top` position. |
10 | Top, |
11 | /// The `center` position. |
12 | Center, |
13 | /// The `bottom` position. |
14 | Bottom, |
15 | /// The `right` position. |
16 | Right, |
17 | /// The `left` position. |
18 | Left, |
19 | } |
20 | |
21 | impl DirectionalPosition { |
22 | /// Checks whether the value can be a horizontal position. |
23 | #[inline ] |
24 | pub fn is_horizontal(&self) -> bool { |
25 | matches!( |
26 | self, |
27 | DirectionalPosition::Center | DirectionalPosition::Left | DirectionalPosition::Right |
28 | ) |
29 | } |
30 | |
31 | /// Checks whether the value can be a vertical position. |
32 | #[inline ] |
33 | pub fn is_vertical(&self) -> bool { |
34 | matches!( |
35 | self, |
36 | DirectionalPosition::Center | DirectionalPosition::Top | DirectionalPosition::Bottom |
37 | ) |
38 | } |
39 | } |
40 | |
41 | impl From<DirectionalPosition> for Length { |
42 | fn from(value: DirectionalPosition) -> Self { |
43 | match value { |
44 | DirectionalPosition::Left | DirectionalPosition::Top => { |
45 | Length::new(number:0.0, unit:LengthUnit::Percent) |
46 | } |
47 | DirectionalPosition::Right | DirectionalPosition::Bottom => { |
48 | Length::new(number:100.0, unit:LengthUnit::Percent) |
49 | } |
50 | DirectionalPosition::Center => Length::new(number:50.0, unit:LengthUnit::Percent), |
51 | } |
52 | } |
53 | } |
54 | |
55 | impl 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<'_> = Stream::from(text); |
61 | let dir_pos: DirectionalPosition = 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 | |
71 | impl Stream<'_> { |
72 | /// Parses a directional position [`left`, `center`, `right`, `bottom`, `top`] from the stream. |
73 | 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)] |
109 | mod 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 | } |
153 | |