<commit_before>use std::fs::File;
use std::collections::HashMap;
use std::io::Write;
use std::path::Path;
use std::ffi::OsStr;
use liquid;
use rss;
use jsonfeed::Feed;
use jsonfeed;

use cobalt_model::{Config, SortOrder};
use cobalt_model::files;
use cobalt_model;
use document::Document;
use error::*;
use template;

/// The primary build function that transforms a directory into a site
pub fn build(config: &Config) -> Result<()> {
    trace!("Build configuration: {:?}", config);

    let source = config.source.as_path();
    let dest = config.destination.as_path();

    let template_extensions: Vec<&OsStr> =
        config.template_extensions.iter().map(OsStr::new).collect();

    let layouts = source.join(&config.layouts_dir);
    let mut layouts_cache = HashMap::new();
    let posts_path = source.join(&config.posts.dir);

    debug!("Layouts directory: {:?}", layouts);
    debug!("Posts directory: {:?}", posts_path);
    debug!("Draft mode enabled: {}", config.include_drafts);

    let parser = template::LiquidParser::with_config(config)?;

    let mut documents = vec![];

    let mut page_files = files::FilesBuilder::new(source)?;
    page_files
        .add_ignore(&format!("!{}", config.posts.dir))?
        .add_ignore(&format!("!{}/**", config.posts.dir))?
        .add_ignore(&format!("{}/**/_*", config.posts.dir))?
        .add_ignore(&format!("{}/**/_*/**", config.posts.dir))?;
    for line in &config.ignore {
        page_files.add_ignore(line.as_str())?;
    }
    let page_files = page_files.build()?;
    for file_path in page_files.files().filter(|p| {
        template_extensions.contains(&p.extension().unwrap_or_else(|| OsStr::new("")))
    }) {
        let rel_src = file_path
            .strip_prefix(source)
            .expect("file was found under the root");

        // if the document is in the posts folder it's considered a post
        let is_post = file_path.starts_with(posts_path.as_path());
        let default_front = if is_post {
            config.posts.default.clone()
        } else {
            config.pages.default.clone()
        };

        let doc = Document::parse(&file_path, rel_src, default_front)
            .chain_err(|| format!("Failed to parse {:?}", rel_src))?;
        if !doc.front.is_draft || config.include_drafts {
            documents.push(doc);
        }
    }

    if config.include_drafts {
        if let Some(ref drafts_dir) = config.posts.drafts_dir {
            debug!("Draft directory: {:?}", drafts_dir);
            let drafts_root = source.join(&drafts_dir);
            let mut draft_files = files::FilesBuilder::new(drafts_root.as_path())?;
            for line in &config.ignore {
                draft_files.add_ignore(line.as_str())?;
            }
            let draft_files = draft_files.build()?;
            for file_path in draft_files.files().filter(|p| {
                template_extensions.contains(&p.extension().unwrap_or_else(|| OsStr::new("")))
            }) {
                // Provide a fake path as if it was not a draft
                let rel_src = file_path
                    .strip_prefix(&drafts_root)
                    .expect("file was found under the root");
                let new_path = Path::new(&config.posts.dir).join(rel_src);

                let default_front = config.posts.default.clone().set_draft(true);

                let doc = Document::parse(&file_path, &new_path, default_front)
                    .chain_err(|| format!("Failed to parse {:?}", rel_src))?;
                documents.push(doc);
            }
        }
    }

    // January 1, 1970 0:00:00 UTC, the beginning of time
    let default_date = cobalt_model::DateTime::default();

    let (mut posts, documents): (Vec<Document>, Vec<Document>) =
        documents.into_iter().partition(|x| x.front.is_post);

    // sort documents by date, if there's no date (none was provided or it couldn't be read) then
    // fall back to the default date
    posts.sort_by(|a, b| {
                      b.front
                          .published_date
                          .unwrap_or(default_date)
                          .cmp(&a.front.published_date.unwrap_or(default_date))
                  });

    match config.posts.order {
        SortOrder::Asc => posts.reverse(),
        SortOrder::Desc => (),
    }

    // collect all posts attributes to pass them to other posts for rendering
    let simple_posts_data: Vec<liquid::Value> = posts
        .iter()
        .map(|x| liquid::Value::Object(x.attributes.clone()))
        .collect();

    trace!("Generating posts");
    for (i, post) in &mut posts.iter_mut().enumerate() {
        trace!("Generating {}", post.url_path);

        // posts are in reverse date order, so previous post is the next in the list (+1)
        let previous = simple_posts_data
            .get(i + 1)
            .cloned()
            .unwrap_or(liquid::Value::Nil);
        post.attributes.insert("previous".to_owned(), previous);
        let next = if i >= 1 {
            simple_posts_data.get(i - 1)
        } else {
            None
        }.cloned()
            .unwrap_or(liquid::Value::Nil);
        post.attributes.insert("next".to_owned(), next);

        for dump in config.dump.iter().filter(|d| d.is_doc()) {
            trace!("Dumping {:?}", dump);
            let (content, ext) = post.render_dump(*dump)?;
            let mut file_path = post.file_path.clone();
            let file_name = file_path
                .file_stem()
                .and_then(|p| p.to_str())
                .expect("page must have file name")
                .to_owned();
            let file_name = format!("_{}.{}.{}", file_name, dump, ext);
            file_path.set_file_name(file_name);
            trace!("Generating {:?}", file_path);
            files::write_document_file(content, dest.join(file_path))?;
        }

        // Everything done with `globals` is terrible for performance.  liquid#95 allows us to
        // improve this.
        let mut globals: liquid::Object =
            vec![("site".to_owned(), liquid::Value::Object(config.site.attributes.clone())),
                 ("posts".to_owned(), liquid::Value::Array(simple_posts_data.clone()))]
                .into_iter()
                .collect();
        globals.insert("page".to_owned(),
                       liquid::Value::Object(post.attributes.clone()));
        post.render_excerpt(&globals, &parser, &config.syntax_highlight.theme)
            .chain_err(|| format!("Failed to render excerpt for {:?}", post.file_path))?;
        post.render_content(&globals, &parser, &config.syntax_highlight.theme)
            .chain_err(|| format!("Failed to render content for {:?}", post.file_path))?;

        // Refresh `page` with the `excerpt` / `content` attribute
        globals.insert("page".to_owned(),
                       liquid::Value::Object(post.attributes.clone()));
        let post_html = post.render(&globals, &parser, &layouts, &mut layouts_cache)
            .chain_err(|| format!("Failed to render for {:?}", post.file_path))?;
        files::write_document_file(post_html, dest.join(&post.file_path))?;
    }

    // check if we should create an RSS file and create it!
    if let Some(ref path) = config.posts.rss {
        create_rss(path, dest, config, &posts)?;
    }
    // check if we should create an jsonfeed file and create it!
    if let Some(ref path) = config.posts.jsonfeed {
        create_jsonfeed(path, dest, config, &posts)?;
    }

    // during post rendering additional attributes such as content were
    // added to posts. collect them so that non-post documents can access them
    let posts_data: Vec<liquid::Value> = posts
        .into_iter()
        .map(|x| liquid::Value::Object(x.attributes))
        .collect();

    trace!("Generating other documents");
    for mut doc in documents {
        trace!("Generating {}", doc.url_path);

        for dump in config.dump.iter().filter(|d| d.is_doc()) {
            trace!("Dumping {:?}", dump);
            let (content, ext) = doc.render_dump(*dump)?;
            let mut file_path = doc.file_path.clone();
            let file_name = file_path
                .file_stem()
                .and_then(|p| p.to_str())
                .expect("page must have file name")
                .to_owned();
            let file_name = format!("_{}.{}.{}", file_name, dump, ext);
            file_path.set_file_name(file_name);
            trace!("Generating {:?}", file_path);
            files::write_document_file(content, dest.join(file_path))?;
        }

        let mut globals: liquid::Object =
            vec![("site".to_owned(), liquid::Value::Object(config.site.attributes.clone())),
                 ("posts".to_owned(), liquid::Value::Array(posts_data.clone()))]
                .into_iter()
                .collect();
        globals.insert("page".to_owned(),
                       liquid::Value::Object(doc.attributes.clone()));
        doc.render_excerpt(&globals, &parser, &config.syntax_highlight.theme)
            .chain_err(|| format!("Failed to render excerpt for {:?}", doc.file_path))?;
        doc.render_content(&globals, &parser, &config.syntax_highlight.theme)
            .chain_err(|| format!("Failed to render content for {:?}", doc.file_path))?;

        // Refresh `page` with the `excerpt` / `content` attribute
        globals.insert("page".to_owned(),
                       liquid::Value::Object(doc.attributes.clone()));
        let doc_html = doc.render(&globals, &parser, &layouts, &mut layouts_cache)
            .chain_err(|| format!("Failed to render for {:?}", doc.file_path))?;
        files::write_document_file(doc_html, dest.join(doc.file_path))?;
    }

    // copy all remaining files in the source to the destination
    // compile SASS along the way
    {
        info!("Copying remaining assets");

        let mut asset_files = files::FilesBuilder::new(source)?;
        for line in &config.ignore {
            asset_files.add_ignore(line.as_str())?;
        }
        let asset_files = asset_files.build()?;
        for file_path in asset_files.files().filter(|p| {
            !template_extensions.contains(&p.extension().unwrap_or_else(|| OsStr::new("")))
        }) {
            if file_path.extension() == Some(OsStr::new("scss")) {
                config.assets.sass.compile_file(source, dest, file_path)?;
            } else {
                let rel_src = file_path
                    .strip_prefix(source)
                    .expect("file was found under the root");
                files::copy_file(&file_path, dest.join(rel_src).as_path())?;
            }
        }
    }

    Ok(())
}

