<commit_before>use std::path::PathBuf;

use git2;
use regex::Regex;

use prelude::*;
use api::{Repo, HeadCommit};

#[derive(Debug)]
pub struct CommitSpec {
    pub repo: String,
    pub path: Option<PathBuf>,
    pub rev: Option<String>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct VcsUrl {
    pub provider: &'static str,
    pub host: String,
    pub path: String,
}

impl CommitSpec {
    pub fn parse(s: &str) -> Result<CommitSpec> {
        lazy_static! {
            static ref SPEC_RE: Regex = Regex::new(
                r"^([^@#]+)(?:#([^@]+))?(?:@(.+))?$").unwrap();
        }
        if let Some(caps) = SPEC_RE.captures(s) {
            Ok(CommitSpec {
                repo: caps[1].to_string(),
                path: caps.get(2).map(|x| PathBuf::from(x.as_str())),
                rev: caps.get(3).map(|x| x.as_str().to_string()),
            })
        } else {
            Err(Error::from(format!("Could not parse commit spec '{}'", s)))
        }
    }
}

fn strip_git_suffix(s: &str) -> &str {
    if s.ends_with(".git") {
        &s[0..s.len() - 4]
    } else {
        s
    }
}

impl VcsUrl {
    pub fn parse(url: &str) -> VcsUrl {
        lazy_static! {
            static ref GITHUB_URL_RE: Regex = Regex::new(
                r"^(?:ssh|https?)://(?:[^@]+@)?github.com/([^/]+)/([^/]+)").unwrap();
            static ref GITHUB_SSH_RE: Regex = Regex::new(
                r"^(?:[^@]+@)?github.com:([^/]+)/([^/]+)").unwrap();
        }
        if let Some(caps) = GITHUB_URL_RE.captures(url) {
            VcsUrl {
                provider: "github",
                host: "github.com".into(),
                path: format!("{}/{}", &caps[1], strip_git_suffix(&caps[2])),
            }
        } else if let Some(caps) = GITHUB_SSH_RE.captures(url) {
            VcsUrl {
                provider: "github",
                host: "github.com".into(),
                path: format!("{}/{}", &caps[1], strip_git_suffix(&caps[2])),
            }
        } else {
            VcsUrl {
                provider: "generic",
                host: "".into(),
                path: url.into(),
            }
        }
    }
}

pub fn is_matching_url(a: &str, b: &str) -> bool {
    VcsUrl::parse(a) == VcsUrl::parse(b)
}

fn find_reference_url(repo: &str, repos: &[Repo]) -> Result<String> {
    for configured_repo in repos {
        if configured_repo.name != repo {
            continue;
        }
        if &configured_repo.provider.id != "github" &&
           &configured_repo.provider.id != "git" {
            return Err(Error::from("For non git repositories \
                                   explicit revisions are required"));
        }

        return Ok(configured_repo.url.clone())
    }

    Err(Error::from(format!("Could not find matching repository for {}", repo)))
}

fn find_matching_head_commit(spec: &CommitSpec, repos: &[Repo], disable_discovery: bool)
    -> Result<Option<String>>
{
    let (repo, discovery) = if let Some(ref path) = spec.path {
        (git2::Repository::open(path)?, false)
    } else {
        (git2::Repository::open_from_env()?, !disable_discovery)
    };

    let reference_url = find_reference_url(&spec.repo, repos)?;

    // direct reference in root repository found.  If we are in discovery
    // mode we want to also check for matching URLs.
    if_chain! {
        if let Ok(remote) = repo.find_remote("origin");
        if let Some(url) = remote.url();
        if !discovery || is_matching_url(url, &reference_url);
        then {
            let head = repo.revparse_single("HEAD")?;
            return Ok(Some(head.id().to_string()));
        }
    }

    // in discovery mode we want to find that repo in associated submodules.
    for submodule in repo.submodules()? {
        if_chain! {
            if let Some(submodule_url) = submodule.url();
            if is_matching_url(submodule_url, &reference_url);
            if let Some(head_oid) = submodule.head_id();
            then {
                return Ok(Some(head_oid.to_string()));
            }
        }
    }

    Ok(None)
}

/// Given commit specs and repos this returns a list of head commits
/// from it.
pub fn find_head_commits(specs: Option<Vec<CommitSpec>>, repos: Vec<Repo>)
    -> Result<Vec<HeadCommit>>
{
    let mut rv = vec![];

    // if commit specs were explicitly provided find head commits with
    // limited amounts of magic.
    if let Some(specs) = specs {
        for spec in &specs {
            let head = if let Some(ref rev) = spec.rev {
                rev.clone()
            } else if let Some(head) = find_matching_head_commit(
                &spec, &repos[..], specs.len() == 1)? {
                head
            } else {
                return Err(Error::from(format!(
                    "Could not find HEAD commit for '{}'", &spec.repo)));
            };
            rv.push(HeadCommit {
                repo: spec.repo.clone(),
                rev: head,
            });
        }

    // otherwise apply all the magic available
    } else {
        for repo in &repos {
            if let Some(head) = find_matching_head_commit(
                &CommitSpec {
                    repo: repo.name.to_string(),
                    path: None,
                    rev: None,
                }, &repos[..], false)? {
                rv.push(HeadCommit {
                    repo: repo.name.to_string(),
                    rev: head,
                });
            }
        }
    }

    Ok(rv)
}

#[test]
fn test_url_parsing() {
    assert_eq!(VcsUrl::parse("http://github.com/mitsuhiko/flask"), VcsUrl {
        provider: "github",
        host: "github.com".into(),
        path: "mitsuhiko/flask".into(),
    });
    assert_eq!(VcsUrl::parse("git@github.com:mitsuhiko/flask.git"), VcsUrl {
        provider: "github",
        host: "github.com".into(),
        path: "mitsuhiko/flask".into(),
    });
}

#[test]
fn test_url_normalization() {
    assert!(is_matching_url("http://github.com/mitsuhiko/flask",
                            "git@github.com:mitsuhiko/flask.git"));
}
<commit_msg>Killed host on vcsurls for now<commit_after>use std::path::PathBuf;

use git2;
use regex::Regex;

use prelude::*;
use api::{Repo, HeadCommit};

#[derive(Debug)]
pub struct CommitSpec {
    pub repo: String,
    pub path: Option<PathBuf>,
    pub rev: Option<String>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct VcsUrl {
    pub provider: &'static str,
    pub id: String,
}

impl CommitSpec {
    pub fn parse(s: &str) -> Result<CommitSpec> {
        lazy_static! {
            static ref SPEC_RE: Regex = Regex::new(
                r"^([^@#]+)(?:#([^@]+))?(?:@(.+))?$").unwrap();
        }
        if let Some(caps) = SPEC_RE.captures(s) {
            Ok(CommitSpec {
                repo: caps[1].to_string(),
                path: caps.get(2).map(|x| PathBuf::from(x.as_str())),
                rev: caps.get(3).map(|x| x.as_str().to_string()),
            })
        } else {
            Err(Error::from(format!("Could not parse commit spec '{}'", s)))
        }
    }
}

fn strip_git_suffix(s: &str) -> &str {
    if s.ends_with(".git") {
        &s[0..s.len() - 4]
    } else {
        s
    }
}

impl VcsUrl {
    pub fn parse(url: &str) -> VcsUrl {
        lazy_static! {
            static ref GITHUB_URL_RE: Regex = Regex::new(
                r"^(?:ssh|https?)://(?:[^@]+@)?github.com/([^/]+)/([^/]+)").unwrap();
            static ref GITHUB_SSH_RE: Regex = Regex::new(
                r"^(?:[^@]+@)?github.com:([^/]+)/([^/]+)").unwrap();
        }
        if let Some(caps) = GITHUB_URL_RE.captures(url) {
            VcsUrl {
                provider: "github",
                id: format!("{}/{}", &caps[1], strip_git_suffix(&caps[2])),
            }
        } else if let Some(caps) = GITHUB_SSH_RE.captures(url) {
            VcsUrl {
                provider: "github",
                id: format!("{}/{}", &caps[1], strip_git_suffix(&caps[2])),
            }
        } else {
            VcsUrl {
                provider: "generic",
                id: url.into(),
            }
        }
    }
}

fn is_matching_url(a: &str, b: &str) -> bool {
    VcsUrl::parse(a) == VcsUrl::parse(b)
}

fn find_reference_url(repo: &str, repos: &[Repo]) -> Result<String> {
    for configured_repo in repos {
        if configured_repo.name != repo {
            continue;
        }
        if &configured_repo.provider.id != "github" &&
           &configured_repo.provider.id != "git" {
            return Err(Error::from("For non git repositories \
                                   explicit revisions are required"));
        }

        return Ok(configured_repo.url.clone())
    }

    Err(Error::from(format!("Could not find matching repository for {}", repo)))
}

fn find_matching_head_commit(spec: &CommitSpec, repos: &[Repo], disable_discovery: bool)
    -> Result<Option<String>>
{
    let (repo, discovery) = if let Some(ref path) = spec.path {
        (git2::Repository::open(path)?, false)
    } else {
        (git2::Repository::open_from_env()?, !disable_discovery)
    };

    let reference_url = find_reference_url(&spec.repo, repos)?;

    // direct reference in root repository found.  If we are in discovery
    // mode we want to also check for matching URLs.
    if_chain! {
        if let Ok(remote) = repo.find_remote("origin");
        if let Some(url) = remote.url();
        if !discovery || is_matching_url(url, &reference_url);
        then {
            let head = repo.revparse_single("HEAD")?;
            return Ok(Some(head.id().to_string()));
        }
    }

    // in discovery mode we want to find that repo in associated submodules.
    for submodule in repo.submodules()? {
        if_chain! {
            if let Some(submodule_url) = submodule.url();
            if is_matching_url(submodule_url, &reference_url);
            if let Some(head_oid) = submodule.head_id();
            then {
                return Ok(Some(head_oid.to_string()));
            }
        }
    }

    Ok(None)
}

/// Given commit specs and repos this returns a list of head commits
/// from it.
pub fn find_head_commits(specs: Option<Vec<CommitSpec>>, repos: Vec<Repo>)
    -> Result<Vec<HeadCommit>>
{
    let mut rv = vec![];

    // if commit specs were explicitly provided find head commits with
    // limited amounts of magic.
    if let Some(specs) = specs {
        for spec in &specs {
            let head = if let Some(ref rev) = spec.rev {
                rev.clone()
            } else if let Some(head) = find_matching_head_commit(
                &spec, &repos[..], specs.len() == 1)? {
                head
            } else {
                return Err(Error::from(format!(
                    "Could not find HEAD commit for '{}'", &spec.repo)));
            };
            rv.push(HeadCommit {
                repo: spec.repo.clone(),
                rev: head,
            });
        }

    // otherwise apply all the magic available
    } else {
        for repo in &repos {
            if let Some(head) = find_matching_head_commit(
                &CommitSpec {
                    repo: repo.name.to_string(),
                    path: None,
                    rev: None,
                }, &repos[..], false)? {
                rv.push(HeadCommit {
                    repo: repo.name.to_string(),
                    rev: head,
                });
            }
        }
    }

    Ok(rv)
}

#[test]
fn test_url_parsing() {
    assert_eq!(VcsUrl::parse("http://github.com/mitsuhiko/flask"), VcsUrl {
        provider: "github",
        path: "mitsuhiko/flask".into(),
    });
    assert_eq!(VcsUrl::parse("git@github.com:mitsuhiko/flask.git"), VcsUrl {
        provider: "github",
        path: "mitsuhiko/flask".into(),
    });
}

#[test]
fn test_url_normalization() {
    assert!(is_matching_url("http://github.com/mitsuhiko/flask",
                            "git@github.com:mitsuhiko/flask.git"));
}
<|endoftext|>


<commit_before>#![warn(trivial_casts, trivial_numeric_casts)]
#![warn(unused_results)]

extern crate ansi_term;
extern crate datetime;
extern crate glob;
extern crate libc;
extern crate locale;
extern crate natord;
extern crate num_cpus;
extern crate number_prefix;
extern crate scoped_threadpool;
extern crate term_grid;
extern crate unicode_width;
extern crate users;
extern crate zoneinfo_compiled;
extern crate term_size;

#[cfg(feature="git")] extern crate git2;

#[macro_use] extern crate lazy_static;
#[macro_use] extern crate log;

use std::env::var_os;
use std::ffi::{OsStr, OsString};
use std::io::{stderr, Write, Result as IOResult};
use std::path::{Component, PathBuf};

use ansi_term::{ANSIStrings, Style};

use fs::{Dir, File};
use fs::feature::ignore::IgnoreCache;
use fs::feature::git::GitCache;
use options::{Options, Vars};
pub use options::Misfire;
use output::{escape, lines, grid, grid_details, details, View, Mode};

mod fs;
mod info;
mod options;
mod output;
mod style;

/// The main program wrapper.
pub struct Exa<'args, 'w, W: Write + 'w> {

