iter::{once, repeat, repeat_n, FusedIterator},
ops::{Index, IndexMut, Not, Range, RangeInclusive},
str::{from_utf8, FromStr, Utf8Error},
- sync::{Arc, OnceLock, Weak},
+ sync::{Arc, OnceLock},
};
use binrw::Error as BinError;
///
/// The root must always be a group, although it is allowed to have no
/// subcategories.
- pub root: Arc<Group>,
+ pub root: Group,
/// Ordering of leaves for presentation.
///
hide_all_labels: bool,
}
+pub type GroupVec<'a> = SmallVec<[&'a Group; 4]>;
+pub struct Path<'a> {
+ groups: GroupVec<'a>,
+ leaf: &'a Leaf,
+}
+
impl Dimension {
pub fn is_empty(&self) -> bool {
self.len() == 0
self.root.nth_leaf(index)
}
+ pub fn leaf_path(&self, index: usize) -> Option<Path<'_>> {
+ self.root.leaf_path(index, SmallVec::new())
+ }
+
pub fn builder(axis: Axis3, root: GroupBuilder) -> DimensionBuilder {
DimensionBuilder::new(axis, root)
}
#[derive(Clone, Debug)]
pub struct Group {
- parent: Option<Weak<Group>>,
len: usize,
name: Box<Value>,
GroupBuilder::new(name)
}
- pub fn parent(&self) -> Option<Arc<Group>> {
- self.parent.as_ref().map(|parent| parent.upgrade().unwrap())
- }
-
pub fn nth_leaf(&self, mut index: usize) -> Option<&Leaf> {
for child in &self.children {
let len = child.len();
None
}
+ pub fn leaf_path<'a>(&'a self, mut index: usize, mut groups: GroupVec<'a>) -> Option<Path<'a>> {
+ for child in &self.children {
+ let len = child.len();
+ if index < len {
+ groups.push(self);
+ return child.leaf_path(index, groups);
+ }
+ index -= len;
+ }
+ None
+ }
+
pub fn len(&self) -> usize {
self.len
}
impl DimensionBuilder {
pub fn new(axis: Axis3, root: GroupBuilder) -> Self {
- let root = root.build(None);
+ let root = root.build(true);
Self {
axis,
dimension: Dimension {
fn len(&self) -> usize {
self.children.iter().map(|category| category.len()).sum()
}
- fn build(self, parent: Option<Weak<Group>>) -> Arc<Group> {
- Arc::new_cyclic(|weak| Group {
+ fn build(self, is_root: bool) -> Group {
+ Group {
len: self.children.iter().map(|c| c.len()).sum(),
name: self.name,
- children: self
- .children
- .into_iter()
- .map(|c| c.build(weak.clone()))
- .collect(),
+ children: self.children.into_iter().map(|c| c.build()).collect(),
show_label: {
// By default, nested group labels are shown, but not dimension root labels.
- self.show_label.unwrap_or(parent.is_some())
+ self.show_label.unwrap_or(!is_root)
},
- parent,
- })
+ }
}
}
CategoryBuilder::Leaf { .. } => 1,
}
}
- fn build(self, parent: Weak<Group>) -> Category {
+ fn build(self) -> Category {
match self {
- Self::Group(group) => Category::Group(group.build(Some(parent))),
+ Self::Group(group) => Category::Group(group.build(false)),
Self::Leaf { name, class } => {
- let leaf = Arc::new(Leaf {
- parent,
- name,
- class,
- });
+ let leaf = Arc::new(Leaf { name, class });
Category::Leaf(leaf)
}
}
#[derive(Clone, Debug)]
pub struct Leaf {
- parent: Weak<Group>,
name: Box<Value>,
/// Default format for values in this category.
impl Leaf {
pub fn new(name: Value) -> Self {
Self {
- parent: Weak::new(),
name: Box::new(name),
class: None,
}
..self
}
}
- pub fn ancestors(&self) -> impl Iterator<Item = Arc<Group>> {
- std::iter::successors(self.parent(), |group| group.parent())
- }
}
/// Pivot result classes.
/// A pivot_category is a leaf (a category) or a group.
#[derive(Clone, Debug)]
pub enum Category {
- Group(Arc<Group>),
+ Group(Group),
Leaf(Arc<Leaf>),
}
fn len(&self) -> usize {
match self {
Category::Group(group) => group.len,
- Category::Leaf(leaf) => 1,
+ Category::Leaf(_) => 1,
}
}
}
}
+ fn leaf_path<'a>(&'a self, index: usize, groups: GroupVec<'a>) -> Option<Path<'a>> {
+ match self {
+ Category::Group(group) => group.leaf_path(index, groups),
+ Category::Leaf(leaf) => {
+ if index == 0 {
+ Some(Path {
+ groups,
+ leaf: &leaf,
+ })
+ } else {
+ None
+ }
+ }
+ }
+ }
+
fn show_label(&self) -> bool {
match self {
Category::Group(group) => group.show_label,
trait CategoryTrait {
fn name(&self) -> &Value;
- fn parent(&self) -> Option<Arc<Group>>;
}
impl CategoryTrait for Group {
fn name(&self) -> &Value {
&self.name
}
-
- fn parent(&self) -> Option<Arc<Group>> {
- self.parent.as_ref().and_then(|parent| parent.upgrade())
- }
}
impl CategoryTrait for Leaf {
fn name(&self) -> &Value {
&self.name
}
-
- fn parent(&self) -> Option<Arc<Group>> {
- Some(self.parent.upgrade().unwrap())
- }
}
impl CategoryTrait for Category {
Category::Leaf(leaf) => leaf.name(),
}
}
-
- fn parent(&self) -> Option<Arc<Group>> {
- match self {
- Category::Group(group) => group.parent(),
- Category::Leaf(leaf) => leaf.parent(),
- }
- }
}
/// Styling for a pivot table.
use enum_map::{enum_map, EnumMap};
use itertools::Itertools;
-use smallvec::SmallVec;
use crate::output::{
- pivot::{Group, HeadingRegion, LabelPosition, Leaf},
+ pivot::{HeadingRegion, LabelPosition, Path},
table::{CellInner, Table},
};
pub footnotes: Option<Table>,
}
-struct HeadingColumn<'a> {
- leaf: &'a Leaf,
- groups: SmallVec<[Arc<Group>; 4]>,
-}
-
-impl HeadingColumn<'_> {
+impl Path<'_> {
pub fn get(&self, y: usize, height: usize) -> Option<&Value> {
if y + 1 == height {
Some(&self.leaf.name)
struct Heading<'a> {
dimension: &'a Dimension,
height: usize,
- columns: Vec<HeadingColumn<'a>>,
+ columns: Vec<Path<'a>>,
}
impl<'a> Heading<'a> {
let mut columns = Vec::new();
let mut height = 0;
for indexes in column_enumeration.iter() {
- let leaf = dimension
- .nth_leaf(dimension.presentation_order[indexes[dim_index]])
+ let mut path = dimension
+ .leaf_path(dimension.presentation_order[indexes[dim_index]])
.unwrap();
- let mut groups = leaf
- .ancestors()
- .filter(|group| group.show_label)
- .collect::<SmallVec<_>>();
- groups.reverse();
- height = height.max(1 + groups.len());
- columns.push(HeadingColumn { leaf, groups });
+ path.groups.retain(|group| group.show_label);
+ height = height.max(1 + path.groups.len());
+ columns.push(path);
}
Some(Self {