use std::collections::{btree_map, BTreeMap};
use std::ops::Index;
use crate::schema::body::FormDataValue;
use crate::schema::types::PrimitiveArray;
use serde::Deserialize;
#[cfg(feature = "input_params")]
use super::input_param::InputParam;
#[derive(Debug, Deserialize, PartialEq)]
pub(crate) struct Table<V>(pub(crate) BTreeMap<String, V>);
pub type PrimitiveTable = Table<PrimitiveArray>;
pub type FormDataTable = Table<FormDataValue>;
#[cfg(feature = "input_params")]
pub type InputParamsTable = Table<InputParam>;
impl<V> Index<&str> for Table<V> {
type Output = V;
fn index(&self, index: &str) -> &Self::Output {
&self.0[index]
}
}
impl<V> IntoIterator for Table<V> {
type Item = (String, V);
type IntoIter = btree_map::IntoIter<String, V>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<V> Default for Table<V> {
fn default() -> Self {
Self(BTreeMap::new())
}
}
pub trait Transform<V, O>: IntoIterator<Item = (String, V)>
where
Self: Sized,
{
fn map_value(value: V) -> O;
fn into_map(self) -> BTreeMap<String, O> {
self.into_iter()
.map(|(k, v)| (k, Self::map_value(v)))
.collect()
}
}
impl<V, O> Transform<V, O> for Table<V>
where
V: Into<O>,
{
fn map_value(value: V) -> O {
value.into()
}
}
impl PrimitiveTable {
pub(crate) fn into_pairs(self) -> Vec<(String, String)> {
let mut vec = Vec::new();
for (key, val) in self {
val.into_iter()
.map(String::from)
.for_each(|v| vec.push((key.clone(), v)));
}
vec
}
}
#[cfg(test)]
impl<V> Table<V> {
pub fn new(table: BTreeMap<String, V>) -> Self {
Self(table)
}
pub fn len(&self) -> usize {
self.0.len()
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn into_pairs() {
let pairs = new_test_table().into_pairs();
assert_eq!(pairs.len(), 6);
assert_pair(&pairs, "string", "value");
assert_pair(&pairs, "integer", "10");
assert_pair(&pairs, "float", "2.1");
assert_pair(&pairs, "boolean", "false");
}
#[test]
fn into_map() {
let map: BTreeMap<String, String> = new_test_table().into_map();
assert_eq!(map.len(), 5);
assert_eq!(map["string"], "value");
assert_eq!(map["integer"], "10");
assert_eq!(map["float"], "2.1");
assert_eq!(map["boolean"], "false");
assert_eq!(map["array"], "one,2");
}
fn new_test_table() -> PrimitiveTable {
let string = r#"
string = "value"
integer = 10
float = 2.1
boolean = false
array = [ "one", 2 ]
"#;
toml::from_str(string).unwrap()
}
fn assert_pair(pairs: &[(String, String)], key: &str, val: &str) {
assert_eq!(pairs.iter().find(|(k, _)| k == key).unwrap().1, val);
}
}