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

//! A helper class for dealing with static archives

use driver::session::Session;
use metadata::filesearch;

use std::io::fs;
use std::os;
use std::run::{ProcessOptions, Process, ProcessOutput};
use std::str;
use extra::tempfile::TempDir;
use syntax::abi;

pub struct Archive {
    priv sess: Session,
    priv dst: Path,
}

fn run_ar(sess: Session, args: &str, cwd: Option<&Path>,
        paths: &[&Path]) -> ProcessOutput {
    let ar = sess.opts.ar.clone().unwrap_or_else(|| ~"ar");
    let mut args = ~[args.to_owned()];
    let mut paths = paths.iter().map(|p| p.as_str().unwrap().to_owned());
    args.extend(&mut paths);
    let mut opts = ProcessOptions::new();
    opts.dir = cwd;
    debug!("{} {}", ar, args.connect(" "));
    match cwd {
        Some(p) => { debug!("inside {}", p.display()); }
        None => {}
    }
    let o = Process::new(ar, args.as_slice(), opts).finish_with_output();
    if !o.status.success() {
        sess.err(format!("{} failed with: {}", ar, o.status));
        sess.note(format!("stdout ---\n{}", str::from_utf8(o.output)));
        sess.note(format!("stderr ---\n{}", str::from_utf8(o.error)));
        sess.abort_if_errors();
    }
    o
}

impl Archive {
    /// Initializes a new static archive with the given object file
    pub fn create<'a>(sess: Session, dst: &'a Path,
                      initial_object: &'a Path) -> Archive {
        run_ar(sess, "crus", None, [dst, initial_object]);
        Archive { sess: sess, dst: dst.clone() }
    }

    /// Opens an existing static archive
    pub fn open(sess: Session, dst: Path) -> Archive {
        assert!(dst.exists());
        Archive { sess: sess, dst: dst }
    }

    /// Read a file in the archive
    pub fn read(&self, file: &str) -> ~[u8] {
        // Apparently if "ar p" is used on windows, it generates a corrupt file
        // which has bad headers and LLVM will immediately choke on it
        if cfg!(windows) && cfg!(windows) { // FIXME(#10734) double-and
            let loc = TempDir::new("rsar").unwrap();
            let archive = os::make_absolute(&self.dst);
            run_ar(self.sess, "x", Some(loc.path()), [&archive,
                                                      &Path::init(file)]);
            fs::File::open(&loc.path().join(file)).read_to_end()
        } else {
            run_ar(self.sess, "p", None, [&self.dst, &Path::init(file)]).output
        }
    }

    /// Adds all of the contents of a native library to this archive. This will
    /// search in the relevant locations for a library named `name`.
    pub fn add_native_library(&mut self, name: &str) {
        let location = self.find_library(name);
        self.add_archive(&location, name);
    }

    /// Adds all of the contents of the rlib at the specified path to this
    /// archive.
    pub fn add_rlib(&mut self, rlib: &Path) {
        let name = rlib.filename_str().unwrap().split('-').next().unwrap();
        self.add_archive(rlib, name);
    }

    fn add_archive(&mut self, archive: &Path, name: &str) {
        let loc = TempDir::new("rsar").unwrap();

        // First, extract the contents of the archive to a temporary directory
        let archive = os::make_absolute(archive);
        run_ar(self.sess, "x", Some(loc.path()), [&archive]);

        // Next, we must rename all of the inputs to "guaranteed unique names".
        // The reason for this is that archives are keyed off the name of the
        // files, so if two files have the same name they will override one
        // another in the archive (bad).
        let files = fs::readdir(loc.path());
        let mut inputs = ~[];
        for file in files.iter() {
            let filename = file.filename_str().unwrap();
            let filename = format!("r-{}-{}", name, filename);
            let new_filename = file.with_filename(filename);
            fs::rename(file, &new_filename);
            inputs.push(new_filename);
        }

        // Finally, add all the renamed files to this archive
        let mut args = ~[&self.dst];
        args.extend(&mut inputs.iter());
        run_ar(self.sess, "r", None, args.as_slice());
    }

    fn find_library(&self, name: &str) -> Path {
        let (prefix, ext) = match self.sess.targ_cfg.os {
            abi::OsWin32 => ("", "lib"), _ => ("lib", "a"),
        };
        let libname = format!("{}{}.{}", prefix, name, ext);

        let mut rustpath = filesearch::rust_path();
        rustpath.push(self.sess.filesearch.get_target_lib_path());
        let path = self.sess.opts.addl_lib_search_paths.iter();
        for path in path.chain(rustpath.iter()) {
            debug!("looking for {} inside {}", name, path.display());
            let test = path.join(libname.clone());
            if test.exists() { return test }
        }
        self.sess.fatal(format!("could not find native static library `{}`, \
                                 perhaps an -L flag is missing?", name));
    }
}
<commit_msg>auto merge of #10785 : alexcrichton/rust/omg-i-hate-windows, r=pcwalton<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A helper class for dealing with static archives

use driver::session::Session;
use metadata::filesearch;

use std::io::fs;
use std::os;
use std::run::{ProcessOptions, Process, ProcessOutput};
use std::str;
use extra::tempfile::TempDir;
use syntax::abi;

pub struct Archive {
    priv sess: Session,
    priv dst: Path,
}

fn run_ar(sess: Session, args: &str, cwd: Option<&Path>,
        paths: &[&Path]) -> ProcessOutput {
    let ar = sess.opts.ar.clone().unwrap_or_else(|| ~"ar");
    let mut args = ~[args.to_owned()];
    let mut paths = paths.iter().map(|p| p.as_str().unwrap().to_owned());
    args.extend(&mut paths);
    let mut opts = ProcessOptions::new();
    opts.dir = cwd;
    debug!("{} {}", ar, args.connect(" "));
    match cwd {
        Some(p) => { debug!("inside {}", p.display()); }
        None => {}
    }
    let o = Process::new(ar, args.as_slice(), opts).finish_with_output();
    if !o.status.success() {
        sess.err(format!("{} failed with: {}", ar, o.status));
        sess.note(format!("stdout ---\n{}", str::from_utf8(o.output)));
        sess.note(format!("stderr ---\n{}", str::from_utf8(o.error)));
        sess.abort_if_errors();
    }
    o
}

impl Archive {
    /// Initializes a new static archive with the given object file
    pub fn create<'a>(sess: Session, dst: &'a Path,
                      initial_object: &'a Path) -> Archive {
        run_ar(sess, "crus", None, [dst, initial_object]);
        Archive { sess: sess, dst: dst.clone() }
    }

    /// Opens an existing static archive
    pub fn open(sess: Session, dst: Path) -> Archive {
        assert!(dst.exists());
        Archive { sess: sess, dst: dst }
    }

    /// Read a file in the archive
    pub fn read(&self, file: &str) -> ~[u8] {
        // Apparently if "ar p" is used on windows, it generates a corrupt file
        // which has bad headers and LLVM will immediately choke on it
        if cfg!(windows) && cfg!(windows) { // FIXME(#10734) double-and
            let loc = TempDir::new("rsar").unwrap();
            let archive = os::make_absolute(&self.dst);
            run_ar(self.sess, "x", Some(loc.path()), [&archive,
                                                      &Path::init(file)]);
            fs::File::open(&loc.path().join(file)).read_to_end()
        } else {
            run_ar(self.sess, "p", None, [&self.dst, &Path::init(file)]).output
        }
    }

    /// Adds all of the contents of a native library to this archive. This will
    /// search in the relevant locations for a library named `name`.
    pub fn add_native_library(&mut self, name: &str) {
        let location = self.find_library(name);
        self.add_archive(&location, name);
    }

    /// Adds all of the contents of the rlib at the specified path to this
    /// archive.
    pub fn add_rlib(&mut self, rlib: &Path) {
        let name = rlib.filename_str().unwrap().split('-').next().unwrap();
        self.add_archive(rlib, name);
    }

    fn add_archive(&mut self, archive: &Path, name: &str) {
        let loc = TempDir::new("rsar").unwrap();

        // First, extract the contents of the archive to a temporary directory
        let archive = os::make_absolute(archive);
        run_ar(self.sess, "x", Some(loc.path()), [&archive]);

        // Next, we must rename all of the inputs to "guaranteed unique names".
        // The reason for this is that archives are keyed off the name of the
        // files, so if two files have the same name they will override one
        // another in the archive (bad).
        let files = fs::readdir(loc.path());
        let mut inputs = ~[];
        for file in files.iter() {
            let filename = file.filename_str().unwrap();
            let filename = format!("r-{}-{}", name, filename);
            let new_filename = file.with_filename(filename);
            fs::rename(file, &new_filename);
            inputs.push(new_filename);
        }

        // Finally, add all the renamed files to this archive
        let mut args = ~[&self.dst];
        args.extend(&mut inputs.iter());
        run_ar(self.sess, "r", None, args.as_slice());
    }

    fn find_library(&self, name: &str) -> Path {
        let (osprefix, osext) = match self.sess.targ_cfg.os {
            abi::OsWin32 => ("", "lib"), _ => ("lib", "a"),
        };
        // On windows, static libraries sometimes show up as libfoo.a and other
        // times show up as foo.lib
        let oslibname = format!("{}{}.{}", osprefix, name, osext);
        let unixlibname = format!("lib{}.a", name);

        let mut rustpath = filesearch::rust_path();
        rustpath.push(self.sess.filesearch.get_target_lib_path());
        let path = self.sess.opts.addl_lib_search_paths.iter();
        for path in path.chain(rustpath.iter()) {
            debug!("looking for {} inside {}", name, path.display());
            let test = path.join(oslibname.as_slice());
            if test.exists() { return test }
            if oslibname != unixlibname {
                let test = path.join(unixlibname.as_slice());
                if test.exists() { return test }
            }
        }
        self.sess.fatal(format!("could not find native static library `{}`, \
                                 perhaps an -L flag is missing?", name));
    }
}
<|endoftext|>


<commit_before><commit_msg>smart<commit_after><|endoftext|>


<commit_before><commit_msg>Add commands unwrap function<commit_after><|endoftext|>


<commit_before><commit_msg>Rename the uniform usage section of the reflection file<commit_after><|endoftext|>


<commit_before><commit_msg>WIP: deflate, lints<commit_after><|endoftext|>


<commit_before><commit_msg>Implemented the wait flag. We not send packets and listen for incoming packets in seperate threads.<commit_after><|endoftext|>


<commit_before><commit_msg>Display world via sdl2<commit_after><|endoftext|>


<commit_before><commit_msg>add refernce to hand in main file<commit_after><|endoftext|>


<commit_before><commit_msg>	modified:   main.rs<commit_after><|endoftext|>


<commit_before>mod herd;
mod request;

extern crate nix;

fn main() {
    let mut threads = 99;
    let requests = 1;
    let host = "http://jacob.uk.com";

    while threads % 100 == 0 {
        let _pid = nix::unistd::fork();
        herd::release(100, requests, host);
        threads = threads - 100;
    }

    herd::release(threads, requests, host);
}
<commit_msg>Fixes bug in process forking logic<commit_after>mod herd;
mod request;

extern crate nix;

fn main() {
    let mut threads = 1;
    let requests = 1;
    let host = "http://jacob.uk.com";

    let processes = threads / 100;

    for _x in 1..processes {
        let _pid = nix::unistd::fork();
    }

    if threads >= 100 {
    	herd::release(100, requests, host);
    }else{
    	herd::release(threads, requests, host);
    }

}
<|endoftext|>


<commit_before><commit_msg>Add read support<commit_after><|endoftext|>


<commit_before><commit_msg>Log all targets (crates) in debug<commit_after><|endoftext|>


<commit_before><commit_msg>add a and i<commit_after><|endoftext|>


<commit_before><commit_msg>Add and update emojis in HashSet correctly<commit_after><|endoftext|>


<commit_before><commit_msg>Fix(Sync): ignore google " " files<commit_after><|endoftext|>


<commit_before><commit_msg>Add `Philosopher` struct<commit_after>struct Philosopher {
    name: String
}

fn main() {

}
<|endoftext|>


<commit_before><commit_msg>Refactor rendering of single ports.<commit_after><|endoftext|>


<commit_before><commit_msg>Add comment to globals.rs<commit_after><|endoftext|>


<commit_before><commit_msg>Add testcase for proper LLVM representation of SIMD types.<commit_after>// Make sure that no 0-sized padding is inserted in structs and that
// structs are represented as expected by Neon intrinsics in LLVM.
// See #87254.

#![crate_type = "lib"]
#![feature(repr_simd)]

#[derive(Copy, Clone, Debug)]
#[repr(simd)]
pub struct int16x4_t(pub i16, pub i16, pub i16, pub i16);

#[derive(Copy, Clone, Debug)]
pub struct int16x4x2_t(pub int16x4_t, pub int16x4_t);
// CHECK: %int16x4x2_t = type { <4 x i16>, <4 x i16> }
<|endoftext|>


<commit_before><commit_msg>Documentation on tray<commit_after><|endoftext|>


<commit_before><commit_msg>Syncfile: tries to parse metadata, but my stinking uuids are truncated<commit_after><|endoftext|>


<commit_before><commit_msg>:art: Implement attachments API<commit_after><|endoftext|>


<commit_before><commit_msg>Publicize SessionStateResponse struct members<commit_after><|endoftext|>


<commit_before><commit_msg>correct fix this time<commit_after><|endoftext|>


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

use errors::{Error, ErrorKind};
use runtest::ProcRes;
use serde_json;
use std::path::Path;
use std::str::FromStr;

// These structs are a subset of the ones found in
// `syntax::json`.

#[derive(Deserialize)]
struct Diagnostic {
    message: String,
    code: Option<DiagnosticCode>,
    level: String,
    spans: Vec<DiagnosticSpan>,
    children: Vec<Diagnostic>,
    rendered: Option<String>,
}

#[derive(Deserialize, Clone)]
struct DiagnosticSpan {
    file_name: String,
    line_start: usize,
    line_end: usize,
    column_start: usize,
    column_end: usize,
    is_primary: bool,
    label: Option<String>,
    suggested_replacement: Option<String>,
    expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
}

impl DiagnosticSpan {
    /// Returns the deepest source span in the macro call stack with a given file name.
    /// This is either the supplied span, or the span for some macro callsite that expanded to it.
    fn first_callsite_in_file(&self, file_name: &str) -> &DiagnosticSpan {
        if self.file_name == file_name {
            self
        } else {
            self.expansion
                .as_ref()
                .map(|origin| origin.span.first_callsite_in_file(file_name))
                .unwrap_or(self)
        }
    }
}

#[derive(Deserialize, Clone)]
struct DiagnosticSpanMacroExpansion {
    /// span where macro was applied to generate this code
    span: DiagnosticSpan,

    /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]")
    macro_decl_name: String,
}

#[derive(Deserialize, Clone)]
struct DiagnosticCode {
    /// The code itself.
    code: String,
    /// An explanation for the code.
    explanation: Option<String>,
}

pub fn extract_rendered(output: &str, proc_res: &ProcRes) -> String {
    output
        .lines()
        .filter_map(|line| {
            if line.starts_with('{') {
                match serde_json::from_str::<Diagnostic>(line) {
                    Ok(diagnostic) => diagnostic.rendered,
                    Err(error) => {
                        proc_res.fatal(Some(&format!(
                            "failed to decode compiler output as json: \
                             `{}`\noutput: {}\nline: {}",
                            error, line, output
                        )));
                    }
                }
            } else {
                None
            }
        })
        .collect()
}

pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
    output
        .lines()
        .flat_map(|line| parse_line(file_name, line, output, proc_res))
        .collect()
}

fn parse_line(file_name: &str, line: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
    // The compiler sometimes intermingles non-JSON stuff into the
    // output.  This hack just skips over such lines. Yuck.
    if line.starts_with('{') {
        match serde_json::from_str::<Diagnostic>(line) {
            Ok(diagnostic) => {
                let mut expected_errors = vec![];
                push_expected_errors(&mut expected_errors, &diagnostic, &[], file_name);
                expected_errors
            }
            Err(error) => {
                proc_res.fatal(Some(&format!(
                    "failed to decode compiler output as json: \
                     `{}`\noutput: {}\nline: {}",
                    error, line, output
                )));
            }
        }
    } else {
        vec![]
    }
}

fn push_expected_errors(
    expected_errors: &mut Vec<Error>,
    diagnostic: &Diagnostic,
    default_spans: &[&DiagnosticSpan],
    file_name: &str,
) {
    // In case of macro expansions, we need to get the span of the callsite
    let spans_info_in_this_file: Vec<_> = diagnostic
        .spans
        .iter()
        .map(|span| (span.is_primary, span.first_callsite_in_file(file_name)))
        .filter(|(_, span)| Path::new(&span.file_name) == Path::new(&file_name))
        .collect();

    let spans_in_this_file: Vec<_> = spans_info_in_this_file.iter()
        .map(|(_, span)| span)
        .collect();

    let primary_spans: Vec<_> = spans_info_in_this_file.iter()
        .filter(|(is_primary, _)| *is_primary)
        .map(|(_, span)| span)
        .take(1) // sometimes we have more than one showing up in the json; pick first
        .cloned()
        .collect();
    let primary_spans = if primary_spans.is_empty() {
        // subdiagnostics often don't have a span of their own;
        // inherit the span from the parent in that case
        default_spans
    } else {
        &primary_spans
    };

    // We break the output into multiple lines, and then append the
    // [E123] to every line in the output. This may be overkill.  The
    // intention was to match existing tests that do things like "//|
    // found `i32` [E123]" and expect to match that somewhere, and yet
    // also ensure that `//~ ERROR E123` *always* works. The
    // assumption is that these multi-line error messages are on their
    // way out anyhow.
    let with_code = |span: &DiagnosticSpan, text: &str| {
        match diagnostic.code {
            Some(ref code) =>
                // FIXME(#33000) -- it'd be better to use a dedicated
                // UI harness than to include the line/col number like
                // this, but some current tests rely on it.
                //
                // Note: Do NOT include the filename. These can easily
                // cause false matches where the expected message
                // appears in the filename, and hence the message
                // changes but the test still passes.
                format!("{}:{}: {}:{}: {} [{}]",
                        span.line_start, span.column_start,
                        span.line_end, span.column_end,
                        text, code.code.clone()),
            None =>
                // FIXME(#33000) -- it'd be better to use a dedicated UI harness
                format!("{}:{}: {}:{}: {}",
                        span.line_start, span.column_start,
                        span.line_end, span.column_end,
                        text),
        }
    };

    // Convert multi-line messages into multiple expected
    // errors. We expect to replace these with something
    // more structured shortly anyhow.
    let mut message_lines = diagnostic.message.lines();
    if let Some(first_line) = message_lines.next() {
        for span in primary_spans {
            let msg = with_code(span, first_line);
            let kind = ErrorKind::from_str(&diagnostic.level).ok();
            expected_errors.push(Error {
                line_num: span.line_start,
                kind,
                msg,
            });
        }
    }
    for next_line in message_lines {
        for span in primary_spans {
            expected_errors.push(Error {
                line_num: span.line_start,
                kind: None,
                msg: with_code(span, next_line),
            });
        }
    }

    // If the message has a suggestion, register that.
    for span in primary_spans {
        if let Some(ref suggested_replacement) = span.suggested_replacement {
            for (index, line) in suggested_replacement.lines().enumerate() {
                expected_errors.push(Error {
                    line_num: span.line_start + index,
                    kind: Some(ErrorKind::Suggestion),
                    msg: line.to_string(),
                });
            }
        }
    }

    // Add notes for the backtrace
    for span in primary_spans {
        for frame in &span.expansion {
            push_backtrace(expected_errors, frame, file_name);
        }
    }

    // Add notes for any labels that appear in the message.
    for span in spans_in_this_file
        .iter()
        .filter(|span| span.label.is_some())
    {
        expected_errors.push(Error {
            line_num: span.line_start,
            kind: Some(ErrorKind::Note),
            msg: span.label.clone().unwrap(),
        });
    }

    // Flatten out the children.
    for child in &diagnostic.children {
        push_expected_errors(expected_errors, child, primary_spans, file_name);
    }
}

fn push_backtrace(
    expected_errors: &mut Vec<Error>,
    expansion: &DiagnosticSpanMacroExpansion,
    file_name: &str,
) {
    if Path::new(&expansion.span.file_name) == Path::new(&file_name) {
        expected_errors.push(Error {
            line_num: expansion.span.line_start,
            kind: Some(ErrorKind::Note),
            msg: format!("in this expansion of {}", expansion.macro_decl_name),
        });
    }

    for previous_expansion in &expansion.span.expansion {
        push_backtrace(expected_errors, previous_expansion, file_name);
    }
}
<commit_msg>Fix compiletest JSON error message<commit_after>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use errors::{Error, ErrorKind};
use runtest::ProcRes;
use serde_json;
use std::path::Path;
use std::str::FromStr;

// These structs are a subset of the ones found in
// `syntax::json`.

#[derive(Deserialize)]
struct Diagnostic {
    message: String,
    code: Option<DiagnosticCode>,
    level: String,
    spans: Vec<DiagnosticSpan>,
    children: Vec<Diagnostic>,
    rendered: Option<String>,
}

#[derive(Deserialize, Clone)]
struct DiagnosticSpan {
    file_name: String,
    line_start: usize,
    line_end: usize,
    column_start: usize,
    column_end: usize,
    is_primary: bool,
    label: Option<String>,
    suggested_replacement: Option<String>,
    expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
}

impl DiagnosticSpan {
    /// Returns the deepest source span in the macro call stack with a given file name.
    /// This is either the supplied span, or the span for some macro callsite that expanded to it.
    fn first_callsite_in_file(&self, file_name: &str) -> &DiagnosticSpan {
        if self.file_name == file_name {
            self
        } else {
            self.expansion
                .as_ref()
                .map(|origin| origin.span.first_callsite_in_file(file_name))
                .unwrap_or(self)
        }
    }
}

#[derive(Deserialize, Clone)]
struct DiagnosticSpanMacroExpansion {
    /// span where macro was applied to generate this code
    span: DiagnosticSpan,

    /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]")
    macro_decl_name: String,
}

#[derive(Deserialize, Clone)]
struct DiagnosticCode {
    /// The code itself.
    code: String,
    /// An explanation for the code.
    explanation: Option<String>,
}

pub fn extract_rendered(output: &str, proc_res: &ProcRes) -> String {
    output
        .lines()
        .filter_map(|line| {
            if line.starts_with('{') {
                match serde_json::from_str::<Diagnostic>(line) {
                    Ok(diagnostic) => diagnostic.rendered,
                    Err(error) => {
                        proc_res.fatal(Some(&format!(
                            "failed to decode compiler output as json: \
                             `{}`\nline: {}\noutput: {}",
                            error, line, output
                        )));
                    }
                }
            } else {
                None
            }
        })
        .collect()
}

pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
    output
        .lines()
        .flat_map(|line| parse_line(file_name, line, output, proc_res))
        .collect()
}

fn parse_line(file_name: &str, line: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
    // The compiler sometimes intermingles non-JSON stuff into the
    // output.  This hack just skips over such lines. Yuck.
    if line.starts_with('{') {
        match serde_json::from_str::<Diagnostic>(line) {
            Ok(diagnostic) => {
                let mut expected_errors = vec![];
                push_expected_errors(&mut expected_errors, &diagnostic, &[], file_name);
                expected_errors
            }
            Err(error) => {
                proc_res.fatal(Some(&format!(
                    "failed to decode compiler output as json: \
                     `{}`\nline: {}\noutput: {}",
                    error, line, output
                )));
            }
        }
    } else {
        vec![]
    }
}

fn push_expected_errors(
    expected_errors: &mut Vec<Error>,
    diagnostic: &Diagnostic,
    default_spans: &[&DiagnosticSpan],
    file_name: &str,
) {
    // In case of macro expansions, we need to get the span of the callsite
    let spans_info_in_this_file: Vec<_> = diagnostic
        .spans
        .iter()
        .map(|span| (span.is_primary, span.first_callsite_in_file(file_name)))
        .filter(|(_, span)| Path::new(&span.file_name) == Path::new(&file_name))
        .collect();

    let spans_in_this_file: Vec<_> = spans_info_in_this_file.iter()
        .map(|(_, span)| span)
        .collect();

    let primary_spans: Vec<_> = spans_info_in_this_file.iter()
        .filter(|(is_primary, _)| *is_primary)
        .map(|(_, span)| span)
        .take(1) // sometimes we have more than one showing up in the json; pick first
        .cloned()
        .collect();
    let primary_spans = if primary_spans.is_empty() {
        // subdiagnostics often don't have a span of their own;
        // inherit the span from the parent in that case
        default_spans
    } else {
        &primary_spans
    };

    // We break the output into multiple lines, and then append the
    // [E123] to every line in the output. This may be overkill.  The
    // intention was to match existing tests that do things like "//|
    // found `i32` [E123]" and expect to match that somewhere, and yet
    // also ensure that `//~ ERROR E123` *always* works. The
    // assumption is that these multi-line error messages are on their
    // way out anyhow.
    let with_code = |span: &DiagnosticSpan, text: &str| {
        match diagnostic.code {
            Some(ref code) =>
                // FIXME(#33000) -- it'd be better to use a dedicated
                // UI harness than to include the line/col number like
                // this, but some current tests rely on it.
                //
                // Note: Do NOT include the filename. These can easily
                // cause false matches where the expected message
                // appears in the filename, and hence the message
                // changes but the test still passes.
                format!("{}:{}: {}:{}: {} [{}]",
                        span.line_start, span.column_start,
                        span.line_end, span.column_end,
                        text, code.code.clone()),
            None =>
                // FIXME(#33000) -- it'd be better to use a dedicated UI harness
                format!("{}:{}: {}:{}: {}",
                        span.line_start, span.column_start,
                        span.line_end, span.column_end,
                        text),
        }
    };

    // Convert multi-line messages into multiple expected
    // errors. We expect to replace these with something
    // more structured shortly anyhow.
    let mut message_lines = diagnostic.message.lines();
    if let Some(first_line) = message_lines.next() {
        for span in primary_spans {
            let msg = with_code(span, first_line);
            let kind = ErrorKind::from_str(&diagnostic.level).ok();
            expected_errors.push(Error {
                line_num: span.line_start,
                kind,
                msg,
            });
        }
    }
    for next_line in message_lines {
        for span in primary_spans {
            expected_errors.push(Error {
                line_num: span.line_start,
                kind: None,
                msg: with_code(span, next_line),
            });
        }
    }

    // If the message has a suggestion, register that.
    for span in primary_spans {
        if let Some(ref suggested_replacement) = span.suggested_replacement {
            for (index, line) in suggested_replacement.lines().enumerate() {
                expected_errors.push(Error {
                    line_num: span.line_start + index,
                    kind: Some(ErrorKind::Suggestion),
                    msg: line.to_string(),
                });
            }
        }
    }

    // Add notes for the backtrace
    for span in primary_spans {
        for frame in &span.expansion {
            push_backtrace(expected_errors, frame, file_name);
        }
    }

    // Add notes for any labels that appear in the message.
    for span in spans_in_this_file
        .iter()
        .filter(|span| span.label.is_some())
    {
        expected_errors.push(Error {
            line_num: span.line_start,
            kind: Some(ErrorKind::Note),
            msg: span.label.clone().unwrap(),
        });
    }

    // Flatten out the children.
    for child in &diagnostic.children {
        push_expected_errors(expected_errors, child, primary_spans, file_name);
    }
}

fn push_backtrace(
    expected_errors: &mut Vec<Error>,
    expansion: &DiagnosticSpanMacroExpansion,
    file_name: &str,
) {
    if Path::new(&expansion.span.file_name) == Path::new(&file_name) {
        expected_errors.push(Error {
            line_num: expansion.span.line_start,
            kind: Some(ErrorKind::Note),
            msg: format!("in this expansion of {}", expansion.macro_decl_name),
        });
    }

    for previous_expansion in &expansion.span.expansion {
        push_backtrace(expected_errors, previous_expansion, file_name);
    }
}
<|endoftext|>


<commit_before><commit_msg>Ignore display enable bit set if display is already enabled<commit_after><|endoftext|>


<commit_before><commit_msg>SYNC_* constants should be unsigned (to reflect usage).<commit_after><|endoftext|>


<commit_before><commit_msg>[No-auto] bin/core/grep: Fix Clippy warnings<commit_after><|endoftext|>


<commit_before><commit_msg>bench: Add tests for access functions<commit_after>#![feature(test)]

extern crate test;
extern crate rle_vec;

use std::iter::FromIterator;
use std::iter::repeat;
use test::Bencher;
use rle_vec::RleVec;

#[bench]
fn rle_loop_10_000_unique_values(b: &mut Bencher) {
    let rle = RleVec::from_iter(0..10_000);
    b.iter(|| {
        for (i, v) in rle.iter().enumerate() {
            assert_eq!(i, *v);
        }
    })
}

#[bench]
fn vec_loop_10_000_unique_values(b: &mut Bencher) {
    let vec = Vec::from_iter(0..10_000);
    b.iter(|| {
        for (i, v) in vec.iter().enumerate() {
            assert_eq!(i, *v);
        }
    })
}

#[bench]
fn rle_loop_10_000_equal_values(b: &mut Bencher) {
    let rle = RleVec::from_iter(repeat(0).take(10_000));
    b.iter(|| {
        for v in rle.iter() {
            assert_eq!(*v, 0);
        }
    })
}

#[bench]
fn vec_loop_10_000_equal_values(b: &mut Bencher) {
    let vec = Vec::from_iter(repeat(0).take(10_000));
    b.iter(|| {
        for v in vec.iter() {
            assert_eq!(*v, 0);
        }
    })
}

#[bench]
fn rle_loop_10_000_runs_of_10_values(b: &mut Bencher) {
    let zeros = repeat(0).take(10);
    let ones = repeat(1).take(10);
    let iter = repeat(zeros.chain(ones)).flat_map(|x| x).take(10_000);

    let rle = RleVec::from_iter(iter);
    b.iter(|| {
        for v in rle.iter() {
            assert!(*v == 0 || *v == 1); // ugly
        }
    })
}

