<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.

#![no_std]
#![allow(unused_attributes)]
#![unstable(feature = "alloc_jemalloc",
            reason = "this library is unlikely to be stabilized in its current \
                      form or name",
            issue = "27783")]
#![deny(warnings)]
#![feature(alloc)]
#![feature(alloc_system)]
#![feature(libc)]
#![feature(linkage)]
#![feature(staged_api)]
#![feature(rustc_attrs)]
#![cfg_attr(dummy_jemalloc, allow(dead_code, unused_extern_crates))]
#![cfg_attr(not(dummy_jemalloc), feature(allocator_api))]
#![rustc_alloc_kind = "exe"]

extern crate alloc;
extern crate alloc_system;
extern crate libc;

#[cfg(not(dummy_jemalloc))]
pub use contents::*;
#[cfg(not(dummy_jemalloc))]
mod contents {
    use core::ptr;

    use alloc::heap::{Alloc, AllocErr, Layout};
    use alloc_system::System;
    use libc::{c_int, c_void, size_t};

    // Note that the symbols here are prefixed by default on macOS and Windows (we
    // don't explicitly request it), and on Android and DragonFly we explicitly
    // request it as unprefixing cause segfaults (mismatches in allocators).
    extern "C" {
        #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
                       target_os = "dragonfly", target_os = "windows", target_env = "musl"),
                   link_name = "je_mallocx")]
        fn mallocx(size: size_t, flags: c_int) -> *mut c_void;
        #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
                       target_os = "dragonfly", target_os = "windows", target_env = "musl"),
                   link_name = "je_calloc")]
        fn calloc(size: size_t, flags: c_int) -> *mut c_void;
        #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
                       target_os = "dragonfly", target_os = "windows", target_env = "musl"),
                   link_name = "je_rallocx")]
        fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
        #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
                       target_os = "dragonfly", target_os = "windows", target_env = "musl"),
                   link_name = "je_xallocx")]
        fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
        #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
                       target_os = "dragonfly", target_os = "windows", target_env = "musl"),
                   link_name = "je_sdallocx")]
        fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
        #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
                       target_os = "dragonfly", target_os = "windows", target_env = "musl"),
                   link_name = "je_nallocx")]
        fn nallocx(size: size_t, flags: c_int) -> size_t;
    }

    const MALLOCX_ZERO: c_int = 0x40;

    // The minimum alignment guaranteed by the architecture. This value is used to
    // add fast paths for low alignment values. In practice, the alignment is a
    // constant at the call site and the branch will be optimized out.
    #[cfg(all(any(target_arch = "arm",
                  target_arch = "mips",
                  target_arch = "powerpc")))]
    const MIN_ALIGN: usize = 8;
    #[cfg(all(any(target_arch = "x86",
                  target_arch = "x86_64",
                  target_arch = "aarch64",
                  target_arch = "powerpc64",
                  target_arch = "mips64",
                  target_arch = "s390x",
                  target_arch = "sparc64")))]
    const MIN_ALIGN: usize = 16;

    // MALLOCX_ALIGN(a) macro
    fn mallocx_align(a: usize) -> c_int {
        a.trailing_zeros() as c_int
    }

    fn align_to_flags(align: usize) -> c_int {
        if align <= MIN_ALIGN {
            0
        } else {
            mallocx_align(align)
        }
    }

    // for symbol names src/librustc/middle/allocator.rs
    // for signatures src/librustc_allocator/lib.rs

    // linkage directives are provided as part of the current compiler allocator
    // ABI

    #[no_mangle]
    #[linkage = "external"]
    pub unsafe extern fn __rde_alloc(size: usize,
                                     align: usize,
                                     err: *mut u8) -> *mut u8 {
        let flags = align_to_flags(align);
        let ptr = mallocx(size as size_t, flags) as *mut u8;
        if ptr.is_null() {
            let layout = Layout::from_size_align_unchecked(size, align);
            ptr::write(err as *mut AllocErr,
                       AllocErr::Exhausted { request: layout });
        }
        ptr
    }

    #[no_mangle]
    #[linkage = "external"]
    pub unsafe extern fn __rde_oom(err: *const u8) -> ! {
        System.oom((*(err as *const AllocErr)).clone())
    }

    #[no_mangle]
    #[linkage = "external"]
    pub unsafe extern fn __rde_dealloc(ptr: *mut u8,
                                       size: usize,
                                       align: usize) {
        let flags = align_to_flags(align);
        sdallocx(ptr as *mut c_void, size, flags);
    }

    #[no_mangle]
    #[linkage = "external"]
    pub unsafe extern fn __rde_usable_size(layout: *const u8,
                                           min: *mut usize,
                                           max: *mut usize) {
        let layout = &*(layout as *const Layout);
        let flags = align_to_flags(layout.align());
        let size = nallocx(layout.size(), flags) as usize;
        *min = layout.size();
        if size > 0 {
            *max = size;
        } else {
            *max = layout.size();
        }
    }

    #[no_mangle]
    #[linkage = "external"]
    pub unsafe extern fn __rde_realloc(ptr: *mut u8,
                                       _old_size: usize,
                                       old_align: usize,
                                       new_size: usize,
                                       new_align: usize,
                                       err: *mut u8) -> *mut u8 {
        if new_align != old_align {
            ptr::write(err as *mut AllocErr,
                       AllocErr::Unsupported { details: "can't change alignments" });
            return 0 as *mut u8
        }

        let flags = align_to_flags(new_align);
        let ptr = rallocx(ptr as *mut c_void, new_size, flags) as *mut u8;
        if ptr.is_null() {
            let layout = Layout::from_size_align_unchecked(new_size, new_align);
            ptr::write(err as *mut AllocErr,
                       AllocErr::Exhausted { request: layout });
        }
        ptr
    }

    #[no_mangle]
    #[linkage = "external"]
    pub unsafe extern fn __rde_alloc_zeroed(size: usize,
                                            align: usize,
                                            err: *mut u8) -> *mut u8 {
        let ptr = if align <= MIN_ALIGN {
            calloc(size as size_t, 1) as *mut u8
        } else {
            let flags = align_to_flags(align) | MALLOCX_ZERO;
            mallocx(size as size_t, flags) as *mut u8
        };
        if ptr.is_null() {
            let layout = Layout::from_size_align_unchecked(size, align);
            ptr::write(err as *mut AllocErr,
                       AllocErr::Exhausted { request: layout });
        }
        ptr
    }

    #[no_mangle]
    #[linkage = "external"]
    pub unsafe extern fn __rde_alloc_excess(size: usize,
                                            align: usize,
                                            excess: *mut usize,
                                            err: *mut u8) -> *mut u8 {
        let p = __rde_alloc(size, align, err);
        if !p.is_null() {
            *excess = size;
        }
        return p
    }

    #[no_mangle]
    #[linkage = "external"]
    pub unsafe extern fn __rde_realloc_excess(ptr: *mut u8,
                                              old_size: usize,
                                              old_align: usize,
                                              new_size: usize,
                                              new_align: usize,
                                              excess: *mut usize,
                                              err: *mut u8) -> *mut u8 {
        let p = __rde_realloc(ptr, old_size, old_align, new_size, new_align, err);
        if !p.is_null() {
            *excess = new_size;
        }
        return p
    }

    #[no_mangle]
    #[linkage = "external"]
    pub unsafe extern fn __rde_grow_in_place(ptr: *mut u8,
                                             old_size: usize,
                                             old_align: usize,
                                             new_size: usize,
                                             new_align: usize) -> u8 {
        __rde_shrink_in_place(ptr, old_size, old_align, new_size, new_align)
    }

    #[no_mangle]
    #[linkage = "external"]
    pub unsafe extern fn __rde_shrink_in_place(ptr: *mut u8,
                                               _old_size: usize,
                                               old_align: usize,
                                               new_size: usize,
                                               new_align: usize) -> u8 {
        if old_align == new_align {
            let flags = align_to_flags(new_align);
            (xallocx(ptr as *mut c_void, new_size, 0, flags) == new_size) as u8
        } else {
            0
        }
    }
}
<commit_msg>Auto merge of #45514 - gnzlbg:jemalloc_realloc2, r=sfackler<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.

#![no_std]
#![allow(unused_attributes)]
#![unstable(feature = "alloc_jemalloc",
            reason = "this library is unlikely to be stabilized in its current \
                      form or name",
            issue = "27783")]
#![deny(warnings)]
#![feature(alloc)]
#![feature(alloc_system)]
#![feature(libc)]
#![feature(linkage)]
#![feature(staged_api)]
#![feature(rustc_attrs)]
#![cfg_attr(dummy_jemalloc, allow(dead_code, unused_extern_crates))]
#![cfg_attr(not(dummy_jemalloc), feature(allocator_api))]
#![rustc_alloc_kind = "exe"]

extern crate alloc;
extern crate alloc_system;
extern crate libc;

#[cfg(not(dummy_jemalloc))]
pub use contents::*;
#[cfg(not(dummy_jemalloc))]
mod contents {
    use core::ptr;

    use alloc::heap::{Alloc, AllocErr, Layout};
    use alloc_system::System;
    use libc::{c_int, c_void, size_t};

    // Note that the symbols here are prefixed by default on macOS and Windows (we
    // don't explicitly request it), and on Android and DragonFly we explicitly
    // request it as unprefixing cause segfaults (mismatches in allocators).
    extern "C" {
        #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
                       target_os = "dragonfly", target_os = "windows", target_env = "musl"),
                   link_name = "je_mallocx")]
        fn mallocx(size: size_t, flags: c_int) -> *mut c_void;
        #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
                       target_os = "dragonfly", target_os = "windows", target_env = "musl"),
                   link_name = "je_calloc")]
        fn calloc(size: size_t, flags: c_int) -> *mut c_void;
        #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
                       target_os = "dragonfly", target_os = "windows", target_env = "musl"),
                   link_name = "je_rallocx")]
        fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
        #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
                       target_os = "dragonfly", target_os = "windows", target_env = "musl"),
                   link_name = "je_xallocx")]
        fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
        #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
                       target_os = "dragonfly", target_os = "windows", target_env = "musl"),
                   link_name = "je_sdallocx")]
        fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
        #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
                       target_os = "dragonfly", target_os = "windows", target_env = "musl"),
                   link_name = "je_nallocx")]
        fn nallocx(size: size_t, flags: c_int) -> size_t;
    }

    const MALLOCX_ZERO: c_int = 0x40;

    // The minimum alignment guaranteed by the architecture. This value is used to
    // add fast paths for low alignment values. In practice, the alignment is a
    // constant at the call site and the branch will be optimized out.
    #[cfg(all(any(target_arch = "arm",
                  target_arch = "mips",
                  target_arch = "powerpc")))]
    const MIN_ALIGN: usize = 8;
    #[cfg(all(any(target_arch = "x86",
                  target_arch = "x86_64",
                  target_arch = "aarch64",
                  target_arch = "powerpc64",
                  target_arch = "mips64",
                  target_arch = "s390x",
                  target_arch = "sparc64")))]
    const MIN_ALIGN: usize = 16;

    // MALLOCX_ALIGN(a) macro
    fn mallocx_align(a: usize) -> c_int {
        a.trailing_zeros() as c_int
    }

    fn align_to_flags(align: usize) -> c_int {
        if align <= MIN_ALIGN {
            0
        } else {
            mallocx_align(align)
        }
    }

    // for symbol names src/librustc/middle/allocator.rs
    // for signatures src/librustc_allocator/lib.rs

    // linkage directives are provided as part of the current compiler allocator
    // ABI

    #[no_mangle]
    #[linkage = "external"]
    pub unsafe extern fn __rde_alloc(size: usize,
                                     align: usize,
                                     err: *mut u8) -> *mut u8 {
        let flags = align_to_flags(align);
        let ptr = mallocx(size as size_t, flags) as *mut u8;
        if ptr.is_null() {
            let layout = Layout::from_size_align_unchecked(size, align);
            ptr::write(err as *mut AllocErr,
                       AllocErr::Exhausted { request: layout });
        }
        ptr
    }

    #[no_mangle]
    #[linkage = "external"]
    pub unsafe extern fn __rde_oom(err: *const u8) -> ! {
        System.oom((*(err as *const AllocErr)).clone())
    }

    #[no_mangle]
    #[linkage = "external"]
    pub unsafe extern fn __rde_dealloc(ptr: *mut u8,
                                       size: usize,
                                       align: usize) {
        let flags = align_to_flags(align);
        sdallocx(ptr as *mut c_void, size, flags);
    }

    #[no_mangle]
    #[linkage = "external"]
    pub unsafe extern fn __rde_usable_size(layout: *const u8,
                                           min: *mut usize,
                                           max: *mut usize) {
        let layout = &*(layout as *const Layout);
        let flags = align_to_flags(layout.align());
        let size = nallocx(layout.size(), flags) as usize;
        *min = layout.size();
        if size > 0 {
            *max = size;
        } else {
            *max = layout.size();
        }
    }

    #[no_mangle]
    #[linkage = "external"]
    pub unsafe extern fn __rde_realloc(ptr: *mut u8,
                                       _old_size: usize,
                                       old_align: usize,
                                       new_size: usize,
                                       new_align: usize,
                                       err: *mut u8) -> *mut u8 {
        if new_align != old_align {
            ptr::write(err as *mut AllocErr,
                       AllocErr::Unsupported { details: "can't change alignments" });
            return 0 as *mut u8
        }

        let flags = align_to_flags(new_align);
        let ptr = rallocx(ptr as *mut c_void, new_size, flags) as *mut u8;
        if ptr.is_null() {
            let layout = Layout::from_size_align_unchecked(new_size, new_align);
            ptr::write(err as *mut AllocErr,
                       AllocErr::Exhausted { request: layout });
        }
        ptr
    }

    #[no_mangle]
    #[linkage = "external"]
    pub unsafe extern fn __rde_alloc_zeroed(size: usize,
                                            align: usize,
                                            err: *mut u8) -> *mut u8 {
        let ptr = if align <= MIN_ALIGN {
            calloc(size as size_t, 1) as *mut u8
        } else {
            let flags = align_to_flags(align) | MALLOCX_ZERO;
            mallocx(size as size_t, flags) as *mut u8
        };
        if ptr.is_null() {
            let layout = Layout::from_size_align_unchecked(size, align);
            ptr::write(err as *mut AllocErr,
                       AllocErr::Exhausted { request: layout });
        }
        ptr
    }

    #[no_mangle]
    #[linkage = "external"]
    pub unsafe extern fn __rde_alloc_excess(size: usize,
                                            align: usize,
                                            excess: *mut usize,
                                            err: *mut u8) -> *mut u8 {
        let p = __rde_alloc(size, align, err);
        if !p.is_null() {
            let flags = align_to_flags(align);
            *excess = nallocx(size, flags) as usize;
        }
        return p
    }

    #[no_mangle]
    #[linkage = "external"]
    pub unsafe extern fn __rde_realloc_excess(ptr: *mut u8,
                                              old_size: usize,
                                              old_align: usize,
                                              new_size: usize,
                                              new_align: usize,
                                              excess: *mut usize,
                                              err: *mut u8) -> *mut u8 {
        let p = __rde_realloc(ptr, old_size, old_align, new_size, new_align, err);
        if !p.is_null() {
            let flags = align_to_flags(new_align);
            *excess = nallocx(new_size, flags) as usize;
        }
        p
    }

    #[no_mangle]
    #[linkage = "external"]
    pub unsafe extern fn __rde_grow_in_place(ptr: *mut u8,
                                             old_size: usize,
                                             old_align: usize,
                                             new_size: usize,
                                             new_align: usize) -> u8 {
        __rde_shrink_in_place(ptr, old_size, old_align, new_size, new_align)
    }

    #[no_mangle]
    #[linkage = "external"]
    pub unsafe extern fn __rde_shrink_in_place(ptr: *mut u8,
                                               _old_size: usize,
                                               old_align: usize,
                                               new_size: usize,
                                               new_align: usize) -> u8 {
        if old_align == new_align {
            let flags = align_to_flags(new_align);
            (xallocx(ptr as *mut c_void, new_size, 0, flags) == new_size) as u8
        } else {
            0
        }
    }
}
<|endoftext|>


<commit_before>pub use self::Level::*;
use rustc_ast::node_id::{NodeId, NodeMap};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
use rustc_errors::{pluralize, Applicability, DiagnosticBuilder};
use rustc_span::edition::Edition;
use rustc_span::{sym, symbol::Ident, MultiSpan, Span, Symbol};

pub mod builtin;

/// Setting for how to handle a lint.
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
pub enum Level {
    Allow,
    Warn,
    Deny,
    Forbid,
}

rustc_data_structures::impl_stable_hash_via_hash!(Level);

impl Level {
    /// Converts a level to a lower-case string.
    pub fn as_str(self) -> &'static str {
        match self {
            Level::Allow => "allow",
            Level::Warn => "warn",
            Level::Deny => "deny",
            Level::Forbid => "forbid",
        }
    }

    /// Converts a lower-case string to a level.
    pub fn from_str(x: &str) -> Option<Level> {
        match x {
            "allow" => Some(Level::Allow),
            "warn" => Some(Level::Warn),
            "deny" => Some(Level::Deny),
            "forbid" => Some(Level::Forbid),
            _ => None,
        }
    }

    /// Converts a symbol to a level.
    pub fn from_symbol(x: Symbol) -> Option<Level> {
        match x {
            sym::allow => Some(Level::Allow),
            sym::warn => Some(Level::Warn),
            sym::deny => Some(Level::Deny),
            sym::forbid => Some(Level::Forbid),
            _ => None,
        }
    }
}

/// Specification of a single lint.
#[derive(Copy, Clone, Debug)]
pub struct Lint {
    /// A string identifier for the lint.
    ///
    /// This identifies the lint in attributes and in command-line arguments.
    /// In those contexts it is always lowercase, but this field is compared
    /// in a way which is case-insensitive for ASCII characters. This allows
    /// `declare_lint!()` invocations to follow the convention of upper-case
    /// statics without repeating the name.
    ///
    /// The name is written with underscores, e.g., "unused_imports".
    /// On the command line, underscores become dashes.
    pub name: &'static str,

    /// Default level for the lint.
    pub default_level: Level,

    /// Description of the lint or the issue it detects.
    ///
    /// e.g., "imports that are never used"
    pub desc: &'static str,

    /// Starting at the given edition, default to the given lint level. If this is `None`, then use
    /// `default_level`.
    pub edition_lint_opts: Option<(Edition, Level)>,

    /// `true` if this lint is reported even inside expansions of external macros.
    pub report_in_external_macro: bool,

    pub future_incompatible: Option<FutureIncompatibleInfo>,

    pub is_plugin: bool,
}

/// Extra information for a future incompatibility lint.
#[derive(Copy, Clone, Debug)]
pub struct FutureIncompatibleInfo {
    /// e.g., a URL for an issue/PR/RFC or error code
    pub reference: &'static str,
    /// If this is an edition fixing lint, the edition in which
    /// this lint becomes obsolete
    pub edition: Option<Edition>,
}

impl Lint {
    pub const fn default_fields_for_macro() -> Self {
        Lint {
            name: "",
            default_level: Level::Forbid,
            desc: "",
            edition_lint_opts: None,
            is_plugin: false,
            report_in_external_macro: false,
            future_incompatible: None,
        }
    }

    /// Gets the lint's name, with ASCII letters converted to lowercase.
    pub fn name_lower(&self) -> String {
        self.name.to_ascii_lowercase()
    }

    pub fn default_level(&self, edition: Edition) -> Level {
        self.edition_lint_opts
            .filter(|(e, _)| *e <= edition)
            .map(|(_, l)| l)
            .unwrap_or(self.default_level)
    }
}

/// Identifies a lint known to the compiler.
#[derive(Clone, Copy, Debug)]
pub struct LintId {
    // Identity is based on pointer equality of this field.
    pub lint: &'static Lint,
}

impl PartialEq for LintId {
    fn eq(&self, other: &LintId) -> bool {
        std::ptr::eq(self.lint, other.lint)
    }
}

impl Eq for LintId {}

impl std::hash::Hash for LintId {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        let ptr = self.lint as *const Lint;
        ptr.hash(state);
    }
}

impl LintId {
    /// Gets the `LintId` for a `Lint`.
    pub fn of(lint: &'static Lint) -> LintId {
        LintId { lint }
    }

    pub fn lint_name_raw(&self) -> &'static str {
        self.lint.name
    }

    /// Gets the name of the lint.
    pub fn to_string(&self) -> String {
        self.lint.name_lower()
    }
}

impl<HCX> HashStable<HCX> for LintId {
    #[inline]
    fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
        self.lint_name_raw().hash_stable(hcx, hasher);
    }
}

impl<HCX> ToStableHashKey<HCX> for LintId {
    type KeyType = &'static str;

    #[inline]
    fn to_stable_hash_key(&self, _: &HCX) -> &'static str {
        self.lint_name_raw()
    }
}

// This could be a closure, but then implementing derive trait
// becomes hacky (and it gets allocated).
#[derive(PartialEq)]
pub enum BuiltinLintDiagnostics {
    Normal,
    BareTraitObject(Span, /* is_global */ bool),
    AbsPathWithModule(Span),
    ProcMacroDeriveResolutionFallback(Span),
    MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
    ElidedLifetimesInPaths(usize, Span, bool, Span, String),
    UnknownCrateTypes(Span, String, String),
    UnusedImports(String, Vec<(Span, String)>),
    RedundantImport(Vec<(Span, bool)>, Ident),
    DeprecatedMacro(Option<Symbol>, Span),
    UnusedDocComment(Span),
}

