<commit_before>extern crate hyper;
extern crate rustc_serialize;

pub mod gists;
pub mod deployments;
pub mod issues;
pub mod rep;
pub mod repository;
pub mod pullrequests;

use gists::{Gists, UserGists};
use hyper::Client;
use hyper::client::{IntoUrl, RequestBuilder};
use hyper::header::{Authorization, UserAgent};
use repository::Repository;
use std::default::Default;
use std::fmt;
use std::io::{Read, Result};

pub enum SortDirection {
  Asc,
  Desc
}

impl fmt::Display for SortDirection {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", match *self {
      SortDirection::Asc => "asc",
      SortDirection::Desc => "desc"
    })
  }
}

impl Default for SortDirection {
  fn default() -> SortDirection {
    SortDirection::Asc
  }
}

pub struct Github<'a> {
  host: &'static str,
  agent: &'static str,
  client: &'a Client,
  token: Option<&'static str>
}

impl<'a> Github<'a> {
  /// create a new Github instance
  pub fn new(
    agent: &'static str, client: &'a Client, token: Option<&'static str>) -> Github<'a> {
    Github::host("https://api.github.com", agent, client, token)
  }

  /// create a new Github instance hosted and a custom location
  pub fn host(
    host: &'static str, agent: &'static str,
    client: &'a Client, token: Option<&'static str>) -> Github<'a> {
    Github {
      host: host,
      agent: agent,
      client: client,
      token: token
    }
  }

  /// return a reference to a github reposistory
  pub fn repo(&self, owner: &'static str, repo: &'static str) -> Repository {
    Repository::new(self, owner, repo)
  }

  /// return a reference to an interface that provides access to a user's gists
  pub fn user_gists(&self, owner: &'static str) -> UserGists {
    UserGists::new(self, owner)
  }

  /// return a reference to an interface that provides access to the
  /// the gists belonging to the owner of the token used to configure this client
  pub fn gists(&self) -> Gists {
    Gists::new(self)
  }

  fn request<U: IntoUrl>(
    &self, request_builder: RequestBuilder<'a, U>, body: Option<&'a [u8]>) -> Result<String> {
    let builder = request_builder.header(
      UserAgent(self.agent.to_owned())
    );
    let authenticated = match self.token {
      Some(token) =>
        builder.header(
          Authorization(format!("token {}", token))
        ),
      _ =>
        builder
    };
    let mut res = match body {
      Some(ref bod) => authenticated.body(*bod).send().unwrap(),
       _ => authenticated.send().unwrap()
    };
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    Ok(body)
  }

  fn get(&self, uri: &str) -> Result<String> {
    let url = format!("{}{}", self.host, uri);
    self.request(
      self.client.get(
        &url
      ), None
    )
  }

  fn delete(&self, uri: &str) -> Result<()> {
    let url = format!("{}{}", self.host, uri);
    self.request(
      self.client.delete(
        &url
      ), None
    ).map(|_| ())
  }

  fn post(&self, uri: &str, message: &[u8]) -> Result<String> {
    let url = format!("{}{}", self.host, uri);
    self.request(
      self.client.post(
        &url
      ),
      Some(message)
    )
  }

  fn put(&self, uri: &str, message: &[u8]) -> Result<String> {
    let url = format!("{}{}", self.host, uri);
    self.request(
      self.client.put(
        &url
      ),
      Some(message)
    )
  }
}
<commit_msg>support patch<commit_after>extern crate hyper;
extern crate rustc_serialize;

pub mod gists;
pub mod deployments;
pub mod issues;
pub mod rep;
pub mod repository;
pub mod pullrequests;

use gists::{Gists, UserGists};
use hyper::Client;
use hyper::client::{IntoUrl, RequestBuilder};
use hyper::method::Method;
use hyper::header::{Authorization, UserAgent};
use repository::Repository;
use std::default::Default;
use std::fmt;
use std::io::{Read, Result};

pub enum SortDirection {
  Asc,
  Desc
}

impl fmt::Display for SortDirection {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", match *self {
      SortDirection::Asc => "asc",
      SortDirection::Desc => "desc"
    })
  }
}

impl Default for SortDirection {
  fn default() -> SortDirection {
    SortDirection::Asc
  }
}

pub struct Github<'a> {
  host: &'static str,
  agent: &'static str,
  client: &'a Client,
  token: Option<&'static str>
}

impl<'a> Github<'a> {
  /// create a new Github instance
  pub fn new(
    agent: &'static str, client: &'a Client, token: Option<&'static str>) -> Github<'a> {
    Github::host("https://api.github.com", agent, client, token)
  }

  /// create a new Github instance hosted and a custom location
  pub fn host(
    host: &'static str, agent: &'static str,
    client: &'a Client, token: Option<&'static str>) -> Github<'a> {
    Github {
      host: host,
      agent: agent,
      client: client,
      token: token
    }
  }

  /// return a reference to a github reposistory
  pub fn repo(&self, owner: &'static str, repo: &'static str) -> Repository {
    Repository::new(self, owner, repo)
  }

  /// return a reference to an interface that provides access to a user's gists
  pub fn user_gists(&self, owner: &'static str) -> UserGists {
    UserGists::new(self, owner)
  }

  /// return a reference to an interface that provides access to the
  /// the gists belonging to the owner of the token used to configure this client
  pub fn gists(&self) -> Gists {
    Gists::new(self)
  }

  fn request<U: IntoUrl>(
    &self, request_builder: RequestBuilder<'a, U>, body: Option<&'a [u8]>) -> Result<String> {
    let builder = request_builder.header(
      UserAgent(self.agent.to_owned())
    );
    let authenticated = match self.token {
      Some(token) =>
        builder.header(
          Authorization(format!("token {}", token))
        ),
      _ =>
        builder
    };
    let mut res = match body {
      Some(ref bod) => authenticated.body(*bod).send().unwrap(),
       _ => authenticated.send().unwrap()
    };
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    Ok(body)
  }

  fn get(&self, uri: &str) -> Result<String> {
    let url = format!("{}{}", self.host, uri);
    self.request(
      self.client.get(
        &url
      ), None
    )
  }

  fn delete(&self, uri: &str) -> Result<()> {
    let url = format!("{}{}", self.host, uri);
    self.request(
      self.client.delete(
        &url
      ), None
    ).map(|_| ())
  }

  fn post(&self, uri: &str, message: &[u8]) -> Result<String> {
    let url = format!("{}{}", self.host, uri);
    self.request(
      self.client.post(
        &url
      ),
      Some(message)
    )
  }

  fn patch(&self, uri: &str, message: &[u8]) -> Result<String> {
    let url = format!("{}{}", self.host, uri);
    self.request(
      self.client.request(
        Method::Patch,
        &url
      ),
      Some(message)
    )
  }

