<commit_before>//
// url.rs - module for url-encoding
//

import vec::len;

export query_escape, query_unescape;

enum enc_mode { query, path, fragment, userinfo }

fn query_escape(s: str) -> str { url_escape(s, query) }
fn query_unescape(s: str) -> str { url_unescape(s, query) }

#[inline(always)]
pure fn ishex(c: u8) -> bool {
    if 48u8 <= c && c <= 57u8 { true }
    else if 65u8 <= c && c <= 90u8  { true }
    else if 97u8 <= c && c <= 122u8 { true }
    else { false }
}

#[inline(always)]
pure fn unhex(c: u8) -> u8 {
    if 48u8 <= c && c <= 57u8 { c - 48u8 }
    else if 65u8 <= c && c <= 90u8  { c - 65u8 + 10u8 }
    else if 97u8 <= c && c <= 122u8 { c - 97u8 + 10u8 }
    else { fail "should be unreachable"; }
}

pure fn should_escape(c: u8, mode: enc_mode) -> bool {
    alt c {
      65u8 to 90u8  { ret false; } // A .. Z
      97u8 to 122u8 { ret false; } // a .. z
      48u8 to 57u8  { ret false; } // 0 .. 9
      _ { }
    }

    alt c {
      45u8  | 95u8 | 46u8 | 33u8 | // '-', '_', '.', '!'
      126u8 | 42u8 | 39u8 | 40u8 | // '~', '*', '\'', '('
      41u8 { false }               // ')'

      36u8 | 38u8 | 43u8 | 44u8 |  // '$', '&', '+', ','
      47u8 | 58u8 | 59u8 | 61u8 |  // '/', ':', ';', '='
      63u8 | 64u8 {                // '?', '@'
        alt mode {
          query    { true }
          fragment { false }
          path     { (c == 63u8) }
          userinfo { (c == 47u8 || c == 58u8 || c == 64u8) }
        }
      }

      _ { true }
    }
}

fn url_escape(s: str, mode: enc_mode) -> str {
    let bs = str::bytes(s);
    let src_length = len(bs);
    let mut space_count = 0u;
    let mut hex_count = 0u;
    let table =
        [48u8, 49u8, 50u8, 51u8, 52u8, 53u8, 54u8, 55u8,
         56u8, 57u8, 65u8, 66u8, 67u8, 68u8, 69u8, 70u8];

    uint::range(0u, src_length) {|i|
        let c = bs[i];
        if should_escape(bs[i], mode) {
            if c == 32u8 && mode == query {
                space_count += 1u;
            } else {
                hex_count += 1u;
            }
        }
    }

    // Nothing to do if there's no space and no escapable chars in `s`
    if space_count == 0u && hex_count == 0u {
        ret s;
    }

    let ts = vec::to_mut(vec::from_elem(src_length + 2u * hex_count, 0u8));
    let mut i = 0u;
    let mut j = 0u;
    let mut c = 0u8;

    while i < src_length {
        c = bs[i];
        if c == 32u8 && mode == query {
            ts[j] = '+' as u8;
            j += 1u;
        } else if should_escape(c, mode) {
            ts[j] = '%' as u8;
            ts[j+1u] = table[c >> 4u8];
            ts[j+2u] = table[c & 0x0f_u8];
            j += 3u;
        } else {
            ts[j] = c;
            j += 1u;
        }
        i += 1u;
    }

    str::from_bytes(vec::from_mut(ts))
}

fn url_unescape(s: str, mode: enc_mode) -> str {
    let bs = str::bytes(s);
    let src_length = len(bs);
    let mut n = 0u;
    let mut i = 0u;
    let mut hasplus = false;

    while i < src_length {
        let c = bs[i];
        if c == 37u8 {
            n += 1u;
            if i+2u >= src_length || !ishex(bs[i+1u]) || !ishex(bs[i+2u]) {
                fail #fmt["Invalid URL escape: '%s'", s];
            }
            i += 3u;
        } else if c == 43u8 {
            hasplus = mode == query;
            i += 1u;
        } else {
            i += 1u;
        }
    }

    if n == 0u && !hasplus {
        ret s;
    }

    let ts = vec::to_mut(vec::from_elem(src_length - 2u * n, 0u8));
    let mut i = 0u;
    let mut j = 0u;

    while i < src_length {
        let c = bs[i];
        if c == 37u8 {
            ts[j] = (unhex(bs[i+1u])<<4u) | unhex(bs[i+2u]);
            j += 1u;
            i += 3u;
        } else if c == 43u8 {
            if mode == query { ts[j] = 32u8; }
            else { ts[j] = 43u8; }
            j += 1u;
            i += 1u;
        } else {
            ts[j] = c;
            j += 1u;
            i += 1u;
        }
    }

    str::from_bytes(vec::from_mut(ts))
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_should_escape() {
        assert should_escape('A' as u8, path) == false;
        assert should_escape('0' as u8, path) == false;
        assert should_escape('?' as u8, path) == true;
        assert should_escape('A' as u8, query) == false;
        assert should_escape('0' as u8, query) == false;
        assert should_escape('@' as u8, query) == true;
        assert should_escape('/' as u8, userinfo) == true;
        assert should_escape(':' as u8, userinfo) == true;
        assert should_escape('$' as u8, userinfo) == false;
        assert should_escape('A' as u8, fragment) == false;
        assert should_escape('0' as u8, fragment) == false;
        assert should_escape(';' as u8, fragment) == false;
    }
    #[test]
    fn test_query_escape() {
        assert query_escape("a") == "a";
        assert query_escape("a z") == "a+z";
        assert query_escape("å") == "%C3%A5";
        assert query_escape("?") == "%3F";
        assert query_escape("あ") == "%E3%81%82";
    }
    #[test]
    fn test_query_unescape() {
        assert query_unescape("a") == "a";
        assert query_unescape("a+z") == "a z";
        assert query_unescape("%3f") == "?";
        assert query_unescape("%C3%A5") == "å";
        assert query_unescape("%E3%81%82") == "あ";
    }
}
<commit_msg>url: add an attr for inlining to should_escape<commit_after>//
// url.rs - module for url-encoding
//

import vec::len;

export query_escape, query_unescape;

enum enc_mode { query, path, fragment, userinfo }

fn query_escape(s: str) -> str { url_escape(s, query) }
fn query_unescape(s: str) -> str { url_unescape(s, query) }

#[inline(always)]
pure fn ishex(c: u8) -> bool {
    if 48u8 <= c && c <= 57u8 { true }
    else if 65u8 <= c && c <= 90u8  { true }
    else if 97u8 <= c && c <= 122u8 { true }
    else { false }
}

#[inline(always)]
pure fn unhex(c: u8) -> u8 {
    if 48u8 <= c && c <= 57u8 { c - 48u8 }
    else if 65u8 <= c && c <= 90u8  { c - 65u8 + 10u8 }
    else if 97u8 <= c && c <= 122u8 { c - 97u8 + 10u8 }
    else { fail "should be unreachable"; }
}

#[inline(always)]
pure fn should_escape(c: u8, mode: enc_mode) -> bool {
    alt c {
      65u8 to 90u8  { ret false; } // A .. Z
      97u8 to 122u8 { ret false; } // a .. z
      48u8 to 57u8  { ret false; } // 0 .. 9
      _ { }
    }

    alt c {
      45u8  | 95u8 | 46u8 | 33u8 | // '-', '_', '.', '!'
      126u8 | 42u8 | 39u8 | 40u8 | // '~', '*', '\'', '('
      41u8 { false }               // ')'

      36u8 | 38u8 | 43u8 | 44u8 |  // '$', '&', '+', ','
      47u8 | 58u8 | 59u8 | 61u8 |  // '/', ':', ';', '='
      63u8 | 64u8 {                // '?', '@'
        alt mode {
          query    { true }
          fragment { false }
          path     { (c == 63u8) }
          userinfo { (c == 47u8 || c == 58u8 || c == 64u8) }
        }
      }

      _ { true }
    }
}

fn url_escape(s: str, mode: enc_mode) -> str {
    let bs = str::bytes(s);
    let src_length = len(bs);
    let mut space_count = 0u;
    let mut hex_count = 0u;
    let table =
        [48u8, 49u8, 50u8, 51u8, 52u8, 53u8, 54u8, 55u8,
         56u8, 57u8, 65u8, 66u8, 67u8, 68u8, 69u8, 70u8];

    uint::range(0u, src_length) {|i|
        let c = bs[i];
        if should_escape(bs[i], mode) {
            if c == 32u8 && mode == query {
                space_count += 1u;
            } else {
                hex_count += 1u;
            }
        }
    }

    // Nothing to do if there's no space and no escapable chars in `s`
    if space_count == 0u && hex_count == 0u {
        ret s;
    }

    let ts = vec::to_mut(vec::from_elem(src_length + 2u * hex_count, 0u8));
    let mut i = 0u;
    let mut j = 0u;
    let mut c = 0u8;

    while i < src_length {
        c = bs[i];
        if c == 32u8 && mode == query {
            ts[j] = '+' as u8;
            j += 1u;
        } else if should_escape(c, mode) {
            ts[j] = '%' as u8;
            ts[j+1u] = table[c >> 4u8];
            ts[j+2u] = table[c & 0x0f_u8];
            j += 3u;
        } else {
            ts[j] = c;
            j += 1u;
        }
        i += 1u;
    }

    str::from_bytes(vec::from_mut(ts))
}

fn url_unescape(s: str, mode: enc_mode) -> str {
    let bs = str::bytes(s);
    let src_length = len(bs);
    let mut n = 0u;
    let mut i = 0u;
    let mut hasplus = false;

    while i < src_length {
        let c = bs[i];
        if c == 37u8 {
            n += 1u;
            if i+2u >= src_length || !ishex(bs[i+1u]) || !ishex(bs[i+2u]) {
                fail #fmt["Invalid URL escape: '%s'", s];
            }
            i += 3u;
        } else if c == 43u8 {
            hasplus = mode == query;
            i += 1u;
        } else {
            i += 1u;
        }
    }

    if n == 0u && !hasplus {
        ret s;
    }

    let ts = vec::to_mut(vec::from_elem(src_length - 2u * n, 0u8));
    let mut i = 0u;
    let mut j = 0u;

    while i < src_length {
        let c = bs[i];
        if c == 37u8 {
            ts[j] = (unhex(bs[i+1u])<<4u) | unhex(bs[i+2u]);
            j += 1u;
            i += 3u;
        } else if c == 43u8 {
            if mode == query { ts[j] = 32u8; }
            else { ts[j] = 43u8; }
            j += 1u;
            i += 1u;
        } else {
            ts[j] = c;
            j += 1u;
            i += 1u;
        }
    }

    str::from_bytes(vec::from_mut(ts))
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_should_escape() {
        assert should_escape('A' as u8, path) == false;
        assert should_escape('0' as u8, path) == false;
        assert should_escape('?' as u8, path) == true;
        assert should_escape('A' as u8, query) == false;
        assert should_escape('0' as u8, query) == false;
        assert should_escape('@' as u8, query) == true;
        assert should_escape('/' as u8, userinfo) == true;
        assert should_escape(':' as u8, userinfo) == true;
        assert should_escape('$' as u8, userinfo) == false;
        assert should_escape('A' as u8, fragment) == false;
        assert should_escape('0' as u8, fragment) == false;
        assert should_escape(';' as u8, fragment) == false;
    }
    #[test]
    fn test_query_escape() {
        assert query_escape("a") == "a";
        assert query_escape("a z") == "a+z";
        assert query_escape("å") == "%C3%A5";
        assert query_escape("?") == "%3F";
        assert query_escape("あ") == "%E3%81%82";
    }
    #[test]
    fn test_query_unescape() {
        assert query_unescape("a") == "a";
        assert query_unescape("a+z") == "a z";
        assert query_unescape("%3f") == "?";
        assert query_unescape("%C3%A5") == "å";
        assert query_unescape("%E3%81%82") == "あ";
    }
}
<|endoftext|>


<commit_before>//! Contains common types for reader and writer.

/// Format of FBX data
#[derive(Debug, Clone, Copy)]
pub enum FbxFormatType {
    /// Binary FBX, with version (for example, `7400` for FBX 7.4).
    Binary(u32),
    /// ASCII FBX.
    Ascii,
}

/// A property type of the FBX node.
#[derive(Debug, Clone, PartialEq)]
pub enum OwnedProperty {
    /// Boolean.
    Bool(bool),
    /// 2 byte signed integer.
    I16(i16),
    /// 4 byte signed integer.
    I32(i32),
    /// 8 byte signed integer.
    I64(i64),
    /// 4 byte single-precision IEEE 754 floating-point number.
    F32(f32),
    /// 8 byte double-precision IEEE 754 floating-point number.
    F64(f64),
    /// Array of boolean.
    VecBool(Vec<bool>),
    /// Array of 4 byte signed integer.
    VecI32(Vec<i32>),
    /// Array of 8 byte signed integer.
    VecI64(Vec<i64>),
    /// Array of 4 byte single-precision IEEE 754 number.
    VecF32(Vec<f32>),
    /// Array of 8 byte double-precision IEEE 754 number.
    VecF64(Vec<f64>),
    /// String.
    ///
    /// Note that the string can contain special character like `\u{0}`.
    String(String),
    /// Raw binary data.
    Binary(Vec<u8>),
}
<commit_msg>Add `common::Property` type for writer<commit_after>//! Contains common types for reader and writer.

/// Format of FBX data
#[derive(Debug, Clone, Copy)]
pub enum FbxFormatType {
    /// Binary FBX, with version (for example, `7400` for FBX 7.4).
    Binary(u32),
    /// ASCII FBX.
    Ascii,
}

/// A property type of the FBX node.
#[derive(Debug, Clone, PartialEq)]
pub enum OwnedProperty {
    /// Boolean.
    Bool(bool),
    /// 2 byte signed integer.
    I16(i16),
    /// 4 byte signed integer.
    I32(i32),
    /// 8 byte signed integer.
    I64(i64),
    /// 4 byte single-precision IEEE 754 floating-point number.
    F32(f32),
    /// 8 byte double-precision IEEE 754 floating-point number.
    F64(f64),
    /// Array of boolean.
    VecBool(Vec<bool>),
    /// Array of 4 byte signed integer.
    VecI32(Vec<i32>),
    /// Array of 8 byte signed integer.
    VecI64(Vec<i64>),
    /// Array of 4 byte single-precision IEEE 754 number.
    VecF32(Vec<f32>),
    /// Array of 8 byte double-precision IEEE 754 number.
    VecF64(Vec<f64>),
    /// String.
    ///
    /// Note that the string can contain special character like `\u{0}`.
    String(String),
    /// Raw binary data.
    Binary(Vec<u8>),
}

/// A property type of the FBX node.
#[derive(Debug, Clone, PartialEq)]
pub enum Property<'a> {
    /// Boolean.
    Bool(bool),
    /// 2 byte signed integer.
    I16(i16),
    /// 4 byte signed integer.
    I32(i32),
    /// 8 byte signed integer.
    I64(i64),
    /// 4 byte single-precision IEEE 754 floating-point number.
    F32(f32),
    /// 8 byte double-precision IEEE 754 floating-point number.
    F64(f64),
    /// Array of boolean.
    VecBool(&'a [bool]),
    /// Array of 4 byte signed integer.
    VecI32(&'a [i32]),
    /// Array of 8 byte signed integer.
    VecI64(&'a [i64]),
    /// Array of 4 byte single-precision IEEE 754 number.
    VecF32(&'a [f32]),
    /// Array of 8 byte double-precision IEEE 754 number.
    VecF64(&'a [f64]),
    /// String.
    ///
    /// Note that the string can contain special character like `\u{0}`.
    String(&'a str),
    /// Raw binary data.
    Binary(&'a [u8]),
}
<|endoftext|>


<commit_before>use std::default::Default;
use std::path;

use serde_yaml;

use error::*;
use files;
use frontmatter;
use legacy::wildwest;
use sass;
use site;
use syntax_highlight::has_syntax_theme;

arg_enum! {
    #[derive(Serialize, Deserialize)]
    #[derive(Debug, PartialEq, Copy, Clone)]
    pub enum Dump {
        DocObject,
        DocTemplate,
        DocLinkObject,
        Document
    }
}

impl Dump {
    pub fn is_doc(&self) -> bool {
        true
    }
}

#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub enum SortOrder {
    Asc,
    Desc,
}

impl Default for SortOrder {
    fn default() -> SortOrder {
        SortOrder::Desc
    }
}

#[derive(Debug, PartialEq)]
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SyntaxHighlight {
    pub theme: String,
}

impl Default for SyntaxHighlight {
    fn default() -> SyntaxHighlight {
        SyntaxHighlight { theme: "base16-ocean.dark".to_owned() }
    }
}

#[derive(Debug, PartialEq, Default)]
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct PageBuilder {
    pub default: frontmatter::FrontmatterBuilder,
}

#[derive(Debug, PartialEq)]
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct PostBuilder {
    pub name: Option<String>,
    pub description: Option<String>,
    pub dir: String,
    pub drafts_dir: Option<String>,
    pub order: SortOrder,
    pub rss: Option<String>,
    pub jsonfeed: Option<String>,
    pub default: frontmatter::FrontmatterBuilder,
}

impl Default for PostBuilder {
    fn default() -> PostBuilder {
        Self {
            name: None,
            description: None,
            dir: "posts".to_owned(),
            drafts_dir: None,
            order: SortOrder::default(),
            rss: None,
            jsonfeed: None,
            default: frontmatter::FrontmatterBuilder::new().set_post(true),
        }
    }
}

const LAYOUTS_DIR: &'static str = "_layouts";

#[derive(Debug, PartialEq)]
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields, default)]
pub struct ConfigBuilder {
    #[serde(skip)]
    pub root: path::PathBuf,
    pub source: String,
    pub destination: String,
    #[serde(skip)]
    pub abs_dest: Option<String>,
    #[serde(skip)]
    pub include_drafts: bool,
    pub default: frontmatter::FrontmatterBuilder,
    pub pages: PageBuilder,
    pub posts: PostBuilder,
    pub site: site::SiteBuilder,
    pub template_extensions: Vec<String>,
    pub ignore: Vec<String>,
    pub syntax_highlight: SyntaxHighlight,
    pub layouts_dir: &'static str,
    pub sass: sass::SassOptions,
    // This is a debug-only field and should be transient rather than persistently set.
    #[serde(skip)]
    pub dump: Vec<Dump>,
}

impl Default for ConfigBuilder {
    fn default() -> ConfigBuilder {
        ConfigBuilder {
            root: path::PathBuf::new(),
            source: "./".to_owned(),
            destination: "./".to_owned(),
            abs_dest: None,
            include_drafts: false,
            default: frontmatter::FrontmatterBuilder::new()
                .set_excerpt_separator("\n\n".to_owned())
                .set_draft(false)
                .set_post(false),
            pages: PageBuilder::default(),
            posts: PostBuilder::default(),
            site: site::SiteBuilder::default(),
            template_extensions: vec!["md".to_owned(), "liquid".to_owned()],
            ignore: vec![],
            syntax_highlight: SyntaxHighlight::default(),
            layouts_dir: LAYOUTS_DIR,
            sass: sass::SassOptions::default(),
            dump: vec![],
        }
    }
}

impl ConfigBuilder {
    pub fn from_file<P: Into<path::PathBuf>>(path: P) -> Result<ConfigBuilder> {
        Self::from_file_internal(path.into())
    }

    fn from_file_internal(path: path::PathBuf) -> Result<ConfigBuilder> {
        let content = files::read_file(&path)?;

        if content.trim().is_empty() {
            return Ok(ConfigBuilder::default());
        }

        let config: wildwest::GlobalConfig = serde_yaml::from_str(&content)?;
        let mut config: ConfigBuilder = config.into();

        let mut root = path;
        root.pop(); // Remove filename
        config.root = root;

        Ok(config)
    }

    pub fn from_cwd<P: Into<path::PathBuf>>(cwd: P) -> Result<ConfigBuilder> {
        Self::from_cwd_internal(cwd.into())
    }

    fn from_cwd_internal(cwd: path::PathBuf) -> Result<ConfigBuilder> {
        let file_path = files::find_project_file(&cwd, ".cobalt.yml");
        let mut config = file_path
            .map(|p| {
                     info!("Using config file {:?}", &p);
                     Self::from_file(&p).chain_err(|| format!("Error reading config file {:?}", p))
                 })
            .unwrap_or_else(|| {
                warn!("No .cobalt.yml file found in current directory, using default config.");
                Ok(ConfigBuilder::default())
            })?;
        config.root = cwd;
        Ok(config)
    }

    pub fn build(self) -> Result<Config> {
        let ConfigBuilder {
            root,
            source,
            destination,
            abs_dest,
            include_drafts,
            default,
            pages,
            posts,
            site,
            template_extensions,
            ignore,
            syntax_highlight,
            layouts_dir,
            sass,
            dump,
        } = self;

        let result: Result<()> = match has_syntax_theme(&syntax_highlight.theme) {
            Ok(true) => Ok(()),
            Ok(false) => {
                Err(format!("Syntax theme '{}' is unsupported", syntax_highlight.theme).into())
            }
            Err(err) => {
                warn!("Syntax theme named '{}' ignored. Reason: {}",
                      syntax_highlight.theme,
                      err);
                Ok(())
            }
        };
        result?;

        let mut pages = pages;
        pages.default = pages.default.merge(default.clone());
        let mut posts = posts;
        posts.default = posts.default.merge(default);

        let source = files::cleanup_path(source);
        let destination = files::cleanup_path(destination);

        let mut ignore = ignore;
        if let Ok(rel_dest) = path::Path::new(&destination).strip_prefix(&source) {
            let rel_dest = rel_dest.to_str().expect("started as a utf-8 string");
            if !rel_dest.is_empty() {
                ignore.push(format!("/{}", rel_dest.to_owned()));
            }
        }

        let source = root.join(source);
        let destination = abs_dest
            .map(|s| s.into())
            .unwrap_or_else(|| root.join(destination));

        let site = site.build(&source)?;

        let config = Config {
            source,
            destination,
            include_drafts,
            pages,
            posts,
            site,
            ignore,
            template_extensions,
            syntax_highlight,
            layouts_dir,
            sass,
            dump,
        };

        Ok(config)
    }
}

#[derive(Debug, PartialEq)]
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields, default)]
pub struct Config {
    pub source: path::PathBuf,
    pub destination: path::PathBuf,
    pub include_drafts: bool,
    pub pages: PageBuilder,
    pub posts: PostBuilder,
    pub site: site::Site,
    pub template_extensions: Vec<String>,
    pub ignore: Vec<String>,
    pub syntax_highlight: SyntaxHighlight,
    pub layouts_dir: &'static str,
    pub sass: sass::SassOptions,
    pub dump: Vec<Dump>,
}

impl Default for Config {
    fn default() -> Config {
        ConfigBuilder::default()
            .build()
            .expect("default config should not fail")
    }
}

#[test]
fn test_from_file_ok() {
    let result = ConfigBuilder::from_file("tests/fixtures/config/.cobalt.yml").unwrap();
    assert_eq!(result,
               ConfigBuilder {
                   root: path::Path::new("tests/fixtures/config").to_path_buf(),
                   destination: "./dest".to_owned(),
                   posts: PostBuilder {
                       dir: "_my_posts".to_owned(),
                       drafts_dir: Some("_drafts".to_owned()),
                       ..Default::default()
                   },
                   ..Default::default()
               });
}

#[test]
fn test_from_file_rss() {
    let result = ConfigBuilder::from_file("tests/fixtures/config/rss.yml").unwrap();
    assert_eq!(result,
               ConfigBuilder {
                   root: path::Path::new("tests/fixtures/config").to_path_buf(),
                   posts: PostBuilder {
                       drafts_dir: Some("_drafts".to_owned()),
                       rss: Some("rss.xml".to_owned()),
                       ..Default::default()
                   },
                   site: site::SiteBuilder {
                       title: Some("My blog!".to_owned()),
                       description: Some("Blog description".to_owned()),
                       base_url: Some("http://example.com".to_owned()),
                       ..Default::default()
                   },
                   ..Default::default()
               });
}

#[test]
fn test_from_file_empty() {
    let result = ConfigBuilder::from_file("tests/fixtures/config/empty.yml").unwrap();
    assert_eq!((result), ConfigBuilder { ..Default::default() });
}

#[test]
fn test_from_file_invalid_syntax() {
    let result = ConfigBuilder::from_file("tests/fixtures/config/invalid_syntax.yml");
    assert!(result.is_err());
}

#[test]
fn test_from_file_not_found() {
    let result = ConfigBuilder::from_file("tests/fixtures/config/config_does_not_exist.yml");
    assert!(result.is_err());
}

#[test]
fn test_from_cwd_ok() {
    let result = ConfigBuilder::from_cwd("tests/fixtures/config").unwrap();
    assert_eq!(result,
               ConfigBuilder {
                   root: path::Path::new("tests/fixtures/config").to_path_buf(),
                   destination: "./dest".to_owned(),
                   posts: PostBuilder {
                       dir: "_my_posts".to_owned(),
                       drafts_dir: Some("_drafts".to_owned()),
                       ..Default::default()
                   },
                   ..Default::default()
               });
}

#[test]
fn test_from_cwd_not_found() {
    let result = ConfigBuilder::from_cwd("tests/fixtures").unwrap();
    assert_eq!(result,
               ConfigBuilder {
                   root: path::Path::new("tests/fixtures").to_path_buf(),
                   ..Default::default()
               });
}

#[test]
fn test_build_dest() {
    let result = ConfigBuilder::from_file("tests/fixtures/config/.cobalt.yml").unwrap();
    let result = result.build().unwrap();
    assert_eq!(result,
               Config {
                   source: path::Path::new("tests/fixtures/config").to_path_buf(),
                   destination: path::Path::new("tests/fixtures/config/./dest").to_path_buf(),
                   posts: PostBuilder {
                       dir: "_my_posts".to_owned(),
                       drafts_dir: Some("_drafts".to_owned()),
                       default: frontmatter::FrontmatterBuilder::new()
                           .set_excerpt_separator("\n\n".to_owned())
                           .set_draft(false)
                           .set_post(true),
                       ..Default::default()
                   },
                   ignore: ["/dest".to_owned()].to_vec(),
                   ..Default::default()
               });
}

#[test]
fn test_build_abs_dest() {
    let mut result = ConfigBuilder::from_file("tests/fixtures/config/.cobalt.yml").unwrap();
    result.abs_dest = Some("hello/world".to_owned());
    let result = result.build().unwrap();
    assert_eq!(result,
               Config {
                   source: path::Path::new("tests/fixtures/config").to_path_buf(),
                   destination: path::Path::new("hello/world").to_path_buf(),
                   posts: PostBuilder {
                       dir: "_my_posts".to_owned(),
                       drafts_dir: Some("_drafts".to_owned()),
                       default: frontmatter::FrontmatterBuilder::new()
                           .set_excerpt_separator("\n\n".to_owned())
                           .set_draft(false)
                           .set_post(true),
                       ..Default::default()
                   },
                   ignore: ["/dest".to_owned()].to_vec(),
                   ..Default::default()
               });
}
<commit_msg>fix(config): Don't support absolute paths<commit_after>use std::default::Default;
use std::path;

use serde_yaml;

use error::*;
use files;
use frontmatter;
use legacy::wildwest;
use sass;
use site;
use syntax_highlight::has_syntax_theme;

arg_enum! {
    #[derive(Serialize, Deserialize)]
    #[derive(Debug, PartialEq, Copy, Clone)]
    pub enum Dump {
        DocObject,
        DocTemplate,
        DocLinkObject,
        Document
    }
}

impl Dump {
    pub fn is_doc(&self) -> bool {
        true
    }
}

#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub enum SortOrder {
    Asc,
    Desc,
}

