format::{F40, F40_2, F40_3, Format, PCT40_1, Settings as FormatSettings},
output::pivot::{
look::{Look, Sizing},
- value::{BareValue, DisplayValue, IntoValueOptions, Value, ValueOptions},
+ value::{BareValue, Value, ValueOptions},
},
settings::{Settings, Show},
variable::Variable,
}
}
+ /// Transposes row and columns.
pub fn transpose(&mut self) {
self.axes.swap(Axis3::X, Axis3::Y);
}
+ /// Returns an iterator through dimensions on the given `axis`.
pub fn axis_dimensions(
&self,
axis: Axis3,
}
None
}
+
+ /// Moves dimension with index `dim_index` from its current axis to
+ /// `new_axis` in position `new_position`.
+ ///
+ /// `dim_index` is an overall dimension index, in the order passed to
+ /// [PivotTable::new] and returned by [PivotTable::dimensions]. This method
+ /// doesn't change these indexes.
+ ///
+ /// `new_position` is an index within `new_axis`, in the range `0..n` where
+ /// `n` is the final number of dimensions along that axis.
+ ///
+ /// # Panic
+ ///
+ /// Panics if `dim_index` or `new_position` is outside the valid range.
pub fn move_dimension(&mut self, dim_index: usize, new_axis: Axis3, new_position: usize) {
let (old_axis, old_position) = self.find_dimension(dim_index).unwrap();
if old_axis == new_axis && old_position == new_position {
}
}
-impl IntoValueOptions for &PivotTable {
- fn into_value_options(self) -> ValueOptions {
+impl From<&PivotTable> for ValueOptions {
+ fn from(value: &PivotTable) -> Self {
ValueOptions {
- show_values: self.style.show_values,
- show_variables: self.style.show_variables,
- small: self.style.small,
- footnote_marker_type: self.style.look.footnote_marker_type,
+ show_values: value.style.show_values,
+ show_variables: value.style.show_variables,
+ small: value.style.small,
+ footnote_marker_type: value.style.look.footnote_marker_type,
}
}
}
pub hide_all_labels: bool,
}
+/// A vector of references to [Group]s.
+///
+/// Used to represent a sequence of groups along a [Path]. This is a [SmallVec]
+/// because groups are usually not deeply nested.
pub type GroupVec<'a> = SmallVec<[&'a Group; 4]>;
+
+/// A path from the root of a [Dimension] to a [Leaf].
pub struct Path<'a> {
+ /// Groups along the path.
groups: GroupVec<'a>,
+
+ /// The leaf.
+ ///
+ /// This is a child of the last [Group].
leaf: &'a Leaf,
}
+/// Group indexes visited along a [Path].
pub type IndexVec = SmallVec<[usize; 4]>;
impl Dimension {
+ /// Constructs a new [Dimension] with the given `root`.
pub fn new(root: Group) -> Self {
Dimension {
presentation_order: (0..root.len()).collect(),
}
}
+ /// Returns this dimension with [Dimension::hide_all_labels] set to true.
+ pub fn with_all_labels_hidden(self) -> Self {
+ Self {
+ hide_all_labels: true,
+ ..self
+ }
+ }
+
+ /// Returns true if [Dimension] has no leaf categories.
+ ///
+ /// A dimension without leaf categories might still contain a hierarchy of
+ /// groups, just none of them with leaves.
pub fn is_empty(&self) -> bool {
self.len() == 0
}
- /// Returns the number of (leaf) categories in this dimension.
+ /// Returns the number of leaf categories in this dimension.
pub fn len(&self) -> usize {
self.root.len()
}
+ /// Returns the leaf with the given 0-based `index`, or `None` if `index >=
+ /// self.len()`.
pub fn nth_leaf(&self, index: usize) -> Option<&Leaf> {
self.root.nth_leaf(index)
}
+ /// Returns the path to the leaf with the given 0-based `index`, or `None`
+ /// if `index >= self.len()`.
pub fn leaf_path(&self, index: usize) -> Option<Path<'_>> {
self.root.leaf_path(index, SmallVec::new())
}
+ /// Returns the series of group child indexes followed to the leaf with the
+ /// given 0-based `index`, or `None` if `index >= self.len()`.
pub fn index_path(&self, index: usize) -> Option<IndexVec> {
self.root.index_path(index, SmallVec::new())
}
-
- pub fn with_all_labels_hidden(self) -> Self {
- Self {
- hide_all_labels: true,
- ..self
- }
- }
}
-/// Specifies a [Category] within a [Group].
+/// Specifies how to find a [Category] within a [Group].
#[derive(Copy, Clone, Debug)]
pub struct CategoryLocator {
/// The index of the leaf to start from.
}
impl CategoryLocator {
+ /// Constructs a `CategoryLocator` for the leaf with the given 0-based
+ /// index.
pub fn new_leaf(leaf_index: usize) -> Self {
Self {
leaf_index,
}
}
+ /// Returns a `CategoryLocator` for the parent category of this one.
pub fn parent(&self) -> Self {
Self {
leaf_index: self.leaf_index,
}
}
+ /// If this is a leaf, returns its 0-based index; otherwise, returns `None`.
pub fn as_leaf(&self) -> Option<usize> {
(self.level == 0).then_some(self.leaf_index)
}
}
+/// A group of categories within a dimension.
#[derive(Clone, Debug, Serialize)]
pub struct Group {
+ /// Number of leaves contained by this group.
#[serde(skip)]
len: usize,
+
+ /// The label displayed for the group.
pub name: Box<Value>,
+ /// Whether to show the label.
+ pub show_label: bool,
+
/// The child categories.
///
/// A group usually has multiple children, but it is allowed to have
/// only one or even (pathologically) none.
pub children: Vec<Category>,
-
- /// Whether to show the group's label.
- pub show_label: bool,
}
impl Group {
+ /// Constructs a new `Group` with the given name. The group initially has
+ /// no children.
pub fn new(name: impl Into<Value>) -> Self {
Self::with_capacity(name, 0)
}
+ /// 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 {
Self {
len: 0,
}
}
+ /// Appends `child` to the group's categories.
pub fn push(&mut self, child: impl Into<Category>) {
let mut child = child.into();
if let Some(group) = child.as_group_mut() {
self.children.push(child);
}
+ /// Returns this group with the given `child` appended to its categories.
pub fn with(mut self, child: impl Into<Category>) -> Self {
self.push(child);
self
}
+ /// Returns this group with the given `children` appended to its categories.
pub fn with_multiple<C>(mut self, children: impl IntoIterator<Item = C>) -> Self
where
C: Into<Category>,
self
}
+ /// Returns this group with `show_label` set to true.
pub fn with_label_shown(self) -> Self {
self.with_show_label(true)
}
+ /// Returns this group with `show_label` set as specified.
pub fn with_show_label(mut self, show_label: bool) -> Self {
self.show_label = show_label;
self
}
- pub fn nth_leaf(&self, mut index: usize) -> Option<&Leaf> {
+ /// Returns the leaf with the given 0-based `index`, or `None` if `index >=
+ /// self.len()`.
+ fn nth_leaf(&self, mut index: usize) -> Option<&Leaf> {
for child in &self.children {
let len = child.len();
if index < len {
None
}
- pub fn leaf_path<'a>(&'a self, mut index: usize, mut groups: GroupVec<'a>) -> Option<Path<'a>> {
+ /// Returns the path to the leaf with the given 0-based `index`, or `None`
+ /// if `index >= self.len()`. `groups` must be the groups already traversed
+ /// to arrive at this group.
+ 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 {
Some(path)
}
- /// Returns `None` if `locator` is invalid (that is, if `locator.leaf_idx >=
- /// self.len` or `locator.level` is greater than the depth of the leaf) or
- /// if `locator` designates `self`.
+ /// Returns the category corresponding to `locator`. Returns `None` if
+ /// `locator` is invalid (that is, if `locator.leaf_idx >= self.len` or
+ /// `locator.level` is greater than the depth of the leaf) or if `locator`
+ /// designates `self`.
pub fn category(&self, locator: CategoryLocator) -> Option<&Category> {
let path = self.locator_path(locator)?;
let mut this = &self.children[*path.get(0)?];
Some(this)
}
+ /// Returns the category corresponding to `locator`. Returns `None` if
+ /// `locator` is invalid (that is, if `locator.leaf_idx >= self.len` or
+ /// `locator.level` is greater than the depth of the leaf) or if `locator`
+ /// designates `self`.
pub fn category_mut(&mut self, locator: CategoryLocator) -> Option<&mut Category> {
let path = self.locator_path(locator)?;
let mut this = &mut self.children[*path.get(0)?];
Some(this)
}
+ /// Returns the number of leaves contained within this group.
pub fn len(&self) -> usize {
self.len
}
+ /// Returns true if this group contains no leaves.
pub fn is_empty(&self) -> bool {
self.len() == 0
}
+ /// Returns this group's label.
pub fn name(&self) -> &Value {
&self.name
}
pub struct Footnotes(Vec<Arc<Footnote>>);
impl Footnotes {
+ /// Constructs a new, empty collection of footnotes.
pub fn new() -> Self {
Self::default()
}
- pub fn push(&mut self, footnote: Footnote) -> Arc<Footnote> {
- let footnote = Arc::new(footnote.with_index(self.0.len()));
- self.0.push(footnote.clone());
- footnote
+ /// Returns the number of footnotes in the collection.
+ pub fn len(&self) -> usize {
+ self.0.len()
}
+ /// Returns true if the collection contains no footnotes.
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
- pub fn len(&self) -> usize {
- self.0.len()
+ /// Adds `footnote` to the collection.
+ pub fn push(&mut self, footnote: Footnote) -> Arc<Footnote> {
+ let footnote = Arc::new(footnote.with_index(self.0.len()));
+ self.0.push(footnote.clone());
+ footnote
}
+ /// Returns the footnote with 0-based index `index`, or `None` if `index >=
+ /// self.len()`.
pub fn get(&self, index: usize) -> Option<&Arc<Footnote>> {
self.0.get(index)
}
}
}
+/// A leaf category within a [Group] and ultimately within a [Dimension].
#[derive(Clone, Debug)]
-pub struct Leaf(Box<Value>);
+pub struct Leaf(pub Box<Value>);
impl Leaf {
+ /// Constructs a new `Leaf` with the given label.
pub fn new(name: Value) -> Self {
Self(Box::new(name))
}
+
+ /// Returns the leaf's label.
pub fn name(&self) -> &Value {
&self.0
}
/// Pivot result classes.
///
-/// These are used to mark [Leaf] categories as having particular types of data,
-/// to set their numeric formats.
+/// Used by [PivotTable::insert_number].
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Class {
- Other,
+ /// An integer value.
Integer,
+ /// A correlation value.
Correlations,
+ /// A measure of significance.
Significance,
+ /// A percentage.
Percent,
+ /// A residual value.
Residual,
+ /// A count.
+ ///
+ /// With a weighted dataset, these are by default displayed with the weight
+ /// variable's format.
Count,
+ /// A value that doesn't fit in one of the other categories.
+ Other,
}
/// A leaf category or a group of them.
#[derive(Clone, Debug, Serialize)]
pub enum Category {
- Group(Group),
- Leaf(Leaf),
+ /// A group.
+ Group(
+ /// The group.
+ Group,
+ ),
+ /// A leaf.
+ Leaf(
+ /// The leaf.
+ Leaf,
+ ),
}
impl Category {
+ /// Returns the [Group] in this `Category`, if there is one.
pub fn as_group(&self) -> Option<&Group> {
match self {
Category::Group(group) => Some(group),
}
}
+ /// Returns the [Group] in this `Category`, if there is one, for
+ /// modification.
pub fn as_group_mut(&mut self) -> Option<&mut Group> {
match self {
Category::Group(group) => Some(group),
}
}
+ /// Returns the [Leaf] in this `Category`, if there is one.
pub fn as_leaf(&self) -> Option<&Leaf> {
match self {
Category::Leaf(leaf) => Some(leaf),
}
}
+ /// Returns the [Leaf] in this `Category`, if there is one, for
+ /// modification.
pub fn as_leaf_mut(&mut self) -> Option<&mut Leaf> {
match self {
Category::Leaf(leaf) => Some(leaf),
}
}
+ /// Returns the category's label.
pub fn name(&self) -> &Value {
match self {
Category::Group(group) => &group.name,
}
}
+ /// Returns the category's label, for modification.
pub fn name_mut(&mut self) -> &mut Value {
match self {
Category::Group(group) => &mut group.name,
}
}
+ /// Returns true if this category's label should be shown.
+ ///
+ /// A leaf category's label is always shown, unless
+ /// [Dimension::hide_all_labels] is true.
+ pub fn show_label(&self) -> bool {
+ match self {
+ Category::Group(group) => group.show_label,
+ Category::Leaf(_) => true,
+ }
+ }
+ /// Returns true if the category contains no leaves.
+ ///
+ /// If this is a leaf category, this always returns false.
pub fn is_empty(&self) -> bool {
self.len() == 0
}
+ /// Returns the number of leaves that this category contains.
pub fn len(&self) -> usize {
match self {
Category::Group(group) => group.len,
}
}
- pub fn nth_leaf(&self, index: usize) -> Option<&Leaf> {
+ fn nth_leaf(&self, index: usize) -> Option<&Leaf> {
match self {
Category::Group(group) => group.nth_leaf(index),
Category::Leaf(leaf) if index == 0 => Some(leaf),
}
}
- pub fn leaf_path<'a>(&'a self, index: usize, groups: GroupVec<'a>) -> Option<Path<'a>> {
+ 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 }),
/// Returns `None` if `locator` is invalid (that is, if `locator.leaf_idx >=
/// self.len` or `locator.level` is greater than the depth of the leaf).
- pub fn category(&self, locator: CategoryLocator) -> Option<&Category> {
+ fn category(&self, locator: CategoryLocator) -> Option<&Category> {
let mut this = self;
for index in this.locator_path(locator)? {
this = &this.as_group().unwrap().children[index];
Some(this)
}
- pub fn category_mut(&mut self, locator: CategoryLocator) -> Option<&mut Category> {
+ fn category_mut(&mut self, locator: CategoryLocator) -> Option<&mut Category> {
let mut this = self;
for index in this.locator_path(locator)? {
this = &mut this.as_group_mut().unwrap().children[index];
}
Some(this)
}
-
- pub fn show_label(&self) -> bool {
- match self {
- Category::Group(group) => group.show_label,
- Category::Leaf(_) => true,
- }
- }
}
impl From<Group> for Category {
#[derive(Copy, Clone, Debug, Enum, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Axis2 {
+ /// X axis.
X,
+ /// Y axis.
Y,
}
impl Axis2 {
+ /// Returns a map from [Axis2::X] to `x` and from [Axis2::Y] to `y`.
pub fn new_enum<T>(x: T, y: T) -> EnumMap<Axis2, T> {
EnumMap::from_array([x, y])
}
+ /// Returns the axis's name, in lowercase, as a static string.
pub fn as_str(&self) -> &'static str {
match self {
Axis2::X => "x",
pub struct Coord2(pub EnumMap<Axis2, isize>);
impl Coord2 {
+ /// Constructs a new `Coord2` with the given `x` and `y` coordinates.
pub fn new(x: isize, y: isize) -> Self {
use Axis2::*;
Self(enum_map! {
})
}
+ /// Constructs a new `Coord2` with coordinate `az` on axis `a` and
+ /// coordinate `bz` on the other axis.
pub fn for_axis((a, az): (Axis2, isize), bz: isize) -> Self {
let mut coord = Self::default();
coord[a] = az;
coord
}
+ /// Constructs a new `Coord2` with coordinates from function `f`.
pub fn from_fn<F>(f: F) -> Self
where
F: FnMut(Axis2) -> isize,
Self(EnumMap::from_fn(f))
}
+ /// Returns the X coordinate.
pub fn x(&self) -> isize {
self.0[Axis2::X]
}
+ /// Returns the Y coordinate.
pub fn y(&self) -> isize {
self.0[Axis2::Y]
}
+ /// Returns the coordinate on the given `axis`.
pub fn get(&self, axis: Axis2) -> isize {
self.0[axis]
}
}
}
+/// A 2-dimensional rectangle.
#[derive(Clone, Debug, Default)]
-pub struct Rect2(pub EnumMap<Axis2, Range<isize>>);
+pub struct Rect2(
+ /// The range along each axis.
+ pub EnumMap<Axis2, Range<isize>>,
+);
impl Rect2 {
+ /// Constructs a new `Rect2` that covers the given X and Y ranges.
pub fn new(x_range: Range<isize>, y_range: Range<isize>) -> Self {
Self(enum_map! {
Axis2::X => x_range.clone(),
Axis2::Y => y_range.clone(),
})
}
- pub fn for_cell(cell: Coord2) -> Self {
- Self::new(cell.x()..cell.x() + 1, cell.y()..cell.y() + 1)
- }
+
+ /// Construct a new `Rect2` that covers `a_range` along axis `a` and
+ /// `b_range` along the other axis.
pub fn for_ranges((a, a_range): (Axis2, Range<isize>), b_range: Range<isize>) -> Self {
let b = !a;
let mut ranges = EnumMap::default();
ranges[b] = b_range;
Self(ranges)
}
+
+ /// Returns the top-left corner of the rectangle.
pub fn top_left(&self) -> Coord2 {
use Axis2::*;
Coord2::new(self[X].start, self[Y].start)
}
+
+ /// Construct a new `Rect2` that covers the ranges returned by `f`.
pub fn from_fn<F>(f: F) -> Self
where
F: FnMut(Axis2) -> Range<isize>,
{
Self(EnumMap::from_fn(f))
}
+
+ /// Shifts the rectangle by `offset` along its axes.
pub fn translate(self, offset: Coord2) -> Rect2 {
Self::from_fn(|axis| self[axis].start + offset[axis]..self[axis].end + offset[axis])
}
+
+ /// Returns true if the rectangle is empty.
pub fn is_empty(&self) -> bool {
self[Axis2::X].is_empty() || self[Axis2::Y].is_empty()
}
}
}
+/// What to show in a footnote marker.
#[derive(Copy, Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub enum FootnoteMarkerType {
Numeric,
}
+/// How to show a footnote marker.
#[derive(Copy, Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub enum FootnoteMarkerPosition {
/// [DatumValue::honor_small]: value::DatumValue::honor_small
pub small: f64,
+ /// The format to use for weight and count variables.
pub weight_format: Format,
}
}
impl PivotTableStyle {
- fn with_look(self, look: Arc<Look>) -> Self {
+ /// Returns this style with the given `look`.
+ pub fn with_look(self, look: Arc<Look>) -> Self {
Self { look, ..self }
}
- fn with_show_values(self, show_values: Option<Show>) -> Self {
+
+ /// Returns this style with the given `show_values`.
+ pub fn with_show_values(self, show_values: Option<Show>) -> Self {
Self {
show_values,
..self
}
}
- fn with_show_variables(self, show_variables: Option<Show>) -> Self {
+
+ /// Returns this style with the given `show_variables`.
+ pub fn with_show_variables(self, show_variables: Option<Show>) -> Self {
Self {
show_variables,
..self
}
}
- fn with_show_title(self, show_title: bool) -> Self {
+
+ /// Returns this style with the given `show_title`.
+ pub fn with_show_title(self, show_title: bool) -> Self {
Self { show_title, ..self }
}
- fn with_show_caption(self, show_caption: bool) -> Self {
+
+ /// Returns this style with the given `show_caption`.
+ pub fn with_show_caption(self, show_caption: bool) -> Self {
Self {
show_caption,
..self
}
}
+
+ /// Returns a mutable reference to this style's [Look].
+ ///
+ /// This unshares the [Arc] used to refer to the [Look].
pub fn look_mut(&mut self) -> &mut Look {
Arc::make_mut(&mut self.look)
}
}
impl PivotTableMetadata {
+ /// Return this metadata with the given `subtype`.
pub fn with_subtype(self, subtype: impl Into<Value>) -> Self {
Self {
subtype: Some(Box::new(subtype.into())),
}
}
+/// A pivot table.
+///
+/// Pivot tables are PSPP's primary form of output. They are analogous to the
+/// pivot tables you might be familiar with from spreadsheets and databases.
+/// See <https://en.wikipedia.org/wiki/Pivot_table> for a brief introduction to
+/// the overall concept of a pivot table.
#[derive(Clone, Debug, Serialize)]
pub struct PivotTable {
+ /// Style.
pub style: PivotTableStyle,
/// Current layer indexes, with `axes[Axis3::Z].dimensions.len()` elements.
/// corresponding leaf.
layer: Vec<usize>,
+ /// Metadata.
pub metadata: PivotTableMetadata,
+
+ /// Footnotes.
pub footnotes: Footnotes,
+
+ /// Dimensions.
dimensions: Vec<Dimension>,
+
+ /// Axes.
axes: EnumMap<Axis3, Axis>,
+
+ /// Data.
cells: HashMap<usize, Value>,
}
}
}
+/// A type that can calculate the index into a [PivotTable]'s data hashmap.
pub trait CellIndex {
+ /// Given the pivot table's `dimensions`, returns an index.
fn cell_index<I>(self, dimensions: I) -> usize
where
I: ExactSizeIterator<Item = usize>;
}
}
-pub struct PrecomputedIndex(pub usize);
+/// A precomputed index.
+pub struct PrecomputedIndex(
+ /// The index.
+ pub usize,
+);
impl CellIndex for PrecomputedIndex {
fn cell_index<I>(self, _dimensions: I) -> usize
}
}
+/// A footnote in a [PivotTable].
+///
+/// A footnote is attached directly to a [Value], but it will only be displayed
+/// correctly if it is also added to [PivotTable::footnotes] for its pivot
+/// table.
#[derive(Clone, Debug, Serialize, PartialEq)]
pub struct Footnote {
+ /// The index within [Footnotes].
#[serde(skip)]
index: usize,
+
+ /// The footnote text.
pub content: Box<Value>,
+
+ /// The footnote marker.
+ ///
+ /// This is usually `None`, in which case [FootnoteMarkerType] determines
+ /// the default marker.
pub marker: Option<Box<Value>>,
+
+ /// Whether to show the footnote.
pub show: bool,
}
impl Footnote {
+ /// Constructs a new footnote.
pub fn new(content: impl Into<Value>) -> Self {
Self {
index: 0,
show: true,
}
}
+
+ /// Returns the footnote with the given optional marker.
pub fn with_marker(self, marker: Option<Value>) -> Self {
Self {
marker: marker.map(Box::new),
..self
}
}
+
+ /// Returns the footnote with the given marker.
pub fn with_some_marker(self, marker: impl Into<Value>) -> Self {
Self::with_marker(self, Some(marker.into()))
}
+ /// Return the footnote with the given `show`.
pub fn with_show(self, show: bool) -> Self {
Self { show, ..self }
}
+ /// Return the footnote with the given `index`.
pub fn with_index(self, index: usize) -> Self {
Self { index, ..self }
}
- pub fn display_marker(&self, options: impl IntoValueOptions) -> DisplayMarker<'_> {
+ /// Returns an object for formatting the footnote's marker.
+ pub fn display_marker(&self, options: impl Into<ValueOptions>) -> impl Display {
DisplayMarker {
footnote: self,
- options: options.into_value_options(),
+ options: options.into(),
}
}
- pub fn display_content(&self, options: impl IntoValueOptions) -> DisplayValue<'_> {
+ /// Returns an object for formatting the footnote's text.
+ pub fn display_content(&self, options: impl Into<ValueOptions>) -> impl Display {
self.content.display(options)
}
+ /// Returns the footnote's index.
pub fn index(&self) -> usize {
self.index
}
}
}
-pub struct DisplayMarker<'a> {
+struct DisplayMarker<'a> {
footnote: &'a Footnote,
options: ValueOptions,
}
}
}
+/// An entry in a metadata table.
pub struct MetadataEntry {
+ /// The label for the entry.
pub name: Value,
+
+ /// The value for the entry.
pub value: MetadataValue,
}
impl MetadataEntry {
+ /// Constructs a new metadata entry with the given name and value.
pub fn new(name: impl Into<Value>, value: MetadataValue) -> Self {
Self {
name: name.into(),
value,
}
}
+
+ /// Converts the metadata entry into a pivot table.
pub fn into_pivot_table(self) -> PivotTable {
let mut data = Vec::new();
let group = match self.visit(&mut data) {
}
}
+/// A value in a metadata table.
pub enum MetadataValue {
- Leaf(Value),
- Group(Vec<MetadataEntry>),
+ /// A value.
+ Leaf(
+ /// The value.
+ Value,
+ ),
+ /// A nested group of entries.
+ Group(
+ /// The entries.
+ Vec<MetadataEntry>,
+ ),
}
impl MetadataValue {
+ /// Construct a new "leaf" metadata value.
pub fn new_leaf(value: impl Into<Value>) -> Self {
Self::Leaf(value.into())
}