<commit_before>use core::fmt::Debug;
use std::any::Any;
use std::mem;

use progress::Timestamp;
use progress::count_map::CountMap;

use communication::Observer;
// use communication::observer::{BufferedObserver, OutputPortFlattener, BroadcastObserver};

use std::rc::Rc;
use std::cell::RefCell;

pub trait Data : Clone+Send+Debug+Any { }
impl<T: Clone+Send+Debug+Any> Data for T { }

// TODO : All the buffering, cloning, and dropping makes pandas sad.
// TODO : It should be easy enough to Rc<RefCell<Vec<Vec<D>>>> things up.
// TODO : OutputPort can do the buffering, broadcasting, and collecting vecs.
// pub struct OutputPort<T: Timestamp, D: Data> {
//     shared: BufferedObserver<D, Rc<RefCell<BroadcastObserver<Box<Observer<Time=T, Data=Vec<D>>>>>>>,
// }
//
// impl<T: Timestamp, D: Data> Observer for OutputPort<T, D> {
//     type Time = T;
//     type Data = D;
//     #[inline(always)] fn open(&mut self, time: &T) { self.shared.open(time); }
//     #[inline(always)] fn show(&mut self, data: &D) { self.shared.show(data); }
//     #[inline(always)] fn give(&mut self, data:  D) { self.shared.give(data); }
//     #[inline(always)] fn shut(&mut self, time: &T) { self.shared.shut(time); }
// }
//
// impl<T: Timestamp, D: Data> OutputPort<T, D> {
//     pub fn new() -> OutputPort<T, D> {
//         OutputPort { shared: BufferedObserver::new(256, Rc::new(RefCell::new(BroadcastObserver::new()))) }
//     }
//     pub fn add_observer<O: Observer<Time=T, Data=D>+'static>(&self, observer: O) {
//         self.shared.inner().borrow_mut().add(Box::new(OutputPortFlattener::new(observer)));
//     }
// }

pub struct OutputPort<T: Timestamp, D: Data> {
    limit:  usize,
    buffer: Vec<D>,
    shared: Rc<RefCell<Vec<Box<Observer<Time=T,Data=Vec<D>>>>>>,
    stash:  Rc<RefCell<Vec<Vec<D>>>>,
}

impl<T: Timestamp, D: Data> Observer for OutputPort<T, D> {
    type Time = T;
    type Data = D;
    #[inline(always)] fn open(&mut self, time: &T) {
        for observer in self.shared.borrow_mut().iter_mut() {
            observer.open(time);
        }
    }
    #[inline(always)] fn show(&mut self, data: &D) { self.give(data.clone()); }
    #[inline(always)] fn give(&mut self, data:  D) {
        self.buffer.push(data);
        if self.buffer.len() > self.limit {
            let mut observers = self.shared.borrow_mut();
            // let mut supply = self.stash.borrow_mut();
            for index in (0..observers.len()) {
                let data = mem::replace(&mut self.buffer, self.stash.borrow_mut().pop().unwrap_or(Vec::new()));
                if index < observers.len() - 1 { self.buffer.push_all(&data); }
                observers[index].give(data);
            }
        }
    }
    #[inline(always)] fn shut(&mut self, time: &T) {
        if self.buffer.len() > 0 {
            let mut observers = self.shared.borrow_mut();
            // let mut supply = ;
            for index in (0..observers.len()) {
                let data = mem::replace(&mut self.buffer, self.stash.borrow_mut().pop().unwrap_or(Vec::new()));
                if index < observers.len() - 1 { self.buffer.push_all(&data); }
                observers[index].give(data);
            }
        }

        for observer in self.shared.borrow_mut().iter_mut() {
            observer.shut(time);
        }
    }
}

impl<T: Timestamp, D: Data> OutputPort<T, D> {
    pub fn new() -> OutputPort<T, D> {
        let limit = 256;
        OutputPort {
            limit:  limit,
            buffer: Vec::with_capacity(limit),
            shared: Rc::new(RefCell::new(Vec::new())),
            stash:  Rc::new(RefCell::new(Vec::new())),
        }
            // shared: BufferedObserver::new(256, Rc::new(RefCell::new(BroadcastObserver::new()))) }
    }
    pub fn add_observer<O: Observer<Time=T, Data=D>+'static>(&self, observer: O) {
        self.shared.borrow_mut().push(Box::new(OutputPortFlattener::new(observer, self.stash.clone())));
    }
}

// TODO : un-implement, and have 'new' return a pair of pub/sub types
impl<T: Timestamp, D: Data> Clone for OutputPort<T, D> {
    fn clone(&self) -> OutputPort<T, D> {
        OutputPort {
            limit:  self.limit,
            buffer: Vec::new(),
            shared: self.shared.clone(),
            stash:  self.stash.clone(),
        }
    }
}

// dual to BufferedObserver, flattens out buffers
pub struct OutputPortFlattener<O: Observer> {
    observer:   O,
    stash:      Rc<RefCell<Vec<Vec<O::Data>>>>,
}

impl<O: Observer> OutputPortFlattener<O> {
    pub fn new(observer: O, stash: Rc<RefCell<Vec<Vec<O::Data>>>>) -> OutputPortFlattener<O> {
        OutputPortFlattener {
            observer: observer,
            stash:    stash,
        }
    }
}

impl<O: Observer> Observer for OutputPortFlattener<O> {
    type Time = O::Time;
    type Data = Vec<O::Data>;
    #[inline(always)] fn open(&mut self, time: &O::Time) -> () { self.observer.open(time); }
    #[inline(always)] fn show(&mut self, _data: &Vec<O::Data>) -> () { panic!("something horribly wrong!") }
    #[inline(always)] fn give(&mut self, mut data:  Vec<O::Data>) -> () {
        for datum in data.drain() { self.observer.give(datum); }
        self.stash.borrow_mut().push(data);
    }
    #[inline(always)] fn shut(&mut self, time: &O::Time) -> () { self.observer.shut(time); }
}

pub struct ObserverHelper<O: Observer> {
    observer:   O,
    counts:     Rc<RefCell<CountMap<O::Time>>>,
    count:      i64,
}

impl<O: Observer> Observer for ObserverHelper<O> where O::Time : Timestamp {
    type Time = O::Time;
    type Data = O::Data;
    #[inline(always)] fn open(&mut self, time: &O::Time) { self.observer.open(time); }
    #[inline(always)] fn show(&mut self, data: &O::Data) { self.count += 1; self.observer.show(data); }
    #[inline(always)] fn give(&mut self, data:  O::Data) { self.count += 1; self.observer.give(data); }
    #[inline(always)] fn shut(&mut self, time: &O::Time) -> () {
        self.counts.borrow_mut().update(time, self.count);
        self.observer.shut(time);
        self.count = 0;
    }
}

impl<O: Observer> ObserverHelper<O> where O::Time : Eq+Clone+'static {
    pub fn new(observer: O, counts: Rc<RefCell<CountMap<O::Time>>>) -> ObserverHelper<O> {
        ObserverHelper {
            observer:   observer,
            counts:     counts,
            count:      0,
        }
    }

    #[inline(always)] pub fn pull_progress(&mut self, updates: &mut CountMap<O::Time>) {
        while let Some((ref time, delta)) = self.counts.borrow_mut().pop() { updates.update(time, delta); }
    }
}
<commit_msg>minor fomatting<commit_after>use core::fmt::Debug;
use std::any::Any;
use std::mem;

use progress::Timestamp;
use progress::count_map::CountMap;

use communication::Observer;
use communication::observer::{BufferedObserver, FlattenedObserver, BroadcastObserver};

use std::rc::Rc;
use std::cell::RefCell;

pub trait Data : Clone+Send+Debug+Any { }
impl<T: Clone+Send+Debug+Any> Data for T { }

// // TODO : All the buffering, cloning, and dropping makes pandas sad.
// // TODO : It should be easy enough to Rc<RefCell<Vec<Vec<D>>>> things up.
// // TODO : OutputPort can do the buffering, broadcasting, and collecting vecs.
// pub struct OutputPort<T: Timestamp, D: Data> {
//     shared: BufferedObserver<D, Rc<RefCell<BroadcastObserver<Box<Observer<Time=T, Data=Vec<D>>>>>>>,
// }
//
// impl<T: Timestamp, D: Data> Observer for OutputPort<T, D> {
//     type Time = T;
//     type Data = D;
//     #[inline(always)] fn open(&mut self, time: &T) { self.shared.open(time); }
//     #[inline(always)] fn show(&mut self, data: &D) { self.shared.show(data); }
//     #[inline(always)] fn give(&mut self, data:  D) { self.shared.give(data); }
//     #[inline(always)] fn shut(&mut self, time: &T) { self.shared.shut(time); }
// }
//
// impl<T: Timestamp, D: Data> OutputPort<T, D> {
//     pub fn new() -> OutputPort<T, D> {
//         OutputPort { shared: BufferedObserver::new(256, Rc::new(RefCell::new(BroadcastObserver::new()))) }
//     }
//     pub fn add_observer<O: Observer<Time=T, Data=D>+'static>(&self, observer: O) {
//         self.shared.inner().borrow_mut().add(Box::new(FlattenedObserver::new(observer)));
//     }
// }
//
// impl<T: Timestamp, D: Data> Clone for OutputPort<T, D> {
//     fn clone(&self) -> OutputPort<T, D> {
//         OutputPort {
//             shared: BufferedObserver::new(256, self.shared.inner().clone()),
//         }
//     }
// }

pub struct OutputPort<T: Timestamp, D: Data> {
    limit:  usize,
    buffer: Vec<D>,
    shared: Rc<RefCell<Vec<Box<Observer<Time=T,Data=Vec<D>>>>>>,
    stash:  Rc<RefCell<Vec<Vec<D>>>>,
}

