1use std::str::FromStr;
2
3use anyhow::{Error, bail, format_err};
4use regex::Regex;
5use serde_derive::Serialize;
6
7use crate::url::Url;
8
9#[derive(Debug, PartialEq, Eq, Hash, Serialize, Clone, Copy)]
10pub enum EnumeratedListType {
11 Arabic,
12 LowerAlpha,
13 UpperAlpha,
14 LowerRoman,
15 UpperRoman,
16}
17
18#[derive(Debug, PartialEq, Eq, Hash, Serialize, Clone, Copy)]
19pub enum AutoFootnoteType {
20 Number,
21 Symbol,
22}
23
24#[derive(Default, Debug, PartialEq, Eq, Hash, Serialize, Clone, Copy)]
25pub enum FixedSpace {
26 Default,
27 #[default]
29 Preserve,
30}
31
32#[derive(Debug, PartialEq, Eq, Hash, Serialize, Clone, Copy)]
33pub enum AlignH {
34 Left,
35 Center,
36 Right,
37}
38#[derive(Debug, PartialEq, Eq, Hash, Serialize, Clone, Copy)]
39pub enum AlignHV {
40 Top,
41 Middle,
42 Bottom,
43 Left,
44 Center,
45 Right,
46}
47#[derive(Debug, PartialEq, Eq, Hash, Serialize, Clone, Copy)]
48pub enum AlignV {
49 Top,
50 Middle,
51 Bottom,
52}
53
54#[derive(Debug, PartialEq, Eq, Hash, Serialize, Clone, Copy)]
55pub enum TableAlignH {
56 Left,
57 Right,
58 Center,
59 Justify,
60 Char,
61}
62#[derive(Debug, PartialEq, Eq, Hash, Serialize, Clone, Copy)]
63pub enum TableBorder {
64 Top,
65 Bottom,
66 TopBottom,
67 All,
68 Sides,
69 None,
70}
71
72#[derive(Debug, PartialEq, Eq, Hash, Serialize, Clone)]
73pub struct ID(pub String);
74#[derive(Debug, PartialEq, Eq, Hash, Serialize, Clone)]
75pub struct NameToken(pub String);
76
77#[derive(Default, Debug, PartialEq, Eq, Hash, Serialize, Clone)]
81pub struct TableGroupCols(pub usize);
82
83#[derive(Debug, PartialEq, Serialize, Clone)]
85pub enum Measure {
86 Em(f64),
88 Ex(f64),
89 Mm(f64),
90 Cm(f64),
91 In(f64),
92 Px(f64),
93 Pt(f64),
94 Pc(f64),
95}
96
97impl FromStr for AlignHV {
98 type Err = Error;
99 fn from_str(s: &str) -> Result<Self, Self::Err> {
100 use self::AlignHV as A;
101 Ok(match s {
102 "top" => A::Top,
103 "middle" => A::Middle,
104 "bottom" => A::Bottom,
105 "left" => A::Left,
106 "center" => A::Center,
107 "right" => A::Right,
108 s => bail!("Invalid Alignment {}", s),
109 })
110 }
111}
112
113impl From<&str> for ID {
114 fn from(s: &str) -> Self {
115 ID(s.to_owned().replace(' ', "-"))
116 }
117}
118
119impl From<&str> for NameToken {
120 fn from(s: &str) -> Self {
121 NameToken(s.to_owned())
122 }
123}
124
125impl FromStr for Measure {
126 type Err = Error;
127 fn from_str(s: &str) -> Result<Self, Self::Err> {
128 use self::Measure as M;
129 let re =
130 Regex::new(r"(?P<float>\d+\.\d*|\.?\d+)\s*(?P<unit>em|ex|mm|cm|in|px|pt|pc)").unwrap();
131 let caps: regex::Captures = re
132 .captures(s)
133 .ok_or_else(|| format_err!("Invalid measure"))?;
134 let value: f64 = caps["float"].parse()?;
135 Ok(match &caps["unit"] {
136 "em" => M::Em(value),
137 "ex" => M::Ex(value),
138 "mm" => M::Mm(value),
139 "cm" => M::Cm(value),
140 "in" => M::In(value),
141 "px" => M::Px(value),
142 "pt" => M::Pt(value),
143 "pc" => M::Pc(value),
144 _ => unreachable!(),
145 })
146 }
147}
148
149#[cfg(test)]
150mod parse_tests {
151 use super::*;
152
153 #[test]
154 fn measure() {
155 let _a: Measure = "1.5em".parse().unwrap();
156 let _b: Measure = "20 mm".parse().unwrap();
157 let _c: Measure = ".5in".parse().unwrap();
158 let _d: Measure = "1.pc".parse().unwrap();
159 }
160}
161
162pub(crate) trait CanBeEmpty {
163 fn is_empty(&self) -> bool;
164}
165
166macro_rules! impl_cannot_be_empty {
172 ($t:ty) => {
173 impl CanBeEmpty for $t {
174 fn is_empty(&self) -> bool { false }
175 }
176 };
177 ($t:ty, $($ts:ty),*) => {
178 impl_cannot_be_empty!($t);
179 impl_cannot_be_empty!($($ts),*);
180 };
181}
182impl_cannot_be_empty!(Url);
183impl_cannot_be_empty!(TableGroupCols);
184
185impl<T> CanBeEmpty for Option<T> {
186 fn is_empty(&self) -> bool {
187 self.is_none()
188 }
189}
190
191impl<T> CanBeEmpty for Vec<T> {
192 fn is_empty(&self) -> bool {
193 self.is_empty()
194 }
195}
196
197impl CanBeEmpty for bool {
198 fn is_empty(&self) -> bool {
199 !self
200 }
201}
202
203impl CanBeEmpty for FixedSpace {
204 fn is_empty(&self) -> bool {
205 self == &FixedSpace::default()
206 }
207}