    /// List of command-line options, having been successfully parsed.
    pub options: Options,

    /// The output handle that we write to. When running the program normally,
    /// this will be `std::io::Stdout`, but it can accept any struct that’s
    /// `Write` so we can write into, say, a vector for testing.
    pub writer: &'w mut W,

    /// List of the free command-line arguments that should correspond to file
    /// names (anything that isn’t an option).
    pub args: Vec<&'args OsStr>,

    /// A global Git cache, if the option was passed in.
    /// This has to last the lifetime of the program, because the user might
    /// want to list several directories in the same repository.
    pub git: Option<GitCache>,

    /// A cache of git-ignored files.
    /// This lasts the lifetime of the program too, for the same reason.
    pub ignore: Option<IgnoreCache>,
}

/// The “real” environment variables type.
/// Instead of just calling `var_os` from within the options module,
/// the method of looking up environment variables has to be passed in.
struct LiveVars;
impl Vars for LiveVars {
    fn get(&self, name: &'static str) -> Option<OsString> {
        var_os(name)
    }
}

/// Create a Git cache populated with the arguments that are going to be
/// listed before they’re actually listed, if the options demand it.
fn git_options(options: &Options, args: &[&OsStr]) -> Option<GitCache> {
    if options.should_scan_for_git() {
        Some(args.iter().map(|os| PathBuf::from(os)).collect())
    }
    else {
        None
    }
}

fn ignore_cache(options: &Options) -> Option<IgnoreCache> {
    use fs::filter::GitIgnore;

    match options.filter.git_ignore {
        GitIgnore::CheckAndIgnore => Some(IgnoreCache::new()),
        GitIgnore::Off            => None,
    }
}

impl<'args, 'w, W: Write + 'w> Exa<'args, 'w, W> {
    pub fn new<I>(args: I, writer: &'w mut W) -> Result<Exa<'args, 'w, W>, Misfire>
    where I: Iterator<Item=&'args OsString> {
        Options::parse(args, &LiveVars).map(move |(options, mut args)| {
            debug!("Dir action from arguments: {:#?}", options.dir_action);
            debug!("Filter from arguments: {:#?}", options.filter);
            debug!("View from arguments: {:#?}", options.view.mode);

            // List the current directory by default, like ls.
            // This has to be done here, otherwise git_options won’t see it.
            if args.is_empty() {
                args = vec![ OsStr::new(".") ];
            }

            let git = git_options(&options, &args);
            let ignore = ignore_cache(&options);
            Exa { options, writer, args, git, ignore }
        })
    }

    pub fn run(&mut self) -> IOResult<i32> {
        let mut files = Vec::new();
        let mut dirs = Vec::new();
        let mut exit_status = 0;

        for file_path in &self.args {
            match File::new(PathBuf::from(file_path), None, None) {
                Err(e) => {
                    exit_status = 2;
                    writeln!(stderr(), "{:?}: {}", file_path, e)?;
                },
                Ok(f) => {
                    if f.is_directory() && !self.options.dir_action.treat_dirs_as_files() {
                        match f.to_dir() {
                            Ok(d) => dirs.push(d),
                            Err(e) => writeln!(stderr(), "{:?}: {}", file_path, e)?,
                        }
                    }
                    else {
                        files.push(f);
                    }
                },
            }
        }

        // We want to print a directory’s name before we list it, *except* in
        // the case where it’s the only directory, *except* if there are any
        // files to print as well. (It’s a double negative)

        let no_files = files.is_empty();
        let is_only_dir = dirs.len() == 1 && no_files;

        self.options.filter.filter_argument_files(&mut files);
        self.print_files(None, files)?;

        self.print_dirs(dirs, no_files, is_only_dir, exit_status)
    }

    fn print_dirs(&mut self, dir_files: Vec<Dir>, mut first: bool, is_only_dir: bool, exit_status: i32) -> IOResult<i32> {
        for dir in dir_files {

            // Put a gap between directories, or between the list of files and
            // the first directory.
            if first {
                first = false;
            }
            else {
                write!(self.writer, "\n")?;
            }

            if !is_only_dir {
                let mut bits = Vec::new();
                escape(dir.path.display().to_string(), &mut bits, Style::default(), Style::default());
                writeln!(self.writer, "{}:", ANSIStrings(&bits))?;
            }

            let mut children = Vec::new();
            for file in dir.files(self.options.filter.dot_filter, self.ignore.as_ref()) {
                match file {
                    Ok(file)       => children.push(file),
                    Err((path, e)) => writeln!(stderr(), "[{}: {}]", path.display(), e)?,
                }
            };

            self.options.filter.filter_child_files(&mut children);
            self.options.filter.sort_files(&mut children);

            if let Some(recurse_opts) = self.options.dir_action.recurse_options() {
                let depth = dir.path.components().filter(|&c| c != Component::CurDir).count() + 1;
                if !recurse_opts.tree && !recurse_opts.is_too_deep(depth) {

                    let mut child_dirs = Vec::new();
                    for child_dir in children.iter().filter(|f| f.is_directory()) {
                        match child_dir.to_dir() {
                            Ok(d)  => child_dirs.push(d),
                            Err(e) => writeln!(stderr(), "{}: {}", child_dir.path.display(), e)?,
                        }
                    }

                    self.print_files(Some(&dir), children)?;
                    match self.print_dirs(child_dirs, false, false, exit_status) {
                        Ok(_) => (),
                        Err(e) => return Err(e),
                    }
                    continue;
                }
            }

            self.print_files(Some(&dir), children)?;
        }

        Ok(exit_status)
    }

    /// Prints the list of files using whichever view is selected.
    /// For various annoying logistical reasons, each one handles
    /// printing differently...
    fn print_files(&mut self, dir: Option<&Dir>, files: Vec<File>) -> IOResult<()> {
        if !files.is_empty() {
            let View { ref mode, ref colours, ref style } = self.options.view;

            match *mode {
                Mode::Lines => {
                    lines::Render { files, colours, style }.render(self.writer)
                }
                Mode::Grid(ref opts) => {
                    grid::Render { files, colours, style, opts }.render(self.writer)
                }
                Mode::Details(ref opts) => {
                    details::Render { dir, files, colours, style, opts, filter: &self.options.filter, recurse: self.options.dir_action.recurse_options() }.render(self.git.as_ref(), self.ignore.as_ref(), self.writer)
                }
                Mode::GridDetails(ref opts) => {
                    grid_details::Render { dir, files, colours, style, grid: &opts.grid, details: &opts.details, filter: &self.options.filter, row_threshold: opts.row_threshold }.render(self.git.as_ref(), self.writer)
                }
            }
        }
        else {
            Ok(())
        }
    }
}
<commit_msg>Make these lines less long<commit_after>#![warn(trivial_casts, trivial_numeric_casts)]
#![warn(unused_results)]

extern crate ansi_term;
extern crate datetime;
extern crate glob;
extern crate libc;
extern crate locale;
extern crate natord;
extern crate num_cpus;
extern crate number_prefix;
extern crate scoped_threadpool;
extern crate term_grid;
extern crate unicode_width;
extern crate users;
extern crate zoneinfo_compiled;
extern crate term_size;

#[cfg(feature="git")] extern crate git2;

#[macro_use] extern crate lazy_static;
#[macro_use] extern crate log;

use std::env::var_os;
use std::ffi::{OsStr, OsString};
use std::io::{stderr, Write, Result as IOResult};
use std::path::{Component, PathBuf};

use ansi_term::{ANSIStrings, Style};

use fs::{Dir, File};
use fs::feature::ignore::IgnoreCache;
use fs::feature::git::GitCache;
use options::{Options, Vars};
pub use options::Misfire;
use output::{escape, lines, grid, grid_details, details, View, Mode};

mod fs;
mod info;
mod options;
mod output;
mod style;

/// The main program wrapper.
pub struct Exa<'args, 'w, W: Write + 'w> {

    /// List of command-line options, having been successfully parsed.
    pub options: Options,

    /// The output handle that we write to. When running the program normally,
    /// this will be `std::io::Stdout`, but it can accept any struct that’s
    /// `Write` so we can write into, say, a vector for testing.
    pub writer: &'w mut W,

    /// List of the free command-line arguments that should correspond to file
    /// names (anything that isn’t an option).
    pub args: Vec<&'args OsStr>,

    /// A global Git cache, if the option was passed in.
    /// This has to last the lifetime of the program, because the user might
    /// want to list several directories in the same repository.
    pub git: Option<GitCache>,

    /// A cache of git-ignored files.
    /// This lasts the lifetime of the program too, for the same reason.
    pub ignore: Option<IgnoreCache>,
}

/// The “real” environment variables type.
/// Instead of just calling `var_os` from within the options module,
/// the method of looking up environment variables has to be passed in.
struct LiveVars;
impl Vars for LiveVars {
    fn get(&self, name: &'static str) -> Option<OsString> {
        var_os(name)
    }
}

/// Create a Git cache populated with the arguments that are going to be
/// listed before they’re actually listed, if the options demand it.
fn git_options(options: &Options, args: &[&OsStr]) -> Option<GitCache> {
    if options.should_scan_for_git() {
        Some(args.iter().map(|os| PathBuf::from(os)).collect())
    }
    else {
        None
    }
}

fn ignore_cache(options: &Options) -> Option<IgnoreCache> {
    use fs::filter::GitIgnore;

    match options.filter.git_ignore {
        GitIgnore::CheckAndIgnore => Some(IgnoreCache::new()),
        GitIgnore::Off            => None,
    }
}

impl<'args, 'w, W: Write + 'w> Exa<'args, 'w, W> {
    pub fn new<I>(args: I, writer: &'w mut W) -> Result<Exa<'args, 'w, W>, Misfire>
    where I: Iterator<Item=&'args OsString> {
        Options::parse(args, &LiveVars).map(move |(options, mut args)| {
            debug!("Dir action from arguments: {:#?}", options.dir_action);
            debug!("Filter from arguments: {:#?}", options.filter);
            debug!("View from arguments: {:#?}", options.view.mode);

            // List the current directory by default, like ls.
            // This has to be done here, otherwise git_options won’t see it.
            if args.is_empty() {
                args = vec![ OsStr::new(".") ];
            }

            let git = git_options(&options, &args);
            let ignore = ignore_cache(&options);
            Exa { options, writer, args, git, ignore }
        })
    }

    pub fn run(&mut self) -> IOResult<i32> {
        let mut files = Vec::new();
        let mut dirs = Vec::new();
        let mut exit_status = 0;

        for file_path in &self.args {
            match File::new(PathBuf::from(file_path), None, None) {
                Err(e) => {
                    exit_status = 2;
                    writeln!(stderr(), "{:?}: {}", file_path, e)?;
                },
                Ok(f) => {
                    if f.is_directory() && !self.options.dir_action.treat_dirs_as_files() {
                        match f.to_dir() {
                            Ok(d) => dirs.push(d),
                            Err(e) => writeln!(stderr(), "{:?}: {}", file_path, e)?,
                        }
                    }
                    else {
                        files.push(f);
                    }
                },
            }
        }

        // We want to print a directory’s name before we list it, *except* in
        // the case where it’s the only directory, *except* if there are any
        // files to print as well. (It’s a double negative)

        let no_files = files.is_empty();
        let is_only_dir = dirs.len() == 1 && no_files;

        self.options.filter.filter_argument_files(&mut files);
        self.print_files(None, files)?;

        self.print_dirs(dirs, no_files, is_only_dir, exit_status)
    }

    fn print_dirs(&mut self, dir_files: Vec<Dir>, mut first: bool, is_only_dir: bool, exit_status: i32) -> IOResult<i32> {
        for dir in dir_files {

            // Put a gap between directories, or between the list of files and
            // the first directory.
            if first {
                first = false;
            }
            else {
                write!(self.writer, "\n")?;
            }

            if !is_only_dir {
                let mut bits = Vec::new();
                escape(dir.path.display().to_string(), &mut bits, Style::default(), Style::default());
                writeln!(self.writer, "{}:", ANSIStrings(&bits))?;
            }

            let mut children = Vec::new();
            for file in dir.files(self.options.filter.dot_filter, self.ignore.as_ref()) {
                match file {
                    Ok(file)       => children.push(file),
                    Err((path, e)) => writeln!(stderr(), "[{}: {}]", path.display(), e)?,
                }
            };

            self.options.filter.filter_child_files(&mut children);
            self.options.filter.sort_files(&mut children);

            if let Some(recurse_opts) = self.options.dir_action.recurse_options() {
                let depth = dir.path.components().filter(|&c| c != Component::CurDir).count() + 1;
                if !recurse_opts.tree && !recurse_opts.is_too_deep(depth) {

                    let mut child_dirs = Vec::new();
                    for child_dir in children.iter().filter(|f| f.is_directory()) {
                        match child_dir.to_dir() {
                            Ok(d)  => child_dirs.push(d),
                            Err(e) => writeln!(stderr(), "{}: {}", child_dir.path.display(), e)?,
                        }
                    }

                    self.print_files(Some(&dir), children)?;
                    match self.print_dirs(child_dirs, false, false, exit_status) {
                        Ok(_) => (),
                        Err(e) => return Err(e),
                    }
                    continue;
                }
            }

            self.print_files(Some(&dir), children)?;
        }

        Ok(exit_status)
    }

    /// Prints the list of files using whichever view is selected.
    /// For various annoying logistical reasons, each one handles
    /// printing differently...
    fn print_files(&mut self, dir: Option<&Dir>, files: Vec<File>) -> IOResult<()> {
        if !files.is_empty() {
            let View { ref mode, ref colours, ref style } = self.options.view;

            match *mode {
                Mode::Lines => {
                    lines::Render { files, colours, style }.render(self.writer)
                }
                Mode::Grid(ref opts) => {
                    grid::Render { files, colours, style, opts }.render(self.writer)
                }
                Mode::Details(ref opts) => {
                    let filter = &self.options.filter;
                    let recurse = self.options.dir_action.recurse_options();
                    details::Render { dir, files, colours, style, opts, filter, recurse }.render(self.git.as_ref(), self.ignore.as_ref(), self.writer)
                }
                Mode::GridDetails(ref opts) => {
                    let grid = &opts.grid;
                    let details = &opts.details;
                    let filter = &self.options.filter;
                    let row_threshold = opts.row_threshold;
                    grid_details::Render { dir, files, colours, style, grid, details, filter, row_threshold }.render(self.git.as_ref(), self.writer)
                }
            }
        }
        else {
            Ok(())
        }
    }
}
<|endoftext|>


<commit_before>// #![allow(dead_code)]

use std::os::raw::{c_int,c_void,c_char};

// type without an instance
pub enum DNSServiceT{}
pub type DNSServiceRef = *mut DNSServiceT;

// type without an instance
pub enum DNSRecordT{}
pub type DNSRecordRef = *mut DNSRecordT;

pub type DNSServiceFlags = u32;
// pub const FLAGS_NONE                 : DNSServiceFlags = 0x0;
pub const FLAGS_MORE_COMING          : DNSServiceFlags = 0x1;
pub const FLAGS_ADD                  : DNSServiceFlags = 0x2;
pub const FLAGS_DEFAULT              : DNSServiceFlags = 0x4;
pub const FLAGS_NO_AUTO_RENAME       : DNSServiceFlags = 0x8;
pub const FLAGS_SHARED               : DNSServiceFlags = 0x10;
pub const FLAGS_UNIQUE               : DNSServiceFlags = 0x20;
pub const FLAGS_BROWSE_DOMAINS       : DNSServiceFlags = 0x40;
pub const FLAGS_REGISTRATION_DOMAINS : DNSServiceFlags = 0x80;
// unix only?
#[cfg(unix)]
pub const FLAGS_LONG_LIVED_QUERY     : DNSServiceFlags = 0x100;
// avahi only?
//pub const FLAGS_ALLOW_REMOTE_QUERY   : DNSServiceFlags = 0x200;
//pub const FLAGS_FORCE_MULTICAS       : DNSServiceFlags = 0x400;
//pub const FLAGS_RETURN_CNAME         : DNSServiceFlags = 0x800;

/// Maximum length of full name including trailing dot and terminating NULL
///
/// See [`kDNSServiceMaxDomainName`](https://developer.apple.com/documentation/dnssd/kdnsservicemaxdomainname)
pub const MAX_DOMAIN_NAME : usize = 1009;

pub const INTERFACE_INDEX_ANY : u32 = 0;
pub const INTERFACE_INDEX_LOCAL_ONLY : u32 = !0;
pub const INTERFACE_INDEX_UNICAST : u32 = !1;
pub const INTERFACE_INDEX_P2P : u32 = !2;

macro_rules! c_api_enum {
	($name:ident : $ty:tt => $($case:ident = $val:expr,)* ) => (
		#[derive(Clone,Copy,Eq,PartialEq,Ord,PartialOrd,Hash,Debug)]
		#[repr($ty)]
		pub enum $name {
			$($case = $val,)*
		}
		impl $name {
			pub fn try_from(value: $ty) -> Option<$name> {
				$(if value == $val {
					Some($name::$case)
				} else)* {
					None
				}
			}
		}
	)
}

pub type DNSServiceErrorType = i32;
c_api_enum!{DNSServiceNoError: i32 =>
	NoError               = 0,
	// windows "TCP Connection Status"
	ConnectionPending     = -65570,
	ConnectionFailed      = -65571,
	ConnectionEstablished = -65572,
	// windows "Non-error values"
	GrowCache             = -65790,
	ConfigChanged         = -65791,
	MemFree               = -65792,
}
/// Known error codes
///
/// See [`DNSServiceErrorType`](https://developer.apple.com/documentation/dnssd/1823426-anonymous)
#[allow(missing_docs)]
c_api_enum!{DNSServiceError: i32 =>
	Unknown               = -65537,
	NoSuchName            = -65538,
	NoMemory              = -65539,
	BadParam              = -65540,
	BadReference          = -65541,
	BadState              = -65542,
	BadFlags              = -65543,
	Unsupported           = -65544,
	NotInitialized        = -65545,
	NoCache               = -65546,
	AlreadyRegistered     = -65547,
	NameConflict          = -65548,
	Invalid               = -65549,
	Incompatible          = -65551,
	BadInterfaceIndex     = -65552,
	Refused               = -65553,
	NoSuchRecord          = -65554,
	NoAuth                = -65555,
	NoSuchKey             = -65556,
	NoValue               = -65557,
	BufferTooSmall        = -65558,
}

pub type DNSServiceDomainEnumReply = Option<extern "C" fn(
	sd_ref: DNSServiceRef,
	flags: DNSServiceFlags,
	interface_index: u32,
	error_code: DNSServiceErrorType,
	reply_domain: *const c_char,
	context: *mut c_void
)>;
pub type DNSServiceRegisterReply = Option<extern "C" fn(
	sd_ref: DNSServiceRef,
	flags: DNSServiceFlags,
	error_code: DNSServiceErrorType,
	name: *const c_char,
	reg_type: *const c_char,
	domain: *const c_char,
	context: *mut c_void
)>;
pub type DNSServiceBrowseReply = Option<extern "C" fn(
	sd_ref: DNSServiceRef,
	flags: DNSServiceFlags,
	interface_index: u32,
	error_code: DNSServiceErrorType,
	service_name: *const c_char,
	reg_type: *const c_char,
	reply_domain: *const c_char,
	context: *mut c_void
)>;
pub type DNSServiceResolveReply = Option<extern "C" fn(
	sd_ref: DNSServiceRef,
	flags: DNSServiceFlags,
	interface_index: u32,
	error_code: DNSServiceErrorType,
	fullname: *const c_char,
	host_target: *const c_char,
	port: u16,
	txt_len: u16,
	txt_record: *const u8,
	context: *mut c_void
)>;
pub type DNSServiceRegisterRecordReply = Option<extern "C" fn(
	sd_ref: DNSServiceRef,
	record_ref: DNSRecordRef,
	flags: DNSServiceFlags,
	error_code: DNSServiceErrorType,
	context: *mut c_void
)>;
pub type DNSServiceQueryRecordReply = Option<extern "C" fn(
	sd_ref: DNSServiceRef,
	flags: DNSServiceFlags,
	interface_index: u32,
	error_code: DNSServiceErrorType,
	fullname: *const c_char,
	rr_type: u16,
	rr_class: u16,
	rd_len: u16,
	rdata: *const u8,
	ttl: u32,
	context: *mut c_void
)>;

