chiark / gitweb /
mformat 2: Deserialise the data that library format 2 needs
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 8 May 2022 10:55:52 +0000 (11:55 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Wed, 11 May 2022 23:19:17 +0000 (00:19 +0100)
Introduce the various enums (including serde(untagged) ones) so that
we can deserialise all of the mf1 and mf2 formats into the same
structure.

Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
src/shapelib-toml.rs
src/shapelib.rs

index e8eb2a0c01b72478189d2bc953491500f404c26c..0def899844a6615ee12e90236ebd9a443edbe89c 100644 (file)
@@ -26,11 +26,49 @@ pub struct GroupDetails {
   #[serde(default)] pub centre: Option<[f64; 2]>,
   #[serde(default)] pub flip: bool,
   #[serde(default)] pub back: Option<Box <dyn PieceSpec>>,
-  #[serde(default="num_traits::identities::One::one")] pub scale: f64,
+  #[serde(default)] pub scale: Option<ScaleDetails>,
   #[serde(default)] pub colours: HashMap<String, RecolourData>,
   pub desc_template: Option<String>,
   pub occulted: Option<OccultationMethod>,
-  #[serde(flatten)] pub outline: Box<dyn shapelib::OutlineDefn>,
+  #[serde(flatten)] pub outline: OutlineDetails,
+}
+
+#[derive(Debug,Deserialize,Copy,Clone)]
+#[serde(untagged)]
+pub enum ScaleDetails {
+  Fit(ScaleFitDetails),
+  Scale(f64),
+  Stretch([f64;2]),
+}
+
+#[derive(Debug,Deserialize,Copy,Clone)]
+pub enum ScaleFitDetails { Fit, Cover, Stretch }
+
+#[derive(Debug,Deserialize)]
+#[serde(untagged)]
+pub enum OutlineDetails {
+  Full(FullOutlineDetails), // introduced with mformat=2
+  Shape(Box<dyn shapelib::OutlineDefn>),
+}
+
+#[derive(Debug,Deserialize)]
+pub struct FullOutlineDetails {
+  shape: Box<dyn shapelib::OutlineDefn>,
+  #[serde(default)] size: Vec<f64>,
+  #[serde(default)] scale: Option<f64>,
+}
+
+impl OutlineDetails {
+  // enum_access could perhaps do this but controlling the serde
+  // would become confusing
+  pub fn shape(&self) -> &dyn shapelib::OutlineDefn { match self {
+    OutlineDetails::Full(full) => &*full.shape,
+    OutlineDetails::Shape(shape) => &**shape,
+  }}
+  pub fn size_scale(&self) -> (&[f64], Option<&f64>) { match self {
+    OutlineDetails::Full(full) => (&full.size, full.scale.as_ref()),
+    OutlineDetails::Shape(_) => default(),
+  }}
 }
 
 #[derive(Deserialize,Clone,Debug)]
index 0812eb886df3dd14be5d48d85e384c1fbbdf120b..ca59bbcf389ba09dca1b01eba882989612f76afc 100644 (file)
@@ -590,7 +590,7 @@ impl FaceTransform {
         .into_inner()
         .unwrap()
     } else {
-      let s = d.scale;
+      let s = group.d.scale_mf1(group.mformat)?;
       [s,s]
     };
     let centre = d.centre.map(Ok).unwrap_or_else(|| Ok::<_,LLE>({
@@ -646,11 +646,22 @@ impl GroupData {
   #[throws(LibraryLoadError)]
   fn load_shape(&self, svg_sz: PosC<f64>) -> (FaceTransform, Outline) {
     let xform = FaceTransform::from_group_mf1(self)?;
-    let outline = self.d.outline.load_mf1(&self, svg_sz)?;
+    let outline = self.d.outline.shape().load_mf1(&self, svg_sz)?;
     (xform, outline)
   }
 }
 
+impl GroupDetails {
+  #[throws(materials_format::Incompat<LLMI>)]
+  fn scale_mf1(&self, mformat: materials_format::Version) -> f64 {
+    match self.scale {
+      None => 1.,
+      Some(ScaleDetails::Scale(s)) => s,
+      _ => throw!(mformat.incompat(LLMI::Scale)),
+    }
+  }
+}
+
 //---------- RectShape ----------
 
 #[derive(Clone,Copy,Debug,Serialize,Deserialize)]
@@ -862,9 +873,14 @@ pub fn load_catalogue(libname: &str, src: &mut dyn LibrarySource)
     let gdefn = resolve_inherit(INHERIT_DEPTH_LIMIT,
                                 groups, groupname, gdefn)?;
     let gdefn: GroupDefn = TV::Table(gdefn.into_owned()).try_into()?;
-    let d = GroupDetails {
-      size: gdefn.d.size.iter().map(|s| s * gdefn.d.scale).collect(),
-      ..gdefn.d
+    let d = if mformat == 1 {
+      let scale = gdefn.d.scale_mf1(mformat)?;
+      GroupDetails {
+        size: gdefn.d.size.iter().map(|s| s * scale).collect(),
+        ..gdefn.d
+      }
+    } else {
+      gdefn.d // v2 isn't going to do this, do this right now
     };
     let group = Arc::new(GroupData {
       groupname: groupname.clone(),