use std::default::Default;
use std::str::Chars;
use std::iter::Peekable;
use std::fmt::Formatter;
use self::FormatText::{Method, URI, Status, ResponseTime, RemoteAddr, RequestTime};
#[derive(Clone)]
pub struct Format(Vec<FormatText>);
impl Default for Format {
fn default() -> Format {
Format::new("{method} {uri} {status} ({response-time})").unwrap()
}
}
impl Format {
pub fn new(s: &str) -> Option<Format> {
let parser = FormatParser::new(s.chars().peekable());
let mut results = Vec::new();
for unit in parser {
match unit {
Some(unit) => results.push(unit),
None => return None
}
}
Some(Format(results))
}
}
pub trait ContextDisplay<'a> {
type Item;
type Display: fmt::Display;
fn display_with(&'a self,
render: &'a Fn(&mut Formatter, &Self::Item) -> Result<(), fmt::Error>)
-> Self::Display;
}
impl<'a> ContextDisplay<'a> for Format {
type Item = FormatText;
type Display = FormatDisplay<'a>;
fn display_with(&'a self,
render: &'a Fn(&mut Formatter, &FormatText) -> Result<(), fmt::Error>)
-> FormatDisplay<'a> {
FormatDisplay {
format: self,
render: render,
}
}
}
struct FormatParser<'a> {
chars: Peekable<Chars<'a>>,
object_buffer: String,
finished: bool
}
impl<'a> FormatParser<'a> {
fn new(chars: Peekable<Chars>) -> FormatParser {
FormatParser {
chars: chars,
object_buffer: String::with_capacity(14),
finished: false
}
}
}
impl<'a> Iterator for FormatParser<'a> {
type Item = Option<FormatText>;
fn next(&mut self) -> Option<Option<FormatText>> {
if self.finished { return None }
match self.chars.next() {
Some('{') => {
self.object_buffer.clear();
let mut chr = self.chars.next();
while chr != None {
match chr.unwrap() {
'}' => break,
c => self.object_buffer.push(c.clone())
}
chr = self.chars.next();
}
let text = match self.object_buffer.as_ref() {
"method" => Method,
"uri" => URI,
"status" => Status,
"response-time" => ResponseTime,
"request-time" => RequestTime,
"ip-addr" => RemoteAddr,
_ => {
self.finished = true;
return Some(None);
}
};
Some(Some(text))
}
Some(c) => {
let mut buffer = String::new();
buffer.push(c);
loop {
match self.chars.peek() {
Some(&'{') | None => return Some(Some(FormatText::Str(buffer))),
Some(_) => {
buffer.push(self.chars.next().unwrap())
}
}
}
},
None => None
}
}
}
#[derive(Clone)]
#[doc(hidden)]
pub enum FormatText {
Str(String),
Method,
URI,
Status,
ResponseTime,
RemoteAddr,
RequestTime
}
pub struct FormatDisplay<'a> {
format: &'a Format,
render: &'a Fn(&mut Formatter, &FormatText) -> Result<(), fmt::Error>,
}
use std::fmt;
impl<'a> fmt::Display for FormatDisplay<'a> {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
let Format(ref format) = *self.format;
for unit in format {
(self.render)(fmt, unit)?;
}
Ok(())
}
}