<commit_before>// Copyright 2012-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.

use std::cell::RefCell;
use std::option;
use std::os;
use std::io;
use std::io::fs;
use std::hashmap::HashSet;

pub enum FileMatch { FileMatches, FileDoesntMatch }

// A module for searching for libraries
// FIXME (#2658): I'm not happy how this module turned out. Should
// probably just be folded into cstore.

/// Functions with type `pick` take a parent directory as well as
/// a file found in that directory.
pub type pick<'a> = 'a |path: &Path| -> FileMatch;

pub struct FileSearch {
    sysroot: @Path,
    addl_lib_search_paths: @RefCell<HashSet<Path>>,
    target_triple: ~str
}

impl FileSearch {
    pub fn for_each_lib_search_path(&self, f: |&Path| -> FileMatch) {
        let mut visited_dirs = HashSet::new();
        let mut found = false;

        let addl_lib_search_paths = self.addl_lib_search_paths.borrow();
        debug!("filesearch: searching additional lib search paths [{:?}]",
               addl_lib_search_paths.get().len());
        for path in addl_lib_search_paths.get().iter() {
            match f(path) {
                FileMatches => found = true,
                FileDoesntMatch => ()
            }
            visited_dirs.insert(path.as_vec().to_owned());
        }

        debug!("filesearch: searching target lib path");
        let tlib_path = make_target_lib_path(self.sysroot,
                                    self.target_triple);
        if !visited_dirs.contains_equiv(&tlib_path.as_vec()) {
            match f(&tlib_path) {
                FileMatches => found = true,
                FileDoesntMatch => ()
            }
        }
        visited_dirs.insert(tlib_path.as_vec().to_owned());
        // Try RUST_PATH
        if !found {
            let rustpath = rust_path();
            for path in rustpath.iter() {
                let tlib_path = make_rustpkg_target_lib_path(path, self.target_triple);
                debug!("is {} in visited_dirs? {:?}", tlib_path.display(),
                        visited_dirs.contains_equiv(&tlib_path.as_vec().to_owned()));

                if !visited_dirs.contains_equiv(&tlib_path.as_vec()) {
                    visited_dirs.insert(tlib_path.as_vec().to_owned());
                    // Don't keep searching the RUST_PATH if one match turns up --
                    // if we did, we'd get a "multiple matching crates" error
                    match f(&tlib_path) {
                       FileMatches => {
                           break;
                       }
                       FileDoesntMatch => ()
                    }
                }
            }
        }
    }

    pub fn get_target_lib_path(&self) -> Path {
        make_target_lib_path(self.sysroot, self.target_triple)
    }

    pub fn get_target_lib_file_path(&self, file: &Path) -> Path {
        let mut p = self.get_target_lib_path();
        p.push(file);
        p
    }

    pub fn search(&self, pick: pick) {
        self.for_each_lib_search_path(|lib_search_path| {
            debug!("searching {}", lib_search_path.display());
            match io::result(|| fs::readdir(lib_search_path)) {
                Ok(files) => {
                    let mut rslt = FileDoesntMatch;
                    let is_rlib = |p: & &Path| {
                        p.extension_str() == Some("rlib")
                    };
                    // Reading metadata out of rlibs is faster, and if we find both
                    // an rlib and a dylib we only read one of the files of
                    // metadata, so in the name of speed, bring all rlib files to
                    // the front of the search list.
                    let files1 = files.iter().filter(|p| is_rlib(p));
                    let files2 = files.iter().filter(|p| !is_rlib(p));
                    for path in files1.chain(files2) {
                        debug!("testing {}", path.display());
                        let maybe_picked = pick(path);
                        match maybe_picked {
                            FileMatches => {
                                debug!("picked {}", path.display());
                                rslt = FileMatches;
                            }
                            FileDoesntMatch => {
                                debug!("rejected {}", path.display());
                            }
                        }
                    }
                    rslt
                }
                Err(..) => FileDoesntMatch,
            }
        });
    }

    pub fn new(maybe_sysroot: &Option<@Path>,
               target_triple: &str,
               addl_lib_search_paths: @RefCell<HashSet<Path>>) -> FileSearch {
        let sysroot = get_sysroot(maybe_sysroot);
        debug!("using sysroot = {}", sysroot.display());
        FileSearch{
            sysroot: sysroot,
            addl_lib_search_paths: addl_lib_search_paths,
            target_triple: target_triple.to_owned()
        }
    }
}

pub fn relative_target_lib_path(target_triple: &str) -> Path {
    let mut p = Path::new(libdir());
    assert!(p.is_relative());
    p.push(rustlibdir());
    p.push(target_triple);
    p.push("lib");
    p
}

fn make_target_lib_path(sysroot: &Path,
                        target_triple: &str) -> Path {
    sysroot.join(&relative_target_lib_path(target_triple))
}

fn make_rustpkg_target_lib_path(dir: &Path,
                        target_triple: &str) -> Path {
    let mut p = dir.join(libdir());
    p.push(target_triple);
    p
}

pub fn get_or_default_sysroot() -> Path {
    match os::self_exe_path() {
      option::Some(p) => { let mut p = p; p.pop(); p }
      option::None => fail!("can't determine value for sysroot")
    }
}

fn get_sysroot(maybe_sysroot: &Option<@Path>) -> @Path {
    match *maybe_sysroot {
      option::Some(sr) => sr,
      option::None => @get_or_default_sysroot()
    }
}

#[cfg(windows)]
static PATH_ENTRY_SEPARATOR: &'static str = ";";
#[cfg(not(windows))]
static PATH_ENTRY_SEPARATOR: &'static str = ":";

/// Returns RUST_PATH as a string, without default paths added
pub fn get_rust_path() -> Option<~str> {
    os::getenv("RUST_PATH")
}

/// Returns the value of RUST_PATH, as a list
/// of Paths. Includes default entries for, if they exist:
/// $HOME/.rust
/// DIR/.rust for any DIR that's the current working directory
/// or an ancestor of it
pub fn rust_path() -> ~[Path] {
    let mut env_rust_path: ~[Path] = match get_rust_path() {
        Some(env_path) => {
            let env_path_components: ~[&str] =
                env_path.split_str(PATH_ENTRY_SEPARATOR).collect();
            env_path_components.map(|&s| Path::new(s))
        }
        None => ~[]
    };
    let mut cwd = os::getcwd();
    // now add in default entries
    let cwd_dot_rust = cwd.join(".rust");
    if !env_rust_path.contains(&cwd_dot_rust) {
        env_rust_path.push(cwd_dot_rust);
    }
    if !env_rust_path.contains(&cwd) {
        env_rust_path.push(cwd.clone());
    }
    loop {
        if { let f = cwd.filename(); f.is_none() || f.unwrap() == bytes!("..") } {
            break
        }
        cwd.set_filename(".rust");
        if !env_rust_path.contains(&cwd) && cwd.exists() {
            env_rust_path.push(cwd.clone());
        }
        cwd.pop();
    }
    let h = os::homedir();
    for h in h.iter() {
        let p = h.join(".rust");
        if !env_rust_path.contains(&p) && p.exists() {
            env_rust_path.push(p);
        }
    }
    env_rust_path
}

// The name of the directory rustc expects libraries to be located.
// On Unix should be "lib", on windows "bin"
pub fn libdir() -> ~str {
    (env!("CFG_LIBDIR_RELATIVE")).to_owned()
}

// The name of rustc's own place to organize libraries.
// Used to be "rustc", now the default is "rustlib"
pub fn rustlibdir() -> ~str {
    (env!("CFG_RUSTLIBDIR")).to_owned()
}
<commit_msg>Follow symlinks in sysroot<commit_after>// Copyright 2012-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.

use std::cell::RefCell;
use std::option;
use std::os;
use std::io;
use std::io::fs;
use std::hashmap::HashSet;

pub enum FileMatch { FileMatches, FileDoesntMatch }

// A module for searching for libraries
// FIXME (#2658): I'm not happy how this module turned out. Should
// probably just be folded into cstore.

/// Functions with type `pick` take a parent directory as well as
/// a file found in that directory.
pub type pick<'a> = 'a |path: &Path| -> FileMatch;

pub struct FileSearch {
    sysroot: @Path,
    addl_lib_search_paths: @RefCell<HashSet<Path>>,
    target_triple: ~str
}

impl FileSearch {
    pub fn for_each_lib_search_path(&self, f: |&Path| -> FileMatch) {
        let mut visited_dirs = HashSet::new();
        let mut found = false;

        let addl_lib_search_paths = self.addl_lib_search_paths.borrow();
        debug!("filesearch: searching additional lib search paths [{:?}]",
               addl_lib_search_paths.get().len());
        for path in addl_lib_search_paths.get().iter() {
            match f(path) {
                FileMatches => found = true,
                FileDoesntMatch => ()
            }
            visited_dirs.insert(path.as_vec().to_owned());
        }

        debug!("filesearch: searching target lib path");
        let tlib_path = make_target_lib_path(self.sysroot,
                                    self.target_triple);
        if !visited_dirs.contains_equiv(&tlib_path.as_vec()) {
            match f(&tlib_path) {
                FileMatches => found = true,
                FileDoesntMatch => ()
            }
        }
        visited_dirs.insert(tlib_path.as_vec().to_owned());
        // Try RUST_PATH
        if !found {
            let rustpath = rust_path();
            for path in rustpath.iter() {
                let tlib_path = make_rustpkg_target_lib_path(path, self.target_triple);
                debug!("is {} in visited_dirs? {:?}", tlib_path.display(),
                        visited_dirs.contains_equiv(&tlib_path.as_vec().to_owned()));

                if !visited_dirs.contains_equiv(&tlib_path.as_vec()) {
                    visited_dirs.insert(tlib_path.as_vec().to_owned());
                    // Don't keep searching the RUST_PATH if one match turns up --
                    // if we did, we'd get a "multiple matching crates" error
                    match f(&tlib_path) {
                       FileMatches => {
                           break;
                       }
                       FileDoesntMatch => ()
                    }
                }
            }
        }
    }

    pub fn get_target_lib_path(&self) -> Path {
        make_target_lib_path(self.sysroot, self.target_triple)
    }

    pub fn get_target_lib_file_path(&self, file: &Path) -> Path {
        let mut p = self.get_target_lib_path();
        p.push(file);
        p
    }

    pub fn search(&self, pick: pick) {
        self.for_each_lib_search_path(|lib_search_path| {
            debug!("searching {}", lib_search_path.display());
            match io::result(|| fs::readdir(lib_search_path)) {
                Ok(files) => {
                    let mut rslt = FileDoesntMatch;
                    let is_rlib = |p: & &Path| {
                        p.extension_str() == Some("rlib")
                    };
                    // Reading metadata out of rlibs is faster, and if we find both
                    // an rlib and a dylib we only read one of the files of
                    // metadata, so in the name of speed, bring all rlib files to
                    // the front of the search list.
                    let files1 = files.iter().filter(|p| is_rlib(p));
                    let files2 = files.iter().filter(|p| !is_rlib(p));
                    for path in files1.chain(files2) {
                        debug!("testing {}", path.display());
                        let maybe_picked = pick(path);
                        match maybe_picked {
                            FileMatches => {
                                debug!("picked {}", path.display());
                                rslt = FileMatches;
                            }
                            FileDoesntMatch => {
                                debug!("rejected {}", path.display());
                            }
                        }
                    }
                    rslt
                }
                Err(..) => FileDoesntMatch,
            }
        });
    }

    pub fn new(maybe_sysroot: &Option<@Path>,
               target_triple: &str,
               addl_lib_search_paths: @RefCell<HashSet<Path>>) -> FileSearch {
        let sysroot = get_sysroot(maybe_sysroot);
        debug!("using sysroot = {}", sysroot.display());
        FileSearch{
            sysroot: sysroot,
            addl_lib_search_paths: addl_lib_search_paths,
            target_triple: target_triple.to_owned()
        }
    }
}

pub fn relative_target_lib_path(target_triple: &str) -> Path {
    let mut p = Path::new(libdir());
    assert!(p.is_relative());
    p.push(rustlibdir());
    p.push(target_triple);
    p.push("lib");
    p
}

fn make_target_lib_path(sysroot: &Path,
                        target_triple: &str) -> Path {
    sysroot.join(&relative_target_lib_path(target_triple))
}

fn make_rustpkg_target_lib_path(dir: &Path,
                        target_triple: &str) -> Path {
    let mut p = dir.join(libdir());
    p.push(target_triple);
    p
}

pub fn get_or_default_sysroot() -> Path {
    // Follow symlinks.  If the resolved path is relative, make it absolute.
    fn canonicalize(path: Option<Path>) -> Option<Path> {
        path.and_then(|mut path|
            match io::io_error::cond.trap(|_| ()).inside(|| fs::readlink(&path)) {
                Some(canon) => {
                    if canon.is_absolute() {
                        Some(canon)
                    } else {
                        path.pop();
                        Some(path.join(canon))
                    }
                },
                None => Some(path),
            })
    }

    match canonicalize(os::self_exe_name()) {
      option::Some(p) => { let mut p = p; p.pop(); p.pop(); p }
      option::None => fail!("can't determine value for sysroot")
    }
}

fn get_sysroot(maybe_sysroot: &Option<@Path>) -> @Path {
    match *maybe_sysroot {
      option::Some(sr) => sr,
      option::None => @get_or_default_sysroot()
    }
}

#[cfg(windows)]
static PATH_ENTRY_SEPARATOR: &'static str = ";";
#[cfg(not(windows))]
static PATH_ENTRY_SEPARATOR: &'static str = ":";

/// Returns RUST_PATH as a string, without default paths added
pub fn get_rust_path() -> Option<~str> {
    os::getenv("RUST_PATH")
}

/// Returns the value of RUST_PATH, as a list
/// of Paths. Includes default entries for, if they exist:
/// $HOME/.rust
/// DIR/.rust for any DIR that's the current working directory
/// or an ancestor of it
pub fn rust_path() -> ~[Path] {
    let mut env_rust_path: ~[Path] = match get_rust_path() {
        Some(env_path) => {
            let env_path_components: ~[&str] =
                env_path.split_str(PATH_ENTRY_SEPARATOR).collect();
            env_path_components.map(|&s| Path::new(s))
        }
        None => ~[]
    };
    let mut cwd = os::getcwd();
    // now add in default entries
    let cwd_dot_rust = cwd.join(".rust");
    if !env_rust_path.contains(&cwd_dot_rust) {
        env_rust_path.push(cwd_dot_rust);
    }
    if !env_rust_path.contains(&cwd) {
        env_rust_path.push(cwd.clone());
    }
    loop {
        if { let f = cwd.filename(); f.is_none() || f.unwrap() == bytes!("..") } {
            break
        }
        cwd.set_filename(".rust");
        if !env_rust_path.contains(&cwd) && cwd.exists() {
            env_rust_path.push(cwd.clone());
        }
        cwd.pop();
    }
    let h = os::homedir();
    for h in h.iter() {
        let p = h.join(".rust");
        if !env_rust_path.contains(&p) && p.exists() {
            env_rust_path.push(p);
        }
    }
    env_rust_path
}

// The name of the directory rustc expects libraries to be located.
// On Unix should be "lib", on windows "bin"
pub fn libdir() -> ~str {
    (env!("CFG_LIBDIR_RELATIVE")).to_owned()
}

// The name of rustc's own place to organize libraries.
// Used to be "rustc", now the default is "rustlib"
pub fn rustlibdir() -> ~str {
    (env!("CFG_RUSTLIBDIR")).to_owned()
}
<|endoftext|>


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

use check::{FnCtxt, structurally_resolved_type};
use check::demand;
use middle::traits::{self, ObjectSafetyViolation, MethodViolationCode};
use middle::traits::{Obligation, ObligationCause};
use middle::traits::report_fulfillment_errors;
use middle::ty::{self, Ty, AsPredicate};
use syntax::ast;
use syntax::codemap::Span;
use util::nodemap::FnvHashSet;
use util::ppaux::{Repr, UserString};

pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                   cast_expr: &ast::Expr,
                                   source_expr: &ast::Expr,
                                   target_object_ty: Ty<'tcx>)
{
    let tcx = fcx.tcx();
    debug!("check_object_cast(cast_expr={}, target_object_ty={})",
           cast_expr.repr(tcx),
           target_object_ty.repr(tcx));

    // Look up vtables for the type we're casting to,
    // passing in the source and target type.  The source
    // must be a pointer type suitable to the object sigil,
    // e.g.: `&x as &Trait` or `box x as Box<Trait>`

    // First, construct a fresh type that we can feed into `<expr>`
    // within `<expr> as <type>` to inform type inference (e.g. to
    // tell it that we are expecting a `Box<_>` or an `&_`).
    let fresh_ty = fcx.infcx().next_ty_var();
    let (object_trait_ty, source_expected_ty) = match target_object_ty.sty {
        ty::ty_uniq(object_trait_ty) => {
            (object_trait_ty, ty::mk_uniq(fcx.tcx(), fresh_ty))
        }
        ty::ty_rptr(target_region, ty::mt { ty: object_trait_ty,
                                            mutbl: target_mutbl }) => {
            (object_trait_ty,
             ty::mk_rptr(fcx.tcx(),
                         target_region, ty::mt { ty: fresh_ty,
                                                 mutbl: target_mutbl }))
        }
        _ => {
            fcx.tcx().sess.span_bug(source_expr.span, "expected object type");
        }
    };

    let source_ty = fcx.expr_ty(source_expr);
    debug!("check_object_cast pre unify source_ty={}", source_ty.repr(tcx));

    // This ensures that the source_ty <: source_expected_ty, which
    // will ensure e.g. that &'a T <: &'b T when doing `&'a T as &'b Trait`
    //
    // FIXME (pnkfelix): do we need to use suptype_with_fn in order to
    // override the error message emitted when the types do not work
    // out in the manner desired?
    demand::suptype(fcx, source_expr.span, source_expected_ty, source_ty);

    debug!("check_object_cast postunify source_ty={}", source_ty.repr(tcx));
    let source_ty = structurally_resolved_type(fcx, source_expr.span, source_ty);
    debug!("check_object_cast resolveto source_ty={}", source_ty.repr(tcx));

    let object_trait = object_trait(&object_trait_ty);

    let referent_ty = match source_ty.sty {
        ty::ty_uniq(ty) => ty,
        ty::ty_rptr(_, ty::mt { ty, mutbl: _ }) => ty,
        _ => fcx.tcx().sess.span_bug(source_expr.span,
                                     "expected appropriate reference type"),
    };

    // Ensure that if Ptr<T> is cast to Ptr<Trait>, then T : Trait.
    push_cast_obligation(fcx, cast_expr, object_trait, referent_ty);
    check_object_safety(tcx, object_trait, source_expr.span);

    fn object_trait<'a, 'tcx>(t: &'a Ty<'tcx>) -> &'a ty::TyTrait<'tcx> {
        match t.sty {
            ty::ty_trait(ref ty_trait) => &**ty_trait,
            _ => panic!("expected ty_trait")
        }
    }

    fn push_cast_obligation<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                      cast_expr: &ast::Expr,
                                      object_trait: &ty::TyTrait<'tcx>,
                                      referent_ty: Ty<'tcx>) {
        let object_trait_ref =
            register_object_cast_obligations(fcx,
                                             cast_expr.span,
                                             object_trait,
                                             referent_ty);

        // Finally record the object_trait_ref for use during trans
        // (it would prob be better not to do this, but it's just kind
        // of a pain to have to reconstruct it).
        fcx.write_object_cast(cast_expr.id, object_trait_ref);
    }
}

