/// An axis within a pivot table.
#[derive(Default)]
-pub struct TableAxis {
+pub struct Axis {
/// `dimensions[0]` is the innermost dimension.
dimensions: Vec<Dimension>,
/// The number of rows or columns along the axis, that is, the product of
- /// `dimensions[*].n_leaves`. It is 0 if any dimension has 0 leaves.
+ /// `dimensions[*].len()`. It is 0 if any dimension has 0 leaves.
extent: usize,
/// Sum of `dimensions[*].label_depth`.
label_depth: usize,
}
+pub struct AxisCursor<'a> {
+ axis: &'a Axis,
+ indexes: Vec<usize>,
+}
+
+impl<'a> AxisCursor<'a> {
+ fn next(&'a mut self) -> Option<&'a Vec<usize>> {
+ if self.indexes.is_empty() {
+ if self
+ .axis
+ .dimensions
+ .iter()
+ .any(|dimension| dimension.is_empty())
+ {
+ return None;
+ }
+ self.indexes = vec![0; self.axis.dimensions.len()];
+ Some(&self.indexes)
+ } else {
+ for (index, dimension) in self.indexes.iter_mut().zip(self.axis.dimensions.iter()) {
+ *index += 1;
+ if *index < dimension.len() {
+ return Some(&self.indexes);
+ };
+ *index = 0
+ }
+ None
+ }
+ }
+}
+
+impl Axis {
+ fn cursor(&self) -> AxisCursor {
+ AxisCursor {
+ axis: self,
+ indexes: Vec::new(),
+ }
+ }
+}
+
/// Dimensions.
///
/// A [Dimension] identifies the categories associated with a single dimension
label_depth: usize,
}
+impl Dimension {
+ pub fn is_empty(&self) -> bool {
+ self.len() == 0
+ }
+
+ pub fn len(&self) -> usize {
+ self.data_leaves.len()
+ }
+}
+
pub struct Group {
name: Value,
label_depth: usize,
caption: Option<Value>,
notes: Option<String>,
dimensions: Vec<Dimension>,
- axes: EnumMap<Axis3, TableAxis>,
- cells: HashMap<u64, Value>,
+ axes: EnumMap<Axis3, Axis>,
+ cells: HashMap<usize, Value>,
}
impl Table {
cells: HashMap::new(),
}
}
+
+ fn cell_index(&self, data_indexes: &[usize]) -> usize {
+ debug_assert_eq!(data_indexes.len(), self.dimensions.len());
+ let mut index = 0;
+ for (dimension, data_index) in self.dimensions.iter().zip(data_indexes.iter()) {
+ debug_assert!(*data_index < dimension.len());
+ index = dimension.len() * index + data_index;
+ }
+ index
+ }
+
+ fn insert(&mut self, data_indexes: &[usize], value: Value) {
+ self.cells.insert(self.cell_index(data_indexes), value);
+ }
+
+ fn get(&self, data_indexes: &[usize]) -> Option<&Value> {
+ self.cells.get(&self.cell_index(data_indexes))
+ }
}
/// Whether to show variable or value labels or the underlying value or variable name.