extern "C" {
	pub fn DNSServiceRefSockFD(sd_ref: DNSServiceRef) -> c_int;
	pub fn DNSServiceProcessResult(sd_ref: DNSServiceRef) -> DNSServiceErrorType;
	pub fn DNSServiceRefDeallocate(sd_ref: DNSServiceRef);
	pub fn DNSServiceEnumerateDomains(
		sd_ref: *mut DNSServiceRef,
		flags: DNSServiceFlags,
		interface_index: u32,
		callback: DNSServiceDomainEnumReply,
		context: *mut c_void
	) -> DNSServiceErrorType;
	pub fn DNSServiceRegister(
		sd_ref: *mut DNSServiceRef,
		flags: DNSServiceFlags,
		interface_index: u32,
		name: *const c_char,
		reg_type: *const c_char,
		domain: *const c_char,
		host: *const c_char,
		port: u16,
		txt_len: u16,
		txt_record: *const u8,
		callback: DNSServiceRegisterReply,
		context: *mut c_void
	) -> DNSServiceErrorType;
	pub fn DNSServiceAddRecord(
		sd_ref: DNSServiceRef,
		record_ref: *mut DNSRecordRef,
		flags: DNSServiceFlags,
		rr_type: u16,
		rd_len: u16,
		rdata: *const u8,
		ttl: u32
	) -> DNSServiceErrorType;
	pub fn DNSServiceUpdateRecord(
		sd_ref: DNSServiceRef,
		record_ref: DNSRecordRef,
		flags: DNSServiceFlags,
		rd_len: u16,
		rdata: *const u8,
		ttl: u32
	) -> DNSServiceErrorType;
	pub fn DNSServiceRemoveRecord(
		sd_ref: DNSServiceRef,
		record_ref: DNSRecordRef,
		flags: DNSServiceFlags
	) -> DNSServiceErrorType;
	pub fn DNSServiceBrowse(
		sd_ref: *mut DNSServiceRef,
		flags: DNSServiceFlags,
		interface_index: u32,
		reg_type: *const c_char,
		domain: *const c_char,
		callback: DNSServiceBrowseReply,
		context: *mut c_void
	) -> DNSServiceErrorType;
	pub fn DNSServiceResolve(
		sd_ref: *mut DNSServiceRef,
		flags: DNSServiceFlags,
		interface_index: u32,
		name: *const c_char,
		reg_type: *const c_char,
		domain: *const c_char,
		callback: DNSServiceResolveReply,
		context: *mut c_void
	) -> DNSServiceErrorType;
	pub fn DNSServiceCreateConnection(sd_ref: *mut DNSServiceRef) -> DNSServiceErrorType;
	pub fn DNSServiceRegisterRecord(
		sd_ref: DNSServiceRef,
		record_ref: *mut DNSRecordRef,
		flags: DNSServiceFlags,
		interface_index: u32,
		fullname: *const c_char,
		rr_type: u16,
		rr_class: u16,
		rd_len: u16,
		rdata: *const u8,
		ttl: u32,
		callback: DNSServiceRegisterRecordReply,
		context: *mut c_void
	) -> DNSServiceErrorType;
	pub fn DNSServiceQueryRecord(
		sd_ref: *mut DNSServiceRef,
		flags: DNSServiceFlags,
		interface_index: u32,
		fullname: *const c_char,
		rr_type: u16,
		rr_class: u16,
		callback: DNSServiceQueryRecordReply,
		context: *mut c_void
	) -> DNSServiceErrorType;
	pub fn DNSServiceReconfirmRecord(
		flags: DNSServiceFlags,
		interface_index: u32,
		fullname: *const c_char,
		rr_type: u16,
		rr_class: u16,
		rd_len: u16,
		rdata: *const u8
	) -> DNSServiceErrorType;
	pub fn DNSServiceConstructFullName(
		fullName: *mut c_char,
		service: *const c_char,
		reg_type: *const c_char,
		domain: *const c_char
	) -> c_int;
}

// TXTRecordRef utils not wrapped - should be easy enough to implement
// in pure rust

#[cfg(windows)]
mod ffi_windows {
	use std::os::raw::{c_int,c_void};
	use super::DNSServiceErrorType;

	pub type DNSServiceInitializeFlags = u32;
	pub const INITIALIZE_FLAGS_NONE            : DNSServiceInitializeFlags = 0x0;
	pub const INITIALIZE_FLAGS_ADVERTISE       : DNSServiceInitializeFlags = 0x1;
	pub const INITIALIZE_FLAGS_NO_SERVER_CHECK : DNSServiceInitializeFlags = 0x2;

	pub type DNSPropertyCode = u32;

	pub const PROPERTY_CODE_VERSION : DNSPropertyCode = 0x76657273;
	#[repr(C)]
	pub struct DnsPropertyVersion {
		pub code: DNSPropertyCode,

		pub client_current_version: u32,
		pub client_oldest_server_version: u32,
		pub server_current_version: u32,
		pub server_oldest_client_version: u32,
	}

	extern "C" {
		pub fn DNSServiceInitialize(
			inFlags: DNSServiceInitializeFlags,
			inCacheEntryCount: c_int
		) -> DNSServiceErrorType;
		pub fn DNSServiceFinalize();
		pub fn DNSServiceCheckVersion() -> DNSServiceErrorType;

		// TODO? DNSPropertyData on windows.
		// the c API uses a union... - using void instead here
		pub fn DNSServiceCopyProperty(
			inCode: DNSPropertyCode,
			outData: *mut c_void) -> DNSServiceErrorType;
		pub fn DNSServiceReleaseProperty(inData: *mut c_void) -> DNSServiceErrorType;
	}
}
#[cfg(windows)]
use self::ffi_windows::*;
<commit_msg>long lived query flags not supported on windows, make it compile anyway<commit_after>// #![allow(dead_code)]

use std::os::raw::{c_int,c_void,c_char};

// type without an instance
pub enum DNSServiceT{}
pub type DNSServiceRef = *mut DNSServiceT;

// type without an instance
pub enum DNSRecordT{}
pub type DNSRecordRef = *mut DNSRecordT;

pub type DNSServiceFlags = u32;
// pub const FLAGS_NONE                 : DNSServiceFlags = 0x0;
pub const FLAGS_MORE_COMING          : DNSServiceFlags = 0x1;
pub const FLAGS_ADD                  : DNSServiceFlags = 0x2;
pub const FLAGS_DEFAULT              : DNSServiceFlags = 0x4;
pub const FLAGS_NO_AUTO_RENAME       : DNSServiceFlags = 0x8;
pub const FLAGS_SHARED               : DNSServiceFlags = 0x10;
pub const FLAGS_UNIQUE               : DNSServiceFlags = 0x20;
pub const FLAGS_BROWSE_DOMAINS       : DNSServiceFlags = 0x40;
pub const FLAGS_REGISTRATION_DOMAINS : DNSServiceFlags = 0x80;
// unix only?
#[cfg(unix)]
pub const FLAGS_LONG_LIVED_QUERY     : DNSServiceFlags = 0x100;
#[cfg(not(unix))]
pub const FLAGS_LONG_LIVED_QUERY     : DNSServiceFlags = 0;
// avahi only?
//pub const FLAGS_ALLOW_REMOTE_QUERY   : DNSServiceFlags = 0x200;
//pub const FLAGS_FORCE_MULTICAS       : DNSServiceFlags = 0x400;
//pub const FLAGS_RETURN_CNAME         : DNSServiceFlags = 0x800;

/// Maximum length of full name including trailing dot and terminating NULL
///
/// See [`kDNSServiceMaxDomainName`](https://developer.apple.com/documentation/dnssd/kdnsservicemaxdomainname)
pub const MAX_DOMAIN_NAME : usize = 1009;

pub const INTERFACE_INDEX_ANY : u32 = 0;
pub const INTERFACE_INDEX_LOCAL_ONLY : u32 = !0;
pub const INTERFACE_INDEX_UNICAST : u32 = !1;
pub const INTERFACE_INDEX_P2P : u32 = !2;

macro_rules! c_api_enum {
	($name:ident : $ty:tt => $($case:ident = $val:expr,)* ) => (
		#[derive(Clone,Copy,Eq,PartialEq,Ord,PartialOrd,Hash,Debug)]
		#[repr($ty)]
		pub enum $name {
			$($case = $val,)*
		}
		impl $name {
			pub fn try_from(value: $ty) -> Option<$name> {
				$(if value == $val {
					Some($name::$case)
				} else)* {
					None
				}
			}
		}
	)
}

pub type DNSServiceErrorType = i32;
c_api_enum!{DNSServiceNoError: i32 =>
	NoError               = 0,
	// windows "TCP Connection Status"
	ConnectionPending     = -65570,
	ConnectionFailed      = -65571,
	ConnectionEstablished = -65572,
	// windows "Non-error values"
	GrowCache             = -65790,
	ConfigChanged         = -65791,
	MemFree               = -65792,
}
/// Known error codes
///
/// See [`DNSServiceErrorType`](https://developer.apple.com/documentation/dnssd/1823426-anonymous)
#[allow(missing_docs)]
c_api_enum!{DNSServiceError: i32 =>
	Unknown               = -65537,
	NoSuchName            = -65538,
	NoMemory              = -65539,
	BadParam              = -65540,
	BadReference          = -65541,
	BadState              = -65542,
	BadFlags              = -65543,
	Unsupported           = -65544,
	NotInitialized        = -65545,
	NoCache               = -65546,
	AlreadyRegistered     = -65547,
	NameConflict          = -65548,
	Invalid               = -65549,
	Incompatible          = -65551,
	BadInterfaceIndex     = -65552,
	Refused               = -65553,
	NoSuchRecord          = -65554,
	NoAuth                = -65555,
	NoSuchKey             = -65556,
	NoValue               = -65557,
	BufferTooSmall        = -65558,
}

pub type DNSServiceDomainEnumReply = Option<extern "C" fn(
	sd_ref: DNSServiceRef,
	flags: DNSServiceFlags,
	interface_index: u32,
	error_code: DNSServiceErrorType,
	reply_domain: *const c_char,
	context: *mut c_void
)>;
pub type DNSServiceRegisterReply = Option<extern "C" fn(
	sd_ref: DNSServiceRef,
	flags: DNSServiceFlags,
	error_code: DNSServiceErrorType,
	name: *const c_char,
	reg_type: *const c_char,
	domain: *const c_char,
	context: *mut c_void
)>;
pub type DNSServiceBrowseReply = Option<extern "C" fn(
	sd_ref: DNSServiceRef,
	flags: DNSServiceFlags,
	interface_index: u32,
	error_code: DNSServiceErrorType,
	service_name: *const c_char,
	reg_type: *const c_char,
	reply_domain: *const c_char,
	context: *mut c_void
)>;
pub type DNSServiceResolveReply = Option<extern "C" fn(
	sd_ref: DNSServiceRef,
	flags: DNSServiceFlags,
	interface_index: u32,
	error_code: DNSServiceErrorType,
	fullname: *const c_char,
	host_target: *const c_char,
	port: u16,
	txt_len: u16,
	txt_record: *const u8,
	context: *mut c_void
)>;
pub type DNSServiceRegisterRecordReply = Option<extern "C" fn(
	sd_ref: DNSServiceRef,
	record_ref: DNSRecordRef,
	flags: DNSServiceFlags,
	error_code: DNSServiceErrorType,
	context: *mut c_void
)>;
pub type DNSServiceQueryRecordReply = Option<extern "C" fn(
	sd_ref: DNSServiceRef,
	flags: DNSServiceFlags,
	interface_index: u32,
	error_code: DNSServiceErrorType,
	fullname: *const c_char,
	rr_type: u16,
	rr_class: u16,
	rd_len: u16,
	rdata: *const u8,
	ttl: u32,
	context: *mut c_void
)>;

