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

#[allow(non_uppercase_pattern_statics)];

use lib::llvm::{llvm, TypeRef, Bool, False, True, TypeKind};
use lib::llvm::{Float, Double, X86_FP80, PPC_FP128, FP128};

use middle::ty;

use middle::trans::context::CrateContext;
use middle::trans::base;

use syntax::ast;
use syntax::abi::{Architecture, X86, X86_64, Arm, Mips};

use std::c_str::ToCStr;
use std::vec;
use std::cast;

use std::libc::{c_uint};

#[deriving(Clone, Eq)]
pub struct Type {
    priv rf: TypeRef
}

macro_rules! ty (
    ($e:expr) => ( Type::from_ref(unsafe { $e }))
)

/**
 * Wrapper for LLVM TypeRef
 */
impl Type {
    #[inline(always)]
    pub fn from_ref(r: TypeRef) -> Type {
        Type {
            rf: r
        }
    }

    #[inline(always)] // So it doesn't kill --opt-level=0 builds of the compiler
    pub fn to_ref(&self) -> TypeRef {
        self.rf
    }

    pub fn void() -> Type {
        ty!(llvm::LLVMVoidTypeInContext(base::task_llcx()))
    }

    pub fn nil() -> Type {
        Type::empty_struct()
    }

    pub fn metadata() -> Type {
        ty!(llvm::LLVMMetadataTypeInContext(base::task_llcx()))
    }

    pub fn i1() -> Type {
        ty!(llvm::LLVMInt1TypeInContext(base::task_llcx()))
    }

    pub fn i8() -> Type {
        ty!(llvm::LLVMInt8TypeInContext(base::task_llcx()))
    }

    pub fn i16() -> Type {
        ty!(llvm::LLVMInt16TypeInContext(base::task_llcx()))
    }

    pub fn i32() -> Type {
        ty!(llvm::LLVMInt32TypeInContext(base::task_llcx()))
    }

    pub fn i64() -> Type {
        ty!(llvm::LLVMInt64TypeInContext(base::task_llcx()))
    }

    pub fn f32() -> Type {
        ty!(llvm::LLVMFloatTypeInContext(base::task_llcx()))
    }

    pub fn f64() -> Type {
        ty!(llvm::LLVMDoubleTypeInContext(base::task_llcx()))
    }

    pub fn bool() -> Type {
        Type::i8()
    }

    pub fn char() -> Type {
        Type::i32()
    }

    pub fn i8p() -> Type {
        Type::i8().ptr_to()
    }

    pub fn int(arch: Architecture) -> Type {
        match arch {
            X86 | Arm | Mips => Type::i32(),
            X86_64 => Type::i64()
        }
    }

    pub fn float(_: Architecture) -> Type {
        // All architectures currently just use doubles as the default
        // float size
        Type::f64()
    }

    pub fn int_from_ty(ctx: &CrateContext, t: ast::int_ty) -> Type {
        match t {
            ast::ty_i => ctx.int_type,
            ast::ty_i8 => Type::i8(),
            ast::ty_i16 => Type::i16(),
            ast::ty_i32 => Type::i32(),
            ast::ty_i64 => Type::i64()
        }
    }

    pub fn uint_from_ty(ctx: &CrateContext, t: ast::uint_ty) -> Type {
        match t {
            ast::ty_u => ctx.int_type,
            ast::ty_u8 => Type::i8(),
            ast::ty_u16 => Type::i16(),
            ast::ty_u32 => Type::i32(),
            ast::ty_u64 => Type::i64()
        }
    }

    pub fn float_from_ty(t: ast::float_ty) -> Type {
        match t {
            ast::ty_f32 => Type::f32(),
            ast::ty_f64 => Type::f64()
        }
    }

    pub fn size_t(arch: Architecture) -> Type {
        Type::int(arch)
    }

    pub fn func(args: &[Type], ret: &Type) -> Type {
        let vec : &[TypeRef] = unsafe { cast::transmute(args) };
        ty!(llvm::LLVMFunctionType(ret.to_ref(), vec::raw::to_ptr(vec),
                                   args.len() as c_uint, False))
    }

    pub fn variadic_func(args: &[Type], ret: &Type) -> Type {
        let vec : &[TypeRef] = unsafe { cast::transmute(args) };
        ty!(llvm::LLVMFunctionType(ret.to_ref(), vec::raw::to_ptr(vec),
                                   args.len() as c_uint, True))
    }

    pub fn func_pair(cx: &CrateContext, fn_ty: &Type) -> Type {
        Type::struct_([fn_ty.ptr_to(), Type::opaque_cbox_ptr(cx)], false)
    }

    pub fn ptr(ty: Type) -> Type {
        ty!(llvm::LLVMPointerType(ty.to_ref(), 0 as c_uint))
    }

    pub fn struct_(els: &[Type], packed: bool) -> Type {
        let els : &[TypeRef] = unsafe { cast::transmute(els) };
        ty!(llvm::LLVMStructTypeInContext(base::task_llcx(), vec::raw::to_ptr(els),
                                          els.len() as c_uint, packed as Bool))
    }

    pub fn named_struct(name: &str) -> Type {
        let ctx = base::task_llcx();
        ty!(name.with_c_str(|s| llvm::LLVMStructCreateNamed(ctx, s)))
    }

    pub fn empty_struct() -> Type {
        Type::struct_([], false)
    }

    pub fn vtable() -> Type {
        Type::array(&Type::i8().ptr_to(), 1)
    }

    pub fn generic_glue_fn(cx: &mut CrateContext) -> Type {
        match cx.tn.find_type("glue_fn") {
            Some(ty) => return ty,
            None => ()
        }

        let ty = Type::glue_fn(Type::i8p());
        cx.tn.associate_type("glue_fn", &ty);

        return ty;
    }

    pub fn glue_fn(t: Type) -> Type {
        Type::func([ Type::nil().ptr_to(), t ],
            &Type::void())
    }

    pub fn tydesc(arch: Architecture) -> Type {
        let mut tydesc = Type::named_struct("tydesc");
        let glue_fn_ty = Type::glue_fn(Type::i8p()).ptr_to();

        let int_ty = Type::int(arch);

        // Must mirror:
        //
        // std::unstable::intrinsics::TyDesc
        // type_desc in rt

        let elems = [int_ty,     // size
                     int_ty,     // align
                     glue_fn_ty, // take
                     glue_fn_ty, // drop
                     glue_fn_ty, // free
                     glue_fn_ty, // visit
                     int_ty, // borrow_offset
                     Type::struct_([Type::i8p(), Type::int(arch)], false)]; // name
        tydesc.set_struct_body(elems, false);

        return tydesc;
    }

    pub fn array(ty: &Type, len: u64) -> Type {
        ty!(llvm::LLVMArrayType(ty.to_ref(), len as c_uint))
    }

    pub fn vector(ty: &Type, len: u64) -> Type {
        ty!(llvm::LLVMVectorType(ty.to_ref(), len as c_uint))
    }

    pub fn vec(arch: Architecture, ty: &Type) -> Type {
        Type::struct_(
            [ Type::int(arch), Type::int(arch), Type::array(ty, 0) ],
        false)
    }

    pub fn opaque_vec(arch: Architecture) -> Type {
        Type::vec(arch, &Type::i8())
    }

    #[inline]
    pub fn box_header_fields(ctx: &CrateContext) -> ~[Type] {
        ~[
            ctx.int_type, ctx.tydesc_type.ptr_to(),
            Type::i8().ptr_to(), Type::i8().ptr_to()
        ]
    }

    pub fn box_header(ctx: &CrateContext) -> Type {
        Type::struct_(Type::box_header_fields(ctx), false)
    }

    pub fn box(ctx: &CrateContext, ty: &Type) -> Type {
        Type::struct_(Type::box_header_fields(ctx) + &[*ty], false)
    }

    pub fn opaque() -> Type {
        Type::i8()
    }

    pub fn opaque_box(ctx: &CrateContext) -> Type {
        Type::box(ctx, &Type::opaque())
    }

    pub fn unique(ctx: &CrateContext, ty: &Type) -> Type {
        Type::box(ctx, ty)
    }

    pub fn opaque_cbox_ptr(cx: &CrateContext) -> Type {
        Type::opaque_box(cx).ptr_to()
    }

    pub fn enum_discrim(cx: &CrateContext) -> Type {
        cx.int_type
    }

    pub fn opaque_trait(ctx: &CrateContext, store: ty::TraitStore) -> Type {
        let tydesc_ptr = ctx.tydesc_type.ptr_to();
        let box_ty = match store {
            ty::BoxTraitStore => Type::opaque_box(ctx),
            ty::UniqTraitStore => Type::unique(ctx, &Type::i8()),
            ty::RegionTraitStore(*) => Type::i8()
        };
        Type::struct_([tydesc_ptr, box_ty.ptr_to()], false)
    }

    pub fn kind(&self) -> TypeKind {
        unsafe {
            llvm::LLVMGetTypeKind(self.to_ref())
        }
    }

    pub fn set_struct_body(&mut self, els: &[Type], packed: bool) {
        unsafe {
            let vec : &[TypeRef] = cast::transmute(els);
            llvm::LLVMStructSetBody(self.to_ref(), vec::raw::to_ptr(vec),
                                    els.len() as c_uint, packed as Bool)
        }
    }

    pub fn ptr_to(&self) -> Type {
        ty!(llvm::LLVMPointerType(self.to_ref(), 0))
    }

    pub fn get_field(&self, idx: uint) -> Type {
        unsafe {
            let num_fields = llvm::LLVMCountStructElementTypes(self.to_ref()) as uint;
            let mut elems = vec::from_elem(num_fields, 0 as TypeRef);

            llvm::LLVMGetStructElementTypes(self.to_ref(), vec::raw::to_mut_ptr(elems));

            Type::from_ref(elems[idx])
        }
    }

    pub fn is_packed(&self) -> bool {
        unsafe {
            llvm::LLVMIsPackedStruct(self.to_ref()) == True
        }
    }

    pub fn element_type(&self) -> Type {
        unsafe {
            Type::from_ref(llvm::LLVMGetElementType(self.to_ref()))
        }
    }

    pub fn array_length(&self) -> uint {
        unsafe {
            llvm::LLVMGetArrayLength(self.to_ref()) as uint
        }
    }

    pub fn field_types(&self) -> ~[Type] {
        unsafe {
            let n_elts = llvm::LLVMCountStructElementTypes(self.to_ref()) as uint;
            if n_elts == 0 {
                return ~[];
            }
            let mut elts = vec::from_elem(n_elts, 0 as TypeRef);
            llvm::LLVMGetStructElementTypes(self.to_ref(), &mut elts[0]);
            cast::transmute(elts)
        }
    }

    pub fn return_type(&self) -> Type {
        ty!(llvm::LLVMGetReturnType(self.to_ref()))
    }

    pub fn func_params(&self) -> ~[Type] {
        unsafe {
            let n_args = llvm::LLVMCountParamTypes(self.to_ref()) as uint;
            let args = vec::from_elem(n_args, 0 as TypeRef);
            llvm::LLVMGetParamTypes(self.to_ref(), vec::raw::to_ptr(args));
            cast::transmute(args)
        }
    }

    pub fn float_width(&self) -> uint {
        match self.kind() {
            Float => 32,
            Double => 64,
            X86_FP80 => 80,
            FP128 | PPC_FP128 => 128,
            _ => fail!("llvm_float_width called on a non-float type")
        }
    }
}
<commit_msg>auto merge of #10677 : jld/rust/type-enum-discrim-rm, r=alexcrichton<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[allow(non_uppercase_pattern_statics)];

use lib::llvm::{llvm, TypeRef, Bool, False, True, TypeKind};
use lib::llvm::{Float, Double, X86_FP80, PPC_FP128, FP128};

use middle::ty;

use middle::trans::context::CrateContext;
use middle::trans::base;

use syntax::ast;
use syntax::abi::{Architecture, X86, X86_64, Arm, Mips};

use std::c_str::ToCStr;
use std::vec;
use std::cast;

use std::libc::{c_uint};

#[deriving(Clone, Eq)]
pub struct Type {
    priv rf: TypeRef
}

macro_rules! ty (
    ($e:expr) => ( Type::from_ref(unsafe { $e }))
)

/**
 * Wrapper for LLVM TypeRef
 */
impl Type {
    #[inline(always)]
    pub fn from_ref(r: TypeRef) -> Type {
        Type {
            rf: r
        }
    }

    #[inline(always)] // So it doesn't kill --opt-level=0 builds of the compiler
    pub fn to_ref(&self) -> TypeRef {
        self.rf
    }

    pub fn void() -> Type {
        ty!(llvm::LLVMVoidTypeInContext(base::task_llcx()))
    }

    pub fn nil() -> Type {
        Type::empty_struct()
    }

    pub fn metadata() -> Type {
        ty!(llvm::LLVMMetadataTypeInContext(base::task_llcx()))
    }

    pub fn i1() -> Type {
        ty!(llvm::LLVMInt1TypeInContext(base::task_llcx()))
    }

    pub fn i8() -> Type {
        ty!(llvm::LLVMInt8TypeInContext(base::task_llcx()))
    }

    pub fn i16() -> Type {
        ty!(llvm::LLVMInt16TypeInContext(base::task_llcx()))
    }

    pub fn i32() -> Type {
        ty!(llvm::LLVMInt32TypeInContext(base::task_llcx()))
    }

    pub fn i64() -> Type {
        ty!(llvm::LLVMInt64TypeInContext(base::task_llcx()))
    }

    pub fn f32() -> Type {
        ty!(llvm::LLVMFloatTypeInContext(base::task_llcx()))
    }

    pub fn f64() -> Type {
        ty!(llvm::LLVMDoubleTypeInContext(base::task_llcx()))
    }

    pub fn bool() -> Type {
        Type::i8()
    }

    pub fn char() -> Type {
        Type::i32()
    }

    pub fn i8p() -> Type {
        Type::i8().ptr_to()
    }

    pub fn int(arch: Architecture) -> Type {
        match arch {
            X86 | Arm | Mips => Type::i32(),
            X86_64 => Type::i64()
        }
    }

    pub fn float(_: Architecture) -> Type {
        // All architectures currently just use doubles as the default
        // float size
        Type::f64()
    }

    pub fn int_from_ty(ctx: &CrateContext, t: ast::int_ty) -> Type {
        match t {
            ast::ty_i => ctx.int_type,
            ast::ty_i8 => Type::i8(),
            ast::ty_i16 => Type::i16(),
            ast::ty_i32 => Type::i32(),
            ast::ty_i64 => Type::i64()
        }
    }

    pub fn uint_from_ty(ctx: &CrateContext, t: ast::uint_ty) -> Type {
        match t {
            ast::ty_u => ctx.int_type,
            ast::ty_u8 => Type::i8(),
            ast::ty_u16 => Type::i16(),
            ast::ty_u32 => Type::i32(),
            ast::ty_u64 => Type::i64()
        }
    }

    pub fn float_from_ty(t: ast::float_ty) -> Type {
        match t {
            ast::ty_f32 => Type::f32(),
            ast::ty_f64 => Type::f64()
        }
    }

    pub fn size_t(arch: Architecture) -> Type {
        Type::int(arch)
    }

    pub fn func(args: &[Type], ret: &Type) -> Type {
        let vec : &[TypeRef] = unsafe { cast::transmute(args) };
        ty!(llvm::LLVMFunctionType(ret.to_ref(), vec::raw::to_ptr(vec),
                                   args.len() as c_uint, False))
    }

    pub fn variadic_func(args: &[Type], ret: &Type) -> Type {
        let vec : &[TypeRef] = unsafe { cast::transmute(args) };
        ty!(llvm::LLVMFunctionType(ret.to_ref(), vec::raw::to_ptr(vec),
                                   args.len() as c_uint, True))
    }

    pub fn func_pair(cx: &CrateContext, fn_ty: &Type) -> Type {
        Type::struct_([fn_ty.ptr_to(), Type::opaque_cbox_ptr(cx)], false)
    }

    pub fn ptr(ty: Type) -> Type {
        ty!(llvm::LLVMPointerType(ty.to_ref(), 0 as c_uint))
    }

    pub fn struct_(els: &[Type], packed: bool) -> Type {
        let els : &[TypeRef] = unsafe { cast::transmute(els) };
        ty!(llvm::LLVMStructTypeInContext(base::task_llcx(), vec::raw::to_ptr(els),
                                          els.len() as c_uint, packed as Bool))
    }

    pub fn named_struct(name: &str) -> Type {
        let ctx = base::task_llcx();
        ty!(name.with_c_str(|s| llvm::LLVMStructCreateNamed(ctx, s)))
    }

    pub fn empty_struct() -> Type {
        Type::struct_([], false)
    }

    pub fn vtable() -> Type {
        Type::array(&Type::i8().ptr_to(), 1)
    }

    pub fn generic_glue_fn(cx: &mut CrateContext) -> Type {
        match cx.tn.find_type("glue_fn") {
            Some(ty) => return ty,
            None => ()
        }

        let ty = Type::glue_fn(Type::i8p());
        cx.tn.associate_type("glue_fn", &ty);

        return ty;
    }

    pub fn glue_fn(t: Type) -> Type {
        Type::func([ Type::nil().ptr_to(), t ],
            &Type::void())
    }

    pub fn tydesc(arch: Architecture) -> Type {
        let mut tydesc = Type::named_struct("tydesc");
        let glue_fn_ty = Type::glue_fn(Type::i8p()).ptr_to();

        let int_ty = Type::int(arch);

        // Must mirror:
        //
        // std::unstable::intrinsics::TyDesc
        // type_desc in rt

        let elems = [int_ty,     // size
                     int_ty,     // align
                     glue_fn_ty, // take
                     glue_fn_ty, // drop
                     glue_fn_ty, // free
                     glue_fn_ty, // visit
                     int_ty, // borrow_offset
                     Type::struct_([Type::i8p(), Type::int(arch)], false)]; // name
        tydesc.set_struct_body(elems, false);

        return tydesc;
    }

    pub fn array(ty: &Type, len: u64) -> Type {
        ty!(llvm::LLVMArrayType(ty.to_ref(), len as c_uint))
    }

    pub fn vector(ty: &Type, len: u64) -> Type {
        ty!(llvm::LLVMVectorType(ty.to_ref(), len as c_uint))
    }

    pub fn vec(arch: Architecture, ty: &Type) -> Type {
        Type::struct_(
            [ Type::int(arch), Type::int(arch), Type::array(ty, 0) ],
        false)
    }

    pub fn opaque_vec(arch: Architecture) -> Type {
        Type::vec(arch, &Type::i8())
    }

    #[inline]
    pub fn box_header_fields(ctx: &CrateContext) -> ~[Type] {
        ~[
            ctx.int_type, ctx.tydesc_type.ptr_to(),
            Type::i8().ptr_to(), Type::i8().ptr_to()
        ]
    }

    pub fn box_header(ctx: &CrateContext) -> Type {
        Type::struct_(Type::box_header_fields(ctx), false)
    }

    pub fn box(ctx: &CrateContext, ty: &Type) -> Type {
        Type::struct_(Type::box_header_fields(ctx) + &[*ty], false)
    }

    pub fn opaque() -> Type {
        Type::i8()
    }

    pub fn opaque_box(ctx: &CrateContext) -> Type {
        Type::box(ctx, &Type::opaque())
    }

    pub fn unique(ctx: &CrateContext, ty: &Type) -> Type {
        Type::box(ctx, ty)
    }

    pub fn opaque_cbox_ptr(cx: &CrateContext) -> Type {
        Type::opaque_box(cx).ptr_to()
    }

    pub fn opaque_trait(ctx: &CrateContext, store: ty::TraitStore) -> Type {
        let tydesc_ptr = ctx.tydesc_type.ptr_to();
        let box_ty = match store {
            ty::BoxTraitStore => Type::opaque_box(ctx),
            ty::UniqTraitStore => Type::unique(ctx, &Type::i8()),
            ty::RegionTraitStore(*) => Type::i8()
        };
        Type::struct_([tydesc_ptr, box_ty.ptr_to()], false)
    }

    pub fn kind(&self) -> TypeKind {
        unsafe {
            llvm::LLVMGetTypeKind(self.to_ref())
        }
    }

    pub fn set_struct_body(&mut self, els: &[Type], packed: bool) {
        unsafe {
            let vec : &[TypeRef] = cast::transmute(els);
            llvm::LLVMStructSetBody(self.to_ref(), vec::raw::to_ptr(vec),
                                    els.len() as c_uint, packed as Bool)
        }
    }