// Check that a trait is 'object-safe'. This should be checked whenever a trait object
// is created (by casting or coercion, etc.). A trait is object-safe if all its
// methods are object-safe. A trait method is object-safe if it does not take
// self by value, has no type parameters and does not use the `Self` type, except
// in self position.
pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>,
                                 object_trait: &ty::TyTrait<'tcx>,
                                 span: Span)
{
    let object_trait_ref =
        object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err);

    if traits::is_object_safe(tcx, object_trait_ref.clone()) {
        return;
    }

    span_err!(tcx.sess, span, E0038,
              "cannot convert to a trait object because trait `{}` is not object-safe",
              ty::item_path_str(tcx, object_trait_ref.def_id()));

    let violations = traits::object_safety_violations(tcx, object_trait_ref.clone());
    for violation in violations {
        match violation {
            ObjectSafetyViolation::SizedSelf => {
                tcx.sess.span_note(
                    span,
                    "the trait cannot require that `Self : Sized`");
            }

            ObjectSafetyViolation::Method(method, MethodViolationCode::ByValueSelf) => {
                tcx.sess.span_note(
                    span,
                    &format!("method `{}` has a receiver type of `Self`, \
                              which cannot be used with a trait object",
                             method.name.user_string(tcx)));
            }

            ObjectSafetyViolation::Method(method, MethodViolationCode::StaticMethod) => {
                tcx.sess.span_note(
                    span,
                    &format!("method `{}` has no receiver",
                             method.name.user_string(tcx)));
            }

            ObjectSafetyViolation::Method(method, MethodViolationCode::ReferencesSelf) => {
                tcx.sess.span_note(
                    span,
                    &format!("method `{}` references the `Self` type \
                              in its arguments or return type",
                             method.name.user_string(tcx)));
            }

            ObjectSafetyViolation::Method(method, MethodViolationCode::Generic) => {
                tcx.sess.span_note(
                    span,
                    &format!("method `{}` has generic type parameters",
                             method.name.user_string(tcx)));
            }
        }
    }
}

pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                                  span: Span,
                                                  object_trait: &ty::TyTrait<'tcx>,
                                                  referent_ty: Ty<'tcx>)
                                                  -> ty::PolyTraitRef<'tcx>
{
    // We can only make objects from sized types.
    fcx.register_builtin_bound(
        referent_ty,
        ty::BoundSized,
        traits::ObligationCause::new(span, fcx.body_id, traits::ObjectSized));

    // This is just for better error reporting. Kinda goofy. The object type stuff
    // needs some refactoring so there is a more convenient type to pass around.
    let object_trait_ty =
        ty::mk_trait(fcx.tcx(),
                     object_trait.principal.clone(),
                     object_trait.bounds.clone());

    debug!("register_object_cast_obligations: referent_ty={} object_trait_ty={}",
           referent_ty.repr(fcx.tcx()),
           object_trait_ty.repr(fcx.tcx()));

    let cause = ObligationCause::new(span,
                                     fcx.body_id,
                                     traits::ObjectCastObligation(object_trait_ty));

    // Create the obligation for casting from T to Trait.
    let object_trait_ref =
        object_trait.principal_trait_ref_with_self_ty(fcx.tcx(), referent_ty);
    let object_obligation =
        Obligation::new(cause.clone(), object_trait_ref.as_predicate());
    fcx.register_predicate(object_obligation);

    // Create additional obligations for all the various builtin
    // bounds attached to the object cast. (In other words, if the
    // object type is Foo+Send, this would create an obligation
    // for the Send check.)
    for builtin_bound in &object_trait.bounds.builtin_bounds {
        fcx.register_builtin_bound(
            referent_ty,
            builtin_bound,
            cause.clone());
    }

    // Create obligations for the projection predicates.
    let projection_bounds =
        object_trait.projection_bounds_with_self_ty(fcx.tcx(), referent_ty);
    for projection_bound in &projection_bounds {
        let projection_obligation =
            Obligation::new(cause.clone(), projection_bound.as_predicate());
        fcx.register_predicate(projection_obligation);
    }

    // Finally, check that there IS a projection predicate for every associated type.
    check_object_type_binds_all_associated_types(fcx.tcx(),
                                                 span,
                                                 object_trait);

    object_trait_ref
}

fn check_object_type_binds_all_associated_types<'tcx>(tcx: &ty::ctxt<'tcx>,
                                                      span: Span,
                                                      object_trait: &ty::TyTrait<'tcx>)
{
    let object_trait_ref =
        object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err);

    let mut associated_types: FnvHashSet<(ast::DefId, ast::Name)> =
        traits::supertraits(tcx, object_trait_ref.clone())
        .flat_map(|tr| {
            let trait_def = ty::lookup_trait_def(tcx, tr.def_id());
            trait_def.associated_type_names
                .clone()
                .into_iter()
                .map(move |associated_type_name| (tr.def_id(), associated_type_name))
        })
        .collect();

    for projection_bound in &object_trait.bounds.projection_bounds {
        let pair = (projection_bound.0.projection_ty.trait_ref.def_id,
                    projection_bound.0.projection_ty.item_name);
        associated_types.remove(&pair);
    }

    for (trait_def_id, name) in associated_types {
        span_err!(tcx.sess, span, E0191,
            "the value of the associated type `{}` (from the trait `{}`) must be specified",
                    name.user_string(tcx),
                    ty::item_path_str(tcx, trait_def_id));
    }
}

pub fn select_all_fcx_obligations_and_apply_defaults(fcx: &FnCtxt) {
    debug!("select_all_fcx_obligations_and_apply_defaults");

    select_fcx_obligations_where_possible(fcx);
    fcx.default_type_parameters();
    select_fcx_obligations_where_possible(fcx);
}

pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) {
    debug!("select_all_fcx_obligations_or_error");

    // upvar inference should have ensured that all deferred call
    // resolutions are handled by now.
    assert!(fcx.inh.deferred_call_resolutions.borrow().is_empty());

    select_all_fcx_obligations_and_apply_defaults(fcx);
    let mut fulfillment_cx = fcx.inh.fulfillment_cx.borrow_mut();
    let r = fulfillment_cx.select_all_or_error(fcx.infcx(), fcx);
    match r {
        Ok(()) => { }
        Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
    }
}

/// Select as many obligations as we can at present.
pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt)
{
    match
        fcx.inh.fulfillment_cx
        .borrow_mut()
        .select_where_possible(fcx.infcx(), fcx)
    {
        Ok(()) => { }
        Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
    }
}

/// Try to select any fcx obligation that we haven't tried yet, in an effort to improve inference.
/// You could just call `select_fcx_obligations_where_possible` except that it leads to repeated
/// work.
pub fn select_new_fcx_obligations(fcx: &FnCtxt) {
    match
        fcx.inh.fulfillment_cx
        .borrow_mut()
        .select_new_obligations(fcx.infcx(), fcx)
    {
        Ok(()) => { }
        Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
    }
}

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

use check::{FnCtxt};
use check::demand;
use middle::traits::{self, ObjectSafetyViolation, MethodViolationCode};
use middle::traits::{Obligation, ObligationCause};
use middle::traits::report_fulfillment_errors;
use middle::ty::{self, Ty, AsPredicate};
use syntax::ast;
use syntax::codemap::Span;
use util::nodemap::FnvHashSet;
use util::ppaux::{Repr, UserString};

pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                   cast_expr: &ast::Expr,
                                   source_expr: &ast::Expr,
                                   target_object_ty: Ty<'tcx>)
{
    let tcx = fcx.tcx();
    debug!("check_object_cast(cast_expr={}, target_object_ty={})",
           cast_expr.repr(tcx),
           target_object_ty.repr(tcx));

    // Look up vtables for the type we're casting to,
    // passing in the source and target type.  The source
    // must be a pointer type suitable to the object sigil,
    // e.g.: `&x as &Trait` or `box x as Box<Trait>`

    // First, construct a fresh type that we can feed into `<expr>`
    // within `<expr> as <type>` to inform type inference (e.g. to
    // tell it that we are expecting a `Box<_>` or an `&_`).
    let fresh_ty = fcx.infcx().next_ty_var();
    let (object_trait_ty, source_expected_ty) = match target_object_ty.sty {
        ty::ty_uniq(object_trait_ty) => {
            (object_trait_ty, ty::mk_uniq(fcx.tcx(), fresh_ty))
        }
        ty::ty_rptr(target_region, ty::mt { ty: object_trait_ty,
                                            mutbl: target_mutbl }) => {
            (object_trait_ty,
             ty::mk_rptr(fcx.tcx(),
                         target_region, ty::mt { ty: fresh_ty,
                                                 mutbl: target_mutbl }))
        }
        _ => {
            fcx.tcx().sess.span_bug(source_expr.span, "expected object type");
        }
    };

    let source_ty = fcx.expr_ty(source_expr);
    debug!("check_object_cast pre unify source_ty={}", source_ty.repr(tcx));

    // This ensures that the source_ty <: source_expected_ty, which
    // will ensure e.g. that &'a T <: &'b T when doing `&'a T as &'b Trait`
    //
    // FIXME (pnkfelix): do we need to use suptype_with_fn in order to
    // override the error message emitted when the types do not work
    // out in the manner desired?
    demand::suptype(fcx, source_expr.span, source_expected_ty, source_ty);

    debug!("check_object_cast postunify source_ty={}", source_ty.repr(tcx));

    let object_trait = object_trait(&object_trait_ty);

    // Ensure that if Ptr<T> is cast to Ptr<Trait>, then T : Trait.
    push_cast_obligation(fcx, cast_expr, object_trait, fresh_ty);
    check_object_safety(tcx, object_trait, source_expr.span);

    fn object_trait<'a, 'tcx>(t: &'a Ty<'tcx>) -> &'a ty::TyTrait<'tcx> {
        match t.sty {
            ty::ty_trait(ref ty_trait) => &**ty_trait,
            _ => panic!("expected ty_trait")
        }
    }

    fn push_cast_obligation<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                      cast_expr: &ast::Expr,
                                      object_trait: &ty::TyTrait<'tcx>,
                                      referent_ty: Ty<'tcx>) {
        let object_trait_ref =
            register_object_cast_obligations(fcx,
                                             cast_expr.span,
                                             object_trait,
                                             referent_ty);

        // Finally record the object_trait_ref for use during trans
        // (it would prob be better not to do this, but it's just kind
        // of a pain to have to reconstruct it).
        fcx.write_object_cast(cast_expr.id, object_trait_ref);
    }
}

// Check that a trait is 'object-safe'. This should be checked whenever a trait object
// is created (by casting or coercion, etc.). A trait is object-safe if all its
// methods are object-safe. A trait method is object-safe if it does not take
// self by value, has no type parameters and does not use the `Self` type, except
// in self position.
pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>,
                                 object_trait: &ty::TyTrait<'tcx>,
                                 span: Span)
{
    let object_trait_ref =
        object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err);

    if traits::is_object_safe(tcx, object_trait_ref.clone()) {
        return;
    }

    span_err!(tcx.sess, span, E0038,
              "cannot convert to a trait object because trait `{}` is not object-safe",
              ty::item_path_str(tcx, object_trait_ref.def_id()));

    let violations = traits::object_safety_violations(tcx, object_trait_ref.clone());
    for violation in violations {
        match violation {
            ObjectSafetyViolation::SizedSelf => {
                tcx.sess.span_note(
                    span,
                    "the trait cannot require that `Self : Sized`");
            }

            ObjectSafetyViolation::Method(method, MethodViolationCode::ByValueSelf) => {
                tcx.sess.span_note(
                    span,
                    &format!("method `{}` has a receiver type of `Self`, \
                              which cannot be used with a trait object",
                             method.name.user_string(tcx)));
            }

            ObjectSafetyViolation::Method(method, MethodViolationCode::StaticMethod) => {
                tcx.sess.span_note(
                    span,
                    &format!("method `{}` has no receiver",
                             method.name.user_string(tcx)));
            }

            ObjectSafetyViolation::Method(method, MethodViolationCode::ReferencesSelf) => {
                tcx.sess.span_note(
                    span,
                    &format!("method `{}` references the `Self` type \
                              in its arguments or return type",
                             method.name.user_string(tcx)));
            }

            ObjectSafetyViolation::Method(method, MethodViolationCode::Generic) => {
                tcx.sess.span_note(
                    span,
                    &format!("method `{}` has generic type parameters",
                             method.name.user_string(tcx)));
            }
        }
    }
}

pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                                  span: Span,
                                                  object_trait: &ty::TyTrait<'tcx>,
                                                  referent_ty: Ty<'tcx>)
                                                  -> ty::PolyTraitRef<'tcx>
{
    // We can only make objects from sized types.
    fcx.register_builtin_bound(
        referent_ty,
        ty::BoundSized,
        traits::ObligationCause::new(span, fcx.body_id, traits::ObjectSized));

    // This is just for better error reporting. Kinda goofy. The object type stuff
    // needs some refactoring so there is a more convenient type to pass around.
    let object_trait_ty =
        ty::mk_trait(fcx.tcx(),
                     object_trait.principal.clone(),
                     object_trait.bounds.clone());

    debug!("register_object_cast_obligations: referent_ty={} object_trait_ty={}",
           referent_ty.repr(fcx.tcx()),
           object_trait_ty.repr(fcx.tcx()));

    let cause = ObligationCause::new(span,
                                     fcx.body_id,
                                     traits::ObjectCastObligation(object_trait_ty));

    // Create the obligation for casting from T to Trait.
    let object_trait_ref =
        object_trait.principal_trait_ref_with_self_ty(fcx.tcx(), referent_ty);
    let object_obligation =
        Obligation::new(cause.clone(), object_trait_ref.as_predicate());
    fcx.register_predicate(object_obligation);

    // Create additional obligations for all the various builtin
    // bounds attached to the object cast. (In other words, if the
    // object type is Foo+Send, this would create an obligation
    // for the Send check.)
    for builtin_bound in &object_trait.bounds.builtin_bounds {
        fcx.register_builtin_bound(
            referent_ty,
            builtin_bound,
            cause.clone());
    }

    // Create obligations for the projection predicates.
    let projection_bounds =
        object_trait.projection_bounds_with_self_ty(fcx.tcx(), referent_ty);
    for projection_bound in &projection_bounds {
        let projection_obligation =
            Obligation::new(cause.clone(), projection_bound.as_predicate());
        fcx.register_predicate(projection_obligation);
    }

    // Finally, check that there IS a projection predicate for every associated type.
    check_object_type_binds_all_associated_types(fcx.tcx(),
                                                 span,
                                                 object_trait);

    object_trait_ref
}

fn check_object_type_binds_all_associated_types<'tcx>(tcx: &ty::ctxt<'tcx>,
                                                      span: Span,
                                                      object_trait: &ty::TyTrait<'tcx>)
{
    let object_trait_ref =
        object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err);

    let mut associated_types: FnvHashSet<(ast::DefId, ast::Name)> =
        traits::supertraits(tcx, object_trait_ref.clone())
        .flat_map(|tr| {
            let trait_def = ty::lookup_trait_def(tcx, tr.def_id());
            trait_def.associated_type_names
                .clone()
                .into_iter()
                .map(move |associated_type_name| (tr.def_id(), associated_type_name))
        })
        .collect();

    for projection_bound in &object_trait.bounds.projection_bounds {
        let pair = (projection_bound.0.projection_ty.trait_ref.def_id,
                    projection_bound.0.projection_ty.item_name);
        associated_types.remove(&pair);
    }

    for (trait_def_id, name) in associated_types {
        span_err!(tcx.sess, span, E0191,
            "the value of the associated type `{}` (from the trait `{}`) must be specified",
                    name.user_string(tcx),
                    ty::item_path_str(tcx, trait_def_id));
    }
}

pub fn select_all_fcx_obligations_and_apply_defaults(fcx: &FnCtxt) {
    debug!("select_all_fcx_obligations_and_apply_defaults");

    select_fcx_obligations_where_possible(fcx);
    fcx.default_type_parameters();
    select_fcx_obligations_where_possible(fcx);
}

pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) {
    debug!("select_all_fcx_obligations_or_error");

    // upvar inference should have ensured that all deferred call
    // resolutions are handled by now.
    assert!(fcx.inh.deferred_call_resolutions.borrow().is_empty());

    select_all_fcx_obligations_and_apply_defaults(fcx);
    let mut fulfillment_cx = fcx.inh.fulfillment_cx.borrow_mut();
    let r = fulfillment_cx.select_all_or_error(fcx.infcx(), fcx);
    match r {
        Ok(()) => { }
        Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
    }
}

/// Select as many obligations as we can at present.
pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt)
{
    match
        fcx.inh.fulfillment_cx
        .borrow_mut()
        .select_where_possible(fcx.infcx(), fcx)
    {
        Ok(()) => { }
        Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
    }
}

/// Try to select any fcx obligation that we haven't tried yet, in an effort to improve inference.
/// You could just call `select_fcx_obligations_where_possible` except that it leads to repeated
/// work.
pub fn select_new_fcx_obligations(fcx: &FnCtxt) {
    match
        fcx.inh.fulfillment_cx
        .borrow_mut()
        .select_new_obligations(fcx.infcx(), fcx)
    {
        Ok(()) => { }
        Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
    }
}

<|endoftext|>


<commit_before>extern crate libc;
extern crate libarchive3_sys;

use self::libarchive3_sys::ffi;
use std::ffi::{CStr, CString};
use std::marker;
use std::ptr;
use std::io::{Result, Error, SeekFrom, Read, Seek, ErrorKind};
use std::error::Error as STDError;
use fs::SeekableRead;
use std::cmp::min;
use std::path::PathBuf;

pub fn initialize() {
    unsafe { libc::setlocale(libc::LC_ALL, CString::new("").unwrap().as_ptr()) };
}

struct Proxy<R: SeekableRead> {
    r: R,
    buf: Vec<u8>,
    pos: u64,
}

impl<R: SeekableRead> Proxy<R> {
    fn new(r: R) -> Proxy<R> {
        let mut v = Vec::new();
        v.resize(4096, 0);
        Proxy {
            r: r,
            buf: v,
            pos: 0,
        }
    }

    fn read(&mut self) -> Result<&[u8]> {
        let n = self.r.read(&mut self.buf[..])?;
        self.pos += n as u64;
        Ok(&self.buf[..n])
    }

    fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
        self.pos = self.r.seek(pos)?;
        Ok(self.pos)
    }
}