#[bench]
fn vec_loop_10_000_runs_of_10_values(b: &mut Bencher) {
    let zeros = repeat(0).take(10);
    let ones = repeat(1).take(10);
    let iter = repeat(zeros.chain(ones)).flat_map(|x| x).take(10_000);

    let vec = Vec::from_iter(iter);
    b.iter(|| {
        for v in vec.iter() {
            assert!(*v == 0 || *v == 1); // ugly
        }
    })
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Common handling of keyboard input and state management for text input controls

use dom::bindings::codegen::Bindings::KeyboardEventBinding::KeyboardEventMethods;
use dom::bindings::js::JSRef;
use dom::keyboardevent::KeyboardEvent;
use servo_util::str::DOMString;

use std::cmp::{min, max};
use std::default::Default;

#[jstraceable]
struct TextPoint {
    /// 0-based line number
    line: uint,
    /// 0-based column number
    index: uint,
}

/// Encapsulated state for handling keyboard input in a single or multiline text input control.
#[jstraceable]
pub struct TextInput {
    /// Current text input content, split across lines without trailing '\n'
    lines: Vec<DOMString>,
    /// Current cursor input point
    edit_point: TextPoint,
    /// Selection range, beginning and end point that can span multiple lines.
    _selection: Option<(TextPoint, TextPoint)>,
    /// Is this a multiline input?
    multiline: bool,
}

/// Resulting action to be taken by the owner of a text input that is handling an event.
pub enum KeyReaction {
    TriggerDefaultAction,
    DispatchInput,
    Nothing,
}

impl Default for TextPoint {
    fn default() -> TextPoint {
        TextPoint {
            line: 0,
            index: 0,
        }
    }
}

/// Control whether this control should allow multiple lines.
#[deriving(PartialEq)]
pub enum Lines {
    Single,
    Multiple,
}

/// The direction in which to delete a character.
#[deriving(PartialEq)]
enum DeleteDir {
    Forward,
    Backward
}

impl TextInput {
    /// Instantiate a new text input control
    pub fn new(lines: Lines, initial: DOMString) -> TextInput {
        let mut i = TextInput {
            lines: vec!(),
            edit_point: Default::default(),
            _selection: None,
            multiline: lines == Multiple,
        };
        i.set_content(initial);
        i
    }

    /// Return the current line under the editing point
    fn get_current_line(&self) -> &DOMString {
        &self.lines[self.edit_point.line]
    }

    /// Insert a character at the current editing point
    fn insert_char(&mut self, ch: char) {
        //TODO: handle replacing selection with character
        let new_line = {
            let prefix = self.get_current_line().as_slice().slice_chars(0, self.edit_point.index);
            let suffix = self.get_current_line().as_slice().slice_chars(self.edit_point.index,
                                                                        self.current_line_length());
            let mut new_line = prefix.to_string();
            new_line.push(ch);
            new_line.push_str(suffix.as_slice());
            new_line
        };

        self.lines[self.edit_point.line] = new_line;
        self.edit_point.index += 1;
    }

    /// Remove a character at the current editing point
    fn delete_char(&mut self, dir: DeleteDir) {
        let forward = dir == Forward;

        //TODO: handle deleting selection
        let prefix_end = if forward {
            self.edit_point.index
        } else {
            if self.multiline {
                //TODO: handle backspacing from position 0 of current line
                if self.edit_point.index == 0 {
                    return;
                }
            } else if self.edit_point.index == 0 {
                return;
            }
            self.edit_point.index - 1
        };
        let suffix_start = if forward {
            let is_eol = self.edit_point.index == self.current_line_length() - 1;
            if self.multiline {
                //TODO: handle deleting from end position of current line
                if is_eol {
                    return;
                }
            } else if is_eol {
                return;
            }
            self.edit_point.index + 1
        } else {
            self.edit_point.index
        };

        let new_line = {
            let prefix = self.get_current_line().as_slice().slice_chars(0, prefix_end);
            let suffix = self.get_current_line().as_slice().slice_chars(suffix_start,
                                                                        self.current_line_length());
            let mut new_line = prefix.to_string();
            new_line.push_str(suffix);
            new_line
        };

        self.lines[self.edit_point.line] = new_line;

        if !forward {
            self.adjust_horizontal(-1);
        }
    }

    /// Return the length of the current line under the editing point.
    fn current_line_length(&self) -> uint {
        self.lines[self.edit_point.line].len()
    }

    /// Adjust the editing point position by a given of lines. The resulting column is
    /// as close to the original column position as possible.
    fn adjust_vertical(&mut self, adjust: int) {
        if !self.multiline {
            return;
        }

        if adjust < 0 && self.edit_point.line as int + adjust < 0 {
            self.edit_point.index = 0;
            self.edit_point.line = 0;
            return;
        } else if adjust > 0 && self.edit_point.line >= min(0, self.lines.len() - adjust as uint) {
            self.edit_point.index = self.current_line_length();
            self.edit_point.line = self.lines.len() - 1;
            return;
        }

        self.edit_point.line = (self.edit_point.line as int + adjust) as uint;
        self.edit_point.index = min(self.current_line_length(), self.edit_point.index);
    }

    /// Adjust the editing point position by a given number of columns. If the adjustment
    /// requested is larger than is available in the current line, the editing point is
    /// adjusted vertically and the process repeats with the remaining adjustment requested.
    fn adjust_horizontal(&mut self, adjust: int) {
        if adjust < 0 {
            if self.multiline {
                let remaining = self.edit_point.index;
                if adjust.abs() as uint > remaining {
                    self.edit_point.index = 0;
                    self.adjust_vertical(-1);
                    self.edit_point.index = self.current_line_length();
                    self.adjust_horizontal(adjust + remaining as int);
                } else {
                    self.edit_point.index = (self.edit_point.index as int + adjust) as uint;
                }
            } else {
                self.edit_point.index = max(0, self.edit_point.index as int + adjust) as uint;
            }
        } else {
            if self.multiline {
                let remaining = self.current_line_length() - self.edit_point.index;
                if adjust as uint > remaining {
                    self.edit_point.index = 0;
                    self.adjust_vertical(1);
                    self.adjust_horizontal(adjust - remaining as int);
                } else {
                    self.edit_point.index += adjust as uint;
                }
            } else {
                self.edit_point.index = min(self.current_line_length(),
                                            self.edit_point.index + adjust as uint);
            }
        }
    }

    /// Deal with a newline input.
    fn handle_return(&mut self) -> KeyReaction {
        if !self.multiline {
            return TriggerDefaultAction;
        }

        //TODO: support replacing selection with newline
        let prefix = self.get_current_line().as_slice().slice_chars(0, self.edit_point.index).to_string();
        let suffix = self.get_current_line().as_slice().slice_chars(self.edit_point.index,
                                                                    self.current_line_length()).to_string();
        self.lines[self.edit_point.line] = prefix;
        self.lines.insert(self.edit_point.line + 1, suffix);
        return DispatchInput;
    }

    /// Process a given `KeyboardEvent` and return an action for the caller to execute.
    pub fn handle_keydown(&mut self, event: JSRef<KeyboardEvent>) -> KeyReaction {
        match event.Key().as_slice() {
            // printable characters have single-character key values
            c if c.len() == 1 => {
                self.insert_char(c.char_at(0));
                return DispatchInput;
            }
            "Space" => {
                self.insert_char(' ');
                DispatchInput
            }
            "Delete" => {
                self.delete_char(Forward);
                DispatchInput
            }
            "Backspace" => {
                self.delete_char(Backward);
                DispatchInput
            }
            "ArrowLeft" => {
                self.adjust_horizontal(-1);
                Nothing
            }
            "ArrowRight" => {
                self.adjust_horizontal(1);
                Nothing
            }
            "ArrowUp" => {
                self.adjust_vertical(-1);
                Nothing
            }
            "ArrowDown" => {
                self.adjust_vertical(1);
                Nothing
            }
            "Enter" => self.handle_return(),
            "Home" => {
                self.edit_point.index = 0;
                Nothing
            }
            "End" => {
                self.edit_point.index = self.current_line_length();
                Nothing
            }
            "Tab" => TriggerDefaultAction,
            _ => Nothing,
        }
    }

    /// Get the current contents of the text input. Multiple lines are joined by \n.
    pub fn get_content(&self) -> DOMString {
        let mut content = "".to_string();
        for (i, line) in self.lines.iter().enumerate() {
            content.push_str(line.as_slice());
            if i < self.lines.len() - 1 {
                content.push('\n');
            }
        }
        content
    }

    /// Set the current contents of the text input. If this is control supports multiple lines,
    /// any \n encountered will be stripped and force a new logical line.
    pub fn set_content(&mut self, content: DOMString) {
        self.lines = if self.multiline {
            content.as_slice().split('\n').map(|s| s.to_string()).collect()
        } else {
            vec!(content)
        };
        self.edit_point.line = min(self.edit_point.line, self.lines.len() - 1);
        self.edit_point.index = min(self.edit_point.index, self.current_line_length() - 1);
    }
}
<commit_msg>allow deleting last char<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Common handling of keyboard input and state management for text input controls

use dom::bindings::codegen::Bindings::KeyboardEventBinding::KeyboardEventMethods;
use dom::bindings::js::JSRef;
use dom::keyboardevent::KeyboardEvent;
use servo_util::str::DOMString;

use std::cmp::{min, max};
use std::default::Default;

#[jstraceable]
struct TextPoint {
    /// 0-based line number
    line: uint,
    /// 0-based column number
    index: uint,
}

/// Encapsulated state for handling keyboard input in a single or multiline text input control.
#[jstraceable]
pub struct TextInput {
    /// Current text input content, split across lines without trailing '\n'
    lines: Vec<DOMString>,
    /// Current cursor input point
    edit_point: TextPoint,
    /// Selection range, beginning and end point that can span multiple lines.
    _selection: Option<(TextPoint, TextPoint)>,
    /// Is this a multiline input?
    multiline: bool,
}

/// Resulting action to be taken by the owner of a text input that is handling an event.
pub enum KeyReaction {
    TriggerDefaultAction,
    DispatchInput,
    Nothing,
}

impl Default for TextPoint {
    fn default() -> TextPoint {
        TextPoint {
            line: 0,
            index: 0,
        }
    }
}

/// Control whether this control should allow multiple lines.
#[deriving(PartialEq)]
pub enum Lines {
    Single,
    Multiple,
}

/// The direction in which to delete a character.
#[deriving(PartialEq)]
enum DeleteDir {
    Forward,
    Backward
}

impl TextInput {
    /// Instantiate a new text input control
    pub fn new(lines: Lines, initial: DOMString) -> TextInput {
        let mut i = TextInput {
            lines: vec!(),
            edit_point: Default::default(),
            _selection: None,
            multiline: lines == Multiple,
        };
        i.set_content(initial);
        i
    }

    /// Return the current line under the editing point
    fn get_current_line(&self) -> &DOMString {
        &self.lines[self.edit_point.line]
    }

    /// Insert a character at the current editing point
    fn insert_char(&mut self, ch: char) {
        //TODO: handle replacing selection with character
        let new_line = {
            let prefix = self.get_current_line().as_slice().slice_chars(0, self.edit_point.index);
            let suffix = self.get_current_line().as_slice().slice_chars(self.edit_point.index,
                                                                        self.current_line_length());
            let mut new_line = prefix.to_string();
            new_line.push(ch);
            new_line.push_str(suffix.as_slice());
            new_line
        };

        self.lines[self.edit_point.line] = new_line;
        self.edit_point.index += 1;
    }

    /// Remove a character at the current editing point
    fn delete_char(&mut self, dir: DeleteDir) {
        let forward = dir == Forward;

        //TODO: handle deleting selection
        let prefix_end = if forward {
            self.edit_point.index
        } else {
            if self.multiline {
                //TODO: handle backspacing from position 0 of current line
                if self.edit_point.index == 0 {
                    return;
                }
            } else if self.edit_point.index == 0 {
                return;
            }
            self.edit_point.index - 1
        };
        let suffix_start = if forward {
            let is_eol = self.edit_point.index == self.current_line_length();
            if self.multiline {
                //TODO: handle deleting from end position of current line
                if is_eol {
                    return;
                }
            } else if is_eol {
                return;
            }
            self.edit_point.index + 1
        } else {
            self.edit_point.index
        };

        let new_line = {
            let prefix = self.get_current_line().as_slice().slice_chars(0, prefix_end);
            let suffix = self.get_current_line().as_slice().slice_chars(suffix_start,
                                                                        self.current_line_length());
            let mut new_line = prefix.to_string();
            new_line.push_str(suffix);
            new_line
        };

        self.lines[self.edit_point.line] = new_line;

        if !forward {
            self.adjust_horizontal(-1);
        }
    }

    /// Return the length of the current line under the editing point.
    fn current_line_length(&self) -> uint {
        self.lines[self.edit_point.line].len()
    }

    /// Adjust the editing point position by a given of lines. The resulting column is
    /// as close to the original column position as possible.
    fn adjust_vertical(&mut self, adjust: int) {
        if !self.multiline {
            return;
        }

        if adjust < 0 && self.edit_point.line as int + adjust < 0 {
            self.edit_point.index = 0;
            self.edit_point.line = 0;
            return;
        } else if adjust > 0 && self.edit_point.line >= min(0, self.lines.len() - adjust as uint) {
            self.edit_point.index = self.current_line_length();
            self.edit_point.line = self.lines.len() - 1;
            return;
        }

        self.edit_point.line = (self.edit_point.line as int + adjust) as uint;
        self.edit_point.index = min(self.current_line_length(), self.edit_point.index);
    }

    /// Adjust the editing point position by a given number of columns. If the adjustment
    /// requested is larger than is available in the current line, the editing point is
    /// adjusted vertically and the process repeats with the remaining adjustment requested.
    fn adjust_horizontal(&mut self, adjust: int) {
        if adjust < 0 {
            if self.multiline {
                let remaining = self.edit_point.index;
                if adjust.abs() as uint > remaining {
                    self.edit_point.index = 0;
                    self.adjust_vertical(-1);
                    self.edit_point.index = self.current_line_length();
                    self.adjust_horizontal(adjust + remaining as int);
                } else {
                    self.edit_point.index = (self.edit_point.index as int + adjust) as uint;
                }
            } else {
                self.edit_point.index = max(0, self.edit_point.index as int + adjust) as uint;
            }
        } else {
            if self.multiline {
                let remaining = self.current_line_length() - self.edit_point.index;
                if adjust as uint > remaining {
                    self.edit_point.index = 0;
                    self.adjust_vertical(1);
                    self.adjust_horizontal(adjust - remaining as int);
                } else {
                    self.edit_point.index += adjust as uint;
                }
            } else {
                self.edit_point.index = min(self.current_line_length(),
                                            self.edit_point.index + adjust as uint);
            }
        }
    }

    /// Deal with a newline input.
    fn handle_return(&mut self) -> KeyReaction {
        if !self.multiline {
            return TriggerDefaultAction;
        }

        //TODO: support replacing selection with newline
        let prefix = self.get_current_line().as_slice().slice_chars(0, self.edit_point.index).to_string();
        let suffix = self.get_current_line().as_slice().slice_chars(self.edit_point.index,
                                                                    self.current_line_length()).to_string();
        self.lines[self.edit_point.line] = prefix;
        self.lines.insert(self.edit_point.line + 1, suffix);
        return DispatchInput;
    }

    /// Process a given `KeyboardEvent` and return an action for the caller to execute.
    pub fn handle_keydown(&mut self, event: JSRef<KeyboardEvent>) -> KeyReaction {
        match event.Key().as_slice() {
            // printable characters have single-character key values
            c if c.len() == 1 => {
                self.insert_char(c.char_at(0));
                return DispatchInput;
            }
            "Space" => {
                self.insert_char(' ');
                DispatchInput
            }
            "Delete" => {
                self.delete_char(Forward);
                DispatchInput
            }
            "Backspace" => {
                self.delete_char(Backward);
                DispatchInput
            }
            "ArrowLeft" => {
                self.adjust_horizontal(-1);
                Nothing
            }
            "ArrowRight" => {
                self.adjust_horizontal(1);
                Nothing
            }
            "ArrowUp" => {
                self.adjust_vertical(-1);
                Nothing
            }
            "ArrowDown" => {
                self.adjust_vertical(1);
                Nothing
            }
            "Enter" => self.handle_return(),
            "Home" => {
                self.edit_point.index = 0;
                Nothing
            }
            "End" => {
                self.edit_point.index = self.current_line_length();
                Nothing
            }
            "Tab" => TriggerDefaultAction,
            _ => Nothing,
        }
    }

    /// Get the current contents of the text input. Multiple lines are joined by \n.
    pub fn get_content(&self) -> DOMString {
        let mut content = "".to_string();
        for (i, line) in self.lines.iter().enumerate() {
            content.push_str(line.as_slice());
            if i < self.lines.len() - 1 {
                content.push('\n');
            }
        }
        content
    }

    /// Set the current contents of the text input. If this is control supports multiple lines,
    /// any \n encountered will be stripped and force a new logical line.
    pub fn set_content(&mut self, content: DOMString) {
        self.lines = if self.multiline {
            content.as_slice().split('\n').map(|s| s.to_string()).collect()
        } else {
            vec!(content)
        };
        self.edit_point.line = min(self.edit_point.line, self.lines.len() - 1);
        self.edit_point.index = min(self.edit_point.index, self.current_line_length() - 1);
    }
}
<|endoftext|>


<commit_before>#![feature(owned_ascii_ext)]

#[macro_use(log)]
extern crate logger;
extern crate rand;
extern crate time;
extern crate util;

use std::ascii::OwnedAsciiExt;
use std::collections::HashMap;
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use std::io::Error as IOError;
use std::io::Write;
use std::num::ParseIntError;
use std::path::Path;
use std::str::from_utf8;
use std::str::FromStr;
use std::str::Utf8Error;

use util::splitargs;
use logger::{Logger, Level};

pub struct Config {
    pub logger: Logger,
    pub daemonize: bool,
    pub databases: u8,
    pub pidfile: String,
    pub bind: Vec<String>,
    pub port: u16,
    pub tcp_keepalive: u32,
    pub active_rehashing: bool,
    pub set_max_intset_entries: usize,
    pub timeout: u64,
    pub unixsocket: Option<String>,
    pub unixsocketperm: u32,
    pub rename_commands: HashMap<String, Option<String>>,
    pub requirepass: Option<String>,
    pub tcp_backlog: i32,
    pub syslog_enabled: bool,
    pub syslog_ident: String,
    pub syslog_facility: String,
}

#[derive(Debug)]
pub enum ConfigError {
    InvalidFormat,
    InvalidParameter,
    IOError(IOError),
    FileNotFound,
}

fn read_string(args: Vec<Vec<u8>>) -> Result<String, ConfigError> {
    if args.len() != 2 {
        Err(ConfigError::InvalidFormat)
    } else {
        Ok(try!(from_utf8(&*args[1])).to_owned())
    }
}

fn read_parse<T>(args: Vec<Vec<u8>>) -> Result<T, ConfigError>
        where T: FromStr {
    let s = try!(read_string(args));
    match s.parse() {
        Ok(f) => Ok(f),
        Err(_) => Err(ConfigError::InvalidParameter),
    }
}

fn read_bool(args: Vec<Vec<u8>>) -> Result<bool, ConfigError> {
    Ok(match &*try!(read_string(args)) {
        "yes" => true,
        "no" => false,
        _ => return Err(ConfigError::InvalidFormat),
    })
}

impl Config {
    pub fn mock(port: u16, logger: Logger) -> Config {
        Config {
            logger: logger,
            active_rehashing: true,
            daemonize: false,
            databases: 16,
            pidfile: "/var/run/sredis.pid".to_owned(),
            bind: vec!["127.0.0.1".to_owned()],
            port: port,
            tcp_keepalive: 0,
            set_max_intset_entries: 512,
            timeout: 0,
            unixsocket: None,
            unixsocketperm: 0700,
            rename_commands: HashMap::new(),
            requirepass: None,
            tcp_backlog: 511,
            syslog_enabled: false,
            syslog_ident: "rsedis".to_owned(),
            syslog_facility: "local0".to_owned(),
        }
    }

    pub fn new(logger: Logger) -> Config {
        Config {
            logger: logger,
            active_rehashing: true,
            daemonize: false,
            databases: 16,
            pidfile: "/var/run/sredis.pid".to_owned(),
            bind: vec![],
            port: 6379,
            tcp_keepalive: 0,
            set_max_intset_entries: 512,
            timeout: 0,
            unixsocket: None,
            unixsocketperm: 0700,
            rename_commands: HashMap::new(),
            requirepass: None,
            tcp_backlog: 511,
            syslog_enabled: false,
            syslog_ident: "rsedis".to_owned(),
            syslog_facility: "local0".to_owned(),
        }
    }

    pub fn parsefile(&mut self, fname: String) -> Result<(), ConfigError> {
        let path = Path::new(&*fname);
        let file = BufReader::new(match File::open(&path) {
            Ok(f) => f,
            Err(_) => {
                log!(self.logger, Warning, "Fatal error, can't open config file '{}'", fname);
                return Err(ConfigError::FileNotFound);
            }
        });
        for line_iter in file.lines() {
            let lline = try!(line_iter);
            let line = lline.trim();
            if line.starts_with("#") {
                continue;
            }

            let args = match splitargs(line.as_bytes()) {
                Ok(args) => args,
                Err(_) => return Err(ConfigError::InvalidFormat),
            };

            if args.len() == 0 {
                continue;
            }

            match &*args[0] {
                b"bind" => self.bind.extend(args[1..].iter().filter(|x| x.len() > 0).map(|x| match from_utf8(x) {
                            Ok(s) => s.to_owned(),
                            Err(_) => "".to_owned(), // TODO: return ConfigError
                            })),
                b"port" => self.port = try!(read_parse(args)),
                b"activerehashing" => self.active_rehashing = try!(read_bool(args)),
                b"daemonize" => self.daemonize = try!(read_bool(args)),
                b"databases" => self.databases = try!(read_parse(args)),
                b"tcp-keepalive" => self.tcp_keepalive = try!(read_parse(args)),
                b"set-max-intset-entries" => self.set_max_intset_entries = try!(read_parse(args)),
                b"timeout" => self.timeout = try!(read_parse(args)),
                b"unixsocket" => self.unixsocket = Some(try!(read_string(args)).to_owned()),
                b"unixsocketperm" => self.unixsocketperm = try!(u32::from_str_radix(&*try!(read_string(args)), 8)),
                b"pidfile" => self.pidfile = try!(read_string(args)).to_owned(),
                b"logfile" => {
                    let logfile = try!(read_string(args));
                    if logfile.len() > 0 {
                        try!(self.logger.set_logfile(&*logfile))
                    }
                },
                b"loglevel" => self.logger.set_loglevel(match &*try!(read_string(args)) {
                    "debug" => Level::Debug,
                    "verbose" => Level::Verbose,
                    "notice" => Level::Notice,
                    "warning" => Level::Warning,
                    _ => return Err(ConfigError::InvalidParameter),
                }),
                b"rename-command" => {
                    if args.len() != 3 {
                        return Err(ConfigError::InvalidFormat)
                    } else {
                        let command = try!(from_utf8(&*args[1])).to_owned();
                        let newname = try!(from_utf8(&*args[2])).to_owned();
                        if newname.len() > 0 {
                            self.rename_commands.insert(newname.into_ascii_lowercase(), Some(command.clone().into_ascii_lowercase()));
                        }
                        self.rename_commands.insert(command.into_ascii_lowercase(), None);
                    }
                },
                b"requirepass" => self.requirepass = Some(try!(read_string(args)).to_owned()),
                b"tcp-backlog" => self.tcp_backlog = try!(read_parse(args)),
                b"syslog-enabled" => self.syslog_enabled = try!(read_bool(args)),
                b"syslog-ident" => self.syslog_ident = try!(read_string(args)).to_owned(),
                b"syslog-facility" => self.syslog_facility = try!(read_string(args)).to_owned(),
                b"include" => if args.len() != 2 {
                    return Err(ConfigError::InvalidFormat)
                } else {
                    try!(self.parsefile(try!(from_utf8(&*args[1])).to_owned()));
                },
                _ => writeln!(&mut std::io::stderr(), "Unknown configuration {:?}", line).unwrap(),
            };
        }
        if self.syslog_enabled {
            self.logger.set_syslog(&self.syslog_ident, &self.syslog_facility);
        }

        Ok(())
    }

    pub fn addresses(&self) -> Vec<(String, u16)> {
        if self.bind.len() == 0 {
            vec![("127.0.0.1".to_owned(), self.port)]
        } else {
            self.bind.iter().map(|s| (s.clone(), self.port)).collect::<Vec<_>>()
        }
    }
}

impl From<IOError> for ConfigError {
    fn from(e: IOError) -> ConfigError { ConfigError::IOError(e) }
}

impl From<ParseIntError> for ConfigError {
    fn from(_: ParseIntError) -> ConfigError { ConfigError::InvalidParameter }
}

impl From<Utf8Error> for ConfigError {
    fn from(_: Utf8Error) -> ConfigError { ConfigError::InvalidParameter }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::HashMap;
    use std::fs::File;
    use std::fs::create_dir;
    use std::io::Write;

    use rand::random;

    use logger::{Logger, Level};
    use util::mstime;

    macro_rules! config {
        ($str: expr, $logger: expr) => ({
            let dirpath = format!("tmp/{}", mstime());
            let filepath = format!("{}/{}.conf", dirpath, random::<u64>());
            match create_dir("tmp") { _ => () }
            match create_dir(dirpath) { _ => () }
            match File::create(filepath.clone()).unwrap().write_all($str) { _ => () }
            let mut config = Config::new($logger);
            config.parsefile(filepath).unwrap();
            config
        })
    }

    #[test]
    fn parse_bind() {
        let config = config!(b"bind 1.2.3.4\nbind 5.6.7.8", Logger::new(Level::Warning));
        assert_eq!(config.bind, vec!["1.2.3.4", "5.6.7.8"]);
        assert_eq!(config.port, 6379);
    }

    #[test]
    fn parse_port() {
        let config = config!(b"port 12345", Logger::new(Level::Warning));
        assert_eq!(config.port, 12345);
        assert_eq!(config.addresses(), vec![("127.0.0.1".to_owned(), 12345)]);
    }

    #[test]
    fn parse_bind_port() {
        let config = config!(b"bind 127.0.0.1\nport 12345", Logger::new(Level::Warning));
        assert_eq!(config.bind, vec!["127.0.0.1"]);
        assert_eq!(config.port, 12345);
    }

    #[test]
    fn parse_daemonize_yes() {
        let config = config!(b"daemonize yes", Logger::new(Level::Warning));
        assert!(config.daemonize);
    }

    #[test]
    fn parse_daemonize_no() {
        let config = config!(b"daemonize no", Logger::new(Level::Warning));
        assert!(!config.daemonize);
    }

    #[test]
    fn parse_active_rehashing_yes() {
        let config = config!(b"activerehashing yes", Logger::new(Level::Warning));
        assert!(config.active_rehashing);
    }

    #[test]
    fn parse_active_rehashing_no() {
        let config = config!(b"activerehashing no", Logger::new(Level::Warning));
        assert!(!config.active_rehashing);
    }

    #[test]
    fn parse_databases() {
        let config = config!(b"databases 20", Logger::new(Level::Warning));
        assert_eq!(config.databases, 20);
    }

    #[test]
    fn parse_keepalive() {
        let config = config!(b"tcp-keepalive 123", Logger::new(Level::Warning));
        assert_eq!(config.tcp_keepalive, 123);
    }

    #[test]
    fn parse_keepalive_quotes() {
        let config = config!(b"tcp-keepalive \"123\"", Logger::new(Level::Warning));
        assert_eq!(config.tcp_keepalive, 123);
    }

    #[test]
    fn parse_set_max_intset_entries() {
        let config = config!(b"set-max-intset-entries 123456", Logger::new(Level::Warning));
        assert_eq!(config.set_max_intset_entries, 123456);
    }

    #[test]
    fn parse_timeout() {
        let config = config!(b"timeout 23456", Logger::new(Level::Warning));
        assert_eq!(config.timeout, 23456);
    }

    #[test]
    fn parse_unixsocket() {
        let config = config!(b"unixsocket /dev/null\nunixsocketperm 777", Logger::new(Level::Warning));
        assert_eq!(config.unixsocket, Some("/dev/null".to_owned()));
        assert_eq!(config.unixsocketperm, 511);
    }

    #[test]
    fn parse_rename_commands() {
        let config = config!(b"rename-command C1 C2\nrename-command HELLO world", Logger::new(Level::Warning));
        let mut h = HashMap::new();
        h.insert("c2".to_owned(), Some("c1".to_owned()));
        h.insert("c1".to_owned(), None);
        h.insert("world".to_owned(), Some("hello".to_owned()));
        h.insert("hello".to_owned(), None);
        assert_eq!(config.rename_commands, h);
    }

    #[test]
    fn parse_requirepass() {
        let config = config!(b"requirepass THISISASTRONGPASSWORD", Logger::new(Level::Warning));
        assert_eq!(config.requirepass, Some("THISISASTRONGPASSWORD".to_owned()));
    }
}
<commit_msg>Remove used of deprecated owned_ascii_ext<commit_after>#[macro_use(log)]
extern crate logger;
extern crate rand;
extern crate time;
extern crate util;

use std::collections::HashMap;
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use std::io::Error as IOError;
use std::io::Write;
use std::num::ParseIntError;
use std::path::Path;
use std::str::from_utf8;
use std::str::FromStr;
use std::str::Utf8Error;

use util::splitargs;
use logger::{Logger, Level};

pub struct Config {
    pub logger: Logger,
    pub daemonize: bool,
    pub databases: u8,
    pub pidfile: String,
    pub bind: Vec<String>,
    pub port: u16,
    pub tcp_keepalive: u32,
    pub active_rehashing: bool,
    pub set_max_intset_entries: usize,
    pub timeout: u64,
    pub unixsocket: Option<String>,
    pub unixsocketperm: u32,
    pub rename_commands: HashMap<String, Option<String>>,
    pub requirepass: Option<String>,
    pub tcp_backlog: i32,
    pub syslog_enabled: bool,
    pub syslog_ident: String,
    pub syslog_facility: String,
}

#[derive(Debug)]
pub enum ConfigError {
    InvalidFormat,
    InvalidParameter,
    IOError(IOError),
    FileNotFound,
}

fn read_string(args: Vec<Vec<u8>>) -> Result<String, ConfigError> {
    if args.len() != 2 {
        Err(ConfigError::InvalidFormat)
    } else {
        Ok(try!(from_utf8(&*args[1])).to_owned())
    }
}

fn read_parse<T>(args: Vec<Vec<u8>>) -> Result<T, ConfigError>
        where T: FromStr {
    let s = try!(read_string(args));
    match s.parse() {
        Ok(f) => Ok(f),
        Err(_) => Err(ConfigError::InvalidParameter),
    }
}

fn read_bool(args: Vec<Vec<u8>>) -> Result<bool, ConfigError> {
    Ok(match &*try!(read_string(args)) {
        "yes" => true,
        "no" => false,
        _ => return Err(ConfigError::InvalidFormat),
    })
}

impl Config {
    pub fn mock(port: u16, logger: Logger) -> Config {
        Config {
            logger: logger,
            active_rehashing: true,
            daemonize: false,
            databases: 16,
            pidfile: "/var/run/sredis.pid".to_owned(),
            bind: vec!["127.0.0.1".to_owned()],
            port: port,
            tcp_keepalive: 0,
            set_max_intset_entries: 512,
            timeout: 0,
            unixsocket: None,
            unixsocketperm: 0700,
            rename_commands: HashMap::new(),
            requirepass: None,
            tcp_backlog: 511,
            syslog_enabled: false,
            syslog_ident: "rsedis".to_owned(),
            syslog_facility: "local0".to_owned(),
        }
    }

    pub fn new(logger: Logger) -> Config {
        Config {
            logger: logger,
            active_rehashing: true,
            daemonize: false,
            databases: 16,
            pidfile: "/var/run/sredis.pid".to_owned(),
            bind: vec![],
            port: 6379,
            tcp_keepalive: 0,
            set_max_intset_entries: 512,
            timeout: 0,
            unixsocket: None,
            unixsocketperm: 0700,
            rename_commands: HashMap::new(),
            requirepass: None,
            tcp_backlog: 511,
            syslog_enabled: false,
            syslog_ident: "rsedis".to_owned(),
            syslog_facility: "local0".to_owned(),
        }
    }

    pub fn parsefile(&mut self, fname: String) -> Result<(), ConfigError> {
        let path = Path::new(&*fname);
        let file = BufReader::new(match File::open(&path) {
            Ok(f) => f,
            Err(_) => {
                log!(self.logger, Warning, "Fatal error, can't open config file '{}'", fname);
                return Err(ConfigError::FileNotFound);
            }
        });
        for line_iter in file.lines() {
            let lline = try!(line_iter);
            let line = lline.trim();
            if line.starts_with("#") {
                continue;
            }

            let args = match splitargs(line.as_bytes()) {
                Ok(args) => args,
                Err(_) => return Err(ConfigError::InvalidFormat),
            };

            if args.len() == 0 {
                continue;
            }

            match &*args[0] {
                b"bind" => self.bind.extend(args[1..].iter().filter(|x| x.len() > 0).map(|x| match from_utf8(x) {
                            Ok(s) => s.to_owned(),
                            Err(_) => "".to_owned(), // TODO: return ConfigError
                            })),
                b"port" => self.port = try!(read_parse(args)),
                b"activerehashing" => self.active_rehashing = try!(read_bool(args)),
                b"daemonize" => self.daemonize = try!(read_bool(args)),
                b"databases" => self.databases = try!(read_parse(args)),
                b"tcp-keepalive" => self.tcp_keepalive = try!(read_parse(args)),
                b"set-max-intset-entries" => self.set_max_intset_entries = try!(read_parse(args)),
                b"timeout" => self.timeout = try!(read_parse(args)),
                b"unixsocket" => self.unixsocket = Some(try!(read_string(args)).to_owned()),
                b"unixsocketperm" => self.unixsocketperm = try!(u32::from_str_radix(&*try!(read_string(args)), 8)),
                b"pidfile" => self.pidfile = try!(read_string(args)).to_owned(),
                b"logfile" => {
                    let logfile = try!(read_string(args));
                    if logfile.len() > 0 {
                        try!(self.logger.set_logfile(&*logfile))
                    }
                },
                b"loglevel" => self.logger.set_loglevel(match &*try!(read_string(args)) {
                    "debug" => Level::Debug,
                    "verbose" => Level::Verbose,
                    "notice" => Level::Notice,
                    "warning" => Level::Warning,
                    _ => return Err(ConfigError::InvalidParameter),
                }),
                b"rename-command" => {
                    if args.len() != 3 {
                        return Err(ConfigError::InvalidFormat)
                    } else {
                        let command = try!(from_utf8(&*args[1])).to_owned();
                        let newname = try!(from_utf8(&*args[2])).to_owned();
                        if newname.len() > 0 {
                            self.rename_commands.insert(newname.to_lowercase(), Some(command.clone().to_lowercase()));
                        }
                        self.rename_commands.insert(command.to_lowercase(), None);
                    }
                },
                b"requirepass" => self.requirepass = Some(try!(read_string(args)).to_owned()),
                b"tcp-backlog" => self.tcp_backlog = try!(read_parse(args)),
                b"syslog-enabled" => self.syslog_enabled = try!(read_bool(args)),
                b"syslog-ident" => self.syslog_ident = try!(read_string(args)).to_owned(),
                b"syslog-facility" => self.syslog_facility = try!(read_string(args)).to_owned(),
                b"include" => if args.len() != 2 {
                    return Err(ConfigError::InvalidFormat)
                } else {
                    try!(self.parsefile(try!(from_utf8(&*args[1])).to_owned()));
                },
                _ => writeln!(&mut std::io::stderr(), "Unknown configuration {:?}", line).unwrap(),
            };
        }
        if self.syslog_enabled {
            self.logger.set_syslog(&self.syslog_ident, &self.syslog_facility);
        }

        Ok(())
    }

    pub fn addresses(&self) -> Vec<(String, u16)> {
        if self.bind.len() == 0 {
            vec![("127.0.0.1".to_owned(), self.port)]
        } else {
            self.bind.iter().map(|s| (s.clone(), self.port)).collect::<Vec<_>>()
        }
    }
}

impl From<IOError> for ConfigError {
    fn from(e: IOError) -> ConfigError { ConfigError::IOError(e) }
}

impl From<ParseIntError> for ConfigError {
    fn from(_: ParseIntError) -> ConfigError { ConfigError::InvalidParameter }
}

impl From<Utf8Error> for ConfigError {
    fn from(_: Utf8Error) -> ConfigError { ConfigError::InvalidParameter }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::HashMap;
    use std::fs::File;
    use std::fs::create_dir;
    use std::io::Write;

    use rand::random;

    use logger::{Logger, Level};
    use util::mstime;

    macro_rules! config {
        ($str: expr, $logger: expr) => ({
            let dirpath = format!("tmp/{}", mstime());
            let filepath = format!("{}/{}.conf", dirpath, random::<u64>());
            match create_dir("tmp") { _ => () }
            match create_dir(dirpath) { _ => () }
            match File::create(filepath.clone()).unwrap().write_all($str) { _ => () }
            let mut config = Config::new($logger);
            config.parsefile(filepath).unwrap();
            config
        })
    }

    #[test]
    fn parse_bind() {
        let config = config!(b"bind 1.2.3.4\nbind 5.6.7.8", Logger::new(Level::Warning));
        assert_eq!(config.bind, vec!["1.2.3.4", "5.6.7.8"]);
        assert_eq!(config.port, 6379);
    }

    #[test]
    fn parse_port() {
        let config = config!(b"port 12345", Logger::new(Level::Warning));
        assert_eq!(config.port, 12345);
        assert_eq!(config.addresses(), vec![("127.0.0.1".to_owned(), 12345)]);
    }

    #[test]
    fn parse_bind_port() {
        let config = config!(b"bind 127.0.0.1\nport 12345", Logger::new(Level::Warning));
        assert_eq!(config.bind, vec!["127.0.0.1"]);
        assert_eq!(config.port, 12345);
    }

    #[test]
    fn parse_daemonize_yes() {
        let config = config!(b"daemonize yes", Logger::new(Level::Warning));
        assert!(config.daemonize);
    }

    #[test]
    fn parse_daemonize_no() {
        let config = config!(b"daemonize no", Logger::new(Level::Warning));
        assert!(!config.daemonize);
    }

    #[test]
    fn parse_active_rehashing_yes() {
        let config = config!(b"activerehashing yes", Logger::new(Level::Warning));
        assert!(config.active_rehashing);
    }

    #[test]
    fn parse_active_rehashing_no() {
        let config = config!(b"activerehashing no", Logger::new(Level::Warning));
        assert!(!config.active_rehashing);
    }

    #[test]
    fn parse_databases() {
        let config = config!(b"databases 20", Logger::new(Level::Warning));
        assert_eq!(config.databases, 20);
    }

    #[test]
    fn parse_keepalive() {
        let config = config!(b"tcp-keepalive 123", Logger::new(Level::Warning));
        assert_eq!(config.tcp_keepalive, 123);
    }

    #[test]
    fn parse_keepalive_quotes() {
        let config = config!(b"tcp-keepalive \"123\"", Logger::new(Level::Warning));
        assert_eq!(config.tcp_keepalive, 123);
    }

    #[test]
    fn parse_set_max_intset_entries() {
        let config = config!(b"set-max-intset-entries 123456", Logger::new(Level::Warning));
        assert_eq!(config.set_max_intset_entries, 123456);
    }

    #[test]
    fn parse_timeout() {
        let config = config!(b"timeout 23456", Logger::new(Level::Warning));
        assert_eq!(config.timeout, 23456);
    }

    #[test]
    fn parse_unixsocket() {
        let config = config!(b"unixsocket /dev/null\nunixsocketperm 777", Logger::new(Level::Warning));
        assert_eq!(config.unixsocket, Some("/dev/null".to_owned()));
        assert_eq!(config.unixsocketperm, 511);
    }

    #[test]
    fn parse_rename_commands() {
        let config = config!(b"rename-command C1 C2\nrename-command HELLO world", Logger::new(Level::Warning));
        let mut h = HashMap::new();
        h.insert("c2".to_owned(), Some("c1".to_owned()));
        h.insert("c1".to_owned(), None);
        h.insert("world".to_owned(), Some("hello".to_owned()));
        h.insert("hello".to_owned(), None);
        assert_eq!(config.rename_commands, h);
    }

    #[test]
    fn parse_requirepass() {
        let config = config!(b"requirepass THISISASTRONGPASSWORD", Logger::new(Level::Warning));
        assert_eq!(config.requirepass, Some("THISISASTRONGPASSWORD".to_owned()));
    }
}
<|endoftext|>


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

// Beginners write `mod.item` when they should write `mod::item`.
// This tests that we suggest the latter when we encounter the former.

pub mod a {
    pub const I: i32 = 1;

    pub fn f() -> i32 { 2 }

    pub mod b {
        pub const J: i32 = 3;

        pub fn g() -> i32 { 4 }
    }
}

fn h1() -> i32 {
    a.I
        //~^ ERROR E0425
        //~| HELP To reference an item from the `a` module, use `a::I`
}

fn h2() -> i32 {
    a.g()
        //~^ ERROR E0425
        //~| HELP To call a function from the `a` module, use `a::g(..)`
}

fn h3() -> i32 {
    a.b.J
        //~^ ERROR E0425
        //~| HELP To reference an item from the `a` module, use `a::b`
}

fn h4() -> i32 {
    a::b.J
        //~^ ERROR E0425
        //~| HELP To reference an item from the `a::b` module, use `a::b::J`
}

fn h5() -> i32 {
    a.b.f()
        //~^ ERROR E0425
        //~| HELP To reference an item from the `a` module, use `a::b`
}

fn h6() -> i32 {
    a::b.f()
        //~^ ERROR E0425
        //~| HELP To call a function from the `a::b` module, use `a::b::f(..)`
}
<|endoftext|>


<commit_before>//! Crate `ruma-api-macros` provides a procedural macro for easily generating
//! [ruma-api](https://github.com/ruma/ruma-api)-compatible endpoints.
//!
//! See the documentation for the `ruma_api!` macro for usage details.

#![deny(
    missing_copy_implementations,
    missing_debug_implementations,
    // missing_docs, # Uncomment when https://github.com/rust-lang/rust/pull/60562 is released.
    warnings
)]
#![warn(
    clippy::empty_line_after_outer_attr,
    clippy::expl_impl_clone_on_copy,
    clippy::if_not_else,
    clippy::items_after_statements,
    clippy::match_same_arms,
    clippy::mem_forget,
    clippy::missing_docs_in_private_items,
    clippy::multiple_inherent_impl,
    clippy::mut_mut,
    clippy::needless_borrow,
    clippy::needless_continue,
    clippy::single_match_else,
    clippy::unicode_not_nfc,
    clippy::use_self,
    clippy::used_underscore_binding,
    clippy::wrong_pub_self_convention,
    clippy::wrong_self_convention
)]
#![allow(clippy::cognitive_complexity)]
// Since we support Rust 1.34.2, we can't apply this suggestion yet
#![allow(clippy::use_self)]
#![recursion_limit = "256"]