  fn put(&self, uri: &str, message: &[u8]) -> Result<String> {
    let url = format!("{}{}", self.host, uri);
    self.request(
      self.client.put(
        &url
      ),
      Some(message)
    )
  }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::cmp::Ordering;

extern crate regex;

use regex::Regex;

pub fn puzzle(input: &str) -> u32 {
    let mut sum_of_sector_ids = 0;

    for line in input.lines() {
        let room = Room::new(line);
        if room.is_real() {
            sum_of_sector_ids += room.sector_id;
        }
    }

    sum_of_sector_ids
}

pub struct Room {
    name: String,
    sector_id: u32,
    checksum: String,
}

impl Room {
    fn new(description: &str) -> Room {
        let regex = Regex::new(r"(?x)
            (?P<name>[a-z-]+)
            -
            (?P<sector_id>[0-9]+)
            \[(?P<checksum>[a-z]{5})\]").expect("Regex is invalid");

        let caps = regex.captures(description).expect("Can't capture");

        Room {
            name: caps.name("name").expect("No name").to_string(),
            sector_id: caps.name("sector_id").expect("No sector id").parse().expect("Can't parse"),
            checksum: caps.name("checksum").expect("No checksum").to_string(),
        }
    }

    fn is_real(&self) -> bool {
        self.checksum == self.computed_checksum()
    }

    fn computed_checksum(&self) -> String {
        let most_common = self.five_most_common_chars();
        let mut s = String::new();
        for &c in most_common.iter() {
            s.push(c);
        }
        s
    }

    fn five_most_common_chars(&self) -> Vec<char> {
        self.chars_by_frequency_desc().into_iter().take(5).collect()
    }

    fn chars_by_frequency_desc(&self) -> Vec<char> {
        let mut tuples: Vec<(char, u32)> = self.chars_by_frequency()
                                               .into_iter()
                                               .collect();
        tuples.sort_by(|a, b| {
            match b.1.cmp(&a.1) {
                Ordering::Equal => a.0.cmp(&b.0),
                other => other,
            }
        });
        tuples.iter().map( |&(k, _)| k ).collect()
    }

    fn chars_by_frequency(&self) -> HashMap<char, u32> {
        let mut freqs = HashMap::new();
        for c in self.name.chars() {
            if c != '-' {
                let count = freqs.entry(c).or_insert(0);
                *count += 1;
            }
        }
        freqs
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::collections::HashMap;

    #[test]
    fn test_extraction() {
        let description = "aaaaa-bbb-z-y-x-123[abxyz]";
        let room = Room::new(description);

        assert_eq!(room.name, "aaaaa-bbb-z-y-x");
        assert_eq!(room.sector_id, 123);
        assert_eq!(room.checksum, "abxyz");
    }

    #[test]
    fn test_chars_by_freq() {
        let room = Room::new("aaaaa-bbb-z-y-x-123[abxyz]");
        let mut expected = HashMap::new();
        expected.insert('a', 5);
        expected.insert('b', 3);
        expected.insert('z', 1);
        expected.insert('y', 1);
        expected.insert('x', 1);
        assert_eq!(room.chars_by_frequency(), expected);
    }

    #[test]
    fn test_chars_by_freq_desc() {
        let room = Room::new("aaaaa-bbb-z-y-x-123[abxyz]");
        assert_eq!(
            room.chars_by_frequency_desc(),
            vec!['a', 'b', 'x', 'y', 'z']
        );
    }

    #[test]
    fn test_five_most_common_chars() {
        let room = Room::new("not-a-real-room-404[oarel]");
        assert_eq!(
            room.five_most_common_chars(),
            vec!['o', 'a', 'r', 'e', 'l']
        );
    }

    #[test]
    fn real_rooms() {
        assert!(Room::new("aaaaa-bbb-z-y-x-123[abxyz]").is_real());
        assert!(Room::new("a-b-c-d-e-f-g-h-987[abcde]").is_real());
        assert!(Room::new("not-a-real-room-404[oarel]").is_real());
    }

    #[test]
    fn decoy_rooms() {
        assert!( ! Room::new("totally-real-room-200[decoy]").is_real() );
    }

    #[test]
    fn test_puzzle() {
        let input = [
            "aaaaa-bbb-z-y-x-123[abxyz]",
            "a-b-c-d-e-f-g-h-987[abcde]",
            "not-a-real-room-404[oarel]",
            "totally-real-room-200[decoy]",
        ].join("\n");

        assert_eq!(puzzle(&input), 1514);
    }
}
<commit_msg>Write a decrypt function<commit_after>use std::collections::HashMap;
use std::cmp::Ordering;

extern crate regex;

use regex::Regex;

pub fn puzzle(input: &str) -> u32 {
    let mut sum_of_sector_ids = 0;

    for line in input.lines() {
        let room = Room::new(line);
        if room.is_real() {
            sum_of_sector_ids += room.sector_id;
        }
    }

    sum_of_sector_ids
}

pub struct Room {
    name: String,
    sector_id: u32,
    checksum: String,
}

impl Room {
    fn new(description: &str) -> Room {
        let regex = Regex::new(r"(?x)
            (?P<name>[a-z-]+)
            -
            (?P<sector_id>[0-9]+)
            \[(?P<checksum>[a-z]{5})\]").expect("Regex is invalid");

        let caps = regex.captures(description).expect("Can't capture");

        Room {
            name: caps.name("name").expect("No name").to_string(),
            sector_id: caps.name("sector_id").expect("No sector id").parse().expect("Can't parse"),
            checksum: caps.name("checksum").expect("No checksum").to_string(),
        }
    }

    fn is_real(&self) -> bool {
        self.checksum == self.computed_checksum()
    }

    fn computed_checksum(&self) -> String {
        let most_common = self.five_most_common_chars();
        let mut s = String::new();
        for &c in most_common.iter() {
            s.push(c);
        }
        s
    }

    fn five_most_common_chars(&self) -> Vec<char> {
        self.chars_by_frequency_desc().into_iter().take(5).collect()
    }

    fn chars_by_frequency_desc(&self) -> Vec<char> {
        let mut tuples: Vec<(char, u32)> = self.chars_by_frequency()
                                               .into_iter()
                                               .collect();
        tuples.sort_by(|a, b| {
            match b.1.cmp(&a.1) {
                Ordering::Equal => a.0.cmp(&b.0),
                other => other,
            }
        });
        tuples.iter().map( |&(k, _)| k ).collect()
    }

    fn chars_by_frequency(&self) -> HashMap<char, u32> {
        let mut freqs = HashMap::new();
        for c in self.name.chars() {
            if c != '-' {
                let count = freqs.entry(c).or_insert(0);
                *count += 1;
            }
        }
        freqs
    }
}

pub fn decrypt(name: &str, rot: u32) -> String {
    let mut answer = String::new();

    for c in name.chars() {
        if c == '-' {
            answer.push(' ');
        } else {
            answer.push(rotn(c, rot))
        }
    }

    answer
}

fn rotn(c: char, rot: u32) -> char {
    let index = (((c.to_digit(36).expect("to_digit failed") - 10) + rot) % 26) as usize;
    let alphabet = "abcdefghijklmnopqrstuvwxyz";
    let alphabet: Vec<char> = alphabet.chars().collect();
    alphabet[index]
}

#[cfg(test)]
mod test {
    use super::*;
    use std::collections::HashMap;

    #[test]
    fn test_decryption() {
        let answer = decrypt("qzmt-zixmtkozy-ivhz", 343);
        assert_eq!("very encrypted name", answer);
    }

    #[test]
    fn test_extraction() {
        let description = "aaaaa-bbb-z-y-x-123[abxyz]";
        let room = Room::new(description);

        assert_eq!(room.name, "aaaaa-bbb-z-y-x");
        assert_eq!(room.sector_id, 123);
        assert_eq!(room.checksum, "abxyz");
    }

    #[test]
    fn test_chars_by_freq() {
        let room = Room::new("aaaaa-bbb-z-y-x-123[abxyz]");
        let mut expected = HashMap::new();
        expected.insert('a', 5);
        expected.insert('b', 3);
        expected.insert('z', 1);
        expected.insert('y', 1);
        expected.insert('x', 1);
        assert_eq!(room.chars_by_frequency(), expected);
    }

    #[test]
    fn test_chars_by_freq_desc() {
        let room = Room::new("aaaaa-bbb-z-y-x-123[abxyz]");
        assert_eq!(
            room.chars_by_frequency_desc(),
            vec!['a', 'b', 'x', 'y', 'z']
        );
    }

    #[test]
    fn test_five_most_common_chars() {
        let room = Room::new("not-a-real-room-404[oarel]");
        assert_eq!(
            room.five_most_common_chars(),
            vec!['o', 'a', 'r', 'e', 'l']
        );
    }

    #[test]
    fn real_rooms() {
        assert!(Room::new("aaaaa-bbb-z-y-x-123[abxyz]").is_real());
        assert!(Room::new("a-b-c-d-e-f-g-h-987[abcde]").is_real());
        assert!(Room::new("not-a-real-room-404[oarel]").is_real());
    }

    #[test]
    fn decoy_rooms() {
        assert!( ! Room::new("totally-real-room-200[decoy]").is_real() );
    }

    #[test]
    fn test_puzzle() {
        let input = [
            "aaaaa-bbb-z-y-x-123[abxyz]",
            "a-b-c-d-e-f-g-h-987[abcde]",
            "not-a-real-room-404[oarel]",
            "totally-real-room-200[decoy]",
        ].join("\n");

        assert_eq!(puzzle(&input), 1514);
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Jeremy Wall <jeremy@marzhillstudios.com>
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// #![feature(trace_macros,log_syntax)]

//! # ucg, A universal configuration grammar.
//!
//! Ucg defines a common grammar for describing a collection of configuration values.
//! ucg allows you to specify configuration values with a syntax that that is immutable,
//! comoposable with copy-on-write semantics, and safe.
//!
//! ## Example
//!
//! ```ucg
//! // named bindings
//! let host = "mysql.internal.net";
//! let port = 8080
//!
//! // format strings
//! let connstr = "mysql://@:@" % (host, port);
//!
//! // tuples
//! let dbconf = {
//!     connstr = connstr,
//!     database = "mydb",
//!     // lists
//!     tables = ["posts", "comments", "users"],
//! };
//! ```
//!
//! ## Syntax
//!
//! ucg is a safe language with type inference that tries to guarantee that it will halt.
//! A valid ucg file is composesed of a series of statements. Statements are any valid
//! ucg expression terminated by a semicolon.
//!
//! ### Reserved words
//!
//! The following words are reserved in ucg and can't be used as named bindings.
//!
//! * let
//! * import
//! * as
//! * select
//! * macro
//!
//! ### Primitive types
//!
//! ucg has a relatively simple syntax with 3 primitive types, Int, Float, and String.
//!
//! * Int, is any integer number.
//! * Float is any number with a decimal point.
//!
//! ```ucg
//! 1.0; // A typical float.
//! 1. // You can leave off the 0 after the decimal point.
//! .1 // the leading 0 is also optional.
//! ```
//!
//! * String is any quoted text. backslashes within a string escape the next preceding
//! character.
//!
//! ``` ucg
//! "foo"; // a smiple string
//! "I'm a \"fine\" looking string"; // escaped quotes in a string.
//! ```
//!
//! ### Complex types
//!
//! ucg has two complex data types, Lists and Tuples.
//!
//! * List's start are surrounded with square brackets `[ ]` and have comma separated elements.
//!
//! ```ucg
//! [1, 2, 3]; // A simple list of numbers.
//!
//! [[1, 2], [3, 4]] // A deep list with embedded lists inside.
//! ```
//!
//! Lists are 0 indexed and you can index into them using the dotted selector syntax.
//!
//! ```ucg
//! let mylist = [0, 1, 2, 3];
//!
//! let zero = mylist.0;
//! ```
//!
//! * Tuple's are an ordered collection of name, value pairs. They are bounded by curly braces `{ }`
//! and contain name = value pairs separated by commas. Trailing commas are permitted. The name must
//! be a bareword without quotes.
//!
//! ```ucg
//! let mytuple = {
//!     field1 = "value1",
//!     field2 = "value2",
//! };
//! ```
//!
//! Tuples can be indexed using dotted selector syntax.
//!
//! ```ucg
//! let field = mytuple.fields1;
//! ```
//!
//! ### Expressions
//!
//! #### Selectors
//!
//! Selectors are references to a bound value in ucg. They can index arbitrarily deep into either tuples or lists.
//! The head of a selector can be any expression that resolves to a tuple or list. Optionally a selector can also be
//! followed by either a bareword to index a tuple field or an integer to index a list position.
//!
//! The simplest selector is just a reference to a bound value by name.
//!
//! ```ucg
//! let mytuple = {
//!     field1 = "a string",
//!     field2 = [{
//!         subfield1 = 1,
//!     }];
//! };
//!
//! mytuple.field2.0; // descend into a deeply nested tuple and array.
//! ```
//!
//! #### Binary operators
//!
//! ucg supports the following operators, +, -, *, /; Each one is type safe and infers the types from the values they operate on.
//! The operators expect both the left and right operands to be of the same type. All of the operators are valid on integers and floats.
//! The + operator can additionally concatenate strings or arrays.
//!
//! ```ucg
//! 1 + 1; // result is 2
//! "foo " + "bar" // result is "foo bar"
//! [1,2] + [3,4]; // result is [1,2,3,4]
//! ```
//!
//! #### Conditional data.
//!
//! ucg supports a limited form of conditional selection of data using the select expression. A select expression starts with the select
//! keyword and is followed by a an expression resolving to a string naming the field to select, an expression resolving to the default value,
//! and a tuple to select the field from. If the field selected is not in the tuple then the default value will be used.
//!
//! ```ucg
//! let want = "baz";
//!
//! //     field  default
//! select want, "quux", {
//!     baz = "foo",
//!     fuzz = "bang",
//! }; // result will be "foo"
//!
//! //     field    default
//! select "quack", "quux", {
//!     baz = "foo",
//!     fuzz = "bang",
//! }; // result will be "quux"
//! ```
//!
//! #### Macros
//!
//! Macros look like functions but they are resolved at compile time and configurations don't execute so they never appear in output.
//! They are useful for constructing tuples of a certain shape or otherwise promoting data reuse. You define a macro with the macro
//! keyword followed by the arguments in parentheses and then a tuple.
//!
//! ```ucg
//! let myfunc = macro (arg1, arg2) {
//!     host = arg1,
//!     port = arg2,
//!     connstr = "couchdb://@:@" % (arg1, arg2),
//! }
//!
//! let my dbconf = myfunc("couchdb.example.org", "9090");
//!
//! let my dbhost = dbconf.host;
//! ```
//!
//! macros always resolve to a tuple. If you want to get a single value out you can use selector syntax to retrieve it.
//!
//! ### Statements
//!
//! There are 3 kinds of statements in a ucg configuration file. expression statements, let statements, and import statements.
//!
//! * expression statements
//! The simplest and least useful is the expression statements. It is any valid expression followed by a semicolon.
//!
//! ```ucg
//! 1;
//! 4 / 2;
//! "foo";
//! "foo" + "bar";
//! ```
//!
//! Despite the fact that these are valid the results are thrown away and can essentially be considered a noop. If we
//! ever create a repl for ucg statements they may prove more useful.
//!
//!  * Let statements
//! The let expression binds the result of any valid expression to a name. It starts with the let keyword and is followed by
//! the name of the binding, =, and a valid ucg expression.
//!
//! ```ucg
//! let name = "foo";
//! ```
//!
//! * Import statement
//! The import statement imports the contents of another ucg file into the current file with a name. The imported files bound
//! values are exposed as a tuple in the referencing file. It starts with the import keyword and is followed by a quoted path
//! to the ucg file, they keyword as, and a name for the imported values.
//!
//! ```ucg
//! import "dbconfigs.ucg" as dbconfigs;
//!
//! let mysqlconf = dbconfigs.mysql;
//! ```
#[macro_use]
extern crate nom;
#[macro_use]
extern crate nom_locate;
extern crate serde_json;

#[macro_use]
pub mod ast;
#[macro_use]
pub mod tokenizer;
pub mod parse;
pub mod build;
pub mod convert;
pub mod error;

mod format;

pub use ast::Value;
pub use ast::Expression;
pub use ast::Statement;

pub use parse::parse;
pub use build::Builder;
<commit_msg>Documentation formatting, grammar, and spelling.<commit_after>// Copyright 2017 Jeremy Wall <jeremy@marzhillstudios.com>
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// #![feature(trace_macros,log_syntax)]

//! # ucg, A universal configuration grammar.
//!
//! Ucg defines a common grammar for describing a collection of configuration values.
//! ucg allows you to specify configuration values with a syntax that that is immutable,
//! comoposable with copy-on-write semantics, and safe.
//!
//! ## Example
//!
//! ```ucg
//! // named bindings
//! let host = "mysql.internal.net";
//! let port = 8080
//!
//! // format strings
//! let connstr = "mysql://@:@" % (host, port);
//!
//! // tuples
//! let dbconf = {
//!     connstr = connstr,
//!     database = "mydb",
//!     // lists
//!     tables = ["posts", "comments", "users"],
//! };
//! ```
//!
//! ## Syntax
//!
//! ucg is a safe language with type inference that tries to guarantee that it will halt.
//! A valid ucg file is composesed of a series of statements. Statements are any valid
//! ucg expression terminated by a semicolon.
//!
//! ### Reserved words
//!
//! The following words are reserved in ucg and can't be used as named bindings.
//!
//! * let
//! * import
//! * as
//! * select
//! * macro
//!
//! ### Primitive types
//!
//! ucg has a relatively simple syntax with 3 primitive types, Int, Float, and String.
//!
//! * Int is any integer number.
//!
//! ```ucg
//! 1; // a single Integer
//! ```
//!
//! * Float is any number with a decimal point.
//!
//! ```ucg
//! 1.0; // A typical float.
//! 1. // You can leave off the 0 after the decimal point.
//! .1 // the leading 0 is also optional.
//! ```
//!
//! * String is any quoted text. backslashes within a string escape the next preceding
//! character.
//!
//! ``` ucg
//! "foo"; // a smiple string
//! "I'm a \"fine\" looking string"; // escaped quotes in a string.
//! ```
//!
//! ### Complex types
//!
//! ucg has two complex data types, Lists and Tuples.
//!
//! * Lists start are surrounded with square brackets `[ ]` and have comma separated elements.
//!
//! ```ucg
//! [1, 2, 3]; // A simple list of numbers.
//!
//! [[1, 2], [3, 4]] // A deep list with embedded lists inside.
//! ```
//!
//! Lists are 0 indexed and you can index into them using the dotted selector syntax.
//!
//! ```ucg
//! let mylist = [0, 1, 2, 3];
//!
//! let zero = mylist.0;
//! ```
//!
//! * Tuple's are an ordered collection of name, value pairs. They are bounded by curly braces `{ }`
//! and contain name = value pairs separated by commas. Trailing commas are permitted. The name must
//! be a bareword without quotes.
//!
//! ```ucg
//! let mytuple = {
//!     field1 = "value1",
//!     field2 = "value2",
//! };
//! ```
//!
//! Tuples can be indexed using dotted selector syntax.
//!
//! ```ucg
//! let field = mytuple.fields1;
//! ```
//!
//! ### Expressions
//!
//! #### Selectors
//!
//! Selectors are references to a bound value in ucg. They can index arbitrarily deep into either tuples or lists.
//! The head of a selector can be any expression that resolves to a tuple or list. Optionally a selector can also be
//! followed by either a bareword to index a tuple field or an integer to index a list position.
//!
//! The simplest selector is just a reference to a bound value by name.
//!
//! ```ucg
//! let mytuple = {
//!     field1 = "a string",
//!     field2 = [{
//!         subfield1 = 1,
//!     }];
//! };
//!
//! mytuple.field2.0; // descend into a deeply nested tuple and array.
//! ```
//!
//! #### Binary operators
//!
//! ucg supports the following operators, +, -, *, /; Each one is type safe and infers the types from the values they operate on.
//! The operators expect both the left and right operands to be of the same type. All of the operators are valid on integers and floats.
//! The + operator can additionally concatenate strings or arrays.
//!
//! ```ucg
//! 1 + 1; // result is 2
//! "foo " + "bar" // result is "foo bar"
//! [1,2] + [3,4]; // result is [1,2,3,4]
//! ```
//!
//! #### Copy expressions
//!
//! ucg Tuples support a form of reuse with copy on write semantics. You can copy a tuple and selectively overwrite fields or add new
//! fields to it with the copy expression. To perform a copy first reference the tuple by a bound name and then use `{ field = value, ... }`
//! syntax to copy with overridden fields  or add completely new fields. When replacing a preexisting field with a new value you cannot
//! change the type of the field. This allows you to define a typed shape for a tuple with default values and then provide new values for
//! some or all of the fields while still enforcing the same types for those fields. Adding completely new fields has no such restriction.
//!
//! ```ucg
//! let base = {
//!     field1 = "value1",
//!     field2 = 100,
//!     field3 = 5.6,
//! };
//!
//! let overridden = base{
//!     field1 = "new value"
//! };
//!
//! let expanded = base{
//!     field2 = 200,
//!     field3 = "look ma a new field",
//! };
//! ```
//!
//! The following will cause an error because the overriden field's value does not match the original.
//!
//! ```ucg
//! let bad = base{
//!     field1 = 300, // Error!!! must be a string.
//! };
//!
//! ```
//!
//! #### Conditional data
//!
//! ucg supports a limited form of conditional data selection of using the select expression. A select expression starts with the `select`
//! keyword and is followed by a an expression resolving to a string naming the field to select, an expression resolving to the default value,
//! and a tuple to select the field from. If the field selected is not in the tuple then the default value will be used.
//!
//! ```ucg
//! let want = "baz";
//!
//! //     field  default
//! select want, "quux", {
//!     baz = "foo",
//!     fuzz = "bang",
//! }; // result will be "foo"
//!
//! //     field    default
//! select "quack", "quux", {
//!     baz = "foo",
//!     fuzz = "bang",
//! }; // result will be "quux"
//! ```
//!
//! #### Macros
//!
//! Macros look like functions but they are resolved at compile time and configurations don't execute so they never appear in output.
//! They are useful for constructing tuples of a certain shape or otherwise promoting data reuse. You define a macro with the `macro`
//! keyword followed by the arguments in parentheses and then a tuple.
//!
//! ```ucg
//! let myfunc = macro (arg1, arg2) {
//!     host = arg1,
//!     port = arg2,
//!     connstr = "couchdb://@:@" % (arg1, arg2),
//! }
//!
//! let my dbconf = myfunc("couchdb.example.org", "9090");
//!
//! let my dbhost = dbconf.host;
//! ```
//!
//! macros always resolve to a tuple. If you want to get a single value out you can use selector syntax to retrieve it.
//!
//! ### Statements
//!
//! There are 3 kinds of statements in a ucg configuration file. expression statements, let statements, and import statements.
//! All ucg statements must be terminated by a semicolon.
//!
//! * expression statements
//!
//! The simplest and least useful is the expression statement. It is any valid expression followed by a semicolon.
//!
//! ```ucg
//! 1;
//! 4 / 2;
//! "foo";
//! "foo" + "bar";
//! ```
//!
//! Despite the fact that these are valid the results are thrown away and can essentially be considered a noop. If we
//! ever create a repl for ucg statements they may prove more useful.
//!
//!  * Let statements
//!
//! The let expression binds the result of any valid expression to a name. It starts with the `let` keyword and is followed by
//! the name of the binding, an `=`, and a valid ucg expression.
//!
//! ```ucg
//! let name = "foo";
//! ```
//!
//! * Import statement
//!
//! The import statement imports the contents of another ucg file into the current file with a name. The imported files bound
//! values are exposed as a tuple in the referencing file. It starts with the `import` keyword and is followed by a quoted path
//! to the ucg file, the keyword `as`, and a name for the imported values.
//!
//! ```ucg
//! import "dbconfigs.ucg" as dbconfigs;
//!
//! let mysqlconf = dbconfigs.mysql;
//! ```
#[macro_use]
extern crate nom;
#[macro_use]
extern crate nom_locate;
extern crate serde_json;

#[macro_use]
pub mod ast;
#[macro_use]
pub mod tokenizer;
pub mod parse;
pub mod build;
pub mod convert;
pub mod error;

mod format;

pub use ast::Value;
pub use ast::Expression;
pub use ast::Statement;

pub use parse::parse;
pub use build::Builder;
<|endoftext|>


<commit_before>#![macro_use]

//! Rust bindings for [libffi](https://sourceware.org/libffi/).
//!
//! The C libffi library provides two main facilities: assembling calls
//! to functions dynamically, and creating closures that can be called
//! as ordinary C functions. In Rust, the latter means that we can turn
//! a Rust lambda (or any object implementing `Fn`/`FnMut`) into an
//! ordinary C function pointer that we can pass as a callback to C.

//! The easiest way to use this library is via the
//! [`high`](high/index.html) layer module, but more flexibility (and
//! less checking) is provided by the [`middle`](middle/index.html) and
//! [`low`](low/index.html) layers.

//! # Usage/Warning
//!
//! This library is experimental/unstable and shouldn’t be used for
//! anything yet. If it does something you need or want to play with
//! then we should talk.
//!
//! It’s [on crates.io](https://crates.io/crates/libffi), so it can be
//! used by adding `libffi` to the dependencies in your project’s
//! `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! libffi = "0.1"
//! ```
//!
//! However, to actually build it, you need to install [Rust
//! bindgen](https://crates.io/crates/bindgen) (0.18.0) and [C
//! libffi](https://sourceware.org/libffi/) (3.2.1) manually first.
//!
//! # Organization
//!
//! This library is organized in four layers, each of which attempts to
//! provide more safety and a simpler interface than the next layer
//! down. From top to bottom:
//!
//!   - The [`high`](high/index.html) layer provides safe(?) and
//!     automatic marshalling of Rust closures into C function pointers.
//!   - The [`middle`](middle/index.html) layer provides memory-managed
//!     abstractions for assembling calls and closures, but is unsafe
//!     because it doesn’t check argument types.
//!   - The [`low`](low/index.html) layer makes no attempts at safety,
//!     but provides a more idiomatically “Rusty” API than the underlying
//!     C library.
//!   - The [`raw`](raw/index.html) layer is a direct mapping of the
//!     C libffi library into Rust, generated by
//!     [bindgen](https://crates.io/crates/bindgen).
//!
//! It should be possible to use any layer without dipping into lower
//! layers (and it will be considered a bug to the extent that it
//! isn’t).
//!
//! # Example
//!
//! In this example, we convert a Rust lambda containing a free variable
//! into an ordinary C code pointer. The type of `fun` below is
//! `extern "C" fn(u64, u64) -> u64`.
//!
//! ```
//! use libffi::high::Closure2;
//!
//! let x = 5u64;
//! let f = |y: u64, z: u64| x + y + z;
//!
//! let closure = Closure2::new(&f);
//! let fun     = closure.code_ptr();
//!
//! assert_eq!(18, fun(6, 7));
//! ```

extern crate libc;

/// Unwrapped definitions imported from the C library (via bindgen).
///
/// This module is generated and undocumented, but you can see the [C
/// libffi documentation](libffi.txt).
pub mod raw;

#[macro_use]
pub mod high;
pub mod middle;
pub mod low;
<commit_msg>got rid of unnecessary #[macro_use]s<commit_after>//! Rust bindings for [libffi](https://sourceware.org/libffi/).
//!
//! The C libffi library provides two main facilities: assembling calls
//! to functions dynamically, and creating closures that can be called
//! as ordinary C functions. In Rust, the latter means that we can turn
//! a Rust lambda (or any object implementing `Fn`/`FnMut`) into an
//! ordinary C function pointer that we can pass as a callback to C.

//! The easiest way to use this library is via the
//! [`high`](high/index.html) layer module, but more flexibility (and
//! less checking) is provided by the [`middle`](middle/index.html) and
//! [`low`](low/index.html) layers.

//! # Usage/Warning
//!
//! This library is experimental/unstable and shouldn’t be used for
//! anything yet. If it does something you need or want to play with
//! then we should talk.
//!
//! It’s [on crates.io](https://crates.io/crates/libffi), so it can be
//! used by adding `libffi` to the dependencies in your project’s
//! `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! libffi = "0.1"
//! ```
//!
//! However, to actually build it, you need to install [Rust
//! bindgen](https://crates.io/crates/bindgen) (0.18.0) and [C
//! libffi](https://sourceware.org/libffi/) (3.2.1) manually first.
//!
//! # Organization
//!
//! This library is organized in four layers, each of which attempts to
//! provide more safety and a simpler interface than the next layer
//! down. From top to bottom:
//!
//!   - The [`high`](high/index.html) layer provides safe(?) and
//!     automatic marshalling of Rust closures into C function pointers.
//!   - The [`middle`](middle/index.html) layer provides memory-managed
//!     abstractions for assembling calls and closures, but is unsafe
//!     because it doesn’t check argument types.
//!   - The [`low`](low/index.html) layer makes no attempts at safety,
//!     but provides a more idiomatically “Rusty” API than the underlying
//!     C library.
//!   - The [`raw`](raw/index.html) layer is a direct mapping of the
//!     C libffi library into Rust, generated by
//!     [bindgen](https://crates.io/crates/bindgen).
//!
//! It should be possible to use any layer without dipping into lower
//! layers (and it will be considered a bug to the extent that it
//! isn’t).
//!
//! # Example
//!
//! In this example, we convert a Rust lambda containing a free variable
//! into an ordinary C code pointer. The type of `fun` below is
//! `extern "C" fn(u64, u64) -> u64`.
//!
//! ```
//! use libffi::high::Closure2;
//!
//! let x = 5u64;
//! let f = |y: u64, z: u64| x + y + z;
//!
//! let closure = Closure2::new(&f);
//! let fun     = closure.code_ptr();
//!
//! assert_eq!(18, fun(6, 7));
//! ```

extern crate libc;

/// Unwrapped definitions imported from the C library (via bindgen).
///
/// This module is generated and undocumented, but you can see the [C
/// libffi documentation](libffi.txt).
pub mod raw;

pub mod high;
pub mod middle;
pub mod low;
<|endoftext|>


<commit_before>//! A simple `io::stdout` and `io::stderr` writing `Logger` implementation from the
//! `log` crate, using the `ansi_term` crate for colors and configured at runtime,
//! or at compile time with simple function calls. Designed for simple CLIs.
//!
//! This library only comes with 3 public ways to initialize the global logger.
//! Ensure you call one of these exactly once early in your rust program as shown
//! in one of the examples below.
//!
//! ## Example
//! The standard example with `clap` as the arg parser.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate clap;
//! extern crate loggerv;
//!
//! use clap::{Arg, App};
//!
//! fn main() {
//!     let args = App::new("app")
//!                    .arg(Arg::with_name("v")
//!                             .short("v")
//!                             .multiple(true)
//!                             .help("Sets the level of verbosity"))
//!                    .get_matches();
//!
//!     loggerv::init_with_verbosity(args.occurrences_of("v")).unwrap();
//!
//!     error!("this is always printed");
//!     warn!("this too, and it's printed to stderr");
//!     info!("this is optional");  // for ./app -v or higher
//!     debug!("this is optional"); // for ./app -vv or higher
//!     trace!("this is optional"); // for ./app -vvv
//! }
//! ```
//!
//! But obviously use whatever argument parsing methods you prefer.
//!
//! ## Example
//! For a compile time switch, all you really need is `log` (for the macros)
//! and `loggerv` for how to print what's being sent to the macros.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! use log::LogLevel;
//!
//! fn main() {
//!     loggerv::init_with_level(LogLevel::Info).unwrap();
//!     debug!("this is a debug {}", "message");
//!     error!("this is printed by default");
//! }
//! ```
//!
//! # Example
//! If you don't really care at all you could just use the plain `init_quiet` function
//! to only show warnings and errors:
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! fn main() {
//!     loggerv::init_quiet().unwrap();
//!     info!("hidden");
//!     error!("this is printed by default");
//! }
//! ```
//!
//!
//! See the documentation for the log crate for more information about its API.
//!

#[cfg(test)]
#[macro_use]
extern crate log;

#[cfg(not(test))]
extern crate log;

extern crate atty;
extern crate ansi_term;

use log::{Log, LogLevel, LogMetadata, LogRecord, SetLoggerError};
use std::io::{self, Write};
use ansi_term::Colour;

pub const DEFAULT_SEPARATOR: &str = ": ";
pub const DEFAULT_LEVEL: LogLevel = LogLevel::Warn;

fn level_style(l: LogLevel) -> Colour {
    match l {
        LogLevel::Error => Colour::Fixed(9), // bright red
        LogLevel::Warn => Colour::Fixed(11), // bright yellow
        LogLevel::Info => Colour::Fixed(10), // bright green
        LogLevel::Debug => Colour::Fixed(7), // light grey
        LogLevel::Trace => Colour::Fixed(8), // grey
    }
}

pub struct Logger {
    level: LogLevel,
    colors: bool,
    separator: String,
}

impl Logger {
    /// Creates a new instance of the verbosity-based logger.
    ///
    /// The default level is WARN. Color is enabled if the parent application or library is running
    /// from a terminal, i.e. running a tty. The default separator is the ": " string.
    pub fn new() -> Logger {
        let colors = atty::is(atty::Stream::Stdout) && atty::is(atty::Stream::Stderr);
        Logger {
            level: DEFAULT_LEVEL,
            colors: colors,
            separator: String::from(DEFAULT_SEPARATOR),
        }
    }

    /// Sets the separator string.
    ///
    /// The separator is the string between the "tag" and the text that make up a log statement.
    /// The tag will be colorized if enabled, while the text will not. The default is `: `.
    pub fn separator(mut self, s: &str) -> Self {
        self.separator = String::from(s);
        self
    }

    /// Converts the verbosity to a log level.
    ///
    /// A verbosity of zero (0) is the default, which means ERROR and WARN log statements are
    /// printed to `stderr`. No other log statements are printed on any of the standard streams
    /// (`stdout` or `stderr`). As the verbosity is increased, the log level is increased and more
    /// log statements will be printed to `stdout`. A verbosity of 1 will print INFO log statements
    /// to `stdout` in addition to ERROR and WARN. A verbosity of 2 will print INFO and DEBUG log
    /// statements to `stdout`. A verbosity of 3 or higher will print INFO, DEBUG, and TRACE
    /// log statements to `stdout` with ERROR and WARN statements printed to `stderr`.
    pub fn verbosity(mut self, v: u64) -> Self {
        self.level = match v {
                0 => LogLevel::Warn,  // default
                1 => LogLevel::Info,  // -v
                2 => LogLevel::Debug, // -vv
                _ => LogLevel::Trace, // -vvv and above
        };
        self
    }

    /// Initializes the logger.
    ///
    /// This also consumes the logger and cannot no longer be modified after initialization.
    pub fn init(self) -> Result<(), SetLoggerError> {
        log::set_logger(|max_level| {
            max_level.set(self.level.to_log_level_filter());
            Box::new(self)
        })
    }
}

impl Log for Logger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.level
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let level = record.level();
            let tag = if self.colors {
                level_style(level).paint(format!("{} [{}]", level, record.location().module_path())).to_string()
            } else {
                format!("{} [{}]", level, record.location().module_path())
            };
            if level <= LogLevel::Warn {
                let _ = writeln!(&mut io::stderr(), "{}{}{}", tag, self.separator, record.args());
            } else {
                println!("{}{}{}", tag, self.separator, record.args());
            }
        }
    }
}

impl Default for Logger {
    fn default() -> Logger {
        Logger::new()
    }
}

/// Initialize loggerv with a maximal log level.
///
/// See the main loggerv documentation page for an example.
//pub fn init_with_level(level: LogLevel) -> Result<(), SetLoggerError> {
    //log::set_logger(|max_level| {
        //max_level.set(log_level.to_log_level_filter());
        //Box::new(Logger::new(log_level))
    //})
//}

/// Initialize loggerv with a verbosity level.
///
/// Intended to be used with an arg parser counting the amount of -v flags.
/// See the main loggerv documentation page for an example.
//pub fn init_with_verbosity(verbosity: u64) -> Result<(), SetLoggerError> {
    //init_with_level(match verbosity {
        //0 => LogLevel::Warn,  // default
        //1 => LogLevel::Info,  // -v
        //2 => LogLevel::Debug, // -vv
        //_ => LogLevel::Trace, // -vvv and above
    //})
//}

/// Initializes loggerv with only warnings and errors.
///
/// See the main loggerv documentation page for an example.
//pub fn init_quiet() -> Result<(), SetLoggerError> {
    //init_with_level(LogLevel::Warn)
//}

#[cfg(test)]
mod tests {
    use init_with_verbosity;

    #[test]
    fn init_and_macros() {
        let l = init_with_verbosity(3);
        assert_eq!(l.is_ok(), true);
        error!("error log");
        warn!("warn log");
        info!("info log");
        debug!("debug log");
        trace!("trace log");
    }
}
<commit_msg>Add ability to disable colors if desired<commit_after>//! A simple `io::stdout` and `io::stderr` writing `Logger` implementation from the
//! `log` crate, using the `ansi_term` crate for colors and configured at runtime,
//! or at compile time with simple function calls. Designed for simple CLIs.
//!
//! This library only comes with 3 public ways to initialize the global logger.
//! Ensure you call one of these exactly once early in your rust program as shown
//! in one of the examples below.
//!
//! ## Example
//! The standard example with `clap` as the arg parser.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate clap;
//! extern crate loggerv;
//!
//! use clap::{Arg, App};
//!
//! fn main() {
//!     let args = App::new("app")
//!                    .arg(Arg::with_name("v")
//!                             .short("v")
//!                             .multiple(true)
//!                             .help("Sets the level of verbosity"))
//!                    .get_matches();
//!
//!     loggerv::init_with_verbosity(args.occurrences_of("v")).unwrap();
//!
//!     error!("this is always printed");
//!     warn!("this too, and it's printed to stderr");
//!     info!("this is optional");  // for ./app -v or higher
//!     debug!("this is optional"); // for ./app -vv or higher
//!     trace!("this is optional"); // for ./app -vvv
//! }
//! ```
//!
//! But obviously use whatever argument parsing methods you prefer.
//!
//! ## Example
//! For a compile time switch, all you really need is `log` (for the macros)
//! and `loggerv` for how to print what's being sent to the macros.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! use log::LogLevel;
//!
//! fn main() {
//!     loggerv::init_with_level(LogLevel::Info).unwrap();
//!     debug!("this is a debug {}", "message");
//!     error!("this is printed by default");
//! }
//! ```
//!
//! # Example
//! If you don't really care at all you could just use the plain `init_quiet` function
//! to only show warnings and errors:
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! fn main() {
//!     loggerv::init_quiet().unwrap();
//!     info!("hidden");
//!     error!("this is printed by default");
//! }
//! ```
//!
//!
//! See the documentation for the log crate for more information about its API.
//!

#[cfg(test)]
#[macro_use]
extern crate log;

#[cfg(not(test))]
extern crate log;

extern crate atty;
extern crate ansi_term;

use log::{Log, LogLevel, LogMetadata, LogRecord, SetLoggerError};
use std::io::{self, Write};
use ansi_term::Colour;

pub const DEFAULT_SEPARATOR: &str = ": ";
pub const DEFAULT_LEVEL: LogLevel = LogLevel::Warn;

fn level_style(l: LogLevel) -> Colour {
    match l {
        LogLevel::Error => Colour::Fixed(9), // bright red
        LogLevel::Warn => Colour::Fixed(11), // bright yellow
        LogLevel::Info => Colour::Fixed(10), // bright green
        LogLevel::Debug => Colour::Fixed(7), // light grey
        LogLevel::Trace => Colour::Fixed(8), // grey
    }
}

pub struct Logger {
    level: LogLevel,
    colors: bool,
    separator: String,
}

impl Logger {
    /// Creates a new instance of the verbosity-based logger.
    ///
    /// The default level is WARN. Color is enabled if the parent application or library is running
    /// from a terminal, i.e. running a tty. The default separator is the ": " string.
    pub fn new() -> Logger {
        let colors = atty::is(atty::Stream::Stdout) && atty::is(atty::Stream::Stderr);
        Logger {
            level: DEFAULT_LEVEL,
            colors: colors,
            separator: String::from(DEFAULT_SEPARATOR),
        }
    }

    /// Sets the separator string.
    ///
    /// The separator is the string between the "tag" and the text that make up a log statement.
    /// The tag will be colorized if enabled, while the text will not. The default is `: `.
    pub fn separator(mut self, s: &str) -> Self {
        self.separator = String::from(s);
        self
    }

    /// Disables color output of all log statements on all streams regardless if the logger is used
    /// in a terminal.
    pub fn disable_color(mut self) -> Self {
        self.colors = false;
        self
    }

    /// Converts the verbosity to a log level.
    ///
    /// A verbosity of zero (0) is the default, which means ERROR and WARN log statements are
    /// printed to `stderr`. No other log statements are printed on any of the standard streams
    /// (`stdout` or `stderr`). As the verbosity is increased, the log level is increased and more
    /// log statements will be printed to `stdout`. A verbosity of 1 will print INFO log statements
    /// to `stdout` in addition to ERROR and WARN. A verbosity of 2 will print INFO and DEBUG log
    /// statements to `stdout`. A verbosity of 3 or higher will print INFO, DEBUG, and TRACE
    /// log statements to `stdout` with ERROR and WARN statements printed to `stderr`.
    pub fn verbosity(mut self, v: u64) -> Self {
        self.level = match v {
                0 => LogLevel::Warn,  // default
                1 => LogLevel::Info,  // -v
                2 => LogLevel::Debug, // -vv
                _ => LogLevel::Trace, // -vvv and above
        };
        self
    }

    /// Initializes the logger.
    ///
    /// This also consumes the logger and cannot no longer be modified after initialization.
    pub fn init(self) -> Result<(), SetLoggerError> {
        log::set_logger(|max_level| {
            max_level.set(self.level.to_log_level_filter());
            Box::new(self)
        })
    }
}

impl Log for Logger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.level
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let level = record.level();
            let tag = if self.colors {
                level_style(level).paint(format!("{} [{}]", level, record.location().module_path())).to_string()
            } else {
                format!("{} [{}]", level, record.location().module_path())
            };
            if level <= LogLevel::Warn {
                let _ = writeln!(&mut io::stderr(), "{}{}{}", tag, self.separator, record.args());
            } else {
                println!("{}{}{}", tag, self.separator, record.args());
            }
        }
    }
}

impl Default for Logger {
    fn default() -> Logger {
        Logger::new()
    }
}

/// Initialize loggerv with a maximal log level.
///
/// See the main loggerv documentation page for an example.
//pub fn init_with_level(level: LogLevel) -> Result<(), SetLoggerError> {
    //log::set_logger(|max_level| {
        //max_level.set(log_level.to_log_level_filter());
        //Box::new(Logger::new(log_level))
    //})
//}

/// Initialize loggerv with a verbosity level.
///
/// Intended to be used with an arg parser counting the amount of -v flags.
/// See the main loggerv documentation page for an example.
//pub fn init_with_verbosity(verbosity: u64) -> Result<(), SetLoggerError> {
    //init_with_level(match verbosity {
        //0 => LogLevel::Warn,  // default
        //1 => LogLevel::Info,  // -v
        //2 => LogLevel::Debug, // -vv
        //_ => LogLevel::Trace, // -vvv and above
    //})
//}

/// Initializes loggerv with only warnings and errors.
///
/// See the main loggerv documentation page for an example.
//pub fn init_quiet() -> Result<(), SetLoggerError> {
    //init_with_level(LogLevel::Warn)
//}

#[cfg(test)]
mod tests {
    use init_with_verbosity;

    #[test]
    fn init_and_macros() {
        let l = init_with_verbosity(3);
        assert_eq!(l.is_ok(), true);
        error!("error log");
        warn!("warn log");
        info!("info log");
        debug!("debug log");
        trace!("trace log");
    }
}
<|endoftext|>


<commit_before>#![crate_type = "lib"]
#![crate_name = "currency"]

use std::cmp::PartialEq;
use std::cmp::PartialOrd;
use std::cmp::Ordering;

use std::ops::Add;
use std::ops::Sub;
use std::ops::Mul;
use std::ops::Div;

use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result;

use std::marker::Copy;

/// Represents currency through an optional symbol and amount of coin.
///
/// Each 100 coins results in a banknote. (100 is formatted as 1.00)
/// The currency will be formatted as such:
///     Currency(Some('$'), 432) ==> "$4.32"
pub struct Currency(pub Option<char>, pub i64);

impl Currency {
    /// Creates a blank Currency as Currency(None, 0)
    ///
    /// # Examples
    ///
    /// ```
    /// let mut c = Currency::new();
    /// ```
    #[inline]
    #[allow(dead_code)]
    pub fn new() -> Currency {
        Currency(None, 0)
    }

    /// Parses a string literal and turns it into a currency.
    ///
    /// Parsing ignores spaces and commas, only taking note of the digits and
    /// leading sign.
    ///
    /// # Examples
    /// ```
    /// Currency::from_string("$4.32") -> Currency(Some('$'), 432)
    /// Currency::from_string("424.44") -> Currency(None, 42444)
    /// Currency::from_string("@12") -> Currency(Some('@'), 1200)
    /// ```
    ///
    /// # Failures
    /// Fails to take note of the floating points position.
    /// ```
    /// Currency::from_string("$42.012) -> Currency(Some('$'), 42012)
    /// Currency::from_string("42.") -> Currency(None, 42)
    /// ```
    ///
    /// # Panics
    /// Panics if a number fails to be parsed; this only occurs if the string
    /// argument has no numbers in it.
    ///
    /// # Safety
    /// If a decimal point is intended to be marked, always use '.'
    /// A "European style" ',' will be ignored.
    /// String::from_string("€4.32") instead of String::from_string("€4,32")
    #[allow(dead_code)]
    pub fn from_string(s: &str) -> Currency {
        // Try to find the sign
        let mut sign = None;
        let mut unicode: u8 = s.chars().next().unwrap() as u8;
        // If the first character is not a letter or a decimal point
        if unicode != 0x2E && (unicode < 0x30 || unicode > 0x39) {
            sign = Some(unicode as char);
        }

        // Find the numbers
        let mut should_multiply = true; // May later change if '.' is specified
        let mut coin_str = String::new();
        for c in s.chars() {
            unicode = c as u8;
            // Only pay attention to numbers
            if unicode >= 0x30 && unicode <= 0x39 {
                coin_str = coin_str + &c.to_string();
            }
            // If coins are explicitly specified (via a '.'), then we shouldn't
            // multiply at the end
            if unicode == 0x2E {
                should_multiply = false;
            }
        }
        // Parse out the resulting number
        let mut coin: i64 = coin_str.parse()
            .ok()
            .expect("Failed to convert string to currency");

        if should_multiply {
            coin *= 100;
        }

        // Return result
        Currency(sign, coin)
    }
}

/// Overloads the '==' operator for Currency objects.
///
/// # Panics
/// Panics if the two comparators are different types of currency, as denoted by
/// the Currency's symbol.
impl PartialEq<Currency> for Currency {
    #[inline]
    fn eq(&self, rhs: &Currency) -> bool {
        self.0 == rhs.0 && self.1 == rhs.1
    }