pub struct Archive<R: SeekableRead> {
    raw: *mut ffi::Struct_archive,
    eof: bool,
    _proxy: Box<Proxy<R>>,
}

unsafe fn set_error(raw: *mut ffi::Struct_archive, e: Error) {
    let desc = CString::new(e.description()).unwrap();
    ffi::archive_set_error(raw, e.raw_os_error().unwrap_or(libc::EIO), desc.as_ptr());
}

unsafe fn error_string(raw: *mut ffi::Struct_archive) -> String {
    CStr::from_ptr(ffi::archive_error_string(raw))
        .to_str()
        .unwrap()
        .to_string()
}

unsafe extern "C" fn read_callback<R: SeekableRead>(raw: *mut ffi::Struct_archive,
                                                    client_data: *mut libc::c_void,
                                                    buffer: *mut *const libc::c_void)
                                                    -> libc::ssize_t {
    let proxy = (client_data as *mut Proxy<R>).as_mut().unwrap();
    let err;
    match proxy.read() {
        Ok(data) => {
            *buffer = data.as_ptr() as *const libc::c_void;
            return data.len() as libc::ssize_t;
        }
        Err(e) => err = e,
    };
    set_error(raw, err);
    -1
}

unsafe extern "C" fn seek_callback<R: SeekableRead>(raw: *mut ffi::Struct_archive,
                                                    client_data: *mut libc::c_void,
                                                    offset: libc::int64_t,
                                                    whence: libc::c_int)
                                                    -> libc::int64_t {
    let proxy = (client_data as *mut Proxy<R>).as_mut().unwrap();
    let pos = match whence {
        libc::SEEK_SET => SeekFrom::Start(offset as u64),
        libc::SEEK_CUR => SeekFrom::Current(offset),
        libc::SEEK_END => SeekFrom::End(offset),
        _ => unreachable!(),
    };
    match proxy.seek(pos) {
        Ok(n) => n as libc::int64_t,
        Err(e) => {
            // correct?
            set_error(raw, e);
            -1
        }
    }
}

impl<R: SeekableRead> Archive<R> {
    pub fn new(r: R) -> Self {
        unsafe {
            let raw = ffi::archive_read_new();
            if raw.is_null() {
                panic!("oom");
            }
            if ffi::archive_read_support_format_all(raw) != ffi::ARCHIVE_OK {
                panic!("not support format");
            }
            if ffi::archive_read_support_filter_all(raw) != ffi::ARCHIVE_OK {
                panic!("not support filter");
            }
            if ffi::archive_read_set_seek_callback(raw, Some(seek_callback::<R>)) !=
               ffi::ARCHIVE_OK {
                panic!("failed to set seek");
            }
            let proxy = Box::into_raw(Box::new(Proxy::new(r)));
            if ffi::archive_read_open(raw,
                                      proxy as *mut libc::c_void,
                                      None,
                                      Some(read_callback::<R>),
                                      None) != ffi::ARCHIVE_OK {
                panic!("failed to open");
            }
            Archive {
                raw: raw,
                eof: false,
                _proxy: Box::from_raw(proxy),
            }
        }
    }

    fn next_entry_raw(&mut self) -> Option<Result<Entry>> {
        if self.eof {
            return None;
        }

        let mut entry = ptr::null_mut();
        loop {
            match unsafe { ffi::archive_read_next_header(self.raw, &mut entry) } {
                ffi::ARCHIVE_OK => break,
                ffi::ARCHIVE_WARN => {
                    warn!("archive_read_next_header: {}",
                          unsafe { error_string(self.raw) });
                    break;
                }
                ffi::ARCHIVE_EOF => {
                    self.eof = true;
                    return None;
                }
                ffi::ARCHIVE_RETRY => {
                    // failed but retryable.
                    warn!("archive_read_next_header: {}, retry.",
                          unsafe { error_string(self.raw) });
                    continue;
                }
                ffi::ARCHIVE_FATAL => {
                    return Some(Err(Error::new(ErrorKind::Other,
                                               unsafe { error_string(self.raw) })));
                }
                _ => unreachable!(),
            }

        }
        Some(Ok(Entry::new(entry)))
    }

    pub fn next_entry<'a>(&'a mut self) -> Option<Result<RefEntry<'a, R>>> {
        self.next_entry_raw()
            .map(|r| r.map(|e| RefEntry::new(e)))
    }

    pub fn find_open<P>(mut self, p: P) -> Option<Result<Reader<R>>>
        where P: Fn(&Entry) -> bool
    {
        loop {
            match self.next_entry_raw() {
                Some(Ok(e)) => {
                    if p(&e) {
                        break;
                    }
                }
                Some(Err(e)) => return Some(Err(e)),
                None => return None,
            }
        }
        Some(Ok(Reader::new(self)))
    }
}

impl<R: SeekableRead> Drop for Archive<R> {
    fn drop(&mut self) {
        unsafe { ffi::archive_read_free(self.raw) };
    }
}

pub struct Reader<R: SeekableRead> {
    a: Archive<R>,
    buf: *const libc::c_void,
    read_pos: usize,
    buf_size: libc::size_t,
    offset: libc::off_t,
    eof: bool,
}

impl<R: SeekableRead> Reader<R> {
    fn new(a: Archive<R>) -> Reader<R> {
        Reader {
            a: a,
            buf: ptr::null(),
            read_pos: 0,
            buf_size: 0,
            offset: 0,
            eof: false,
        }
    }

    fn fill_gap(&mut self, buf: &mut [u8]) -> usize {
        if self.read_pos < self.offset as usize {
            let l = min(buf.len(), (self.offset as usize) - self.read_pos);
            for x in &mut buf[..l] {
                *x = 0;
            }
            self.read_pos += l;
            return l;
        }
        0
    }

    fn read_data_block(&mut self) -> Result<()> {
        if self.eof {
            return Ok(());
        }

        while self.offset as usize + self.buf_size as usize <= self.read_pos {
            match unsafe {
                      ffi::archive_read_data_block(self.a.raw,
                                                   &mut self.buf,
                                                   &mut self.buf_size,
                                                   &mut self.offset)
                  } {
                ffi::ARCHIVE_OK => continue,
                ffi::ARCHIVE_WARN => {
                    warn!("archive_read_data_block: {}",
                          unsafe { error_string(self.a.raw) });
                    continue;
                }
                ffi::ARCHIVE_EOF => {
                    self.eof = true;
                    return Ok(());
                }
                ffi::ARCHIVE_RETRY => {
                    // failed but retryable.
                    warn!("archive_read_data_block: {}, retry",
                          unsafe { error_string(self.a.raw) });
                    continue;
                }
                ffi::ARCHIVE_FATAL => {
                    return Err(Error::new(ErrorKind::Other, unsafe { error_string(self.a.raw) }));
                }
                _ => unreachable!(),
            }
        }
        Ok(())
    }
}

impl<R: SeekableRead> Read for Reader<R> {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        self.read_data_block()?;
        let n = self.fill_gap(buf);
        if n > 0 {
            return Ok(n);
        }
        let begin = self.read_pos - self.offset as usize;
        let l = min(buf.len(), self.buf_size - begin);
        unsafe {
            let p = (self.buf as *const u8).offset(begin as isize);
            ptr::copy_nonoverlapping(p, buf.as_mut_ptr(), l);
        }
        self.read_pos += l;
        Ok(l)
    }
}

impl<R: SeekableRead> Seek for Reader<R> {
    fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
        match pos {
            SeekFrom::Start(n) => self.read_pos = n as usize,
            SeekFrom::End(_) => unimplemented!(),
            SeekFrom::Current(n) => self.read_pos += n as usize,
        }
        Ok(self.read_pos as u64)
    }
}

pub struct Entry {
    entry: *mut ffi::Struct_archive_entry,
}

impl Entry {
    fn new(entry: *mut ffi::Struct_archive_entry) -> Entry {
        Entry { entry: entry }
    }

    pub fn pathname(&self) -> PathBuf {
        let c_str = unsafe { CStr::from_ptr(ffi::archive_entry_pathname(self.entry)) };
        PathBuf::from(c_str.to_string_lossy().as_ref())
    }

    pub fn size(&self) -> libc::int64_t {
        unsafe { ffi::archive_entry_size(self.entry) }
    }

    pub fn filetype(&self) -> libc::mode_t {
        unsafe { ffi::archive_entry_filetype(self.entry) }
    }
}

pub struct RefEntry<'a, R: SeekableRead + 'a> {
    e: Entry,
    _m: marker::PhantomData<&'a R>,
}

impl<'a, R: SeekableRead> RefEntry<'a, R> {
    fn new(e: Entry) -> RefEntry<'a, R> {
        RefEntry {
            e: e,
            _m: marker::PhantomData,
        }
    }

    pub fn pathname(&self) -> PathBuf {
        self.e.pathname()
    }

    pub fn size(&self) -> libc::int64_t {
        self.e.size()
    }

    pub fn filetype(&self) -> libc::mode_t {
        self.e.filetype()
    }
}
<commit_msg>check null<commit_after>extern crate libc;
extern crate libarchive3_sys;

use self::libarchive3_sys::ffi;
use std::ffi::{CStr, CString};
use std::marker;
use std::ptr;
use std::io::{Result, Error, SeekFrom, Read, Seek, ErrorKind};
use std::error::Error as STDError;
use fs::SeekableRead;
use std::cmp::min;
use std::path::PathBuf;

pub fn initialize() {
    unsafe { libc::setlocale(libc::LC_ALL, CString::new("").unwrap().as_ptr()) };
}

struct Proxy<R: SeekableRead> {
    r: R,
    buf: Vec<u8>,
    pos: u64,
}

impl<R: SeekableRead> Proxy<R> {
    fn new(r: R) -> Proxy<R> {
        let mut v = Vec::new();
        v.resize(4096, 0);
        Proxy {
            r: r,
            buf: v,
            pos: 0,
        }
    }

    fn read(&mut self) -> Result<&[u8]> {
        let n = self.r.read(&mut self.buf[..])?;
        self.pos += n as u64;
        Ok(&self.buf[..n])
    }

    fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
        self.pos = self.r.seek(pos)?;
        Ok(self.pos)
    }
}

pub struct Archive<R: SeekableRead> {
    raw: *mut ffi::Struct_archive,
    eof: bool,
    _proxy: Box<Proxy<R>>,
}

unsafe fn set_error(raw: *mut ffi::Struct_archive, e: Error) {
    let desc = CString::new(e.description()).unwrap();
    ffi::archive_set_error(raw, e.raw_os_error().unwrap_or(libc::EIO), desc.as_ptr());
}

unsafe fn error_string(raw: *mut ffi::Struct_archive) -> String {
    let p = ffi::archive_error_string(raw);
    if p.is_null() {
        "unknown".to_string()
    } else {
        CStr::from_ptr(p).to_str().unwrap().to_string()
    }
}

unsafe extern "C" fn read_callback<R: SeekableRead>(raw: *mut ffi::Struct_archive,
                                                    client_data: *mut libc::c_void,
                                                    buffer: *mut *const libc::c_void)
                                                    -> libc::ssize_t {
    let proxy = (client_data as *mut Proxy<R>).as_mut().unwrap();
    let err;
    match proxy.read() {
        Ok(data) => {
            *buffer = data.as_ptr() as *const libc::c_void;
            return data.len() as libc::ssize_t;
        }
        Err(e) => err = e,
    };
    set_error(raw, err);
    -1
}

unsafe extern "C" fn seek_callback<R: SeekableRead>(raw: *mut ffi::Struct_archive,
                                                    client_data: *mut libc::c_void,
                                                    offset: libc::int64_t,
                                                    whence: libc::c_int)
                                                    -> libc::int64_t {
    let proxy = (client_data as *mut Proxy<R>).as_mut().unwrap();
    let pos = match whence {
        libc::SEEK_SET => SeekFrom::Start(offset as u64),
        libc::SEEK_CUR => SeekFrom::Current(offset),
        libc::SEEK_END => SeekFrom::End(offset),
        _ => unreachable!(),
    };
    match proxy.seek(pos) {
        Ok(n) => n as libc::int64_t,
        Err(e) => {
            // correct?
            set_error(raw, e);
            -1
        }
    }
}

impl<R: SeekableRead> Archive<R> {
    pub fn new(r: R) -> Self {
        unsafe {
            let raw = ffi::archive_read_new();
            if raw.is_null() {
                panic!("oom");
            }
            if ffi::archive_read_support_format_all(raw) != ffi::ARCHIVE_OK {
                panic!("not support format");
            }
            if ffi::archive_read_support_filter_all(raw) != ffi::ARCHIVE_OK {
                panic!("not support filter");
            }
            if ffi::archive_read_set_seek_callback(raw, Some(seek_callback::<R>)) !=
               ffi::ARCHIVE_OK {
                panic!("failed to set seek");
            }
            let proxy = Box::into_raw(Box::new(Proxy::new(r)));
            if ffi::archive_read_open(raw,
                                      proxy as *mut libc::c_void,
                                      None,
                                      Some(read_callback::<R>),
                                      None) != ffi::ARCHIVE_OK {
                panic!("failed to open");
            }
            Archive {
                raw: raw,
                eof: false,
                _proxy: Box::from_raw(proxy),
            }
        }
    }

    fn next_entry_raw(&mut self) -> Option<Result<Entry>> {
        if self.eof {
            return None;
        }

        let mut entry = ptr::null_mut();
        loop {
            match unsafe { ffi::archive_read_next_header(self.raw, &mut entry) } {
                ffi::ARCHIVE_OK => break,
                ffi::ARCHIVE_WARN => {
                    warn!("archive_read_next_header: {}",
                          unsafe { error_string(self.raw) });
                    break;
                }
                ffi::ARCHIVE_EOF => {
                    self.eof = true;
                    return None;
                }
                ffi::ARCHIVE_RETRY => {
                    // failed but retryable.
                    warn!("archive_read_next_header: {}, retry.",
                          unsafe { error_string(self.raw) });
                    continue;
                }
                ffi::ARCHIVE_FATAL => {
                    return Some(Err(Error::new(ErrorKind::Other,
                                               unsafe { error_string(self.raw) })));
                }
                _ => unreachable!(),
            }

        }
        Some(Ok(Entry::new(entry)))
    }

    pub fn next_entry<'a>(&'a mut self) -> Option<Result<RefEntry<'a, R>>> {
        self.next_entry_raw()
            .map(|r| r.map(|e| RefEntry::new(e)))
    }

    pub fn find_open<P>(mut self, p: P) -> Option<Result<Reader<R>>>
        where P: Fn(&Entry) -> bool
    {
        loop {
            match self.next_entry_raw() {
                Some(Ok(e)) => {
                    if p(&e) {
                        break;
                    }
                }
                Some(Err(e)) => return Some(Err(e)),
                None => return None,
            }
        }
        Some(Ok(Reader::new(self)))
    }
}

impl<R: SeekableRead> Drop for Archive<R> {
    fn drop(&mut self) {
        unsafe { ffi::archive_read_free(self.raw) };
    }
}

pub struct Reader<R: SeekableRead> {
    a: Archive<R>,
    buf: *const libc::c_void,
    read_pos: usize,
    buf_size: libc::size_t,
    offset: libc::off_t,
    eof: bool,
}

impl<R: SeekableRead> Reader<R> {
    fn new(a: Archive<R>) -> Reader<R> {
        Reader {
            a: a,
            buf: ptr::null(),
            read_pos: 0,
            buf_size: 0,
            offset: 0,
            eof: false,
        }
    }

    fn fill_gap(&mut self, buf: &mut [u8]) -> usize {
        if self.read_pos < self.offset as usize {
            let l = min(buf.len(), (self.offset as usize) - self.read_pos);
            for x in &mut buf[..l] {
                *x = 0;
            }
            self.read_pos += l;
            return l;
        }
        0
    }

    fn read_data_block(&mut self) -> Result<()> {
        if self.eof {
            return Ok(());
        }

        while self.offset as usize + self.buf_size as usize <= self.read_pos {
            match unsafe {
                      ffi::archive_read_data_block(self.a.raw,
                                                   &mut self.buf,
                                                   &mut self.buf_size,
                                                   &mut self.offset)
                  } {
                ffi::ARCHIVE_OK => continue,
                ffi::ARCHIVE_WARN => {
                    warn!("archive_read_data_block: {}",
                          unsafe { error_string(self.a.raw) });
                    continue;
                }
                ffi::ARCHIVE_EOF => {
                    self.eof = true;
                    return Ok(());
                }
                ffi::ARCHIVE_RETRY => {
                    // failed but retryable.
                    warn!("archive_read_data_block: {}, retry",
                          unsafe { error_string(self.a.raw) });
                    continue;
                }
                ffi::ARCHIVE_FATAL => {
                    return Err(Error::new(ErrorKind::Other, unsafe { error_string(self.a.raw) }));
                }
                _ => unreachable!(),
            }
        }
        Ok(())
    }
}

impl<R: SeekableRead> Read for Reader<R> {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        self.read_data_block()?;
        let n = self.fill_gap(buf);
        if n > 0 {
            return Ok(n);
        }
        let begin = self.read_pos - self.offset as usize;
        let l = min(buf.len(), self.buf_size - begin);
        unsafe {
            let p = (self.buf as *const u8).offset(begin as isize);
            ptr::copy_nonoverlapping(p, buf.as_mut_ptr(), l);
        }
        self.read_pos += l;
        Ok(l)
    }
}

impl<R: SeekableRead> Seek for Reader<R> {
    fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
        match pos {
            SeekFrom::Start(n) => self.read_pos = n as usize,
            SeekFrom::End(_) => unimplemented!(),
            SeekFrom::Current(n) => self.read_pos += n as usize,
        }
        Ok(self.read_pos as u64)
    }
}

pub struct Entry {
    entry: *mut ffi::Struct_archive_entry,
}

impl Entry {
    fn new(entry: *mut ffi::Struct_archive_entry) -> Entry {
        Entry { entry: entry }
    }

    pub fn pathname(&self) -> PathBuf {
        let c_str = unsafe { CStr::from_ptr(ffi::archive_entry_pathname(self.entry)) };
        PathBuf::from(c_str.to_string_lossy().as_ref())
    }

    pub fn size(&self) -> libc::int64_t {
        unsafe { ffi::archive_entry_size(self.entry) }
    }

    pub fn filetype(&self) -> libc::mode_t {
        unsafe { ffi::archive_entry_filetype(self.entry) }
    }
}

pub struct RefEntry<'a, R: SeekableRead + 'a> {
    e: Entry,
    _m: marker::PhantomData<&'a R>,
}

impl<'a, R: SeekableRead> RefEntry<'a, R> {
    fn new(e: Entry) -> RefEntry<'a, R> {
        RefEntry {
            e: e,
            _m: marker::PhantomData,
        }
    }

    pub fn pathname(&self) -> PathBuf {
        self.e.pathname()
    }

    pub fn size(&self) -> libc::int64_t {
        self.e.size()
    }

    pub fn filetype(&self) -> libc::mode_t {
        self.e.filetype()
    }
}
<|endoftext|>