// creates a new RSS file with the contents of the site blog
fn create_rss(path: &str, dest: &Path, config: &Config, posts: &[Document]) -> Result<()> {
    let rss_path = dest.join(path);
    info!("Creating RSS file at {}", rss_path.display());

    let title = &config.posts.title;
    let description = config
        .posts
        .description
        .as_ref()
        .map(|s| s.as_str())
        .unwrap_or("");
    let link = config
        .site
        .base_url
        .as_ref()
        .ok_or(ErrorKind::ConfigFileMissingFields)?;

    let items: Result<Vec<rss::Item>> = posts.iter().map(|doc| doc.to_rss(link)).collect();
    let items = items?;

    let channel = rss::ChannelBuilder::default()
        .title(title.to_owned())
        .link(link.to_owned())
        .description(description.to_owned())
        .items(items)
        .build()?;

    let rss_string = channel.to_string();
    trace!("RSS data: {}", rss_string);

    let mut rss_file = File::create(&rss_path)?;
    rss_file
        .write_all(br#"<?xml version="1.0" encoding="UTF-8"?>"#)?;
    rss_file.write_all(&rss_string.into_bytes())?;
    rss_file.write_all(b"\n")?;

    Ok(())
}

// creates a new jsonfeed file with the contents of the site blog
fn create_jsonfeed(path: &str, dest: &Path, config: &Config, posts: &[Document]) -> Result<()> {
    let jsonfeed_path = dest.join(path);
    info!("Creating jsonfeed file at {}", jsonfeed_path.display());

    let title = &config.posts.title;
    let description = config
        .posts
        .description
        .as_ref()
        .map(|s| s.as_str())
        .unwrap_or("");
    let link = config
        .site
        .base_url
        .as_ref()
        .ok_or(ErrorKind::ConfigFileMissingFields)?;

    let jsonitems = posts.iter().map(|doc| doc.to_jsonfeed(link)).collect();

    let feed = Feed {
        title: title.to_string(),
        items: jsonitems,
        home_page_url: Some(link.to_string()),
        description: Some(description.to_string()),
        ..Default::default()
    };

    let jsonfeed_string = jsonfeed::to_string(&feed).unwrap();
    files::write_document_file(jsonfeed_string, jsonfeed_path)?;

    Ok(())
}
<commit_msg>fix(rss): Don't error if the RSS folder doesn't exist.<commit_after>use std::fs;
use std::collections::HashMap;
use std::io::Write;
use std::path::Path;
use std::ffi::OsStr;
use liquid;
use rss;
use jsonfeed::Feed;
use jsonfeed;

use cobalt_model::{Config, SortOrder};
use cobalt_model::files;
use cobalt_model;
use document::Document;
use error::*;
use template;

/// The primary build function that transforms a directory into a site
pub fn build(config: &Config) -> Result<()> {
    trace!("Build configuration: {:?}", config);

    let source = config.source.as_path();
    let dest = config.destination.as_path();

    let template_extensions: Vec<&OsStr> =
        config.template_extensions.iter().map(OsStr::new).collect();

    let layouts = source.join(&config.layouts_dir);
    let mut layouts_cache = HashMap::new();
    let posts_path = source.join(&config.posts.dir);

    debug!("Layouts directory: {:?}", layouts);
    debug!("Posts directory: {:?}", posts_path);
    debug!("Draft mode enabled: {}", config.include_drafts);

    let parser = template::LiquidParser::with_config(config)?;

    let mut documents = vec![];

    let mut page_files = files::FilesBuilder::new(source)?;
    page_files
        .add_ignore(&format!("!{}", config.posts.dir))?
        .add_ignore(&format!("!{}/**", config.posts.dir))?
        .add_ignore(&format!("{}/**/_*", config.posts.dir))?
        .add_ignore(&format!("{}/**/_*/**", config.posts.dir))?;
    for line in &config.ignore {
        page_files.add_ignore(line.as_str())?;
    }
    let page_files = page_files.build()?;
    for file_path in page_files.files().filter(|p| {
        template_extensions.contains(&p.extension().unwrap_or_else(|| OsStr::new("")))
    }) {
        let rel_src = file_path
            .strip_prefix(source)
            .expect("file was found under the root");

        // if the document is in the posts folder it's considered a post
        let is_post = file_path.starts_with(posts_path.as_path());
        let default_front = if is_post {
            config.posts.default.clone()
        } else {
            config.pages.default.clone()
        };

        let doc = Document::parse(&file_path, rel_src, default_front)
            .chain_err(|| format!("Failed to parse {:?}", rel_src))?;
        if !doc.front.is_draft || config.include_drafts {
            documents.push(doc);
        }
    }

    if config.include_drafts {
        if let Some(ref drafts_dir) = config.posts.drafts_dir {
            debug!("Draft directory: {:?}", drafts_dir);
            let drafts_root = source.join(&drafts_dir);
            let mut draft_files = files::FilesBuilder::new(drafts_root.as_path())?;
            for line in &config.ignore {
                draft_files.add_ignore(line.as_str())?;
            }
            let draft_files = draft_files.build()?;
            for file_path in draft_files.files().filter(|p| {
                template_extensions.contains(&p.extension().unwrap_or_else(|| OsStr::new("")))
            }) {
                // Provide a fake path as if it was not a draft
                let rel_src = file_path
                    .strip_prefix(&drafts_root)
                    .expect("file was found under the root");
                let new_path = Path::new(&config.posts.dir).join(rel_src);

                let default_front = config.posts.default.clone().set_draft(true);

                let doc = Document::parse(&file_path, &new_path, default_front)
                    .chain_err(|| format!("Failed to parse {:?}", rel_src))?;
                documents.push(doc);
            }
        }
    }

    // January 1, 1970 0:00:00 UTC, the beginning of time
    let default_date = cobalt_model::DateTime::default();

    let (mut posts, documents): (Vec<Document>, Vec<Document>) =
        documents.into_iter().partition(|x| x.front.is_post);

    // sort documents by date, if there's no date (none was provided or it couldn't be read) then
    // fall back to the default date
    posts.sort_by(|a, b| {
                      b.front
                          .published_date
                          .unwrap_or(default_date)
                          .cmp(&a.front.published_date.unwrap_or(default_date))
                  });

    match config.posts.order {
        SortOrder::Asc => posts.reverse(),
        SortOrder::Desc => (),
    }

    // collect all posts attributes to pass them to other posts for rendering
    let simple_posts_data: Vec<liquid::Value> = posts
        .iter()
        .map(|x| liquid::Value::Object(x.attributes.clone()))
        .collect();

    trace!("Generating posts");
    for (i, post) in &mut posts.iter_mut().enumerate() {
        trace!("Generating {}", post.url_path);

        // posts are in reverse date order, so previous post is the next in the list (+1)
        let previous = simple_posts_data
            .get(i + 1)
            .cloned()
            .unwrap_or(liquid::Value::Nil);
        post.attributes.insert("previous".to_owned(), previous);
        let next = if i >= 1 {
            simple_posts_data.get(i - 1)
        } else {
            None
        }.cloned()
            .unwrap_or(liquid::Value::Nil);
        post.attributes.insert("next".to_owned(), next);

        for dump in config.dump.iter().filter(|d| d.is_doc()) {
            trace!("Dumping {:?}", dump);
            let (content, ext) = post.render_dump(*dump)?;
            let mut file_path = post.file_path.clone();
            let file_name = file_path
                .file_stem()
                .and_then(|p| p.to_str())
                .expect("page must have file name")
                .to_owned();
            let file_name = format!("_{}.{}.{}", file_name, dump, ext);
            file_path.set_file_name(file_name);
            trace!("Generating {:?}", file_path);
            files::write_document_file(content, dest.join(file_path))?;
        }

        // Everything done with `globals` is terrible for performance.  liquid#95 allows us to
        // improve this.
        let mut globals: liquid::Object =
            vec![("site".to_owned(), liquid::Value::Object(config.site.attributes.clone())),
                 ("posts".to_owned(), liquid::Value::Array(simple_posts_data.clone()))]
                .into_iter()
                .collect();
        globals.insert("page".to_owned(),
                       liquid::Value::Object(post.attributes.clone()));
        post.render_excerpt(&globals, &parser, &config.syntax_highlight.theme)
            .chain_err(|| format!("Failed to render excerpt for {:?}", post.file_path))?;
        post.render_content(&globals, &parser, &config.syntax_highlight.theme)
            .chain_err(|| format!("Failed to render content for {:?}", post.file_path))?;

        // Refresh `page` with the `excerpt` / `content` attribute
        globals.insert("page".to_owned(),
                       liquid::Value::Object(post.attributes.clone()));
        let post_html = post.render(&globals, &parser, &layouts, &mut layouts_cache)
            .chain_err(|| format!("Failed to render for {:?}", post.file_path))?;
        files::write_document_file(post_html, dest.join(&post.file_path))?;
    }

    // check if we should create an RSS file and create it!
    if let Some(ref path) = config.posts.rss {
        create_rss(path, dest, config, &posts)?;
    }
    // check if we should create an jsonfeed file and create it!
    if let Some(ref path) = config.posts.jsonfeed {
        create_jsonfeed(path, dest, config, &posts)?;
    }

    // during post rendering additional attributes such as content were
    // added to posts. collect them so that non-post documents can access them
    let posts_data: Vec<liquid::Value> = posts
        .into_iter()
        .map(|x| liquid::Value::Object(x.attributes))
        .collect();

    trace!("Generating other documents");
    for mut doc in documents {
        trace!("Generating {}", doc.url_path);

        for dump in config.dump.iter().filter(|d| d.is_doc()) {
            trace!("Dumping {:?}", dump);
            let (content, ext) = doc.render_dump(*dump)?;
            let mut file_path = doc.file_path.clone();
            let file_name = file_path
                .file_stem()
                .and_then(|p| p.to_str())
                .expect("page must have file name")
                .to_owned();
            let file_name = format!("_{}.{}.{}", file_name, dump, ext);
            file_path.set_file_name(file_name);
            trace!("Generating {:?}", file_path);
            files::write_document_file(content, dest.join(file_path))?;
        }

        let mut globals: liquid::Object =
            vec![("site".to_owned(), liquid::Value::Object(config.site.attributes.clone())),
                 ("posts".to_owned(), liquid::Value::Array(posts_data.clone()))]
                .into_iter()
                .collect();
        globals.insert("page".to_owned(),
                       liquid::Value::Object(doc.attributes.clone()));
        doc.render_excerpt(&globals, &parser, &config.syntax_highlight.theme)
            .chain_err(|| format!("Failed to render excerpt for {:?}", doc.file_path))?;
        doc.render_content(&globals, &parser, &config.syntax_highlight.theme)
            .chain_err(|| format!("Failed to render content for {:?}", doc.file_path))?;

        // Refresh `page` with the `excerpt` / `content` attribute
        globals.insert("page".to_owned(),
                       liquid::Value::Object(doc.attributes.clone()));
        let doc_html = doc.render(&globals, &parser, &layouts, &mut layouts_cache)
            .chain_err(|| format!("Failed to render for {:?}", doc.file_path))?;
        files::write_document_file(doc_html, dest.join(doc.file_path))?;
    }

    // copy all remaining files in the source to the destination
    // compile SASS along the way
    {
        info!("Copying remaining assets");

        let mut asset_files = files::FilesBuilder::new(source)?;
        for line in &config.ignore {
            asset_files.add_ignore(line.as_str())?;
        }
        let asset_files = asset_files.build()?;
        for file_path in asset_files.files().filter(|p| {
            !template_extensions.contains(&p.extension().unwrap_or_else(|| OsStr::new("")))
        }) {
            if file_path.extension() == Some(OsStr::new("scss")) {
                config.assets.sass.compile_file(source, dest, file_path)?;
            } else {
                let rel_src = file_path
                    .strip_prefix(source)
                    .expect("file was found under the root");
                files::copy_file(&file_path, dest.join(rel_src).as_path())?;
            }
        }
    }

    Ok(())
}

// creates a new RSS file with the contents of the site blog
fn create_rss(path: &str, dest: &Path, config: &Config, posts: &[Document]) -> Result<()> {
    let rss_path = dest.join(path);
    info!("Creating RSS file at {}", rss_path.display());

    let title = &config.posts.title;
    let description = config
        .posts
        .description
        .as_ref()
        .map(|s| s.as_str())
        .unwrap_or("");
    let link = config
        .site
        .base_url
        .as_ref()
        .ok_or(ErrorKind::ConfigFileMissingFields)?;

    let items: Result<Vec<rss::Item>> = posts.iter().map(|doc| doc.to_rss(link)).collect();
    let items = items?;

    let channel = rss::ChannelBuilder::default()
        .title(title.to_owned())
        .link(link.to_owned())
        .description(description.to_owned())
        .items(items)
        .build()?;

    let rss_string = channel.to_string();
    trace!("RSS data: {}", rss_string);

    // create target directories if any exist
    if let Some(parent) = rss_path.parent() {
        fs::create_dir_all(parent)
            .map_err(|e| format!("Could not create {:?}: {}", parent, e))?;
    }

    let mut rss_file = fs::File::create(&rss_path)?;
    rss_file
        .write_all(br#"<?xml version="1.0" encoding="UTF-8"?>"#)?;
    rss_file.write_all(&rss_string.into_bytes())?;
    rss_file.write_all(b"\n")?;

    Ok(())
}

// creates a new jsonfeed file with the contents of the site blog
fn create_jsonfeed(path: &str, dest: &Path, config: &Config, posts: &[Document]) -> Result<()> {
    let jsonfeed_path = dest.join(path);
    info!("Creating jsonfeed file at {}", jsonfeed_path.display());

    let title = &config.posts.title;
    let description = config
        .posts
        .description
        .as_ref()
        .map(|s| s.as_str())
        .unwrap_or("");
    let link = config
        .site
        .base_url
        .as_ref()
        .ok_or(ErrorKind::ConfigFileMissingFields)?;

    let jsonitems = posts.iter().map(|doc| doc.to_jsonfeed(link)).collect();

    let feed = Feed {
        title: title.to_string(),
        items: jsonitems,
        home_page_url: Some(link.to_string()),
        description: Some(description.to_string()),
        ..Default::default()
    };

    let jsonfeed_string = jsonfeed::to_string(&feed).unwrap();
    files::write_document_file(jsonfeed_string, jsonfeed_path)?;

    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2015 Adrien Champion. See the COPYRIGHT file at the top-level
// directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
Basic types used by the library.
*/

use std::io ;
use std::fmt ;

use nom::IResult ;

/** Alias for `io` results of unit. */
pub type IoResUnit = io::Result<()> ;
/** Alias for `io` results of `bool`. */
pub type IoResBool = io::Result<bool> ;
/** Alias for generic `io` results. */
pub type IoRes<T> = io::Result<T> ;

/** Unexpected result for an SMT Lib 2 command. */
#[derive(Debug)]
pub enum UnexSmtRes {
  /** An unsupported command was issued. */
  Unsupported,
  /** A command produced an error. */
  Error(String),
  /** An input/output error occured. */
  IoError(io::Error),
}
impl fmt::Display for UnexSmtRes {
  fn fmt(& self, fmt: & mut fmt::Formatter) -> fmt::Result {
    match * self {
      UnexSmtRes::Unsupported => write!(fmt, "unsupported"),
      UnexSmtRes::Error(ref s) => write!(fmt, "{}", s),
      UnexSmtRes::IoError(ref e) => write!(fmt, "io error: {}", e),
    }
  }
}

/** Result of an SMT query. */
pub type SmtRes<T> = Result<T, UnexSmtRes> ;

/** Result of an SMT statement. */
pub type UnitSmtRes = SmtRes<()> ;

/** A symbol printable in the SMT Lib 2 standard given some info. */
pub trait Sym2Smt<Info> {
  /** Prints a symbol to a writer given some info. */
  fn sym_to_smt2(& self, writer: & mut io::Write, & Info) -> IoResUnit ;
}

/** An expression printable in the SMT Lib 2 standard given some info. */
pub trait Expr2Smt<Info> {
  /** Prints an expression to a writer given some info. */
  fn expr_to_smt2(& self, writer: & mut io::Write, & Info) -> IoResUnit ;
}

/** A sort printable in the SMT Lib 2 standard. */
pub trait Sort2Smt {
  /** Prints a sort to a writer info. */
  fn sort_to_smt2(& self, writer: & mut io::Write) -> IoResUnit ;
}

impl<'a> Sym2Smt<()>  for & 'a str {
  fn sym_to_smt2(& self, writer: & mut io::Write, _: & ()) -> IoResUnit {
    write!(writer, "{}", self)
  }
}
impl<'a> Expr2Smt<()> for & 'a str {
  fn expr_to_smt2(& self, writer: & mut io::Write, info: & ()) -> IoResUnit {
    self.sym_to_smt2(writer, info)
  }
}
impl<'a> Sort2Smt for & 'a str {
  fn sort_to_smt2(& self, writer: & mut io::Write) -> IoResUnit {
    self.sym_to_smt2(writer, & ())
  }
}

/** Generic type for the parsing of an SMT Lib 2 answer.

Either a value of the expected type or an unexpected error. */
pub type SmtParseResult<T> = Result<T, UnexSmtRes> ;

/** Parsers on the user's structure.

Not all of them are necessary depending on the queries wanted. See each method
for details.*/
pub trait ParseSmt2 {
  /** Type of identifiers in the user's structure. */
  type Ident : ::std::fmt::Debug ;
  /** Type of values in the user's structure. */
  type Value : ::std::fmt::Debug ;
  /** Type of expressions in the user's structure. */
  type Expr :  ::std::fmt::Debug ;
  /** Type of proofs in the user's structure. */
  type Proof : ::std::fmt::Debug ;
  /** Type of the info passed when parsing expressions. */
  type I ;

  /** Parses an ident from self, viewed as a reader.

  Required by

  * `get-assignment`
  * `get-model`
  * `get-unsat-assumptions`
  * `get-unsat-core` */
  #[inline(always)]
  fn parse_ident<'a>(
    & self, & 'a [u8]
  ) -> IResult<& 'a [u8], Self::Ident> ;

  /** Parses a value from self, viewed as a reader.

  Required by

  * `get-value`
  * `get-assignment`
  * `get-model` */
  #[inline(always)]
  fn parse_value<'a>(
    & self, & 'a [u8]
  ) -> IResult<& 'a [u8], Self::Value> ;

  /** Parses an expression from self, viewed as a reader.

  Required by

  * `get_assertions` */
  #[inline(always)]
  fn parse_expr<'a>(
    & self, & 'a [u8], & Self::I
  ) -> IResult<& 'a [u8], Self::Expr> ;

  /** Parses a proof from self, viewed as a reader.

  Required by

  * `get_proof` */
  #[inline(always)]
  fn parse_proof<'a>(
    & self, & 'a [u8]
  ) -> IResult<& 'a [u8], Self::Proof> ;
}

impl ParseSmt2 for () {
  type Ident = () ;
  type Value = () ;
  type Expr = () ;
  type Proof = () ;
  type I = () ;
  fn parse_ident<'a>(
    & self, _: & 'a [u8]
  ) -> IResult<& 'a [u8], Self::Ident> {
    panic!("parser on () called")
  }
  fn parse_value<'a>(
    & self, _: & 'a [u8]
  ) -> IResult<& 'a [u8], Self::Value> {
    panic!("parser on () called")
  }
  fn parse_expr<'a>(
    & self, _: & 'a [u8], _: & ()
  ) -> IResult<& 'a [u8], Self::Expr> {
    panic!("parser on () called")
  }
  fn parse_proof<'a>(
    & self, _: & 'a [u8]
  ) -> IResult<& 'a [u8], Self::Proof> {
    panic!("parser on () called")
  }
}

/** SMT Lib 2 logics. */
#[allow(non_camel_case_types)]
pub enum Logic {
  /** Quantifier-free uninterpreted functions. */
  QF_UF,
  /** Quantifier-free linear integer arithmetic. */
  QF_LIA,
  /** Quantifier-free non-linear integer arithmetic. */
  QF_NIA,
  /** Quantifier-free linear real arithmetic. */
  QF_LRA,
  /** Quantifier-free arrays, uninterpreted functions, linear integer
  arithmetic. */
  QF_AUFLIA,
  /** Quantifier-free arrays, uninterpreted functions, linear integer
  arithmetic. */
  AUFLIA,
  /** Arrays, uninterpreted functions, linear integer/real arithmetic. */
  AUFLIRA,
  /** arrays, uninterpreted functions, non-linear integer/real arithmetic. */
  AUFNIRA,
  /** Linear real arithmetic. */
  LRA,
}

impl Logic {
  /** Prints the logic in a writer in SMT Lib 2 format. */
  pub fn to_smt2(& self, writer: & mut io::Write, _: ()) -> IoResUnit {
    use self::Logic::* ;
    match * self {
      QF_UF => write!(writer, "QF_UF"),
      QF_LIA => write!(writer, "QF_LIA"),
      QF_NIA => write!(writer, "QF_NIA"),
      QF_LRA => write!(writer, "QF_LRA"),
      QF_AUFLIA => write!(writer, "QF_AUFLIA"),
      AUFLIA => write!(writer, "AUFLIA"),
      AUFLIRA => write!(writer, "AUFLIRA"),
      AUFNIRA => write!(writer, "AUFNIRA"),
      LRA => write!(writer, "LRA"),
    }
  }
}<commit_msg>Sym2Smt for String<commit_after>// Copyright 2015 Adrien Champion. See the COPYRIGHT file at the top-level
// directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
Basic types used by the library.
*/

use std::io ;
use std::fmt ;

use nom::IResult ;

/** Alias for `io` results of unit. */
pub type IoResUnit = io::Result<()> ;
/** Alias for `io` results of `bool`. */
pub type IoResBool = io::Result<bool> ;
/** Alias for generic `io` results. */
pub type IoRes<T> = io::Result<T> ;

/** Unexpected result for an SMT Lib 2 command. */
#[derive(Debug)]
pub enum UnexSmtRes {
  /** An unsupported command was issued. */
  Unsupported,
  /** A command produced an error. */
  Error(String),
  /** An input/output error occured. */
  IoError(io::Error),
}
impl fmt::Display for UnexSmtRes {
  fn fmt(& self, fmt: & mut fmt::Formatter) -> fmt::Result {
    match * self {
      UnexSmtRes::Unsupported => write!(fmt, "unsupported"),
      UnexSmtRes::Error(ref s) => write!(fmt, "{}", s),
      UnexSmtRes::IoError(ref e) => write!(fmt, "io error: {}", e),
    }
  }
}

/** Result of an SMT query. */
pub type SmtRes<T> = Result<T, UnexSmtRes> ;

/** Result of an SMT statement. */
pub type UnitSmtRes = SmtRes<()> ;

/** A symbol printable in the SMT Lib 2 standard given some info. */
pub trait Sym2Smt<Info> {
  /** Prints a symbol to a writer given some info. */
  fn sym_to_smt2(& self, writer: & mut io::Write, & Info) -> IoResUnit ;
}

/** An expression printable in the SMT Lib 2 standard given some info. */
pub trait Expr2Smt<Info> {
  /** Prints an expression to a writer given some info. */
  fn expr_to_smt2(& self, writer: & mut io::Write, & Info) -> IoResUnit ;
}

/** A sort printable in the SMT Lib 2 standard. */
pub trait Sort2Smt {
  /** Prints a sort to a writer info. */
  fn sort_to_smt2(& self, writer: & mut io::Write) -> IoResUnit ;
}

impl<'a> Sym2Smt<()>  for & 'a str {
  fn sym_to_smt2(& self, writer: & mut io::Write, _: & ()) -> IoResUnit {
    write!(writer, "{}", self)
  }
}
impl<'a> Expr2Smt<()> for & 'a str {
  fn expr_to_smt2(& self, writer: & mut io::Write, info: & ()) -> IoResUnit {
    self.sym_to_smt2(writer, info)
  }
}
impl<'a> Sort2Smt for & 'a str {
  fn sort_to_smt2(& self, writer: & mut io::Write) -> IoResUnit {
    self.sym_to_smt2(writer, & ())
  }
}

impl Sym2Smt<()>  for String {
  fn sym_to_smt2(& self, writer: & mut io::Write, _: & ()) -> IoResUnit {
    write!(writer, "{}", self)
  }
}
impl Expr2Smt<()> for String {
  fn expr_to_smt2(& self, writer: & mut io::Write, info: & ()) -> IoResUnit {
    self.sym_to_smt2(writer, info)
  }
}
impl Sort2Smt for String {
  fn sort_to_smt2(& self, writer: & mut io::Write) -> IoResUnit {
    self.sym_to_smt2(writer, & ())
  }
}

/** Generic type for the parsing of an SMT Lib 2 answer.

Either a value of the expected type or an unexpected error. */
pub type SmtParseResult<T> = Result<T, UnexSmtRes> ;

/** Parsers on the user's structure.

Not all of them are necessary depending on the queries wanted. See each method
for details.*/
pub trait ParseSmt2 {
  /** Type of identifiers in the user's structure. */
  type Ident : ::std::fmt::Debug ;
  /** Type of values in the user's structure. */
  type Value : ::std::fmt::Debug ;
  /** Type of expressions in the user's structure. */
  type Expr :  ::std::fmt::Debug ;
  /** Type of proofs in the user's structure. */
  type Proof : ::std::fmt::Debug ;
  /** Type of the info passed when parsing expressions. */
  type I ;

  /** Parses an ident from self, viewed as a reader.

  Required by

  * `get-assignment`
  * `get-model`
  * `get-unsat-assumptions`
  * `get-unsat-core` */
  #[inline(always)]
  fn parse_ident<'a>(
    & self, & 'a [u8]
  ) -> IResult<& 'a [u8], Self::Ident> ;

  /** Parses a value from self, viewed as a reader.

  Required by

  * `get-value`
  * `get-assignment`
  * `get-model` */
  #[inline(always)]
  fn parse_value<'a>(
    & self, & 'a [u8]
  ) -> IResult<& 'a [u8], Self::Value> ;

  /** Parses an expression from self, viewed as a reader.

  Required by

  * `get_assertions` */
  #[inline(always)]
  fn parse_expr<'a>(
    & self, & 'a [u8], & Self::I
  ) -> IResult<& 'a [u8], Self::Expr> ;

  /** Parses a proof from self, viewed as a reader.

  Required by

  * `get_proof` */
  #[inline(always)]
  fn parse_proof<'a>(
    & self, & 'a [u8]
  ) -> IResult<& 'a [u8], Self::Proof> ;
}

impl ParseSmt2 for () {
  type Ident = () ;
  type Value = () ;
  type Expr = () ;
  type Proof = () ;
  type I = () ;
  fn parse_ident<'a>(
    & self, _: & 'a [u8]
  ) -> IResult<& 'a [u8], Self::Ident> {
    panic!("parser on () called")
  }
  fn parse_value<'a>(
    & self, _: & 'a [u8]
  ) -> IResult<& 'a [u8], Self::Value> {
    panic!("parser on () called")
  }
  fn parse_expr<'a>(
    & self, _: & 'a [u8], _: & ()
  ) -> IResult<& 'a [u8], Self::Expr> {
    panic!("parser on () called")
  }
  fn parse_proof<'a>(
    & self, _: & 'a [u8]
  ) -> IResult<& 'a [u8], Self::Proof> {
    panic!("parser on () called")
  }
}

/** SMT Lib 2 logics. */
#[allow(non_camel_case_types)]
pub enum Logic {
  /** Quantifier-free uninterpreted functions. */
  QF_UF,
  /** Quantifier-free linear integer arithmetic. */
  QF_LIA,
  /** Quantifier-free non-linear integer arithmetic. */
  QF_NIA,
  /** Quantifier-free linear real arithmetic. */
  QF_LRA,
  /** Quantifier-free arrays, uninterpreted functions, linear integer
  arithmetic. */
  QF_AUFLIA,
  /** Quantifier-free arrays, uninterpreted functions, linear integer
  arithmetic. */
  AUFLIA,
  /** Arrays, uninterpreted functions, linear integer/real arithmetic. */
  AUFLIRA,
  /** arrays, uninterpreted functions, non-linear integer/real arithmetic. */
  AUFNIRA,
  /** Linear real arithmetic. */
  LRA,
}

impl Logic {
  /** Prints the logic in a writer in SMT Lib 2 format. */
  pub fn to_smt2(& self, writer: & mut io::Write, _: ()) -> IoResUnit {
    use self::Logic::* ;
    match * self {
      QF_UF => write!(writer, "QF_UF"),
      QF_LIA => write!(writer, "QF_LIA"),
      QF_NIA => write!(writer, "QF_NIA"),
      QF_LRA => write!(writer, "QF_LRA"),
      QF_AUFLIA => write!(writer, "QF_AUFLIA"),
      AUFLIA => write!(writer, "AUFLIA"),
      AUFLIRA => write!(writer, "AUFLIRA"),
      AUFNIRA => write!(writer, "AUFNIRA"),
      LRA => write!(writer, "LRA"),
    }
  }
}<|endoftext|>


<commit_before>#[derive(Debug)]
pub enum IntToEnumError {
    InvalidU8(u8),
    InvalidU16(u16),
}

/// Named curves, as defined in [RFC4492] and [RFC7027]
enum_from_primitive! {
#[derive(Debug)]
#[repr(u16)]
pub enum NamedCurve {
    Sect163k1 = 1,
    Sect163r1 = 2,
    Sect163r2 = 3,
    Sect193r1 = 4,
    Sect193r2 = 5,
    Sect233k1 = 6,
    Sect233r1 = 7,
    Sect239k1 = 8,
    Sect283k1 = 9,
    Sect283r1 = 10,
    Sect409k1 = 11,
    Sect409r1 = 12,
    Sect571k1 = 13,
    Sect571r1 = 14,
    Secp160k1 = 15,
    Secp160r1 = 16,
    Secp160r2 = 17,
    Secp192k1 = 18,
    Secp192r1 = 19,
    Secp224k1 = 20,
    Secp224r1 = 21,
    Secp256k1 = 22,
    Secp256r1 = 23,
    Secp384r1 = 24,
    Secp521r1 = 25,
    BrainpoolP256r1 = 26,
    BrainpoolP384r1 = 27,
    BrainpoolP512r1 = 28,
    ArbitraryExplicitPrimeCurves = 0xFF01,
    ArbitraryExplicitChar2Curves = 0xFF02,
}
}

/// Hash algorithms, as defined in [RFC5246]
enum_from_primitive! {
#[derive(Debug)]
#[repr(u8)]
pub enum HashAlgorithm {
    None = 0,
    Md5 = 1,
    Sha1 = 2,
    Sha224 = 3,
    Sha256 = 4,
    Sha384 = 5,
    Sha512 = 6,
}
}

/// Signature algorithms, as defined in [RFC5246]
enum_from_primitive! {
#[derive(Debug)]
#[repr(u8)]
pub enum SignatureAlgorithm {
    Anonymous = 0,
    Rsa = 1,
    Dsa = 2,
    Ecdsa = 3,
}
}

#[macro_export]
macro_rules! error_if (
  ($i:expr, $cond:expr, $err:expr) => (
    {
      if $cond {
        IResult::Error($err)
      } else {
        IResult::Done($i, ())
      }
    }
  );
  ($i:expr, $cond:expr, $err:expr) => (
    error!($i, $cond, $err);
  );
);

pub fn bytes_to_u64(s: &[u8]) -> Result<u64, &'static str> {
    let mut u = 0;

    for &c in s {
        u *= 256;
        u += c as u64;
    }

    Ok(u)
}

#[macro_use]
macro_rules! parse_hex_to_u64 (
    ( $i:expr, $size:expr ) => (
        map_res!($i, take!(($size as usize)), $crate::bytes_to_u64)
    );
);

#[macro_use]
named!(pub parse_uint24<&[u8], u64>, parse_hex_to_u64!(3));

//named!(parse_hex4<&[u8], u64>, parse_hex_to_u64!(4));
<commit_msg>Add curves identifiers from RFC7919<commit_after>#[derive(Debug)]
pub enum IntToEnumError {
    InvalidU8(u8),
    InvalidU16(u16),
}

/// Named curves, as defined in [RFC4492], [RFC7027], [RFC7919]
enum_from_primitive! {
#[derive(Debug)]
#[repr(u16)]
pub enum NamedCurve {
    Sect163k1 = 1,
    Sect163r1 = 2,
    Sect163r2 = 3,
    Sect193r1 = 4,
    Sect193r2 = 5,
    Sect233k1 = 6,
    Sect233r1 = 7,
    Sect239k1 = 8,
    Sect283k1 = 9,
    Sect283r1 = 10,
    Sect409k1 = 11,
    Sect409r1 = 12,
    Sect571k1 = 13,
    Sect571r1 = 14,
    Secp160k1 = 15,
    Secp160r1 = 16,
    Secp160r2 = 17,
    Secp192k1 = 18,
    Secp192r1 = 19,
    Secp224k1 = 20,
    Secp224r1 = 21,
    Secp256k1 = 22,
    Secp256r1 = 23,
    Secp384r1 = 24,
    Secp521r1 = 25,
    BrainpoolP256r1 = 26,
    BrainpoolP384r1 = 27,
    BrainpoolP512r1 = 28,
    EcdhX25519 = 29,
    EcdhX448 = 30,
    Ffdhe2048 = 0x100,
    Ffdhe3072 = 0x101,
    Ffdhe4096 = 0x102,
    Ffdhe6144 = 0x103,
    Ffdhe8192 = 0x104,
    ArbitraryExplicitPrimeCurves = 0xFF01,
    ArbitraryExplicitChar2Curves = 0xFF02,
}
}

/// Hash algorithms, as defined in [RFC5246]
enum_from_primitive! {
#[derive(Debug)]
#[repr(u8)]
pub enum HashAlgorithm {
    None = 0,
    Md5 = 1,
    Sha1 = 2,
    Sha224 = 3,
    Sha256 = 4,
    Sha384 = 5,
    Sha512 = 6,
}
}

/// Signature algorithms, as defined in [RFC5246]
enum_from_primitive! {
#[derive(Debug)]
#[repr(u8)]
pub enum SignatureAlgorithm {
    Anonymous = 0,
    Rsa = 1,
    Dsa = 2,
    Ecdsa = 3,
}
}

#[macro_export]
macro_rules! error_if (
  ($i:expr, $cond:expr, $err:expr) => (
    {
      if $cond {
        IResult::Error($err)
      } else {
        IResult::Done($i, ())
      }
    }
  );
  ($i:expr, $cond:expr, $err:expr) => (
    error!($i, $cond, $err);
  );
);

pub fn bytes_to_u64(s: &[u8]) -> Result<u64, &'static str> {
    let mut u = 0;

    for &c in s {
        u *= 256;
        u += c as u64;
    }

    Ok(u)
}

#[macro_use]
macro_rules! parse_hex_to_u64 (
    ( $i:expr, $size:expr ) => (
        map_res!($i, take!(($size as usize)), $crate::bytes_to_u64)
    );
);

#[macro_use]
named!(pub parse_uint24<&[u8], u64>, parse_hex_to_u64!(3));

//named!(parse_hex4<&[u8], u64>, parse_hex_to_u64!(4));
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate toml;

use lists::{SeparatorTactic, ListTactic};

macro_rules! configuration_option_enum{
    ($e:ident: $( $x:ident ),+ $(,)*) => {
        #[derive(Copy, Clone, Eq, PartialEq, Debug)]
        pub enum $e {
            $( $x ),+
        }

        impl_enum_decodable!($e, $( $x ),+);
    }
}

configuration_option_enum! { NewlineStyle:
    Windows, // \r\n
    Unix, // \n
    Native, // \r\n in Windows, \n on other platforms
}

configuration_option_enum! { BraceStyle:
    AlwaysNextLine,
    PreferSameLine,
    // Prefer same line except where there is a where clause, in which case force
    // the brace to the next line.
    SameLineWhere,
}

// How to indent a function's return type.
configuration_option_enum! { ReturnIndent:
    // Aligned with the arguments
    WithArgs,
    // Aligned with the where clause
    WithWhereClause,
}

// How to stle a struct literal.
configuration_option_enum! { StructLitStyle:
    // First line on the same line as the opening brace, all lines aligned with
    // the first line.
    Visual,
    // First line is on a new line and all lines align with block indent.
    Block,
    // FIXME Maybe we should also have an option to align types.
}

configuration_option_enum! { BlockIndentStyle:
    // Same level as parent.
    Inherit,
    // One level deeper than parent.
    Tabbed,
    // Aligned with block open.
    Visual,
}

configuration_option_enum! { Density:
    // Fit as much on one line as possible.
    Compressed,
    // Use more lines.
    Tall,
    // Try to compress if the body is empty.
    CompressedIfEmpty,
}

configuration_option_enum! { TypeDensity:
    // No spaces around "=" and "+"
    Compressed,
    // Spaces around " = " and " + "
    Wide,
}

impl Density {
    pub fn to_list_tactic(self) -> ListTactic {
        match self {
            Density::Compressed => ListTactic::Mixed,
            Density::Tall | Density::CompressedIfEmpty => ListTactic::HorizontalVertical,
        }
    }
}

configuration_option_enum! { LicensePolicy:
    // Do not place license text at top of files
    NoLicense,
    // Use the text in "license" field as the license
    TextLicense,
    // Use a text file as the license text
    FileLicense,
}

configuration_option_enum! { MultilineStyle:
    // Use horizontal layout if it fits in one line, fall back to vertical
    PreferSingle,
    // Use vertical layout
    ForceMulti,
}

impl MultilineStyle {
    pub fn to_list_tactic(self) -> ListTactic {
        match self {
            MultilineStyle::PreferSingle => ListTactic::HorizontalVertical,
            MultilineStyle::ForceMulti => ListTactic::Vertical,
        }
    }
}

configuration_option_enum! { ReportTactic:
    Always,
    Unnumbered,
    Never,
}

configuration_option_enum! { WriteMode:
    // Used internally to represent when no option is given
    // Treated as Replace.
    Default,
    // Backsup the original file and overwrites the orignal.
    Replace,
    // Overwrites original file without backup.
    Overwrite,
    // Write the output to stdout.
    Display,
    // Write the diff to stdout.
    Diff,
    // Display how much of the input file was processed
    Coverage,
    // Unfancy stdout
    Plain,
    // Output a checkstyle XML file.
    Checkstyle,
}

// This trait and the following impl blocks are there so that we an use
// UCFS inside the get_docs() function on types for configs.
pub trait ConfigType {
    fn get_variant_names() -> String;
}

impl ConfigType for bool {
    fn get_variant_names() -> String {
        String::from("<boolean>")
    }
}

impl ConfigType for usize {
    fn get_variant_names() -> String {
        String::from("<unsigned integer>")
    }
}

impl ConfigType for String {
    fn get_variant_names() -> String {
        String::from("<string>")
    }
}

pub struct ConfigHelpItem {
    option_name: &'static str,
    doc_string: &'static str,
    variant_names: String,
    default: &'static str,
}

impl ConfigHelpItem {
    pub fn option_name(&self) -> &'static str {
        self.option_name
    }

    pub fn doc_string(&self) -> &'static str {
        self.doc_string
    }

    pub fn variant_names(&self) -> &String {
        &self.variant_names
    }

    pub fn default(&self) -> &'static str {
        self.default
    }
}

macro_rules! create_config {
    ($($i:ident: $ty:ty, $def:expr, $( $dstring:expr ),+ );+ $(;)*) => (
        #[derive(RustcDecodable, Clone)]
        pub struct Config {
            $(pub $i: $ty),+
        }

        // Just like the Config struct but with each property wrapped
        // as Option<T>. This is used to parse a rustfmt.toml that doesn't
        // specity all properties of `Config`.
        // We first parse into `ParsedConfig`, then create a default `Config`
        // and overwrite the properties with corresponding values from `ParsedConfig`
        #[derive(RustcDecodable, Clone)]
        pub struct ParsedConfig {
            $(pub $i: Option<$ty>),+
        }

        impl Config {

            fn fill_from_parsed_config(mut self, parsed: ParsedConfig) -> Config {
            $(
                if let Some(val) = parsed.$i {
                    self.$i = val;
                }
            )+
                self
            }

            pub fn from_toml(toml: &str) -> Config {
                let parsed = toml.parse().unwrap();
                let parsed_config:ParsedConfig = match toml::decode(parsed) {
                    Some(decoded) => decoded,
                    None => {
                        println!("Decoding config file failed. Config:\n{}", toml);
                        let parsed: toml::Value = toml.parse().unwrap();
                        println!("\n\nParsed:\n{:?}", parsed);
                        panic!();
                    }
                };
                Config::default().fill_from_parsed_config(parsed_config)
            }

            pub fn override_value(&mut self, key: &str, val: &str) {
                match key {
                    $(
                        stringify!($i) => {
                            self.$i = val.parse::<$ty>().unwrap();
                        }
                    )+
                    _ => panic!("Bad config key!")
                }
            }

            pub fn print_docs() {
                use std::cmp;
                let max = 0;
                $( let max = cmp::max(max, stringify!($i).len()+1); )+
                let mut space_str = String::with_capacity(max);
                for _ in 0..max {
                    space_str.push(' ');
                }
                println!("Configuration Options:");
                $(
                    let name_raw = stringify!($i);
                    let mut name_out = String::with_capacity(max);
                    for _ in name_raw.len()..max-1 {
                        name_out.push(' ')
                    }
                    name_out.push_str(name_raw);
                    name_out.push(' ');
                    println!("{}{} Default: {:?}",
                             name_out,
                             <$ty>::get_variant_names(),
                             $def);
                    $(
                        println!("{}{}", space_str, $dstring);
                    )+
                    println!("");
                )+
            }
        }

        // Template for the default configuration
        impl Default for Config {
            fn default() -> Config {
                Config {
                    $(
                        $i: $def,
                    )+
                }
            }
        }
    )
}

create_config! {
    verbose: bool, false, "Use verbose output";
    skip_children: bool, false, "Don't reformat out of line modules";
    max_width: usize, 100, "Maximum width of each line";
    ideal_width: usize, 80, "Ideal width of each line";
    tab_spaces: usize, 4, "Number of spaces per tab";
    fn_call_width: usize, 60,
        "Maximum width of the args of a function call before falling back to vertical formatting";
    struct_lit_width: usize, 16,
        "Maximum width in the body of a struct lit before falling back to vertical formatting";
    newline_style: NewlineStyle, NewlineStyle::Unix, "Unix or Windows line endings";
    fn_brace_style: BraceStyle, BraceStyle::SameLineWhere, "Brace style for functions";
    item_brace_style: BraceStyle, BraceStyle::SameLineWhere, "Brace style for structs and enums";
    impl_empty_single_line: bool, true, "Put empty-body implementations on a single line";
    fn_empty_single_line: bool, true, "Put empty-body functions on a single line";
    fn_single_line: bool, false, "Put single-expression functions on a single line";
    fn_return_indent: ReturnIndent, ReturnIndent::WithArgs,
        "Location of return type in function declaration";
    fn_args_paren_newline: bool, true, "If function argument parenthesis goes on a newline";
    fn_args_density: Density, Density::Tall, "Argument density in functions";
    fn_args_layout: StructLitStyle, StructLitStyle::Visual, "Layout of function arguments";
    fn_arg_indent: BlockIndentStyle, BlockIndentStyle::Visual, "Indent on function arguments";
    type_punctuation_density: TypeDensity, TypeDensity::Wide,
        "Determines if '+' or '=' are wrapped in spaces in the punctuation of types";
    // Should we at least try to put the where clause on the same line as the rest of the
    // function decl?
    where_density: Density, Density::CompressedIfEmpty, "Density of a where clause";
    // Visual will be treated like Tabbed
    where_indent: BlockIndentStyle, BlockIndentStyle::Tabbed, "Indentation of a where clause";
    where_layout: ListTactic, ListTactic::Vertical, "Element layout inside a where clause";
    where_pred_indent: BlockIndentStyle, BlockIndentStyle::Visual,
        "Indentation style of a where predicate";
    where_trailing_comma: bool, false, "Put a trailing comma on where clauses";
    generics_indent: BlockIndentStyle, BlockIndentStyle::Visual, "Indentation of generics";
    struct_trailing_comma: SeparatorTactic, SeparatorTactic::Vertical,
        "If there is a trailing comma on structs";
    struct_lit_trailing_comma: SeparatorTactic, SeparatorTactic::Vertical,
        "If there is a trailing comma on literal structs";
    struct_lit_style: StructLitStyle, StructLitStyle::Block, "Style of struct definition";
    struct_lit_multiline_style: MultilineStyle, MultilineStyle::PreferSingle,
        "Multiline style on literal structs";
    enum_trailing_comma: bool, true, "Put a trailing comma on enum declarations";
    report_todo: ReportTactic, ReportTactic::Always,
        "Report all, none or unnumbered occurrences of TODO in source file comments";
    report_fixme: ReportTactic, ReportTactic::Never,
        "Report all, none or unnumbered occurrences of FIXME in source file comments";
    chain_base_indent: BlockIndentStyle, BlockIndentStyle::Visual, "Indent on chain base";
    chain_indent: BlockIndentStyle, BlockIndentStyle::Visual, "Indentation of chain";
    reorder_imports: bool, false, "Reorder import statements alphabetically";
    single_line_if_else: bool, false, "Put else on same line as closing brace for if statements";
    format_strings: bool, true, "Format string literals, or leave as is";
    chains_overflow_last: bool, true, "Allow last call in method chain to break the line";
    take_source_hints: bool, true, "Retain some formatting characteristics from the source code";
    hard_tabs: bool, false, "Use tab characters for indentation, spaces for alignment";
    wrap_comments: bool, false, "Break comments to fit on the line";
    normalise_comments: bool, true, "Convert /* */ comments to // comments where possible";
    wrap_match_arms: bool, true, "Wrap multiline match arms in blocks";
    match_block_trailing_comma: bool, false,
        "Put a trailing comma after a block based match arm (non-block arms are not affected)";
    match_wildcard_trailing_comma: bool, true, "Put a trailing comma after a wildcard arm";
    write_mode: WriteMode, WriteMode::Default,
        "What Write Mode to use when none is supplied: Replace, Overwrite, Display, Diff, Coverage";
}
<commit_msg>config: Disable report_todo by default<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate toml;

use lists::{SeparatorTactic, ListTactic};

macro_rules! configuration_option_enum{
    ($e:ident: $( $x:ident ),+ $(,)*) => {
        #[derive(Copy, Clone, Eq, PartialEq, Debug)]
        pub enum $e {
            $( $x ),+
        }

        impl_enum_decodable!($e, $( $x ),+);
    }
}

configuration_option_enum! { NewlineStyle:
    Windows, // \r\n
    Unix, // \n
    Native, // \r\n in Windows, \n on other platforms
}

configuration_option_enum! { BraceStyle:
    AlwaysNextLine,
    PreferSameLine,
    // Prefer same line except where there is a where clause, in which case force
    // the brace to the next line.
    SameLineWhere,
}

// How to indent a function's return type.
configuration_option_enum! { ReturnIndent:
    // Aligned with the arguments
    WithArgs,
    // Aligned with the where clause
    WithWhereClause,
}

// How to stle a struct literal.
configuration_option_enum! { StructLitStyle:
    // First line on the same line as the opening brace, all lines aligned with
    // the first line.
    Visual,
    // First line is on a new line and all lines align with block indent.
    Block,
    // FIXME Maybe we should also have an option to align types.
}

configuration_option_enum! { BlockIndentStyle:
    // Same level as parent.
    Inherit,
    // One level deeper than parent.
    Tabbed,
    // Aligned with block open.
    Visual,
}

configuration_option_enum! { Density:
    // Fit as much on one line as possible.
    Compressed,
    // Use more lines.
    Tall,
    // Try to compress if the body is empty.
    CompressedIfEmpty,
}

configuration_option_enum! { TypeDensity:
    // No spaces around "=" and "+"
    Compressed,
    // Spaces around " = " and " + "
    Wide,
}

impl Density {
    pub fn to_list_tactic(self) -> ListTactic {
        match self {
            Density::Compressed => ListTactic::Mixed,
            Density::Tall | Density::CompressedIfEmpty => ListTactic::HorizontalVertical,
        }
    }
}

configuration_option_enum! { LicensePolicy:
    // Do not place license text at top of files
    NoLicense,
    // Use the text in "license" field as the license
    TextLicense,
    // Use a text file as the license text
    FileLicense,
}

configuration_option_enum! { MultilineStyle:
    // Use horizontal layout if it fits in one line, fall back to vertical
    PreferSingle,
    // Use vertical layout
    ForceMulti,
}

impl MultilineStyle {
    pub fn to_list_tactic(self) -> ListTactic {
        match self {
            MultilineStyle::PreferSingle => ListTactic::HorizontalVertical,
            MultilineStyle::ForceMulti => ListTactic::Vertical,
        }
    }
}

configuration_option_enum! { ReportTactic:
    Always,
    Unnumbered,
    Never,
}

configuration_option_enum! { WriteMode:
    // Used internally to represent when no option is given
    // Treated as Replace.
    Default,
    // Backsup the original file and overwrites the orignal.
    Replace,
    // Overwrites original file without backup.
    Overwrite,
    // Write the output to stdout.
    Display,
    // Write the diff to stdout.
    Diff,
    // Display how much of the input file was processed
    Coverage,
    // Unfancy stdout
    Plain,
    // Output a checkstyle XML file.
    Checkstyle,
}