    #[inline]
    fn ne(&self, rhs: &Currency) -> bool {
        self.0 != rhs.0 || self.1 != rhs.1
    }
}

/// Overloads the order operators for Currency objects.
///
/// These operators include '<', '<=', '>', and '>='.
///
/// # Panics
/// Panics if the two comparators are different types of currency, as denoted by
/// the Currency's symbol.
impl PartialOrd<Currency> for Currency {
    #[inline]
    fn partial_cmp(&self, rhs: &Currency) -> Option<Ordering> {
        if self.0 == rhs.0 {
            if self < rhs { return Some(Ordering::Less) }
            if self == rhs { return Some(Ordering::Equal) }
            if self > rhs { return Some(Ordering::Greater) }
        }
        None
    }

    #[inline]
    fn lt(&self, rhs: &Currency) -> bool {
        if self.0 == rhs.0 {
            self.1 < rhs.1
        }
        else {
            panic!("Cannot compare two different types of currency.");
        }
    }
    #[inline]
    fn le(&self, rhs: &Currency) -> bool {
        self < rhs || self == rhs
    }
    #[inline]
    fn gt(&self, rhs: &Currency) -> bool {
        if self.0 == rhs.0 {
            self.1 > rhs.1
        }
        else {
            panic!("Cannot compare two different types of currency.");
        }
    }
    #[inline]
    fn ge(&self, rhs: &Currency) -> bool {
        self > rhs || self == rhs
    }
}

/// Overloads the '+' operator for Currency objects.
///
/// # Panics
/// Panics if the two addends are different types of currency, as denoted by the
/// Currency's symbol.
impl Add for Currency {
    type Output = Currency;