impl<T: Timestamp, D: Data> Observer for OutputPort<T, D> {
    type Time = T;
    type Data = D;
    #[inline(always)] fn open(&mut self, time: &T) {
        for observer in self.shared.borrow_mut().iter_mut() {
            observer.open(time);
        }
    }
    #[inline(always)] fn show(&mut self, data: &D) { self.give(data.clone()); }
    #[inline(always)] fn give(&mut self, data:  D) {
        self.buffer.push(data);
        if self.buffer.len() > self.limit {
            let mut observers = self.shared.borrow_mut();
            for index in (0..observers.len()) {
                let data = mem::replace(&mut self.buffer, self.stash.borrow_mut().pop().unwrap_or(Vec::new()));
                if index < observers.len() - 1 { self.buffer.push_all(&data); }
                observers[index].give(data);
            }
        }
    }
    #[inline(always)] fn shut(&mut self, time: &T) {
        if self.buffer.len() > 0 {
            let mut observers = self.shared.borrow_mut();
            for index in (0..observers.len()) {
                let data = mem::replace(&mut self.buffer, self.stash.borrow_mut().pop().unwrap_or(Vec::new()));
                if index < observers.len() - 1 { self.buffer.push_all(&data); }
                observers[index].give(data);
            }
        }

        for observer in self.shared.borrow_mut().iter_mut() {
            observer.shut(time);
        }
    }
}

impl<T: Timestamp, D: Data> OutputPort<T, D> {
    pub fn new() -> OutputPort<T, D> {
        let limit = 256;
        OutputPort {
            limit:  limit,
            buffer: Vec::with_capacity(limit),
            shared: Rc::new(RefCell::new(Vec::new())),
            stash:  Rc::new(RefCell::new(Vec::new())),
        }
    }
    pub fn add_observer<O: Observer<Time=T, Data=D>+'static>(&self, observer: O) {
        self.shared.borrow_mut().push(Box::new(OutputPortFlattener::new(observer, self.stash.clone())));
    }
}

// TODO : un-implement, and have 'new' return a pair of pub/sub types
impl<T: Timestamp, D: Data> Clone for OutputPort<T, D> {
    fn clone(&self) -> OutputPort<T, D> {
        OutputPort {
            limit:  self.limit,
            buffer: Vec::new(),
            shared: self.shared.clone(),
            stash:  self.stash.clone(),
        }
    }
}

// dual to BufferedObserver, flattens out buffers
pub struct OutputPortFlattener<O: Observer> {
    observer:   O,
    stash:      Rc<RefCell<Vec<Vec<O::Data>>>>,
}

impl<O: Observer> OutputPortFlattener<O> {
    pub fn new(observer: O, stash: Rc<RefCell<Vec<Vec<O::Data>>>>) -> OutputPortFlattener<O> {
        OutputPortFlattener {
            observer: observer,
            stash:    stash,
        }
    }
}

impl<O: Observer> Observer for OutputPortFlattener<O> {
    type Time = O::Time;
    type Data = Vec<O::Data>;
    #[inline(always)] fn open(&mut self, time: &O::Time) -> () { self.observer.open(time); }
    #[inline(always)] fn show(&mut self, _data: &Vec<O::Data>) -> () { panic!("something horribly wrong!") }
    #[inline(always)] fn give(&mut self, mut data:  Vec<O::Data>) -> () {
        for datum in data.drain() { self.observer.give(datum); }
        self.stash.borrow_mut().push(data);
    }
    #[inline(always)] fn shut(&mut self, time: &O::Time) -> () { self.observer.shut(time); }
}

pub struct ObserverHelper<O: Observer> {
    observer:   O,
    counts:     Rc<RefCell<CountMap<O::Time>>>,
    count:      i64,
}

impl<O: Observer> Observer for ObserverHelper<O> where O::Time : Timestamp {
    type Time = O::Time;
    type Data = O::Data;
    #[inline(always)] fn open(&mut self, time: &O::Time) { self.observer.open(time); }
    #[inline(always)] fn show(&mut self, data: &O::Data) { self.count += 1; self.observer.show(data); }
    #[inline(always)] fn give(&mut self, data:  O::Data) { self.count += 1; self.observer.give(data); }
    #[inline(always)] fn shut(&mut self, time: &O::Time) -> () {
        self.counts.borrow_mut().update(time, self.count);
        self.observer.shut(time);
        self.count = 0;
    }
}

impl<O: Observer> ObserverHelper<O> where O::Time : Eq+Clone+'static {
    pub fn new(observer: O, counts: Rc<RefCell<CountMap<O::Time>>>) -> ObserverHelper<O> {
        ObserverHelper {
            observer:   observer,
            counts:     counts,
            count:      0,
        }
    }

    #[inline(always)] pub fn pull_progress(&mut self, updates: &mut CountMap<O::Time>) {
        while let Some((ref time, delta)) = self.counts.borrow_mut().pop() { updates.update(time, delta); }
    }
}
<|endoftext|>


<commit_before>//! An interpreter for the rust-installer package format.  Responsible
//! for installing from a directory or tarball to an installation
//! prefix, represented by a `Components` instance.

use crate::dist::component::components::*;
use crate::dist::component::transaction::*;

use crate::dist::temp;
use crate::errors::*;
use crate::utils::notifications::Notification;
use crate::utils::utils;

use std::collections::HashSet;
use std::fmt;
use std::io::Read;
use std::path::{Path, PathBuf};

/// The current metadata revision used by rust-installer
pub const INSTALLER_VERSION: &str = "3";
pub const VERSION_FILE: &str = "rust-installer-version";

pub trait Package: fmt::Debug {
    fn contains(&self, component: &str, short_name: Option<&str>) -> bool;
    fn install<'a>(
        &self,
        target: &Components,
        component: &str,
        short_name: Option<&str>,
        tx: Transaction<'a>,
    ) -> Result<Transaction<'a>>;
    fn components(&self) -> Vec<String>;
}

#[derive(Debug)]
pub struct DirectoryPackage {
    path: PathBuf,
    components: HashSet<String>,
    copy: bool,
}

impl DirectoryPackage {
    pub fn new(path: PathBuf, copy: bool) -> Result<Self> {
        validate_installer_version(&path)?;

        let content = utils::read_file("package components", &path.join("components"))?;
        let components = content
            .lines()
            .map(std::borrow::ToOwned::to_owned)
            .collect();
        Ok(DirectoryPackage {
            path,
            components,
            copy,
        })
    }
}

fn validate_installer_version(path: &Path) -> Result<()> {
    let file = utils::read_file("installer version", &path.join(VERSION_FILE))?;
    let v = file.trim();
    if v == INSTALLER_VERSION {
        Ok(())
    } else {
        Err(ErrorKind::BadInstallerVersion(v.to_owned()).into())
    }
}

impl Package for DirectoryPackage {
    fn contains(&self, component: &str, short_name: Option<&str>) -> bool {
        self.components.contains(component)
            || if let Some(n) = short_name {
                self.components.contains(n)
            } else {
                false
            }
    }
    fn install<'a>(
        &self,
        target: &Components,
        name: &str,
        short_name: Option<&str>,
        tx: Transaction<'a>,
    ) -> Result<Transaction<'a>> {
        let actual_name = if self.components.contains(name) {
            name
        } else if let Some(n) = short_name {
            n
        } else {
            name
        };

        let root = self.path.join(actual_name);

        let manifest = utils::read_file("package manifest", &root.join("manifest.in"))?;
        let mut builder = target.add(name, tx);

        for l in manifest.lines() {
            let part = ComponentPart::decode(l)
                .ok_or_else(|| ErrorKind::CorruptComponent(name.to_owned()))?;

            let path = part.1;
            let src_path = root.join(&path);

            match &*part.0 {
                "file" => {
                    if self.copy {
                        builder.copy_file(path.clone(), &src_path)?
                    } else {
                        builder.move_file(path.clone(), &src_path)?
                    }
                }
                "dir" => {
                    if self.copy {
                        builder.copy_dir(path.clone(), &src_path)?
                    } else {
                        builder.move_dir(path.clone(), &src_path)?
                    }
                }
                _ => return Err(ErrorKind::CorruptComponent(name.to_owned()).into()),
            }

            set_file_perms(&target.prefix().path().join(path), &src_path)?;
        }

        let tx = builder.finish()?;

        Ok(tx)
    }

    fn components(&self) -> Vec<String> {
        self.components.iter().cloned().collect()
    }
}

// On Unix we need to set up the file permissions correctly so
// binaries are executable and directories readable. This shouldn't be
// necessary: the source files *should* have the right permissions,
// but due to rust-lang/rust#25479 they don't.
#[cfg(unix)]
fn set_file_perms(dest_path: &Path, src_path: &Path) -> Result<()> {
    use std::fs::{self, Metadata};
    use std::os::unix::fs::PermissionsExt;
    use walkdir::WalkDir;

    // Compute whether this entry needs the X bit
    fn needs_x(meta: &Metadata) -> bool {
        meta.is_dir() || // Directories need it
        meta.permissions().mode() & 0o700 == 0o700 // If it is rwx for the user, it gets the X bit
    }

    // By convention, anything in the bin/ directory of the package is a binary
    let is_bin = if let Some(p) = src_path.parent() {
        p.ends_with("bin")
    } else {
        false
    };

    let is_dir = utils::is_directory(dest_path);

    if is_dir {
        // Walk the directory setting everything
        for entry in WalkDir::new(dest_path) {
            let entry = entry.chain_err(|| ErrorKind::ComponentDirPermissionsFailed)?;
            let meta = entry
                .metadata()
                .chain_err(|| ErrorKind::ComponentDirPermissionsFailed)?;

            let mut perm = meta.permissions();
            perm.set_mode(if needs_x(&meta) { 0o755 } else { 0o644 });
            fs::set_permissions(entry.path(), perm)
                .chain_err(|| ErrorKind::ComponentFilePermissionsFailed)?;
        }
    } else {
        let meta =
            fs::metadata(dest_path).chain_err(|| ErrorKind::ComponentFilePermissionsFailed)?;
        let mut perm = meta.permissions();
        perm.set_mode(if is_bin || needs_x(&meta) {
            0o755
        } else {
            0o644
        });
        fs::set_permissions(dest_path, perm)
            .chain_err(|| ErrorKind::ComponentFilePermissionsFailed)?;
    }

    Ok(())
}

