<commit_before>use std::{cell::RefCell, default::Default, fmt};

use union_find::{QuickFindUf, Union, UnionByRank, UnionFind, UnionResult};

use crate::base::{
    fixed::{FixedVec, FixedVecMap},
    kind::ArcKind,
    symbol::Symbol,
    types::{self, ArcType, InternerVisitor, Skolem, Type, TypeContext, Walker},
};
use crate::typ::RcType;

#[derive(Debug, PartialEq, Functor)]
pub enum Error<T> {
    Occurs(T, T),
}

impl<T> fmt::Display for Error<T>
where
    T: fmt::Display,
    T: for<'a> types::ToDoc<'a, ::pretty::Arena<'a, ()>, (), ()>,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match *self {
            Occurs(ref var, ref typ) => write!(f, "Variable `{}` occurs in `{}`.", var, typ),
        }
    }
}

pub struct Substitution<T>
where
    T: Substitutable,
{
    /// Union-find data structure used to store the relationships of all variables in the
    /// substitution
    union: RefCell<QuickFindUf<UnionByLevel>>,
    /// Vector containing all created variables for this substitution. Needed for the `real` method
    /// which needs to always be able to return a `&T` reference
    variables: FixedVec<T>,
    /// For variables which have been infered to have a real type (not a variable) their types are
    /// stored here. As the type stored will never changed we use a `FixedVecMap` lets `real` return
    /// `&T` from this map safely.
    types: FixedVecMap<T>,
    factory: T::Factory,
    interner: T::Interner,
}

impl<T> TypeContext<Symbol, T> for Substitution<T>
where
    T: Substitutable + From<Type<Symbol, T>>,
    for<'a> &'a T::Interner: TypeContext<Symbol, T>,
{
    gluon_base::forward_type_interner_methods!(Symbol, T, self_, &self_.interner);
}

impl<'a, T> TypeContext<Symbol, T> for &'a Substitution<T>
where
    T: Substitutable + From<Type<Symbol, T>>,
    &'a T::Interner: TypeContext<Symbol, T>,
{
    gluon_base::forward_type_interner_methods!(Symbol, T, self_, &self_.interner);
}

impl<'a> types::Substitution<Symbol, RcType> for &'a Substitution<RcType> {
    fn new_var(&mut self) -> RcType {
        Substitution::new_var(*self)
    }
    fn new_skolem(&mut self, name: Symbol, kind: ArcKind) -> RcType {
        Substitution::new_skolem(*self, name, kind)
    }
}

impl<T> Default for Substitution<T>
where
    T: Substitutable,
    T::Factory: Default,
    T::Interner: Default,
{
    fn default() -> Substitution<T> {
        Substitution::new(Default::default(), Default::default())
    }
}

/// Trait which variables need to implement to allow the substitution to get to the u32 identifying
/// the variable
pub trait Variable {
    fn get_id(&self) -> u32;
}

impl Variable for u32 {
    fn get_id(&self) -> u32 {
        *self
    }
}

pub trait VariableFactory {
    type Variable: Variable;

    fn new(&self, x: u32) -> Self::Variable;
}

impl VariableFactory for () {
    type Variable = u32;

    fn new(&self, x: u32) -> Self::Variable {
        x
    }
}

/// Trait implemented on types which may contain substitutable variables
pub trait Substitutable: Sized {
    type Variable: Variable;

    type Factory: VariableFactory<Variable = Self::Variable>;

    type Interner: Default;

    /// Constructs a new object from its variable type
    fn from_variable(subs: &Substitution<Self>, x: Self::Variable) -> Self;

    /// Retrieves the variable if `self` is a variable otherwise returns `None`
    fn get_var(&self) -> Option<&Self::Variable>;

    fn get_id(&self) -> Option<u32> {
        self.get_var().map(|var| var.get_id())
    }

    fn traverse<'a, F>(&'a self, f: &mut F)
    where
        F: Walker<'a, Self>;

    fn instantiate(&self, subs: &Substitution<Self>) -> Self;

    // Allowed return true even if the type does not contain variables but not false if it does
    // contain
    fn contains_variables(&self) -> bool {
        true
    }

    fn on_union(&self) -> Option<&Self> {
        None
    }
}

pub fn occurs<T>(typ: &T, subs: &Substitution<T>, var: &T::Variable) -> bool
where
    T: Substitutable,
{
    struct Occurs<'a, T: Substitutable + 'a> {
        occurs: bool,
        var: &'a T::Variable,
        subs: &'a Substitution<T>,
    }
    impl<'a, 't, T> Walker<'t, T> for Occurs<'a, T>
    where
        T: Substitutable,
    {
        fn walk(&mut self, typ: &'t T) {
            if !typ.contains_variables() || self.occurs {
                return;
            }
            let typ = self.subs.real(typ);
            if let Some(other) = typ.get_var() {
                if self.var.get_id() == other.get_id() {
                    self.occurs = true;
                    typ.traverse(self);
                    return;
                }
                self.subs.update_level(self.var.get_id(), other.get_id());
            }
            typ.traverse(self);
        }
    }

    let mut occurs = Occurs {
        occurs: false,
        var: var,
        subs: subs,
    };
    occurs.walk(typ);
    occurs.occurs
}

/// Specialized union implementation which makes sure that variables with a higher level always
/// point to the lower level variable.
///
/// map.union(1, 2);
/// map.find(2) -> 1
/// map.find(1) -> 1
#[derive(Debug)]
struct UnionByLevel {
    rank: UnionByRank,
    level: u32,
}

impl Default for UnionByLevel {
    fn default() -> UnionByLevel {
        UnionByLevel {
            rank: UnionByRank::default(),
            level: ::std::u32::MAX,
        }
    }
}

impl Union for UnionByLevel {
    #[inline]
    fn union(left: UnionByLevel, right: UnionByLevel) -> UnionResult<UnionByLevel> {
        use std::cmp::Ordering;
        let (rank_result, rank) = match Union::union(left.rank, right.rank) {
            UnionResult::Left(l) => (
                UnionResult::Left(UnionByLevel {
                    rank: l,
                    level: left.level,
                }),
                l,
            ),
            UnionResult::Right(r) => (
                UnionResult::Right(UnionByLevel {
                    rank: r,
                    level: left.level,
                }),
                r,
            ),
        };
        match left.level.cmp(&right.level) {
            Ordering::Less => UnionResult::Left(UnionByLevel {
                rank: rank,
                level: left.level,
            }),
            Ordering::Greater => UnionResult::Right(UnionByLevel {
                rank: rank,
                level: right.level,
            }),
            Ordering::Equal => rank_result,
        }
    }
}

impl<T> fmt::Debug for Substitution<T>
where
    T: fmt::Debug + Substitutable,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "Substitution {{ map: {:?}, var_id: {:?} }}",
            self.union.borrow(),
            self.var_id()
        )
    }
}

impl<T> Substitution<T>
where
    T: Substitutable,
{
    pub fn new(factory: T::Factory, interner: T::Interner) -> Substitution<T> {
        Substitution {
            union: RefCell::new(QuickFindUf::new(0)),
            variables: FixedVec::new(),
            types: FixedVecMap::new(),
            factory: factory,
            interner,
        }
    }

    pub fn var_id(&self) -> u32 {
        self.variables.len() as u32
    }

    pub fn clear(&mut self) {
        self.types.clear();
        self.variables.clear();
    }

    pub fn insert(&self, var: u32, t: T) {
        match t.get_var() {
            Some(_) => ice!(
                "Tried to insert variable which is not allowed as that would cause memory \
                 unsafety"
            ),
            None => match self.types.try_insert(var as usize, t.into()) {
                Ok(()) => (),
                Err(_) => ice!("Expected variable to not have a type associated with it"),
            },
        }
    }

    pub fn replace(&mut self, var: u32, t: T) {
        debug_assert!(t.get_id() != Some(var));
        self.types.insert(var as usize, t.into());
    }

    /// Creates a new variable
    pub fn new_var(&self) -> T
    where
        T: Clone,
    {
        self.new_var_fn(|var| T::from_variable(self, self.factory.new(var)))
    }

    pub fn new_var_fn<F>(&self, f: F) -> T
    where
        T: Clone,
        F: FnOnce(u32) -> T,
    {
        let var_id = self.variables.len() as u32;
        let id = self.union.borrow_mut().insert(UnionByLevel {
            ..UnionByLevel::default()
        });
        assert!(id == self.variables.len());
        debug!("New var {}", self.variables.len());

        let var = f(var_id);
        self.variables.push(var.clone().into());
        var
    }

    /// If `typ` is a variable this returns the real unified value of that variable. Otherwise it
    /// just returns the type itself. Note that the returned type may contain terms which also need
    /// to have `real` called on them.
    pub fn real<'r>(&'r self, typ: &'r T) -> &'r T {
        match typ.get_var() {
            Some(var) => match self.find_type_for_var(var.get_id()) {
                Some(t) => t,
                None => typ,
            },
            _ => typ,
        }
    }

    pub fn get_var(&self, var: u32) -> Option<&T> {
        self.variables.get(var as usize)
    }

    pub fn find_type_for_var(&self, var: u32) -> Option<&T> {
        let mut union = self.union.borrow_mut();
        if var as usize >= union.size() {
            return None;
        }
        let index = union.find(var as usize);
        self.types.get(index).or_else(|| {
            if var == index as u32 {
                None
            } else {
                Some(&self.variables[index as usize])
            }
        })
    }

    /// Updates the level of `other` to be the minimum level value of `var` and `other`
    pub fn update_level(&self, var: u32, other: u32) {
        let level = ::std::cmp::min(self.get_level(var), self.get_level(other));
        let mut union = self.union.borrow_mut();
        union.get_mut(other as usize).level = level;
    }

    pub fn set_level(&self, var: u32, level: u32) {
        let mut union = self.union.borrow_mut();
        union.get_mut(var as usize).level = level;
    }

    pub fn get_level(&self, mut var: u32) -> u32 {
        if let Some(v) = self.find_type_for_var(var) {
            var = v.get_var().map_or(var, |v| v.get_id());
        }
        let mut union = self.union.borrow_mut();
        let level = &mut union.get_mut(var as usize).level;
        *level = ::std::cmp::min(*level, var);
        *level
    }

    pub fn replace_variable(&self, typ: &T) -> Option<T>
    where
        T: Clone,
    {
        match typ.get_var() {
            Some(id) => self.find_type_for_var(id.get_id()).cloned(),
            None => None,
        }
    }
}

pub fn is_variable_unified(subs: &Substitution<RcType>, var: &RcType) -> bool {
    match **var {
        Type::Variable(ref var) => subs.find_type_for_var(var.id).is_some(),
        _ => false,
    }
}

impl<T: Substitutable + Clone> Substitution<T> {
    pub fn make_real(&self, typ: &mut T) {
        *typ = self.real(typ).clone();
    }
}

impl<T: Substitutable + PartialEq + Clone> Substitution<T> {
    /// Takes `id` and updates the substitution to say that it should have the same type as `typ`
    pub fn union(&self, id: &T::Variable, typ: &T) -> Result<Option<T>, Error<T>>
    where
        T::Variable: Clone,
        T: fmt::Display,
    {
        let resolved_type = typ.on_union();
        let typ = resolved_type.unwrap_or(typ);
        // Nothing needs to be done if both are the same variable already (also prevents the occurs
        // check from failing)
        if typ
            .get_var()
            .map_or(false, |other| other.get_id() == id.get_id())
        {
            return Ok(None);
        }
        if occurs(typ, self, id) {
            return Err(Error::Occurs(
                T::from_variable(self, id.clone()),
                typ.clone(),
            ));
        }
        {
            let id_type = self.find_type_for_var(id.get_id());
            let other_type = self.real(typ);
            if id_type.map_or(false, |x| x == other_type)
                || other_type.get_var().map(|y| y.get_id()) == Some(id.get_id())
            {
                return Ok(None);
            }
        }
        {
            let typ = resolved_type.unwrap_or(typ);
            match typ.get_var().map(|id| id.get_id()) {
                Some(other_id) => {
                    self.union
                        .borrow_mut()
                        .union(id.get_id() as usize, other_id as usize);
                    self.update_level(id.get_id(), other_id);
                    self.update_level(other_id, id.get_id());
                }
                _ => {
                    if let Some(other_id) = typ.get_id() {
                        self.update_level(id.get_id(), other_id);
                    }

                    self.insert(id.get_id(), typ.clone());
                }
            }
        }
        Ok(resolved_type.cloned())
    }

    pub fn unbound_variables(&self, level: u32) -> impl Iterator<Item = &T> {
        (level..(self.variables.len() as u32)).filter_map(move |i| {
            if self.find_type_for_var(i).is_none() && self.get_level(i) >= level {
                Some(&self.variables[i as usize])
            } else {
                None
            }
        })
    }
}

impl Substitution<RcType> {
    pub fn new_skolem(&self, name: Symbol, kind: ArcKind) -> RcType {
        self.new_var_fn(|id| (&*self).skolem(Skolem { name, id, kind }))
    }

    pub fn zonk(&self, typ: &RcType) -> RcType {
        types::walk_move_type(
            typ.clone(),
            &mut InternerVisitor::new(&mut &*self, |_, typ: &RcType| match typ.get_var() {
                Some(var) => match self.find_type_for_var(var.get_id()) {
                    Some(t) => Some(self.zonk(t)),
                    None => None,
                },
                None => None,
            }),
        )
    }

    // Stub kept in case multiple types are attempted again
    pub fn bind_arc(&self, typ: &RcType) -> ArcType {
        typ.clone()
    }
}
<commit_msg>perf: Avoid recursing when zonking a type without variables<commit_after>use std::{cell::RefCell, default::Default, fmt};

use union_find::{QuickFindUf, Union, UnionByRank, UnionFind, UnionResult};

use crate::base::{
    fixed::{FixedVec, FixedVecMap},
    kind::ArcKind,
    symbol::Symbol,
    types::{self, ArcType, Flags, FlagsVisitor, Skolem, Type, TypeContext, Walker},
};
use crate::typ::RcType;

#[derive(Debug, PartialEq, Functor)]
pub enum Error<T> {
    Occurs(T, T),
}

impl<T> fmt::Display for Error<T>
where
    T: fmt::Display,
    T: for<'a> types::ToDoc<'a, ::pretty::Arena<'a, ()>, (), ()>,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match *self {
            Occurs(ref var, ref typ) => write!(f, "Variable `{}` occurs in `{}`.", var, typ),
        }
    }
}

pub struct Substitution<T>
where
    T: Substitutable,
{
    /// Union-find data structure used to store the relationships of all variables in the
    /// substitution
    union: RefCell<QuickFindUf<UnionByLevel>>,
    /// Vector containing all created variables for this substitution. Needed for the `real` method
    /// which needs to always be able to return a `&T` reference
    variables: FixedVec<T>,
    /// For variables which have been infered to have a real type (not a variable) their types are
    /// stored here. As the type stored will never changed we use a `FixedVecMap` lets `real` return
    /// `&T` from this map safely.
    types: FixedVecMap<T>,
    factory: T::Factory,
    interner: T::Interner,
}

impl<T> TypeContext<Symbol, T> for Substitution<T>
where
    T: Substitutable + From<Type<Symbol, T>>,
    for<'a> &'a T::Interner: TypeContext<Symbol, T>,
{
    gluon_base::forward_type_interner_methods!(Symbol, T, self_, &self_.interner);
}

impl<'a, T> TypeContext<Symbol, T> for &'a Substitution<T>
where
    T: Substitutable + From<Type<Symbol, T>>,
    &'a T::Interner: TypeContext<Symbol, T>,
{
    gluon_base::forward_type_interner_methods!(Symbol, T, self_, &self_.interner);
}

impl<'a> types::Substitution<Symbol, RcType> for &'a Substitution<RcType> {
    fn new_var(&mut self) -> RcType {
        Substitution::new_var(*self)
    }
    fn new_skolem(&mut self, name: Symbol, kind: ArcKind) -> RcType {
        Substitution::new_skolem(*self, name, kind)
    }
}

impl<T> Default for Substitution<T>
where
    T: Substitutable,
    T::Factory: Default,
    T::Interner: Default,
{
    fn default() -> Substitution<T> {
        Substitution::new(Default::default(), Default::default())
    }
}

/// Trait which variables need to implement to allow the substitution to get to the u32 identifying
/// the variable
pub trait Variable {
    fn get_id(&self) -> u32;
}

impl Variable for u32 {
    fn get_id(&self) -> u32 {
        *self
    }
}

pub trait VariableFactory {
    type Variable: Variable;

    fn new(&self, x: u32) -> Self::Variable;
}

impl VariableFactory for () {
    type Variable = u32;

    fn new(&self, x: u32) -> Self::Variable {
        x
    }
}

/// Trait implemented on types which may contain substitutable variables
pub trait Substitutable: Sized {
    type Variable: Variable;

    type Factory: VariableFactory<Variable = Self::Variable>;

    type Interner: Default;

    /// Constructs a new object from its variable type
    fn from_variable(subs: &Substitution<Self>, x: Self::Variable) -> Self;

    /// Retrieves the variable if `self` is a variable otherwise returns `None`
    fn get_var(&self) -> Option<&Self::Variable>;

    fn get_id(&self) -> Option<u32> {
        self.get_var().map(|var| var.get_id())
    }

    fn traverse<'a, F>(&'a self, f: &mut F)
    where
        F: Walker<'a, Self>;

    fn instantiate(&self, subs: &Substitution<Self>) -> Self;

    // Allowed return true even if the type does not contain variables but not false if it does
    // contain
    fn contains_variables(&self) -> bool {
        true
    }

    fn on_union(&self) -> Option<&Self> {
        None
    }
}

pub fn occurs<T>(typ: &T, subs: &Substitution<T>, var: &T::Variable) -> bool
where
    T: Substitutable,
{
    struct Occurs<'a, T: Substitutable + 'a> {
        occurs: bool,
        var: &'a T::Variable,
        subs: &'a Substitution<T>,
    }
    impl<'a, 't, T> Walker<'t, T> for Occurs<'a, T>
    where
        T: Substitutable,
    {
        fn walk(&mut self, typ: &'t T) {
            if !typ.contains_variables() || self.occurs {
                return;
            }
            let typ = self.subs.real(typ);
            if let Some(other) = typ.get_var() {
                if self.var.get_id() == other.get_id() {
                    self.occurs = true;
                    typ.traverse(self);
                    return;
                }
                self.subs.update_level(self.var.get_id(), other.get_id());
            }
            typ.traverse(self);
        }
    }

    let mut occurs = Occurs {
        occurs: false,
        var: var,
        subs: subs,
    };
    occurs.walk(typ);
    occurs.occurs
}

/// Specialized union implementation which makes sure that variables with a higher level always
/// point to the lower level variable.
///
/// map.union(1, 2);
/// map.find(2) -> 1
/// map.find(1) -> 1
#[derive(Debug)]
struct UnionByLevel {
    rank: UnionByRank,
    level: u32,
}

impl Default for UnionByLevel {
    fn default() -> UnionByLevel {
        UnionByLevel {
            rank: UnionByRank::default(),
            level: ::std::u32::MAX,
        }
    }
}

impl Union for UnionByLevel {
    #[inline]
    fn union(left: UnionByLevel, right: UnionByLevel) -> UnionResult<UnionByLevel> {
        use std::cmp::Ordering;
        let (rank_result, rank) = match Union::union(left.rank, right.rank) {
            UnionResult::Left(l) => (
                UnionResult::Left(UnionByLevel {
                    rank: l,
                    level: left.level,
                }),
                l,
            ),
            UnionResult::Right(r) => (
                UnionResult::Right(UnionByLevel {
                    rank: r,
                    level: left.level,
                }),
                r,
            ),
        };
        match left.level.cmp(&right.level) {
            Ordering::Less => UnionResult::Left(UnionByLevel {
                rank: rank,
                level: left.level,
            }),
            Ordering::Greater => UnionResult::Right(UnionByLevel {
                rank: rank,
                level: right.level,
            }),
            Ordering::Equal => rank_result,
        }
    }
}

impl<T> fmt::Debug for Substitution<T>
where
    T: fmt::Debug + Substitutable,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "Substitution {{ map: {:?}, var_id: {:?} }}",
            self.union.borrow(),
            self.var_id()
        )
    }
}

impl<T> Substitution<T>
where
    T: Substitutable,
{
    pub fn new(factory: T::Factory, interner: T::Interner) -> Substitution<T> {
        Substitution {
            union: RefCell::new(QuickFindUf::new(0)),
            variables: FixedVec::new(),
            types: FixedVecMap::new(),
            factory: factory,
            interner,
        }
    }

    pub fn var_id(&self) -> u32 {
        self.variables.len() as u32
    }

    pub fn clear(&mut self) {
        self.types.clear();
        self.variables.clear();
    }

    pub fn insert(&self, var: u32, t: T) {
        match t.get_var() {
            Some(_) => ice!(
                "Tried to insert variable which is not allowed as that would cause memory \
                 unsafety"
            ),
            None => match self.types.try_insert(var as usize, t.into()) {
                Ok(()) => (),
                Err(_) => ice!("Expected variable to not have a type associated with it"),
            },
        }
    }

    pub fn replace(&mut self, var: u32, t: T) {
        debug_assert!(t.get_id() != Some(var));
        self.types.insert(var as usize, t.into());
    }

    /// Creates a new variable
    pub fn new_var(&self) -> T
    where
        T: Clone,
    {
        self.new_var_fn(|var| T::from_variable(self, self.factory.new(var)))
    }

    pub fn new_var_fn<F>(&self, f: F) -> T
    where
        T: Clone,
        F: FnOnce(u32) -> T,
    {
        let var_id = self.variables.len() as u32;
        let id = self.union.borrow_mut().insert(UnionByLevel {
            ..UnionByLevel::default()
        });
        assert!(id == self.variables.len());
        debug!("New var {}", self.variables.len());

        let var = f(var_id);
        self.variables.push(var.clone().into());
        var
    }

    /// If `typ` is a variable this returns the real unified value of that variable. Otherwise it
    /// just returns the type itself. Note that the returned type may contain terms which also need
    /// to have `real` called on them.
    pub fn real<'r>(&'r self, typ: &'r T) -> &'r T {
        match typ.get_var() {
            Some(var) => match self.find_type_for_var(var.get_id()) {
                Some(t) => t,
                None => typ,
            },
            _ => typ,
        }
    }

    pub fn get_var(&self, var: u32) -> Option<&T> {
        self.variables.get(var as usize)
    }

    pub fn find_type_for_var(&self, var: u32) -> Option<&T> {
        let mut union = self.union.borrow_mut();
        if var as usize >= union.size() {
            return None;
        }
        let index = union.find(var as usize);
        self.types.get(index).or_else(|| {
            if var == index as u32 {
                None
            } else {
                Some(&self.variables[index as usize])
            }
        })
    }

    /// Updates the level of `other` to be the minimum level value of `var` and `other`
    pub fn update_level(&self, var: u32, other: u32) {
        let level = ::std::cmp::min(self.get_level(var), self.get_level(other));
        let mut union = self.union.borrow_mut();
        union.get_mut(other as usize).level = level;
    }

    pub fn set_level(&self, var: u32, level: u32) {
        let mut union = self.union.borrow_mut();
        union.get_mut(var as usize).level = level;
    }

    pub fn get_level(&self, mut var: u32) -> u32 {
        if let Some(v) = self.find_type_for_var(var) {
            var = v.get_var().map_or(var, |v| v.get_id());
        }
        let mut union = self.union.borrow_mut();
        let level = &mut union.get_mut(var as usize).level;
        *level = ::std::cmp::min(*level, var);
        *level
    }

    pub fn replace_variable(&self, typ: &T) -> Option<T>
    where
        T: Clone,
    {
        match typ.get_var() {
            Some(id) => self.find_type_for_var(id.get_id()).cloned(),
            None => None,
        }
    }
}

pub fn is_variable_unified(subs: &Substitution<RcType>, var: &RcType) -> bool {
    match **var {
        Type::Variable(ref var) => subs.find_type_for_var(var.id).is_some(),
        _ => false,
    }
}

impl<T: Substitutable + Clone> Substitution<T> {
    pub fn make_real(&self, typ: &mut T) {
        *typ = self.real(typ).clone();
    }
}

impl<T: Substitutable + PartialEq + Clone> Substitution<T> {
    /// Takes `id` and updates the substitution to say that it should have the same type as `typ`
    pub fn union(&self, id: &T::Variable, typ: &T) -> Result<Option<T>, Error<T>>
    where
        T::Variable: Clone,
        T: fmt::Display,
    {
        let resolved_type = typ.on_union();
        let typ = resolved_type.unwrap_or(typ);
        // Nothing needs to be done if both are the same variable already (also prevents the occurs
        // check from failing)
        if typ
            .get_var()
            .map_or(false, |other| other.get_id() == id.get_id())
        {
            return Ok(None);
        }
        if occurs(typ, self, id) {
            return Err(Error::Occurs(
                T::from_variable(self, id.clone()),
                typ.clone(),
            ));
        }
        {
            let id_type = self.find_type_for_var(id.get_id());
            let other_type = self.real(typ);
            if id_type.map_or(false, |x| x == other_type)
                || other_type.get_var().map(|y| y.get_id()) == Some(id.get_id())
            {
                return Ok(None);
            }
        }
        {
            let typ = resolved_type.unwrap_or(typ);
            match typ.get_var().map(|id| id.get_id()) {
                Some(other_id) => {
                    self.union
                        .borrow_mut()
                        .union(id.get_id() as usize, other_id as usize);
                    self.update_level(id.get_id(), other_id);
                    self.update_level(other_id, id.get_id());
                }
                _ => {
                    if let Some(other_id) = typ.get_id() {
                        self.update_level(id.get_id(), other_id);
                    }

                    self.insert(id.get_id(), typ.clone());
                }
            }
        }
        Ok(resolved_type.cloned())
    }

    pub fn unbound_variables(&self, level: u32) -> impl Iterator<Item = &T> {
        (level..(self.variables.len() as u32)).filter_map(move |i| {
            if self.find_type_for_var(i).is_none() && self.get_level(i) >= level {
                Some(&self.variables[i as usize])
            } else {
                None
            }
        })
    }
}

impl Substitution<RcType> {
    pub fn new_skolem(&self, name: Symbol, kind: ArcKind) -> RcType {
        self.new_var_fn(|id| (&*self).skolem(Skolem { name, id, kind }))
    }

    pub fn zonk(&self, typ: &RcType) -> RcType {
        types::walk_move_type(
            typ.clone(),
            &mut FlagsVisitor(Flags::HAS_VARIABLES, |typ: &RcType| match typ.get_var() {
                Some(var) => match self.find_type_for_var(var.get_id()) {
                    Some(t) => Some(self.zonk(t)),
                    None => None,
                },
                None => None,
            }),
        )
    }

    // Stub kept in case multiple types are attempted again
    pub fn bind_arc(&self, typ: &RcType) -> ArcType {
        typ.clone()
    }
}
<|endoftext|>


<commit_before>//! Header and related types.

use std;
use std::ffi::{CStr, CString};
use std::marker::PhantomData;

use openexr_sys::*;

use cexr_type_aliases::*;
use error::{Result, Error};
use frame_buffer::{FrameBuffer, FrameBufferMut};
use libc::c_int;

pub use cexr_type_aliases::{Channel, Compression, LineOrder};

/// Represents an OpenEXR file header.
///
/// The file header describes the properties of the image, such as image
/// resolution, the channels it contains, custom attributes, etc.  It is used
/// both for fetching information about a loaded EXR file and for defining the
/// properties of a file to be written.
///
/// # Examples
///
/// Creating a header for a file that will be written:
///
/// ```
/// use openexr::{Header, PixelType};
///
/// Header::new()
///     .set_resolution(1920, 1080)
///     .add_channel("R", PixelType::FLOAT)
///     .add_channel("G", PixelType::FLOAT)
///     .add_channel("B", PixelType::FLOAT);
/// ```
pub struct Header {
    pub(crate) handle: *mut CEXR_Header,
    pub(crate) owned: bool,
    pub(crate) _phantom: PhantomData<CEXR_Header>,
}

impl Header {
    /// Creates a new header.
    pub fn new() -> Self {
        // Create underlying C header
        let header = {
            let display_window = Box2i {
                min: CEXR_V2i { x: 0, y: 0 },
                max: CEXR_V2i { x: 1, y: 1 },
            };
            let data_window = display_window;
            let pixel_aspect_ratio = 1.0;
            let screen_window_center = CEXR_V2f { x: 0.0, y: 0.0 };
            let screen_window_width = 1.0;
            let line_order = LineOrder::INCREASING_Y;
            let compression = Compression::PIZ_COMPRESSION;
            let header = unsafe {
                CEXR_Header_new(&display_window,
                                &data_window,
                                pixel_aspect_ratio,
                                &screen_window_center,
                                screen_window_width,
                                line_order,
                                compression)
            };
            header
        };

        Self {
            handle: header,
            owned: true,
            _phantom: PhantomData,
        }
    }

    /// Sets the resolution.
    ///
    /// This is really just a shortcut for setting both the display window
    /// and data window to `(0, 0), (width-1, height-1)`.
    pub fn set_resolution(&mut self, width: u32, height: u32) -> &mut Self {
        let window = Box2i {
            min: CEXR_V2i { x: 0, y: 0 },
            max: CEXR_V2i {
                x: width as i32 - 1,
                y: height as i32 - 1,
            },
        };
        unsafe {
            CEXR_Header_set_display_window(self.handle, window);
        }
        unsafe {
            CEXR_Header_set_data_window(self.handle, window);
        }
        self
    }

    /// Sets the display window.
    ///
    /// For simple use-cases, it's better to use `set_resolution()` instead.
    pub fn set_display_window(&mut self, window: Box2i) -> &mut Self {
        assert!(window.min.x < window.max.x);
        assert!(window.min.y < window.max.y);
        unsafe {
            CEXR_Header_set_display_window(self.handle, window);
        }
        self
    }

    /// Sets the data window.
    ///
    /// For simple use-cases, it's better to use `set_resolution()` instead.
    pub fn set_data_window(&mut self, window: Box2i) -> &mut Self {
        assert!(window.min.x < window.max.x);
        assert!(window.min.y < window.max.y);
        unsafe {
            CEXR_Header_set_data_window(self.handle, window);
        }
        self
    }

    /// Sets the pixel aspect ratio.
    pub fn set_pixel_aspect_ratio(&mut self, aspect_ratio: f32) -> &mut Self {
        unsafe {
            CEXR_Header_set_pixel_aspect_ratio(self.handle, aspect_ratio);
        }
        self
    }

    /// Sets the screen window center.
    pub fn set_screen_window_center(&mut self, center: (f32, f32)) -> &mut Self {
        unsafe {
            CEXR_Header_set_screen_window_center(self.handle,
                                                 CEXR_V2f {
                                                     x: center.0,
                                                     y: center.1,
                                                 });
        }
        self
    }

    /// Sets the screen window width.
    pub fn set_screen_window_width(&mut self, width: f32) -> &mut Self {
        unsafe {
            CEXR_Header_set_screen_window_width(self.handle, width);
        }
        self
    }

    /// Sets the line order.
    pub fn set_line_order(&mut self, line_order: LineOrder) -> &mut Self {
        unsafe {
            CEXR_Header_set_line_order(self.handle, line_order);
        }
        self
    }

    /// Sets the compression mode.
    pub fn set_compression(&mut self, compression: Compression) -> &mut Self {
        unsafe {
            CEXR_Header_set_compression(self.handle, compression);
        }
        self
    }

    /// Adds a channel.
    ///
    /// This is a simplified version of `add_channel_detailed()`, using some reasonable
    /// defaults for the details.  Specifically: sampling is set to (1, 1)
    /// and p_linear is set to true.
    pub fn add_channel(&mut self, name: &str, pixel_type: PixelType) -> &mut Self {
        self.add_channel_detailed(name,
                                  Channel {
                                      pixel_type: pixel_type,
                                      x_sampling: 1,
                                      y_sampling: 1,
                                      p_linear: true,
                                  })
    }

    /// Adds a channel, specifying full details.
    pub fn add_channel_detailed(&mut self, name: &str, channel: Channel) -> &mut Self {
        let cname = CString::new(name.as_bytes()).unwrap();
        unsafe { CEXR_Header_insert_channel(self.handle, cname.as_ptr(), channel) };
        self
    }

    /// Convenience method for the dimensions of the data window.
    pub fn data_dimensions(&self) -> (u32, u32) {
        let window = self.data_window();
        ((window.max.x - window.min.x + 1) as u32, (window.max.y - window.min.y + 1) as u32)
    }

    /// Access to the data window.
    pub fn data_window(&self) -> &Box2i {
        unsafe { &*CEXR_Header_data_window(self.handle) }
    }

    /// Access to the display window.
    pub fn display_window(&self) -> &Box2i {
        unsafe { &*CEXR_Header_display_window(self.handle) }
    }

    /// Returns an iterator over the channels in the header.
    pub fn channels<'a>(&'a self) -> ChannelIter<'a> {
        ChannelIter {
            iterator: unsafe { CEXR_Header_channel_list_iter(self.handle) },
            _phantom_1: PhantomData,
            _phantom_2: PhantomData,
        }
    }

    /// Access channels by name.
    pub fn get_channel<'a>(&'a self, name: &str) -> Option<&'a Channel> {
        let c_name = CString::new(name.as_bytes()).unwrap();
        let out = unsafe { CEXR_Header_get_channel(self.handle, c_name.as_ptr()) };
        if out != std::ptr::null() {
            Some(unsafe { &(*out) })
        } else {
            None
        }
    }

    /// Determine whether this header describes an environment map, and if so, what type
    pub fn envmap(&self) -> Option<Envmap> {
        if unsafe { CEXR_Header_has_envmap(self.handle) } {
            match unsafe { CEXR_Header_envmap(self.handle) } {
                0 => Some(Envmap::LatLong),
                1 => Some(Envmap::Cube),
                _ => None,
            }
        } else {
            None
        }
    }

    /// Declare whether this header represents an environment map
    pub fn set_envmap(&mut self, envmap: Option<Envmap>) -> &mut Self {
        if let Some(x) = envmap {
            unsafe { CEXR_Header_set_envmap(self.handle, x as c_int) }
        } else {
            unsafe { CEXR_Header_erase_attribute(self.handle, b"envmap\0".as_ptr() as *const _) }
        }
        self
    }

    pub(crate) fn validate_framebuffer_for_output(&self, framebuffer: &FrameBuffer) -> Result<()> {
        for chan in self.channels() {
            let (name, h_channel) = chan?;
            if let Some(fb_channel) = framebuffer._get_channel(name) {
                Header::validate_channel(name, &h_channel, &fb_channel)?;
            } else {
                return Err(Error::Generic(format!("FrameBuffer is missing \
                    channel '{}' expected by Header",
                                                  name)));
            }
        }
        Ok(())
    }

    pub(crate) fn validate_framebuffer_for_input(&self,
                                                 framebuffer: &FrameBufferMut)
                                                 -> Result<()> {
        for chan in self.channels() {
            let (name, h_channel) = chan?;
            if let Some(fb_channel) = framebuffer._get_channel(name) {
                Header::validate_channel(name, &h_channel, &fb_channel)?;
            }
        }
        Ok(())
    }

    // Factored out shared code from the validate_framebuffer_* methods above.
    fn validate_channel(name: &str, h_chan: &Channel, fb_chan: &Channel) -> Result<()> {
        if fb_chan.pixel_type != h_chan.pixel_type {
            return Err(Error::Generic(format!("Header and FrameBuffer channel \
                types don't match: '{}' is {:?} in Header and {:?} in \
                FrameBuffer",
                                              name,
                                              h_chan.pixel_type,
                                              fb_chan.pixel_type)));
        }
        if fb_chan.x_sampling != h_chan.x_sampling || fb_chan.y_sampling != h_chan.y_sampling {
            return Err(Error::Generic(format!("Header and FrameBuffer channel \
                subsampling don't match: channel '{}' is {}x{} in Header and \
                {}x{} in FrameBuffer",
                                              name,
                                              h_chan.x_sampling,
                                              h_chan.y_sampling,
                                              fb_chan.x_sampling,
                                              fb_chan.y_sampling)));
        }

        Ok(())
    }
}

impl Drop for Header {
    fn drop(&mut self) {
        if self.owned {
            unsafe { CEXR_Header_delete(self.handle) };
        }
    }
}

/// An iterator over the channels in a `Header`.
///
/// Yields a tuple of the name and description of each channel.
pub struct ChannelIter<'a> {
    iterator: *mut CEXR_ChannelListIter,
    _phantom_1: PhantomData<CEXR_ChannelListIter>,
    _phantom_2: PhantomData<&'a Header>,
}

impl<'a> Drop for ChannelIter<'a> {
    fn drop(&mut self) {
        unsafe { CEXR_ChannelListIter_delete(self.iterator) };
    }
}

impl<'a> Iterator for ChannelIter<'a> {
    type Item = Result<(&'a str, Channel)>;
    fn next(&mut self) -> Option<Result<(&'a str, Channel)>> {
        let mut name = unsafe { std::mem::uninitialized() };
        let mut channel = unsafe { std::mem::uninitialized() };
        if unsafe { CEXR_ChannelListIter_next(self.iterator, &mut name, &mut channel) } {
            // TODO: use CStr::from_bytes_with_nul() instead to avoid memory unsafety
            // if the string is not nul terminated.
            let cname = unsafe { CStr::from_ptr(name) };
            let str_name = cname.to_str();
            if let Ok(n) = str_name {
                Some(Ok((n, channel)))
            } else {
                Some(Err(Error::Generic(format!("Invalid channel name: {:?}", cname))))
            }
        } else {
            None
        }
    }
}

/// Types of environment maps
pub enum Envmap {
    /// Latitude-longitude projection
    LatLong = 0,
    /// Cubemap
    Cube = 1,
}
<commit_msg>Add missing derives on Envmap (#19)<commit_after>//! Header and related types.

use std;
use std::ffi::{CStr, CString};
use std::marker::PhantomData;

use openexr_sys::*;

use cexr_type_aliases::*;
use error::{Result, Error};
use frame_buffer::{FrameBuffer, FrameBufferMut};
use libc::c_int;

pub use cexr_type_aliases::{Channel, Compression, LineOrder};

/// Represents an OpenEXR file header.
///
/// The file header describes the properties of the image, such as image
/// resolution, the channels it contains, custom attributes, etc.  It is used
/// both for fetching information about a loaded EXR file and for defining the
/// properties of a file to be written.
///
/// # Examples
///
/// Creating a header for a file that will be written:
///
/// ```
/// use openexr::{Header, PixelType};
///
/// Header::new()
///     .set_resolution(1920, 1080)
///     .add_channel("R", PixelType::FLOAT)
///     .add_channel("G", PixelType::FLOAT)
///     .add_channel("B", PixelType::FLOAT);
/// ```
pub struct Header {
    pub(crate) handle: *mut CEXR_Header,
    pub(crate) owned: bool,
    pub(crate) _phantom: PhantomData<CEXR_Header>,
}

impl Header {
    /// Creates a new header.
    pub fn new() -> Self {
        // Create underlying C header
        let header = {
            let display_window = Box2i {
                min: CEXR_V2i { x: 0, y: 0 },
                max: CEXR_V2i { x: 1, y: 1 },
            };
            let data_window = display_window;
            let pixel_aspect_ratio = 1.0;
            let screen_window_center = CEXR_V2f { x: 0.0, y: 0.0 };
            let screen_window_width = 1.0;
            let line_order = LineOrder::INCREASING_Y;
            let compression = Compression::PIZ_COMPRESSION;
            let header = unsafe {
                CEXR_Header_new(&display_window,
                                &data_window,
                                pixel_aspect_ratio,
                                &screen_window_center,
                                screen_window_width,
                                line_order,
                                compression)
            };
            header
        };

        Self {
            handle: header,
            owned: true,
            _phantom: PhantomData,
        }
    }

    /// Sets the resolution.
    ///
    /// This is really just a shortcut for setting both the display window
    /// and data window to `(0, 0), (width-1, height-1)`.
    pub fn set_resolution(&mut self, width: u32, height: u32) -> &mut Self {
        let window = Box2i {
            min: CEXR_V2i { x: 0, y: 0 },
            max: CEXR_V2i {
                x: width as i32 - 1,
                y: height as i32 - 1,
            },
        };
        unsafe {
            CEXR_Header_set_display_window(self.handle, window);
        }
        unsafe {
            CEXR_Header_set_data_window(self.handle, window);
        }
        self
    }

    /// Sets the display window.
    ///
    /// For simple use-cases, it's better to use `set_resolution()` instead.
    pub fn set_display_window(&mut self, window: Box2i) -> &mut Self {
        assert!(window.min.x < window.max.x);
        assert!(window.min.y < window.max.y);
        unsafe {
            CEXR_Header_set_display_window(self.handle, window);
        }
        self
    }

    /// Sets the data window.
    ///
    /// For simple use-cases, it's better to use `set_resolution()` instead.
    pub fn set_data_window(&mut self, window: Box2i) -> &mut Self {
        assert!(window.min.x < window.max.x);
        assert!(window.min.y < window.max.y);
        unsafe {
            CEXR_Header_set_data_window(self.handle, window);
        }
        self
    }

    /// Sets the pixel aspect ratio.
    pub fn set_pixel_aspect_ratio(&mut self, aspect_ratio: f32) -> &mut Self {
        unsafe {
            CEXR_Header_set_pixel_aspect_ratio(self.handle, aspect_ratio);
        }
        self
    }

    /// Sets the screen window center.
    pub fn set_screen_window_center(&mut self, center: (f32, f32)) -> &mut Self {
        unsafe {
            CEXR_Header_set_screen_window_center(self.handle,
                                                 CEXR_V2f {
                                                     x: center.0,
                                                     y: center.1,
                                                 });
        }
        self
    }

    /// Sets the screen window width.
    pub fn set_screen_window_width(&mut self, width: f32) -> &mut Self {
        unsafe {
            CEXR_Header_set_screen_window_width(self.handle, width);
        }
        self
    }

    /// Sets the line order.
    pub fn set_line_order(&mut self, line_order: LineOrder) -> &mut Self {
        unsafe {
            CEXR_Header_set_line_order(self.handle, line_order);
        }
        self
    }

    /// Sets the compression mode.
    pub fn set_compression(&mut self, compression: Compression) -> &mut Self {
        unsafe {
            CEXR_Header_set_compression(self.handle, compression);
        }
        self
    }

    /// Adds a channel.
    ///
    /// This is a simplified version of `add_channel_detailed()`, using some reasonable
    /// defaults for the details.  Specifically: sampling is set to (1, 1)
    /// and p_linear is set to true.
    pub fn add_channel(&mut self, name: &str, pixel_type: PixelType) -> &mut Self {
        self.add_channel_detailed(name,
                                  Channel {
                                      pixel_type: pixel_type,
                                      x_sampling: 1,
                                      y_sampling: 1,
                                      p_linear: true,
                                  })
    }

    /// Adds a channel, specifying full details.
    pub fn add_channel_detailed(&mut self, name: &str, channel: Channel) -> &mut Self {
        let cname = CString::new(name.as_bytes()).unwrap();
        unsafe { CEXR_Header_insert_channel(self.handle, cname.as_ptr(), channel) };
        self
    }

    /// Convenience method for the dimensions of the data window.
    pub fn data_dimensions(&self) -> (u32, u32) {
        let window = self.data_window();
        ((window.max.x - window.min.x + 1) as u32, (window.max.y - window.min.y + 1) as u32)
    }

    /// Access to the data window.
    pub fn data_window(&self) -> &Box2i {
        unsafe { &*CEXR_Header_data_window(self.handle) }
    }

    /// Access to the display window.
    pub fn display_window(&self) -> &Box2i {
        unsafe { &*CEXR_Header_display_window(self.handle) }
    }

    /// Returns an iterator over the channels in the header.
    pub fn channels<'a>(&'a self) -> ChannelIter<'a> {
        ChannelIter {
            iterator: unsafe { CEXR_Header_channel_list_iter(self.handle) },
            _phantom_1: PhantomData,
            _phantom_2: PhantomData,
        }
    }

    /// Access channels by name.
    pub fn get_channel<'a>(&'a self, name: &str) -> Option<&'a Channel> {
        let c_name = CString::new(name.as_bytes()).unwrap();
        let out = unsafe { CEXR_Header_get_channel(self.handle, c_name.as_ptr()) };
        if out != std::ptr::null() {
            Some(unsafe { &(*out) })
        } else {
            None
        }
    }

    /// Determine whether this header describes an environment map, and if so, what type
    pub fn envmap(&self) -> Option<Envmap> {
        if unsafe { CEXR_Header_has_envmap(self.handle) } {
            match unsafe { CEXR_Header_envmap(self.handle) } {
                0 => Some(Envmap::LatLong),
                1 => Some(Envmap::Cube),
                _ => None,
            }
        } else {
            None
        }
    }

    /// Declare whether this header represents an environment map
    pub fn set_envmap(&mut self, envmap: Option<Envmap>) -> &mut Self {
        if let Some(x) = envmap {
            unsafe { CEXR_Header_set_envmap(self.handle, x as c_int) }
        } else {
            unsafe { CEXR_Header_erase_attribute(self.handle, b"envmap\0".as_ptr() as *const _) }
        }
        self
    }

    pub(crate) fn validate_framebuffer_for_output(&self, framebuffer: &FrameBuffer) -> Result<()> {
        for chan in self.channels() {
            let (name, h_channel) = chan?;
            if let Some(fb_channel) = framebuffer._get_channel(name) {
                Header::validate_channel(name, &h_channel, &fb_channel)?;
            } else {
                return Err(Error::Generic(format!("FrameBuffer is missing \
                    channel '{}' expected by Header",
                                                  name)));
            }
        }
        Ok(())
    }

    pub(crate) fn validate_framebuffer_for_input(&self,
                                                 framebuffer: &FrameBufferMut)
                                                 -> Result<()> {
        for chan in self.channels() {
            let (name, h_channel) = chan?;
            if let Some(fb_channel) = framebuffer._get_channel(name) {
                Header::validate_channel(name, &h_channel, &fb_channel)?;
            }
        }
        Ok(())
    }

    // Factored out shared code from the validate_framebuffer_* methods above.
    fn validate_channel(name: &str, h_chan: &Channel, fb_chan: &Channel) -> Result<()> {
        if fb_chan.pixel_type != h_chan.pixel_type {
            return Err(Error::Generic(format!("Header and FrameBuffer channel \
                types don't match: '{}' is {:?} in Header and {:?} in \
                FrameBuffer",
                                              name,
                                              h_chan.pixel_type,
                                              fb_chan.pixel_type)));
        }
        if fb_chan.x_sampling != h_chan.x_sampling || fb_chan.y_sampling != h_chan.y_sampling {
            return Err(Error::Generic(format!("Header and FrameBuffer channel \
                subsampling don't match: channel '{}' is {}x{} in Header and \
                {}x{} in FrameBuffer",
                                              name,
                                              h_chan.x_sampling,
                                              h_chan.y_sampling,
                                              fb_chan.x_sampling,
                                              fb_chan.y_sampling)));
        }

        Ok(())
    }
}

impl Drop for Header {
    fn drop(&mut self) {
        if self.owned {
            unsafe { CEXR_Header_delete(self.handle) };
        }
    }
}

/// An iterator over the channels in a `Header`.
///
/// Yields a tuple of the name and description of each channel.
pub struct ChannelIter<'a> {
    iterator: *mut CEXR_ChannelListIter,
    _phantom_1: PhantomData<CEXR_ChannelListIter>,
    _phantom_2: PhantomData<&'a Header>,
}

impl<'a> Drop for ChannelIter<'a> {
    fn drop(&mut self) {
        unsafe { CEXR_ChannelListIter_delete(self.iterator) };
    }
}

impl<'a> Iterator for ChannelIter<'a> {
    type Item = Result<(&'a str, Channel)>;
    fn next(&mut self) -> Option<Result<(&'a str, Channel)>> {
        let mut name = unsafe { std::mem::uninitialized() };
        let mut channel = unsafe { std::mem::uninitialized() };
        if unsafe { CEXR_ChannelListIter_next(self.iterator, &mut name, &mut channel) } {
            // TODO: use CStr::from_bytes_with_nul() instead to avoid memory unsafety
            // if the string is not nul terminated.
            let cname = unsafe { CStr::from_ptr(name) };
            let str_name = cname.to_str();
            if let Ok(n) = str_name {
                Some(Ok((n, channel)))
            } else {
                Some(Err(Error::Generic(format!("Invalid channel name: {:?}", cname))))
            }
        } else {
            None
        }
    }
}

/// Types of environment maps
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Envmap {
    /// Latitude-longitude projection
    LatLong = 0,
    /// Cubemap
    Cube = 1,
}
<|endoftext|>


<commit_before>use std::{mem, ptr};
use libc::{c_char, c_void, c_int, size_t, pid_t, off_t};
use fcntl::{fcntl, Fd, OFlag, O_NONBLOCK, O_CLOEXEC, FD_CLOEXEC};
use fcntl::FcntlArg::{F_SETFD, F_SETFL};

use errno::{SysResult, SysError, from_ffi};
use core::raw::Slice as RawSlice;
use utils::ToCStr;
use std::ffi::CString;

#[cfg(target_os = "linux")]
pub use self::linux::*;

mod ffi {
    use super::{IovecR,IovecW};
    use libc::{c_char, c_int, size_t, ssize_t};
    pub use libc::{close, read, write, pipe, ftruncate};
    pub use libc::funcs::posix88::unistd::fork;
    use fcntl::Fd;

    extern {
        // duplicate a file descriptor
        // doc: http://man7.org/linux/man-pages/man2/dup.2.html
        pub fn dup(oldfd: c_int) -> c_int;
        pub fn dup2(oldfd: c_int, newfd: c_int) -> c_int;

        // change working directory
        // doc: http://man7.org/linux/man-pages/man2/chdir.2.html
        pub fn chdir(path: *const c_char) -> c_int;

        // execute program
        // doc: http://man7.org/linux/man-pages/man2/execve.2.html
        pub fn execve(filename: *const c_char, argv: *const *const c_char, envp: *const *const c_char) -> c_int;

        // run the current process in the background
        // doc: http://man7.org/linux/man-pages/man3/daemon.3.html
        pub fn daemon(nochdir: c_int, noclose: c_int) -> c_int;

        // sets the hostname to the value given
        // doc: http://man7.org/linux/man-pages/man2/gethostname.2.html
        pub fn gethostname(name: *mut c_char, len: size_t) -> c_int;

        // gets the hostname
        // doc: http://man7.org/linux/man-pages/man2/gethostname.2.html
        pub fn sethostname(name: *const c_char, len: size_t) -> c_int;

        // vectorized version of write
        // doc: http://man7.org/linux/man-pages/man2/writev.2.html
        pub fn writev(fd: Fd, iov: *const IovecW, iovcnt: c_int) -> ssize_t;

        // vectorized version of read
        // doc: http://man7.org/linux/man-pages/man2/readv.2.html
        pub fn readv(fd: Fd, iov: *const IovecR, iovcnt: c_int) -> ssize_t;
    }
}

#[derive(Copy)]
pub enum Fork {
    Parent(pid_t),
    Child
}

impl Fork {
    pub fn is_child(&self) -> bool {
        match *self {
            Fork::Child => true,
            _ => false
        }
    }

    pub fn is_parent(&self) -> bool {
        match *self {
            Fork::Parent(_) => true,
            _ => false
        }
    }
}

pub fn fork() -> SysResult<Fork> {
    use self::Fork::*;

    let res = unsafe { ffi::fork() };

    if res < 0 {
        return Err(SysError::last());
    } else if res == 0 {
        Ok(Child)
    } else {
        Ok(Parent(res))
    }
}

// We use phantom types to maintain memory safety.
// If readv/writev were using simple &[Iovec] we could initialize
// Iovec with immutable slice and then pass it to readv, overwriting content
// we dont have write access to:
// let mut v = Vec::new();
// let iov = Iovec::from_slice(immutable_vec.as_slice());
// v.push(iov);
// let _:SysResult<usize> = readv(fd, v.as_slice());

// We do not want <T> to appear in ffi functions, so we provide this aliases.
type IovecR = Iovec<ToRead>;
type IovecW = Iovec<ToWrite>;

#[derive(Copy)]
pub struct ToRead;
#[derive(Copy)]
pub struct ToWrite;

#[repr(C)]
pub struct Iovec<T> {
    iov_base: *mut c_void,
    iov_len: size_t,
}

impl <T> Iovec<T> {
    #[inline]
    pub fn as_slice<'a>(&'a self) -> &'a [u8] {
        unsafe { mem::transmute(RawSlice { data: self.iov_base as *const u8, len: self.iov_len as usize }) }
    }
}

impl Iovec<ToWrite> {
    #[inline]
    pub fn from_slice(buf: &[u8]) -> Iovec<ToWrite> {
        Iovec {
            iov_base: buf.as_ptr() as *mut c_void,
            iov_len: buf.len() as size_t
        }
    }
}

impl Iovec<ToRead> {
    #[inline]
    pub fn from_mut_slice(buf: &mut [u8]) -> Iovec<ToRead> {
        Iovec {
            iov_base: buf.as_ptr() as *mut c_void,
            iov_len: buf.len() as size_t
        }
    }
}

