From 2800c88d51da9ca7d33eccc0428bc5574edb01f7 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Tue, 2 Dec 2025 08:43:49 -0800 Subject: [PATCH] renaming --- rust/pspp/src/output/drivers/csv.rs | 6 +- rust/pspp/src/output/drivers/html.rs | 14 ++-- rust/pspp/src/output/pivot.rs | 72 ++------------------ rust/pspp/src/output/pivot/output.rs | 16 ++--- rust/pspp/src/output/render.rs | 44 ++++++------- rust/pspp/src/output/table.rs | 99 ++++++++++++++++++++++------ 6 files changed, 125 insertions(+), 126 deletions(-) diff --git a/rust/pspp/src/output/drivers/csv.rs b/rust/pspp/src/output/drivers/csv.rs index f756b36b2b..738f50e73f 100644 --- a/rust/pspp/src/output/drivers/csv.rs +++ b/rust/pspp/src/output/drivers/csv.rs @@ -32,9 +32,7 @@ use crate::{ dictionary::Dictionary, format::{DisplayPlain, Type}, output::{ - Item, - drivers::Driver, - pivot::{ Index2}, + drivers::Driver, table::CellPos, Item }, util::ToSmallString as _, variable::Variable, @@ -336,7 +334,7 @@ impl CsvDriver { write!(&mut self.file, "{}", self.options.delimiter)?; } - let coord = Index2::new(x, y); + let coord = CellPos::new(x, y); let content = table.get(coord); if content.is_top_left() { let display = content.inner().value.display(pivot_table); diff --git a/rust/pspp/src/output/drivers/html.rs b/rust/pspp/src/output/drivers/html.rs index 4ea1a8e638..e0d2b9245c 100644 --- a/rust/pspp/src/output/drivers/html.rs +++ b/rust/pspp/src/output/drivers/html.rs @@ -28,8 +28,8 @@ use smallstr::SmallString; use crate::output::{ drivers::Driver, pivot::{ - Axis2, BorderStyle, Color, HorzAlign, Index2, IndexRect2, PivotTable, Stroke, VertAlign - }, table::{DrawCell, Table}, Details, Item + Axis2, BorderStyle, Color, HorzAlign, IndexRect2, PivotTable, Stroke, VertAlign + }, table::{DrawCell, CellPos, Table}, Details, Item }; #[derive(Clone, Debug, Deserialize, Serialize)] @@ -85,7 +85,7 @@ where writeln!(&mut self.writer, ">")?; if let Some(title) = output.title { - let cell = title.get(Index2::new(0, 0)); + let cell = title.get(CellPos::new(0, 0)); self.put_cell( DrawCell::new(cell.inner(), &title), IndexRect2::new(0..1, 0..1), @@ -113,7 +113,7 @@ where for y in 0..output.body.n.y() { writeln!(&mut self.writer, "")?; for x in output.body.iter_x(y) { - let cell = output.body.get(Index2::new(x, y)); + let cell = output.body.get(CellPos::new(x, y)); if cell.is_top_left() { let is_header = x < output.body.h[Axis2::X] || y < output.body.h[Axis2::Y]; let tag = if is_header { "th" } else { "td" }; @@ -134,7 +134,7 @@ where writeln!(&mut self.writer, "")?; if let Some(caption) = output.caption { self.put_cell( - DrawCell::new(caption.get(Index2::new(0, 0)).inner(), &caption), + DrawCell::new(caption.get(CellPos::new(0, 0)).inner(), &caption), IndexRect2::new(0..output.body.n[Axis2::X], 0..1), "td", None, @@ -236,7 +236,7 @@ where &mut style, table.get_rule( Axis2::X, - Index2::new(rect[Axis2::X].end, rect[Axis2::Y].start), + CellPos::new(rect[Axis2::X].end, rect[Axis2::Y].start), ), "right", ); @@ -246,7 +246,7 @@ where &mut style, table.get_rule( Axis2::Y, - Index2::new(rect[Axis2::X].start, rect[Axis2::Y].end), + CellPos::new(rect[Axis2::X].start, rect[Axis2::Y].end), ), "bottom", ); diff --git a/rust/pspp/src/output/pivot.rs b/rust/pspp/src/output/pivot.rs index 1c14d1c819..756098f173 100644 --- a/rust/pspp/src/output/pivot.rs +++ b/rust/pspp/src/output/pivot.rs @@ -76,10 +76,9 @@ use crate::{ calendar::date_time_to_pspp, data::{ByteString, Datum, EncodedString}, format::{ - DATETIME40_0, Decimal, F8_2, F40, F40_2, F40_3, Format, PCT40_1, - Settings as FormatSettings, Type, UncheckedFormat, + Decimal, Format, Settings as FormatSettings, Type, UncheckedFormat, DATETIME40_0, F40, F40_2, F40_3, F8_2, PCT40_1 }, - output::spv::html::Markup, + output::{spv::html::Markup, table::CellPos}, settings::{Settings, Show}, util::ToSmallString, variable::{VarType, Variable}, @@ -1606,65 +1605,6 @@ impl TryFrom for Axis2 { } } -#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)] -pub struct Index2(pub EnumMap); - -impl Index2 { - pub fn new(x: usize, y: usize) -> Self { - use Axis2::*; - Self(enum_map! { - X => x, - Y => y - }) - } - - pub fn for_axis((a, az): (Axis2, usize), bz: usize) -> Self { - let mut coord = Self::default(); - coord[a] = az; - coord[!a] = bz; - coord - } - - pub fn from_fn(f: F) -> Self - where - F: FnMut(Axis2) -> usize, - { - Self(EnumMap::from_fn(f)) - } - - pub fn x(&self) -> usize { - self.0[Axis2::X] - } - - pub fn y(&self) -> usize { - self.0[Axis2::Y] - } - - pub fn get(&self, axis: Axis2) -> usize { - self.0[axis] - } -} - -impl From> for Index2 { - fn from(value: EnumMap) -> Self { - Self(value) - } -} - -impl Index for Index2 { - type Output = usize; - - fn index(&self, index: Axis2) -> &Self::Output { - &self.0[index] - } -} - -impl IndexMut for Index2 { - fn index_mut(&mut self, index: Axis2) -> &mut Self::Output { - &mut self.0[index] - } -} - /// A 2-dimensional `(x,y)` pair. #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)] pub struct Coord2(pub EnumMap); @@ -1793,7 +1733,7 @@ impl IndexRect2 { Axis2::Y => y_range.clone(), }) } - pub fn for_cell(cell: Index2) -> Self { + pub fn for_cell(cell: CellPos) -> Self { Self::new(cell.x()..cell.x() + 1, cell.y()..cell.y() + 1) } pub fn for_ranges((a, a_range): (Axis2, Range), b_range: Range) -> Self { @@ -1803,9 +1743,9 @@ impl IndexRect2 { ranges[b] = b_range; Self(ranges) } - pub fn top_left(&self) -> Index2 { + pub fn top_left(&self) -> CellPos { use Axis2::*; - Index2::new(self[X].start, self[Y].start) + CellPos::new(self[X].start, self[Y].start) } pub fn from_fn(f: F) -> Self where @@ -1813,7 +1753,7 @@ impl IndexRect2 { { Self(EnumMap::from_fn(f)) } - pub fn translate(self, offset: Index2) -> IndexRect2 { + pub fn translate(self, offset: CellPos) -> IndexRect2 { Self::from_fn(|axis| self[axis].start + offset[axis]..self[axis].end + offset[axis]) } pub fn is_empty(&self) -> bool { diff --git a/rust/pspp/src/output/pivot/output.rs b/rust/pspp/src/output/pivot/output.rs index b19fa9ae92..a37f0cbda4 100644 --- a/rust/pspp/src/output/pivot/output.rs +++ b/rust/pspp/src/output/pivot/output.rs @@ -20,8 +20,8 @@ use enum_map::{EnumMap, enum_map}; use itertools::Itertools; use crate::output::{ - pivot::{HeadingRegion, Index2, IndexRect2, LabelPosition, Path, RowParity}, - table::{CellInner, Table}, + pivot::{HeadingRegion, IndexRect2, LabelPosition, Path, RowParity}, + table::{CellInner, CellPos, Table}, }; use super::{ @@ -139,15 +139,15 @@ impl PivotTable { I: Iterator> + ExactSizeIterator, { let mut table = Table::new( - Index2::new(1, rows.len()), - Index2::new(0, 0), + CellPos::new(1, rows.len()), + CellPos::new(0, 0), self.style.look.areas.clone(), self.borders(false), self.into_value_options(), ); for (y, row) in rows.enumerate() { table.put( - IndexRect2::for_cell(Index2::new(0, y)), + IndexRect2::for_cell(CellPos::new(0, y)), CellInner::new(area, row), ); } @@ -178,13 +178,13 @@ impl PivotTable { pub fn output_body(&self, layer_indexes: &[usize], printing: bool) -> Table { let headings = EnumMap::from_fn(|axis| Headings::new(self, axis, layer_indexes)); - let data = Index2::from_fn(|axis| headings[axis].width()); - let mut stub = Index2::from_fn(|axis| headings[!axis].height()); + let data = CellPos::from_fn(|axis| headings[axis].width()); + let mut stub = CellPos::from_fn(|axis| headings[!axis].height()); if headings[Axis2::Y].row_label_position == LabelPosition::Corner && stub.y() == 0 { stub[Axis2::Y] = 1; } let mut body = Table::new( - Index2::from_fn(|axis| data[axis] + stub[axis]), + CellPos::from_fn(|axis| data[axis] + stub[axis]), stub, self.style.look.areas.clone(), self.borders(printing), diff --git a/rust/pspp/src/output/render.rs b/rust/pspp/src/output/render.rs index 8a687ca836..f96b44e34b 100644 --- a/rust/pspp/src/output/render.rs +++ b/rust/pspp/src/output/render.rs @@ -25,8 +25,8 @@ use itertools::interleave; use num::Integer; use smallvec::SmallVec; -use crate::output::pivot::{Index2, IndexRect2, VertAlign}; -use crate::output::table::DrawCell; +use crate::output::pivot::{IndexRect2, VertAlign}; +use crate::output::table::{DrawCell, CellPos}; use super::pivot::{Axis2, BorderStyle, Coord2, Look, PivotTable, Rect2, Stroke}; use super::table::{Content, Table}; @@ -187,10 +187,10 @@ struct Page { /// Size of the table in cells. /// - n: Index2, + n: CellPos, /// Header size. Cells `0..h[X]` are rendered horizontally, and `0..h[Y]` vertically. - h: Index2, + h: CellPos, /// Main region of cells to render. r: IndexRect2, @@ -293,7 +293,7 @@ struct Page { /// ``` /// Each entry maps from a cell that overflows to the space that has been /// trimmed off the cell. - overflows: HashMap>, + overflows: HashMap>, /// If a single column (or row) is too wide (or tall) to fit on a page /// reasonably, then [Break::next] will split a single row or column across @@ -620,7 +620,7 @@ impl Page { *self.cp[axis].last().unwrap() } - fn new_mappings(h: Index2, r: &IndexRect2) -> EnumMap { + fn new_mappings(h: CellPos, r: &IndexRect2) -> EnumMap { EnumMap::from_fn(|axis| { [ Map { @@ -651,11 +651,11 @@ impl Page { z + self.get_map(axis, z).ofs } - fn map_coord(&self, coord: Index2) -> Index2 { - Index2::from_fn(|a| self.map_z(a, coord[a])) + fn map_coord(&self, coord: CellPos) -> CellPos { + CellPos::from_fn(|a| self.map_z(a, coord[a])) } - fn get_cell(&self, coord: Index2) -> RenderCell<'_> { + fn get_cell(&self, coord: CellPos) -> RenderCell<'_> { let maps = EnumMap::from_fn(|axis| self.get_map(axis, coord[axis])); let cell = self.table.get(self.map_coord(coord)); RenderCell { @@ -760,7 +760,7 @@ impl Page { if self.h[a] == 0 || z0 > self.h[a] || pixel0 > 0 { let mut z = 0; while z < self.n[b] { - let d = Index2::for_axis((a, z0), z); + let d = CellPos::for_axis((a, z0), z); let cell = self.get_cell(d); let overflow0 = pixel0 > 0 || cell.rect[a].start < z0; let overflow1 = cell.rect[a].end > z1 || (cell.rect[a].end == z1 && pixel1 > 0); @@ -787,7 +787,7 @@ impl Page { // Add overflows along the right side. let mut z = 0; while z < self.n[b] { - let d = Index2::for_axis((a, z1 - 1), z); + let d = CellPos::for_axis((a, z1 - 1), z); let cell = self.get_cell(d); if cell.rect[a].end > z1 || (cell.rect[a].end == z1 && pixel1 > 0) @@ -849,7 +849,7 @@ impl Page { let mut x = cells[X].start; while x < cells[X].end { if !is_rule(x) && !is_rule(y) { - let cell = self.get_cell(Index2::new(x / 2, y / 2)); + let cell = self.get_cell(CellPos::new(x / 2, y / 2)); self.draw_cell(device, ofs, &cell); x = rule_ofs(cell.rect[X].end); } else { @@ -861,13 +861,13 @@ impl Page { for y in cells[Y].clone() { for x in cells[X].clone() { if is_rule(x) || is_rule(y) { - self.draw_rule(device, ofs, Index2::new(x, y)); + self.draw_rule(device, ofs, CellPos::new(x, y)); } } } } - fn draw_rule(&self, device: &mut dyn Device, ofs: Coord2, coord: Index2) { + fn draw_rule(&self, device: &mut dyn Device, ofs: Coord2, coord: CellPos) { const NO_BORDER: BorderStyle = BorderStyle::none(); let styles = EnumMap::from_fn(|a: Axis2| { let b = !a; @@ -908,15 +908,15 @@ impl Page { } } - fn get_rule(&self, a: Axis2, coord: Index2) -> BorderStyle { - let coord = Index2::from_fn(|a| coord[a] / 2); + fn get_rule(&self, a: Axis2, coord: CellPos) -> BorderStyle { + let coord = CellPos::from_fn(|a| coord[a] / 2); let coord = self.map_coord(coord); let border = self.table.get_rule(a, coord); if self.h[a] > 0 && coord[a] == self.h[a] { let border2 = self .table - .get_rule(a, Index2::for_axis((a, self.h[a]), coord[!a])); + .get_rule(a, CellPos::for_axis((a, self.h[a]), coord[!a])); border.combine(border2) } else { border @@ -982,7 +982,7 @@ struct Selection { z1: usize, p0: isize, p1: isize, - h: Index2, + h: CellPos, } impl Selection { @@ -990,11 +990,11 @@ impl Selection { /// /// `coord` must be in the selected region or the results will not make /// sense. - fn coord_to_subpage(&self, coord: Index2) -> Index2 { + fn coord_to_subpage(&self, coord: CellPos) -> CellPos { let a = self.a; let b = self.b; let ha0 = self.h[a]; - Index2::for_axis((a, max(coord[a] + ha0 - self.z0, ha0)), coord[b]) + CellPos::for_axis((a, max(coord[a] + ha0 - self.z0, ha0)), coord[b]) } } @@ -1105,7 +1105,7 @@ fn measure_rule(device: &dyn Device, table: &Table, a: Axis2, z: usize) -> isize // Determine the types of rules that are present. let mut rules = EnumMap::default(); for w in 0..table.n[b] { - let stroke = table.get_rule(a, Index2::for_axis((a, z), w)).stroke; + let stroke = table.get_rule(a, CellPos::for_axis((a, z), w)).stroke; rules[stroke] = true; } @@ -1282,7 +1282,7 @@ impl Break { if self.axis == Axis2::Y && device.params().can_adjust_break { let mut x = 0; while x < self.page.n[Axis2::X] { - let cell = self.page.get_cell(Index2::new(x, z)); + let cell = self.page.get_cell(CellPos::new(x, z)); let better_pixel = device.adjust_break( cell.content, Coord2::new( diff --git a/rust/pspp/src/output/table.rs b/rust/pspp/src/output/table.rs index 174d89d791..3413c16605 100644 --- a/rust/pspp/src/output/table.rs +++ b/rust/pspp/src/output/table.rs @@ -26,16 +26,17 @@ //! Some drivers use tables as an implementation detail of rendering pivot //! tables. -use std::{borrow::Cow, ops::Range, sync::Arc}; +use std::{ + borrow::Cow, + ops::{Index, IndexMut, Range}, + sync::Arc, +}; use enum_map::{EnumMap, enum_map}; use ndarray::{Array, Array2}; use crate::output::{ - pivot::{ - CellStyle, DisplayValue, FontStyle, Footnote, HorzAlign, Index2, IndexRect2, - ValueInner, - }, + pivot::{CellStyle, DisplayValue, FontStyle, Footnote, HorzAlign, IndexRect2, ValueInner}, spv::html, }; @@ -43,9 +44,69 @@ use super::pivot::{ Area, AreaStyle, Axis2, Border, BorderStyle, HeadingRegion, Value, ValueOptions, }; +/// The `(x,y)` position of a cell in a [Table]. +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)] +pub struct CellPos(pub EnumMap); + +impl CellPos { + pub fn new(x: usize, y: usize) -> Self { + use Axis2::*; + Self(enum_map! { + X => x, + Y => y + }) + } + + pub fn for_axis((a, az): (Axis2, usize), bz: usize) -> Self { + let mut coord = Self::default(); + coord[a] = az; + coord[!a] = bz; + coord + } + + pub fn from_fn(f: F) -> Self + where + F: FnMut(Axis2) -> usize, + { + Self(EnumMap::from_fn(f)) + } + + pub fn x(&self) -> usize { + self.0[Axis2::X] + } + + pub fn y(&self) -> usize { + self.0[Axis2::Y] + } + + pub fn get(&self, axis: Axis2) -> usize { + self.0[axis] + } +} + +impl From> for CellPos { + fn from(value: EnumMap) -> Self { + Self(value) + } +} + +impl Index for CellPos { + type Output = usize; + + fn index(&self, index: Axis2) -> &Self::Output { + &self.0[index] + } +} + +impl IndexMut for CellPos { + fn index_mut(&mut self, index: Axis2) -> &mut Self::Output { + &mut self.0[index] + } +} + #[derive(Clone, Debug)] pub struct CellRef<'a> { - pub pos: Index2, + pub pos: CellPos, pub content: &'a Content, } @@ -111,7 +172,7 @@ impl Content { /// Returns the rectangle that this cell covers. If the cell doesn't contain /// that information, returns a rectangle containing `pos`. - pub fn rect(&self, pos: Index2) -> IndexRect2 { + pub fn rect(&self, pos: CellPos) -> IndexRect2 { match self { Content::Join(cell) => cell.region.clone(), _ => IndexRect2::for_cell(pos), @@ -123,7 +184,7 @@ impl Content { .map_or(x + 1, |region| region[Axis2::X].end) } - pub fn is_top_left(&self, pos: Index2) -> bool { + pub fn is_top_left(&self, pos: CellPos) -> bool { self.joined_rect().is_none_or(|r| pos == r.top_left()) } @@ -195,10 +256,10 @@ impl CellInner { #[derive(derive_more::Debug)] pub struct Table { /// Number of rows and columns. - pub n: Index2, + pub n: CellPos, /// Table header rows and columns. - pub h: Index2, + pub h: CellPos, pub contents: Array2, @@ -220,8 +281,8 @@ pub struct Table { impl Table { pub fn new( - n: Index2, - headers: Index2, + n: CellPos, + headers: CellPos, areas: EnumMap, borders: EnumMap, value_options: ValueOptions, @@ -240,14 +301,14 @@ impl Table { } } - pub fn get(&self, coord: Index2) -> CellRef<'_> { + pub fn get(&self, coord: CellPos) -> CellRef<'_> { CellRef { pos: coord, content: &self.contents[[coord.x(), coord.y()]], } } - pub fn get_rule(&self, axis: Axis2, pos: Index2) -> BorderStyle { + pub fn get_rule(&self, axis: Axis2, pos: CellPos) -> BorderStyle { self.rules[axis][[pos.x(), pos.y()]].map_or(BorderStyle::none(), |b| self.borders[b]) } @@ -298,7 +359,7 @@ impl Table { } /// The heading region that `pos` is part of, if any. - pub fn heading_region(&self, pos: Index2) -> Option { + pub fn heading_region(&self, pos: CellPos) -> Option { if pos.x() < self.h.x() { Some(HeadingRegion::Rows) } else if pos.y() < self.h.y() { @@ -333,7 +394,7 @@ impl Iterator for XIter<'_> { fn next(&mut self) -> Option { let next_x = self .x - .map_or(0, |x| self.table.get(Index2::new(x, self.y)).next_x()); + .map_or(0, |x| self.table.get(CellPos::new(x, self.y)).next_x()); if next_x >= self.table.n.x() { None } else { @@ -356,7 +417,7 @@ impl<'a> Cells<'a> { next: if table.is_empty() { None } else { - Some(table.get(Index2::new(0, 0))) + Some(table.get(CellPos::new(0, 0))) }, } } @@ -373,9 +434,9 @@ impl<'a> Iterator for Cells<'a> { self.next = loop { let next_x = next.next_x(); let coord = if next_x < self.table.n[X] { - Index2::new(next_x, next.pos.y()) + CellPos::new(next_x, next.pos.y()) } else if next.pos.y() + 1 < self.table.n[Y] { - Index2::new(0, next.pos.y() + 1) + CellPos::new(0, next.pos.y() + 1) } else { break None; }; -- 2.30.2