<commit_before>//! Treiber stacks.

use std::sync::atomic;
use std::ptr;
use {Atomic, Guard};

/// A Treiber stack.
///
/// Treiber stacks are one way to implement concurrent LIFO stack.
///
/// Treiber stacks builds on linked lists. They are lock-free and non-blocking. It can be compared
/// to transactional memory in that it repeats operations, if another thread changes it while.
///
/// The ABA problem is of course addressed through the API of this crate.
pub struct Treiber<T> {
    /// The head node.
    head: Atomic<Node<T>>,
}

impl<T> Drop for Treiber<T> {
    fn drop(&mut self) {
        // Due to the nature of Treiber stacks, there are no active guards of things within the
        // structure. They're all gone, thus we can safely mess with the inner structure.

        unsafe {
            let ptr = self.head.get_inner_mut().get_mut();

            if !ptr.is_null() {
                // Call destructors on the stack.
                (**ptr).destroy();
                // Finally deallocate the pointer itself.
                drop(Box::from_raw(*ptr));
                // Set it to null to prevent `Atomic`'s destructor from running.
                *ptr = ptr::null_mut();
            }
        }
    }
}

impl<T> Treiber<T> {
    /// Create a new, empty Treiber stack.
    pub fn new() -> Treiber<T> {
        Treiber {
            head: Atomic::default(),
        }
    }

    /// Pop an item from the stack.
    // TODO: Change this return type.
    pub fn pop(&self) -> Option<Guard<T>> {
        // TODO: Use `catch {}` here when it lands.
        // Read the head snapshot.
        let mut snapshot = self.head.load(atomic::Ordering::Acquire);

        // Unless the head snapshot is `None`, try to replace it with the tail.
        while let Some(node) = snapshot {
            // Attempt to replace the head with the tail of the head.
            match unsafe {
                self.head.compare_and_swap_raw(
                    node.as_raw(),
                    node.next as *mut Node<T>,
                    atomic::Ordering::Release,
                )
            } {
                // It succeeded; return the item.
                Ok(_) => return Some(node.map(|x| &x.item)),
                // It failed, update the head snapshot and continue.
                Err(new) => snapshot = new,
            }
        }

        // As the head was empty, there is nothing to pop.
        None
    }

    /// Push an item to the stack.
    pub fn push(&self, item: T)
    where T: 'static {
        // Load the head snapshot.
        let mut snapshot = self.head.load(atomic::Ordering::Relaxed);
        let mut snapshot_ptr: Option<*const Node<T>>;

        // TODO: Use `catch {}` here when it lands.
        // Construct a node, which will be the new head.
        let mut node = Box::new(Node {
            item: item,
            // Placeholder; we will replace it with an actual value in the loop.
            next: ptr::null(),
        });

        loop {
            // Derive the nullable snapshot pointer from the head snapshot.
            snapshot_ptr = snapshot.as_ref().map(Guard::as_raw);
            // Construct the next-pointer of the new node from the head snapshot.
            node.next = snapshot_ptr.unwrap_or(ptr::null());

            // TODO: This should be something that ignores the guard creation when the CAS
            //       succeeds, because it's expensive to do and not used anyway. It should be easy
            //       enough to implement, but I am struggling to come up with a good name for the
            //       method.

            // CAS from the read pointer to the new head.
            match self.head.compare_and_swap(snapshot_ptr, Some(node), atomic::Ordering::Release) {
                // If it succeeds, the item has been pushed.
                Ok(_) => break,
                // If it fails, we will retry the CAS with updated values.
                Err((new_head, Some(node2))) => {
                    // Update the head snapshot.
                    snapshot = new_head;
                    // Put the box we gave back to the variable where it belongs.
                    node = node2;
                },
                // This should never be reached as we gave an argument which was unconditionally
                // `Some`.
                _ => unreachable!(),
            }
        }
    }
}

/// A node in the stack.
struct Node<T> {
    /// The data this node holds.
    item: T,
    /// The next node.
    next: *const Node<T>,
}