    #[inline]
    fn add(self, rhs: Currency) -> Currency {
        if self.0 == rhs.0 {
            Currency(self.0, self.1 + rhs.1)
        } else {
            panic!("Cannot add two different types of currency!");
        }
    }
}

/// Overloads the '-' operator for Currency objects.
///
/// # Panics
/// Panics if the minuend and subtrahend are two different types of currency,
/// as denoted by the Currency's symbol.
impl Sub for Currency {
    type Output = Currency;

    #[inline]
    fn sub(self, rhs: Currency) -> Currency {
        if self.0 == rhs.0 {
            Currency(self.0, self.1 - rhs.1)
        } else {
            panic!("Cannot subtract two different types of currency!");
        }
    }
}

/// Overloads the '*' operator for Currency objects.
///
/// Allows a Currency to be multiplied by an i64.
impl Mul<i64> for Currency {
    type Output = Currency;

    #[inline]
    fn mul(self, rhs: i64) -> Currency {
        Currency(self.0, self.1 * rhs)
    }
}

/// Overloads the '*' operator for i64.
///
/// Allows an i64 to be multiplied by a Currency.
/// Completes the commutative property for i64 multiplied by Currency.
impl Mul<Currency> for i64 {
    type Output = Currency;

    #[inline]
    fn mul(self, rhs: Currency) -> Currency {
        Currency(rhs.0, rhs.1 * self)
    }
}

/// Overloads the '/' operator for Currency objects.
///
/// Allows a Currency to be divided by an i64.
impl Div<i64> for Currency {
    type Output = Currency;