    pub fn ptr_to(&self) -> Type {
        ty!(llvm::LLVMPointerType(self.to_ref(), 0))
    }

    pub fn get_field(&self, idx: uint) -> Type {
        unsafe {
            let num_fields = llvm::LLVMCountStructElementTypes(self.to_ref()) as uint;
            let mut elems = vec::from_elem(num_fields, 0 as TypeRef);

            llvm::LLVMGetStructElementTypes(self.to_ref(), vec::raw::to_mut_ptr(elems));

            Type::from_ref(elems[idx])
        }
    }

    pub fn is_packed(&self) -> bool {
        unsafe {
            llvm::LLVMIsPackedStruct(self.to_ref()) == True
        }
    }

    pub fn element_type(&self) -> Type {
        unsafe {
            Type::from_ref(llvm::LLVMGetElementType(self.to_ref()))
        }
    }

    pub fn array_length(&self) -> uint {
        unsafe {
            llvm::LLVMGetArrayLength(self.to_ref()) as uint
        }
    }

    pub fn field_types(&self) -> ~[Type] {
        unsafe {
            let n_elts = llvm::LLVMCountStructElementTypes(self.to_ref()) as uint;
            if n_elts == 0 {
                return ~[];
            }
            let mut elts = vec::from_elem(n_elts, 0 as TypeRef);
            llvm::LLVMGetStructElementTypes(self.to_ref(), &mut elts[0]);
            cast::transmute(elts)
        }
    }

    pub fn return_type(&self) -> Type {
        ty!(llvm::LLVMGetReturnType(self.to_ref()))
    }

    pub fn func_params(&self) -> ~[Type] {
        unsafe {
            let n_args = llvm::LLVMCountParamTypes(self.to_ref()) as uint;
            let args = vec::from_elem(n_args, 0 as TypeRef);
            llvm::LLVMGetParamTypes(self.to_ref(), vec::raw::to_ptr(args));
            cast::transmute(args)
        }
    }

    pub fn float_width(&self) -> uint {
        match self.kind() {
            Float => 32,
            Double => 64,
            X86_FP80 => 80,
            FP128 | PPC_FP128 => 128,
            _ => fail!("llvm_float_width called on a non-float type")
        }
    }
}
<|endoftext|>


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

#![cfg_attr(target_os = "nacl", allow(dead_code))]

use env;
use io::prelude::*;
use io;
use libc;
use str;
use sync::atomic::{self, Ordering};

pub use sys::backtrace::write;

#[cfg(target_pointer_width = "64")]
pub const HEX_WIDTH: usize = 18;

#[cfg(target_pointer_width = "32")]
pub const HEX_WIDTH: usize = 10;

// For now logging is turned off by default, and this function checks to see
// whether the magical environment variable is present to see if it's turned on.
pub fn log_enabled() -> bool {
    static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0);
    match ENABLED.load(Ordering::SeqCst) {
        1 => return false,
        2 => return true,
        _ => {}
    }

    let val = match env::var_os("RUST_BACKTRACE") {
        Some(x) => if &x == "0" { 1 } else { 2 },
        None => 1,
    };
    ENABLED.store(val, Ordering::SeqCst);
    val == 2
}

// These output functions should now be used everywhere to ensure consistency.
pub fn output(w: &mut Write, idx: isize, addr: *mut libc::c_void,
              s: Option<&[u8]>) -> io::Result<()> {
    write!(w, "  {:2}: {:2$?} - ", idx, addr, HEX_WIDTH)?;
    match s.and_then(|s| str::from_utf8(s).ok()) {
        Some(string) => demangle(w, string)?,
        None => write!(w, "<unknown>")?,
    }
    w.write_all(&['\n' as u8])
}

#[allow(dead_code)]
pub fn output_fileline(w: &mut Write, file: &[u8], line: libc::c_int,
                       more: bool) -> io::Result<()> {
    let file = str::from_utf8(file).unwrap_or("<unknown>");
    // prior line: "  ##: {:2$} - func"
    write!(w, "      {:3$}at {}:{}", "", file, line, HEX_WIDTH)?;
    if more {
        write!(w, " <... and possibly more>")?;
    }
    w.write_all(&['\n' as u8])
}

// All rust symbols are in theory lists of "::"-separated identifiers. Some
// assemblers, however, can't handle these characters in symbol names. To get
// around this, we use C++-style mangling. The mangling method is:
//
// 1. Prefix the symbol with "_ZN"
// 2. For each element of the path, emit the length plus the element
// 3. End the path with "E"
//
// For example, "_ZN4testE" => "test" and "_ZN3foo3barE" => "foo::bar".
//
// We're the ones printing our backtraces, so we can't rely on anything else to
// demangle our symbols. It's *much* nicer to look at demangled symbols, so
// this function is implemented to give us nice pretty output.
//
// Note that this demangler isn't quite as fancy as it could be. We have lots
// of other information in our symbols like hashes, version, type information,
// etc. Additionally, this doesn't handle glue symbols at all.
pub fn demangle(writer: &mut Write, s: &str) -> io::Result<()> {
    // First validate the symbol. If it doesn't look like anything we're
    // expecting, we just print it literally. Note that we must handle non-rust
    // symbols because we could have any function in the backtrace.
    let mut valid = true;
    let mut inner = s;
    if s.len() > 4 && s.starts_with("_ZN") && s.ends_with("E") {
        inner = &s[3 .. s.len() - 1];
    // On Windows, dbghelp strips leading underscores, so we accept "ZN...E" form too.
    } else if s.len() > 3 && s.starts_with("ZN") && s.ends_with("E") {
        inner = &s[2 .. s.len() - 1];
    } else {
        valid = false;
    }

    if valid {
        let mut chars = inner.chars();
        while valid {
            let mut i = 0;
            for c in chars.by_ref() {
                if c.is_numeric() {
                    i = i * 10 + c as usize - '0' as usize;
                } else {
                    break
                }
            }
            if i == 0 {
                valid = chars.next().is_none();
                break
            } else if chars.by_ref().take(i - 1).count() != i - 1 {
                valid = false;
            }
        }
    }

    // Alright, let's do this.
    if !valid {
        writer.write_all(s.as_bytes())?;
    } else {
        let mut first = true;
        while !inner.is_empty() {
            if !first {
                writer.write_all(b"::")?;
            } else {
                first = false;
            }
            let mut rest = inner;
            while rest.chars().next().unwrap().is_numeric() {
                rest = &rest[1..];
            }
            let i: usize = inner[.. (inner.len() - rest.len())].parse().unwrap();
            inner = &rest[i..];
            rest = &rest[..i];
            while !rest.is_empty() {
                if rest.starts_with("$") {
                    macro_rules! demangle {
                        ($($pat:expr, => $demangled:expr),*) => ({
                            $(if rest.starts_with($pat) {
                                try!(writer.write_all($demangled));
                                rest = &rest[$pat.len()..];
                              } else)*
                            {
                                try!(writer.write_all(rest.as_bytes()));
                                break;
                            }

                        })
                    }

                    // see src/librustc/back/link.rs for these mappings
                    demangle! (
                        "$SP$", => b"@",
                        "$BP$", => b"*",
                        "$RF$", => b"&",
                        "$LT$", => b"<",
                        "$GT$", => b">",
                        "$LP$", => b"(",
                        "$RP$", => b")",
                        "$C$", => b",",

                        // in theory we can demangle any Unicode code point, but
                        // for simplicity we just catch the common ones.
                        "$u7e$", => b"~",
                        "$u20$", => b" ",
                        "$u27$", => b"'",
                        "$u5b$", => b"[",
                        "$u5d$", => b"]",
                        "$u7b$", => b"{",
                        "$u7d$", => b"}"
                    )
                } else {
                    let idx = match rest.find('$') {
                        None => rest.len(),
                        Some(i) => i,
                    };
                    writer.write_all(rest[..idx].as_bytes())?;
                    rest = &rest[idx..];
                }
            }
        }
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use sys_common;
    macro_rules! t { ($a:expr, $b:expr) => ({
        let mut m = Vec::new();
        sys_common::backtrace::demangle(&mut m, $a).unwrap();
        assert_eq!(String::from_utf8(m).unwrap(), $b);
    }) }

    #[test]
    fn demangle() {
        t!("test", "test");
        t!("_ZN4testE", "test");
        t!("_ZN4test", "_ZN4test");
        t!("_ZN4test1a2bcE", "test::a::bc");
    }

    #[test]
    fn demangle_dollars() {
        t!("_ZN4$RP$E", ")");
        t!("_ZN8$RF$testE", "&test");
        t!("_ZN8$BP$test4foobE", "*test::foob");
        t!("_ZN9$u20$test4foobE", " test::foob");
    }

    #[test]
    fn demangle_many_dollars() {
        t!("_ZN13test$u20$test4foobE", "test test::foob");
        t!("_ZN12test$BP$test4foobE", "test*test::foob");
    }

    #[test]
    fn demangle_windows() {
        t!("ZN4testE", "test");
        t!("ZN13test$u20$test4foobE", "test test::foob");
        t!("ZN12test$RF$test4foobE", "test&test::foob");
    }
}
<commit_msg>Auto merge of #36059 - CryZe:improved-demangling, r=alexcrichton<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg_attr(target_os = "nacl", allow(dead_code))]

use env;
use io::prelude::*;
use io;
use libc;
use str;
use sync::atomic::{self, Ordering};

pub use sys::backtrace::write;

#[cfg(target_pointer_width = "64")]
pub const HEX_WIDTH: usize = 18;

#[cfg(target_pointer_width = "32")]
pub const HEX_WIDTH: usize = 10;

// For now logging is turned off by default, and this function checks to see
// whether the magical environment variable is present to see if it's turned on.
pub fn log_enabled() -> bool {
    static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0);
    match ENABLED.load(Ordering::SeqCst) {
        1 => return false,
        2 => return true,
        _ => {}
    }

    let val = match env::var_os("RUST_BACKTRACE") {
        Some(x) => if &x == "0" { 1 } else { 2 },
        None => 1,
    };
    ENABLED.store(val, Ordering::SeqCst);
    val == 2
}

// These output functions should now be used everywhere to ensure consistency.
pub fn output(w: &mut Write, idx: isize, addr: *mut libc::c_void,
              s: Option<&[u8]>) -> io::Result<()> {
    write!(w, "  {:2}: {:2$?} - ", idx, addr, HEX_WIDTH)?;
    match s.and_then(|s| str::from_utf8(s).ok()) {
        Some(string) => demangle(w, string)?,
        None => write!(w, "<unknown>")?,
    }
    w.write_all(&['\n' as u8])
}

