simple web server
This commit is contained in:
parent
50a25c494a
commit
921b62ed97
5 changed files with 624 additions and 40 deletions
|
|
@ -1,6 +1,4 @@
|
|||
use std::collections::HashMap;
|
||||
use std::fmt::Write;
|
||||
use std::rc::Rc;
|
||||
use std::{collections::HashMap, fmt::Write, sync::Arc};
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use pdf::{backend::Backend, content::Operation, primitive::Primitive};
|
||||
|
|
@ -21,15 +19,21 @@ const DATE_DISPLAY_FORMAT: &[time::format_description::FormatItem] =
|
|||
time::macros::format_description!("[year]-[month]-[day]");
|
||||
|
||||
pub struct DataSet {
|
||||
pub columns: Vec<Rc<String>>,
|
||||
pub columns: Vec<Arc<String>>,
|
||||
pub rows: Vec<DataPoint>,
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("PDF contained no data rows")]
|
||||
NoData,
|
||||
}
|
||||
|
||||
impl DataSet {
|
||||
pub fn extract<B: Backend>(doc: &pdf::file::File<B>) -> Option<Self> {
|
||||
pub fn extract<B: Backend>(doc: &pdf::file::File<B>) -> Result<Self, Error> {
|
||||
let mut doc_iter = DocumentIterator::new(doc).peekable();
|
||||
|
||||
let mut columns: Vec<(Rc<String>, f32)> = Vec::new();
|
||||
let mut columns: Vec<(Arc<String>, f32)> = Vec::new();
|
||||
let mut rows: Vec<DataPoint> = Vec::new();
|
||||
|
||||
let (mut current_datapoint, mut current_y) = loop {
|
||||
|
|
@ -39,7 +43,7 @@ impl DataSet {
|
|||
let column_x = text.x;
|
||||
while let Some(more) = doc_iter.peek() {
|
||||
if is_new_column_header(&more.text) || DATE_REGEX.is_match(&more.text) {
|
||||
columns.push((Rc::new(column_name), column_x));
|
||||
columns.push((Arc::new(column_name), column_x));
|
||||
break;
|
||||
}
|
||||
column_name += " ";
|
||||
|
|
@ -53,7 +57,7 @@ impl DataSet {
|
|||
);
|
||||
}
|
||||
} else {
|
||||
return None;
|
||||
return Err(Error::NoData);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -79,40 +83,44 @@ impl DataSet {
|
|||
}
|
||||
}
|
||||
|
||||
Some(Self {
|
||||
Ok(Self {
|
||||
columns: columns.into_iter().map(|(column, _)| column).collect(),
|
||||
rows,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn csv_header(&self) -> Result<String, std::fmt::Error> {
|
||||
let mut header = String::from("Date");
|
||||
for column in self.columns.iter() {
|
||||
write!(&mut header, ",{}", column)?;
|
||||
}
|
||||
Ok(header)
|
||||
}
|
||||
|
||||
pub fn csv_row(&self, datapoint: &DataPoint) -> Result<String, std::fmt::Error> {
|
||||
let mut csv_row = datapoint
|
||||
.date
|
||||
.format(DATE_DISPLAY_FORMAT)
|
||||
.expect("Failed to format date!");
|
||||
for column in self.columns.iter() {
|
||||
if let Some(val) = datapoint.values.get(column) {
|
||||
write!(&mut csv_row, ",{}", val)?;
|
||||
} else {
|
||||
write!(&mut csv_row, ",")?;
|
||||
}
|
||||
}
|
||||
Ok(csv_row)
|
||||
}
|
||||
|
||||
pub fn csv_rows(&self) -> impl Iterator<Item = Result<String, std::fmt::Error>> + '_ {
|
||||
std::iter::once_with(|| {
|
||||
let mut header = String::from("Date");
|
||||
for column in self.columns.iter() {
|
||||
write!(&mut header, ",{}", column)?;
|
||||
}
|
||||
Ok(header)
|
||||
})
|
||||
.chain(self.rows.iter().map(|datapoint| {
|
||||
let mut csv_row = datapoint
|
||||
.date
|
||||
.format(DATE_DISPLAY_FORMAT)
|
||||
.expect("Failed to format date!");
|
||||
for column in self.columns.iter() {
|
||||
if let Some(val) = datapoint.values.get(column) {
|
||||
write!(&mut csv_row, ",{}", val)?;
|
||||
} else {
|
||||
write!(&mut csv_row, ",")?;
|
||||
}
|
||||
}
|
||||
Ok(csv_row)
|
||||
}))
|
||||
std::iter::once_with(|| self.csv_header())
|
||||
.chain(self.rows.iter().map(|datapoint| self.csv_row(datapoint)))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DataPoint {
|
||||
pub date: Date,
|
||||
pub values: HashMap<Rc<String>, u32>,
|
||||
pub values: HashMap<Arc<String>, u32>,
|
||||
}
|
||||
|
||||
impl DataPoint {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue