work
authorBen Pfaff <blp@cs.stanford.edu>
Mon, 5 Jan 2026 20:53:14 +0000 (12:53 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Mon, 5 Jan 2026 20:53:14 +0000 (12:53 -0800)
rust/pspp/src/output/pivot.rs
rust/pspp/src/output/pivot/output.rs
rust/pspp/src/spv/read/legacy_xml.rs
rust/pspp/src/spv/read/light.rs
rust/pspp/src/spv/read/tests.rs
rust/pspp/src/spv/write.rs

index f6431c77486fde851756adc206244e9b52fb046d..dd261b3eca76e861b22eb561f11ef5ab4f90d6f8 100644 (file)
@@ -614,7 +614,7 @@ pub struct Dimension {
     ///
     /// The root must always be a group, although it is allowed to have no
     /// subcategories.
-    pub root: Group,
+    root: Group,
 
     /// Ordering of leaves for presentation.
     ///
@@ -626,6 +626,13 @@ pub struct Dimension {
     pub hide_all_labels: bool,
 }
 
+impl Dimension {
+    /// Returns the root [Group] of the dimension.
+    pub fn root(&self) -> &Group {
+        &self.root
+    }
+}
+
 /// A vector of references to [Group]s.
 ///
 /// Used to represent a sequence of groups along a [Path].  This is a [SmallVec]
@@ -745,7 +752,7 @@ pub struct Group {
     len: usize,
 
     /// The label displayed for the group.
-    pub name: Box<Value>,
+    name: Box<Value>,
 
     /// Whether to show the label.
     pub show_label: bool,
@@ -754,7 +761,7 @@ pub struct Group {
     ///
     /// A group usually has multiple children, but it is allowed to have
     /// only one or even (pathologically) none.
-    pub children: Vec<Category>,
+    children: Vec<Category>,
 }
 
 impl Group {
@@ -764,6 +771,11 @@ impl Group {
         Self::with_capacity(name, 0)
     }
 
+    /// Returns the group's child categories.
+    pub fn children(&self) -> &[Category] {
+        &self.children
+    }
+
     /// Constructs a new `Group` with the given name and initial child
     /// `capacity`.  The group initially has no children.
     pub fn with_capacity(name: impl Into<Value>, capacity: usize) -> Self {
@@ -982,17 +994,23 @@ impl FromIterator<Footnote> for Footnotes {
 
 /// A leaf category within a [Group] and ultimately within a [Dimension].
 #[derive(Clone, Debug)]
-pub struct Leaf(pub Box<Value>);
+pub struct Leaf {
+    data_index: usize,
+    name: Box<Value>,
+}
 
 impl Leaf {
     /// Constructs a new `Leaf` with the given label.
     pub fn new(name: Value) -> Self {
-        Self(Box::new(name))
+        Self {
+            data_index: 0,
+            name: Box::new(name),
+        }
     }
 
     /// Returns the leaf's label.
     pub fn name(&self) -> &Value {
-        &self.0
+        &self.name
     }
 
     /// Returns a sequence of `Leaf`s for the given range, for use with
@@ -1010,7 +1028,7 @@ impl Serialize for Leaf {
     where
         S: serde::Serializer,
     {
-        self.0.serialize(serializer)
+        self.name.serialize(serializer)
     }
 }
 
@@ -1092,7 +1110,7 @@ impl Category {
     pub fn name(&self) -> &Value {
         match self {
             Category::Group(group) => &group.name,
-            Category::Leaf(leaf) => &leaf.0,
+            Category::Leaf(leaf) => &leaf.name,
         }
     }
 
@@ -1100,7 +1118,7 @@ impl Category {
     pub fn name_mut(&mut self) -> &mut Value {
         match self {
             Category::Group(group) => &mut group.name,
-            Category::Leaf(leaf) => &mut leaf.0,
+            Category::Leaf(leaf) => &mut leaf.name,
         }
     }
 
index b47d2c22a657da740f5f78d64e30a99a60da1107..29b2664e2e6bdd82367e39519dbd62a3d174fe42 100644 (file)
@@ -312,7 +312,7 @@ impl PivotTable {
                     Axis2::X,
                     [
                         Box::new(name),
-                        dimension.nth_leaf(layer_index).unwrap().0.clone(),
+                        dimension.nth_leaf(layer_index).unwrap().name.clone(),
                     ]
                     .into_iter(),
                 )
@@ -441,7 +441,7 @@ impl Path<'_> {
         if let Some(group) = self.groups.get(y) {
             (&*group.name, y..y + 1)
         } else {
-            (&self.leaf.0, self.groups.len()..height)
+            (&self.leaf.name, self.groups.len()..height)
         }
     }
 }
index e015329e9dec0906343c1c2a1b6a797ccce3af56..7843d01aa60c4f14e03d153fbdfaa81571b664b3 100644 (file)
@@ -365,7 +365,12 @@ impl Visualization {
 
         Ok(PivotTable::new(
             dims.into_iter()
-                .map(|dim| (dim.axis, dim.dimension))
+                .map(|dim| {
+                    (
+                        dim.axis,
+                        Dimension::new(dim.root).with_hide_all_labels(dim.hide_all_labels),
+                    )
+                })
                 .collect::<Vec<_>>(),
         )
         .with_look(Arc::new(look))
@@ -1756,13 +1761,13 @@ impl<'a> DecodedSet<'a> {
                     let Some(dim_index) = s.dimension_index.get() else {
                         continue;
                     };
-                    let dimension = &mut dims[dim_index].dimension;
+                    let root = &mut dims[dim_index].root;
                     let Ok(axis) = Axis2::try_from(dims[dim_index].axis) else {
                         continue;
                     };
                     for index in w.include.split(';').filter_map(|s| s.parse::<usize>().ok()) {
                         if let Some(locator) = s.coordinate_to_index.borrow().get(&index).copied()
-                            && let Some(category) = dimension.root.category_mut(locator)
+                            && let Some(category) = root.category_mut(locator)
                         {
                             self.apply(
                                 category.name_mut(),
@@ -2328,19 +2333,17 @@ fn decode_dimension<'a>(
         dimension_label.set_font_style(dim_font);
     }
 
-    let dimension = Dimension::new(
-        Group::new(dimension_label)
-            .with_multiple(cats.into_iter().map(|cb| cb.category))
-            .with_show_label(show_label),
-    )
-    .with_hide_all_labels(hide_all_labels);
+    let root = Group::new(dimension_label)
+        .with_multiple(cats.into_iter().map(|cb| cb.category))
+        .with_show_label(show_label);
 
     for variable in &variables {
         variable.dimension_index.set(Some(dims.len()));
     }
     dims.push(Dim {
         axis: a,
-        dimension,
+        hide_all_labels,
+        root,
         series: variables[0],
     });
 }
@@ -2385,6 +2388,7 @@ fn decode_axis_dimensions<'a, 'b>(
 
 struct Dim<'a> {
     axis: Axis3,
-    dimension: pivot::Dimension,
+    root: pivot::Group,
+    hide_all_labels: bool,
     series: &'a Series,
 }
index 4046464be321f82e839fe1803437f41f9a7dd440..9b6ede22b0d1b4198af8f710cb3971c7f4966714 100644 (file)
@@ -159,6 +159,7 @@ impl LightTable {
     }
 
     pub fn decode(&self, mut warn: &mut dyn FnMut(LightWarning)) -> PivotTable {
+        dbg!(self);
         let encoding = self.formats.encoding(warn);
 
         let n1 = self.formats.n1();
@@ -190,11 +191,7 @@ impl LightTable {
                 for category in &d.categories {
                     category.decode(encoding, &footnotes, &mut root, warn);
                 }
-                pivot::Dimension {
-                    presentation_order: (0..root.len()).collect(), /*XXX*/
-                    root,
-                    hide_all_labels: d.hide_all_labels,
-                }
+                pivot::Dimension::new(root).with_hide_all_labels(d.hide_all_labels)
             })
             .collect::<Vec<_>>();
         let dimensions = match self.axes.decode(dimensions) {
index a8ef1ac7756563d6441ed2b36cc58529b6dfb910..57e24a961ce7bd16c065e5d2d0b3def6ec8574f4 100644 (file)
@@ -13,6 +13,11 @@ use crate::{
     spv::SpvArchive,
 };
 
+#[test]
+fn light1() {
+    test_raw_spvfile("light1", None);
+}
+
 #[test]
 fn legacy1() {
     test_raw_spvfile("legacy1", None);
index 92fd02f9fdefdf4c9f5625b386ed944ade2a4e66..7f241d92ccf596b9b4b17a194fe915f5463b51f7 100644 (file)
@@ -679,20 +679,20 @@ impl BinWrite for Dimension {
         (index, x2): (usize, u8),
     ) -> binrw::BinResult<()> {
         (
-            &self.root.name,
+            self.root().name(),
             0u8, // x1
             x2,
             2u32, // x3
-            SpvBool(!self.root.show_label),
+            SpvBool(!self.root().show_label),
             SpvBool(self.hide_all_labels),
             SpvBool(true),
             index as u32,
-            self.root.children.len() as u32,
+            self.root().children().len() as u32,
         )
             .write_options(writer, endian, ())?;
 
         let mut data_indexes = self.presentation_order.iter().copied();
-        for child in &self.root.children {
+        for child in self.root().children() {
             child.write_le(writer, &mut data_indexes)?;
         }
         Ok(())
@@ -746,11 +746,11 @@ impl Group {
             1u8,
             0u32, // x23
             -1i32,
-            self.children.len() as u32,
+            self.children().len() as u32,
         )
             .write_le(writer)?;
 
-        for child in &self.children {
+        for child in self.children() {
             child.write_le(writer, data_indexes)?;
         }
         Ok(())