<commit_before>#![stable(feature = "", since = "1.30.0")]

#![allow(non_camel_case_types)]
#![cfg_attr(stage0, allow(dead_code))]

//! Utilities related to FFI bindings.

use ::fmt;

/// Equivalent to C's `void` type when used as a [pointer].
///
/// In essence, `*const c_void` is equivalent to C's `const void*`
/// and `*mut c_void` is equivalent to C's `void*`. That said, this is
/// *not* the same as C's `void` return type, which is Rust's `()` type.
///
/// To model pointers to opaque types in FFI, until `extern type` is
/// stabilized, it is recommended to use a newtype wrapper around an empty
/// byte array. See the [Nomicon] for details.
///
/// [pointer]: ../../std/primitive.pointer.html
/// [Nomicon]: https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
// N.B., for LLVM to recognize the void pointer type and by extension
//     functions like malloc(), we need to have it represented as i8* in
//     LLVM bitcode. The enum used here ensures this and prevents misuse
//     of the "raw" type by only having private variants.. We need two
//     variants, because the compiler complains about the repr attribute
//     otherwise.
#[repr(u8)]
#[stable(feature = "raw_os", since = "1.1.0")]
pub enum c_void {
    #[unstable(feature = "c_void_variant", reason = "should not have to exist",
               issue = "0")]
    #[doc(hidden)] __variant1,
    #[unstable(feature = "c_void_variant", reason = "should not have to exist",
               issue = "0")]
    #[doc(hidden)] __variant2,
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for c_void {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("c_void")
    }
}

/// Basic implementation of a `va_list`.
#[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
              not(target_arch = "x86_64")),
          all(target_arch = "aarch4", target_os = "ios"),
          windows))]
#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
extern {
    type VaListImpl;
}

#[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
              not(target_arch = "x86_64")),
          windows))]
impl fmt::Debug for VaListImpl {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "va_list* {:p}", self)
    }
}

/// AArch64 ABI implementation of a `va_list`. See the
/// [Aarch64 Procedure Call Standard] for more details.
///
/// [AArch64 Procedure Call Standard]:
/// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
#[cfg(all(target_arch = "aarch64", not(windows)))]
#[repr(C)]
#[derive(Debug)]
#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
struct VaListImpl {
    stack: *mut (),
    gr_top: *mut (),
    vr_top: *mut (),
    gr_offs: i32,
    vr_offs: i32,
}

/// PowerPC ABI implementation of a `va_list`.
#[cfg(all(target_arch = "powerpc", not(windows)))]
#[repr(C)]
#[derive(Debug)]
#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
struct VaListImpl {
    gpr: u8,
    fpr: u8,
    reserved: u16,
    overflow_arg_area: *mut (),
    reg_save_area: *mut (),
}

/// x86_64 ABI implementation of a `va_list`.
#[cfg(all(target_arch = "x86_64", not(windows)))]
#[repr(C)]
#[derive(Debug)]
#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
struct VaListImpl {
    gp_offset: i32,
    fp_offset: i32,
    overflow_arg_area: *mut (),
    reg_save_area: *mut (),
}

/// A wrapper for a `va_list`
#[lang = "va_list"]
#[derive(Debug)]
#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
#[repr(transparent)]
#[cfg(not(stage0))]
pub struct VaList<'a>(&'a mut VaListImpl);

// The VaArgSafe trait needs to be used in public interfaces, however, the trait
// itself must not be allowed to be used outside this module. Allowing users to
// implement the trait for a new type (thereby allowing the va_arg intrinsic to
// be used on a new type) is likely to cause undefined behavior.
//
// FIXME(dlrobertson): In order to use the VaArgSafe trait in a public interface
// but also ensure it cannot be used elsewhere, the trait needs to be public
// within a private module. Once RFC 2145 has been implemented look into
// improving this.
mod sealed_trait {
    /// Trait which whitelists the allowed types to be used with [VaList::arg]
    ///
    /// [VaList::va_arg]: struct.VaList.html#method.arg
    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "27745")]
    pub trait VaArgSafe {}
}

macro_rules! impl_va_arg_safe {
    ($($t:ty),+) => {
        $(
            #[unstable(feature = "c_variadic",
                       reason = "the `c_variadic` feature has not been properly tested on \
                                 all supported platforms",
                       issue = "27745")]
            impl sealed_trait::VaArgSafe for $t {}
        )+
    }
}

impl_va_arg_safe!{i8, i16, i32, i64, usize}
impl_va_arg_safe!{u8, u16, u32, u64, isize}
impl_va_arg_safe!{f64}

#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
impl<T> sealed_trait::VaArgSafe for *mut T {}
#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
impl<T> sealed_trait::VaArgSafe for *const T {}

#[cfg(not(stage0))]
impl<'a> VaList<'a> {
    /// Advance to the next arg.
    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "27745")]
    pub unsafe fn arg<T: sealed_trait::VaArgSafe>(&mut self) -> T {
        va_arg(self)
    }

    /// Copy the `va_list` at the current location.
    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "27745")]
    pub unsafe fn copy<F, R>(&mut self, f: F) -> R
            where F: for<'copy> FnOnce(VaList<'copy>) -> R {
        #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
                      not(target_arch = "x86_64")),
                  all(target_arch = "aarch4", target_os = "ios"),
                  windows))]
        let mut ap = va_copy(self);
        #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"),
                  not(windows)))]
        let mut ap_inner = va_copy(self);
        #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"),
                  not(windows)))]
        let mut ap = VaList(&mut ap_inner);
        let ret = f(VaList(ap.0));
        va_end(&mut ap);
        ret
    }
}

#[cfg(not(stage0))]
extern "rust-intrinsic" {
    /// Destroy the arglist `ap` after initialization with `va_start` or
    /// `va_copy`.
    fn va_end(ap: &mut VaList);

    /// Copy the current location of arglist `src` to the arglist `dst`.
    #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
                  not(target_arch = "x86_64")),
              windows))]
    fn va_copy<'a>(src: &VaList<'a>) -> VaList<'a>;
    #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"),
              not(windows)))]
    fn va_copy(src: &VaList) -> VaListImpl;

    /// Loads an argument of type `T` from the `va_list` `ap` and increment the
    /// argument `ap` points to.
    fn va_arg<T: sealed_trait::VaArgSafe>(ap: &mut VaList) -> T;
}
<commit_msg>Update code comments of `c_void` to explain the reasoning for its current implementation<commit_after>#![stable(feature = "", since = "1.30.0")]

#![allow(non_camel_case_types)]
#![cfg_attr(stage0, allow(dead_code))]

//! Utilities related to FFI bindings.

use ::fmt;

/// Equivalent to C's `void` type when used as a [pointer].
///
/// In essence, `*const c_void` is equivalent to C's `const void*`
/// and `*mut c_void` is equivalent to C's `void*`. That said, this is
/// *not* the same as C's `void` return type, which is Rust's `()` type.
///
/// To model pointers to opaque types in FFI, until `extern type` is
/// stabilized, it is recommended to use a newtype wrapper around an empty
/// byte array. See the [Nomicon] for details.
///
/// [pointer]: ../../std/primitive.pointer.html
/// [Nomicon]: https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
// N.B., for LLVM to recognize the void pointer type and by extension
//     functions like malloc(), we need to have it represented as i8* in
//     LLVM bitcode. The enum used here ensures this and prevents misuse
//     of the "raw" type by only having private variants. We need two
//     variants, because the compiler complains about the repr attribute
//     otherwise and we need at least one variant as otherwise the enum
//     would be uninhabited and at least dereferencing such pointers would
//     be UB.
#[repr(u8)]
#[stable(feature = "raw_os", since = "1.1.0")]
pub enum c_void {
    #[unstable(feature = "c_void_variant", reason = "temporary implementation detail",
               issue = "0")]
    #[doc(hidden)] __variant1,
    #[unstable(feature = "c_void_variant", reason = "temporary implementation detail",
               issue = "0")]
    #[doc(hidden)] __variant2,
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for c_void {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("c_void")
    }
}

/// Basic implementation of a `va_list`.
#[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
              not(target_arch = "x86_64")),
          all(target_arch = "aarch4", target_os = "ios"),
          windows))]
#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
extern {
    type VaListImpl;
}

#[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
              not(target_arch = "x86_64")),
          windows))]
impl fmt::Debug for VaListImpl {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "va_list* {:p}", self)
    }
}

/// AArch64 ABI implementation of a `va_list`. See the
/// [Aarch64 Procedure Call Standard] for more details.
///
/// [AArch64 Procedure Call Standard]:
/// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
#[cfg(all(target_arch = "aarch64", not(windows)))]
#[repr(C)]
#[derive(Debug)]
#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
struct VaListImpl {
    stack: *mut (),
    gr_top: *mut (),
    vr_top: *mut (),
    gr_offs: i32,
    vr_offs: i32,
}

/// PowerPC ABI implementation of a `va_list`.
#[cfg(all(target_arch = "powerpc", not(windows)))]
#[repr(C)]
#[derive(Debug)]
#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
struct VaListImpl {
    gpr: u8,
    fpr: u8,
    reserved: u16,
    overflow_arg_area: *mut (),
    reg_save_area: *mut (),
}

/// x86_64 ABI implementation of a `va_list`.
#[cfg(all(target_arch = "x86_64", not(windows)))]
#[repr(C)]
#[derive(Debug)]
#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
struct VaListImpl {
    gp_offset: i32,
    fp_offset: i32,
    overflow_arg_area: *mut (),
    reg_save_area: *mut (),
}

/// A wrapper for a `va_list`
#[lang = "va_list"]
#[derive(Debug)]
#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
#[repr(transparent)]
#[cfg(not(stage0))]
pub struct VaList<'a>(&'a mut VaListImpl);

// The VaArgSafe trait needs to be used in public interfaces, however, the trait
// itself must not be allowed to be used outside this module. Allowing users to
// implement the trait for a new type (thereby allowing the va_arg intrinsic to
// be used on a new type) is likely to cause undefined behavior.
//
// FIXME(dlrobertson): In order to use the VaArgSafe trait in a public interface
// but also ensure it cannot be used elsewhere, the trait needs to be public
// within a private module. Once RFC 2145 has been implemented look into
// improving this.
mod sealed_trait {
    /// Trait which whitelists the allowed types to be used with [VaList::arg]
    ///
    /// [VaList::va_arg]: struct.VaList.html#method.arg
    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "27745")]
    pub trait VaArgSafe {}
}

macro_rules! impl_va_arg_safe {
    ($($t:ty),+) => {
        $(
            #[unstable(feature = "c_variadic",
                       reason = "the `c_variadic` feature has not been properly tested on \
                                 all supported platforms",
                       issue = "27745")]
            impl sealed_trait::VaArgSafe for $t {}
        )+
    }
}

impl_va_arg_safe!{i8, i16, i32, i64, usize}
impl_va_arg_safe!{u8, u16, u32, u64, isize}
impl_va_arg_safe!{f64}

#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
impl<T> sealed_trait::VaArgSafe for *mut T {}
#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
impl<T> sealed_trait::VaArgSafe for *const T {}

#[cfg(not(stage0))]
impl<'a> VaList<'a> {
    /// Advance to the next arg.
    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "27745")]
    pub unsafe fn arg<T: sealed_trait::VaArgSafe>(&mut self) -> T {
        va_arg(self)
    }

    /// Copy the `va_list` at the current location.
    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "27745")]
    pub unsafe fn copy<F, R>(&mut self, f: F) -> R
            where F: for<'copy> FnOnce(VaList<'copy>) -> R {
        #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
                      not(target_arch = "x86_64")),
                  all(target_arch = "aarch4", target_os = "ios"),
                  windows))]
        let mut ap = va_copy(self);
        #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"),
                  not(windows)))]
        let mut ap_inner = va_copy(self);
        #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"),
                  not(windows)))]
        let mut ap = VaList(&mut ap_inner);
        let ret = f(VaList(ap.0));
        va_end(&mut ap);
        ret
    }
}

#[cfg(not(stage0))]
extern "rust-intrinsic" {
    /// Destroy the arglist `ap` after initialization with `va_start` or
    /// `va_copy`.
    fn va_end(ap: &mut VaList);

    /// Copy the current location of arglist `src` to the arglist `dst`.
    #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
                  not(target_arch = "x86_64")),
              windows))]
    fn va_copy<'a>(src: &VaList<'a>) -> VaList<'a>;
    #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"),
              not(windows)))]
    fn va_copy(src: &VaList) -> VaListImpl;

    /// Loads an argument of type `T` from the `va_list` `ap` and increment the
    /// argument `ap` points to.
    fn va_arg<T: sealed_trait::VaArgSafe>(ap: &mut VaList) -> T;
}
<|endoftext|>


<commit_before>use crate::ty::query::Providers;
use crate::hir::def_id::DefId;
use crate::hir;
use crate::ty::TyCtxt;
use syntax_pos::symbol::{sym, Symbol};
use rustc_target::spec::abi::Abi;
use crate::hir::map::blocks::FnLikeNode;
use syntax::attr;

impl<'tcx> TyCtxt<'tcx> {
    /// Whether the `def_id` counts as const fn in your current crate, considering all active
    /// feature gates
    pub fn is_const_fn(self, def_id: DefId) -> bool {
        self.is_const_fn_raw(def_id) && match self.is_unstable_const_fn(def_id) {
            Some(feature_name) => {
                // has a `rustc_const_unstable` attribute, check whether the user enabled the
                // corresponding feature gate.
                self.features()
                    .declared_lib_features
                    .iter()
                    .any(|&(sym, _)| sym == feature_name)
            },
            // functions without const stability are either stable user written
            // const fn or the user is using feature gates and we thus don't
            // care what they do
            None => true,
        }
    }

    /// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
    pub fn is_unstable_const_fn(self, def_id: DefId) -> Option<Symbol> {
        if self.is_const_fn_raw(def_id) {
            let const_stab = self.lookup_const_stability(def_id)?;
            if const_stab.level.is_unstable() {
                Some(const_stab.feature)
            } else {
                None
            }
        } else {
            None
        }
    }

    /// Returns `true` if the `def_id` refers to an intrisic which we've whitelisted
    /// for being called from stable `const fn`s (`min_const_fn`).
    ///
    /// Adding more intrinsics requires sign-off from @rust-lang/lang.
    ///
    /// This list differs from the list in `is_const_intrinsic` in the sense that any item on this
    /// list must be on the `is_const_intrinsic` list, too, because if an intrinsic is callable from
    /// stable, it must be callable at all.
    fn is_intrinsic_min_const_fn(self, def_id: DefId) -> bool {
        match self.item_name(def_id) {
            | sym::size_of
            | sym::min_align_of
            | sym::needs_drop
            // Arithmetic:
            | sym::add_with_overflow // ~> .overflowing_add
            | sym::sub_with_overflow // ~> .overflowing_sub
            | sym::mul_with_overflow // ~> .overflowing_mul
            | sym::wrapping_add // ~> .wrapping_add
            | sym::wrapping_sub // ~> .wrapping_sub
            | sym::wrapping_mul // ~> .wrapping_mul
            | sym::saturating_add // ~> .saturating_add
            | sym::saturating_sub // ~> .saturating_sub
            | sym::unchecked_shl // ~> .wrapping_shl
            | sym::unchecked_shr // ~> .wrapping_shr
            | sym::rotate_left // ~> .rotate_left
            | sym::rotate_right // ~> .rotate_right
            | sym::ctpop // ~> .count_ones
            | sym::ctlz // ~> .leading_zeros
            | sym::cttz // ~> .trailing_zeros
            | sym::bswap // ~> .swap_bytes
            | sym::bitreverse // ~> .reverse_bits
            => true,
            _ => false,
        }
    }

    /// Returns `true` if this function must conform to `min_const_fn`
    pub fn is_min_const_fn(self, def_id: DefId) -> bool {
        // Bail out if the signature doesn't contain `const`
        if !self.is_const_fn_raw(def_id) {
            return false;
        }
        if let Abi::RustIntrinsic = self.fn_sig(def_id).abi() {
            return self.is_intrinsic_min_const_fn(def_id);
        }

        if self.features().staged_api {
            // In order for a libstd function to be considered min_const_fn
            // it needs to be stable and have no `rustc_const_unstable` attribute.
            match self.lookup_const_stability(def_id) {
                // `rustc_const_unstable` functions don't need to conform.
                Some(&attr::ConstStability { ref level, .. }) if level.is_unstable() => false,
                None => if let Some(stab) = self.lookup_stability(def_id) {
                    if stab.level.is_stable() {
                        self.sess.span_err(
                            self.def_span(def_id),
                            "stable const functions must have either `rustc_const_stable` or \
                            `rustc_const_unstable` attribute",
                        );
                        // While we errored above, because we don't know if we need to conform, we
                        // err on the "safe" side and require min_const_fn.
                        true
                    } else {
                        // Unstable functions need not conform to min const fn.
                        false
                    }
                } else {
                    // Internal functions need not conform to min const fn unless used inside stable
                    // const fns. Annotate the internal function with a const stability attribute if
                    // you need this.
                    false
                },
                // Everything else needs to conform, because it would be callable from
                // other `min_const_fn` functions.
                _ => true,
            }
        } else {
            // users enabling the `const_fn` feature gate can do what they want
            !self.features().const_fn
        }
    }
}

pub fn provide(providers: &mut Providers<'_>) {
    /// Const evaluability whitelist is here to check evaluability at the
    /// top level beforehand.
    fn is_const_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> Option<bool> {
        match tcx.fn_sig(def_id).abi() {
            Abi::RustIntrinsic |
            Abi::PlatformIntrinsic => {
                // FIXME: deduplicate these two lists as much as possible
                match tcx.item_name(def_id) {
                    // Keep this list in the same order as the match patterns in
                    // `librustc_mir/interpret/intrinsics.rs`

                    // This whitelist is a list of intrinsics that have a miri-engine implementation
                    // and can thus be called when enabling enough feature gates. The similar
                    // whitelist in `is_intrinsic_min_const_fn` (in this file), exists for allowing
                    // the intrinsics to be called by stable const fns.
                    | sym::caller_location

                    | sym::min_align_of
                    | sym::pref_align_of
                    | sym::needs_drop
                    | sym::size_of
                    | sym::type_id
                    | sym::type_name

                    | sym::ctpop
                    | sym::cttz
                    | sym::cttz_nonzero
                    | sym::ctlz
                    | sym::ctlz_nonzero
                    | sym::bswap
                    | sym::bitreverse

                    | sym::wrapping_add
                    | sym::wrapping_sub
                    | sym::wrapping_mul
                    | sym::add_with_overflow
                    | sym::sub_with_overflow
                    | sym::mul_with_overflow

                    | sym::saturating_add
                    | sym::saturating_sub

                    | sym::unchecked_shl
                    | sym::unchecked_shr

                    | sym::rotate_left
                    | sym::rotate_right

                    | sym::ptr_offset_from

                    | sym::transmute

                    | sym::simd_insert

                    | sym::simd_extract

                    => Some(true),

                    _ => Some(false)
                }
            }
            _ => None
        }
    }

    /// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether
    /// said intrinsic is on the whitelist for being const callable.
    fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
        let hir_id = tcx.hir().as_local_hir_id(def_id)
                              .expect("Non-local call to local provider is_const_fn");

        let node = tcx.hir().get(hir_id);

        if let Some(whitelisted) = is_const_intrinsic(tcx, def_id) {
            whitelisted
        } else if let Some(fn_like) = FnLikeNode::from_node(node) {
            fn_like.constness() == hir::Constness::Const
        } else if let hir::Node::Ctor(_) = node {
            true
        } else {
            false
        }
    }

    fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
        tcx.is_const_fn(def_id) && match tcx.lookup_const_stability(def_id) {
            Some(stab) => {
                if cfg!(debug_assertions) && stab.promotable {
                    let sig = tcx.fn_sig(def_id);
                    assert_eq!(
                        sig.unsafety(),
                        hir::Unsafety::Normal,
                        "don't mark const unsafe fns as promotable",
                        // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
                    );
                }
                stab.promotable
            },
            None => false,
        }
    }

    fn const_fn_is_allowed_fn_ptr(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
        tcx.is_const_fn(def_id) &&
            tcx.lookup_const_stability(def_id)
                .map(|stab| stab.allow_const_fn_ptr).unwrap_or(false)
    }

    *providers = Providers {
        is_const_fn_raw,
        is_promotable_const_fn,
        const_fn_is_allowed_fn_ptr,
        ..*providers
    };
}
<commit_msg>Change the const stab default for internal const fns<commit_after>use crate::ty::query::Providers;
use crate::hir::def_id::DefId;
use crate::hir;
use crate::ty::TyCtxt;
use syntax_pos::symbol::{sym, Symbol};
use rustc_target::spec::abi::Abi;
use crate::hir::map::blocks::FnLikeNode;
use syntax::attr;

impl<'tcx> TyCtxt<'tcx> {
    /// Whether the `def_id` counts as const fn in your current crate, considering all active
    /// feature gates
    pub fn is_const_fn(self, def_id: DefId) -> bool {
        self.is_const_fn_raw(def_id) && match self.is_unstable_const_fn(def_id) {
            Some(feature_name) => {
                // has a `rustc_const_unstable` attribute, check whether the user enabled the
                // corresponding feature gate.
                self.features()
                    .declared_lib_features
                    .iter()
                    .any(|&(sym, _)| sym == feature_name)
            },
            // functions without const stability are either stable user written
            // const fn or the user is using feature gates and we thus don't
            // care what they do
            None => true,
        }
    }

    /// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
    pub fn is_unstable_const_fn(self, def_id: DefId) -> Option<Symbol> {
        if self.is_const_fn_raw(def_id) {
            let const_stab = self.lookup_const_stability(def_id)?;
            if const_stab.level.is_unstable() {
                Some(const_stab.feature)
            } else {
                None
            }
        } else {
            None
        }
    }

    /// Returns `true` if the `def_id` refers to an intrisic which we've whitelisted
    /// for being called from stable `const fn`s (`min_const_fn`).
    ///
    /// Adding more intrinsics requires sign-off from @rust-lang/lang.
    ///
    /// This list differs from the list in `is_const_intrinsic` in the sense that any item on this
    /// list must be on the `is_const_intrinsic` list, too, because if an intrinsic is callable from
    /// stable, it must be callable at all.
    fn is_intrinsic_min_const_fn(self, def_id: DefId) -> bool {
        match self.item_name(def_id) {
            | sym::size_of
            | sym::min_align_of
            | sym::needs_drop
            // Arithmetic:
            | sym::add_with_overflow // ~> .overflowing_add
            | sym::sub_with_overflow // ~> .overflowing_sub
            | sym::mul_with_overflow // ~> .overflowing_mul
            | sym::wrapping_add // ~> .wrapping_add
            | sym::wrapping_sub // ~> .wrapping_sub
            | sym::wrapping_mul // ~> .wrapping_mul
            | sym::saturating_add // ~> .saturating_add
            | sym::saturating_sub // ~> .saturating_sub
            | sym::unchecked_shl // ~> .wrapping_shl
            | sym::unchecked_shr // ~> .wrapping_shr
            | sym::rotate_left // ~> .rotate_left
            | sym::rotate_right // ~> .rotate_right
            | sym::ctpop // ~> .count_ones
            | sym::ctlz // ~> .leading_zeros
            | sym::cttz // ~> .trailing_zeros
            | sym::bswap // ~> .swap_bytes
            | sym::bitreverse // ~> .reverse_bits
            => true,
            _ => false,
        }
    }

    /// Returns `true` if this function must conform to `min_const_fn`
    pub fn is_min_const_fn(self, def_id: DefId) -> bool {
        // Bail out if the signature doesn't contain `const`
        if !self.is_const_fn_raw(def_id) {
            return false;
        }
        if let Abi::RustIntrinsic = self.fn_sig(def_id).abi() {
            return self.is_intrinsic_min_const_fn(def_id);
        }

        if self.features().staged_api {
            // In order for a libstd function to be considered min_const_fn
            // it needs to be stable and have no `rustc_const_unstable` attribute.
            match self.lookup_const_stability(def_id) {
                // `rustc_const_unstable` functions don't need to conform.
                Some(&attr::ConstStability { ref level, .. }) if level.is_unstable() => false,
                None => if let Some(stab) = self.lookup_stability(def_id) {
                    if stab.level.is_stable() {
                        self.sess.span_err(
                            self.def_span(def_id),
                            "stable const functions must have either `rustc_const_stable` or \
                            `rustc_const_unstable` attribute",
                        );
                        // While we errored above, because we don't know if we need to conform, we
                        // err on the "safe" side and require min_const_fn.
                        true
                    } else {
                        // Unstable functions need not conform to min const fn.
                        false
                    }
                } else {
                    // Internal functions are forced to conform to min const fn.
                    // Annotate the internal function with a const stability attribute if
                    // you need to use unstable features.
                    // Note: this is an arbitrary choice that does not affect stability or const
                    // safety or anything, it just changes whether we need to annotate some
                    // internal functions with `rustc_const_stable` or with `rustc_const_unstable`
                    true
                },
                // Everything else needs to conform, because it would be callable from
                // other `min_const_fn` functions.
                _ => true,
            }
        } else {
            // users enabling the `const_fn` feature gate can do what they want
            !self.features().const_fn
        }
    }
}

pub fn provide(providers: &mut Providers<'_>) {
    /// Const evaluability whitelist is here to check evaluability at the
    /// top level beforehand.
    fn is_const_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> Option<bool> {
        match tcx.fn_sig(def_id).abi() {
            Abi::RustIntrinsic |
            Abi::PlatformIntrinsic => {
                // FIXME: deduplicate these two lists as much as possible
                match tcx.item_name(def_id) {
                    // Keep this list in the same order as the match patterns in
                    // `librustc_mir/interpret/intrinsics.rs`

                    // This whitelist is a list of intrinsics that have a miri-engine implementation
                    // and can thus be called when enabling enough feature gates. The similar
                    // whitelist in `is_intrinsic_min_const_fn` (in this file), exists for allowing
                    // the intrinsics to be called by stable const fns.
                    | sym::caller_location

                    | sym::min_align_of
                    | sym::pref_align_of
                    | sym::needs_drop
                    | sym::size_of
                    | sym::type_id
                    | sym::type_name

                    | sym::ctpop
                    | sym::cttz
                    | sym::cttz_nonzero
                    | sym::ctlz
                    | sym::ctlz_nonzero
                    | sym::bswap
                    | sym::bitreverse

                    | sym::wrapping_add
                    | sym::wrapping_sub
                    | sym::wrapping_mul
                    | sym::add_with_overflow
                    | sym::sub_with_overflow
                    | sym::mul_with_overflow

                    | sym::saturating_add
                    | sym::saturating_sub

                    | sym::unchecked_shl
                    | sym::unchecked_shr

                    | sym::rotate_left
                    | sym::rotate_right

                    | sym::ptr_offset_from

                    | sym::transmute

                    | sym::simd_insert

                    | sym::simd_extract

                    => Some(true),

                    _ => Some(false)
                }
            }
            _ => None
        }
    }

    /// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether
    /// said intrinsic is on the whitelist for being const callable.
    fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
        let hir_id = tcx.hir().as_local_hir_id(def_id)
                              .expect("Non-local call to local provider is_const_fn");

        let node = tcx.hir().get(hir_id);

        if let Some(whitelisted) = is_const_intrinsic(tcx, def_id) {
            whitelisted
        } else if let Some(fn_like) = FnLikeNode::from_node(node) {
            fn_like.constness() == hir::Constness::Const
        } else if let hir::Node::Ctor(_) = node {
            true
        } else {
            false
        }
    }

    fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
        tcx.is_const_fn(def_id) && match tcx.lookup_const_stability(def_id) {
            Some(stab) => {
                if cfg!(debug_assertions) && stab.promotable {
                    let sig = tcx.fn_sig(def_id);
                    assert_eq!(
                        sig.unsafety(),
                        hir::Unsafety::Normal,
                        "don't mark const unsafe fns as promotable",
                        // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
                    );
                }
                stab.promotable
            },
            None => false,
        }
    }

    fn const_fn_is_allowed_fn_ptr(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
        tcx.is_const_fn(def_id) &&
            tcx.lookup_const_stability(def_id)
                .map(|stab| stab.allow_const_fn_ptr).unwrap_or(false)
    }

    *providers = Providers {
        is_const_fn_raw,
        is_promotable_const_fn,
        const_fn_is_allowed_fn_ptr,
        ..*providers
    };
}
<|endoftext|>


<commit_before>
/// A priority queue implemented with a binary heap
use core::cmp::Ord;

pub struct PriorityQueue <T: Copy Ord>{
    priv data: ~[T],
}

impl <T: Copy Ord> PriorityQueue<T> {
    /// Returns the greatest item in the queue - fails if empty
    pure fn top(&self) -> &self/T { &self.data[0] }

    /// Returns the greatest item in the queue - None if empty
    pure fn maybe_top(&self) -> Option<&self/T> {
        if self.is_empty() { None } else { Some(self.top()) }
    }

    /// Returns the length of the queue
    pure fn len(&self) -> uint { self.data.len() }

    /// Returns true if a queue contains no elements
    pure fn is_empty(&self) -> bool { self.data.is_empty() }

    /// Returns true if a queue contains some elements
    pure fn is_not_empty(&self) -> bool { self.data.is_not_empty() }

    /// Returns the number of elements the queue can hold without reallocating
    pure fn capacity(&self) -> uint { vec::capacity(&self.data) }

    fn reserve(&mut self, n: uint) { vec::reserve(&mut self.data, n) }

    fn reserve_at_least(&mut self, n: uint) {
        vec::reserve_at_least(&mut self.data, n)
    }

    /// Drop all items from the queue
    fn clear(&mut self) { self.data.truncate(0) }

    /// Pop the greatest item from the queue - fails if empty
    fn pop(&mut self) -> T {
        let mut item = self.data.pop();
        if self.is_not_empty() { item <-> self.data[0]; self.siftdown(0); }
        item
    }

    /// Pop the greatest item from the queue - None if empty
    fn maybe_pop(&mut self) -> Option<T> {
        if self.is_empty() { None } else { Some(self.pop()) }
    }

    /// Push an item onto the queue
    fn push(&mut self, item: T) {
        self.data.push(item);
        self.siftup(0, self.len() - 1);
    }

    /// Optimized version of a push followed by a pop
    fn push_pop(&mut self, item: T) -> T {
        let mut item = item;
        if self.is_not_empty() && self.data[0] > item {
            item <-> self.data[0];
            self.siftdown(0);
        }
        item
    }

    /// Optimized version of a pop followed by a push - fails if empty
    fn replace(&mut self, item: T) -> T {
        let mut item = item;
        item <-> self.data[0];
        self.siftdown(0);
        item
    }

    /// Consume the PriorityQueue and return the underlying vector
    pure fn to_vec(self) -> ~[T] { let PriorityQueue{data: v} = self; v }

    /// Consume the PriorityQueue and return a vector in sorted (ascending) order
    pure fn to_sorted_vec(self) -> ~[T] {
        let mut q = self;
        let mut end = q.len();
        while end > 1 {
            end -= 1;
            q.data[end] <-> q.data[0];
            unsafe { q.siftdown_range(0, end) } // purity-checking workaround
        }
        q.to_vec()
    }

    static pub pure fn from_vec(xs: ~[T]) -> PriorityQueue<T> {
        let mut q = PriorityQueue{data: xs,};
        let mut n = q.len() / 2;
        while n > 0 {
            n -= 1;
            unsafe { q.siftdown(n) }; // purity-checking workaround
        }
        q
    }

    priv fn siftup(&mut self, startpos: uint, pos: uint) {
        let mut pos = pos;
        let newitem = self.data[pos];

        while pos > startpos {
            let parentpos = (pos - 1) >> 1;
            let parent = self.data[parentpos];
            if newitem > parent {
                self.data[pos] = parent;
                pos = parentpos;
                loop
            }
            break
        }
        self.data[pos] = newitem;
    }

    priv fn siftdown_range(&mut self, pos: uint, endpos: uint) {
        let mut pos = pos;
        let startpos = pos;
        let newitem = self.data[pos];

        let mut childpos = 2 * pos + 1;
        while childpos < endpos {
            let rightpos = childpos + 1;
            if rightpos < endpos &&
                   !(self.data[childpos] > self.data[rightpos]) {
                childpos = rightpos;
            }
            self.data[pos] = self.data[childpos];
            pos = childpos;
            childpos = 2 * pos + 1;
        }
        self.data[pos] = newitem;
        self.siftup(startpos, pos);
    }

    priv fn siftdown(&mut self, pos: uint) {
        self.siftdown_range(pos, self.len());
    }
}

#[cfg(test)]
mod tests {
    use sort::merge_sort;
    use core::cmp::le;
    use priority_queue::PriorityQueue::from_vec;

