Skip to content

Commit

Permalink
Remove the unsafe code in Table::as_ref (#146)
Browse files Browse the repository at this point in the history
* Remove the unsafe code in Table::as_ref

* Implement `AsTableSlice` for `AsRef<Table>` for better backward compatibility
  • Loading branch information
david0u0 committed Dec 27, 2022
1 parent e159600 commit 25cfe72
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 42 deletions.
7 changes: 4 additions & 3 deletions src/csv.rs
Expand Up @@ -3,6 +3,7 @@
use csv;

pub use self::csv::{Reader, Writer, Result, ReaderBuilder};
use crate::AsTableSlice;
use std::path::Path;
use std::io::{Read, Write};

Expand Down Expand Up @@ -67,14 +68,14 @@ impl super::Table {

/// Write the table to the specified writer.
pub fn to_csv<W: Write>(&self, w: W) -> Result<Writer<W>> {
self.as_ref().to_csv(w)
self.as_slice().to_csv(w)
}

/// Write the table to the specified writer.
///
/// This allows for format customisation.
pub fn to_csv_writer<W: Write>(&self, writer: Writer<W>) -> Result<Writer<W>> {
self.as_ref().to_csv_writer(writer)
self.as_slice().to_csv_writer(writer)
}
}

Expand Down Expand Up @@ -147,4 +148,4 @@ mod tests {
assert_eq!(table.get_row(1).unwrap().get_cell(2).unwrap().get_content(), "C");
assert_eq!(table.get_row(2).unwrap().get_cell(1).unwrap().get_content(), "DEFG");
}
}
}
10 changes: 5 additions & 5 deletions src/evcxr.rs
@@ -1,6 +1,6 @@
//! This modules contains traits and implementations to work within Evcxr

use super::TableSlice;
use super::AsTableSlice;
use super::utils::StringWriter;
use std::io::Write;

Expand All @@ -10,20 +10,20 @@ pub trait EvcxrDisplay {
fn evcxr_display(&self);
}

impl<'a, T> EvcxrDisplay for T
impl<T> EvcxrDisplay for T
where
T: AsRef<TableSlice<'a>>,
T: AsTableSlice,
{
fn evcxr_display(&self) {
let mut writer = StringWriter::new();
// Plain Text
let _ = writer.write_all(b"EVCXR_BEGIN_CONTENT text/plain\n");
let _ = self.as_ref().print(&mut writer);
let _ = self.as_slice().print(&mut writer);
let _ = writer.write_all(b"\nEVCXR_END_CONTENT\n");

// Html
let _ = writer.write_all(b"EVCXR_BEGIN_CONTENT text/html\n");
let _ = self.as_ref().print_html(&mut writer);
let _ = self.as_slice().print_html(&mut writer);
let _ = writer.write_all(b"\nEVCXR_END_CONTENT\n");
println!("{}", writer.as_string());
}
Expand Down
79 changes: 45 additions & 34 deletions src/lib.rs
Expand Up @@ -59,7 +59,7 @@ pub struct Table {
/// # }
/// ```
///
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct TableSlice<'a> {
format: &'a TableFormat,
titles: &'a Option<Row>,
Expand Down Expand Up @@ -220,6 +220,7 @@ impl<'a> TableSlice<'a> {
out.flush()?;
Ok(())
}

}

impl<'a> IntoIterator for &'a TableSlice<'a> {
Expand Down Expand Up @@ -259,7 +260,7 @@ impl Table {
// #[deprecated(since="0.8.0", note="Will become private in future release. See [issue #87](https://github.com/phsym/prettytable-rs/issues/87)")]
#[cfg(test)] // Only used for testing for now
pub (crate) fn get_column_num(&self) -> usize {
self.as_ref().get_column_num()
self.as_slice().get_column_num()
}

/// Get the number of rows
Expand Down Expand Up @@ -353,13 +354,13 @@ impl Table {
/// Print the table to `out` and returns the number
/// of lines printed, or an error
pub fn print<T: Write + ?Sized>(&self, out: &mut T) -> Result<usize, Error> {
self.as_ref().print(out)
self.as_slice().print(out)
}

/// Print the table to terminal `out`, applying styles when needed and returns the number
/// of lines printed, or an error
pub fn print_term<T: Terminal + ?Sized>(&self, out: &mut T) -> Result<usize, Error> {
self.as_ref().print_term(out)
self.as_slice().print_term(out)
}

/// Print the table to standard output. Colors won't be displayed unless
Expand All @@ -371,7 +372,7 @@ impl Table {
/// # Returns
/// A `Result` holding the number of lines printed, or an `io::Error` if any failure happens
pub fn print_tty(&self, force_colorize: bool) -> Result<usize, Error> {
self.as_ref().print_tty(force_colorize)
self.as_slice().print_tty(force_colorize)
}

/// Print the table to standard output. Colors won't be displayed unless
Expand All @@ -381,12 +382,29 @@ impl Table {
/// Any failure to print is ignored. For better control, use `print_tty()`.
/// Calling `printstd()` is equivalent to calling `print_tty(false)` and ignoring the result.
pub fn printstd(&self) {
self.as_ref().printstd()
self.as_slice().printstd()
}

/// Print table in HTML format to `out`.
pub fn print_html<T: Write + ?Sized>(&self, out: &mut T) -> Result<(), Error> {
self.as_ref().print_html(out)
self.as_slice().print_html(out)
}

}

trait AsTableSlice {
fn as_slice(&self) -> TableSlice<'_> ;
}

impl AsTableSlice for Table {
fn as_slice(&self) -> TableSlice<'_> {
TableSlice { format: &self.format, titles: &self.titles, rows: &self.rows }
}
}

impl <T> AsTableSlice for T where T: AsRef<Table> {
fn as_slice(&self) -> TableSlice<'_> {
self.as_ref().as_slice()
}
}

Expand All @@ -412,7 +430,7 @@ impl IndexMut<usize> for Table {

impl fmt::Display for Table {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
self.as_ref().fmt(fmt)
self.as_slice().fmt(fmt)
}
}

Expand Down Expand Up @@ -456,7 +474,7 @@ impl<'a> IntoIterator for &'a Table {
type Item = &'a Row;
type IntoIter = Iter<'a, Row>;
fn into_iter(self) -> Self::IntoIter {
self.as_ref().row_iter()
self.row_iter()
}
}

Expand Down Expand Up @@ -502,23 +520,19 @@ impl<'a> Iterator for ColumnIterMut<'a> {
}
}

impl<'a> AsRef<TableSlice<'a>> for TableSlice<'a> {
fn as_ref(&self) -> &TableSlice<'a> {
self
impl <'a> AsTableSlice for TableSlice<'a> {
fn as_slice(&self) -> TableSlice<'_> {
*self
}
}

impl<'a> AsRef<TableSlice<'a>> for Table {
impl<'a> AsRef<TableSlice<'a>> for TableSlice<'a> {
fn as_ref(&self) -> &TableSlice<'a> {
unsafe {
// All this is a bit hacky. Let's try to find something else
let s = &mut *((self as *const Table) as *mut Table);
s.rows.shrink_to_fit();
&*(self as *const Table as *const TableSlice<'a>)
}
self
}
}


/// Trait implemented by types which can be sliced
pub trait Slice<'a, E> {
/// Type output after slicing
Expand All @@ -528,17 +542,14 @@ pub trait Slice<'a, E> {
}

impl<'a, T, E> Slice<'a, E> for T
where T: AsRef<TableSlice<'a>>,
where T: AsTableSlice,
[Row]: Index<E, Output = [Row]>
{
type Output = TableSlice<'a>;
fn slice(&'a self, arg: E) -> Self::Output {
let sl = self.as_ref();
TableSlice {
format: sl.format,
titles: sl.titles,
rows: sl.rows.index(arg),
}
let mut sl = self.as_slice();
sl.rows = sl.rows.index(arg);
sl
}
}

Expand Down Expand Up @@ -600,7 +611,7 @@ macro_rules! ptable {

#[cfg(test)]
mod tests {
use crate::{Table, Slice, Row, Cell, format};
use crate::{Table, Slice, Row, Cell, format, AsTableSlice};
use format::consts::{FORMAT_DEFAULT, FORMAT_NO_LINESEP, FORMAT_NO_COLSEP, FORMAT_CLEAN, FORMAT_BOX_CHARS};
use crate::utils::StringWriter;

Expand Down Expand Up @@ -661,21 +672,21 @@ mod tests {
fn table_size() {
let mut table = Table::new();
assert!(table.is_empty());
assert!(table.as_ref().is_empty());
assert!(table.as_slice().is_empty());
assert_eq!(table.len(), 0);
assert_eq!(table.as_ref().len(), 0);
assert_eq!(table.as_slice().len(), 0);
assert_eq!(table.get_column_num(), 0);
assert_eq!(table.as_ref().get_column_num(), 0);
assert_eq!(table.as_slice().get_column_num(), 0);
table.add_empty_row();
assert!(!table.is_empty());
assert!(!table.as_ref().is_empty());
assert!(!table.as_slice().is_empty());
assert_eq!(table.len(), 1);
assert_eq!(table.as_ref().len(), 1);
assert_eq!(table.as_slice().len(), 1);
assert_eq!(table.get_column_num(), 0);
assert_eq!(table.as_ref().get_column_num(), 0);
assert_eq!(table.as_slice().get_column_num(), 0);
table[0].add_cell(Cell::default());
assert_eq!(table.get_column_num(), 1);
assert_eq!(table.as_ref().get_column_num(), 1);
assert_eq!(table.as_slice().get_column_num(), 1);
}

#[test]
Expand Down

0 comments on commit 25cfe72

Please sign in to comment.