Move parser code out of file.rs
This commit is contained in:
parent
4b8d7b0c4f
commit
589844102d
3 changed files with 129 additions and 125 deletions
|
@ -1,32 +1,3 @@
|
||||||
use regex::Regex;
|
|
||||||
|
|
||||||
pub struct ParserError {
|
|
||||||
summary: String,
|
|
||||||
parsertext: String,
|
|
||||||
index: i32,
|
|
||||||
explanation: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ParserError {
|
|
||||||
fn new(sum: &'static str, text: String, idx: i32, expl: &'static str) -> ParserError {
|
|
||||||
ParserError {
|
|
||||||
summary: String::from(sum),
|
|
||||||
parsertext: text,
|
|
||||||
index: idx,
|
|
||||||
explanation: Some(String::from(expl)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn short(sum: &'static str, text: String, idx: i32) -> ParserError {
|
|
||||||
ParserError {
|
|
||||||
summary: String::from(sum),
|
|
||||||
parsertext: text,
|
|
||||||
index: idx,
|
|
||||||
explanation: None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum FileHeaderSpec {
|
pub enum FileHeaderSpec {
|
||||||
Null,
|
Null,
|
||||||
Bool,
|
Bool,
|
||||||
|
@ -49,104 +20,8 @@ pub enum FileHeaderData {
|
||||||
Array { values: Box<Vec<FileHeaderData>> },
|
Array { values: Box<Vec<FileHeaderData>> },
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FileHeaderParser : Sized {
|
|
||||||
fn new(spec: &FileHeaderSpec) -> Self;
|
|
||||||
fn read(&self, string: Option<String>) -> Result<FileHeaderData, ParserError>;
|
|
||||||
fn write(&self, data: &FileHeaderData) -> Result<String, ParserError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait FileData : Sized {
|
pub trait FileData : Sized {
|
||||||
fn get_fulltext(&self) -> String;
|
fn get_fulltext(&self) -> String;
|
||||||
fn get_abbrev(&self) -> String;
|
fn get_abbrev(&self) -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FileDataParser<FD: FileData + Sized> : Sized {
|
|
||||||
fn new() -> Self;
|
|
||||||
fn read(&self, string: Option<String>) -> Result<FD, ParserError>;
|
|
||||||
fn write(&self, data: &FD) -> Result<String, ParserError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
type TextTpl = (Option<String>, Option<String>);
|
|
||||||
|
|
||||||
pub struct Parser<HP, DP>
|
|
||||||
{
|
|
||||||
headerp : HP,
|
|
||||||
datap : DP,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<HP, DP> Parser<HP, DP> where
|
|
||||||
HP: FileHeaderParser,
|
|
||||||
{
|
|
||||||
|
|
||||||
fn new(headerp: HP, datap: DP) -> Parser<HP, DP> {
|
|
||||||
Parser {
|
|
||||||
headerp: headerp,
|
|
||||||
datap: datap,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read<FD>(&self, s: String) -> Result<(FileHeaderData, FD), ParserError>
|
|
||||||
where FD: FileData + Sized,
|
|
||||||
DP: FileDataParser<FD>
|
|
||||||
{
|
|
||||||
let divided = divide_text(&s);
|
|
||||||
|
|
||||||
if divided.is_err() {
|
|
||||||
return Err(divided.err().unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
let (header, data) = divided.ok().unwrap();
|
|
||||||
|
|
||||||
let h_parseres = self.headerp.read(header);
|
|
||||||
let d_parseres = self.datap.read(data);
|
|
||||||
|
|
||||||
if h_parseres.is_err() {
|
|
||||||
return Err(h_parseres.err().unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
if d_parseres.is_err() {
|
|
||||||
return Err(d_parseres.err().unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok((h_parseres.ok().unwrap(), d_parseres.ok().unwrap()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write<FD>(&self, tpl : (FileHeaderData, FD)) -> Result<String, ParserError>
|
|
||||||
where FD: FileData + Sized,
|
|
||||||
DP: FileDataParser<FD>
|
|
||||||
{
|
|
||||||
let (header, data) = tpl;
|
|
||||||
let h_text = self.headerp.write(&header);
|
|
||||||
let d_text = self.datap.write(&data);
|
|
||||||
|
|
||||||
if h_text.is_err() {
|
|
||||||
return Err(h_text.err().unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
if d_text.is_err() {
|
|
||||||
return Err(d_text.err().unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(h_text.ok().unwrap() + &d_text.ok().unwrap()[..])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn divide_text(text: &String) -> Result<TextTpl, ParserError> {
|
|
||||||
let re = Regex::new(r"(?m)^\-\-\-$\n(.*)^\-\-\-$\n(.*)").unwrap();
|
|
||||||
|
|
||||||
let captures = re.captures(&text[..]).unwrap_or(
|
|
||||||
return Err(ParserError::new("Cannot run regex on text",
|
|
||||||
text.clone(), 0,
|
|
||||||
"Cannot run regex on text to divide it into header and content."))
|
|
||||||
);
|
|
||||||
|
|
||||||
if captures.len() != 2 {
|
|
||||||
return Err(ParserError::new("Unexpected Regex output",
|
|
||||||
text.clone(), 0,
|
|
||||||
"The regex to divide text into header and content had an unexpected output."))
|
|
||||||
}
|
|
||||||
|
|
||||||
let header = captures.at(0).map(|s| String::from(s));
|
|
||||||
let content = captures.at(1).map(|s| String::from(s));
|
|
||||||
Ok((header, content))
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ pub use std::error::Error;
|
||||||
pub use runtime::Runtime;
|
pub use runtime::Runtime;
|
||||||
|
|
||||||
mod file;
|
mod file;
|
||||||
|
mod parser;
|
||||||
|
|
||||||
pub trait StorageBackend {
|
pub trait StorageBackend {
|
||||||
|
|
||||||
|
|
128
src/storage/parser.rs
Normal file
128
src/storage/parser.rs
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
use super::file::*;
|
||||||
|
|
||||||
|
pub struct ParserError {
|
||||||
|
summary: String,
|
||||||
|
parsertext: String,
|
||||||
|
index: i32,
|
||||||
|
explanation: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParserError {
|
||||||
|
fn new(sum: &'static str, text: String, idx: i32, expl: &'static str) -> ParserError {
|
||||||
|
ParserError {
|
||||||
|
summary: String::from(sum),
|
||||||
|
parsertext: text,
|
||||||
|
index: idx,
|
||||||
|
explanation: Some(String::from(expl)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn short(sum: &'static str, text: String, idx: i32) -> ParserError {
|
||||||
|
ParserError {
|
||||||
|
summary: String::from(sum),
|
||||||
|
parsertext: text,
|
||||||
|
index: idx,
|
||||||
|
explanation: None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FileHeaderParser : Sized {
|
||||||
|
fn new(spec: &FileHeaderSpec) -> Self;
|
||||||
|
fn read(&self, string: Option<String>) -> Result<FileHeaderData, ParserError>;
|
||||||
|
fn write(&self, data: &FileHeaderData) -> Result<String, ParserError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FileDataParser<FD: FileData + Sized> : Sized {
|
||||||
|
fn new() -> Self;
|
||||||
|
fn read(&self, string: Option<String>) -> Result<FD, ParserError>;
|
||||||
|
fn write(&self, data: &FD) -> Result<String, ParserError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
type TextTpl = (Option<String>, Option<String>);
|
||||||
|
|
||||||
|
pub struct Parser<HP, DP>
|
||||||
|
{
|
||||||
|
headerp : HP,
|
||||||
|
datap : DP,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<HP, DP> Parser<HP, DP> where
|
||||||
|
HP: FileHeaderParser,
|
||||||
|
{
|
||||||
|
|
||||||
|
fn new(headerp: HP, datap: DP) -> Parser<HP, DP> {
|
||||||
|
Parser {
|
||||||
|
headerp: headerp,
|
||||||
|
datap: datap,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read<FD>(&self, s: String) -> Result<(FileHeaderData, FD), ParserError>
|
||||||
|
where FD: FileData + Sized,
|
||||||
|
DP: FileDataParser<FD>
|
||||||
|
{
|
||||||
|
let divided = divide_text(&s);
|
||||||
|
|
||||||
|
if divided.is_err() {
|
||||||
|
return Err(divided.err().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
let (header, data) = divided.ok().unwrap();
|
||||||
|
|
||||||
|
let h_parseres = self.headerp.read(header);
|
||||||
|
let d_parseres = self.datap.read(data);
|
||||||
|
|
||||||
|
if h_parseres.is_err() {
|
||||||
|
return Err(h_parseres.err().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
if d_parseres.is_err() {
|
||||||
|
return Err(d_parseres.err().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((h_parseres.ok().unwrap(), d_parseres.ok().unwrap()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write<FD>(&self, tpl : (FileHeaderData, FD)) -> Result<String, ParserError>
|
||||||
|
where FD: FileData + Sized,
|
||||||
|
DP: FileDataParser<FD>
|
||||||
|
{
|
||||||
|
let (header, data) = tpl;
|
||||||
|
let h_text = self.headerp.write(&header);
|
||||||
|
let d_text = self.datap.write(&data);
|
||||||
|
|
||||||
|
if h_text.is_err() {
|
||||||
|
return Err(h_text.err().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
if d_text.is_err() {
|
||||||
|
return Err(d_text.err().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(h_text.ok().unwrap() + &d_text.ok().unwrap()[..])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn divide_text(text: &String) -> Result<TextTpl, ParserError> {
|
||||||
|
let re = Regex::new(r"(?m)^\-\-\-$\n(.*)^\-\-\-$\n(.*)").unwrap();
|
||||||
|
|
||||||
|
let captures = re.captures(&text[..]).unwrap_or(
|
||||||
|
return Err(ParserError::new("Cannot run regex on text",
|
||||||
|
text.clone(), 0,
|
||||||
|
"Cannot run regex on text to divide it into header and content."))
|
||||||
|
);
|
||||||
|
|
||||||
|
if captures.len() != 2 {
|
||||||
|
return Err(ParserError::new("Unexpected Regex output",
|
||||||
|
text.clone(), 0,
|
||||||
|
"The regex to divide text into header and content had an unexpected output."))
|
||||||
|
}
|
||||||
|
|
||||||
|
let header = captures.at(0).map(|s| String::from(s));
|
||||||
|
let content = captures.at(1).map(|s| String::from(s));
|
||||||
|
Ok((header, content))
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue