<commit_before>use ndarray::{Array, Ix, Axis, ArrayView, stack};
use std::collections::HashMap;
use std::hash::Hash;
use std::fmt::Debug;
use num::Float;

pub type Column<T> = Array<T, Ix>;
pub type Row<T> = Vec<T>;
pub type Matrix<T> = Array<T, (Ix, Ix)>;
pub type ColumnView<'a, T> = ArrayView<'a, T, Ix>;
pub type MatrixView<'a, T> = ArrayView<'a, T, (Ix, Ix)>;

#[derive(Debug, Clone, PartialEq)]
pub struct DataFrame<T: Float> {
    data_map: HashMap<String, usize>,
    inner_matrix: Matrix<T>,
}

impl<T: Float> DataFrame<T> {
    pub fn inner_matrix(&self) -> &Matrix<T> {
        &self.inner_matrix
    }
    pub fn datamap(&self) -> &HashMap<String, usize> {
        &self.data_map
    }

    pub fn new(data: Matrix<T>, names: Vec<String>) -> Result<DataFrame<T>, &'static str> {

        if names.len() != data.shape()[1] {
            return Err("shape mismatch!");
        }

        let datamap: HashMap<String, usize> = names.iter()
            .enumerate()
            .map(|(x, y)| (y.clone(), x))
            .collect();

        let dm = DataFrame {
            data_map: datamap,
            inner_matrix: data,
        };

        Ok(dm)
    }

    pub fn get(self, name: String) -> Result<Column<T>, &'static str> {
        match self.data_map.get(&name) {
            Some(x) => Ok(self.inner_matrix.column(*x).to_owned()),
            None => Err("no such column exists"),
        }
    }

    pub fn insert(mut self, data: Matrix<T>, name: String) -> Result<DataFrame<T>, &'static str> {

        let idx = {
            self.data_map.len()
        };
        self.data_map.insert(name, idx);
        self.inner_matrix = match stack(Axis(1), &[self.inner_matrix.view(), data.view()]) {
            Ok(z) => z,
            Err(_) => return Err("could not insert into matrix."),
        };
        Ok(self)

    }

    pub fn inner_join(self, other: DataFrame<T>, on: &str) -> Result<DataFrame<T>, &'static str> {

        let h: HashMap<Value, usize> = {
            let h_idx: &usize = match self.data_map
                .get(on) {
                Some(z) => z,
                None => return Err("column name does not exist in self dataframe"),
            };

            self.inner_matrix
                .column(*h_idx)
                .indexed_iter()
                .map(|(x, y)| (Value::new(*y), x))
                .collect()
        };

        let j: HashMap<Value, usize> = {
            let j_idx: &usize = match other.data_map
                .get(on) {
                Some(z) => z,
                None => return Err("column name does not exist in other dataframe"),
            };

            other.inner_matrix
                .column(*j_idx)
                .indexed_iter()
                .map(|(x, y)| (Value::new(*y), x))
                .collect()
        };

        let idxs: Vec<(Value, usize, Option<usize>)> =
            Join::new(JoinType::InnerJoin, h.into_iter(), j).collect();

        if idxs.len() == 0 {
            return Err("no common values");
        }

        let new_matrix: Matrix<T> = {
            let i1: Vec<usize> = idxs.iter().map(|&(_, x, _)| x).collect();
            let i2: Vec<usize> = idxs.iter().map(|&(_, _, y)| y.unwrap()).collect();
            let mat1 = self.inner_matrix.select(Axis(0), &i1[..]);
            let mat2 = other.inner_matrix.select(Axis(0), &i2[..]);
            match stack(Axis(1), &[mat1.view(), mat2.view()]) {
                Ok(z) => z,
                Err(_) => return Err("could not build joined matrix."),
            }

        };

        let mut n1: Vec<String> = self.data_map.keys().map(|x| x.clone()).collect();
        let n2: Vec<String> = other.data_map.keys().map(|x| x.clone() + "_x").collect();
        n1.extend_from_slice(&n2[..]);

        println!("join names shape - {:?}", n1.len());
        println!("join matrix shape - {:?}", new_matrix.shape()[1]);
        DataFrame::new(new_matrix, n1)
    }
}

#[derive(Hash, Eq, Debug, Clone,PartialEq)]
struct Value((u64, i16, i8));

impl Value {
    fn new<T: Float>(val: T) -> Value {
        Value(val.integer_decode())
    }
}

pub enum JoinType {
    InnerJoin,
    OuterLeftJoin,
}
pub enum Join<L, K, RV> {
    InnerJoin { left: L, right: HashMap<K, RV> },
    OuterLeftJoin { left: L, right: HashMap<K, RV> },
}

impl<L, K, RV> Join<L, K, RV>
    where K: Hash + Eq
{
    pub fn new<LI, RI>(t: JoinType, left: LI, right: RI) -> Self
        where L: Iterator<Item = LI::Item>,
              LI: IntoIterator<IntoIter = L>,
              RI: IntoIterator<Item = (K, RV)>
    {
        match t {
            JoinType::InnerJoin => {
                Join::InnerJoin {
                    left: left.into_iter(),
                    right: right.into_iter().collect(),
                }
            }
            JoinType::OuterLeftJoin => {
                Join::OuterLeftJoin {
                    left: left.into_iter(),
                    right: right.into_iter().collect(),
                }
            }

        }

    }
}

impl<L, K, LV, RV> Iterator for Join<L, K, RV>
    where L: Iterator<Item = (K, LV)>,
          K: Hash + Eq + Debug,
          RV: Clone + Debug
{
    type Item = (K, LV, Option<RV>);

    fn next(&mut self) -> Option<Self::Item> {
        match self {
            &mut Join::InnerJoin { ref mut left, ref right } => {
                loop {
                    match left.next() {
                        Some((k, lv)) => {
                            let rv = right.get(&k);
                            match rv {
                                Some(v) => return Some((k, lv, Some(v).cloned())),
                                None => continue,
                            }
                        }
                        None => return None,
                    }

                }
            }
            &mut Join::OuterLeftJoin { ref mut left, ref right } => {
                match left.next() {
                    Some((k, lv)) => {
                        let rv = right.get(&k);
                        Some((k, lv, rv.cloned()))
                    }
                    None => None,
                }
            }
        }

    }
}

// To implement....?
// // parallelized join
// // parallelized concatenation
// // parallelized frequency counts
// // index dataframe?
// // sample rows
// // find/select
// // sort
// // statistics (mean, median, stdev)
// // print
//
// // statistics (mean, median, stdev)
// // print
<commit_msg>removed row type<commit_after>use ndarray::{Array, Ix, Axis, ArrayView, stack};
use std::collections::HashMap;
use std::hash::Hash;
use std::fmt::Debug;
use num::Float;

pub type Column<T> = Array<T, Ix>;
pub type Matrix<T> = Array<T, (Ix, Ix)>;
pub type ColumnView<'a, T> = ArrayView<'a, T, Ix>;
pub type MatrixView<'a, T> = ArrayView<'a, T, (Ix, Ix)>;

#[derive(Debug, Clone, PartialEq)]
pub struct DataFrame<T: Float> {
    data_map: HashMap<String, usize>,
    inner_matrix: Matrix<T>,
}

impl<T: Float> DataFrame<T> {
    pub fn inner_matrix(&self) -> &Matrix<T> {
        &self.inner_matrix
    }
    pub fn datamap(&self) -> &HashMap<String, usize> {
        &self.data_map
    }

    pub fn new(data: Matrix<T>, names: Vec<String>) -> Result<DataFrame<T>, &'static str> {

        if names.len() != data.shape()[1] {
            return Err("shape mismatch!");
        }

        let datamap: HashMap<String, usize> = names.iter()
            .enumerate()
            .map(|(x, y)| (y.clone(), x))
            .collect();

        let dm = DataFrame {
            data_map: datamap,
            inner_matrix: data,
        };

        Ok(dm)
    }

    pub fn get(self, name: String) -> Result<Column<T>, &'static str> {
        match self.data_map.get(&name) {
            Some(x) => Ok(self.inner_matrix.column(*x).to_owned()),
            None => Err("no such column exists"),
        }
    }

    pub fn insert(mut self, data: Matrix<T>, name: String) -> Result<DataFrame<T>, &'static str> {

        let idx = {
            self.data_map.len()
        };
        self.data_map.insert(name, idx);
        self.inner_matrix = match stack(Axis(1), &[self.inner_matrix.view(), data.view()]) {
            Ok(z) => z,
            Err(_) => return Err("could not insert into matrix."),
        };
        Ok(self)

    }

    pub fn inner_join(self, other: DataFrame<T>, on: &str) -> Result<DataFrame<T>, &'static str> {

        let h: HashMap<Value, usize> = {
            let h_idx: &usize = match self.data_map
                .get(on) {
                Some(z) => z,
                None => return Err("column name does not exist in self dataframe"),
            };

            self.inner_matrix
                .column(*h_idx)
                .indexed_iter()
                .map(|(x, y)| (Value::new(*y), x))
                .collect()
        };

        let j: HashMap<Value, usize> = {
            let j_idx: &usize = match other.data_map
                .get(on) {
                Some(z) => z,
                None => return Err("column name does not exist in other dataframe"),
            };

            other.inner_matrix
                .column(*j_idx)
                .indexed_iter()
                .map(|(x, y)| (Value::new(*y), x))
                .collect()
        };

        let idxs: Vec<(Value, usize, Option<usize>)> =
            Join::new(JoinType::InnerJoin, h.into_iter(), j).collect();

        if idxs.len() == 0 {
            return Err("no common values");
        }

        let new_matrix: Matrix<T> = {
            let i1: Vec<usize> = idxs.iter().map(|&(_, x, _)| x).collect();
            let i2: Vec<usize> = idxs.iter().map(|&(_, _, y)| y.unwrap()).collect();
            let mat1 = self.inner_matrix.select(Axis(0), &i1[..]);
            let mat2 = other.inner_matrix.select(Axis(0), &i2[..]);
            match stack(Axis(1), &[mat1.view(), mat2.view()]) {
                Ok(z) => z,
                Err(_) => return Err("could not build joined matrix."),
            }

        };

        let mut n1: Vec<String> = self.data_map.keys().map(|x| x.clone()).collect();
        let n2: Vec<String> = other.data_map.keys().map(|x| x.clone() + "_x").collect();
        n1.extend_from_slice(&n2[..]);

        println!("join names shape - {:?}", n1.len());
        println!("join matrix shape - {:?}", new_matrix.shape()[1]);
        DataFrame::new(new_matrix, n1)
    }
}

#[derive(Hash, Eq, Debug, Clone,PartialEq)]
struct Value((u64, i16, i8));

impl Value {
    fn new<T: Float>(val: T) -> Value {
        Value(val.integer_decode())
    }
}

pub enum JoinType {
    InnerJoin,
    OuterLeftJoin,
}
pub enum Join<L, K, RV> {
    InnerJoin { left: L, right: HashMap<K, RV> },
    OuterLeftJoin { left: L, right: HashMap<K, RV> },
}

impl<L, K, RV> Join<L, K, RV>
    where K: Hash + Eq
{
    pub fn new<LI, RI>(t: JoinType, left: LI, right: RI) -> Self
        where L: Iterator<Item = LI::Item>,
              LI: IntoIterator<IntoIter = L>,
              RI: IntoIterator<Item = (K, RV)>
    {
        match t {
            JoinType::InnerJoin => {
                Join::InnerJoin {
                    left: left.into_iter(),
                    right: right.into_iter().collect(),
                }
            }
            JoinType::OuterLeftJoin => {
                Join::OuterLeftJoin {
                    left: left.into_iter(),
                    right: right.into_iter().collect(),
                }
            }

        }

    }
}

impl<L, K, LV, RV> Iterator for Join<L, K, RV>
    where L: Iterator<Item = (K, LV)>,
          K: Hash + Eq + Debug,
          RV: Clone + Debug
{
    type Item = (K, LV, Option<RV>);

    fn next(&mut self) -> Option<Self::Item> {
        match self {
            &mut Join::InnerJoin { ref mut left, ref right } => {
                loop {
                    match left.next() {
                        Some((k, lv)) => {
                            let rv = right.get(&k);
                            match rv {
                                Some(v) => return Some((k, lv, Some(v).cloned())),
                                None => continue,
                            }
                        }
                        None => return None,
                    }

                }
            }
            &mut Join::OuterLeftJoin { ref mut left, ref right } => {
                match left.next() {
                    Some((k, lv)) => {
                        let rv = right.get(&k);
                        Some((k, lv, rv.cloned()))
                    }
                    None => None,
                }
            }
        }

    }
}

// To implement....?
// // parallelized join
// // parallelized concatenation
// // parallelized frequency counts
// // index dataframe?
// // sample rows
// // find/select
// // sort
// // statistics (mean, median, stdev)
// // print
//
// // statistics (mean, median, stdev)
// // print
<|endoftext|>


<commit_before>//! The datum module provides a data structure, Datum, that implements the Unify trait.
//! Datum aims to be a drop-in for any algorithm in ai_kit that operates on the Unify trait.

#[cfg(feature = "with-constraint")]
use constraints::ConstraintValue;
use core;
use std;
use std::collections::HashMap;
use std::str;
use utils;

#[derive(Clone, Debug, Serialize, Deserialize, PartialOrd)]
pub enum Datum {
    #[serde(rename="null")]
    Nil,
    #[serde(rename="str")]
    String(String),
    #[serde(rename="int")]
    Int(i64),
    #[serde(rename="float")]
    Float(f64),
    #[serde(rename="var")]
    Variable(String),
    #[serde(rename="vec")]
    Vector(Vec<Datum>),
    #[serde(rename="fn")]
    Function { head: Box<Datum>, args: Vec<Datum> },
}

impl Datum {
    pub fn to_string(&self) -> Option<String> {
        match *self {
            Datum::String(ref value) => Some(value.clone()),
            _ => None,
        }
    }

    pub fn to_int(&self) -> Option<i64> {
        match *self {
            Datum::Int(ref value) => Some(value.clone()),
            _ => None,
        }
    }

    pub fn to_float(&self) -> Option<f64> {
        match *self {
            Datum::Float(ref f_value) => Some(f_value.clone()),
            Datum::Int(ref i_value) => Some((i_value.clone() as f64)),
            _ => None,
        }
    }

    pub fn to_variable(&self) -> Option<String> {
        match *self {
            Datum::Variable(ref value) => Some(value.clone()),
            _ => None,
        }
    }

    pub fn pprint(&self) -> String {
        match *self {
            Datum::String(ref s) => format!("{}", s),
            Datum::Int(ref i) => format!("{}", i),
            Datum::Float(ref f) => format!("{}", f),
            Datum::Variable(ref v) => format!("{}", v),
            Datum::Vector(ref args) => {
                let elements: Vec<String> = args.iter().map(|e| e.pprint()).collect();
                format!("({})", elements.join(","))
            }
            Datum::Nil => format!("nil"),
            Datum::Function { ref head, ref args } => {
                let elements: Vec<String> = args.iter().map(|e| e.pprint()).collect();
                format!("({} ({}))", head, elements.join(","))
            }
        }
    }
}

impl Default for Datum {
    fn default() -> Self {
        Datum::Nil
    }
}

impl PartialEq for Datum {
    fn eq(&self, other: &Datum) -> bool {
        match *self {
            Datum::String(ref s) => {
                match *other {
                    Datum::String(ref s2) => s == s2,
                    _ => false,
                }
            }
            Datum::Int(ref i) => {
                match *other {
                    Datum::Int(ref i2) => i == i2,
                    _ => false,
                }
            }
            Datum::Float(ref f) => {
                match *other {
                    Datum::Float(ref f2) => f == f2,
                    _ => false,
                }
            }
            Datum::Variable(ref v) => {
                match *other {
                    Datum::Variable(ref v2) => v == v2,
                    _ => false,
                }
            }
            Datum::Vector(ref args) => {
                match *other {
                    Datum::Vector(ref args2) => args == args2,
                    _ => false,
                }
            }
            Datum::Nil => {
                match *other {
                    Datum::Nil => true,
                    _ => false,
                }
            }
            Datum::Function { ref head, ref args } => {
                match *other {
                    Datum::Function { head: ref head2, args: ref args2 } if args.len() == args2.len() => head == head2 && args == args2,
                    _ => false,
                }
            }
        }
    }
}

impl Eq for Datum {}
impl Ord for Datum {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.partial_cmp(other).unwrap()
    }
}

impl core::BindingsValue for Datum {
    fn variable(s: &String) -> Option<Self> {
        Some(Datum::Variable(s.clone()))
    }
    fn to_variable(&self) -> Option<String> {
        self.to_variable()
    }
}

#[cfg(feature = "with-constraint")]
impl ConstraintValue for Datum {
    fn to_float(&self) -> Option<f64> {
        self.to_float()
    }
    fn float(c: f64) -> Self {
        Datum::Float(c)
    }
}

impl core::Unify<Datum> for Datum {
    fn unify(&self, other: &Datum, bindings: &core::Bindings<Self>) -> Option<core::Bindings<Self>> {

        fn unify_args(args: &Vec<Datum>, args2: &Vec<Datum>, bindings: &core::Bindings<Datum>) -> Option<core::Bindings<Datum>> {
            utils::fold_while_some(bindings.clone(),
                                   &mut args.iter().zip(args2.iter()),
                                   &|bindings: core::Bindings<Datum>, (ref a, ref b): (&Datum, &Datum)| a.unify(&b, &bindings))
        }
        match *self {
            Datum::Variable(ref var_name) => bindings.update_bindings(var_name, other),
            Datum::Vector(ref args) => {
                match *other {
                    Datum::Vector(ref args2) if args.len() == args2.len() => unify_args(args, args2, &bindings),
                    _ => None,
                }
            }
            _ => {
                match *other {
                    Datum::Variable(ref var_name) => bindings.update_bindings(var_name, self),
                    _ => {
                        if self == other {
                            Some(bindings.clone())
                        } else {
                            None
                        }
                    }
                }
            }
        }
    }

    fn apply_bindings(&self, bindings: &core::Bindings<Self>) -> Option<Self> {
        fn apply_bindings_to_args(args: &Vec<Datum>, bindings: &core::Bindings<Datum>) -> Option<Vec<Datum>> {
            utils::map_while_some(&mut args.iter(), &|arg| arg.apply_bindings(bindings))
        }
        match *self {
            Datum::Variable(ref var_name) => bindings.get_binding(var_name).or_else(|| Some(self.clone())),
            Datum::Vector(ref args) => apply_bindings_to_args(args, bindings).and_then(|args| Some(Datum::Vector(args))),
            _ => Some(self.clone()),
        }
    }

    fn variables(&self) -> Vec<String> {
        match *self {
            Datum::Variable(ref v) => vec![v.clone()],
            Datum::Vector(ref args) => {
                let mut variables = Vec::new();
                for arg in args.iter() {
                    variables.extend(arg.variables().into_iter());
                }
                variables
            }
            _ => Vec::new(),
        }
    }

    fn rename_variables(&self, renamed_variables: &HashMap<String, String>) -> Self {
        match *self {
            Datum::Variable(ref v) => {
                renamed_variables.get(v)
                    .and_then(|new_v| Some(Datum::Variable(new_v.clone())))
                    .or_else(|| Some(self.clone()))
                    .unwrap()
            }
            Datum::Vector(ref args) => Datum::Vector(args.iter().map(|arg| arg.rename_variables(renamed_variables)).collect()),
            _ => self.clone(),
        }
    }

    fn nil() -> Self {
        Datum::Nil
    }
}

impl std::fmt::Display for Datum {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", self.pprint())
    }
}

#[cfg(test)]
mod tests;
<commit_msg>Extended Datum enum to have a new `Map` variant for recording key-value relationships<commit_after>//! The datum module provides a data structure, Datum, that implements the Unify trait.
//! Datum aims to be a drop-in for any algorithm in ai_kit that operates on the Unify trait.

#[cfg(feature = "with-constraint")]
use constraints::ConstraintValue;
use core;
use std;
use std::collections::{BTreeMap, HashMap};
use std::str;
use utils;