// This trait and the following impl blocks are there so that we an use
// UCFS inside the get_docs() function on types for configs.
pub trait ConfigType {
    fn get_variant_names() -> String;
}

impl ConfigType for bool {
    fn get_variant_names() -> String {
        String::from("<boolean>")
    }
}

impl ConfigType for usize {
    fn get_variant_names() -> String {
        String::from("<unsigned integer>")
    }
}

impl ConfigType for String {
    fn get_variant_names() -> String {
        String::from("<string>")
    }
}

pub struct ConfigHelpItem {
    option_name: &'static str,
    doc_string: &'static str,
    variant_names: String,
    default: &'static str,
}

impl ConfigHelpItem {
    pub fn option_name(&self) -> &'static str {
        self.option_name
    }

    pub fn doc_string(&self) -> &'static str {
        self.doc_string
    }

    pub fn variant_names(&self) -> &String {
        &self.variant_names
    }

    pub fn default(&self) -> &'static str {
        self.default
    }
}

macro_rules! create_config {
    ($($i:ident: $ty:ty, $def:expr, $( $dstring:expr ),+ );+ $(;)*) => (
        #[derive(RustcDecodable, Clone)]
        pub struct Config {
            $(pub $i: $ty),+
        }

        // Just like the Config struct but with each property wrapped
        // as Option<T>. This is used to parse a rustfmt.toml that doesn't
        // specity all properties of `Config`.
        // We first parse into `ParsedConfig`, then create a default `Config`
        // and overwrite the properties with corresponding values from `ParsedConfig`
        #[derive(RustcDecodable, Clone)]
        pub struct ParsedConfig {
            $(pub $i: Option<$ty>),+
        }

        impl Config {

            fn fill_from_parsed_config(mut self, parsed: ParsedConfig) -> Config {
            $(
                if let Some(val) = parsed.$i {
                    self.$i = val;
                }
            )+
                self
            }

            pub fn from_toml(toml: &str) -> Config {
                let parsed = toml.parse().unwrap();
                let parsed_config:ParsedConfig = match toml::decode(parsed) {
                    Some(decoded) => decoded,
                    None => {
                        println!("Decoding config file failed. Config:\n{}", toml);
                        let parsed: toml::Value = toml.parse().unwrap();
                        println!("\n\nParsed:\n{:?}", parsed);
                        panic!();
                    }
                };
                Config::default().fill_from_parsed_config(parsed_config)
            }

            pub fn override_value(&mut self, key: &str, val: &str) {
                match key {
                    $(
                        stringify!($i) => {
                            self.$i = val.parse::<$ty>().unwrap();
                        }
                    )+
                    _ => panic!("Bad config key!")
                }
            }

            pub fn print_docs() {
                use std::cmp;
                let max = 0;
                $( let max = cmp::max(max, stringify!($i).len()+1); )+
                let mut space_str = String::with_capacity(max);
                for _ in 0..max {
                    space_str.push(' ');
                }
                println!("Configuration Options:");
                $(
                    let name_raw = stringify!($i);
                    let mut name_out = String::with_capacity(max);
                    for _ in name_raw.len()..max-1 {
                        name_out.push(' ')
                    }
                    name_out.push_str(name_raw);
                    name_out.push(' ');
                    println!("{}{} Default: {:?}",
                             name_out,
                             <$ty>::get_variant_names(),
                             $def);
                    $(
                        println!("{}{}", space_str, $dstring);
                    )+
                    println!("");
                )+
            }
        }

        // Template for the default configuration
        impl Default for Config {
            fn default() -> Config {
                Config {
                    $(
                        $i: $def,
                    )+
                }
            }
        }
    )
}

create_config! {
    verbose: bool, false, "Use verbose output";
    skip_children: bool, false, "Don't reformat out of line modules";
    max_width: usize, 100, "Maximum width of each line";
    ideal_width: usize, 80, "Ideal width of each line";
    tab_spaces: usize, 4, "Number of spaces per tab";
    fn_call_width: usize, 60,
        "Maximum width of the args of a function call before falling back to vertical formatting";
    struct_lit_width: usize, 16,
        "Maximum width in the body of a struct lit before falling back to vertical formatting";
    newline_style: NewlineStyle, NewlineStyle::Unix, "Unix or Windows line endings";
    fn_brace_style: BraceStyle, BraceStyle::SameLineWhere, "Brace style for functions";
    item_brace_style: BraceStyle, BraceStyle::SameLineWhere, "Brace style for structs and enums";
    impl_empty_single_line: bool, true, "Put empty-body implementations on a single line";
    fn_empty_single_line: bool, true, "Put empty-body functions on a single line";
    fn_single_line: bool, false, "Put single-expression functions on a single line";
    fn_return_indent: ReturnIndent, ReturnIndent::WithArgs,
        "Location of return type in function declaration";
    fn_args_paren_newline: bool, true, "If function argument parenthesis goes on a newline";
    fn_args_density: Density, Density::Tall, "Argument density in functions";
    fn_args_layout: StructLitStyle, StructLitStyle::Visual, "Layout of function arguments";
    fn_arg_indent: BlockIndentStyle, BlockIndentStyle::Visual, "Indent on function arguments";
    type_punctuation_density: TypeDensity, TypeDensity::Wide,
        "Determines if '+' or '=' are wrapped in spaces in the punctuation of types";
    // Should we at least try to put the where clause on the same line as the rest of the
    // function decl?
    where_density: Density, Density::CompressedIfEmpty, "Density of a where clause";
    // Visual will be treated like Tabbed
    where_indent: BlockIndentStyle, BlockIndentStyle::Tabbed, "Indentation of a where clause";
    where_layout: ListTactic, ListTactic::Vertical, "Element layout inside a where clause";
    where_pred_indent: BlockIndentStyle, BlockIndentStyle::Visual,
        "Indentation style of a where predicate";
    where_trailing_comma: bool, false, "Put a trailing comma on where clauses";
    generics_indent: BlockIndentStyle, BlockIndentStyle::Visual, "Indentation of generics";
    struct_trailing_comma: SeparatorTactic, SeparatorTactic::Vertical,
        "If there is a trailing comma on structs";
    struct_lit_trailing_comma: SeparatorTactic, SeparatorTactic::Vertical,
        "If there is a trailing comma on literal structs";
    struct_lit_style: StructLitStyle, StructLitStyle::Block, "Style of struct definition";
    struct_lit_multiline_style: MultilineStyle, MultilineStyle::PreferSingle,
        "Multiline style on literal structs";
    enum_trailing_comma: bool, true, "Put a trailing comma on enum declarations";
    report_todo: ReportTactic, ReportTactic::Never,
        "Report all, none or unnumbered occurrences of TODO in source file comments";
    report_fixme: ReportTactic, ReportTactic::Never,
        "Report all, none or unnumbered occurrences of FIXME in source file comments";
    chain_base_indent: BlockIndentStyle, BlockIndentStyle::Visual, "Indent on chain base";
    chain_indent: BlockIndentStyle, BlockIndentStyle::Visual, "Indentation of chain";
    reorder_imports: bool, false, "Reorder import statements alphabetically";
    single_line_if_else: bool, false, "Put else on same line as closing brace for if statements";
    format_strings: bool, true, "Format string literals, or leave as is";
    chains_overflow_last: bool, true, "Allow last call in method chain to break the line";
    take_source_hints: bool, true, "Retain some formatting characteristics from the source code";
    hard_tabs: bool, false, "Use tab characters for indentation, spaces for alignment";
    wrap_comments: bool, false, "Break comments to fit on the line";
    normalise_comments: bool, true, "Convert /* */ comments to // comments where possible";
    wrap_match_arms: bool, true, "Wrap multiline match arms in blocks";
    match_block_trailing_comma: bool, false,
        "Put a trailing comma after a block based match arm (non-block arms are not affected)";
    match_wildcard_trailing_comma: bool, true, "Put a trailing comma after a wildcard arm";
    write_mode: WriteMode, WriteMode::Default,
        "What Write Mode to use when none is supplied: Replace, Overwrite, Display, Diff, Coverage";
}
<|endoftext|>


<commit_before>use value::Value;
use source::Source;

use std::env;
use std::error::Error;
use std::collections::HashMap;
use std::borrow::Cow;

#[derive(Default)]
pub struct Config {
    env_prefix: Option<String>,

    defaults: HashMap<String, Value>,
    overrides: HashMap<String, Value>,
    environ: HashMap<String, Value>,
    sources: Vec<HashMap<String, Value>>,
}

impl Config {
    pub fn new() -> Config {
        Default::default()
    }

    /// Merge in configuration values from the given source.
    pub fn merge<T>(&mut self, mut source: T) -> Result<(), Box<Error>>
        where T: Source
    {
        self.sources.push(source.build()?);

        Ok(())
    }

    /// Defines a prefix that environment variables
    /// must start with to be considered.
    ///
    /// By default all environment variables are considered. This can lead to unexpected values
    /// in configuration (eg. `PATH`).
    pub fn set_env_prefix(&mut self, prefix: &str) {
        self.env_prefix = Some(prefix.to_uppercase());
    }

    /// Sets the default value for this key. The default value is only used
    /// when no other value is provided.
    pub fn set_default<T>(&mut self, key: &str, value: T)
        where T: Into<Value>
    {
        self.defaults.insert(key.to_lowercase(), value.into());
    }

    /// Sets an override for this key.
    pub fn set<T>(&mut self, key: &str, value: T)
        where T: Into<Value>
    {
        self.overrides.insert(key.to_lowercase(), value.into());
    }

    pub fn get<'a>(&'a mut self, key: &str) -> Option<&'a Value> {
        // Check explicit override

        if let Some(value) = self.overrides.get(key) {
            return Some(value);
        }

        // Check environment

        // Transform key into an env_key which is uppercased
        // and has the optional prefix applied
        let mut env_key = String::new();

        if let Some(ref env_prefix) = self.env_prefix {
            env_key.push_str(env_prefix);
            env_key.push('_');
        }

        env_key.push_str(&key.to_uppercase());

        if let Ok(value) = env::var(env_key.clone()) {
            // TODO: Find a better way to do this?
            self.environ.insert(key.into(), value.into());
            return self.environ.get(key);
        }

        // Check sources

        for source in &mut self.sources.iter().rev() {
            if let Some(value) = source.get(key) {
                return Some(value);
            }
        }

        // Check explicit defaults

        if let Some(value) = self.defaults.get(key) {
            return Some(value);
        }

        None
    }

    pub fn get_str<'a>(&'a mut self, key: &str) -> Option<Cow<'a, str>> {
        if let Some(value) = self.get(key) {
            value.as_str()
        } else {
            None
        }
    }

    pub fn get_int(&mut self, key: &str) -> Option<i64> {
        if let Some(value) = self.get(key) {
            value.as_int()
        } else {
            None
        }
    }

    pub fn get_float(&mut self, key: &str) -> Option<f64> {
        if let Some(value) = self.get(key) {
            value.as_float()
        } else {
            None
        }
    }

    pub fn get_bool(&mut self, key: &str) -> Option<bool> {
        if let Some(value) = self.get(key) {
            value.as_bool()
        } else {
            None
        }
    }
}

#[cfg(test)]
mod test {
    // use std::env;
    use super::Config;

    // Retrieval of a non-existent key
    #[test]
    fn test_not_found() {
        let mut c = Config::new();

        assert_eq!(c.get_int("key"), None);
    }

    // // Environment override
    // #[test]
    // fn test_env_override() {
    //     let mut c = Config::new();

    //     c.set_default("key_1", false);

    //     env::set_var("KEY_1", "1");

    //     assert_eq!(c.get_bool("key_1"), Some(true));

    //     // TODO(@rust): Is there a way to easily kill this at the end of a test?
    //     env::remove_var("KEY_1");
    // }

    // // Environment prefix
    // #[test]
    // fn test_env_prefix() {
    //     let mut c = Config::new();

    //     env::set_var("KEY_1", "1");
    //     env::set_var("CFG_KEY_2", "false");