#[allow(dead_code)]
pub fn output_fileline(w: &mut Write, file: &[u8], line: libc::c_int,
                       more: bool) -> io::Result<()> {
    let file = str::from_utf8(file).unwrap_or("<unknown>");
    // prior line: "  ##: {:2$} - func"
    write!(w, "      {:3$}at {}:{}", "", file, line, HEX_WIDTH)?;
    if more {
        write!(w, " <... and possibly more>")?;
    }
    w.write_all(&['\n' as u8])
}

// All rust symbols are in theory lists of "::"-separated identifiers. Some
// assemblers, however, can't handle these characters in symbol names. To get
// around this, we use C++-style mangling. The mangling method is:
//
// 1. Prefix the symbol with "_ZN"
// 2. For each element of the path, emit the length plus the element
// 3. End the path with "E"
//
// For example, "_ZN4testE" => "test" and "_ZN3foo3barE" => "foo::bar".
//
// We're the ones printing our backtraces, so we can't rely on anything else to
// demangle our symbols. It's *much* nicer to look at demangled symbols, so
// this function is implemented to give us nice pretty output.
//
// Note that this demangler isn't quite as fancy as it could be. We have lots
// of other information in our symbols like hashes, version, type information,
// etc. Additionally, this doesn't handle glue symbols at all.
pub fn demangle(writer: &mut Write, s: &str) -> io::Result<()> {
    // First validate the symbol. If it doesn't look like anything we're
    // expecting, we just print it literally. Note that we must handle non-rust
    // symbols because we could have any function in the backtrace.
    let mut valid = true;
    let mut inner = s;
    if s.len() > 4 && s.starts_with("_ZN") && s.ends_with("E") {
        inner = &s[3 .. s.len() - 1];
    // On Windows, dbghelp strips leading underscores, so we accept "ZN...E" form too.
    } else if s.len() > 3 && s.starts_with("ZN") && s.ends_with("E") {
        inner = &s[2 .. s.len() - 1];
    } else {
        valid = false;
    }

    if valid {
        let mut chars = inner.chars();
        while valid {
            let mut i = 0;
            for c in chars.by_ref() {
                if c.is_numeric() {
                    i = i * 10 + c as usize - '0' as usize;
                } else {
                    break
                }
            }
            if i == 0 {
                valid = chars.next().is_none();
                break
            } else if chars.by_ref().take(i - 1).count() != i - 1 {
                valid = false;
            }
        }
    }

    // Alright, let's do this.
    if !valid {
        writer.write_all(s.as_bytes())?;
    } else {
        let mut first = true;
        while !inner.is_empty() {
            if !first {
                writer.write_all(b"::")?;
            } else {
                first = false;
            }
            let mut rest = inner;
            while rest.chars().next().unwrap().is_numeric() {
                rest = &rest[1..];
            }
            let i: usize = inner[.. (inner.len() - rest.len())].parse().unwrap();
            inner = &rest[i..];
            rest = &rest[..i];
            if rest.starts_with("_$") {
                rest = &rest[1..];
            }
            while !rest.is_empty() {
                if rest.starts_with(".") {
                    if let Some('.') = rest[1..].chars().next() {
                        writer.write_all(b"::")?;
                        rest = &rest[2..];
                    } else {
                        writer.write_all(b".")?;
                        rest = &rest[1..];
                    }
                } else if rest.starts_with("$") {
                    macro_rules! demangle {
                        ($($pat:expr => $demangled:expr),*) => ({
                            $(if rest.starts_with($pat) {
                                try!(writer.write_all($demangled));
                                rest = &rest[$pat.len()..];
                              } else)*
                            {
                                try!(writer.write_all(rest.as_bytes()));
                                break;
                            }

                        })
                    }

                    // see src/librustc/back/link.rs for these mappings
                    demangle! (
                        "$SP$" => b"@",
                        "$BP$" => b"*",
                        "$RF$" => b"&",
                        "$LT$" => b"<",
                        "$GT$" => b">",
                        "$LP$" => b"(",
                        "$RP$" => b")",
                        "$C$" => b",",

                        // in theory we can demangle any Unicode code point, but
                        // for simplicity we just catch the common ones.
                        "$u7e$" => b"~",
                        "$u20$" => b" ",
                        "$u27$" => b"'",
                        "$u5b$" => b"[",
                        "$u5d$" => b"]",
                        "$u7b$" => b"{",
                        "$u7d$" => b"}",
                        "$u3b$" => b";",
                        "$u2b$" => b"+",
                        "$u22$" => b"\""
                    )
                } else {
                    let idx = match rest.char_indices().find(|&(_, c)| c == '$' || c == '.') {
                        None => rest.len(),
                        Some((i, _)) => i,
                    };
                    writer.write_all(rest[..idx].as_bytes())?;
                    rest = &rest[idx..];
                }
            }
        }
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use sys_common;
    macro_rules! t { ($a:expr, $b:expr) => ({
        let mut m = Vec::new();
        sys_common::backtrace::demangle(&mut m, $a).unwrap();
        assert_eq!(String::from_utf8(m).unwrap(), $b);
    }) }

    #[test]
    fn demangle() {
        t!("test", "test");
        t!("_ZN4testE", "test");
        t!("_ZN4test", "_ZN4test");
        t!("_ZN4test1a2bcE", "test::a::bc");
    }

    #[test]
    fn demangle_dollars() {
        t!("_ZN4$RP$E", ")");
        t!("_ZN8$RF$testE", "&test");
        t!("_ZN8$BP$test4foobE", "*test::foob");
        t!("_ZN9$u20$test4foobE", " test::foob");
        t!("_ZN35Bar$LT$$u5b$u32$u3b$$u20$4$u5d$$GT$E", "Bar<[u32; 4]>");
    }

    #[test]
    fn demangle_many_dollars() {
        t!("_ZN13test$u20$test4foobE", "test test::foob");
        t!("_ZN12test$BP$test4foobE", "test*test::foob");
    }

    #[test]
    fn demangle_windows() {
        t!("ZN4testE", "test");
        t!("ZN13test$u20$test4foobE", "test test::foob");
        t!("ZN12test$RF$test4foobE", "test&test::foob");
    }

    #[test]
    fn demangle_elements_beginning_with_underscore() {
        t!("_ZN13_$LT$test$GT$E", "<test>");
        t!("_ZN28_$u7b$$u7b$closure$u7d$$u7d$E", "{{closure}}");
        t!("_ZN15__STATIC_FMTSTRE", "__STATIC_FMTSTR");
    }

    #[test]
    fn demangle_trait_impls() {
        t!("_ZN71_$LT$Test$u20$$u2b$$u20$$u27$static$u20$as$u20$foo..Bar$LT$Test$GT$$GT$3barE",
           "<Test + 'static as foo::Bar<Test>>::bar");
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/// Contains the API configuration as prescribed by ECMA 402.
///
/// The meaning of the options is the same as in the similarly named
/// options in the JS version.
///
/// See [DateTimeFormatOptions] for the contents of the options.  See the [DateTimeFormat::try_new]
/// for the use of the options.
pub mod options {
    /// The date and time formatting options.
    #[derive(Eq, PartialEq, Debug, Clone)]
    pub enum Style {
        /// Full length format style.
        ///
        /// * Date: "Wednesday, December 19, 2012"
        /// * Time: "7:00:00 PM Pacific Standard Time"
        Full,
        /// Long length format style.
        ///
        /// * Date: "December 19, 2012"
        /// * Time: "7:00:00 PM PST"
        Long,
        /// Medium length format style.
        ///
        /// * Date: "Dec 19, 2012"
        /// * Time: "7:00:00 PM"
        Medium,
        /// Short length format style.
        ///
        /// * Date: "12/29/12"
        /// * "7:00 PM"
        Short,
    }

    /// Controls the calendar to use.
    ///
    /// Possible values include: "buddhist", "chinese", " coptic", "ethiopia", "ethiopic",
    /// "gregory", " hebrew", "indian", "islamic", "iso8601", " japanese", "persian", "roc".
    ///
    /// The value entered as currency is not validated.  This responsibility is
    /// delegated to the implementor.
    #[derive(Eq, PartialEq, Debug, Clone)]
    pub struct Calendar(pub String);

    impl Default for Calendar {
        fn default() -> Self {
            Self("gregory".into())
        }
    }

    impl From<&str> for Calendar {
        fn from(s: &str) -> Self {
            Self(s.to_string())
        }
    }

    /// The way day periods should be expressed.
    #[derive(Eq, PartialEq, Debug, Clone)]
    pub enum DayPeriod {
        Narrow,
        Short,
        Long,
    }

    /// Controls the number formatting.
    ///
    /// Possible values include: "arab", "arabext", " bali", "beng", "deva", "fullwide", "gujr",
    /// "guru", "hanidec", "khmr", " knda", "laoo", "latn", "limb", "mlym", " mong", "mymr",
    /// "orya", "tamldec", " telu", "thai", "tibt".
    ///
    /// The value entered as currency is not validated.  This responsibility is
    /// delegated to the implementor.
    #[derive(Eq, PartialEq, Debug, Clone)]
    pub struct NumberingSystem(pub String);

    impl From<&str> for NumberingSystem {
        fn from(s: &str) -> Self {
            Self(s.to_string())
        }
    }

    impl Default for NumberingSystem {
        fn default() -> Self {
            Self("latn".to_string())
        }
    }

    /// Controls the time zone formatting.
    ///
    /// The value entered as currency is not validated.  This responsibility is
    /// delegated to the implementor.
    #[derive(Eq, PartialEq, Debug, Clone)]
    pub struct TimeZone(pub String);

    impl From<&str> for TimeZone {
        fn from(s: &str) -> Self {
            Self(s.to_string())
        }
    }

    impl Default for TimeZone {
        fn default() -> Self {
            Self("UTC".to_string())
        }
    }

    /// The hour cycle to use
    #[derive(Eq, PartialEq, Debug, Clone)]
    pub enum HourCycle {
        /// 12 hour cycle, 0..11.
        H11,
        /// 12 hour cycle, 1..12.
        H12,
        /// 4 hour cycle, 0..23.
        H23,
        /// 4 hour cycle, 1..24.
        H24
    }

    #[derive(Eq, PartialEq, Debug, Clone)]
    pub enum Weekday {
        /// "Thursday"
        Long,
        /// "Thu",
        Short,
        /// "T",
        Narrow,
    }

    #[derive(Eq, PartialEq, Debug, Clone)]
    pub enum Era {
        /// "Anno Domini"
        Long,
        /// "AD",
        Short,
        /// "A",
        Narrow,
    }

    #[derive(Eq, PartialEq, Debug, Clone)]
    pub enum DisplaySize {
        /// "2012"
        Numeric,
        /// "12"
        TwoDigit,
    }

    #[derive(Eq, PartialEq, Debug, Clone)]
    pub enum Month {
        /// "3"
        Numeric,
        /// "03",
        TwoDigit,
        /// "March",
        Long,
        /// "Mar"
        Short,
        /// "M"
        Narrow,
    }

    #[derive(Eq, PartialEq, Debug, Clone)]
    pub enum TimeZoneStyle {
    }
}

#[derive(Eq, PartialEq, Debug, Clone)]
pub struct DateTimeFormatOptions {
    /// The formatting style to use for formatting the date part.
    pub date_style: options::Style,
    /// The formatting style to use for formatting the time part.
    pub time_style: options::Style,
    /// The number of fractional seconds to apply when calling `format`.
    /// Valid values are 0 to 3.
    pub fractional_second_digits: u8,
    /// If left unspecified, the locale default is used.
    pub calendar: Option<options::Calendar>,
    /// If left unspecified, the locale default is used.
    pub day_period: Option<options::DayPeriod>,
    /// If left unspecified, the locale default is used.
    pub numbering_system: Option<options::NumberingSystem>,
    /// If left unspecified, the locale default is used.
    pub time_zone: Option<options::TimeZone>,
    /// If left unspecified, the locale default is used.
    pub hour_cycle: Option<options::HourCycle>,
    /// If left unspecified, the locale default is used.
    pub weekday: Option<options::Weekday>,
    /// If left unspecified, the locale default is used.
    pub era: Option<options::Era>,
    /// If left unspecified, the locale default is used.
    pub year: Option<options::DisplaySize>,
    /// If left unspecified, the locale default is used.
    pub month: Option<options::Month>,
    /// If left unspecified, the locale default is used.
    pub day: Option<options::DisplaySize>,
    /// If left unspecified, the locale default is used.
    pub hour: Option<options::DisplaySize>,
    /// If left unspecified, the locale default is used.
    pub minute: Option<options::DisplaySize>,
    /// If left unspecified, the locale default is used.
    pub second: Option<options::DisplaySize>,
    /// If left unspecified, the locale default is used.
    pub time_zone_style: Option<options::TimeZoneStyle>,
}

impl Default for DateTimeFormatOptions {
    fn default() -> Self {
        Self{
            date_style: options::Style::Long,
            time_style: options::Style::Long,
            fractional_second_digits: 2,
            day_period: None,
            numbering_system: None,
            calendar: None,
            time_zone: None,
            hour_cycle: None,
            weekday: None,
            era: None,
            year: None,
            month: None,
            day: None,
            hour: None,
            minute: None,
            second: None,
            time_zone_style: None,
        }
    }
}

use std::fmt;

pub trait DateTimeFormat {
    /// The type of error reported, if any.
    type Error: std::error::Error;

    /// Creates a new [DateTimeFormat].
    ///
    /// Creation may fail, for example, if the locale-specific data is not loaded, or if
    /// the supplied options are inconsistent.
    fn try_new<L>(l: L, opts: DateTimeFormatOptions) -> Result<Self, Self::Error>
    where
        L: crate::Locale,
        Self: Sized;

    /// Formats `date` into the supplied standard `writer` [fmt::Write].
    ///
    /// The original [ECMA 402 function][ecma402fmt] returns a string.  This is likely the only
    /// reasonably generic option in JavaScript so it is adequate.  In Rust, however, it is
    /// possible to pass in a standard formatting strategy (through `writer`).
    ///
    ///   [ecma402fmt]:
    ///   https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/format
    ///
    /// The `date` holds the number of seconds (with fractional part) since the beginning of the
    /// Unix epoch.  The date is a very generic type because there is no official date-time type
    /// in Rust.
    fn format<I, D, W>(&self, date: D, writer: &mut W) -> fmt::Result
    where
        I: fmt::Display,
        D: AsRef<f64>,
        W: fmt::Write;
}
<commit_msg>fixup: review comments<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/// Contains the API configuration as prescribed by ECMA 402.
///
/// The meaning of the options is the same as in the similarly named
/// options in the JS version.
///
/// See [DateTimeFormatOptions] for the contents of the options.  See the [DateTimeFormat::try_new]
/// for the use of the options.
pub mod options {
    /// The date and time formatting options.
    #[derive(Eq, PartialEq, Debug, Clone)]
    pub enum Style {
        /// Full length format style.
        ///
        /// * Date: "Wednesday, December 19, 2012"
        /// * Time: "7:00:00 PM Pacific Standard Time"
        Full,
        /// Long length format style.
        ///
        /// * Date: "December 19, 2012"
        /// * Time: "7:00:00 PM PST"
        Long,
        /// Medium length format style.
        ///
        /// * Date: "Dec 19, 2012"
        /// * Time: "7:00:00 PM"
        Medium,
        /// Short length format style.
        ///
        /// * Date: "12/29/12"
        /// * "7:00 PM"
        Short,
    }

    /// Controls the calendar to use.
    ///
    /// Possible values include: "buddhist", "chinese", " coptic", "ethiopia", "ethiopic",
    /// "gregory", " hebrew", "indian", "islamic", "iso8601", " japanese", "persian", "roc".
    ///
    /// The value entered as currency is not validated.  This responsibility is
    /// delegated to the implementor.
    #[derive(Eq, PartialEq, Debug, Clone)]
    pub struct Calendar(pub String);

    impl Default for Calendar {
        fn default() -> Self {
            Self("gregory".into())
        }
    }

    impl From<&str> for Calendar {
        fn from(s: &str) -> Self {
            Self(s.to_string())
        }
    }

    /// The way day periods (morning, afternoon) should be expressed.
    #[derive(Eq, PartialEq, Debug, Clone)]
    pub enum DayPeriod {
        /// "AM", "PM"
        Narrow,
        /// "A.M.", "P.M".
        Short,
        /// "Morning", "Afternoon".
        Long,
    }

    /// Controls the number formatting.
    ///
    /// Possible values include: "arab", "arabext", " bali", "beng", "deva", "fullwide", "gujr",
    /// "guru", "hanidec", "khmr", " knda", "laoo", "latn", "limb", "mlym", " mong", "mymr",
    /// "orya", "tamldec", " telu", "thai", "tibt".
    ///
    /// The value entered is not validated.  This responsibility is delegated to the implementor.
    #[derive(Eq, PartialEq, Debug, Clone)]
    pub struct NumberingSystem(pub String);

    impl From<&str> for NumberingSystem {
        fn from(s: &str) -> Self {
            Self(s.to_string())
        }
    }

    impl Default for NumberingSystem {
        fn default() -> Self {
            Self("latn".to_string())
        }
    }

    /// Controls the time zone formatting.
    ///
    /// The value entered is not validated.  This responsibility is delegated to the implementor.
    #[derive(Eq, PartialEq, Debug, Clone)]
    pub struct TimeZone(pub String);

    impl From<&str> for TimeZone {
        fn from(s: &str) -> Self {
            Self(s.to_string())
        }
    }

    impl Default for TimeZone {
        fn default() -> Self {
            Self("UTC".to_string())
        }
    }

    /// The hour cycle to use
    #[derive(Eq, PartialEq, Debug, Clone)]
    pub enum HourCycle {
        /// 12 hour cycle, 0..11.
        H11,
        /// 12 hour cycle, 1..12.
        H12,
        /// 4 hour cycle, 0..23.
        H23,
        /// 4 hour cycle, 1..24.
        H24
    }

    #[derive(Eq, PartialEq, Debug, Clone)]
    pub enum Weekday {
        /// "Thursday"
        Long,
        /// "Thu",
        Short,
        /// "T",
        Narrow,
    }

    #[derive(Eq, PartialEq, Debug, Clone)]
    pub enum Era {
        /// "Anno Domini"
        Long,
        /// "AD",
        Short,
        /// "A",
        Narrow,
    }

    #[derive(Eq, PartialEq, Debug, Clone)]
    pub enum DisplaySize {
        /// "2012"
        Numeric,
        /// "12"
        TwoDigit,
    }

    #[derive(Eq, PartialEq, Debug, Clone)]
    pub enum Month {
        /// "3"
        Numeric,
        /// "03",
        TwoDigit,
        /// "March",
        Long,
        /// "Mar"
        Short,
        /// "M"
        Narrow,
    }

    /// The time zone name styling to use.
    #[derive(Eq, PartialEq, Debug, Clone)]
    pub enum TimeZoneStyle {
        /// "British Summer Time"
        Long,
        /// "GMT+1"
        Short,
    }
}

#[derive(Eq, PartialEq, Debug, Clone)]
pub struct DateTimeFormatOptions {
    /// The formatting style to use for formatting the date part.
    pub date_style: options::Style,
    /// The formatting style to use for formatting the time part.
    pub time_style: options::Style,
    /// The number of fractional seconds to apply when calling `format`.
    /// Valid values are 0 to 3.
    pub fractional_second_digits: u8,
    /// If left unspecified, the locale default is used.
    pub calendar: Option<options::Calendar>,
    /// If left unspecified, the locale default is used.
    pub day_period: Option<options::DayPeriod>,
    /// If left unspecified, the locale default is used.
    pub numbering_system: Option<options::NumberingSystem>,
    /// If left unspecified, the locale default is used.
    pub time_zone: Option<options::TimeZone>,
    /// If left unspecified, the locale default is used.
    pub hour_cycle: Option<options::HourCycle>,
    /// If left unspecified, the locale default is used.
    pub weekday: Option<options::Weekday>,
    /// If left unspecified, the locale default is used.
    pub era: Option<options::Era>,
    /// If left unspecified, the locale default is used.
    pub year: Option<options::DisplaySize>,
    /// If left unspecified, the locale default is used.
    pub month: Option<options::Month>,
    /// If left unspecified, the locale default is used.
    pub day: Option<options::DisplaySize>,
    /// If left unspecified, the locale default is used.
    pub hour: Option<options::DisplaySize>,
    /// If left unspecified, the locale default is used.
    pub minute: Option<options::DisplaySize>,
    /// If left unspecified, the locale default is used.
    pub second: Option<options::DisplaySize>,
    /// If left unspecified, the locale default is used.
    pub time_zone_style: Option<options::TimeZoneStyle>,
}

impl Default for DateTimeFormatOptions {
    fn default() -> Self {
        Self{
            date_style: options::Style::Long,
            time_style: options::Style::Long,
            fractional_second_digits: 2,
            day_period: None,
            numbering_system: None,
            calendar: None,
            time_zone: None,
            hour_cycle: None,
            weekday: None,
            era: None,
            year: None,
            month: None,
            day: None,
            hour: None,
            minute: None,
            second: None,
            time_zone_style: None,
        }
    }
}

use std::fmt;

pub trait DateTimeFormat {
    /// The type of error reported, if any.
    type Error: std::error::Error;

    /// Creates a new [DateTimeFormat].
    ///
    /// Creation may fail, for example, if the locale-specific data is not loaded, or if
    /// the supplied options are inconsistent.
    fn try_new<L>(l: L, opts: DateTimeFormatOptions) -> Result<Self, Self::Error>
    where
        L: crate::Locale,
        Self: Sized;

    /// Formats `date` into the supplied standard `writer` [fmt::Write].
    ///
    /// The original [ECMA 402 function][ecma402fmt] returns a string.  This is likely the only
    /// reasonably generic option in JavaScript so it is adequate.  In Rust, however, it is
    /// possible to pass in a standard formatting strategy (through `writer`).
    ///
    ///   [ecma402fmt]:
    ///   https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/format
    ///
    /// The `date` holds the number of seconds (with fractional part) since the beginning of the
    /// Unix epoch.  The date is a very generic type because there is no official date-time type
    /// in Rust.
    fn format<I, D, W>(&self, date: D, writer: &mut W) -> fmt::Result
    where
        I: fmt::Display,
        D: AsRef<f64>,
        W: fmt::Write;
}
<|endoftext|>


<commit_before>// compile-flags: -Zmiri-track-pointer-tag=1372
// do not run on anything but x86_64 linux, because minor libstd changes can change the borrow stack ids
// only-x86_64
// only-linux

use std::mem;

fn main() {
    let mut target = 42;
    // Make sure we cannot use a raw-tagged `&mut` pointing to a frozen location.
    // Even just creating it unfreezes.
    let raw = &mut target as *mut _; // let this leak to raw
    let reference = unsafe { &*raw }; // freeze
    let ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag
    let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag
    //~^ ERROR disabling item [SharedReadOnly for <1372>] for tag Some(<untagged>)
    // Now we retag, making our ref top-of-stack -- and, in particular, unfreezing.
    let _val = *reference;
}
<commit_msg>Remove a flaky test<commit_after><|endoftext|>


<commit_before>use parking_lot::Mutex;
use std::collections::hash_map::RandomState;
use std::fmt;
use std::hash::BuildHasher;
use std::hash::Hash;
use std::marker::PhantomData;
use std::num::NonZeroU32;
use std::sync::Arc;
use std::time::{Duration, Instant};

use evmap::{self, ReadHandle, WriteHandle};

use {
    algorithms::{Algorithm, DefaultAlgorithm, RateLimitState},
    InconsistentCapacity, NegativeMultiDecision,
};

type MapWriteHandle<K, A, H> = Arc<Mutex<WriteHandle<K, <A as Algorithm>::BucketState, (), H>>>;

/// An in-memory rate limiter that regulates a single rate limit for
/// multiple keys.
///
/// Keyed rate limiters can be used to e.g. enforce a per-IP address
/// or a per-customer request limit on the server side.
///
/// This implementation of the keyed rate limiter uses
/// [`evmap`](../../../evmap/index.html), a read lock-free, concurrent
/// hash map. Addition of new keys (e.g. a new customer making their
/// first request) is synchronized and happens one at a time (it
/// synchronizes writes to minimize the effects from `evmap`'s
/// eventually consistent behavior on key addition), while reads of
/// existing keys all happen simultaneously, then get synchronized by
/// the rate limiting algorithm itself.
///
/// # Expiring old keys
/// If a key has not been checked in a long time, that key can be
/// expired safely (the next rate limit check for that key would
/// behave as if the key was not present in the map, after all). To
/// remove the unused keys and free up space, use the
/// [`cleanup`](method.cleanup) method:
///
/// ```
/// # use std::num::NonZeroU32;
/// # use std::time::Duration;
/// use ratelimit_meter::{KeyedRateLimiter};
/// # #[macro_use] extern crate nonzero_ext;
/// # extern crate ratelimit_meter;
/// # fn main () {
/// let mut limiter = KeyedRateLimiter::<&str>::new(nonzero!(100u32), Duration::from_secs(5));
/// limiter.check("hi there");
/// // time passes...
///
/// // remove all keys that have been expireable for 10 minutes:
/// limiter.cleanup(Duration::from_secs(600));
/// # }
/// ```
#[derive(Clone)]
pub struct KeyedRateLimiter<
    K: Eq + Hash + Clone,
    A: Algorithm = DefaultAlgorithm,
    H: BuildHasher + Clone = RandomState,
> {
    algorithm: PhantomData<A>,
    params: A::BucketParams,
    map_reader: ReadHandle<K, A::BucketState, (), H>,
    map_writer: MapWriteHandle<K, A, H>,
}

impl<A, K> fmt::Debug for KeyedRateLimiter<K, A>
where
    A: Algorithm,
    K: Eq + Hash + Clone,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "KeyedRateLimiter{{{params:?}}}", params = self.params)
    }
}

