Skip to main content

geogebra_types/
raw.rs

1//! Raw GeoGebra structures.
2
3use std::marker::PhantomData;
4
5use serde::{de::Visitor, ser::SerializeMap, Deserialize, Serialize};
6use serde_repr::{Deserialize_repr, Serialize_repr};
7
8/// Top-level element representing a Geogebra workspace
9#[derive(Debug, Clone, Serialize, Deserialize)]
10#[serde(rename_all = "camelCase", rename = "geogebra")]
11pub struct Geogebra {
12    /// Format version. Schema states this attribute is deprecated, but Geogebra complains
13    /// if it's not here. Library was tested with 5.0
14    #[serde(rename = "@format")]
15    pub format: String,
16    /// Application to load this file in.
17    #[serde(rename = "@app")]
18    pub app: String,
19    /// Subapplication to load this file in.
20    #[serde(rename = "@subApp")]
21    pub sub_app: String,
22    /// The contained construction
23    pub construction: Construction,
24}
25
26/// The construction contained in the workspace
27#[derive(Debug, Clone, Default, Serialize, Deserialize)]
28pub struct Construction {
29    /// Construction's items
30    #[serde(rename = "$value")]
31    pub items: Vec<ConstructionItem>,
32}
33
34/// An item of the construction element.
35#[derive(Debug, Clone, Serialize, Deserialize)]
36#[serde(rename_all = "camelCase")]
37pub enum ConstructionItem {
38    /// An element of the construction.
39    Element(Element),
40    /// A construction command.
41    Command(Command),
42    /// An expression
43    Expression(Expression),
44}
45
46/// A construction element.
47#[derive(Debug, Clone, Serialize, Deserialize)]
48#[serde(rename_all = "camelCase")]
49pub struct Element {
50    /// Type of this element
51    #[serde(rename = "@type")]
52    pub type_: ElementType,
53    /// The element's label
54    #[serde(rename = "@label")]
55    pub label: String,
56    /// The element's caption
57    pub caption: Option<Val<String>>,
58    /// What should be displayed in place of the label
59    pub label_mode: Val<LabelMode>,
60    /// Which parts of the element should be shown
61    pub show: Show,
62    /// The element's coordinates
63    pub coords: Option<Coords>,
64    /// How to draw the line, if this is a line
65    pub line_style: Option<LineStyle>,
66    /// Color of this object
67    pub obj_color: Option<ObjColorType>,
68}
69
70/// Type of an element
71#[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/// Style of a line
84#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)]
85pub struct LineStyle {
86    /// Thickness. 5 by default
87    #[serde(rename = "@thickness")]
88    pub thickness: Option<u16>,
89    /// Stroke
90    #[serde(rename = "@type")]
91    pub type_: Option<LineType>,
92    /// Opacity of this object
93    #[serde(rename = "@opacity")]
94    pub opacity: Option<f64>,
95}
96
97/// Stroke of a line
98#[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr)]
99#[repr(u16)]
100pub enum LineType {
101    /// Solid line
102    Solid = 0,
103    /// Short dashes
104    DashedShort = 10,
105    /// Long dashes
106    DashedLong = 15,
107    /// Dots
108    Dotted = 20,
109    /// Dots and dashes
110    DashedDotted = 30,
111}
112
113/// A value in an attribute
114#[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/// What to display in place of an element's label
127#[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr)]
128#[repr(u8)]
129pub enum LabelMode {
130    /// Label
131    Label,
132    /// Label = Value
133    LabelAndValue,
134    /// Value
135    Value,
136    /// Caption
137    Caption,
138    /// Caption = Value
139    CaptionAndValue,
140}
141
142/// What parts of an element should be shown.
143#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
144pub struct Show {
145    /// Show the object itself.
146    #[serde(rename = "@object")]
147    pub object: bool,
148    /// Show the object's label
149    #[serde(rename = "@label")]
150    pub label: bool,
151}
152
153impl Show {
154    /// Show only the object
155    #[must_use]
156    pub fn object() -> Self {
157        Self {
158            object: true,
159            label: false,
160        }
161    }
162
163    /// Show only the label
164    #[must_use]
165    pub fn label() -> Self {
166        Self {
167            object: false,
168            label: true,
169        }
170    }
171
172    /// Show both the object and its label
173    #[must_use]
174    pub fn object_and_label() -> Self {
175        Self {
176            object: true,
177            label: true,
178        }
179    }
180
181    /// Show neither the object nor its label
182    #[must_use]
183    pub fn none() -> Self {
184        Self {
185            object: false,
186            label: false,
187        }
188    }
189}
190
191/// Cartesian coordinates of an element
192#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
193pub struct Coords {
194    /// X coordinate
195    #[serde(rename = "@x")]
196    x: f64,
197    /// Y coordinate
198    #[serde(rename = "@y")]
199    y: f64,
200    /// Z coordinate
201    #[serde(rename = "@z")]
202    z: f64,
203}
204
205impl Coords {
206    /// Create new coords from X and Y coordinates. Z is automatically set to 1.
207    #[must_use]
208    pub fn xy(x: f64, y: f64) -> Self {
209        Self { x, y, z: 1.0 }
210    }
211}
212
213/// A construction command.
214#[derive(Debug, Clone, Serialize, Deserialize)]
215pub struct Command {
216    /// The name of the command
217    #[serde(rename = "@name")]
218    pub name: String,
219    /// Command inputs
220    pub input: IndexedAttrs<String>,
221    /// Command outputs
222    pub output: IndexedAttrs<String>,
223}
224
225/// Helper for Geogebra's `a1`, `a2`, `a3` attributes in io.
226#[derive(Debug, Clone)]
227pub struct IndexedAttrs<T> {
228    /// Attributes
229    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/// A Geogebra expression
286#[derive(Debug, Clone, Serialize, Deserialize)]
287pub struct Expression {
288    /// Type of this expression
289    #[serde(rename = "@type")]
290    pub type_: ElementType,
291    /// Label of this expression
292    #[serde(rename = "@label")]
293    pub label: String,
294    /// The expression itself
295    #[serde(rename = "@exp")]
296    pub exp: String,
297}
298
299/// Color in Geogebra
300#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
301pub struct ObjColorType {
302    /// The red channel
303    #[serde(rename = "@r")]
304    pub r: u8,
305    /// The green channel
306    #[serde(rename = "@g")]
307    pub g: u8,
308    /// The blue channel
309    #[serde(rename = "@b")]
310    pub b: u8,
311}