#[derive(Clone, Debug, Serialize, Deserialize, PartialOrd)]
pub enum Datum {
    #[serde(rename="null")]
    Nil,
    #[serde(rename="str")]
    String(String),
    #[serde(rename="int")]
    Int(i64),
    #[serde(rename="float")]
    Float(f64),
    #[serde(rename="var")]
    Variable(String),
    #[serde(rename="vec")]
    Vector(Vec<Datum>),
    #[serde(rename="map")]
    Map(BTreeMap<String, Datum>),
    #[serde(rename="fn")]
    Function { head: Box<Datum>, args: Vec<Datum> },
}

impl Datum {
    pub fn to_string(&self) -> Option<String> {
        match *self {
            Datum::String(ref value) => Some(value.clone()),
            _ => None,
        }
    }

    pub fn to_int(&self) -> Option<i64> {
        match *self {
            Datum::Int(ref value) => Some(value.clone()),
            _ => None,
        }
    }

    pub fn to_float(&self) -> Option<f64> {
        match *self {
            Datum::Float(ref f_value) => Some(f_value.clone()),
            Datum::Int(ref i_value) => Some((i_value.clone() as f64)),
            _ => None,
        }
    }

    pub fn to_variable(&self) -> Option<String> {
        match *self {
            Datum::Variable(ref value) => Some(value.clone()),
            _ => None,
        }
    }

    pub fn pprint(&self) -> String {
        match *self {
            Datum::String(ref s) => format!("{}", s),
            Datum::Int(ref i) => format!("{}", i),
            Datum::Float(ref f) => format!("{}", f),
            Datum::Variable(ref v) => format!("{}", v),
            Datum::Vector(ref args) => {
                let elements: Vec<String> = args.iter().map(|e| e.pprint()).collect();
                format!("({})", elements.join(","))
            }
            Datum::Map(ref args) => {
                let elements: Vec<String> = args.iter().map(|(k, v)| format!("{} => {}", k, v.pprint())).collect();
                format!("({})", elements.join(","))
            }
            Datum::Nil => format!("nil"),
            Datum::Function { ref head, ref args } => {
                let elements: Vec<String> = args.iter().map(|e| e.pprint()).collect();
                format!("({} ({}))", head, elements.join(","))
            }
        }
    }
}

impl Default for Datum {
    fn default() -> Self {
        Datum::Nil
    }
}

impl PartialEq for Datum {
    fn eq(&self, other: &Datum) -> bool {
        match *self {
            Datum::String(ref s) => {
                match *other {
                    Datum::String(ref s2) => s == s2,
                    _ => false,
                }
            }
            Datum::Int(ref i) => {
                match *other {
                    Datum::Int(ref i2) => i == i2,
                    _ => false,
                }
            }
            Datum::Float(ref f) => {
                match *other {
                    Datum::Float(ref f2) => f == f2,
                    _ => false,
                }
            }
            Datum::Variable(ref v) => {
                match *other {
                    Datum::Variable(ref v2) => v == v2,
                    _ => false,
                }
            }
            Datum::Vector(ref args) => {
                match *other {
                    Datum::Vector(ref args2) => args == args2,
                    _ => false,
                }
            }
            Datum::Map(ref args) => {
                match *other {
                    Datum::Map(ref args2) => args == args2,
                    _ => false,
                }
            }
            Datum::Nil => {
                match *other {
                    Datum::Nil => true,
                    _ => false,
                }
            }
            Datum::Function { ref head, ref args } => {
                match *other {
                    Datum::Function { head: ref head2, args: ref args2 } if args.len() == args2.len() => head == head2 && args == args2,
                    _ => false,
                }
            }
        }
    }
}

impl Eq for Datum {}
impl Ord for Datum {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.partial_cmp(other).unwrap()
    }
}

impl core::BindingsValue for Datum {
    fn variable(s: &String) -> Option<Self> {
        Some(Datum::Variable(s.clone()))
    }
    fn to_variable(&self) -> Option<String> {
        self.to_variable()
    }
}

#[cfg(feature = "with-constraint")]
impl ConstraintValue for Datum {
    fn to_float(&self) -> Option<f64> {
        self.to_float()
    }
    fn float(c: f64) -> Self {
        Datum::Float(c)
    }
}

impl core::Unify<Datum> for Datum {
    fn unify(&self, other: &Datum, bindings: &core::Bindings<Self>) -> Option<core::Bindings<Self>> {

        fn unify_args(args: &Vec<Datum>, args2: &Vec<Datum>, bindings: &core::Bindings<Datum>) -> Option<core::Bindings<Datum>> {
            utils::fold_while_some(bindings.clone(),
                                   &mut args.iter().zip(args2.iter()),
                                   &|bindings: core::Bindings<Datum>, (ref a, ref b): (&Datum, &Datum)| a.unify(&b, &bindings))
        }

        fn unify_maps(args: &BTreeMap<String, Datum>,
                      args2: &BTreeMap<String, Datum>,
                      bindings: &core::Bindings<Datum>)
                      -> Option<core::Bindings<Datum>> {
            if args.len() != args2.len() {
                None
            } else {
                utils::fold_while_some(bindings.clone(),
                                       &mut args.iter(),
                                       &|bindings: core::Bindings<Datum>, (ref k, ref v): (&String, &Datum)| {
                                           args2.get(*k).and_then(|v2| v.unify(v2, &bindings))
                                       })
            }
        }
        match *self {
            Datum::Variable(ref var_name) => bindings.update_bindings(var_name, other),
            Datum::Vector(ref args) => {
                match *other {
                    Datum::Vector(ref args2) if args.len() == args2.len() => unify_args(args, args2, &bindings),
                    _ => None,
                }
            }
            Datum::Map(ref args) => {
                match *other {
                    Datum::Map(ref args2) if args.len() == args2.len() => unify_maps(args, args2, &bindings),
                    _ => None,
                }
            }
            _ => {
                match *other {
                    Datum::Variable(ref var_name) => bindings.update_bindings(var_name, self),
                    _ => {
                        if self == other {
                            Some(bindings.clone())
                        } else {
                            None
                        }
                    }
                }
            }
        }
    }

    fn apply_bindings(&self, bindings: &core::Bindings<Self>) -> Option<Self> {
        fn apply_bindings_to_args(args: &Vec<Datum>, bindings: &core::Bindings<Datum>) -> Option<Vec<Datum>> {
            utils::map_while_some(&mut args.iter(), &|arg| arg.apply_bindings(bindings))
        }
        fn apply_bindings_to_map(args: &BTreeMap<String, Datum>, bindings: &core::Bindings<Datum>) -> Option<BTreeMap<String, Datum>> {
            utils::map_while_some(&mut args.iter(),
                                  &|(k, v)| v.apply_bindings(bindings).and_then(|v| Some((k.clone(), v))))
                .and_then(|tuple_vec| Some(tuple_vec.into_iter().collect::<BTreeMap<String, Datum>>()))
        }
        match *self {
            Datum::Variable(ref var_name) => bindings.get_binding(var_name).or_else(|| Some(self.clone())),
            Datum::Vector(ref args) => apply_bindings_to_args(args, bindings).and_then(|args| Some(Datum::Vector(args))),
            Datum::Map(ref args) => apply_bindings_to_map(args, bindings).and_then(|args| Some(Datum::Map(args))),
            _ => Some(self.clone()),
        }
    }

    fn variables(&self) -> Vec<String> {
        match *self {
            Datum::Variable(ref v) => vec![v.clone()],
            Datum::Vector(ref args) => {
                let mut variables = Vec::new();
                for arg in args.iter() {
                    variables.extend(arg.variables().into_iter());
                }
                variables
            }
            Datum::Map(ref args) => {
                let mut variables = Vec::new();
                for v in args.values() {
                    variables.extend(v.variables().into_iter());
                }
                variables
            }
            _ => Vec::new(),
        }
    }

    fn rename_variables(&self, renamed_variables: &HashMap<String, String>) -> Self {
        match *self {
            Datum::Variable(ref v) => {
                renamed_variables.get(v)
                    .and_then(|new_v| Some(Datum::Variable(new_v.clone())))
                    .or_else(|| Some(self.clone()))
                    .unwrap()
            }
            Datum::Vector(ref args) => Datum::Vector(args.iter().map(|arg| arg.rename_variables(renamed_variables)).collect()),
            Datum::Map(ref args) => Datum::Map(args.iter().map(|(k, v)| (k.clone(), v.rename_variables(renamed_variables))).collect()),
            _ => self.clone(),
        }
    }

    fn nil() -> Self {
        Datum::Nil
    }
}

impl std::fmt::Display for Datum {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", self.pprint())
    }
}

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>extern crate toml;
extern crate rustc_serialize;
extern crate walkdir;

use error::YabsError;
use ext::*;
use rustc_serialize::{Decodable, Encodable, json};
use walkdir::{WalkDir, WalkDirIterator, DirEntry};

use std::ffi::OsStr;

pub struct Target {
    pub target: String,
    pub all: String,
}

// General trait for any description.
pub trait Desc<T> {
    fn new() -> T;
    fn from_toml_table(table: toml::Value) -> Result<T, YabsError>;
    fn print_json(&self);
}

impl<T: Decodable + Encodable + Default> Desc<T> for T {
    // Creates an empty description using `Default`
    fn new() -> T {
        Default::default()
    }

    fn from_toml_table(table: toml::Value) -> Result<T, YabsError> {
        Ok(try!(Decodable::decode(&mut toml::Decoder::new(table.clone()))))
    }

    fn print_json(&self) {
        println!("{}", json::as_pretty_json(&self));
    }
}

pub trait FromFile<T> {
    fn from_file(file: &str, name: &str) -> Result<T, Vec<YabsError>>;
}

// FromFile for anything T that implements Desc etc.
impl<T: Decodable + Encodable + Default + Desc<T>> FromFile<T> for T {
    fn from_file(file: &str, name: &str) -> Result<T, Vec<YabsError>> {
        parse_toml_file(file).and_then(|toml| {
            toml.get(name)
                .ok_or(vec![YabsError::NoDesc(name.to_owned())])
                .and_then(|desc| {
                    Decodable::decode(&mut toml::Decoder::new(desc.clone()))
                        .map_err(|err| vec![YabsError::TomlDecode(err)])
                })
        })
    }
}

#[derive(Debug,Default,RustcDecodable,RustcEncodable,Clone,PartialEq)]
pub struct ProjDesc {
    name: Option<String>,
    target: Option<Vec<String>>,
    lang: Option<String>,
    os: Option<String>,
    version: Option<String>,
    compiler: Option<String>,
    pub src: Option<Vec<String>>,
    libs: Option<Vec<String>>,
    lib_dir: Option<Vec<String>>,
    inc: Option<Vec<String>>,
    cflags: Option<Vec<String>>,
    explicit_cflags: Option<String>,
    lflags: Option<Vec<String>>,
    ignore: Option<Vec<String>>,
    before_script: Option<Vec<String>>,
    after_script: Option<Vec<String>>,
    static_lib: Option<bool>,
    ar: Option<String>,
    arflags: Option<String>,
    clean: Option<Vec<String>>,
}

impl ProjDesc {
    pub fn is_in_ignore(&self, entry: &DirEntry) -> bool {
        if let Some(ignore) = self.ignore.as_ref() {
            for path in ignore {
                if let Some(entry_str) = entry.path().to_str() {
                    if entry_str.find(path).is_some() {
                        return true;
                    }
                }
            }
        }
        false
    }

    pub fn gen_file_list(&mut self) -> Result<(), YabsError> {
        // If sources are listed don't scan for files
        if self.src.is_some() {
            return Ok(());
        }
        let mut sources = Vec::new();
        let walk_dir = WalkDir::new(".").into_iter();
        for entry in walk_dir.filter_entry(|e| !&self.is_in_ignore(e)) {
            let entry = try!(entry);
            if entry.path().is_file() {
                let file_ext = entry.path().extension().unwrap_or(OsStr::new(""));
                if let Some(ext) = file_ext.to_str() {
                    if let Some(lang) = self.lang.as_ref() {
                        if ext == lang {
                            if let Some(entry_str) = entry.path().to_str() {
                                sources.push(entry_str.to_owned());
                            }
                        }
                    }
                }
            }
        }
        sources.sort();
        self.src = Some(sources);
        Ok(())
    }

    // Concatenates a vector of strings `list`, prepending each entry with `prepend`
    pub fn prepend_op_vec(&self, list: &Option<Vec<String>>, prepend: &str) -> String {
        let mut horrid_string = String::new();
        if let Some(items) = list.as_ref() {
            if let Some(split_last) = items.split_last() {
                for sub_item in split_last.1 {
                    if self.is_command(&sub_item) {
                        horrid_string.push_str(&format!("{} ", sub_item));
                    } else {
                        horrid_string.push_str(&format!("{}{} ", prepend.to_owned(), sub_item));
                    }
                }
                if self.is_command(&split_last.0) {
                    horrid_string.push_str(&format!("{} ", split_last.0));
                } else {
                    horrid_string.push_str(&format!("{}{}", prepend.to_owned(), split_last.0.clone()));
                }
            }
        }
        return horrid_string;
    }

    // Any string that starts with the character "`" is regarded as a command
    pub fn is_command(&self, string: &String) -> bool {
        if string.starts_with("`") {
            return true;
        } else {
            return false;
        }
    }

    pub fn gen_target_list(&self) -> Target {
        let mut all = String::new();
        let mut target_str = String::new();
        if let Some(targets) = self.target.clone() {
            all = targets.concat();
            if let Some(static_lib) = self.static_lib {
                if targets.len() == 1 {
                    if static_lib {
                        target_str = format!("$(TARGET): $(OBJ)\n\
                            \t$(AR) $(ARFLAGS) $(TARGET) $(OBJ)\n\n");
                    } else {
                        target_str = format!("$(TARGET): $(OBJ)\n\
                            \t$(CC) $(LFLAGS) -o $(TARGET) $(OBJ) $(LIBDIR) $(LIBS)\n\n");
                    }
                } else {
                    if static_lib {
                        for target in targets {
                            target_str.push_str(&format!("{0}: $(OBJ)\n\
                                    \t$(AR) $(ARFLAGS) {0} $(OBJ)\n\n", target));
                        }
                    } else {
                        for target in targets {
                            target_str.push_str(&format!("{0}: $(OBJ)\n\
                                    \t$(CC) $(LFLAGS) -o {0} $(OBJ) $(LIBDIR) $(LIBS)\n\n", target));
                        }
                    }
                }
            }
        };
        Target { target: target_str, all: all }
    }

    fn gen_lib_dir_list(&self) -> String {
        return self.prepend_op_vec(&self.lib_dir, "-L");
    }

    fn gen_lib_list(&self) -> String {
        return self.prepend_op_vec(&self.libs, "-l");
    }

    fn gen_cflags_list(&self) -> String {
        return self.prepend_op_vec(&self.cflags, "-");
    }

    fn gen_lflags_list(&self) -> String {
        return self.prepend_op_vec(&self.lflags, "-");
    }

    fn gen_src_list(&self) -> String {
        let mut horrid_string: String = "SRC\t= ".to_owned();
        let mut lang = self.lang.clone().unwrap_or("cpp".to_owned());
        lang.insert(0, '.');
        if let Some(source_list) = self.src.as_ref() {
            // Multiple sources
            if source_list.len() > 1 {
                if let Some(split_first) = source_list.split_first() {
                    horrid_string.push_str(&format!("{} \\\n", split_first.0));
                    if let Some(split_last) = split_first.1.clone().split_last() {
                        for src in split_last.1 {
                            horrid_string.push_str(&format!("\t  {} \\\n", src));
                        }
                        horrid_string.push_str(&format!("\t  {}\n", split_last.0));
                    }
                }
            // One source file
            } else {
                for src in source_list {
                    horrid_string.push_str(&format!("{}\n", src));
                }
            }
            let mut parsed_obj_list = Vec::new();
            for obj in source_list {
                parsed_obj_list.push(obj.replace(&lang, ".o"));
            }
            horrid_string.push_str("OBJ\t= ");
            if parsed_obj_list.len() > 1 {
                if let Some(split_first) = parsed_obj_list.split_first() {
                    horrid_string.push_str(&format!("{} \\\n", split_first.0));
                    if let Some(split_last) = split_first.1.clone().split_last() {
                        for src in split_last.1 {
                            horrid_string.push_str(&format!("\t  {} \\\n", src));
                        }
                        horrid_string.push_str(&format!("\t  {}", split_last.0));
                    }
                }
            } else {
                for obj in parsed_obj_list {
                    horrid_string.push_str(&format!("{}\n", obj));
                }
            }
        }
        return horrid_string;
    }

    fn gen_inc_list(&self) -> String {
        return self.prepend_op_vec(&self.inc, "-I");
    }

    pub fn gen_make(&mut self) -> Result<String, YabsError> {
        try!(self.gen_file_list());
        let target = &self.gen_target_list();
        Ok(format!(
            "INSTALL\t= /usr/bin/env install\n\
                AR\t= {ar}\n\
                ARFLAGS\t= {ar_flags}\n\
                DEST\t=\n\
                PREFIX\t=\n\
                CC\t= {compiler}\n\
                BINDIR\t=\n\
                TARGET\t= {all}\n\
                LINK\t= {compiler}\n\
                CFLAGS\t= {cflags}\n\
                LFLAGS\t=\n\
                LIBS\t= {libs}\n\
                INCDIR\t= {incdir}\n\
                LIBDIR\t= {lib_dir}\n\
                CLEAN\t=\n\
                DEL\t= rm -f\n\
                {srcs}\n\n\
                first: all\n\n\
                .PHONY: doc clean\n\n\
                all: {all}\n\n\
                {target_command}\
                %.o: %.{lang}\n\t$(CC) -c $(CFLAGS) $(INCDIR) -o $@ $<\n\
                clean:\n\
                \t$(DEL) $(OBJ)\n\
                \t$(DEL) {all}\n\
                \t$(DEL) {clean_list}\n\
                ",
                compiler = &self.compiler.as_ref().unwrap_or(&"gcc".to_owned()),
                ar = &self.ar.as_ref().unwrap_or(&"/usr/bin/env ar".to_owned()),
                ar_flags = &self.arflags.as_ref().unwrap_or(&"rcs".to_owned()),
                all = target.all,
                target_command = target.target,
                cflags = &self.gen_cflags_list(),
                libs = &self.gen_lib_list(),
                incdir = &self.gen_inc_list(),
                lib_dir = &self.gen_lib_dir_list(),
                srcs = &self.gen_src_list(),
                lang = &self.lang.clone().unwrap_or("c".to_owned()),
                clean_list = &self.clean.clone().unwrap_or(vec![]).concat()))
    }

    pub fn build_bin(&mut self) -> Result<(), YabsError> {
        try!(self.gen_file_list());
        if let Some(src_list) = self.src.as_ref() {
            let mut lang = self.lang.clone().unwrap_or("cpp".to_owned());
            lang.insert(0, '.');
            let mut cmd_string;
            let mut obj_vec = Vec::new();
            for src in src_list {
                cmd_string = format!("{cc} -c {cflag} {inc} -o {object} {source}",
                                         cc = self.compiler.as_ref().unwrap_or(&"gcc".to_owned()),
                                         cflag = self.gen_cflags_list(),
                                         inc = self.gen_inc_list(),
                                         source = src,
                                         object = src.replace(&lang, ".o"),
                                         );
                try!(run_cmd(cmd_string));
                obj_vec.push(src.replace(&lang, ".o"));
            }
            for target in self.target.clone().unwrap_or(vec!["a".to_owned()]) {
                if self.static_lib.unwrap_or(false) == true {
                    cmd_string = format!("{ar} {ar_flags} {target} {obj_list}",
                                                 ar = self.ar.as_ref().unwrap_or(&"/usr/bin/env ar".to_owned()),
                                                 ar_flags = self.arflags.as_ref().unwrap_or(&"rcs".to_owned()),
                                                 target = target,
                                                 obj_list = obj_vec.concat(),
                                                 );
                    try!(run_cmd(cmd_string));
                } else {
                    cmd_string = format!("{cc} {lflags} -o {target} {obj_list} {lib_dir} {libs}",
                                                 cc = self.compiler.as_ref().unwrap_or(&"gcc".to_owned()),
                                                 lflags = self.gen_lflags_list(),
                                                 target = target,
                                                 obj_list = obj_vec.concat(),
                                                 lib_dir = self.gen_lib_dir_list(),
                                                 libs = self.gen_lib_list());
                    try!(run_cmd(cmd_string));
                }
            };
        };
        Ok(())
    }
}

// Descibe how to install this project
#[derive(Debug,Default,RustcDecodable,RustcEncodable,Clone,PartialEq)]
pub struct InstallDesc {
    prefix: Option<String>,
}

// Generate documentation for this project
#[derive(Debug,Default,RustcDecodable,RustcEncodable,Clone,PartialEq)]
pub struct DocDesc {
    doc: Option<Vec<String>>,
}

impl DocDesc {
    pub fn gen_make(&self) -> String {
        let mut doc_str = String::from("doc:\n");
        if let Some(doc) = self.doc.clone() {
            for line in doc {
                doc_str.push_str(&format!("\t{}\n", &line));
            }
        }
        return doc_str;
    }
}
<commit_msg>Check if command also ends with '`'<commit_after>extern crate toml;
extern crate rustc_serialize;
extern crate walkdir;

use error::YabsError;
use ext::*;
use rustc_serialize::{Decodable, Encodable, json};
use walkdir::{WalkDir, WalkDirIterator, DirEntry};

use std::ffi::OsStr;

pub struct Target {
    pub target: String,
    pub all: String,
}

// General trait for any description.
pub trait Desc<T> {
    fn new() -> T;
    fn from_toml_table(table: toml::Value) -> Result<T, YabsError>;
    fn print_json(&self);
}

impl<T: Decodable + Encodable + Default> Desc<T> for T {
    // Creates an empty description using `Default`
    fn new() -> T {
        Default::default()
    }

    fn from_toml_table(table: toml::Value) -> Result<T, YabsError> {
        Ok(try!(Decodable::decode(&mut toml::Decoder::new(table.clone()))))
    }

    fn print_json(&self) {
        println!("{}", json::as_pretty_json(&self));
    }
}

pub trait FromFile<T> {
    fn from_file(file: &str, name: &str) -> Result<T, Vec<YabsError>>;
}

// FromFile for anything T that implements Desc etc.
impl<T: Decodable + Encodable + Default + Desc<T>> FromFile<T> for T {
    fn from_file(file: &str, name: &str) -> Result<T, Vec<YabsError>> {
        parse_toml_file(file).and_then(|toml| {
            toml.get(name)
                .ok_or(vec![YabsError::NoDesc(name.to_owned())])
                .and_then(|desc| {
                    Decodable::decode(&mut toml::Decoder::new(desc.clone()))
                        .map_err(|err| vec![YabsError::TomlDecode(err)])
                })
        })
    }
}

#[derive(Debug,Default,RustcDecodable,RustcEncodable,Clone,PartialEq)]
pub struct ProjDesc {
    name: Option<String>,
    target: Option<Vec<String>>,
    lang: Option<String>,
    os: Option<String>,
    version: Option<String>,
    compiler: Option<String>,
    pub src: Option<Vec<String>>,
    libs: Option<Vec<String>>,
    lib_dir: Option<Vec<String>>,
    inc: Option<Vec<String>>,
    cflags: Option<Vec<String>>,
    explicit_cflags: Option<String>,
    lflags: Option<Vec<String>>,
    ignore: Option<Vec<String>>,
    before_script: Option<Vec<String>>,
    after_script: Option<Vec<String>>,
    static_lib: Option<bool>,
    ar: Option<String>,
    arflags: Option<String>,
    clean: Option<Vec<String>>,
}

impl ProjDesc {
    pub fn is_in_ignore(&self, entry: &DirEntry) -> bool {
        if let Some(ignore) = self.ignore.as_ref() {
            for path in ignore {
                if let Some(entry_str) = entry.path().to_str() {
                    if entry_str.find(path).is_some() {
                        return true;
                    }
                }
            }
        }
        false
    }

    pub fn gen_file_list(&mut self) -> Result<(), YabsError> {
        // If sources are listed don't scan for files
        if self.src.is_some() {
            return Ok(());
        }
        let mut sources = Vec::new();
        let walk_dir = WalkDir::new(".").into_iter();
        for entry in walk_dir.filter_entry(|e| !&self.is_in_ignore(e)) {
            let entry = try!(entry);
            if entry.path().is_file() {
                let file_ext = entry.path().extension().unwrap_or(OsStr::new(""));
                if let Some(ext) = file_ext.to_str() {
                    if let Some(lang) = self.lang.as_ref() {
                        if ext == lang {
                            if let Some(entry_str) = entry.path().to_str() {
                                sources.push(entry_str.to_owned());
                            }
                        }
                    }
                }
            }
        }
        sources.sort();
        self.src = Some(sources);
        Ok(())
    }

    // Concatenates a vector of strings `list`, prepending each entry with `prepend`
    pub fn prepend_op_vec(&self, list: &Option<Vec<String>>, prepend: &str) -> String {
        let mut horrid_string = String::new();
        if let Some(items) = list.as_ref() {
            if let Some(split_last) = items.split_last() {
                for sub_item in split_last.1 {
                    if self.is_command(&sub_item) {
                        horrid_string.push_str(&format!("{} ", sub_item));
                    } else {
                        horrid_string.push_str(&format!("{}{} ", prepend.to_owned(), sub_item));
                    }
                }
                if self.is_command(&split_last.0) {
                    horrid_string.push_str(&format!("{} ", split_last.0));
                } else {
                    horrid_string.push_str(&format!("{}{}", prepend.to_owned(), split_last.0.clone()));
                }
            }
        }
        return horrid_string;
    }

    // Any string that starts and ends with the character "`" is regarded as a command
    pub fn is_command(&self, string: &String) -> bool {
        if string.starts_with("`") && string.ends_with("`") {
            return true;
        } else {
            return false;
        }
    }

    pub fn gen_target_list(&self) -> Target {
        let mut all = String::new();
        let mut target_str = String::new();
        if let Some(targets) = self.target.clone() {
            all = targets.concat();
            if let Some(static_lib) = self.static_lib {
                if targets.len() == 1 {
                    if static_lib {
                        target_str = format!("$(TARGET): $(OBJ)\n\
                            \t$(AR) $(ARFLAGS) $(TARGET) $(OBJ)\n\n");
                    } else {
                        target_str = format!("$(TARGET): $(OBJ)\n\
                            \t$(CC) $(LFLAGS) -o $(TARGET) $(OBJ) $(LIBDIR) $(LIBS)\n\n");
                    }
                } else {
                    if static_lib {
                        for target in targets {
                            target_str.push_str(&format!("{0}: $(OBJ)\n\
                                    \t$(AR) $(ARFLAGS) {0} $(OBJ)\n\n", target));
                        }
                    } else {
                        for target in targets {
                            target_str.push_str(&format!("{0}: $(OBJ)\n\
                                    \t$(CC) $(LFLAGS) -o {0} $(OBJ) $(LIBDIR) $(LIBS)\n\n", target));
                        }
                    }
                }
            }
        };
        Target { target: target_str, all: all }
    }

    fn gen_lib_dir_list(&self) -> String {
        return self.prepend_op_vec(&self.lib_dir, "-L");
    }

    fn gen_lib_list(&self) -> String {
        return self.prepend_op_vec(&self.libs, "-l");
    }

    fn gen_cflags_list(&self) -> String {
        return self.prepend_op_vec(&self.cflags, "-");
    }

    fn gen_lflags_list(&self) -> String {
        return self.prepend_op_vec(&self.lflags, "-");
    }

    fn gen_src_list(&self) -> String {
        let mut horrid_string: String = "SRC\t= ".to_owned();
        let mut lang = self.lang.clone().unwrap_or("cpp".to_owned());
        lang.insert(0, '.');
        if let Some(source_list) = self.src.as_ref() {
            // Multiple sources
            if source_list.len() > 1 {
                if let Some(split_first) = source_list.split_first() {
                    horrid_string.push_str(&format!("{} \\\n", split_first.0));
                    if let Some(split_last) = split_first.1.clone().split_last() {
                        for src in split_last.1 {
                            horrid_string.push_str(&format!("\t  {} \\\n", src));
                        }
                        horrid_string.push_str(&format!("\t  {}\n", split_last.0));
                    }
                }
            // One source file
            } else {
                for src in source_list {
                    horrid_string.push_str(&format!("{}\n", src));
                }
            }
            let mut parsed_obj_list = Vec::new();
            for obj in source_list {
                parsed_obj_list.push(obj.replace(&lang, ".o"));
            }
            horrid_string.push_str("OBJ\t= ");
            if parsed_obj_list.len() > 1 {
                if let Some(split_first) = parsed_obj_list.split_first() {
                    horrid_string.push_str(&format!("{} \\\n", split_first.0));
                    if let Some(split_last) = split_first.1.clone().split_last() {
                        for src in split_last.1 {
                            horrid_string.push_str(&format!("\t  {} \\\n", src));
                        }
                        horrid_string.push_str(&format!("\t  {}", split_last.0));
                    }
                }
            } else {
                for obj in parsed_obj_list {
                    horrid_string.push_str(&format!("{}\n", obj));
                }
            }
        }
        return horrid_string;
    }

    fn gen_inc_list(&self) -> String {
        return self.prepend_op_vec(&self.inc, "-I");
    }

    pub fn gen_make(&mut self) -> Result<String, YabsError> {
        try!(self.gen_file_list());
        let target = &self.gen_target_list();
        Ok(format!(
            "INSTALL\t= /usr/bin/env install\n\
                AR\t= {ar}\n\
                ARFLAGS\t= {ar_flags}\n\
                DEST\t=\n\
                PREFIX\t=\n\
                CC\t= {compiler}\n\
                BINDIR\t=\n\
                TARGET\t= {all}\n\
                LINK\t= {compiler}\n\
                CFLAGS\t= {cflags}\n\
                LFLAGS\t=\n\
                LIBS\t= {libs}\n\
                INCDIR\t= {incdir}\n\
                LIBDIR\t= {lib_dir}\n\
                CLEAN\t=\n\
                DEL\t= rm -f\n\
                {srcs}\n\n\
                first: all\n\n\
                .PHONY: doc clean\n\n\
                all: {all}\n\n\
                {target_command}\
                %.o: %.{lang}\n\t$(CC) -c $(CFLAGS) $(INCDIR) -o $@ $<\n\
                clean:\n\
                \t$(DEL) $(OBJ)\n\
                \t$(DEL) {all}\n\
                \t$(DEL) {clean_list}\n\
                ",
                compiler = &self.compiler.as_ref().unwrap_or(&"gcc".to_owned()),
                ar = &self.ar.as_ref().unwrap_or(&"/usr/bin/env ar".to_owned()),
                ar_flags = &self.arflags.as_ref().unwrap_or(&"rcs".to_owned()),
                all = target.all,
                target_command = target.target,
                cflags = &self.gen_cflags_list(),
                libs = &self.gen_lib_list(),
                incdir = &self.gen_inc_list(),
                lib_dir = &self.gen_lib_dir_list(),
                srcs = &self.gen_src_list(),
                lang = &self.lang.clone().unwrap_or("c".to_owned()),
                clean_list = &self.clean.clone().unwrap_or(vec![]).concat()))
    }

    pub fn build_bin(&mut self) -> Result<(), YabsError> {
        try!(self.gen_file_list());
        if let Some(src_list) = self.src.as_ref() {
            let mut lang = self.lang.clone().unwrap_or("cpp".to_owned());
            lang.insert(0, '.');
            let mut cmd_string;
            let mut obj_vec = Vec::new();
            for src in src_list {
                cmd_string = format!("{cc} -c {cflag} {inc} -o {object} {source}",
                                         cc = self.compiler.as_ref().unwrap_or(&"gcc".to_owned()),
                                         cflag = self.gen_cflags_list(),
                                         inc = self.gen_inc_list(),
                                         source = src,
                                         object = src.replace(&lang, ".o"),
                                         );
                try!(run_cmd(cmd_string));
                obj_vec.push(src.replace(&lang, ".o"));
            }
            for target in self.target.clone().unwrap_or(vec!["a".to_owned()]) {
                if self.static_lib.unwrap_or(false) == true {
                    cmd_string = format!("{ar} {ar_flags} {target} {obj_list}",
                                                 ar = self.ar.as_ref().unwrap_or(&"/usr/bin/env ar".to_owned()),
                                                 ar_flags = self.arflags.as_ref().unwrap_or(&"rcs".to_owned()),
                                                 target = target,
                                                 obj_list = obj_vec.concat(),
                                                 );
                    try!(run_cmd(cmd_string));
                } else {
                    cmd_string = format!("{cc} {lflags} -o {target} {obj_list} {lib_dir} {libs}",
                                                 cc = self.compiler.as_ref().unwrap_or(&"gcc".to_owned()),
                                                 lflags = self.gen_lflags_list(),
                                                 target = target,
                                                 obj_list = obj_vec.concat(),
                                                 lib_dir = self.gen_lib_dir_list(),
                                                 libs = self.gen_lib_list());
                    try!(run_cmd(cmd_string));
                }
            };
        };
        Ok(())
    }
}

// Descibe how to install this project
#[derive(Debug,Default,RustcDecodable,RustcEncodable,Clone,PartialEq)]
pub struct InstallDesc {
    prefix: Option<String>,
}

// Generate documentation for this project
#[derive(Debug,Default,RustcDecodable,RustcEncodable,Clone,PartialEq)]
pub struct DocDesc {
    doc: Option<Vec<String>>,
}

impl DocDesc {
    pub fn gen_make(&self) -> String {
        let mut doc_str = String::from("doc:\n");
        if let Some(doc) = self.doc.clone() {
            for line in doc {
                doc_str.push_str(&format!("\t{}\n", &line));
            }
        }
        return doc_str;
    }
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate errno;

use self::libc::{uint32_t, c_int};

use std::{ptr, mem, env};
use std::fmt;

use libproc::proc_pid;

#[cfg(test)]
use std::io;
#[cfg(test)]
use std::io::Write;

// See https://opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/sys/msgbuf.h
const MAX_MSG_BSIZE : c_int = (1*1024*1024);
const MSG_MAGIC : c_int = 0x063061;

// See /usr/include/sys/msgbuf.h on your Mac.
#[repr(C)]
struct MessageBuffer {
    pub msg_magic : c_int,
    pub msg_size : c_int,
    pub msg_bufx : c_int,      // write pointer
    pub msg_bufr : c_int,      // read pointer
    pub msg_bufc : * mut u8     // buffer
}

impl Default for MessageBuffer {
    fn default() -> MessageBuffer {
        MessageBuffer {
            msg_magic : 0,
            msg_size : 0,
            msg_bufx : 0,
            msg_bufr : 0,
            msg_bufc : ptr::null_mut() as * mut u8
        }
    }
}

impl fmt::Debug for MessageBuffer {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MessageBuffer {{ magic: 0x{:x}, size: {}, bufx: {}}}", self.msg_magic, self.msg_size, self.msg_bufx)
    }
}

// this extern block links to the libproc library
// Original signatures of functions can be found at http://opensource.apple.com/source/Libc/Libc-594.9.4/darwin/libproc.c
#[link(name = "proc", kind = "dylib")]
extern {
    fn proc_kmsgbuf(buffer : *mut MessageBuffer, buffersize : uint32_t) -> c_int;
}

/// Get upto buffersize bytes from the the kernel message buffer - as used by dmesg
/// extern crate libproc;
/// extern crate libc;
///
/// use std::str;
/// use std::io::Write;
/// use libproc::libproc::kmesg_buffer;
///
/// fn main() {
///     if kmesg_buffer::am_root() {
///         match kmesg_buffer::kmsgbuf() {
///             Ok(message) => println!("{}", message),
///             Err(err) => writeln!(&mut std::io::stderr(), "Error: {}", err).unwrap()
///         }
///     } else {
///         writeln!(&mut std::io::stderr(), "Must be run as root").unwrap()
///     }
// See http://opensource.apple.com//source/system_cmds/system_cmds-336.6/dmesg.tproj/dmesg.c
pub fn kmsgbuf() -> Result<String, String> {
    let mut message_buffer : MessageBuffer = Default::default();
    let ret: i32;

    unsafe {
        ret = proc_kmsgbuf(&mut message_buffer, mem::size_of::<MessageBuffer>() as u32);
    }

    if ret <= 0 {
        Err(proc_pid::get_errno_with_message(ret))
    } else
    {
        if message_buffer.msg_magic != MSG_MAGIC {
            println!("Message buffer: {:?}", message_buffer);
            Err(format!("The magic number 0x{:x} is incorrect", message_buffer.msg_magic))
        } else {
            // Avoid starting beyond the end of the buffer
            if message_buffer.msg_bufx >= MAX_MSG_BSIZE {
                message_buffer.msg_bufx = 0;
            }
            let mut output : Vec<u8> = Vec::new();

            // The message buffer is circular; start at the read pointer, and go to the write pointer - 1.
            unsafe {
                let mut ch : u8;
//                let newl : bool = false;
//                let skip : bool = false;
                let mut p : * mut u8 = message_buffer.msg_bufc.offset(message_buffer.msg_bufx as isize);
                let ep : * mut u8 = message_buffer.msg_bufc.offset((message_buffer.msg_bufx - 1) as isize);
//                let buf : [u8; 5];

                while p != ep {
                    // If at the end, then loop around to the start
                    // TODO should use actual size (from struct element) - not the max size??
                    if p == message_buffer.msg_bufc.offset(MAX_MSG_BSIZE as isize) {
                        p = message_buffer.msg_bufc;
                    }

                    ch = *p;

                    /* Skip "\n<.*>" syslog sequences.
                    if skip {
                        if ch == '>' {
                            newl = skip = false;
                        }
                        continue;
                    }

                    if newl && ch == '<' {
                        skip = true;
                        continue;
                    }

                    if ch == '\0' {
                        continue;
                    }

                    newl = ch == '\n';

//                    (void)vis(buf, ch, 0, 0);

                    if buf[1] == 0 {
                        output.append(buf[0]);
                    } else {
                        output.append("%s", buf);
                    }
                    */

                    output.push(ch);
                    p = p.offset(1);
                }

                Ok(String::from_utf8(output).unwrap())
            }
        }
    }
}

pub fn am_root() -> bool {
    match env::var("USER") {
        Ok(val) => val == "root",
        Err(_) => false,
    }
}

// If you want this test to actually test something, then you need to run as root 'sudo cargo test'
#[test]
fn kmessagebuffer_test() {
    if am_root() {
        match kmsgbuf() {
            Ok(buffer) => println!("Buffer: {:?}", buffer),
            Err(message) => assert!(false, message)
        }
    } else {
        writeln!(&mut io::stdout(), "test libproc::kmesg_buffer::kmessagebuffer_test ... skipped as it needs to be run as root").unwrap();
    }
}
<commit_msg>Update kmesg_buffer.rs<commit_after>extern crate libc;
extern crate errno;

use self::libc::{uint32_t, c_int};

use std::{ptr, mem, env};
use std::fmt;

use libproc::proc_pid;

#[cfg(test)]
use std::io;
#[cfg(test)]
use std::io::Write;

// See https://opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/sys/msgbuf.h
const MAX_MSG_BSIZE : c_int = (1*1024*1024);
const MSG_MAGIC : c_int = 0x063061;

// See /usr/include/sys/msgbuf.h on your Mac.
#[repr(C)]
struct MessageBuffer {
    pub msg_magic : c_int,
    pub msg_size : c_int,
    pub msg_bufx : c_int,      // write pointer
    pub msg_bufr : c_int,      // read pointer
    pub msg_bufc : * mut u8     // buffer
}

impl Default for MessageBuffer {
    fn default() -> MessageBuffer {
        MessageBuffer {
            msg_magic : 0,
            msg_size : 0,
            msg_bufx : 0,
            msg_bufr : 0,
            msg_bufc : ptr::null_mut() as * mut u8
        }
    }
}

