├── .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 |
4 |
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 |
10 |
11 |
12 |
13 |
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 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
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 |
--------------------------------------------------------------------------------