#[cfg(windows)]
fn set_file_perms(_dest_path: &Path, _src_path: &Path) -> Result<()> {
    Ok(())
}

#[derive(Debug)]
pub struct TarPackage<'a>(DirectoryPackage, temp::Dir<'a>);

impl<'a> TarPackage<'a> {
    pub fn new<R: Read>(
        stream: R,
        temp_cfg: &'a temp::Cfg,
        notify_handler: Option<&'a dyn Fn(Notification<'_>)>,
    ) -> Result<Self> {
        let temp_dir = temp_cfg.new_directory()?;
        let mut archive = tar::Archive::new(stream);
        // The rust-installer packages unpack to a directory called
        // $pkgname-$version-$target. Skip that directory when
        // unpacking.
        unpack_without_first_dir(&mut archive, &*temp_dir, notify_handler)?;

        Ok(TarPackage(
            DirectoryPackage::new(temp_dir.to_owned(), false)?,
            temp_dir,
        ))
    }
}

#[cfg(windows)]
mod unpacker {
    use std::sync::atomic::{AtomicUsize, Ordering};
    use std::sync::Arc;
    use threadpool;

    use crate::utils::notifications::Notification;

    pub struct Unpacker<'a> {
        n_files: Arc<AtomicUsize>,
        pool: threadpool::ThreadPool,
        notify_handler: Option<&'a dyn Fn(Notification<'_>)>,
    }

    impl<'a> Unpacker<'a> {
        pub fn new(notify_handler: Option<&'a dyn Fn(Notification<'_>)>) -> Self {
            // Defaults to hardware thread count threads; this is suitable for
            // our needs as IO bound operations tend to show up as write latencies
            // rather than close latencies, so we don't need to look at
            // more threads to get more IO dispatched at this stage in the process.
            let pool = threadpool::Builder::new()
                .thread_name("CloseHandle".into())
                .build();
            Unpacker {
                n_files: Arc::new(AtomicUsize::new(0)),
                pool: pool,
                notify_handler: notify_handler,
            }
        }

        pub fn handle(&mut self, unpacked: tar::Unpacked) {
            if let tar::Unpacked::File(f) = unpacked {
                self.n_files.fetch_add(1, Ordering::Relaxed);
                let n_files = self.n_files.clone();
                self.pool.execute(move || {
                    drop(f);
                    n_files.fetch_sub(1, Ordering::Relaxed);
                });
            }
        }
    }

    impl<'a> Drop for Unpacker<'a> {
        fn drop(&mut self) {
            // Some explanation is in order. Even though the tar we are reading from (if
            // any) will have had its FileWithProgress download tracking
            // completed before we hit drop, that is not true if we are unwinding due to a
            // failure, where the logical ownership of the progress bar is
            // ambiguous, and as the tracker itself is abstracted out behind
            // notifications etc we cannot just query for that. So: we assume no
            // more reads of the underlying tar will take place: either the
            // error unwinding will stop reads, or we completed; either way, we
            // notify finished to the tracker to force a reset to zero; we set
            // the units to files, show our progress, and set our units back
            // afterwards. The largest archives today - rust docs - have ~20k
            // items, and the download tracker's progress is confounded with
            // actual handling of data today, we synthesis a data buffer and
            // pretend to have bytes to deliver.
            self.notify_handler
                .map(|handler| handler(Notification::DownloadFinished));
            self.notify_handler
                .map(|handler| handler(Notification::DownloadPushUnits("handles")));
            let mut prev_files = self.n_files.load(Ordering::Relaxed);
            self.notify_handler.map(|handler| {
                handler(Notification::DownloadContentLengthReceived(
                    prev_files as u64,
                ))
            });
            if prev_files > 50 {
                println!("Closing {} deferred file handles", prev_files);
            }
            let buf: Vec<u8> = vec![0; prev_files];
            assert!(32767 > prev_files);
            let mut current_files = prev_files;
            while current_files != 0 {
                use std::thread::sleep;
                sleep(std::time::Duration::from_millis(100));
                prev_files = current_files;
                current_files = self.n_files.load(Ordering::Relaxed);
                let step_count = prev_files - current_files;
                self.notify_handler.map(|handler| {
                    handler(Notification::DownloadDataReceived(&buf[0..step_count]))
                });
            }
            self.pool.join();
            self.notify_handler
                .map(|handler| handler(Notification::DownloadFinished));
            self.notify_handler
                .map(|handler| handler(Notification::DownloadPopUnits));
        }
    }
}

#[cfg(not(windows))]
mod unpacker {
    use crate::utils::notifications::Notification;
    pub struct Unpacker {}
    impl Unpacker {
        pub fn new<'a>(_notify_handler: Option<&'a dyn Fn(Notification<'_>)>) -> Unpacker {
            Unpacker {}
        }
        pub fn handle(&mut self, _unpacked: tar::Unpacked) {}
    }
}

fn unpack_without_first_dir<'a, R: Read>(
    archive: &mut tar::Archive<R>,
    path: &Path,
    notify_handler: Option<&'a dyn Fn(Notification<'_>)>,
) -> Result<()> {
    let mut unpacker = unpacker::Unpacker::new(notify_handler);
    let entries = archive
        .entries()
        .chain_err(|| ErrorKind::ExtractingPackage)?;
    let mut checked_parents: HashSet<PathBuf> = HashSet::new();

    for entry in entries {
        let mut entry = entry.chain_err(|| ErrorKind::ExtractingPackage)?;
        let relpath = {
            let path = entry.path();
            let path = path.chain_err(|| ErrorKind::ExtractingPackage)?;
            path.into_owned()
        };
        let mut components = relpath.components();
        // Throw away the first path component
        components.next();
        let full_path = path.join(&components.as_path());

        // Create the full path to the entry if it does not exist already
        match full_path.parent() {
            Some(parent) => {
                if !checked_parents.contains(parent) {
                    checked_parents.insert(parent.clone().to_owned());
                    // It would be nice to optimise this stat out, but the tar could be like so:
                    // a/deep/file.txt
                    // a/file.txt
                    // which would require tracking the segments rather than a simple hash.
                    // Until profile shows that one stat per dir is a problem (vs one stat per file)
                    // leave till later.

                    if !parent.exists() {
                        std::fs::create_dir_all(&parent)
                            .chain_err(|| ErrorKind::ExtractingPackage)?
                    }
                }
            }
            _ => (),
        };
        entry.set_preserve_mtime(false);
        entry
            .unpack(&full_path)
            .map(|unpacked| unpacker.handle(unpacked))
            .chain_err(|| ErrorKind::ExtractingPackage)?;
    }

    Ok(())
}

impl<'a> Package for TarPackage<'a> {
    fn contains(&self, component: &str, short_name: Option<&str>) -> bool {
        self.0.contains(component, short_name)
    }
    fn install<'b>(
        &self,
        target: &Components,
        component: &str,
        short_name: Option<&str>,
        tx: Transaction<'b>,
    ) -> Result<Transaction<'b>> {
        self.0.install(target, component, short_name, tx)
    }
    fn components(&self) -> Vec<String> {
        self.0.components()
    }
}

#[derive(Debug)]
pub struct TarGzPackage<'a>(TarPackage<'a>);

impl<'a> TarGzPackage<'a> {
    pub fn new<R: Read>(
        stream: R,
        temp_cfg: &'a temp::Cfg,
        notify_handler: Option<&'a dyn Fn(Notification<'_>)>,
    ) -> Result<Self> {
        let stream = flate2::read::GzDecoder::new(stream);
        Ok(TarGzPackage(TarPackage::new(
            stream,
            temp_cfg,
            notify_handler,
        )?))
    }
}

impl<'a> Package for TarGzPackage<'a> {
    fn contains(&self, component: &str, short_name: Option<&str>) -> bool {
        self.0.contains(component, short_name)
    }
    fn install<'b>(
        &self,
        target: &Components,
        component: &str,
        short_name: Option<&str>,
        tx: Transaction<'b>,
    ) -> Result<Transaction<'b>> {
        self.0.install(target, component, short_name, tx)
    }
    fn components(&self) -> Vec<String> {
        self.0.components()
    }
}

#[derive(Debug)]
pub struct TarXzPackage<'a>(TarPackage<'a>);

impl<'a> TarXzPackage<'a> {
    pub fn new<R: Read>(
        stream: R,
        temp_cfg: &'a temp::Cfg,
        notify_handler: Option<&'a dyn Fn(Notification<'_>)>,
    ) -> Result<Self> {
        let stream = xz2::read::XzDecoder::new(stream);
        Ok(TarXzPackage(TarPackage::new(
            stream,
            temp_cfg,
            notify_handler,
        )?))
    }
}

