blob: dec967bd6949d0ac4d62fda5cce31ae59632cb93 [file] [log] [blame]
//! This module contains an [`Dup`] setting the [`Table`].
//!
//! # Example
//!
//! ```
//! # use tabled::{Table, settings::{Dup, object::{Columns, Rows}}};
//! # let data: Vec<&'static str> = Vec::new();
//! let mut table = Table::new(&data);
//! table.with(Dup::new(Rows::first(), Columns::first()));
//! ```
//!
//! [`Table`]: crate::Table
use papergrid::config::Position;
use crate::{
grid::records::{ExactRecords, PeekableRecords, Records, RecordsMut},
settings::{object::Object, TableOption},
};
/// [`Dup`] duplicates a given set of cells into another set of ones [`Table`].
///
/// # Example
///
/// ```
/// use tabled::{Table, settings::{object::Rows, Dup}};
///
/// let data = [
/// ["1", "2", "3"],
/// ["Some\nMulti\nLine\nText", "and a line", "here"],
/// ["4", "5", "6"],
/// ];
///
/// let mut table = Table::new(&data);
/// table.with(Dup::new(Rows::single(1), Rows::single(2)));
///
/// assert_eq!(
/// table.to_string(),
/// "+-------+------------+------+\n\
/// | 0 | 1 | 2 |\n\
/// +-------+------------+------+\n\
/// | Some | and a line | here |\n\
/// | Multi | | |\n\
/// | Line | | |\n\
/// | Text | | |\n\
/// +-------+------------+------+\n\
/// | Some | and a line | here |\n\
/// | Multi | | |\n\
/// | Line | | |\n\
/// | Text | | |\n\
/// +-------+------------+------+\n\
/// | 4 | 5 | 6 |\n\
/// +-------+------------+------+",
/// )
/// ```
///
/// [`Table`]: crate::Table
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Dup<Dst, Src> {
src: Src,
dst: Dst,
}
impl<Dst, Src> Dup<Dst, Src> {
/// New creates a new [`Dup`] modifier.
///
/// # Example
///
/// ```
/// # use tabled::{Table, settings::{Dup, object::{Columns, Rows}}};
/// # let data: Vec<&'static str> = Vec::new();
/// let mut table = Table::new(&data);
/// table.with(Dup::new(Rows::first(), Columns::last()));
/// ```
pub fn new(dst: Dst, src: Src) -> Self {
Self { src, dst }
}
}
impl<Dst, Src, R, D, C> TableOption<R, D, C> for Dup<Dst, Src>
where
Dst: Object<R>,
Src: Object<R>,
R: Records + ExactRecords + PeekableRecords + RecordsMut<String>,
{
fn change(self, records: &mut R, _: &mut C, _: &mut D) {
let input = collect_input(records, self.src);
set_cells(records, &input, self.dst);
}
}
fn collect_input<R, O>(records: &mut R, src: O) -> Vec<String>
where
O: Object<R>,
R: Records + ExactRecords + PeekableRecords + RecordsMut<String>,
{
let count_rows = records.count_rows();
let count_columns = records.count_columns();
let mut input = Vec::new();
for entity in src.cells(records) {
for pos in entity.iter(count_rows, count_columns) {
if !is_valid_cell(pos, count_rows, count_columns) {
continue;
}
let text = records.get_text(pos).to_owned();
input.push(text);
}
}
input
}
fn set_cells<R, O>(records: &mut R, src: &[String], dst: O)
where
O: Object<R>,
R: Records + ExactRecords + PeekableRecords + RecordsMut<String>,
{
if src.is_empty() {
return;
}
let count_rows = records.count_rows();
let count_columns = records.count_columns();
for entity in dst.cells(records) {
let mut source = src.iter().cycle();
for pos in entity.iter(count_rows, count_columns) {
if !is_valid_cell(pos, count_rows, count_columns) {
continue;
}
let text = source.next().unwrap().clone();
records.set(pos, text);
}
}
}
fn is_valid_cell((row, col): Position, count_rows: usize, count_columns: usize) -> bool {
if row > count_rows {
return false;
}
if col > count_columns {
return false;
}
true
}