From ec1df06b245ee432230bfcdc5e00c6213f79025f Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 27 Oct 2015 23:11:56 +0100 Subject: [PATCH 01/25] Add file header types for specifying header structure and parsing it from "raw" text. --- src/module/mod.rs | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/module/mod.rs b/src/module/mod.rs index 9fd8b88a..59a10317 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -54,3 +54,57 @@ pub trait Module { } + +pub mod file { + + pub struct ParserError { + summary: String, + parsertext: String, + index: i32, + explanation: Option, + } + + pub mod header { + + pub enum FileHeaderSpec { + Null, + Bool, + Integer, + UInteger, + Float, + Text, + Key { name: String, value_type: Box }, + Array { allowed_types: Box> }, + } + + pub enum FileHeaderData { + Null, + Bool(bool), + Integer(i64), + UInteger(u64), + Float(f64), + Text(String), + Key { name: String, value: Box }, + Array { values: Box> }, + } + + pub trait FileHeaderParser { + fn new(spec: &FileHeaderSpec) -> Self; + fn read(&self, string: &String) -> Result; + fn write(&self, data: &FileHeaderData) -> Result; + } + + } + + pub trait FileData { + fn get_fulltext(&self) -> String; + fn get_abbrev(&self) -> String; + } + + pub trait FileParser { + fn new(header_parser: &header::FileHeaderParser) -> FileParser; + fn read(&self, string: String) -> (header::FileHeaderData, FileData); + fn write(&self, hdr: &header::FileHeaderData, data: &FileData) -> Result; + } + +} From 6ec4a701d3ba4dc47d0586cdbcf3d973fda17e3c Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 28 Oct 2015 17:37:58 +0100 Subject: [PATCH 02/25] Implement ParserError --- src/module/mod.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/module/mod.rs b/src/module/mod.rs index 59a10317..fd304137 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -64,6 +64,26 @@ pub mod file { explanation: Option, } + 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 mod header { pub enum FileHeaderSpec { From bdb0792040dd5b8d4d82e5c71e63edcb9c7e0a80 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 28 Oct 2015 17:26:46 +0100 Subject: [PATCH 03/25] Add extern crate regex --- src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.rs b/src/main.rs index 704e1c14..6471438a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ #[macro_use] extern crate clap; #[macro_use] extern crate log; extern crate config; +extern crate regex; use cli::CliConfig; use configuration::Configuration; From 1166f313a3983da032b77b9f2131c7309f48048b Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 28 Oct 2015 17:27:03 +0100 Subject: [PATCH 04/25] Add divide_text() function --- src/module/mod.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/module/mod.rs b/src/module/mod.rs index fd304137..4bcfaf21 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -57,6 +57,8 @@ pub trait Module { pub mod file { + use regex::Regex; + pub struct ParserError { summary: String, parsertext: String, @@ -127,4 +129,26 @@ pub mod file { fn write(&self, hdr: &header::FileHeaderData, data: &FileData) -> Result; } + pub type HeaderDataTpl = (Option, Option); + + pub fn divide_text(text: String) -> Result { + 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)) + } + } From 6fa42204cb12c9d497d20e244cbd8ba79224e344 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 28 Oct 2015 18:57:26 +0100 Subject: [PATCH 05/25] FileParser -> FileDataParser Let the FileParser be a FileDataParser, so we have uncoupled the header parsers from the data parsers. This way we can make the parsing process multithreaded. --- src/module/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/module/mod.rs b/src/module/mod.rs index 4bcfaf21..3da8f4d1 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -123,10 +123,10 @@ pub mod file { fn get_abbrev(&self) -> String; } - pub trait FileParser { - fn new(header_parser: &header::FileHeaderParser) -> FileParser; - fn read(&self, string: String) -> (header::FileHeaderData, FileData); - fn write(&self, hdr: &header::FileHeaderData, data: &FileData) -> Result; + pub trait FileDataParser { + fn new() -> FileDataParser; + fn read(&self, string: String) -> FileData; + fn write(&self, data: &FileData) -> Result; } pub type HeaderDataTpl = (Option, Option); From 647d5611c71fc0d6f3741ddc61967d637e485df0 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 28 Oct 2015 19:20:20 +0100 Subject: [PATCH 06/25] Out Traits here must implement the Sized trait --- src/module/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/module/mod.rs b/src/module/mod.rs index 3da8f4d1..f935997b 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -110,7 +110,7 @@ pub mod file { Array { values: Box> }, } - pub trait FileHeaderParser { + pub trait FileHeaderParser : Sized { fn new(spec: &FileHeaderSpec) -> Self; fn read(&self, string: &String) -> Result; fn write(&self, data: &FileHeaderData) -> Result; @@ -118,12 +118,12 @@ pub mod file { } - pub trait FileData { + pub trait FileData : Sized { fn get_fulltext(&self) -> String; fn get_abbrev(&self) -> String; } - pub trait FileDataParser { + pub trait FileDataParser : Sized { fn new() -> FileDataParser; fn read(&self, string: String) -> FileData; fn write(&self, data: &FileData) -> Result; From 380d58a3c0f6637dea015223c0a510de6e857130 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 28 Oct 2015 19:21:22 +0100 Subject: [PATCH 07/25] Move header types/traits outside own module --- src/module/mod.rs | 52 ++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/src/module/mod.rs b/src/module/mod.rs index f935997b..c0d8f110 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -86,36 +86,32 @@ pub mod file { } } - pub mod header { + pub enum FileHeaderSpec { + Null, + Bool, + Integer, + UInteger, + Float, + Text, + Key { name: String, value_type: Box }, + Array { allowed_types: Box> }, + } - pub enum FileHeaderSpec { - Null, - Bool, - Integer, - UInteger, - Float, - Text, - Key { name: String, value_type: Box }, - Array { allowed_types: Box> }, - } - - pub enum FileHeaderData { - Null, - Bool(bool), - Integer(i64), - UInteger(u64), - Float(f64), - Text(String), - Key { name: String, value: Box }, - Array { values: Box> }, - } - - pub trait FileHeaderParser : Sized { - fn new(spec: &FileHeaderSpec) -> Self; - fn read(&self, string: &String) -> Result; - fn write(&self, data: &FileHeaderData) -> Result; - } + pub enum FileHeaderData { + Null, + Bool(bool), + Integer(i64), + UInteger(u64), + Float(f64), + Text(String), + Key { name: String, value: Box }, + Array { values: Box> }, + } + pub trait FileHeaderParser : Sized { + fn new(spec: &FileHeaderSpec) -> Self; + fn read(&self, string: &String) -> Result; + fn write(&self, data: &FileHeaderData) -> Result; } pub trait FileData : Sized { From bbefacd0a2ec82765c5109c7fbce903585f566fe Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 28 Oct 2015 20:40:07 +0100 Subject: [PATCH 08/25] FileHeaderParser::read() should get the string, not a ref to it --- src/module/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/module/mod.rs b/src/module/mod.rs index c0d8f110..95dbd515 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -110,7 +110,7 @@ pub mod file { pub trait FileHeaderParser : Sized { fn new(spec: &FileHeaderSpec) -> Self; - fn read(&self, string: &String) -> Result; + fn read(&self, string: String) -> Result; fn write(&self, data: &FileHeaderData) -> Result; } From 1a4b3f9747e496ba1b750dbbc16ccf542ce188e6 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 28 Oct 2015 20:41:27 +0100 Subject: [PATCH 09/25] FileDataParser::read() should return Result<> --- src/module/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/module/mod.rs b/src/module/mod.rs index 95dbd515..93056718 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -121,7 +121,7 @@ pub mod file { pub trait FileDataParser : Sized { fn new() -> FileDataParser; - fn read(&self, string: String) -> FileData; + fn read(&self, string: String) -> Result; fn write(&self, data: &FileData) -> Result; } From 11c2fe12602947040f026f01bdc0c731ab561a0a Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 28 Oct 2015 21:28:34 +0100 Subject: [PATCH 10/25] Implement Abstract Parser which uses Header- and Data-Parser internally --- src/module/mod.rs | 58 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/src/module/mod.rs b/src/module/mod.rs index 93056718..58fe32bc 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -110,7 +110,7 @@ pub mod file { pub trait FileHeaderParser : Sized { fn new(spec: &FileHeaderSpec) -> Self; - fn read(&self, string: String) -> Result; + fn read(&self, string: Option) -> Result; fn write(&self, data: &FileHeaderData) -> Result; } @@ -119,15 +119,59 @@ pub mod file { fn get_abbrev(&self) -> String; } - pub trait FileDataParser : Sized { - fn new() -> FileDataParser; - fn read(&self, string: String) -> Result; - fn write(&self, data: &FileData) -> Result; + pub trait FileDataParser : Sized { + fn new() -> Self; + fn read(&self, string: Option) -> Result; + fn write(&self, data: &FD) -> Result; } - pub type HeaderDataTpl = (Option, Option); + type TextTpl = (Option, Option); - pub fn divide_text(text: String) -> Result { + pub struct Parser + { + headerp : HP, + datap : DP, + } + + impl Parser where + HP: FileHeaderParser, + { + + fn new(headerp: HP, datap: DP) -> Parser { + Parser { + headerp: headerp, + datap: datap, + } + } + + fn read(&self, s: String) -> Result<(FileHeaderData, FD), ParserError> + where FD: FileData + Sized, + DP: FileDataParser + { + 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 divide_text(text: &String) -> Result { let re = Regex::new(r"(?m)^\-\-\-$\n(.*)^\-\-\-$\n(.*)").unwrap(); let captures = re.captures(&text[..]).unwrap_or( From 50f140edef136887c4bedf3ac2757be1bcfc66ce Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 30 Oct 2015 01:05:44 +0100 Subject: [PATCH 11/25] Implement Parser.write() --- src/module/mod.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/module/mod.rs b/src/module/mod.rs index 58fe32bc..521e2f56 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -169,6 +169,25 @@ pub mod file { Ok((h_parseres.ok().unwrap(), d_parseres.ok().unwrap())) } + + fn write(&self, tpl : (FileHeaderData, FD)) -> Result + where FD: FileData + Sized, + DP: FileDataParser + { + 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 { From 52579a3e7c460a5d5f17e1265cfec98ecc9abae1 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 30 Oct 2015 14:31:26 +0100 Subject: [PATCH 12/25] Move: src/storage.rs -> src/storage/mod.rs --- src/{storage.rs => storage/mod.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{storage.rs => storage/mod.rs} (100%) diff --git a/src/storage.rs b/src/storage/mod.rs similarity index 100% rename from src/storage.rs rename to src/storage/mod.rs From 2989cb803dc3c4693478dce97705c0dc5e2163b4 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 30 Oct 2015 14:31:45 +0100 Subject: [PATCH 13/25] Move module/file to storage/file --- src/module/mod.rs | 157 -------------------------------------------- src/storage/file.rs | 152 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+), 157 deletions(-) create mode 100644 src/storage/file.rs diff --git a/src/module/mod.rs b/src/module/mod.rs index 521e2f56..9fd8b88a 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -54,160 +54,3 @@ pub trait Module { } - -pub mod file { - - use regex::Regex; - - pub struct ParserError { - summary: String, - parsertext: String, - index: i32, - explanation: Option, - } - - 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 { - Null, - Bool, - Integer, - UInteger, - Float, - Text, - Key { name: String, value_type: Box }, - Array { allowed_types: Box> }, - } - - pub enum FileHeaderData { - Null, - Bool(bool), - Integer(i64), - UInteger(u64), - Float(f64), - Text(String), - Key { name: String, value: Box }, - Array { values: Box> }, - } - - pub trait FileHeaderParser : Sized { - fn new(spec: &FileHeaderSpec) -> Self; - fn read(&self, string: Option) -> Result; - fn write(&self, data: &FileHeaderData) -> Result; - } - - pub trait FileData : Sized { - fn get_fulltext(&self) -> String; - fn get_abbrev(&self) -> String; - } - - pub trait FileDataParser : Sized { - fn new() -> Self; - fn read(&self, string: Option) -> Result; - fn write(&self, data: &FD) -> Result; - } - - type TextTpl = (Option, Option); - - pub struct Parser - { - headerp : HP, - datap : DP, - } - - impl Parser where - HP: FileHeaderParser, - { - - fn new(headerp: HP, datap: DP) -> Parser { - Parser { - headerp: headerp, - datap: datap, - } - } - - fn read(&self, s: String) -> Result<(FileHeaderData, FD), ParserError> - where FD: FileData + Sized, - DP: FileDataParser - { - 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(&self, tpl : (FileHeaderData, FD)) -> Result - where FD: FileData + Sized, - DP: FileDataParser - { - 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 { - 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)) - } - -} diff --git a/src/storage/file.rs b/src/storage/file.rs new file mode 100644 index 00000000..1766dbf2 --- /dev/null +++ b/src/storage/file.rs @@ -0,0 +1,152 @@ +use regex::Regex; + +pub struct ParserError { + summary: String, + parsertext: String, + index: i32, + explanation: Option, +} + +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 { + Null, + Bool, + Integer, + UInteger, + Float, + Text, + Key { name: String, value_type: Box }, + Array { allowed_types: Box> }, +} + +pub enum FileHeaderData { + Null, + Bool(bool), + Integer(i64), + UInteger(u64), + Float(f64), + Text(String), + Key { name: String, value: Box }, + Array { values: Box> }, +} + +pub trait FileHeaderParser : Sized { + fn new(spec: &FileHeaderSpec) -> Self; + fn read(&self, string: Option) -> Result; + fn write(&self, data: &FileHeaderData) -> Result; +} + +pub trait FileData : Sized { + fn get_fulltext(&self) -> String; + fn get_abbrev(&self) -> String; +} + +pub trait FileDataParser : Sized { + fn new() -> Self; + fn read(&self, string: Option) -> Result; + fn write(&self, data: &FD) -> Result; +} + +type TextTpl = (Option, Option); + +pub struct Parser +{ + headerp : HP, + datap : DP, +} + +impl Parser where + HP: FileHeaderParser, +{ + + fn new(headerp: HP, datap: DP) -> Parser { + Parser { + headerp: headerp, + datap: datap, + } + } + + fn read(&self, s: String) -> Result<(FileHeaderData, FD), ParserError> + where FD: FileData + Sized, + DP: FileDataParser + { + 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(&self, tpl : (FileHeaderData, FD)) -> Result + where FD: FileData + Sized, + DP: FileDataParser + { + 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 { + 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)) +} From 4b8d7b0c4fad0e73647ef4caac870e8220334f24 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 30 Oct 2015 14:32:22 +0100 Subject: [PATCH 14/25] Add module file --- src/storage/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/storage/mod.rs b/src/storage/mod.rs index 42f88ae4..28267aad 100644 --- a/src/storage/mod.rs +++ b/src/storage/mod.rs @@ -4,6 +4,8 @@ pub use std::error::Error; pub use runtime::Runtime; +mod file; + pub trait StorageBackend { fn name(&self) -> String; From 589844102da75293b840fb184912a1c7e8d9d20a Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 30 Oct 2015 14:44:41 +0100 Subject: [PATCH 15/25] Move parser code out of file.rs --- src/storage/file.rs | 125 ----------------------------------------- src/storage/mod.rs | 1 + src/storage/parser.rs | 128 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 125 deletions(-) create mode 100644 src/storage/parser.rs diff --git a/src/storage/file.rs b/src/storage/file.rs index 1766dbf2..3007f6d3 100644 --- a/src/storage/file.rs +++ b/src/storage/file.rs @@ -1,32 +1,3 @@ -use regex::Regex; - -pub struct ParserError { - summary: String, - parsertext: String, - index: i32, - explanation: Option, -} - -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 { Null, Bool, @@ -49,104 +20,8 @@ pub enum FileHeaderData { Array { values: Box> }, } -pub trait FileHeaderParser : Sized { - fn new(spec: &FileHeaderSpec) -> Self; - fn read(&self, string: Option) -> Result; - fn write(&self, data: &FileHeaderData) -> Result; -} - pub trait FileData : Sized { fn get_fulltext(&self) -> String; fn get_abbrev(&self) -> String; } -pub trait FileDataParser : Sized { - fn new() -> Self; - fn read(&self, string: Option) -> Result; - fn write(&self, data: &FD) -> Result; -} - -type TextTpl = (Option, Option); - -pub struct Parser -{ - headerp : HP, - datap : DP, -} - -impl Parser where - HP: FileHeaderParser, -{ - - fn new(headerp: HP, datap: DP) -> Parser { - Parser { - headerp: headerp, - datap: datap, - } - } - - fn read(&self, s: String) -> Result<(FileHeaderData, FD), ParserError> - where FD: FileData + Sized, - DP: FileDataParser - { - 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(&self, tpl : (FileHeaderData, FD)) -> Result - where FD: FileData + Sized, - DP: FileDataParser - { - 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 { - 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)) -} diff --git a/src/storage/mod.rs b/src/storage/mod.rs index 28267aad..403c8369 100644 --- a/src/storage/mod.rs +++ b/src/storage/mod.rs @@ -5,6 +5,7 @@ pub use std::error::Error; pub use runtime::Runtime; mod file; +mod parser; pub trait StorageBackend { diff --git a/src/storage/parser.rs b/src/storage/parser.rs new file mode 100644 index 00000000..4a345636 --- /dev/null +++ b/src/storage/parser.rs @@ -0,0 +1,128 @@ +use regex::Regex; + +use super::file::*; + +pub struct ParserError { + summary: String, + parsertext: String, + index: i32, + explanation: Option, +} + +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) -> Result; + fn write(&self, data: &FileHeaderData) -> Result; +} + +pub trait FileDataParser : Sized { + fn new() -> Self; + fn read(&self, string: Option) -> Result; + fn write(&self, data: &FD) -> Result; +} + +type TextTpl = (Option, Option); + +pub struct Parser +{ + headerp : HP, + datap : DP, +} + +impl Parser where + HP: FileHeaderParser, +{ + + fn new(headerp: HP, datap: DP) -> Parser { + Parser { + headerp: headerp, + datap: datap, + } + } + + fn read(&self, s: String) -> Result<(FileHeaderData, FD), ParserError> + where FD: FileData + Sized, + DP: FileDataParser + { + 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(&self, tpl : (FileHeaderData, FD)) -> Result + where FD: FileData + Sized, + DP: FileDataParser + { + 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 { + 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)) +} + From e426f384f45f6d86b9e19b5fff87cfd7731e9ac5 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 30 Oct 2015 14:47:21 +0100 Subject: [PATCH 16/25] Remove old code --- src/storage/mod.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/storage/mod.rs b/src/storage/mod.rs index 403c8369..629a07bc 100644 --- a/src/storage/mod.rs +++ b/src/storage/mod.rs @@ -7,13 +7,3 @@ pub use runtime::Runtime; mod file; mod parser; -pub trait StorageBackend { - - fn name(&self) -> String; - - fn create(&self, file : File) -> Option; - fn read(&self, path: Path) -> Result; - fn update(&self, file : File) -> Option; - fn destroy(&self, path: Path) -> Option; - -} From b6d52b2616ab0a512524ad885751b129d8ad82a2 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 30 Oct 2015 15:22:11 +0100 Subject: [PATCH 17/25] Implement: Error, Debug, Display for ParserError --- src/storage/parser.rs | 45 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/storage/parser.rs b/src/storage/parser.rs index 4a345636..c4f009c6 100644 --- a/src/storage/parser.rs +++ b/src/storage/parser.rs @@ -1,4 +1,7 @@ use regex::Regex; +use std::error::Error; +use std::fmt::{Debug, Display, Formatter}; +use std::fmt; use super::file::*; @@ -29,6 +32,48 @@ impl ParserError { } } +impl Error for ParserError { + + fn description(&self) -> &str { + &self.summary[..] + } + + fn cause(&self) -> Option<&Error> { + None + } + +} + +impl Debug for ParserError { + + fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + write!(fmt, "ParserError: {}\n\n", self.summary); + + if let Some(ref e) = self.explanation { + write!(fmt, "{}\n\n", e); + } + + write!(fmt, "On position {}\nin\n{}", self.index, self.parsertext); + Ok(()) + } + +} + +impl Display for ParserError { + + fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + write!(fmt, "ParserError: {}", self.summary); + + if let Some(ref e) = self.explanation { + write!(fmt, "\n\n{}", e); + } + + Ok(()) + } + +} + + pub trait FileHeaderParser : Sized { fn new(spec: &FileHeaderSpec) -> Self; fn read(&self, string: Option) -> Result; From d54825de6bc907d0dddb2176382c6ec3375eb3a9 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 30 Oct 2015 15:23:29 +0100 Subject: [PATCH 18/25] Move divide_text() into scope of impl Parser --- src/storage/parser.rs | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/storage/parser.rs b/src/storage/parser.rs index c4f009c6..4d278d5f 100644 --- a/src/storage/parser.rs +++ b/src/storage/parser.rs @@ -109,7 +109,7 @@ impl Parser where where FD: FileData + Sized, DP: FileDataParser { - let divided = divide_text(&s); + let divided = self.divide_text(&s); if divided.is_err() { return Err(divided.err().unwrap()); @@ -149,25 +149,26 @@ impl Parser where Ok(h_text.ok().unwrap() + &d_text.ok().unwrap()[..]) } -} -fn divide_text(text: &String) -> Result { - let re = Regex::new(r"(?m)^\-\-\-$\n(.*)^\-\-\-$\n(.*)").unwrap(); + fn divide_text(&self, text: &String) -> Result { + 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.")) - ); + 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.")) + 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)) } - let header = captures.at(0).map(|s| String::from(s)); - let content = captures.at(1).map(|s| String::from(s)); - Ok((header, content)) } From e6fb2f232d62e36ee9f94e73fdc60d41eb6a5f9d Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 30 Oct 2015 16:47:04 +0100 Subject: [PATCH 19/25] FileHeaderSpec, FileHeaderData can derive Debug --- src/storage/file.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/storage/file.rs b/src/storage/file.rs index 3007f6d3..b58486cc 100644 --- a/src/storage/file.rs +++ b/src/storage/file.rs @@ -1,3 +1,4 @@ +#[derive(Debug)] pub enum FileHeaderSpec { Null, Bool, @@ -9,6 +10,7 @@ pub enum FileHeaderSpec { Array { allowed_types: Box> }, } +#[derive(Debug)] pub enum FileHeaderData { Null, Bool(bool), From 96ca9637d1e2d2be3f98baa2751494767ccdb070 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 30 Oct 2015 16:48:48 +0100 Subject: [PATCH 20/25] Add type MatchError --- src/storage/file.rs | 48 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/storage/file.rs b/src/storage/file.rs index b58486cc..72d7a83a 100644 --- a/src/storage/file.rs +++ b/src/storage/file.rs @@ -1,3 +1,7 @@ +use std::error::Error; +use std::fmt::{Debug, Display, Formatter}; +use std::fmt; + #[derive(Debug)] pub enum FileHeaderSpec { Null, @@ -27,3 +31,47 @@ pub trait FileData : Sized { fn get_abbrev(&self) -> String; } +pub struct MatchError { + summary: String, + path: Vec, + expected: FileHeaderSpec, + found: FileHeaderSpec +} + +impl MatchError { + pub fn format(&self) -> String { + format!("MatchError: {:?}\n\nHaving: {:?}\nExpected: {:?}\nFound: {:?}\n", + self.summary, self.path, self.expected, self.found) + } +} + +impl Error for MatchError { + + fn description(&self) -> &str { + &self.summary[..] + } + + fn cause(&self) -> Option<&Error> { + None + } + +} + +impl Debug for MatchError { + + fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + write!(fmt, "{}", self.format()); + Ok(()) + } + +} + +impl Display for MatchError { + + fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + write!(fmt, "{}", self.format()); + Ok(()) + } + +} + From f9cc0e41ce691e110bc25fc0ee9b188296260b63 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 30 Oct 2015 16:50:02 +0100 Subject: [PATCH 21/25] Implement Display for FileHeaderSpec --- src/storage/file.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/storage/file.rs b/src/storage/file.rs index 72d7a83a..bc1c57c9 100644 --- a/src/storage/file.rs +++ b/src/storage/file.rs @@ -31,6 +31,27 @@ pub trait FileData : Sized { fn get_abbrev(&self) -> String; } +impl Display for FileHeaderSpec { + + fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + match self { + &FileHeaderSpec::Null => write!(fmt, "NULL"), + &FileHeaderSpec::Bool => write!(fmt, "Bool"), + &FileHeaderSpec::Integer => write!(fmt, "Integer"), + &FileHeaderSpec::UInteger => write!(fmt, "UInteger"), + &FileHeaderSpec::Float => write!(fmt, "Float"), + &FileHeaderSpec::Text => write!(fmt, "Text"), + &FileHeaderSpec::Key{name: ref n, value_type: ref vt} => { + write!(fmt, "Key({:?}) -> {:?}", n, vt) + } + &FileHeaderSpec::Array{allowed_types: ref at} => { + write!(fmt, "Array({:?})", at) + } + } + } + +} + pub struct MatchError { summary: String, path: Vec, From caee02c33300bbb5bedf560d37ff99fdd0276cfb Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 30 Oct 2015 16:50:43 +0100 Subject: [PATCH 22/25] Add algorithm to match spec on data --- src/storage/file.rs | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/storage/file.rs b/src/storage/file.rs index bc1c57c9..302105c0 100644 --- a/src/storage/file.rs +++ b/src/storage/file.rs @@ -96,3 +96,42 @@ impl Display for MatchError { } +pub fn match_header_spec(spec: &FileHeaderSpec, data: &FileHeaderData) + -> Option +{ + let tpl = (spec, data); + match tpl { + (&FileHeaderSpec::Null, &FileHeaderData::Null) => { } + (&FileHeaderSpec::Bool, &FileHeaderData::Bool(_)) => { } + (&FileHeaderSpec::Integer, &FileHeaderData::Integer(_)) => { } + (&FileHeaderSpec::UInteger, &FileHeaderData::UInteger(_)) => { } + (&FileHeaderSpec::Float, &FileHeaderData::Float(_)) => { } + (&FileHeaderSpec::Text, &FileHeaderData::Text(_)) => { } + + ( + &FileHeaderSpec::Key{name: ref kname, value_type: ref vtype}, + &FileHeaderData::Key{name: ref n, value: ref val} + ) => { + if kname != n { + // error + } + return match_header_spec(&*vtype, &*val); + } + + ( + &FileHeaderSpec::Array{allowed_types: ref vtypes}, + &FileHeaderData::Array{values: ref vs} + ) => { + for (t, v) in vtypes.iter().zip(vs.iter()) { + let res = match_header_spec(t, v); + if res.is_some() { + return res; + } + } + } + + _ => { unreachable!() } + } + None +} + From 10697feb8aba9e5af0821ea397939ee713acde23 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 30 Oct 2015 17:35:18 +0100 Subject: [PATCH 23/25] Add error generating Which required adding of lifetimes --- src/storage/file.rs | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/src/storage/file.rs b/src/storage/file.rs index 302105c0..f37081b8 100644 --- a/src/storage/file.rs +++ b/src/storage/file.rs @@ -52,21 +52,34 @@ impl Display for FileHeaderSpec { } -pub struct MatchError { +pub struct MatchError<'a> { summary: String, path: Vec, - expected: FileHeaderSpec, - found: FileHeaderSpec + expected: &'a FileHeaderSpec, + found: &'a FileHeaderData } -impl MatchError { +impl<'a> MatchError<'a> { + + pub fn new(s: String, + path: Vec, + ex: &'a FileHeaderSpec, + found: &'a FileHeaderData) -> MatchError<'a> { + MatchError { + summary: s, + path: path, + expected: ex, + found: found, + } + } + pub fn format(&self) -> String { format!("MatchError: {:?}\n\nHaving: {:?}\nExpected: {:?}\nFound: {:?}\n", self.summary, self.path, self.expected, self.found) } } -impl Error for MatchError { +impl<'a> Error for MatchError<'a> { fn description(&self) -> &str { &self.summary[..] @@ -78,7 +91,7 @@ impl Error for MatchError { } -impl Debug for MatchError { +impl<'a> Debug for MatchError<'a> { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { write!(fmt, "{}", self.format()); @@ -87,7 +100,7 @@ impl Debug for MatchError { } -impl Display for MatchError { +impl<'a> Display for MatchError<'a> { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { write!(fmt, "{}", self.format()); @@ -96,11 +109,10 @@ impl Display for MatchError { } -pub fn match_header_spec(spec: &FileHeaderSpec, data: &FileHeaderData) - -> Option +pub fn match_header_spec<'a>(spec: &'a FileHeaderSpec, data: &'a FileHeaderData) + -> Option> { - let tpl = (spec, data); - match tpl { + match (spec, data) { (&FileHeaderSpec::Null, &FileHeaderData::Null) => { } (&FileHeaderSpec::Bool, &FileHeaderData::Bool(_)) => { } (&FileHeaderSpec::Integer, &FileHeaderData::Integer(_)) => { } @@ -130,7 +142,12 @@ pub fn match_header_spec(spec: &FileHeaderSpec, data: &FileHeaderData) } } - _ => { unreachable!() } + (k, v) => { + return Some(MatchError::new(String::from("Expected type does not match found type"), + vec![], + k, v + )) + } } None } From 9dde3e4f72b9ef3371a5997802fbb9180652b04f Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 30 Oct 2015 17:46:25 +0100 Subject: [PATCH 24/25] Remove path member from MatchError At this point, this is too complicated to implement for me. --- src/storage/file.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/storage/file.rs b/src/storage/file.rs index f37081b8..0d0df446 100644 --- a/src/storage/file.rs +++ b/src/storage/file.rs @@ -54,7 +54,6 @@ impl Display for FileHeaderSpec { pub struct MatchError<'a> { summary: String, - path: Vec, expected: &'a FileHeaderSpec, found: &'a FileHeaderData } @@ -62,20 +61,18 @@ pub struct MatchError<'a> { impl<'a> MatchError<'a> { pub fn new(s: String, - path: Vec, ex: &'a FileHeaderSpec, found: &'a FileHeaderData) -> MatchError<'a> { MatchError { summary: s, - path: path, expected: ex, found: found, } } pub fn format(&self) -> String { - format!("MatchError: {:?}\n\nHaving: {:?}\nExpected: {:?}\nFound: {:?}\n", - self.summary, self.path, self.expected, self.found) + format!("MatchError: {:?}\nExpected: {:?}\nFound: {:?}\n", + self.summary, self.expected, self.found) } } @@ -144,7 +141,6 @@ pub fn match_header_spec<'a>(spec: &'a FileHeaderSpec, data: &'a FileHeaderData) (k, v) => { return Some(MatchError::new(String::from("Expected type does not match found type"), - vec![], k, v )) } From 1c2c52fa37fc9fe79b9fe6ee60a0f6efe31cc9c5 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 30 Oct 2015 18:09:01 +0100 Subject: [PATCH 25/25] Add "Map" type to FileHeaderSpec and FileHeaderData --- src/storage/file.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/storage/file.rs b/src/storage/file.rs index 0d0df446..bfa147af 100644 --- a/src/storage/file.rs +++ b/src/storage/file.rs @@ -11,6 +11,7 @@ pub enum FileHeaderSpec { Float, Text, Key { name: String, value_type: Box }, + Map { keys: Vec }, Array { allowed_types: Box> }, } @@ -23,6 +24,7 @@ pub enum FileHeaderData { Float(f64), Text(String), Key { name: String, value: Box }, + Map { keys: Vec }, Array { values: Box> }, } @@ -44,6 +46,9 @@ impl Display for FileHeaderSpec { &FileHeaderSpec::Key{name: ref n, value_type: ref vt} => { write!(fmt, "Key({:?}) -> {:?}", n, vt) } + &FileHeaderSpec::Map{keys: ref ks} => { + write!(fmt, "Map -> {:?}", ks) + } &FileHeaderSpec::Array{allowed_types: ref at} => { write!(fmt, "Array({:?})", at) } @@ -127,6 +132,18 @@ pub fn match_header_spec<'a>(spec: &'a FileHeaderSpec, data: &'a FileHeaderData) return match_header_spec(&*vtype, &*val); } + ( + &FileHeaderSpec::Map{keys: ref sks}, + &FileHeaderData::Map{keys: ref dks} + ) => { + for (s, d) in sks.iter().zip(dks.iter()) { + let res = match_header_spec(s, d); + if res.is_some() { + return res; + } + } + } + ( &FileHeaderSpec::Array{allowed_types: ref vtypes}, &FileHeaderData::Array{values: ref vs}