simple_tables_core/
lib.rs

1//! Simple Tables Core
2
3pub mod error;
4
5// Trait
6pub trait TableRow {
7    /// Returns a vector containing the names of the fields
8    fn get_fields() -> Vec<&'static str>;
9    /// Returns a vector containing the types of the fields
10    fn get_field_types() -> Vec<&'static str>;
11    // TODO? add a function to return a map of the fields and their types
12    /// Returns the amount of fields in this struct
13    fn field_count() -> usize { Self::get_fields().iter().count() }
14}
15
16/// A table should conform to this trait. `Row` is the table's row type.
17pub trait Table<Row: TableRow> {
18    // Maybe not needed here: const UID: String;
19    // TODO: to_string() and fmt() using pretty ASCII tables. Also have a max column size => wrap lines, but that's for later
20    // /// Gets the highest width of each element in the table, used for debugging and printing
21    // fn get_sizes(&self) -> Vec<isize>;
22    /// Gets the column size of a specific column. Requires that the column can be converted to a
23    /// String.
24    ///
25    /// # Examples
26    /// ```rust
27    /// # use simple_tables::macros::{table_row, table};
28    /// # #[table_row]
29    /// # struct TableRow {
30    /// #     id: u32,
31    /// #     name: String
32    /// # }
33    /// #
34    /// # #[table(rows = TableRow)]
35    /// # struct MyTable {}
36    ///
37    /// let vec: Vec<TableRow> = vec![TableRow{id: 1000, name: String::from("Abc")}, TableRow{id: 2, name: String::from("Bd")}];
38    /// let table = MyTable::from_vec(&vec);
39    ///
40    /// assert_eq!(3, table.get_column_size(|row| row.name.clone()).unwrap());
41    /// assert_eq!(4, table.get_column_size(|row| row.id).unwrap());
42    /// ```
43    fn get_column_size<ColumnType: ToString>(&self, column: fn(&Row) -> ColumnType) -> Option<usize> {
44        let mut sizes: Vec<usize> = Vec::new();
45        for row in self.get_rows() {
46            let col = column(row);
47            let size = get_size(col);
48            sizes.push(size);
49        }
50        match sizes.iter().max() {
51            Some(max) => Some(max.to_owned()),
52            None => None
53        }
54    }
55    /// Creates a new empty `Table`
56    fn new() -> Self;
57    
58    // fn to_string(&self) -> String {
59    //     let field_names = Row::get_fields();
60    //     let field_lenghts = /*for all fields self.get_column_size(/*TODO*/ |row| { 1 });*/ vec![5,5,5];
61    //     let cols: Vec<String> = self.get_column(|row| row.to_string());
62    //
63    //     String::from("")
64    // }
65    /// Creates a new `Table` with an initial value for the rows
66    fn from_vec(vec: &Vec<Row>) -> Self;
67    /// Returns an immutable reference to the rows of this table
68    fn get_rows(&self) -> &Vec<Row>;
69    /// Returns a mutable reference to the rows of this table
70    fn get_rows_mut(&mut self) -> &mut Vec<Row>;
71    /// Pushes a new row to the end of the table
72    fn push(&mut self, row: Row) { self.get_rows_mut().push(row); }
73    /// Inserts a new row at the top of the table (element 0)
74    fn insert_top(&mut self, row: Row) { self.get_rows_mut().insert(0, row); }
75    /// Inserts a new row at index `i`
76    fn insert(&mut self, i: usize, row: Row) { self.get_rows_mut().insert(i, row); }
77    /// Returns the column with the specific name
78    ///
79    /// # Example
80    /// ```rust
81    /// # use simple_tables::macros::{table_row, table};
82    /// # #[table_row]
83    /// # struct TableRow {
84    /// #     id: u32,
85    /// #     name: String
86    /// # }
87    /// #
88    /// # #[table(rows = TableRow)]
89    /// # struct MyTable {}
90    /// #
91    /// let vec: Vec<TableRow> = vec![TableRow{id: 1, name: String::from("A")}, TableRow{id: 2, name: String::from("B")}];
92    /// let table = MyTable::from_vec(&vec);
93    ///
94    /// let ids: Vec<u32> = table.get_column(|row| row.id);
95    /// assert_eq!(vec![1,2], ids);
96    /// ```
97    fn get_column<ColumnType>(
98        &self,
99        column: fn(&Row) -> ColumnType
100    )
101        -> Vec<ColumnType>
102    {
103        let columns: Vec<ColumnType> = self.get_rows().to_owned().into_iter().map(|row| {
104            column(row)
105        }).collect();
106        columns
107    }
108    // TODO (is this even possible?)
109    // /// Returns the column at the spefic index
110    // fn get_column_at<ColumnType>(&self, column: usize) -> Vec<ColumnType>;
111    /// Returns the row at the index
112    fn get_row_at(&self, i: usize) -> Option<&Row> { self.get_rows().get(i) }
113    /// Removes the row at the index and returns the row
114    fn rm_row_at(&mut self, i: usize) -> Row {
115        self.get_rows_mut().remove(i)
116    }
117
118    // TODO
119    // /// Sorts the rows based on a specific column
120    // fn sort_on(&mut self, based_on: &str);
121    // /// Returns a sorted copy of the rows.<br/>
122    // /// The rows are sorted based on a column.
123    // fn get_sorted(&self, based_on: &str) -> Vec<Row>;
124
125    fn column_count(&self) -> usize { Row::field_count() }
126    fn row_count(&self) -> usize { self.get_rows().len() }
127}
128// TODO: implement IntoIter for Table
129
130/// Defines a table with a unique identifier. This class should be implemented alongside the
131/// [`Table`](crate::Table) trait.
132///
133/// When you have a table with a uid, this trait has to be implemented manually for now.
134///
135/// # To implement
136/// - [`get_id_from_row`](crate::IdTable)
137///
138/// # Notes
139/// - If your IDE tells you following error when implementing this trait:
140///   ```bash
141///   the trait bound `MyTable: Table<TableRow>` is not satisfied
142///   ```
143///   you can simply ignore it given
144///   that you are using the `table_row` macro. Your IDE just doesn't know the `Table` trait is
145///   already implemented for your struct. When you run your program, it will actually compile and
146///   run.
147pub trait IdTable<UidType: PartialEq, Row: TableRow>: Table<Row> {
148    /// Gets the uid from a row, this should be implemented manually (for now) for structs with uids.
149    ///
150    /// # Example
151    /// ```rust
152    /// # use simple_tables::macros::{table_row, table};
153    /// # fn main() {
154    /// #[table_row]
155    /// struct MyTableRow {
156    ///     id: i32,
157    ///     name: String
158    /// }
159    ///
160    /// #[table(rows = MyTableRow)]
161    /// struct MyTable {}
162    ///
163    /// impl simple_tables::IdTable<i32, MyTableRow> for MyTable {
164    ///     fn get_id_from_row(row: i32) -> i32 {
165    ///         row.id
166    ///     }
167    /// }
168    /// # }
169    /// ```
170    fn get_id_from_row(row: &Row) -> UidType;
171    
172    /// Returns the row with the specific uid
173    fn get_row(&self, uid: UidType) -> Option<&Row> {
174        let val: Option<&Row> = self.get_rows().iter().find_map(|row| {
175            if Self::get_id_from_row(row) == uid {
176                Some(row)
177            }  else {
178                None
179            }
180        });
181        
182        val
183    }
184    
185    /// Returns a mutable reference to a row
186    fn get_row_mut(&mut self, uid: UidType) -> Option<&mut Row> {
187        let val: Option<&mut Row> = self.get_rows_mut().iter_mut().find_map(|row| {
188            if Self::get_id_from_row(row) == uid {
189                Some(row)
190            }  else {
191                None
192            }
193        });
194    
195        val
196    }
197    
198    /// Returns the index of the row with the uid. Will be None if there is no row with this uid.
199    fn get_row_index(&self, uid: UidType) -> Option<usize> {
200        let val: Option<usize> = self.get_rows().iter().enumerate().find_map(|(i, row)| {
201            if Self::get_id_from_row(row) == uid {
202                Some(i)
203            } else {
204                None
205            }
206        });
207        val
208    }
209    
210    /// Removes the row with the uid from the table and returns the row. Returns an error if there
211    /// is no table row with the uid.
212    fn rm_row(&mut self, uid: UidType) -> Result<Row, crate::error::TableError> {
213        if let Some(index) = self.get_row_index(uid) {
214            Ok(self.rm_row_at(index))
215        } else {
216            Err(crate::error::TableError { kind: crate::error::TableErrorKind::CouldNotRemove, message: "There is no table row with this uid".to_string() })
217        }
218    }
219    
220    // TODO
221    // /// Searches through the sorted rows using the uid. Only works if the rows have been sorted first,
222    // /// the [`sort`](table_rows::core::Table::sort) function can help with this.
223    // fn sorted_search(&self, uid: V) -> Option<Row>;
224    // /// Sorts the rows based on the `uid`
225    // ///
226    // /// # Panics
227    // /// if there is no `uid` set
228    // fn sort(&mut self);
229}
230
231fn get_size<Type: ToString>(var: Type) -> usize {
232    // let type_id = var.type_id();
233    let len = var.to_string().chars().into_iter().count();
234    len
235    // if type_id == TypeId::of::<String>() {
236    //     (var as String).chars().into_iter().count();
237    // } else if type_id == TypeId::of::<str>() {
238    //     (var as str).chars().into_iter().count();
239    // } else if type_id == TypeId::of::<usize> {
240    //     (var as usize)
241    // }
242}