    //     c.set_env_prefix("CFG");

    //     assert_eq!(c.get_bool("key_1"), None);
    //     assert_eq!(c.get_bool("key_2"), Some(false));

    //     // TODO(@rust): Is there a way to easily kill this at the end of a test?
    //     env::remove_var("KEY_1");
    //     env::remove_var("CFG_KEY_2");
    // }

    // Explicit override
    #[test]
    fn test_default_override() {
        let mut c = Config::new();

        c.set_default("key_1", false);
        c.set_default("key_2", false);

        assert!(!c.get_bool("key_1").unwrap());
        assert!(!c.get_bool("key_2").unwrap());

        c.set("key_2", true);

        assert!(!c.get_bool("key_1").unwrap());
        assert!(c.get_bool("key_2").unwrap());
    }

    // Storage and retrieval of String values
    #[test]
    fn test_str() {
        let mut c = Config::new();

        c.set("key", "value");

        assert_eq!(c.get_str("key").unwrap(), "value");
    }

    // Storage and retrieval of Boolean values
    #[test]
    fn test_bool() {
        let mut c = Config::new();

        c.set("key", true);

        assert_eq!(c.get_bool("key").unwrap(), true);
    }

    // Storage and retrieval of Float values
    #[test]
    fn test_float() {
        let mut c = Config::new();

        c.set("key", 3.14);

        assert_eq!(c.get_float("key").unwrap(), 3.14);
    }

    // Storage and retrieval of Integer values
    #[test]
    fn test_int() {
        let mut c = Config::new();

        c.set("key", 42);

        assert_eq!(c.get_int("key").unwrap(), 42);
    }

    // Storage of various values and retrieval as String
    #[test]
    fn test_retrieve_str() {
        let mut c = Config::new();

        c.set("key_1", 115);
        c.set("key_2", 1.23);
        c.set("key_3", false);

        assert_eq!(c.get_str("key_1").unwrap(), "115");
        assert_eq!(c.get_str("key_2").unwrap(), "1.23");
        assert_eq!(c.get_str("key_3").unwrap(), "false");
    }

    // Storage of various values and retrieval as Integer
    #[test]
    fn test_retrieve_int() {
        let mut c = Config::new();

        c.set("key_1", "121");
        c.set("key_2", 5.12);
        c.set("key_3", 5.72);
        c.set("key_4", false);
        c.set("key_5", true);
        c.set("key_6", "asga");

        assert_eq!(c.get_int("key_1"), Some(121));
        assert_eq!(c.get_int("key_2"), Some(5));
        assert_eq!(c.get_int("key_3"), Some(6));
        assert_eq!(c.get_int("key_4"), Some(0));
        assert_eq!(c.get_int("key_5"), Some(1));
        assert_eq!(c.get_int("key_6"), None);
    }

    // Storage of various values and retrieval as Float
    #[test]
    fn test_retrieve_float() {
        let mut c = Config::new();

        c.set("key_1", "121");
        c.set("key_2", "121.512");
        c.set("key_3", 5);
        c.set("key_4", false);
        c.set("key_5", true);
        c.set("key_6", "asga");

        assert_eq!(c.get_float("key_1"), Some(121.0));
        assert_eq!(c.get_float("key_2"), Some(121.512));
        assert_eq!(c.get_float("key_3"), Some(5.0));
        assert_eq!(c.get_float("key_4"), Some(0.0));
        assert_eq!(c.get_float("key_5"), Some(1.0));
        assert_eq!(c.get_float("key_6"), None);
    }

    // Storage of various values and retrieval as Boolean
    #[test]
    fn test_retrieve_bool() {
        let mut c = Config::new();

        c.set("key_1", "121");
        c.set("key_2", "1");
        c.set("key_3", "0");
        c.set("key_4", "true");
        c.set("key_5", "");
        c.set("key_6", 51);
        c.set("key_7", 0);
        c.set("key_8", 12.12);
        c.set("key_9", 1.0);
        c.set("key_10", 0.0);
        c.set("key_11", "asga");

        assert_eq!(c.get_bool("key_1"), Some(false));
        assert_eq!(c.get_bool("key_2"), Some(true));
        assert_eq!(c.get_bool("key_3"), Some(false));
        assert_eq!(c.get_bool("key_4"), Some(true));
        assert_eq!(c.get_bool("key_5"), Some(false));
        assert_eq!(c.get_bool("key_6"), Some(true));
        assert_eq!(c.get_bool("key_7"), Some(false));
        assert_eq!(c.get_bool("key_8"), Some(true));
        assert_eq!(c.get_bool("key_9"), Some(true));
        assert_eq!(c.get_bool("key_10"), Some(false));
        assert_eq!(c.get_bool("key_11"), Some(false));
    }
}
<commit_msg>:green_heart:<commit_after>use value::Value;
use source::Source;

use std::env;
use std::error::Error;
use std::collections::HashMap;
use std::borrow::Cow;

#[derive(Default)]
pub struct Config {
    env_prefix: Option<String>,

    defaults: HashMap<String, Value>,
    overrides: HashMap<String, Value>,
    environ: HashMap<String, Value>,
    sources: Vec<HashMap<String, Value>>,
}

impl Config {
    pub fn new() -> Config {
        Default::default()
    }

    /// Merge in configuration values from the given source.
    pub fn merge<T>(&mut self, mut source: T) -> Result<(), Box<Error>>
        where T: Source
    {
        self.sources.push(source.build()?);

        Ok(())
    }

    /// Defines a prefix that environment variables
    /// must start with to be considered.
    ///
    /// By default all environment variables are considered. This can lead to unexpected values
    /// in configuration (eg. `PATH`).
    pub fn set_env_prefix(&mut self, prefix: &str) {
        self.env_prefix = Some(prefix.to_uppercase());
    }

    /// Sets the default value for this key. The default value is only used
    /// when no other value is provided.
    pub fn set_default<T>(&mut self, key: &str, value: T)
        where T: Into<Value>
    {
        self.defaults.insert(key.to_lowercase(), value.into());
    }

    /// Sets an override for this key.
    pub fn set<T>(&mut self, key: &str, value: T)
        where T: Into<Value>
    {
        self.overrides.insert(key.to_lowercase(), value.into());
    }

    pub fn get<'a>(&'a mut self, key: &str) -> Option<&'a Value> {
        // Check explicit override

        if let Some(value) = self.overrides.get(key) {
            return Some(value);
        }

        // Check environment

        // Transform key into an env_key which is uppercased
        // and has the optional prefix applied
        let mut env_key = String::new();

        if let Some(ref env_prefix) = self.env_prefix {
            env_key.push_str(env_prefix);
            env_key.push('_');
        }

        env_key.push_str(&key.to_uppercase());

        if let Ok(value) = env::var(env_key.clone()) {
            // TODO: Find a better way to do this?
            self.environ.insert(key.into(), value.into());
            return self.environ.get(key);
        }

        // Check sources

        for source in &mut self.sources.iter().rev() {
            if let Some(value) = source.get(key) {
                return Some(value);
            }
        }

        // Check explicit defaults

        if let Some(value) = self.defaults.get(key) {
            return Some(value);
        }

        None
    }

    pub fn get_str<'a>(&'a mut self, key: &str) -> Option<Cow<'a, str>> {
        self.get(key).and_then(Value::as_str)
    }

    pub fn get_int(&mut self, key: &str) -> Option<i64> {
        if let Some(value) = self.get(key) {
            value.as_int()
        } else {
            None
        }
    }

    pub fn get_float(&mut self, key: &str) -> Option<f64> {
        if let Some(value) = self.get(key) {
            value.as_float()
        } else {
            None
        }
    }

    pub fn get_bool(&mut self, key: &str) -> Option<bool> {
        if let Some(value) = self.get(key) {
            value.as_bool()
        } else {
            None
        }
    }
}

#[cfg(test)]
mod test {
    // use std::env;
    use super::Config;

    // Retrieval of a non-existent key
    #[test]
    fn test_not_found() {
        let mut c = Config::new();

        assert_eq!(c.get_int("key"), None);
    }

    // // Environment override
    // #[test]
    // fn test_env_override() {
    //     let mut c = Config::new();

    //     c.set_default("key_1", false);

    //     env::set_var("KEY_1", "1");

    //     assert_eq!(c.get_bool("key_1"), Some(true));

    //     // TODO(@rust): Is there a way to easily kill this at the end of a test?
    //     env::remove_var("KEY_1");
    // }

    // // Environment prefix
    // #[test]
    // fn test_env_prefix() {
    //     let mut c = Config::new();

    //     env::set_var("KEY_1", "1");
    //     env::set_var("CFG_KEY_2", "false");

    //     c.set_env_prefix("CFG");

    //     assert_eq!(c.get_bool("key_1"), None);
    //     assert_eq!(c.get_bool("key_2"), Some(false));

    //     // TODO(@rust): Is there a way to easily kill this at the end of a test?
    //     env::remove_var("KEY_1");
    //     env::remove_var("CFG_KEY_2");
    // }

    // Explicit override
    #[test]
    fn test_default_override() {
        let mut c = Config::new();

        c.set_default("key_1", false);
        c.set_default("key_2", false);

        assert!(!c.get_bool("key_1").unwrap());
        assert!(!c.get_bool("key_2").unwrap());

        c.set("key_2", true);

        assert!(!c.get_bool("key_1").unwrap());
        assert!(c.get_bool("key_2").unwrap());
    }

    // Storage and retrieval of String values
    #[test]
    fn test_str() {
        let mut c = Config::new();

        c.set("key", "value");

        assert_eq!(c.get_str("key").unwrap(), "value");
    }

    // Storage and retrieval of Boolean values
    #[test]
    fn test_bool() {
        let mut c = Config::new();

        c.set("key", true);

        assert_eq!(c.get_bool("key").unwrap(), true);
    }

    // Storage and retrieval of Float values
    #[test]
    fn test_float() {
        let mut c = Config::new();

        c.set("key", 3.14);

        assert_eq!(c.get_float("key").unwrap(), 3.14);
    }

    // Storage and retrieval of Integer values
    #[test]
    fn test_int() {
        let mut c = Config::new();

        c.set("key", 42);

        assert_eq!(c.get_int("key").unwrap(), 42);
    }

    // Storage of various values and retrieval as String
    #[test]
    fn test_retrieve_str() {
        let mut c = Config::new();

        c.set("key_1", 115);
        c.set("key_2", 1.23);
        c.set("key_3", false);

        assert_eq!(c.get_str("key_1").unwrap(), "115");
        assert_eq!(c.get_str("key_2").unwrap(), "1.23");
        assert_eq!(c.get_str("key_3").unwrap(), "false");
    }

    // Storage of various values and retrieval as Integer
    #[test]
    fn test_retrieve_int() {
        let mut c = Config::new();

        c.set("key_1", "121");
        c.set("key_2", 5.12);
        c.set("key_3", 5.72);
        c.set("key_4", false);
        c.set("key_5", true);
        c.set("key_6", "asga");

        assert_eq!(c.get_int("key_1"), Some(121));
        assert_eq!(c.get_int("key_2"), Some(5));
        assert_eq!(c.get_int("key_3"), Some(6));
        assert_eq!(c.get_int("key_4"), Some(0));
        assert_eq!(c.get_int("key_5"), Some(1));
        assert_eq!(c.get_int("key_6"), None);
    }

    // Storage of various values and retrieval as Float
    #[test]
    fn test_retrieve_float() {
        let mut c = Config::new();

        c.set("key_1", "121");
        c.set("key_2", "121.512");
        c.set("key_3", 5);
        c.set("key_4", false);
        c.set("key_5", true);
        c.set("key_6", "asga");

        assert_eq!(c.get_float("key_1"), Some(121.0));
        assert_eq!(c.get_float("key_2"), Some(121.512));
        assert_eq!(c.get_float("key_3"), Some(5.0));
        assert_eq!(c.get_float("key_4"), Some(0.0));
        assert_eq!(c.get_float("key_5"), Some(1.0));
        assert_eq!(c.get_float("key_6"), None);
    }

