<commit_before>// Copyright 2014 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 LinkerFlavor;
use target::{LinkArgs, TargetOptions};
use std::default::Default;

pub fn opts() -> TargetOptions {
    let mut pre_link_args = LinkArgs::new();
    pre_link_args.insert(LinkerFlavor::Gcc, vec![
            // And here, we see obscure linker flags #45. On windows, it has been
            // found to be necessary to have this flag to compile liblibc.
            //
            // First a bit of background. On Windows, the file format is not ELF,
            // but COFF (at least according to LLVM). COFF doesn't officially allow
            // for section names over 8 characters, apparently. Our metadata
            // section, ".note.rustc", you'll note is over 8 characters.
            //
            // On more recent versions of gcc on mingw, apparently the section name
            // is *not* truncated, but rather stored elsewhere in a separate lookup
            // table. On older versions of gcc, they apparently always truncated th
            // section names (at least in some cases). Truncating the section name
            // actually creates "invalid" objects [1] [2], but only for some
            // introspection tools, not in terms of whether it can be loaded.
            //
            // Long story short, passing this flag forces the linker to *not*
            // truncate section names (so we can find the metadata section after
            // it's compiled). The real kicker is that rust compiled just fine on
            // windows for quite a long time *without* this flag, so I have no idea
            // why it suddenly started failing for liblibc. Regardless, we
            // definitely don't want section name truncation, so we're keeping this
            // flag for windows.
            //
            // [1] - https://sourceware.org/bugzilla/show_bug.cgi?id=13130
            // [2] - https://code.google.com/p/go/issues/detail?id=2139
            "-Wl,--enable-long-section-names".to_string(),

            // Tell GCC to avoid linker plugins, because we are not bundling
            // them with Windows installer, and Rust does its own LTO anyways.
            "-fno-use-linker-plugin".to_string(),

            // Always enable DEP (NX bit) when it is available
            "-Wl,--nxcompat".to_string(),

            // Do not use the standard system startup files or libraries when linking
            "-nostdlib".to_string(),
        ]);

    let mut late_link_args = LinkArgs::new();
    late_link_args.insert(LinkerFlavor::Gcc, vec![
        "-lmingwex".to_string(),
        "-lmingw32".to_string(),
        "-lgcc".to_string(), // alas, mingw* libraries above depend on libgcc
        "-lmsvcrt".to_string(),
        "-lmsvcrt".to_string(), // mingw is insane...?
        "-luser32".to_string(),
        "-lkernel32".to_string(),
    ]);

    TargetOptions {
        // FIXME(#13846) this should be enabled for windows
        function_sections: false,
        linker: "gcc".to_string(),
        dynamic_linking: true,
        executables: true,
        dll_prefix: "".to_string(),
        dll_suffix: ".dll".to_string(),
        exe_suffix: ".exe".to_string(),
        staticlib_prefix: "".to_string(),
        staticlib_suffix: ".lib".to_string(),
        no_default_libraries: true,
        target_family: Some("windows".to_string()),
        is_like_windows: true,
        allows_weak_linkage: false,
        pre_link_args,
        pre_link_objects_exe: vec![
            "crt2.o".to_string(),    // mingw C runtime initialization for executables
            "rsbegin.o".to_string(), // Rust compiler runtime initialization, see rsbegin.rs
        ],
        pre_link_objects_dll: vec![
            "dllcrt2.o".to_string(), // mingw C runtime initialization for dlls
            "rsbegin.o".to_string(),
        ],
        late_link_args,
        post_link_objects: vec![
            "rsend.o".to_string()
        ],
        custom_unwind_resume: true,

        .. Default::default()
    }
}
<commit_msg>Document the mingw -lmsvcrt hack better<commit_after>// Copyright 2014 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 LinkerFlavor;
use target::{LinkArgs, TargetOptions};
use std::default::Default;

pub fn opts() -> TargetOptions {
    let mut pre_link_args = LinkArgs::new();
    pre_link_args.insert(LinkerFlavor::Gcc, vec![
            // And here, we see obscure linker flags #45. On windows, it has been
            // found to be necessary to have this flag to compile liblibc.
            //
            // First a bit of background. On Windows, the file format is not ELF,
            // but COFF (at least according to LLVM). COFF doesn't officially allow
            // for section names over 8 characters, apparently. Our metadata
            // section, ".note.rustc", you'll note is over 8 characters.
            //
            // On more recent versions of gcc on mingw, apparently the section name
            // is *not* truncated, but rather stored elsewhere in a separate lookup
            // table. On older versions of gcc, they apparently always truncated th
            // section names (at least in some cases). Truncating the section name
            // actually creates "invalid" objects [1] [2], but only for some
            // introspection tools, not in terms of whether it can be loaded.
            //
            // Long story short, passing this flag forces the linker to *not*
            // truncate section names (so we can find the metadata section after
            // it's compiled). The real kicker is that rust compiled just fine on
            // windows for quite a long time *without* this flag, so I have no idea
            // why it suddenly started failing for liblibc. Regardless, we
            // definitely don't want section name truncation, so we're keeping this
            // flag for windows.
            //
            // [1] - https://sourceware.org/bugzilla/show_bug.cgi?id=13130
            // [2] - https://code.google.com/p/go/issues/detail?id=2139
            "-Wl,--enable-long-section-names".to_string(),

            // Tell GCC to avoid linker plugins, because we are not bundling
            // them with Windows installer, and Rust does its own LTO anyways.
            "-fno-use-linker-plugin".to_string(),

            // Always enable DEP (NX bit) when it is available
            "-Wl,--nxcompat".to_string(),

            // Do not use the standard system startup files or libraries when linking
            "-nostdlib".to_string(),
        ]);

    let mut late_link_args = LinkArgs::new();
    late_link_args.insert(LinkerFlavor::Gcc, vec![
        "-lmingwex".to_string(),
        "-lmingw32".to_string(),
        "-lgcc".to_string(), // alas, mingw* libraries above depend on libgcc
        "-lmsvcrt".to_string(),
        // mingw's msvcrt is a weird hybrid import library and static library.
        // And it seems that the linker fails to use import symbols from msvcrt
        // that are required from functions in msvcrt in certain cases. For example
        // `_fmode` that is used by an implementation of `__p__fmode` in x86_64.
        // Listing the library twice seems to fix that, and seems to also be done
        // by mingw's gcc (Though not sure if it's done on purpose, or by mistake).
        //
        // See https://github.com/rust-lang/rust/pull/47483
        "-lmsvcrt".to_string(),
        "-luser32".to_string(),
        "-lkernel32".to_string(),
    ]);

    TargetOptions {
        // FIXME(#13846) this should be enabled for windows
        function_sections: false,
        linker: "gcc".to_string(),
        dynamic_linking: true,
        executables: true,
        dll_prefix: "".to_string(),
        dll_suffix: ".dll".to_string(),
        exe_suffix: ".exe".to_string(),
        staticlib_prefix: "".to_string(),
        staticlib_suffix: ".lib".to_string(),
        no_default_libraries: true,
        target_family: Some("windows".to_string()),
        is_like_windows: true,
        allows_weak_linkage: false,
        pre_link_args,
        pre_link_objects_exe: vec![
            "crt2.o".to_string(),    // mingw C runtime initialization for executables
            "rsbegin.o".to_string(), // Rust compiler runtime initialization, see rsbegin.rs
        ],
        pre_link_objects_dll: vec![
            "dllcrt2.o".to_string(), // mingw C runtime initialization for dlls
            "rsbegin.o".to_string(),
        ],
        late_link_args,
        post_link_objects: vec![
            "rsend.o".to_string()
        ],
        custom_unwind_resume: true,

        .. Default::default()
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 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 rustc::ty;
use std::fs;
use std::path::PathBuf;

pub fn dep_graph_path<'tcx>(tcx: &ty::TyCtxt<'tcx>) -> Option<PathBuf> {
    // For now, just save/load dep-graph from
    // directory/dep_graph.rbml
    tcx.sess.opts.incremental.as_ref().and_then(|incr_dir| {
        match fs::create_dir_all(&incr_dir){
            Ok(()) => {}
            Err(err) => {
                tcx.sess.err(
                    &format!("could not create the directory `{}`: {}",
                             incr_dir.display(), err));
                return None;
            }
        }

        Some(incr_dir.join("dep_graph.rbml"))
    })
}

<commit_msg>rustc: Handle concurrent `create_dir` requests<commit_after>// Copyright 2014 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 rustc::ty;

use std::fs;
use std::io;
use std::path::{PathBuf, Path};

pub fn dep_graph_path<'tcx>(tcx: &ty::TyCtxt<'tcx>) -> Option<PathBuf> {
    // For now, just save/load dep-graph from
    // directory/dep_graph.rbml
    tcx.sess.opts.incremental.as_ref().and_then(|incr_dir| {
        match create_dir_racy(&incr_dir) {
            Ok(()) => {}
            Err(err) => {
                tcx.sess.err(
                    &format!("could not create the directory `{}`: {}",
                             incr_dir.display(), err));
                return None;
            }
        }

        Some(incr_dir.join("dep_graph.rbml"))
    })
}

// Like std::fs::create_dir_all, except handles concurrent calls among multiple
// threads or processes.
fn create_dir_racy(path: &Path) -> io::Result<()> {
    match fs::create_dir(path) {
        Ok(()) => return Ok(()),
        Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => return Ok(()),
        Err(ref e) if e.kind() == io::ErrorKind::NotFound => {}
        Err(e) => return Err(e),
    }
    match path.parent() {
        Some(p) => try!(create_dir_racy(p)),
        None => return Err(io::Error::new(io::ErrorKind::Other,
                                          "failed to create whole tree")),
    }
    match fs::create_dir(path) {
        Ok(()) => Ok(()),
        Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(()),
        Err(e) => Err(e),
    }
}
<|endoftext|>


<commit_before>use crate::NewlineStyle;

/// Apply this newline style to the formatted text. When the style is set
/// to `Auto`, the `raw_input_text` is used to detect the existing line
/// endings.
///
/// If the style is set to `Auto` and `raw_input_text` contains no
/// newlines, the `Native` style will be used.
pub(crate) fn apply_newline_style(
    newline_style: NewlineStyle,
    formatted_text: &mut String,
    raw_input_text: &str,
) {
    *formatted_text = match effective_newline_style(newline_style, raw_input_text) {
        EffectiveNewlineStyle::Windows => convert_to_windows_newlines(formatted_text),
        EffectiveNewlineStyle::Unix => convert_to_unix_newlines(formatted_text),
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum EffectiveNewlineStyle {
    Windows,
    Unix,
}

fn effective_newline_style(
    newline_style: NewlineStyle,
    raw_input_text: &str,
) -> EffectiveNewlineStyle {
    match newline_style {
        NewlineStyle::Auto => auto_detect_newline_style(raw_input_text),
        NewlineStyle::Native => native_newline_style(),
        NewlineStyle::Windows => EffectiveNewlineStyle::Windows,
        NewlineStyle::Unix => EffectiveNewlineStyle::Unix,
    }
}

const LINE_FEED: char = '\n';
const CARRIAGE_RETURN: char = '\r';
const WINDOWS_NEWLINE: &str = "\r\n";
const UNIX_NEWLINE: &str = "\n";

fn auto_detect_newline_style(raw_input_text: &str) -> EffectiveNewlineStyle {
    let first_line_feed_pos = raw_input_text.chars().position(|ch| ch == LINE_FEED);
    match first_line_feed_pos {
        Some(first_line_feed_pos) => {
            let char_before_line_feed_pos = first_line_feed_pos.saturating_sub(1);
            let char_before_line_feed = raw_input_text.chars().nth(char_before_line_feed_pos);
            match char_before_line_feed {
                Some(CARRIAGE_RETURN) => EffectiveNewlineStyle::Windows,
                _ => EffectiveNewlineStyle::Unix,
            }
        }
        None => native_newline_style(),
    }
}

fn native_newline_style() -> EffectiveNewlineStyle {
    if cfg!(windows) {
        EffectiveNewlineStyle::Windows
    } else {
        EffectiveNewlineStyle::Unix
    }
}

fn convert_to_windows_newlines(formatted_text: &String) -> String {
    let mut transformed = String::with_capacity(2 * formatted_text.capacity());
    let mut chars = formatted_text.chars().peekable();
    while let Some(current_char) = chars.next() {
        let next_char = chars.peek();
        match current_char {
            LINE_FEED => transformed.push_str(WINDOWS_NEWLINE),
            CARRIAGE_RETURN if next_char == Some(&LINE_FEED) => {}
            current_char => transformed.push(current_char),
        }
    }
    transformed
}

fn convert_to_unix_newlines(formatted_text: &String) -> String {
    formatted_text.replace(WINDOWS_NEWLINE, UNIX_NEWLINE)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn auto_detects_unix_newlines() {
        assert_eq!(
            EffectiveNewlineStyle::Unix,
            auto_detect_newline_style("One\nTwo\nThree")
        );
    }

    #[test]
    fn auto_detects_windows_newlines() {
        assert_eq!(
            EffectiveNewlineStyle::Windows,
            auto_detect_newline_style("One\r\nTwo\r\nThree")
        );
    }

    #[test]
    fn auto_detects_windows_newlines_with_multibyte_char_on_first_line() {
        assert_eq!(
            EffectiveNewlineStyle::Windows,
            auto_detect_newline_style("A 🎢 of a first line\r\nTwo\r\nThree")
        );
    }

    #[test]
    fn falls_back_to_native_newlines_if_no_newlines_are_found() {
        let expected_newline_style = if cfg!(windows) {
            EffectiveNewlineStyle::Windows
        } else {
            EffectiveNewlineStyle::Unix
        };
        assert_eq!(
            expected_newline_style,
            auto_detect_newline_style("One Two Three")
        );
    }

    #[test]
    fn auto_detects_and_applies_unix_newlines() {
        let formatted_text = "One\nTwo\nThree";
        let raw_input_text = "One\nTwo\nThree";

        let mut out = String::from(formatted_text);
        apply_newline_style(NewlineStyle::Auto, &mut out, raw_input_text);
        assert_eq!("One\nTwo\nThree", &out, "auto should detect 'lf'");
    }

    #[test]
    fn auto_detects_and_applies_windows_newlines() {
        let formatted_text = "One\nTwo\nThree";
        let raw_input_text = "One\r\nTwo\r\nThree";

        let mut out = String::from(formatted_text);
        apply_newline_style(NewlineStyle::Auto, &mut out, raw_input_text);
        assert_eq!("One\r\nTwo\r\nThree", &out, "auto should detect 'crlf'");
    }

    #[test]
    fn auto_detects_and_applies_native_newlines() {
        let formatted_text = "One\nTwo\nThree";
        let raw_input_text = "One Two Three";

        let mut out = String::from(formatted_text);
        apply_newline_style(NewlineStyle::Auto, &mut out, raw_input_text);

        if cfg!(windows) {
            assert_eq!(
                "One\r\nTwo\r\nThree", &out,
                "auto-native-windows should detect 'crlf'"
            );
        } else {
            assert_eq!(
                "One\nTwo\nThree", &out,
                "auto-native-unix should detect 'lf'"
            );
        }
    }

    #[test]
    fn applies_unix_newlines() {
        test_newlines_are_applied_correctly(
            "One\r\nTwo\nThree",
            "One\nTwo\nThree",
            NewlineStyle::Unix,
        );
    }

    #[test]
    fn applying_windows_newlines_changes_nothing_for_windows_newlines() {
        let formatted_text = "One\r\nTwo\r\nThree";

        test_newlines_are_applied_correctly(formatted_text, formatted_text, NewlineStyle::Windows);
    }

    #[test]
    fn keeps_carriage_returns_when_applying_windows_newlines_to_str_with_unix_newlines() {
        test_newlines_are_applied_correctly(
            "One\nTwo\nThree\rDrei",
            "One\r\nTwo\r\nThree\rDrei",
            NewlineStyle::Windows,
        );
    }

    #[test]
    fn keeps_carriage_returns_when_applying_unix_newlines_to_str_with_unix_newlines() {
        test_newlines_are_applied_correctly(
            "One\nTwo\nThree\rDrei",
            "One\nTwo\nThree\rDrei",
            NewlineStyle::Unix,
        );
    }

    #[test]
    fn keeps_carriage_returns_when_applying_windows_newlines_to_str_with_windows_newlines() {
        test_newlines_are_applied_correctly(
            "One\r\nTwo\r\nThree\rDrei",
            "One\r\nTwo\r\nThree\rDrei",
            NewlineStyle::Windows,
        );
    }

    #[test]
    fn keeps_carriage_returns_when_applying_unix_newlines_to_str_with_windows_newlines() {
        test_newlines_are_applied_correctly(
            "One\r\nTwo\r\nThree\rDrei",
            "One\nTwo\nThree\rDrei",
            NewlineStyle::Unix,
        );
    }

    fn test_newlines_are_applied_correctly(
        input: &str,
        expected: &str,
        newline_style: NewlineStyle,
    ) {
        let mut out = String::from(input);
        apply_newline_style(newline_style, &mut out, input);
        assert_eq!(expected, &out);
    }
}
<commit_msg>Add tests to cover more edge cases<commit_after>use crate::NewlineStyle;

/// Apply this newline style to the formatted text. When the style is set
/// to `Auto`, the `raw_input_text` is used to detect the existing line
/// endings.
///
/// If the style is set to `Auto` and `raw_input_text` contains no
/// newlines, the `Native` style will be used.
pub(crate) fn apply_newline_style(
    newline_style: NewlineStyle,
    formatted_text: &mut String,
    raw_input_text: &str,
) {
    *formatted_text = match effective_newline_style(newline_style, raw_input_text) {
        EffectiveNewlineStyle::Windows => convert_to_windows_newlines(formatted_text),
        EffectiveNewlineStyle::Unix => convert_to_unix_newlines(formatted_text),
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum EffectiveNewlineStyle {
    Windows,
    Unix,
}

fn effective_newline_style(
    newline_style: NewlineStyle,
    raw_input_text: &str,
) -> EffectiveNewlineStyle {
    match newline_style {
        NewlineStyle::Auto => auto_detect_newline_style(raw_input_text),
        NewlineStyle::Native => native_newline_style(),
        NewlineStyle::Windows => EffectiveNewlineStyle::Windows,
        NewlineStyle::Unix => EffectiveNewlineStyle::Unix,
    }
}

const LINE_FEED: char = '\n';
const CARRIAGE_RETURN: char = '\r';
const WINDOWS_NEWLINE: &str = "\r\n";
const UNIX_NEWLINE: &str = "\n";

fn auto_detect_newline_style(raw_input_text: &str) -> EffectiveNewlineStyle {
    let first_line_feed_pos = raw_input_text.chars().position(|ch| ch == LINE_FEED);
    match first_line_feed_pos {
        Some(first_line_feed_pos) => {
            let char_before_line_feed_pos = first_line_feed_pos.saturating_sub(1);
            let char_before_line_feed = raw_input_text.chars().nth(char_before_line_feed_pos);
            match char_before_line_feed {
                Some(CARRIAGE_RETURN) => EffectiveNewlineStyle::Windows,
                _ => EffectiveNewlineStyle::Unix,
            }
        }
        None => native_newline_style(),
    }
}

fn native_newline_style() -> EffectiveNewlineStyle {
    if cfg!(windows) {
        EffectiveNewlineStyle::Windows
    } else {
        EffectiveNewlineStyle::Unix
    }
}

fn convert_to_windows_newlines(formatted_text: &String) -> String {
    let mut transformed = String::with_capacity(2 * formatted_text.capacity());
    let mut chars = formatted_text.chars().peekable();
    while let Some(current_char) = chars.next() {
        let next_char = chars.peek();
        match current_char {
            LINE_FEED => transformed.push_str(WINDOWS_NEWLINE),
            CARRIAGE_RETURN if next_char == Some(&LINE_FEED) => {}
            current_char => transformed.push(current_char),
        }
    }
    transformed
}

fn convert_to_unix_newlines(formatted_text: &String) -> String {
    formatted_text.replace(WINDOWS_NEWLINE, UNIX_NEWLINE)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn auto_detects_unix_newlines() {
        assert_eq!(
            EffectiveNewlineStyle::Unix,
            auto_detect_newline_style("One\nTwo\nThree")
        );
    }

    #[test]
    fn auto_detects_windows_newlines() {
        assert_eq!(
            EffectiveNewlineStyle::Windows,
            auto_detect_newline_style("One\r\nTwo\r\nThree")
        );
    }

    #[test]
    fn auto_detects_windows_newlines_with_multibyte_char_on_first_line() {
        assert_eq!(
            EffectiveNewlineStyle::Windows,
            auto_detect_newline_style("A 🎢 of a first line\r\nTwo\r\nThree")
        );
    }

    #[test]
    fn falls_back_to_native_newlines_if_no_newlines_are_found() {
        let expected_newline_style = if cfg!(windows) {
            EffectiveNewlineStyle::Windows
        } else {
            EffectiveNewlineStyle::Unix
        };
        assert_eq!(
            expected_newline_style,
            auto_detect_newline_style("One Two Three")
        );
    }

    #[test]
    fn auto_detects_and_applies_unix_newlines() {
        let formatted_text = "One\nTwo\nThree";
        let raw_input_text = "One\nTwo\nThree";

        let mut out = String::from(formatted_text);
        apply_newline_style(NewlineStyle::Auto, &mut out, raw_input_text);
        assert_eq!("One\nTwo\nThree", &out, "auto should detect 'lf'");
    }

    #[test]
    fn auto_detects_and_applies_windows_newlines() {
        let formatted_text = "One\nTwo\nThree";
        let raw_input_text = "One\r\nTwo\r\nThree";

        let mut out = String::from(formatted_text);
        apply_newline_style(NewlineStyle::Auto, &mut out, raw_input_text);
        assert_eq!("One\r\nTwo\r\nThree", &out, "auto should detect 'crlf'");
    }

    #[test]
    fn auto_detects_and_applies_native_newlines() {
        let formatted_text = "One\nTwo\nThree";
        let raw_input_text = "One Two Three";

        let mut out = String::from(formatted_text);
        apply_newline_style(NewlineStyle::Auto, &mut out, raw_input_text);

        if cfg!(windows) {
            assert_eq!(
                "One\r\nTwo\r\nThree", &out,
                "auto-native-windows should detect 'crlf'"
            );
        } else {
            assert_eq!(
                "One\nTwo\nThree", &out,
                "auto-native-unix should detect 'lf'"
            );
        }
    }

    #[test]
    fn applies_unix_newlines() {
        test_newlines_are_applied_correctly(
            "One\r\nTwo\nThree",
            "One\nTwo\nThree",
            NewlineStyle::Unix,
        );
    }

    #[test]
    fn applying_unix_newlines_changes_nothing_for_unix_newlines() {
        let formatted_text = "One\nTwo\nThree";
        test_newlines_are_applied_correctly(formatted_text, formatted_text, NewlineStyle::Unix);
    }

    #[test]
    fn applies_unix_newlines_to_string_with_unix_and_windows_newlines() {
        test_newlines_are_applied_correctly(
            "One\r\nTwo\r\nThree\nFour",
            "One\nTwo\nThree\nFour",
            NewlineStyle::Unix,
        );
    }

    #[test]
    fn applies_windows_newlines_to_string_with_unix_and_windows_newlines() {
        test_newlines_are_applied_correctly(
            "One\nTwo\nThree\r\nFour",
            "One\r\nTwo\r\nThree\r\nFour",
            NewlineStyle::Windows,
        );
    }

    #[test]
    fn applying_windows_newlines_changes_nothing_for_windows_newlines() {
        let formatted_text = "One\r\nTwo\r\nThree";
        test_newlines_are_applied_correctly(formatted_text, formatted_text, NewlineStyle::Windows);
    }

    #[test]
    fn keeps_carriage_returns_when_applying_windows_newlines_to_str_with_unix_newlines() {
        test_newlines_are_applied_correctly(
            "One\nTwo\nThree\rDrei",
            "One\r\nTwo\r\nThree\rDrei",
            NewlineStyle::Windows,
        );
    }

    #[test]
    fn keeps_carriage_returns_when_applying_unix_newlines_to_str_with_unix_newlines() {
        test_newlines_are_applied_correctly(
            "One\nTwo\nThree\rDrei",
            "One\nTwo\nThree\rDrei",
            NewlineStyle::Unix,
        );
    }

    #[test]
    fn keeps_carriage_returns_when_applying_windows_newlines_to_str_with_windows_newlines() {
        test_newlines_are_applied_correctly(
            "One\r\nTwo\r\nThree\rDrei",
            "One\r\nTwo\r\nThree\rDrei",
            NewlineStyle::Windows,
        );
    }

    #[test]
    fn keeps_carriage_returns_when_applying_unix_newlines_to_str_with_windows_newlines() {
        test_newlines_are_applied_correctly(
            "One\r\nTwo\r\nThree\rDrei",
            "One\nTwo\nThree\rDrei",
            NewlineStyle::Unix,
        );
    }

    fn test_newlines_are_applied_correctly(
        input: &str,
        expected: &str,
        newline_style: NewlineStyle,
    ) {
        let mut out = String::from(input);
        apply_newline_style(newline_style, &mut out, input);
        assert_eq!(expected, &out);
    }
}
<|endoftext|>


<commit_before>//! Main utility to dispatch and manage Xen events

use core::ptr::null_mut;

use core::intrinsics::atomic_xchg;

use hal::xen::shared_info;

use hal::xen::defs::EvtchnPort;
use hal::xen::defs::ULONG_SIZE;

use hal::arch::utils::{first_bit, wmb};
use hal::arch::utils::{atomic_set_bit, atomic_clear_bit};

const NUMBER_OF_EVENTS: usize = 1024;

pub type EventHandler = fn(port: EvtchnPort, data: *mut u8) -> ();

#[derive(Clone, Copy)]
struct EventData {
    pub handler: EventHandler,
    pub data: *mut u8,
}

impl EventData {
    pub const fn new(handler: EventHandler, data: *mut u8) -> Self {
        EventData {
            handler: handler,
            data: data,
        }
    }
}

pub struct Dispatcher {
    handlers: [EventData; NUMBER_OF_EVENTS],
}

impl Dispatcher {
    pub fn default_handler(port: EvtchnPort, _data: *mut u8) {
        panic!("Unhandled port ({})", port);
    }

    pub const fn new() -> Self {
        Dispatcher {
            handlers: [EventData::new(Dispatcher::default_handler, null_mut());
                       NUMBER_OF_EVENTS],
        }
    }

    #[inline(always)]
    pub unsafe fn serve_event(&self) {
        let cpu = &mut shared_info.vcpu_info[0];

        cpu.evtchn_upcall_pending = 0;

        wmb();

        let mut pending_sel = atomic_xchg(&mut cpu.evtchn_pending_sel, 0);

        while pending_sel != 0 {
            let next_event_offset = first_bit(pending_sel);

            pending_sel &= !(1 << next_event_offset);

            let mut event = shared_info.evtchn_pending[next_event_offset] &
                            !shared_info.evtchn_mask[next_event_offset];

            while event != 0 {
                let event_offset = first_bit(event);
                let port = (next_event_offset * ULONG_SIZE * 8) + event_offset;

                event &= !(1 << event_offset);

                if port >= NUMBER_OF_EVENTS {
                    panic!("Event occurred for out of bound port ({})", port);
                }

                (self.handlers[port].handler)(port as EvtchnPort,
                                              self.handlers[port].data);

                atomic_clear_bit(port, &mut shared_info.evtchn_pending[0]);
            }
        }
    }

    pub fn bind_port(&mut self, port: EvtchnPort, handler: EventHandler,
                     data: *mut u8) {
        if self.handlers[port as usize].handler !=
            Dispatcher::default_handler {
            panic!("Trying to override non default handler for port {}", port);
        }

        self.handlers[port as usize] = EventData::new(handler, data);
    }

    pub fn mask_all(&self) {
        let mut i: EvtchnPort = 0;

        while (i as usize) < NUMBER_OF_EVENTS {
            self.mask_event(i);

            i += 1;
        }
    }

    pub fn mask_event(&self, port: EvtchnPort) {
        unsafe {
            if port < (NUMBER_OF_EVENTS as EvtchnPort) {
                atomic_set_bit(port as usize, &mut shared_info.evtchn_mask[0]);
            }
        }
    }

    pub fn unmask_event(&self, port: EvtchnPort) {
        unsafe {
            if port < (NUMBER_OF_EVENTS as EvtchnPort) {
                atomic_clear_bit(port as usize,
                                 &mut shared_info.evtchn_mask[0]);
            }
        }
    }
}
<commit_msg>xen/event: Add Dispatcher::alloc_unbound()<commit_after>//! Main utility to dispatch and manage Xen events

use core::ptr::null_mut;

use core::intrinsics::atomic_xchg;

use hal::xen::shared_info;

use hal::xen::defs::EvtchnPort;
use hal::xen::defs::{ULONG_SIZE, DOMID_SELF};

use hal::xen::event::{event_channel_op, EventOp};

use hal::arch::utils::{first_bit, wmb};
use hal::arch::utils::{atomic_set_bit, atomic_clear_bit};

const NUMBER_OF_EVENTS: usize = 1024;

pub type EventHandler = fn(port: EvtchnPort, data: *mut u8) -> ();

#[derive(Clone, Copy)]
struct EventData {
    pub handler: EventHandler,
    pub data: *mut u8,
}

#[repr(C)]
/// struct evtchn_alloc_unbound
struct AllocUnbound {
    dom: u16,
    remote_dom: u16,
    port: EvtchnPort,
}

impl EventData {
    pub const fn new(handler: EventHandler, data: *mut u8) -> Self {
        EventData {
            handler: handler,
            data: data,
        }
    }
}

pub struct Dispatcher {
    handlers: [EventData; NUMBER_OF_EVENTS],
}

impl Dispatcher {
    pub fn default_handler(port: EvtchnPort, _data: *mut u8) {
        panic!("Unhandled port ({})", port);
    }

    pub const fn new() -> Self {
        Dispatcher {
            handlers: [EventData::new(Dispatcher::default_handler, null_mut());
                       NUMBER_OF_EVENTS],
        }
    }

    #[inline(always)]
    pub unsafe fn serve_event(&self) {
        let cpu = &mut shared_info.vcpu_info[0];

        cpu.evtchn_upcall_pending = 0;

        wmb();

        let mut pending_sel = atomic_xchg(&mut cpu.evtchn_pending_sel, 0);

        while pending_sel != 0 {
            let next_event_offset = first_bit(pending_sel);

            pending_sel &= !(1 << next_event_offset);

            let mut event = shared_info.evtchn_pending[next_event_offset] &
                            !shared_info.evtchn_mask[next_event_offset];

            while event != 0 {
                let event_offset = first_bit(event);
                let port = (next_event_offset * ULONG_SIZE * 8) + event_offset;

                event &= !(1 << event_offset);

                if port >= NUMBER_OF_EVENTS {
                    panic!("Event occurred for out of bound port ({})", port);
                }

                (self.handlers[port].handler)(port as EvtchnPort,
                                              self.handlers[port].data);

                atomic_clear_bit(port, &mut shared_info.evtchn_pending[0]);
            }
        }
    }

    pub fn bind_port(&mut self, port: EvtchnPort, handler: EventHandler,
                     data: *mut u8) {
        if self.handlers[port as usize].handler !=
            Dispatcher::default_handler {
            panic!("Trying to override non default handler for port {}", port);
        }

        self.handlers[port as usize] = EventData::new(handler, data);
    }

    /// Allocate a new event `port` and register an `handler` for it
    ///
    /// This function basically allocate the port through Xen and call
    /// `bind_port`
    pub fn alloc_unbound(&mut self, remote: u16, handler: EventHandler,
                         data: *mut u8) -> Result<EvtchnPort, i32> {
        let mut op = AllocUnbound {
            dom: DOMID_SELF,
            remote_dom: remote,
            port: 0,
        };

        let ret = event_channel_op(EventOp::AllocUnbound, &mut op);

        if ret != 0 {
            return Err(ret);
        }

        self.bind_port(op.port, handler, data);

        Ok(op.port)
    }

    pub fn mask_all(&self) {
        let mut i: EvtchnPort = 0;

        while (i as usize) < NUMBER_OF_EVENTS {
            self.mask_event(i);

            i += 1;
        }
    }

    pub fn mask_event(&self, port: EvtchnPort) {
        unsafe {
            if port < (NUMBER_OF_EVENTS as EvtchnPort) {
                atomic_set_bit(port as usize, &mut shared_info.evtchn_mask[0]);
            }
        }
    }

    pub fn unmask_event(&self, port: EvtchnPort) {
        unsafe {
            if port < (NUMBER_OF_EVENTS as EvtchnPort) {
                atomic_clear_bit(port as usize,
                                 &mut shared_info.evtchn_mask[0]);
            }
        }
    }
}
<|endoftext|>


<commit_before>use index::btree::internal::InNode;
use index::btree::{NodeCellRef, NodeWriteGuard, write_node, BPlusTree, NodeData};
use index::{EntryKey, Slice};
use std::fmt::Debug;

pub fn is_node_serial<KS, PS>(node: &NodeWriteGuard<KS, PS>) -> bool
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    // check keys
    for i in 0..node.len() {
        if node.keys()[i] <= smallvec!() {
            error!("EMPTY KEY DETECTED !!!");
            return false;
        }
    }
    for i in 1..node.len() {
        if node.keys()[i - 1] >= node.keys()[i] {
            error!("serial check failed for key ordering");
            return false;
        }
    }
    true
}

pub fn is_node_list_serial<KS, PS>(nodes: &Vec<NodeWriteGuard<KS, PS>>) -> bool
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    if nodes.len() == 0 {
        return true;
    }
    for (i, n) in nodes.iter().enumerate() {
        if !is_node_serial(n) {
            error!("node at {} not serial", i);
            return false;
        }
    }

    // check right ref
    for i in 0..nodes.len() - 1 {
        let first_right_bound = nodes[i].right_bound();
        let second_first_node = nodes[i + 1].first_key();
        let second_right_bound = nodes[i + 1].right_bound();
        if first_right_bound >= second_right_bound {
            error!("right bound at {} larger than right right bound", i);
            return false;
        }
        if first_right_bound > second_first_node {
            error!("right bound at {} larger than right first node", i);
            return false;
        }
    }
    return true;
}

pub fn is_node_level_serial<KS, PS>(mut node: NodeWriteGuard<KS, PS>, lsm_level: usize, tree_level: usize) -> bool
    where
        KS: Slice<EntryKey> + Debug + 'static,
        PS: Slice<NodeCellRef> + 'static,
{
    loop {
        let right_ref = node.right_ref().unwrap();
        let right_bound = if !node.is_empty_node() {
            let right_bound = node.right_bound();
            if !is_node_serial(&node) {
                error!("Node not serial - {} - {}", lsm_level, tree_level);
                return false;
            }
            if node.first_key() > right_bound {
                error!("Node have right key smaller than the first - {} - {}", lsm_level, tree_level);
                return false;
            }
            if node.last_key() > right_bound {
                error!("Node have right key smaller than the last - {} - {}", lsm_level, tree_level);
                return false;
            }
            right_bound
        } else {
            unreachable!()
        };
        let next = write_node(right_ref);
        if next.is_none() {
            debug!("Node level check reached non node - {} - {}", lsm_level, tree_level);
            return true;
        }
        if !next.is_empty_node() {
            if next.first_key() < right_bound {
                error!("next first key smaller than right bound - {} - {}, type {}. Left keys {:?}, right keys {:?}, right bound {:?}, next right bound {:?}",
                       lsm_level, tree_level, node.type_name(), node.keys(), next.keys(), node.right_bound(), next.right_bound());
                return false;
            }
            if next.right_bound() < right_bound {
                error!("next right bound key smaller than right bound - {} - {}", lsm_level, tree_level);
                return false
            }
        }
        node = next;
    }
}

pub fn is_tree_in_order<KS, PS>(tree: &BPlusTree<KS, PS>, level: usize) -> bool
    where
        KS: Slice<EntryKey> + Debug + 'static,
        PS: Slice<NodeCellRef> + 'static,
{
    debug!("Checking tree {} in order...", level);
    return ensure_level_in_order::<KS, PS>(&tree.get_root(), level, 0);
}

fn ensure_level_in_order<KS, PS>(node: &NodeCellRef, lsm_level: usize, tree_level: usize) -> bool
    where
        KS: Slice<EntryKey> + Debug + 'static,
        PS: Slice<NodeCellRef> + 'static,
{
    let first_node = write_node::<KS, PS>(&node);
    let sub_ref = match &*first_node {
        &NodeData::Internal(ref n) => Some(n.ptrs.as_slice_immute()[0].clone()),
        _ => None
    };
    if !is_node_level_serial(first_node, lsm_level, tree_level) {
        return false;
    }
    if let Some(sub_level) = sub_ref {
        return ensure_level_in_order::<KS, PS>(&sub_level, lsm_level, tree_level + 1);
    }
    return true;
}<commit_msg>min_key on empty for verification<commit_after>use index::btree::internal::InNode;
use index::btree::{NodeCellRef, NodeWriteGuard, write_node, BPlusTree, NodeData};
use index::{EntryKey, Slice};
use std::fmt::Debug;

pub fn is_node_serial<KS, PS>(node: &NodeWriteGuard<KS, PS>) -> bool
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    // check keys
    for i in 0..node.len() {
        if node.keys()[i] <= smallvec!() {
            error!("EMPTY KEY DETECTED !!!");
            return false;
        }
    }
    for i in 1..node.len() {
        if node.keys()[i - 1] >= node.keys()[i] {
            error!("serial check failed for key ordering");
            return false;
        }
    }
    true
}

pub fn is_node_list_serial<KS, PS>(nodes: &Vec<NodeWriteGuard<KS, PS>>) -> bool
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    if nodes.len() == 0 {
        return true;
    }
    for (i, n) in nodes.iter().enumerate() {
        if !is_node_serial(n) {
            error!("node at {} not serial", i);
            return false;
        }
    }

    // check right ref
    for i in 0..nodes.len() - 1 {
        let first_right_bound = nodes[i].right_bound();
        let second_first_node = nodes[i + 1].first_key();
        let second_right_bound = nodes[i + 1].right_bound();
        if first_right_bound >= second_right_bound {
            error!("right bound at {} larger than right right bound", i);
            return false;
        }
        if first_right_bound > second_first_node {
            error!("right bound at {} larger than right first node", i);
            return false;
        }
    }
    return true;
}

pub fn is_node_level_serial<KS, PS>(mut node: NodeWriteGuard<KS, PS>, lsm_level: usize, tree_level: usize) -> bool
    where
        KS: Slice<EntryKey> + Debug + 'static,
        PS: Slice<NodeCellRef> + 'static,
{
    let min_key = smallvec!();
    loop {
        let right_ref = node.right_ref().unwrap();
        let right_bound = if !node.is_empty_node() {
            let right_bound = node.right_bound();
            if !is_node_serial(&node) {
                error!("Node not serial - {} - {}", lsm_level, tree_level);
                return false;
            }
            if node.first_key() > right_bound {
                error!("Node have right key smaller than the first - {} - {}", lsm_level, tree_level);
                return false;
            }
            if node.last_key() > right_bound {
                error!("Node have right key smaller than the last - {} - {}", lsm_level, tree_level);
                return false;
            }
            right_bound
        } else {
            &min_key
        };
        let next = write_node(right_ref);
        if next.is_none() {
            debug!("Node level check reached non node - {} - {}", lsm_level, tree_level);
            return true;
        }
        if !next.is_empty_node() {
            assert!(right_bound > &min_key);
            if next.first_key() < right_bound {
                error!("next first key smaller than right bound - {} - {}, type {}. Left keys {:?}, right keys {:?}, right bound {:?}, next right bound {:?}",
                       lsm_level, tree_level, node.type_name(), node.keys(), next.keys(), node.right_bound(), next.right_bound());
                return false;
            }
            if next.right_bound() < right_bound {
                error!("next right bound key smaller than right bound - {} - {}", lsm_level, tree_level);
                return false
            }
        }
        node = next;
    }
}

pub fn is_tree_in_order<KS, PS>(tree: &BPlusTree<KS, PS>, level: usize) -> bool
    where
        KS: Slice<EntryKey> + Debug + 'static,
        PS: Slice<NodeCellRef> + 'static,
{
    debug!("Checking tree {} in order...", level);
    return ensure_level_in_order::<KS, PS>(&tree.get_root(), level, 0);
}

fn ensure_level_in_order<KS, PS>(node: &NodeCellRef, lsm_level: usize, tree_level: usize) -> bool
    where
        KS: Slice<EntryKey> + Debug + 'static,
        PS: Slice<NodeCellRef> + 'static,
{
    let first_node = write_node::<KS, PS>(&node);
    let sub_ref = match &*first_node {
        &NodeData::Internal(ref n) => Some(n.ptrs.as_slice_immute()[0].clone()),
        _ => None
    };
    if !is_node_level_serial(first_node, lsm_level, tree_level) {
        return false;
    }
    if let Some(sub_level) = sub_ref {
        return ensure_level_in_order::<KS, PS>(&sub_level, lsm_level, tree_level + 1);
    }
    return true;
}<|endoftext|>


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

//! Parsing of GCC-style Language-Specific Data Area (LSDA)
//! For details see:
//!   http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
//!   http://mentorembedded.github.io/cxx-abi/exceptions.pdf
//!   http://www.airs.com/blog/archives/460
//!   http://www.airs.com/blog/archives/464
//!
//! A reference implementation may be found in the GCC source tree
//! (<root>/libgcc/unwind-c.c as of this writing)

#![allow(non_upper_case_globals)]
#![allow(unused)]

use dwarf::DwarfReader;
use core::mem;

pub const DW_EH_PE_omit: u8 = 0xFF;
pub const DW_EH_PE_absptr: u8 = 0x00;

pub const DW_EH_PE_uleb128: u8 = 0x01;
pub const DW_EH_PE_udata2: u8 = 0x02;
pub const DW_EH_PE_udata4: u8 = 0x03;
pub const DW_EH_PE_udata8: u8 = 0x04;
pub const DW_EH_PE_sleb128: u8 = 0x09;
pub const DW_EH_PE_sdata2: u8 = 0x0A;
pub const DW_EH_PE_sdata4: u8 = 0x0B;
pub const DW_EH_PE_sdata8: u8 = 0x0C;