impl<A, K> KeyedRateLimiter<K, A>
where
    A: Algorithm,
    K: Eq + Hash + Clone,
{
    /// Construct a new rate limiter that allows `capacity` cells per
    /// time unit through.
    /// # Examples
    /// ```
    /// # use std::num::NonZeroU32;
    /// # use std::time::Duration;
    /// use ratelimit_meter::{KeyedRateLimiter};
    /// # #[macro_use] extern crate nonzero_ext;
    /// # extern crate ratelimit_meter;
    /// # fn main () {
    /// let _limiter = KeyedRateLimiter::<&str>::new(nonzero!(100u32), Duration::from_secs(5));
    /// # }
    /// ```
    pub fn new(capacity: NonZeroU32, per_time_unit: Duration) -> Self {
        let (r, mut w): (
            ReadHandle<K, A::BucketState>,
            WriteHandle<K, A::BucketState>,
        ) = evmap::new();
        w.refresh();
        KeyedRateLimiter {
            algorithm: PhantomData,
            params: <A as Algorithm>::params_from_constructor(
                capacity,
                nonzero!(1u32),
                per_time_unit,
            ).unwrap(),
            map_reader: r,
            map_writer: Arc::new(Mutex::new(w)),
        }
    }

    /// Construct a new keyed rate limiter that allows `capacity`
    /// cells per second.
    ///
    /// # Examples
    /// Constructing a rate limiter keyed by `&str` that lets through
    /// 100 cells per second:
    ///
    /// ```
    /// # use std::time::Duration;
    /// use ratelimit_meter::{KeyedRateLimiter, GCRA};
    /// # #[macro_use] extern crate nonzero_ext;
    /// # extern crate ratelimit_meter;
    /// # fn main () {
    /// let _limiter = KeyedRateLimiter::<&str, GCRA>::per_second(nonzero!(100u32));
    /// # }
    /// ```
    pub fn per_second(capacity: NonZeroU32) -> Self {
        Self::new(capacity, Duration::from_secs(1))
    }

    /// Return a constructor that can be used to construct a keyed
    /// rate limiter with the builder pattern.
    pub fn build_with_capacity(capacity: NonZeroU32) -> Builder<K, A, RandomState> {
        Builder {
            capacity,
            ..Default::default()
        }
    }

    fn check_and_update_key<E, F>(&self, key: K, update: F) -> Result<(), E>
    where
        F: Fn(&A::BucketState) -> Result<(), E>,
    {
        self.map_reader
            .get_and(&key, |v| {
                // we have at least one element (owing to the nature of
                // the evmap, it says there could be >1
                // entries, but we'll only ever add one):
                let state = &v[0];
                update(state)
            }).unwrap_or_else(|| {
                // entry does not exist, let's add one.
                let mut w = self.map_writer.lock();
                let state: A::BucketState = Default::default();
                let result = update(&state);
                w.update(key, state);
                w.flush();
                result
            })
    }

    /// Tests whether a single cell for the given key can be
    /// accommodated at the given time stamp. See
    /// [`check`](#method.check).
    pub fn check_at(
        &mut self,
        key: K,
        at: Instant,
    ) -> Result<(), <A as Algorithm>::NegativeDecision> {
        self.check_and_update_key(key, |state| {
            <A as Algorithm>::test_and_update(state, &self.params, at)
        })
    }

    /// Tests if `n` cells for the given key can be accommodated at
    /// the given time (`Instant::now()`), using
    /// [`check_n`](#method.check_n)
    pub fn check_n_at(
        &mut self,
        key: K,
        n: u32,
        at: Instant,
    ) -> Result<(), NegativeMultiDecision<<A as Algorithm>::NegativeDecision>> {
        self.check_and_update_key(key, |state| {
            <A as Algorithm>::test_n_and_update(state, &self.params, n, at)
        })
    }

    /// Tests if a single cell for the given key can be accommodated
    /// at `Instant::now()`. If it can be, `check` updates the rate
    /// limiter state on that key to account for the conforming cell
    /// and returns `Ok(())`.
    ///
    /// If the cell is non-conforming (i.e., it can't be accomodated
    /// at this time stamp), `check_at` returns `Err` with information
    /// about the earliest time at which a cell could be considered
    /// conforming under that key.
    pub fn check(&mut self, key: K) -> Result<(), <A as Algorithm>::NegativeDecision> {
        self.check_at(key, Instant::now())
    }

    /// Tests if `n` cells for the given key can be accommodated at
    /// the current time stamp. If (and only if) all cells in the
    /// batch can be accomodated, the `MultiDecider` updates the rate
    /// limiter state on that key to account for all cells and returns
    /// `Ok(())`.
    ///
    /// If the entire batch of cells would not be conforming but the
    /// rate limiter has the capacity to accomodate the cells at any
    /// point in time, `check_n_at` returns error
    /// [`NegativeMultiDecision::BatchNonConforming`](../../enum.NegativeMultiDecision.html#variant.BatchNonConforming),
    /// holding the number of cells and the rate limiter's negative
    /// outcome result.
    ///
    /// If `n` exceeds the bucket capacity, `check_n_at` returns
    /// [`NegativeMultiDecision::InsufficientCapacity`](../../enum.NegativeMultiDecision.html#variant.InsufficientCapacity),
    /// indicating that a batch of this many cells can never succeed.
    pub fn check_n(
        &mut self,
        key: K,
        n: u32,
    ) -> Result<(), NegativeMultiDecision<<A as Algorithm>::NegativeDecision>> {
        self.check_n_at(key, n, Instant::now())
    }

    /// Removes the keys from this rate limiter that can be expired
    /// safely and returns the keys that were removed.
    ///
    /// To be eligible for expiration, a key's rate limiter state must
    /// be at least `min_age` past its last relevance (see
    /// [`RateLimitState.last_touched`](../../algorithms/trait.RateLimitState.html#method.last_touched)).
    ///
    /// This method works in two parts, but both parts block new keys
    /// from getting added while they're running:
    /// * First, it collects the keys that are eligible for expiration.
    /// * Then, it expires these keys.
    ///
    /// # Race conditions
    /// Since this is happening concurrently with other operations,
    /// race conditions can & will occur. It's possible that cells are
    /// accounted between the time `cleanup_at` is called and their
    /// expiry.  These cells will lost.
    ///
    /// The time window in which this can occur is hopefully short
    /// enough that this is an acceptable risk of loss in accuracy.
    pub fn cleanup<D: Into<Option<Duration>>>(&mut self, min_age: D) -> Vec<K> {
        self.cleanup_at(min_age, Instant::now())
    }

    /// Removes the keys from this rate limiter that can be expired
    /// safely at the given time stamp. See
    /// [`cleanup`](#method.cleanup). It returns the list of expired
    /// keys.
    pub fn cleanup_at<D: Into<Option<Duration>>, I: Into<Option<Instant>>>(
        &mut self,
        min_age: D,
        at: I,
    ) -> Vec<K> {
        let params = &self.params;
        let min_age = min_age.into().unwrap_or_else(|| Duration::new(0, 0));
        let at = at.into().unwrap_or_else(Instant::now);

        let mut expireable: Vec<K> = vec![];
        self.map_reader.for_each(|k, v| {
            if let Some(state) = v.get(0) {
                if state.last_touched(params) < at - min_age {
                    expireable.push(k.clone());
                }
            }
        });

        // Now take the map write lock and remove all the keys that we
        // collected:
        let mut w = self.map_writer.lock();
        for key in expireable.iter().cloned() {
            w.empty(key);
        }
        w.refresh();
        expireable
    }
}

