use std::fmt::{Debug, Display, Formatter};
use std::fs::File;
use std::io::{BufRead, BufReader, Lines};
#[derive(Debug, Clone)]
pub struct SnippetError<'a> {
message: &'a str
}
impl<'a> Display for SnippetError<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.message)
}
}
impl<'a> std::error::Error for SnippetError<'a> {}
#[derive(Debug)]
pub struct SnippetParser<'a> {
path: Option<&'a str>,
iter_reader: Option<Lines<BufReader<File>>>,
snippets: Option<Vec<Snippet>>,
snippet_index: usize
}
impl<'a> SnippetParser<'a> {
pub fn new() -> Self {
Self { path: None, iter_reader: None, snippets: None, snippet_index: 0 }
}
pub fn read(path: &'a str) -> std::io::Result<Self> {
let file = File::open(path);
if file.is_err() {
return Err(file.err().unwrap());
}
let reader = BufReader::new(file.unwrap());
Ok(Self { path: Some(path), iter_reader: Some(reader.lines()), snippets: None, snippet_index: 0 })
}
pub fn from_snippets(snips: Vec<Snippet>) -> Self {
Self { path: None, iter_reader: None, snippets: Some(snips), snippet_index: 0 }
}
}
impl<'a> SnippetParser<'a> {
pub fn add_snippet(&mut self, snip: Snippet) {
if let Some(snippets) = &mut self.snippets {
snippets.push(snip);
} else {
self.snippets = Some(vec![snip]);
}
}
pub fn get_snippets(&self) -> std::io::Result<Vec<Snippet>> {
return if self.path.is_some() {
let file = File::open(self.path.unwrap());
if file.is_err() {
return Err(file.err().unwrap());
}
let reader = BufReader::new(file.unwrap());
let copy_of_self = Self {
path: Some(self.path.unwrap()),
iter_reader: Some(reader.lines()),
snippets: self.snippets.clone(),
snippet_index: 0
};
let file_snippets: Vec<Snippet> = copy_of_self.into_iter().map(|snippet| snippet.clone()).collect();
Ok(file_snippets)
} else {
if let Some(snippets) = &self.snippets {
Ok(snippets.clone())
} else {
Ok(Vec::new())
}
}
}
pub fn get_snippet(&self, title: &str) -> std::io::Result<Option<Snippet>> {
let snippets = self.get_snippets();
if let Ok(snippets) = snippets {
let found_snippet: Option<&Snippet> = snippets.iter().find_map(|snippet| {
if &snippet.title == title {
Some(snippet)
} else {
None
}
});
return if let Some(found_snippet) = found_snippet {
Ok(Some(found_snippet.clone()))
} else {
Ok(None)
}
} else {
Err(snippets.err().unwrap())
}
}
}
impl Iterator for SnippetParser<'_> {
type Item = Snippet;
fn next(&mut self) -> Option<Self::Item> {
if self.iter_reader.is_some() {
return if let Some(snippet) = &self.read_next_snippet() {
Some(snippet.clone())
} else {
self.read_next_from_snippets()
}
} else {
self.read_next_from_snippets()
}
}
}
#[cfg(test)]
#[test]
fn read_next_snippet_test() {
let mut parser = SnippetParser::read("./tests/snippets/snippet_test.snip").unwrap();
let first_snip = "\
Are we human?
Or are we dancer?\
";
let second_snip = "\
This is my church.
This is where I heal my hurts.";
let third_snip = "\
Never gonna give you up
Never gonna let you down
Never gonna run around and desert you
Never gonna make you cry
Never gonna say goodbye
Never gonna tell a lie and hurt you
\
";
let first_read_snip = parser.read_next_snippet().unwrap();
let second_read_snip = parser.read_next_snippet().unwrap();
let third_read_snip = parser.read_next_snippet().unwrap();
assert_eq!(first_snip, first_read_snip.s);
assert_eq!(second_snip, second_read_snip.s);
assert_eq!(third_snip, third_read_snip.s);
assert_eq!("snippet1", first_read_snip.title);
assert_eq!("snippet2", second_read_snip.title);
assert_eq!("snippet3 with space", third_read_snip.title);
assert_eq!(None, parser.read_next_snippet());
}
#[cfg(test)]
#[test]
fn read_next_snippet_test_with_adding_snippet() {
let mut parser = SnippetParser::read("./tests/snippets/snippet_test.snip").unwrap();
let first_snip = "\
Are we human?
Or are we dancer?\
";
let second_snip = "\
This is my church.
This is where I heal my hurts.";
let third_snip = "\
Never gonna give you up
Never gonna let you down
Never gonna run around and desert you
Never gonna make you cry
Never gonna say goodbye
Never gonna tell a lie and hurt you
\
";
let fourth_snip = "\
Are you on the square?
Are you on the hammer?
Are you ready to stand right here right now
Before the devil?
\
";
let fourth_snippet = Snippet::new("Square Hammer".to_string(), fourth_snip.to_string());
parser.add_snippet(fourth_snippet);
println!("{:?}", parser);
let first_read_snip = parser.read_next_snippet().unwrap();
let second_read_snip = parser.read_next_snippet().unwrap();
let third_read_snip = parser.read_next_snippet().unwrap();
let fourth_read_snip = parser.read_next_snippet();
assert_eq!(first_snip, first_read_snip.s);
assert_eq!(second_snip, second_read_snip.s);
assert_eq!(third_snip, third_read_snip.s);
assert_eq!("snippet1", first_read_snip.title);
assert_eq!("snippet2", second_read_snip.title);
assert_eq!("snippet3 with space", third_read_snip.title);
assert_eq!(None, fourth_read_snip);
assert_eq!(None, parser.read_next_snippet());
}
impl<'a> SnippetParser<'a> {
fn read_next_snippet(&mut self) -> Option<Snippet> {
let mut title: String = String::new();
let mut started = false;
let mut lines: Vec<String> = Vec::new();
loop {
if let Some(_lines) = &mut self.iter_reader {
let line = _lines.next();
if let Some(line) = line {
if line.is_err() {
return None;
}
if started == false {
if line.as_ref().unwrap().contains("--") {
let _title = line.unwrap().replace("--", "");
title = _title.trim().to_string();
started = true;
}
} else {
if line.as_ref().unwrap().contains("-- end --") {
break; } else {
lines.push(line.unwrap());
}
}
} else {
return None;
}
} else {
return None;
}
}
let len_of_lines = lines.len();
let s: String = lines
.into_iter()
.enumerate()
.flat_map(|(index, line)| {
let mut line = line;
if index != len_of_lines - 1 {
line.push_str("\n");
}
line.chars().collect::<Vec<char>>()
}).collect();
Some(Snippet::new(title, s))
}
fn read_next_from_snippets(&mut self) -> Option<Snippet> {
if let Some(snippets) = &self.snippets {
let snippet = snippets.get(self.snippet_index);
self.snippet_index += 1;
if let Some(snippet) = snippet {
Some(snippet.clone())
} else {
None
}
} else {
None
}
}
}
impl ToString for SnippetParser<'_> {
fn to_string(&self) -> String {
let mut s = String::new();
for snip in self.get_snippets().unwrap() {
s.push_str(snip.to_string().as_str());
s.push_str("\n");
}
s
}
}
#[derive(Clone, PartialEq, Debug)]
pub struct Snippet {
title: String,
s: String
}
impl ToString for Snippet {
fn to_string(&self) -> String {
String::from(
format!("-- {} --\n{}\n-- end --", self.title, self.s)
)
}
}
impl Snippet {
pub fn new(title: String, s: String) -> Snippet {
Snippet { title, s }
}
pub fn append(&mut self, s: &str) {
self.s += s;
}
pub fn get_string(&self) -> &str {
&self.s
}
}