]> pintos-os.org Git - pspp/commitdiff
code cleanup
authorBen Pfaff <blp@cs.stanford.edu>
Fri, 21 Aug 2026 00:38:16 +0000 (17:38 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Fri, 21 Aug 2026 00:38:16 +0000 (17:38 -0700)
rust/Cargo.lock
rust/pspp/Cargo.toml
rust/pspp/src/output.rs
rust/pspp/src/spv/read/graph.rs
rust/pspp/src/spv/read/graph/frames.rs

index 4f11c99691d4759223d35f3c37832ed289d310fb..28978d7597864140ecc1ed0392e0511a24777108 100644 (file)
@@ -146,7 +146,7 @@ checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -168,7 +168,7 @@ checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -224,14 +224,14 @@ dependencies = [
  "regex",
  "rustc-hash",
  "shlex",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
 name = "binrw"
-version = "0.15.0"
+version = "0.15.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81419ff39e6ed10a92a7f125290859776ced35d9a08a665ae40b23e7ca702f30"
+checksum = "6ad120d555272286c1017d25165ab8bd74806f13fc85b258484ec7e4ce75458f"
 dependencies = [
  "array-init",
  "binrw_derive",
@@ -240,15 +240,15 @@ dependencies = [
 
 [[package]]
 name = "binrw_derive"
-version = "0.15.0"
+version = "0.15.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "376404e55ec40d0d6f8b4b7df3f87b87954bd987f0cf9a7207ea3b6ea5c9add4"
+checksum = "6df92e0e9baae4dc82c7bad7715ca40c0a5c71539057bf2ea04a5c29c980410b"
 dependencies = [
  "either",
  "owo-colors",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -497,7 +497,7 @@ dependencies = [
  "heck",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -641,7 +641,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
 dependencies = [
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -685,7 +685,7 @@ dependencies = [
  "ident_case",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -696,7 +696,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81"
 dependencies = [
  "darling_core",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -750,7 +750,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -770,7 +770,7 @@ checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
  "unicode-xid",
 ]
 
@@ -799,7 +799,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -856,7 +856,7 @@ checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -865,7 +865,17 @@ version = "2.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9"
 dependencies = [
- "enum-map-derive",
+ "enum-map-derive 0.17.0",
+ "serde",
+]
+
+[[package]]
+name = "enum-map"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4532960034c15ba2f55e9eee631040ecc473c32e6c4b200828c759840f13a06"
+dependencies = [
+ "enum-map-derive 1.0.1",
  "serde",
 ]
 
@@ -877,7 +887,18 @@ checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "enum-map-derive"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7127272f64b3e098f7d81f350d672081b879bff896d219c42370dc858b1af9ff"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 3.0.3",
 ]
 
 [[package]]
@@ -898,7 +919,7 @@ dependencies = [
  "darling",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -1066,7 +1087,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -1315,7 +1336,7 @@ dependencies = [
  "heck",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -1661,7 +1682,7 @@ checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -1965,7 +1986,7 @@ checksum = "973e7178a678cfd059ccec50887658d482ce16b0aa9da3888ddeab5cd5eb4889"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -2290,7 +2311,7 @@ dependencies = [
  "pest_meta",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -2343,7 +2364,7 @@ dependencies = [
  "phf_shared 0.11.3",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -2381,7 +2402,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -2467,14 +2488,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6837b9e10d61f45f987d50808f83d1ee3d206c66acf650c3e4ae2e1f6ddedf55"
 dependencies = [
  "proc-macro2",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.95"
+version = "1.0.107"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
+checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
 dependencies = [
  "unicode-ident",
 ]
@@ -2503,7 +2524,8 @@ dependencies = [
  "either",
  "encoding_rs",
  "enum-iterator",
- "enum-map",
+ "enum-map 2.7.3",
+ "enum-map 3.1.0",
  "enumset",
  "erased-serde",
  "flate2",
@@ -2553,7 +2575,7 @@ version = "0.1.0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -2594,9 +2616,9 @@ dependencies = [
 
 [[package]]
 name = "quote"
-version = "1.0.40"
+version = "1.0.47"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
 dependencies = [
  "proc-macro2",
 ]
@@ -2846,9 +2868,9 @@ dependencies = [
 
 [[package]]
 name = "serde"
-version = "1.0.228"
+version = "1.0.229"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
 dependencies = [
  "serde_core",
  "serde_derive",
@@ -2856,22 +2878,22 @@ dependencies = [
 
 [[package]]
 name = "serde_core"
-version = "1.0.228"
+version = "1.0.229"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
+checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.228"
+version = "1.0.229"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
+checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 3.0.3",
 ]
 
 [[package]]
@@ -2906,7 +2928,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -3114,6 +3136,17 @@ dependencies = [
  "unicode-ident",
 ]
 
+[[package]]
+name = "syn"
+version = "3.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
 [[package]]
 name = "synstructure"
 version = "0.13.2"
@@ -3122,7 +3155,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -3191,7 +3224,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -3264,7 +3297,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -3404,7 +3437,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -3432,7 +3465,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -3583,7 +3616,7 @@ dependencies = [
  "log",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
  "wasm-bindgen-shared",
 ]
 
@@ -3605,7 +3638,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
@@ -3699,7 +3732,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -3710,7 +3743,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -4024,7 +4057,7 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
  "synstructure",
 ]
 
@@ -4045,7 +4078,7 @@ checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -4065,7 +4098,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
  "synstructure",
 ]
 
@@ -4086,7 +4119,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
@@ -4119,7 +4152,7 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.117",
 ]
 
 [[package]]
index d3fbf3159bad8536bf018157454d379dbb9535f2..daafe95045f498bacaa5ba4b6bbd9212ec1da762 100644 (file)
@@ -10,7 +10,7 @@ license = "GPL-3.0-or-later"
 aes = "0.8.4"
 anyhow = "1.0.69"
 base64 = "0.22.1"
-binrw = "0.15.0"
+binrw = "0.15.2"
 bit-vec = "0.8.0"
 cairo-rs = { version = "0.22.0", features = ["ps", "png", "pdf", "svg"] }
 chardetng = "0.1.17"
@@ -25,7 +25,7 @@ displaydoc = "0.2.5"
 either = "1.13.0"
 encoding_rs = { version = "0.8.32", features = ["serde"] }
 enum-iterator = "2.1.0"
-enum-map = { version = "2.7.3", features = ["serde"] }
+enum-map = { version = "3.1.0", features = ["serde"] }
 enumset = "1.1.10"
 erased-serde = "0.4.9"
 flate2 = "1.0.26"
index 3223c21fcf58952c85930b3ff2c3406a59a1b960..8f9121565407d629b26fff44989a24513546c195 100644 (file)
@@ -554,7 +554,7 @@ fn text_item_table_look() -> Arc<Look> {
         Arc::new({
             let mut look = Look::default().with_borders(EnumMap::from_fn(|_| BorderStyle::none()));
             for style in look.areas.values_mut() {
-                style.cell_style.margins = EnumMap::from_fn(|_| [0, 0]);
+                style.cell_style.margins = EnumMap::default();
             }
             look
         })
index 2d4d959c1d7189a53379414b8ff9f0d51b7f0aad..004b9471797fae9f83e75e3f375497eedcf595c1 100644 (file)
@@ -2517,19 +2517,17 @@ impl<'a> Element<'a> {
         axis_domains: &mut EnumMap<Axis3, AxisDomain<'a>>,
         styles: &'a HashMap<String, Style>,
     ) -> Result<Self, GraphError> {
-        let mut variables = EnumMap::default();
-        for (coordinate, axis) in
-            [&raw.x, &raw.y, &raw.z]
-                .into_iter()
-                .zip([Axis3::X, Axis3::Y, Axis3::Z])
-        {
-            if let Some(coordinate) = &coordinate {
-                let series = series
-                    .get(coordinate.variable.as_str())
-                    .ok_or_else(|| GraphError::MissingVariable(coordinate.variable.clone()))?;
-                variables[axis] = Some(series.clone());
-            }
-        }
+        let mut variables = EnumMap::try_from_fn(|axis| {
+            raw.positions[axis]
+                .as_ref()
+                .map(|coordinate| {
+                    series
+                        .get(coordinate.variable.as_str())
+                        .cloned()
+                        .ok_or_else(|| GraphError::MissingVariable(coordinate.variable.clone()))
+                })
+                .transpose()
+        })?;
         let mut ignore_minmax = EnumMap::default();
         for statistic in &raw.statistics {
             match statistic {
@@ -2900,11 +2898,10 @@ enum BreakRepresentation {
     Wings,
 }
 
-#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 enum Graphic {
     /// Bar chart of bars.  Each `(x,y)` bar covers `0..y` at the given `x`
     /// coordinate.
-    #[default]
     Interval,
     /// Scatter-plot of `(x,y)` points.
     Point,
@@ -2934,55 +2931,26 @@ enum Graphic {
     Polygon,
 }
 
-#[derive(Deserialize, Debug, Default)]
-#[serde(rename_all = "camelCase")]
-#[serde(default)]
+#[derive(Debug)]
 struct RawElement {
-    #[serde(rename = "@id")]
     id: Option<String>,
-
-    #[serde(rename = "@breakRepresentation")]
     break_representation: Option<BreakRepresentation>,
-
-    #[serde(rename = "@closed")]
     closed: bool,
-
-    #[serde(rename = "@preserveStraightLines")]
     preserve_straight_lines: bool,
-
-    #[serde(rename = "@centerIn3D")]
     center_in_3d: bool,
-
-    #[serde(rename = "@medianStyle")]
     median_style: Option<String>,
-
-    #[serde(rename = "@fenceStyle")]
     fence_style: Option<String>,
-
-    #[serde(rename = "@hingeStyle")]
     hinge_style: Option<String>,
-
-    #[serde(rename = "@outlierStyle")]
     outlier_style: Option<String>,
-
-    #[serde(rename = "@extremeStyle")]
     extreme_style: Option<String>,
-
-    #[serde(rename = "@style")]
     style: Option<String>,
-
-    #[serde(rename = "$value")]
     statistics: Vec<Statistic>,
 
-    position: Vec<Coordinate>,
-    x: Option<Coordinate>,
-    y: Option<Coordinate>,
-    z: Option<Coordinate>,
+    positions: EnumMap<Axis3, Option<Coordinate>>,
     color: Vec<ColorAesthetic>,
     style_by: Vec<StyleBy>,
 
     /// Type of graphic.
-    #[serde(skip)]
     graphic: Graphic,
 }
 
@@ -2991,13 +2959,85 @@ impl RawElement {
         self.graphic = graphic;
         self
     }
-    fn coordinate(&self, index: usize) -> Option<&Coordinate> {
-        match index {
-            0 => self.x.as_ref(),
-            1 => self.y.as_ref(),
-            2 => self.z.as_ref(),
-            _ => None,
+}
+
+impl<'de> Deserialize<'de> for RawElement {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        #[derive(Deserialize, Debug, Default)]
+        #[serde(rename_all = "camelCase")]
+        #[serde(default)]
+        struct ElementSpec {
+            #[serde(rename = "@id")]
+            id: Option<String>,
+
+            #[serde(rename = "@breakRepresentation")]
+            break_representation: Option<BreakRepresentation>,
+
+            #[serde(rename = "@closed")]
+            closed: bool,
+
+            #[serde(rename = "@preserveStraightLines")]
+            preserve_straight_lines: bool,
+
+            #[serde(rename = "@centerIn3D")]
+            center_in_3d: bool,
+
+            #[serde(rename = "@medianStyle")]
+            median_style: Option<String>,
+
+            #[serde(rename = "@fenceStyle")]
+            fence_style: Option<String>,
+
+            #[serde(rename = "@hingeStyle")]
+            hinge_style: Option<String>,
+
+            #[serde(rename = "@outlierStyle")]
+            outlier_style: Option<String>,
+
+            #[serde(rename = "@extremeStyle")]
+            extreme_style: Option<String>,
+
+            #[serde(rename = "@style")]
+            style: Option<String>,
+
+            #[serde(rename = "$value")]
+            statistics: Vec<Statistic>,
+
+            /// `position` is just a generic way to say x, y, z
+            position: Vec<Coordinate>,
+            x: Option<Coordinate>,
+            y: Option<Coordinate>,
+            z: Option<Coordinate>,
+            color: Vec<ColorAesthetic>,
+            style_by: Vec<StyleBy>,
+        }
+
+        let raw = ElementSpec::deserialize(deserializer)?;
+        let mut positions = EnumMap::from_array([raw.x, raw.y, raw.z]);
+        for (position, axis) in zip(raw.position, all()) {
+            positions[axis] = Some(position);
         }
+        Ok(Self {
+            id: raw.id,
+            break_representation: raw.break_representation,
+            closed: raw.closed,
+            preserve_straight_lines: raw.preserve_straight_lines,
+            center_in_3d: raw.center_in_3d,
+            median_style: raw.median_style,
+            fence_style: raw.fence_style,
+            hinge_style: raw.hinge_style,
+            outlier_style: raw.outlier_style,
+            extreme_style: raw.extreme_style,
+            style: raw.style,
+            statistics: raw.statistics,
+            positions,
+            color: raw.color,
+            style_by: raw.style_by,
+            graphic: Graphic::Area,
+        })
     }
 }
 
@@ -4268,7 +4308,6 @@ impl<'de> Deserialize<'de> for LocationLength {
 
 #[derive(Debug)]
 pub struct Frame<'a> {
-    id: Option<String>,
     frame_type: FrameType<'a>,
     parent: Option<usize>,
     children: Vec<usize>,
@@ -4277,6 +4316,15 @@ pub struct Frame<'a> {
 }
 
 impl<'a> Frame<'a> {
+    fn new(frame_type: FrameType<'a>, parent: Option<usize>) -> Self {
+        Self {
+            frame_type,
+            parent,
+            children: Vec::new(),
+            locations: EnumMap::default(),
+            position: EnumMap::default(),
+        }
+    }
     fn children(&self, frames: &'a [Frame<'a>]) -> impl Iterator<Item = &'a Frame<'a>> {
         self.children.iter().copied().map(|index| &frames[index])
     }
@@ -4350,10 +4398,7 @@ impl Rect {
     }
 
     fn try_from_fn<E>(f: impl Fn(Axis2) -> Result<Span, E>) -> Result<Self, E> {
-        let mut map = EnumMap::default();
-        map[Axis2::X] = f(Axis2::X)?;
-        map[Axis2::Y] = f(Axis2::Y)?;
-        Ok(Self(map))
+        Ok(Self(EnumMap::try_from_fn(|axis| f(axis))?))
     }
 
     /// Returns a demerits score based on how much this rectangle overflows the
index f571479a702d8820ded4b898d50de66ab66ebf98..cf7600a24a3c0d1db3c42325f107eb33a0637b34 100644 (file)
@@ -19,16 +19,8 @@ use crate::{
 
 impl Visualization {
     pub fn decode_frames<'a>(&'a self) -> Frames<'a> {
-        let mut frames = Vec::new();
+        let mut frames = vec![Frame::new(FrameType::Visualization(self), None)];
         let mut ids = HashMap::new();
-        frames.push(Frame {
-            id: self.id.clone(),
-            frame_type: FrameType::Visualization(self),
-            parent: None,
-            children: Vec::new(),
-            locations: EnumMap::default(),
-            position: EnumMap::default(),
-        });
         fn decode_container<'a>(
             parent: usize,
             container: &'a Container,
@@ -40,14 +32,7 @@ impl Visualization {
             if let Some(id) = &container.id {
                 ids.insert(id, container_index);
             }
-            frames.push(Frame {
-                id: container.id.clone(),
-                frame_type: FrameType::Container(container),
-                parent: Some(parent),
-                children: Vec::new(),
-                locations: EnumMap::default(),
-                position: EnumMap::default(),
-            });
+            frames.push(Frame::new(FrameType::Container(container), Some(parent)));
             for child in &container.children {
                 match child {
                     AnyFrame::Graph(graph) => {
@@ -56,14 +41,7 @@ impl Visualization {
                         if let Some(id) = &graph.id {
                             ids.insert(id, index);
                         }
-                        frames.push(Frame {
-                            id: graph.id.clone(),
-                            frame_type: FrameType::Graph(graph),
-                            parent: Some(container_index),
-                            children: Vec::new(),
-                            locations: EnumMap::default(),
-                            position: EnumMap::default(),
-                        });
+                        frames.push(Frame::new(FrameType::Graph(graph), Some(container_index)));
                     }
                     AnyFrame::LabelFrame(label_frame) => {
                         let index = frames.len();
@@ -71,14 +49,10 @@ impl Visualization {
                         if let Some(id) = &label_frame.id {
                             ids.insert(id, index);
                         }
-                        frames.push(Frame {
-                            id: label_frame.id.clone(),
-                            frame_type: FrameType::LabelFrame(label_frame),
-                            parent: Some(container_index),
-                            children: Vec::new(),
-                            locations: EnumMap::default(),
-                            position: EnumMap::default(),
-                        });
+                        frames.push(Frame::new(
+                            FrameType::LabelFrame(label_frame),
+                            Some(container_index),
+                        ));
                     }
                     AnyFrame::Legend(legend) => {
                         let index = frames.len();
@@ -86,14 +60,7 @@ impl Visualization {
                         if let Some(id) = &legend.id {
                             ids.insert(id, index);
                         }
-                        frames.push(Frame {
-                            id: legend.id.clone(),
-                            frame_type: FrameType::Legend(legend),
-                            parent: Some(container_index),
-                            children: Vec::new(),
-                            locations: EnumMap::default(),
-                            position: EnumMap::default(),
-                        });
+                        frames.push(Frame::new(FrameType::Legend(legend), Some(container_index)));
                     }
                     AnyFrame::Container(container) => {
                         decode_container(container_index, container, frames, ids)
@@ -110,14 +77,7 @@ impl Visualization {
                     if let Some(id) = &graph.id {
                         ids.insert(id, index);
                     }
-                    frames.push(Frame {
-                        id: graph.id.clone(),
-                        frame_type: FrameType::Graph(graph),
-                        parent: Some(0),
-                        children: Vec::new(),
-                        locations: EnumMap::default(),
-                        position: EnumMap::default(),
-                    });
+                    frames.push(Frame::new(FrameType::Graph(graph), Some(0)));
                 }
                 AnyFrame::LabelFrame(label_frame) => {
                     let index = frames.len();
@@ -125,14 +85,7 @@ impl Visualization {
                     if let Some(id) = &label_frame.id {
                         ids.insert(id, index);
                     }
-                    frames.push(Frame {
-                        id: label_frame.id.clone(),
-                        frame_type: FrameType::LabelFrame(label_frame),
-                        parent: Some(0),
-                        children: Vec::new(),
-                        locations: EnumMap::default(),
-                        position: EnumMap::default(),
-                    });
+                    frames.push(Frame::new(FrameType::LabelFrame(label_frame), Some(0)));
                 }
                 AnyFrame::Container(container) => {
                     decode_container(0, container, &mut frames, &mut ids)
@@ -163,6 +116,16 @@ pub enum FrameType<'a> {
 }
 
 impl<'a> FrameType<'a> {
+    fn id(&self) -> &Option<String> {
+        match self {
+            FrameType::Visualization(visualization) => &visualization.id,
+            FrameType::Container(container) => &container.id,
+            FrameType::Graph(graph) => &graph.id,
+            FrameType::LabelFrame(label_frame) => &label_frame.id,
+            FrameType::Legend(legend) => &legend.id,
+        }
+    }
+
     fn preferred_size(&self, max: &EnumMap<Axis2, Option<f64>>) -> EnumMap<Axis2, f64> {
         let default = match self {
             FrameType::Visualization(_) | FrameType::Container(_) => EnumMap::default(),
@@ -621,7 +584,7 @@ impl<'a> Frames<'a> {
                     .set("height", height)
                     .set("fill", "none")
                     .set("stroke", "red");
-                if let Some(id) = &frame.id {
+                if let Some(id) = frame.frame_type.id() {
                     rectangle.append(Title::new(id));
                 }
                 group.append(rectangle);