impl<'a> Package for TarXzPackage<'a> {
    fn contains(&self, component: &str, short_name: Option<&str>) -> bool {
        self.0.contains(component, short_name)
    }
    fn install<'b>(
        &self,
        target: &Components,
        component: &str,
        short_name: Option<&str>,
        tx: Transaction<'b>,
    ) -> Result<Transaction<'b>> {
        self.0.install(target, component, short_name, tx)
    }
    fn components(&self) -> Vec<String> {
        self.0.components()
    }
}
<commit_msg>Fix clippy: single_match<commit_after>//! An interpreter for the rust-installer package format.  Responsible
//! for installing from a directory or tarball to an installation
//! prefix, represented by a `Components` instance.

use crate::dist::component::components::*;
use crate::dist::component::transaction::*;

use crate::dist::temp;
use crate::errors::*;
use crate::utils::notifications::Notification;
use crate::utils::utils;

use std::collections::HashSet;
use std::fmt;
use std::io::Read;
use std::path::{Path, PathBuf};

/// The current metadata revision used by rust-installer
pub const INSTALLER_VERSION: &str = "3";
pub const VERSION_FILE: &str = "rust-installer-version";

pub trait Package: fmt::Debug {
    fn contains(&self, component: &str, short_name: Option<&str>) -> bool;
    fn install<'a>(
        &self,
        target: &Components,
        component: &str,
        short_name: Option<&str>,
        tx: Transaction<'a>,
    ) -> Result<Transaction<'a>>;
    fn components(&self) -> Vec<String>;
}

#[derive(Debug)]
pub struct DirectoryPackage {
    path: PathBuf,
    components: HashSet<String>,
    copy: bool,
}

impl DirectoryPackage {
    pub fn new(path: PathBuf, copy: bool) -> Result<Self> {
        validate_installer_version(&path)?;

        let content = utils::read_file("package components", &path.join("components"))?;
        let components = content
            .lines()
            .map(std::borrow::ToOwned::to_owned)
            .collect();
        Ok(DirectoryPackage {
            path,
            components,
            copy,
        })
    }
}

fn validate_installer_version(path: &Path) -> Result<()> {
    let file = utils::read_file("installer version", &path.join(VERSION_FILE))?;
    let v = file.trim();
    if v == INSTALLER_VERSION {
        Ok(())
    } else {
        Err(ErrorKind::BadInstallerVersion(v.to_owned()).into())
    }
}

impl Package for DirectoryPackage {
    fn contains(&self, component: &str, short_name: Option<&str>) -> bool {
        self.components.contains(component)
            || if let Some(n) = short_name {
                self.components.contains(n)
            } else {
                false
            }
    }
    fn install<'a>(
        &self,
        target: &Components,
        name: &str,
        short_name: Option<&str>,
        tx: Transaction<'a>,
    ) -> Result<Transaction<'a>> {
        let actual_name = if self.components.contains(name) {
            name
        } else if let Some(n) = short_name {
            n
        } else {
            name
        };

        let root = self.path.join(actual_name);

        let manifest = utils::read_file("package manifest", &root.join("manifest.in"))?;
        let mut builder = target.add(name, tx);

        for l in manifest.lines() {
            let part = ComponentPart::decode(l)
                .ok_or_else(|| ErrorKind::CorruptComponent(name.to_owned()))?;

            let path = part.1;
            let src_path = root.join(&path);

            match &*part.0 {
                "file" => {
                    if self.copy {
                        builder.copy_file(path.clone(), &src_path)?
                    } else {
                        builder.move_file(path.clone(), &src_path)?
                    }
                }
                "dir" => {
                    if self.copy {
                        builder.copy_dir(path.clone(), &src_path)?
                    } else {
                        builder.move_dir(path.clone(), &src_path)?
                    }
                }
                _ => return Err(ErrorKind::CorruptComponent(name.to_owned()).into()),
            }

            set_file_perms(&target.prefix().path().join(path), &src_path)?;
        }

        let tx = builder.finish()?;

        Ok(tx)
    }

    fn components(&self) -> Vec<String> {
        self.components.iter().cloned().collect()
    }
}

// On Unix we need to set up the file permissions correctly so
// binaries are executable and directories readable. This shouldn't be
// necessary: the source files *should* have the right permissions,
// but due to rust-lang/rust#25479 they don't.
#[cfg(unix)]
fn set_file_perms(dest_path: &Path, src_path: &Path) -> Result<()> {
    use std::fs::{self, Metadata};
    use std::os::unix::fs::PermissionsExt;
    use walkdir::WalkDir;

    // Compute whether this entry needs the X bit
    fn needs_x(meta: &Metadata) -> bool {
        meta.is_dir() || // Directories need it
        meta.permissions().mode() & 0o700 == 0o700 // If it is rwx for the user, it gets the X bit
    }

    // By convention, anything in the bin/ directory of the package is a binary
    let is_bin = if let Some(p) = src_path.parent() {
        p.ends_with("bin")
    } else {
        false
    };

    let is_dir = utils::is_directory(dest_path);

    if is_dir {
        // Walk the directory setting everything
        for entry in WalkDir::new(dest_path) {
            let entry = entry.chain_err(|| ErrorKind::ComponentDirPermissionsFailed)?;
            let meta = entry
                .metadata()
                .chain_err(|| ErrorKind::ComponentDirPermissionsFailed)?;

            let mut perm = meta.permissions();
            perm.set_mode(if needs_x(&meta) { 0o755 } else { 0o644 });
            fs::set_permissions(entry.path(), perm)
                .chain_err(|| ErrorKind::ComponentFilePermissionsFailed)?;
        }
    } else {
        let meta =
            fs::metadata(dest_path).chain_err(|| ErrorKind::ComponentFilePermissionsFailed)?;
        let mut perm = meta.permissions();
        perm.set_mode(if is_bin || needs_x(&meta) {
            0o755
        } else {
            0o644
        });
        fs::set_permissions(dest_path, perm)
            .chain_err(|| ErrorKind::ComponentFilePermissionsFailed)?;
    }

    Ok(())
}

#[cfg(windows)]
fn set_file_perms(_dest_path: &Path, _src_path: &Path) -> Result<()> {
    Ok(())
}

#[derive(Debug)]
pub struct TarPackage<'a>(DirectoryPackage, temp::Dir<'a>);

impl<'a> TarPackage<'a> {
    pub fn new<R: Read>(
        stream: R,
        temp_cfg: &'a temp::Cfg,
        notify_handler: Option<&'a dyn Fn(Notification<'_>)>,
    ) -> Result<Self> {
        let temp_dir = temp_cfg.new_directory()?;
        let mut archive = tar::Archive::new(stream);
        // The rust-installer packages unpack to a directory called
        // $pkgname-$version-$target. Skip that directory when
        // unpacking.
        unpack_without_first_dir(&mut archive, &*temp_dir, notify_handler)?;

        Ok(TarPackage(
            DirectoryPackage::new(temp_dir.to_owned(), false)?,
            temp_dir,
        ))
    }
}

#[cfg(windows)]
mod unpacker {
    use std::sync::atomic::{AtomicUsize, Ordering};
    use std::sync::Arc;
    use threadpool;

    use crate::utils::notifications::Notification;

    pub struct Unpacker<'a> {
        n_files: Arc<AtomicUsize>,
        pool: threadpool::ThreadPool,
        notify_handler: Option<&'a dyn Fn(Notification<'_>)>,
    }

    impl<'a> Unpacker<'a> {
        pub fn new(notify_handler: Option<&'a dyn Fn(Notification<'_>)>) -> Self {
            // Defaults to hardware thread count threads; this is suitable for
            // our needs as IO bound operations tend to show up as write latencies
            // rather than close latencies, so we don't need to look at
            // more threads to get more IO dispatched at this stage in the process.
            let pool = threadpool::Builder::new()
                .thread_name("CloseHandle".into())
                .build();
            Unpacker {
                n_files: Arc::new(AtomicUsize::new(0)),
                pool: pool,
                notify_handler: notify_handler,
            }
        }

        pub fn handle(&mut self, unpacked: tar::Unpacked) {
            if let tar::Unpacked::File(f) = unpacked {
                self.n_files.fetch_add(1, Ordering::Relaxed);
                let n_files = self.n_files.clone();
                self.pool.execute(move || {
                    drop(f);
                    n_files.fetch_sub(1, Ordering::Relaxed);
                });
            }
        }
    }

    impl<'a> Drop for Unpacker<'a> {
        fn drop(&mut self) {
            // Some explanation is in order. Even though the tar we are reading from (if
            // any) will have had its FileWithProgress download tracking
            // completed before we hit drop, that is not true if we are unwinding due to a
            // failure, where the logical ownership of the progress bar is
            // ambiguous, and as the tracker itself is abstracted out behind
            // notifications etc we cannot just query for that. So: we assume no
            // more reads of the underlying tar will take place: either the
            // error unwinding will stop reads, or we completed; either way, we
            // notify finished to the tracker to force a reset to zero; we set
            // the units to files, show our progress, and set our units back
            // afterwards. The largest archives today - rust docs - have ~20k
            // items, and the download tracker's progress is confounded with
            // actual handling of data today, we synthesis a data buffer and
            // pretend to have bytes to deliver.
            self.notify_handler
                .map(|handler| handler(Notification::DownloadFinished));
            self.notify_handler
                .map(|handler| handler(Notification::DownloadPushUnits("handles")));
            let mut prev_files = self.n_files.load(Ordering::Relaxed);
            self.notify_handler.map(|handler| {
                handler(Notification::DownloadContentLengthReceived(
                    prev_files as u64,
                ))
            });
            if prev_files > 50 {
                println!("Closing {} deferred file handles", prev_files);
            }
            let buf: Vec<u8> = vec![0; prev_files];
            assert!(32767 > prev_files);
            let mut current_files = prev_files;
            while current_files != 0 {
                use std::thread::sleep;
                sleep(std::time::Duration::from_millis(100));
                prev_files = current_files;
                current_files = self.n_files.load(Ordering::Relaxed);
                let step_count = prev_files - current_files;
                self.notify_handler.map(|handler| {
                    handler(Notification::DownloadDataReceived(&buf[0..step_count]))
                });
            }
            self.pool.join();
            self.notify_handler
                .map(|handler| handler(Notification::DownloadFinished));
            self.notify_handler
                .map(|handler| handler(Notification::DownloadPopUnits));
        }
    }
}