extern "C" {
	pub fn DNSServiceRefSockFD(sd_ref: DNSServiceRef) -> c_int;
	pub fn DNSServiceProcessResult(sd_ref: DNSServiceRef) -> DNSServiceErrorType;
	pub fn DNSServiceRefDeallocate(sd_ref: DNSServiceRef);
	pub fn DNSServiceEnumerateDomains(
		sd_ref: *mut DNSServiceRef,
		flags: DNSServiceFlags,
		interface_index: u32,
		callback: DNSServiceDomainEnumReply,
		context: *mut c_void
	) -> DNSServiceErrorType;
	pub fn DNSServiceRegister(
		sd_ref: *mut DNSServiceRef,
		flags: DNSServiceFlags,
		interface_index: u32,
		name: *const c_char,
		reg_type: *const c_char,
		domain: *const c_char,
		host: *const c_char,
		port: u16,
		txt_len: u16,
		txt_record: *const u8,
		callback: DNSServiceRegisterReply,
		context: *mut c_void
	) -> DNSServiceErrorType;
	pub fn DNSServiceAddRecord(
		sd_ref: DNSServiceRef,
		record_ref: *mut DNSRecordRef,
		flags: DNSServiceFlags,
		rr_type: u16,
		rd_len: u16,
		rdata: *const u8,
		ttl: u32
	) -> DNSServiceErrorType;
	pub fn DNSServiceUpdateRecord(
		sd_ref: DNSServiceRef,
		record_ref: DNSRecordRef,
		flags: DNSServiceFlags,
		rd_len: u16,
		rdata: *const u8,
		ttl: u32
	) -> DNSServiceErrorType;
	pub fn DNSServiceRemoveRecord(
		sd_ref: DNSServiceRef,
		record_ref: DNSRecordRef,
		flags: DNSServiceFlags
	) -> DNSServiceErrorType;
	pub fn DNSServiceBrowse(
		sd_ref: *mut DNSServiceRef,
		flags: DNSServiceFlags,
		interface_index: u32,
		reg_type: *const c_char,
		domain: *const c_char,
		callback: DNSServiceBrowseReply,
		context: *mut c_void
	) -> DNSServiceErrorType;
	pub fn DNSServiceResolve(
		sd_ref: *mut DNSServiceRef,
		flags: DNSServiceFlags,
		interface_index: u32,
		name: *const c_char,
		reg_type: *const c_char,
		domain: *const c_char,
		callback: DNSServiceResolveReply,
		context: *mut c_void
	) -> DNSServiceErrorType;
	pub fn DNSServiceCreateConnection(sd_ref: *mut DNSServiceRef) -> DNSServiceErrorType;
	pub fn DNSServiceRegisterRecord(
		sd_ref: DNSServiceRef,
		record_ref: *mut DNSRecordRef,
		flags: DNSServiceFlags,
		interface_index: u32,
		fullname: *const c_char,
		rr_type: u16,
		rr_class: u16,
		rd_len: u16,
		rdata: *const u8,
		ttl: u32,
		callback: DNSServiceRegisterRecordReply,
		context: *mut c_void
	) -> DNSServiceErrorType;
	pub fn DNSServiceQueryRecord(
		sd_ref: *mut DNSServiceRef,
		flags: DNSServiceFlags,
		interface_index: u32,
		fullname: *const c_char,
		rr_type: u16,
		rr_class: u16,
		callback: DNSServiceQueryRecordReply,
		context: *mut c_void
	) -> DNSServiceErrorType;
	pub fn DNSServiceReconfirmRecord(
		flags: DNSServiceFlags,
		interface_index: u32,
		fullname: *const c_char,
		rr_type: u16,
		rr_class: u16,
		rd_len: u16,
		rdata: *const u8
	) -> DNSServiceErrorType;
	pub fn DNSServiceConstructFullName(
		fullName: *mut c_char,
		service: *const c_char,
		reg_type: *const c_char,
		domain: *const c_char
	) -> c_int;
}

// TXTRecordRef utils not wrapped - should be easy enough to implement
// in pure rust

#[cfg(windows)]
mod ffi_windows {
	use std::os::raw::{c_int,c_void};
	use super::DNSServiceErrorType;

	pub type DNSServiceInitializeFlags = u32;
	pub const INITIALIZE_FLAGS_NONE            : DNSServiceInitializeFlags = 0x0;
	pub const INITIALIZE_FLAGS_ADVERTISE       : DNSServiceInitializeFlags = 0x1;
	pub const INITIALIZE_FLAGS_NO_SERVER_CHECK : DNSServiceInitializeFlags = 0x2;

	pub type DNSPropertyCode = u32;

	pub const PROPERTY_CODE_VERSION : DNSPropertyCode = 0x76657273;
	#[repr(C)]
	pub struct DnsPropertyVersion {
		pub code: DNSPropertyCode,

		pub client_current_version: u32,
		pub client_oldest_server_version: u32,
		pub server_current_version: u32,
		pub server_oldest_client_version: u32,
	}

	extern "C" {
		pub fn DNSServiceInitialize(
			inFlags: DNSServiceInitializeFlags,
			inCacheEntryCount: c_int
		) -> DNSServiceErrorType;
		pub fn DNSServiceFinalize();
		pub fn DNSServiceCheckVersion() -> DNSServiceErrorType;

		// TODO? DNSPropertyData on windows.
		// the c API uses a union... - using void instead here
		pub fn DNSServiceCopyProperty(
			inCode: DNSPropertyCode,
			outData: *mut c_void) -> DNSServiceErrorType;
		pub fn DNSServiceReleaseProperty(inData: *mut c_void) -> DNSServiceErrorType;
	}
}
#[cfg(windows)]
use self::ffi_windows::*;
<|endoftext|>


<commit_before>#![feature(rustc_private, never_type, decl_macro)]
#![allow(intra_doc_link_resolution_failure)]

extern crate flate2;
extern crate rustc;
extern crate rustc_allocator;
extern crate rustc_codegen_ssa;
extern crate rustc_codegen_utils;
extern crate rustc_data_structures;
extern crate rustc_fs_util;
extern crate rustc_incremental;
extern crate rustc_mir;
extern crate rustc_target;
extern crate syntax;

use std::any::Any;
use std::sync::mpsc;

use rustc::dep_graph::DepGraph;
use rustc::middle::cstore::{EncodedMetadata, MetadataLoader};
use rustc::session::config::OutputFilenames;
use rustc::ty::query::Providers;
use rustc::util::common::ErrorReported;
use rustc_codegen_utils::codegen_backend::CodegenBackend;

use cranelift::codegen::settings;

use crate::constant::ConstantCx;
use crate::prelude::*;

mod abi;
mod allocator;
mod analyze;
mod archive;
mod base;
mod common;
mod constant;
mod debuginfo;
mod driver;
mod intrinsics;
mod linkage;
mod main_shim;
mod metadata;
mod pretty_clif;
mod trap;
mod unimpl;
mod unsize;
mod value_and_place;
mod vtable;

mod prelude {
    pub use std::any::Any;
    pub use std::collections::{HashMap, HashSet};
    pub use std::convert::TryInto;

    pub use syntax::ast::{FloatTy, IntTy, UintTy};
    pub use syntax::source_map::{Pos, Span, DUMMY_SP};

    pub use rustc::bug;
    pub use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
    pub use rustc::mir::{self, interpret::AllocId, mono::MonoItem, *};
    pub use rustc::session::{
        config::{CrateType, Lto},
        Session,
    };
    pub use rustc::ty::layout::{self, Abi, LayoutOf, Scalar, Size, TyLayout, VariantIdx};
    pub use rustc::ty::{
        self, FnSig, Instance, InstanceDef, ParamEnv, PolyFnSig, Ty, TyCtxt,
        TypeAndMut, TypeFoldable,
    };
    pub use rustc_data_structures::{
        fx::{FxHashMap, FxHashSet},
        indexed_vec::Idx,
        sync::Lrc,
    };
    pub use rustc_mir::monomorphize::collector;

    pub use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
    pub use rustc_codegen_ssa::traits::*;
    pub use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleKind};

    pub use cranelift::codegen::ir::{
        condcodes::IntCC, function::Function, ExternalName, FuncRef, Inst, SourceLoc, StackSlot,
    };
    pub use cranelift::codegen::isa::CallConv;
    pub use cranelift::codegen::Context;
    pub use cranelift::prelude::*;
    pub use cranelift_module::{
        self, Backend, DataContext, DataId, FuncId, FuncOrDataId, Linkage, Module,
    };

    pub use crate::abi::*;
    pub use crate::base::{trans_operand, trans_place};
    pub use crate::common::*;
    pub use crate::debuginfo::{DebugContext, FunctionDebugContext};
    pub use crate::trap::*;
    pub use crate::unimpl::{unimpl, with_unimpl_span};
    pub use crate::value_and_place::{CValue, CPlace};
    pub use crate::{Caches, CodegenCx};

    pub struct PrintOnPanic<F: Fn() -> String>(pub F);
    impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
        fn drop(&mut self) {
            if ::std::thread::panicking() {
                println!("{}", (self.0)());
            }
        }
    }
}

pub struct Caches<'tcx> {
    pub context: Context,
    pub vtables: HashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
}

impl Default for Caches<'_> {
    fn default() -> Self {
        Caches {
            context: Context::new(),
            vtables: HashMap::new(),
        }
    }
}

pub struct CodegenCx<'clif, 'tcx, B: Backend + 'static> {
    tcx: TyCtxt<'tcx>,
    module: &'clif mut Module<B>,
    ccx: ConstantCx,
    caches: Caches<'tcx>,
    debug_context: Option<&'clif mut DebugContext<'tcx>>,
}

impl<'clif, 'tcx, B: Backend + 'static> CodegenCx<'clif, 'tcx, B> {
    fn new(
        tcx: TyCtxt<'tcx>,
        module: &'clif mut Module<B>,
        debug_context: Option<&'clif mut DebugContext<'tcx>>,
    ) -> Self {
        CodegenCx {
            tcx,
            module,
            ccx: ConstantCx::default(),
            caches: Caches::default(),
            debug_context,
        }
    }

    fn finalize(self) {
        self.ccx.finalize(self.tcx, self.module);
    }
}

struct CraneliftCodegenBackend;

impl CodegenBackend for CraneliftCodegenBackend {
    fn init(&self, sess: &Session) {
        for cty in sess.opts.crate_types.iter() {
            match *cty {
                CrateType::Rlib | CrateType::Dylib | CrateType::Executable => {}
                _ => {
                    sess.warn(&format!(
                        "Rustc codegen cranelift doesn't support output type {}",
                        cty
                    ));
                }
            }
        }
        match sess.lto() {
            Lto::Fat | Lto::Thin | Lto::ThinLocal => {
                sess.warn("Rustc codegen cranelift doesn't support lto");
            }
            Lto::No => {}
        }
        if sess.opts.cg.rpath {
            sess.err("rpath is not yet supported");
        }
        if sess.opts.debugging_opts.pgo_gen.enabled() {
            sess.err("pgo is not supported");
        }
    }

    fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> {
        Box::new(crate::metadata::CraneliftMetadataLoader)
    }

    fn provide(&self, providers: &mut Providers) {
        rustc_codegen_utils::symbol_names::provide(providers);
        rustc_codegen_ssa::back::symbol_export::provide(providers);

        providers.target_features_whitelist = |tcx, _cnum| tcx.arena.alloc(FxHashMap::default());
    }
    fn provide_extern(&self, providers: &mut Providers) {
        rustc_codegen_ssa::back::symbol_export::provide_extern(providers);
    }

    fn codegen_crate<'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: EncodedMetadata,
        need_metadata_module: bool,
        _rx: mpsc::Receiver<Box<dyn Any + Send>>,
    ) -> Box<dyn Any> {
        driver::codegen_crate(tcx, metadata, need_metadata_module)
    }

    fn join_codegen_and_link(
        &self,
        res: Box<dyn Any>,
        sess: &Session,
        _dep_graph: &DepGraph,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use rustc_codegen_ssa::back::link::link_binary;

        let codegen_results = *res
            .downcast::<CodegenResults>()
            .expect("Expected CraneliftCodegenBackend's CodegenResult, found Box<Any>");

        let target_cpu = ::target_lexicon::HOST.to_string();
        link_binary::<crate::archive::ArArchiveBuilder<'_>>(
            sess,
            &codegen_results,
            outputs,
            &codegen_results.crate_name.as_str(),
            &target_cpu,
        );

        Ok(())
    }
}

fn target_triple(sess: &Session) -> target_lexicon::Triple {
    let mut target = &*sess.target.target.llvm_target;

    // FIXME add support for x86_64-apple-macosx10.7.0 to target-lexicon
    if target.starts_with("x86_64-apple-macosx") {
        target = "x86_64-apple-darwin";
    }

    target.parse().unwrap()
}