/// Lints that are buffered up early on in the `Session` before the
/// `LintLevels` is calculated.
#[derive(PartialEq)]
pub struct BufferedEarlyLint {
    /// The span of code that we are linting on.
    pub span: MultiSpan,

    /// The lint message.
    pub msg: String,

    /// The `NodeId` of the AST node that generated the lint.
    pub node_id: NodeId,

    /// A lint Id that can be passed to
    /// `rustc_lint::early::EarlyContextAndPass::check_id`.
    pub lint_id: LintId,

    /// Customization of the `DiagnosticBuilder<'_>` for the lint.
    pub diagnostic: BuiltinLintDiagnostics,
}

#[derive(Default)]
pub struct LintBuffer {
    pub map: NodeMap<Vec<BufferedEarlyLint>>,
}

impl LintBuffer {
    pub fn add_early_lint(&mut self, early_lint: BufferedEarlyLint) {
        let arr = self.map.entry(early_lint.node_id).or_default();
        if !arr.contains(&early_lint) {
            arr.push(early_lint);
        }
    }

    pub fn add_lint(
        &mut self,
        lint: &'static Lint,
        node_id: NodeId,
        span: MultiSpan,
        msg: &str,
        diagnostic: BuiltinLintDiagnostics,
    ) {
        let lint_id = LintId::of(lint);
        let msg = msg.to_string();
        self.add_early_lint(BufferedEarlyLint { lint_id, node_id, span, msg, diagnostic });
    }

    pub fn take(&mut self, id: NodeId) -> Vec<BufferedEarlyLint> {
        self.map.remove(&id).unwrap_or_default()
    }

    pub fn buffer_lint(
        &mut self,
        lint: &'static Lint,
        id: NodeId,
        sp: impl Into<MultiSpan>,
        msg: &str,
    ) {
        self.add_lint(lint, id, sp.into(), msg, BuiltinLintDiagnostics::Normal)
    }

    pub fn buffer_lint_with_diagnostic(
        &mut self,
        lint: &'static Lint,
        id: NodeId,
        sp: impl Into<MultiSpan>,
        msg: &str,
        diagnostic: BuiltinLintDiagnostics,
    ) {
        self.add_lint(lint, id, sp.into(), msg, diagnostic)
    }
}

/// Declares a static item of type `&'static Lint`.
#[macro_export]
macro_rules! declare_lint {
    ($vis: vis $NAME: ident, $Level: ident, $desc: expr) => (
        $crate::declare_lint!(
            $vis $NAME, $Level, $desc,
        );
    );
    ($vis: vis $NAME: ident, $Level: ident, $desc: expr,
     $(@future_incompatible = $fi:expr;)? $($v:ident),*) => (
        $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
            name: stringify!($NAME),
            default_level: $crate::lint::$Level,
            desc: $desc,
            edition_lint_opts: None,
            is_plugin: false,
            $($v: true,)*
            $(future_incompatible: Some($fi),)*
            ..$crate::lint::Lint::default_fields_for_macro()
        };
    );
    ($vis: vis $NAME: ident, $Level: ident, $desc: expr,
     $lint_edition: expr => $edition_level: ident
    ) => (
        $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
            name: stringify!($NAME),
            default_level: $crate::lint::$Level,
            desc: $desc,
            edition_lint_opts: Some(($lint_edition, $crate::lint::Level::$edition_level)),
            report_in_external_macro: false,
            is_plugin: false,
        };
    );
}

#[macro_export]
macro_rules! declare_tool_lint {
    (
        $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level: ident, $desc: expr
    ) => (
        $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false}
    );
    (
        $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
        report_in_external_macro: $rep:expr
    ) => (
         $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep}
    );
    (
        $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
        $external:expr
    ) => (
        $(#[$attr])*
        $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
            name: &concat!(stringify!($tool), "::", stringify!($NAME)),
            default_level: $crate::lint::$Level,
            desc: $desc,
            edition_lint_opts: None,
            report_in_external_macro: $external,
            future_incompatible: None,
            is_plugin: true,
        };
    );
}

/// Declares a static `LintArray` and return it as an expression.
#[macro_export]
macro_rules! lint_array {
    ($( $lint:expr ),* ,) => { lint_array!( $($lint),* ) };
    ($( $lint:expr ),*) => {{
        vec![$($lint),*]
    }}
}

pub type LintArray = Vec<&'static Lint>;

pub trait LintPass {
    fn name(&self) -> &'static str;
}

/// Implements `LintPass for $name` with the given list of `Lint` statics.
#[macro_export]
macro_rules! impl_lint_pass {
    ($name:ident => [$($lint:expr),* $(,)?]) => {
        impl $crate::lint::LintPass for $name {
            fn name(&self) -> &'static str { stringify!($name) }
        }
        impl $name {
            pub fn get_lints() -> $crate::lint::LintArray { $crate::lint_array!($($lint),*) }
        }
    };
}

/// Declares a type named `$name` which implements `LintPass`.
/// To the right of `=>` a comma separated list of `Lint` statics is given.
#[macro_export]
macro_rules! declare_lint_pass {
    ($(#[$m:meta])* $name:ident => [$($lint:expr),* $(,)?]) => {
        $(#[$m])* #[derive(Copy, Clone)] pub struct $name;
        $crate::impl_lint_pass!($name => [$($lint),*]);
    };
}

pub fn add_elided_lifetime_in_path_suggestion(
    sess: &crate::Session,
    db: &mut DiagnosticBuilder<'_>,
    n: usize,
    path_span: Span,
    incl_angl_brckt: bool,
    insertion_span: Span,
    anon_lts: String,
) {
    let (replace_span, suggestion) = if incl_angl_brckt {
        (insertion_span, anon_lts)
    } else {
        // When possible, prefer a suggestion that replaces the whole
        // `Path<T>` expression with `Path<'_, T>`, rather than inserting `'_, `
        // at a point (which makes for an ugly/confusing label)
        if let Ok(snippet) = sess.source_map().span_to_snippet(path_span) {
            // But our spans can get out of whack due to macros; if the place we think
            // we want to insert `'_` isn't even within the path expression's span, we
            // should bail out of making any suggestion rather than panicking on a
            // subtract-with-overflow or string-slice-out-out-bounds (!)
            // FIXME: can we do better?
            if insertion_span.lo().0 < path_span.lo().0 {
                return;
            }
            let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize;
            if insertion_index > snippet.len() {
                return;
            }
            let (before, after) = snippet.split_at(insertion_index);
            (path_span, format!("{}{}{}", before, anon_lts, after))
        } else {
            (insertion_span, anon_lts)
        }
    };
    db.span_suggestion(
        replace_span,
        &format!("indicate the anonymous lifetime{}", pluralize!(n)),
        suggestion,
        Applicability::MachineApplicable,
    );
}
<commit_msg>Allow types (with lifetimes/generics) in impl_lint_pass<commit_after>pub use self::Level::*;
use rustc_ast::node_id::{NodeId, NodeMap};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
use rustc_errors::{pluralize, Applicability, DiagnosticBuilder};
use rustc_span::edition::Edition;
use rustc_span::{sym, symbol::Ident, MultiSpan, Span, Symbol};

pub mod builtin;

/// Setting for how to handle a lint.
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
pub enum Level {
    Allow,
    Warn,
    Deny,
    Forbid,
}

rustc_data_structures::impl_stable_hash_via_hash!(Level);

impl Level {
    /// Converts a level to a lower-case string.
    pub fn as_str(self) -> &'static str {
        match self {
            Level::Allow => "allow",
            Level::Warn => "warn",
            Level::Deny => "deny",
            Level::Forbid => "forbid",
        }
    }

    /// Converts a lower-case string to a level.
    pub fn from_str(x: &str) -> Option<Level> {
        match x {
            "allow" => Some(Level::Allow),
            "warn" => Some(Level::Warn),
            "deny" => Some(Level::Deny),
            "forbid" => Some(Level::Forbid),
            _ => None,
        }
    }

    /// Converts a symbol to a level.
    pub fn from_symbol(x: Symbol) -> Option<Level> {
        match x {
            sym::allow => Some(Level::Allow),
            sym::warn => Some(Level::Warn),
            sym::deny => Some(Level::Deny),
            sym::forbid => Some(Level::Forbid),
            _ => None,
        }
    }
}

/// Specification of a single lint.
#[derive(Copy, Clone, Debug)]
pub struct Lint {
    /// A string identifier for the lint.
    ///
    /// This identifies the lint in attributes and in command-line arguments.
    /// In those contexts it is always lowercase, but this field is compared
    /// in a way which is case-insensitive for ASCII characters. This allows
    /// `declare_lint!()` invocations to follow the convention of upper-case
    /// statics without repeating the name.
    ///
    /// The name is written with underscores, e.g., "unused_imports".
    /// On the command line, underscores become dashes.
    pub name: &'static str,

    /// Default level for the lint.
    pub default_level: Level,

    /// Description of the lint or the issue it detects.
    ///
    /// e.g., "imports that are never used"
    pub desc: &'static str,

    /// Starting at the given edition, default to the given lint level. If this is `None`, then use
    /// `default_level`.
    pub edition_lint_opts: Option<(Edition, Level)>,

    /// `true` if this lint is reported even inside expansions of external macros.
    pub report_in_external_macro: bool,

    pub future_incompatible: Option<FutureIncompatibleInfo>,

    pub is_plugin: bool,
}

/// Extra information for a future incompatibility lint.
#[derive(Copy, Clone, Debug)]
pub struct FutureIncompatibleInfo {
    /// e.g., a URL for an issue/PR/RFC or error code
    pub reference: &'static str,
    /// If this is an edition fixing lint, the edition in which
    /// this lint becomes obsolete
    pub edition: Option<Edition>,
}

impl Lint {
    pub const fn default_fields_for_macro() -> Self {
        Lint {
            name: "",
            default_level: Level::Forbid,
            desc: "",
            edition_lint_opts: None,
            is_plugin: false,
            report_in_external_macro: false,
            future_incompatible: None,
        }
    }

    /// Gets the lint's name, with ASCII letters converted to lowercase.
    pub fn name_lower(&self) -> String {
        self.name.to_ascii_lowercase()
    }

    pub fn default_level(&self, edition: Edition) -> Level {
        self.edition_lint_opts
            .filter(|(e, _)| *e <= edition)
            .map(|(_, l)| l)
            .unwrap_or(self.default_level)
    }
}

/// Identifies a lint known to the compiler.
#[derive(Clone, Copy, Debug)]
pub struct LintId {
    // Identity is based on pointer equality of this field.
    pub lint: &'static Lint,
}

impl PartialEq for LintId {
    fn eq(&self, other: &LintId) -> bool {
        std::ptr::eq(self.lint, other.lint)
    }
}

impl Eq for LintId {}

impl std::hash::Hash for LintId {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        let ptr = self.lint as *const Lint;
        ptr.hash(state);
    }
}

impl LintId {
    /// Gets the `LintId` for a `Lint`.
    pub fn of(lint: &'static Lint) -> LintId {
        LintId { lint }
    }

