Skip to content

Instantly share code, notes, and snippets.

Created July 13, 2015 19:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/862e0f810673d396e516 to your computer and use it in GitHub Desktop.
Save anonymous/862e0f810673d396e516 to your computer and use it in GitHub Desktop.
Shared via Rust Playground
// from https://github.com/mcast/markdown-chapterise/commit/5b48c728
use std::cell::RefCell;
use std::iter::Peekable;
use std::ops::DerefMut;
use std::iter::FilterMap;
use std::io::Lines;
use std::io::BufReader;
use std::fs::File;
use std::io::Result;
pub struct MarkdownStream<T: Iterator<Item=String>> {
input: Box<Peekable<Box<T>>>,
}
fn io_unwrap(result: Result<String>) -> Option<String> {
result.ok()
}
impl<T: Iterator<Item=String>> MarkdownStream<T> {
// pub fn new_io<IoT: Iterator<Item=Result<String>>>(lines: Box<IoT>) -> MarkdownStream<T>
pub fn new_io(lines: Box<Iterator<Item=Result<String>>>) -> MarkdownStream<T>
{
let lines: Box<Iterator<Item=String>> =
Box::new(lines.filter_map(io_unwrap));
MarkdownStream { input: Box::new(lines.peekable()) }
// three boxes, hmm
}
pub fn new(lines: Box<T>) -> MarkdownStream<T>
{
let lines = lines.peekable();
MarkdownStream { input: Box::new(lines) }
}
}
// iterator howto - thanks http://rustbyexample.com/trait/iter.html
impl<T: Iterator<Item=String>> Iterator for MarkdownStream<T> {
type Item = MarkdownEle;
fn next(&mut self) -> Option<MarkdownEle> {
let mut lines = self.input.deref_mut();
let line = match lines.next() {
None => return None,
Some(x) => x,
};
let next = lines.peek();
Some(MarkdownEle::new(line, next))
}
}
#[cfg(test)]
mod tests {
use super::MarkdownStream;
use super::MarkdownEle;
use std::slice::Iter;
fn stringvec(input: Vec<&str>) -> (Vec<String>, Iter<String>) {
let v_cp = input.clone();
let out: Vec<String> = input
.into_iter()
.map(|s| String::from_str(s) + "\n")
.collect::<Vec<String>>();
(v_cp, out)
}
#[test]
fn t_vec_others() {
let (v, i) = stringvec(vec!("Hello", "world"));
let m = MarkdownStream::new(i);
assert_eq!(m.next(), Some(MarkdownEle::Other { txt: v[0] }));
}
}
#[derive(Debug, PartialEq)]
pub enum MarkdownEle {
Head { txt: String, n: u32 },
Other { txt: String },
}
impl MarkdownEle {
pub fn new(line: String, next: Option<&String>) -> MarkdownEle {
let mut hdr_level = 0;
for ch in line.chars() {
match ch {
'#' => hdr_level += 1,
' ' => break,
_ => {
hdr_level = 0;
break
},
}
}
// setext (underlined) header detection XXX: a bit fast'n'loose
match next {
Some(t) => {
let mut num_minus = 0;
let mut num_equ = 0;
for ch in t.chars() {
match ch {
'-' => num_minus += 1,
'=' => num_equ += 1,
_ => {
num_minus = 0;
num_equ = 0;
break
},
}
}
match (hdr_level, num_equ, num_minus) {
// setext levels
(0, 0, 0) => (),
(0, _n, 0) => hdr_level = 1,
(0, 0, _n) => hdr_level = 2,
_ => (),
}
},
None => (),
};
match hdr_level {
0 => MarkdownEle::Other { txt: line },
n => MarkdownEle::Head { txt: line, n: n },
}
}
}
#[test]
fn headcheck() {
let h = "#### foo";
let h = h.to_string();
let junk = "wibble".to_string();
let out1 = MarkdownEle::new(h.clone(), None);
let out2 = MarkdownEle::new(h.clone(), Some(&junk));
let want = MarkdownEle::Head { txt: h, n: 4 };
assert_eq!(out1, want);
assert_eq!(out2, want);
}
#[test]
fn othercheck() {
let ht = " hello world".to_owned();
let h1 = "==".to_owned();
let h2 = "--".to_owned();
assert_eq!(MarkdownEle::new(ht.clone(), None),
MarkdownEle::Other { txt: ht.clone() });
assert_eq!(MarkdownEle::new(ht.clone(), Some(&h1)),
MarkdownEle::Head { txt: ht.clone(), n: 1 });
assert_eq!(MarkdownEle::new(ht.clone(), Some(&h2)),
MarkdownEle::Head { txt: ht.clone(), n: 2 });
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment