//! The general strategy is just to use a plist for storage. Also, lots of
//! unwrapping.
//!
//! There are lots of other ways this could go, including something serde-like
//! where it gets serialized to more Rust-native structures, proc macros, etc.
use std::collections::HashMap;
use crate::from_plist::FromPlist;
use crate::to_plist::ToPlist;
use crate::plist::Plist;
#[derive(Debug, FromPlist, ToPlist)]
pub struct Font {
pub glyphs: Vec<Glyph>,
}
#[derive(Debug, FromPlist, ToPlist)]
pub struct Glyph {
pub layers: Vec<Layer>,
pub glyphname: String,
}
#[derive(Debug, FromPlist, ToPlist)]
pub struct Layer {
pub layer_id: String,
pub width: f64,
pub paths: Option<Vec<Path>>,
pub components: Option<Vec<Component>>,
#[rest]
pub other_stuff: HashMap<String, Plist>,
}
#[derive(Debug, FromPlist, ToPlist)]
pub struct Path {
pub closed: bool,
pub nodes: Vec<Node>,
}
#[derive(Debug)]
pub struct Node {
pub x: f64,
pub y: f64,
pub node_type: NodeType,
}
#[derive(Debug)]
pub enum NodeType {
Line,
OffCurve,
Curve,
CurveSmooth,
}
#[derive(Debug, FromPlist, ToPlist)]
pub struct Component {
pub name: String,
pub transform: Option<String>,
}
impl FromPlist for Node {
fn from_plist(plist: Plist) -> Self {
let mut spl = plist.as_str().unwrap().split(' ');
let x = spl.next().unwrap().parse().unwrap();
let y = spl.next().unwrap().parse().unwrap();
let node_type = spl.next().unwrap().parse().unwrap();
Node { x, y, node_type }
}
}
impl std::str::FromStr for NodeType {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"LINE" => Ok(NodeType::Line),
"OFFCURVE" => Ok(NodeType::OffCurve),
"CURVE" => Ok(NodeType::Curve),
"CURVE SMOOTH" => Ok(NodeType::CurveSmooth),
_ => Err(format!("unknown node type {}", s)),
}
}
}
impl NodeType {
fn glyphs_str(&self) -> &'static str {
match self {
NodeType::Line => "LINE",
NodeType::OffCurve => "OFFCURVE",
NodeType::Curve => "CURVE",
NodeType::CurveSmooth => "CURVE SMOOTH",
}
}
}
impl ToPlist for Node {
fn to_plist(self) -> Plist {
format!("{} {} {}", self.x, self.y, self.node_type.glyphs_str()).into()
}
}