impl Default for SortOrder {
    fn default() -> SortOrder {
        SortOrder::Desc
    }
}

#[derive(Debug, PartialEq)]
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SyntaxHighlight {
    pub theme: String,
}

impl Default for SyntaxHighlight {
    fn default() -> SyntaxHighlight {
        SyntaxHighlight { theme: "base16-ocean.dark".to_owned() }
    }
}

#[derive(Debug, PartialEq, Default)]
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct PageBuilder {
    pub default: frontmatter::FrontmatterBuilder,
}

#[derive(Debug, PartialEq)]
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct PostBuilder {
    pub name: Option<String>,
    pub description: Option<String>,
    pub dir: String,
    pub drafts_dir: Option<String>,
    pub order: SortOrder,
    pub rss: Option<String>,
    pub jsonfeed: Option<String>,
    pub default: frontmatter::FrontmatterBuilder,
}

impl Default for PostBuilder {
    fn default() -> PostBuilder {
        Self {
            name: None,
            description: None,
            dir: "posts".to_owned(),
            drafts_dir: None,
            order: SortOrder::default(),
            rss: None,
            jsonfeed: None,
            default: frontmatter::FrontmatterBuilder::new().set_post(true),
        }
    }
}

const LAYOUTS_DIR: &'static str = "_layouts";

#[derive(Debug, PartialEq)]
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields, default)]
pub struct ConfigBuilder {
    #[serde(skip)]
    pub root: path::PathBuf,
    pub source: String,
    pub destination: String,
    #[serde(skip)]
    pub abs_dest: Option<String>,
    #[serde(skip)]
    pub include_drafts: bool,
    pub default: frontmatter::FrontmatterBuilder,
    pub pages: PageBuilder,
    pub posts: PostBuilder,
    pub site: site::SiteBuilder,
    pub template_extensions: Vec<String>,
    pub ignore: Vec<String>,
    pub syntax_highlight: SyntaxHighlight,
    pub layouts_dir: &'static str,
    pub sass: sass::SassOptions,
    // This is a debug-only field and should be transient rather than persistently set.
    #[serde(skip)]
    pub dump: Vec<Dump>,
}

impl Default for ConfigBuilder {
    fn default() -> ConfigBuilder {
        ConfigBuilder {
            root: path::PathBuf::new(),
            source: "./".to_owned(),
            destination: "./".to_owned(),
            abs_dest: None,
            include_drafts: false,
            default: frontmatter::FrontmatterBuilder::new()
                .set_excerpt_separator("\n\n".to_owned())
                .set_draft(false)
                .set_post(false),
            pages: PageBuilder::default(),
            posts: PostBuilder::default(),
            site: site::SiteBuilder::default(),
            template_extensions: vec!["md".to_owned(), "liquid".to_owned()],
            ignore: vec![],
            syntax_highlight: SyntaxHighlight::default(),
            layouts_dir: LAYOUTS_DIR,
            sass: sass::SassOptions::default(),
            dump: vec![],
        }
    }
}

impl ConfigBuilder {
    pub fn from_file<P: Into<path::PathBuf>>(path: P) -> Result<ConfigBuilder> {
        Self::from_file_internal(path.into())
    }

    fn from_file_internal(path: path::PathBuf) -> Result<ConfigBuilder> {
        let content = files::read_file(&path)?;

        if content.trim().is_empty() {
            return Ok(ConfigBuilder::default());
        }

        let config: wildwest::GlobalConfig = serde_yaml::from_str(&content)?;
        let mut config: ConfigBuilder = config.into();

        let mut root = path;
        root.pop(); // Remove filename
        config.root = root;

        Ok(config)
    }

    pub fn from_cwd<P: Into<path::PathBuf>>(cwd: P) -> Result<ConfigBuilder> {
        Self::from_cwd_internal(cwd.into())
    }

    fn from_cwd_internal(cwd: path::PathBuf) -> Result<ConfigBuilder> {
        let file_path = files::find_project_file(&cwd, ".cobalt.yml");
        let mut config = file_path
            .map(|p| {
                     info!("Using config file {:?}", &p);
                     Self::from_file(&p).chain_err(|| format!("Error reading config file {:?}", p))
                 })
            .unwrap_or_else(|| {
                warn!("No .cobalt.yml file found in current directory, using default config.");
                Ok(ConfigBuilder::default())
            })?;
        config.root = cwd;
        Ok(config)
    }

    pub fn build(self) -> Result<Config> {
        let ConfigBuilder {
            root,
            source,
            destination,
            abs_dest,
            include_drafts,
            default,
            pages,
            posts,
            site,
            template_extensions,
            ignore,
            syntax_highlight,
            layouts_dir,
            sass,
            dump,
        } = self;

        let result: Result<()> = match has_syntax_theme(&syntax_highlight.theme) {
            Ok(true) => Ok(()),
            Ok(false) => {
                Err(format!("Syntax theme '{}' is unsupported", syntax_highlight.theme).into())
            }
            Err(err) => {
                warn!("Syntax theme named '{}' ignored. Reason: {}",
                      syntax_highlight.theme,
                      err);
                Ok(())
            }
        };
        result?;

        let mut pages = pages;
        pages.default = pages.default.merge(default.clone());
        let mut posts = posts;
        posts.default = posts.default.merge(default);

        if posts.dir.starts_with('/') {
            bail!("posts dir {} must be a relative path", posts.dir)
        }
        if let Some(ref drafts_dir) = posts.drafts_dir {
            if drafts_dir.starts_with('/') {
                bail!("posts dir {} must be a relative path", drafts_dir)
            }
        }

        let source = files::cleanup_path(source);
        let destination = files::cleanup_path(destination);

        let mut ignore = ignore;
        if let Ok(rel_dest) = path::Path::new(&destination).strip_prefix(&source) {
            let rel_dest = rel_dest.to_str().expect("started as a utf-8 string");
            if !rel_dest.is_empty() {
                ignore.push(format!("/{}", rel_dest.to_owned()));
            }
        }

        let source = root.join(source);
        let destination = abs_dest
            .map(|s| s.into())
            .unwrap_or_else(|| root.join(destination));

        let site = site.build(&source)?;

        let config = Config {
            source,
            destination,
            include_drafts,
            pages,
            posts,
            site,
            ignore,
            template_extensions,
            syntax_highlight,
            layouts_dir,
            sass,
            dump,
        };

        Ok(config)
    }
}

#[derive(Debug, PartialEq)]
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields, default)]
pub struct Config {
    pub source: path::PathBuf,
    pub destination: path::PathBuf,
    pub include_drafts: bool,
    pub pages: PageBuilder,
    pub posts: PostBuilder,
    pub site: site::Site,
    pub template_extensions: Vec<String>,
    pub ignore: Vec<String>,
    pub syntax_highlight: SyntaxHighlight,
    pub layouts_dir: &'static str,
    pub sass: sass::SassOptions,
    pub dump: Vec<Dump>,
}

impl Default for Config {
    fn default() -> Config {
        ConfigBuilder::default()
            .build()
            .expect("default config should not fail")
    }
}

#[test]
fn test_from_file_ok() {
    let result = ConfigBuilder::from_file("tests/fixtures/config/.cobalt.yml").unwrap();
    assert_eq!(result,
               ConfigBuilder {
                   root: path::Path::new("tests/fixtures/config").to_path_buf(),
                   destination: "./dest".to_owned(),
                   posts: PostBuilder {
                       dir: "_my_posts".to_owned(),
                       drafts_dir: Some("_drafts".to_owned()),
                       ..Default::default()
                   },
                   ..Default::default()
               });
}

#[test]
fn test_from_file_rss() {
    let result = ConfigBuilder::from_file("tests/fixtures/config/rss.yml").unwrap();
    assert_eq!(result,
               ConfigBuilder {
                   root: path::Path::new("tests/fixtures/config").to_path_buf(),
                   posts: PostBuilder {
                       drafts_dir: Some("_drafts".to_owned()),
                       rss: Some("rss.xml".to_owned()),
                       ..Default::default()
                   },
                   site: site::SiteBuilder {
                       title: Some("My blog!".to_owned()),
                       description: Some("Blog description".to_owned()),
                       base_url: Some("http://example.com".to_owned()),
                       ..Default::default()
                   },
                   ..Default::default()
               });
}

#[test]
fn test_from_file_empty() {
    let result = ConfigBuilder::from_file("tests/fixtures/config/empty.yml").unwrap();
    assert_eq!((result), ConfigBuilder { ..Default::default() });
}

#[test]
fn test_from_file_invalid_syntax() {
    let result = ConfigBuilder::from_file("tests/fixtures/config/invalid_syntax.yml");
    assert!(result.is_err());
}

#[test]
fn test_from_file_not_found() {
    let result = ConfigBuilder::from_file("tests/fixtures/config/config_does_not_exist.yml");
    assert!(result.is_err());
}

#[test]
fn test_from_cwd_ok() {
    let result = ConfigBuilder::from_cwd("tests/fixtures/config").unwrap();
    assert_eq!(result,
               ConfigBuilder {
                   root: path::Path::new("tests/fixtures/config").to_path_buf(),
                   destination: "./dest".to_owned(),
                   posts: PostBuilder {
                       dir: "_my_posts".to_owned(),
                       drafts_dir: Some("_drafts".to_owned()),
                       ..Default::default()
                   },
                   ..Default::default()
               });
}

#[test]
fn test_from_cwd_not_found() {
    let result = ConfigBuilder::from_cwd("tests/fixtures").unwrap();
    assert_eq!(result,
               ConfigBuilder {
                   root: path::Path::new("tests/fixtures").to_path_buf(),
                   ..Default::default()
               });
}

#[test]
fn test_build_default() {
    let config = ConfigBuilder::default();
    config.build().unwrap();
}
#[test]
fn test_build_dest() {
    let result = ConfigBuilder::from_file("tests/fixtures/config/.cobalt.yml").unwrap();
    let result = result.build().unwrap();
    assert_eq!(result,
               Config {
                   source: path::Path::new("tests/fixtures/config").to_path_buf(),
                   destination: path::Path::new("tests/fixtures/config/./dest").to_path_buf(),
                   posts: PostBuilder {
                       dir: "_my_posts".to_owned(),
                       drafts_dir: Some("_drafts".to_owned()),
                       default: frontmatter::FrontmatterBuilder::new()
                           .set_excerpt_separator("\n\n".to_owned())
                           .set_draft(false)
                           .set_post(true),
                       ..Default::default()
                   },
                   ignore: ["/dest".to_owned()].to_vec(),
                   ..Default::default()
               });
}

#[test]
fn test_build_abs_dest() {
    let mut result = ConfigBuilder::from_file("tests/fixtures/config/.cobalt.yml").unwrap();
    result.abs_dest = Some("hello/world".to_owned());
    let result = result.build().unwrap();
    assert_eq!(result,
               Config {
                   source: path::Path::new("tests/fixtures/config").to_path_buf(),
                   destination: path::Path::new("hello/world").to_path_buf(),
                   posts: PostBuilder {
                       dir: "_my_posts".to_owned(),
                       drafts_dir: Some("_drafts".to_owned()),
                       default: frontmatter::FrontmatterBuilder::new()
                           .set_excerpt_separator("\n\n".to_owned())
                           .set_draft(false)
                           .set_post(true),
                       ..Default::default()
                   },
                   ignore: ["/dest".to_owned()].to_vec(),
                   ..Default::default()
               });
}

#[test]
fn test_build_posts_rel() {
    let mut config = ConfigBuilder::default();
    config.posts.dir = "rel".into();
    let config = config.build().unwrap();
    assert_eq!(config.posts.dir, "rel");
}

#[test]
fn test_build_posts_abs() {
    let mut config = ConfigBuilder::default();
    config.posts.dir = "/root".into();
    assert!(config.build().is_err());
}

#[test]
fn test_build_drafts_rel() {
    let mut config = ConfigBuilder::default();
    config.posts.drafts_dir = Some("rel".into());
    let config = config.build().unwrap();
    assert_eq!(config.posts.drafts_dir, Some("rel".into()));
}

#[test]
fn test_build_drafts_abs() {
    let mut config = ConfigBuilder::default();
    config.posts.drafts_dir = Some("/root".into());
    assert!(config.build().is_err());
}
<|endoftext|>


<commit_before>//!
//! The main `Desync` struct
//!

use super::scheduler::*;

use std::sync::Arc;
use futures::channel::oneshot;
use futures::future::Future;

///
/// A data storage structure used to govern synchronous and asynchronous access to an underlying object.
///
pub struct Desync<T: Send> {
    /// Queue used for scheduling runtime for this object
    queue:  Arc<JobQueue>,

    /// Data for this object. Boxed so the pointer remains the same through the lifetime of the object.
    data:   Box<T>
}

// Rust actually derives this anyway at the moment
unsafe impl<T: Send> Send for Desync<T> {}

// True iff queue: Sync
unsafe impl<T: Send> Sync for Desync<T> {}

///
/// Used for passing the data pointer through to the queue
///
/// 'Safe' because the queue is synchronised during drop, so we can never use the pointer
/// if the object does not exist.
///
struct DataRef<T: Send>(*const T);
unsafe impl<T: Send> Send for DataRef<T> {}

// TODO: we can change DataRef to Shared (https://doc.rust-lang.org/std/ptr/struct.Shared.html in the future)

// TODO: T does not need to be static as we know that its lifetime is at least the lifetime of Desync<T> and hence the queue
impl<T: 'static+Send> Desync<T> {
    ///
    /// Creates a new Desync object
    ///
    pub fn new(data: T) -> Desync<T> {
        let queue = queue();

        Desync {
            queue:  queue,
            data:   Box::new(data)
        }
    }

    ///
    /// Performs an operation asynchronously on this item. This function will return
    /// immediately and the job will happen on a separate thread at some time in the
    /// future (generally fairly soon).
    ///
    /// Jobs are always performed in the order that they are queued and are always
    /// performed synchronously with respect to this object.
    ///
    #[inline]
    #[deprecated(since="0.3.0", note="please use `desync` instead")]
    pub fn r#async<TFn>(&self, job: TFn)
    where TFn: 'static+Send+FnOnce(&mut T) -> () {
        self.desync(job)
    }

    ///
    /// Performs an operation asynchronously on this item. This function will return
    /// immediately and the job will happen on a separate thread at some time in the
    /// future (generally fairly soon).
    ///
    /// Jobs are always performed in the order that they are queued and are always
    /// performed synchronously with respect to this object.
    ///
    pub fn desync<TFn>(&self, job: TFn)
    where TFn: 'static+Send+FnOnce(&mut T) -> () {
        unsafe {
            // As drop() is the last thing called, we know that this object will still exist at the point where the queue makes the asynchronous callback
            let data = DataRef(&*self.data);

            desync(&self.queue, move || {
                let data = data.0 as *mut T;
                job(&mut *data);
            })
        }
    }

    ///
    /// Performs an operation synchronously on this item. This will be queued with any other
    /// jobs that this item may be performing, and this function will not return until the
    /// job is complete and the result is available.
    ///
    pub fn sync<TFn, Result>(&self, job: TFn) -> Result
    where TFn: Send+FnOnce(&mut T) -> Result, Result: Send {
        let result = unsafe {
            // As drop() is the last thing called, we know that this object will still exist at the point where the callback occurs
            let data = DataRef(&*self.data);

            sync(&self.queue, move || {
                let data = data.0 as *mut T;
                job(&mut *data)
            })
        };

        result
    }

    ///
    /// Performs an operation asynchronously on the contents of this item, returning the
    /// result via a future.
    ///
    pub fn future<TFn, Item: 'static+Send>(&self, job: TFn) -> impl Future<Output=Result<Item, oneshot::Canceled>>+Send
    where TFn: 'static+Send+FnOnce(&mut T) -> Item {
        let (send, receive) = oneshot::channel();

        self.desync(|data| {
            let result = job(data);

            if let Err(_result) = send.send(result) {
                // The listening side disconnected: we'll throw away the result and act like a normal desync instead
            }
        });

        receive
    }

    ///
    /// After the pending operations for this item are performed, waits for the
    /// supplied future to complete and then calls the specified function
    ///
    pub fn after<'a, TFn, Res: 'static+Send, Fut: 'static+Future+Send>(&self, after: Fut, job: TFn) -> impl 'static+Future<Output=Result<Res, oneshot::Canceled>>+Send
    where TFn: 'static+Send+FnOnce(&mut T, Fut::Output) -> Res {
        unsafe {
            // As drop() is the last thing called, we know that this object will still exist at the point where the callback occurs
            // Also, we'll have exclusive access to this object when the callback occurs
            let data = DataRef(&*self.data);

            scheduler().after(&self.queue, after, move |future_result| {
                let data = data.0 as *mut T;
                job(&mut *data, future_result)
            })
        }
    }
}

impl<T: Send> Drop for Desync<T> {
    fn drop(&mut self) {
        // Ensure that everything on the queue has committed by queueing a last synchronous event
        // (Not synchronising the queue would make this unsafe as we would hold on to a pointer to
        // the internal data structure)
        sync(&self.queue, || {});
    }
}
<commit_msg>Reduce the amount of code in the unsafe block here<commit_after>//!
//! The main `Desync` struct
//!

use super::scheduler::*;

use std::sync::Arc;
use futures::channel::oneshot;
use futures::future::Future;

///
/// A data storage structure used to govern synchronous and asynchronous access to an underlying object.
///
pub struct Desync<T: Send> {
    /// Queue used for scheduling runtime for this object
    queue:  Arc<JobQueue>,

    /// Data for this object. Boxed so the pointer remains the same through the lifetime of the object.
    data:   Box<T>
}

// Rust actually derives this anyway at the moment
unsafe impl<T: Send> Send for Desync<T> {}

// True iff queue: Sync
unsafe impl<T: Send> Sync for Desync<T> {}

///
/// Used for passing the data pointer through to the queue
///
/// 'Safe' because the queue is synchronised during drop, so we can never use the pointer
/// if the object does not exist.
///
struct DataRef<T: Send>(*const T);
unsafe impl<T: Send> Send for DataRef<T> {}

// TODO: we can change DataRef to Shared (https://doc.rust-lang.org/std/ptr/struct.Shared.html in the future)

// TODO: T does not need to be static as we know that its lifetime is at least the lifetime of Desync<T> and hence the queue
impl<T: 'static+Send> Desync<T> {
    ///
    /// Creates a new Desync object
    ///
    pub fn new(data: T) -> Desync<T> {
        let queue = queue();

        Desync {
            queue:  queue,
            data:   Box::new(data)
        }
    }

    ///
    /// Performs an operation asynchronously on this item. This function will return
    /// immediately and the job will happen on a separate thread at some time in the
    /// future (generally fairly soon).
    ///
    /// Jobs are always performed in the order that they are queued and are always
    /// performed synchronously with respect to this object.
    ///
    #[inline]
    #[deprecated(since="0.3.0", note="please use `desync` instead")]
    pub fn r#async<TFn>(&self, job: TFn)
    where TFn: 'static+Send+FnOnce(&mut T) -> () {
        self.desync(job)
    }

    ///
    /// Performs an operation asynchronously on this item. This function will return
    /// immediately and the job will happen on a separate thread at some time in the
    /// future (generally fairly soon).
    ///
    /// Jobs are always performed in the order that they are queued and are always
    /// performed synchronously with respect to this object.
    ///
    pub fn desync<TFn>(&self, job: TFn)
    where TFn: 'static+Send+FnOnce(&mut T) -> () {
        // As drop() is the last thing called, we know that this object will still exist at the point where the queue makes the asynchronous callback
        let data = DataRef(&*self.data);

        desync(&self.queue, move || {
            let data = data.0 as *mut T;
            job(unsafe { &mut *data });
        })
    }

    ///
    /// Performs an operation synchronously on this item. This will be queued with any other
    /// jobs that this item may be performing, and this function will not return until the
    /// job is complete and the result is available.
    ///
    pub fn sync<TFn, Result>(&self, job: TFn) -> Result
    where TFn: Send+FnOnce(&mut T) -> Result, Result: Send {
        let result = unsafe {
            // As drop() is the last thing called, we know that this object will still exist at the point where the callback occurs
            let data = DataRef(&*self.data);

            sync(&self.queue, move || {
                let data = data.0 as *mut T;
                job(&mut *data)
            })
        };

        result
    }

    ///
    /// Performs an operation asynchronously on the contents of this item, returning the
    /// result via a future.
    ///
    pub fn future<TFn, Item: 'static+Send>(&self, job: TFn) -> impl Future<Output=Result<Item, oneshot::Canceled>>+Send
    where TFn: 'static+Send+FnOnce(&mut T) -> Item {
        let (send, receive) = oneshot::channel();

        self.desync(|data| {
            let result = job(data);

            if let Err(_result) = send.send(result) {
                // The listening side disconnected: we'll throw away the result and act like a normal desync instead
            }
        });

        receive
    }

    ///
    /// After the pending operations for this item are performed, waits for the
    /// supplied future to complete and then calls the specified function
    ///
    pub fn after<'a, TFn, Res: 'static+Send, Fut: 'static+Future+Send>(&self, after: Fut, job: TFn) -> impl 'static+Future<Output=Result<Res, oneshot::Canceled>>+Send
    where TFn: 'static+Send+FnOnce(&mut T, Fut::Output) -> Res {
        // As drop() is the last thing called, we know that this object will still exist at the point where the callback occurs
        // Also, we'll have exclusive access to this object when the callback occurs
        let data = DataRef(&*self.data);

        scheduler().after(&self.queue, after, move |future_result| {
            let data = data.0 as *mut T;
            job(unsafe { &mut *data }, future_result)
        })
    }
}

impl<T: Send> Drop for Desync<T> {
    fn drop(&mut self) {
        // Ensure that everything on the queue has committed by queueing a last synchronous event
        // (Not synchronising the queue would make this unsafe as we would hold on to a pointer to
        // the internal data structure)
        sync(&self.queue, || {});
    }
}
<|endoftext|>


<commit_before>//! An emulated 128 bit unsigned integer.
//!
//! This module provides `Emu128`, a 128 bit unsigned integer that is
//! emulated using two `u64` types. This is useful for operations on
//! IPv6 address, which are 128 bit unsigned integers.
//!
//! Currently `Emu128` only implements those operations that are useful
//! for the `Ipv6Net` type. It is not intended to become a full `u128`
//! implementation.
//!
//! Conversion between `Ipv6Addr` and `Emu128` is provided by a `From`
//! and `Into` implementation on `Emu128`.
//!
//! [`Emu128`]: struct.Emu128.html

use std::ops::{BitAnd, BitOr, Shr, Shl};

/// An emulated 128 bit unsigned integer.
///
/// This module provides `Emu128`, a 128 bit unsigned integer that is
/// emulated using two `u64` types. This is useful for operations on
/// IPv6 address, which are 128 bit unsigned integers.
///
/// Currently `Emu128` only implements those operations that are useful
/// for the `Ipv6Net` type. It is not intended to become a full `u128`
/// implementation.
///
/// Conversion between `Ipv6Addr` and `Emu128` is provided by a `From`
/// and `Into` implementation on `Emu128`.
///
/// # Examples
///
/// ```
/// use std::u64;
/// use ipnet::Emu128;
///
/// let i0 = Emu128::min_value();
/// let i1 = Emu128::from([1, 1]);
/// let i2 = Emu128::max_value();
/// let i3 = Emu128::from([1, u64::MAX]);
///
/// assert_eq!(i0, Emu128 { hi: 0, lo: 0 });
/// assert_eq!(i2, Emu128 { hi: std::u64::MAX, lo: std::u64::MAX });
/// assert_eq!(i0.saturating_sub(i2), Emu128::min_value());
/// assert_eq!(i2.saturating_add(i2), Emu128::max_value());
/// assert_eq!(i1.saturating_add(i1), Emu128 { hi: 2, lo: 2 });
/// assert_eq!(i2.saturating_sub(i1), Emu128 { hi: std::u64::MAX-1, lo: std::u64::MAX-1 });
/// assert_eq!(i3.saturating_add(i1), Emu128 { hi: 3, lo: 0 });
/// assert_eq!(i3.saturating_sub(i1), Emu128 { hi: 0, lo: std::u64::MAX-1 });
/// assert_eq!(i1 << 1, Emu128 { hi: 2, lo: 2 });
/// assert_eq!(i1 << 63, Emu128 { hi: 1 << 63, lo: 1 << 63 });
/// assert_eq!(i1 << 127, Emu128 { hi: 1 << 63, lo: 0 });
/// assert_eq!(i1 >> 1, Emu128 { hi: 0, lo: 1u64 << 63 });
/// assert_eq!(i1 >> 63, Emu128 { hi: 0, lo: 2 });
/// assert_eq!(i1 >> 127, Emu128 { hi: 0, lo: 0 });
/// assert_eq!(i0 | i1, Emu128 { hi: 1, lo: 1 });
/// assert_eq!(i1 & i1, Emu128 { hi: 1, lo: 1 });
/// assert_eq!(i1 & i3, Emu128 { hi: 1, lo: 1 });
/// assert_eq!(i1 | i3, Emu128 { hi: 1, lo: std::u64::MAX });
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Emu128 {
    pub hi: u64,
    pub lo: u64,
}

impl Emu128 {
    pub fn min_value() -> Emu128 {
        Emu128 { hi: 0, lo: 0 }
    }

    pub fn max_value() -> Emu128 {
        Emu128 { hi: u64::max_value(), lo: u64::max_value() }
    }

    pub fn saturating_add(self, other: Emu128) -> Emu128 {
        let (lo, ov) = self.lo.overflowing_add(other.lo);
        let res = self.hi.checked_add(other.hi).and_then(|x| x.checked_add(if ov { 1 } else { 0 }));
        match res {
            Some(hi) => Emu128 { hi: hi, lo: lo },
            None => Emu128::max_value(),
        }
    }

    pub fn saturating_sub(self, other: Emu128) -> Emu128 {
        let (lo, ov) = self.lo.overflowing_sub(other.lo);
        let res = self.hi.checked_sub(other.hi).and_then(|x| x.checked_sub(if ov { 1 } else { 0 }));
        match res {
            Some(hi) => Emu128 { hi: hi, lo: lo },
            None => Emu128::min_value(),
        }
    }

    pub fn leading_zeros(self) -> u32 {
        if self.hi > 0 { self.hi.leading_zeros() } else { self.lo.leading_zeros() + 64 }
    }

    pub fn trailing_zeros(self) -> u32 {
        if self.lo > 0 { self.lo.trailing_zeros() } else { self.hi.trailing_zeros() + 64 }
    }
}

impl Shl<u8> for Emu128 {
    type Output = Self;

    fn shl(self, rhs: u8) -> Emu128 {
        if rhs < 64 {
            Emu128 {
                hi: self.hi << rhs | self.lo >> (64-rhs),
                lo: self.lo << rhs
            }
        }
        else {
            Emu128 {
                hi: self.lo << (rhs-64),
                lo: 0
            }
        }
    }
}

impl Shr<u8> for Emu128 {
    type Output = Self;

    fn shr(self, rhs: u8) -> Emu128 {
        if rhs < 64 {
            Emu128 {
                hi: self.hi >> rhs,
                lo: self.lo >> rhs | self.hi << (64-rhs),
            }
        }
        else {
            Emu128 {
                hi: 0,
                lo: self.hi >> (rhs-64),
            }
        }
    }
}

impl BitAnd for Emu128 {
    type Output = Self;
    fn bitand(self, rhs: Emu128) -> Emu128 {
        Emu128 {
            hi: self.hi & rhs.hi,
            lo: self.lo & rhs.lo,
        }
    }
}

impl BitOr for Emu128 {
    type Output = Self;
    fn bitor(self, rhs: Emu128) -> Emu128 {
        Emu128 {
            hi: self.hi | rhs.hi,
            lo: self.lo | rhs.lo,
        }
    }
}

/// Convert an a `[u64; 2]` slice into an `Emu128`.
///
/// # Examples
///
/// ```
/// use ipnet::Emu128;
///
/// let u = Emu128::from([123u64, 123u64]);
/// let v: [u64; 2] = u.into();
/// assert_eq!(v, [123u64, 123u64]);
/// ```
impl From<[u64; 2]> for Emu128 {
    fn from(slice: [u64; 2]) -> Self {
        Emu128 {
            hi: slice[0],
            lo: slice[1],
        }
    }
}

/// Convert an Emu128 into a `[u64; 2]` slice.
///
/// # Examples
///
/// ```
/// use ipnet::Emu128;
///
/// let u = Emu128::from([123u64, 123u64]);
/// let v: [u64; 2] = u.into();
/// assert_eq!(v, [123u64, 123u64]);
/// ```
impl From<Emu128> for [u64; 2] {
    fn from(u: Emu128) -> Self {
        [u.hi, u.lo]
    }
}
<commit_msg>Added conversion from u32<commit_after>//! An emulated 128 bit unsigned integer.
//!
//! This module provides `Emu128`, a 128 bit unsigned integer that is
//! emulated using two `u64` types. This is useful for operations on
//! IPv6 address, which are 128 bit unsigned integers.
//!
//! Currently `Emu128` only implements those operations that are useful
//! for the `Ipv6Net` type. It is not intended to become a full `u128`
//! implementation.
//!
//! Conversion between `Ipv6Addr` and `Emu128` is provided by a `From`
//! and `Into` implementation on `Emu128`.
//!
//! [`Emu128`]: struct.Emu128.html

use std::ops::{BitAnd, BitOr, Shr, Shl};

/// An emulated 128 bit unsigned integer.
///
/// This module provides `Emu128`, a 128 bit unsigned integer that is
/// emulated using two `u64` types. This is useful for operations on
/// IPv6 address, which are 128 bit unsigned integers.
///
/// Currently `Emu128` only implements those operations that are useful
/// for the `Ipv6Net` type. It is not intended to become a full `u128`
/// implementation.
///
/// Conversion between `Ipv6Addr` and `Emu128` is provided by a `From`
/// and `Into` implementation on `Emu128`.
///
/// # Examples
///
/// ```
/// use std::u64;
/// use ipnet::Emu128;
///
/// let i0 = Emu128::min_value();
/// let i1 = Emu128::from([1, 1]);
/// let i2 = Emu128::max_value();
/// let i3 = Emu128::from([1, u64::MAX]);
///
/// assert_eq!(i0, Emu128 { hi: 0, lo: 0 });
/// assert_eq!(i2, Emu128 { hi: std::u64::MAX, lo: std::u64::MAX });
/// assert_eq!(i0.saturating_sub(i2), Emu128::min_value());
/// assert_eq!(i2.saturating_add(i2), Emu128::max_value());
/// assert_eq!(i1.saturating_add(i1), Emu128 { hi: 2, lo: 2 });
/// assert_eq!(i2.saturating_sub(i1), Emu128 { hi: std::u64::MAX-1, lo: std::u64::MAX-1 });
/// assert_eq!(i3.saturating_add(i1), Emu128 { hi: 3, lo: 0 });
/// assert_eq!(i3.saturating_sub(i1), Emu128 { hi: 0, lo: std::u64::MAX-1 });
/// assert_eq!(i1 << 1, Emu128 { hi: 2, lo: 2 });
/// assert_eq!(i1 << 63, Emu128 { hi: 1 << 63, lo: 1 << 63 });
/// assert_eq!(i1 << 127, Emu128 { hi: 1 << 63, lo: 0 });
/// assert_eq!(i1 >> 1, Emu128 { hi: 0, lo: 1u64 << 63 });
/// assert_eq!(i1 >> 63, Emu128 { hi: 0, lo: 2 });
/// assert_eq!(i1 >> 127, Emu128 { hi: 0, lo: 0 });
/// assert_eq!(i0 | i1, Emu128 { hi: 1, lo: 1 });
/// assert_eq!(i1 & i1, Emu128 { hi: 1, lo: 1 });
/// assert_eq!(i1 & i3, Emu128 { hi: 1, lo: 1 });
/// assert_eq!(i1 | i3, Emu128 { hi: 1, lo: std::u64::MAX });
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Emu128 {
    pub hi: u64,
    pub lo: u64,
}

impl Emu128 {
    pub fn min_value() -> Emu128 {
        Emu128 { hi: 0, lo: 0 }
    }

    pub fn max_value() -> Emu128 {
        Emu128 { hi: u64::max_value(), lo: u64::max_value() }
    }

    pub fn saturating_add(self, other: Emu128) -> Emu128 {
        let (lo, ov) = self.lo.overflowing_add(other.lo);
        let res = self.hi.checked_add(other.hi).and_then(|x| x.checked_add(if ov { 1 } else { 0 }));
        match res {
            Some(hi) => Emu128 { hi: hi, lo: lo },
            None => Emu128::max_value(),
        }
    }

    pub fn saturating_sub(self, other: Emu128) -> Emu128 {
        let (lo, ov) = self.lo.overflowing_sub(other.lo);
        let res = self.hi.checked_sub(other.hi).and_then(|x| x.checked_sub(if ov { 1 } else { 0 }));
        match res {
            Some(hi) => Emu128 { hi: hi, lo: lo },
            None => Emu128::min_value(),
        }
    }

    pub fn leading_zeros(self) -> u32 {
        if self.hi > 0 { self.hi.leading_zeros() } else { self.lo.leading_zeros() + 64 }
    }

    pub fn trailing_zeros(self) -> u32 {
        if self.lo > 0 { self.lo.trailing_zeros() } else { self.hi.trailing_zeros() + 64 }
    }
}

impl Shl<u8> for Emu128 {
    type Output = Self;

    fn shl(self, rhs: u8) -> Emu128 {
        if rhs < 64 {
            Emu128 {
                hi: self.hi << rhs | self.lo >> (64-rhs),
                lo: self.lo << rhs
            }
        }
        else {
            Emu128 {
                hi: self.lo << (rhs-64),
                lo: 0
            }
        }
    }
}

impl Shr<u8> for Emu128 {
    type Output = Self;

    fn shr(self, rhs: u8) -> Emu128 {
        if rhs < 64 {
            Emu128 {
                hi: self.hi >> rhs,
                lo: self.lo >> rhs | self.hi << (64-rhs),
            }
        }
        else {
            Emu128 {
                hi: 0,
                lo: self.hi >> (rhs-64),
            }
        }
    }
}

impl BitAnd for Emu128 {
    type Output = Self;
    fn bitand(self, rhs: Emu128) -> Emu128 {
        Emu128 {
            hi: self.hi & rhs.hi,
            lo: self.lo & rhs.lo,
        }
    }
}

impl BitOr for Emu128 {
    type Output = Self;
    fn bitor(self, rhs: Emu128) -> Emu128 {
        Emu128 {
            hi: self.hi | rhs.hi,
            lo: self.lo | rhs.lo,
        }
    }
}

/// Convert a `u32` into an `EMU128`.
///
/// # Examples
///
/// ```
/// use ipnet::Emu128;
///
/// assert_eq!(Emu128::from([0u64, 1u64]), Emu128::from(1u32));
/// ```
impl From<u32> for Emu128 {
    fn from(u: u32) -> Self {
        Emu128 {
            hi: 0,
            lo: u as u64,
        }
    }
}

/// Convert an a `[u64; 2]` slice into an `Emu128`.
///
/// # Examples
///
/// ```
/// use ipnet::Emu128;
///
/// let u = Emu128::from([123u64, 123u64]);
/// let v: [u64; 2] = u.into();
/// assert_eq!(v, [123u64, 123u64]);
/// ```
impl From<[u64; 2]> for Emu128 {
    fn from(slice: [u64; 2]) -> Self {
        Emu128 {
            hi: slice[0],
            lo: slice[1],
        }
    }
}

/// Convert an Emu128 into a `[u64; 2]` slice.
///
/// # Examples
///
/// ```
/// use ipnet::Emu128;
///
/// let u = Emu128::from([123u64, 123u64]);
/// let v: [u64; 2] = u.into();
/// assert_eq!(v, [123u64, 123u64]);
/// ```
impl From<Emu128> for [u64; 2] {
    fn from(u: Emu128) -> Self {
        [u.hi, u.lo]
    }
}
<|endoftext|>


<commit_before>use hyper;
use std::convert::From;
use serde_json;
use std::num::ParseIntError;

impl From<::json::Error> for HueError {
    fn from(e: ::json::Error) -> HueError {
        HueErrorKind::BridgeError {
            address:e.address,
            description:e.description,
            error:From::from(e.code)
        }.into()
    }
}

error_chain! {

    types {
        HueError, HueErrorKind, ResultExt, Result;
    }

    errors {
        /// this does not happen in practice
        MalformedResponse { }
        /// An error that occured in the bridge
        BridgeError { address:String, description:String, error:BridgeError} {
            description("bridge error")
            display("Bridge error: {:?} address: {} description: {}", error, address, description)
        }
    }

    foreign_links {
        JsonError(serde_json::Error);
        HyperError(hyper::Error);
        ParseIntError(ParseIntError);
    }

}

macro_rules! error_enum {
    (
        $(#[$meta:meta])*
        pub enum $name:ident{
            $($err:ident = $n:expr),+;
            $other:ident
        }
    ) => (
        $(#[$meta])*
        pub enum $name{
            $($err = $n,)+
            $other
        }
        impl From<u16> for $name{
            fn from(n: u16) -> Self{
                match n {
                    $($n => $name::$err,)+
                    _ => $name::$other
                }
            }
        }
    );
}

error_enum!{
    /// All errors defined in http://www.developers.meethue.com/documentation/error-messages
    #[repr(u16)]
    #[allow(missing_docs)]
    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
    pub enum BridgeError {
        // Generic Errors
        UnauthorizedUser = 1,
        BodyContainsInvalidJson = 2,
        ResourceNotAvailable = 3,
        MethodNotAvailableForResource = 4,
        MissingParametersInBody = 5,
        ParameterNotAvailable = 6,
        InvalidValueForParameter = 7,
        ParameterIsNotModifiable = 8,
        TooManyItemsInList = 11,
        ProtalConnectionRequired = 12,
        InternalError = 901,

        // Command Specific Errors
        LinkButtonNotPressed = 101,
        DHCPCannotBeDisabled = 110,
        InvalidUpdateState = 111,
        DeviceIsSetToOff = 201,
        GroupCouldNotBeCreatedGroupFull = 301,
        DeviceCouldNotBeAddedGroupFull = 302,
        DeviceIsUnreachable = 304,
        UpdateOrDeleteGroupOfThisTypeNotAllowed = 305,
        LightAlreadyUsed = 306,
        SceneCouldNotBeCreated = 401,
        SceneCouldNotBeCreatedBufferFull = 402,
        SceneCouldNotBeRemoved = 403,
        NotAllowedToCreateSensorType = 501,
        SensorListIsFull = 502,
        RuleEngineFull = 601,
        ConditionError = 607,
        ActionError = 608,
        UnableToActivae = 609,
        ScheduleListIsFull = 701,
        ScheduleTimezoneNotValid = 702,
        ScheduleCannotSetTimeAndLocalTime = 703,
        CannotCreateSchedule = 704,
        CannotEnableScheduleTimeInPast = 705,
        CommandError = 706,
        SourceModelInvalid = 801,
        SourceFactoryNew = 802,
        InvalidState = 803;
        Other
    }
}

#[test]
fn bridge_errors() {
    use self::BridgeError::*;

    assert_eq!(BridgeError::from(101), LinkButtonNotPressed);
    assert_eq!(BridgeError::from(0), Other);
    assert_eq!(BridgeError::from(51234), Other);
    assert_eq!(BridgeError::from(4), MethodNotAvailableForResource);
    assert_eq!(SceneCouldNotBeRemoved as u16, 403);
    assert_eq!(InternalError as u16, 901);
}
<commit_msg>cleanup bridge error (unfortunately documentation is not allowed by error-chain for the fields)<commit_after>use hyper;
use std::convert::From;
use serde_json;
use std::num::ParseIntError;

impl From<::json::Error> for HueError {
    fn from(e: ::json::Error) -> HueError {
        HueErrorKind::BridgeError {
            address:e.address,
            description:e.description,
            error:From::from(e.code)
        }.into()
    }
}

error_chain! {

    types {
        HueError, HueErrorKind, ResultExt, Result;
    }

    errors {
        /// this does not happen in practice
        MalformedResponse { }
        /// An error that occured in the bridge
        BridgeError {
            address:String,
            description:String,
            error:BridgeError
        } {
            description("bridge error")
            display("Bridge error: {:?} address: {} description: {}", error, address, description)
        }
    }

    foreign_links {
        JsonError(serde_json::Error);
        HyperError(hyper::Error);
        ParseIntError(ParseIntError);
    }

}

macro_rules! error_enum {
    (
        $(#[$meta:meta])*
        pub enum $name:ident{
            $($err:ident = $n:expr),+;
            $other:ident
        }
    ) => (
        $(#[$meta])*
        pub enum $name{
            $($err = $n,)+
            $other
        }
        impl From<u16> for $name{
            fn from(n: u16) -> Self{
                match n {
                    $($n => $name::$err,)+
                    _ => $name::$other
                }
            }
        }
    );
}

error_enum!{
    /// All errors defined in http://www.developers.meethue.com/documentation/error-messages
    #[repr(u16)]
    #[allow(missing_docs)]
    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
    pub enum BridgeError {
        // Generic Errors
        UnauthorizedUser = 1,
        BodyContainsInvalidJson = 2,
        ResourceNotAvailable = 3,
        MethodNotAvailableForResource = 4,
        MissingParametersInBody = 5,
        ParameterNotAvailable = 6,
        InvalidValueForParameter = 7,
        ParameterIsNotModifiable = 8,
        TooManyItemsInList = 11,
        ProtalConnectionRequired = 12,
        InternalError = 901,

        // Command Specific Errors
        LinkButtonNotPressed = 101,
        DHCPCannotBeDisabled = 110,
        InvalidUpdateState = 111,
        DeviceIsSetToOff = 201,
        GroupCouldNotBeCreatedGroupFull = 301,
        DeviceCouldNotBeAddedGroupFull = 302,
        DeviceIsUnreachable = 304,
        UpdateOrDeleteGroupOfThisTypeNotAllowed = 305,
        LightAlreadyUsed = 306,
        SceneCouldNotBeCreated = 401,
        SceneCouldNotBeCreatedBufferFull = 402,
        SceneCouldNotBeRemoved = 403,
        NotAllowedToCreateSensorType = 501,
        SensorListIsFull = 502,
        RuleEngineFull = 601,
        ConditionError = 607,
        ActionError = 608,
        UnableToActivae = 609,
        ScheduleListIsFull = 701,
        ScheduleTimezoneNotValid = 702,
        ScheduleCannotSetTimeAndLocalTime = 703,
        CannotCreateSchedule = 704,
        CannotEnableScheduleTimeInPast = 705,
        CommandError = 706,
        SourceModelInvalid = 801,
        SourceFactoryNew = 802,
        InvalidState = 803;
        Other
    }
}

#[test]
fn bridge_errors() {
    use self::BridgeError::*;

    assert_eq!(BridgeError::from(101), LinkButtonNotPressed);
    assert_eq!(BridgeError::from(0), Other);
    assert_eq!(BridgeError::from(51234), Other);
    assert_eq!(BridgeError::from(4), MethodNotAvailableForResource);
    assert_eq!(SceneCouldNotBeRemoved as u16, 403);
    assert_eq!(InternalError as u16, 901);
}
<|endoftext|>


<commit_before>use std::fmt;

pub enum OscError {
    BadOscPacket(String),
    BadOscAddress(String),
    BadOscMessage(String),
    BadOscString(String),
    BadOscBundle,
}

impl fmt::Display for OscError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            _ => write!(f, "{}", "TODO"),
        }
    }
}
<commit_msg>Create type alias to simplify code<commit_after>use std::fmt;

type OscResult<T> = Result<T, OscError>;

pub enum OscError {
    BadOscPacket(String),
    BadOscAddress(String),
    BadOscMessage(String),
    BadOscString(String),
    BadOscBundle,
}

impl fmt::Display for OscError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            _ => write!(f, "{}", "TODO"),
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::cell::RefCell;

/// Format all iterator elements lazily, separated by `sep`.
///
/// See [`.format()`](trait.Itertools.html#method.format) for more information.
pub struct Format<'a, I, F> {
    sep: &'a str,
    /// Format uses interior mutability because Display::fmt takes &self.
    inner: RefCell<(I, F)>,
}