fn build_isa(sess: &Session) -> Box<dyn isa::TargetIsa + 'static> {
    let mut flags_builder = settings::builder();
    flags_builder.enable("is_pic").unwrap();
    flags_builder.set("probestack_enabled", "false").unwrap(); // ___cranelift_probestack is not provided
        flags_builder.set("enable_verifier", if cfg!(debug_assertions) {
        "true"
    } else {
        "false"
    }).unwrap();

    // FIXME enable again when https://github.com/CraneStation/cranelift/issues/664 is fixed
    /*
    use rustc::session::config::OptLevel;
    match sess.opts.optimize {
        OptLevel::No => {
            flags_builder.set("opt_level", "fastest").unwrap();
        }
        OptLevel::Less | OptLevel::Default => {}
        OptLevel::Aggressive => {
            flags_builder.set("opt_level", "best").unwrap();
        }
        OptLevel::Size | OptLevel::SizeMin => {
            sess.warn("Optimizing for size is not supported. Just ignoring the request");
        }
    }*/

    let target_triple = target_triple(sess);
    let flags = settings::Flags::new(flags_builder);
    cranelift::codegen::isa::lookup(target_triple)
        .unwrap()
        .finish(flags)
}

/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    Box::new(CraneliftCodegenBackend)
}
<commit_msg>Rustup to rustc 1.37.0-nightly (0beb2ba16 2019-07-02)<commit_after>#![feature(rustc_private, never_type, decl_macro)]
#![allow(intra_doc_link_resolution_failure)]

extern crate flate2;
extern crate rustc;
extern crate rustc_allocator;
extern crate rustc_codegen_ssa;
extern crate rustc_codegen_utils;
extern crate rustc_data_structures;
extern crate rustc_fs_util;
extern crate rustc_incremental;
extern crate rustc_mir;
extern crate rustc_target;
extern crate syntax;

use std::any::Any;
use std::sync::mpsc;

use rustc::dep_graph::DepGraph;
use rustc::middle::cstore::{EncodedMetadata, MetadataLoader};
use rustc::session::config::OutputFilenames;
use rustc::ty::query::Providers;
use rustc::util::common::ErrorReported;
use rustc_codegen_utils::codegen_backend::CodegenBackend;

use cranelift::codegen::settings;

use crate::constant::ConstantCx;
use crate::prelude::*;

mod abi;
mod allocator;
mod analyze;
mod archive;
mod base;
mod common;
mod constant;
mod debuginfo;
mod driver;
mod intrinsics;
mod linkage;
mod main_shim;
mod metadata;
mod pretty_clif;
mod trap;
mod unimpl;
mod unsize;
mod value_and_place;
mod vtable;

mod prelude {
    pub use std::any::Any;
    pub use std::collections::{HashMap, HashSet};
    pub use std::convert::TryInto;

    pub use syntax::ast::{FloatTy, IntTy, UintTy};
    pub use syntax::source_map::{Pos, Span, DUMMY_SP};

    pub use rustc::bug;
    pub use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
    pub use rustc::mir::{self, interpret::AllocId, mono::MonoItem, *};
    pub use rustc::session::{
        config::{CrateType, Lto},
        Session,
    };
    pub use rustc::ty::layout::{self, Abi, LayoutOf, Scalar, Size, TyLayout, VariantIdx};
    pub use rustc::ty::{
        self, FnSig, Instance, InstanceDef, ParamEnv, PolyFnSig, Ty, TyCtxt,
        TypeAndMut, TypeFoldable,
    };
    pub use rustc_data_structures::{
        fx::{FxHashMap, FxHashSet},
        indexed_vec::Idx,
        sync::Lrc,
    };
    pub use rustc_mir::monomorphize::collector;

    pub use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
    pub use rustc_codegen_ssa::traits::*;
    pub use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleKind};

    pub use cranelift::codegen::ir::{
        condcodes::IntCC, function::Function, ExternalName, FuncRef, Inst, SourceLoc, StackSlot,
    };
    pub use cranelift::codegen::isa::CallConv;
    pub use cranelift::codegen::Context;
    pub use cranelift::prelude::*;
    pub use cranelift_module::{
        self, Backend, DataContext, DataId, FuncId, FuncOrDataId, Linkage, Module,
    };

    pub use crate::abi::*;
    pub use crate::base::{trans_operand, trans_place};
    pub use crate::common::*;
    pub use crate::debuginfo::{DebugContext, FunctionDebugContext};
    pub use crate::trap::*;
    pub use crate::unimpl::{unimpl, with_unimpl_span};
    pub use crate::value_and_place::{CValue, CPlace};
    pub use crate::{Caches, CodegenCx};

    pub struct PrintOnPanic<F: Fn() -> String>(pub F);
    impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
        fn drop(&mut self) {
            if ::std::thread::panicking() {
                println!("{}", (self.0)());
            }
        }
    }
}

pub struct Caches<'tcx> {
    pub context: Context,
    pub vtables: HashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
}

impl Default for Caches<'_> {
    fn default() -> Self {
        Caches {
            context: Context::new(),
            vtables: HashMap::new(),
        }
    }
}

pub struct CodegenCx<'clif, 'tcx, B: Backend + 'static> {
    tcx: TyCtxt<'tcx>,
    module: &'clif mut Module<B>,
    ccx: ConstantCx,
    caches: Caches<'tcx>,
    debug_context: Option<&'clif mut DebugContext<'tcx>>,
}

impl<'clif, 'tcx, B: Backend + 'static> CodegenCx<'clif, 'tcx, B> {
    fn new(
        tcx: TyCtxt<'tcx>,
        module: &'clif mut Module<B>,
        debug_context: Option<&'clif mut DebugContext<'tcx>>,
    ) -> Self {
        CodegenCx {
            tcx,
            module,
            ccx: ConstantCx::default(),
            caches: Caches::default(),
            debug_context,
        }
    }

    fn finalize(self) {
        self.ccx.finalize(self.tcx, self.module);
    }
}

struct CraneliftCodegenBackend;

impl CodegenBackend for CraneliftCodegenBackend {
    fn init(&self, _sess: &Session) {}

    fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> {
        Box::new(crate::metadata::CraneliftMetadataLoader)
    }

    fn provide(&self, providers: &mut Providers) {
        rustc_codegen_utils::symbol_names::provide(providers);
        rustc_codegen_ssa::back::symbol_export::provide(providers);

        providers.target_features_whitelist = |tcx, _cnum| tcx.arena.alloc(FxHashMap::default());
    }
    fn provide_extern(&self, providers: &mut Providers) {
        rustc_codegen_ssa::back::symbol_export::provide_extern(providers);
    }

    fn codegen_crate<'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: EncodedMetadata,
        need_metadata_module: bool,
        _rx: mpsc::Receiver<Box<dyn Any + Send>>,
    ) -> Box<dyn Any> {
        driver::codegen_crate(tcx, metadata, need_metadata_module)
    }

    fn join_codegen_and_link(
        &self,
        res: Box<dyn Any>,
        sess: &Session,
        _dep_graph: &DepGraph,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use rustc_codegen_ssa::back::link::link_binary;

        let codegen_results = *res
            .downcast::<CodegenResults>()
            .expect("Expected CraneliftCodegenBackend's CodegenResult, found Box<Any>");

        let target_cpu = ::target_lexicon::HOST.to_string();
        link_binary::<crate::archive::ArArchiveBuilder<'_>>(
            sess,
            &codegen_results,
            outputs,
            &codegen_results.crate_name.as_str(),
            &target_cpu,
        );

        Ok(())
    }
}

fn target_triple(sess: &Session) -> target_lexicon::Triple {
    let mut target = &*sess.target.target.llvm_target;

    // FIXME add support for x86_64-apple-macosx10.7.0 to target-lexicon
    if target.starts_with("x86_64-apple-macosx") {
        target = "x86_64-apple-darwin";
    }

    target.parse().unwrap()
}

fn build_isa(sess: &Session) -> Box<dyn isa::TargetIsa + 'static> {
    let mut flags_builder = settings::builder();
    flags_builder.enable("is_pic").unwrap();
    flags_builder.set("probestack_enabled", "false").unwrap(); // ___cranelift_probestack is not provided
        flags_builder.set("enable_verifier", if cfg!(debug_assertions) {
        "true"
    } else {
        "false"
    }).unwrap();

    // FIXME enable again when https://github.com/CraneStation/cranelift/issues/664 is fixed
    /*
    use rustc::session::config::OptLevel;
    match sess.opts.optimize {
        OptLevel::No => {
            flags_builder.set("opt_level", "fastest").unwrap();
        }
        OptLevel::Less | OptLevel::Default => {}
        OptLevel::Aggressive => {
            flags_builder.set("opt_level", "best").unwrap();
        }
        OptLevel::Size | OptLevel::SizeMin => {
            sess.warn("Optimizing for size is not supported. Just ignoring the request");
        }
    }*/

    let target_triple = target_triple(sess);
    let flags = settings::Flags::new(flags_builder);
    cranelift::codegen::isa::lookup(target_triple)
        .unwrap()
        .finish(flags)
}

/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    Box::new(CraneliftCodegenBackend)
}
<|endoftext|>


<commit_before>//! Reads and writes point cloud data stored in the ASPRS las file format.

#![deny(missing_copy_implementations, missing_debug_implementations, missing_docs, trivial_casts,
        trivial_numeric_casts, unsafe_code, unstable_features, unused_extern_crates,
        unused_import_braces, unused_qualifications)]

extern crate byteorder;

pub mod header;
pub mod error;
pub mod file;
pub mod point;
mod io;
mod scale;
pub mod stream;
pub mod vlr;

pub use file::File;
pub use point::Point;
pub use stream::Stream;

use std::result;

/// Crate-specific resuls.
pub type Result<T> = result::Result<T, error::Error>;
<commit_msg>Re-export Error<commit_after>//! Reads and writes point cloud data stored in the ASPRS las file format.

#![deny(missing_copy_implementations, missing_debug_implementations, missing_docs, trivial_casts,
        trivial_numeric_casts, unsafe_code, unstable_features, unused_extern_crates,
        unused_import_braces, unused_qualifications)]

extern crate byteorder;

pub mod header;
pub mod error;
pub mod file;
pub mod point;
mod io;
mod scale;
pub mod stream;
pub mod vlr;

pub use error::Error;
pub use file::File;
pub use point::Point;
pub use stream::Stream;

use std::result;

/// Crate-specific resuls.
pub type Result<T> = result::Result<T, Error>;
<|endoftext|>


<commit_before>#![crate_id = "bodyparser"]
#![license = "MIT"]

extern crate iron;
extern crate serialize;

use iron::{Ingot, Alloy, Request, Response};
use iron::ingot::{Status, Continue};

use serialize::json;
use serialize::json::Json;

#[deriving(Clone)]
struct Parsed(Json);

#[deriving(Clone)]
pub struct BodyParser;

impl BodyParser {
    fn new() -> BodyParser {
        BodyParser
    }
}

impl<Rq: Request, Rs: Response> Ingot<Rq, Rs> for BodyParser {
    fn enter(&mut self, _rq: &mut Rq, _rs: &mut Rs, alloy: &mut Alloy) -> Status {
        alloy.insert::<Parsed>(Parsed(parse_body(_rq.body())));
        Continue
    }
}

fn parse_body(x:&str) -> Json {
    let json_object = json::from_str(x.as_slice());
    json_object.clone().unwrap()
}<commit_msg>(doc) Added documentation title<commit_after>//! Body Parser middleware for Iron
#![crate_id = "bodyparser"]
#![license = "MIT"]

extern crate iron;
extern crate serialize;