impl<T> Node<T> {
    /// Destroy the node and its precessors.
    ///
    /// This doesn't call the destructor on `T`.
    ///
    /// # Safety
    ///
    /// As this can be called multiple times, it is marked unsafe.
    unsafe fn destroy(&mut self) {
        // FIXME: Since this is recursive (and although it is likely optimized out), there might be
        //        cases where this leads to stack overflow, given correct compilation flags and
        //        sufficiently many elements.

        // Recursively drop the next node, if it exists.
        if !self.next.is_null() {
            drop(Box::from_raw(self.next as *mut Node<T>));
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::thread;
    use std::sync::Arc;
    use std::sync::atomic::AtomicUsize;

    #[derive(Clone)]
    struct Dropper {
        d: Arc<AtomicUsize>,
    }

    impl Drop for Dropper {
        fn drop(&mut self) {
            self.d.fetch_add(1, atomic::Ordering::Relaxed);
        }
    }

    #[test]
    fn simple1() {
        let stack = Treiber::new();

        stack.push(1);
        stack.push(200);
        stack.push(44);

        assert_eq!(*stack.pop().unwrap(), 44);
        assert_eq!(*stack.pop().unwrap(), 200);
        assert_eq!(*stack.pop().unwrap(), 1);
        assert!(stack.pop().is_none());

        ::gc();
    }

    #[test]
    fn simple2() {
        let stack = Treiber::new();

        for _ in 0..16 {
            stack.push(1);
            stack.push(200);
            stack.push(44);

            assert_eq!(*stack.pop().unwrap(), 44);
            assert_eq!(*stack.pop().unwrap(), 200);
            stack.push(20000);

            assert_eq!(*stack.pop().unwrap(), 20000);
            assert_eq!(*stack.pop().unwrap(), 1);

            assert!(stack.pop().is_none());
            assert!(stack.pop().is_none());
            assert!(stack.pop().is_none());
            assert!(stack.pop().is_none());
        }

        ::gc();
    }

    #[test]
    fn simple3() {
        let stack = Treiber::new();

        for i in 0..10000 {
            stack.push(i);
        }

        for i in (0..10000).rev() {
            assert_eq!(*stack.pop().unwrap(), i);
        }

        for i in 0..10000 {
            stack.push(i);
        }

        for i in (0..10000).rev() {
            assert_eq!(*stack.pop().unwrap(), i);
        }

        assert!(stack.pop().is_none());
        assert!(stack.pop().is_none());
        assert!(stack.pop().is_none());
        assert!(stack.pop().is_none());
    }

    #[test]
    fn push_pop() {
        let stack = Arc::new(Treiber::new());
        let mut j = Vec::new();
        for _ in 0..16 {
            let s = stack.clone();
            j.push(thread::spawn(move || {
                for _ in 0..10_000_000 {
                    s.push(23);
                    assert_eq!(*s.pop().unwrap(), 23);
                }
            }));
        }

        for i in j {
            i.join().unwrap();
        }
    }

    #[test]
    fn increment() {
        let stack = Arc::new(Treiber::<u64>::new());
        stack.push(0);
        let mut j = Vec::new();

        // 16 times, we add the numbers from 0 to 1000 to the only element in the stack.
        for _ in 0..16 {
            let s = stack.clone();
            j.push(thread::spawn(move || {
                for n in 0..1001 {
                    loop {
                        if let Some(x) = s.pop() {
                            s.push(*x + n);
                            break;
                        }
                    }
                }
            }));
        }

        for i in j {
            i.join().unwrap();
        }

        assert_eq!(*stack.pop().unwrap(), 16 * 1000 * 1001 / 2);
    }

    #[test]
    fn sum() {
        let stack = Arc::new(Treiber::<i64>::new());
        let mut j = Vec::new();

        for _ in 0..1000 {
            stack.push(10);
        }

        // We preserve the sum of the stack's elements.
        for _ in 0..16 {
            let s = stack.clone();
            j.push(thread::spawn(move || {
                for _ in 0..100000 {
                    loop {
                        if let Some(a) = s.pop() {
                            loop {
                                if let Some(b) = s.pop() {
                                    s.push(*a + 1);
                                    s.push(*b - 1);

                                    break;
                                }
                            }

                            break;
                        }
                    }
                }
            }));
        }

        for i in j {
            i.join().unwrap();
        }

        let mut sum = 0;
        while let Some(x) = stack.pop() {
            sum += *x;
        }
        assert_eq!(sum, 10000);
    }

    #[test]
    fn drop() {
        let drops = Arc::new(AtomicUsize::default());
        let stack = Arc::new(Treiber::new());

        let d = Dropper {
            d: drops.clone(),
        };

        let mut j = Vec::new();
        for _ in 0..16 {
            let d = d.clone();
            let stack = stack.clone();

            j.push(thread::spawn(move || {
                for _ in 0..20 {
                    stack.push(d.clone());
                }

                stack.pop();
                stack.pop();
            }))
        }

        for i in j {
            i.join().unwrap();
        }

        ::gc();
        // The 16 are for the `d` variable in the loop above.
        assert_eq!(drops.load(atomic::Ordering::Relaxed), 32 + 16);

        // Drop the last arc.
        let _ = stack;
        ::gc();

        assert_eq!(drops.load(atomic::Ordering::Relaxed), 200 + 16);
    }
}
<commit_msg>Add test for panicking in destructor of `conc::sync::Treiber`.<commit_after>//! Treiber stacks.

use std::sync::atomic;
use std::ptr;
use {Atomic, Guard};

/// A Treiber stack.
///
/// Treiber stacks are one way to implement concurrent LIFO stack.
///
/// Treiber stacks builds on linked lists. They are lock-free and non-blocking. It can be compared
/// to transactional memory in that it repeats operations, if another thread changes it while.
///
/// The ABA problem is of course addressed through the API of this crate.
pub struct Treiber<T> {
    /// The head node.
    head: Atomic<Node<T>>,
}

impl<T> Drop for Treiber<T> {
    fn drop(&mut self) {
        // Due to the nature of Treiber stacks, there are no active guards of things within the
        // structure. They're all gone, thus we can safely mess with the inner structure.

        unsafe {
            let ptr = self.head.get_inner_mut().get_mut();

            if !ptr.is_null() {
                // Call destructors on the stack.
                (**ptr).destroy();
                // Finally deallocate the pointer itself.
                // TODO: Figure out if it is sound if this destructor panics.
                drop(Box::from_raw(*ptr));
                // Set it to null to prevent `Atomic`'s destructor from running.
                *ptr = ptr::null_mut();
            }
        }
    }
}

impl<T> Treiber<T> {
    /// Create a new, empty Treiber stack.
    pub fn new() -> Treiber<T> {
        Treiber {
            head: Atomic::default(),
        }
    }

    /// Pop an item from the stack.
    // TODO: Change this return type.
    pub fn pop(&self) -> Option<Guard<T>> {
        // TODO: Use `catch {}` here when it lands.
        // Read the head snapshot.
        let mut snapshot = self.head.load(atomic::Ordering::Acquire);

        // Unless the head snapshot is `None`, try to replace it with the tail.
        while let Some(node) = snapshot {
            // Attempt to replace the head with the tail of the head.
            match unsafe {
                self.head.compare_and_swap_raw(
                    node.as_raw(),
                    node.next as *mut Node<T>,
                    atomic::Ordering::Release,
                )
            } {
                // It succeeded; return the item.
                Ok(_) => return Some(node.map(|x| &x.item)),
                // It failed, update the head snapshot and continue.
                Err(new) => snapshot = new,
            }
        }

        // As the head was empty, there is nothing to pop.
        None
    }

    /// Push an item to the stack.
    pub fn push(&self, item: T)
    where T: 'static {
        // Load the head snapshot.
        let mut snapshot = self.head.load(atomic::Ordering::Relaxed);
        let mut snapshot_ptr: Option<*const Node<T>>;

        // TODO: Use `catch {}` here when it lands.
        // Construct a node, which will be the new head.
        let mut node = Box::new(Node {
            item: item,
            // Placeholder; we will replace it with an actual value in the loop.
            next: ptr::null(),
        });

        loop {
            // Derive the nullable snapshot pointer from the head snapshot.
            snapshot_ptr = snapshot.as_ref().map(Guard::as_raw);
            // Construct the next-pointer of the new node from the head snapshot.
            node.next = snapshot_ptr.unwrap_or(ptr::null());

            // TODO: This should be something that ignores the guard creation when the CAS
            //       succeeds, because it's expensive to do and not used anyway. It should be easy
            //       enough to implement, but I am struggling to come up with a good name for the
            //       method.

            // CAS from the read pointer to the new head.
            match self.head.compare_and_swap(snapshot_ptr, Some(node), atomic::Ordering::Release) {
                // If it succeeds, the item has been pushed.
                Ok(_) => break,
                // If it fails, we will retry the CAS with updated values.
                Err((new_head, Some(node2))) => {
                    // Update the head snapshot.
                    snapshot = new_head;
                    // Put the box we gave back to the variable where it belongs.
                    node = node2;
                },
                // This should never be reached as we gave an argument which was unconditionally
                // `Some`.
                _ => unreachable!(),
            }
        }
    }
}

/// A node in the stack.
struct Node<T> {
    /// The data this node holds.
    item: T,
    /// The next node.
    next: *const Node<T>,
}

impl<T> Node<T> {
    /// Destroy the node and its precessors.
    ///
    /// This doesn't call the destructor on `T`.
    ///
    /// # Safety
    ///
    /// As this can be called multiple times, it is marked unsafe.
    unsafe fn destroy(&mut self) {
        // FIXME: Since this is recursive (and although it is likely optimized out), there might be
        //        cases where this leads to stack overflow, given correct compilation flags and
        //        sufficiently many elements.

        // Recursively drop the next node, if it exists.
        if !self.next.is_null() {
            drop(Box::from_raw(self.next as *mut Node<T>));
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::thread;
    use std::sync::Arc;
    use std::sync::atomic::AtomicUsize;

    #[derive(Clone)]
    struct Dropper {
        d: Arc<AtomicUsize>,
    }

    impl Drop for Dropper {
        fn drop(&mut self) {
            self.d.fetch_add(1, atomic::Ordering::Relaxed);
        }
    }

    #[test]
    fn empty() {
        for _ in 0..1000 {
            let b = Box::new(20);
            Treiber::<u8>::new();
            assert_eq!(*b, 20);
        }
    }

    #[test]
    fn simple1() {
        let stack = Treiber::new();

        stack.push(1);
        stack.push(200);
        stack.push(44);

        assert_eq!(*stack.pop().unwrap(), 44);
        assert_eq!(*stack.pop().unwrap(), 200);
        assert_eq!(*stack.pop().unwrap(), 1);
        assert!(stack.pop().is_none());

        ::gc();
    }

    #[test]
    fn simple2() {
        let stack = Treiber::new();

        for _ in 0..16 {
            stack.push(1);
            stack.push(200);
            stack.push(44);

            assert_eq!(*stack.pop().unwrap(), 44);
            assert_eq!(*stack.pop().unwrap(), 200);
            stack.push(20000);

            assert_eq!(*stack.pop().unwrap(), 20000);
            assert_eq!(*stack.pop().unwrap(), 1);

            assert!(stack.pop().is_none());
            assert!(stack.pop().is_none());
            assert!(stack.pop().is_none());
            assert!(stack.pop().is_none());
        }

        ::gc();
    }

    #[test]
    fn simple3() {
        let stack = Treiber::new();

        for i in 0..10000 {
            stack.push(i);
        }

        for i in (0..10000).rev() {
            assert_eq!(*stack.pop().unwrap(), i);
        }

        for i in 0..10000 {
            stack.push(i);
        }

        for i in (0..10000).rev() {
            assert_eq!(*stack.pop().unwrap(), i);
        }

        assert!(stack.pop().is_none());
        assert!(stack.pop().is_none());
        assert!(stack.pop().is_none());
        assert!(stack.pop().is_none());
    }

    #[test]
    fn push_pop() {
        let stack = Arc::new(Treiber::new());
        let mut j = Vec::new();
        for _ in 0..16 {
            let s = stack.clone();
            j.push(thread::spawn(move || {
                for _ in 0..10_000_000 {
                    s.push(23);
                    assert_eq!(*s.pop().unwrap(), 23);
                }
            }));
        }

        for i in j {
            i.join().unwrap();
        }
    }

    #[test]
    fn increment() {
        let stack = Arc::new(Treiber::<u64>::new());
        stack.push(0);
        let mut j = Vec::new();

        // 16 times, we add the numbers from 0 to 1000 to the only element in the stack.
        for _ in 0..16 {
            let s = stack.clone();
            j.push(thread::spawn(move || {
                for n in 0..1001 {
                    loop {
                        if let Some(x) = s.pop() {
                            s.push(*x + n);
                            break;
                        }
                    }
                }
            }));
        }

        for i in j {
            i.join().unwrap();
        }

        assert_eq!(*stack.pop().unwrap(), 16 * 1000 * 1001 / 2);
    }

    #[test]
    fn sum() {
        let stack = Arc::new(Treiber::<i64>::new());
        let mut j = Vec::new();

        for _ in 0..1000 {
            stack.push(10);
        }

        // We preserve the sum of the stack's elements.
        for _ in 0..16 {
            let s = stack.clone();
            j.push(thread::spawn(move || {
                for _ in 0..100000 {
                    loop {
                        if let Some(a) = s.pop() {
                            loop {
                                if let Some(b) = s.pop() {
                                    s.push(*a + 1);
                                    s.push(*b - 1);

                                    break;
                                }
                            }

                            break;
                        }
                    }
                }
            }));
        }

        for i in j {
            i.join().unwrap();
        }

        let mut sum = 0;
        while let Some(x) = stack.pop() {
            sum += *x;
        }
        assert_eq!(sum, 10000);
    }

    #[test]
    fn drop() {
        let drops = Arc::new(AtomicUsize::default());
        let stack = Arc::new(Treiber::new());

        let d = Dropper {
            d: drops.clone(),
        };

        let mut j = Vec::new();
        for _ in 0..16 {
            let d = d.clone();
            let stack = stack.clone();

            j.push(thread::spawn(move || {
                for _ in 0..20 {
                    stack.push(d.clone());
                }

                stack.pop();
                stack.pop();
            }))
        }

        for i in j {
            i.join().unwrap();
        }

        ::gc();
        // The 16 are for the `d` variable in the loop above.
        assert_eq!(drops.load(atomic::Ordering::Relaxed), 32 + 16);

        // Drop the last arc.
        let _ = stack;
        ::gc();

        assert_eq!(drops.load(atomic::Ordering::Relaxed), 200 + 16);
    }

    #[test]
    #[should_panic]
    fn panic_in_dtor() {
        struct A;
        impl Drop for A {
            fn drop(&mut self) {
                panic!();
            }
        }

        let stack = Treiber::new();
        stack.push(Box::new(A));
        stack.push(Box::new(A));
        stack.push(Box::new(A));
    }
}
<|endoftext|>