I'm playing around with a data structure for holding a couple of different types and I'm creating a gross Option spaghetti. I've just started learning Rust, and I think there is probably a better way to do this that I am not aware of. There is also a lot of code duplication that I don't know how to get rid of. Any help would be appreciated.
use chrono::NaiveDateTime;
use std::collections::HashMap;
use std::ops::Index;
#[derive(Debug)]
pub enum Column {
Numeric(Box<Vec<Option<f64>>>),
Alphabetic(Box<Vec<Option<String>>>),
Tempic(Box<Vec<Option<NaiveDateTime>>>),
}
impl Column {
fn numeric() -> Column {
Column::Numeric(Box::new(Vec::new()))
}
fn alphabetic() -> Column {
Column::Alphabetic(Box::new(Vec::new()))
}
fn tempic() -> Column {
Column::Tempic(Box::new(Vec::new()))
}
fn unwrap_numeric(&self) -> Option<&Box<Vec<Option<f64>>>> {
if let Column::Numeric(v) = self {
return Some(v);
} else {
return None;
}
}
fn unwrap_alphabetic(&self) -> Option<&Box<Vec<Option<String>>>> {
if let Column::Alphabetic(v) = self {
return Some(v);
} else {
return None;
}
}
fn unwrap_tempic(&self) -> Option<&Box<Vec<Option<NaiveDateTime>>>> {
if let Column::Tempic(v) = self {
return Some(v);
} else {
return None;
}
}
}
pub struct Tansu {
pub data: HashMap<String, Column>,
}
impl Tansu {
pub fn new() -> Tansu {
Tansu {
data: HashMap::new(),
}
}
pub fn add_to_numeric(&mut self, key: &str, data: Option<f64>) {
let c = self
.data
.entry(key.to_string())
.or_insert(Column::numeric());
if let Column::Numeric(v) = c {
v.push(data);
}
}
pub fn add_to_alphabetic(&mut self, key: &str, data: Option<String>) {
let c = self
.data
.entry(key.to_string())
.or_insert(Column::alphabetic());
if let Column::Alphabetic(v) = c {
v.push(data);
}
}
pub fn add_to_tempic(&mut self, key: &str, data: Option<NaiveDateTime>) {
let c = self.data.entry(key.to_string()).or_insert(Column::tempic());
if let Column::Tempic(v) = c {
v.push(data);
}
}
}
impl Index<&str> for Tansu {
type Output = Column;
fn index(&self, key: &str) -> &Self::Output {
match &self.data.get(key) {
Some(r) => r,
None => panic!(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn setup() -> Tansu {
Tansu::new()
}
#[test]
fn no_existing_key() {
let mut t = setup();
t.add_to_numeric("test", Some(5.0));
assert_eq!(
t.data.get("test").unwrap().unwrap_numeric().unwrap()[0],
Some(5.0)
);
}
#[test]
fn indexable() {
let mut t = setup();
t.add_to_numeric("test", Some(5.0));
assert_eq!(t["test"].unwrap_numeric().unwrap()[0], Some(5.0));
}
#[test]
fn print_it() {
println!("{:?}", "hi");
}
}