pub fn new_format<'a, I, F>(iter: I, separator: &'a str, f: F) -> Format<'a, I, F>
    where I: Iterator,
          F: FnMut(I::Item, &mut FnMut(&fmt::Display) -> fmt::Result) -> fmt::Result,
{
    Format{sep: separator, inner: RefCell::new((iter, f))}
}

impl<'a, I, F> fmt::Display for Format<'a, I, F>
    where I: Iterator,
          F: FnMut(I::Item, &mut FnMut(&fmt::Display) -> fmt::Result) -> fmt::Result,
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let mut cb = &mut |disp: &fmt::Display| write!(fmt, "{}", disp);
        let (ref mut iter, ref mut format)  = *self.inner.borrow_mut();

        if let Some(fst) = iter.next() {
            try!(format(fst, cb));
            for elt in iter {
                if self.sep.len() > 0 {
                    try!(cb(&self.sep));
                }
                try!(format(elt, cb));
            }
        }
        Ok(())
    }
}

impl<'a, I, F> fmt::Debug for Format<'a, I, F>
    where I: Iterator,
          F: FnMut(I::Item, &mut FnMut(&fmt::Display) -> fmt::Result) -> fmt::Result,
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, fmt)
    }
}

<commit_msg>format: Fix pattern match for Rust 1.0<commit_after>use std::fmt;
use std::cell::RefCell;

/// Format all iterator elements lazily, separated by `sep`.
///
/// See [`.format()`](trait.Itertools.html#method.format) for more information.
pub struct Format<'a, I, F> {
    sep: &'a str,
    /// Format uses interior mutability because Display::fmt takes &self.
    inner: RefCell<(I, F)>,
}

pub fn new_format<'a, I, F>(iter: I, separator: &'a str, f: F) -> Format<'a, I, F>
    where I: Iterator,
          F: FnMut(I::Item, &mut FnMut(&fmt::Display) -> fmt::Result) -> fmt::Result,
{
    Format{sep: separator, inner: RefCell::new((iter, f))}
}

impl<'a, I, F> fmt::Display for Format<'a, I, F>
    where I: Iterator,
          F: FnMut(I::Item, &mut FnMut(&fmt::Display) -> fmt::Result) -> fmt::Result,
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let mut cb = &mut |disp: &fmt::Display| write!(fmt, "{}", disp);
        // the extra *&mut is a workaround for Rust 1.0
        let (ref mut iter, ref mut format)  = *&mut *self.inner.borrow_mut();

        if let Some(fst) = iter.next() {
            try!(format(fst, cb));
            for elt in iter {
                if self.sep.len() > 0 {
                    try!(cb(&self.sep));
                }
                try!(format(elt, cb));
            }
        }
        Ok(())
    }
}

impl<'a, I, F> fmt::Debug for Format<'a, I, F>
    where I: Iterator,
          F: FnMut(I::Item, &mut FnMut(&fmt::Display) -> fmt::Result) -> fmt::Result,
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, fmt)
    }
}

<|endoftext|>


<commit_before>use std::io::{Write, stderr};

use rotor::{EventSet, PollOpt, Void};
use rotor::mio::{TryRead, TryWrite};
use rotor::mio::tcp::{TcpListener, TcpStream};
use rotor::{Machine, Response, EarlyScope, Scope};

use super::util::*;

pub struct Context {
    pub root_dir: String,
}

pub enum Gopher {
    Server(TcpListener),
    Connection(TcpStream),
}

impl Gopher {
    pub fn new(sock: TcpListener, scope: &mut EarlyScope)
        -> Response<Gopher, Void>
    {
        scope.register(&sock, EventSet::readable(), PollOpt::edge())
            .unwrap();
        Response::ok(Gopher::Server(sock))
    }
    fn accept(self) -> Response<Gopher, TcpStream> {
        match self {
            Gopher::Server(sock) => {
                match sock.accept() {
                    Ok(Some((conn, _))) => {
                        Response::spawn(Gopher::Server(sock), conn)
                    }
                    Ok(None) => {
                        Response::ok(Gopher::Server(sock))
                    }
                    Err(e) => {
                        writeln!(&mut stderr(), "Error: {}", e).ok();
                        Response::ok(Gopher::Server(sock))
                    }
                }
            }
            _ => unreachable!(),
        }
    }
}

impl Machine for Gopher {
    type Context = Context;
    type Seed = TcpStream;

    fn create(conn: TcpStream, scope: &mut Scope<Context>)
        -> Response<Self, Void>
    {
        scope.register(&conn, EventSet::readable(), PollOpt::level())
            .unwrap();
        Response::ok(Gopher::Connection(conn))
    }

    fn ready(self, _events: EventSet, scope: &mut Scope<Context>)
        -> Response<Self, TcpStream>
    {
        match self {
            me @ Gopher::Server(..) => me.accept(),
            Gopher::Connection(mut sock) => {
                let mut data = [0u8; 1024];
                match sock.try_read(&mut data) {
                    Err(e) => {
                        writeln!(&mut stderr(), "read: {}", e).ok();
                        Response::done()
                    }
                    Ok(Some(0)) => {
                        Response::done()
                    }
                    Ok(Some(x)) => {
                        match local_path_for_request(&data[..x], &scope.root_dir) {
                            Some(p) => {
                                match sock.try_write(&p) {
                                    Ok(Some(x)) => {
                                        // TODO(nokaa): keep writing while x < p.len
                                        if x < p.len() {
                                            println!("not enough");
                                        }
                                        Response::done()
                                    }
                                    Ok(None) => Response::done(),
                                    Err(e) => {
                                        writeln!(&mut stderr(), "write: {}", e).ok();
                                        Response::done()
                                    }
                                }
                            }
                            None => Response::done(),
                        }
                    }
                    Ok(None) => {
                        Response::ok(Gopher::Connection(sock))
                    }
                }
            }
        }
    }
    fn spawned(self, _scope: &mut Scope<Context>) -> Response<Self, TcpStream>
    {
        match self {
            me @ Gopher::Server(..) => me.accept(),
            _ => unreachable!(),
        }
    }
    fn timeout(self, _scope: &mut Scope<Context>)
        -> Response<Self, TcpStream>
    {
        unreachable!();
    }
    fn wakeup(self, _scope: &mut Scope<Context>)
        -> Response<Self, TcpStream>
    {
        unreachable!();
    }
}
<commit_msg>Add 404 error equivalent<commit_after>use std::io::{Write, stderr};
use std::str;

use rotor::{EventSet, PollOpt, Void};
use rotor::mio::{TryRead, TryWrite};
use rotor::mio::tcp::{TcpListener, TcpStream};
use rotor::{Machine, Response, EarlyScope, Scope};

use super::util::*;

pub struct Context {
    pub root_dir: String,
}

pub enum Gopher {
    Server(TcpListener),
    Connection(TcpStream),
}

impl Gopher {
    pub fn new(sock: TcpListener, scope: &mut EarlyScope)
        -> Response<Gopher, Void>
    {
        scope.register(&sock, EventSet::readable(), PollOpt::edge())
            .unwrap();
        Response::ok(Gopher::Server(sock))
    }
    fn accept(self) -> Response<Gopher, TcpStream> {
        match self {
            Gopher::Server(sock) => {
                match sock.accept() {
                    Ok(Some((conn, _))) => {
                        Response::spawn(Gopher::Server(sock), conn)
                    }
                    Ok(None) => {
                        Response::ok(Gopher::Server(sock))
                    }
                    Err(e) => {
                        writeln!(&mut stderr(), "Error: {}", e).ok();
                        Response::ok(Gopher::Server(sock))
                    }
                }
            }
            _ => unreachable!(),
        }
    }
}

impl Machine for Gopher {
    type Context = Context;
    type Seed = TcpStream;

    fn create(conn: TcpStream, scope: &mut Scope<Context>)
        -> Response<Self, Void>
    {
        scope.register(&conn, EventSet::readable(), PollOpt::level())
            .unwrap();
        Response::ok(Gopher::Connection(conn))
    }

    fn ready(self, _events: EventSet, scope: &mut Scope<Context>)
        -> Response<Self, TcpStream>
    {
        match self {
            me @ Gopher::Server(..) => me.accept(),
            Gopher::Connection(mut sock) => {
                let mut data = [0u8; 1024];
                match sock.try_read(&mut data) {
                    Err(e) => {
                        writeln!(&mut stderr(), "read: {}", e).ok();
                        Response::done()
                    }
                    Ok(Some(0)) => {
                        Response::done()
                    }
                    Ok(Some(x)) => {
                        match local_path_for_request(&data[..x], &scope.root_dir) {
                            Some(p) => {
                                match sock.try_write(&p) {
                                    Ok(Some(x)) => {
                                        // TODO(nokaa): keep writing while x < p.len
                                        if x < p.len() {
                                            println!("not enough");
                                        }
                                        Response::done()
                                    }
                                    Ok(None) => Response::done(),
                                    Err(e) => {
                                        writeln!(&mut stderr(), "write: {}", e).ok();
                                        Response::done()
                                    }
                                }
                            }
                            None => {
                                let token = str::from_utf8(&data[..x-2]).unwrap();
                                let d = &format!("3Sorry, but the requested token '{}' could not be found.\tErr\tlocalhost\t70\r\n.", token)[..];
                                match sock.try_write(d.as_bytes()) {
                                    Ok(_) => Response::done(),
                                    Err(e) => {
                                        writeln!(&mut stderr(), "write: {}", e).ok();
                                        Response::done()
                                    }
                                }
                            }
                        }
                    }
                    Ok(None) => {
                        Response::ok(Gopher::Connection(sock))
                    }
                }
            }
        }
    }
    fn spawned(self, _scope: &mut Scope<Context>) -> Response<Self, TcpStream>
    {
        match self {
            me @ Gopher::Server(..) => me.accept(),
            _ => unreachable!(),
        }
    }
    fn timeout(self, _scope: &mut Scope<Context>)
        -> Response<Self, TcpStream>
    {
        unreachable!();
    }
    fn wakeup(self, _scope: &mut Scope<Context>)
        -> Response<Self, TcpStream>
    {
        unreachable!();
    }
}
<|endoftext|>


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