extern crate proc_macro;

use proc_macro::TokenStream;
use quote::ToTokens;

use crate::api::{Api, RawApi};

mod api;

/// Generates a `ruma_api::Endpoint` from a concise definition.
///
/// The macro expects the following structure as input:
///
/// ```text
/// ruma_api! {
///     metadata {
///         description: &'static str
///         method: http::Method,
///         name: &'static str,
///         path: &'static str,
///         rate_limited: bool,
///         requires_authentication: bool,
///     }
///
///     request {
///         // Struct fields for each piece of data required
///         // to make a request to this API endpoint.
///     }
///
///     response {
///         // Struct fields for each piece of data expected
///         // in the response from this API endpoint.
///     }
/// }
/// # }
/// ```
///
/// This will generate a `ruma_api::Metadata` value to be used for the `ruma_api::Endpoint`'s
/// associated constant, single `Request` and `Response` structs, and the necessary trait
/// implementations to convert the request into a `http::Request` and to create a response from a
/// `http::Response` and vice versa.
///
/// The details of each of the three sections of the macros are documented below.
///
/// ## Metadata
///
/// *   `description`: A short description of what the endpoint does.
/// *   `method`: The HTTP method used for requests to the endpoint.
///     It's not necessary to import `http::Method`'s associated constants. Just write
///     the value as if it was imported, e.g. `GET`.
/// *   `name`: A unique name for the endpoint.
///     Generally this will be the same as the containing module.
/// *   `path`: The path component of the URL for the endpoint, e.g. "/foo/bar".
///     Components of the path that are parameterized can indicate a varible by using a Rust
///     identifier prefixed with a colon, e.g. `/foo/:some_parameter`.
///     A corresponding query string parameter will be expected in the request struct (see below
///     for details).
/// *   `rate_limited`: Whether or not the endpoint enforces rate limiting on requests.
/// *   `requires_authentication`: Whether or not the endpoint requires a valid access token.
///
/// ## Request
///
/// The request block contains normal struct field definitions.
/// Doc comments and attributes are allowed as normal.
/// There are also a few special attributes available to control how the struct is converted into a
/// `http::Request`:
///
/// *   `#[ruma_api(header = HEADER_NAME)]`: Fields with this attribute will be treated as HTTP
///     headers on the request.
///     The value must implement `AsRef<str>`.
///     Generally this is a `String`.
///     The attribute value shown above as `HEADER_NAME` must be a header name constant from
///     `http::header`, e.g. `CONTENT_TYPE`.
/// *   `#[ruma_api(path)]`: Fields with this attribute will be inserted into the matching path
///     component of the request URL.
/// *   `#[ruma_api(query)]`: Fields with this attribute will be inserting into the URL's query
///     string.
///
/// Any field that does not include one of these attributes will be part of the request's JSON
/// body.
///
/// ## Response
///
/// Like the request block, the response block consists of normal struct field definitions.
/// Doc comments and attributes are allowed as normal.
/// There is also a special attribute available to control how the struct is created from a
/// `http::Request`:
///
/// *   `#[ruma_api(header = HEADER_NAME)]`: Fields with this attribute will be treated as HTTP
///     headers on the response.
///     The value must implement `AsRef<str>`.
///     Generally this is a `String`.
///     The attribute value shown above as `HEADER_NAME` must be a header name constant from
///     `http::header`, e.g. `CONTENT_TYPE`.
///
/// Any field that does not include the above attribute will be expected in the response's JSON
/// body.
///
/// ## Newtype bodies
///
/// Both the request and response block also support "newtype bodies" by using the
/// `#[ruma_api(body)]` attribute on a field. If present on a field, the entire request or response
/// body will be treated as the value of the field. This allows you to treat the entire request or
/// response body as a specific type, rather than a JSON object with named fields. Only one field in
/// each struct can be marked with this attribute. It is an error to have a newtype body field and
/// normal body fields within the same struct.
///
/// # Examples
///
/// ```rust,ignore
/// pub mod some_endpoint {
///     use ruma_api_macros::ruma_api;
///
///     ruma_api! {
///         metadata {
///             description: "Does something.",
///             method: GET,
///             name: "some_endpoint",
///             path: "/_matrix/some/endpoint/:baz",
///             rate_limited: false,
///             requires_authentication: false,
///         }
///
///         request {
///             pub foo: String,
///
///             #[ruma_api(header = CONTENT_TYPE)]
///             pub content_type: String,
///
///             #[ruma_api(query)]
///             pub bar: String,
///
///             #[ruma_api(path)]
///             pub baz: String,
///         }
///
///         response {
///             #[ruma_api(header = CONTENT_TYPE)]
///             pub content_type: String,
///
///             pub value: String,
///         }
///     }
/// }
///
/// pub mod newtype_body_endpoint {
///     use ruma_api_macros::ruma_api;
///
///     #[derive(Clone, Debug, Deserialize, Serialize)]
///     pub struct MyCustomType {
///         pub foo: String,
///     }
///
///     ruma_api! {
///         metadata {
///             description: "Does something.",
///             method: GET,
///             name: "newtype_body_endpoint",
///             path: "/_matrix/some/newtype/body/endpoint",
///             rate_limited: false,
///             requires_authentication: false,
///         }
///
///         request {
///             #[ruma_api(body)]
///             pub file: Vec<u8>,
///         }
///
///         response {
///             #[ruma_api(body)]
///             pub my_custom_type: MyCustomType,
///         }
///     }
/// }
/// ```
#[proc_macro]
pub fn ruma_api(input: TokenStream) -> TokenStream {
    let raw_api = syn::parse_macro_input!(input as RawApi);

    let api = Api::from(raw_api);

    api.into_token_stream().into()
}
<commit_msg>Update macro crate's attributes<commit_after>//! Crate `ruma-api-macros` provides a procedural macro for easily generating
//! [ruma-api](https://github.com/ruma/ruma-api)-compatible endpoints.
//!
//! See the documentation for the `ruma_api!` macro for usage details.