    #[inline]
    fn div(self, rhs: i64) -> Currency {
        Currency(self.0, self.1 / rhs)
    }
}

/// Allows Currencies to be displayed as Strings
///
/// # Examples
/// ```
/// Currency(Some('$'), 1210).to_string() == "$12.10"
/// Currency(None, 1210.to_string() == "12.10"
/// ```
impl Display for Currency {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> Result {
        let decimal = (self.1 / 100).to_string()
            + &('.').to_string()
            + &(self.1 % 100).to_string();
        match self.0 {
            Some(c) => write!(f, "{}{}", c, decimal),
            None    => write!(f, "{}", decimal),
        }
    }
}

/// Allows Currencies to be copied, rather than using move semantics.
impl Copy for Currency { }
impl Clone for Currency {
    #[inline]
    fn clone(&self) -> Currency { *self }
}

#[test]
fn eq_works() {
    let a = Currency(Some('$'), 1210);
    let b = Currency(Some('$'), 1210);
    let c = Currency(Some('$'), 1251);

    assert!(a == b);
    assert!(b == b);
    assert!(b == a);
    assert!(a != c);
}

#[test]
fn ord_works() {
    let a = Currency(Some('$'), 1210);
    let b = Currency(Some('$'), 1211);
    let c = Currency(Some('$'), 1311);
    let d = Currency(Some('$'), 1210);

    assert_eq!(a.partial_cmp(&b), Some(Ordering::Less));
    assert_eq!(a.partial_cmp(&c), Some(Ordering::Less));
    assert_eq!(a.partial_cmp(&d), Some(Ordering::Equal));
    assert_eq!(c.partial_cmp(&a), Some(Ordering::Greater));

    assert!(a < b);
    assert!(a < c);
    assert!(a <= a);
    assert!(a <= c);
    assert!(b > a);
    assert!(c > a);
    assert!(a >= a);
    assert!(c >= a);
}

#[test]
fn arithmetic_works() {
    let x = Currency(Some('$'), 1206);
    let y = Currency(Some('$'), 1143);

    assert!(x + y == Currency(Some('$'), 2349)
         && y + x == Currency(Some('$'), 2349));
    assert!(x - y == Currency(Some('$'), 63));
    assert!(y - x == Currency(Some('$'), -63));
    assert!(x * 2 == Currency(Some('$'), 2412)
         && 2 * x == Currency(Some('$'), 2412));
    assert!(x / 2 == Currency(Some('$'), 603));
}

#[test]
fn parse_works() {
    let a = Currency(Some('$'), 1210);
    let b = Currency::from_string("$12.10");
    assert!(a == b);

    let c = Currency(Some('$'), 1200);
    let d = Currency::from_string("$12");
    assert!(c == d);
}

#[test]
fn display_works() {
    assert!(Currency(Some('$'), 1210).to_string() == "$12.10");
    assert!(Currency(None, 1210).to_string() == "12.10");
}
<commit_msg>Update lib.rs<commit_after>#![crate_type = "lib"]
#![crate_name = "currency"]

use std::cmp::PartialEq;
use std::cmp::PartialOrd;
use std::cmp::Ordering;

use std::ops::Add;
use std::ops::Sub;
use std::ops::Mul;
use std::ops::Div;

use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result;

use std::marker::Copy;

/// Represents currency through an optional symbol and amount of coin.
///
/// Each 100 coins results in a banknote. (100 is formatted as 1.00)
/// The currency will be formatted as such:
///     Currency(Some('$'), 432) ==> "$4.32"
#[derive(Debug)]
pub struct Currency(pub Option<char>, pub i64);

impl Currency {
    /// Creates a blank Currency as Currency(None, 0)
    ///
    /// # Examples
    ///
    /// ```
    /// let mut c = Currency::new();
    /// ```
    #[inline]
    #[allow(dead_code)]
    pub fn new() -> Currency {
        Currency(None, 0)
    }

    /// Parses a string literal and turns it into a currency.
    ///
    /// Parsing ignores spaces and commas, only taking note of the digits and
    /// leading sign.
    ///
    /// # Examples
    /// ```
    /// Currency::from_string("$4.32") -> Currency(Some('$'), 432)
    /// Currency::from_string("424.44") -> Currency(None, 42444)
    /// Currency::from_string("@12") -> Currency(Some('@'), 1200)
    /// ```
    ///
    /// # Failures
    /// Fails to take note of the floating points position.
    /// ```
    /// Currency::from_string("$42.012) -> Currency(Some('$'), 42012)
    /// Currency::from_string("42.") -> Currency(None, 42)
    /// ```
    ///
    /// # Panics
    /// Panics if a number fails to be parsed; this only occurs if the string
    /// argument has no numbers in it.
    ///
    /// # Safety
    /// If a decimal point is intended to be marked, always use '.'
    /// A "European style" ',' will be ignored.
    /// String::from_string("€4.32") instead of String::from_string("€4,32")
    #[allow(dead_code)]
    pub fn from_string(s: &str) -> Currency {
        // Try to find the sign
        let mut sign = None;
        let mut unicode: u8 = s.chars().next().unwrap() as u8;
        // If the first character is not a letter or a decimal point
        if unicode != 0x2E && (unicode < 0x30 || unicode > 0x39) {
            sign = Some(unicode as char);
        }

        // Find the numbers
        let mut should_multiply = true; // May later change if '.' is specified
        let mut coin_str = String::new();
        for c in s.chars() {
            unicode = c as u8;
            // Only pay attention to numbers
            if unicode >= 0x30 && unicode <= 0x39 {
                coin_str = coin_str + &c.to_string();
            }
            // If coins are explicitly specified (via a '.'), then we shouldn't
            // multiply at the end
            if unicode == 0x2E {
                should_multiply = false;
            }
        }
        // Parse out the resulting number
        let mut coin: i64 = coin_str.parse()
            .ok()
            .expect("Failed to convert string to currency");

        if should_multiply {
            coin *= 100;
        }

        // Return result
        Currency(sign, coin)
    }
}

/// Overloads the '==' operator for Currency objects.
///
/// # Panics
/// Panics if the two comparators are different types of currency, as denoted by
/// the Currency's symbol.
impl PartialEq<Currency> for Currency {
    #[inline]
    fn eq(&self, rhs: &Currency) -> bool {
        self.0 == rhs.0 && self.1 == rhs.1
    }

    #[inline]
    fn ne(&self, rhs: &Currency) -> bool {
        self.0 != rhs.0 || self.1 != rhs.1
    }
}

/// Overloads the order operators for Currency objects.
///
/// These operators include '<', '<=', '>', and '>='.
///
/// # Panics
/// Panics if the two comparators are different types of currency, as denoted by
/// the Currency's symbol.
impl PartialOrd<Currency> for Currency {
    #[inline]
    fn partial_cmp(&self, rhs: &Currency) -> Option<Ordering> {
        if self.0 == rhs.0 {
            if self < rhs { return Some(Ordering::Less) }
            if self == rhs { return Some(Ordering::Equal) }
            if self > rhs { return Some(Ordering::Greater) }
        }
        None
    }

    #[inline]
    fn lt(&self, rhs: &Currency) -> bool {
        if self.0 == rhs.0 {
            self.1 < rhs.1
        }
        else {
            panic!("Cannot compare two different types of currency.");
        }
    }
    #[inline]
    fn le(&self, rhs: &Currency) -> bool {
        self < rhs || self == rhs
    }
    #[inline]
    fn gt(&self, rhs: &Currency) -> bool {
        if self.0 == rhs.0 {
            self.1 > rhs.1
        }
        else {
            panic!("Cannot compare two different types of currency.");
        }
    }
    #[inline]
    fn ge(&self, rhs: &Currency) -> bool {
        self > rhs || self == rhs
    }
}

/// Overloads the '+' operator for Currency objects.
///
/// # Panics
/// Panics if the two addends are different types of currency, as denoted by the
/// Currency's symbol.
impl Add for Currency {
    type Output = Currency;

    #[inline]
    fn add(self, rhs: Currency) -> Currency {
        if self.0 == rhs.0 {
            Currency(self.0, self.1 + rhs.1)
        } else {
            panic!("Cannot add two different types of currency!");
        }
    }
}

/// Overloads the '-' operator for Currency objects.
///
/// # Panics
/// Panics if the minuend and subtrahend are two different types of currency,
/// as denoted by the Currency's symbol.
impl Sub for Currency {
    type Output = Currency;

    #[inline]
    fn sub(self, rhs: Currency) -> Currency {
        if self.0 == rhs.0 {
            Currency(self.0, self.1 - rhs.1)
        } else {
            panic!("Cannot subtract two different types of currency!");
        }
    }
}

/// Overloads the '*' operator for Currency objects.
///
/// Allows a Currency to be multiplied by an i64.
impl Mul<i64> for Currency {
    type Output = Currency;

    #[inline]
    fn mul(self, rhs: i64) -> Currency {
        Currency(self.0, self.1 * rhs)
    }
}

/// Overloads the '*' operator for i64.
///
/// Allows an i64 to be multiplied by a Currency.
/// Completes the commutative property for i64 multiplied by Currency.
impl Mul<Currency> for i64 {
    type Output = Currency;

    #[inline]
    fn mul(self, rhs: Currency) -> Currency {
        Currency(rhs.0, rhs.1 * self)
    }
}

/// Overloads the '/' operator for Currency objects.
///
/// Allows a Currency to be divided by an i64.
impl Div<i64> for Currency {
    type Output = Currency;

    #[inline]
    fn div(self, rhs: i64) -> Currency {
        Currency(self.0, self.1 / rhs)
    }
}

/// Allows Currencies to be displayed as Strings
///
/// # Examples
/// ```
/// Currency(Some('$'), 1210).to_string() == "$12.10"
/// Currency(None, 1210.to_string() == "12.10"
/// ```
impl Display for Currency {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> Result {
        let decimal = (self.1 / 100).to_string()
            + &('.').to_string()
            + &(self.1 % 100).to_string();
        match self.0 {
            Some(c) => write!(f, "{}{}", c, decimal),
            None    => write!(f, "{}", decimal),
        }
    }
}

/// Allows Currencies to be copied, rather than using move semantics.
impl Copy for Currency { }
impl Clone for Currency {
    #[inline]
    fn clone(&self) -> Currency { *self }
}

#[test]
fn eq_works() {
    let a = Currency(Some('$'), 1210);
    let b = Currency(Some('$'), 1210);
    let c = Currency(Some('$'), 1251);

    assert!(a == b);
    assert!(b == b);
    assert!(b == a);
    assert!(a != c);
}

#[test]
fn ord_works() {
    let a = Currency(Some('$'), 1210);
    let b = Currency(Some('$'), 1211);
    let c = Currency(Some('$'), 1311);
    let d = Currency(Some('$'), 1210);

    assert_eq!(a.partial_cmp(&b), Some(Ordering::Less));
    assert_eq!(a.partial_cmp(&c), Some(Ordering::Less));
    assert_eq!(a.partial_cmp(&d), Some(Ordering::Equal));
    assert_eq!(c.partial_cmp(&a), Some(Ordering::Greater));

    assert!(a < b);
    assert!(a < c);
    assert!(a <= a);
    assert!(a <= c);
    assert!(b > a);
    assert!(c > a);
    assert!(a >= a);
    assert!(c >= a);
}

#[test]
fn arithmetic_works() {
    let x = Currency(Some('$'), 1206);
    let y = Currency(Some('$'), 1143);

    assert!(x + y == Currency(Some('$'), 2349)
         && y + x == Currency(Some('$'), 2349));
    assert!(x - y == Currency(Some('$'), 63));
    assert!(y - x == Currency(Some('$'), -63));
    assert!(x * 2 == Currency(Some('$'), 2412)
         && 2 * x == Currency(Some('$'), 2412));
    assert!(x / 2 == Currency(Some('$'), 603));
}

#[test]
fn parse_works() {
    let a = Currency(Some('$'), 1210);
    let b = Currency::from_string("$12.10");
    assert!(a == b);

    let c = Currency(Some('$'), 1200);
    let d = Currency::from_string("$12");
    assert!(c == d);
}

#[test]
fn display_works() {
    assert!(Currency(Some('$'), 1210).to_string() == "$12.10");
    assert!(Currency(None, 1210).to_string() == "12.10");
}
<|endoftext|>


<commit_before>//! This is a crate for coloring and formatting terminal output. Simple
//! example:
//!
//! ```
//! extern crate term_painter;
//!
//! use term_painter::ToStyle;
//! use term_painter::Color::*;
//! use term_painter::Attr::*;
//!
//! fn main() {
//!     println!("{} or {} or {}",
//!         Red.paint("Red"),
//!         Bold.paint("Bold"),
//!         Red.bold().paint("Both!"));
//! }
//! ```
//!
//! How to use it
//! -------------
//! Formatting works in two steps mainly:
//!
//! 1. Creating a style
//! 2. Use this style to "paint" something and reviece a `Painted` object
//!
//! 1. Creating a style
//! -------------------
//! To create a style a startpoint is needed: This can either be a startpoint
//! with an attached modifier (like `Red`: modifies the fg-color) or the
//! `Plain` startpoint, which does not modify anything.
//! After that the startpoint can be modified by modifiers like `bold()` or
//! `fg()`.
//!
//! ```
//! extern crate term_painter;
//!
//! use term_painter::ToStyle;
//! use term_painter::Color::*;
//! use term_painter::Attr::*;
//!
//! fn main() {
//!     let x = 5;
//!
//!     // These two are equivalent
//!     println!("{}", x);
//!     println!("{}", Plain.paint(&x));
//!
//!     // These two are equivalent, too
//!     println!("{}", Red.paint(&x));
//!     println!("{}", Plain.fg(Red).paint(&x));
//! }
//! ```
//! You can chain as many modifier as you want. Every modifier overrides
//! preceding modifier:
//!
//! `println("{}", Plain.fg(Red).fg(Blue).paint("Apple")); // blue, not red`
//!
//! 2. Use the style
//! ----------------
//! After building the style, you can call `paint` to use it on some object.
//! `paint` will return the wrapper object `Painted` that holds your object and
//! the specified style. `Painted` implements `Display` and/or `Debug` if the
//! type of the given Object, `T`, does. So the `Painted` object can be printed
//! via `println!` or similar macros. When it gets printed, it will apply the
//! given style before printing the object of type `T` and will reset the style
//! after printing.
//!
//! `Note`: `paint` will consume the passed object. This is no problem when
//! passing constant literals (like `paint("cheesecake")`) or types that are
//! `Copy`. Otherwise it could be confusing because just printing should not
//! consume a variable. To prevent consuming, just pass a borrow to the object
//! (with `&`). Example:
//!
//! ```
//! extern crate term_painter;
//!
//! use term_painter::ToStyle;
//! use term_painter::Color::*;
//! use term_painter::Attr::*;
//!
//! fn main() {
//!     let non_copy = "cake".to_string();  // String is *not* Copy
//!     let copy = 27;  // usize/isize *is* Copy
//!
//!     println!("{}", Plain.paint(&non_copy));
//!     println!("{}", Plain.paint(&copy));
//!     // non_copy is still usable here...
//!     // copy is still usable here...
//!
//!     println!("{}", Plain.paint(non_copy));
//!     println!("{}", Plain.paint(copy));
//!     // non_copy was moved into paint, so it not usable anymore...
//!     // copy is still usable here...
//! }
//! ```
//!

extern crate term;

use std::default::Default;
use std::fmt::{Display, Debug, Error, Formatter};
use std::cell::RefCell;

/// Everything that can be seen as part of a style. This is the core of this
/// crate. All functions ("style modifier") consume self and return a modified
/// version of the style.
pub trait ToStyle : Clone {
    fn to_style(self) -> Style;