impl fmt::Debug for MessageBuffer {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MessageBuffer {{ magic: 0x{:x}, size: {}, bufx: {}}}", self.msg_magic, self.msg_size, self.msg_bufx)
    }
}

// this extern block links to the libproc library
// Original signatures of functions can be found at http://opensource.apple.com/source/Libc/Libc-594.9.4/darwin/libproc.c
#[link(name = "proc", kind = "dylib")]
extern {
    fn proc_kmsgbuf(buffer : *mut MessageBuffer, buffersize : uint32_t) -> c_int;
}

/// Get upto buffersize bytes from the the kernel message buffer - as used by dmesg
/// extern crate libproc;
/// extern crate libc;
///
/// use std::str;
/// use std::io::Write;
/// use libproc::libproc::kmesg_buffer;
///
/// fn main() {
///     if kmesg_buffer::am_root() {
///         match kmesg_buffer::kmsgbuf() {
///             Ok(message) => println!("{}", message),
///             Err(err) => writeln!(&mut std::io::stderr(), "Error: {}", err).unwrap()
///         }
///     } else {
///         writeln!(&mut std::io::stderr(), "Must be run as root").unwrap()
///     }
// See http://opensource.apple.com//source/system_cmds/system_cmds-336.6/dmesg.tproj/dmesg.c
pub fn kmsgbuf() -> Result<String, String> {
    let mut message_buffer : MessageBuffer = Default::default();
    let ret: i32;

    unsafe {
        ret = proc_kmsgbuf(&mut message_buffer, mem::size_of::<MessageBuffer>() as u32);
    }

    if ret <= 0 {
        Err(proc_pid::get_errno_with_message(ret))
    } else
    {
        if message_buffer.msg_magic != MSG_MAGIC {
            println!("Message buffer: {:?}", message_buffer);
            Err(format!("The magic number 0x{:x} is incorrect", message_buffer.msg_magic))
        } else {
            // Avoid starting beyond the end of the buffer
            if message_buffer.msg_bufx >= MAX_MSG_BSIZE {
                message_buffer.msg_bufx = 0;
            }
            let mut output : Vec<u8> = Vec::new();

            // The message buffer is circular; start at the read pointer, and go to the write pointer - 1.
            unsafe {
                let mut ch : u8;
//                let newl : bool = false;
//                let skip : bool = false;
                let mut p : * mut u8 = message_buffer.msg_bufc.offset(message_buffer.msg_bufx as isize);
                let ep : * mut u8 = message_buffer.msg_bufc.offset((message_buffer.msg_bufx - 1) as isize);
//                let buf : [u8; 5];

                while p != ep {
                    // If at the end, then loop around to the start
                    // TODO should use actual size (from struct element) - not the max size??
                    if p == message_buffer.msg_bufc.offset(MAX_MSG_BSIZE as isize) {
                        p = message_buffer.msg_bufc;
                    }

                    ch = *p;

                    /* Skip "\n<.*>" syslog sequences.
                    if skip {
                        if ch == '>' {
                            newl = skip = false;
                        }
                        continue;
                    }

                    if newl && ch == '<' {
                        skip = true;
                        continue;
                    }

                    if ch == '\0' {
                        continue;
                    }

                    newl = ch == '\n';

//                    (void)vis(buf, ch, 0, 0);

                    if buf[1] == 0 {
                        output.append(buf[0]);
                    } else {
                        output.append("%s", buf);
                    }
                    */

                    output.push(ch);
                    p = p.offset(1);
                }

                Ok(String::from_utf8(output).unwrap())
            }
        }
    }
}

pub fn am_root() -> bool {
    libc::getuid() == 0
}

// If you want this test to actually test something, then you need to run as root 'sudo cargo test'
#[test]
fn kmessagebuffer_test() {
    if am_root() {
        match kmsgbuf() {
            Ok(buffer) => println!("Buffer: {:?}", buffer),
            Err(message) => assert!(false, message)
        }
    } else {
        writeln!(&mut io::stdout(), "test libproc::kmesg_buffer::kmessagebuffer_test ... skipped as it needs to be run as root").unwrap();
    }
}
<|endoftext|>


<commit_before>use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Instance, TyCtxt, TypeFoldable};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_span::sym;
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits;
use traits::{Reveal, translate_substs};

use log::debug;

pub fn resolve_instance<'tcx>(
    tcx: TyCtxt<'tcx>,
    param_env: ty::ParamEnv<'tcx>,
    def_id: DefId,
    substs: SubstsRef<'tcx>,
) -> Option<Instance<'tcx>> {
    debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
    let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) {
        debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env);
        let item = tcx.associated_item(def_id);
        resolve_associated_item(tcx, &item, param_env, trait_def_id, substs)
    } else {
        let ty = tcx.type_of(def_id);
        let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, &ty);

        let def = match item_type.kind {
            ty::FnDef(..)
                if {
                    let f = item_type.fn_sig(tcx);
                    f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic
                } =>
            {
                debug!(" => intrinsic");
                ty::InstanceDef::Intrinsic(def_id)
            }
            ty::FnDef(def_id, substs) if Some(def_id) == tcx.lang_items().drop_in_place_fn() => {
                let ty = substs.type_at(0);

                if ty.needs_drop(tcx, param_env) {
                    // `DropGlue` requires a monomorphic aka concrete type.
                    if ty.needs_subst() {
                        return None;
                    }

                    debug!(" => nontrivial drop glue");
                    ty::InstanceDef::DropGlue(def_id, Some(ty))
                } else {
                    debug!(" => trivial drop glue");
                    ty::InstanceDef::DropGlue(def_id, None)
                }
            }
            _ => {
                debug!(" => free item");
                ty::InstanceDef::Item(def_id)
            }
        };
        Some(Instance { def, substs })
    };
    debug!("resolve(def_id={:?}, substs={:?}) = {:?}", def_id, substs, result);
    result
}

fn resolve_associated_item<'tcx>(
    tcx: TyCtxt<'tcx>,
    trait_item: &ty::AssocItem,
    param_env: ty::ParamEnv<'tcx>,
    trait_id: DefId,
    rcvr_substs: SubstsRef<'tcx>,
) -> Option<Instance<'tcx>> {
    let def_id = trait_item.def_id;
    debug!(
        "resolve_associated_item(trait_item={:?}, \
            param_env={:?}, \
            trait_id={:?}, \
            rcvr_substs={:?})",
        def_id, param_env, trait_id, rcvr_substs
    );

    let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
    let vtbl = tcx.codegen_fulfill_obligation((param_env, ty::Binder::bind(trait_ref)))?;

    // Now that we know which impl is being used, we can dispatch to
    // the actual function:
    match vtbl {
        traits::VtableImpl(impl_data) => {
            debug!(
                "resolving VtableImpl: {:?}, {:?}, {:?}, {:?}",
                param_env, trait_item, rcvr_substs, impl_data
            );
            assert!(!rcvr_substs.needs_infer());

            let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap();
            let trait_def = tcx.trait_def(trait_def_id);
            let leaf_def = trait_def
                .ancestors(tcx, impl_data.impl_def_id)
                .ok()?
                .leaf_def(tcx, trait_item.ident, trait_item.kind)
                .unwrap_or_else(|| {
                    bug!("{:?} not found in {:?}", trait_item, impl_data.impl_def_id);
                });
            let def_id = leaf_def.item.def_id;

            let substs = tcx.infer_ctxt().enter(|infcx| {
                let param_env = param_env.with_reveal_all();
                let substs = rcvr_substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
                let substs = translate_substs(
                    &infcx,
                    param_env,
                    impl_data.impl_def_id,
                    substs,
                    leaf_def.defining_node,
                );
                infcx.tcx.erase_regions(&substs)
            });

            // Since this is a trait item, we need to see if the item is either a trait default item
            // or a specialization because we can't resolve those unless we can `Reveal::All`.
            // NOTE: This should be kept in sync with the similar code in
            // `rustc_middle::traits::project::assemble_candidates_from_impls()`.
            let eligible = if leaf_def.is_final() {
                // Non-specializable items are always projectable.
                true
            } else {
                // Only reveal a specializable default if we're past type-checking
                // and the obligation is monomorphic, otherwise passes such as
                // transmute checking and polymorphic MIR optimizations could
                // get a result which isn't correct for all monomorphizations.
                if param_env.reveal == Reveal::All { !trait_ref.needs_subst() } else { false }
            };

            if !eligible {
                return None;
            }

            let substs = tcx.erase_regions(&substs);
            Some(ty::Instance::new(def_id, substs))
        }
        traits::VtableGenerator(generator_data) => Some(Instance {
            def: ty::InstanceDef::Item(generator_data.generator_def_id),
            substs: generator_data.substs,
        }),
        traits::VtableClosure(closure_data) => {
            let trait_closure_kind = tcx.fn_trait_kind_from_lang_item(trait_id).unwrap();
            Some(Instance::resolve_closure(
                tcx,
                closure_data.closure_def_id,
                closure_data.substs,
                trait_closure_kind,
            ))
        }
        traits::VtableFnPointer(ref data) => {
            // `FnPtrShim` requires a monomorphic aka concrete type.
            if data.fn_ty.needs_subst() {
                return None;
            }

            Some(Instance {
                def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty),
                substs: rcvr_substs,
            })
        }
        traits::VtableObject(ref data) => {
            let index = traits::get_vtable_index_of_object_method(tcx, data, def_id);
            Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs })
        }
        traits::VtableBuiltin(..) => {
            if Some(trait_ref.def_id) == tcx.lang_items().clone_trait() {
                // FIXME(eddyb) use lang items for methods instead of names.
                let name = tcx.item_name(def_id);
                if name == sym::clone {
                    let self_ty = trait_ref.self_ty();

                    // `CloneShim` requires a monomorphic aka concrete type.
                    if self_ty.needs_subst() {
                        return None;
                    }

                    Some(Instance {
                        def: ty::InstanceDef::CloneShim(def_id, self_ty),
                        substs: rcvr_substs,
                    })
                } else {
                    assert_eq!(name, sym::clone_from);

                    // Use the default `fn clone_from` from `trait Clone`.
                    let substs = tcx.erase_regions(&rcvr_substs);
                    Some(ty::Instance::new(def_id, substs))
                }
            } else {
                None
            }
        }
        traits::VtableAutoImpl(..) | traits::VtableParam(..) | traits::VtableTraitAlias(..) => None,
    }
}
<commit_msg>Assert that the trait ref does not need inference<commit_after>use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Instance, TyCtxt, TypeFoldable};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_span::sym;
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits;
use traits::{Reveal, translate_substs};