#[cfg(not(windows))]
mod unpacker {
    use crate::utils::notifications::Notification;
    pub struct Unpacker {}
    impl Unpacker {
        pub fn new<'a>(_notify_handler: Option<&'a dyn Fn(Notification<'_>)>) -> Unpacker {
            Unpacker {}
        }
        pub fn handle(&mut self, _unpacked: tar::Unpacked) {}
    }
}

fn unpack_without_first_dir<'a, R: Read>(
    archive: &mut tar::Archive<R>,
    path: &Path,
    notify_handler: Option<&'a dyn Fn(Notification<'_>)>,
) -> Result<()> {
    let mut unpacker = unpacker::Unpacker::new(notify_handler);
    let entries = archive
        .entries()
        .chain_err(|| ErrorKind::ExtractingPackage)?;
    let mut checked_parents: HashSet<PathBuf> = HashSet::new();

    for entry in entries {
        let mut entry = entry.chain_err(|| ErrorKind::ExtractingPackage)?;
        let relpath = {
            let path = entry.path();
            let path = path.chain_err(|| ErrorKind::ExtractingPackage)?;
            path.into_owned()
        };
        let mut components = relpath.components();
        // Throw away the first path component
        components.next();
        let full_path = path.join(&components.as_path());

        // Create the full path to the entry if it does not exist already
        if let Some(parent) = full_path.parent() {
            if !checked_parents.contains(parent) {
                checked_parents.insert(parent.clone().to_owned());
                // It would be nice to optimise this stat out, but the tar could be like so:
                // a/deep/file.txt
                // a/file.txt
                // which would require tracking the segments rather than a simple hash.
                // Until profile shows that one stat per dir is a problem (vs one stat per file)
                // leave till later.

                if !parent.exists() {
                    std::fs::create_dir_all(&parent).chain_err(|| ErrorKind::ExtractingPackage)?
                }
            }
        }
        entry.set_preserve_mtime(false);
        entry
            .unpack(&full_path)
            .map(|unpacked| unpacker.handle(unpacked))
            .chain_err(|| ErrorKind::ExtractingPackage)?;
    }

    Ok(())
}

impl<'a> Package for TarPackage<'a> {
    fn contains(&self, component: &str, short_name: Option<&str>) -> bool {
        self.0.contains(component, short_name)
    }
    fn install<'b>(
        &self,
        target: &Components,
        component: &str,
        short_name: Option<&str>,
        tx: Transaction<'b>,
    ) -> Result<Transaction<'b>> {
        self.0.install(target, component, short_name, tx)
    }
    fn components(&self) -> Vec<String> {
        self.0.components()
    }
}

#[derive(Debug)]
pub struct TarGzPackage<'a>(TarPackage<'a>);

impl<'a> TarGzPackage<'a> {
    pub fn new<R: Read>(
        stream: R,
        temp_cfg: &'a temp::Cfg,
        notify_handler: Option<&'a dyn Fn(Notification<'_>)>,
    ) -> Result<Self> {
        let stream = flate2::read::GzDecoder::new(stream);
        Ok(TarGzPackage(TarPackage::new(
            stream,
            temp_cfg,
            notify_handler,
        )?))
    }
}

impl<'a> Package for TarGzPackage<'a> {
    fn contains(&self, component: &str, short_name: Option<&str>) -> bool {
        self.0.contains(component, short_name)
    }
    fn install<'b>(
        &self,
        target: &Components,
        component: &str,
        short_name: Option<&str>,
        tx: Transaction<'b>,
    ) -> Result<Transaction<'b>> {
        self.0.install(target, component, short_name, tx)
    }
    fn components(&self) -> Vec<String> {
        self.0.components()
    }
}

#[derive(Debug)]
pub struct TarXzPackage<'a>(TarPackage<'a>);

impl<'a> TarXzPackage<'a> {
    pub fn new<R: Read>(
        stream: R,
        temp_cfg: &'a temp::Cfg,
        notify_handler: Option<&'a dyn Fn(Notification<'_>)>,
    ) -> Result<Self> {
        let stream = xz2::read::XzDecoder::new(stream);
        Ok(TarXzPackage(TarPackage::new(
            stream,
            temp_cfg,
            notify_handler,
        )?))
    }
}

impl<'a> Package for TarXzPackage<'a> {
    fn contains(&self, component: &str, short_name: Option<&str>) -> bool {
        self.0.contains(component, short_name)
    }
    fn install<'b>(
        &self,
        target: &Components,
        component: &str,
        short_name: Option<&str>,
        tx: Transaction<'b>,
    ) -> Result<Transaction<'b>> {
        self.0.install(target, component, short_name, tx)
    }
    fn components(&self) -> Vec<String> {
        self.0.components()
    }
}
<|endoftext|>


<commit_before>#![allow(unused_variables)]

use block::Block;
use cocoa::base::{BOOL, id};
use cocoa::foundation::NSUInteger;
use libc::c_void;
use {MTLFeatureSet, MTLPipelineOption, MTLSize};

/// The `MTLDevice` protocol defines the interface to a single graphics processor (GPU). You use
/// an object that conforms to this protocol to query the capabilities of the processor and to
/// allocate objects used to access those capabilities.
///
/// Your app does not define classes that implement this protocol; it is used by Metal to provide
/// a device object to your app. To obtain a system device, call the `MTLCreateSystemDefaultDevice`
/// function or select a result from the `MTLCopyAllDevices` function.
///
/// Most objects in Metal that perform graphics rendering and computational work are associated
/// directly with a specific device. For example, texture objects are created by a device object
/// and can be used only with that device. Most methods on a `MTLDevice` object create non-transient
/// objects, including command queues, resources (such as buffers and textures), and pipeline
/// states. These objects can be expensive to create and you are encouraged to create them soon
/// after your app launches and reuse them throughout the lifetime of your app. Avoid creating these
/// objects in performance sensitive code.
pub trait MTLDevice {
    /// A Boolean value that indicates whether a device supports a packed depth/stencil buffer.
    /// (read-only)
    ///
    /// # Discussion
    ///
    /// If the value is `YES`, the device supports the `MTLPixelFormatDepth24Unorm_Stencil8` pixel
    /// format.
    unsafe fn depth24Stencil8PixelFormatSupported(self) -> BOOL;

    /// A Boolean value that indicates whether a device is configured as headless. (read-only)
    ///
    /// # Discussion
    ///
    /// If the value is `YES`, the device can not and does not have any displays attached.
    unsafe fn headless(self) -> BOOL;

    /// Boolean value that indicates whether a device is low-power. (read-only)
    ///
    /// # Discussion
    ///
    /// On multi-GPU systems that support automatic graphics switching, this property will return
    /// `YES` for the lower-power GPU.
    unsafe fn lowPower(self) -> BOOL;

    /// The maximum number of threads along each dimension of a threadgroup. (read-only)
    ///
    /// # Discussion
    ///
    /// This is the maximum compute grid size (width, height, depth) supported by the device.
    ///
    /// For more information on the specific capabilities of each feature set, see
    /// [Metal Programming Guide](https://developer.apple.com/library/prerelease/ios/documentation/
    ///     Miscellaneous/Conceptual/MetalProgrammingGuide/Introduction/
    ///     Introduction.html#//apple_ref/doc/uid/TP40014221
    /// ).
    unsafe fn maxThreadsPerGroup(self) -> MTLSize;

    /// A string that identifies the device. (read-only)
    ///
    /// # Discussion
    ///
    /// When this object is viewed in the Xcode debugger, its name is used to label the device.
    /// The name should only be used for informational purposes.
    unsafe fn name(self) -> id;

    /// Determines whether a device implements a particular feature set.
    ///
    /// # Parameters
    ///
    /// `featureSet` - A value that indicates the feature set you are interested in.
    ///
    /// # Return Value
    ///
    /// `YES` if the feature set is supported by the device; otherwise `NO`.
    ///
    /// # Discussion
    ///
    /// For more information on the specific capabilities of each feature set, see
    /// [Metal Programming Guide](https://developer.apple.com/library/prerelease/ios/documentation/
    ///     Miscellaneous/Conceptual/MetalProgrammingGuide/Introduction/
    ///     Introduction.html#//apple_ref/doc/uid/TP40014221
    /// ).
    unsafe fn supportsFeatureSet(self, featureSet: MTLFeatureSet) -> BOOL;

    /// Determines whether a device supports a given texture sample count.
    ///
    /// # Parameters
    ///
    /// `textureSampleCount` - The sample count you are interested in.
    ///
    /// # Return Value
    ///
    /// `YES` if the sample count is supported by the device; otherwise `NO`.
    ///
    /// # Discussion
    ///
    /// For more information on the specific capabilities of each feature set, see
    /// [Metal Programming Guide](https://developer.apple.com/library/prerelease/ios/documentation/
    ///     Miscellaneous/Conceptual/MetalProgrammingGuide/Introduction/
    ///     Introduction.html#//apple_ref/doc/uid/TP40014221
    /// ).
    unsafe fn supportsTextureSampleCount(self, textureSampleCount: NSUInteger) -> BOOL;