    /// Sets the foreground (text) color.
    fn fg(self, c: Color) -> Style {
        let mut s = self.to_style();
        s.fg = c;
        s
    }

    /// Sets the background color.
    fn bg(self, c: Color) -> Style {
        let mut s = self.to_style();
        s.bg = c;
        s
    }

    /// Makes the text bold.
    fn bold(self) -> Style {
        let mut s = self.to_style();
        s.bold = true;
        s
    }

    /// Dim mode.
    fn dim(self) -> Style {
        let mut s = self.to_style();
        s.dim = true;
        s
    }

    /// Underlines the text.
    fn underline(self) -> Style {
        let mut s = self.to_style();
        s.underline = true;
        s
    }

    /// Underlines the text.
    fn blink(self) -> Style {
        let mut s = self.to_style();
        s.blink = true;
        s
    }

    /// Underlines the text.
    fn reverse(self) -> Style {
        let mut s = self.to_style();
        s.reverse = true;
        s
    }

    /// Secure mode.
    fn secure(self) -> Style {
        let mut s = self.to_style();
        s.secure = true;
        s
    }

    /// Wraps the style specified in `self` and something of arbitrary type
    /// into a `Painted`. When `Painted` is printed it will print the arbitrary
    /// something with the given style. `T` needs to implement
    /// `std::fmt::Display` or `std::fmt::Debug`.
    fn paint<T>(&self, obj: T) -> Painted<T> {
        Painted { style: self.clone().to_style() , obj: obj }
    }
}

/// Lists all possible Colors. It implements `ToStyle` so it's possible to call
/// `ToStyle`'s methods direclty on a `Color` variant like:
///
/// `println!("{}", Color::Red.bold().paint("Red and bold"));`
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Color {
    Normal,
    Black,
    Red,
    Green,
    Yellow,
    Blue,
    Magenta,
    Cyan,
    White,
    BrightBlack,
    BrightRed,
    BrightGreen,
    BrightYellow,
    BrightBlue,
    BrightMagenta,
    BrightCyan,
    BrightWhite,
}

impl Color {
    /// Returns the associated constant from `term::color::Color`.
    fn term_constant(&self) -> Option<term::color::Color> {
        match *self {
            Color::Normal  => None,
            Color::Black   => Some(term::color::BLACK),
            Color::Red     => Some(term::color::RED),
            Color::Green   => Some(term::color::GREEN),
            Color::Yellow  => Some(term::color::YELLOW),
            Color::Blue    => Some(term::color::BLUE),
            Color::Magenta => Some(term::color::MAGENTA),
            Color::Cyan    => Some(term::color::CYAN),
            Color::White   => Some(term::color::WHITE),
            Color::BrightBlack   => Some(term::color::BRIGHT_BLACK),
            Color::BrightRed     => Some(term::color::BRIGHT_RED),
            Color::BrightGreen   => Some(term::color::BRIGHT_GREEN),
            Color::BrightYellow  => Some(term::color::BRIGHT_YELLOW),
            Color::BrightBlue    => Some(term::color::BRIGHT_BLUE),
            Color::BrightMagenta => Some(term::color::BRIGHT_MAGENTA),
            Color::BrightCyan    => Some(term::color::BRIGHT_CYAN),
            Color::BrightWhite   => Some(term::color::BRIGHT_WHITE),
        }
    }
}

impl Default for Color {
    fn default() -> Self {
        Color::Normal
    }
}

impl ToStyle for Color {
    /// Returns a Style with default values and the `self` color as foreground
    /// color.
    fn to_style(self) -> Style {
        let mut s = Style::default();
        s.fg = self;
        s
    }
}

/// Lists possible attributes. It implements `ToStyle` so it's possible to call
/// `ToStyle`'s methods directly on a `Attr` variant like:
///
/// `println!("{}", Attr::Bold.fg(Color::Red).paint("Red and bold"));`
///
/// For more information about enum variants, see `term::Attr` Documentation.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Attr {
    /// Just default style
    Plain,
    Bold,
    Dim,
    Underline,
    Blink,
    Reverse,
    Secure,
}

impl ToStyle for Attr {
    /// Returns a Style with default values and the `self` attribute enabled.
    fn to_style(self) -> Style {
        let mut s = Style::default();
        match self {
            Attr::Plain => {},
            Attr::Bold => s.bold = true,
            Attr::Dim => s.dim = true,
            Attr::Underline => s.underline = true,
            Attr::Blink => s.blink = true,
            Attr::Reverse => s.reverse = true,
            Attr::Secure => s.secure = true,
        }
        s
    }
}

/// Saves all properties of a style. Implements `ToStyle`, so you can call
/// style modifiers on it.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Style {
    pub fg: Color,
    pub bg: Color,
    pub bold: bool,
    pub dim: bool,
    pub underline: bool,
    pub blink: bool,
    pub reverse: bool,
    pub secure: bool,
}

impl Default for Style {
    fn default() -> Self {
        Style {
            fg: Color::default(),
            bg: Color::default(),
            bold: false,
            dim: false,
            underline: false,
            blink: false,
            reverse: false,
            secure: false,
        }
    }
}

// static INIT_TERM: Once = ONCE_INIT;
thread_local!(static TERM: RefCell<Option<Box<term::StdoutTerminal>>>
    = RefCell::new(term::stdout()));

impl Style {
    fn prepare(&self) -> Result<(), Error> {
        macro_rules! try_term {
            ($e:expr) => ({
                match $e {
                    Ok(true) => {},
                    _ => { return Err(Error); },
                }
            })
        }

        TERM.with(|term_opt| {
            let mut tmut = term_opt.borrow_mut();
            let mut t = match tmut.as_mut() {
                None => return Err(Error),
                Some(t) => t,
            };

            match self.fg.term_constant() {
                None => {},
                Some(c) => { try_term!(t.fg(c)); },
            }
            match self.bg.term_constant() {
                None => {},
                Some(c) => { try_term!(t.bg(c)); },
            }
            if self.bold { try_term!(t.attr(term::Attr::Bold)) }
            if self.underline { try_term!(t.attr(term::Attr::Underline(true))) }
            if self.blink { try_term!(t.attr(term::Attr::Blink)) }
            if self.reverse { try_term!(t.attr(term::Attr::Reverse)) }
            if self.secure { try_term!(t.attr(term::Attr::Secure)) }

            Ok(())
        })
    }

    fn cleanup(&self) -> Result<(), Error> {
        TERM.with(|term_opt| {
            let mut tmut = term_opt.borrow_mut();
            match tmut.as_mut() {
                None => Err(Error),
                Some(t) =>
                    match t.reset() {
                        Ok(true) => Ok(()),
                        _ => Err(Error),
                    },
            }
        })
    }
}

impl ToStyle for Style {
    /// Dummy implementation that just returns `self`.
    fn to_style(self) -> Style {
        self
    }
}

/// Saves a style and a reference to something that will be printed in that
/// style. That something of type `T` needs to implement either
/// `std::fmt::Debug` or `std::fmt::Display`
pub struct Painted<T> {
    style: Style,
    obj: T,
}

impl<T: Display> Display for Painted<T> {
    /// Implementation for `T: Display` -> to print with `{}`.
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        try!(self.style.prepare());
        try!(write!(f, "{}", self.obj));
        self.style.cleanup()
    }
}

impl<T: Debug> Debug for Painted<T> {
    /// Implementation for `T: Debug` -> to print with `{:?}`.
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        try!(self.style.prepare());
        try!(write!(f, "{:?}", self.obj));
        self.style.cleanup()
    }
}

// ----- Tests ------
#[cfg(test)]
mod test {
    use super::Color::*;
    use super::Attr::*;
    use super::ToStyle;

    #[test]
    fn modifier_order() {
        // The order of modifiers shouldn't play a role.
        assert_eq!(Plain.bold().fg(Red), Plain.fg(Red).bold());
        assert_eq!(Plain.bold().bg(Red), Plain.bg(Red).bold());
        assert_eq!(Plain.underline().fg(Red), Plain.fg(Red).underline());

        // The startpoints should have the same effect as the modifier.
        assert_eq!(Red.to_style(), Plain.fg(Red));
        assert_eq!(Bold.to_style(), Plain.bold());
    }

