├── .gitignore ├── .idea ├── codeStyles │ ├── codeStyleConfig.xml │ └── Project.xml ├── vcs.xml ├── .gitignore ├── modules.xml └── git_toolbox_prj.xml ├── src ├── lib.rs ├── table_map_errors.rs ├── tablemap_helpers.rs ├── table_map.rs └── tests.rs ├── .github └── workflows │ └── rust.yml ├── Cargo.toml ├── table_map.iml ├── benches └── benches.rs ├── README.md └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub use crate::table_map::TableMap as TableMap; 2 | 3 | #[doc = include_str!("../README.md")] 4 | 5 | pub mod table_map; 6 | pub mod table_map_errors; 7 | pub mod tablemap_helpers; 8 | #[cfg(test)] 9 | mod tests; 10 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/table_map_errors.rs: -------------------------------------------------------------------------------- 1 | use thiserror::Error; 2 | 3 | #[derive(Error, Debug)] 4 | pub enum TableMapErrors { 5 | #[error("Column name does not exist")] 6 | InvalidColumnName, 7 | 8 | #[error("No data is set")] 9 | NoDataSet, 10 | 11 | #[error("Invalid row index")] 12 | InvalidRowIndex, 13 | } 14 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Build 20 | run: cargo build --verbose 21 | - name: Run doc tests 22 | run: cargo test --verbose --doc 23 | - name: Run tests 24 | run: cargo test --verbose 25 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "table_map" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | thiserror = "1.0.40" 10 | indexmap = "2.0.0" 11 | tracing = "0.1.37" 12 | tracing-subscriber = "0.3.17" 13 | strum = { version = "0.25.0", features = ["derive"] } 14 | strum_macros = "0.25.1" 15 | 16 | [dev-dependencies] 17 | criterion = "0.5.1" 18 | rand = "0.8.5" 19 | 20 | 21 | [[bench]] 22 | name = "benches" 23 | harness = false -------------------------------------------------------------------------------- /.idea/git_toolbox_prj.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /table_map.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 21 | 22 | 26 | 27 | 28 | 30 | 31 | -------------------------------------------------------------------------------- /benches/benches.rs: -------------------------------------------------------------------------------- 1 | use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; 2 | use rand::distributions::{Alphanumeric, DistString}; 3 | use std::collections::{BTreeMap, HashMap}; 4 | 5 | use table_map::{TableMap, update_row}; 6 | 7 | macro_rules! inserter { 8 | ($($c: expr, $v: stmt),+) => { 9 | $c, $v,+ 10 | }; 11 | } 12 | 13 | fn criterion_benchmark(c: &mut Criterion) { 14 | let mut tm = TableMap::new(); 15 | for _ in 0..100 { 16 | let string = Alphanumeric.sample_string(&mut rand::thread_rng(), 16); 17 | tm.add_column(&string) 18 | } 19 | let columns = tm.get_columns(); 20 | let mut group = c.benchmark_group("insertion bench"); 21 | group.bench_function("TableMap", |b| { 22 | b.iter(|| { 23 | for _ in 0..100 { 24 | for ii in 0..100 { 25 | update_row! { 26 | tm, 27 | &columns[ii], 28 | Alphanumeric.sample_string(&mut rand::thread_rng(), 16) 29 | } 30 | } 31 | tm.next_row(); 32 | } 33 | }) 34 | }); 35 | group.bench_function("inserting hash map", |b| { 36 | b.iter(|| { 37 | let mut n: Vec> = vec![]; 38 | for _ in 0..100 { 39 | let mut hm = BTreeMap::new(); 40 | for ii in 0..100 { 41 | hm.insert( 42 | columns[ii].as_str(), 43 | Alphanumeric.sample_string(&mut rand::thread_rng(), 16), 44 | ); 45 | } 46 | n.push(hm.values().cloned().collect()) 47 | } 48 | }) 49 | }); 50 | group.finish(); 51 | } 52 | 53 | criterion_group!(benches, criterion_benchmark); 54 | criterion_main!(benches); 55 | -------------------------------------------------------------------------------- /src/tablemap_helpers.rs: -------------------------------------------------------------------------------- 1 | #[macro_export] 2 | macro_rules! setters_fn { 3 | () => { 4 | 5 | impl From for String { 6 | fn from(value: Columns) -> Self { 7 | let string: &str = value.into(); 8 | string.to_string() 9 | } 10 | } 11 | pub fn columns(tm: &mut TableMap) { 12 | tm.add_columns(Columns::iter().map(|v| v.into()).collect()); 13 | } 14 | 15 | pub fn upd_str(tm: &mut TableMap, row: usize, col: Columns, val: &str) { 16 | tm.update_row(row, col.into(), val.to_string()).unwrap(); 17 | } 18 | 19 | pub fn upd_string(tm: &mut TableMap, row: usize, col: Columns, val: &str) { 20 | tm.update_row(row, col.into(), val.to_string()).unwrap(); 21 | } 22 | 23 | pub fn ins_str(tm: &mut TableMap, c: Columns, v: &str) { 24 | tm.insert(c.into(), v.to_string()).unwrap(); 25 | } 26 | 27 | pub fn ins_string(tm: &mut TableMap, c: Columns, v: String) { 28 | tm.insert(c.into(), v).unwrap(); 29 | } 30 | 31 | pub fn get_column( 32 | tm: &TableMap, 33 | c: Columns, 34 | index: Option, 35 | ) -> Result { 36 | let cname: String = c.into(); 37 | if let Some(idx) = index { 38 | tm.get_column_value_by_index(idx, &cname) 39 | } else { 40 | tm.get_column_value(&cname) 41 | } 42 | } 43 | }; 44 | } 45 | 46 | #[macro_export] 47 | macro_rules! col { 48 | ($tm: expr) => { 49 | $tm.add_columns(Columns::iter().map(|v| v.into()).collect()); 50 | }; 51 | } 52 | 53 | #[cfg(test)] 54 | mod tests { 55 | use strum::IntoEnumIterator; 56 | use strum_macros::{EnumIter, EnumString, IntoStaticStr}; 57 | 58 | use crate::table_map_errors::TableMapErrors; 59 | use crate::TableMap; 60 | 61 | #[derive(EnumIter, IntoStaticStr, EnumString)] 62 | pub enum Columns { 63 | Name, 64 | Address, 65 | } 66 | 67 | setters_fn!(); 68 | 69 | #[test] 70 | fn test_adding_column_from_enum() { 71 | let mut tm: TableMap = TableMap::new(); 72 | col!(tm); 73 | assert_eq!( 74 | tm.get_columns(), 75 | vec!["Name".to_string(), "Address".to_string()] 76 | ); 77 | 78 | ins_str(&mut tm, Columns::Name, "John"); 79 | ins_str(&mut tm, Columns::Address, "Unknown"); 80 | tm.next_row(); 81 | ins_str(&mut tm, Columns::Name, "Doe"); 82 | ins_str(&mut tm, Columns::Name, "Still not known"); 83 | upd_str(&mut tm, 0, Columns::Address, "Searching") 84 | } 85 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TableMap 2 | 3 | HashMap, BTreeMap, IndexMap needs a lot of memory in case of String based keys, and large number of data. 4 | 5 | This is a simple library that tries to memory efficiently provide a `IndexMap` with a String key like functionality using vecs, that might have a large number of data with string keys. There might be other better solutions in the wild. 6 | 7 | As the String keys are mapped to vec index we are storing the string keys only once, so of we keep the best of both worlds. I have not benchmarked it, so can not say anything about performance. 8 | 9 | Simple macros are provided for easy assigning of data. 10 | 11 | TableMap become more useful with `tablemap_helpers`. Check the last example 12 | 13 | #### To do 14 | 15 | - [ ] fill to end row by index 16 | - [ ] Removing a row 17 | - [ ] Clear data 18 | 19 | 20 | ## Initializing and inserting 21 | 22 | ```rust 23 | use table_map::{push, update_row, TableMap}; 24 | 25 | 26 | fn main() { 27 | let mut cm = TableMap::new(); 28 | cm.add_columns(vec!["c0", "c1", "c2", "c3"]); 29 | // single insert 30 | cm.insert("c1", "Something").unwrap(); 31 | // single insert using macro, will not change row 32 | update_row! { cm, "c0", "c0v" } 33 | // multiple inserts using macro, will not add a new row 34 | update_row! { 35 | cm, 36 | "c1", "Something", 37 | "c2", "v2", 38 | "c3", "32" 39 | } 40 | // this will create a new row and insert 41 | push! { 42 | cm, 43 | "c0", "Another thing", 44 | "c1", "second column", 45 | "c2", "another value", 46 | "c3", "final column" 47 | } 48 | // getting a value from current row 49 | let v = cm.get_column_value("c1").unwrap(); 50 | assert_eq!(v, "second column"); 51 | // getting a value from another row 52 | let v = cm.get_column_value_by_index(0, "c1").unwrap(); 53 | assert_eq!(v, "Something"); 54 | } 55 | 56 | ``` 57 | 58 | This also provides benefit with different datasets, which may not have similar columns. 59 | So, in case of one dataset with columns `c1` and `c2` another with `c5` and `c6` 60 | 61 | ```rust 62 | use table_map::{push, update_row, TableMap}; 63 | 64 | fn main() { 65 | let mut cm = TableMap::new(); 66 | // first dataset, but you can add all of the columns beforehand as usual 67 | // cm.add_columns(vec!["c0", "c1", "c4", "c5"]); 68 | 69 | cm.add_columns(vec!["c0", "c1"]); 70 | // insert data for first dataset 71 | push! { 72 | cm, 73 | "c0", "c0v", 74 | "c1", "Something" 75 | } 76 | // now another dataset found 77 | cm.add_columns(vec!["c4", "c5"]); 78 | // insert data for second dataset 79 | push! { 80 | cm, 81 | "c4", "v2", 82 | "c5", "32" 83 | } 84 | 85 | // another dataset with mixed columns, as names are already added, 86 | // no new columns will be added and the sequence will stay 87 | // the same 88 | cm.add_columns(vec!["c1", "c5"]); 89 | push! { 90 | cm, 91 | "c1", "another set", 92 | "c5", "mixed dataset" 93 | } 94 | 95 | assert_eq!( 96 | cm.get_vec(), 97 | &vec![ 98 | vec!["c0v", "Something"], // NOTE: this is not filled up 99 | vec!["", "", "v2", "32"], 100 | vec!["", "another set", "", "mixed dataset"], 101 | ] 102 | ); 103 | } 104 | 105 | ``` 106 | 107 | One issue is, as noted in the example above, any rows inserted before a new column is added, 108 | will not be filled up, and cause error when we try to get value for the new column from those 109 | rows. Any rows added after will have them. 110 | 111 | To solve this issue, `fill_to_end` method should be used for each row as necessary. 112 | 113 | Following example attempts to clarify the issue, and provide solution. 114 | 115 | ```rust 116 | use table_map::{push, update_row, TableMap}; 117 | fn main() { 118 | 119 | let mut cm = TableMap::new(); 120 | cm.add_columns(vec!["c0", "c1", "c2", "c3"]); 121 | 122 | update_row! { 123 | cm, 124 | "c0", "r1d0", 125 | "c2", "r1d2" 126 | } 127 | 128 | // now a new column is added 129 | cm.add_column("c4"); 130 | 131 | // this will cause a NoDataSet error, cause column c4 was created after setting 132 | // this row, and it does not exists 133 | let n = cm.get_column_value("c4"); 134 | assert!(n.is_err()); 135 | 136 | // fill the row with default value 137 | cm.fill_to_end(); 138 | // now it will be okay 139 | let n = cm.get_column_value("c4"); 140 | assert!(n.is_ok()); 141 | 142 | // all the next rows will have all the columns 143 | push! { 144 | cm, 145 | "c0", "r2d0", 146 | "c2", "r2d2" 147 | } 148 | 149 | // this will work without filling up 150 | let n = cm.get_column_value("c4"); 151 | assert!(n.is_ok()); 152 | } 153 | 154 | ``` 155 | 156 | ## Using tablemap_helpers 157 | 158 | add all the columns from the enum 159 | Columns is an enum that should derive #[derive(EnumIter)] 160 | 161 | ```rust 162 | 163 | use strum::IntoEnumIterator; 164 | use strum_macros::{EnumIter, IntoStaticStr, EnumString}; 165 | use table_map::{col, TableMap, setters_fn}; 166 | use table_map::table_map_errors::TableMapErrors; 167 | 168 | #[derive(EnumIter, IntoStaticStr, EnumString)] 169 | pub enum Columns { 170 | Name, 171 | Address 172 | } 173 | 174 | // bring in all the useful setters 175 | setters_fn!(); 176 | 177 | fn main() { 178 | let mut tm: TableMap = TableMap::new(); 179 | col!(tm); 180 | assert_eq!( 181 | tm.get_columns(), 182 | vec!["Name".to_string(), "Address".to_string()] 183 | ); 184 | 185 | ins_str(&mut tm, Columns::Name, "John"); 186 | ins_str(&mut tm, Columns::Address, "Unknown"); 187 | tm.next_row(); 188 | ins_str(&mut tm, Columns::Name, "Doe"); 189 | ins_str(&mut tm, Columns::Name, "Still not known"); 190 | upd_str(&mut tm, 0, Columns::Address, "Still Searching"); 191 | tm.next_row(); 192 | // in case we have string 193 | let n = "John Doe".to_string(); 194 | ins_string(&mut tm, Columns::Name, n); 195 | assert_eq!( 196 | get_column(&mut tm, Columns::Name, Some(0)).unwrap(), 197 | "John" 198 | ); 199 | assert_eq!( 200 | get_column(&mut tm, Columns::Name, Some(1)).unwrap(), 201 | "Still not known" 202 | ); 203 | assert_eq!( 204 | get_column(&mut tm, Columns::Name, None).unwrap(), 205 | "John Doe" 206 | ); 207 | } 208 | 209 | ``` 210 | ## What this crate tries to solve? 211 | 212 | It is trying to maintain the lower memory usage of a vec and ordered key based accessing of an IndexMap. 213 | 214 | In my own testing, with a dataset of 947300 rows, 215 | * HashMap/IndexMap implementation was out of memory on my 64GB machine, 216 | * TableMap was 37GB. 217 | * Interestingly Python was only 27GB. 218 | 219 | As I understand, HashMap/IndexMap, stores all the keys for each row, and in addition to that, they provide performance for the price of high memory usage. Unfortunately, It was not suitable for my task and I have not found any other solutions online. So here's what I devised. 220 | 221 | `fill_to_end` may not be optimal. If I ever find a better way, I will try to incorporate it. 222 | -------------------------------------------------------------------------------- /src/table_map.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | use std::slice::Iter; 3 | 4 | use indexmap::IndexMap; 5 | 6 | use crate::table_map_errors::TableMapErrors; 7 | 8 | /// 9 | /// Updates the current row, it will create a new row if no rows exists 10 | /// ``` 11 | /// use table_map::{update_row, TableMap}; 12 | /// 13 | /// let mut cm = TableMap::new(); 14 | /// cm.add_columns(vec!["col_0", "col_1", "col_2", "col_3"]); 15 | /// update_row! { cm, "col_0", "Some value" } 16 | /// update_row! { 17 | /// cm, 18 | /// "col_1", "Something", 19 | /// "col_2", "another thing", 20 | /// "col_3", "more thing" 21 | /// } 22 | /// ``` 23 | /// 24 | #[macro_export] 25 | macro_rules! update_row { 26 | 27 | ($cm: ident, $cn: expr, $m: expr) => { 28 | $cm.insert($cn, $m).unwrap() 29 | }; 30 | 31 | ($cm: ident, $($cn: expr, $m: expr),+) => {{ 32 | $($cm.insert($cn, $m).unwrap();)+ 33 | }}; 34 | 35 | } 36 | 37 | /// 38 | /// insert data in a new row 39 | /// ``` 40 | /// use table_map::{push, update_row, TableMap}; 41 | /// 42 | /// let mut cm = TableMap::new(); 43 | /// cm.add_columns(vec!["col_0", "col_1", "col_2", "col_3"]); 44 | /// push! { cm, "col_0", "Some value" } 45 | /// push! { 46 | /// cm, 47 | /// "col_1", "Something", 48 | /// "col_2", "another thing", 49 | /// "col_3", "more thing" 50 | /// } 51 | /// ``` 52 | /// 53 | #[macro_export] 54 | macro_rules! push { 55 | ($cm: ident, $cn: expr, $m: expr) => { 56 | $cm.next_row(); 57 | $cm.insert($cn, $m).unwrap(); 58 | }; 59 | 60 | ($cm: ident, $($cn: expr, $m: expr),+) => {{ 61 | $cm.next_row(); 62 | $($cm.insert($cn, $m).unwrap();)+ 63 | }}; 64 | } 65 | 66 | #[derive(Clone)] 67 | pub struct TableMap { 68 | columns: IndexMap, 69 | col_index: usize, 70 | rows: Vec>, 71 | is_current_row_dirty: bool 72 | } 73 | 74 | impl TableMap { 75 | pub fn new() -> Self { 76 | Self { 77 | columns: IndexMap::new(), 78 | col_index: 0, 79 | rows: vec![], 80 | is_current_row_dirty: true 81 | } 82 | } 83 | 84 | /// returns current row index, None if there is no rows inserted yet 85 | pub fn current_row_index(&self) -> Option { 86 | if self.rows.len() == 0 { return None } 87 | Some(self.rows.len() - 1) 88 | } 89 | /// number of rows 90 | pub fn num_rows(&self) -> usize { 91 | self.rows.len() 92 | } 93 | 94 | /// number of columns 95 | pub fn num_cols(&self) -> usize { 96 | self.columns.len() 97 | } 98 | 99 | /// Column, in sequence, can be used as headers when generating a CSV file 100 | pub fn get_columns(&self) -> Vec { 101 | self.columns.keys().cloned().collect() 102 | } 103 | 104 | /// moves to next row. 105 | pub fn next_row(&mut self) { 106 | self.rows.push(vec![T::default(); self.columns.len()]); 107 | } 108 | 109 | /// copies current row, and push it at the end, creating duplicate 110 | pub fn copy_row(&mut self) { 111 | let new_row = self.rows.last().cloned().unwrap(); 112 | self.rows.push(new_row); 113 | } 114 | 115 | /// copies the row given by row_index, and push it at the end, creating duplicate 116 | pub fn copy_row_at_index(&mut self, row_index: usize) { 117 | let new_row = self.rows.get( row_index).cloned().unwrap(); 118 | self.rows.push(new_row); 119 | } 120 | 121 | /// Adds a column 122 | pub fn add_column(&mut self, col_name: &str) { 123 | if self.columns.contains_key(col_name) { 124 | return; 125 | } 126 | self.columns.insert(col_name.to_string(), self.col_index); 127 | self.col_index += 1; 128 | } 129 | 130 | /// Adds multiple columns, the sequence will be maintained. 131 | pub fn add_columns(&mut self, cols: Vec<&str>) { 132 | for col in cols { 133 | self.add_column(col) 134 | } 135 | } 136 | 137 | /// Inserts value in the target vec in the given index. If there's not enough elements, 138 | /// it will fill it up with default value, and then insert the value in required position 139 | pub fn insert(&mut self, col_name: &str, value: T) -> Result<(), TableMapErrors> { 140 | let index = self.get_column_index(col_name)?; 141 | self.fill_to_end(); 142 | let current_row = self.get_or_create_current_row(); 143 | current_row[index] = value; 144 | Ok(()) 145 | } 146 | 147 | pub fn get_column_index(&self, col_name: &str) -> Result { 148 | self.columns 149 | .get(col_name) 150 | .ok_or(TableMapErrors::InvalidColumnName) 151 | .cloned() 152 | } 153 | 154 | /// If there are more columns than the target row, fills, all the missing columns 155 | /// with default value 156 | pub fn fill_to_end(&mut self) { 157 | let n = self.col_index - 1; 158 | self.fill_target(&n, 0); 159 | } 160 | 161 | fn fill_target(&mut self, end: &usize, start: usize) { 162 | let current_row = self.get_or_create_current_row(); 163 | for ii in start..=*end { 164 | if let None = current_row.get(ii) { 165 | current_row.push(T::default()) 166 | } 167 | } 168 | } 169 | 170 | /// gets data from current row, using the column name. 171 | pub fn get_column_value(&self, col_name: &str) -> Result { 172 | let index = self.get_column_index(col_name)?; 173 | let current_row = self.get_current_row()?; 174 | current_row 175 | .get(index) 176 | .ok_or(TableMapErrors::NoDataSet) 177 | .cloned() 178 | } 179 | 180 | /// gets data from indexed row, using the column name. 181 | pub fn get_column_value_by_index( 182 | &self, 183 | row_index: usize, 184 | col_name: &str, 185 | ) -> Result { 186 | let index = self.get_column_index(col_name)?; 187 | let selected_row = self 188 | .rows 189 | .get(row_index) 190 | .ok_or(TableMapErrors::InvalidRowIndex)?; 191 | selected_row 192 | .get(index) 193 | .ok_or(TableMapErrors::NoDataSet) 194 | .cloned() 195 | } 196 | 197 | /// get all the data, this returns reference, so will not take any additional memory 198 | pub fn get_vec(&self) -> &Vec> { 199 | &self.rows 200 | } 201 | 202 | pub fn update_row(&mut self, row_index: usize, col_name: &str, new_val: T) -> Result<(), TableMapErrors> { 203 | let index = self.get_column_index(col_name)?; 204 | let row = self.get_row_by_index_mut(row_index)?; 205 | if let Some(val) = row.get_mut(index) { 206 | *val = new_val; 207 | } 208 | Ok(()) 209 | } 210 | 211 | fn get_row_by_index_mut(&mut self, row: usize) -> Result<&mut Vec, TableMapErrors> { 212 | self.rows 213 | .get_mut(row) 214 | .ok_or(TableMapErrors::InvalidRowIndex) 215 | } 216 | 217 | pub fn get_current_row(&self) -> Result<&Vec, TableMapErrors> { 218 | self.rows.last().ok_or(TableMapErrors::NoDataSet) 219 | } 220 | 221 | pub fn get_current_row_mut(&mut self) -> Result<&mut Vec, TableMapErrors> { 222 | self.rows.last_mut().ok_or(TableMapErrors::NoDataSet) 223 | } 224 | 225 | pub fn get_or_create_current_row(&mut self) -> &mut Vec { 226 | if self.rows.last().is_none() { 227 | self.rows.push(vec![T::default(); self.columns.len()]); 228 | } 229 | self.rows.last_mut().unwrap() 230 | } 231 | 232 | /// returns iter for the inner vec 233 | pub fn iter(&self) -> Iter<'_, Vec> { 234 | self.rows.iter() 235 | } 236 | 237 | } 238 | -------------------------------------------------------------------------------- /src/tests.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | #[test] 4 | fn test_filling() { 5 | let mut tm = TableMap::new(); 6 | tm.add_columns(vec!["c0", "c1", "c2", "c3"]); 7 | tm.insert("c0", "Something").unwrap(); 8 | let v = tm.get_vec(); 9 | println!("{:?}", v); 10 | assert_eq!( 11 | v[0], 12 | vec!["Something", "", "", ""] 13 | ); 14 | tm.fill_to_end(); 15 | let v = tm.get_vec(); 16 | println!("{:?}", v); 17 | assert_eq!( 18 | v[0], 19 | vec!["Something", "", "", ""] 20 | ); 21 | } 22 | 23 | #[test] 24 | fn test_macro() { 25 | let mut tm = TableMap::new(); 26 | tm.add_columns(vec!["c0", "c1", "c2", "c3"]); 27 | update_row! { tm, "c0", "c0v" } 28 | update_row! { 29 | tm, 30 | "c1", "Something", 31 | "c2", "v2", 32 | "c3", "32" 33 | } 34 | // get all the columns, sequence is maintained 35 | assert_eq!(tm.get_columns(), vec!["c0", "c1", "c2", "c3"]); 36 | assert_eq!(tm.get_vec(), &vec![vec!["c0v", "Something", "v2", "32"]]); 37 | } 38 | 39 | #[test] 40 | fn get_column_index_by_name() { 41 | let mut tm = TableMap::new(); 42 | tm.add_columns(vec!["c0", "c1", "c2", "c3"]); 43 | update_row! { tm, "c0", "c0v" } 44 | update_row! { 45 | tm, 46 | "c1", "Something", 47 | "c2", "v2", 48 | "c3", "32" 49 | } 50 | // get all the columns, sequence is maintained 51 | assert_eq!( 52 | tm.get_column_value_by_index(0, "c0").unwrap(), 53 | "c0v" 54 | ); 55 | assert_eq!(tm.get_column_value("c1").unwrap(), "Something"); 56 | } 57 | 58 | #[test] 59 | fn get_value_by_name() { 60 | let mut tm: TableMap = TableMap::new(); 61 | tm.add_columns(vec!["c0", "c1", "c2", "c3"]); 62 | 63 | assert_eq!(tm.get_column_index("c3").unwrap(), 3); 64 | } 65 | 66 | #[test] 67 | fn test_macro_obj() { 68 | #[derive(Clone, Default, PartialEq, Debug)] 69 | struct TestStruct { 70 | val: i32, 71 | } 72 | let ar = vec![ 73 | TestStruct { val: 30 }, 74 | TestStruct { val: 100 }, 75 | TestStruct { val: 1230 }, 76 | TestStruct { val: 800 }, 77 | ]; 78 | let mut tm = TableMap::new(); 79 | tm.add_columns(vec!["c0", "c1", "c2", "c3"]); 80 | update_row! { tm, "c0", ar[0].clone() } 81 | update_row! { 82 | tm, 83 | "c1", ar[1].clone(), 84 | "c2", ar[2].clone(), 85 | "c3", ar[3].clone() 86 | } 87 | assert_eq!(tm.get_vec(), &vec![ar]) 88 | } 89 | 90 | #[test] 91 | fn test_insert_randomly() { 92 | let mut tm = TableMap::new(); 93 | tm.add_columns(vec!["c0", "c1", "c2", "c3"]); 94 | 95 | update_row! { 96 | tm, 97 | "c1", "Something", 98 | "c3", "Another thing", 99 | "c2", "First thing" 100 | } 101 | assert_eq!(tm.get_column_value("c1").unwrap(), "Something"); 102 | assert!(tm.get_column_value("c10").is_err()); 103 | assert_eq!( 104 | tm.get_vec(), 105 | &vec![vec!["", "Something", "First thing", "Another thing"]] 106 | ); 107 | } 108 | 109 | #[test] 110 | fn test_extending_with_new_column() { 111 | let mut tm = TableMap::new(); 112 | tm.add_columns(vec!["c0", "c1", "c2", "c3"]); 113 | update_row! { 114 | tm, 115 | "c1", "Something", 116 | "c3", "Another thing", 117 | "c2", "First thing" 118 | } 119 | tm.add_column("c5"); 120 | tm.insert("c0", "First First thing").unwrap(); 121 | // no matter how the data is inserted, the sequence of column is maintained 122 | assert_eq!( 123 | tm.get_vec(), 124 | &vec![vec![ 125 | "First First thing", 126 | "Something", 127 | "First thing", 128 | "Another thing", 129 | "", 130 | ]] 131 | ); 132 | } 133 | 134 | #[test] 135 | fn test_multiple_row_with_empty_column() { 136 | let mut tm = TableMap::new(); 137 | tm.add_columns(vec!["c0", "c1", "c2", "c3"]); 138 | push! { 139 | tm, 140 | "c0", "c0v", 141 | "c1", "Something", 142 | "c2", "v2", 143 | "c3", "32" 144 | } 145 | push! { 146 | tm, 147 | "c0", "c0v", 148 | "c2", "v2", 149 | "c3", "32" 150 | } 151 | push! { 152 | tm, 153 | "c0", "c0v", 154 | "c1", "Something", 155 | "c2", "v2" 156 | } 157 | assert_eq!( 158 | tm.get_vec(), 159 | &vec![ 160 | vec!["c0v", "Something", "v2", "32"], 161 | vec!["c0v", "", "v2", "32"], 162 | vec!["c0v", "Something", "v2", ""], 163 | ] 164 | ); 165 | } 166 | 167 | #[test] 168 | fn test_multi_datasets_csv() { 169 | let mut tm = TableMap::new(); 170 | tm.add_columns(vec!["c0", "c1"]); 171 | // insert data for first dataset 172 | push! { 173 | tm, 174 | "c0", "c0v", 175 | "c1", "Something" 176 | } 177 | tm.add_columns(vec!["c4", "c5"]); 178 | // insert data for second dataset 179 | push! { 180 | tm, 181 | "c4", "v2", 182 | "c5", "32" 183 | } 184 | // mixture of dataset is possible 185 | tm.add_columns(vec!["c1", "c5"]); 186 | push! { 187 | tm, 188 | "c1", "another set", 189 | "c5", "mixed dataset" 190 | } 191 | assert_eq!( 192 | tm.get_vec(), 193 | &vec![ 194 | vec!["c0v", "Something"], 195 | vec!["", "", "v2", "32"], 196 | vec!["", "another set", "", "mixed dataset"], 197 | ] 198 | ); 199 | } 200 | 201 | // testing unset columns 202 | fn setup_for_unset_columns() -> TableMap { 203 | let mut tm = TableMap::new(); 204 | tm.add_columns(vec!["c0", "c1", "c2", "c3"]); 205 | update_row! { 206 | tm, 207 | "c0", "r1d0".into(), 208 | "c2", "r1d2".into() 209 | } 210 | tm 211 | } 212 | 213 | #[test] 214 | fn test_unset_column_value_should_be_empty() { 215 | let tm = setup_for_unset_columns(); 216 | // this will be an empty value, as inserted row does not set "c3" column 217 | assert_eq!(tm.get_column_value("c3").unwrap(), ""); 218 | } 219 | 220 | #[test] 221 | fn test_accessing_rows_added_before_additional_column_returns_error() { 222 | let mut tm = setup_for_unset_columns(); 223 | tm.add_column("c4"); 224 | // this will cause a NoDataSet error, cause column c4 was created after setting *this* row 225 | assert!(tm.get_column_value("c4").is_err()); 226 | } 227 | 228 | #[test] 229 | fn test_filling_unset_columns() { 230 | let mut tm = setup_for_unset_columns(); 231 | tm.add_column("c4"); 232 | tm.fill_to_end(); 233 | assert!(tm.get_column_value("c4").is_ok()); 234 | } 235 | 236 | #[test] 237 | fn test_before_moving_to_next_row_will_not_fill_up_current_row() { 238 | let mut tm = setup_for_unset_columns(); 239 | tm.add_column("c4"); 240 | tm.next_row(); 241 | assert!(tm.get_column_value_by_index(0, "c4").is_err()); 242 | } 243 | 244 | #[test] 245 | fn ignore_last_empty_row() { 246 | let mut tm: TableMap = TableMap::new(); 247 | tm.add_columns(vec!["c0", "c1", "c2", "c3"]); 248 | assert_eq!(tm.get_vec(), &Vec::>::new()); 249 | push! { 250 | tm, 251 | "c0", "r0d0".into(), 252 | "c2", "r0d2".into() 253 | } 254 | assert_eq!( 255 | tm.get_vec(), 256 | &vec![ 257 | vec![ 258 | "r0d0".to_string(), 259 | "".to_string(), 260 | "r0d2".to_string(), 261 | "".to_string(), 262 | ] 263 | ] 264 | ); 265 | } 266 | 267 | #[test] 268 | fn accessing_previous_row() { 269 | let mut tm = TableMap::new(); 270 | tm.add_columns(vec!["c0", "c1", "c2", "c3"]); 271 | push! { 272 | tm, 273 | "c0", "r0d0".into(), 274 | "c2", "r0d2".into() 275 | } 276 | push! { 277 | tm, 278 | "c0", "r1d0".into(), 279 | "c2", "r1d2".into() 280 | } 281 | push! { 282 | tm, 283 | "c0", "r2d0".into(), 284 | "c1", "r2d1".into() 285 | } 286 | tm.update_row(1, "c1", "r1d1.new").unwrap(); 287 | tm.update_row(0, "c2", "r0d2.mod").unwrap(); 288 | 289 | assert_eq!( 290 | tm.get_vec(), 291 | &vec![ 292 | vec![ "r0d0", "", "r0d2.mod", ""], 293 | vec![ "r1d0", "r1d1.new", "r1d2", ""], 294 | vec![ "r2d0", "r2d1", "", ""], 295 | ] 296 | ) 297 | } 298 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "1.0.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "anes" 16 | version = "0.1.6" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" 19 | 20 | [[package]] 21 | name = "anstyle" 22 | version = "1.0.1" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" 25 | 26 | [[package]] 27 | name = "autocfg" 28 | version = "1.1.0" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 31 | 32 | [[package]] 33 | name = "bitflags" 34 | version = "2.3.3" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" 37 | 38 | [[package]] 39 | name = "bumpalo" 40 | version = "3.13.0" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" 43 | 44 | [[package]] 45 | name = "cast" 46 | version = "0.3.0" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" 49 | 50 | [[package]] 51 | name = "cc" 52 | version = "1.0.81" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "6c6b2562119bf28c3439f7f02db99faf0aa1a8cdfe5772a2ee155d32227239f0" 55 | dependencies = [ 56 | "libc", 57 | ] 58 | 59 | [[package]] 60 | name = "cfg-if" 61 | version = "1.0.0" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 64 | 65 | [[package]] 66 | name = "ciborium" 67 | version = "0.2.1" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" 70 | dependencies = [ 71 | "ciborium-io", 72 | "ciborium-ll", 73 | "serde", 74 | ] 75 | 76 | [[package]] 77 | name = "ciborium-io" 78 | version = "0.2.1" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" 81 | 82 | [[package]] 83 | name = "ciborium-ll" 84 | version = "0.2.1" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" 87 | dependencies = [ 88 | "ciborium-io", 89 | "half", 90 | ] 91 | 92 | [[package]] 93 | name = "clap" 94 | version = "4.3.19" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "5fd304a20bff958a57f04c4e96a2e7594cc4490a0e809cbd48bb6437edaa452d" 97 | dependencies = [ 98 | "clap_builder", 99 | ] 100 | 101 | [[package]] 102 | name = "clap_builder" 103 | version = "4.3.19" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1" 106 | dependencies = [ 107 | "anstyle", 108 | "clap_lex", 109 | ] 110 | 111 | [[package]] 112 | name = "clap_lex" 113 | version = "0.5.0" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" 116 | 117 | [[package]] 118 | name = "criterion" 119 | version = "0.5.1" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" 122 | dependencies = [ 123 | "anes", 124 | "cast", 125 | "ciborium", 126 | "clap", 127 | "criterion-plot", 128 | "is-terminal", 129 | "itertools", 130 | "num-traits", 131 | "once_cell", 132 | "oorandom", 133 | "plotters", 134 | "rayon", 135 | "regex", 136 | "serde", 137 | "serde_derive", 138 | "serde_json", 139 | "tinytemplate", 140 | "walkdir", 141 | ] 142 | 143 | [[package]] 144 | name = "criterion-plot" 145 | version = "0.5.0" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" 148 | dependencies = [ 149 | "cast", 150 | "itertools", 151 | ] 152 | 153 | [[package]] 154 | name = "crossbeam-channel" 155 | version = "0.5.8" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" 158 | dependencies = [ 159 | "cfg-if", 160 | "crossbeam-utils", 161 | ] 162 | 163 | [[package]] 164 | name = "crossbeam-deque" 165 | version = "0.8.3" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" 168 | dependencies = [ 169 | "cfg-if", 170 | "crossbeam-epoch", 171 | "crossbeam-utils", 172 | ] 173 | 174 | [[package]] 175 | name = "crossbeam-epoch" 176 | version = "0.9.15" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" 179 | dependencies = [ 180 | "autocfg", 181 | "cfg-if", 182 | "crossbeam-utils", 183 | "memoffset", 184 | "scopeguard", 185 | ] 186 | 187 | [[package]] 188 | name = "crossbeam-utils" 189 | version = "0.8.16" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" 192 | dependencies = [ 193 | "cfg-if", 194 | ] 195 | 196 | [[package]] 197 | name = "either" 198 | version = "1.8.1" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" 201 | 202 | [[package]] 203 | name = "equivalent" 204 | version = "1.0.1" 205 | source = "registry+https://github.com/rust-lang/crates.io-index" 206 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 207 | 208 | [[package]] 209 | name = "errno" 210 | version = "0.3.2" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" 213 | dependencies = [ 214 | "errno-dragonfly", 215 | "libc", 216 | "windows-sys", 217 | ] 218 | 219 | [[package]] 220 | name = "errno-dragonfly" 221 | version = "0.1.2" 222 | source = "registry+https://github.com/rust-lang/crates.io-index" 223 | checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" 224 | dependencies = [ 225 | "cc", 226 | "libc", 227 | ] 228 | 229 | [[package]] 230 | name = "getrandom" 231 | version = "0.2.10" 232 | source = "registry+https://github.com/rust-lang/crates.io-index" 233 | checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" 234 | dependencies = [ 235 | "cfg-if", 236 | "libc", 237 | "wasi", 238 | ] 239 | 240 | [[package]] 241 | name = "half" 242 | version = "1.8.2" 243 | source = "registry+https://github.com/rust-lang/crates.io-index" 244 | checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" 245 | 246 | [[package]] 247 | name = "hashbrown" 248 | version = "0.14.0" 249 | source = "registry+https://github.com/rust-lang/crates.io-index" 250 | checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" 251 | 252 | [[package]] 253 | name = "heck" 254 | version = "0.4.1" 255 | source = "registry+https://github.com/rust-lang/crates.io-index" 256 | checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 257 | 258 | [[package]] 259 | name = "hermit-abi" 260 | version = "0.3.2" 261 | source = "registry+https://github.com/rust-lang/crates.io-index" 262 | checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" 263 | 264 | [[package]] 265 | name = "indexmap" 266 | version = "2.0.0" 267 | source = "registry+https://github.com/rust-lang/crates.io-index" 268 | checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" 269 | dependencies = [ 270 | "equivalent", 271 | "hashbrown", 272 | ] 273 | 274 | [[package]] 275 | name = "is-terminal" 276 | version = "0.4.9" 277 | source = "registry+https://github.com/rust-lang/crates.io-index" 278 | checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" 279 | dependencies = [ 280 | "hermit-abi", 281 | "rustix", 282 | "windows-sys", 283 | ] 284 | 285 | [[package]] 286 | name = "itertools" 287 | version = "0.10.5" 288 | source = "registry+https://github.com/rust-lang/crates.io-index" 289 | checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" 290 | dependencies = [ 291 | "either", 292 | ] 293 | 294 | [[package]] 295 | name = "itoa" 296 | version = "1.0.9" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" 299 | 300 | [[package]] 301 | name = "js-sys" 302 | version = "0.3.64" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" 305 | dependencies = [ 306 | "wasm-bindgen", 307 | ] 308 | 309 | [[package]] 310 | name = "lazy_static" 311 | version = "1.4.0" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 314 | 315 | [[package]] 316 | name = "libc" 317 | version = "0.2.147" 318 | source = "registry+https://github.com/rust-lang/crates.io-index" 319 | checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" 320 | 321 | [[package]] 322 | name = "linux-raw-sys" 323 | version = "0.4.5" 324 | source = "registry+https://github.com/rust-lang/crates.io-index" 325 | checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" 326 | 327 | [[package]] 328 | name = "log" 329 | version = "0.4.19" 330 | source = "registry+https://github.com/rust-lang/crates.io-index" 331 | checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" 332 | 333 | [[package]] 334 | name = "memchr" 335 | version = "2.5.0" 336 | source = "registry+https://github.com/rust-lang/crates.io-index" 337 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 338 | 339 | [[package]] 340 | name = "memoffset" 341 | version = "0.9.0" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" 344 | dependencies = [ 345 | "autocfg", 346 | ] 347 | 348 | [[package]] 349 | name = "nu-ansi-term" 350 | version = "0.46.0" 351 | source = "registry+https://github.com/rust-lang/crates.io-index" 352 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 353 | dependencies = [ 354 | "overload", 355 | "winapi", 356 | ] 357 | 358 | [[package]] 359 | name = "num-traits" 360 | version = "0.2.15" 361 | source = "registry+https://github.com/rust-lang/crates.io-index" 362 | checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" 363 | dependencies = [ 364 | "autocfg", 365 | ] 366 | 367 | [[package]] 368 | name = "num_cpus" 369 | version = "1.16.0" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" 372 | dependencies = [ 373 | "hermit-abi", 374 | "libc", 375 | ] 376 | 377 | [[package]] 378 | name = "once_cell" 379 | version = "1.18.0" 380 | source = "registry+https://github.com/rust-lang/crates.io-index" 381 | checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" 382 | 383 | [[package]] 384 | name = "oorandom" 385 | version = "11.1.3" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" 388 | 389 | [[package]] 390 | name = "overload" 391 | version = "0.1.1" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 394 | 395 | [[package]] 396 | name = "pin-project-lite" 397 | version = "0.2.10" 398 | source = "registry+https://github.com/rust-lang/crates.io-index" 399 | checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" 400 | 401 | [[package]] 402 | name = "plotters" 403 | version = "0.3.5" 404 | source = "registry+https://github.com/rust-lang/crates.io-index" 405 | checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" 406 | dependencies = [ 407 | "num-traits", 408 | "plotters-backend", 409 | "plotters-svg", 410 | "wasm-bindgen", 411 | "web-sys", 412 | ] 413 | 414 | [[package]] 415 | name = "plotters-backend" 416 | version = "0.3.5" 417 | source = "registry+https://github.com/rust-lang/crates.io-index" 418 | checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" 419 | 420 | [[package]] 421 | name = "plotters-svg" 422 | version = "0.3.5" 423 | source = "registry+https://github.com/rust-lang/crates.io-index" 424 | checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" 425 | dependencies = [ 426 | "plotters-backend", 427 | ] 428 | 429 | [[package]] 430 | name = "ppv-lite86" 431 | version = "0.2.17" 432 | source = "registry+https://github.com/rust-lang/crates.io-index" 433 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 434 | 435 | [[package]] 436 | name = "proc-macro2" 437 | version = "1.0.63" 438 | source = "registry+https://github.com/rust-lang/crates.io-index" 439 | checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" 440 | dependencies = [ 441 | "unicode-ident", 442 | ] 443 | 444 | [[package]] 445 | name = "quote" 446 | version = "1.0.29" 447 | source = "registry+https://github.com/rust-lang/crates.io-index" 448 | checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" 449 | dependencies = [ 450 | "proc-macro2", 451 | ] 452 | 453 | [[package]] 454 | name = "rand" 455 | version = "0.8.5" 456 | source = "registry+https://github.com/rust-lang/crates.io-index" 457 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 458 | dependencies = [ 459 | "libc", 460 | "rand_chacha", 461 | "rand_core", 462 | ] 463 | 464 | [[package]] 465 | name = "rand_chacha" 466 | version = "0.3.1" 467 | source = "registry+https://github.com/rust-lang/crates.io-index" 468 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 469 | dependencies = [ 470 | "ppv-lite86", 471 | "rand_core", 472 | ] 473 | 474 | [[package]] 475 | name = "rand_core" 476 | version = "0.6.4" 477 | source = "registry+https://github.com/rust-lang/crates.io-index" 478 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 479 | dependencies = [ 480 | "getrandom", 481 | ] 482 | 483 | [[package]] 484 | name = "rayon" 485 | version = "1.7.0" 486 | source = "registry+https://github.com/rust-lang/crates.io-index" 487 | checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" 488 | dependencies = [ 489 | "either", 490 | "rayon-core", 491 | ] 492 | 493 | [[package]] 494 | name = "rayon-core" 495 | version = "1.11.0" 496 | source = "registry+https://github.com/rust-lang/crates.io-index" 497 | checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" 498 | dependencies = [ 499 | "crossbeam-channel", 500 | "crossbeam-deque", 501 | "crossbeam-utils", 502 | "num_cpus", 503 | ] 504 | 505 | [[package]] 506 | name = "regex" 507 | version = "1.9.1" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" 510 | dependencies = [ 511 | "aho-corasick", 512 | "memchr", 513 | "regex-automata", 514 | "regex-syntax", 515 | ] 516 | 517 | [[package]] 518 | name = "regex-automata" 519 | version = "0.3.3" 520 | source = "registry+https://github.com/rust-lang/crates.io-index" 521 | checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" 522 | dependencies = [ 523 | "aho-corasick", 524 | "memchr", 525 | "regex-syntax", 526 | ] 527 | 528 | [[package]] 529 | name = "regex-syntax" 530 | version = "0.7.4" 531 | source = "registry+https://github.com/rust-lang/crates.io-index" 532 | checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" 533 | 534 | [[package]] 535 | name = "rustix" 536 | version = "0.38.6" 537 | source = "registry+https://github.com/rust-lang/crates.io-index" 538 | checksum = "1ee020b1716f0a80e2ace9b03441a749e402e86712f15f16fe8a8f75afac732f" 539 | dependencies = [ 540 | "bitflags", 541 | "errno", 542 | "libc", 543 | "linux-raw-sys", 544 | "windows-sys", 545 | ] 546 | 547 | [[package]] 548 | name = "rustversion" 549 | version = "1.0.14" 550 | source = "registry+https://github.com/rust-lang/crates.io-index" 551 | checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" 552 | 553 | [[package]] 554 | name = "ryu" 555 | version = "1.0.15" 556 | source = "registry+https://github.com/rust-lang/crates.io-index" 557 | checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" 558 | 559 | [[package]] 560 | name = "same-file" 561 | version = "1.0.6" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 564 | dependencies = [ 565 | "winapi-util", 566 | ] 567 | 568 | [[package]] 569 | name = "scopeguard" 570 | version = "1.1.0" 571 | source = "registry+https://github.com/rust-lang/crates.io-index" 572 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 573 | 574 | [[package]] 575 | name = "serde" 576 | version = "1.0.168" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | checksum = "d614f89548720367ded108b3c843be93f3a341e22d5674ca0dd5cd57f34926af" 579 | dependencies = [ 580 | "serde_derive", 581 | ] 582 | 583 | [[package]] 584 | name = "serde_derive" 585 | version = "1.0.168" 586 | source = "registry+https://github.com/rust-lang/crates.io-index" 587 | checksum = "d4fe589678c688e44177da4f27152ee2d190757271dc7f1d5b6b9f68d869d641" 588 | dependencies = [ 589 | "proc-macro2", 590 | "quote", 591 | "syn", 592 | ] 593 | 594 | [[package]] 595 | name = "serde_json" 596 | version = "1.0.103" 597 | source = "registry+https://github.com/rust-lang/crates.io-index" 598 | checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" 599 | dependencies = [ 600 | "itoa", 601 | "ryu", 602 | "serde", 603 | ] 604 | 605 | [[package]] 606 | name = "sharded-slab" 607 | version = "0.1.4" 608 | source = "registry+https://github.com/rust-lang/crates.io-index" 609 | checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" 610 | dependencies = [ 611 | "lazy_static", 612 | ] 613 | 614 | [[package]] 615 | name = "smallvec" 616 | version = "1.11.0" 617 | source = "registry+https://github.com/rust-lang/crates.io-index" 618 | checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" 619 | 620 | [[package]] 621 | name = "strum" 622 | version = "0.25.0" 623 | source = "registry+https://github.com/rust-lang/crates.io-index" 624 | checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" 625 | dependencies = [ 626 | "strum_macros", 627 | ] 628 | 629 | [[package]] 630 | name = "strum_macros" 631 | version = "0.25.2" 632 | source = "registry+https://github.com/rust-lang/crates.io-index" 633 | checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059" 634 | dependencies = [ 635 | "heck", 636 | "proc-macro2", 637 | "quote", 638 | "rustversion", 639 | "syn", 640 | ] 641 | 642 | [[package]] 643 | name = "syn" 644 | version = "2.0.23" 645 | source = "registry+https://github.com/rust-lang/crates.io-index" 646 | checksum = "59fb7d6d8281a51045d62b8eb3a7d1ce347b76f312af50cd3dc0af39c87c1737" 647 | dependencies = [ 648 | "proc-macro2", 649 | "quote", 650 | "unicode-ident", 651 | ] 652 | 653 | [[package]] 654 | name = "table_map" 655 | version = "0.1.0" 656 | dependencies = [ 657 | "criterion", 658 | "indexmap", 659 | "rand", 660 | "strum", 661 | "strum_macros", 662 | "thiserror", 663 | "tracing", 664 | "tracing-subscriber", 665 | ] 666 | 667 | [[package]] 668 | name = "thiserror" 669 | version = "1.0.41" 670 | source = "registry+https://github.com/rust-lang/crates.io-index" 671 | checksum = "c16a64ba9387ef3fdae4f9c1a7f07a0997fce91985c0336f1ddc1822b3b37802" 672 | dependencies = [ 673 | "thiserror-impl", 674 | ] 675 | 676 | [[package]] 677 | name = "thiserror-impl" 678 | version = "1.0.41" 679 | source = "registry+https://github.com/rust-lang/crates.io-index" 680 | checksum = "d14928354b01c4d6a4f0e549069adef399a284e7995c7ccca94e8a07a5346c59" 681 | dependencies = [ 682 | "proc-macro2", 683 | "quote", 684 | "syn", 685 | ] 686 | 687 | [[package]] 688 | name = "thread_local" 689 | version = "1.1.7" 690 | source = "registry+https://github.com/rust-lang/crates.io-index" 691 | checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" 692 | dependencies = [ 693 | "cfg-if", 694 | "once_cell", 695 | ] 696 | 697 | [[package]] 698 | name = "tinytemplate" 699 | version = "1.2.1" 700 | source = "registry+https://github.com/rust-lang/crates.io-index" 701 | checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" 702 | dependencies = [ 703 | "serde", 704 | "serde_json", 705 | ] 706 | 707 | [[package]] 708 | name = "tracing" 709 | version = "0.1.37" 710 | source = "registry+https://github.com/rust-lang/crates.io-index" 711 | checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" 712 | dependencies = [ 713 | "cfg-if", 714 | "pin-project-lite", 715 | "tracing-attributes", 716 | "tracing-core", 717 | ] 718 | 719 | [[package]] 720 | name = "tracing-attributes" 721 | version = "0.1.26" 722 | source = "registry+https://github.com/rust-lang/crates.io-index" 723 | checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" 724 | dependencies = [ 725 | "proc-macro2", 726 | "quote", 727 | "syn", 728 | ] 729 | 730 | [[package]] 731 | name = "tracing-core" 732 | version = "0.1.31" 733 | source = "registry+https://github.com/rust-lang/crates.io-index" 734 | checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" 735 | dependencies = [ 736 | "once_cell", 737 | "valuable", 738 | ] 739 | 740 | [[package]] 741 | name = "tracing-log" 742 | version = "0.1.3" 743 | source = "registry+https://github.com/rust-lang/crates.io-index" 744 | checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" 745 | dependencies = [ 746 | "lazy_static", 747 | "log", 748 | "tracing-core", 749 | ] 750 | 751 | [[package]] 752 | name = "tracing-subscriber" 753 | version = "0.3.17" 754 | source = "registry+https://github.com/rust-lang/crates.io-index" 755 | checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" 756 | dependencies = [ 757 | "nu-ansi-term", 758 | "sharded-slab", 759 | "smallvec", 760 | "thread_local", 761 | "tracing-core", 762 | "tracing-log", 763 | ] 764 | 765 | [[package]] 766 | name = "unicode-ident" 767 | version = "1.0.10" 768 | source = "registry+https://github.com/rust-lang/crates.io-index" 769 | checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" 770 | 771 | [[package]] 772 | name = "valuable" 773 | version = "0.1.0" 774 | source = "registry+https://github.com/rust-lang/crates.io-index" 775 | checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" 776 | 777 | [[package]] 778 | name = "walkdir" 779 | version = "2.3.3" 780 | source = "registry+https://github.com/rust-lang/crates.io-index" 781 | checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" 782 | dependencies = [ 783 | "same-file", 784 | "winapi-util", 785 | ] 786 | 787 | [[package]] 788 | name = "wasi" 789 | version = "0.11.0+wasi-snapshot-preview1" 790 | source = "registry+https://github.com/rust-lang/crates.io-index" 791 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 792 | 793 | [[package]] 794 | name = "wasm-bindgen" 795 | version = "0.2.87" 796 | source = "registry+https://github.com/rust-lang/crates.io-index" 797 | checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" 798 | dependencies = [ 799 | "cfg-if", 800 | "wasm-bindgen-macro", 801 | ] 802 | 803 | [[package]] 804 | name = "wasm-bindgen-backend" 805 | version = "0.2.87" 806 | source = "registry+https://github.com/rust-lang/crates.io-index" 807 | checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" 808 | dependencies = [ 809 | "bumpalo", 810 | "log", 811 | "once_cell", 812 | "proc-macro2", 813 | "quote", 814 | "syn", 815 | "wasm-bindgen-shared", 816 | ] 817 | 818 | [[package]] 819 | name = "wasm-bindgen-macro" 820 | version = "0.2.87" 821 | source = "registry+https://github.com/rust-lang/crates.io-index" 822 | checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" 823 | dependencies = [ 824 | "quote", 825 | "wasm-bindgen-macro-support", 826 | ] 827 | 828 | [[package]] 829 | name = "wasm-bindgen-macro-support" 830 | version = "0.2.87" 831 | source = "registry+https://github.com/rust-lang/crates.io-index" 832 | checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" 833 | dependencies = [ 834 | "proc-macro2", 835 | "quote", 836 | "syn", 837 | "wasm-bindgen-backend", 838 | "wasm-bindgen-shared", 839 | ] 840 | 841 | [[package]] 842 | name = "wasm-bindgen-shared" 843 | version = "0.2.87" 844 | source = "registry+https://github.com/rust-lang/crates.io-index" 845 | checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" 846 | 847 | [[package]] 848 | name = "web-sys" 849 | version = "0.3.64" 850 | source = "registry+https://github.com/rust-lang/crates.io-index" 851 | checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" 852 | dependencies = [ 853 | "js-sys", 854 | "wasm-bindgen", 855 | ] 856 | 857 | [[package]] 858 | name = "winapi" 859 | version = "0.3.9" 860 | source = "registry+https://github.com/rust-lang/crates.io-index" 861 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 862 | dependencies = [ 863 | "winapi-i686-pc-windows-gnu", 864 | "winapi-x86_64-pc-windows-gnu", 865 | ] 866 | 867 | [[package]] 868 | name = "winapi-i686-pc-windows-gnu" 869 | version = "0.4.0" 870 | source = "registry+https://github.com/rust-lang/crates.io-index" 871 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 872 | 873 | [[package]] 874 | name = "winapi-util" 875 | version = "0.1.5" 876 | source = "registry+https://github.com/rust-lang/crates.io-index" 877 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 878 | dependencies = [ 879 | "winapi", 880 | ] 881 | 882 | [[package]] 883 | name = "winapi-x86_64-pc-windows-gnu" 884 | version = "0.4.0" 885 | source = "registry+https://github.com/rust-lang/crates.io-index" 886 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 887 | 888 | [[package]] 889 | name = "windows-sys" 890 | version = "0.48.0" 891 | source = "registry+https://github.com/rust-lang/crates.io-index" 892 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 893 | dependencies = [ 894 | "windows-targets", 895 | ] 896 | 897 | [[package]] 898 | name = "windows-targets" 899 | version = "0.48.1" 900 | source = "registry+https://github.com/rust-lang/crates.io-index" 901 | checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" 902 | dependencies = [ 903 | "windows_aarch64_gnullvm", 904 | "windows_aarch64_msvc", 905 | "windows_i686_gnu", 906 | "windows_i686_msvc", 907 | "windows_x86_64_gnu", 908 | "windows_x86_64_gnullvm", 909 | "windows_x86_64_msvc", 910 | ] 911 | 912 | [[package]] 913 | name = "windows_aarch64_gnullvm" 914 | version = "0.48.0" 915 | source = "registry+https://github.com/rust-lang/crates.io-index" 916 | checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" 917 | 918 | [[package]] 919 | name = "windows_aarch64_msvc" 920 | version = "0.48.0" 921 | source = "registry+https://github.com/rust-lang/crates.io-index" 922 | checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" 923 | 924 | [[package]] 925 | name = "windows_i686_gnu" 926 | version = "0.48.0" 927 | source = "registry+https://github.com/rust-lang/crates.io-index" 928 | checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" 929 | 930 | [[package]] 931 | name = "windows_i686_msvc" 932 | version = "0.48.0" 933 | source = "registry+https://github.com/rust-lang/crates.io-index" 934 | checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" 935 | 936 | [[package]] 937 | name = "windows_x86_64_gnu" 938 | version = "0.48.0" 939 | source = "registry+https://github.com/rust-lang/crates.io-index" 940 | checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" 941 | 942 | [[package]] 943 | name = "windows_x86_64_gnullvm" 944 | version = "0.48.0" 945 | source = "registry+https://github.com/rust-lang/crates.io-index" 946 | checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" 947 | 948 | [[package]] 949 | name = "windows_x86_64_msvc" 950 | version = "0.48.0" 951 | source = "registry+https://github.com/rust-lang/crates.io-index" 952 | checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" 953 | --------------------------------------------------------------------------------