Skip to content

Commit

Permalink
(refactor) Preliminary cleanup and comments.
Browse files Browse the repository at this point in the history
  • Loading branch information
reem committed Oct 30, 2014
1 parent a8e7844 commit 3ba99ad
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 110 deletions.
11 changes: 1 addition & 10 deletions .gitignore
@@ -1,4 +1,3 @@
deps/
.DS_Store
*~
*#
Expand All @@ -12,13 +11,5 @@ deps/
*.dummy
*.exe
*-test
/bin/main
/bin/test-internal
/bin/test-external
/doc/
/target/
/build/
/.rust/
rusti.sh
/examples/*
!/examples/*.rs
Cargo.lock
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -51,3 +51,4 @@ One of us ([@reem](https://github.com/reem/), [@zzmp](https://github.com/zzmp/),
[@theptrk](https://github.com/theptrk/), [@mcreinhard](https://github.com/mcreinhard))
is usually on `#iron` on the mozilla irc. Come say hi and ask any questions you might have.
We are also usually on `#rust` and `#rust-webdev`.

226 changes: 127 additions & 99 deletions src/format.rs
Expand Up @@ -2,22 +2,26 @@ use iron::{Request, Response};
use term::{attr, color};
use http::status::NotFound;

use std::default::Default;
use std::from_str::FromStr;

/// A formatting style for the `Logger`, consisting of multiple
/// `FormatUnit`s concatenated into one line.
#[deriving(Clone)]
pub struct Format(pub Vec<FormatUnit>);

impl Format {
impl Default for Format {
/// Return the default formatting style for the `Logger`:
///
/// ```ignore
/// {method} {uri} -> {status} ({response_time})
/// ```
///
/// The method is in bold, and the response status is colored blue for 100s,
/// green for 200s, yellow for 300s, and red for 400s and 500s. For now,
/// this needs to take `req`/`res` as arguments in order to color the status
/// appropriately.
pub fn default() -> Format {
fn default() -> Format {
fn status_color(_req: &Request, res: &Response) -> Option<color::Color> {
match res.status.as_ref().unwrap_or(&NotFound).code() / 100 {
1 => Some(color::BLUE), // Information
Expand All @@ -27,133 +31,178 @@ impl Format {
_ => None
}
}
Format::from_format_string("@[bold]{method}@@ {uri} @[bold]->@@ @[C]{status}@@ ({response_time})",
&mut vec![FunctionColor(status_color)], &mut vec![]).unwrap()

Format::new("@[bold]{method}@@ {uri} @[bold]->@@ @[C]{status}@@ ({response_time})",
vec![FunctionColor(status_color)], vec![]).unwrap()
}
}

impl Format {
/// Create a `Format` from a format string, which can contain the fields
/// `{method}`, `{uri}`, `{status}`, and `{response_time}`.
/// Returns `None` if the format string syntax is incorrect.
pub fn from_format_string(s: &str, colors: &mut Vec<FormatColor>,
attrses: &mut Vec<FormatAttrs>) -> Option<Format> {
pub fn new(s: &str, mut colors: Vec<FormatColor>,
mut attrses: Vec<FormatAttrs>) -> Option<Format> {

// We use these as stacks, but in the wrong direction.
attrses.reverse();
colors.reverse();

// The buffer we will be filling with formatting options.
let mut result = vec![];
let mut string = String::from_str("");
let mut name = String::from_str("");

// String buffers will we use throughout to build relevant Strings.
let mut string = "".into_string();
let mut name = "".into_string();

// Attributes we will set and push into result.
let mut color = ConstantColor(None);
let mut attrs = ConstantAttrs(vec![]);

// The characters of the input string, which we are parsing.
let mut chars = s.chars();
let mut color: FormatColor = ConstantColor(None);
let mut attrs: FormatAttrs = ConstantAttrs(vec![]);

loop {
match chars.next() {
None => {
result.push(FormatUnit {text: Str(string), color: color, attrs: attrs.clone()});
// No more chars, push our final format unit.
result.push(FormatUnit { text: Str(string), color: color, attrs: attrs.clone() });

// Done.
return Some(Format(result));
}
},

// Parse a thing to print, e.g. {method}, {uri}.
Some('{') => {
result.push(FormatUnit {text: Str(string), color: color, attrs: attrs.clone()});
string = String::from_str("");
result.push(FormatUnit { text: Str(string), color: color, attrs: attrs.clone() });
string = "".into_string();

loop {
match chars.next() {
None => { return None; }
None => return None,

Some('}') => {
let text = match name.as_slice() {
"method" => Method,
"uri" => URI,
"status" => Status,
"response_time" => ResponseTime,
str => Str(String::from_str(str))
_ => return None
};
match text {
Str(_) => { return None; }
_ => {
result.push(FormatUnit { text: text, color: color, attrs: attrs.clone() });
name = String::from_str("");
break;
}
}
}
Some(c) => { name.push(c); }

result.push(FormatUnit { text: text, color: color, attrs: attrs.clone() });
name.clear();
break;
},

Some(c) => name.push(c)
}
}
}
},

// Begin the application of an attribute. The grammar is as follows:
//
// `@[attribute]applies to@@`
//
// @ begins the attribute, which is then followed by `[attribute]`, which declares
// what attribute is being applied, then follows the text or {object} that the
// attribute will be applied to. `@@` then ends the application of the attribute.
Some('@') => {
result.push(FormatUnit {text: Str(string), color: color, attrs: attrs.clone()});
string = String::from_str("");
result.push(FormatUnit { text: Str(string), color: color, attrs: attrs.clone() });
string = "".into_string();

match chars.next() {
// This is actually the end of an attribute application.
Some('@') => {
color = ConstantColor(None);
attrs = ConstantAttrs(vec![]);
}
},

// Parse the attribute or style being applied.
Some('[') => {
loop {
match chars.next() {
None => { return None; }
// Unexpected end of input.
None => { return None; },

// Parse the attribute.
Some(']') => {
for word in name.as_slice().split(' ') {
for word in name.as_slice().words() {
match word {
"A" => {
attrs = attrses.remove(0).unwrap_or(ConstantAttrs(vec![]));
}
attrs = attrses.pop().unwrap_or(ConstantAttrs(vec![]));
},

"C" => {
color = colors.remove(0).unwrap_or(ConstantColor(None));
}
style => match style_from_name(style) {
color = colors.pop().unwrap_or(ConstantColor(None));
},

style => match from_str(style) {
Some(Color(c)) => match color {
ConstantColor(_) => { color = ConstantColor(Some(c)); }
FunctionColor(_) => ()
ConstantColor(_) => { color = ConstantColor(Some(c)); },
_ => {}
},

Some(Attr(a)) => match attrs {
ConstantAttrs(ref mut v) => { v.push(a); }
FunctionAttrs(_) => ()
ConstantAttrs(ref mut v) => { v.push(a); },
_ => {}
},
None => ()

_ => {}
}
}
}
name = String::from_str("");

name.clear();
break;
}
},

Some(c) => { name.push(c); }
}
}
}
_ => { return None; }
// Unexpected non `@` or `[` after `@`
_ => return None,
}
}
},

Some(c) => { string.push(c); }
}
}
}
}

fn style_from_name(name: &str) -> Option<ColorOrAttr> {
match name {
"black" => Some(Color(color::BLACK)),
"blue" => Some(Color(color::BLUE)),
"brightblack" => Some(Color(color::BRIGHT_BLACK)),
"brightblue" => Some(Color(color::BRIGHT_BLUE)),
"brightcyan" => Some(Color(color::BRIGHT_CYAN)),
"brightgreen" => Some(Color(color::BRIGHT_GREEN)),
"brightmagenta" => Some(Color(color::BRIGHT_MAGENTA)),
"brightred" => Some(Color(color::BRIGHT_RED)),
"brightwhite" => Some(Color(color::BRIGHT_WHITE)),
"brightyellow" => Some(Color(color::BRIGHT_YELLOW)),
"cyan" => Some(Color(color::CYAN)),
"green" => Some(Color(color::GREEN)),
"magenta" => Some(Color(color::MAGENTA)),
"red" => Some(Color(color::RED)),
"white" => Some(Color(color::WHITE)),
"yellow" => Some(Color(color::YELLOW)),

"bold" => Some(Attr(attr::Bold)),
"dim" => Some(Attr(attr::Dim)),
"italic" => Some(Attr(attr::Italic(true))),
"underline" => Some(Attr(attr::Underline(true))),
"blink" => Some(Attr(attr::Blink)),
"standout" => Some(Attr(attr::Standout(true))),
"reverse" => Some(Attr(attr::Reverse)),
"secure" => Some(Attr(attr::Secure)),

_ => None
impl FromStr for ColorOrAttr {
fn from_str(name: &str) -> Option<ColorOrAttr> {
match name {
"black" => Some(Color(color::BLACK)),
"blue" => Some(Color(color::BLUE)),
"brightblack" => Some(Color(color::BRIGHT_BLACK)),
"brightblue" => Some(Color(color::BRIGHT_BLUE)),
"brightcyan" => Some(Color(color::BRIGHT_CYAN)),
"brightgreen" => Some(Color(color::BRIGHT_GREEN)),
"brightmagenta" => Some(Color(color::BRIGHT_MAGENTA)),
"brightred" => Some(Color(color::BRIGHT_RED)),
"brightwhite" => Some(Color(color::BRIGHT_WHITE)),
"brightyellow" => Some(Color(color::BRIGHT_YELLOW)),
"cyan" => Some(Color(color::CYAN)),
"green" => Some(Color(color::GREEN)),
"magenta" => Some(Color(color::MAGENTA)),
"red" => Some(Color(color::RED)),
"white" => Some(Color(color::WHITE)),
"yellow" => Some(Color(color::YELLOW)),

"bold" => Some(Attr(attr::Bold)),
"dim" => Some(Attr(attr::Dim)),
"italic" => Some(Attr(attr::Italic(true))),
"underline" => Some(Attr(attr::Underline(true))),
"blink" => Some(Attr(attr::Blink)),
"standout" => Some(Attr(attr::Standout(true))),
"reverse" => Some(Attr(attr::Reverse)),
"secure" => Some(Attr(attr::Secure)),

_ => None
}
}
}

Expand All @@ -175,35 +224,13 @@ pub enum FormatAttrs {
}

impl Clone for FormatColor {
fn clone(&self) -> FormatColor {
match *self {
ConstantColor(color) => ConstantColor(color),
FunctionColor(f) => FunctionColor(f)
}
}
fn clone(&self) -> FormatColor { *self }
}

impl Clone for FormatAttrs {
fn clone(&self) -> FormatAttrs {
match *self {
ConstantAttrs(ref attrs) => {
let mut attrs_clone = vec![];
for &attr in attrs.iter() {
attrs_clone.push(match attr {
attr::Bold => attr::Bold,
attr::Dim => attr::Dim,
attr::Italic(bool) => attr::Italic(bool),
attr::Underline(bool) => attr::Underline(bool),
attr::Blink => attr::Blink,
attr::Standout(bool) => attr::Standout(bool),
attr::Reverse => attr::Reverse,
attr::Secure => attr::Secure,
attr::ForegroundColor(color) => attr::ForegroundColor(color),
attr::BackgroundColor(color) => attr::BackgroundColor(color)
});
}
ConstantAttrs(attrs_clone)
}
ConstantAttrs(ref attrs) => ConstantAttrs(attrs.iter().map(|&attr| attr).collect()),
FunctionAttrs(f) => FunctionAttrs(f)
}
}
Expand All @@ -227,3 +254,4 @@ pub struct FormatUnit {
pub color: FormatColor,
pub attrs: FormatAttrs
}

2 changes: 1 addition & 1 deletion src/lib.rs
Expand Up @@ -64,7 +64,7 @@ impl AfterMiddleware for Logger {
fn after(&self, req: &mut Request, res: &mut Response) -> IronResult<()> {
let entry_time = *req.extensions.find::<StartTime, u64>().unwrap();
let response_time_ms = (precise_time_ns() - entry_time) as f64 / 1000000.0;
let Format(format) = self.format.clone().unwrap_or(Format::default());
let Format(format) = self.format.clone().unwrap_or_default();

let render = |text: &FormatText| {
match *text {
Expand Down

0 comments on commit 3ba99ad

Please sign in to comment.