    // Storage of various values and retrieval as Boolean
    #[test]
    fn test_retrieve_bool() {
        let mut c = Config::new();

        c.set("key_1", "121");
        c.set("key_2", "1");
        c.set("key_3", "0");
        c.set("key_4", "true");
        c.set("key_5", "");
        c.set("key_6", 51);
        c.set("key_7", 0);
        c.set("key_8", 12.12);
        c.set("key_9", 1.0);
        c.set("key_10", 0.0);
        c.set("key_11", "asga");

        assert_eq!(c.get_bool("key_1"), None);
        assert_eq!(c.get_bool("key_2"), Some(true));
        assert_eq!(c.get_bool("key_3"), Some(false));
        assert_eq!(c.get_bool("key_4"), Some(true));
        assert_eq!(c.get_bool("key_5"), None);
        assert_eq!(c.get_bool("key_6"), Some(true));
        assert_eq!(c.get_bool("key_7"), Some(false));
        assert_eq!(c.get_bool("key_8"), Some(true));
        assert_eq!(c.get_bool("key_9"), Some(true));
        assert_eq!(c.get_bool("key_10"), Some(false));
        assert_eq!(c.get_bool("key_11"), None);
    }
}
<|endoftext|>


<commit_before>// Copyright:: Copyright (c) 2015-2016 Chef Software, Inc.
//
// The terms of the Evaluation Agreement (Bldr) between Chef Software Inc. and the party accessing
// this file ("Licensee") apply to Licensee's use of the Software until such time that the Software
// is made available under an open source license such as the Apache 2.0 License.

use std;
use std::fs::File;
use std::io::Read;
use std::net;
use std::path::Path;
use std::result;
use std::str::FromStr;

use toml;

use error::{Error, Result};

pub trait ConfigFile: Sized {
    type Error: std::error::Error + From<Error>;

    fn from_file<T: AsRef<Path>>(filepath: T) -> result::Result<Self, Self::Error> {
        let mut file = match File::open(filepath.as_ref()) {
            Ok(f) => f,
            Err(e) => return Err(Self::Error::from(Error::ConfigFileIO(e))),
        };
        let mut raw = String::new();
        match file.read_to_string(&mut raw) {
            Ok(_) => (),
            Err(e) => return Err(Self::Error::from(Error::ConfigFileIO(e))),
        }
        let mut parser = toml::Parser::new(&raw);
        match parser.parse() {
            Some(toml) => Self::from_toml(toml),
            None => {
                let msg = format_errors(&parser);
                Err(Self::Error::from(Error::ConfigFileSyntax(msg)))
            }
        }
    }

    fn from_toml(toml: toml::Table) -> result::Result<Self, Self::Error>;
}

pub trait ParseInto<T> {
    fn parse_into(&self, field: &'static str, out: &mut T) -> Result<bool>;
}

impl ParseInto<net::SocketAddrV4> for toml::Table {
    fn parse_into(&self, field: &'static str, out: &mut net::SocketAddrV4) -> Result<bool> {
        if let Some(val) = self.get(field) {
            if let Some(v) = val.as_str() {
                match net::SocketAddrV4::from_str(v) {
                    Ok(addr) => {
                        *out = addr;
                        Ok(true)
                    }
                    Err(_) => Err(Error::ConfigInvalidSocketAddrV4(field, val.clone())),
                }
            } else {
                Err(Error::ConfigInvalidSocketAddrV4(field, val.clone()))
            }
        } else {
            Ok(false)
        }
    }
}

impl ParseInto<net::Ipv4Addr> for toml::Table {
    fn parse_into(&self, field: &'static str, out: &mut net::Ipv4Addr) -> Result<bool> {
        if let Some(val) = self.get(field) {
            if let Some(v) = val.as_str() {
                match net::Ipv4Addr::from_str(v) {
                    Ok(addr) => {
                        *out = addr;
                        Ok(true)
                    }
                    Err(_) => Err(Error::ConfigInvalidIpv4Addr(field, val.clone())),
                }
            } else {
                Err(Error::ConfigInvalidIpv4Addr(field, val.clone()))
            }
        } else {
            Ok(false)
        }
    }
}

impl ParseInto<String> for toml::Table {
    fn parse_into(&self, field: &'static str, out: &mut String) -> Result<bool> {
        if let Some(val) = self.get(field) {
            if let Some(v) = val.as_str() {
                *out = v.to_string();
                Ok(true)
            } else {
                Err(Error::ConfigInvalidString(field, val.clone()))
            }
        } else {
            Ok(false)
        }
    }
}

fn format_errors(parser: &toml::Parser) -> String {
    let mut msg = String::new();
    for err in &parser.errors {
        let (loline, locol) = parser.to_linecol(err.lo);
        let (hiline, hicol) = parser.to_linecol(err.hi);
        msg.push_str(&format!("\t{}:{}-{}:{} error: {}\n",
                              loline,
                              locol,
                              hiline,
                              hicol,
                              err.desc));
    }
    msg
}
<commit_msg>Configure builder servers from file<commit_after>// Copyright:: Copyright (c) 2015-2016 Chef Software, Inc.
//
// The terms of the Evaluation Agreement (Bldr) between Chef Software Inc. and the party accessing
// this file ("Licensee") apply to Licensee's use of the Software until such time that the Software
// is made available under an open source license such as the Apache 2.0 License.

use std;
use std::fs::File;
use std::io::Read;
use std::net;
use std::path::Path;
use std::result;
use std::str::FromStr;

use toml;

use error::{Error, Result};

pub trait ConfigFile: Sized {
    type Error: std::error::Error + From<Error>;

    fn from_file<T: AsRef<Path>>(filepath: T) -> result::Result<Self, Self::Error> {
        let mut file = match File::open(filepath.as_ref()) {
            Ok(f) => f,
            Err(e) => return Err(Self::Error::from(Error::ConfigFileIO(e))),
        };
        let mut raw = String::new();
        match file.read_to_string(&mut raw) {
            Ok(_) => (),
            Err(e) => return Err(Self::Error::from(Error::ConfigFileIO(e))),
        }
        let mut parser = toml::Parser::new(&raw);
        match parser.parse() {
            Some(toml) => Self::from_toml(toml),
            None => {
                let msg = format_errors(&parser);
                Err(Self::Error::from(Error::ConfigFileSyntax(msg)))
            }
        }
    }

    fn from_toml(toml: toml::Table) -> result::Result<Self, Self::Error>;
}

pub trait ParseInto<T> {
    fn parse_into(&self, field: &'static str, out: &mut T) -> Result<bool>;
}

impl ParseInto<net::SocketAddrV4> for toml::Table {
    fn parse_into(&self, field: &'static str, out: &mut net::SocketAddrV4) -> Result<bool> {
        if let Some(val) = self.get(field) {
            if let Some(v) = val.as_str() {
                match net::SocketAddrV4::from_str(v) {
                    Ok(addr) => {
                        *out = addr;
                        Ok(true)
                    }
                    Err(_) => Err(Error::ConfigInvalidSocketAddrV4(field, val.clone())),
                }
            } else {
                Err(Error::ConfigInvalidSocketAddrV4(field, val.clone()))
            }
        } else {
            Ok(false)
        }
    }
}

impl ParseInto<net::Ipv4Addr> for toml::Table {
    fn parse_into(&self, field: &'static str, out: &mut net::Ipv4Addr) -> Result<bool> {
        if let Some(val) = self.get(field) {
            if let Some(v) = val.as_str() {
                match net::Ipv4Addr::from_str(v) {
                    Ok(addr) => {
                        *out = addr;
                        Ok(true)
                    }
                    Err(_) => Err(Error::ConfigInvalidIpv4Addr(field, val.clone())),
                }
            } else {
                Err(Error::ConfigInvalidIpv4Addr(field, val.clone()))
            }
        } else {
            Ok(false)
        }
    }
}

impl ParseInto<String> for toml::Table {
    fn parse_into(&self, field: &'static str, out: &mut String) -> Result<bool> {
        if let Some(val) = self.get(field) {
            if let Some(v) = val.as_str() {
                *out = v.to_string();
                Ok(true)
            } else {
                Err(Error::ConfigInvalidString(field, val.clone()))
            }
        } else {
            Ok(false)
        }
    }
}

impl ParseInto<usize> for toml::Table {
    fn parse_into(&self, field: &'static str, out: &mut usize) -> Result<bool> {
        if let Some(val) = self.get(field) {
            if let Some(v) = val.as_integer() {
                *out = v as usize;
                Ok(true)
            } else {
                Err(Error::ConfigInvalidString(field, val.clone()))
            }
        } else {
            Ok(false)
        }
    }
}

fn format_errors(parser: &toml::Parser) -> String {
    let mut msg = String::new();
    for err in &parser.errors {
        let (loline, locol) = parser.to_linecol(err.lo);
        let (hiline, hicol) = parser.to_linecol(err.hi);
        msg.push_str(&format!("\t{}:{}-{}:{} error: {}\n",
                              loline,
                              locol,
                              hiline,
                              hicol,
                              err.desc));
    }
    msg
}
<|endoftext|>


<commit_before>use mio::Token;

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct Cookie(u64);

impl Cookie {
    #[inline(always)]
    pub fn new(token: Token, nonce: u64) -> Cookie {
        // TODO: panic on overflow?
        Cookie((token.0 << 48) as u64 | (nonce & 0xFFFFFFFFFFFF))
    }

    #[inline(always)]
    pub fn token(self) -> Token {
        Token((self.0 >> 48) as usize)
    }

    #[inline(always)]
    pub fn nonce(self) -> u64 {
        self.0 & 0xFFFFFFFFFFFF
    }
}

#[cfg(test)]
mod tests {
    use super::Cookie;
    use mio::Token;

    #[test]
    fn round_trip() {
        let a = Cookie::new(Token(1), 1);
        assert_eq!(a.token(), Token(1));
        assert_eq!(a.nonce(), 1);
        let a = Cookie::new(Token((1 << 16) - 1), (1 << 48) - 1);
        assert_eq!(a.token(), Token((1 << 16) - 1));
        assert_eq!(a.nonce(), (1 << 48) - 1);
    }

    #[test]
    fn overflow() {
        let a = Cookie::new(Token((1 << 16) + 1), (1 << 48) + 1);
        assert_eq!(a.token(), Token(1));
        assert_eq!(a.nonce(), 1);
    }
}
<commit_msg>impl Display/Debug for Cookie<commit_after>use mio::Token;
use std::fmt;

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct Cookie(u64);

impl Cookie {
    #[inline(always)]
    pub fn new(token: Token, nonce: u64) -> Cookie {
        // TODO: panic on overflow?
        Cookie((token.0 << 48) as u64 | (nonce & 0xFFFFFFFFFFFF))
    }

    #[inline(always)]
    pub fn token(self) -> Token {
        Token((self.0 >> 48) as usize)
    }

    #[inline(always)]
    pub fn nonce(self) -> u64 {
        self.0 & 0xFFFFFFFFFFFF
    }
}

impl fmt::Display for Cookie {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        f.debug_struct("Cookie")
            .field("token", &self.token())
            .field("nonce", &self.nonce())
            .finish()
    }
}

#[cfg(test)]
mod tests {
    use super::Cookie;
    use mio::Token;

    #[test]
    fn round_trip() {
        let a = Cookie::new(Token(1), 1);
        assert_eq!(a.token(), Token(1));
        assert_eq!(a.nonce(), 1);
        let a = Cookie::new(Token((1 << 16) - 1), (1 << 48) - 1);
        assert_eq!(a.token(), Token((1 << 16) - 1));
        assert_eq!(a.nonce(), (1 << 48) - 1);
    }

    #[test]
    fn overflow() {
        let a = Cookie::new(Token((1 << 16) + 1), (1 << 48) + 1);
        assert_eq!(a.token(), Token(1));
        assert_eq!(a.nonce(), 1);
    }
}
<|endoftext|>