pub const DW_EH_PE_pcrel: u8 = 0x10;
pub const DW_EH_PE_textrel: u8 = 0x20;
pub const DW_EH_PE_datarel: u8 = 0x30;
pub const DW_EH_PE_funcrel: u8 = 0x40;
pub const DW_EH_PE_aligned: u8 = 0x50;

pub const DW_EH_PE_indirect: u8 = 0x80;

#[derive(Copy, Clone)]
pub struct EHContext<'a> {
    pub ip: usize, // Current instruction pointer
    pub func_start: usize, // Address of the current function
    pub get_text_start: &'a Fn() -> usize, // Get address of the code section
    pub get_data_start: &'a Fn() -> usize, // Get address of the data section
}

pub enum EHAction {
    None,
    Cleanup(usize),
    Catch(usize),
    Terminate,
}

pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm"));

pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction {
    if lsda.is_null() {
        return EHAction::None;
    }

    let func_start = context.func_start;
    let mut reader = DwarfReader::new(lsda);

    let start_encoding = reader.read::<u8>();
    // base address for landing pad offsets
    let lpad_base = if start_encoding != DW_EH_PE_omit {
        read_encoded_pointer(&mut reader, context, start_encoding)
    } else {
        func_start
    };

    let ttype_encoding = reader.read::<u8>();
    if ttype_encoding != DW_EH_PE_omit {
        // Rust doesn't analyze exception types, so we don't care about the type table
        reader.read_uleb128();
    }

    let call_site_encoding = reader.read::<u8>();
    let call_site_table_length = reader.read_uleb128();
    let action_table = reader.ptr.offset(call_site_table_length as isize);
    let ip = context.ip;

    if !USING_SJLJ_EXCEPTIONS {
        while reader.ptr < action_table {
            let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding);
            let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding);
            let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding);
            let cs_action = reader.read_uleb128();
            // Callsite table is sorted by cs_start, so if we've passed the ip, we
            // may stop searching.
            if ip < func_start + cs_start {
                break;
            }
            if ip < func_start + cs_start + cs_len {
                if cs_lpad == 0 {
                    return EHAction::None;
                } else {
                    let lpad = lpad_base + cs_lpad;
                    return interpret_cs_action(cs_action, lpad);
                }
            }
        }
        // If ip is not present in the table, call terminate.  This is for
        // a destructor inside a cleanup, or a library routine the compiler
        // was not expecting to throw
        EHAction::Terminate
    } else {
        // SjLj version:
        // The "IP" is an index into the call-site table, with two exceptions:
        // -1 means 'no-action', and 0 means 'terminate'.
        match ip as isize {
           -1 => return EHAction::None,
            0 => return EHAction::Terminate,
            _ => (),
        }
        let mut idx = ip;
        loop {
            let cs_lpad = reader.read_uleb128();
            let cs_action = reader.read_uleb128();
            idx -= 1;
            if idx == 0 {
                // Can never have null landing pad for sjlj -- that would have
                // been indicated by a -1 call site index.
                let lpad = (cs_lpad + 1) as usize;
                return interpret_cs_action(cs_action, lpad);
            }
        }
    }
}

fn interpret_cs_action(cs_action: u64, lpad: usize) -> EHAction {
    if cs_action == 0 {
        EHAction::Cleanup(lpad)
    } else {
        EHAction::Catch(lpad)
    }
}

#[inline]
fn round_up(unrounded: usize, align: usize) -> usize {
    assert!(align.is_power_of_two());
    (unrounded + align - 1) & !(align - 1)
}

unsafe fn read_encoded_pointer(reader: &mut DwarfReader,
                               context: &EHContext,
                               encoding: u8)
                               -> usize {
    assert!(encoding != DW_EH_PE_omit);

    // DW_EH_PE_aligned implies it's an absolute pointer value
    if encoding == DW_EH_PE_aligned {
        reader.ptr = round_up(reader.ptr as usize, mem::size_of::<usize>()) as *const u8;
        return reader.read::<usize>();
    }

    let mut result = match encoding & 0x0F {
        DW_EH_PE_absptr => reader.read::<usize>(),
        DW_EH_PE_uleb128 => reader.read_uleb128() as usize,
        DW_EH_PE_udata2 => reader.read::<u16>() as usize,
        DW_EH_PE_udata4 => reader.read::<u32>() as usize,
        DW_EH_PE_udata8 => reader.read::<u64>() as usize,
        DW_EH_PE_sleb128 => reader.read_sleb128() as usize,
        DW_EH_PE_sdata2 => reader.read::<i16>() as usize,
        DW_EH_PE_sdata4 => reader.read::<i32>() as usize,
        DW_EH_PE_sdata8 => reader.read::<i64>() as usize,
        _ => panic!(),
    };

    result += match encoding & 0x70 {
        DW_EH_PE_absptr => 0,
        // relative to address of the encoded value, despite the name
        DW_EH_PE_pcrel => reader.ptr as usize,
        DW_EH_PE_funcrel => {
            assert!(context.func_start != 0);
            context.func_start
        }
        DW_EH_PE_textrel => {
            (*context.get_text_start)()
        }
        DW_EH_PE_datarel => {
            (*context.get_data_start)()
        }
        _ => panic!(),
    };

    if encoding & DW_EH_PE_indirect != 0 {
        result = *(result as *const usize);
    }

    result
}
<commit_msg>Auto merge of #35014 - vadimcn:travis-test, r=alexcrichton<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.

//! Parsing of GCC-style Language-Specific Data Area (LSDA)
//! For details see:
//!   http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
//!   http://mentorembedded.github.io/cxx-abi/exceptions.pdf
//!   http://www.airs.com/blog/archives/460
//!   http://www.airs.com/blog/archives/464
//!
//! A reference implementation may be found in the GCC source tree
//! (<root>/libgcc/unwind-c.c as of this writing)

#![allow(non_upper_case_globals)]
#![allow(unused)]

use dwarf::DwarfReader;
use core::mem;

pub const DW_EH_PE_omit: u8 = 0xFF;
pub const DW_EH_PE_absptr: u8 = 0x00;

pub const DW_EH_PE_uleb128: u8 = 0x01;
pub const DW_EH_PE_udata2: u8 = 0x02;
pub const DW_EH_PE_udata4: u8 = 0x03;
pub const DW_EH_PE_udata8: u8 = 0x04;
pub const DW_EH_PE_sleb128: u8 = 0x09;
pub const DW_EH_PE_sdata2: u8 = 0x0A;
pub const DW_EH_PE_sdata4: u8 = 0x0B;
pub const DW_EH_PE_sdata8: u8 = 0x0C;

pub const DW_EH_PE_pcrel: u8 = 0x10;
pub const DW_EH_PE_textrel: u8 = 0x20;
pub const DW_EH_PE_datarel: u8 = 0x30;
pub const DW_EH_PE_funcrel: u8 = 0x40;
pub const DW_EH_PE_aligned: u8 = 0x50;

pub const DW_EH_PE_indirect: u8 = 0x80;

#[derive(Copy, Clone)]
pub struct EHContext<'a> {
    pub ip: usize, // Current instruction pointer
    pub func_start: usize, // Address of the current function
    pub get_text_start: &'a Fn() -> usize, // Get address of the code section
    pub get_data_start: &'a Fn() -> usize, // Get address of the data section
}

pub enum EHAction {
    None,
    Cleanup(usize),
    Catch(usize),
    Terminate,
}

pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm"));

pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction {
    if lsda.is_null() {
        return EHAction::None;
    }

    let func_start = context.func_start;
    let mut reader = DwarfReader::new(lsda);

    let start_encoding = reader.read::<u8>();
    // base address for landing pad offsets
    let lpad_base = if start_encoding != DW_EH_PE_omit {
        read_encoded_pointer(&mut reader, context, start_encoding)
    } else {
        func_start
    };

    let ttype_encoding = reader.read::<u8>();
    if ttype_encoding != DW_EH_PE_omit {
        // Rust doesn't analyze exception types, so we don't care about the type table
        reader.read_uleb128();
    }

    let call_site_encoding = reader.read::<u8>();
    let call_site_table_length = reader.read_uleb128();
    let action_table = reader.ptr.offset(call_site_table_length as isize);
    let ip = context.ip;

    if !USING_SJLJ_EXCEPTIONS {
        while reader.ptr < action_table {
            let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding);
            let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding);
            let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding);
            let cs_action = reader.read_uleb128();
            // Callsite table is sorted by cs_start, so if we've passed the ip, we
            // may stop searching.
            if ip < func_start + cs_start {
                break;
            }
            if ip < func_start + cs_start + cs_len {
                if cs_lpad == 0 {
                    return EHAction::None;
                } else {
                    let lpad = lpad_base + cs_lpad;
                    return interpret_cs_action(cs_action, lpad);
                }
            }
        }
        // Ip is not present in the table.  This should not hapen... but it does: issie #35011.
        // So rather than returning EHAction::Terminate, we do this.
        EHAction::None
    } else {
        // SjLj version:
        // The "IP" is an index into the call-site table, with two exceptions:
        // -1 means 'no-action', and 0 means 'terminate'.
        match ip as isize {
           -1 => return EHAction::None,
            0 => return EHAction::Terminate,
            _ => (),
        }
        let mut idx = ip;
        loop {
            let cs_lpad = reader.read_uleb128();
            let cs_action = reader.read_uleb128();
            idx -= 1;
            if idx == 0 {
                // Can never have null landing pad for sjlj -- that would have
                // been indicated by a -1 call site index.
                let lpad = (cs_lpad + 1) as usize;
                return interpret_cs_action(cs_action, lpad);
            }
        }
    }
}

fn interpret_cs_action(cs_action: u64, lpad: usize) -> EHAction {
    if cs_action == 0 {
        EHAction::Cleanup(lpad)
    } else {
        EHAction::Catch(lpad)
    }
}

#[inline]
fn round_up(unrounded: usize, align: usize) -> usize {
    assert!(align.is_power_of_two());
    (unrounded + align - 1) & !(align - 1)
}

unsafe fn read_encoded_pointer(reader: &mut DwarfReader,
                               context: &EHContext,
                               encoding: u8)
                               -> usize {
    assert!(encoding != DW_EH_PE_omit);

    // DW_EH_PE_aligned implies it's an absolute pointer value
    if encoding == DW_EH_PE_aligned {
        reader.ptr = round_up(reader.ptr as usize, mem::size_of::<usize>()) as *const u8;
        return reader.read::<usize>();
    }

    let mut result = match encoding & 0x0F {
        DW_EH_PE_absptr => reader.read::<usize>(),
        DW_EH_PE_uleb128 => reader.read_uleb128() as usize,
        DW_EH_PE_udata2 => reader.read::<u16>() as usize,
        DW_EH_PE_udata4 => reader.read::<u32>() as usize,
        DW_EH_PE_udata8 => reader.read::<u64>() as usize,
        DW_EH_PE_sleb128 => reader.read_sleb128() as usize,
        DW_EH_PE_sdata2 => reader.read::<i16>() as usize,
        DW_EH_PE_sdata4 => reader.read::<i32>() as usize,
        DW_EH_PE_sdata8 => reader.read::<i64>() as usize,
        _ => panic!(),
    };

    result += match encoding & 0x70 {
        DW_EH_PE_absptr => 0,
        // relative to address of the encoded value, despite the name
        DW_EH_PE_pcrel => reader.ptr as usize,
        DW_EH_PE_funcrel => {
            assert!(context.func_start != 0);
            context.func_start
        }
        DW_EH_PE_textrel => {
            (*context.get_text_start)()
        }
        DW_EH_PE_datarel => {
            (*context.get_data_start)()
        }
        _ => panic!(),
    };

    if encoding & DW_EH_PE_indirect != 0 {
        result = *(result as *const usize);
    }

    result
}
<|endoftext|>


<commit_before>#![allow(unstable)]

extern crate piston;
extern crate graphics;
extern crate sdl2_window;
extern crate opengl_graphics;

use std::cell::RefCell;
use opengl_graphics::{
    Gl,
    OpenGL,
    Texture,
};
use sdl2_window::Sdl2Window;

fn main() {
    let opengl = OpenGL::_3_2;
    let window = Sdl2Window::new(
        opengl,
        piston::window::WindowSettings {
            title: "Image".to_string(),
            size: [300, 300],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        }
    );

    let image = Path::new("./bin/assets/rust-logo.png");
    let image = Texture::from_path(&image).unwrap();
    let ref mut gl = Gl::new(opengl);
    let window = RefCell::new(window);
    for e in piston::events(&window) {
        use piston::event::RenderEvent;

        if let Some(args) = e.render_args() {
            use graphics::*;
            gl.draw([0, 0, args.width as i32, args.height as i32], |c, gl| {
                graphics::clear([1.0; 4], gl);
                graphics::image(&image, &c, gl);
            });
        };
    }
}

<commit_msg>Upgraded "image" example to latest Rust<commit_after>#![feature(core, path)]

extern crate piston;
extern crate graphics;
extern crate sdl2_window;
extern crate opengl_graphics;

use std::cell::RefCell;
use opengl_graphics::{
    Gl,
    OpenGL,
    Texture,
};
use sdl2_window::Sdl2Window;

fn main() {
    let opengl = OpenGL::_3_2;
    let window = Sdl2Window::new(
        opengl,
        piston::window::WindowSettings {
            title: "Image".to_string(),
            size: [300, 300],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        }
    );

    let image = Path::new("./bin/assets/rust-logo.png");
    let image = Texture::from_path(&image).unwrap();
    let ref mut gl = Gl::new(opengl);
    let window = RefCell::new(window);
    for e in piston::events(&window) {
        use piston::event::RenderEvent;

        if let Some(args) = e.render_args() {
            use graphics::*;
            gl.draw([0, 0, args.width as i32, args.height as i32], |c, gl| {
                graphics::clear([1.0; 4], gl);
                graphics::image(&image, &c, gl);
            });
        };
    }
}

<|endoftext|>


<commit_before>// Copyright 2016 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 cmp;
use io::{Error, ErrorKind, Result};
use mem;
use net::{SocketAddr, Shutdown};
use path::Path;
use sys::fs::{File, OpenOptions};
use sys::syscall::TimeSpec;
use sys_common::{AsInner, FromInner, IntoInner};
use time::Duration;

use super::{path_to_peer_addr, path_to_local_addr};

#[derive(Debug)]
pub struct TcpStream(File);

impl TcpStream {
    pub fn connect(addr: &SocketAddr) -> Result<TcpStream> {
        let path = format!("tcp:{}", addr);
        let mut options = OpenOptions::new();
        options.read(true);
        options.write(true);
        Ok(TcpStream(File::open(&Path::new(path.as_str()), &options)?))
    }

    pub fn connect_timeout(_addr: &SocketAddr, _timeout: Duration) -> Result<()> {
        Err(Error::new(ErrorKind::Other, "TcpStream::connect_timeout not implemented"))
    }

    pub fn duplicate(&self) -> Result<TcpStream> {
        Ok(TcpStream(self.0.dup(&[])?))
    }

    pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
        self.0.read(buf)
    }

    pub fn write(&self, buf: &[u8]) -> Result<usize> {
        self.0.write(buf)
    }

    pub fn take_error(&self) -> Result<Option<Error>> {
        Ok(None)
    }

    pub fn peer_addr(&self) -> Result<SocketAddr> {
        let path = self.0.path()?;
        Ok(path_to_peer_addr(path.to_str().unwrap_or("")))
    }

    pub fn socket_addr(&self) -> Result<SocketAddr> {
        let path = self.0.path()?;
        Ok(path_to_local_addr(path.to_str().unwrap_or("")))
    }

    pub fn peek(&self, _buf: &mut [u8]) -> Result<usize> {
        Err(Error::new(ErrorKind::Other, "TcpStream::peek not implemented"))
    }

    pub fn shutdown(&self, _how: Shutdown) -> Result<()> {
        Err(Error::new(ErrorKind::Other, "TcpStream::shutdown not implemented"))
    }

    pub fn nodelay(&self) -> Result<bool> {
        Err(Error::new(ErrorKind::Other, "TcpStream::nodelay not implemented"))
    }

    pub fn nonblocking(&self) -> Result<bool> {
        self.0.fd().nonblocking()
    }

    pub fn only_v6(&self) -> Result<bool> {
        Err(Error::new(ErrorKind::Other, "TcpStream::only_v6 not implemented"))
    }

    pub fn ttl(&self) -> Result<u32> {
        let mut ttl = [0];
        let file = self.0.dup(b"ttl")?;
        file.read(&mut ttl)?;
        Ok(ttl[0] as u32)
    }

    pub fn read_timeout(&self) -> Result<Option<Duration>> {
        let mut time = TimeSpec::default();
        let file = self.0.dup(b"read_timeout")?;
        if file.read(&mut time)? >= mem::size_of::<TimeSpec>() {
            Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32)))
        } else {
            Ok(None)
        }
    }

    pub fn write_timeout(&self) -> Result<Option<Duration>> {
        let mut time = TimeSpec::default();
        let file = self.0.dup(b"write_timeout")?;
        if file.read(&mut time)? >= mem::size_of::<TimeSpec>() {
            Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32)))
        } else {
            Ok(None)
        }
    }

    pub fn set_nodelay(&self, _nodelay: bool) -> Result<()> {
        Err(Error::new(ErrorKind::Other, "TcpStream::set_nodelay not implemented"))
    }

    pub fn set_nonblocking(&self, nonblocking: bool) -> Result<()> {
        self.0.fd().set_nonblocking(nonblocking)
    }

    pub fn set_only_v6(&self, _only_v6: bool) -> Result<()> {
        Err(Error::new(ErrorKind::Other, "TcpStream::set_only_v6 not implemented"))
    }

    pub fn set_ttl(&self, ttl: u32) -> Result<()> {
        let file = self.0.dup(b"ttl")?;
        file.write(&[cmp::min(ttl, 255) as u8])?;
        Ok(())
    }

    pub fn set_read_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
        let file = self.0.dup(b"read_timeout")?;
        if let Some(duration) = duration_option {
            file.write(&TimeSpec {
                tv_sec: duration.as_secs() as i64,
                tv_nsec: duration.subsec_nanos() as i32
            })?;
        } else {
            file.write(&[])?;
        }
        Ok(())
    }

    pub fn set_write_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
        let file = self.0.dup(b"write_timeout")?;
        if let Some(duration) = duration_option {
            file.write(&TimeSpec {
                tv_sec: duration.as_secs() as i64,
                tv_nsec: duration.subsec_nanos() as i32
            })?;
        } else {
            file.write(&[])?;
        }
        Ok(())
    }
}

impl AsInner<File> for TcpStream {
    fn as_inner(&self) -> &File { &self.0 }
}

impl FromInner<File> for TcpStream {
    fn from_inner(file: File) -> TcpStream {
        TcpStream(file)
    }
}

impl IntoInner<File> for TcpStream {
    fn into_inner(self) -> File { self.0 }
}

#[derive(Debug)]
pub struct TcpListener(File);

impl TcpListener {
    pub fn bind(addr: &SocketAddr) -> Result<TcpListener> {
        let path = format!("tcp:/{}", addr);
        let mut options = OpenOptions::new();
        options.read(true);
        options.write(true);
        Ok(TcpListener(File::open(&Path::new(path.as_str()), &options)?))
    }

    pub fn accept(&self) -> Result<(TcpStream, SocketAddr)> {
        let file = self.0.dup(b"listen")?;
        let path = file.path()?;
        let peer_addr = path_to_peer_addr(path.to_str().unwrap_or(""));
        Ok((TcpStream(file), peer_addr))
    }

    pub fn duplicate(&self) -> Result<TcpListener> {
        Ok(TcpListener(self.0.dup(&[])?))
    }

    pub fn take_error(&self) -> Result<Option<Error>> {
        Ok(None)
    }

    pub fn socket_addr(&self) -> Result<SocketAddr> {
        let path = self.0.path()?;
        Ok(path_to_local_addr(path.to_str().unwrap_or("")))
    }

    pub fn nonblocking(&self) -> Result<bool> {
        Err(Error::new(ErrorKind::Other, "TcpListener::nonblocking not implemented"))
    }

    pub fn only_v6(&self) -> Result<bool> {
        Err(Error::new(ErrorKind::Other, "TcpListener::only_v6 not implemented"))
    }

    pub fn ttl(&self) -> Result<u32> {
        let mut ttl = [0];
        let file = self.0.dup(b"ttl")?;
        file.read(&mut ttl)?;
        Ok(ttl[0] as u32)
    }

    pub fn set_nonblocking(&self, _nonblocking: bool) -> Result<()> {
        Err(Error::new(ErrorKind::Other, "TcpListener::set_nonblocking not implemented"))
    }

    pub fn set_only_v6(&self, _only_v6: bool) -> Result<()> {
        Err(Error::new(ErrorKind::Other, "TcpListener::set_only_v6 not implemented"))
    }

    pub fn set_ttl(&self, ttl: u32) -> Result<()> {
        let file = self.0.dup(b"ttl")?;
        file.write(&[cmp::min(ttl, 255) as u8])?;
        Ok(())
    }
}