/// A constructor for keyed rate limiters.
pub struct Builder<K: Eq + Hash + Clone, A: Algorithm, H: BuildHasher> {
    end_result: PhantomData<(K, A)>,
    capacity: NonZeroU32,
    cell_weight: NonZeroU32,
    per_time_unit: Duration,
    hasher: H,
    map_capacity: Option<usize>,
}

impl<K, A> Default for Builder<K, A, RandomState>
where
    K: Eq + Hash + Clone,
    A: Algorithm,
{
    fn default() -> Builder<K, A, RandomState> {
        Builder {
            end_result: PhantomData,
            map_capacity: None,
            capacity: nonzero!(1u32),
            cell_weight: nonzero!(1u32),
            per_time_unit: Duration::from_secs(1),
            hasher: RandomState::new(),
        }
    }
}

impl<K, A, H> Builder<K, A, H>
where
    K: Eq + Hash + Clone,
    A: Algorithm,
    H: BuildHasher,
{
    /// Sets the hashing method used for the map.
    pub fn with_hasher<H2: BuildHasher>(self, hash_builder: H2) -> Builder<K, A, H2> {
        Builder {
            hasher: hash_builder,
            end_result: self.end_result,
            capacity: self.capacity,
            cell_weight: self.cell_weight,
            per_time_unit: self.per_time_unit,
            map_capacity: self.map_capacity,
        }
    }

    /// Sets the "weight" of each cell that is checked against the
    /// bucket.
    pub fn with_cell_weight(self, cell_weight: NonZeroU32) -> Result<Self, InconsistentCapacity> {
        if self.cell_weight > self.capacity {
            return Err(InconsistentCapacity {
                capacity: self.capacity,
                cell_weight,
            });
        }
        Ok(Builder {
            cell_weight,
            ..self
        })
    }

    /// Sets the initial number of keys that the map can hold before
    /// rehashing.
    pub fn with_map_capacity(self, map_capacity: usize) -> Self {
        Builder {
            map_capacity: Some(map_capacity),
            ..self
        }
    }

    /// Constructs a keyed rate limiter with the given options.
    pub fn build(self) -> Result<KeyedRateLimiter<K, A, H>, InconsistentCapacity>
    where
        H: Clone,
    {
        let map_opts = evmap::Options::default().with_hasher(self.hasher);
        let (r, mut w) = if self.map_capacity.is_some() {
            map_opts
                .with_capacity(self.map_capacity.unwrap())
                .construct()
        } else {
            map_opts.construct()
        };

        w.refresh();
        Ok(KeyedRateLimiter {
            algorithm: PhantomData,
            params: <A as Algorithm>::params_from_constructor(
                self.capacity,
                self.cell_weight,
                self.per_time_unit,
            )?,
            map_reader: r,
            map_writer: Arc::new(Mutex::new(w)),
        })
    }
}
<commit_msg>Improve keyed rate limiter docs<commit_after>use parking_lot::Mutex;
use std::collections::hash_map::RandomState;
use std::fmt;
use std::hash::BuildHasher;
use std::hash::Hash;
use std::marker::PhantomData;
use std::num::NonZeroU32;
use std::sync::Arc;
use std::time::{Duration, Instant};

