1use std::marker::PhantomData;
4
5use serde::{de::Visitor, ser::SerializeMap, Deserialize, Serialize};
6use serde_repr::{Deserialize_repr, Serialize_repr};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10#[serde(rename_all = "camelCase", rename = "geogebra")]
11pub struct Geogebra {
12 #[serde(rename = "@format")]
15 pub format: String,
16 #[serde(rename = "@app")]
18 pub app: String,
19 #[serde(rename = "@subApp")]
21 pub sub_app: String,
22 pub construction: Construction,
24}
25
26#[derive(Debug, Clone, Default, Serialize, Deserialize)]
28pub struct Construction {
29 #[serde(rename = "$value")]
31 pub items: Vec<ConstructionItem>,
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
36#[serde(rename_all = "camelCase")]
37pub enum ConstructionItem {
38 Element(Element),
40 Command(Command),
42 Expression(Expression),
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
48#[serde(rename_all = "camelCase")]
49pub struct Element {
50 #[serde(rename = "@type")]
52 pub type_: ElementType,
53 #[serde(rename = "@label")]
55 pub label: String,
56 pub caption: Option<Val<String>>,
58 pub label_mode: Val<LabelMode>,
60 pub show: Show,
62 pub coords: Option<Coords>,
64 pub line_style: Option<LineStyle>,
66 pub obj_color: Option<ObjColorType>,
68}
69
70#[derive(Debug, Clone, Serialize, Deserialize)]
72#[serde(rename_all = "camelCase")]
73pub enum ElementType {
74 Point,
75 Segment,
76 Line,
77 Numeric,
78 Conic,
79 Ray,
80 List,
81}
82
83#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)]
85pub struct LineStyle {
86 #[serde(rename = "@thickness")]
88 pub thickness: Option<u16>,
89 #[serde(rename = "@type")]
91 pub type_: Option<LineType>,
92 #[serde(rename = "@opacity")]
94 pub opacity: Option<f64>,
95}
96
97#[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr)]
99#[repr(u16)]
100pub enum LineType {
101 Solid = 0,
103 DashedShort = 10,
105 DashedLong = 15,
107 Dotted = 20,
109 DashedDotted = 30,
111}
112
113#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
115pub struct Val<T> {
116 #[serde(rename = "@val")]
117 pub val: T,
118}
119
120impl<T> From<T> for Val<T> {
121 fn from(value: T) -> Self {
122 Self { val: value }
123 }
124}
125
126#[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr)]
128#[repr(u8)]
129pub enum LabelMode {
130 Label,
132 LabelAndValue,
134 Value,
136 Caption,
138 CaptionAndValue,
140}
141
142#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
144pub struct Show {
145 #[serde(rename = "@object")]
147 pub object: bool,
148 #[serde(rename = "@label")]
150 pub label: bool,
151}
152
153impl Show {
154 #[must_use]
156 pub fn object() -> Self {
157 Self {
158 object: true,
159 label: false,
160 }
161 }
162
163 #[must_use]
165 pub fn label() -> Self {
166 Self {
167 object: false,
168 label: true,
169 }
170 }
171
172 #[must_use]
174 pub fn object_and_label() -> Self {
175 Self {
176 object: true,
177 label: true,
178 }
179 }
180
181 #[must_use]
183 pub fn none() -> Self {
184 Self {
185 object: false,
186 label: false,
187 }
188 }
189}
190
191#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
193pub struct Coords {
194 #[serde(rename = "@x")]
196 x: f64,
197 #[serde(rename = "@y")]
199 y: f64,
200 #[serde(rename = "@z")]
202 z: f64,
203}
204
205impl Coords {
206 #[must_use]
208 pub fn xy(x: f64, y: f64) -> Self {
209 Self { x, y, z: 1.0 }
210 }
211}
212
213#[derive(Debug, Clone, Serialize, Deserialize)]
215pub struct Command {
216 #[serde(rename = "@name")]
218 pub name: String,
219 pub input: IndexedAttrs<String>,
221 pub output: IndexedAttrs<String>,
223}
224
225#[derive(Debug, Clone)]
227pub struct IndexedAttrs<T> {
228 pub attrs: Vec<T>,
230}
231
232impl<T> From<Vec<T>> for IndexedAttrs<T> {
233 fn from(value: Vec<T>) -> Self {
234 Self { attrs: value }
235 }
236}
237
238impl<T: Serialize> Serialize for IndexedAttrs<T> {
239 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
240 where
241 S: serde::Serializer,
242 {
243 let mut s = serializer.serialize_map(Some(self.attrs.len()))?;
244
245 for (i, attr) in self.attrs.iter().enumerate() {
246 s.serialize_entry(&format!("@a{i}"), attr)?;
247 }
248
249 s.end()
250 }
251}
252
253impl<'de, T: Deserialize<'de>> Deserialize<'de> for IndexedAttrs<T> {
254 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
255 where
256 D: serde::Deserializer<'de>,
257 {
258 deserializer.deserialize_map(IndexedAttrsVisitor(PhantomData))
259 }
260}
261
262struct IndexedAttrsVisitor<T>(PhantomData<T>);
263
264impl<'de, T: Deserialize<'de>> Visitor<'de> for IndexedAttrsVisitor<T> {
265 type Value = IndexedAttrs<T>;
266
267 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
268 write!(formatter, "a map")
269 }
270
271 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
272 where
273 A: serde::de::MapAccess<'de>,
274 {
275 let mut attrs = Vec::new();
276
277 while let Some(v) = map.next_value()? {
278 attrs.push(v);
279 }
280
281 Ok(IndexedAttrs { attrs })
282 }
283}
284
285#[derive(Debug, Clone, Serialize, Deserialize)]
287pub struct Expression {
288 #[serde(rename = "@type")]
290 pub type_: ElementType,
291 #[serde(rename = "@label")]
293 pub label: String,
294 #[serde(rename = "@exp")]
296 pub exp: String,
297}
298
299#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
301pub struct ObjColorType {
302 #[serde(rename = "@r")]
304 pub r: u8,
305 #[serde(rename = "@g")]
307 pub g: u8,
308 #[serde(rename = "@b")]
310 pub b: u8,
311}