1use crate::{Error, Stream};
2
3#[allow(missing_docs)]
7#[derive(Clone, Hash, Copy, PartialEq, Eq, Debug)]
8pub enum Align {
9 None,
10 XMinYMin,
11 XMidYMin,
12 XMaxYMin,
13 XMinYMid,
14 XMidYMid,
15 XMaxYMid,
16 XMinYMax,
17 XMidYMax,
18 XMaxYMax,
19}
20
21impl quote::ToTokens for Align {
22 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
23 match self {
24 Align::None => quote::quote! {Align::None},
25 Align::XMinYMin => quote::quote! {svgrtypes::Align::XMinYMin},
26 Align::XMidYMin => quote::quote! {svgrtypes::Align::XMidYMin},
27 Align::XMaxYMin => quote::quote! {svgrtypes::Align::XMaxYMin},
28 Align::XMinYMid => quote::quote! {svgrtypes::Align::XMinYMid},
29 Align::XMidYMid => quote::quote! {svgrtypes::Align::XMidYMid},
30 Align::XMaxYMid => quote::quote! {svgrtypes::Align::XMaxYMid},
31 Align::XMinYMax => quote::quote! {svgrtypes::Align::XMinYMax},
32 Align::XMidYMax => quote::quote! {svgrtypes::Align::XMidYMax},
33 Align::XMaxYMax => quote::quote! {svgrtypes::Align::XMaxYMax},
34 }
35 .to_tokens(tokens)
36 }
37}
38
39#[derive(Clone, Hash, Copy, PartialEq, Eq, Debug)]
45pub struct AspectRatio {
46 pub defer: bool,
50 pub align: Align,
52 pub slice: bool,
57}
58
59impl quote::ToTokens for AspectRatio {
60 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
61 let Self {
62 defer,
63 slice,
64 align,
65 } = self;
66
67 quote::quote! {
68 svgrtypes::AspectRatio {
69 defer: #defer,
70 slice: #slice,
71 align: #align,
72 }
73 }
74 .to_tokens(tokens)
75 }
76}
77
78impl std::str::FromStr for AspectRatio {
79 type Err = Error;
80
81 fn from_str(text: &str) -> Result<Self, Error> {
82 let mut s = Stream::from(text);
83
84 s.skip_spaces();
85
86 let defer = s.starts_with(b"defer");
87 if defer {
88 s.advance(5);
89 s.consume_byte(b' ')?;
90 s.skip_spaces();
91 }
92
93 let start = s.pos();
94 let align = s.consume_ascii_ident();
95 let align = match align {
96 "none" => Align::None,
97 "xMinYMin" => Align::XMinYMin,
98 "xMidYMin" => Align::XMidYMin,
99 "xMaxYMin" => Align::XMaxYMin,
100 "xMinYMid" => Align::XMinYMid,
101 "xMidYMid" => Align::XMidYMid,
102 "xMaxYMid" => Align::XMaxYMid,
103 "xMinYMax" => Align::XMinYMax,
104 "xMidYMax" => Align::XMidYMax,
105 "xMaxYMax" => Align::XMaxYMax,
106 _ => return Err(Error::UnexpectedData(s.calc_char_pos_at(start))),
107 };
108
109 s.skip_spaces();
110
111 let mut slice = false;
112 if !s.at_end() {
113 let start = s.pos();
114 let v = s.consume_ascii_ident();
115 match v {
116 "meet" => {}
117 "slice" => slice = true,
118 "" => {}
119 _ => return Err(Error::UnexpectedData(s.calc_char_pos_at(start))),
120 };
121 }
122
123 Ok(AspectRatio {
124 defer,
125 align,
126 slice,
127 })
128 }
129}
130
131impl Default for AspectRatio {
132 #[inline]
133 fn default() -> Self {
134 AspectRatio {
135 defer: false,
136 align: Align::XMidYMid,
137 slice: false,
138 }
139 }
140}
141
142#[rustfmt::skip]
143#[cfg(test)]
144mod tests {
145 use super::*;
146 use std::str::FromStr;
147
148 macro_rules! test {
149 ($name:ident, $text:expr, $result:expr) => (
150 #[test]
151 fn $name() {
152 let v = AspectRatio::from_str($text).unwrap();
153 assert_eq!(v, $result);
154 }
155 )
156 }
157
158 test!(parse_1, "none", AspectRatio {
159 defer: false,
160 align: Align::None,
161 slice: false,
162 });
163
164 test!(parse_2, "defer none", AspectRatio {
165 defer: true,
166 align: Align::None,
167 slice: false,
168 });
169
170 test!(parse_3, "xMinYMid", AspectRatio {
171 defer: false,
172 align: Align::XMinYMid,
173 slice: false,
174 });
175
176 test!(parse_4, "xMinYMid slice", AspectRatio {
177 defer: false,
178 align: Align::XMinYMid,
179 slice: true,
180 });
181
182 test!(parse_5, "xMinYMid meet", AspectRatio {
183 defer: false,
184 align: Align::XMinYMid,
185 slice: false,
186 });
187}