use evmap::{self, ReadHandle, WriteHandle};

use {
    algorithms::{Algorithm, DefaultAlgorithm, RateLimitState},
    InconsistentCapacity, NegativeMultiDecision,
};

type MapWriteHandle<K, A, H> = Arc<Mutex<WriteHandle<K, <A as Algorithm>::BucketState, (), H>>>;

/// An in-memory rate limiter that regulates a single rate limit for
/// multiple keys.
///
/// Keyed rate limiters can be used to e.g. enforce a per-IP address
/// or a per-customer request limit on the server side.
///
/// This implementation of the keyed rate limiter uses
/// [`evmap`](../../../evmap/index.html), a read lock-free, concurrent
/// hash map. Addition of new keys (e.g. a new customer making their
/// first request) is synchronized and happens one at a time (it
/// synchronizes writes to minimize the effects from `evmap`'s
/// eventually consistent behavior on key addition), while reads of
/// existing keys all happen simultaneously, then get synchronized by
/// the rate limiting algorithm itself.
///
/// # Expiring old keys
/// If a key has not been checked in a long time, that key can be
/// expired safely (the next rate limit check for that key would
/// behave as if the key was not present in the map, after all). To
/// remove the unused keys and free up space, use the
/// [`cleanup`](method.cleanup) method:
///
/// ```
/// # use std::num::NonZeroU32;
/// # use std::time::Duration;
/// use ratelimit_meter::{KeyedRateLimiter};
/// # #[macro_use] extern crate nonzero_ext;
/// # extern crate ratelimit_meter;
/// # fn main () {
/// let mut limiter = KeyedRateLimiter::<&str>::new(nonzero!(100u32), Duration::from_secs(5));
/// limiter.check("hi there");
/// // time passes...
///
/// // remove all keys that have been expireable for 10 minutes:
/// limiter.cleanup(Duration::from_secs(600));
/// # }
/// ```
#[derive(Clone)]
pub struct KeyedRateLimiter<
    K: Eq + Hash + Clone,
    A: Algorithm = DefaultAlgorithm,
    H: BuildHasher + Clone = RandomState,
> {
    algorithm: PhantomData<A>,
    params: A::BucketParams,
    map_reader: ReadHandle<K, A::BucketState, (), H>,
    map_writer: MapWriteHandle<K, A, H>,
}

impl<A, K> fmt::Debug for KeyedRateLimiter<K, A>
where
    A: Algorithm,
    K: Eq + Hash + Clone,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "KeyedRateLimiter{{{params:?}}}", params = self.params)
    }
}