    unsafe fn newDefaultLibrary(self) -> id;
    unsafe fn newLibraryWithFile_error(self, filePath: id, error: id) -> id;
    unsafe fn newLibraryWithSource_options_completionHandler(
        self, source: id, options: id, completionHandler: MTLNewLibraryCompletionHandler) -> id;

    #[cfg_attr(rustfmt, rustfmt_skip)] // This definition is too long to fit on one line
    unsafe fn newLibraryWithSource_options_error(self, source: id, options: id, error: *mut id)
                                                 -> id;
    unsafe fn newLibraryWithData_error(self, data: id, error: id) -> id;

    unsafe fn newCommandQueue(self) -> id;

    #[cfg_attr(rustfmt, rustfmt_skip)] // This definition is too long to fit on one line
    unsafe fn newCommandQueueWithMaxCommandBufferCount(self, maxCommandBufferCount: NSUInteger)
                                                       -> id;

    unsafe fn newBufferWithLength_Options(self, length: NSUInteger, options: id) -> id;
    unsafe fn newBufferWithBytes_Length_Options(self, pointer: *mut c_void, length: NSUInteger,
                                                options: id)
                                                -> id;
    unsafe fn newBufferWithBytesNoCopy_length_options_deallocator(self, pointer: *mut c_void,
                                                                  length: NSUInteger,
                                                                  deallocator: Block<(*mut c_void,
                                                                                NSUInteger),
                                                                                ()>);

    unsafe fn newTextureWithDescriptor(self, descriptor: id) -> id;

    unsafe fn newSamplerStateWithDescriptor(self, descriptor: id) -> id;

    unsafe fn newStencilDepthStateWithDescriptor(self, descriptor: id) -> id;

    unsafe fn newRenderPipleineStateWithDescriptor_completionHandler(
            self, descriptor: id, completionHandler: MTLNewRenderPipleineStateCompletionHandler);

    unsafe fn newRenderPipelineStateWithDescriptor_options_completionHandler(
            self, descriptor: id, options: MTLPipelineOption,
            completionHandler: MTLNewRenderPipelineStateWithReflectionCompletionHandler);

    unsafe fn newRenderPipelineStateWithDescriptor_error(self, descriptor: id, error: id);

    unsafe fn newRenderPipelineStateWithDescriptor_options_reflection(self, descriptor: id,
                                                                      options: MTLPipelineOption,
                                                                      reflection: id, error: id);

    unsafe fn newComputePipelineStateWithFunction_completionHandler(
            self, function: id, completionHandler: MTLNewComputePipelineStateCompletionHandler);

    unsafe fn newComputePipelineStateWithFunction_options_completionHandler(
            self, function: id, options: MTLPipelineOption,
            completionHandler: MTLNewComputePipelineStateWithReflectionCompletionHandler);

    unsafe fn newComputePipelineStateWithFunction_error(self, function: id, error: id);

    unsafe fn newComputePipelineStateWithFunction_options_reflection_error(
            self, function: id, options: MTLPipelineOption, reflection: id, error: id);

    unsafe fn newComputePipelineStateWithDescriptor_options_completionHandler(
            self, descriptor: id, options: MTLPipelineOption,
            completionHandler: MTLNewComputePipelineStateWithReflectionCompletionHandler);

    unsafe fn newComputePipelineStateWithDescriptor_options_reflection_error(
            self, descriptor: id, options: MTLPipelineOption, reflection: id, error: id);
}

impl MTLDevice for id {
    unsafe fn depth24Stencil8PixelFormatSupported(self) -> BOOL {
        msg_send![self, isDepth24Stencil8PixelFormatSupported]
    }

    unsafe fn headless(self) -> BOOL {
        msg_send![self, isHeadless]
    }

    unsafe fn lowPower(self) -> BOOL {
        msg_send![self, isLowPower]
    }

    unsafe fn maxThreadsPerGroup(self) -> MTLSize {
        msg_send![self, maxThreadsPerThreadgroup]
    }

    unsafe fn name(self) -> id {
        msg_send![self, name]
    }

    unsafe fn supportsFeatureSet(self, featureSet: MTLFeatureSet) -> BOOL {
        msg_send![self, supportsFeatureSet:featureSet]
    }

    unsafe fn supportsTextureSampleCount(self, textureSampleCount: NSUInteger) -> BOOL {
        msg_send![self, supportsTextureSampleCount:textureSampleCount]
    }

    unsafe fn newDefaultLibrary(self) -> id {
        msg_send![self, newDefaultLibrary]
    }

    unsafe fn newLibraryWithFile_error(self, filePath: id, error: id) -> id {
        msg_send![self, newLibraryWithFile:filePath error:error]
    }

    unsafe fn newLibraryWithSource_options_completionHandler(
        self, source: id, options: id, completionHandler: MTLNewLibraryCompletionHandler)
        -> id {
        msg_send![self, newLibraryWithSource:source options:options
                           completionHandler:completionHandler]
    }

    #[cfg_attr(rustfmt, rustfmt_skip)] // This definition is too long to fit on one line
    unsafe fn newLibraryWithSource_options_error(self, source: id, options: id, error: *mut id)
                                                 -> id {
        msg_send![self, newLibraryWithSource:source options:options error:error]
    }

    unsafe fn newLibraryWithData_error(self, data: id, error: id) -> id {
        msg_send![self, newLibraryWithData:data error:error]
    }

    unsafe fn newCommandQueue(self) -> id {
        msg_send![self, newCommandQueue]
    }

    #[cfg_attr(rustfmt, rustfmt_skip)] // This definition is too long to fit on one line
    unsafe fn newCommandQueueWithMaxCommandBufferCount(self, maxCommandBufferCount: NSUInteger)
                                                       -> id {
        msg_send![self, newCommandQueueWithMaxCommandBufferCount:maxCommandBufferCount]
    }

    unsafe fn newBufferWithLength_Options(self, length: NSUInteger, options: id) -> id {
        msg_send![self, newBufferWithLength:length options:options]
    }

    unsafe fn newBufferWithBytes_Length_Options(self, pointer: *mut c_void, length: NSUInteger,
                                                options: id)
                                                -> id {
        msg_send![self, newBufferWithBytes:pointer length:length options:options]
    }

    unsafe fn newBufferWithBytesNoCopy_length_options_deallocator(self, pointer: *mut c_void,
                                                                  length: NSUInteger,
                                                                  deallocator: Block<(*mut c_void,
                                                                                NSUInteger),
                                                                                ()>) {
        msg_send![self, newBufferWithBytesNoCopy:pointer length:length deallocator:deallocator]
    }

    unsafe fn newTextureWithDescriptor(self, descriptor: id) -> id {
        msg_send![self, newTextureWithDescriptor:descriptor]
    }

    unsafe fn newSamplerStateWithDescriptor(self, descriptor: id) -> id {
        msg_send![self, newSamplerStateWithDescriptor:descriptor]
    }

    unsafe fn newStencilDepthStateWithDescriptor(self, descriptor: id) -> id {
        msg_send![self, newStencilDepthStateWithDescriptor:descriptor]
    }

    unsafe fn newRenderPipleineStateWithDescriptor_completionHandler(
            self, descriptor: id,
            completionHandler: MTLNewRenderPipleineStateCompletionHandler) {
        msg_send![self, newRenderPipleineStateWithDescriptor:descriptor
                                           completionHandler:completionHandler]
    }

    unsafe fn newRenderPipelineStateWithDescriptor_options_completionHandler(
            self, descriptor: id, options: MTLPipelineOption,
            completionHandler: MTLNewRenderPipelineStateWithReflectionCompletionHandler) {
        msg_send![self, newRenderPipelineStateWithDescriptor:descriptor
                                                     options:options
                                           completionHandler:completionHandler]
    }

    unsafe fn newRenderPipelineStateWithDescriptor_error(self, descriptor: id, error: id) {
        msg_send![self, newRenderPipelineStateWithDescriptor:descriptor error:error]
    }

    unsafe fn newRenderPipelineStateWithDescriptor_options_reflection(self, descriptor: id,
                                                                      options: MTLPipelineOption,
                                                                      reflection: id, error: id) {
        msg_send![self, newRenderPipelineStateWithDescriptor:descriptor
                                                     options:options
                                                  reflection:reflection
                                                       error:error]
    }

    unsafe fn newComputePipelineStateWithFunction_completionHandler(
                  self,
                  function: id,
                  completionHandler: MTLNewComputePipelineStateCompletionHandler) {
        msg_send![self, newComputePipelineStateWithFunction:function
                                          completionHandler:completionHandler]
    }

    unsafe fn newComputePipelineStateWithFunction_options_completionHandler(
            self, function: id, options: MTLPipelineOption,
            completionHandler: MTLNewComputePipelineStateWithReflectionCompletionHandler) {
        msg_send![self, newComputePipelineStateWithFunction:function
                                                    options:options
                                          completionHandler:completionHandler]
    }

    unsafe fn newComputePipelineStateWithFunction_error(self, function: id, error: id) {
        msg_send![self, newComputePipelineStateWithFunction:function error:error]
    }

    unsafe fn newComputePipelineStateWithFunction_options_reflection_error(
            self, function: id, options: MTLPipelineOption, reflection: id, error: id) {
        msg_send![self, newComputePipelineStateWithFunction:function
                                                    options:options
                                                 reflection:reflection
                                                      error:error]
    }

    unsafe fn newComputePipelineStateWithDescriptor_options_completionHandler(
                   self,
                   descriptor: id,
                   options: MTLPipelineOption,
                   completionHandler: MTLNewComputePipelineStateWithReflectionCompletionHandler) {
        msg_send![self, newComputePipelineStateWithDescriptor:descriptor
                                                      options:options
                                            completionHandler:completionHandler]
    }
    unsafe fn newComputePipelineStateWithDescriptor_options_reflection_error(
            self, descriptor: id, options: MTLPipelineOption, reflection: id, error: id) {
        msg_send![self, newComputePipelineStateWithDescriptor:descriptor
                                                      options:options
                                                   reflection:reflection
                                                        error:error]
    }
}