use log::debug;

pub fn resolve_instance<'tcx>(
    tcx: TyCtxt<'tcx>,
    param_env: ty::ParamEnv<'tcx>,
    def_id: DefId,
    substs: SubstsRef<'tcx>,
) -> Option<Instance<'tcx>> {
    debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
    let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) {
        debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env);
        let item = tcx.associated_item(def_id);
        resolve_associated_item(tcx, &item, param_env, trait_def_id, substs)
    } else {
        let ty = tcx.type_of(def_id);
        let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, &ty);

        let def = match item_type.kind {
            ty::FnDef(..)
                if {
                    let f = item_type.fn_sig(tcx);
                    f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic
                } =>
            {
                debug!(" => intrinsic");
                ty::InstanceDef::Intrinsic(def_id)
            }
            ty::FnDef(def_id, substs) if Some(def_id) == tcx.lang_items().drop_in_place_fn() => {
                let ty = substs.type_at(0);

                if ty.needs_drop(tcx, param_env) {
                    // `DropGlue` requires a monomorphic aka concrete type.
                    if ty.needs_subst() {
                        return None;
                    }

                    debug!(" => nontrivial drop glue");
                    ty::InstanceDef::DropGlue(def_id, Some(ty))
                } else {
                    debug!(" => trivial drop glue");
                    ty::InstanceDef::DropGlue(def_id, None)
                }
            }
            _ => {
                debug!(" => free item");
                ty::InstanceDef::Item(def_id)
            }
        };
        Some(Instance { def, substs })
    };
    debug!("resolve(def_id={:?}, substs={:?}) = {:?}", def_id, substs, result);
    result
}

fn resolve_associated_item<'tcx>(
    tcx: TyCtxt<'tcx>,
    trait_item: &ty::AssocItem,
    param_env: ty::ParamEnv<'tcx>,
    trait_id: DefId,
    rcvr_substs: SubstsRef<'tcx>,
) -> Option<Instance<'tcx>> {
    let def_id = trait_item.def_id;
    debug!(
        "resolve_associated_item(trait_item={:?}, \
            param_env={:?}, \
            trait_id={:?}, \
            rcvr_substs={:?})",
        def_id, param_env, trait_id, rcvr_substs
    );

    let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
    let vtbl = tcx.codegen_fulfill_obligation((param_env, ty::Binder::bind(trait_ref)))?;

    // Now that we know which impl is being used, we can dispatch to
    // the actual function:
    match vtbl {
        traits::VtableImpl(impl_data) => {
            debug!(
                "resolving VtableImpl: {:?}, {:?}, {:?}, {:?}",
                param_env, trait_item, rcvr_substs, impl_data
            );
            assert!(!rcvr_substs.needs_infer());
            assert!(!trait_ref.needs_infer());

            let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap();
            let trait_def = tcx.trait_def(trait_def_id);
            let leaf_def = trait_def
                .ancestors(tcx, impl_data.impl_def_id)
                .ok()?
                .leaf_def(tcx, trait_item.ident, trait_item.kind)
                .unwrap_or_else(|| {
                    bug!("{:?} not found in {:?}", trait_item, impl_data.impl_def_id);
                });
            let def_id = leaf_def.item.def_id;

            let substs = tcx.infer_ctxt().enter(|infcx| {
                let param_env = param_env.with_reveal_all();
                let substs = rcvr_substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
                let substs = translate_substs(
                    &infcx,
                    param_env,
                    impl_data.impl_def_id,
                    substs,
                    leaf_def.defining_node,
                );
                infcx.tcx.erase_regions(&substs)
            });

            // Since this is a trait item, we need to see if the item is either a trait default item
            // or a specialization because we can't resolve those unless we can `Reveal::All`.
            // NOTE: This should be kept in sync with the similar code in
            // `rustc_middle::traits::project::assemble_candidates_from_impls()`.
            let eligible = if leaf_def.is_final() {
                // Non-specializable items are always projectable.
                true
            } else {
                // Only reveal a specializable default if we're past type-checking
                // and the obligation is monomorphic, otherwise passes such as
                // transmute checking and polymorphic MIR optimizations could
                // get a result which isn't correct for all monomorphizations.
                if param_env.reveal == Reveal::All { !trait_ref.needs_subst() } else { false }
            };

            if !eligible {
                return None;
            }

            let substs = tcx.erase_regions(&substs);
            Some(ty::Instance::new(def_id, substs))
        }
        traits::VtableGenerator(generator_data) => Some(Instance {
            def: ty::InstanceDef::Item(generator_data.generator_def_id),
            substs: generator_data.substs,
        }),
        traits::VtableClosure(closure_data) => {
            let trait_closure_kind = tcx.fn_trait_kind_from_lang_item(trait_id).unwrap();
            Some(Instance::resolve_closure(
                tcx,
                closure_data.closure_def_id,
                closure_data.substs,
                trait_closure_kind,
            ))
        }
        traits::VtableFnPointer(ref data) => {
            // `FnPtrShim` requires a monomorphic aka concrete type.
            if data.fn_ty.needs_subst() {
                return None;
            }

            Some(Instance {
                def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty),
                substs: rcvr_substs,
            })
        }
        traits::VtableObject(ref data) => {
            let index = traits::get_vtable_index_of_object_method(tcx, data, def_id);
            Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs })
        }
        traits::VtableBuiltin(..) => {
            if Some(trait_ref.def_id) == tcx.lang_items().clone_trait() {
                // FIXME(eddyb) use lang items for methods instead of names.
                let name = tcx.item_name(def_id);
                if name == sym::clone {
                    let self_ty = trait_ref.self_ty();

                    // `CloneShim` requires a monomorphic aka concrete type.
                    if self_ty.needs_subst() {
                        return None;
                    }

                    Some(Instance {
                        def: ty::InstanceDef::CloneShim(def_id, self_ty),
                        substs: rcvr_substs,
                    })
                } else {
                    assert_eq!(name, sym::clone_from);

                    // Use the default `fn clone_from` from `trait Clone`.
                    let substs = tcx.erase_regions(&rcvr_substs);
                    Some(ty::Instance::new(def_id, substs))
                }
            } else {
                None
            }
        }
        traits::VtableAutoImpl(..) | traits::VtableParam(..) | traits::VtableTraitAlias(..) => None,
    }
}
<|endoftext|>


<commit_before>use crate::ffi::{CStr, OsStr, OsString};
use crate::marker::PhantomData;
use crate::os::wasi::ffi::OsStrExt;
use crate::vec;

pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}

pub unsafe fn cleanup() {}

pub struct Args {
    iter: vec::IntoIter<OsString>,
    _dont_send_or_sync_me: PhantomData<*mut ()>,
}

/// Returns the command line arguments
pub fn args() -> Args {
    Args {
        iter: maybe_args().unwrap_or(Vec::new()).into_iter(),
        _dont_send_or_sync_me: PhantomData,
    }
}

fn maybe_args() -> Option<Vec<OsString>> {
    unsafe {
        let (argc, buf_size) = wasi::args_sizes_get().ok()?;
        let mut argv = Vec::with_capacity(argc);
        let mut buf = Vec::with_capacity(buf_size);
        wasi::args_get(argv.as_mut_ptr(), buf.as_mut_ptr()).ok()?;
        let mut ret = Vec::with_capacity(argc);
        for ptr in argv {
            let s = CStr::from_ptr(ptr.cast());
            ret.push(OsStr::from_bytes(s.to_bytes()).to_owned());
        }
        Some(ret)
    }
}

impl Args {
    pub fn inner_debug(&self) -> &[OsString] {
        self.iter.as_slice()
    }
}

impl Iterator for Args {
    type Item = OsString;
    fn next(&mut self) -> Option<OsString> {
        self.iter.next()
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}

impl ExactSizeIterator for Args {
    fn len(&self) -> usize {
        self.iter.len()
    }
}

impl DoubleEndedIterator for Args {
    fn next_back(&mut self) -> Option<OsString> {
        self.iter.next_back()
    }
}
<commit_msg>Rollup merge of #67065 - alexcrichton:update-wasi, r=sfackler<commit_after>use crate::ffi::{CStr, OsStr, OsString};
use crate::marker::PhantomData;
use crate::os::wasi::ffi::OsStrExt;
use crate::vec;

pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}

pub unsafe fn cleanup() {}

pub struct Args {
    iter: vec::IntoIter<OsString>,
    _dont_send_or_sync_me: PhantomData<*mut ()>,
}

/// Returns the command line arguments
pub fn args() -> Args {
    Args {
        iter: maybe_args().unwrap_or(Vec::new()).into_iter(),
        _dont_send_or_sync_me: PhantomData,
    }
}

fn maybe_args() -> Option<Vec<OsString>> {
    unsafe {
        let (argc, buf_size) = wasi::args_sizes_get().ok()?;
        let mut argv = Vec::with_capacity(argc);
        let mut buf = Vec::with_capacity(buf_size);
        wasi::args_get(argv.as_mut_ptr(), buf.as_mut_ptr()).ok()?;
        argv.set_len(argc);
        let mut ret = Vec::with_capacity(argc);
        for ptr in argv {
            let s = CStr::from_ptr(ptr.cast());
            ret.push(OsStr::from_bytes(s.to_bytes()).to_owned());
        }
        Some(ret)
    }
}

impl Args {
    pub fn inner_debug(&self) -> &[OsString] {
        self.iter.as_slice()
    }
}

impl Iterator for Args {
    type Item = OsString;
    fn next(&mut self) -> Option<OsString> {
        self.iter.next()
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}

impl ExactSizeIterator for Args {
    fn len(&self) -> usize {
        self.iter.len()
    }
}

impl DoubleEndedIterator for Args {
    fn next_back(&mut self) -> Option<OsString> {
        self.iter.next_back()
    }
}
<|endoftext|>