impl<A, K> KeyedRateLimiter<K, A>
where
    A: Algorithm,
    K: Eq + Hash + Clone,
{
    /// Construct a new rate limiter that allows `capacity` cells per
    /// time unit through.
    /// # Examples
    /// ```
    /// # use std::num::NonZeroU32;
    /// # use std::time::Duration;
    /// use ratelimit_meter::{KeyedRateLimiter};
    /// # #[macro_use] extern crate nonzero_ext;
    /// # extern crate ratelimit_meter;
    /// # fn main () {
    /// let _limiter = KeyedRateLimiter::<&str>::new(nonzero!(100u32), Duration::from_secs(5));
    /// # }
    /// ```
    pub fn new(capacity: NonZeroU32, per_time_unit: Duration) -> Self {
        let (r, mut w): (
            ReadHandle<K, A::BucketState>,
            WriteHandle<K, A::BucketState>,
        ) = evmap::new();
        w.refresh();
        KeyedRateLimiter {
            algorithm: PhantomData,
            params: <A as Algorithm>::params_from_constructor(
                capacity,
                nonzero!(1u32),
                per_time_unit,
            ).unwrap(),
            map_reader: r,
            map_writer: Arc::new(Mutex::new(w)),
        }
    }

    /// Construct a new keyed rate limiter that allows `capacity`
    /// cells per second.
    ///
    /// # Examples
    /// Constructing a rate limiter keyed by `&str` that lets through
    /// 100 cells per second:
    ///
    /// ```
    /// # use std::time::Duration;
    /// use ratelimit_meter::{KeyedRateLimiter, GCRA};
    /// # #[macro_use] extern crate nonzero_ext;
    /// # extern crate ratelimit_meter;
    /// # fn main () {
    /// let _limiter = KeyedRateLimiter::<&str, GCRA>::per_second(nonzero!(100u32));
    /// # }
    /// ```
    pub fn per_second(capacity: NonZeroU32) -> Self {
        Self::new(capacity, Duration::from_secs(1))
    }

    /// Return a constructor that can be used to construct a keyed
    /// rate limiter with the builder pattern.
    pub fn build_with_capacity(capacity: NonZeroU32) -> Builder<K, A, RandomState> {
        Builder {
            capacity,
            ..Default::default()
        }
    }

    fn check_and_update_key<E, F>(&self, key: K, update: F) -> Result<(), E>
    where
        F: Fn(&A::BucketState) -> Result<(), E>,
    {
        self.map_reader
            .get_and(&key, |v| {
                // we have at least one element (owing to the nature of
                // the evmap, it says there could be >1
                // entries, but we'll only ever add one):
                let state = &v[0];
                update(state)
            }).unwrap_or_else(|| {
                // entry does not exist, let's add one.
                let mut w = self.map_writer.lock();
                let state: A::BucketState = Default::default();
                let result = update(&state);
                w.update(key, state);
                w.flush();
                result
            })
    }

    /// Tests if a single cell for the given key can be accommodated
    /// at `Instant::now()`. If it can be, `check` updates the rate
    /// limiter state on that key to account for the conforming cell
    /// and returns `Ok(())`.
    ///
    /// If the cell is non-conforming (i.e., it can't be accomodated
    /// at this time stamp), `check_at` returns `Err` with information
    /// about the earliest time at which a cell could be considered
    /// conforming under that key.
    pub fn check(&mut self, key: K) -> Result<(), <A as Algorithm>::NegativeDecision> {
        self.check_at(key, Instant::now())
    }

    /// Tests if `n` cells for the given key can be accommodated at
    /// the current time stamp. If (and only if) all cells in the
    /// batch can be accomodated, the `MultiDecider` updates the rate
    /// limiter state on that key to account for all cells and returns
    /// `Ok(())`.
    ///
    /// If the entire batch of cells would not be conforming but the
    /// rate limiter has the capacity to accomodate the cells at any
    /// point in time, `check_n_at` returns error
    /// [`NegativeMultiDecision::BatchNonConforming`](../../enum.NegativeMultiDecision.html#variant.BatchNonConforming),
    /// holding the number of cells and the rate limiter's negative
    /// outcome result.
    ///
    /// If `n` exceeds the bucket capacity, `check_n_at` returns
    /// [`NegativeMultiDecision::InsufficientCapacity`](../../enum.NegativeMultiDecision.html#variant.InsufficientCapacity),
    /// indicating that a batch of this many cells can never succeed.
    pub fn check_n(
        &mut self,
        key: K,
        n: u32,
    ) -> Result<(), NegativeMultiDecision<<A as Algorithm>::NegativeDecision>> {
        self.check_n_at(key, n, Instant::now())
    }

    /// Tests whether a single cell for the given key can be
    /// accommodated at the given time stamp. See
    /// [`check`](#method.check).
    pub fn check_at(
        &mut self,
        key: K,
        at: Instant,
    ) -> Result<(), <A as Algorithm>::NegativeDecision> {
        self.check_and_update_key(key, |state| {
            <A as Algorithm>::test_and_update(state, &self.params, at)
        })
    }

    /// Tests if `n` cells for the given key can be accommodated at
    /// the given time (`Instant::now()`), using
    /// [`check_n`](#method.check_n)
    pub fn check_n_at(
        &mut self,
        key: K,
        n: u32,
        at: Instant,
    ) -> Result<(), NegativeMultiDecision<<A as Algorithm>::NegativeDecision>> {
        self.check_and_update_key(key, |state| {
            <A as Algorithm>::test_n_and_update(state, &self.params, n, at)
        })
    }

    /// Removes the keys from this rate limiter that can be expired
    /// safely and returns the keys that were removed.
    ///
    /// To be eligible for expiration, a key's rate limiter state must
    /// be at least `min_age` past its last relevance (see
    /// [`RateLimitState.last_touched`](../../algorithms/trait.RateLimitState.html#method.last_touched)).
    ///
    /// This method works in two parts, but both parts block new keys
    /// from getting added while they're running:
    /// * First, it collects the keys that are eligible for expiration.
    /// * Then, it expires these keys.
    ///
    /// Note that this only affects new keys that need to be
    /// added. Rate-limiting operations on existing keys continue
    /// concurrently.
    ///
    /// # Race conditions
    /// Since this is happening concurrently with other operations,
    /// race conditions can & will occur. It's possible that cells are
    /// accounted between the time `cleanup_at` is called and their
    /// expiry.  These cells will lost.
    ///
    /// The time window in which this can occur is hopefully short
    /// enough that this is an acceptable risk of loss in accuracy.
    pub fn cleanup<D: Into<Option<Duration>>>(&mut self, min_age: D) -> Vec<K> {
        self.cleanup_at(min_age, Instant::now())
    }

    /// Removes the keys from this rate limiter that can be expired
    /// safely at the given time stamp. See
    /// [`cleanup`](#method.cleanup). It returns the list of expired
    /// keys.
    pub fn cleanup_at<D: Into<Option<Duration>>, I: Into<Option<Instant>>>(
        &mut self,
        min_age: D,
        at: I,
    ) -> Vec<K> {
        let params = &self.params;
        let min_age = min_age.into().unwrap_or_else(|| Duration::new(0, 0));
        let at = at.into().unwrap_or_else(Instant::now);

        let mut expireable: Vec<K> = vec![];
        self.map_reader.for_each(|k, v| {
            if let Some(state) = v.get(0) {
                if state.last_touched(params) < at - min_age {
                    expireable.push(k.clone());
                }
            }
        });

        // Now take the map write lock and remove all the keys that we
        // collected:
        let mut w = self.map_writer.lock();
        for key in expireable.iter().cloned() {
            w.empty(key);
        }
        w.refresh();
        expireable
    }
}

/// A constructor for keyed rate limiters.
pub struct Builder<K: Eq + Hash + Clone, A: Algorithm, H: BuildHasher> {
    end_result: PhantomData<(K, A)>,
    capacity: NonZeroU32,
    cell_weight: NonZeroU32,
    per_time_unit: Duration,
    hasher: H,
    map_capacity: Option<usize>,
}

impl<K, A> Default for Builder<K, A, RandomState>
where
    K: Eq + Hash + Clone,
    A: Algorithm,
{
    fn default() -> Builder<K, A, RandomState> {
        Builder {
            end_result: PhantomData,
            map_capacity: None,
            capacity: nonzero!(1u32),
            cell_weight: nonzero!(1u32),
            per_time_unit: Duration::from_secs(1),
            hasher: RandomState::new(),
        }
    }
}

impl<K, A, H> Builder<K, A, H>
where
    K: Eq + Hash + Clone,
    A: Algorithm,
    H: BuildHasher,
{
    /// Sets the hashing method used for the map.
    pub fn with_hasher<H2: BuildHasher>(self, hash_builder: H2) -> Builder<K, A, H2> {
        Builder {
            hasher: hash_builder,
            end_result: self.end_result,
            capacity: self.capacity,
            cell_weight: self.cell_weight,
            per_time_unit: self.per_time_unit,
            map_capacity: self.map_capacity,
        }
    }

    /// Sets the "weight" of each cell that is checked against the
    /// bucket.
    pub fn with_cell_weight(self, cell_weight: NonZeroU32) -> Result<Self, InconsistentCapacity> {
        if self.cell_weight > self.capacity {
            return Err(InconsistentCapacity {
                capacity: self.capacity,
                cell_weight,
            });
        }
        Ok(Builder {
            cell_weight,
            ..self
        })
    }

    /// Sets the initial number of keys that the map can hold before
    /// rehashing.
    pub fn with_map_capacity(self, map_capacity: usize) -> Self {
        Builder {
            map_capacity: Some(map_capacity),
            ..self
        }
    }

    /// Constructs a keyed rate limiter with the given options.
    pub fn build(self) -> Result<KeyedRateLimiter<K, A, H>, InconsistentCapacity>
    where
        H: Clone,
    {
        let map_opts = evmap::Options::default().with_hasher(self.hasher);
        let (r, mut w) = if self.map_capacity.is_some() {
            map_opts
                .with_capacity(self.map_capacity.unwrap())
                .construct()
        } else {
            map_opts.construct()
        };

        w.refresh();
        Ok(KeyedRateLimiter {
            algorithm: PhantomData,
            params: <A as Algorithm>::params_from_constructor(
                self.capacity,
                self.cell_weight,
                self.per_time_unit,
            )?,
            map_reader: r,
            map_writer: Arc::new(Mutex::new(w)),
        })
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Stefan Lankes, RWTH Aachen University
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

pub mod write;
pub mod exit;

use syscall::exit::sys_exit;
use syscall::write::sys_write;

/// number of the sytem call `exit`
pub const SYSNO_EXIT: usize = 0;

/// number of the sytem call `write`
pub const SYSNO_WRITE: usize = 1;

/// total number of system calls
pub const NO_SYSCALLS: usize = 2;

#[repr(align(64))]
#[repr(C)]
pub struct SyscallTable{
	 handle: [*const usize; NO_SYSCALLS]
}

impl SyscallTable {
	pub const fn new() -> Self {
		SyscallTable {
			handle:	[sys_exit as *const _,
					 sys_write as *const _]
		}
	}
}

unsafe impl Send for SyscallTable {}
unsafe impl Sync for SyscallTable {}

#[no_mangle]
pub static SYSHANDLER_TABLE: SyscallTable = SyscallTable::new();
<commit_msg>remove typos<commit_after>// Copyright (c) 2017 Stefan Lankes, RWTH Aachen University
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

pub mod write;
pub mod exit;

use syscall::exit::sys_exit;
use syscall::write::sys_write;

/// number of the system call `exit`
pub const SYSNO_EXIT: usize = 0;

/// number of the system call `write`
pub const SYSNO_WRITE: usize = 1;

/// total number of system calls
pub const NO_SYSCALLS: usize = 2;

#[repr(align(64))]
#[repr(C)]
pub struct SyscallTable{
	 handle: [*const usize; NO_SYSCALLS]
}

impl SyscallTable {
	pub const fn new() -> Self {
		SyscallTable {
			handle:	[sys_exit as *const _,
					 sys_write as *const _]
		}
	}
}

unsafe impl Send for SyscallTable {}
unsafe impl Sync for SyscallTable {}

#[no_mangle]
pub static SYSHANDLER_TABLE: SyscallTable = SyscallTable::new();
<|endoftext|>