    #[test]
    fn modifier_override() {
        // The latter modifier should override the one before
        assert_eq!(Plain.fg(Red).fg(Blue), Plain.fg(Blue));
        assert_eq!(Plain.fg(Red).fg(Blue), Blue.to_style());
        assert_eq!(Red.fg(Blue), Plain.fg(Blue));
        assert_eq!(Red.fg(Blue), Blue.to_style());
    }
}
<commit_msg>Add information to documentation<commit_after>//! This is a crate for coloring and formatting terminal output. Simple
//! example:
//!
//! ```
//! extern crate term_painter;
//!
//! use term_painter::ToStyle;
//! use term_painter::Color::*;
//! use term_painter::Attr::*;
//!
//! fn main() {
//!     println!("{} or {} or {}",
//!         Red.paint("Red"),
//!         Bold.paint("Bold"),
//!         Red.bold().paint("Both!"));
//! }
//! ```
//!
//! This crate uses `rust-lang/term` to do the formatting. You can of course
//! use `term` directly, but it's kinda clumsy. Hence this library.
//!
//!
//! How to use it
//! -------------
//! Formatting works in two steps mainly:
//!
//! 1. Creating a style
//! 2. Use this style to "paint" something and reviece a `Painted` object
//!
//! 1. Creating a style
//! -------------------
//! To create a style a startpoint is needed: This can either be a startpoint
//! with an attached modifier (like `Red`: modifies the fg-color) or the
//! `Plain` startpoint, which does not modify anything.
//! After that the startpoint can be modified by modifiers like `bold()` or
//! `fg()`.
//!
//! ```
//! extern crate term_painter;
//!
//! use term_painter::ToStyle;
//! use term_painter::Color::*;
//! use term_painter::Attr::*;
//!
//! fn main() {
//!     let x = 5;
//!
//!     // These two are equivalent
//!     println!("{}", x);
//!     println!("{}", Plain.paint(&x));
//!
//!     // These two are equivalent, too
//!     println!("{}", Red.paint(&x));
//!     println!("{}", Plain.fg(Red).paint(&x));
//! }
//! ```
//! You can chain as many modifier as you want. Every modifier overrides
//! preceding modifier:
//!
//! `println("{}", Plain.fg(Red).fg(Blue).paint("Apple")); // blue, not red`
//!
//! 2. Use the style
//! ----------------
//! After building the style, you can call `paint` to use it on some object.
//! `paint` will return the wrapper object `Painted` that holds your object and
//! the specified style. `Painted` implements `Display` and/or `Debug` if the
//! type of the given Object, `T`, does. So the `Painted` object can be printed
//! via `println!` or similar macros. When it gets printed, it will apply the
//! given style before printing the object of type `T` and will reset the style
//! after printing.
//!
//! `Note`: `paint` will consume the passed object. This is no problem when
//! passing constant literals (like `paint("cheesecake")`) or types that are
//! `Copy`. Otherwise it could be confusing because just printing should not
//! consume a variable. To prevent consuming, just pass a borrow to the object
//! (with `&`). Example:
//!
//! ```
//! extern crate term_painter;
//!
//! use term_painter::ToStyle;
//! use term_painter::Color::*;
//! use term_painter::Attr::*;
//!
//! fn main() {
//!     let non_copy = "cake".to_string();  // String is *not* Copy
//!     let copy = 27;  // usize/isize *is* Copy
//!
//!     println!("{}", Plain.paint(&non_copy));
//!     println!("{}", Plain.paint(&copy));
//!     // non_copy is still usable here...
//!     // copy is still usable here...
//!
//!     println!("{}", Plain.paint(non_copy));
//!     println!("{}", Plain.paint(copy));
//!     // non_copy was moved into paint, so it not usable anymore...
//!     // copy is still usable here...
//! }
//! ```
//!
//! Some Notes
//! ----------
//! If you don't want to pollute your namespace with `Color` and `Attr` names,
//! you can use a more qualified name (`Color::Red.paint(..)`) and remove these
//! `use` statements: `use term_painter::Color::*;` and
//! `use term_painter::Attr::*;`.
//!
//! And please note that global state is changed when printing a `Painted`
//! object. This means that some state is set before and reset after printing.
//! This means that, for example, using this library in `format!` or `write!`
//! won't work. The color formatting is not stored in the resulting string.
//! Although Unix terminals do modify color and formatting by printing special
//! control characters, Windows and others do not. And since this library uses
//! the plattform independent library `term`. This was a design choice.
//!
//!
//!
//!

extern crate term;

use std::default::Default;
use std::fmt::{Display, Debug, Error, Formatter};
use std::cell::RefCell;

/// Everything that can be seen as part of a style. This is the core of this
/// crate. All functions ("style modifier") consume self and return a modified
/// version of the style.
pub trait ToStyle : Clone {
    fn to_style(self) -> Style;

    /// Sets the foreground (text) color.
    fn fg(self, c: Color) -> Style {
        let mut s = self.to_style();
        s.fg = c;
        s
    }

    /// Sets the background color.
    fn bg(self, c: Color) -> Style {
        let mut s = self.to_style();
        s.bg = c;
        s
    }

    /// Makes the text bold.
    fn bold(self) -> Style {
        let mut s = self.to_style();
        s.bold = true;
        s
    }

    /// Dim mode.
    fn dim(self) -> Style {
        let mut s = self.to_style();
        s.dim = true;
        s
    }

    /// Underlines the text.
    fn underline(self) -> Style {
        let mut s = self.to_style();
        s.underline = true;
        s
    }

    /// Underlines the text.
    fn blink(self) -> Style {
        let mut s = self.to_style();
        s.blink = true;
        s
    }

    /// Underlines the text.
    fn reverse(self) -> Style {
        let mut s = self.to_style();
        s.reverse = true;
        s
    }

    /// Secure mode.
    fn secure(self) -> Style {
        let mut s = self.to_style();
        s.secure = true;
        s
    }

    /// Wraps the style specified in `self` and something of arbitrary type
    /// into a `Painted`. When `Painted` is printed it will print the arbitrary
    /// something with the given style. `T` needs to implement
    /// `std::fmt::Display` or `std::fmt::Debug`.
    fn paint<T>(&self, obj: T) -> Painted<T> {
        Painted { style: self.clone().to_style() , obj: obj }
    }
}

/// Lists all possible Colors. It implements `ToStyle` so it's possible to call
/// `ToStyle`'s methods direclty on a `Color` variant like:
///
/// `println!("{}", Color::Red.bold().paint("Red and bold"));`
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Color {
    Normal,
    Black,
    Red,
    Green,
    Yellow,
    Blue,
    Magenta,
    Cyan,
    White,
    BrightBlack,
    BrightRed,
    BrightGreen,
    BrightYellow,
    BrightBlue,
    BrightMagenta,
    BrightCyan,
    BrightWhite,
}

impl Color {
    /// Returns the associated constant from `term::color::Color`.
    fn term_constant(&self) -> Option<term::color::Color> {
        match *self {
            Color::Normal  => None,
            Color::Black   => Some(term::color::BLACK),
            Color::Red     => Some(term::color::RED),
            Color::Green   => Some(term::color::GREEN),
            Color::Yellow  => Some(term::color::YELLOW),
            Color::Blue    => Some(term::color::BLUE),
            Color::Magenta => Some(term::color::MAGENTA),
            Color::Cyan    => Some(term::color::CYAN),
            Color::White   => Some(term::color::WHITE),
            Color::BrightBlack   => Some(term::color::BRIGHT_BLACK),
            Color::BrightRed     => Some(term::color::BRIGHT_RED),
            Color::BrightGreen   => Some(term::color::BRIGHT_GREEN),
            Color::BrightYellow  => Some(term::color::BRIGHT_YELLOW),
            Color::BrightBlue    => Some(term::color::BRIGHT_BLUE),
            Color::BrightMagenta => Some(term::color::BRIGHT_MAGENTA),
            Color::BrightCyan    => Some(term::color::BRIGHT_CYAN),
            Color::BrightWhite   => Some(term::color::BRIGHT_WHITE),
        }
    }
}

impl Default for Color {
    fn default() -> Self {
        Color::Normal
    }
}

impl ToStyle for Color {
    /// Returns a Style with default values and the `self` color as foreground
    /// color.
    fn to_style(self) -> Style {
        let mut s = Style::default();
        s.fg = self;
        s
    }
}

/// Lists possible attributes. It implements `ToStyle` so it's possible to call
/// `ToStyle`'s methods directly on a `Attr` variant like:
///
/// `println!("{}", Attr::Bold.fg(Color::Red).paint("Red and bold"));`
///
/// For more information about enum variants, see `term::Attr` Documentation.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Attr {
    /// Just default style
    Plain,
    Bold,
    Dim,
    Underline,
    Blink,
    Reverse,
    Secure,
}

impl ToStyle for Attr {
    /// Returns a Style with default values and the `self` attribute enabled.
    fn to_style(self) -> Style {
        let mut s = Style::default();
        match self {
            Attr::Plain => {},
            Attr::Bold => s.bold = true,
            Attr::Dim => s.dim = true,
            Attr::Underline => s.underline = true,
            Attr::Blink => s.blink = true,
            Attr::Reverse => s.reverse = true,
            Attr::Secure => s.secure = true,
        }
        s
    }
}

/// Saves all properties of a style. Implements `ToStyle`, so you can call
/// style modifiers on it.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Style {
    pub fg: Color,
    pub bg: Color,
    pub bold: bool,
    pub dim: bool,
    pub underline: bool,
    pub blink: bool,
    pub reverse: bool,
    pub secure: bool,
}

impl Default for Style {
    fn default() -> Self {
        Style {
            fg: Color::default(),
            bg: Color::default(),
            bold: false,
            dim: false,
            underline: false,
            blink: false,
            reverse: false,
            secure: false,
        }
    }
}

// static INIT_TERM: Once = ONCE_INIT;
thread_local!(static TERM: RefCell<Option<Box<term::StdoutTerminal>>>
    = RefCell::new(term::stdout()));

impl Style {
    fn prepare(&self) -> Result<(), Error> {
        macro_rules! try_term {
            ($e:expr) => ({
                match $e {
                    Ok(true) => {},
                    _ => { return Err(Error); },
                }
            })
        }

        TERM.with(|term_opt| {
            let mut tmut = term_opt.borrow_mut();
            let mut t = match tmut.as_mut() {
                None => return Err(Error),
                Some(t) => t,
            };

            match self.fg.term_constant() {
                None => {},
                Some(c) => { try_term!(t.fg(c)); },
            }
            match self.bg.term_constant() {
                None => {},
                Some(c) => { try_term!(t.bg(c)); },
            }
            if self.bold { try_term!(t.attr(term::Attr::Bold)) }
            if self.underline { try_term!(t.attr(term::Attr::Underline(true))) }
            if self.blink { try_term!(t.attr(term::Attr::Blink)) }
            if self.reverse { try_term!(t.attr(term::Attr::Reverse)) }
            if self.secure { try_term!(t.attr(term::Attr::Secure)) }

            Ok(())
        })
    }

    fn cleanup(&self) -> Result<(), Error> {
        TERM.with(|term_opt| {
            let mut tmut = term_opt.borrow_mut();
            match tmut.as_mut() {
                None => Err(Error),
                Some(t) =>
                    match t.reset() {
                        Ok(true) => Ok(()),
                        _ => Err(Error),
                    },
            }
        })
    }
}

impl ToStyle for Style {
    /// Dummy implementation that just returns `self`.
    fn to_style(self) -> Style {
        self
    }
}

/// Saves a style and a reference to something that will be printed in that
/// style. That something of type `T` needs to implement either
/// `std::fmt::Debug` or `std::fmt::Display`
pub struct Painted<T> {
    style: Style,
    obj: T,
}

impl<T: Display> Display for Painted<T> {
    /// Implementation for `T: Display` -> to print with `{}`.
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        try!(self.style.prepare());
        try!(write!(f, "{}", self.obj));
        self.style.cleanup()
    }
}

impl<T: Debug> Debug for Painted<T> {
    /// Implementation for `T: Debug` -> to print with `{:?}`.
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        try!(self.style.prepare());
        try!(write!(f, "{:?}", self.obj));
        self.style.cleanup()
    }
}

// ----- Tests ------
#[cfg(test)]
mod test {
    use super::Color::*;
    use super::Attr::*;
    use super::ToStyle;

    #[test]
    fn modifier_order() {
        // The order of modifiers shouldn't play a role.
        assert_eq!(Plain.bold().fg(Red), Plain.fg(Red).bold());
        assert_eq!(Plain.bold().bg(Red), Plain.bg(Red).bold());
        assert_eq!(Plain.underline().fg(Red), Plain.fg(Red).underline());

        // The startpoints should have the same effect as the modifier.
        assert_eq!(Red.to_style(), Plain.fg(Red));
        assert_eq!(Bold.to_style(), Plain.bold());
    }

    #[test]
    fn modifier_override() {
        // The latter modifier should override the one before
        assert_eq!(Plain.fg(Red).fg(Blue), Plain.fg(Blue));
        assert_eq!(Plain.fg(Red).fg(Blue), Blue.to_style());
        assert_eq!(Red.fg(Blue), Plain.fg(Blue));
        assert_eq!(Red.fg(Blue), Blue.to_style());
    }
}
<|endoftext|>