chiark / gitweb /
mformat 2: Actually parse the outline properly
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Wed, 11 May 2022 23:37:15 +0000 (00:37 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Thu, 12 May 2022 00:55:24 +0000 (01:55 +0100)
This turns out to be quite hard.

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

index e81bafe3d70e1366f0d92f2a1d282d660f1ccda7..f5dfc2d2803e0a2dcfcb7a86ec4016c42831e4b3 100644 (file)
@@ -4,6 +4,8 @@
 
 pub use crate::prelude::*;
 
+use shapelib::OutlineDefnEnum;
+
 #[doc(hidden)] pub type LLE = shapelib::LibraryLoadError;
 
 // At the implementation level, each loaded item contains an
@@ -30,7 +32,7 @@ pub struct GroupDetails {
   #[serde(default)] pub colours: HashMap<String, RecolourData>,
   pub desc_template: Option<String>,
   pub occulted: Option<OccultationMethod>,
-  #[serde(flatten)] pub outline: OutlineDetails,
+  pub outline: OutlineDetails,
 }
 
 #[derive(Debug,Deserialize,Copy,Clone)]
@@ -48,12 +50,12 @@ pub enum ScaleFitDetails { Fit, Cover, Stretch }
 #[serde(untagged)]
 pub enum OutlineDetails {
   Full(FullOutlineDetails), // introduced with mformat=2
-  Shape(Box<dyn shapelib::OutlineDefn>),
+  Shape(OutlineDefnEnum),
 }
 
 #[derive(Debug,Deserialize)]
 pub struct FullOutlineDetails {
-  shape: Box<dyn shapelib::OutlineDefn>,
+  shape: OutlineDefnEnum,
   #[serde(default)] size: Vec<f64>,
   #[serde(default)] scale: Option<f64>,
 }
@@ -61,9 +63,9 @@ pub struct FullOutlineDetails {
 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 shape(&self) -> OutlineDefnEnum { 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()),
index d853b3b2cdd18b1cd5a53191a827f920020f572d..7daa48e91fdcc9ba9104044cb33d5e6aad2256cd 100644 (file)
@@ -31,19 +31,6 @@ pub struct GroupData {
   #[allow(dead_code)] /*TODO*/ mformat: materials_format::Version,
 }
 
-#[typetag::deserialize(tag="outline")]
-pub trait OutlineDefn: Debug + Sync + Send + 'static {
-  /// Success or failure must not depend on `svg_sz`
-  ///
-  /// Called to *check* the group configuration before load, but
-  /// with a dummy svg_gz of [1,1].  That must correctly predict
-  /// success with other sizes.
-  fn load(&self, size: PosC<f64>) -> Outline {
-    RectShape { xy: size }.into()
-  }
-
-  fn load_mf1(&self, group: &GroupData) -> Result<Outline,LLE>;
-}
 #[derive(Debug,Clone,Copy)]
 pub struct ShapeCalculable { }
 
@@ -727,6 +714,51 @@ impl GroupDetails {
   }
 }
 
+//---------- OutlineDefn etc. ----------
+
+#[ambassador::delegatable_trait]
+pub trait OutlineDefn: Debug + Sync + Send + 'static {
+  /// Success or failure must not depend on `svg_sz`
+  ///
+  /// Called to *check* the group configuration before load, but
+  /// with a dummy svg_gz of [1,1].  That must correctly predict
+  /// success with other sizes.
+  fn load(&self, size: PosC<f64>) -> Outline {
+    RectShape { xy: size }.into()
+  }
+
+  fn load_mf1(&self, group: &GroupData) -> Result<Outline,LLE>;
+}
+
+// We used to do this via typetag and Box<dyn OutlineDefn>
+//
+// But I didnt manage to get typetag to deserialise these unit variants.
+// Instead, we have this enum and a cheesy macro to impl OutlineDefn
+// by delegating to a freshly made (static) unit struct value.
+macro_rules! outline_defns {
+  { $( $Shape:ident ),* } => { paste!{
+
+    #[derive(Deserialize,Debug,Copy,Clone,Eq,PartialEq)]
+    pub enum OutlineDefnEnum {
+      $( $Shape, )*
+    }
+
+    impl OutlineDefnEnum {
+      fn defn(self) -> &'static dyn OutlineDefn {
+        match self { $(
+          Self::$Shape => &[< $Shape Defn >] as _,
+        )* }
+      }
+    }
+
+  } }
+}
+
+outline_defns! { Circle, Rect }
+impl_via_ambassador!{
+  impl OutlineDefn for OutlineDefnEnum { defn() }
+}
+
 //---------- RectShape ----------
 
 #[derive(Clone,Copy,Debug,Serialize,Deserialize)]
@@ -780,8 +812,7 @@ impl OutlineTrait for RectShape {
 }
 
 #[derive(Deserialize,Debug)]
-struct RectDefn { }
-#[typetag::deserialize(name="Rect")]
+struct RectDefn;
 impl OutlineDefn for RectDefn {
   fn load(&self, size: PosC<f64>) -> Outline {
     RectShape { xy: size }.into()
@@ -818,8 +849,7 @@ impl OutlineTrait for CircleShape {
 }
 
 #[derive(Deserialize,Debug)]
-struct CircleDefn { }
-#[typetag::deserialize(name="Circle")]
+struct CircleDefn;
 impl OutlineDefn for CircleDefn {
   fn load(&self, size: PosC<f64>) -> Outline {
     let diam = size