Skip to content

Commit

Permalink
[designspace] Deserialize lib fields
Browse files Browse the repository at this point in the history
This was about as painful as expected, and requires us to manually glue
together the xml data model with the plist model, using serde.

To briefly summarize the problem: XML data, by definition, does not have
any defined semantics. Semantics are added on top of XML on a per-case
basis, by indicating the document type inline
(<https://en.wikipedia.org/wiki/Document_type_declaration>).

The plist crate does implement derive for plist types, but they are based on the
assumption that type information is being provided by some deserializer
(e.g. for a specific file format). This is the right thing for the plist
crate to do. Unfortunately quick_xml cannot provide this type
information, since quick_xml does not know that we are deserializing a
plist.

To make this all work, I have added a bunch of manual deserialize code.
This code will only work when deserializing from XML; if in the future
we wish to serialize to other formats, we will need to revise it.

Some notes:

- This only implements deserialization, not serialization. (This is
  fine, since we do not currently serialize anyway, but we'll have to
  figure that out eventually)
- this does not support the UID type, which is not accepted in XML
  plists
  • Loading branch information
cmyr committed Jul 28, 2023
1 parent 843ca05 commit 081b73d
Show file tree
Hide file tree
Showing 5 changed files with 503 additions and 1 deletion.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ rayon = { version = "1.3.0", optional = true }
kurbo = { version = "0.9.0", optional = true }
thiserror = "1.0"
indexmap = {version = "2.0.0", features = ["serde"] }
base64 = "0.21.2"

[dependencies.druid]
default-features = false
Expand Down
31 changes: 31 additions & 0 deletions src/designspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

use std::{fs::File, io::BufReader, path::Path};

use plist::Dictionary;

use crate::error::DesignSpaceLoadError;
use crate::serde_xml_plist as serde_plist;

/// A [designspace].
///
Expand All @@ -24,6 +27,9 @@ pub struct DesignSpaceDocument {
/// One or more instances.
#[serde(default, deserialize_with = "serde_impls::deserialize_instances")]
pub instances: Vec<Instance>,
/// Additional arbitrary user data
#[serde(default, deserialize_with = "serde_plist::deserialize_dict")]
pub lib: Dictionary,
}

/// An [axis].
Expand Down Expand Up @@ -131,6 +137,9 @@ pub struct Instance {
/// Location in designspace.
#[serde(deserialize_with = "serde_impls::deserialize_location")]
pub location: Vec<Dimension>,
/// Arbitrary data about this instance
#[serde(default, deserialize_with = "serde_plist::deserialize_dict")]
pub lib: Dictionary,
}

/// A [design space dimension].
Expand Down Expand Up @@ -215,6 +224,7 @@ mod serde_impls {
mod tests {
use std::path::Path;

use plist::Value;
use pretty_assertions::assert_eq;

use crate::designspace::{AxisMapping, Dimension};
Expand Down Expand Up @@ -280,4 +290,25 @@ mod tests {
assert_eq!(ds.instances[0].name.as_deref(), Some("Test Family Regular"));
assert!(ds.instances[1].name.is_none());
}

#[test]
fn load_lib() {
let loaded = DesignSpaceDocument::load("testdata/wght.designspace").unwrap();
assert_eq!(
loaded.lib.get("org.linebender.hasLoadedLibCorrectly"),
Some(&Value::String("Absolutely!".into()))
);

let params = loaded.instances[0]
.lib
.get("com.schriftgestaltung.customParameters")
.and_then(Value::as_array)
.unwrap();
assert_eq!(params[0].as_array().unwrap()[0].as_string(), Some("xHeight"));
assert_eq!(params[0].as_array().unwrap()[1].as_string(), Some("536"));
assert_eq!(
params[1].as_array().unwrap()[1].as_array().unwrap()[0].as_unsigned_integer(),
Some(2)
);
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ mod kerning;
mod layer;
mod name;
mod names;
mod serde_xml_plist;
mod shared_types;
mod upconversion;
pub(crate) mod util;
Expand Down
Loading

0 comments on commit 081b73d

Please sign in to comment.