use std::marker::PhantomData;
use serde::{de::Visitor, ser::SerializeMap, Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", rename = "geogebra")]
pub struct Geogebra {
#[serde(rename = "@format")]
pub format: String,
#[serde(rename = "@app")]
pub app: String,
#[serde(rename = "@subApp")]
pub sub_app: String,
pub construction: Construction,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Construction {
#[serde(rename = "$value")]
pub items: Vec<ConstructionItem>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum ConstructionItem {
Element(Element),
Command(Command),
Expression(Expression),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Element {
#[serde(rename = "@type")]
pub type_: ElementType,
#[serde(rename = "@label")]
pub label: String,
pub caption: Option<Val<String>>,
pub label_mode: Val<LabelMode>,
pub show: Show,
pub coords: Option<Coords>,
pub line_style: Option<LineStyle>,
pub obj_color: Option<ObjColorType>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum ElementType {
Point,
Segment,
Line,
Numeric,
Conic,
Ray,
List,
}
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)]
pub struct LineStyle {
#[serde(rename = "@thickness")]
pub thickness: Option<u16>,
#[serde(rename = "@type")]
pub type_: Option<LineType>,
#[serde(rename = "@opacity")]
pub opacity: Option<f64>,
}
#[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr)]
#[repr(u16)]
pub enum LineType {
Solid = 0,
DashedShort = 10,
DashedLong = 15,
Dotted = 20,
DashedDotted = 30,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct Val<T> {
#[serde(rename = "@val")]
pub val: T,
}
impl<T> From<T> for Val<T> {
fn from(value: T) -> Self {
Self { val: value }
}
}
#[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr)]
#[repr(u8)]
pub enum LabelMode {
Label,
LabelAndValue,
Value,
Caption,
CaptionAndValue,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct Show {
#[serde(rename = "@object")]
pub object: bool,
#[serde(rename = "@label")]
pub label: bool,
}
impl Show {
#[must_use]
pub fn object() -> Self {
Self {
object: true,
label: false,
}
}
#[must_use]
pub fn label() -> Self {
Self {
object: false,
label: true,
}
}
#[must_use]
pub fn object_and_label() -> Self {
Self {
object: true,
label: true,
}
}
#[must_use]
pub fn none() -> Self {
Self {
object: false,
label: false,
}
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct Coords {
#[serde(rename = "@x")]
x: f64,
#[serde(rename = "@y")]
y: f64,
#[serde(rename = "@z")]
z: f64,
}
impl Coords {
#[must_use]
pub fn xy(x: f64, y: f64) -> Self {
Self { x, y, z: 1.0 }
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Command {
#[serde(rename = "@name")]
pub name: String,
pub input: IndexedAttrs<String>,
pub output: IndexedAttrs<String>,
}
#[derive(Debug, Clone)]
pub struct IndexedAttrs<T> {
pub attrs: Vec<T>,
}
impl<T> From<Vec<T>> for IndexedAttrs<T> {
fn from(value: Vec<T>) -> Self {
Self { attrs: value }
}
}
impl<T: Serialize> Serialize for IndexedAttrs<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut s = serializer.serialize_map(Some(self.attrs.len()))?;
for (i, attr) in self.attrs.iter().enumerate() {
s.serialize_entry(&format!("@a{i}"), attr)?;
}
s.end()
}
}
impl<'de, T: Deserialize<'de>> Deserialize<'de> for IndexedAttrs<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_map(IndexedAttrsVisitor(PhantomData))
}
}
struct IndexedAttrsVisitor<T>(PhantomData<T>);
impl<'de, T: Deserialize<'de>> Visitor<'de> for IndexedAttrsVisitor<T> {
type Value = IndexedAttrs<T>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(formatter, "a map")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: serde::de::MapAccess<'de>,
{
let mut attrs = Vec::new();
while let Some(v) = map.next_value()? {
attrs.push(v);
}
Ok(IndexedAttrs { attrs })
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Expression {
#[serde(rename = "@type")]
pub type_: ElementType,
#[serde(rename = "@label")]
pub label: String,
#[serde(rename = "@exp")]
pub exp: String,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct ObjColorType {
#[serde(rename = "@r")]
pub r: u8,
#[serde(rename = "@g")]
pub g: u8,
#[serde(rename = "@b")]
pub b: u8,
}