    #[test]
    fn test_top_and_pop() {
        let data = ~[2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
        let mut sorted = merge_sort(data, le);
        let mut heap = from_vec(data);
        while heap.is_not_empty() {
            assert *heap.top() == sorted.last();
            assert heap.pop() == sorted.pop();
        }
    }

    #[test]
    fn test_push() {
        let mut heap = from_vec(~[2, 4, 9]);
        assert heap.len() == 3;
        assert *heap.top() == 9;
        heap.push(11);
        assert heap.len() == 4;
        assert *heap.top() == 11;
        heap.push(5);
        assert heap.len() == 5;
        assert *heap.top() == 11;
        heap.push(27);
        assert heap.len() == 6;
        assert *heap.top() == 27;
        heap.push(3);
        assert heap.len() == 7;
        assert *heap.top() == 27;
        heap.push(103);
        assert heap.len() == 8;
        assert *heap.top() == 103;
    }

    #[test]
    fn test_push_pop() {
        let mut heap = from_vec(~[5, 5, 2, 1, 3]);
        assert heap.len() == 5;
        assert heap.push_pop(6) == 6;
        assert heap.len() == 5;
        assert heap.push_pop(0) == 5;
        assert heap.len() == 5;
        assert heap.push_pop(4) == 5;
        assert heap.len() == 5;
        assert heap.push_pop(1) == 4;
        assert heap.len() == 5;
    }

    #[test]
    fn test_replace() {
        let mut heap = from_vec(~[5, 5, 2, 1, 3]);
        assert heap.len() == 5;
        assert heap.replace(6) == 5;
        assert heap.len() == 5;
        assert heap.replace(0) == 6;
        assert heap.len() == 5;
        assert heap.replace(4) == 5;
        assert heap.len() == 5;
        assert heap.replace(1) == 4;
        assert heap.len() == 5;
    }

    fn check_to_vec(data: ~[int]) {
        let heap = from_vec(data);
        assert merge_sort(heap.to_vec(), le) == merge_sort(data, le);
        assert heap.to_sorted_vec() == merge_sort(data, le);
    }

    #[test]
    fn test_to_vec() {
        check_to_vec(~[]);
        check_to_vec(~[5]);
        check_to_vec(~[3, 2]);
        check_to_vec(~[2, 3]);
        check_to_vec(~[5, 1, 2]);
        check_to_vec(~[1, 100, 2, 3]);
        check_to_vec(~[1, 3, 5, 7, 9, 2, 4, 6, 8, 0]);
        check_to_vec(~[2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
        check_to_vec(~[9, 11, 9, 9, 9, 9, 11, 2, 3, 4, 11, 9, 0, 0, 0, 0]);
        check_to_vec(~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
        check_to_vec(~[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]);
        check_to_vec(~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 1, 2]);
        check_to_vec(~[5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1]);
    }

    #[test]
    #[should_fail]
    fn test_empty_pop() { let mut heap = from_vec::<int>(~[]); heap.pop(); }

    #[test]
    fn test_empty_maybe_pop() {
        let mut heap = from_vec::<int>(~[]);
        assert heap.maybe_pop().is_none();
    }

    #[test]
    #[should_fail]
    fn test_empty_top() { let empty = from_vec::<int>(~[]); empty.top(); }

    #[test]
    fn test_empty_maybe_top() {
        let empty = from_vec::<int>(~[]);
        assert empty.maybe_top().is_none();
    }

    #[test]
    #[should_fail]
    fn test_empty_replace() {
        let mut heap = from_vec::<int>(~[]);
        heap.replace(5);
    }
}
<commit_msg>priority_queue: clean up naming<commit_after>
/// A priority queue implemented with a binary heap
use core::cmp::Ord;

pub struct PriorityQueue <T: Copy Ord>{
    priv data: ~[T],
}

impl <T: Copy Ord> PriorityQueue<T> {
    /// Returns the greatest item in the queue - fails if empty
    pure fn top(&self) -> &self/T { &self.data[0] }

    /// Returns the greatest item in the queue - None if empty
    pure fn maybe_top(&self) -> Option<&self/T> {
        if self.is_empty() { None } else { Some(self.top()) }
    }

    /// Returns the length of the queue
    pure fn len(&self) -> uint { self.data.len() }

    /// Returns true if a queue contains no elements
    pure fn is_empty(&self) -> bool { self.data.is_empty() }

    /// Returns true if a queue contains some elements
    pure fn is_not_empty(&self) -> bool { self.data.is_not_empty() }

    /// Returns the number of elements the queue can hold without reallocating
    pure fn capacity(&self) -> uint { vec::capacity(&self.data) }

    fn reserve(&mut self, n: uint) { vec::reserve(&mut self.data, n) }

    fn reserve_at_least(&mut self, n: uint) {
        vec::reserve_at_least(&mut self.data, n)
    }

    /// Drop all items from the queue
    fn clear(&mut self) { self.data.truncate(0) }

    /// Pop the greatest item from the queue - fails if empty
    fn pop(&mut self) -> T {
        let mut item = self.data.pop();
        if self.is_not_empty() { item <-> self.data[0]; self.siftdown(0); }
        item
    }

    /// Pop the greatest item from the queue - None if empty
    fn maybe_pop(&mut self) -> Option<T> {
        if self.is_empty() { None } else { Some(self.pop()) }
    }

    /// Push an item onto the queue
    fn push(&mut self, item: T) {
        self.data.push(item);
        self.siftup(0, self.len() - 1);
    }

    /// Optimized version of a push followed by a pop
    fn push_pop(&mut self, item: T) -> T {
        let mut item = item;
        if self.is_not_empty() && self.data[0] > item {
            item <-> self.data[0];
            self.siftdown(0);
        }
        item
    }

    /// Optimized version of a pop followed by a push - fails if empty
    fn replace(&mut self, item: T) -> T {
        let mut item = item;
        item <-> self.data[0];
        self.siftdown(0);
        item
    }

    /// Consume the PriorityQueue and return the underlying vector
    pure fn to_vec(self) -> ~[T] { let PriorityQueue{data: v} = self; v }

    /// Consume the PriorityQueue and return a vector in sorted (ascending) order
    pure fn to_sorted_vec(self) -> ~[T] {
        let mut q = self;
        let mut end = q.len();
        while end > 1 {
            end -= 1;
            q.data[end] <-> q.data[0];
            unsafe { q.siftdown_range(0, end) } // purity-checking workaround
        }
        q.to_vec()
    }

    static pub pure fn from_vec(xs: ~[T]) -> PriorityQueue<T> {
        let mut q = PriorityQueue{data: xs,};
        let mut n = q.len() / 2;
        while n > 0 {
            n -= 1;
            unsafe { q.siftdown(n) }; // purity-checking workaround
        }
        q
    }

    priv fn siftup(&mut self, start: uint, pos: uint) {
        let mut pos = pos;
        let new = self.data[pos];

        while pos > start {
            let parent = (pos - 1) >> 1;
            if new > self.data[parent] {
                self.data[pos] = self.data[parent];
                pos = parent;
                loop
            }
            break
        }
        self.data[pos] = new;
    }

    priv fn siftdown_range(&mut self, pos: uint, end: uint) {
        let mut pos = pos;
        let start = pos;
        let new = self.data[pos];

        let mut child = 2 * pos + 1;
        while child < end {
            let right = child + 1;
            if right < end && !(self.data[child] > self.data[right]) {
                child = right;
            }
            self.data[pos] = self.data[child];
            pos = child;
            child = 2 * pos + 1;
        }
        self.data[pos] = new;
        self.siftup(start, pos);
    }

    priv fn siftdown(&mut self, pos: uint) {
        self.siftdown_range(pos, self.len());
    }
}

#[cfg(test)]
mod tests {
    use sort::merge_sort;
    use core::cmp::le;
    use priority_queue::PriorityQueue::from_vec;

    #[test]
    fn test_top_and_pop() {
        let data = ~[2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
        let mut sorted = merge_sort(data, le);
        let mut heap = from_vec(data);
        while heap.is_not_empty() {
            assert *heap.top() == sorted.last();
            assert heap.pop() == sorted.pop();
        }
    }

    #[test]
    fn test_push() {
        let mut heap = from_vec(~[2, 4, 9]);
        assert heap.len() == 3;
        assert *heap.top() == 9;
        heap.push(11);
        assert heap.len() == 4;
        assert *heap.top() == 11;
        heap.push(5);
        assert heap.len() == 5;
        assert *heap.top() == 11;
        heap.push(27);
        assert heap.len() == 6;
        assert *heap.top() == 27;
        heap.push(3);
        assert heap.len() == 7;
        assert *heap.top() == 27;
        heap.push(103);
        assert heap.len() == 8;
        assert *heap.top() == 103;
    }

    #[test]
    fn test_push_pop() {
        let mut heap = from_vec(~[5, 5, 2, 1, 3]);
        assert heap.len() == 5;
        assert heap.push_pop(6) == 6;
        assert heap.len() == 5;
        assert heap.push_pop(0) == 5;
        assert heap.len() == 5;
        assert heap.push_pop(4) == 5;
        assert heap.len() == 5;
        assert heap.push_pop(1) == 4;
        assert heap.len() == 5;
    }

    #[test]
    fn test_replace() {
        let mut heap = from_vec(~[5, 5, 2, 1, 3]);
        assert heap.len() == 5;
        assert heap.replace(6) == 5;
        assert heap.len() == 5;
        assert heap.replace(0) == 6;
        assert heap.len() == 5;
        assert heap.replace(4) == 5;
        assert heap.len() == 5;
        assert heap.replace(1) == 4;
        assert heap.len() == 5;
    }

    fn check_to_vec(data: ~[int]) {
        let heap = from_vec(data);
        assert merge_sort(heap.to_vec(), le) == merge_sort(data, le);
        assert heap.to_sorted_vec() == merge_sort(data, le);
    }

    #[test]
    fn test_to_vec() {
        check_to_vec(~[]);
        check_to_vec(~[5]);
        check_to_vec(~[3, 2]);
        check_to_vec(~[2, 3]);
        check_to_vec(~[5, 1, 2]);
        check_to_vec(~[1, 100, 2, 3]);
        check_to_vec(~[1, 3, 5, 7, 9, 2, 4, 6, 8, 0]);
        check_to_vec(~[2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
        check_to_vec(~[9, 11, 9, 9, 9, 9, 11, 2, 3, 4, 11, 9, 0, 0, 0, 0]);
        check_to_vec(~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
        check_to_vec(~[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]);
        check_to_vec(~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 1, 2]);
        check_to_vec(~[5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1]);
    }

    #[test]
    #[should_fail]
    fn test_empty_pop() { let mut heap = from_vec::<int>(~[]); heap.pop(); }

    #[test]
    fn test_empty_maybe_pop() {
        let mut heap = from_vec::<int>(~[]);
        assert heap.maybe_pop().is_none();
    }

    #[test]
    #[should_fail]
    fn test_empty_top() { let empty = from_vec::<int>(~[]); empty.top(); }

    #[test]
    fn test_empty_maybe_top() {
        let empty = from_vec::<int>(~[]);
        assert empty.maybe_top().is_none();
    }

    #[test]
    #[should_fail]
    fn test_empty_replace() {
        let mut heap = from_vec::<int>(~[]);
        heap.replace(5);
    }
}
<|endoftext|>


<commit_before>use crypto::digest::Digest;
use crypto::sha1::Sha1;
use num;
use std::fmt;

pub const LENGTH: usize = 160;

#[derive(Clone,Copy,Eq,Hash,PartialEq)]
pub struct Address {
    data: [u8; 20]
}

impl Address {
    pub fn for_content(content: &str) -> Address {
        let mut hasher = Sha1::new();
        hasher.input_str(content);
        let mut data = [0; 20];
        hasher.result(&mut data);
        Address {
            data: data
        }
    }

    pub fn from_numeric(numeric: num::BigUint) -> Address {
        let bytes = numeric.to_bytes_be();
        let mut data = [0; 20];
        for (place, byte) in data.iter_mut().rev().zip(bytes.iter().rev()).rev() {
            *place = *byte
        }
        Address {
            data: data
        }
    }

    pub fn from_str(string: &str) -> Address {
        use rustc_serialize::hex::FromHex;
        let bytes = string.from_hex().unwrap();
        let mut data = [0u8; 20];
        for (place, byte) in data.iter_mut().zip(bytes.iter()) {
            *place = *byte;
        }
        Address {
            data: data
        }
    }

    pub fn null() -> Address {
        let data = [0; 20];
        Address { data: data }
    }

    pub fn random(min: &num::BigUint, max: &num::BigUint) -> Address {
        use rand;
        use num::bigint::RandBigInt;

        let mut rng = rand::StdRng::new().unwrap();
        let numeric = rng.gen_biguint_range(min, max);
        Self::from_numeric(numeric)
    }

    pub fn as_numeric(&self) -> num::BigUint {
        // TODO: Expensive
        num::BigUint::from_bytes_be(&self.data)
    }

    pub fn distance_from(&self, other: &Self) -> num::BigUint {
        use std::ops::BitXor;
        self.as_numeric().bitxor(other.as_numeric())
    }

    pub fn to_str(&self) -> String {
        use rustc_serialize::hex::ToHex;
        self.data.to_hex()
    }
}

pub trait Addressable {
    fn get_address(&self) -> Address;
}

impl fmt::Debug for Address {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Address {{ {} }}", self.to_str())
    }
}

#[cfg(test)]
mod tests {
    use num;
    use super::{Address, LENGTH};

    #[test]
    fn test_for_content() {
        let address = Address::for_content("some string");
        assert_eq!(address.to_str(), "8b45e4bd1c6acb88bebf6407d16205f567e62a3e");
    }

    #[test]
    fn test_from_numeric() {
        use num::bigint::ToBigUint;

        let numeric = 0x0000000000000000000000000000000000000001.to_biguint().unwrap();
        let address = Address::from_numeric(numeric);
        assert_eq!(address.as_numeric(), 0x0000000000000000000000000000000000000001.to_biguint().unwrap());
        assert_eq!(address.to_str(), "0000000000000000000000000000000000000001");

        let numeric = num::pow(2.to_biguint().unwrap(), 158) -
            num::pow(2.to_biguint().unwrap(), 157) -
            num::pow(2.to_biguint().unwrap(), 156);
        let address = Address::from_numeric(numeric.clone());
        assert_eq!(address.as_numeric(), numeric);
        assert_eq!(address.to_str(), "1000000000000000000000000000000000000000");

        let numeric = num::pow(2.to_biguint().unwrap(), LENGTH) - 1.to_biguint().unwrap();
        let address = Address::from_numeric(numeric);
        assert_eq!(address.as_numeric(), num::pow(2.to_biguint().unwrap(), LENGTH) - 1.to_biguint().unwrap());
        assert_eq!(address.to_str(), "ffffffffffffffffffffffffffffffffffffffff");
    }

    #[test]
    fn test_from_str() {
        let address = Address::from_str("8b45e4bd1c6acb88bebf6407d16205f567e62a3e");
        assert_eq!(address.to_str(), "8b45e4bd1c6acb88bebf6407d16205f567e62a3e");
    }

    #[test]
    fn test_as_numeric() {
        use num::bigint::ToBigUint;

        let address = Address::from_str("000000000000000000000000000000000000000f");
        assert_eq!(address.as_numeric(), 15u8.to_biguint().unwrap());
        let address = Address::from_str("00000000000000000000000000000000000000f0");
        assert_eq!(address.as_numeric(), 240u8.to_biguint().unwrap());
    }

    #[test]
    fn test_equal() {
        let a = Address::from_str("8b45e4bd1c6acb88bebf6407d16205f567e62a3e");
        let b = Address::from_str("8b45e4bd1c6acb88bebf6407d16205f567e62a3e");
        assert_eq!(a, b);
    }

    #[test]
    fn test_not_equal() {
        let a = Address::from_str("8b45e4bd1c6acb88bebf6407d16205f567e62a3e");
        let b = Address::from_str("8b45e4bd1c6acb88bebf6407d16205f567e62a3f");
        assert!(a != b);
    }
}
<commit_msg>Optimize Address by compacting bytes into u32s<commit_after>use crypto::digest::Digest;
use crypto::sha1::Sha1;
use num;
use std::fmt;

pub const LENGTH: usize = 160;

fn compact_bytes(data: &[u8]) -> [u32; 5] {
    let mut compacted = [0; 5];
    for (compact, bytes) in compacted.iter_mut().zip(data.chunks(4).rev()) {
        *compact = bytes.iter()
            .rev()
            .enumerate()
            .fold(0u32, |sum, (i, &b)| sum + ((b as u32) << (8 * i)));
    }
    compacted
}

#[derive(Clone,Copy,Eq,Hash,PartialEq)]
pub struct Address {
    data: [u32; 5]
}

impl Address {
    pub fn for_content(content: &str) -> Address {
        let mut hasher = Sha1::new();
        hasher.input_str(content);
        let mut data = [0; 20];
        hasher.result(&mut data);
        Address {
            data: compact_bytes(&data)
        }
    }

    pub fn from_numeric(numeric: num::BigUint) -> Address {
        let data = numeric.to_bytes_be();
        Address {
            data: compact_bytes(data.as_slice())
        }
    }

    pub fn from_str(string: &str) -> Address {
        use rustc_serialize::hex::FromHex;
        let bytes = string.from_hex().unwrap();
        let mut data = [0u8; 20];
        for (place, byte) in data.iter_mut().zip(bytes.iter()) {
            *place = *byte;
        }
        Address {
            data: compact_bytes(&data)
        }
    }

    pub fn null() -> Address {
        Address {
            data: [0; 5]
        }
    }

    pub fn random(min: &num::BigUint, max: &num::BigUint) -> Address {
        use rand;
        use num::bigint::RandBigInt;

        let mut rng = rand::StdRng::new().unwrap();
        let numeric = rng.gen_biguint_range(min, max);
        Self::from_numeric(numeric)
    }

    pub fn as_numeric(&self) -> num::BigUint {
        num::BigUint::new(self.data.to_vec())
    }

    pub fn distance_from(&self, other: &Self) -> num::BigUint {
        use std::ops::BitXor;
        self.as_numeric().bitxor(other.as_numeric())
    }

    pub fn to_str(&self) -> String {
        format!("{:040x}", self.as_numeric())
    }
}

pub trait Addressable {
    fn get_address(&self) -> Address;
}

impl fmt::Debug for Address {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Address {{ {} }}", self.to_str())
    }
}

#[cfg(test)]
mod tests {
    use num;
    use super::{Address, LENGTH};

    #[test]
    fn test_for_content() {
        let address = Address::for_content("some string");
        assert_eq!(address.to_str(), "8b45e4bd1c6acb88bebf6407d16205f567e62a3e");
    }

    #[test]
    fn test_from_numeric() {
        use num::bigint::ToBigUint;

        let numeric = 0x0000000000000000000000000000000000000001.to_biguint().unwrap();
        let address = Address::from_numeric(numeric);
        assert_eq!(address.as_numeric(), 0x0000000000000000000000000000000000000001.to_biguint().unwrap());
        assert_eq!(address.to_str(), "0000000000000000000000000000000000000001");

        let numeric = num::pow(2.to_biguint().unwrap(), 158) -
            num::pow(2.to_biguint().unwrap(), 157) -
            num::pow(2.to_biguint().unwrap(), 156);
        let address = Address::from_numeric(numeric.clone());
        assert_eq!(address.as_numeric(), numeric);
        assert_eq!(address.to_str(), "1000000000000000000000000000000000000000");

        let numeric = num::pow(2.to_biguint().unwrap(), LENGTH) - 1.to_biguint().unwrap();
        let address = Address::from_numeric(numeric);
        assert_eq!(address.as_numeric(), num::pow(2.to_biguint().unwrap(), LENGTH) - 1.to_biguint().unwrap());
        assert_eq!(address.to_str(), "ffffffffffffffffffffffffffffffffffffffff");
    }

    #[test]
    fn test_from_str() {
        let address = Address::from_str("8b45e4bd1c6acb88bebf6407d16205f567e62a3e");
        assert_eq!(address.to_str(), "8b45e4bd1c6acb88bebf6407d16205f567e62a3e");
    }

    #[test]
    fn test_as_numeric() {
        use num::bigint::ToBigUint;

        let address = Address::from_str("000000000000000000000000000000000000000f");
        assert_eq!(address.as_numeric(), 15u8.to_biguint().unwrap());
        let address = Address::from_str("00000000000000000000000000000000000000f0");
        assert_eq!(address.as_numeric(), 240u8.to_biguint().unwrap());
    }

    #[test]
    fn test_equal() {
        let a = Address::from_str("8b45e4bd1c6acb88bebf6407d16205f567e62a3e");
        let b = Address::from_str("8b45e4bd1c6acb88bebf6407d16205f567e62a3e");
        assert_eq!(a, b);
    }

    #[test]
    fn test_not_equal() {
        let a = Address::from_str("8b45e4bd1c6acb88bebf6407d16205f567e62a3e");
        let b = Address::from_str("8b45e4bd1c6acb88bebf6407d16205f567e62a3f");
        assert!(a != b);
    }
}
<|endoftext|>


<commit_before>#[allow(unused)]
pub mod entity;
pub mod http;
pub mod response;
pub mod postparams;

extern crate hyper;
extern crate serde_json;
extern crate urlencoded;

use hyper::client;
use hyper::mime::Mime;
use std;
use std::collections::HashMap;
use std::fmt::Debug;
use std::io::Read;
use std::option::Option;
use std::process::exit;
use std::result::Result;

#[derive(Debug)]
pub struct Api {
    base_uri: &'static str,
    api_key: String,
    login_token: String,
    client: hyper::client::Client,
    user_agent: String,
}

#[allow(unused)]
impl Api {

    /// Create a new api client
    pub fn new(api_key: String) -> Api {
        let crates_version = &std::env::var("CARGO_PKG_VERSION")
            .unwrap_or("unknown".to_string());
        let crates_name = std::env::var("CARGO_PKG_NAME").
            unwrap_or("unknown".to_string());

        let ua = format!("libproxer-rust({}/v{})", crates_name, crates_version);

        Api {
            base_uri:    "http://proxer.me/api/v1/",
            api_key:     api_key,
            login_token: "None".to_string(),
            client:      hyper::client::Client::new(),
            user_agent:  ua,
        }
    }

    pub fn info_get_full_info(self, id: u32) -> Result<client::response::Response, hyper::Error> {
        use api::entity::response::*;
        let url = "info/fullentry";

        let mut post = postparams::Postparams::new();

        post.add("id", id);

        response::Response::new::<info::fullinfo::FullInfo>(self.http_req(url, post))
    }

    fn http_req<T: ToString>(self, url: &str, data: T) -> Result<client::response::Response, hyper::Error> {
        let uri = self.base_uri.to_string()+url;
        let hyper_url = hyper::Url::parse(&uri).unwrap();

        let mut headers = hyper::header::Headers::new();
        header! {(ProxerApiKeyHeader, "proxer-api-key") => [String]}
        header! {(UserAgent, "User-Agent") => [String]}
        headers.set(ProxerApiKeyHeader(self.api_key));
        headers.set(UserAgent(self.user_agent));
        headers.set(hyper::header::ContentType::form_url_encoded());

        self.client
            .post(hyper_url)
            .headers(headers)
            .body(&data.to_string())
            .send()
    }

    pub fn read_json(json: String) -> std::result::Result<serde_json::Value, serde_json::Error> {
        serde_json::from_str(&json)
    }
}
<commit_msg>expect `Postparams` instead of generic with `ToString` trait<commit_after>#[allow(unused)]
pub mod entity;
pub mod http;
pub mod response;
pub mod postparams;

extern crate hyper;
extern crate serde_json;
extern crate urlencoded;

use hyper::client;
use hyper::mime::Mime;
use std;
use std::collections::HashMap;
use std::fmt::Debug;
use std::io::Read;
use std::option::Option;
use std::process::exit;
use std::result::Result;

#[derive(Debug)]
pub struct Api {
    base_uri: &'static str,
    api_key: String,
    login_token: String,
    client: hyper::client::Client,
    user_agent: String,
}

#[allow(unused)]
impl Api {

    /// Create a new api client
    pub fn new(api_key: String) -> Api {
        let crates_version = &std::env::var("CARGO_PKG_VERSION")
            .unwrap_or("unknown".to_string());
        let crates_name = std::env::var("CARGO_PKG_NAME").
            unwrap_or("unknown".to_string());

        let ua = format!("libproxer-rust({}/v{})", crates_name, crates_version);

        Api {
            base_uri:    "http://proxer.me/api/v1/",
            api_key:     api_key,
            login_token: "None".to_string(),
            client:      hyper::client::Client::new(),
            user_agent:  ua,
        }
    }

    pub fn info_get_full_info(self, id: u32) -> Result<client::response::Response, hyper::Error> {
        use api::entity::response::*;
        let url = "info/fullentry";

        let mut post = postparams::Postparams::new();
        post.add("id", id);

        response::Response::new::<info::fullinfo::FullInfo>(self.http_req(url, post))
    }

    fn http_req(self, url: &str, data: postparams::Postparams) -> Result<client::response::Response, hyper::Error> {
        let uri = self.base_uri.to_string()+url;
        let hyper_url = hyper::Url::parse(&uri).unwrap();

        let mut headers = hyper::header::Headers::new();
        header! {(ProxerApiKeyHeader, "proxer-api-key") => [String]}
        header! {(UserAgent, "User-Agent") => [String]}
        headers.set(ProxerApiKeyHeader(self.api_key));
        headers.set(UserAgent(self.user_agent));
        headers.set(hyper::header::ContentType::form_url_encoded());

        self.client
            .post(hyper_url)
            .headers(headers)
            .body(&data.to_string())
            .send()
    }

    pub fn read_json(json: String) -> std::result::Result<serde_json::Value, serde_json::Error> {
        serde_json::from_str(&json)
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt;

use ansi_term::{Color, Style};

/// Holds information about how to style a module
pub struct ModuleStyle {
    pub background: Color,
    pub foreground: Color,
    /// Attributes like bold, italicized, underlined, etc...
    pub text_properties: Vec<Style>,
}

/// Attempts to convert a string into an `ansi_term::Color`.
///
/// Returns a `TryFromError` if the provided string doesn't match
/// any of the colors defined in crate `ansi_term`.
pub fn try_color_from_str(s: &str) -> Result<Color, TryFromError> {
    match s {
        "black" => Ok(Color::Black),
        "red" => Ok(Color::Red),
        "green" => Ok(Color::Green),
        "yellow" => Ok(Color::Yellow),
        "blue" => Ok(Color::Blue),
        "purple" => Ok(Color::Purple),
        "cyan" => Ok(Color::Cyan),
        "white" => Ok(Color::White),
        _ => Err(TryFromError),
    }
}

#[derive(Debug, PartialEq)]
/// Error type for when converting a string fails
pub struct TryFromError;

impl fmt::Display for TryFromError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

impl Error for TryFromError {
    fn description(&self) -> &str {
        "unrecognized input"
    }
}

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

    #[test]
    fn test_color_try_from_str() {
        assert_eq!(try_color_from_str("blue"), Ok(Color::Blue));
        assert_eq!(try_color_from_str("teal"), Err(TryFromError));
    }
}
<commit_msg>feat: add error type for config parsing<commit_after>use std::error::Error;
use std::fmt;

use ansi_term::{Color, Style};

/// Holds information about how to style a module
pub struct ModuleStyle {
    pub background: Color,
    pub foreground: Color,
    /// Attributes like bold, italicized, underlined, etc...
    pub text_properties: Vec<Style>,
}

// We use methods of the form "try_*_from_*" because the user should
// just be able to specify (in their config) what color/style they
// want, and we have to be able to parse what they say into a
// meaningful type.

/// Attempts to convert a string into an `ansi_term::Color`.
///
/// Returns a `ConvertError` if the provided string doesn't match
/// any of the colors defined in crate `ansi_term`.
pub fn try_color_from_str(s: &str) -> Result<Color, ConvertError> {
    match s {
        "black" => Ok(Color::Black),
        "red" => Ok(Color::Red),
        "green" => Ok(Color::Green),
        "yellow" => Ok(Color::Yellow),
        "blue" => Ok(Color::Blue),
        "purple" => Ok(Color::Purple),
        "cyan" => Ok(Color::Cyan),
        "white" => Ok(Color::White),
        _ => Err(ConvertError::NoSuchMatch),
    }
}

// NOTE: We do not need a try_color_from_u8.
// The implementation would just look like:
// pub fn try_color_from_u8(i: u8) -> Color { Color::u8(i) }
// It would always succeed due to Rust's type system.

/// Attempts to convert a string into an `ansi_term::Color::RGB`.
///
/// Returns a `ConvertError::InvalidForm` if the provided string is
/// not of the form "(u8, u8, u8)".
pub fn try_rgb_from_str(s: &str) -> Result<Color, ConvertError> {
    unimplemented!()
}

#[derive(Debug, PartialEq)]
/// Error type for when a conversion fails
pub enum ConvertError {
    /// Input doesn't correspond to a valid result
    NoSuchMatch,
    /// Input is malformed and cannot be parsed
    InvalidForm,
}

impl fmt::Display for ConvertError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

impl Error for ConvertError {
    fn description(&self) -> &str {
        match *self {
            ConvertError::NoSuchMatch => "no match was found for the provided input",
            ConvertError::InvalidForm => "provided input was malformed and could not be parsed",
        }
    }
}

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

    #[test]
    fn test_color_try_from_str() {
        assert_eq!(try_color_from_str("blue"), Ok(Color::Blue));
        assert_eq!(try_color_from_str("teal"), Err(ConvertError::NoSuchMatch));
    }
}
<|endoftext|>


<commit_before>use node::{ Body, Expr };
use parser::{ Parse, Context };
use TokenValue;
use { Result, Expect };
use error::{ Error, ErrorMessage };

impl<'c> Parse<'c> for Body<'c> {
    type Output = Body<'c>;

    fn parse<'r>(parser: &mut Context<'r, 'c>)
        -> Result<Body<'c>>
    {
        let mut maybe_line = None;
        let mut rv = Vec::new();

        while let Some(token) = try!(parser.maybe_current()) {
            if let None = maybe_line {
                maybe_line = Some(token.line);
            }
            match token.value {
                TokenValue::Text(t) => {
                    try!(parser.next());
                    rv.push(Body::Text { value: t, line: token.line })
                },
                TokenValue::VarStart => {
                    try!(parser.next());
                    let expr = try!(Expr::parse(parser));
                    try!(parser.expect(TokenValue::VarEnd));
                    rv.push(Body::Print { expr: Box::new(expr), line: token.line });
                },
                TokenValue::BlockStart => {
                    try!(parser.next());
                    let token = try!(parser.current());

                    let tag_name = match token.value {
                        TokenValue::Name(n) => n,
                        _ => return Err(Error::new_at(ErrorMessage::MustStartWithTagName, token.line)),
                    };

                    let subparser = match parser.env.handlers.get(tag_name) {
                        Some(sp) => sp,
                        None => {
                            unreachable!("errors when subparser not found not implemented")
                        }
                    };

                    let node = try!(subparser.parse(parser));
                    try!(parser.next());

                    unreachable!("token parsers not implemented")
                },
                tv => { panic!("not implemented {:?}", tv) },
            };
        }

        if rv.len() == 1 {
            Ok(rv.remove(0))
        } else {
            Ok(Body::List { items: rv })
        }
    }
}
<commit_msg>Initiate subparsing at BlockStart.<commit_after>use node::{ Body, Expr };
use parser::{ Parse, Context };
use TokenValue;
use { Result, Expect };
use error::{ Error, ErrorMessage };

impl<'c> Parse<'c> for Body<'c> {
    type Output = Body<'c>;

    fn parse<'r>(parser: &mut Context<'r, 'c>)
        -> Result<Body<'c>>
    {
        let mut maybe_line = None;
        let mut rv = Vec::new();

        while let Some(token) = try!(parser.maybe_current()) {
            if let None = maybe_line {
                maybe_line = Some(token.line);
            }
            match token.value {
                TokenValue::Text(t) => {
                    try!(parser.next());
                    rv.push(Body::Text { value: t, line: token.line })
                },
                TokenValue::VarStart => {
                    try!(parser.next());
                    let expr = try!(Expr::parse(parser));
                    try!(parser.expect(TokenValue::VarEnd));
                    rv.push(Body::Print { expr: Box::new(expr), line: token.line });
                },
                TokenValue::BlockStart => {
                    try!(parser.next());
                    let token = try!(parser.current());

                    let tag_name = match token.value {
                        TokenValue::Name(n) => n,
                        _ => return Err(Error::new_at(ErrorMessage::MustStartWithTagName, token.line)),
                    };

                    let subparser = match parser.env.handlers.get(tag_name) {
                        Some(sp) => sp,
                        None => {
                            unreachable!("errors when subparser not found not implemented")
                        }
                    };

                    try!(parser.next());
                    if let Some(node) = try!(subparser.parse(parser)) {
                         rv.push(node);
                    }
                },
                tv => { panic!("not implemented {:?}", tv) },
            };
        }

        if rv.len() == 1 {
            Ok(rv.remove(0))
        } else {
            Ok(Body::List { items: rv })
        }
    }
}
<|endoftext|>


<commit_before>use stamp::Stamp;

pub struct Filled {
    filler: String,
    height: usize,
    width: usize,
}

impl Filled {
    pub fn new(width: usize, height: usize, filler: &str) -> Self {
        let filler = filler.to_string();

        Filled {
            filler,
            height,
            width
        }
    }

    pub fn blank(width: usize, height: usize) -> Self {
        Self::new(width, height, " ")
    }

    pub fn render(&self) -> String {
        let mut s = String::new();

        for r in 0..self.height {
            for c in 0..self.width {
                s += &self.filler;

            }
            if r != self.height - 1 {
                s += "\n";
            }
        }

        s
    }
}

pub struct BorderChars {
    left: &'static str,
    bottom_left: &'static str,
    bottom: &'static str,
    bottom_right: &'static str,
    right: &'static str,
    top_left: &'static str,
    top: &'static str,
    top_right: &'static str,
}

pub const ASCII_BORDER: BorderChars = BorderChars {
    left: "|",
    bottom_left: "+",
    bottom: "-",
    bottom_right: "+",
    right: "|",
    top_left: "+",
    top: "-",
    top_right: "+",
};

pub const UNICODE_BORDER: BorderChars = BorderChars {
    left: "│",
    bottom_left: "└",
    bottom: "─",
    bottom_right: "┘",
    right: "│",
    top_left: "┌",
    top: "─",
    top_right: "┐",
};

pub struct Border {
    chars: BorderChars,
    height: usize,
    width: usize,
}

impl Border {
    pub fn new(chars: BorderChars, width: usize, height: usize) -> Self {
        Border {
            chars,
            height,
            width,
        }
    }

    pub fn render(&self) -> String {
        self.render_checked().unwrap()
    }

    fn render_checked(&self) -> Result<String, ()> {
        let filled = Stamp::new(&Filled::blank(self.width, self.height).render())?;

        let bottom_left = Stamp::new(self.chars.bottom_left)?;
        let bottom_right = Stamp::new(self.chars.bottom_right)?;
        let top_left = Stamp::new(self.chars.top_left)?;
        let top_right = Stamp::new(self.chars.top_right)?;

        let bottom = Stamp::new(&self.render_bottom())?;
        let left = Stamp::new(&self.render_left())?;
        let right = Stamp::new(&self.render_right())?;
        let top = Stamp::new(&self.render_top())?;

        let layered = filled
            .layer(&top_left, 0, 0)?
            .layer(&top, 1, 0)?
            .layer(&top_right, self.width - 1, 0)?
            .layer(&right, self.width - 1, 1)?
            .layer(&bottom_right, self.width - 1, self.height - 1)?
            .layer(&bottom, 1, self.height - 1)?
            .layer(&bottom_left, 0, self.height - 1)?
            .layer(&left, 0, 1)?;

        Ok(layered.render())
    }

    fn render_bottom(&self) -> String {
        render_horizontal_line(self.chars.bottom, self.width - 2)
    }

    fn render_left(&self) -> String {
        render_vertical_line(self.chars.left, self.height - 2)
    }

    fn render_right(&self) -> String {
        render_vertical_line(self.chars.right, self.height - 2)
    }

    fn render_top(&self) -> String {
        render_horizontal_line(self.chars.top, self.width - 2)
    }
}

fn render_horizontal_line(c: &str, size: usize) -> String {
    use std::iter::{FromIterator, repeat};

    String::from_iter(repeat(c.to_string()).take(size))
}

fn render_vertical_line(c: &str, size: usize) -> String {
    let mut s = String::new();

    for i in 0..size {
        s += c;

        if i != size - 1 {
            s += "\n";
        }
    }

    s
}
<commit_msg>Rename unused loop variable<commit_after>use stamp::Stamp;

pub struct Filled {
    filler: String,
    height: usize,
    width: usize,
}

impl Filled {
    pub fn new(width: usize, height: usize, filler: &str) -> Self {
        let filler = filler.to_string();

        Filled {
            filler,
            height,
            width
        }
    }

    pub fn blank(width: usize, height: usize) -> Self {
        Self::new(width, height, " ")
    }

    pub fn render(&self) -> String {
        let mut s = String::new();

        for r in 0..self.height {
            for _c in 0..self.width {
                s += &self.filler;

            }
            if r != self.height - 1 {
                s += "\n";
            }
        }

        s
    }
}

pub struct BorderChars {
    left: &'static str,
    bottom_left: &'static str,
    bottom: &'static str,
    bottom_right: &'static str,
    right: &'static str,
    top_left: &'static str,
    top: &'static str,
    top_right: &'static str,
}

pub const ASCII_BORDER: BorderChars = BorderChars {
    left: "|",
    bottom_left: "+",
    bottom: "-",
    bottom_right: "+",
    right: "|",
    top_left: "+",
    top: "-",
    top_right: "+",
};

pub const UNICODE_BORDER: BorderChars = BorderChars {
    left: "│",
    bottom_left: "└",
    bottom: "─",
    bottom_right: "┘",
    right: "│",
    top_left: "┌",
    top: "─",
    top_right: "┐",
};

pub struct Border {
    chars: BorderChars,
    height: usize,
    width: usize,
}

impl Border {
    pub fn new(chars: BorderChars, width: usize, height: usize) -> Self {
        Border {
            chars,
            height,
            width,
        }
    }

    pub fn render(&self) -> String {
        self.render_checked().unwrap()
    }

    fn render_checked(&self) -> Result<String, ()> {
        let filled = Stamp::new(&Filled::blank(self.width, self.height).render())?;

        let bottom_left = Stamp::new(self.chars.bottom_left)?;
        let bottom_right = Stamp::new(self.chars.bottom_right)?;
        let top_left = Stamp::new(self.chars.top_left)?;
        let top_right = Stamp::new(self.chars.top_right)?;

        let bottom = Stamp::new(&self.render_bottom())?;
        let left = Stamp::new(&self.render_left())?;
        let right = Stamp::new(&self.render_right())?;
        let top = Stamp::new(&self.render_top())?;

        let layered = filled
            .layer(&top_left, 0, 0)?
            .layer(&top, 1, 0)?
            .layer(&top_right, self.width - 1, 0)?
            .layer(&right, self.width - 1, 1)?
            .layer(&bottom_right, self.width - 1, self.height - 1)?
            .layer(&bottom, 1, self.height - 1)?
            .layer(&bottom_left, 0, self.height - 1)?
            .layer(&left, 0, 1)?;

        Ok(layered.render())
    }

    fn render_bottom(&self) -> String {
        render_horizontal_line(self.chars.bottom, self.width - 2)
    }

    fn render_left(&self) -> String {
        render_vertical_line(self.chars.left, self.height - 2)
    }

    fn render_right(&self) -> String {
        render_vertical_line(self.chars.right, self.height - 2)
    }

    fn render_top(&self) -> String {
        render_horizontal_line(self.chars.top, self.width - 2)
    }
}

fn render_horizontal_line(c: &str, size: usize) -> String {
    use std::iter::{FromIterator, repeat};

    String::from_iter(repeat(c.to_string()).take(size))
}

fn render_vertical_line(c: &str, size: usize) -> String {
    let mut s = String::new();

    for i in 0..size {
        s += c;

        if i != size - 1 {
            s += "\n";
        }
    }

    s
}
<|endoftext|>