pub type MTLNewLibraryCompletionHandler = Block<(id, id), ()>;
pub type MTLNewRenderPipleineStateCompletionHandler = Block<(id, id), ()>;
pub type MTLNewRenderPipelineStateWithReflectionCompletionHandler = Block<(id, id, id), ()>;
pub type MTLNewComputePipelineStateCompletionHandler = Block<(id, id), ()>;
pub type MTLNewComputePipelineStateWithReflectionCompletionHandler = Block<(id, id, id), ()>;
<commit_msg>Functions which take a mutable error parameter should pass that parameter by mut pointer<commit_after>#![allow(unused_variables)]

use block::Block;
use cocoa::base::{BOOL, id};
use cocoa::foundation::NSUInteger;
use libc::c_void;
use {MTLFeatureSet, MTLPipelineOption, MTLSize};

/// The `MTLDevice` protocol defines the interface to a single graphics processor (GPU). You use
/// an object that conforms to this protocol to query the capabilities of the processor and to
/// allocate objects used to access those capabilities.
///
/// Your app does not define classes that implement this protocol; it is used by Metal to provide
/// a device object to your app. To obtain a system device, call the `MTLCreateSystemDefaultDevice`
/// function or select a result from the `MTLCopyAllDevices` function.
///
/// Most objects in Metal that perform graphics rendering and computational work are associated
/// directly with a specific device. For example, texture objects are created by a device object
/// and can be used only with that device. Most methods on a `MTLDevice` object create non-transient
/// objects, including command queues, resources (such as buffers and textures), and pipeline
/// states. These objects can be expensive to create and you are encouraged to create them soon
/// after your app launches and reuse them throughout the lifetime of your app. Avoid creating these
/// objects in performance sensitive code.
pub trait MTLDevice {
    /// A Boolean value that indicates whether a device supports a packed depth/stencil buffer.
    /// (read-only)
    ///
    /// # Discussion
    ///
    /// If the value is `YES`, the device supports the `MTLPixelFormatDepth24Unorm_Stencil8` pixel
    /// format.
    unsafe fn depth24Stencil8PixelFormatSupported(self) -> BOOL;

    /// A Boolean value that indicates whether a device is configured as headless. (read-only)
    ///
    /// # Discussion
    ///
    /// If the value is `YES`, the device can not and does not have any displays attached.
    unsafe fn headless(self) -> BOOL;

    /// Boolean value that indicates whether a device is low-power. (read-only)
    ///
    /// # Discussion
    ///
    /// On multi-GPU systems that support automatic graphics switching, this property will return
    /// `YES` for the lower-power GPU.
    unsafe fn lowPower(self) -> BOOL;

    /// The maximum number of threads along each dimension of a threadgroup. (read-only)
    ///
    /// # Discussion
    ///
    /// This is the maximum compute grid size (width, height, depth) supported by the device.
    ///
    /// For more information on the specific capabilities of each feature set, see
    /// [Metal Programming Guide](https://developer.apple.com/library/prerelease/ios/documentation/
    ///     Miscellaneous/Conceptual/MetalProgrammingGuide/Introduction/
    ///     Introduction.html#//apple_ref/doc/uid/TP40014221
    /// ).
    unsafe fn maxThreadsPerGroup(self) -> MTLSize;

    /// A string that identifies the device. (read-only)
    ///
    /// # Discussion
    ///
    /// When this object is viewed in the Xcode debugger, its name is used to label the device.
    /// The name should only be used for informational purposes.
    unsafe fn name(self) -> id;

    /// Determines whether a device implements a particular feature set.
    ///
    /// # Parameters
    ///
    /// `featureSet` - A value that indicates the feature set you are interested in.
    ///
    /// # Return Value
    ///
    /// `YES` if the feature set is supported by the device; otherwise `NO`.
    ///
    /// # Discussion
    ///
    /// For more information on the specific capabilities of each feature set, see
    /// [Metal Programming Guide](https://developer.apple.com/library/prerelease/ios/documentation/
    ///     Miscellaneous/Conceptual/MetalProgrammingGuide/Introduction/
    ///     Introduction.html#//apple_ref/doc/uid/TP40014221
    /// ).
    unsafe fn supportsFeatureSet(self, featureSet: MTLFeatureSet) -> BOOL;

    /// Determines whether a device supports a given texture sample count.
    ///
    /// # Parameters
    ///
    /// `textureSampleCount` - The sample count you are interested in.
    ///
    /// # Return Value
    ///
    /// `YES` if the sample count is supported by the device; otherwise `NO`.
    ///
    /// # Discussion
    ///
    /// For more information on the specific capabilities of each feature set, see
    /// [Metal Programming Guide](https://developer.apple.com/library/prerelease/ios/documentation/
    ///     Miscellaneous/Conceptual/MetalProgrammingGuide/Introduction/
    ///     Introduction.html#//apple_ref/doc/uid/TP40014221
    /// ).
    unsafe fn supportsTextureSampleCount(self, textureSampleCount: NSUInteger) -> BOOL;

    unsafe fn newDefaultLibrary(self) -> id;
    unsafe fn newLibraryWithFile_error(self, filePath: id, error: *mut id) -> id;
    unsafe fn newLibraryWithSource_options_completionHandler(
        self, source: id, options: id, completionHandler: MTLNewLibraryCompletionHandler) -> id;

    #[cfg_attr(rustfmt, rustfmt_skip)] // This definition is too long to fit on one line
    unsafe fn newLibraryWithSource_options_error(self, source: id, options: id, error: *mut id)
                                                 -> id;
    unsafe fn newLibraryWithData_error(self, data: id, error: *mut id) -> id;

    unsafe fn newCommandQueue(self) -> id;

    #[cfg_attr(rustfmt, rustfmt_skip)] // This definition is too long to fit on one line
    unsafe fn newCommandQueueWithMaxCommandBufferCount(self, maxCommandBufferCount: NSUInteger)
                                                       -> id;

    unsafe fn newBufferWithLength_Options(self, length: NSUInteger, options: id) -> id;
    unsafe fn newBufferWithBytes_Length_Options(self, pointer: *mut c_void, length: NSUInteger,
                                                options: id)
                                                -> id;
    unsafe fn newBufferWithBytesNoCopy_length_options_deallocator(self, pointer: *mut c_void,
                                                                  length: NSUInteger,
                                                                  deallocator: Block<(*mut c_void,
                                                                                NSUInteger),
                                                                                ()>);

    unsafe fn newTextureWithDescriptor(self, descriptor: id) -> id;

    unsafe fn newSamplerStateWithDescriptor(self, descriptor: id) -> id;

    unsafe fn newStencilDepthStateWithDescriptor(self, descriptor: id) -> id;

    unsafe fn newRenderPipleineStateWithDescriptor_completionHandler(
            self, descriptor: id, completionHandler: MTLNewRenderPipleineStateCompletionHandler);

    unsafe fn newRenderPipelineStateWithDescriptor_options_completionHandler(
            self, descriptor: id, options: MTLPipelineOption,
            completionHandler: MTLNewRenderPipelineStateWithReflectionCompletionHandler);

    unsafe fn newRenderPipelineStateWithDescriptor_error(self, descriptor: id, error: id);

    unsafe fn newRenderPipelineStateWithDescriptor_options_reflection(self, descriptor: id,
                                                                      options: MTLPipelineOption,
                                                                      reflection: id, error: id);

    unsafe fn newComputePipelineStateWithFunction_completionHandler(
            self, function: id, completionHandler: MTLNewComputePipelineStateCompletionHandler);

    unsafe fn newComputePipelineStateWithFunction_options_completionHandler(
            self, function: id, options: MTLPipelineOption,
            completionHandler: MTLNewComputePipelineStateWithReflectionCompletionHandler);

    unsafe fn newComputePipelineStateWithFunction_error(self, function: id, error: id);

    unsafe fn newComputePipelineStateWithFunction_options_reflection_error(
            self, function: id, options: MTLPipelineOption, reflection: id, error: id);

    unsafe fn newComputePipelineStateWithDescriptor_options_completionHandler(
            self, descriptor: id, options: MTLPipelineOption,
            completionHandler: MTLNewComputePipelineStateWithReflectionCompletionHandler);

    unsafe fn newComputePipelineStateWithDescriptor_options_reflection_error(
            self, descriptor: id, options: MTLPipelineOption, reflection: id, error: id);
}

impl MTLDevice for id {
    unsafe fn depth24Stencil8PixelFormatSupported(self) -> BOOL {
        msg_send![self, isDepth24Stencil8PixelFormatSupported]
    }

    unsafe fn headless(self) -> BOOL {
        msg_send![self, isHeadless]
    }

    unsafe fn lowPower(self) -> BOOL {
        msg_send![self, isLowPower]
    }

    unsafe fn maxThreadsPerGroup(self) -> MTLSize {
        msg_send![self, maxThreadsPerThreadgroup]
    }

    unsafe fn name(self) -> id {
        msg_send![self, name]
    }

    unsafe fn supportsFeatureSet(self, featureSet: MTLFeatureSet) -> BOOL {
        msg_send![self, supportsFeatureSet:featureSet]
    }

    unsafe fn supportsTextureSampleCount(self, textureSampleCount: NSUInteger) -> BOOL {
        msg_send![self, supportsTextureSampleCount:textureSampleCount]
    }