use iron::{Ingot, Alloy, Request, Response};
use iron::ingot::{Status, Continue};

use serialize::json;
use serialize::json::Json;

#[deriving(Clone)]
struct Parsed(Json);

#[deriving(Clone)]
pub struct BodyParser;

impl BodyParser {
    fn new() -> BodyParser {
        BodyParser
    }
}

impl<Rq: Request, Rs: Response> Ingot<Rq, Rs> for BodyParser {
    fn enter(&mut self, _rq: &mut Rq, _rs: &mut Rs, alloy: &mut Alloy) -> Status {
        alloy.insert::<Parsed>(Parsed(parse_body(_rq.body())));
        Continue
    }
}

fn parse_body(x:&str) -> Json {
    let json_object = json::from_str(x.as_slice());
    json_object.clone().unwrap()
}<|endoftext|>


<commit_before>use crate::exceptions::{CalculateError, IOError};
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
use std::fs;
use std::fs::DirEntry;

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Measurement {
    pub command: String,
    pub mean: f64,
    pub stddev: f64,
    pub median: f64,
    pub user: f64,
    pub system: f64,
    pub min: f64,
    pub max: f64,
    pub times: Vec<f64>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Measurements {
    pub results: Vec<Measurement>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Data {
    pub threshold: f64,
    pub difference: f64,
    pub baseline: f64,
    pub dev: f64,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Calculation {
    pub metric: String,
    pub regression: bool,
    pub data: Data,
}

#[derive(Debug, Clone, PartialEq)]
pub struct MeasurementGroup {
    pub version: String,
    pub run: String,
    pub measurement: Measurement,
}

fn calculate(metric: &str, dev: &Measurement, baseline: &Measurement) -> Vec<Calculation> {
    let median_threshold = 1.05; // 5% regression threshold
    let median_difference = dev.median / baseline.median;

    let stddev_threshold = 1.05; // 5% regression threshold
    let stddev_difference = dev.stddev / baseline.stddev;

    vec![
        Calculation {
            metric: ["median", metric].join("_"),
            regression: median_difference > median_threshold,
            data: Data {
                threshold: median_threshold,
                difference: median_difference,
                baseline: baseline.median,
                dev: dev.median,
            }
        },
        Calculation {
            metric: ["stddev", metric].join("_"),
            regression: stddev_difference > stddev_threshold,
            data: Data {
                threshold: stddev_threshold,
                difference: stddev_difference,
                baseline: baseline.stddev,
                dev: dev.stddev,
            }
        },
    ]
}

// given a directory, read all files in the directory and return each
// filename with the deserialized json contents of that file
fn measurements_from_files(
    results_directory: &Path,
) -> Result<Vec<(PathBuf, Measurements)>, CalculateError> {
    fs::read_dir(results_directory)
        .or_else(|e| Err(IOError::ReadErr(results_directory.to_path_buf(), Some(e))))
        .or_else(|e| Err(CalculateError::CalculateIOError(e)))?
        .into_iter()
        .map(|entry| {
            let ent: DirEntry = entry.or_else(|e| Err(IOError::ReadErr(results_directory.to_path_buf(), Some(e))))
                .or_else(|e| Err(CalculateError::CalculateIOError(e)))?;

            Ok(ent.path())
        })
        .collect::<Result<Vec<PathBuf>, CalculateError>>()?
        .iter()
        .filter(|path| {
            path
                .extension()
                .and_then(|ext| ext.to_str())
                .map_or(false, |ext| ext.ends_with("json"))
        })
        .map(|path| {
            fs::read_to_string(path)
                .or_else(|e| Err(IOError::BadFileContentsErr(path.clone(), Some(e))))
                .or_else(|e| Err(CalculateError::CalculateIOError(e)))
                .and_then(|contents| {
                    serde_json::from_str::<Measurements>(&contents)
                        .or_else(|e| Err(CalculateError::BadJSONErr(path.clone(), Some(e))))
                })
                .map(|m| (path.clone(), m))
        })
        .collect()
}

// given a list of filename-measurement pairs, detect any regressions by grouping
// measurements together by filename
fn calculate_regressions(
    measurements: &[(PathBuf, Measurement)],
) -> Result<Vec<Calculation>, CalculateError> {
    let mut measurement_groups: Vec<MeasurementGroup> = measurements
        .into_iter()
        .map(|(p, m)| {
            p.file_name()
                .ok_or_else(|| IOError::MissingFilenameErr(p.to_path_buf()))
                .and_then(|name| {
                    name.to_str()
                        .ok_or_else(|| IOError::FilenameNotUnicodeErr(p.to_path_buf()))
                })
                .map(|name| {
                    let parts: Vec<&str> = name.split("_").collect();
                    MeasurementGroup {
                        version: parts[0].to_owned(),
                        run: parts[1..].join("_"),
                        measurement: m.clone(),
                    }
                })
        })
        .collect::<Result<Vec<MeasurementGroup>, IOError>>()
        .or_else(|e| Err(CalculateError::CalculateIOError(e)))?;

    measurement_groups.sort_by(|x, y| (&x.run, &x.version).cmp(&(&y.run, &y.version)));

    // locking up mutation
    let sorted_measurement_groups = measurement_groups;

    let calculations: Vec<Calculation> = sorted_measurement_groups
        .into_iter()
        .group_by(|x| x.run.clone())
        .into_iter()
        .map(|(_, g)| {
            let mut groups: Vec<MeasurementGroup> = g.collect();
            groups.sort_by(|x, y| x.version.cmp(&y.version));

            match groups.len() {
                2 => {
                    let dev = &groups[1];
                    let baseline = &groups[0];

                    if dev.version == "dev" && baseline.version == "baseline" {
                        Ok(calculate(&dev.run, &dev.measurement, &baseline.measurement))
                    } else {
                        Err(CalculateError::BadBranchNameErr(baseline.version.clone(), dev.version.clone()))
                    }
                },
                i => Err(CalculateError::BadGroupSizeErr(i, groups)),
            }
        })
        .collect::<Result<Vec<Vec<Calculation>>, CalculateError>>()?
        .concat();

    Ok(calculations)
}

pub fn regressions(results_directory: &PathBuf) -> Result<Vec<Calculation>, CalculateError> {
    measurements_from_files(Path::new(&results_directory)).and_then(|v| match v[..] {
        // exit early with an Err if there are no results to process
        [] => {
            Err(CalculateError::NoResultsErr(results_directory.clone()))
        },

        _ => {
            // we expect two runs for each project-metric pairing: one for each branch, baseline
            // and dev. An odd result count is unexpected.
            if v.len() % 2 == 1 {
                Err(CalculateError::OddResultsCountErr(v.len(), results_directory.clone()))
            } else {
                // otherwise, we can do our comparisons
                let measurements = v
                    .into_iter()
                    // the way we're running these, the files will each contain exactly one measurement, hence `results[0]`
                    .map(|(p, ms)| (p, ms.results[0].clone()))
                    .collect::<Vec<(PathBuf, Measurement)>>();

                calculate_regressions(&measurements)
            }
        },
    })
}
<commit_msg>make the happy path use references and clone in the exception paths<commit_after>use crate::exceptions::{CalculateError, IOError};
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
use std::fs;
use std::fs::DirEntry;

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Measurement {
    pub command: String,
    pub mean: f64,
    pub stddev: f64,
    pub median: f64,
    pub user: f64,
    pub system: f64,
    pub min: f64,
    pub max: f64,
    pub times: Vec<f64>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Measurements {
    pub results: Vec<Measurement>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Data {
    pub threshold: f64,
    pub difference: f64,
    pub baseline: f64,
    pub dev: f64,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Calculation {
    pub metric: String,
    pub regression: bool,
    pub data: Data,
}

#[derive(Debug, Clone, PartialEq)]
pub struct MeasurementGroup {
    pub version: String,
    pub run: String,
    pub measurement: Measurement,
}

fn calculate(metric: &str, dev: &Measurement, baseline: &Measurement) -> Vec<Calculation> {
    let median_threshold = 1.05; // 5% regression threshold
    let median_difference = dev.median / baseline.median;

    let stddev_threshold = 1.05; // 5% regression threshold
    let stddev_difference = dev.stddev / baseline.stddev;

    vec![
        Calculation {
            metric: ["median", metric].join("_"),
            regression: median_difference > median_threshold,
            data: Data {
                threshold: median_threshold,
                difference: median_difference,
                baseline: baseline.median,
                dev: dev.median,
            }
        },
        Calculation {
            metric: ["stddev", metric].join("_"),
            regression: stddev_difference > stddev_threshold,
            data: Data {
                threshold: stddev_threshold,
                difference: stddev_difference,
                baseline: baseline.stddev,
                dev: dev.stddev,
            }
        },
    ]
}

// given a directory, read all files in the directory and return each
// filename with the deserialized json contents of that file
fn measurements_from_files(
    results_directory: &Path,
) -> Result<Vec<(PathBuf, Measurements)>, CalculateError> {
    fs::read_dir(results_directory)
        .or_else(|e| Err(IOError::ReadErr(results_directory.to_path_buf(), Some(e))))
        .or_else(|e| Err(CalculateError::CalculateIOError(e)))?
        .into_iter()
        .map(|entry| {
            let ent: DirEntry = entry.or_else(|e| Err(IOError::ReadErr(results_directory.to_path_buf(), Some(e))))
                .or_else(|e| Err(CalculateError::CalculateIOError(e)))?;

            Ok(ent.path())
        })
        .collect::<Result<Vec<PathBuf>, CalculateError>>()?
        .iter()
        .filter(|path| {
            path
                .extension()
                .and_then(|ext| ext.to_str())
                .map_or(false, |ext| ext.ends_with("json"))
        })
        .map(|path| {
            fs::read_to_string(path)
                .or_else(|e| Err(IOError::BadFileContentsErr(path.clone(), Some(e))))
                .or_else(|e| Err(CalculateError::CalculateIOError(e)))
                .and_then(|contents| {
                    serde_json::from_str::<Measurements>(&contents)
                        .or_else(|e| Err(CalculateError::BadJSONErr(path.clone(), Some(e))))
                })
                .map(|m| (path.clone(), m))
        })
        .collect()
}

// given a list of filename-measurement pairs, detect any regressions by grouping
// measurements together by filename
fn calculate_regressions(
    measurements: &[(PathBuf, Measurement)],
) -> Result<Vec<Calculation>, CalculateError> {
    let mut measurement_groups: Vec<MeasurementGroup> = measurements
        .iter()
        .map(|(p, m)| {
            p.file_name()
                .ok_or_else(|| IOError::MissingFilenameErr(p.to_path_buf()))
                .and_then(|name| {
                    name.to_str()
                        .ok_or_else(|| IOError::FilenameNotUnicodeErr(p.to_path_buf()))
                })
                .map(|name| {
                    let parts: Vec<&str> = name.split("_").collect();
                    MeasurementGroup {
                        version: parts[0].to_owned(),
                        run: parts[1..].join("_"),
                        measurement: m.clone(),
                    }
                })
        })
        .collect::<Result<Vec<MeasurementGroup>, IOError>>()
        .or_else(|e| Err(CalculateError::CalculateIOError(e)))?;

    measurement_groups.sort_by(|x, y| (&x.run, &x.version).cmp(&(&y.run, &y.version)));

    // locking up mutation
    let sorted_measurement_groups = measurement_groups;

    let calculations: Vec<Calculation> = sorted_measurement_groups
        .iter()
        .group_by(|x| x.run.clone())
        .into_iter()
        .map(|(_, g)| {
            let mut groups: Vec<&MeasurementGroup> = g.collect();
            groups.sort_by(|x, y| x.version.cmp(&y.version));

            match groups.len() {
                2 => {
                    let dev = &groups[1];
                    let baseline = &groups[0];

                    if dev.version == "dev" && baseline.version == "baseline" {
                        Ok(calculate(&dev.run, &dev.measurement, &baseline.measurement))
                    } else {
                        Err(CalculateError::BadBranchNameErr(baseline.version.clone(), dev.version.clone()))
                    }
                },
                i => {
                    let gs: Vec<MeasurementGroup> = groups.into_iter().map(|x| x.clone()).collect();
                    Err(CalculateError::BadGroupSizeErr(i, gs))
                },
            }
        })
        .collect::<Result<Vec<Vec<Calculation>>, CalculateError>>()?
        .concat();

    Ok(calculations)
}

pub fn regressions(results_directory: &PathBuf) -> Result<Vec<Calculation>, CalculateError> {
    measurements_from_files(Path::new(&results_directory)).and_then(|v| match v[..] {
        // exit early with an Err if there are no results to process
        [] => {
            Err(CalculateError::NoResultsErr(results_directory.clone()))
        },

        _ => {
            // we expect two runs for each project-metric pairing: one for each branch, baseline
            // and dev. An odd result count is unexpected.
            if v.len() % 2 == 1 {
                Err(CalculateError::OddResultsCountErr(v.len(), results_directory.clone()))
            } else {
                // otherwise, we can do our comparisons
                let measurements = v
                    .into_iter()
                    // the way we're running these, the files will each contain exactly one measurement, hence `results[0]`
                    .map(|(p, ms)| (p, ms.results[0].clone()))
                    .collect::<Vec<(PathBuf, Measurement)>>();

                calculate_regressions(&measurements)
            }
        },
    })
}
<|endoftext|>


<commit_before>//
// yaml.rs
// Nothing to see here yet
//

extern crate serialize;

use std::io::{IoError, IoResult, Writer, MemWriter};
use std::collections::{TreeMap};
use serialize::{Encodable, Encoder, Decodable, Decoder};

#[deriving(Clone, PartialEq, PartialOrd)]
pub enum Yaml {
        Integer(int),
        Float(f64),
        String(String),
        Boolean(bool),
        Sequence(Vec<Yaml>),
        Map(TreeMap<String, Yaml>),
        Null,
}

//
// Encode a Rust object into a yaml document
// in typical yaml terms this would be 'dump'
//
//
pub fn encode<'writer, T: Encodable<YamlEncoder<'writer>, IoError>>(object: &T) -> String {
    let buffer = YamlEncoder::buffer_encode(object);
    String::from_utf8(buffer).unwrap()
}

pub type EncodeResult = IoResult<()>;

//
//
//
struct YamlEncoder<'writer> {
    writer: &'writer mut Writer,
}

impl<'writer> YamlEncoder<'writer> {

    pub fn new(writer: &'writer mut Writer) -> YamlEncoder<'writer> {
        YamlEncoder {
            writer: writer
        }
    }

    pub fn buffer_encode<T:Encodable<YamlEncoder<>, IoError>>(object: &T) -> Vec<u8> {
        let mut writer = MemWriter::new();
        {
            let mut encoder = YamlEncoder::new(&mut writer as &mut Writer);
            object.encode(&mut encoder);
        }
        writer.unwrap()
    }

}

impl<'writer> Encoder<IoError> for YamlEncoder<'writer> {
        // Primitive types:
    fn emit_nil(&mut self) -> EncodeResult {
        write!(self.writer, "null")
    }

    // TODO
    fn emit_uint(&mut self, v: uint) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    // TODO
    fn emit_u64(&mut self, v: u64) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    // TODO
    fn emit_u32(&mut self, v: u32) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    // TODO
    fn emit_u16(&mut self, v: u16) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    // TODO
    fn emit_u8(&mut self, v: u8) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    // TODO
    fn emit_int(&mut self, v: int) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    // TODO
    fn emit_i64(&mut self, v: i64) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    // TODO
    fn emit_i32(&mut self, v: i32) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    // TODO
    fn emit_i16(&mut self, v: i16) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    // TODO
    fn emit_i8(&mut self, v: i8) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_bool(&mut self, v: bool) -> EncodeResult {
        if v {
            write!(self.writer, "true")
        } else {
            write!(self.writer, "false")
        }
    }

    // TODO
    fn emit_f64(&mut self, v: f64) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    // TODO
    fn emit_f32(&mut self, v: f32) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    // TODO
    fn emit_char(&mut self, v: char) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    // TODO
    fn emit_str(&mut self, v: &str) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_enum(&mut self, _name: &str, f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_enum_variant(&mut self,
                         name: &str,
                         _id: uint,
                         cnt: uint,
                         f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_enum_variant_arg(&mut self,
                             idx: uint,
                             f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_enum_struct_variant(&mut self,
                                name: &str,
                                id: uint,
                                cnt: uint,
                                f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_enum_struct_variant_field(&mut self,
                                      _: &str,
                                      idx: uint,
                                      f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_struct(&mut self,
                   _: &str,
                   _: uint,
                   f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_struct_field(&mut self,
                         name: &str,
                         idx: uint,
                         f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_tuple(&mut self, len: uint, f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }
    fn emit_tuple_arg(&mut self,
                      idx: uint,
                      f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_tuple_struct(&mut self,
                         _name: &str,
                         len: uint,
                         f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }
    fn emit_tuple_struct_arg(&mut self,
                             idx: uint,
                             f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_option(&mut self, f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }
    fn emit_option_none(&mut self) -> EncodeResult {
        self.emit_nil()
    }

    fn emit_option_some(&mut self, f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        f(self)
    }

    fn emit_seq(&mut self, _len: uint, f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_seq_elt(&mut self, idx: uint, f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_map(&mut self, _len: uint, f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_map_elt_key(&mut self,
                        idx: uint,
                        f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_map_elt_val(&mut self,
                        _idx: uint,
                        f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }
}

#[cfg(test)]
mod tests {
    extern crate serialize;

    use std::string::String;
    use serialize::{Encodable, Encoder, Decodable, Decoder};
    use super::{encode};

    #[deriving(Encodable)]
    struct Person {
        name: String,
        age: int
    }

    #[test]
    fn test_encode_null() {

        let object: Option<String> = None;

        let document = encode(&object);

        let expected = "null".to_string();

        assert_eq!(document, expected);
    }

}
<commit_msg>macro to get around unsafe lifetimes thing<commit_after>//
// yaml.rs
// Nothing to see here yet
//
#![feature(macro_rules)]

extern crate serialize;

use std::io::{IoError, IoResult, Writer, MemWriter};
use std::collections::{TreeMap};
use serialize::{Encodable, Encoder, Decodable, Decoder};

#[deriving(Clone, PartialEq, PartialOrd)]
pub enum Yaml {
        Integer(int),
        Float(f64),
        String(String),
        Boolean(bool),
        Sequence(Vec<Yaml>),
        Map(TreeMap<String, Yaml>),
        Null,
}

//
// Encode a Rust object into a yaml document
// in typical yaml terms this would be 'dump'
//
//
#[macro_export]
macro_rules! encode {
    ($obj:ident) => {
        {
            let mut writer = MemWriter::new();
            {
                let mut encoder = YamlEncoder::new(&mut writer);
                $obj.encode(&mut encoder);
            }
            String::from_utf8(writer.unwrap()).unwrap()
        }
    }
}

pub type EncodeResult = IoResult<()>;

struct YamlEncoder<'writer> {
    writer: &'writer mut Writer
}

impl<'writer> YamlEncoder<'writer> {

    pub fn new(writer: &'writer mut Writer) -> YamlEncoder<'writer> {
        YamlEncoder {
            writer: writer
        }
    }

    //pub fn buffer_encode<'writer, T:Encodable<YamlEncoder<'writer>, IoError>>(object: &T) -> Vec<u8> {
    //    let writer = MemWriter::new();
    //    {
    //        let mut encoder = YamlEncoder::new(&mut writer as &mut Writer);
    //        object.encode(&mut encoder);
    //    }
    //    writer.unwrap()
    //}

}

impl <'writer>Encoder<IoError> for YamlEncoder<'writer> {
        // Primitive types:
    fn emit_nil(&mut self) -> EncodeResult {
        write!(self.writer, "null")
    }

    // TODO
    fn emit_uint(&mut self, v: uint) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    // TODO
    fn emit_u64(&mut self, v: u64) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    // TODO
    fn emit_u32(&mut self, v: u32) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    // TODO
    fn emit_u16(&mut self, v: u16) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    // TODO
    fn emit_u8(&mut self, v: u8) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    // TODO
    fn emit_int(&mut self, v: int) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    // TODO
    fn emit_i64(&mut self, v: i64) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    // TODO
    fn emit_i32(&mut self, v: i32) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    // TODO
    fn emit_i16(&mut self, v: i16) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    // TODO
    fn emit_i8(&mut self, v: i8) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_bool(&mut self, v: bool) -> EncodeResult {
        if v {
            write!(self.writer, "true")
        } else {
            write!(self.writer, "false")
        }
    }

    // TODO
    fn emit_f64(&mut self, v: f64) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    // TODO
    fn emit_f32(&mut self, v: f32) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    // TODO
    fn emit_char(&mut self, v: char) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    // TODO
    fn emit_str(&mut self, v: &str) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_enum(&mut self, _name: &str, f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_enum_variant(&mut self,
                         name: &str,
                         _id: uint,
                         cnt: uint,
                         f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_enum_variant_arg(&mut self,
                             idx: uint,
                             f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_enum_struct_variant(&mut self,
                                name: &str,
                                id: uint,
                                cnt: uint,
                                f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_enum_struct_variant_field(&mut self,
                                      _: &str,
                                      idx: uint,
                                      f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_struct(&mut self,
                   _: &str,
                   _: uint,
                   f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_struct_field(&mut self,
                         name: &str,
                         idx: uint,
                         f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_tuple(&mut self, len: uint, f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }
    fn emit_tuple_arg(&mut self,
                      idx: uint,
                      f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_tuple_struct(&mut self,
                         _name: &str,
                         len: uint,
                         f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }
    fn emit_tuple_struct_arg(&mut self,
                             idx: uint,
                             f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_option(&mut self, f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }
    fn emit_option_none(&mut self) -> EncodeResult {
        self.emit_nil()
    }

    fn emit_option_some(&mut self, f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        f(self)
    }

    fn emit_seq(&mut self, _len: uint, f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_seq_elt(&mut self, idx: uint, f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_map(&mut self, _len: uint, f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_map_elt_key(&mut self,
                        idx: uint,
                        f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }

    fn emit_map_elt_val(&mut self,
                        _idx: uint,
                        f: |&mut YamlEncoder<'writer>| -> EncodeResult) -> EncodeResult {
        write!(self.writer, "Unsupported")
    }
}

#[cfg(test)]
mod tests {

    #![feature(phase)]

    extern crate serialize;

    use std::string::String;
    use std::io::MemWriter;
    use serialize::{Encodable, Encoder, Decodable, Decoder};

    #[phase(syntax)]
    use super::{YamlEncoder};

    #[deriving(Encodable)]
    struct Person {
        name: String,
        age: int
    }

    #[test]
    fn test_encode_null() {
        let object: Option<String> = None;
        let document = {
            let mut writer = MemWriter::new();
            {
                let mut encoder = YamlEncoder::new(&mut writer as &mut Writer);
                object.encode(&mut encoder);
            }
            String::from_utf8(writer.unwrap()).unwrap()
        };

        let expected = "null".to_string();
        assert_eq!(document, expected);
    }

}
<|endoftext|>