#[inline]
pub fn dup(oldfd: Fd) -> SysResult<Fd> {
    let res = unsafe { ffi::dup(oldfd) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(res)
}

#[inline]
pub fn dup2(oldfd: Fd, newfd: Fd) -> SysResult<Fd> {
    let res = unsafe { ffi::dup2(oldfd, newfd) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(res)
}

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
pub fn dup3(oldfd: Fd, newfd: Fd, flags: OFlag) -> SysResult<Fd> {
    type F = unsafe extern "C" fn(c_int, c_int, c_int) -> c_int;

    extern {
        #[linkage = "extern_weak"]
        static dup3: *const ();
    }

    if !dup3.is_null() {
        let res = unsafe {
            mem::transmute::<*const (), F>(dup3)(
                oldfd, newfd, flags.bits())
        };

        if res < 0 {
            return Err(SysError::last());
        }

        Ok(res)
    } else {
        dup3_polyfill(oldfd, newfd, flags)
    }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
pub fn dup3(oldfd: Fd, newfd: Fd, flags: OFlag) -> SysResult<Fd> {
    dup3_polyfill(oldfd, newfd, flags)
}

#[inline]
fn dup3_polyfill(oldfd: Fd, newfd: Fd, flags: OFlag) -> SysResult<Fd> {
    use errno::EINVAL;

    if oldfd == newfd {
        return Err(SysError { kind: EINVAL });
    }

    let fd = try!(dup2(oldfd, newfd));

    if flags.contains(O_CLOEXEC) {
        if let Err(e) = fcntl(fd, F_SETFD(FD_CLOEXEC)) {
            let _ = close(fd);
            return Err(e);
        }
    }

    Ok(fd)
}

#[inline]
pub fn chdir<S: ToCStr>(path: S) -> SysResult<()> {
    let path = path.to_c_str();
    let res = unsafe { ffi::chdir(path.as_ptr()) };

    if res != 0 {
        return Err(SysError::last());
    }

    return Ok(())
}

#[inline]
pub fn execve(filename: &CString, args: &[CString], env: &[CString]) -> SysResult<()> {
    let mut args_p: Vec<*const c_char> = args.iter().map(|s| s.as_ptr()).collect();
    args_p.push(ptr::null());

    let mut env_p: Vec<*const c_char> = env.iter().map(|s| s.as_ptr()).collect();
    env_p.push(ptr::null());

    let res = unsafe {
        ffi::execve(filename.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
    };

    if res != 0 {
        return Err(SysError::last());
    }

    unreachable!()
}

pub fn daemon(nochdir: bool, noclose: bool) -> SysResult<()> {
    let res = unsafe { ffi::daemon(nochdir as c_int, noclose as c_int) };
    from_ffi(res)
}

pub fn sethostname(name: &[u8]) -> SysResult<()> {
    let ptr = name.as_ptr() as *const c_char;
    let len = name.len() as size_t;

    let res = unsafe { ffi::sethostname(ptr, len) };
    from_ffi(res)
}

pub fn gethostname(name: &mut [u8]) -> SysResult<()> {
    let ptr = name.as_mut_ptr() as *mut c_char;
    let len = name.len() as size_t;

    let res = unsafe { ffi::gethostname(ptr, len) };
    from_ffi(res)
}

pub fn close(fd: Fd) -> SysResult<()> {
    let res = unsafe { ffi::close(fd) };
    from_ffi(res)
}

pub fn read(fd: Fd, buf: &mut [u8]) -> SysResult<usize> {
    let res = unsafe { ffi::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t) };

    if res < 0 {
        return Err(SysError::last());
    }

    return Ok(res as usize)
}

pub fn write(fd: Fd, buf: &[u8]) -> SysResult<usize> {
    let res = unsafe { ffi::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t) };

    if res < 0 {
        return Err(SysError::last());
    }

    return Ok(res as usize)
}

pub fn writev(fd: Fd, iov: &[Iovec<ToWrite>]) -> SysResult<usize> {
    let res = unsafe { ffi::writev(fd, iov.as_ptr(), iov.len() as c_int) };
    if res < 0 {
        return Err(SysError::last());
    }

    return Ok(res as usize)
}

pub fn readv(fd: Fd, iov: &mut [Iovec<ToRead>]) -> SysResult<usize> {
    let res = unsafe { ffi::readv(fd, iov.as_ptr(), iov.len() as c_int) };
    if res < 0 {
        return Err(SysError::last());
    }

    return Ok(res as usize)
}

pub fn pipe() -> SysResult<(Fd, Fd)> {
    unsafe {
        let mut res;
        let mut fds: [c_int; 2] = mem::uninitialized();

        res = ffi::pipe(fds.as_mut_ptr());

        if res < 0 {
            return Err(SysError::last());
        }

        Ok((fds[0], fds[1]))
    }
}

#[cfg(target_os = "linux")]
pub fn pipe2(flags: OFlag) -> SysResult<(Fd, Fd)> {
    type F = unsafe extern "C" fn(fds: *mut c_int, flags: c_int) -> c_int;

    extern {
        #[linkage = "extern_weak"]
        static pipe2: *const ();
    }

    let feat_atomic = !pipe2.is_null();

    unsafe {
        let mut res;
        let mut fds: [c_int; 2] = mem::uninitialized();

        if feat_atomic {
            res = mem::transmute::<*const (), F>(pipe2)(
                fds.as_mut_ptr(), flags.bits());
        } else {
            res = ffi::pipe(fds.as_mut_ptr());
        }

        if res < 0 {
            return Err(SysError::last());
        }

        if !feat_atomic {
            try!(pipe2_setflags(fds[0], fds[1], flags));
        }

        Ok((fds[0], fds[1]))
    }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
pub fn pipe2(flags: OFlag) -> SysResult<(Fd, Fd)> {
    unsafe {
        let mut res;
        let mut fds: [c_int; 2] = mem::uninitialized();

        res = ffi::pipe(fds.as_mut_ptr());

        if res < 0 {
            return Err(SysError::last());
        }

        try!(pipe2_setflags(fds[0], fds[1], flags));

        Ok((fds[0], fds[1]))
    }
}

fn pipe2_setflags(fd1: Fd, fd2: Fd, flags: OFlag) -> SysResult<()> {
    let mut res = Ok(());

    if flags.contains(O_CLOEXEC) {
        res = res
            .and_then(|_| fcntl(fd1, F_SETFD(FD_CLOEXEC)))
            .and_then(|_| fcntl(fd2, F_SETFD(FD_CLOEXEC)));
    }

    if flags.contains(O_NONBLOCK) {
        res = res
            .and_then(|_| fcntl(fd1, F_SETFL(O_NONBLOCK)))
            .and_then(|_| fcntl(fd2, F_SETFL(O_NONBLOCK)));
    }

    match res {
        Ok(_) => Ok(()),
        Err(e) => {
            let _ = close(fd1);
            let _ = close(fd2);
            return Err(e);
        }
    }
}

pub fn ftruncate(fd: Fd, len: off_t) -> SysResult<()> {
    if unsafe { ffi::ftruncate(fd, len) } < 0 {
        Err(SysError::last())
    } else {
        Ok(())
    }
}

#[cfg(target_os = "linux")]
mod linux {
    use std::path::Path;
    use syscall::{syscall, SYSPIVOTROOT};
    use errno::{SysResult, SysError};
    use utils::ToCStr;

    pub fn pivot_root(new_root: &Path, put_old: &Path) -> SysResult<()> {
        let new_root = new_root.to_c_str();
        let put_old = put_old.to_c_str();

        let res = unsafe {
            syscall(SYSPIVOTROOT, new_root.as_ptr(), put_old.as_ptr())
        };

        if res != 0 {
            return Err(SysError::last());
        }

        Ok(())
    }
}
<commit_msg>Add a safe wrapper for `libc::isatty`.<commit_after>use std::{mem, ptr};
use libc::{c_char, c_void, c_int, size_t, pid_t, off_t};
use fcntl::{fcntl, Fd, OFlag, O_NONBLOCK, O_CLOEXEC, FD_CLOEXEC};
use fcntl::FcntlArg::{F_SETFD, F_SETFL};

use errno::{SysResult, SysError, from_ffi};
use core::raw::Slice as RawSlice;
use utils::ToCStr;
use std::ffi::CString;

#[cfg(target_os = "linux")]
pub use self::linux::*;

mod ffi {
    use super::{IovecR,IovecW};
    use libc::{c_char, c_int, size_t, ssize_t};
    pub use libc::{close, read, write, pipe, ftruncate};
    pub use libc::funcs::posix88::unistd::fork;
    use fcntl::Fd;

    extern {
        // duplicate a file descriptor
        // doc: http://man7.org/linux/man-pages/man2/dup.2.html
        pub fn dup(oldfd: c_int) -> c_int;
        pub fn dup2(oldfd: c_int, newfd: c_int) -> c_int;

        // change working directory
        // doc: http://man7.org/linux/man-pages/man2/chdir.2.html
        pub fn chdir(path: *const c_char) -> c_int;

        // execute program
        // doc: http://man7.org/linux/man-pages/man2/execve.2.html
        pub fn execve(filename: *const c_char, argv: *const *const c_char, envp: *const *const c_char) -> c_int;

        // run the current process in the background
        // doc: http://man7.org/linux/man-pages/man3/daemon.3.html
        pub fn daemon(nochdir: c_int, noclose: c_int) -> c_int;

        // sets the hostname to the value given
        // doc: http://man7.org/linux/man-pages/man2/gethostname.2.html
        pub fn gethostname(name: *mut c_char, len: size_t) -> c_int;

        // gets the hostname
        // doc: http://man7.org/linux/man-pages/man2/gethostname.2.html
        pub fn sethostname(name: *const c_char, len: size_t) -> c_int;

        // vectorized version of write
        // doc: http://man7.org/linux/man-pages/man2/writev.2.html
        pub fn writev(fd: Fd, iov: *const IovecW, iovcnt: c_int) -> ssize_t;

        // vectorized version of read
        // doc: http://man7.org/linux/man-pages/man2/readv.2.html
        pub fn readv(fd: Fd, iov: *const IovecR, iovcnt: c_int) -> ssize_t;
    }
}

#[derive(Copy)]
pub enum Fork {
    Parent(pid_t),
    Child
}

impl Fork {
    pub fn is_child(&self) -> bool {
        match *self {
            Fork::Child => true,
            _ => false
        }
    }

    pub fn is_parent(&self) -> bool {
        match *self {
            Fork::Parent(_) => true,
            _ => false
        }
    }
}

pub fn fork() -> SysResult<Fork> {
    use self::Fork::*;

    let res = unsafe { ffi::fork() };

    if res < 0 {
        return Err(SysError::last());
    } else if res == 0 {
        Ok(Child)
    } else {
        Ok(Parent(res))
    }
}

// We use phantom types to maintain memory safety.
// If readv/writev were using simple &[Iovec] we could initialize
// Iovec with immutable slice and then pass it to readv, overwriting content
// we dont have write access to:
// let mut v = Vec::new();
// let iov = Iovec::from_slice(immutable_vec.as_slice());
// v.push(iov);
// let _:SysResult<usize> = readv(fd, v.as_slice());

// We do not want <T> to appear in ffi functions, so we provide this aliases.
type IovecR = Iovec<ToRead>;
type IovecW = Iovec<ToWrite>;

#[derive(Copy)]
pub struct ToRead;
#[derive(Copy)]
pub struct ToWrite;

#[repr(C)]
pub struct Iovec<T> {
    iov_base: *mut c_void,
    iov_len: size_t,
}

impl <T> Iovec<T> {
    #[inline]
    pub fn as_slice<'a>(&'a self) -> &'a [u8] {
        unsafe { mem::transmute(RawSlice { data: self.iov_base as *const u8, len: self.iov_len as usize }) }
    }
}

impl Iovec<ToWrite> {
    #[inline]
    pub fn from_slice(buf: &[u8]) -> Iovec<ToWrite> {
        Iovec {
            iov_base: buf.as_ptr() as *mut c_void,
            iov_len: buf.len() as size_t
        }
    }
}

impl Iovec<ToRead> {
    #[inline]
    pub fn from_mut_slice(buf: &mut [u8]) -> Iovec<ToRead> {
        Iovec {
            iov_base: buf.as_ptr() as *mut c_void,
            iov_len: buf.len() as size_t
        }
    }
}

#[inline]
pub fn dup(oldfd: Fd) -> SysResult<Fd> {
    let res = unsafe { ffi::dup(oldfd) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(res)
}

#[inline]
pub fn dup2(oldfd: Fd, newfd: Fd) -> SysResult<Fd> {
    let res = unsafe { ffi::dup2(oldfd, newfd) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(res)
}

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
pub fn dup3(oldfd: Fd, newfd: Fd, flags: OFlag) -> SysResult<Fd> {
    type F = unsafe extern "C" fn(c_int, c_int, c_int) -> c_int;

    extern {
        #[linkage = "extern_weak"]
        static dup3: *const ();
    }

    if !dup3.is_null() {
        let res = unsafe {
            mem::transmute::<*const (), F>(dup3)(
                oldfd, newfd, flags.bits())
        };

        if res < 0 {
            return Err(SysError::last());
        }

        Ok(res)
    } else {
        dup3_polyfill(oldfd, newfd, flags)
    }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
pub fn dup3(oldfd: Fd, newfd: Fd, flags: OFlag) -> SysResult<Fd> {
    dup3_polyfill(oldfd, newfd, flags)
}

#[inline]
fn dup3_polyfill(oldfd: Fd, newfd: Fd, flags: OFlag) -> SysResult<Fd> {
    use errno::EINVAL;

    if oldfd == newfd {
        return Err(SysError { kind: EINVAL });
    }

    let fd = try!(dup2(oldfd, newfd));

    if flags.contains(O_CLOEXEC) {
        if let Err(e) = fcntl(fd, F_SETFD(FD_CLOEXEC)) {
            let _ = close(fd);
            return Err(e);
        }
    }

    Ok(fd)
}

#[inline]
pub fn chdir<S: ToCStr>(path: S) -> SysResult<()> {
    let path = path.to_c_str();
    let res = unsafe { ffi::chdir(path.as_ptr()) };

    if res != 0 {
        return Err(SysError::last());
    }

    return Ok(())
}

#[inline]
pub fn execve(filename: &CString, args: &[CString], env: &[CString]) -> SysResult<()> {
    let mut args_p: Vec<*const c_char> = args.iter().map(|s| s.as_ptr()).collect();
    args_p.push(ptr::null());

    let mut env_p: Vec<*const c_char> = env.iter().map(|s| s.as_ptr()).collect();
    env_p.push(ptr::null());

    let res = unsafe {
        ffi::execve(filename.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
    };

    if res != 0 {
        return Err(SysError::last());
    }

    unreachable!()
}

pub fn daemon(nochdir: bool, noclose: bool) -> SysResult<()> {
    let res = unsafe { ffi::daemon(nochdir as c_int, noclose as c_int) };
    from_ffi(res)
}

pub fn sethostname(name: &[u8]) -> SysResult<()> {
    let ptr = name.as_ptr() as *const c_char;
    let len = name.len() as size_t;

    let res = unsafe { ffi::sethostname(ptr, len) };
    from_ffi(res)
}

pub fn gethostname(name: &mut [u8]) -> SysResult<()> {
    let ptr = name.as_mut_ptr() as *mut c_char;
    let len = name.len() as size_t;

    let res = unsafe { ffi::gethostname(ptr, len) };
    from_ffi(res)
}

pub fn close(fd: Fd) -> SysResult<()> {
    let res = unsafe { ffi::close(fd) };
    from_ffi(res)
}

pub fn read(fd: Fd, buf: &mut [u8]) -> SysResult<usize> {
    let res = unsafe { ffi::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t) };

    if res < 0 {
        return Err(SysError::last());
    }

    return Ok(res as usize)
}

pub fn write(fd: Fd, buf: &[u8]) -> SysResult<usize> {
    let res = unsafe { ffi::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t) };

    if res < 0 {
        return Err(SysError::last());
    }

    return Ok(res as usize)
}

pub fn writev(fd: Fd, iov: &[Iovec<ToWrite>]) -> SysResult<usize> {
    let res = unsafe { ffi::writev(fd, iov.as_ptr(), iov.len() as c_int) };
    if res < 0 {
        return Err(SysError::last());
    }

    return Ok(res as usize)
}

pub fn readv(fd: Fd, iov: &mut [Iovec<ToRead>]) -> SysResult<usize> {
    let res = unsafe { ffi::readv(fd, iov.as_ptr(), iov.len() as c_int) };
    if res < 0 {
        return Err(SysError::last());
    }

    return Ok(res as usize)
}

pub fn pipe() -> SysResult<(Fd, Fd)> {
    unsafe {
        let mut res;
        let mut fds: [c_int; 2] = mem::uninitialized();

        res = ffi::pipe(fds.as_mut_ptr());

        if res < 0 {
            return Err(SysError::last());
        }

        Ok((fds[0], fds[1]))
    }
}

#[cfg(target_os = "linux")]
pub fn pipe2(flags: OFlag) -> SysResult<(Fd, Fd)> {
    type F = unsafe extern "C" fn(fds: *mut c_int, flags: c_int) -> c_int;

    extern {
        #[linkage = "extern_weak"]
        static pipe2: *const ();
    }

    let feat_atomic = !pipe2.is_null();

    unsafe {
        let mut res;
        let mut fds: [c_int; 2] = mem::uninitialized();

        if feat_atomic {
            res = mem::transmute::<*const (), F>(pipe2)(
                fds.as_mut_ptr(), flags.bits());
        } else {
            res = ffi::pipe(fds.as_mut_ptr());
        }

        if res < 0 {
            return Err(SysError::last());
        }

        if !feat_atomic {
            try!(pipe2_setflags(fds[0], fds[1], flags));
        }

        Ok((fds[0], fds[1]))
    }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
pub fn pipe2(flags: OFlag) -> SysResult<(Fd, Fd)> {
    unsafe {
        let mut res;
        let mut fds: [c_int; 2] = mem::uninitialized();

        res = ffi::pipe(fds.as_mut_ptr());

        if res < 0 {
            return Err(SysError::last());
        }

        try!(pipe2_setflags(fds[0], fds[1], flags));

        Ok((fds[0], fds[1]))
    }
}

fn pipe2_setflags(fd1: Fd, fd2: Fd, flags: OFlag) -> SysResult<()> {
    let mut res = Ok(());

    if flags.contains(O_CLOEXEC) {
        res = res
            .and_then(|_| fcntl(fd1, F_SETFD(FD_CLOEXEC)))
            .and_then(|_| fcntl(fd2, F_SETFD(FD_CLOEXEC)));
    }

    if flags.contains(O_NONBLOCK) {
        res = res
            .and_then(|_| fcntl(fd1, F_SETFL(O_NONBLOCK)))
            .and_then(|_| fcntl(fd2, F_SETFL(O_NONBLOCK)));
    }

    match res {
        Ok(_) => Ok(()),
        Err(e) => {
            let _ = close(fd1);
            let _ = close(fd2);
            return Err(e);
        }
    }
}

pub fn ftruncate(fd: Fd, len: off_t) -> SysResult<()> {
    if unsafe { ffi::ftruncate(fd, len) } < 0 {
        Err(SysError::last())
    } else {
        Ok(())
    }
}

pub fn isatty(fd: Fd) -> SysResult<bool> {
    use {errno, libc};

    if unsafe { libc::isatty(fd) } == 1 {
        Ok(true)
    } else {
        match SysError::last() {
            // ENOTTY means `fd` is a valid file descriptor, but not a TTY, so
            // we return `Ok(false)`
            SysError { kind: errno::ENOTTY } => Ok(false),
            err => Err(err)
        }
    }
}

#[cfg(target_os = "linux")]
mod linux {
    use std::path::Path;
    use syscall::{syscall, SYSPIVOTROOT};
    use errno::{SysResult, SysError};
    use utils::ToCStr;

    pub fn pivot_root(new_root: &Path, put_old: &Path) -> SysResult<()> {
        let new_root = new_root.to_c_str();
        let put_old = put_old.to_c_str();

        let res = unsafe {
            syscall(SYSPIVOTROOT, new_root.as_ptr(), put_old.as_ptr())
        };

        if res != 0 {
            return Err(SysError::last());
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>use super::Numeric;
use std::ops::{Add, Sub, Mul, Div, Rem};

#[cfg(features = "parallel")]
use super::parallel::*;

pub trait Vector<N>: Sized where N: Numeric {
    #[cfg(features = "unstable")]
    fn is_perpendicular_to<M>(self, v_prime: Self) -> bool
    where Self: Mul<Self, Output=M>
        , M: PartialEq
    {
        (self * v_prime) == M::zero()
    }
}

#[cfg(not(simd))]
/// A 3D vector of any numeric type.
///
/// This is the non-SIMD version.
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
pub struct Vector3<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              , pub z: N
              }

macro_rules! e { ($e:expr) => { $e } }

macro_rules! impl_v3_ops {
    ($($name:ident, $fun:ident, $op:tt)*) => {$(
        // implement the operation for vector & vector
        #[cfg(not(features = "parallel"))]
        impl<N> $name<Vector3<N>> for Vector3<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector3<N>;
            fn $fun(self, rhs: Self) -> Vector3<N> {
                Vector3 { x: e!(self.x $op rhs.x)
                        , y: e!(self.y $op rhs.y)
                        , z: e!(self.z $op rhs.z)
                        }
            }
        }
        // implement the operation for vector & scalar
        #[cfg(not(features = "parallel"))]
        impl<N> $name<N> for Vector3<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector3<N>;
            fn $fun(self, rhs: N) -> Vector3<N> {
                Vector3 { x: e!(self.x $op rhs)
                        , y: e!(self.y $op rhs)
                        , z: e!(self.z $op rhs)
                        }
            }
        }
    )*};
}

impl_v3_ops!{
    Add, add, +
    Sub, sub, -
    Div, div, /
    Rem, rem, %
}

impl<N> Mul<N> for Vector3<N>
where N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Vector3 { x: self.x * rhs
                , y: self.y * rhs
                , z: self.z * rhs
                }
    }

}

impl<N> Mul<Vector3<N>> for Vector3<N>
where N: Numeric
    , N: Mul<Output = N> + Add<Output = N>
    , N: Copy
{
    type Output = N;
    fn mul(self, rhs: Self) -> N {
        (self.x * rhs.x) +
        (self.y * rhs.y) +
        (self.z * rhs.z)
    }
}

#[cfg(features = "parallel")]
impl<N> Mul<N> for Vector3<N>
where Self: Simdalize<Elem = N>
    , N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
}

#[cfg(not(simd))]
/// A 2D vector of any numeric type.
///
/// This is the non-SIMD version.
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
pub struct Vector2<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              }