#![deny(
    missing_copy_implementations,
    missing_debug_implementations,
    // missing_docs, # Uncomment when https://github.com/rust-lang/rust/pull/60562 is released.
)]
#![allow(clippy::cognitive_complexity)]
// Since we support Rust 1.34.2, we can't apply this suggestion yet
#![allow(clippy::use_self)]
#![recursion_limit = "256"]

extern crate proc_macro;

use proc_macro::TokenStream;
use quote::ToTokens;

use crate::api::{Api, RawApi};

mod api;

/// Generates a `ruma_api::Endpoint` from a concise definition.
///
/// The macro expects the following structure as input:
///
/// ```text
/// ruma_api! {
///     metadata {
///         description: &'static str
///         method: http::Method,
///         name: &'static str,
///         path: &'static str,
///         rate_limited: bool,
///         requires_authentication: bool,
///     }
///
///     request {
///         // Struct fields for each piece of data required
///         // to make a request to this API endpoint.
///     }
///
///     response {
///         // Struct fields for each piece of data expected
///         // in the response from this API endpoint.
///     }
/// }
/// # }
/// ```
///
/// This will generate a `ruma_api::Metadata` value to be used for the `ruma_api::Endpoint`'s
/// associated constant, single `Request` and `Response` structs, and the necessary trait
/// implementations to convert the request into a `http::Request` and to create a response from a
/// `http::Response` and vice versa.
///
/// The details of each of the three sections of the macros are documented below.
///
/// ## Metadata
///
/// *   `description`: A short description of what the endpoint does.
/// *   `method`: The HTTP method used for requests to the endpoint.
///     It's not necessary to import `http::Method`'s associated constants. Just write
///     the value as if it was imported, e.g. `GET`.
/// *   `name`: A unique name for the endpoint.
///     Generally this will be the same as the containing module.
/// *   `path`: The path component of the URL for the endpoint, e.g. "/foo/bar".
///     Components of the path that are parameterized can indicate a varible by using a Rust
///     identifier prefixed with a colon, e.g. `/foo/:some_parameter`.
///     A corresponding query string parameter will be expected in the request struct (see below
///     for details).
/// *   `rate_limited`: Whether or not the endpoint enforces rate limiting on requests.
/// *   `requires_authentication`: Whether or not the endpoint requires a valid access token.
///
/// ## Request
///
/// The request block contains normal struct field definitions.
/// Doc comments and attributes are allowed as normal.
/// There are also a few special attributes available to control how the struct is converted into a
/// `http::Request`:
///
/// *   `#[ruma_api(header = HEADER_NAME)]`: Fields with this attribute will be treated as HTTP
///     headers on the request.
///     The value must implement `AsRef<str>`.
///     Generally this is a `String`.
///     The attribute value shown above as `HEADER_NAME` must be a header name constant from
///     `http::header`, e.g. `CONTENT_TYPE`.
/// *   `#[ruma_api(path)]`: Fields with this attribute will be inserted into the matching path
///     component of the request URL.
/// *   `#[ruma_api(query)]`: Fields with this attribute will be inserting into the URL's query
///     string.
///
/// Any field that does not include one of these attributes will be part of the request's JSON
/// body.
///
/// ## Response
///
/// Like the request block, the response block consists of normal struct field definitions.
/// Doc comments and attributes are allowed as normal.
/// There is also a special attribute available to control how the struct is created from a
/// `http::Request`:
///
/// *   `#[ruma_api(header = HEADER_NAME)]`: Fields with this attribute will be treated as HTTP
///     headers on the response.
///     The value must implement `AsRef<str>`.
///     Generally this is a `String`.
///     The attribute value shown above as `HEADER_NAME` must be a header name constant from
///     `http::header`, e.g. `CONTENT_TYPE`.
///
/// Any field that does not include the above attribute will be expected in the response's JSON
/// body.
///
/// ## Newtype bodies
///
/// Both the request and response block also support "newtype bodies" by using the
/// `#[ruma_api(body)]` attribute on a field. If present on a field, the entire request or response
/// body will be treated as the value of the field. This allows you to treat the entire request or
/// response body as a specific type, rather than a JSON object with named fields. Only one field in
/// each struct can be marked with this attribute. It is an error to have a newtype body field and
/// normal body fields within the same struct.
///
/// # Examples
///
/// ```rust,ignore
/// pub mod some_endpoint {
///     use ruma_api_macros::ruma_api;
///
///     ruma_api! {
///         metadata {
///             description: "Does something.",
///             method: GET,
///             name: "some_endpoint",
///             path: "/_matrix/some/endpoint/:baz",
///             rate_limited: false,
///             requires_authentication: false,
///         }
///
///         request {
///             pub foo: String,
///
///             #[ruma_api(header = CONTENT_TYPE)]
///             pub content_type: String,
///
///             #[ruma_api(query)]
///             pub bar: String,
///
///             #[ruma_api(path)]
///             pub baz: String,
///         }
///
///         response {
///             #[ruma_api(header = CONTENT_TYPE)]
///             pub content_type: String,
///
///             pub value: String,
///         }
///     }
/// }
///
/// pub mod newtype_body_endpoint {
///     use ruma_api_macros::ruma_api;
///
///     #[derive(Clone, Debug, Deserialize, Serialize)]
///     pub struct MyCustomType {
///         pub foo: String,
///     }
///
///     ruma_api! {
///         metadata {
///             description: "Does something.",
///             method: GET,
///             name: "newtype_body_endpoint",
///             path: "/_matrix/some/newtype/body/endpoint",
///             rate_limited: false,
///             requires_authentication: false,
///         }
///
///         request {
///             #[ruma_api(body)]
///             pub file: Vec<u8>,
///         }
///
///         response {
///             #[ruma_api(body)]
///             pub my_custom_type: MyCustomType,
///         }
///     }
/// }
/// ```
#[proc_macro]
pub fn ruma_api(input: TokenStream) -> TokenStream {
    let raw_api = syn::parse_macro_input!(input as RawApi);

    let api = Api::from(raw_api);

    api.into_token_stream().into()
}
<|endoftext|>


<commit_before><commit_msg>Actually test fract(float).<commit_after><|endoftext|>


<commit_before><commit_msg>debug<commit_after><|endoftext|>