    unsafe fn newDefaultLibrary(self) -> id {
        msg_send![self, newDefaultLibrary]
    }

    unsafe fn newLibraryWithFile_error(self, filePath: id, error: *mut id) -> id {
        msg_send![self, newLibraryWithFile:filePath error:error]
    }

    unsafe fn newLibraryWithSource_options_completionHandler(
        self, source: id, options: id, completionHandler: MTLNewLibraryCompletionHandler)
        -> id {
        msg_send![self, newLibraryWithSource:source options:options
                           completionHandler:completionHandler]
    }

    #[cfg_attr(rustfmt, rustfmt_skip)] // This definition is too long to fit on one line
    unsafe fn newLibraryWithSource_options_error(self, source: id, options: id, error: *mut id)
                                                 -> id {
        msg_send![self, newLibraryWithSource:source options:options error:error]
    }

    unsafe fn newLibraryWithData_error(self, data: id, error: *mut id) -> id {
        msg_send![self, newLibraryWithData:data error:error]
    }

    unsafe fn newCommandQueue(self) -> id {
        msg_send![self, newCommandQueue]
    }

    #[cfg_attr(rustfmt, rustfmt_skip)] // This definition is too long to fit on one line
    unsafe fn newCommandQueueWithMaxCommandBufferCount(self, maxCommandBufferCount: NSUInteger)
                                                       -> id {
        msg_send![self, newCommandQueueWithMaxCommandBufferCount:maxCommandBufferCount]
    }

    unsafe fn newBufferWithLength_Options(self, length: NSUInteger, options: id) -> id {
        msg_send![self, newBufferWithLength:length options:options]
    }

    unsafe fn newBufferWithBytes_Length_Options(self, pointer: *mut c_void, length: NSUInteger,
                                                options: id)
                                                -> id {
        msg_send![self, newBufferWithBytes:pointer length:length options:options]
    }

    unsafe fn newBufferWithBytesNoCopy_length_options_deallocator(self, pointer: *mut c_void,
                                                                  length: NSUInteger,
                                                                  deallocator: Block<(*mut c_void,
                                                                                NSUInteger),
                                                                                ()>) {
        msg_send![self, newBufferWithBytesNoCopy:pointer length:length deallocator:deallocator]
    }

    unsafe fn newTextureWithDescriptor(self, descriptor: id) -> id {
        msg_send![self, newTextureWithDescriptor:descriptor]
    }

    unsafe fn newSamplerStateWithDescriptor(self, descriptor: id) -> id {
        msg_send![self, newSamplerStateWithDescriptor:descriptor]
    }

    unsafe fn newStencilDepthStateWithDescriptor(self, descriptor: id) -> id {
        msg_send![self, newStencilDepthStateWithDescriptor:descriptor]
    }

    unsafe fn newRenderPipleineStateWithDescriptor_completionHandler(
            self, descriptor: id,
            completionHandler: MTLNewRenderPipleineStateCompletionHandler) {
        msg_send![self, newRenderPipleineStateWithDescriptor:descriptor
                                           completionHandler:completionHandler]
    }

    unsafe fn newRenderPipelineStateWithDescriptor_options_completionHandler(
            self, descriptor: id, options: MTLPipelineOption,
            completionHandler: MTLNewRenderPipelineStateWithReflectionCompletionHandler) {
        msg_send![self, newRenderPipelineStateWithDescriptor:descriptor
                                                     options:options
                                           completionHandler:completionHandler]
    }

    unsafe fn newRenderPipelineStateWithDescriptor_error(self, descriptor: id, error: id) {
        msg_send![self, newRenderPipelineStateWithDescriptor:descriptor error:error]
    }

    unsafe fn newRenderPipelineStateWithDescriptor_options_reflection(self, descriptor: id,
                                                                      options: MTLPipelineOption,
                                                                      reflection: id, error: id) {
        msg_send![self, newRenderPipelineStateWithDescriptor:descriptor
                                                     options:options
                                                  reflection:reflection
                                                       error:error]
    }

    unsafe fn newComputePipelineStateWithFunction_completionHandler(
                  self,
                  function: id,
                  completionHandler: MTLNewComputePipelineStateCompletionHandler) {
        msg_send![self, newComputePipelineStateWithFunction:function
                                          completionHandler:completionHandler]
    }

    unsafe fn newComputePipelineStateWithFunction_options_completionHandler(
            self, function: id, options: MTLPipelineOption,
            completionHandler: MTLNewComputePipelineStateWithReflectionCompletionHandler) {
        msg_send![self, newComputePipelineStateWithFunction:function
                                                    options:options
                                          completionHandler:completionHandler]
    }

    unsafe fn newComputePipelineStateWithFunction_error(self, function: id, error: id) {
        msg_send![self, newComputePipelineStateWithFunction:function error:error]
    }

    unsafe fn newComputePipelineStateWithFunction_options_reflection_error(
            self, function: id, options: MTLPipelineOption, reflection: id, error: id) {
        msg_send![self, newComputePipelineStateWithFunction:function
                                                    options:options
                                                 reflection:reflection
                                                      error:error]
    }

    unsafe fn newComputePipelineStateWithDescriptor_options_completionHandler(
                   self,
                   descriptor: id,
                   options: MTLPipelineOption,
                   completionHandler: MTLNewComputePipelineStateWithReflectionCompletionHandler) {
        msg_send![self, newComputePipelineStateWithDescriptor:descriptor
                                                      options:options
                                            completionHandler:completionHandler]
    }
    unsafe fn newComputePipelineStateWithDescriptor_options_reflection_error(
            self, descriptor: id, options: MTLPipelineOption, reflection: id, error: id) {
        msg_send![self, newComputePipelineStateWithDescriptor:descriptor
                                                      options:options
                                                   reflection:reflection
                                                        error:error]
    }
}

pub type MTLNewLibraryCompletionHandler = Block<(id, id), ()>;
pub type MTLNewRenderPipleineStateCompletionHandler = Block<(id, id), ()>;
pub type MTLNewRenderPipelineStateWithReflectionCompletionHandler = Block<(id, id, id), ()>;
pub type MTLNewComputePipelineStateCompletionHandler = Block<(id, id), ()>;
pub type MTLNewComputePipelineStateWithReflectionCompletionHandler = Block<(id, id, id), ()>;
<|endoftext|>


<commit_before>// Copyright 2018 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 infer::InferCtxt;
use ty::{self, Ty, TyCtxt};
use hir::def_id::DefId;

use super::{FulfillmentContext, FulfillmentError};
use super::{ObligationCause, PredicateObligation, PendingPredicateObligation};

pub trait TraitEngine<'tcx> {
    fn normalize_projection_type<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
        param_env: ty::ParamEnv<'tcx>,
        projection_ty: ty::ProjectionTy<'tcx>,
        cause: ObligationCause<'tcx>,
    ) -> Ty<'tcx>;

    fn register_bound<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
        param_env: ty::ParamEnv<'tcx>,
        ty: Ty<'tcx>,
        def_id: DefId,
        cause: ObligationCause<'tcx>,
    );

    fn register_predicate_obligation<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
        obligation: PredicateObligation<'tcx>,
    );

    fn select_all_or_error<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
    ) -> Result<(), Vec<FulfillmentError<'tcx>>>;

    fn select_where_possible<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
    ) -> Result<(), Vec<FulfillmentError<'tcx>>>;

    fn pending_obligations(&self) -> Vec<PendingPredicateObligation<'tcx>>;
}

impl<'a, 'gcx, 'tcx> dyn TraitEngine<'tcx> +'tcx {
   pub fn new(_tcx: TyCtxt<'_, '_, 'tcx>) -> Box<Self> {
       Box::new(FulfillmentContext::new())
   }

   pub fn register_predicate_obligations<I>(&mut self,
                                            infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                            obligations: I)
       where I: IntoIterator<Item = PredicateObligation<'tcx>>
   {
       for obligation in obligations {
           self.register_predicate_obligation(infcx, obligation);
       }
   }
}
<commit_msg>apply rustfmt<commit_after>// Copyright 2018 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 infer::InferCtxt;
use ty::{self, Ty, TyCtxt};
use hir::def_id::DefId;

use super::{FulfillmentContext, FulfillmentError};
use super::{ObligationCause, PendingPredicateObligation, PredicateObligation};

pub trait TraitEngine<'tcx> {
    fn normalize_projection_type<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
        param_env: ty::ParamEnv<'tcx>,
        projection_ty: ty::ProjectionTy<'tcx>,
        cause: ObligationCause<'tcx>,
    ) -> Ty<'tcx>;

    fn register_bound<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
        param_env: ty::ParamEnv<'tcx>,
        ty: Ty<'tcx>,
        def_id: DefId,
        cause: ObligationCause<'tcx>,
    );

    fn register_predicate_obligation<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
        obligation: PredicateObligation<'tcx>,
    );

    fn select_all_or_error<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
    ) -> Result<(), Vec<FulfillmentError<'tcx>>>;

    fn select_where_possible<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
    ) -> Result<(), Vec<FulfillmentError<'tcx>>>;

    fn pending_obligations(&self) -> Vec<PendingPredicateObligation<'tcx>>;
}

impl<'a, 'gcx, 'tcx> TraitEngine<'tcx> + 'tcx {
    pub fn new(_tcx: TyCtxt<'_, '_, 'tcx>) -> Box<Self> {
        Box::new(FulfillmentContext::new())
    }

    pub fn register_predicate_obligations<I>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
        obligations: I,
    ) where
        I: IntoIterator<Item = PredicateObligation<'tcx>>,
    {
        for obligation in obligations {
            self.register_predicate_obligation(infcx, obligation);
        }
    }
}
<|endoftext|>