struct History {
    h: Vec<(usize, usize)>
}

struct Board {
        board: [usize; 8],
}

impl Board{
    fn new() -> Board {
        Board{
            board: [8,8,8,8,8,8,8,8]
        }
    }

    fn set(&mut self, x: usize, y: usize){
        self.board[x] = y;
    }

    fn get(&self, x: usize) -> usize {
        self.board[x]
    }

    fn pos_set(&self, x: usize, y: usize) -> bool {
        self.get(x) == y
    }

    fn done(&self) -> bool {
        for i in 0..self.board.len() {
            if self.board[i] == 8 {
                return false;
            }
        }
        return true;
    }

    fn print(&self){
        println!("\n---------------------------------");
        for i in 0..8 {
            print!("|");
            for j in 0..8 {
                match self.get(j).cmp(&i) {
                    Ordering::Equal     => print!(" {} |", "X"),
                    Ordering::Greater   => print!(" {} |", " "),
                    Ordering::Less      => print!(" {} |", " "),
                }
            }
            println!("\n---------------------------------");
        }
    }

    fn collision(&self, x: usize, y: usize) -> bool {
        // col
        if self.get(x) != 8 {
            //println!("column true");
            return true;
        }

        for i in 0..8 {
            if self.pos_set(i, y) {
                //println!("row true");
                return true;
            }
        }

        let mut x_pos;
        let mut y_pos;
        if x < (7 - y) {
            x_pos = 0;
            y_pos = y + x;
        } else {
            x_pos = x - (7 - y);
            y_pos = 7;
        }

        loop {
            if self.pos_set(x_pos, y_pos){
                //println!("diag 1 found");
                return true;
            }
            if y_pos == 0 {
                break;
            }
            if x_pos == 7 {
                break;
            }
            x_pos = x_pos + 1;
            y_pos = y_pos - 1;
        }

        let mut x_pos;
        let mut y_pos;
        if y < x {
            x_pos = x - y;
            y_pos = 0;
        } else {
            x_pos = 0;
            y_pos = y - x;
        }

        loop {
            if self.pos_set(x_pos, y_pos){
                //println!("diag 1 found");
                return true;
            }
            if y_pos == 7 {
                break;
            }
            if x_pos == 7 {
                break;
            }
            x_pos = x_pos + 1;
            y_pos = y_pos + 1;
        }

        return false;
    }
}

fn find_my_queens(board: &mut Board, history: &mut History, row: usize, col: usize){
    if board.done() {
        board.print();
        return;
    }

    let r = row % 8;
    let mut c = 0;
    let mut found = false;
    for i in col..8 {
        if !board.collision(i, r){
            c = i;
            found = true;
            break;
        }
    }

    if found {
        board.set(c, r);
        history.h.push((c, r));
        find_my_queens(board, history, r + 1, 0);
    } else {
        match history.h.pop() {
            Some((x,_)) => {
                board.set(x, 8);
                if r == 0 {
                    find_my_queens(board, history, r, x + 1)
                } else {
                    find_my_queens(board, history, r - 1, x + 1)
                }
            }
            None => println!("Nope")
        }
    }
}

fn main() {
    let mut board = Board::new();
    let mut history = History { h: vec![] };
    find_my_queens(&mut board, &mut history, 5, 5);
}
<commit_msg>fix eight_queens<commit_after>use std::cmp::Ordering;

struct History {
    h: Vec<(usize, usize)>
}

struct Board {
        board: [usize; 8],
}

impl Board{
    fn new() -> Board {
        Board{
            board: [8,8,8,8,8,8,8,8]
        }
    }

    fn set(&mut self, x: usize, y: usize){
        self.board[x] = y;
    }

    fn get(&self, x: usize) -> usize {
        self.board[x]
    }

    fn pos_set(&self, x: usize, y: usize) -> bool {
        self.get(x) == y
    }

    fn done(&self) -> bool {
        for i in 0..self.board.len() {
            if self.board[i] == 8 {
                return false;
            }
        }
        return true;
    }

    fn print(&self){
        println!("\n---------------------------------");
        for i in 0..8 {
            print!("|");
            for j in 0..8 {
                match self.get(j).cmp(&i) {
                    Ordering::Equal     => print!(" {} |", "X"),
                    Ordering::Greater   => print!(" {} |", " "),
                    Ordering::Less      => print!(" {} |", " "),
                }
            }
            println!("\n---------------------------------");
        }
    }

    fn collision(&self, x: usize, y: usize) -> bool {
        // col
        if self.get(x) != 8 {
            //println!("column true");
            return true;
        }

        for i in 0..8 {
            if self.pos_set(i, y) {
                //println!("row true");
                return true;
            }
        }

        let mut x_pos;
        let mut y_pos;
        if x < (7 - y) {
            x_pos = 0;
            y_pos = y + x;
        } else {
            x_pos = x - (7 - y);
            y_pos = 7;
        }

        loop {
            if self.pos_set(x_pos, y_pos){
                //println!("diag 1 found");
                return true;
            }
            if y_pos == 0 {
                break;
            }
            if x_pos == 7 {
                break;
            }
            x_pos = x_pos + 1;
            y_pos = y_pos - 1;
        }

        let mut x_pos;
        let mut y_pos;
        if y < x {
            x_pos = x - y;
            y_pos = 0;
        } else {
            x_pos = 0;
            y_pos = y - x;
        }

        loop {
            if self.pos_set(x_pos, y_pos){
                //println!("diag 1 found");
                return true;
            }
            if y_pos == 7 {
                break;
            }
            if x_pos == 7 {
                break;
            }
            x_pos = x_pos + 1;
            y_pos = y_pos + 1;
        }

        return false;
    }
}

fn find_my_queens(board: &mut Board, history: &mut History, row: usize, col: usize){
    if board.done() {
        board.print();
        return;
    }

    let r = row % 8;
    let mut c = 0;
    let mut found = false;
    for i in col..8 {
        if !board.collision(i, r){
            c = i;
            found = true;
            break;
        }
    }

    if found {
        board.set(c, r);
        history.h.push((c, r));
        find_my_queens(board, history, r + 1, 0);
    } else {
        match history.h.pop() {
            Some((x,_)) => {
                board.set(x, 8);
                if r == 0 {
                    find_my_queens(board, history, r, x + 1)
                } else {
                    find_my_queens(board, history, r - 1, x + 1)
                }
            }
            None => {}
        }
    }
}

fn main() {

    for i in 0..8 {
        for j in 0..8 {
            let mut board = Board::new();
            let mut history = History { h: vec![] };
            find_my_queens(&mut board, &mut history, j, i);
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::ffi::CString;
use std::os::unix::ffi::OsStrExt;
use std::path::PathBuf;

use libc;

// In C this would be simple getenv(). Not in Rust though
pub fn getenv(var: &str) -> Option<CString> {
    if let Some(value) = env::var_os(var) {
        let value = value.as_os_str().as_bytes();
        CString::new(value).ok()
    } else {
        None
    }
    // let to_bytes = |x: &OsString| x.as_os_str().as_bytes();
    // let to_bytes = |x: &OsString| x.into::<Vec<u8>>();
    // env::var_os(&self.env).map(to_bytes).and_then(|x| CString::new(x).ok())
}

// Helper wrappers around libc::* API
pub fn fork() -> libc::pid_t {
    unsafe { libc::fork() }
}

pub fn execvp(argv: Vec<*const libc::c_char>) {
    assert!(unsafe { libc::execvp(argv[0], argv.as_ptr()) } > -1);
}

pub fn dup2(fd1: i32, fd2: i32) {
    assert!(unsafe { libc::dup2(fd1, fd2) } > -1);
}

pub fn close(fd: i32) {
    assert_eq!(unsafe { libc::close(fd) }, 0);
}

pub fn pipe() -> (i32, i32) {
    let mut fds = [0; 2];
    assert_eq!(unsafe { libc::pipe(fds.as_mut_ptr()) }, 0);
    (fds[0], fds[1])
}

fn which(exec: &str) -> Option<PathBuf> {
    if let Some(path) = env::var_os("PATH") {
        let paths = env::split_paths(&path);
        for path in paths {
            let candidate = path.join(exec);
            if path.join(exec).exists() {
                return Some(candidate);
            }
        }
    }
    None
}

pub fn default_pager() -> Option<CString> {
    // let pathbuf2cstring = |p: PathBuf| CString::new(p.as_os_str().as_bytes()).ok();
    let str2cstring = |x: &str| CString::new(x).ok();
    let pathbuf2cstring = |p: PathBuf| p.to_str().and_then(str2cstring);
    which("more").and_then(pathbuf2cstring)
}

#[cfg(test)]
mod tests {
    use super::{default_pager, which};
    use std::ffi::CString;
    use std::path::PathBuf;

    #[test]
    fn more_found_in_path() {
        assert!(which("more").is_some())
    }

    #[test]
    fn erom_not_found_in_path() {
        assert!(which("erom").is_none())
    }

    #[test]
    fn which_more() {
        assert_eq!(which("more"), Some(PathBuf::from("/usr/bin/more")));
    }

    #[test]
    fn usr_bin_more_default_pager() {
        let usr_bin_more = CString::new("/usr/bin/more").unwrap();
        assert_eq!(default_pager(), Some(usr_bin_more));
    }
}
<commit_msg>Refactor<commit_after>use std::env;
use std::ffi::CString;
use std::os::unix::ffi::{OsStrExt, OsStringExt};
use std::path::PathBuf;

use libc;

// In C this would be simple getenv(). Not in Rust though
pub fn getenv(var: &str) -> Option<CString> {
    if let Some(value) = env::var_os(var) {
        let value = value.as_os_str().as_bytes();
        CString::new(value).ok()
    } else {
        None
    }
    // let to_bytes = |x: &OsString| x.as_os_str().as_bytes();
    // let to_bytes = |x: &OsString| x.into::<Vec<u8>>();
    // env::var_os(&self.env).map(to_bytes).and_then(|x| CString::new(x).ok())
}

// Helper wrappers around libc::* API
pub fn fork() -> libc::pid_t {
    unsafe { libc::fork() }
}

pub fn execvp(argv: Vec<*const libc::c_char>) {
    assert!(unsafe { libc::execvp(argv[0], argv.as_ptr()) } > -1);
}

pub fn dup2(fd1: i32, fd2: i32) {
    assert!(unsafe { libc::dup2(fd1, fd2) } > -1);
}

pub fn close(fd: i32) {
    assert_eq!(unsafe { libc::close(fd) }, 0);
}

pub fn pipe() -> (i32, i32) {
    let mut fds = [0; 2];
    assert_eq!(unsafe { libc::pipe(fds.as_mut_ptr()) }, 0);
    (fds[0], fds[1])
}

fn which(exec: &str) -> Option<PathBuf> {
    if let Some(path) = env::var_os("PATH") {
        let paths = env::split_paths(&path);
        for path in paths {
            let candidate = path.join(exec);
            if path.join(exec).exists() {
                return Some(candidate);
            }
        }
    }
    None
}

pub fn default_pager() -> Option<CString> {
    which("more")
        .map(|p| p.into_os_string().into_vec())
        .and_then(|s| CString::new(s).ok())
}

#[cfg(test)]
mod tests {
    use super::{default_pager, which};
    use std::ffi::CString;
    use std::path::PathBuf;

    #[test]
    fn more_found_in_path() {
        assert!(which("more").is_some())
    }

    #[test]
    fn erom_not_found_in_path() {
        assert!(which("erom").is_none())
    }

    #[test]
    fn which_more() {
        assert_eq!(which("more"), Some(PathBuf::from("/usr/bin/more")));
    }

    #[test]
    fn usr_bin_more_default_pager() {
        let usr_bin_more = CString::new("/usr/bin/more").unwrap();
        assert_eq!(default_pager(), Some(usr_bin_more));
    }
}
<|endoftext|>