macro_rules! e { ($e:expr) => { $e } }

macro_rules! impl_v2_ops {
    ($($name:ident, $fun:ident, $op:tt)*) => {$(
        // implement the operation for vector & vector
        #[cfg(not(features = "parallel"))]
        impl<N> $name<Vector2<N>> for Vector2<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector2<N>;
            fn $fun(self, rhs: Self) -> Vector2<N> {
                Vector2 { x: e!(self.x $op rhs.x)
                        , y: e!(self.y $op rhs.y)
                        }
            }
        }
        // implement the operation for vector & scalar
        #[cfg(not(features = "parallel"))]
        impl<N> $name<N> for Vector2<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector2<N>;
            fn $fun(self, rhs: N) -> Vector2<N> {
                Vector2 { x: e!(self.x $op rhs)
                        , y: e!(self.y $op rhs)
                        }
            }
        }
    )*};
}

impl_v2_ops! { Add, add, +
               Sub, sub, -
               Div, div, /
               Rem, rem, %
             }

impl<N> Mul<N> for Vector2<N>
where N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Vector2 { x: self.x * rhs
                , y: self.y * rhs
                }
    }
}

#[cfg(features = "parallel")]
impl<N> Mul<N> for Vector2<N>
where Self: Simdalize<Elem = N>
    , N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
}

impl<N> Mul<Vector2<N>> for Vector2<N>
where N: Numeric
    , N: Mul<Output = N> + Add<Output = N>
    , N: Copy
{
    type Output = N;
    fn mul(self, rhs: Self) -> N {
        (self.x * rhs.x) + (self.y * rhs.y)
    }
}
<commit_msg>Add SIMD scalar ops for V2 and V3<commit_after>use super::Numeric;
use std::ops::{Add, Sub, Mul, Div, Rem};

#[cfg(features = "parallel")]
use super::parallel::*;

pub trait Vector<N>: Sized where N: Numeric {
    #[cfg(features = "unstable")]
    fn is_perpendicular_to<M>(self, v_prime: Self) -> bool
    where Self: Mul<Self, Output=M>
        , M: PartialEq
    {
        (self * v_prime) == M::zero()
    }
}

#[cfg(not(simd))]
/// A 3D vector of any numeric type.
///
/// This is the non-SIMD version.
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
pub struct Vector3<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              , pub z: N
              }

