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}