use crate::error::CascError;
use std::fs::File;
use std::io::{BufRead, BufReader, Read};
use std::path::Path;
#[derive(Debug)]
pub(crate) struct DSVFile {
delimiter: String,
comment: Option<String>,
pub(crate) rows: Vec<Vec<String>>,
}
impl DSVFile {
pub(crate) fn new() -> Self {
Self {
delimiter: ",".to_string(),
comment: None,
rows: Vec::new(),
}
}
pub(crate) fn with_delimiter(delimiter: &str) -> Self {
Self {
delimiter: delimiter.to_string(),
comment: None,
rows: Vec::new(),
}
}
pub(crate) fn from_file<P: AsRef<Path>>(
file: P,
delimiter: &str,
comment: Option<&str>,
) -> Result<Self, CascError> {
let file = File::open(file)?;
let mut dsv = Self {
delimiter: delimiter.to_string(),
comment: comment.map(|s| s.to_string()),
rows: Vec::new(),
};
dsv.load(file)?;
Ok(dsv)
}
pub(crate) fn load<R: Read>(&mut self, reader: R) -> Result<(), CascError> {
let buffered = BufReader::new(reader);
let supports_commenting = self.comment.as_deref().map_or(false, |c| !c.is_empty());
for line in buffered.lines() {
let line = line?;
if line.trim().is_empty() {
continue;
}
if supports_commenting {
if let Some(ref comment) = self.comment {
if line.starts_with(comment) {
continue;
}
}
}
let row: Vec<String> = line.split(&self.delimiter).map(|s| s.to_string()).collect();
self.rows.push(row);
}
Ok(())
}
pub(crate) fn header(&self) -> Option<&Vec<String>> {
self.rows.first()
}
}