    pub fn lint_name_raw(&self) -> &'static str {
        self.lint.name
    }

    /// Gets the name of the lint.
    pub fn to_string(&self) -> String {
        self.lint.name_lower()
    }
}

impl<HCX> HashStable<HCX> for LintId {
    #[inline]
    fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
        self.lint_name_raw().hash_stable(hcx, hasher);
    }
}

impl<HCX> ToStableHashKey<HCX> for LintId {
    type KeyType = &'static str;

    #[inline]
    fn to_stable_hash_key(&self, _: &HCX) -> &'static str {
        self.lint_name_raw()
    }
}

// This could be a closure, but then implementing derive trait
// becomes hacky (and it gets allocated).
#[derive(PartialEq)]
pub enum BuiltinLintDiagnostics {
    Normal,
    BareTraitObject(Span, /* is_global */ bool),
    AbsPathWithModule(Span),
    ProcMacroDeriveResolutionFallback(Span),
    MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
    ElidedLifetimesInPaths(usize, Span, bool, Span, String),
    UnknownCrateTypes(Span, String, String),
    UnusedImports(String, Vec<(Span, String)>),
    RedundantImport(Vec<(Span, bool)>, Ident),
    DeprecatedMacro(Option<Symbol>, Span),
    UnusedDocComment(Span),
}

/// Lints that are buffered up early on in the `Session` before the
/// `LintLevels` is calculated.
#[derive(PartialEq)]
pub struct BufferedEarlyLint {
    /// The span of code that we are linting on.
    pub span: MultiSpan,

    /// The lint message.
    pub msg: String,

    /// The `NodeId` of the AST node that generated the lint.
    pub node_id: NodeId,

    /// A lint Id that can be passed to
    /// `rustc_lint::early::EarlyContextAndPass::check_id`.
    pub lint_id: LintId,

    /// Customization of the `DiagnosticBuilder<'_>` for the lint.
    pub diagnostic: BuiltinLintDiagnostics,
}

#[derive(Default)]
pub struct LintBuffer {
    pub map: NodeMap<Vec<BufferedEarlyLint>>,
}

impl LintBuffer {
    pub fn add_early_lint(&mut self, early_lint: BufferedEarlyLint) {
        let arr = self.map.entry(early_lint.node_id).or_default();
        if !arr.contains(&early_lint) {
            arr.push(early_lint);
        }
    }

    pub fn add_lint(
        &mut self,
        lint: &'static Lint,
        node_id: NodeId,
        span: MultiSpan,
        msg: &str,
        diagnostic: BuiltinLintDiagnostics,
    ) {
        let lint_id = LintId::of(lint);
        let msg = msg.to_string();
        self.add_early_lint(BufferedEarlyLint { lint_id, node_id, span, msg, diagnostic });
    }

    pub fn take(&mut self, id: NodeId) -> Vec<BufferedEarlyLint> {
        self.map.remove(&id).unwrap_or_default()
    }

    pub fn buffer_lint(
        &mut self,
        lint: &'static Lint,
        id: NodeId,
        sp: impl Into<MultiSpan>,
        msg: &str,
    ) {
        self.add_lint(lint, id, sp.into(), msg, BuiltinLintDiagnostics::Normal)
    }

    pub fn buffer_lint_with_diagnostic(
        &mut self,
        lint: &'static Lint,
        id: NodeId,
        sp: impl Into<MultiSpan>,
        msg: &str,
        diagnostic: BuiltinLintDiagnostics,
    ) {
        self.add_lint(lint, id, sp.into(), msg, diagnostic)
    }
}

/// Declares a static item of type `&'static Lint`.
#[macro_export]
macro_rules! declare_lint {
    ($vis: vis $NAME: ident, $Level: ident, $desc: expr) => (
        $crate::declare_lint!(
            $vis $NAME, $Level, $desc,
        );
    );
    ($vis: vis $NAME: ident, $Level: ident, $desc: expr,
     $(@future_incompatible = $fi:expr;)? $($v:ident),*) => (
        $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
            name: stringify!($NAME),
            default_level: $crate::lint::$Level,
            desc: $desc,
            edition_lint_opts: None,
            is_plugin: false,
            $($v: true,)*
            $(future_incompatible: Some($fi),)*
            ..$crate::lint::Lint::default_fields_for_macro()
        };
    );
    ($vis: vis $NAME: ident, $Level: ident, $desc: expr,
     $lint_edition: expr => $edition_level: ident
    ) => (
        $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
            name: stringify!($NAME),
            default_level: $crate::lint::$Level,
            desc: $desc,
            edition_lint_opts: Some(($lint_edition, $crate::lint::Level::$edition_level)),
            report_in_external_macro: false,
            is_plugin: false,
        };
    );
}

#[macro_export]
macro_rules! declare_tool_lint {
    (
        $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level: ident, $desc: expr
    ) => (
        $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false}
    );
    (
        $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
        report_in_external_macro: $rep:expr
    ) => (
         $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep}
    );
    (
        $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
        $external:expr
    ) => (
        $(#[$attr])*
        $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
            name: &concat!(stringify!($tool), "::", stringify!($NAME)),
            default_level: $crate::lint::$Level,
            desc: $desc,
            edition_lint_opts: None,
            report_in_external_macro: $external,
            future_incompatible: None,
            is_plugin: true,
        };
    );
}

/// Declares a static `LintArray` and return it as an expression.
#[macro_export]
macro_rules! lint_array {
    ($( $lint:expr ),* ,) => { lint_array!( $($lint),* ) };
    ($( $lint:expr ),*) => {{
        vec![$($lint),*]
    }}
}

pub type LintArray = Vec<&'static Lint>;

pub trait LintPass {
    fn name(&self) -> &'static str;
}

/// Implements `LintPass for $ty` with the given list of `Lint` statics.
#[macro_export]
macro_rules! impl_lint_pass {
    ($ty:ty => [$($lint:expr),* $(,)?]) => {
        impl $crate::lint::LintPass for $ty {
            fn name(&self) -> &'static str { stringify!($ty) }
        }
        impl $ty {
            pub fn get_lints() -> $crate::lint::LintArray { $crate::lint_array!($($lint),*) }
        }
    };
}

/// Declares a type named `$name` which implements `LintPass`.
/// To the right of `=>` a comma separated list of `Lint` statics is given.
#[macro_export]
macro_rules! declare_lint_pass {
    ($(#[$m:meta])* $name:ident => [$($lint:expr),* $(,)?]) => {
        $(#[$m])* #[derive(Copy, Clone)] pub struct $name;
        $crate::impl_lint_pass!($name => [$($lint),*]);
    };
}

pub fn add_elided_lifetime_in_path_suggestion(
    sess: &crate::Session,
    db: &mut DiagnosticBuilder<'_>,
    n: usize,
    path_span: Span,
    incl_angl_brckt: bool,
    insertion_span: Span,
    anon_lts: String,
) {
    let (replace_span, suggestion) = if incl_angl_brckt {
        (insertion_span, anon_lts)
    } else {
        // When possible, prefer a suggestion that replaces the whole
        // `Path<T>` expression with `Path<'_, T>`, rather than inserting `'_, `
        // at a point (which makes for an ugly/confusing label)
        if let Ok(snippet) = sess.source_map().span_to_snippet(path_span) {
            // But our spans can get out of whack due to macros; if the place we think
            // we want to insert `'_` isn't even within the path expression's span, we
            // should bail out of making any suggestion rather than panicking on a
            // subtract-with-overflow or string-slice-out-out-bounds (!)
            // FIXME: can we do better?
            if insertion_span.lo().0 < path_span.lo().0 {
                return;
            }
            let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize;
            if insertion_index > snippet.len() {
                return;
            }
            let (before, after) = snippet.split_at(insertion_index);
            (path_span, format!("{}{}{}", before, anon_lts, after))
        } else {
            (insertion_span, anon_lts)
        }
    };
    db.span_suggestion(
        replace_span,
        &format!("indicate the anonymous lifetime{}", pluralize!(n)),
        suggestion,
        Applicability::MachineApplicable,
    );
}
<|endoftext|>


<commit_before>use crate::FileTime;
use libc::{time_t, timespec};
use std::fs;
use std::os::unix::prelude::*;

cfg_if::cfg_if! {
    if #[cfg(target_os = "linux")] {
        mod utimes;
        mod linux;
        pub use self::linux::*;
    } else if #[cfg(target_os = "macos")] {
        mod utimes;
        mod macos;
        pub use self::macos::*;
    } else if #[cfg(any(target_os = "android",
                        target_os = "solaris",
                        target_os = "emscripten",
                        target_os = "freebsd",
                        target_os = "netbsd",
                        target_os = "openbsd"))] {
        mod utimensat;
        pub use self::utimensat::*;
    } else {
        mod utimes;
        pub use self::utimes::*;
    }
}

#[allow(dead_code)]
fn to_timespec(ft: &Option<FileTime>) -> timespec {
    cfg_if::cfg_if! {
        if #[cfg(target_os = "macos")] {
            // https://github.com/apple/darwin-xnu/blob/a449c6a3b8014d9406c2ddbdc81795da24aa7443/bsd/sys/stat.h#L541
            const UTIME_OMIT: i64 = -2;
        } else {
            const UTIME_OMIT: i64 = 1_073_741_822;
        }
    }

    if let &Some(ft) = ft {
        timespec {
            tv_sec: ft.seconds() as time_t,
            tv_nsec: ft.nanoseconds() as _,
        }
    } else {
        timespec {
            tv_sec: 0,
            tv_nsec: UTIME_OMIT as _,
        }
    }
}

pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime {
    FileTime {
        seconds: meta.mtime(),
        nanos: meta.mtime_nsec() as u32,
    }
}

pub fn from_last_access_time(meta: &fs::Metadata) -> FileTime {
    FileTime {
        seconds: meta.atime(),
        nanos: meta.atime_nsec() as u32,
    }
}

pub fn from_creation_time(meta: &fs::Metadata) -> Option<FileTime> {
    macro_rules! birthtim {
        ($(($e:expr, $i:ident)),*) => {
            #[cfg(any($(target_os = $e),*))]
            fn imp(meta: &fs::Metadata) -> Option<FileTime> {
                $(
                    #[cfg(target_os = $e)]
                    use std::os::$i::fs::MetadataExt;
                )*
                Some(FileTime {
                    seconds: meta.st_birthtime(),
                    nanos: meta.st_birthtime_nsec() as u32,
                })
            }

            #[cfg(all($(not(target_os = $e)),*))]
            fn imp(_meta: &fs::Metadata) -> Option<FileTime> {
                None
            }
        }
    }

    birthtim! {
        ("bitrig", bitrig),
        ("freebsd", freebsd),
        ("ios", ios),
        ("macos", macos),
        ("openbsd", openbsd)
    }

    imp(meta)
}
<commit_msg>Add illumos target support (#51)<commit_after>use crate::FileTime;
use libc::{time_t, timespec};
use std::fs;
use std::os::unix::prelude::*;

cfg_if::cfg_if! {
    if #[cfg(target_os = "linux")] {
        mod utimes;
        mod linux;
        pub use self::linux::*;
    } else if #[cfg(target_os = "macos")] {
        mod utimes;
        mod macos;
        pub use self::macos::*;
    } else if #[cfg(any(target_os = "android",
                        target_os = "solaris",
                        target_os = "illumos",
                        target_os = "emscripten",
                        target_os = "freebsd",
                        target_os = "netbsd",
                        target_os = "openbsd"))] {
        mod utimensat;
        pub use self::utimensat::*;
    } else {
        mod utimes;
        pub use self::utimes::*;
    }
}

#[allow(dead_code)]
fn to_timespec(ft: &Option<FileTime>) -> timespec {
    cfg_if::cfg_if! {
        if #[cfg(target_os = "macos")] {
            // https://github.com/apple/darwin-xnu/blob/a449c6a3b8014d9406c2ddbdc81795da24aa7443/bsd/sys/stat.h#L541
            const UTIME_OMIT: i64 = -2;
        } else {
            const UTIME_OMIT: i64 = 1_073_741_822;
        }
    }

    if let &Some(ft) = ft {
        timespec {
            tv_sec: ft.seconds() as time_t,
            tv_nsec: ft.nanoseconds() as _,
        }
    } else {
        timespec {
            tv_sec: 0,
            tv_nsec: UTIME_OMIT as _,
        }
    }
}

pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime {
    FileTime {
        seconds: meta.mtime(),
        nanos: meta.mtime_nsec() as u32,
    }
}

pub fn from_last_access_time(meta: &fs::Metadata) -> FileTime {
    FileTime {
        seconds: meta.atime(),
        nanos: meta.atime_nsec() as u32,
    }
}

pub fn from_creation_time(meta: &fs::Metadata) -> Option<FileTime> {
    macro_rules! birthtim {
        ($(($e:expr, $i:ident)),*) => {
            #[cfg(any($(target_os = $e),*))]
            fn imp(meta: &fs::Metadata) -> Option<FileTime> {
                $(
                    #[cfg(target_os = $e)]
                    use std::os::$i::fs::MetadataExt;
                )*
                Some(FileTime {
                    seconds: meta.st_birthtime(),
                    nanos: meta.st_birthtime_nsec() as u32,
                })
            }

            #[cfg(all($(not(target_os = $e)),*))]
            fn imp(_meta: &fs::Metadata) -> Option<FileTime> {
                None
            }
        }
    }

    birthtim! {
        ("bitrig", bitrig),
        ("freebsd", freebsd),
        ("ios", ios),
        ("macos", macos),
        ("openbsd", openbsd)
    }

    imp(meta)
}
<|endoftext|>


<commit_before>//! The dump module contains code related for outputing/dumping data.
use std::fmt::Display;
use std::convert::From;
use super::errors::*;

/// Enum which provides all possible output value formats supported by the dump module.
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum OutputFormat {
    Hex,
    Decimal,
    Octal,
    Binary,
}

impl From<String> for OutputFormat {
    fn from(format_string: String) -> Self {
        match format_string.to_lowercase().as_ref() {
            "hex" => OutputFormat::Hex,
            "dec" => OutputFormat::Decimal,
            "oct" => OutputFormat::Octal,
            "bin" => OutputFormat::Binary,
            _ => panic!("Invalid output format"),
        }
    }
}

#[derive(Debug, Clone, Copy)]
pub struct OutputSettings {
    start_address: usize,
    show_address: bool,
    group_size: usize,
    columns: usize,
    show_interpretation: bool,
    output_fmt: OutputFormat,
}

impl OutputSettings {
    pub fn new() -> OutputSettings {
        OutputSettings {
            start_address: 0,
            show_address: true,
            group_size: 1,
            columns: 8,
            show_interpretation: true,
            output_fmt: OutputFormat::Hex,
        }
    }

    pub fn bytes_per_line(&self) -> usize {
        self.columns * self.group_size
    }

    pub fn start_address(mut self, address: usize) -> Self {
        self.start_address = address;
        self
    }

    pub fn show_address(mut self, show: bool) -> Self {
        self.show_address = show;
        self
    }

    pub fn group_size(mut self, size: usize) -> Self {
        self.group_size = size;
        self
    }

    pub fn columns(mut self, columns: usize) -> Self {
        self.columns = columns;
        self
    }

    pub fn show_interpretation(mut self, show: bool) -> Self {
        self.show_interpretation = show;
        self
    }

    pub fn format(mut self, fmt: OutputFormat) -> Self {
        self.output_fmt = fmt;
        self
    }
}

/// The `OutputLine` struct contains all  information needed to dump/output a single line of data.
#[derive(Debug)]
pub struct OutputLine<'a> {
    output_settings: OutputSettings,
    data: &'a [u8],
}

impl<'a> OutputLine<'a> {
    pub fn new(data: &[u8]) -> OutputLine {
        OutputLine {
            output_settings: OutputSettings::new(),
            data: data,
        }
    }

    pub fn format(self, settings: OutputSettings) -> Self {
        OutputLine {
            output_settings: settings,
            data: self.data,
        }
    }

    fn write_address(&self, f: &mut ::fmt::Formatter) -> Result<usize> {
        write!(f, "{:08.X}: ", self.output_settings.start_address)?;
        Ok(10)
    }

    fn write_bytes(&self, f: &mut ::fmt::Formatter) -> Result<usize> {
        let mut byte_count = 0;
        let mut bytes_written = 0;
        for b in self.data.iter() {
            byte_count += 1;
            let is_seperator_necessary = byte_count % self.output_settings.group_size == 0;
            if is_seperator_necessary {
                bytes_written += self.write_formated_byte(f, b)?;
                write!(f, " ")?;
                bytes_written += 1;
            } else {
                bytes_written += self.write_formated_byte(f, b)?;
            }
        }
        Ok(bytes_written)
    }

    fn write_formated_byte(&self, f: &mut ::fmt::Formatter, byte: &u8) -> Result<usize> {
        match self.output_settings.output_fmt {
            OutputFormat::Hex => {
                write!(f, "{:02.X}", byte)?;
                Ok(2)
            }
            OutputFormat::Octal => {
                write!(f, "{:03.o}", byte)?;
                Ok(3)
            }
            OutputFormat::Decimal => {
                write!(f, "{:03}", byte)?;
                Ok(3)
            }
            OutputFormat::Binary => {
                write!(f, "{:08b}", byte)?;
                Ok(8)
            }
        }
    }

    fn write_interpretation(&self, f: &mut ::fmt::Formatter) -> Result<usize> {
        write!(f, "   ");
        for b in self.data.iter() {
            match *b {
                character @ 20u8...126u8 => write!(f, "{}", character as char)?,
                _ => write!(f, "{}", ".")?,
            }
        }
        Ok(self.data.len())
    }
}

impl<'a> ::fmt::Display for OutputLine<'a> {
    fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
        let format_size = |fmt: OutputFormat| match fmt {
            OutputFormat::Hex => 2,
            OutputFormat::Octal => 3,
            OutputFormat::Decimal => 3,
            OutputFormat::Binary => 8,
        };
        if self.output_settings.show_address {
            self.write_address(f);
        }
        // FIXME NiCo: whats the issues here?!
        let bytes_written = self.write_bytes(f).unwrap();
        let expected_length = self.output_settings.columns * self.output_settings.group_size *
                              format_size(self.output_settings.output_fmt) +
                              (self.output_settings.columns);
        let padding = expected_length - bytes_written;
        for i in 0..padding {
            write!(f, " ")?;
        }
        if self.output_settings.show_interpretation {
            self.write_interpretation(f);
        }
        Ok(())
    }
}

mod test {

    use super::*;
    use std::fmt::Write;

    struct TestFixture {
        data: [u8; 8],
        small_data: [u8; 5],
    }

    impl TestFixture {
        fn new() -> Self {
            TestFixture {
                data: [0, 255, 127, 128, 56, 65, 1, 33],
                small_data: [0, 255, 80, 44, 7],
            }
        }

        fn data(&self) -> &[u8] {
            &self.data
        }

        fn small_data(&self) -> &[u8] {
            &self.small_data
        }
    }

    #[test]
    fn output_settings_can_be_constructed() {
        let output_settings = OutputSettings::new();
        assert!(true);
    }

    #[test]
    fn output_settings_builder() {
        let format = OutputFormat::Binary;
        let start_address = 0xFF00AABB;
        let group_size = 2;
        let show_address = false;
        let show_interpretation = false;

        let mut output_settings = OutputSettings::new()
            .format(format)
            .start_address(start_address)
            .group_size(group_size)
            .show_address(show_address)
            .show_interpretation(show_interpretation);

        assert_eq!(output_settings.output_fmt, format);
        assert_eq!(output_settings.start_address, start_address);
        assert_eq!(output_settings.group_size, group_size);
        assert_eq!(output_settings.show_address, show_address);
        assert_eq!(output_settings.show_interpretation, show_interpretation);
    }

    #[test]
    fn output_settings_get_bytes_per_line() {
        {
            let group_size = 8;
            let columns = 2;
            let mut output_settings = OutputSettings::new().columns(columns).group_size(group_size);
            assert_eq!(group_size * columns, output_settings.bytes_per_line())
        }
        {
            let group_size = 5;
            let columns = 4;
            let mut output_settings = OutputSettings::new().columns(columns).group_size(group_size);
            assert_eq!(group_size * columns, output_settings.bytes_per_line())
        }
        {
            let group_size = 9;
            let columns = 4;
            let mut output_settings = OutputSettings::new().columns(columns).group_size(group_size);
            assert_eq!(group_size * columns, output_settings.bytes_per_line())
        }
    }

    #[test]
    fn output_settings_from_string() {
        assert_eq!(OutputFormat::Binary, OutputFormat::from("bin".to_string()));
        assert_eq!(OutputFormat::Hex, OutputFormat::from("hex".to_string()));
        assert_eq!(OutputFormat::Octal, OutputFormat::from("oct".to_string()));
        assert_eq!(OutputFormat::Decimal, OutputFormat::from("dec".to_string()));

        assert_eq!(OutputFormat::Binary, OutputFormat::from("Bin".to_string()));
        assert_eq!(OutputFormat::Hex, OutputFormat::from("hEx".to_string()));
        assert_eq!(OutputFormat::Octal, OutputFormat::from("ocT".to_string()));
        assert_eq!(OutputFormat::Decimal, OutputFormat::from("DEC".to_string()));
    }

    #[test]
    fn outputline_can_be_constructed() {
        let fixture = TestFixture::new();
        let output_line = OutputLine::new(fixture.data());
        assert!(true);
    }

    #[test]
    fn default_output_format_for_a_single_line() {
        let fixture = TestFixture::new();
        let output_line = OutputLine::new(fixture.data());
        let expected_output = "00000000: 00 FF 7F 80 38 41 01 21    ....8A.!";
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }

    #[test]
    fn default_output_format_for_a_single_line_with_padding() {
        let fixture = TestFixture::new();
        let output_line = OutputLine::new(fixture.small_data());
        let expected_output = "00000000: 00 FF 50 2C 07             ..P,.";
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }

    #[test]
    fn octal_output_format_on_a_single_line() {
        let fixture = TestFixture::new();
        let output_settings = OutputSettings::new().format(OutputFormat::Octal);
        let output_line = OutputLine::new(fixture.data()).format(output_settings);
        let expected_output = "00000000: 000 377 177 200 070 101 001 041    ....8A.!";
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }

    #[test]
    fn octal_output_format_for_a_single_line_with_padding() {
        let fixture = TestFixture::new();
        let output_settings = OutputSettings::new().format(OutputFormat::Octal);
        let output_line = OutputLine::new(fixture.small_data()).format(output_settings);
        let expected_output = "00000000: 000 377 120 054 007                ..P,.";
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }

    #[test]
    fn binary_output_format_on_a_single_line() {
        let fixture = TestFixture::new();
        let output_settings = OutputSettings::new().format(OutputFormat::Binary);
        let output_line = OutputLine::new(fixture.data()).format(output_settings);
        let expected_output = "00000000: 00000000 11111111 01111111 10000000 00111000 01000001 00000001 00100001    ....8A.!";
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }

    #[test]
    fn binary_output_format_for_a_single_line_with_padding() {
        // small_data: [0, 255, 80, 44, 7],
        let fixture = TestFixture::new();
        let output_settings = OutputSettings::new().format(OutputFormat::Binary);
        let output_line = OutputLine::new(fixture.small_data()).format(output_settings);
        let expected_output = "00000000: 00000000 11111111 01010000 00101100 00000111                               ..P,.";
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }
}
<commit_msg>Remove pointless comment<commit_after>//! The dump module contains code related for outputing/dumping data.
use std::fmt::Display;
use std::convert::From;
use super::errors::*;

/// Enum which provides all possible output value formats supported by the dump module.
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum OutputFormat {
    Hex,
    Decimal,
    Octal,
    Binary,
}

impl From<String> for OutputFormat {
    fn from(format_string: String) -> Self {
        match format_string.to_lowercase().as_ref() {
            "hex" => OutputFormat::Hex,
            "dec" => OutputFormat::Decimal,
            "oct" => OutputFormat::Octal,
            "bin" => OutputFormat::Binary,
            _ => panic!("Invalid output format"),
        }
    }
}

#[derive(Debug, Clone, Copy)]
pub struct OutputSettings {
    start_address: usize,
    show_address: bool,
    group_size: usize,
    columns: usize,
    show_interpretation: bool,
    output_fmt: OutputFormat,
}

impl OutputSettings {
    pub fn new() -> OutputSettings {
        OutputSettings {
            start_address: 0,
            show_address: true,
            group_size: 1,
            columns: 8,
            show_interpretation: true,
            output_fmt: OutputFormat::Hex,
        }
    }

    pub fn bytes_per_line(&self) -> usize {
        self.columns * self.group_size
    }

    pub fn start_address(mut self, address: usize) -> Self {
        self.start_address = address;
        self
    }

    pub fn show_address(mut self, show: bool) -> Self {
        self.show_address = show;
        self
    }

    pub fn group_size(mut self, size: usize) -> Self {
        self.group_size = size;
        self
    }

    pub fn columns(mut self, columns: usize) -> Self {
        self.columns = columns;
        self
    }

    pub fn show_interpretation(mut self, show: bool) -> Self {
        self.show_interpretation = show;
        self
    }

    pub fn format(mut self, fmt: OutputFormat) -> Self {
        self.output_fmt = fmt;
        self
    }
}

/// The `OutputLine` struct contains all  information needed to dump/output a single line of data.
#[derive(Debug)]
pub struct OutputLine<'a> {
    output_settings: OutputSettings,
    data: &'a [u8],
}

impl<'a> OutputLine<'a> {
    pub fn new(data: &[u8]) -> OutputLine {
        OutputLine {
            output_settings: OutputSettings::new(),
            data: data,
        }
    }

    pub fn format(self, settings: OutputSettings) -> Self {
        OutputLine {
            output_settings: settings,
            data: self.data,
        }
    }

    fn write_address(&self, f: &mut ::fmt::Formatter) -> Result<usize> {
        write!(f, "{:08.X}: ", self.output_settings.start_address)?;
        Ok(10)
    }

    fn write_bytes(&self, f: &mut ::fmt::Formatter) -> Result<usize> {
        let mut byte_count = 0;
        let mut bytes_written = 0;
        for b in self.data.iter() {
            byte_count += 1;
            let is_seperator_necessary = byte_count % self.output_settings.group_size == 0;
            if is_seperator_necessary {
                bytes_written += self.write_formated_byte(f, b)?;
                write!(f, " ")?;
                bytes_written += 1;
            } else {
                bytes_written += self.write_formated_byte(f, b)?;
            }
        }
        Ok(bytes_written)
    }

    fn write_formated_byte(&self, f: &mut ::fmt::Formatter, byte: &u8) -> Result<usize> {
        match self.output_settings.output_fmt {
            OutputFormat::Hex => {
                write!(f, "{:02.X}", byte)?;
                Ok(2)
            }
            OutputFormat::Octal => {
                write!(f, "{:03.o}", byte)?;
                Ok(3)
            }
            OutputFormat::Decimal => {
                write!(f, "{:03}", byte)?;
                Ok(3)
            }
            OutputFormat::Binary => {
                write!(f, "{:08b}", byte)?;
                Ok(8)
            }
        }
    }

    fn write_interpretation(&self, f: &mut ::fmt::Formatter) -> Result<usize> {
        write!(f, "   ");
        for b in self.data.iter() {
            match *b {
                character @ 20u8...126u8 => write!(f, "{}", character as char)?,
                _ => write!(f, "{}", ".")?,
            }
        }
        Ok(self.data.len())
    }
}

impl<'a> ::fmt::Display for OutputLine<'a> {
    fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
        let format_size = |fmt: OutputFormat| match fmt {
            OutputFormat::Hex => 2,
            OutputFormat::Octal => 3,
            OutputFormat::Decimal => 3,
            OutputFormat::Binary => 8,
        };
        if self.output_settings.show_address {
            self.write_address(f);
        }
        // FIXME NiCo: whats the issues here?!
        let bytes_written = self.write_bytes(f).unwrap();
        let expected_length = self.output_settings.columns * self.output_settings.group_size *
                              format_size(self.output_settings.output_fmt) +
                              (self.output_settings.columns);
        let padding = expected_length - bytes_written;
        for i in 0..padding {
            write!(f, " ")?;
        }
        if self.output_settings.show_interpretation {
            self.write_interpretation(f);
        }
        Ok(())
    }
}

mod test {

    use super::*;
    use std::fmt::Write;

    struct TestFixture {
        data: [u8; 8],
        small_data: [u8; 5],
    }

    impl TestFixture {
        fn new() -> Self {
            TestFixture {
                data: [0, 255, 127, 128, 56, 65, 1, 33],
                small_data: [0, 255, 80, 44, 7],
            }
        }

        fn data(&self) -> &[u8] {
            &self.data
        }

        fn small_data(&self) -> &[u8] {
            &self.small_data
        }
    }

    #[test]
    fn output_settings_can_be_constructed() {
        let output_settings = OutputSettings::new();
        assert!(true);
    }

    #[test]
    fn output_settings_builder() {
        let format = OutputFormat::Binary;
        let start_address = 0xFF00AABB;
        let group_size = 2;
        let show_address = false;
        let show_interpretation = false;

        let mut output_settings = OutputSettings::new()
            .format(format)
            .start_address(start_address)
            .group_size(group_size)
            .show_address(show_address)
            .show_interpretation(show_interpretation);

        assert_eq!(output_settings.output_fmt, format);
        assert_eq!(output_settings.start_address, start_address);
        assert_eq!(output_settings.group_size, group_size);
        assert_eq!(output_settings.show_address, show_address);
        assert_eq!(output_settings.show_interpretation, show_interpretation);
    }

    #[test]
    fn output_settings_get_bytes_per_line() {
        {
            let group_size = 8;
            let columns = 2;
            let mut output_settings = OutputSettings::new().columns(columns).group_size(group_size);
            assert_eq!(group_size * columns, output_settings.bytes_per_line())
        }
        {
            let group_size = 5;
            let columns = 4;
            let mut output_settings = OutputSettings::new().columns(columns).group_size(group_size);
            assert_eq!(group_size * columns, output_settings.bytes_per_line())
        }
        {
            let group_size = 9;
            let columns = 4;
            let mut output_settings = OutputSettings::new().columns(columns).group_size(group_size);
            assert_eq!(group_size * columns, output_settings.bytes_per_line())
        }
    }

    #[test]
    fn output_settings_from_string() {
        assert_eq!(OutputFormat::Binary, OutputFormat::from("bin".to_string()));
        assert_eq!(OutputFormat::Hex, OutputFormat::from("hex".to_string()));
        assert_eq!(OutputFormat::Octal, OutputFormat::from("oct".to_string()));
        assert_eq!(OutputFormat::Decimal, OutputFormat::from("dec".to_string()));

        assert_eq!(OutputFormat::Binary, OutputFormat::from("Bin".to_string()));
        assert_eq!(OutputFormat::Hex, OutputFormat::from("hEx".to_string()));
        assert_eq!(OutputFormat::Octal, OutputFormat::from("ocT".to_string()));
        assert_eq!(OutputFormat::Decimal, OutputFormat::from("DEC".to_string()));
    }

    #[test]
    fn outputline_can_be_constructed() {
        let fixture = TestFixture::new();
        let output_line = OutputLine::new(fixture.data());
        assert!(true);
    }

    #[test]
    fn default_output_format_for_a_single_line() {
        let fixture = TestFixture::new();
        let output_line = OutputLine::new(fixture.data());
        let expected_output = "00000000: 00 FF 7F 80 38 41 01 21    ....8A.!";
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }

    #[test]
    fn default_output_format_for_a_single_line_with_padding() {
        let fixture = TestFixture::new();
        let output_line = OutputLine::new(fixture.small_data());
        let expected_output = "00000000: 00 FF 50 2C 07             ..P,.";
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }

    #[test]
    fn octal_output_format_on_a_single_line() {
        let fixture = TestFixture::new();
        let output_settings = OutputSettings::new().format(OutputFormat::Octal);
        let output_line = OutputLine::new(fixture.data()).format(output_settings);
        let expected_output = "00000000: 000 377 177 200 070 101 001 041    ....8A.!";
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }

    #[test]
    fn octal_output_format_for_a_single_line_with_padding() {
        let fixture = TestFixture::new();
        let output_settings = OutputSettings::new().format(OutputFormat::Octal);
        let output_line = OutputLine::new(fixture.small_data()).format(output_settings);
        let expected_output = "00000000: 000 377 120 054 007                ..P,.";
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }

    #[test]
    fn binary_output_format_on_a_single_line() {
        let fixture = TestFixture::new();
        let output_settings = OutputSettings::new().format(OutputFormat::Binary);
        let output_line = OutputLine::new(fixture.data()).format(output_settings);
        let expected_output = "00000000: 00000000 11111111 01111111 10000000 00111000 01000001 00000001 00100001    ....8A.!";
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }

    #[test]
    fn binary_output_format_for_a_single_line_with_padding() {
        let fixture = TestFixture::new();
        let output_settings = OutputSettings::new().format(OutputFormat::Binary);
        let output_line = OutputLine::new(fixture.small_data()).format(output_settings);
        let expected_output = "00000000: 00000000 11111111 01010000 00101100 00000111                               ..P,.";
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use nom::IResult;
use std::io::{stderr, Write, ErrorKind};
use std::process;
use std::fmt;
use wires::{OffsetRadix, Options, StringExtractor};

#[derive(Debug)]
struct ZWord {
    first: u8,
    second: u8,
    third: u8,
    last_bit: u8
}

impl ZWord {
    pub fn to_string(&self) -> String {
        let ZWord { first: a, second: b, third: c, .. } = *self;
        let chars = vec![
            char_from_5_bits(a),
            char_from_5_bits(b),
            char_from_5_bits(c)
        ];
        let s : String = chars.into_iter().collect();
        s
    }
}

pub struct ZorkStringExtractor {

}

impl ZorkStringExtractor {
    fn read_until_break(&self, bytes: &[u8], collection: &mut Vec<ZWord>) -> usize {
        let mut bytes_consumed = 0usize;
        let mut slice = bytes;
        loop {
            let result = take_z_word(slice);
            if let IResult::Done(rest, word) = result {
                bytes_consumed += 2;
                let should_break = word.last_bit == 1 || rest.len() <= 2;
                collection.push(word);
                slice = rest;
                if should_break { break; }
            }
        }
        bytes_consumed
    }
    fn dump_zword_vec(&self, words: &Vec<ZWord>) -> String{
        let strings : Vec<String> = words
            .into_iter()
            .map(|zword| zword.to_string())
            .collect();

        strings.concat()
    }
}

impl StringExtractor for ZorkStringExtractor {
    fn bytes_to_strings<W: Write>(&self, bytes: &[u8], writer: &mut W, options: &Options) {
        let length = bytes.len();
        let mut offset = 0usize;
        let mut collection : Vec<ZWord> = Vec::new();

        while offset < (length - 2) {
            let bytes_consumed = self.read_until_break(&bytes[offset..], &mut collection);
            let o_string = self.offset_string(offset, options.print_offset);
            let string = self.dump_zword_vec(&collection);
            let write_result = writeln!(writer, "{}{}", o_string, string);
            if let Err(e) = write_result {
                match e.kind() {
                    ErrorKind::BrokenPipe => break,
                        _ => {
                            writeln!(stderr(), "{}", e).unwrap();
                            process::exit(1);
                        }
                }
            }
            offset += bytes_consumed;
            collection.truncate(0);
        }
    }

    fn offset_string(&self, offset: usize, radix: OffsetRadix) -> String {
        let mut output = "".to_string();
        match radix {
            OffsetRadix::Hex => fmt::write(&mut output, format_args!("0x{:X}: ", offset)).unwrap(),
            OffsetRadix::Octal => fmt::write(&mut output, format_args!("0o{:o}: ", offset)).unwrap(),
            OffsetRadix::Decimal => fmt::write(&mut output, format_args!("{}: ", offset)).unwrap(),
            OffsetRadix::None => ()
        }

        output
    }
}

named!( take_5_bits<u8>, bits!( take_bits!( u8, 5 ) ) );

named!( take_z_word<&[u8],ZWord>,
    bits!(
        do_parse!(
            first: take_bits!( u8, 5 ) >>
            second: take_bits!( u8, 5 ) >>
            third: take_bits!( u8, 5 ) >>
            last_bit: take_bits!( u8, 1 ) >>
            (
                ZWord {
                    first: first,
                    second: second,
                    third: third,
                    last_bit: last_bit
                }
            )
        )
    )
);

fn char_from_5_bits(fiver: u8) -> char {
    let alphabet_table: Vec<char> = vec![
        ' ', '?', '?', '?', '?', '?', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
        'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' ];
    alphabet_table[fiver as usize]
}

/* The other two alphabet tables
[| " "; "?"; "?"; "?"; "?"; "?"; "A"; "B"; "C"; "D"; "E"; "F"; "G"; "H"; "I"; "J";
   "K"; "L"; "M"; "N"; "O"; "P"; "Q"; "R"; "S"; "T"; "U"; "V"; "W"; "X"; "Y"; "Z" |];
[| " "; "?"; "?"; "?"; "?"; "?"; "?"; "\n"; "0"; "1"; "2"; "3"; "4"; "5"; "6"; "7";
   "8"; "9"; "."; ","; "!"; "?"; "_"; "#"; "'"; "\""; "/"; "\\"; "-"; ":"; "("; ")" |] |]
*/

fn z_string_fragment(bytes: &[u8]) -> String {
    if let IResult::Done(_, word) = take_z_word(bytes) {
       return word.to_string();
    }
    //TODO handle error case
    "NOT IMPLEMENTED".to_string()
}

fn read_until_break(bytes: &[u8], collection: &mut Vec<ZWord>) {
    let mut slice = bytes;
    loop {
        let result = take_z_word(slice);
        if let IResult::Done(rest, word) = result {
            let should_break = word.last_bit == 1 || rest.len() <= 2;
            collection.push(word);
            slice = rest;
            if should_break { break; }
        }
    }
}

pub fn dump_string_until_break<W: Write>(bytes: &[u8], writer: &mut W) {
    let mut collection : Vec<ZWord> = Vec::new();
    read_until_break(bytes, &mut collection);
    let strings : Vec<String> = collection
        .into_iter()
        .map(|z_word| z_word.to_string())
        .collect();

    for s in strings.into_iter() {
        let write_result = writeln!(writer, "{}", s);
        if let Err(e) = write_result {
            match e.kind() {
                ErrorKind::BrokenPipe => break,
                    _ => {
                        writeln!(stderr(), "{}", e).unwrap();
                        process::exit(1);
                    }
            }
        }
    }
}

#[test]
fn it_takes_bits() {
    let input = vec![0b10101010, 0b11110000, 0b00110011];
    let sl    = &input[..];
    assert_eq!(take_5_bits( sl ), IResult::Done(&sl[1..], 21) );
}

#[test]
fn it_can_get_letter() {
    let starts_with_six = vec! [0b00110111, 0b11110000, 0b11110001];
    let sl = &starts_with_six[..];
    let expected = 'a';
    let actual = char_from_5_bits( take_5_bits(sl).to_result().unwrap() );
    assert_eq!(expected, actual);
}

#[test]
fn it_can_parse_the() {
    let bytes_for_the = vec! [0b1100_1011u8, 0b0101_0101u8];
    let sl = &bytes_for_the[..];
    let expected = "the".to_string();
    let actual = z_string_fragment(sl);
    assert_eq!(expected, actual);
}

#[test]
fn read_until_break_breaks() {
    let bytes_for_the = vec! [0b1100_1011u8, 0b0101_0100u8, 0b1100_1011u8, 0b0101_0101u8, 0b1100_1011u8, 0b0101_0101u8];
    let sl = &bytes_for_the[..];
    let expected = "thethe".to_string();
    let mut collection : Vec<ZWord> = Vec::new();
    read_until_break(sl, &mut collection);
    println!("{:?}", collection);
    let strings : Vec<String> = collection
        .into_iter()
        .map(|zword| zword.to_string())
        .collect();

    let actual = strings.concat();

    assert_eq!(expected, actual);
}<commit_msg>fixed zork strings (still all lower)<commit_after>#![allow(dead_code)]

use nom::IResult;
use std::io::{stderr, Write, ErrorKind};
use std::process;
use std::fmt;
use wires::{OffsetRadix, Options, StringExtractor};

#[derive(Debug)]
struct ZWord {
    first: u8,
    second: u8,
    third: u8,
    last_bit: u8
}

impl ZWord {
    pub fn to_string(&self) -> String {
        let ZWord { first: a, second: b, third: c, .. } = *self;
        let chars = vec![
            char_from_5_bits(a),
            char_from_5_bits(b),
            char_from_5_bits(c)
        ];
        let s : String = chars.into_iter().collect();
        s
    }
}

pub struct ZorkStringExtractor {

}

impl ZorkStringExtractor {
    fn read_until_break(&self, bytes: &[u8], collection: &mut Vec<ZWord>) -> usize {
        let mut bytes_consumed = 0usize;
        let mut slice = bytes;
        loop {
            let result = take_z_word(slice);
            if let IResult::Done(rest, word) = result {
                bytes_consumed += 2;
                let should_break = word.last_bit == 1 || rest.len() <= 2;
                collection.push(word);
                slice = rest;
                if should_break { break; }
            }
        }
        bytes_consumed
    }
    fn dump_zword_vec(&self, words: &Vec<ZWord>) -> String{
        let strings : Vec<String> = words
            .into_iter()
            .map(|zword| zword.to_string())
            .collect();

        strings.concat()
    }
}

impl StringExtractor for ZorkStringExtractor {
    fn bytes_to_strings<W: Write>(&self, bytes: &[u8], writer: &mut W, options: &Options) {
        let length = bytes.len();
        let mut offset = 0usize;
        let mut collection : Vec<ZWord> = Vec::new();

        while offset < (length - 2) {
            let bytes_consumed = self.read_until_break(&bytes[offset..], &mut collection);
            let o_string = self.offset_string(offset, options.print_offset);
            let string = self.dump_zword_vec(&collection);
            let write_result = writeln!(writer, "{}{}", o_string, string);
            if let Err(e) = write_result {
                match e.kind() {
                    ErrorKind::BrokenPipe => break,
                        _ => {
                            writeln!(stderr(), "{}", e).unwrap();
                            process::exit(1);
                        }
                }
            }
            offset += bytes_consumed;
            collection.truncate(0);
        }
    }

    fn offset_string(&self, offset: usize, radix: OffsetRadix) -> String {
        let mut output = "".to_string();
        match radix {
            OffsetRadix::Hex => fmt::write(&mut output, format_args!("0x{:X}: ", offset)).unwrap(),
            OffsetRadix::Octal => fmt::write(&mut output, format_args!("0o{:o}: ", offset)).unwrap(),
            OffsetRadix::Decimal => fmt::write(&mut output, format_args!("{}: ", offset)).unwrap(),
            OffsetRadix::None => ()
        }

        output
    }
}

named!( take_5_bits<u8>, bits!( take_bits!( u8, 5 ) ) );

named!( take_z_word<&[u8],ZWord>,
    bits!(
        do_parse!(
            word_end_bit: take_bits!( u8, 1 ) >>
            first: take_bits!( u8, 5 ) >>
            second: take_bits!( u8, 5 ) >>
            third: take_bits!( u8, 5 ) >>
            (
                ZWord {
                    first: first,
                    second: second,
                    third: third,
                    last_bit: word_end_bit
                }
            )
        )
    )
);

fn char_from_5_bits(fiver: u8) -> char {
    let alphabet_table: Vec<char> = vec![
        ' ', '?', '?', '?', '?', '?', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
        'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' ];
    alphabet_table[fiver as usize]
}

/* The other two alphabet tables
[| " "; "?"; "?"; "?"; "?"; "?"; "A"; "B"; "C"; "D"; "E"; "F"; "G"; "H"; "I"; "J";
   "K"; "L"; "M"; "N"; "O"; "P"; "Q"; "R"; "S"; "T"; "U"; "V"; "W"; "X"; "Y"; "Z" |];
[| " "; "?"; "?"; "?"; "?"; "?"; "?"; "\n"; "0"; "1"; "2"; "3"; "4"; "5"; "6"; "7";
   "8"; "9"; "."; ","; "!"; "?"; "_"; "#"; "'"; "\""; "/"; "\\"; "-"; ":"; "("; ")" |] |]
*/

fn z_string_fragment(bytes: &[u8]) -> String {
    if let IResult::Done(_, word) = take_z_word(bytes) {
       return word.to_string();
    }
    //TODO handle error case
    "NOT IMPLEMENTED".to_string()
}

fn read_until_break(bytes: &[u8], collection: &mut Vec<ZWord>) {
    let mut slice = bytes;
    loop {
        let result = take_z_word(slice);
        if let IResult::Done(rest, word) = result {
            let should_break = word.last_bit == 1 || rest.len() <= 2;
            collection.push(word);
            slice = rest;
            if should_break { break; }
        }
    }
}

pub fn dump_string_until_break<W: Write>(bytes: &[u8], writer: &mut W) {
    let mut collection : Vec<ZWord> = Vec::new();
    read_until_break(bytes, &mut collection);
    let strings : Vec<String> = collection
        .into_iter()
        .map(|z_word| z_word.to_string())
        .collect();

    for s in strings.into_iter() {
        let write_result = writeln!(writer, "{}", s);
        if let Err(e) = write_result {
            match e.kind() {
                ErrorKind::BrokenPipe => break,
                    _ => {
                        writeln!(stderr(), "{}", e).unwrap();
                        process::exit(1);
                    }
            }
        }
    }
}

#[test]
fn it_takes_bits() {
    let input = vec![0b10101010, 0b11110000, 0b00110011];
    let sl    = &input[..];
    assert_eq!(take_5_bits( sl ), IResult::Done(&sl[1..], 21) );
}

#[test]
fn it_can_get_letter() {
    let starts_with_six = vec! [0b00110111, 0b11110000, 0b11110001];
    let sl = &starts_with_six[..];
    let expected = 'a';
    let actual = char_from_5_bits( take_5_bits(sl).to_result().unwrap() );
    assert_eq!(expected, actual);
}

#[test]
fn it_can_parse_the() {
    let bytes_for_the = vec! [0b1100_1011u8, 0b0101_0101u8];
    let sl = &bytes_for_the[..];
    let expected = "the".to_string();
    let actual = z_string_fragment(sl);
    assert_eq!(expected, actual);
}

#[test]
fn read_until_break_breaks() {
    let bytes_for_the = vec! [0b1100_1011u8, 0b0101_0100u8, 0b1100_1011u8, 0b0101_0101u8, 0b1100_1011u8, 0b0101_0101u8];
    let sl = &bytes_for_the[..];
    let expected = "thethe".to_string();
    let mut collection : Vec<ZWord> = Vec::new();
    read_until_break(sl, &mut collection);
    println!("{:?}", collection);
    let strings : Vec<String> = collection
        .into_iter()
        .map(|zword| zword.to_string())
        .collect();

    let actual = strings.concat();

    assert_eq!(expected, actual);
}<|endoftext|>


<commit_before>// Claxon -- A FLAC decoding library in Rust
// Copyright 2015 van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

extern crate claxon;
extern crate hound;

use claxon::{Block, FlacReader};
use hound::{WavSpec, WavWriter};
use std::env;
use std::path::Path;

fn decode_file(fname: &Path) {
    let mut reader = FlacReader::open(fname).expect("failed to open FLAC stream");

    // TODO: Write fallback for other sample widths and channel numbers.
    assert!(reader.streaminfo().bits_per_sample == 16);
    assert!(reader.streaminfo().channels == 2);

    let spec = WavSpec {
        // TODO: u8 for channels, is that weird? Would u32 be better?
        channels: reader.streaminfo().channels as u16,
        sample_rate: reader.streaminfo().sample_rate,
        // TODO: again, would u32 be better, even if the range is smaller?
        bits_per_sample: reader.streaminfo().bits_per_sample as u16,
        sample_format: hound::SampleFormat::Int,
    };

    let fname_wav = fname.with_extension("wav");
    let mut wav_writer = WavWriter::create(fname_wav, spec).expect("failed to create wav file");

    let mut frame_reader = reader.blocks();
    let mut block = Block::empty();
    loop {
        // Read a single frame. Recycle the buffer from the previous frame to
        // avoid allocations as much as possible.
        match frame_reader.read_next_or_eof(block.into_buffer()) {
            Ok(Some(next_block)) => block = next_block,
            Ok(None) => break, // EOF.
            Err(error) => panic!("{}", error),
        }

        let mut sample_writer = wav_writer.get_i16_writer(block.duration() * 2);

        // Write the samples in the block to the wav file, channels interleaved.
        for (left, right) in block.stereo_samples() {
            // The `stereo_samples()` iterator does not yield more samples
            // than the duration of the block, so we never write more
            // samples to the writer than requested, hence using the
            // unchecked functions is safe here.
            unsafe {
                sample_writer.write_sample_unchecked(left);
                sample_writer.write_sample_unchecked(right);
            }
        }

        sample_writer.flush().expect("failed to write samples to wav file");
    }

    wav_writer.finalize().expect("failed to finalize wav file");
}

fn main() {
    let mut no_args = true;

    for fname in env::args().skip(1) {
        no_args = false;

        print!("{}", fname);
        decode_file(&Path::new(&fname));
        println!(": done");
    }

    if no_args {
        println!("no files to decode");
    }
}
<commit_msg>Fix name in copyright notice<commit_after>// Claxon -- A FLAC decoding library in Rust
// Copyright 2015 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

extern crate claxon;
extern crate hound;

use claxon::{Block, FlacReader};
use hound::{WavSpec, WavWriter};
use std::env;
use std::path::Path;

fn decode_file(fname: &Path) {
    let mut reader = FlacReader::open(fname).expect("failed to open FLAC stream");

    // TODO: Write fallback for other sample widths and channel numbers.
    assert!(reader.streaminfo().bits_per_sample == 16);
    assert!(reader.streaminfo().channels == 2);

    let spec = WavSpec {
        // TODO: u8 for channels, is that weird? Would u32 be better?
        channels: reader.streaminfo().channels as u16,
        sample_rate: reader.streaminfo().sample_rate,
        // TODO: again, would u32 be better, even if the range is smaller?
        bits_per_sample: reader.streaminfo().bits_per_sample as u16,
        sample_format: hound::SampleFormat::Int,
    };

    let fname_wav = fname.with_extension("wav");
    let mut wav_writer = WavWriter::create(fname_wav, spec).expect("failed to create wav file");

    let mut frame_reader = reader.blocks();
    let mut block = Block::empty();
    loop {
        // Read a single frame. Recycle the buffer from the previous frame to
        // avoid allocations as much as possible.
        match frame_reader.read_next_or_eof(block.into_buffer()) {
            Ok(Some(next_block)) => block = next_block,
            Ok(None) => break, // EOF.
            Err(error) => panic!("{}", error),
        }

        let mut sample_writer = wav_writer.get_i16_writer(block.duration() * 2);

        // Write the samples in the block to the wav file, channels interleaved.
        for (left, right) in block.stereo_samples() {
            // The `stereo_samples()` iterator does not yield more samples
            // than the duration of the block, so we never write more
            // samples to the writer than requested, hence using the
            // unchecked functions is safe here.
            unsafe {
                sample_writer.write_sample_unchecked(left);
                sample_writer.write_sample_unchecked(right);
            }
        }

        sample_writer.flush().expect("failed to write samples to wav file");
    }

    wav_writer.finalize().expect("failed to finalize wav file");
}

fn main() {
    let mut no_args = true;

    for fname in env::args().skip(1) {
        no_args = false;

        print!("{}", fname);
        decode_file(&Path::new(&fname));
        println!(": done");
    }

    if no_args {
        println!("no files to decode");
    }
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate http;
extern crate router;

// To build, $ cargo test
// To use, go to http://127.0.0.1:3000/test

use std::io::net::ip::Ipv4Addr;
use iron::{Server, Iron, Request, Response, Chain, Status, Unwind, FromFn};
use http::status;
use router::{Router, Params};

fn main() {
    let mut server: Server = Iron::new();
    let mut router = Router::new();

    fn handler(req: &mut Request, res: &mut Response) -> Status {
        let ref query = req.extensions.find::<Router, Params>().unwrap().find("query").unwrap();
        let _ = res.serve(status::Ok, query.as_slice());
        Unwind
    }

    // Setup our route.
    router.get("/:query", FromFn::new(handler));

    server.chain.link(router);
    server.listen(Ipv4Addr(127, 0, 0, 1), 3000);
}
<commit_msg>(update) Updated simple example for new Router and new Iron.<commit_after>extern crate iron;
extern crate http;
extern crate router;

// To build, $ cargo test
// To use, go to http://127.0.0.1:3000/test

use std::io::net::ip::Ipv4Addr;
use iron::{Iron, Request, Response, IronResult};
use iron::status;
use router::{Router, Params};

fn main() {
    let mut router = Router::new();
    router.get("/", handler);
    router.get("/:query", handler);

    Iron::new(router).listen(Ipv4Addr(127, 0, 0, 1), 3000);

    fn handler(req: &mut Request) -> IronResult<Response> {
        let ref query = req.extensions.find::<Router, Params>().unwrap().find("query").unwrap_or("/");
        Ok(Response::with(status::Ok, *query))
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

use std::io::{Cursor};

extern crate test;
extern crate pickle;

fn main() {
    let buffer = include_bytes!("../pickle");

    println!("{:?}", pickle::unpickle(&mut Cursor::new(&buffer[..])));
    ()
}<commit_msg>Disable unused feature<commit_after>
use std::io::{Cursor};

extern crate test;
extern crate pickle;

fn main() {
    let buffer = include_bytes!("../pickle");

    println!("{:?}", pickle::unpickle(&mut Cursor::new(&buffer[..])));
    ()
}<|endoftext|>