1use integer_or_float::IntegerOrFloat;
4
5mod xml;
6
7use std::fmt::Debug;
8#[cfg(feature = "glifserde")]
9use serde::{Serialize, Deserialize};
10
11use crate::error::GlifParserError;
12use crate::pedantry::{FloatClass, Mend, Pedantry};
13use crate::point::PointData;
14use crate::string::GlifStringLenOne;
15
16#[cfg_attr(feature = "glifserde", derive(Serialize, Deserialize))]
17#[derive(Clone, Debug, Derivative, PartialEq, Eq, Unwrap, IsVariant)]
18#[derivative(Default(new="true"))]
19pub enum AnchorType {
20 Mark,
21 #[derivative(Default)]
22 Base,
23}
24
25impl<S> From<S> for AnchorType where S: AsRef<str> {
26 fn from(s: S) -> Self {
27 if s.as_ref().chars().nth(0) == Some('_') {
28 Self::Mark
29 } else {
30 Self::Base
31 }
32 }
33}
34
35pub trait FromOption<S: Into<AnchorType>>: Default {
36 fn from_option(s: Option<S>) -> AnchorType {
37 match s {
38 Some(ss) => ss.into(),
39 None => AnchorType::default()
40 }
41 }
42}
43impl<S: Into<Self>> FromOption<S> for AnchorType {}
44
45#[cfg_attr(feature = "glifserde", derive(Serialize, Deserialize))]
46#[derive(Constructor, Clone, Debug, Default, PartialEq)]
47pub struct Anchor<PD: PointData> {
48 pub x: f32,
49 pub y: f32,
50 #[cfg_attr(feature = "glifserde", serde(default))]
51 pub class: Option<String>,
52 #[cfg_attr(feature = "glifserde", serde(default))]
53 pub data: PD,
54 #[cfg_attr(feature = "glifserde", serde(default))]
55 pub atype: AnchorType,
56}
57
58impl<PD: PointData> Anchor<PD> {
59 pub fn from_glif(ga: &GlifAnchor, pedantry: Pedantry) -> Result<Self, GlifParserError> {
60 let (x, y) = (pedantry.level.maybe_round(ga.x, FloatClass::Anchor), pedantry.level.maybe_round(ga.y, FloatClass::Anchor));
61 let class = ga.class.as_ref().map(|gs|gs.to_string());
62 if pedantry.mend != Mend::Always && (!ga.x.holding_integer().is_ok() || !ga.y.holding_integer().is_ok()) {
63 return Err(GlifParserError::PedanticXmlParseError("Anchor was a float, not an integer!".to_string()))
64 }
65 let atype = AnchorType::from_option(class.as_ref());
66 Ok(Self {
67 x, y, class, atype, data: PD::default()
68 })
69 }
70}
71
72#[cfg_attr(feature = "glifserde", derive(Serialize, Deserialize))]
73#[derive(Constructor, Clone, Debug, Default, PartialEq)]
74pub struct GlifAnchor {
75 pub x: IntegerOrFloat,
76 pub y: IntegerOrFloat,
77 pub class: Option<GlifStringLenOne>,
78}