impl AsInner<File> for TcpListener {
    fn as_inner(&self) -> &File { &self.0 }
}

impl FromInner<File> for TcpListener {
    fn from_inner(file: File) -> TcpListener {
        TcpListener(file)
    }
}

impl IntoInner<File> for TcpListener {
    fn into_inner(self) -> File { self.0 }
}
<commit_msg>Update tcp.rs<commit_after>// Copyright 2016 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 cmp;
use io::{Error, ErrorKind, Result};
use mem;
use net::{SocketAddr, Shutdown};
use path::Path;
use sys::fs::{File, OpenOptions};
use sys::syscall::TimeSpec;
use sys_common::{AsInner, FromInner, IntoInner};
use time::Duration;

use super::{path_to_peer_addr, path_to_local_addr};

#[derive(Debug)]
pub struct TcpStream(File);

impl TcpStream {
    pub fn connect(addr: &SocketAddr) -> Result<TcpStream> {
        let path = format!("tcp:{}", addr);
        let mut options = OpenOptions::new();
        options.read(true);
        options.write(true);
        Ok(TcpStream(File::open(&Path::new(path.as_str()), &options)?))
    }

    pub fn connect_timeout(_addr: &SocketAddr, _timeout: Duration) -> Result<TcpStream> {
        Err(Error::new(ErrorKind::Other, "TcpStream::connect_timeout not implemented"))
    }

    pub fn duplicate(&self) -> Result<TcpStream> {
        Ok(TcpStream(self.0.dup(&[])?))
    }

    pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
        self.0.read(buf)
    }

    pub fn write(&self, buf: &[u8]) -> Result<usize> {
        self.0.write(buf)
    }

    pub fn take_error(&self) -> Result<Option<Error>> {
        Ok(None)
    }

    pub fn peer_addr(&self) -> Result<SocketAddr> {
        let path = self.0.path()?;
        Ok(path_to_peer_addr(path.to_str().unwrap_or("")))
    }

    pub fn socket_addr(&self) -> Result<SocketAddr> {
        let path = self.0.path()?;
        Ok(path_to_local_addr(path.to_str().unwrap_or("")))
    }

    pub fn peek(&self, _buf: &mut [u8]) -> Result<usize> {
        Err(Error::new(ErrorKind::Other, "TcpStream::peek not implemented"))
    }

    pub fn shutdown(&self, _how: Shutdown) -> Result<()> {
        Err(Error::new(ErrorKind::Other, "TcpStream::shutdown not implemented"))
    }

    pub fn nodelay(&self) -> Result<bool> {
        Err(Error::new(ErrorKind::Other, "TcpStream::nodelay not implemented"))
    }

    pub fn nonblocking(&self) -> Result<bool> {
        self.0.fd().nonblocking()
    }

    pub fn only_v6(&self) -> Result<bool> {
        Err(Error::new(ErrorKind::Other, "TcpStream::only_v6 not implemented"))
    }

    pub fn ttl(&self) -> Result<u32> {
        let mut ttl = [0];
        let file = self.0.dup(b"ttl")?;
        file.read(&mut ttl)?;
        Ok(ttl[0] as u32)
    }

    pub fn read_timeout(&self) -> Result<Option<Duration>> {
        let mut time = TimeSpec::default();
        let file = self.0.dup(b"read_timeout")?;
        if file.read(&mut time)? >= mem::size_of::<TimeSpec>() {
            Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32)))
        } else {
            Ok(None)
        }
    }

    pub fn write_timeout(&self) -> Result<Option<Duration>> {
        let mut time = TimeSpec::default();
        let file = self.0.dup(b"write_timeout")?;
        if file.read(&mut time)? >= mem::size_of::<TimeSpec>() {
            Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32)))
        } else {
            Ok(None)
        }
    }

    pub fn set_nodelay(&self, _nodelay: bool) -> Result<()> {
        Err(Error::new(ErrorKind::Other, "TcpStream::set_nodelay not implemented"))
    }

    pub fn set_nonblocking(&self, nonblocking: bool) -> Result<()> {
        self.0.fd().set_nonblocking(nonblocking)
    }

    pub fn set_only_v6(&self, _only_v6: bool) -> Result<()> {
        Err(Error::new(ErrorKind::Other, "TcpStream::set_only_v6 not implemented"))
    }

    pub fn set_ttl(&self, ttl: u32) -> Result<()> {
        let file = self.0.dup(b"ttl")?;
        file.write(&[cmp::min(ttl, 255) as u8])?;
        Ok(())
    }

    pub fn set_read_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
        let file = self.0.dup(b"read_timeout")?;
        if let Some(duration) = duration_option {
            file.write(&TimeSpec {
                tv_sec: duration.as_secs() as i64,
                tv_nsec: duration.subsec_nanos() as i32
            })?;
        } else {
            file.write(&[])?;
        }
        Ok(())
    }

    pub fn set_write_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
        let file = self.0.dup(b"write_timeout")?;
        if let Some(duration) = duration_option {
            file.write(&TimeSpec {
                tv_sec: duration.as_secs() as i64,
                tv_nsec: duration.subsec_nanos() as i32
            })?;
        } else {
            file.write(&[])?;
        }
        Ok(())
    }
}

impl AsInner<File> for TcpStream {
    fn as_inner(&self) -> &File { &self.0 }
}

impl FromInner<File> for TcpStream {
    fn from_inner(file: File) -> TcpStream {
        TcpStream(file)
    }
}

impl IntoInner<File> for TcpStream {
    fn into_inner(self) -> File { self.0 }
}

#[derive(Debug)]
pub struct TcpListener(File);

impl TcpListener {
    pub fn bind(addr: &SocketAddr) -> Result<TcpListener> {
        let path = format!("tcp:/{}", addr);
        let mut options = OpenOptions::new();
        options.read(true);
        options.write(true);
        Ok(TcpListener(File::open(&Path::new(path.as_str()), &options)?))
    }

    pub fn accept(&self) -> Result<(TcpStream, SocketAddr)> {
        let file = self.0.dup(b"listen")?;
        let path = file.path()?;
        let peer_addr = path_to_peer_addr(path.to_str().unwrap_or(""));
        Ok((TcpStream(file), peer_addr))
    }

    pub fn duplicate(&self) -> Result<TcpListener> {
        Ok(TcpListener(self.0.dup(&[])?))
    }

    pub fn take_error(&self) -> Result<Option<Error>> {
        Ok(None)
    }

    pub fn socket_addr(&self) -> Result<SocketAddr> {
        let path = self.0.path()?;
        Ok(path_to_local_addr(path.to_str().unwrap_or("")))
    }

    pub fn nonblocking(&self) -> Result<bool> {
        Err(Error::new(ErrorKind::Other, "TcpListener::nonblocking not implemented"))
    }

    pub fn only_v6(&self) -> Result<bool> {
        Err(Error::new(ErrorKind::Other, "TcpListener::only_v6 not implemented"))
    }

    pub fn ttl(&self) -> Result<u32> {
        let mut ttl = [0];
        let file = self.0.dup(b"ttl")?;
        file.read(&mut ttl)?;
        Ok(ttl[0] as u32)
    }

    pub fn set_nonblocking(&self, _nonblocking: bool) -> Result<()> {
        Err(Error::new(ErrorKind::Other, "TcpListener::set_nonblocking not implemented"))
    }

    pub fn set_only_v6(&self, _only_v6: bool) -> Result<()> {
        Err(Error::new(ErrorKind::Other, "TcpListener::set_only_v6 not implemented"))
    }

    pub fn set_ttl(&self, ttl: u32) -> Result<()> {
        let file = self.0.dup(b"ttl")?;
        file.write(&[cmp::min(ttl, 255) as u8])?;
        Ok(())
    }
}

impl AsInner<File> for TcpListener {
    fn as_inner(&self) -> &File { &self.0 }
}

impl FromInner<File> for TcpListener {
    fn from_inner(file: File) -> TcpListener {
        TcpListener(file)
    }
}

impl IntoInner<File> for TcpListener {
    fn into_inner(self) -> File { self.0 }
}
<|endoftext|>


<commit_before>use super::*;

pub(super) fn mod_items(p: &mut Parser) {
    many(p, |p| {
        skip_to_first(
            p, item_first, mod_item,
            "expected item",
        )
    });
}

fn item_first(p: &Parser) -> bool {
    match p.current() {
        STRUCT_KW | FN_KW => true,
        _ => false,
    }
}

fn mod_item(p: &mut Parser) {
    if item(p) {
        if p.current() == SEMI {
            node(p, ERROR, |p| {
                p.error()
                    .message("expected item, found `;`\n\
                              consider removing this semicolon")
                    .emit();
                p.bump();
            })
        }
    }
}

fn item(p: &mut Parser) -> bool {
    attributes::outer_attributes(p);
    visibility(p);
    node_if(p, STRUCT_KW, STRUCT_ITEM, struct_item)
        || node_if(p, FN_KW, FN_ITEM, fn_item)
}

fn struct_item(p: &mut Parser) {
    p.expect(IDENT)
        && p.curly_block(|p| comma_list(p, EOF, struct_field));
}

fn struct_field(p: &mut Parser) -> bool {
    node_if(p, IDENT, STRUCT_FIELD, |p| {
        p.expect(COLON) && p.expect(IDENT);
    })
}

fn fn_item(p: &mut Parser) {
    p.expect(IDENT) && p.expect(L_PAREN) && p.expect(R_PAREN)
        && p.curly_block(|p| ());
}

<commit_msg>Musings about items<commit_after>use super::*;

pub(super) fn mod_items(p: &mut Parser) {
    many(p, |p| {
        skip_to_first(
            p, item_first, mod_item,
            "expected item",
        )
    });
}

fn item_first(p: &Parser) -> bool {
    match p.current() {
        STRUCT_KW | FN_KW => true,
        _ => false,
    }
}

fn mod_item(p: &mut Parser) {
    if item(p) {
        if p.current() == SEMI {
            node(p, ERROR, |p| {
                p.error()
                    .message("expected item, found `;`\n\
                              consider removing this semicolon")
                    .emit();
                p.bump();
            })
        }
    }
}

fn item(p: &mut Parser) -> bool {
    attributes::outer_attributes(p);
    visibility(p);
    //    node_if(p, USE_KW, USE_ITEM, use_item)
    // || extern crate_fn
    // || node_if(p, STATIC_KW, STATIC_ITEM, static_item)
    // || node_if(p, CONST_KW, CONST_ITEM, const_item) or const FN!
    // || unsafe trait, impl
    // || node_if(p, FN_KW, FN_ITEM, fn_item)
    // || node_if(p, MOD_KW, MOD_ITEM, mod_item)
    // || node_if(p, TYPE_KW, TYPE_ITEM, type_item)
    node_if(p, STRUCT_KW, STRUCT_ITEM, struct_item)
        || node_if(p, FN_KW, FN_ITEM, fn_item)
}

