]> pintos-os.org Git - pspp/commitdiff
more types cleanup
authorBen Pfaff <blp@cs.stanford.edu>
Wed, 19 Aug 2026 23:55:24 +0000 (16:55 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Wed, 19 Aug 2026 23:55:24 +0000 (16:55 -0700)
rust/pspp/src/spv/read/graph.rs

index b5ae47dead42d895565399e4a6df3b92f0098abd..d89becf3a6fcb14bf2717570c26ccbb6c5a76ee9 100644 (file)
@@ -159,6 +159,55 @@ impl<'de> Deserialize<'de> for Visualization {
     where
         D: Deserializer<'de>,
     {
+        #[derive(Deserialize, Debug)]
+        #[serde(rename_all = "camelCase")]
+        pub struct RawVisualization {
+            /// Locale used for output, e.g. `en-US`.
+            #[serde(rename = "@lang")]
+            lang: Option<String>,
+
+            /// The `id` for the base [Style] for the graph.
+            #[serde(rename = "@style")]
+            _style: Option<String>,
+
+            /// Title or caption.
+            #[serde(rename = "@description")]
+            _description: Option<String>,
+
+            /// VizML Schema version number.
+            #[serde(rename = "@version")]
+            _version: Option<String>,
+
+            #[serde(rename = "@id")]
+            id: Option<String>,
+
+            #[serde(rename = "$value")]
+            children: Vec<VisChild>,
+        }
+
+        #[derive(Deserialize, Debug)]
+        #[serde(rename_all = "camelCase")]
+        enum VisChild {
+            SourceVariable(SourceVariable),
+            DerivedVariable(DerivedVariable),
+            /// This is a kind of stub for data that is supplied through another source.
+            /// In the corpus, these just have an `id` attribute, but there's no value
+            /// in parsing it.
+            UserSource,
+            DelimitedFileSource(DelimitedFileSource),
+            EmbeddedSource(EmbeddedSource),
+            CategoricalDomain(CategoricalDomain),
+            IntervalDomain(IntervalDomain),
+            Graph(Graph),
+            LabelFrame(LabelFrame),
+            Container(Container),
+            StyleCycle(StyleCycle),
+            Style(Style),
+            Location(Location),
+            #[serde(other)]
+            Other,
+        }
+
         let RawVisualization {
             lang,
             _style,
@@ -222,32 +271,6 @@ impl<'de> Deserialize<'de> for Visualization {
     }
 }
 
-#[derive(Deserialize, Debug)]
-#[serde(rename_all = "camelCase")]
-pub struct RawVisualization {
-    /// Locale used for output, e.g. `en-US`.
-    #[serde(rename = "@lang")]
-    lang: Option<String>,
-
-    /// The `id` for the base [Style] for the graph.
-    #[serde(rename = "@style")]
-    _style: Option<String>,
-
-    /// Title or caption.
-    #[serde(rename = "@description")]
-    _description: Option<String>,
-
-    /// VizML Schema version number.
-    #[serde(rename = "@version")]
-    _version: Option<String>,
-
-    #[serde(rename = "@id")]
-    id: Option<String>,
-
-    #[serde(rename = "$value")]
-    children: Vec<VisChild>,
-}
-
 impl Visualization {
     fn all_variables(&self) -> impl Iterator<Item = &dyn Variable> {
         let source_variables = self
@@ -351,17 +374,7 @@ impl Visualization {
         let elements = graph
             .elements
             .iter()
-            .map(|(raw, graphic)| {
-                Element::new(
-                    raw,
-                    locale,
-                    *graphic,
-                    series,
-                    bin_widths,
-                    axis_domains,
-                    styles,
-                )
-            })
+            .map(|raw| Element::new(raw, locale, series, bin_widths, axis_domains, styles))
             .collect::<Result<Vec<_>, _>>()?;
         let dimensions = graph.coordinates.dimensions().collect_vec();
         for (index, axis) in [Axis3::X, Axis3::Y, Axis3::Z].into_iter().enumerate() {
@@ -911,7 +924,7 @@ impl Visualization {
                         }
 
                         let mut element_svg = Group::new().with_id(&element.raw.id);
-                        match element.graphic {
+                        match element.raw.graphic {
                             Graphic::Interval => {
                                 // Size defaults to 33%.
                                 let fraction = match style.symbol_size {
@@ -1197,29 +1210,6 @@ impl Series {
     }
 }
 
-#[derive(Deserialize, Debug)]
-#[serde(rename_all = "camelCase")]
-enum VisChild {
-    SourceVariable(SourceVariable),
-    DerivedVariable(DerivedVariable),
-    /// This is a kind of stub for data that is supplied through another source.
-    /// In the corpus, these just have an `id` attribute, but there's no value
-    /// in parsing it.
-    UserSource,
-    DelimitedFileSource(DelimitedFileSource),
-    EmbeddedSource(EmbeddedSource),
-    CategoricalDomain(CategoricalDomain),
-    IntervalDomain(IntervalDomain),
-    Graph(Graph),
-    LabelFrame(LabelFrame),
-    Container(Container),
-    StyleCycle(StyleCycle),
-    Style(Style),
-    Location(Location),
-    #[serde(other)]
-    Other,
-}
-
 #[derive(Deserialize, Debug)]
 #[serde(rename_all = "camelCase")]
 struct DelimitedFileSource {
@@ -2506,7 +2496,6 @@ struct ValueMapEntry {
 struct Element<'a> {
     raw: &'a RawElement,
     style: Cow<'a, Style>,
-    graphic: Graphic,
     variables: EnumMap<Axis3, Option<Series>>,
 
     /// Whether to ignore this element for the purpose of computing minimum and
@@ -2522,7 +2511,6 @@ impl<'a> Element<'a> {
     fn new(
         raw: &'a RawElement,
         locale: &'static Locale<'static>,
-        graphic: Graphic,
         series: &BTreeMap<&str, Series>,
         bin_widths: &mut BTreeMap<String, f64>,
         axis_domains: &mut EnumMap<Axis3, AxisDomain<'a>>,
@@ -2777,7 +2765,6 @@ impl<'a> Element<'a> {
             } else {
                 Cow::Owned(Style::default())
             },
-            graphic,
             variables,
             ignore_minmax,
         })
@@ -2792,7 +2779,7 @@ struct Graph {
     faceting: Option<Faceting>,
     facet_layout: Option<FacetLayout>,
     coordinates: Coordinates,
-    elements: Vec<(RawElement, Graphic)>,
+    elements: Vec<RawElement>,
 }
 
 impl Graph {
@@ -2825,6 +2812,37 @@ impl<'de> Deserialize<'de> for Graph {
     where
         D: Deserializer<'de>,
     {
+        #[derive(Deserialize, Debug)]
+        #[serde(rename_all = "camelCase")]
+        struct RawGraph {
+            #[serde(rename = "@id")]
+            id: Option<String>,
+
+            #[serde(rename = "@cellStyle")]
+            cell_style: Option<String>,
+
+            #[serde(rename = "$value")]
+            children: Vec<GraphChild>,
+        }
+
+        #[derive(Deserialize, Debug)]
+        #[serde(rename_all = "camelCase")]
+        enum GraphChild {
+            Location(Location),
+            Faceting(Faceting),
+            FacetLayout(FacetLayout),
+            Coordinates(Coordinates),
+            Interval(RawElement),
+            Point(RawElement),
+            Line(RawElement),
+            Polygon(RawElement),
+            Area(RawElement),
+            Schema(RawElement),
+            Edge(RawElement),
+            Path(RawElement),
+            LineGuide,
+        }
+
         let raw_graph = RawGraph::deserialize(deserializer)?;
         let mut locations = Vec::new();
         let mut faceting = None;
@@ -2833,14 +2851,18 @@ impl<'de> Deserialize<'de> for Graph {
         let mut elements = Vec::new();
         for child in raw_graph.children {
             match child {
-                GraphChild::Interval(interval) => elements.push((interval, Graphic::Interval)),
-                GraphChild::Point(point) => elements.push((point, Graphic::Point)),
-                GraphChild::Line(line) => elements.push((line, Graphic::Line)),
-                GraphChild::Polygon(polygon) => elements.push((polygon, Graphic::Polygon)),
-                GraphChild::Area(area) => elements.push((area, Graphic::Area)),
-                GraphChild::Schema(schema) => elements.push((schema, Graphic::Schema)),
-                GraphChild::Edge(edge) => elements.push((edge, Graphic::Edge)),
-                GraphChild::Path(path) => elements.push((path, Graphic::Path)),
+                GraphChild::Interval(interval) => {
+                    elements.push(interval.with_graphic(Graphic::Interval))
+                }
+                GraphChild::Point(point) => elements.push(point.with_graphic(Graphic::Point)),
+                GraphChild::Line(line) => elements.push(line.with_graphic(Graphic::Line)),
+                GraphChild::Polygon(polygon) => {
+                    elements.push(polygon.with_graphic(Graphic::Polygon))
+                }
+                GraphChild::Area(area) => elements.push(area.with_graphic(Graphic::Area)),
+                GraphChild::Schema(schema) => elements.push(schema.with_graphic(Graphic::Schema)),
+                GraphChild::Edge(edge) => elements.push(edge.with_graphic(Graphic::Edge)),
+                GraphChild::Path(path) => elements.push(path.with_graphic(Graphic::Path)),
                 GraphChild::Location(location) => locations.push(location),
                 GraphChild::Faceting(value) => {
                     if faceting.replace(value).is_some() {
@@ -2872,91 +2894,6 @@ impl<'de> Deserialize<'de> for Graph {
     }
 }
 
-#[derive(Deserialize, Debug)]
-#[serde(rename_all = "camelCase")]
-struct RawGraph {
-    #[serde(rename = "@id")]
-    id: Option<String>,
-
-    #[serde(rename = "@cellStyle")]
-    cell_style: Option<String>,
-
-    #[serde(rename = "$value")]
-    children: Vec<GraphChild>,
-}
-
-impl RawGraph {
-    fn coordinates(&self) -> impl Iterator<Item = &Coordinates> {
-        self.children.iter().filter_map(|child| match child {
-            GraphChild::Coordinates(coordinates) => Some(coordinates),
-            _ => None,
-        })
-    }
-
-    fn elements(&self) -> impl Iterator<Item = (&RawElement, Graphic)> {
-        self.children.iter().filter_map(|child| child.element())
-    }
-
-    fn faceting(&self) -> Option<&Faceting> {
-        self.children.iter().find_map(|child| child.faceting())
-    }
-}
-
-#[derive(Deserialize, Debug)]
-#[serde(rename_all = "camelCase")]
-enum GraphChild {
-    Location(Location),
-    Faceting(Faceting),
-    FacetLayout(FacetLayout),
-    Coordinates(Coordinates),
-    Interval(RawElement),
-    Point(RawElement),
-    Line(RawElement),
-    Polygon(RawElement),
-    Area(RawElement),
-    Schema(RawElement),
-    Edge(RawElement),
-    Path(RawElement),
-    LineGuide,
-}
-
-impl GraphChild {
-    fn element(&self) -> Option<(&RawElement, Graphic)> {
-        match self {
-            GraphChild::Interval(interval) => Some((interval, Graphic::Interval)),
-            GraphChild::Point(point) => Some((point, Graphic::Point)),
-            GraphChild::Line(line) => Some((line, Graphic::Line)),
-            GraphChild::Polygon(polygon) => Some((polygon, Graphic::Polygon)),
-            GraphChild::Area(area) => Some((area, Graphic::Area)),
-            GraphChild::Schema(schema) => Some((schema, Graphic::Schema)),
-            GraphChild::Edge(edge) => Some((edge, Graphic::Edge)),
-            GraphChild::Path(path) => Some((path, Graphic::Path)),
-            _ => None,
-        }
-    }
-
-    fn facet_layout(&self) -> Option<&FacetLayout> {
-        match self {
-            Self::FacetLayout(facet_layout) => Some(facet_layout),
-            _ => None,
-        }
-    }
-
-    fn location(&self) -> Option<&Location> {
-        match self {
-            Self::Location(location) => Some(location),
-            _ => None,
-        }
-    }
-
-    fn faceting(&self) -> Option<&Faceting> {
-        match self {
-            Self::Faceting(faceting) => Some(faceting),
-            _ => None,
-        }
-    }
-}
-
 #[derive(Copy, Clone, Deserialize, Debug, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 enum BreakRepresentation {
@@ -2965,10 +2902,11 @@ enum BreakRepresentation {
     Wings,
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, Default, 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,
@@ -3044,9 +2982,15 @@ struct RawElement {
     z: Option<Coordinate>,
     color: Vec<ColorAesthetic>,
     style_by: Vec<StyleBy>,
+    #[serde(skip)]
+    graphic: Graphic,
 }
 
 impl RawElement {
+    fn with_graphic(mut self, graphic: Graphic) -> Self {
+        self.graphic = graphic;
+        self
+    }
     fn coordinate(&self, index: usize) -> Option<&Coordinate> {
         match index {
             0 => self.x.as_ref(),
@@ -4160,6 +4104,35 @@ impl<'de> Deserialize<'de> for Container {
     where
         D: Deserializer<'de>,
     {
+        #[derive(Deserialize, Debug)]
+        #[serde(rename_all = "camelCase")]
+        struct RawContainer {
+            #[serde(rename = "@id")]
+            id: Option<String>,
+            #[serde(rename = "$value")]
+            #[serde(default)]
+            children: Vec<ContainerChild>,
+        }
+
+        #[derive(Deserialize, Debug)]
+        #[serde(rename_all = "camelCase")]
+        enum ContainerChild {
+            Location(Location),
+            Container(Container),
+            Graph(Graph),
+            Legend(Legend),
+            LabelFrame(LabelFrame),
+        }
+
+        impl ContainerChild {
+            fn location(&self) -> Option<&Location> {
+                match self {
+                    Self::Location(location) => Some(location),
+                    _ => None,
+                }
+            }
+        }
+
         let raw_container = RawContainer::deserialize(deserializer)?;
         let mut locations = Vec::new();
         let mut children = Vec::new();
@@ -4184,35 +4157,6 @@ impl<'de> Deserialize<'de> for Container {
     }
 }
 
-#[derive(Deserialize, Debug)]
-#[serde(rename_all = "camelCase")]
-struct RawContainer {
-    #[serde(rename = "@id")]
-    id: Option<String>,
-    #[serde(rename = "$value")]
-    #[serde(default)]
-    children: Vec<ContainerChild>,
-}
-
-#[derive(Deserialize, Debug)]
-#[serde(rename_all = "camelCase")]
-enum ContainerChild {
-    Location(Location),
-    Container(Container),
-    Graph(Graph),
-    Legend(Legend),
-    LabelFrame(LabelFrame),
-}
-
-impl ContainerChild {
-    fn location(&self) -> Option<&Location> {
-        match self {
-            Self::Location(location) => Some(location),
-            _ => None,
-        }
-    }
-}
-
 #[derive(Deserialize, Debug)]
 #[serde(rename_all = "camelCase")]
 struct Legend {