use super::package::Result;
use super::paragraph::Paragraph;
use super::parts::tap::{TableProperties, CellProperties, TableJustification};
#[derive(Debug, Clone)]
pub struct Table {
rows: Vec<Row>,
properties: Option<TableProperties>,
}
impl Table {
#[allow(dead_code)]
pub(crate) fn new(rows: Vec<Row>) -> Self {
Self { rows, properties: None }
}
#[allow(dead_code)]
pub(crate) fn with_properties(rows: Vec<Row>, properties: TableProperties) -> Self {
Self {
rows,
properties: Some(properties),
}
}
pub fn row_count(&self) -> Result<usize> {
Ok(self.rows.len())
}
pub fn column_count(&self) -> Result<usize> {
if let Some(first_row) = self.rows.first() {
first_row.cell_count()
} else {
Ok(0)
}
}
pub fn rows(&self) -> Result<Vec<Row>> {
Ok(self.rows.clone())
}
pub fn cell(&self, row_idx: usize, col_idx: usize) -> Result<Option<Cell>> {
if let Some(row) = self.rows.get(row_idx) {
let cells = row.cells()?;
Ok(cells.get(col_idx).cloned())
} else {
Ok(None)
}
}
pub fn properties(&self) -> Option<&TableProperties> {
self.properties.as_ref()
}
pub fn justification(&self) -> Option<TableJustification> {
self.properties.as_ref().map(|p| p.justification)
}
pub fn has_header_row(&self) -> bool {
self.properties.as_ref().is_some_and(|p| p.is_header_row)
}
}
#[derive(Debug, Clone)]
pub struct Row {
cells: Vec<Cell>,
row_properties: Option<TableProperties>,
}
impl Row {
#[allow(unused)]
pub(crate) fn new(cells: Vec<Cell>) -> Self {
Self {
cells,
row_properties: None,
}
}
#[allow(unused)]
pub(crate) fn with_properties(cells: Vec<Cell>, properties: TableProperties) -> Self {
Self {
cells,
row_properties: Some(properties),
}
}
pub fn cell_count(&self) -> Result<usize> {
Ok(self.cells.len())
}
pub fn cells(&self) -> Result<Vec<Cell>> {
Ok(self.cells.clone())
}
pub fn properties(&self) -> Option<&TableProperties> {
self.row_properties.as_ref()
}
pub fn height(&self) -> Option<i16> {
self.row_properties.as_ref().and_then(|p| p.row_height)
}
pub fn is_header(&self) -> bool {
self.row_properties.as_ref().is_some_and(|p| p.is_header_row)
}
}
#[derive(Debug, Clone)]
pub struct Cell {
text: String,
paragraphs: Vec<Paragraph>,
properties: Option<CellProperties>,
}
impl Cell {
#[allow(unused)]
pub(crate) fn new(text: String) -> Self {
Self {
text: text.clone(),
paragraphs: vec![Paragraph::new(text)],
properties: None,
}
}
#[allow(unused)]
pub(crate) fn with_properties(
paragraphs: Vec<Paragraph>,
properties: Option<CellProperties>,
) -> Self {
let text = paragraphs
.iter()
.filter_map(|p| p.text().ok())
.collect::<Vec<&str>>()
.join("\n");
Self {
text,
paragraphs,
properties,
}
}
pub fn text(&self) -> Result<&str> {
Ok(&self.text)
}
pub fn paragraphs(&self) -> Result<Vec<Paragraph>> {
Ok(self.paragraphs.clone())
}
pub fn properties(&self) -> Option<&CellProperties> {
self.properties.as_ref()
}
pub fn vertical_alignment(&self) -> Option<super::parts::tap::VerticalAlignment> {
self.properties.as_ref().map(|p| p.vertical_alignment)
}
pub fn background_color(&self) -> Option<(u8, u8, u8)> {
self.properties.as_ref().and_then(|p| p.background_color)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cell_text() {
let cell = Cell::new("Cell content".to_string());
assert_eq!(cell.text().unwrap(), "Cell content");
}
#[test]
fn test_row_cell_count() {
let cells = vec![
Cell::new("A".to_string()),
Cell::new("B".to_string()),
Cell::new("C".to_string()),
];
let row = Row::new(cells);
assert_eq!(row.cell_count().unwrap(), 3);
}
#[test]
fn test_table_dimensions() {
let row1 = Row::new(vec![Cell::new("A".to_string()), Cell::new("B".to_string())]);
let row2 = Row::new(vec![Cell::new("C".to_string()), Cell::new("D".to_string())]);
let table = Table::new(vec![row1, row2]);
assert_eq!(table.row_count().unwrap(), 2);
assert_eq!(table.column_count().unwrap(), 2);
}
}