fn struct_item(p: &mut Parser) {
    p.expect(IDENT)
        && p.curly_block(|p| comma_list(p, EOF, struct_field));
}

fn struct_field(p: &mut Parser) -> bool {
    node_if(p, IDENT, STRUCT_FIELD, |p| {
        p.expect(COLON) && p.expect(IDENT);
    })
}

fn fn_item(p: &mut Parser) {
    p.expect(IDENT) && p.expect(L_PAREN) && p.expect(R_PAREN)
        && p.curly_block(|p| ());
}

<|endoftext|>


<commit_before>use crate::ast::{Enum, Field, Input, Struct, Variant};
use crate::attr::Attrs;
use quote::ToTokens;
use std::collections::BTreeSet as Set;
use syn::{Error, Member, Result};

pub(crate) const CHECKED: &str = "checked in validation";

impl Input<'_> {
    pub(crate) fn validate(&self) -> Result<()> {
        match self {
            Input::Struct(input) => input.validate(),
            Input::Enum(input) => input.validate(),
        }
    }
}

impl Struct<'_> {
    fn validate(&self) -> Result<()> {
        check_non_field_attrs(&self.attrs)?;
        check_field_attrs(&self.fields)?;
        for field in &self.fields {
            field.validate()?;
        }
        Ok(())
    }
}

impl Enum<'_> {
    fn validate(&self) -> Result<()> {
        check_non_field_attrs(&self.attrs)?;
        let has_display = self.has_display();
        for variant in &self.variants {
            variant.validate()?;
            if has_display && variant.attrs.display.is_none() {
                return Err(Error::new_spanned(
                    variant.original,
                    "missing #[error(\"...\")] display attribute",
                ));
            }
        }
        let mut from_types = Set::new();
        for variant in &self.variants {
            if let Some(from_field) = variant.from_field() {
                let repr = from_field.ty.to_token_stream().to_string();
                if !from_types.insert(repr) {
                    return Err(Error::new_spanned(
                        from_field.original,
                        "cannot derive From because another variant has the same source type",
                    ));
                }
            }
        }
        Ok(())
    }
}

impl Variant<'_> {
    fn validate(&self) -> Result<()> {
        check_non_field_attrs(&self.attrs)?;
        check_field_attrs(&self.fields)?;
        for field in &self.fields {
            field.validate()?;
        }
        Ok(())
    }
}

impl Field<'_> {
    fn validate(&self) -> Result<()> {
        if let Some(display) = &self.attrs.display {
            return Err(Error::new_spanned(
                display.original,
                "not expected here; the #[error(...)] attribute belongs on top of a struct or an enum variant",
            ));
        }
        Ok(())
    }
}

fn check_non_field_attrs(attrs: &Attrs) -> Result<()> {
    if let Some(from) = &attrs.from {
        return Err(Error::new_spanned(
            from,
            "not expected here; the #[from] attribute belongs on a specific field",
        ));
    }
    if let Some(source) = &attrs.source {
        return Err(Error::new_spanned(
            source,
            "not expected here; the #[source] attribute belongs on a specific field",
        ));
    }
    if let Some(backtrace) = &attrs.backtrace {
        return Err(Error::new_spanned(
            backtrace,
            "not expected here; the #[backtrace] attribute belongs on a specific field",
        ));
    }
    Ok(())
}

fn check_field_attrs(fields: &[Field]) -> Result<()> {
    let mut from_field = None;
    let mut source_field = None;
    let mut backtrace_field = None;
    let mut has_backtrace = false;
    for field in fields {
        if let Some(from) = field.attrs.from {
            if from_field.is_some() {
                return Err(Error::new_spanned(from, "duplicate #[from] attribute"));
            }
            from_field = Some(field);
        }
        if let Some(source) = field.attrs.source {
            if source_field.is_some() {
                return Err(Error::new_spanned(source, "duplicate #[source] attribute"));
            }
            source_field = Some(field);
        }
        if let Some(backtrace) = field.attrs.backtrace {
            if backtrace_field.is_some() {
                return Err(Error::new_spanned(
                    backtrace,
                    "duplicate #[backtrace] attribute",
                ));
            }
            backtrace_field = Some(field);
            has_backtrace = true;
        }
        has_backtrace |= field.is_backtrace();
    }
    if let (Some(from_field), Some(source_field)) = (from_field, source_field) {
        if !same_member(from_field, source_field) {
            return Err(Error::new_spanned(
                from_field.attrs.from,
                "#[from] is only supported on the source field, not any other field",
            ));
        }
    }
    if let Some(from_field) = from_field {
        if fields.len() > 1 + has_backtrace as usize {
            return Err(Error::new_spanned(
                from_field.attrs.from,
                "deriving From requires no fields other than source and backtrace",
            ));
        }
    }
    Ok(())
}

fn same_member(one: &Field, two: &Field) -> bool {
    match (&one.member, &two.member) {
        (Member::Named(one), Member::Named(two)) => one == two,
        (Member::Unnamed(one), Member::Unnamed(two)) => one.index == two.index,
        _ => unreachable!(),
    }
}
<commit_msg>Validate transparent attribute<commit_after>use crate::ast::{Enum, Field, Input, Struct, Variant};
use crate::attr::Attrs;
use quote::ToTokens;
use std::collections::BTreeSet as Set;
use syn::{Error, Member, Result};

pub(crate) const CHECKED: &str = "checked in validation";

impl Input<'_> {
    pub(crate) fn validate(&self) -> Result<()> {
        match self {
            Input::Struct(input) => input.validate(),
            Input::Enum(input) => input.validate(),
        }
    }
}

impl Struct<'_> {
    fn validate(&self) -> Result<()> {
        check_non_field_attrs(&self.attrs)?;
        if let Some(transparent) = self.attrs.transparent {
            if self.fields.len() != 1 {
                return Err(Error::new_spanned(
                    transparent,
                    "#[error(transparent)] requires exactly one field",
                ));
            }
            if let Some(source) = self.fields.iter().filter_map(|f| f.attrs.source).next() {
                return Err(Error::new_spanned(
                    source,
                    "transparent error struct can't contain #[source]",
                ));
            }
        }
        check_field_attrs(&self.fields)?;
        for field in &self.fields {
            field.validate()?;
        }
        Ok(())
    }
}

impl Enum<'_> {
    fn validate(&self) -> Result<()> {
        check_non_field_attrs(&self.attrs)?;
        let has_display = self.has_display();
        for variant in &self.variants {
            variant.validate()?;
            if has_display && variant.attrs.display.is_none() && variant.attrs.transparent.is_none()
            {
                return Err(Error::new_spanned(
                    variant.original,
                    "missing #[error(\"...\")] display attribute",
                ));
            }
        }
        let mut from_types = Set::new();
        for variant in &self.variants {
            if let Some(from_field) = variant.from_field() {
                let repr = from_field.ty.to_token_stream().to_string();
                if !from_types.insert(repr) {
                    return Err(Error::new_spanned(
                        from_field.original,
                        "cannot derive From because another variant has the same source type",
                    ));
                }
            }
        }
        Ok(())
    }
}

impl Variant<'_> {
    fn validate(&self) -> Result<()> {
        check_non_field_attrs(&self.attrs)?;
        if self.attrs.transparent.is_some() {
            if self.fields.len() != 1 {
                return Err(Error::new_spanned(
                    self.original,
                    "#[error(transparent)] requires exactly one field",
                ));
            }
            if let Some(source) = self.fields.iter().filter_map(|f| f.attrs.source).next() {
                return Err(Error::new_spanned(
                    source,
                    "transparent variant can't contain #[source]",
                ));
            }
        }
        check_field_attrs(&self.fields)?;
        for field in &self.fields {
            field.validate()?;
        }
        Ok(())
    }
}

impl Field<'_> {
    fn validate(&self) -> Result<()> {
        if let Some(display) = &self.attrs.display {
            return Err(Error::new_spanned(
                display.original,
                "not expected here; the #[error(...)] attribute belongs on top of a struct or an enum variant",
            ));
        }
        Ok(())
    }
}

fn check_non_field_attrs(attrs: &Attrs) -> Result<()> {
    if let Some(from) = &attrs.from {
        return Err(Error::new_spanned(
            from,
            "not expected here; the #[from] attribute belongs on a specific field",
        ));
    }
    if let Some(source) = &attrs.source {
        return Err(Error::new_spanned(
            source,
            "not expected here; the #[source] attribute belongs on a specific field",
        ));
    }
    if let Some(backtrace) = &attrs.backtrace {
        return Err(Error::new_spanned(
            backtrace,
            "not expected here; the #[backtrace] attribute belongs on a specific field",
        ));
    }
    if let Some(display) = &attrs.display {
        if attrs.transparent.is_some() {
            return Err(Error::new_spanned(
                display.original,
                "cannot have both #[error(transparent)] and a display attribute",
            ));
        }
    }
    Ok(())
}

fn check_field_attrs(fields: &[Field]) -> Result<()> {
    let mut from_field = None;
    let mut source_field = None;
    let mut backtrace_field = None;
    let mut has_backtrace = false;
    for field in fields {
        if let Some(from) = field.attrs.from {
            if from_field.is_some() {
                return Err(Error::new_spanned(from, "duplicate #[from] attribute"));
            }
            from_field = Some(field);
        }
        if let Some(source) = field.attrs.source {
            if source_field.is_some() {
                return Err(Error::new_spanned(source, "duplicate #[source] attribute"));
            }
            source_field = Some(field);
        }
        if let Some(backtrace) = field.attrs.backtrace {
            if backtrace_field.is_some() {
                return Err(Error::new_spanned(
                    backtrace,
                    "duplicate #[backtrace] attribute",
                ));
            }
            backtrace_field = Some(field);
            has_backtrace = true;
        }
        has_backtrace |= field.is_backtrace();
    }
    if let (Some(from_field), Some(source_field)) = (from_field, source_field) {
        if !same_member(from_field, source_field) {
            return Err(Error::new_spanned(
                from_field.attrs.from,
                "#[from] is only supported on the source field, not any other field",
            ));
        }
    }
    if let Some(from_field) = from_field {
        if fields.len() > 1 + has_backtrace as usize {
            return Err(Error::new_spanned(
                from_field.attrs.from,
                "deriving From requires no fields other than source and backtrace",
            ));
        }
    }
    Ok(())
}

fn same_member(one: &Field, two: &Field) -> bool {
    match (&one.member, &two.member) {
        (Member::Named(one), Member::Named(two)) => one == two,
        (Member::Unnamed(one), Member::Unnamed(two)) => one.index == two.index,
        _ => unreachable!(),
    }
}
<|endoftext|>