macro_rules! e { ($e:expr) => { $e } }

macro_rules! impl_v3_ops {
    ($($name:ident, $fun:ident, $op:tt)*) => {$(
        // implement the operation for vector & vector
        impl<N> $name<Vector3<N>> for Vector3<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector3<N>;
            fn $fun(self, rhs: Self) -> Vector3<N> {
                Vector3 { x: e!(self.x $op rhs.x)
                        , y: e!(self.y $op rhs.y)
                        , z: e!(self.z $op rhs.z)
                        }
            }
        }
        // implement the operation for vector & scalar
        impl<N> $name<N> for Vector3<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector3<N>;
            fn $fun(self, rhs: N) -> Vector3<N> {
                Vector3 { x: e!(self.x $op rhs)
                        , y: e!(self.y $op rhs)
                        , z: e!(self.z $op rhs)
                        }
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for Vector3<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
            , N: Copy
        {
            type Output = Self;
            fn $fun(self, rhs: N) -> Output {
                e!(self.simdalize() $op N::splat(rhs))
            }
        }
    )*};
}

impl_v3_ops!{
    Add, add, +
    Sub, sub, -
    Div, div, /
    Rem, rem, %
}

impl<N> Mul<N> for Vector3<N>
where N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Vector3 { x: self.x * rhs
                , y: self.y * rhs
                , z: self.z * rhs
                }
    }

}

impl<N> Mul<Vector3<N>> for Vector3<N>
where N: Numeric
    , N: Mul<Output = N> + Add<Output = N>
    , N: Copy
{
    type Output = N;
    fn mul(self, rhs: Self) -> N {
        (self.x * rhs.x) +
        (self.y * rhs.y) +
        (self.z * rhs.z)
    }
}

#[cfg(features = "parallel")]
impl<N> Mul<N> for Vector3<N>
where Self: Simdalize<Elem = N>
    , N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
}

#[cfg(not(simd))]
/// A 2D vector of any numeric type.
///
/// This is the non-SIMD version.
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
pub struct Vector2<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              }

macro_rules! e { ($e:expr) => { $e } }

macro_rules! impl_v2_ops {
    ($($name:ident, $fun:ident, $op:tt)*) => {$(
        // implement the operation for vector & vector
        impl<N> $name<Vector2<N>> for Vector2<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector2<N>;
            fn $fun(self, rhs: Self) -> Vector2<N> {
                Vector2 { x: e!(self.x $op rhs.x)
                        , y: e!(self.y $op rhs.y)
                        }
            }
        }
        // implement the operation for vector & scalar
        impl<N> $name<N> for Vector2<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector2<N>;
            fn $fun(self, rhs: N) -> Vector2<N> {
                Vector2 { x: e!(self.x $op rhs)
                        , y: e!(self.y $op rhs)
                        }
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for Vector2<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
            , N: Copy
        {
            type Output = Self;
            fn $fun(self, rhs: N) -> Output {
                e!(self.simdalize() $op N::splat(rhs))
            }
        }
    )*};
}

impl_v2_ops! { Add, add, +
               Sub, sub, -
               Div, div, /
               Rem, rem, %
             }

impl<N> Mul<N> for Vector2<N>
where N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Vector2 { x: self.x * rhs
                , y: self.y * rhs
                }
    }
}

#[cfg(features = "parallel")]
impl<N> Mul<N> for Vector2<N>
where Self: Simdalize<Elem = N>
    , N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
}

impl<N> Mul<Vector2<N>> for Vector2<N>
where N: Numeric
    , N: Mul<Output = N> + Add<Output = N>
    , N: Copy
{
    type Output = N;
    fn mul(self, rhs: Self) -> N {
        (self.x * rhs.x) + (self.y * rhs.y)
    }
}
<|endoftext|>


<commit_before>use std::ops::{Add, Sub, Mul, Neg};

#[derive(Debug, Clone, Copy)]
pub struct Vec3 {
    pub x: f64,
    pub y: f64,
    pub z: f64
}

pub type Point = Vec3;

#[derive(Debug)]
pub struct Ray {
    pub origin: Vec3,
    pub direction: Vec3
}

impl Vec3 {
    pub fn new(x: f64, y: f64, z: f64) -> Vec3 {
        Vec3 { x: x, y: y, z: z }
    }

    #[inline(always)]
    pub fn dot(self, other: Vec3) -> f64 {
        let Vec3 { x: x1, y: y1, z: z1 } = self;
        let Vec3 { x: x2, y: y2, z: z2 } = other;

        (x1 * x2) + (y1 * y2) + (z1 * z2)
    }

    pub fn cross(self, other: Vec3) -> Vec3 {
        let Vec3 { x: x1, y: y1, z: z1 } = self;
        let Vec3 { x: x2, y: y2, z: z2 } = other;

        Vec3 { x: y1 * z2 - z1 * y2,
               y: z1 * x2 - x1 * z2,
               z: x1 * y2 - y1 * x2 }
    }

    pub fn mag_squared(self) -> f64 {
        self.dot(self)
    }

    pub fn normalized(self) -> Vec3 {
        let mag = self.mag_squared().sqrt();
        let Vec3 { x: x1, y: y1, z: z1 } = self;

        Vec3 { x: x1 / mag, y: y1 / mag, z: z1 / mag }
    }
}

impl Add for Vec3 {
    type Output = Vec3;

    #[inline(always)]
    fn add(self, other: Vec3) -> Vec3 {
        let Vec3 { x: x1, y: y1, z: z1 } = self;
        let Vec3 { x: x2, y: y2, z: z2 } = other;

        Vec3 { x: x1 + x2, y: y1 + y2, z: z1 + z2 }
    }
}

impl Sub for Vec3 {
    type Output = Vec3;

    #[inline(always)]
    fn sub(self, other: Vec3) -> Vec3 {
        let Vec3 { x: x1, y: y1, z: z1 } = self;
        let Vec3 { x: x2, y: y2, z: z2 } = other;

        Vec3 { x: x1 - x2, y: y1 - y2, z: z1 - z2 }
    }
}

impl Mul<f64> for Vec3 {
    type Output = Vec3;

    #[inline(always)]
    fn mul(self, other: f64) -> Vec3 {
        let Vec3 { x: x1, y: y1, z: z1 } = self;

        Vec3 { x: other*x1, y: other*y1, z: other*z1 }
    }
}

impl Neg for Vec3 {
    type Output = Vec3;

    #[inline(always)]
    fn neg(self) -> Vec3 {
        let Vec3 { x: x1, y: y1, z: z1 } = self;

        Vec3 { x: -x1, y: -y1, z: -z1 }
    }
}
<commit_msg>Add vector-float division<commit_after>use std::ops::{Add, Sub, Mul, Neg, Div};

#[derive(Debug, Clone, Copy)]
pub struct Vec3 {
    pub x: f64,
    pub y: f64,
    pub z: f64
}

pub type Point = Vec3;

#[derive(Debug)]
pub struct Ray {
    pub origin: Vec3,
    pub direction: Vec3
}

impl Vec3 {
    pub fn new(x: f64, y: f64, z: f64) -> Vec3 {
        Vec3 { x: x, y: y, z: z }
    }

    #[inline(always)]
    pub fn dot(self, other: Vec3) -> f64 {
        let Vec3 { x: x1, y: y1, z: z1 } = self;
        let Vec3 { x: x2, y: y2, z: z2 } = other;

        (x1 * x2) + (y1 * y2) + (z1 * z2)
    }

    pub fn cross(self, other: Vec3) -> Vec3 {
        let Vec3 { x: x1, y: y1, z: z1 } = self;
        let Vec3 { x: x2, y: y2, z: z2 } = other;

        Vec3 { x: y1 * z2 - z1 * y2,
               y: z1 * x2 - x1 * z2,
               z: x1 * y2 - y1 * x2 }
    }

    pub fn mag_squared(self) -> f64 {
        self.dot(self)
    }

    pub fn normalized(self) -> Vec3 {
        let mag = self.mag_squared().sqrt();
        let Vec3 { x: x1, y: y1, z: z1 } = self;

        Vec3 { x: x1 / mag, y: y1 / mag, z: z1 / mag }
    }
}

impl Add for Vec3 {
    type Output = Vec3;

    #[inline(always)]
    fn add(self, other: Vec3) -> Vec3 {
        let Vec3 { x: x1, y: y1, z: z1 } = self;
        let Vec3 { x: x2, y: y2, z: z2 } = other;

        Vec3 { x: x1 + x2, y: y1 + y2, z: z1 + z2 }
    }
}

impl Sub for Vec3 {
    type Output = Vec3;

    #[inline(always)]
    fn sub(self, other: Vec3) -> Vec3 {
        let Vec3 { x: x1, y: y1, z: z1 } = self;
        let Vec3 { x: x2, y: y2, z: z2 } = other;

        Vec3 { x: x1 - x2, y: y1 - y2, z: z1 - z2 }
    }
}

impl Mul<f64> for Vec3 {
    type Output = Vec3;

    #[inline(always)]
    fn mul(self, other: f64) -> Vec3 {
        let Vec3 { x: x1, y: y1, z: z1 } = self;

        Vec3 { x: other*x1, y: other*y1, z: other*z1 }
    }
}

impl Div<f64> for Vec3 {
    type Output = Vec3;

    #[inline(always)]
    fn div(self, other: f64) -> Vec3 {
        let Vec3 { x: x1, y: y1, z: z1 } = self;

        Vec3 { x: x1 / other, y: y1 / other, z: z1 / other }
    }
}

impl Neg for Vec3 {
    type Output = Vec3;

    #[inline(always)]
    fn neg(self) -> Vec3 {
        let Vec3 { x: x1, y: y1, z: z1 } = self;

        Vec3 { x: -x1, y: -y1, z: -z1 }
    }
}
<|endoftext|>


<commit_before>extern crate http;
extern crate iron;

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

fn main() {
    Iron::new(hello_world).listen(Ipv4Addr(127, 0, 0, 1), 3000);
    println!("On 3000");
}

fn hello_world(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with(status::Ok, "Hello, world!"))
}
<commit_msg>Implement response time example<commit_after>extern crate iron;
extern crate time;
extern crate typemap;

use std::io::net::ip::Ipv4Addr;
use iron::status;
use iron::{
    AfterMiddleware,
    BeforeMiddleware,
    Chain,
    ChainBuilder,
    Iron,
    Request,
    Response,
    IronResult,
};
use time::precise_time_ns;
use typemap::Assoc;

fn main() {
    let mut chain = ChainBuilder::new(hello_world);
    chain.link_before(ResponseTime);
    chain.link_after(ResponseTime);
    Iron::new(chain).listen(Ipv4Addr(127, 0, 0, 1), 3000);
    println!("On 3000");
}

fn hello_world(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with(status::Ok, "Hello, world!"))
}

struct ResponseTime;

impl Assoc<u64> for ResponseTime {}

impl BeforeMiddleware for ResponseTime {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        req.extensions.insert::<ResponseTime, u64>(precise_time_ns());
        Ok(())
    }
}

impl AfterMiddleware for ResponseTime {
    fn after(&self, req: &mut Request, _: &mut Response) -> IronResult<()> {
        let delta = precise_time_ns() - *req.extensions.find::<ResponseTime, u64>().unwrap();
        println!("Request took: {} ms", (delta as f64) / 1000000.0);
        Ok(())
    }
}
<|endoftext|>