<commit_before>mod terminal;
mod ansi;

use std::io::{self, Write};
use self::terminal::{Terminal, Event, Key};
use self::ansi::{clear, cursor};
use rff::choice::Choice;

pub struct Interface {
    choices: Vec<String>,
    matching: Vec<Choice>,
    search: String,
    terminal: Terminal
}

impl Interface {
    /// Creates a new Interface with the provided input choices.
    pub fn with_choices(choices: Vec<String>) -> Interface {
        let mut term = Terminal::from("/dev/tty").unwrap();
        term.set_raw_mode().unwrap();

        Interface {
            choices: choices,
            matching: Vec::new(),
            search: String::new(),
            terminal: term
        }
    }

    // Starts the interface
    pub fn run(&mut self) {
        self.filter_choices();
        self.render().expect("Unable to render");

        for event in self.terminal.events().unwrap() {
            match event {
                Ok(Event::Key(Key::Ctrl('c'))) => {
                    return;
                },

                Ok(Event::Key(Key::Char(ch))) => {
                    self.search.push(ch);
                    self.filter_choices();
                    self.render().expect("Unable to render");
                },

                Ok(Event::Key(Key::Backspace)) => {
                    self.search.pop();
                    self.filter_choices();
                    self.render().expect("Unable to render");
                },

                Ok(_) => {}
                Err(err) => write!(self.terminal, "{:?}", err).unwrap(),
            };
        }
    }

    fn filter_choices(&mut self) {
        let mut matches = self.choices.
            iter().
            cloned().
            filter_map(|choice| Choice::new(&self.search, choice)).
            collect::<Vec<_>>();

        matches.sort_by(|a, b| b.partial_cmp(&a).unwrap());

        self.matching = matches;
    }

    fn render(&mut self) -> io::Result<()> {
        let ref mut term = self.terminal;
        write!(term, "{}{}", clear::Line, cursor::Column(1))?;
        write!(term, "> {}", self.search)?;

        let choices = self.matching.iter().map(|c| c.text()).take(10);
        let num_choices = choices.len() as u16;

        for choice in choices {
            write!(term, "\r\n{}{}", clear::Line, choice)?;
        }

        let column = format!("> {}", self.search).len() as u16;
        write!(term, "{}{}", cursor::Up(num_choices), cursor::Column(column + 1))?;

        Ok(())
    }
}
<commit_msg>Clean up interface printing<commit_after>mod terminal;
mod ansi;

use std::io::{self, Write};
use self::terminal::{Terminal, Event, Key};
use self::ansi::{clear, cursor};
use rff::choice::Choice;

pub struct Interface {
    choices: Vec<String>,
    matching: Vec<Choice>,
    search: String,
    terminal: Terminal
}

impl Interface {
    /// Creates a new Interface with the provided input choices.
    pub fn with_choices(choices: Vec<String>) -> Interface {
        let mut term = Terminal::from("/dev/tty").unwrap();
        term.set_raw_mode().unwrap();

        Interface {
            choices: choices,
            matching: Vec::new(),
            search: String::new(),
            terminal: term
        }
    }

    // Starts the interface
    pub fn run(&mut self) {
        self.filter_choices();
        self.render().expect("Unable to render");

        for event in self.terminal.events().unwrap() {
            match event {
                Ok(Event::Key(Key::Ctrl('c'))) => {
                    return;
                },

                Ok(Event::Key(Key::Char(ch))) => {
                    self.search.push(ch);
                    self.filter_choices();
                    self.render().expect("Unable to render");
                },

                Ok(Event::Key(Key::Backspace)) => {
                    self.search.pop();
                    self.filter_choices();
                    self.render().expect("Unable to render");
                },

                Ok(_) => {}
                Err(err) => write!(self.terminal, "{:?}", err).unwrap(),
            };
        }
    }

    fn filter_choices(&mut self) {
        let mut matches = self.choices.
            iter().
            cloned().
            filter_map(|choice| Choice::new(&self.search, choice)).
            collect::<Vec<_>>();

        matches.sort_by(|a, b| b.partial_cmp(&a).unwrap());

        self.matching = matches;
    }

    fn render(&mut self) -> io::Result<()> {
        let ref mut term = self.terminal;
        write!(term, "{}{}", clear::Screen, cursor::Column(1))?;
        write!(term, "> {}", self.search)?;

        let choices = self.matching.iter().map(|c| c.text()).take(10);
        let num_choices = choices.len() as u16;

        for choice in choices {
            let choice = choice.chars().
                take(term.max_width as usize).
                collect::<String>();

            write!(term, "\r\n{}", choice)?;
        }

        if num_choices > 0 {
            let column = format!("> {}", self.search).len() as u16;
            write!(term, "{}{}", cursor::Up(num_choices), cursor::Column(column + 1))?;
        }

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


<commit_before>// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.

use tipb::expression::FieldType;

use super::super::function::RpnFunction;
use crate::coprocessor::codec::data_type::ScalarValue;

/// A type for each node in the RPN expression list.
#[derive(Debug)]
pub enum RpnExpressionNode {
    /// Represents a function call.
    FnCall {
        func: Box<dyn RpnFunction>,
        field_type: FieldType,
    },

    /// Represents a scalar constant value.
    Constant {
        value: ScalarValue,
        field_type: FieldType,
    },

    /// Represents a reference to a column in the columns specified in evaluation.
    ColumnRef { offset: usize },
}

impl RpnExpressionNode {
    /// Gets the field type.
    #[inline]
    pub fn field_type(&self) -> Option<&FieldType> {
        match self {
            RpnExpressionNode::FnCall { ref field_type, .. } => Some(field_type),
            RpnExpressionNode::Constant { ref field_type, .. } => Some(field_type),
            RpnExpressionNode::ColumnRef { .. } => None,
        }
    }

    /// Borrows the function instance for `FnCall` variant.
    #[inline]
    pub fn fn_call_func(&self) -> Option<&dyn RpnFunction> {
        match self {
            RpnExpressionNode::FnCall { ref func, .. } => Some(&*func),
            _ => None,
        }
    }

    /// Borrows the constant value for `Constant` variant.
    #[inline]
    pub fn constant_value(&self) -> Option<&ScalarValue> {
        match self {
            RpnExpressionNode::Constant { ref value, .. } => Some(value),
            _ => None,
        }
    }

    /// Gets the column offset for `ColumnRef` variant.
    #[inline]
    pub fn column_ref_offset(&self) -> Option<usize> {
        match self {
            RpnExpressionNode::ColumnRef { ref offset, .. } => Some(*offset),
            _ => None,
        }
    }
}

/// An expression in Reverse Polish notation, which is simply a list of RPN expression nodes.
///
/// You may want to build it using `RpnExpressionBuilder`.
#[derive(Debug)]
pub struct RpnExpression(Vec<RpnExpressionNode>);

impl std::ops::Deref for RpnExpression {
    type Target = Vec<RpnExpressionNode>;

    fn deref(&self) -> &Vec<RpnExpressionNode> {
        &self.0
    }
}

impl std::ops::DerefMut for RpnExpression {
    fn deref_mut(&mut self) -> &mut Vec<RpnExpressionNode> {
        &mut self.0
    }
}

impl From<Vec<RpnExpressionNode>> for RpnExpression {
    fn from(v: Vec<RpnExpressionNode>) -> Self {
        Self(v)
    }
}

impl AsRef<[RpnExpressionNode]> for RpnExpression {
    fn as_ref(&self) -> &[RpnExpressionNode] {
        self.0.as_ref()
    }
}

// For `RpnExpression::eval`, see `expr_eval` file.
<commit_msg>Adds ret_field_type (#4512)<commit_after>// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.

use tipb::expression::FieldType;

use super::super::function::RpnFunction;
use crate::coprocessor::codec::data_type::ScalarValue;

/// A type for each node in the RPN expression list.
#[derive(Debug)]
pub enum RpnExpressionNode {
    /// Represents a function call.
    FnCall {
        func: Box<dyn RpnFunction>,
        field_type: FieldType,
    },

    /// Represents a scalar constant value.
    Constant {
        value: ScalarValue,
        field_type: FieldType,
    },

    /// Represents a reference to a column in the columns specified in evaluation.
    ColumnRef { offset: usize },
}

impl RpnExpressionNode {
    /// Gets the field type.
    #[inline]
    pub fn field_type(&self) -> Option<&FieldType> {
        match self {
            RpnExpressionNode::FnCall { ref field_type, .. } => Some(field_type),
            RpnExpressionNode::Constant { ref field_type, .. } => Some(field_type),
            RpnExpressionNode::ColumnRef { .. } => None,
        }
    }

    /// Borrows the function instance for `FnCall` variant.
    #[inline]
    pub fn fn_call_func(&self) -> Option<&dyn RpnFunction> {
        match self {
            RpnExpressionNode::FnCall { ref func, .. } => Some(&*func),
            _ => None,
        }
    }

    /// Borrows the constant value for `Constant` variant.
    #[inline]
    pub fn constant_value(&self) -> Option<&ScalarValue> {
        match self {
            RpnExpressionNode::Constant { ref value, .. } => Some(value),
            _ => None,
        }
    }

    /// Gets the column offset for `ColumnRef` variant.
    #[inline]
    pub fn column_ref_offset(&self) -> Option<usize> {
        match self {
            RpnExpressionNode::ColumnRef { ref offset, .. } => Some(*offset),
            _ => None,
        }
    }
}

/// An expression in Reverse Polish notation, which is simply a list of RPN expression nodes.
///
/// You may want to build it using `RpnExpressionBuilder`.
#[derive(Debug)]
pub struct RpnExpression(Vec<RpnExpressionNode>);

impl std::ops::Deref for RpnExpression {
    type Target = Vec<RpnExpressionNode>;

    fn deref(&self) -> &Vec<RpnExpressionNode> {
        &self.0
    }
}

impl std::ops::DerefMut for RpnExpression {
    fn deref_mut(&mut self) -> &mut Vec<RpnExpressionNode> {
        &mut self.0
    }
}

impl From<Vec<RpnExpressionNode>> for RpnExpression {
    fn from(v: Vec<RpnExpressionNode>) -> Self {
        Self(v)
    }
}

impl AsRef<[RpnExpressionNode]> for RpnExpression {
    fn as_ref(&self) -> &[RpnExpressionNode] {
        self.0.as_ref()
    }
}

impl RpnExpression {
    /// Gets the field type of the return value.
    pub fn ret_field_type<'a>(&'a self, schema: &'a [FieldType]) -> &'a FieldType {
        assert!(!self.0.is_empty());
        let last_node = self.0.last().unwrap();
        match last_node {
            RpnExpressionNode::FnCall { field_type, .. } => field_type,
            RpnExpressionNode::Constant { field_type, .. } => field_type,
            RpnExpressionNode::ColumnRef { offset } => &schema[*offset],
        }
    }
}

// For `RpnExpression::eval`, see `expr_eval` file.
<|endoftext|>


<commit_before>
use ndarray::{Array, Ix, Axis, ArrayView, stack};
use std::collections::HashMap;
use std::mem;

pub type Column = Array<f64, Ix>;
pub type Row = Array<f64, Ix>;

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

// macro_rules! dataframe {
//     ($name : ident,($($field: expr),*), ($($value: expr),*)) => {
//         #[derive(Debug, PartialEq)]
//         struct $name { $($field: ndarray::Array<f64, Ix>),* };
//         impl Default for $name {
//             fn default() -> $name {
//                 $name {
//                 $($field : $value),*
//                 }
//             }
//         }
//
//
//
//     };
// }

#[derive(Debug, PartialEq)]
pub struct DataFrame<'b> {
    data_map: HashMap<&'b str, Column>,
}

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

pub fn integer_decode(val: f64) -> (u64, i16, i8) {
    let bits: u64 = unsafe { mem::transmute(val) };
    let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
    let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
    let mantissa = if exponent == 0 {
        (bits & 0xfffffffffffff) << 1
    } else {
        (bits & 0xfffffffffffff) | 0x10000000000000
    };

    exponent -= 1023 + 52;
    (mantissa, exponent, sign)
}

impl Value {
    fn new(val: f64) -> Value {
        Value(integer_decode(val))
    }
}

impl<'b> DataFrame<'b> {
    pub fn new(data_map: HashMap<&'b str, Column>) -> DataFrame<'b> {
        DataFrame { data_map: data_map }

    }

    pub fn from_array(data: &'b Matrix, names: &'b Vec<&'b str>) -> Result<DataFrame<'b>, &'b str> {
        if data.cols() != names.len() {
            return Err("mismatched dimensions");
        }
        let data_map: HashMap<&'b str, Column> =
            names.iter().zip(data.axis_iter(Axis(1))).map(|(x, y)| (*x, y.to_owned())).collect();

        Ok(DataFrame::new(data_map))
    }

    pub fn from_vec(data: &'b Vec<Row>, names: Vec<&'b str>) -> Result<DataFrame<'b>, &'b str> {
        let data = stack(Axis(0),
                         &data.iter()
                             .map(|x| x.view().into_shape((1, x.dim())).unwrap())
                             .collect::<Vec<MatrixView<'b>>>()[..]);
        DataFrame::from_array(data.unwrap(), &names)
        // if data.len() != names.len() {
        //     return Err("mismatched dimensions");
        // }
        // let data_map: HashMap<&'b str, Column> =
        //     names.iter().zip(data).map(|(x, y)| (*x, y.to_owned())).collect();
        //
        // Ok(DataFrame::new(data_map))
        // let data = stack(Axis(0),
        //                  &data.iter()
        //                      .map(|x| x.view().into_shape((1, x.dim())).unwrap())
        //                      .collect::<Vec<MatrixView<'b>>>()[..])
        //     .unwrap();
        // if data.cols() != names.len() {
        //     return Err("mismatched dimensions");
        // }
        // let data_map: HashMap<&'b str, Column> =
        //     names.iter().zip(data.axis_iter(Axis(1))).map(|(x, y)| (*x, y.to_owned())).collect();
        //
        // Ok(DataFrame::new(data_map))
    }

    pub fn get(&self, name: &'b str) -> Option<&Column> {
        self.data_map.get(&name)
    }

    // fn get_mut(&mut self, name: &'b str) -> Option<&mut Column> {
    //     self.data_map.get_mut(&name)
    // }

    pub fn inner_join(&self, other: &DataFrame<'b>, on: &'b str) -> Result<DataFrame<'b>, &'b str> {
        let h: HashMap<Value, usize> = self.get(on)
            .unwrap()
            .iter()
            .enumerate()
            .map(|(x, y)| (Value::new(*y), x))
            .collect();
        let j: HashMap<Value, usize> = other.get(on)
            .unwrap()
            .iter()
            .enumerate()
            .map(|(x, y)| (Value::new(*y), x))
            .collect();
        let mut vs = vec![];
        for row_key in h.keys() {
            match j.get(row_key) {
                None => continue,
                Some(v) => {
                    let idx = *h.get(row_key).unwrap();
                    let p = self.data_map
                        .values()
                        .map(|x| x.get(idx).unwrap())
                        .map(|x| *x);

                    let o = other.data_map
                        .iter()
                        .filter(|&(x, _)| *x != on)
                        .map(|(_, y)| y.get(*v).unwrap())
                        .map(|x| *x);

                    let chain = p.chain(o);

                    vs.push(chain.collect());

                }
            };
        }
        if vs.len() == 0 {
            return Err("No matching values in join column.");
        }
        let name_chain = self.data_map
            .keys()
            .chain(other.data_map.keys().filter(|&x| *x != on))
            .map(|x| *x)
            .collect::<Vec<&'b str>>();
        DataFrame::from_vec(&vs, name_chain)
    }
}

// The following implementation requires a copy, which we don't want!
// Alternative solution to inserting is to mutate the original matrix, but this also requires a
// copy!
// fn insert(&mut self, name: &'a str, value: Column) {
//     match self.data.entry(name) {
//         Entry::Occupied(mut o) => {
//             o.get_mut();
//         }
//         Entry::Vacant(v) => {
//             v.insert(value.view());
//         }
//     };
// }

// parallelized join
// parallelized concatenation
// parallelized frequency counts
// index dataframe?
// sample rows
// find/select
// sort
// statistics (mean, median, stdev)
// print
<commit_msg>updated<commit_after>
use ndarray::{Array, Ix, Axis, ArrayView, stack};
use std::collections::HashMap;
use std::mem;

pub type Column = Array<f64, Ix>;
pub type Row = Array<f64, Ix>;

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

// macro_rules! dataframe {
//     ($name : ident,($($field: expr),*), ($($value: expr),*)) => {
//         #[derive(Debug, PartialEq)]
//         struct $name { $($field: ndarray::Array<f64, Ix>),* };
//         impl Default for $name {
//             fn default() -> $name {
//                 $name {
//                 $($field : $value),*
//                 }
//             }
//         }
//
//
//
//     };
// }

#[derive(Debug, PartialEq)]
pub struct DataFrame<'b> {
    data_map: HashMap<&'b str, Column>,
}

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

pub fn integer_decode(val: f64) -> (u64, i16, i8) {
    let bits: u64 = unsafe { mem::transmute(val) };
    let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
    let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
    let mantissa = if exponent == 0 {
        (bits & 0xfffffffffffff) << 1
    } else {
        (bits & 0xfffffffffffff) | 0x10000000000000
    };

    exponent -= 1023 + 52;
    (mantissa, exponent, sign)
}

impl Value {
    fn new(val: f64) -> Value {
        Value(integer_decode(val))
    }
}

impl<'b> DataFrame<'b> {
    pub fn new(data_map: HashMap<&'b str, Column>) -> DataFrame<'b> {
        DataFrame { data_map: data_map }

    }

    pub fn from_array(data: &'b Matrix, names: &'b Vec<&'b str>) -> Result<DataFrame<'b>, &'b str> {
        if data.cols() != names.len() {
            return Err("mismatched dimensions");
        }
        let data_map: HashMap<&'b str, Column> =
            names.iter().zip(data.axis_iter(Axis(1))).map(|(x, y)| (*x, y.to_owned())).collect();

        Ok(DataFrame::new(data_map))
    }

    pub fn from_vec(data: &'b Vec<Row>, names: Vec<&'b str>) -> Result<DataFrame<'b>, &'b str> {
        let data = stack(Axis(0),
                         &data.iter()
                             .map(|x| x.view().into_shape((1, x.dim())).unwrap())
                             .collect::<Vec<MatrixView<'b>>>()[..]);
        DataFrame::from_array(&data.unwrap(), &names)
        // if data.len() != names.len() {
        //     return Err("mismatched dimensions");
        // }
        // let data_map: HashMap<&'b str, Column> =
        //     names.iter().zip(data).map(|(x, y)| (*x, y.to_owned())).collect();
        //
        // Ok(DataFrame::new(data_map))
        // let data = stack(Axis(0),
        //                  &data.iter()
        //                      .map(|x| x.view().into_shape((1, x.dim())).unwrap())
        //                      .collect::<Vec<MatrixView<'b>>>()[..])
        //     .unwrap();
        // if data.cols() != names.len() {
        //     return Err("mismatched dimensions");
        // }
        // let data_map: HashMap<&'b str, Column> =
        //     names.iter().zip(data.axis_iter(Axis(1))).map(|(x, y)| (*x, y.to_owned())).collect();
        //
        // Ok(DataFrame::new(data_map))
    }

    pub fn get(&self, name: &'b str) -> Option<&Column> {
        self.data_map.get(&name)
    }

    // fn get_mut(&mut self, name: &'b str) -> Option<&mut Column> {
    //     self.data_map.get_mut(&name)
    // }

    pub fn inner_join(&self, other: &DataFrame<'b>, on: &'b str) -> Result<DataFrame<'b>, &'b str> {
        let h: HashMap<Value, usize> = self.get(on)
            .unwrap()
            .iter()
            .enumerate()
            .map(|(x, y)| (Value::new(*y), x))
            .collect();
        let j: HashMap<Value, usize> = other.get(on)
            .unwrap()
            .iter()
            .enumerate()
            .map(|(x, y)| (Value::new(*y), x))
            .collect();
        let mut vs = vec![];
        for row_key in h.keys() {
            match j.get(row_key) {
                None => continue,
                Some(v) => {
                    let idx = *h.get(row_key).unwrap();
                    let p = self.data_map
                        .values()
                        .map(|x| x.get(idx).unwrap())
                        .map(|x| *x);

                    let o = other.data_map
                        .iter()
                        .filter(|&(x, _)| *x != on)
                        .map(|(_, y)| y.get(*v).unwrap())
                        .map(|x| *x);

                    let chain = p.chain(o);

                    vs.push(chain.collect());

                }
            };
        }
        if vs.len() == 0 {
            return Err("No matching values in join column.");
        }
        let name_chain = self.data_map
            .keys()
            .chain(other.data_map.keys().filter(|&x| *x != on))
            .map(|x| *x)
            .collect::<Vec<&'b str>>();
        DataFrame::from_vec(&vs, name_chain)
    }
}

// The following implementation requires a copy, which we don't want!
// Alternative solution to inserting is to mutate the original matrix, but this also requires a
// copy!
// fn insert(&mut self, name: &'a str, value: Column) {
//     match self.data.entry(name) {
//         Entry::Occupied(mut o) => {
//             o.get_mut();
//         }
//         Entry::Vacant(v) => {
//             v.insert(value.view());
//         }
//     };
// }

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


<commit_before>
use super::row::Row;
use super::schema::{Schema, Type};

pub enum StreamError {
    ValidationError(String),
}

pub struct Stream {
    max_id: u64,
    rows: Vec<Row>,
    schema: Schema,
}

/**
This is a weird DB.  There's no primary key, since everything is based off append only streaming

*/
impl Stream {
    pub fn new() -> Stream {
        let mut stream = Stream {
            max_id: 0,
            rows: Vec::new(),
            schema: Schema::new(),
        };
        stream.schema.add_type("_id", Type::Int);
        stream.schema.add_type("_created", Type::Timestamp);
        stream
    }

    pub fn insert() -> Result<Row, StreamError> {
        Err(StreamError::ValidationError("Could not insert".to_string()))
    }
}

#[cfg(tests)]
mod tests {

}<commit_msg>working on inserting rows<commit_after>use std::collections::HashMap;

use super::row::Row;
use super::schema::{Schema, Type};
use super::field::Field;

pub enum StreamError {
    ValidationError(String),
}

pub struct Stream {
    max_id: u64,
    rows: Vec<Row>,
    schema: Schema,
}

/**
This is a weird DB.  There's no primary key, since everything is based off append only streaming

*/
impl Stream {
    pub fn new() -> Stream {
        let mut stream = Stream {
            max_id: 0,
            rows: Vec::new(),
            schema: Schema::new(),
        };
        stream.schema.add_type("_id", Type::Int);
        stream.schema.add_type("_created", Type::Timestamp);
        stream
    }

    pub fn insert(data: HashMap<String, Field>) -> Result<Row, StreamError> {
        // validate the inserted data
        Err(StreamError::ValidationError("Could not insert".to_string()))
    }
}

#[cfg(tests)]
mod tests {

}<|endoftext|>


<commit_before>#![feature(core_intrinsics, patchpoint_call_intrinsic, stackmap_call_intrinsic)]
#![feature(question_mark)]
// #![feature(type_ascription)]
// #![feature(rustc_attrs)]
#![feature(libc)]
#![feature(const_fn)]
#![feature(rustc_private)]
#![feature(linkage)]
#![feature(drop_types_in_const)]
#![feature(unboxed_closures)]
#![allow(unused_features)]

extern crate libc;
#[macro_use] extern crate log;

extern crate util;

pub use util::*;
use util::unwind_hack::{unw_regnum_t};
use util::llvm_stackmaps::LocationVariant;

use elf::Section;

use std::intrinsics;

const DEMO_ID: i64 = 0;
const SUBCALL1_ID: i64 = 1;
const SUBCALL2_ID: i64 = 2;

#[no_mangle]
pub fn subcall_1(data: *mut u8) {
    println!("Enter `subcall_1`");
    unsafe {
        intrinsics::stackmap_call(SUBCALL1_ID, 0, subcall_2, data);
        // intrinsics::patchpoint_call(SUBCALL1_ID, 13, subcall_2, data);
    }
    println!("Finis `subcall_1`");
}

#[linkage="external"]
fn subcall_2(data: *mut u8) {
    println!("Enter `subcall_2`");
    let mut i = 0;
    let mut saw_one = false;
    print!("[");
    let mut datum = unsafe { *data.offset(i) as char };
    while datum != '\0' {
        if saw_one {
            print!(", ");
        }
        print!("{}", datum);
        saw_one = true;
        i += 1;
        datum = unsafe { *data.offset(i) as char };
    }
    println!("]");
    unsafe {
        intrinsics::stackmap_call(SUBCALL2_ID, 0, subcall_3, data);
        // intrinsics::patchpoint_call(SUBCALL2_ID, 13, subcall_3, data);

    }
    println!("Finis `subcall_2`");
}

use self::backtrace_hack::ReturnAddress;
use self::backtrace_hack::dlinfo_fbase;

#[derive(Debug)]
enum FrameInfo<'a> {
    Addr(ReturnAddress),
    StackMap(StackMapFrameInfo<'a>),
}

#[derive(Debug)]
struct StackMapFrameInfo<'a> {
    addr: ReturnAddress,
    patchpoint_id: u64,
    instruction_offset: u32,
    locations: &'a [Location],
    live_outs: &'a [LiveOut],
}

trait StackMapExt {
    fn frame_info(&self, addr: ReturnAddress) -> FrameInfo;
}

impl StackMapExt for StackMap {
    fn frame_info(&self, addr: ReturnAddress) -> FrameInfo {
        let mut frame_info = None;

        debug!("");
        debug!("addr: {:?}", addr);

	if let Some(_base) = dlinfo_fbase(addr.0) {
            // Okay, we have a base address for the shared object of addr

            // We still need to find the function itself as well as
            // the call-site within it; here's a naive way to do it.
            //
            // FIXME: build structure ahead of time that allows
            // something faster than this linear scan.
            for r in self.records() {
                let fn_address = address_id(r.patchpoint_id()).unwrap();
                let instr_offset = r.instruction_offset() as usize;
                let call_address = fn_address + instr_offset;

                debug!("frame_info addr {:?} \
                                     record {:?} \
                                     fn_address: 0x{:x} \
                                     instr_offset: {:?} \
                                     call_address: 0x{:x} \
                                     delta: {}",
                         addr, r, fn_address, instr_offset, call_address,
                         call_address as isize - (addr.0 as isize));

                if call_address == addr.0 as usize {
                    assert!(frame_info.is_none());
                    frame_info = Some(StackMapFrameInfo {
                        addr: addr,
                        patchpoint_id: r.patchpoint_id(),
                        instruction_offset: r.instruction_offset(),
                        locations: r.locations(),
                        live_outs: r.live_outs(),
                    })
                }
            }
        } else {
            println!("frame_info no fbase for {:?}", addr);
        }

        if let Some(frame_info) = frame_info {
            FrameInfo::StackMap(frame_info)
        } else {
            FrameInfo::Addr(addr)
        }
    }
}

#[no_mangle]
pub fn subcall_3(_data: *mut u8) {
    println!("Start `subcall_3`");

    let map = unsafe { STACK_MAP.get() };
    println!("map:                              {:?}", map);
    unsafe {
        for i in 0..ADDRESS_IDS.len() {
            println!("ADDRESS_IDS[i] 0x{:x}", ADDRESS_IDS[i]);
        }
    }

    let unw = unwind_hack::UnwindContext::new();
    let mut cursor = Some(unw.cursor());

    while let Some(c) = cursor {
        let ip = c.get_reg(unwind_hack::UNW_REG_IP).unwrap();
        let sp = c.get_reg(unwind_hack::UNW_REG_SP).unwrap();
        debug!("ip: 0x{:x} sp: 0x{:x}", ip, sp);
        let opt_fbase = backtrace_hack::dlinfo_fbase(ip as *const libc::c_void);
        debug!("dlinfo_fbase: {:?}", opt_fbase);
        if let Some(fbase) = opt_fbase {
            debug!("dlrel ip: 0x{:x}", ip - (fbase as u64));
        }

        let (offset, name) = {
            let mut buf = Vec::with_capacity(256);
            match c.get_proc_name(&mut buf) {
                Err(e) => {
                    println!("failed to .get_proc_name from subcall_3: {:?}", e);
                    cursor = c.step().unwrap();
                    println!("");
                    continue;
                }
                Ok(offset) => (offset, String::from_utf8(buf).unwrap()),
            }
        };
        debug!("ip: 0x{:08x} name: {} offset: {}", ip, name, offset);
        debug!("start of fn:  0x{:08x}", ip - offset);
        if let Some(fbase) = opt_fbase {
            debug!("rel start of fn:  0x{:08x}", ip - offset - (fbase as u64));
        }
        for (i, rec) in map.records().iter().enumerate() {
            if address_id(rec.patchpoint_id()) == Some((ip - offset) as usize) &&
                rec.instruction_offset() as u64 == offset
            {
                println!("found match at ({}) for `{}`: {:?}", i, name, rec);
                for (j, loc) in rec.locations().iter().enumerate() {
                    let loc_interpreted: i64 = match *loc.variant() {
                        LocationVariant::Register { dwarf_regnum } => {
                            c.get_reg(dwarf_regnum as unw_regnum_t).unwrap() as i64
                        }
                        LocationVariant::Direct { dwarf_regnum, offset } => {
                            c.get_reg(dwarf_regnum as unw_regnum_t).unwrap() as i64 + offset as i64
                        }
                        LocationVariant::Indirect { dwarf_regnum, offset } => {
                            unsafe {
                                *((c.get_reg(dwarf_regnum as unw_regnum_t).unwrap() as i64 +
                                   offset as i64)
                                  as usize as *const usize) as i64
                            }
                        }
                        LocationVariant::Constant { value } => {
                            value as i64
                        }
                        LocationVariant::ConstIndex { offset: _ } => {
                            unimplemented!()
                        }
                    };
                    println!("rec[{}].loc[{}] {:?} => 0x{:x}",
                             i, j, loc, loc_interpreted);
                }
            }
        }

        cursor = c.step().unwrap();
        println!("");
    }
    println!("Finis `subcall_3`");
}

#[cfg(use_backtrace_hack)]
fn subcall_3(data: *mut u8) {
    println!("Start `subcall_3`");
    let map = unsafe { STACK_MAP.get() };
    println!("map:                   {:?}", map);
    let addresses = backtrace_hack::backtrace_return_addresses();
    println!("backtrace:             {:?}", addresses);
    let dlinfos = backtrace_hack::backtrace_dlinfos(&addresses);
    println!("backtrace dlinfos:     {:?}", dlinfos);
    let frame_infos: Vec<_> = addresses.iter()
        .map(|a| map.frame_info(*a))
        .collect();
    println!("backtrace frame_infos: {:?}", frame_infos);
    println!("Finis `subcall_3`");
}

fn main() {
    let local: u32 = 0;
    unsafe { MAIN_LOCAL = &local as *const _ as usize; }
    demo().unwrap();
}

#[derive(Debug)]
pub enum DemoError {
    ParseError(elf::ParseError),
    MissingSection(String),
}

impl std::convert::From<elf::ParseError> for DemoError {
    fn from(x: elf::ParseError) -> Self { DemoError::ParseError(x) }
}

use self::llvm_stackmaps::{LiveOut, Location, StackMap};
use std::cell::UnsafeCell;

struct SharedStackMap {
    map: UnsafeCell<Option<StackMap>>
}

impl SharedStackMap {
    /// Initializes the map. Unsafe because it does not attempt to
    /// enforce thread safety in any way: its your own job to make
    /// sure you do this once and only once.
    unsafe fn initialize(&self, map: StackMap) { *self.map.get() = Some(map); }
    const fn new() -> Self { SharedStackMap { map: UnsafeCell::new(None) } }
    unsafe fn get(&self) -> &'static StackMap {
        (*self.map.get()).as_ref().expect("Cannot get an uninitialized stack map")
    }
}

/// I am going to manually ensure that all clients of SharedStackMap access
/// it in solely a read-only fashion.
unsafe impl Sync for SharedStackMap { }

static STACK_MAP: SharedStackMap = SharedStackMap::new();
static mut ADDRESS_IDS: [usize; 3] = [0; 3];
fn address_id(patchpoint_id: u64) -> Option<usize> {
    unsafe {
        if patchpoint_id > ::std::usize::MAX as u64 { return None; }
        let idx = patchpoint_id as usize;
        if idx >= ADDRESS_IDS.len() { return None; }
        Some(ADDRESS_IDS[idx])
    }
}

#[derive(Debug)]
pub struct FnPtrData(i64, *const libc::c_void);

impl FnPtrData {
    const fn new<T, F>(id: i64, f: *const F) -> Self where F: Fn<T> {
        FnPtrData(id, f as *const libc::c_void)
    }
}

unsafe impl Sync for FnPtrData { }

#[link_section = ".fn_id_data"]
pub static DEMO_ID_DATA: FnPtrData = FnPtrData::new(DEMO_ID, &demo);

#[link_section = ".fn_id_data"]
pub static SUBCALL1_ID_DATA: FnPtrData = FnPtrData::new(SUBCALL1_ID, &subcall_1);

#[link_section = ".fn_id_data"]
pub static SUBCALL2_ID_DATA: FnPtrData = FnPtrData::new(SUBCALL2_ID, &subcall_2);

fn my_binary() -> Result<elf::File, elf::ParseError> {
    use std::path::Path;
    // FIXME: this is not a reliable way to extract the executable file path.
    // (look into alternatives)
    let binary = std::env::args().next().unwrap();

    println!("Hello World from {}", binary);

    let path = Path::new(&binary);
    elf::File::open_path(&path)
}

fn my_section<'a>(file: &'a elf::File, section_name: &str) -> Result<&'a Section, DemoError> {
    let name = section_name.to_string();
    file.get_section(name.clone())
        .ok_or_else(|| DemoError::MissingSection(name))
}

fn fn_ids(file: &elf::File) -> Result<&[FnPtrData], DemoError> {
    Ok(unsafe { ::std::mem::transmute(&my_section(file, ".fn_id_data")?.data[..]) })
}

fn initialize_shared_state() -> Result<(), DemoError> {
    use self::byteorder::LittleEndian;

    // FIXME: LLVM's stackmap/patchpoint intrinsic API does
    // not embed the identity of the function context where the
    // stackmap/patchpoint.
    //
    // It instead requires each stackmap/patchpoint invocation to
    // include a (globally unique) 64-bit ID, known at compile time.
    //
    // The problem for me is that it means that I have the
    // responsibility of building a mapping from functions to their
    // unique ID's, just so I can map from the return address to the
    // appropriate stackmap record. :(
    //
    // (I do not quite understand why they made this so hard;
    // presumably it is because the stackmap/patchpoint interface was
    // designed for use in JITs, not in AOT compilers.)
    //
    // In any case, for now I can just hardcode a table with the
    // necessary mapping from patchpoint IDs to function addresses.
    // (And hopefully I can hack the Rust backend to generate a table
    // like this automatically, though ensuring the IDs are unique
    // will be a bit harder than what I do here. I guess for that
    // I might as well re-use the SVH approach... we'll cross that
    // bridge when we get to it.)
    unsafe {
        ADDRESS_IDS[DEMO_ID as usize] = demo as usize;
        ADDRESS_IDS[SUBCALL1_ID as usize] = subcall_1 as usize;
        ADDRESS_IDS[SUBCALL2_ID as usize] = subcall_2 as usize;
    }

    let file = my_binary()?;
    let fn_id_data = fn_ids(&file)?;
    println!("fn_id_data section: {:?}", fn_id_data);
    unsafe {
        println!("ADDRESS_IDS: 0x{:x} 0x{:x} 0x{:x}", ADDRESS_IDS[0], ADDRESS_IDS[1], ADDRESS_IDS[2]);
    }

    let stackmap_section = my_section(&file, ".llvm_stackmaps")?;
    println!("stackmap_section: {:?}", stackmap_section);

    let stack_map = StackMap::read_from::<LittleEndian>(&mut &stackmap_section.data[..]);
    println!("stack_map: {:?}", stack_map);
    let map = stack_map.expect("Cannot do demo without valid stack map");
    unsafe { STACK_MAP.initialize(map); }
    Ok(())
}

#[no_mangle]
// #[rustc_mir(borrowck_graphviz_postflow="/tmp/foo.dot")]
pub fn demo() -> Result<(), DemoError> {
    try!(initialize_shared_state());

    let mut data = vec![b'h', b'e', b'l', b'l', b'o', 0];
    println!("data addr: {:?}", &data as *const _);

    unsafe {
        intrinsics::stackmap_call(DEMO_ID, 0, subcall_1, data.as_mut_ptr());
        // intrinsics::patchpoint_call(DEMO_ID, 13, subcall_1, data.as_mut_ptr());
    }

    println!("Goodbye World");

    Ok(())
}
<commit_msg>checkpoint experimental foo.rs.<commit_after>#![feature(core_intrinsics, patchpoint_call_intrinsic, stackmap_call_intrinsic)]
#![feature(question_mark)]
// #![feature(type_ascription)]
// #![feature(rustc_attrs)]
#![feature(libc)]
#![feature(const_fn)]
#![feature(rustc_private)]
#![feature(linkage)]
#![feature(drop_types_in_const)]
#![feature(unboxed_closures)]
#![allow(unused_features)]

extern crate libc;
#[macro_use] extern crate log;

extern crate util;

pub use util::*;
use util::unwind_hack::{unw_regnum_t};
use util::llvm_stackmaps::LocationVariant;

use elf::Section;

use std::intrinsics;

const DEMO_ID: i64 = 0;
const SUBCALL1_ID: i64 = 1;
const SUBCALL2_ID: i64 = 2;

#[no_mangle]
pub fn subcall_1(data: *mut u8) {
    println!("Enter `subcall_1`");
    unsafe {
        intrinsics::stackmap_call(SUBCALL1_ID, 0, subcall_2, data);
        // intrinsics::patchpoint_call(SUBCALL1_ID, 13, subcall_2, data);
    }
    println!("Finis `subcall_1`");
}

#[linkage="external"]
fn subcall_2(data: *mut u8) {
    println!("Enter `subcall_2`");
    let mut i = 0;
    let mut saw_one = false;
    print!("[");
    let mut datum = unsafe { *data.offset(i) as char };
    while datum != '\0' {
        if saw_one {
            print!(", ");
        }
        print!("{}", datum);
        saw_one = true;
        i += 1;
        datum = unsafe { *data.offset(i) as char };
    }
    println!("]");
    unsafe {
        intrinsics::stackmap_call(SUBCALL2_ID, 0, subcall_3, data);
        // intrinsics::patchpoint_call(SUBCALL2_ID, 13, subcall_3, data);

    }
    println!("Finis `subcall_2`");
}

use self::backtrace_hack::ReturnAddress;
use self::backtrace_hack::dlinfo_fbase;

#[derive(Debug)]
enum FrameInfo<'a> {
    Addr(ReturnAddress),
    StackMap(StackMapFrameInfo<'a>),
}

#[derive(Debug)]
struct StackMapFrameInfo<'a> {
    addr: ReturnAddress,
    patchpoint_id: u64,
    instruction_offset: u32,
    locations: &'a [Location],
    live_outs: &'a [LiveOut],
}

trait StackMapExt {
    fn frame_info(&self, addr: ReturnAddress) -> FrameInfo;
}

impl StackMapExt for StackMap {
    fn frame_info(&self, addr: ReturnAddress) -> FrameInfo {
        let mut frame_info = None;

        debug!("");
        debug!("addr: {:?}", addr);

	if let Some(_base) = dlinfo_fbase(addr.0) {
            // Okay, we have a base address for the shared object of addr

            // We still need to find the function itself as well as
            // the call-site within it; here's a naive way to do it.
            //
            // FIXME: build structure ahead of time that allows
            // something faster than this linear scan.
            for r in self.records() {
                let fn_address = address_id(r.patchpoint_id()).unwrap();
                let instr_offset = r.instruction_offset() as usize;
                let call_address = fn_address + instr_offset;

                debug!("frame_info addr {:?} \
                                     record {:?} \
                                     fn_address: 0x{:x} \
                                     instr_offset: {:?} \
                                     call_address: 0x{:x} \
                                     delta: {}",
                         addr, r, fn_address, instr_offset, call_address,
                         call_address as isize - (addr.0 as isize));

                if call_address == addr.0 as usize {
                    assert!(frame_info.is_none());
                    frame_info = Some(StackMapFrameInfo {
                        addr: addr,
                        patchpoint_id: r.patchpoint_id(),
                        instruction_offset: r.instruction_offset(),
                        locations: r.locations(),
                        live_outs: r.live_outs(),
                    })
                }
            }
        } else {
            println!("frame_info no fbase for {:?}", addr);
        }

        if let Some(frame_info) = frame_info {
            FrameInfo::StackMap(frame_info)
        } else {
            FrameInfo::Addr(addr)
        }
    }
}

#[no_mangle]
pub fn subcall_3(_data: *mut u8) {
    println!("Start `subcall_3`");

    let map = unsafe { STACK_MAP.get() };
    println!("map:                              {:?}", map);
    unsafe {
        for i in 0..ADDRESS_IDS.len() {
            println!("ADDRESS_IDS[i] 0x{:x}", ADDRESS_IDS[i]);
        }
    }

    let unw = unwind_hack::UnwindContext::new();
    let mut cursor = Some(unw.cursor());

    while let Some(c) = cursor {
        let ip = c.get_reg(unwind_hack::UNW_REG_IP).unwrap();
        let sp = c.get_reg(unwind_hack::UNW_REG_SP).unwrap();
        debug!("ip: 0x{:x} sp: 0x{:x}", ip, sp);
        let opt_fbase = backtrace_hack::dlinfo_fbase(ip as *const libc::c_void);
        debug!("dlinfo_fbase: {:?}", opt_fbase);
        if let Some(fbase) = opt_fbase {
            debug!("dlrel ip: 0x{:x}", ip - (fbase as u64));
        }

        let (offset, name) = {
            let mut buf = Vec::with_capacity(256);
            match c.get_proc_name(&mut buf) {
                Err(e) => {
                    println!("failed to .get_proc_name from subcall_3: {:?}", e);
                    cursor = c.step().unwrap();
                    println!("");
                    continue;
                }
                Ok(offset) => (offset, String::from_utf8(buf).unwrap()),
            }
        };
        debug!("ip: 0x{:08x} name: {} offset: {}", ip, name, offset);
        debug!("start of fn:  0x{:08x}", ip - offset);
        if let Some(fbase) = opt_fbase {
            debug!("rel start of fn:  0x{:08x}", ip - offset - (fbase as u64));
        }
        for (i, rec) in map.records().iter().enumerate() {
            if address_id(rec.patchpoint_id()) == Some((ip - offset) as usize) &&
                rec.instruction_offset() as u64 == offset
            {
                println!("found match at ({}) for `{}`: {:?}", i, name, rec);
                for (j, loc) in rec.locations().iter().enumerate() {
                    let loc_interpreted: i64 = match *loc.variant() {
                        LocationVariant::Register { dwarf_regnum } => {
                            c.get_reg(dwarf_regnum as unw_regnum_t).unwrap() as i64
                        }
                        LocationVariant::Direct { dwarf_regnum, offset } => {
                            c.get_reg(dwarf_regnum as unw_regnum_t).unwrap() as i64 + offset as i64
                        }
                        LocationVariant::Indirect { dwarf_regnum, offset } => {
                            unsafe {
                                *((c.get_reg(dwarf_regnum as unw_regnum_t).unwrap() as i64 +
                                   offset as i64)
                                  as usize as *const usize) as i64
                            }
                        }
                        LocationVariant::Constant { value } => {
                            value as i64
                        }
                        LocationVariant::ConstIndex { offset: _ } => {
                            unimplemented!()
                        }
                    };
                    println!("rec[{}].loc[{}] {:?} => 0x{:x}",
                             i, j, loc, loc_interpreted);
                }
            }
        }

        cursor = c.step().unwrap();
        println!("");
    }
    println!("Finis `subcall_3`");
}

#[cfg(use_backtrace_hack)]
fn subcall_3(data: *mut u8) {
    println!("Start `subcall_3`");
    let map = unsafe { STACK_MAP.get() };
    println!("map:                   {:?}", map);
    let addresses = backtrace_hack::backtrace_return_addresses();
    println!("backtrace:             {:?}", addresses);
    let dlinfos = backtrace_hack::backtrace_dlinfos(&addresses);
    println!("backtrace dlinfos:     {:?}", dlinfos);
    let frame_infos: Vec<_> = addresses.iter()
        .map(|a| map.frame_info(*a))
        .collect();
    println!("backtrace frame_infos: {:?}", frame_infos);
    println!("Finis `subcall_3`");
}

fn main() {
    let local: u32 = 0;
    unsafe { MAIN_LOCAL = &local as *const _ as usize; }
    demo().unwrap();
}

#[derive(Debug)]
pub enum DemoError {
    ParseError(elf::ParseError),
    MissingSection(String),
}

impl std::convert::From<elf::ParseError> for DemoError {
    fn from(x: elf::ParseError) -> Self { DemoError::ParseError(x) }
}

use self::llvm_stackmaps::{LiveOut, Location, StackMap};
use std::cell::UnsafeCell;

struct SharedStackMap {
    map: UnsafeCell<Option<StackMap>>
}

impl SharedStackMap {
    /// Initializes the map. Unsafe because it does not attempt to
    /// enforce thread safety in any way: its your own job to make
    /// sure you do this once and only once.
    unsafe fn initialize(&self, map: StackMap) { *self.map.get() = Some(map); }
    const fn new() -> Self { SharedStackMap { map: UnsafeCell::new(None) } }
    unsafe fn get(&self) -> &'static StackMap {
        (*self.map.get()).as_ref().expect("Cannot get an uninitialized stack map")
    }
}

/// I am going to manually ensure that all clients of SharedStackMap access
/// it in solely a read-only fashion.
unsafe impl Sync for SharedStackMap { }

static STACK_MAP: SharedStackMap = SharedStackMap::new();
static mut ADDRESS_IDS: [usize; 3] = [0; 3];
fn address_id(patchpoint_id: u64) -> Option<usize> {
    unsafe {
        if patchpoint_id > ::std::usize::MAX as u64 { return None; }
        let idx = patchpoint_id as usize;
        if idx >= ADDRESS_IDS.len() { return None; }
        Some(ADDRESS_IDS[idx])
    }
}

#[derive(Debug)]
pub struct FnPtrData(i64, *const libc::c_void);
unsafe impl Sync for FnPtrData { }

#[no_mangle]
#[link_section = ".fn_id_data"]
pub static DEMO_ID_DATA: FnPtrData = FnPtrData(DEMO_ID, demo as _);

#[no_mangle]
#[link_section = ".fn_id_data"]
pub static SUBCALL1_ID_DATA: FnPtrData = FnPtrData(SUBCALL1_ID, subcall_1 as _);

#[no_mangle]
#[link_section = ".fn_id_data"]
pub static SUBCALL2_ID_DATA: FnPtrData = FnPtrData(SUBCALL2_ID, subcall_2 as _);

pub static FN_IDS: [FnPtrData; 3] = [
    FnPtrData(DEMO_ID, demo as _),
    FnPtrData(SUBCALL1_ID, subcall_1 as _),
    FnPtrData(SUBCALL2_ID, subcall_2 as _),
    ];

fn my_binary() -> Result<elf::File, elf::ParseError> {
    use std::path::Path;
    // FIXME: this is not a reliable way to extract the executable file path.
    // (look into alternatives)
    let binary = std::env::args().next().unwrap();

    println!("Hello World from {}", binary);

    let path = Path::new(&binary);
    elf::File::open_path(&path)
}

fn my_section<'a>(file: &'a elf::File, section_name: &str) -> Result<&'a Section, DemoError> {
    let name = section_name.to_string();
    file.get_section(name.clone())
        .ok_or_else(|| DemoError::MissingSection(name))
}

fn fn_ids(file: &elf::File) -> Result<(&elf::types::SectionHeader, &[FnPtrData]), DemoError> {
    let fn_id_data = my_section(file, ".fn_id_data")?;
    let hdr = &fn_id_data.shdr;
    Ok((hdr, unsafe {
        std::slice::from_raw_parts(fn_id_data.data.as_ptr() as *const FnPtrData,
                                   hdr.size as usize / std::mem::size_of::<FnPtrData>())
    }))
}

fn initialize_shared_state() -> Result<(), DemoError> {
    use self::byteorder::LittleEndian;

    // FIXME: LLVM's stackmap/patchpoint intrinsic API does
    // not embed the identity of the function context where the
    // stackmap/patchpoint.
    //
    // It instead requires each stackmap/patchpoint invocation to
    // include a (globally unique) 64-bit ID, known at compile time.
    //
    // The problem for me is that it means that I have the
    // responsibility of building a mapping from functions to their
    // unique ID's, just so I can map from the return address to the
    // appropriate stackmap record. :(
    //
    // (I do not quite understand why they made this so hard;
    // presumably it is because the stackmap/patchpoint interface was
    // designed for use in JITs, not in AOT compilers.)
    //
    // In any case, for now I can just hardcode a table with the
    // necessary mapping from patchpoint IDs to function addresses.
    // (And hopefully I can hack the Rust backend to generate a table
    // like this automatically, though ensuring the IDs are unique
    // will be a bit harder than what I do here. I guess for that
    // I might as well re-use the SVH approach... we'll cross that
    // bridge when we get to it.)
    unsafe {
        ADDRESS_IDS[DEMO_ID as usize] = demo as usize;
        ADDRESS_IDS[SUBCALL1_ID as usize] = subcall_1 as usize;
        ADDRESS_IDS[SUBCALL2_ID as usize] = subcall_2 as usize;
    }

    let file = my_binary()?;
    let fn_id_data = fn_ids(&file)?;
    println!("fn_id_data section: {:?}", fn_id_data);
    println!("FN_IDS: 0x{:?} 0x{:?} 0x{:?}", FN_IDS[0], FN_IDS[1], FN_IDS[2]);

    let stackmap_section = my_section(&file, ".llvm_stackmaps")?;
    println!("stackmap_section: {:?}", stackmap_section);

    let stack_map = StackMap::read_from::<LittleEndian>(&mut &stackmap_section.data[..]);
    println!("stack_map: {:?}", stack_map);
    let map = stack_map.expect("Cannot do demo without valid stack map");
    unsafe { STACK_MAP.initialize(map); }
    Ok(())
}

#[no_mangle]
// #[rustc_mir(borrowck_graphviz_postflow="/tmp/foo.dot")]
pub fn demo() -> Result<(), DemoError> {
    try!(initialize_shared_state());

    let mut data = vec![b'h', b'e', b'l', b'l', b'o', 0];
    println!("data addr: {:?}", &data as *const _);

    unsafe {
        intrinsics::stackmap_call(DEMO_ID, 0, subcall_1, data.as_mut_ptr());
        // intrinsics::patchpoint_call(DEMO_ID, 13, subcall_1, data.as_mut_ptr());
    }

    println!("Goodbye World");

    Ok(())
}
<|endoftext|>


<commit_before>extern crate regex;

mod retention_policy;

use std::process::exit;

pub use self::retention_policy::RetentionPolicy;

use super::file::{ METADATA_DISK_SIZE, ARCHIVE_INFO_DISK_SIZE };

#[derive(Debug)]
pub struct Schema {
    pub retention_policies: Vec<RetentionPolicy>
}

impl Schema {
    // TODO: Change to Result type
    pub fn new_from_retention_specs(specs: Vec<String>) -> Schema {
        let retention_policies : Vec<RetentionPolicy> = {
            let expanded_pairs : Vec<Option<RetentionPolicy>> = specs.iter().map(|ts| {
                RetentionPolicy::spec_to_retention_policy(ts)
            }).collect();

            if expanded_pairs.iter().any(|x| x.is_none()) {
                let specs_iter = specs.iter();
                let pairs_iter = expanded_pairs.iter();
                let error_pairs : Vec<(&String, &Option<RetentionPolicy>)> = specs_iter.zip(pairs_iter).collect();
                validate_retention_policies(&error_pairs);
            }

            expanded_pairs.iter().filter(|x| x.is_some()).map(|x| x.unwrap()).collect()
        };

        Schema{ retention_policies: retention_policies }
    }

    pub fn header_size_on_disk(&self) -> u64 {
        METADATA_DISK_SIZE as u64 +
        (ARCHIVE_INFO_DISK_SIZE*self.retention_policies.len()) as u64
    }

    pub fn size_on_disk(&self) -> u64 {
        let retentions_disk_size = self.retention_policies.iter().fold(0, |tally, policy| {
            debug!("policy: {:?} size on disk: {}", policy, policy.size_on_disk());
            tally + policy.size_on_disk()
        });

        self.header_size_on_disk() + retentions_disk_size
    }

    pub fn max_retention(&self) -> u64 {
        if self.retention_policies.len() == 0 {
            0
        } else {
            self.retention_policies.iter().map(|&rp| rp.retention).max().unwrap()
        }
    }
}

fn retention_capture_to_pair(regex_match: regex::Captures) -> Option<RetentionPolicy> {
    let precision_opt = regex_match.at(1);
    let precision_mult = regex_match.at(2).unwrap_or("s");
    let retention_opt = regex_match.at(3);
    let retention_mult = regex_match.at(4);

    if precision_opt.is_some() && retention_opt.is_some() {
        let precision = {
            let base_precision = precision_opt.unwrap().parse::<u64>().unwrap();
            base_precision * mult_str_to_num(precision_mult)
        };

        let retention = {
            let base_retention = retention_opt.unwrap().parse::<u64>().unwrap();

            match retention_mult {
                Some(mult_str) => {
                    base_retention * mult_str_to_num(mult_str)
                },
                None => {
                    // user has not provided a multipler so this is interpreted
                    // as the number of points so we have to
                    // calculate retention from the number of points
                    base_retention * precision
                }
            }
        };

        let retention_spec = RetentionPolicy {
            precision: precision,
            retention: retention
        };

        Some(retention_spec)
    } else {
        None
    }
}

fn parse_spec_to_retention_policy(spec: &str) -> Option<RetentionPolicy> {
    // TODO: regex should be built as const using macro regex!
    // but that's only available in nightlies.
    let retention_matcher = regex::Regex::new({r"^(\d+)([smhdwy])?:(\d+)([smhdwy])?$"}).unwrap();
    match retention_matcher.captures(spec) {
        Some(regex_match) => {
            retention_capture_to_pair(regex_match)
        },
        None => None
    }
}

fn validate_retention_policies(expanded_pairs: &Vec<(&String, &Option<RetentionPolicy>)> ) {
    let _ : Vec<()> = expanded_pairs.iter().map(|pair: &(&String, &Option<RetentionPolicy>)| {
        let (ref string, ref opt) = *pair;
        if opt.is_none() {
            println!("error: {} is not a valid retention policy", string);
            exit(1);
        }
    }).collect();
}

#[test]
fn test_size_on_disk(){
    let first_policy = RetentionPolicy {
        precision: 1,
        retention: 60
    };

    let second_policy = RetentionPolicy {
        precision: 60,
        retention: 60
    };

    let mut little_schema = Schema {
        retention_policies: vec![]
    };

    let expected = METADATA_DISK_SIZE as u64
            + ARCHIVE_INFO_DISK_SIZE as u64 * 2
            + 60*12 // first policy size
            + 1*12; // second policy size

    little_schema.retention_policies.push(first_policy);
    little_schema.retention_policies.push(second_policy);

    assert_eq!(little_schema.size_on_disk(), expected);
}
<commit_msg>Bad merge. Fix.<commit_after>extern crate regex;

mod retention_policy;

use std::process::exit;

pub use self::retention_policy::RetentionPolicy;

use super::file::{ METADATA_DISK_SIZE, ARCHIVE_INFO_DISK_SIZE };

#[derive(Debug)]
pub struct Schema {
    pub retention_policies: Vec<RetentionPolicy>
}

impl Schema {
    // TODO: Change to Result type
    pub fn new_from_retention_specs(specs: Vec<String>) -> Schema {
        let retention_policies : Vec<RetentionPolicy> = {
            let expanded_pairs : Vec<Option<RetentionPolicy>> = specs.iter().map(|ts| {
                RetentionPolicy::spec_to_retention_policy(ts)
            }).collect();

            if expanded_pairs.iter().any(|x| x.is_none()) {
                let specs_iter = specs.iter();
                let pairs_iter = expanded_pairs.iter();
                let error_pairs : Vec<(&String, &Option<RetentionPolicy>)> = specs_iter.zip(pairs_iter).collect();
                validate_retention_policies(&error_pairs);
            }

            expanded_pairs.iter().filter(|x| x.is_some()).map(|x| x.unwrap()).collect()
        };

        Schema{ retention_policies: retention_policies }
    }

    pub fn header_size_on_disk(&self) -> u64 {
        METADATA_DISK_SIZE as u64 +
        (ARCHIVE_INFO_DISK_SIZE*self.retention_policies.len()) as u64
    }

    pub fn size_on_disk(&self) -> u64 {
        let retentions_disk_size = self.retention_policies.iter().fold(0, |tally, policy| {
            debug!("policy: {:?} size on disk: {}", policy, policy.size_on_disk());
            tally + policy.size_on_disk()
        });

        self.header_size_on_disk() + retentions_disk_size
    }

    pub fn max_retention(&self) -> u64 {
        if self.retention_policies.len() == 0 {
            0
        } else {
            self.retention_policies.iter().map(|&rp| rp.retention).max().unwrap()
        }
    }
}

fn validate_retention_policies(expanded_pairs: &Vec<(&String, &Option<RetentionPolicy>)> ) {
    let _ : Vec<()> = expanded_pairs.iter().map(|pair: &(&String, &Option<RetentionPolicy>)| {
        let (ref string, ref opt) = *pair;
        if opt.is_none() {
            println!("error: {} is not a valid retention policy", string);
            exit(1);
        }
    }).collect();
}

#[test]
fn test_size_on_disk(){
    let first_policy = RetentionPolicy {
        precision: 1,
        retention: 60
    };

    let second_policy = RetentionPolicy {
        precision: 60,
        retention: 60
    };

    let mut little_schema = Schema {
        retention_policies: vec![]
    };

    let expected = METADATA_DISK_SIZE as u64
            + ARCHIVE_INFO_DISK_SIZE as u64 * 2
            + 60*12 // first policy size
            + 1*12; // second policy size

    little_schema.retention_policies.push(first_policy);
    little_schema.retention_policies.push(second_policy);

    assert_eq!(little_schema.size_on_disk(), expected);
}
<|endoftext|>


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

/*!
Syntax extension to generate FourCCs.

Once loaded, fourcc!() is called with a single 4-character string,
and an optional ident that is either `big`, `little`, or `target`.
The ident represents endianness, and specifies in which direction
the characters should be read. If the ident is omitted, it is assumed
to be `big`, i.e. left-to-right order. It returns a u32.

# Examples

To load the extension and use it:

```rust,ignore
#[phase(syntax)]
extern crate fourcc;

fn main() {
    let val = fourcc!("\xC0\xFF\xEE!");
    assert_eq!(val, 0xC0FFEE21u32);
    let little_val = fourcc!("foo ", little);
    assert_eq!(little_val, 0x21EEFFC0u32);
}
 ```

# References

* [Wikipedia: FourCC](http://en.wikipedia.org/wiki/FourCC)

*/

#![crate_id = "fourcc#0.11-pre"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://static.rust-lang.org/doc/master")]

#![deny(deprecated_owned_vector)]
#![feature(macro_registrar, managed_boxes)]

extern crate syntax;

use syntax::ast;
use syntax::ast::Name;
use syntax::attr::contains;
use syntax::codemap::{Span, mk_sp};
use syntax::ext::base;
use syntax::ext::base::{SyntaxExtension, BasicMacroExpander, NormalTT, ExtCtxt, MacExpr};
use syntax::ext::build::AstBuilder;
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::InternedString;

#[macro_registrar]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
    register(token::intern("fourcc"),
        NormalTT(~BasicMacroExpander {
            expander: expand_syntax_ext,
            span: None,
        },
        None));
}

pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> ~base::MacResult {
    let (expr, endian) = parse_tts(cx, tts);

    let little = match endian {
        None => false,
        Some(Ident{ident, span}) => match token::get_ident(ident).get() {
            "little" => true,
            "big" => false,
            "target" => target_endian_little(cx, sp),
            _ => {
                cx.span_err(span, "invalid endian directive in fourcc!");
                target_endian_little(cx, sp)
            }
        }
    };

    let s = match expr.node {
        // expression is a literal
        ast::ExprLit(ref lit) => match lit.node {
            // string literal
            ast::LitStr(ref s, _) => {
                if s.get().char_len() != 4 {
                    cx.span_err(expr.span, "string literal with len != 4 in fourcc!");
                }
                s
            }
            _ => {
                cx.span_err(expr.span, "unsupported literal in fourcc!");
                return base::DummyResult::expr(sp)
            }
        },
        _ => {
            cx.span_err(expr.span, "non-literal in fourcc!");
            return base::DummyResult::expr(sp)
        }
    };

    let mut val = 0u32;
    for codepoint in s.get().chars().take(4) {
        let byte = if codepoint as u32 > 0xFF {
            cx.span_err(expr.span, "fourcc! literal character out of range 0-255");
            0u8
        } else {
            codepoint as u8
        };

        val = if little {
            (val >> 8) | ((byte as u32) << 24)
        } else {
            (val << 8) | (byte as u32)
        };
    }
    let e = cx.expr_lit(sp, ast::LitUint(val as u64, ast::TyU32));
    MacExpr::new(e)
}

struct Ident {
    ident: ast::Ident,
    span: Span
}

fn parse_tts(cx: &ExtCtxt, tts: &[ast::TokenTree]) -> (@ast::Expr, Option<Ident>) {
    let p = &mut parse::new_parser_from_tts(cx.parse_sess(),
                                            cx.cfg(),
                                            tts.iter()
                                               .map(|x| (*x).clone())
                                               .collect());
    let ex = p.parse_expr();
    let id = if p.token == token::EOF {
        None
    } else {
        p.expect(&token::COMMA);
        let lo = p.span.lo;
        let ident = p.parse_ident();
        let hi = p.last_span.hi;
        Some(Ident{ident: ident, span: mk_sp(lo, hi)})
    };
    if p.token != token::EOF {
        p.unexpected();
    }
    (ex, id)
}

fn target_endian_little(cx: &ExtCtxt, sp: Span) -> bool {
    let meta = cx.meta_name_value(sp, InternedString::new("target_endian"),
        ast::LitStr(InternedString::new("little"), ast::CookedStr));
    contains(cx.cfg().as_slice(), meta)
}

// FIXME (10872): This is required to prevent an LLVM assert on Windows
#[test]
fn dummy_test() { }
<commit_msg>librustc: Remove `~EXPR`, `~TYPE`, and `~PAT` from the language, except for `~str`/`~[]`.<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
Syntax extension to generate FourCCs.

Once loaded, fourcc!() is called with a single 4-character string,
and an optional ident that is either `big`, `little`, or `target`.
The ident represents endianness, and specifies in which direction
the characters should be read. If the ident is omitted, it is assumed
to be `big`, i.e. left-to-right order. It returns a u32.

# Examples

To load the extension and use it:

```rust,ignore
#[phase(syntax)]
extern crate fourcc;

fn main() {
    let val = fourcc!("\xC0\xFF\xEE!");
    assert_eq!(val, 0xC0FFEE21u32);
    let little_val = fourcc!("foo ", little);
    assert_eq!(little_val, 0x21EEFFC0u32);
}
 ```

# References

* [Wikipedia: FourCC](http://en.wikipedia.org/wiki/FourCC)

*/

#![crate_id = "fourcc#0.11-pre"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://static.rust-lang.org/doc/master")]

#![deny(deprecated_owned_vector)]
#![feature(macro_registrar, managed_boxes)]

extern crate syntax;

use syntax::ast;
use syntax::ast::Name;
use syntax::attr::contains;
use syntax::codemap::{Span, mk_sp};
use syntax::ext::base;
use syntax::ext::base::{SyntaxExtension, BasicMacroExpander, NormalTT, ExtCtxt, MacExpr};
use syntax::ext::build::AstBuilder;
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::InternedString;

#[macro_registrar]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
    register(token::intern("fourcc"),
        NormalTT(box BasicMacroExpander {
            expander: expand_syntax_ext,
            span: None,
        },
        None));
}

pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                         -> Box<base::MacResult> {
    let (expr, endian) = parse_tts(cx, tts);

    let little = match endian {
        None => false,
        Some(Ident{ident, span}) => match token::get_ident(ident).get() {
            "little" => true,
            "big" => false,
            "target" => target_endian_little(cx, sp),
            _ => {
                cx.span_err(span, "invalid endian directive in fourcc!");
                target_endian_little(cx, sp)
            }
        }
    };

    let s = match expr.node {
        // expression is a literal
        ast::ExprLit(ref lit) => match lit.node {
            // string literal
            ast::LitStr(ref s, _) => {
                if s.get().char_len() != 4 {
                    cx.span_err(expr.span, "string literal with len != 4 in fourcc!");
                }
                s
            }
            _ => {
                cx.span_err(expr.span, "unsupported literal in fourcc!");
                return base::DummyResult::expr(sp)
            }
        },
        _ => {
            cx.span_err(expr.span, "non-literal in fourcc!");
            return base::DummyResult::expr(sp)
        }
    };

    let mut val = 0u32;
    for codepoint in s.get().chars().take(4) {
        let byte = if codepoint as u32 > 0xFF {
            cx.span_err(expr.span, "fourcc! literal character out of range 0-255");
            0u8
        } else {
            codepoint as u8
        };

        val = if little {
            (val >> 8) | ((byte as u32) << 24)
        } else {
            (val << 8) | (byte as u32)
        };
    }
    let e = cx.expr_lit(sp, ast::LitUint(val as u64, ast::TyU32));
    MacExpr::new(e)
}

struct Ident {
    ident: ast::Ident,
    span: Span
}

fn parse_tts(cx: &ExtCtxt, tts: &[ast::TokenTree]) -> (@ast::Expr, Option<Ident>) {
    let p = &mut parse::new_parser_from_tts(cx.parse_sess(),
                                            cx.cfg(),
                                            tts.iter()
                                               .map(|x| (*x).clone())
                                               .collect());
    let ex = p.parse_expr();
    let id = if p.token == token::EOF {
        None
    } else {
        p.expect(&token::COMMA);
        let lo = p.span.lo;
        let ident = p.parse_ident();
        let hi = p.last_span.hi;
        Some(Ident{ident: ident, span: mk_sp(lo, hi)})
    };
    if p.token != token::EOF {
        p.unexpected();
    }
    (ex, id)
}

fn target_endian_little(cx: &ExtCtxt, sp: Span) -> bool {
    let meta = cx.meta_name_value(sp, InternedString::new("target_endian"),
        ast::LitStr(InternedString::new("little"), ast::CookedStr));
    contains(cx.cfg().as_slice(), meta)
}

// FIXME (10872): This is required to prevent an LLVM assert on Windows
#[test]
fn dummy_test() { }
<|endoftext|>


<commit_before>#[crate_id="github.com/sfackler/rust-phf#phf:0.0"];
#[crate_type="lib"];
#[feature(managed_boxes, macro_registrar)];

extern mod syntax;

use std::vec::VecIterator;

use syntax::ast;
use syntax::ast::{Name, TokenTree, LitStr, MutImmutable, Expr, ExprVec, ExprLit};
use syntax::codemap::Span;
use syntax::ext::base::{SyntaxExtension,
                        ExtCtxt,
                        MacResult,
                        MRExpr,
                        NormalTT,
                        SyntaxExpanderTT,
                        SyntaxExpanderTTExpanderWithoutContext};
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::{COMMA, EOF, FAT_ARROW};

pub struct PhfMap<T> {
    #[doc(hidden)]
    entries: &'static [(&'static str, T)],
}

impl<T> Container for PhfMap<T> {
    #[inline]
    fn len(&self) -> uint {
        self.entries.len()
    }
}

impl<T> Map<&'static str, T> for PhfMap<T> {
    #[inline]
    fn find<'a>(&'a self, key: & &'static str) -> Option<&'a T> {
        self.entries.bsearch(|&(val, _)| val.cmp(key)).map(|idx| {
            let (_, ref val) = self.entries[idx];
            val
        })
    }
}

impl<T> PhfMap<T> {
    #[inline]
    pub fn entries<'a>(&'a self) -> PhfMapEntries<'a, T> {
        PhfMapEntries { iter: self.entries.iter() }
    }

    #[inline]
    pub fn keys<'a>(&'a self) -> PhfMapKeys<'a, T> {
        PhfMapKeys { iter: self.entries() }
    }

    #[inline]
    pub fn values<'a>(&'a self) -> PhfMapValues<'a, T> {
        PhfMapValues { iter: self.entries() }
    }
}

pub struct PhfMapEntries<'a, T> {
    priv iter: VecIterator<'a, (&'static str, T)>,
}

impl<'a, T> Iterator<(&'static str, &'a T)> for PhfMapEntries<'a, T> {
    #[inline]
    fn next(&mut self) -> Option<(&'static str, &'a T)> {
        self.iter.next().map(|&(key, ref value)| (key, value))
    }
}

pub struct PhfMapKeys<'a, T> {
    priv iter: PhfMapEntries<'a, T>,
}

impl<'a, T> Iterator<&'static str> for PhfMapKeys<'a, T> {
    #[inline]
    fn next(&mut self) -> Option<&'static str> {
        self.iter.next().map(|(key, _)| key)
    }
}

pub struct PhfMapValues<'a, T> {
    priv iter: PhfMapEntries<'a, T>,
}

impl<'a, T> Iterator<&'a T> for PhfMapValues<'a, T> {
    #[inline]
    fn next(&mut self) -> Option<&'a T> {
        self.iter.next().map(|(_, value)| value)
    }
}

#[macro_registrar]
#[doc(hidden)]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
    register(token::intern("phf_map"),
             NormalTT(~SyntaxExpanderTT {
                expander: SyntaxExpanderTTExpanderWithoutContext(expand_mphf_map),
                span: None
             },
             None));
}

fn expand_mphf_map(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> MacResult {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                tts.to_owned());
    let mut pairs = ~[];

    while parser.token != EOF {
        let key = parser.parse_expr();

        let key_str = match key.node {
            ExprLit(lit) => {
                match lit.node {
                    LitStr(s, _) => s,
                    _ => cx.span_fatal(key.span, "expected string literal"),
                }
            }
            _ => cx.span_fatal(key.span, "expected string literal"),
        };

        if !parser.eat(&FAT_ARROW) {
            cx.span_fatal(parser.span, "expected `=>`");
        }

        let value = parser.parse_expr();

        pairs.push((key_str, key, value));

        if !parser.eat(&COMMA) && parser.token != EOF {
            cx.span_fatal(parser.span, "expected `,`");
        }
    }

    pairs.sort_by(|&(ref a, _, _), &(ref b, _, _)| a.cmp(b));
    check_for_duplicates(cx, sp, pairs);

    let entries = pairs.move_iter()
        .map(|(_, key, value)| quote_expr!(&*cx, ($key, $value)))
        .collect();
    let entries = @Expr {
        id: ast::DUMMY_NODE_ID,
        node: ExprVec(entries, MutImmutable),
        span: sp,
    };

    MRExpr(quote_expr!(cx, PhfMap { entries: &'static $entries }))
}

fn check_for_duplicates(cx: &mut ExtCtxt, sp: Span, entries: &[(@str, @Expr, @Expr)]) {
    let mut in_dup = false;
    for window in entries.windows(2) {
        let (a, a_expr, _) = window[0];
        let (b, b_expr, _) = window[1];
        if a == b {
            if !in_dup {
                cx.span_err(sp, format!("duplicate key \"{}\"", a));
                cx.span_err(a_expr.span, "one occurrence here");
                in_dup = true;
            }
            cx.span_err(b_expr.span, "one occurrence here");
        } else {
            in_dup = false;
        }
    }
    cx.parse_sess().span_diagnostic.handler().abort_if_errors();
}
<commit_msg>Update to new name of vec iterator<commit_after>#[crate_id="github.com/sfackler/rust-phf#phf:0.0"];
#[crate_type="lib"];
#[feature(managed_boxes, macro_registrar)];

extern mod syntax;

use std::vec;

use syntax::ast;
use syntax::ast::{Name, TokenTree, LitStr, MutImmutable, Expr, ExprVec, ExprLit};
use syntax::codemap::Span;
use syntax::ext::base::{SyntaxExtension,
                        ExtCtxt,
                        MacResult,
                        MRExpr,
                        NormalTT,
                        SyntaxExpanderTT,
                        SyntaxExpanderTTExpanderWithoutContext};
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::{COMMA, EOF, FAT_ARROW};

pub struct PhfMap<T> {
    #[doc(hidden)]
    entries: &'static [(&'static str, T)],
}

impl<T> Container for PhfMap<T> {
    #[inline]
    fn len(&self) -> uint {
        self.entries.len()
    }
}

impl<T> Map<&'static str, T> for PhfMap<T> {
    #[inline]
    fn find<'a>(&'a self, key: & &'static str) -> Option<&'a T> {
        self.entries.bsearch(|&(val, _)| val.cmp(key)).map(|idx| {
            let (_, ref val) = self.entries[idx];
            val
        })
    }
}

impl<T> PhfMap<T> {
    #[inline]
    pub fn entries<'a>(&'a self) -> PhfMapEntries<'a, T> {
        PhfMapEntries { iter: self.entries.iter() }
    }

    #[inline]
    pub fn keys<'a>(&'a self) -> PhfMapKeys<'a, T> {
        PhfMapKeys { iter: self.entries() }
    }

    #[inline]
    pub fn values<'a>(&'a self) -> PhfMapValues<'a, T> {
        PhfMapValues { iter: self.entries() }
    }
}

pub struct PhfMapEntries<'a, T> {
    priv iter: vec::Items<'a, (&'static str, T)>,
}

impl<'a, T> Iterator<(&'static str, &'a T)> for PhfMapEntries<'a, T> {
    #[inline]
    fn next(&mut self) -> Option<(&'static str, &'a T)> {
        self.iter.next().map(|&(key, ref value)| (key, value))
    }
}

pub struct PhfMapKeys<'a, T> {
    priv iter: PhfMapEntries<'a, T>,
}

impl<'a, T> Iterator<&'static str> for PhfMapKeys<'a, T> {
    #[inline]
    fn next(&mut self) -> Option<&'static str> {
        self.iter.next().map(|(key, _)| key)
    }
}

pub struct PhfMapValues<'a, T> {
    priv iter: PhfMapEntries<'a, T>,
}

impl<'a, T> Iterator<&'a T> for PhfMapValues<'a, T> {
    #[inline]
    fn next(&mut self) -> Option<&'a T> {
        self.iter.next().map(|(_, value)| value)
    }
}

#[macro_registrar]
#[doc(hidden)]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
    register(token::intern("phf_map"),
             NormalTT(~SyntaxExpanderTT {
                expander: SyntaxExpanderTTExpanderWithoutContext(expand_mphf_map),
                span: None
             },
             None));
}

fn expand_mphf_map(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> MacResult {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                tts.to_owned());
    let mut pairs = ~[];

    while parser.token != EOF {
        let key = parser.parse_expr();

        let key_str = match key.node {
            ExprLit(lit) => {
                match lit.node {
                    LitStr(s, _) => s,
                    _ => cx.span_fatal(key.span, "expected string literal"),
                }
            }
            _ => cx.span_fatal(key.span, "expected string literal"),
        };

        if !parser.eat(&FAT_ARROW) {
            cx.span_fatal(parser.span, "expected `=>`");
        }

        let value = parser.parse_expr();

        pairs.push((key_str, key, value));

        if !parser.eat(&COMMA) && parser.token != EOF {
            cx.span_fatal(parser.span, "expected `,`");
        }
    }

    pairs.sort_by(|&(ref a, _, _), &(ref b, _, _)| a.cmp(b));
    check_for_duplicates(cx, sp, pairs);

    let entries = pairs.move_iter()
        .map(|(_, key, value)| quote_expr!(&*cx, ($key, $value)))
        .collect();
    let entries = @Expr {
        id: ast::DUMMY_NODE_ID,
        node: ExprVec(entries, MutImmutable),
        span: sp,
    };

    MRExpr(quote_expr!(cx, PhfMap { entries: &'static $entries }))
}

fn check_for_duplicates(cx: &mut ExtCtxt, sp: Span, entries: &[(@str, @Expr, @Expr)]) {
    let mut in_dup = false;
    for window in entries.windows(2) {
        let (a, a_expr, _) = window[0];
        let (b, b_expr, _) = window[1];
        if a == b {
            if !in_dup {
                cx.span_err(sp, format!("duplicate key \"{}\"", a));
                cx.span_err(a_expr.span, "one occurrence here");
                in_dup = true;
            }
            cx.span_err(b_expr.span, "one occurrence here");
        } else {
            in_dup = false;
        }
    }
    cx.parse_sess().span_diagnostic.handler().abort_if_errors();
}
<|endoftext|>


<commit_before>use decoders::Image;
extern crate itertools;
use self::itertools::Itertools;

pub fn camera_to_lab(img: &Image, inb: &[f32]) -> Vec<f32> {
  let mut out: Vec<f32> = vec![0.0; (img.width*img.height*3) as usize];
  let cmatrix = cam_to_xyz_matrix(img);

  let mut opos = 0;
  for pos in (0..(img.height*img.width*4)).step(4) {
    let cr = inb[pos];
    let cg = inb[pos+1];
    let cb = inb[pos+2];
    let ce = inb[pos+3];

    let x = cr * cmatrix[0][0] + cg * cmatrix[0][1] + cb * cmatrix[0][2] + ce * cmatrix[0][3];
    let y = cr * cmatrix[1][0] + cg * cmatrix[1][1] + cb * cmatrix[1][2] + ce * cmatrix[1][3];
    let z = cr * cmatrix[2][0] + cg * cmatrix[2][1] + cb * cmatrix[2][2] + ce * cmatrix[2][3];

    let (l,a,b) = xyz_to_lab(x,y,z);

    out[opos+0] = l;
    out[opos+1] = a;
    out[opos+2] = b;

    opos += 3;
  }

  out
}

pub fn lab_to_rec709(img: &Image, inb: &[f32]) -> Vec<f32> {
  let mut out: Vec<f32> = vec![0.0; (img.width*img.height*3) as usize];
  let cmatrix = xyz_to_rec709_matrix();

  let mut opos = 0;
  for pos in (0..(img.height*img.width*3)).step(3) {
    let l = inb[pos];
    let a = inb[pos+1];
    let b = inb[pos+2];

    let (x,y,z) = lab_to_xyz(l,a,b);

    let r = x * cmatrix[0][0] + y * cmatrix[0][1] + z * cmatrix[0][2];
    let g = x * cmatrix[1][0] + y * cmatrix[1][1] + z * cmatrix[1][2];
    let b = x * cmatrix[2][0] + y * cmatrix[2][1] + z * cmatrix[2][2];

    out[opos+0] = r;
    out[opos+1] = g;
    out[opos+2] = b;

    opos += 3;
  }

  out
}

fn inverse(inm: [[f32;3];3]) -> [[f32;3];3] {
  let invdet = 1.0 / (
    inm[0][0] * (inm[1][1] * inm[2][2] - inm[2][1] * inm[1][2]) -
    inm[0][1] * (inm[1][0] * inm[2][2] - inm[1][2] * inm[2][0]) +
    inm[0][2] * (inm[1][0] * inm[2][1] - inm[1][1] * inm[2][0])
  );

  let mut out = [[0.0; 3];3];
  out[0][0] =  (inm[1][1]*inm[2][2] - inm[2][1]*inm[1][2]) * invdet;
  out[0][1] = -(inm[0][1]*inm[2][2] - inm[0][2]*inm[2][1]) * invdet;
  out[0][2] =  (inm[0][1]*inm[1][2] - inm[0][2]*inm[1][1]) * invdet;
  out[1][0] = -(inm[1][0]*inm[2][2] - inm[1][2]*inm[2][0]) * invdet;
  out[1][1] =  (inm[0][0]*inm[2][2] - inm[0][2]*inm[2][0]) * invdet;
  out[1][2] = -(inm[0][0]*inm[1][2] - inm[1][0]*inm[0][2]) * invdet;
  out[2][0] =  (inm[1][0]*inm[2][1] - inm[2][0]*inm[1][1]) * invdet;
  out[2][1] = -(inm[0][0]*inm[2][1] - inm[2][0]*inm[0][1]) * invdet;
  out[2][2] =  (inm[0][0]*inm[1][1] - inm[1][0]*inm[0][1]) * invdet;

  out
}

fn pseudoinverse(inm: [[f32;3];4]) -> [[f32;4];3] {
  let mut temp: [[f32;6];3] = [[0.0; 6];3];

  for i in 0..3 {
    for j in 0..6 {
      temp[i][j] = if j == i+3 { 1.0 } else { 0.0 };
    }
    for j in 0..3 {
      for k in 0..4 {
        temp[i][j] += inm[k][i] * inm[k][j];
      }
    }
  }

  for i in 0..3 {
    let mut num = temp[i][i];
    for j in 0..6 {
      temp[i][j] /= num;
    }
    for k in 0..3 {
      if k == i { continue }
      num = temp[k][i];
      for j in 0..6 {
        temp[k][j] -= temp[i][j] * num;
      }
    }
  }

  let mut out: [[f32;4];3] = [[0.0; 4];3];

  for i in 0..4 {
    for j in 0..3 {
      out[j][i] = 0.0;
      for k in 0..3 {
        out[j][i] += temp[j][k+3] * inm[i][k];
      }
    }
  }

  out
}

fn cam_to_xyz_matrix(img: &Image) -> [[f32;4];3] {
  let mut xyz_to_cam = [[0.0;3];4];
  for i in 0..12 {
    xyz_to_cam[i/3][i%3] = img.color_matrix[i] as f32;
  }

  // Normalize xyz_to_cam so that xyz_to_cam * (1,1,1) is (1,1,1,1)
  for i in 0..4 {
    let mut num = 0.0;
    for j in 0..3 {
      num += xyz_to_cam[i][j];
    }
    for j in 0..3 {
      xyz_to_cam[i][j] = if num == 0.0 {
        0.0
      }  else {
        xyz_to_cam[i][j] / num
      };
    }
  }

  pseudoinverse(xyz_to_cam)
}

fn xyz_to_rec709_matrix() -> [[f32;3];3] {
  let mut rgb_to_xyz = [
  // sRGB D65
    [ 0.412453, 0.357580, 0.180423 ],
    [ 0.212671, 0.715160, 0.072169 ],
    [ 0.019334, 0.119193, 0.950227 ],
  ];

  // Normalize rgb_to_xyz so that rgb_to_xyz * (1,1,1) is (1,1,1)
  for i in 0..3 {
    let mut num = 0.0;
    for j in 0..3 {
      num += rgb_to_xyz[i][j];
    }
    for j in 0..3 {
      rgb_to_xyz[i][j] = if num == 0.0 {
        0.0
      }  else {
        rgb_to_xyz[i][j] / num
      };
    }
  }

  inverse(rgb_to_xyz)
}

fn xyz_to_lab(x: f32, y: f32, z: f32) -> (f32,f32,f32) {
  // D50 White
  let xw = 0.9642; let yw = 1.000; let zw = 0.8249;

  let l = 116.0 * labf(y/yw) - 16.0;
  let a = 500.0 * (labf(x/xw) - labf(y/yw));
  let b = 200.0 * (labf(y/yw) - labf(z/zw));

  (l/100.0,(a+128.0)/256.0,(b+128.0)/256.0)
}

fn labf(val: f32) -> f32 {
  let cutoff = (6.0/29.0)*(6.0/29.0)*(6.0/29.0);
  let multiplier = (1.0/3.0) * (29.0/6.0) * (29.0/6.0);
  let constant = 4.0 / 29.0;

  if val > cutoff {
    val.powf(1.0 / 3.0)
  } else {
    val * multiplier + constant
  }
}

fn lab_to_xyz(l: f32, a: f32, b: f32) -> (f32,f32,f32) {
  // D50 White
  let xw = 0.9642; let yw = 1.000; let zw = 0.8249;

  let cl = l * 100.0;
  let ca = (a * 256.0) - 128.0;
  let cb = (b * 256.0) - 128.0;

  let x = xw * labinvf((1.0/116.0) * (cl+16.0) + (1.0/500.0) * ca);
  let y = yw * labinvf((1.0/116.0) * (cl+16.0));
  let z = zw * labinvf((1.0/116.0) * (cl+16.0) - (1.0/200.0) * cb);

  (x,y,z)
}

fn labinvf(val: f32) -> f32 {
  let cutoff = 6.0 / 29.0;
  let multiplier = 3.0 * (6.0/29.0) * (6.0/29.0);
  let constant = multiplier * (-4.0 / 29.0);

  if val > cutoff {
    val.powf(3.0)
  } else {
    val * multiplier + constant
  }
}
<commit_msg>colorspaces: improve calculations of XYZ matrices<commit_after>use decoders::Image;
extern crate itertools;
use self::itertools::Itertools;

pub fn camera_to_lab(img: &Image, inb: &[f32]) -> Vec<f32> {
  let mut out: Vec<f32> = vec![0.0; (img.width*img.height*3) as usize];
  let cmatrix = cam_to_xyz_matrix(img);

  let mut opos = 0;
  for pos in (0..(img.height*img.width*4)).step(4) {
    let cr = inb[pos];
    let cg = inb[pos+1];
    let cb = inb[pos+2];
    let ce = inb[pos+3];

    let x = cr * cmatrix[0][0] + cg * cmatrix[0][1] + cb * cmatrix[0][2] + ce * cmatrix[0][3];
    let y = cr * cmatrix[1][0] + cg * cmatrix[1][1] + cb * cmatrix[1][2] + ce * cmatrix[1][3];
    let z = cr * cmatrix[2][0] + cg * cmatrix[2][1] + cb * cmatrix[2][2] + ce * cmatrix[2][3];

    let (l,a,b) = xyz_to_lab(x,y,z);

    out[opos+0] = l;
    out[opos+1] = a;
    out[opos+2] = b;

    opos += 3;
  }

  out
}

pub fn lab_to_rec709(img: &Image, inb: &[f32]) -> Vec<f32> {
  let mut out: Vec<f32> = vec![0.0; (img.width*img.height*3) as usize];
  let cmatrix = xyz_to_rec709_matrix();

  let mut opos = 0;
  for pos in (0..(img.height*img.width*3)).step(3) {
    let l = inb[pos];
    let a = inb[pos+1];
    let b = inb[pos+2];

    let (x,y,z) = lab_to_xyz(l,a,b);

    let r = x * cmatrix[0][0] + y * cmatrix[0][1] + z * cmatrix[0][2];
    let g = x * cmatrix[1][0] + y * cmatrix[1][1] + z * cmatrix[1][2];
    let b = x * cmatrix[2][0] + y * cmatrix[2][1] + z * cmatrix[2][2];

    out[opos+0] = r;
    out[opos+1] = g;
    out[opos+2] = b;

    opos += 3;
  }

  out
}

fn inverse(inm: [[f32;3];3]) -> [[f32;3];3] {
  let invdet = 1.0 / (
    inm[0][0] * (inm[1][1] * inm[2][2] - inm[2][1] * inm[1][2]) -
    inm[0][1] * (inm[1][0] * inm[2][2] - inm[1][2] * inm[2][0]) +
    inm[0][2] * (inm[1][0] * inm[2][1] - inm[1][1] * inm[2][0])
  );

  let mut out = [[0.0; 3];3];
  out[0][0] =  (inm[1][1]*inm[2][2] - inm[2][1]*inm[1][2]) * invdet;
  out[0][1] = -(inm[0][1]*inm[2][2] - inm[0][2]*inm[2][1]) * invdet;
  out[0][2] =  (inm[0][1]*inm[1][2] - inm[0][2]*inm[1][1]) * invdet;
  out[1][0] = -(inm[1][0]*inm[2][2] - inm[1][2]*inm[2][0]) * invdet;
  out[1][1] =  (inm[0][0]*inm[2][2] - inm[0][2]*inm[2][0]) * invdet;
  out[1][2] = -(inm[0][0]*inm[1][2] - inm[1][0]*inm[0][2]) * invdet;
  out[2][0] =  (inm[1][0]*inm[2][1] - inm[2][0]*inm[1][1]) * invdet;
  out[2][1] = -(inm[0][0]*inm[2][1] - inm[2][0]*inm[0][1]) * invdet;
  out[2][2] =  (inm[0][0]*inm[1][1] - inm[1][0]*inm[0][1]) * invdet;

  out
}

fn pseudoinverse(inm: [[f32;3];4]) -> [[f32;4];3] {
  let mut temp: [[f32;6];3] = [[0.0; 6];3];

  for i in 0..3 {
    for j in 0..6 {
      temp[i][j] = if j == i+3 { 1.0 } else { 0.0 };
    }
    for j in 0..3 {
      for k in 0..4 {
        temp[i][j] += inm[k][i] * inm[k][j];
      }
    }
  }

  for i in 0..3 {
    let mut num = temp[i][i];
    for j in 0..6 {
      temp[i][j] /= num;
    }
    for k in 0..3 {
      if k == i { continue }
      num = temp[k][i];
      for j in 0..6 {
        temp[k][j] -= temp[i][j] * num;
      }
    }
  }

  let mut out: [[f32;4];3] = [[0.0; 4];3];

  for i in 0..4 {
    for j in 0..3 {
      out[j][i] = 0.0;
      for k in 0..3 {
        out[j][i] += temp[j][k+3] * inm[i][k];
      }
    }
  }

  out
}

fn cam_to_xyz_matrix(img: &Image) -> [[f32;4];3] {
  let mut xyz_to_cam = [[0.0;3];4];
  for i in 0..12 {
    xyz_to_cam[i/3][i%3] = img.color_matrix[i] as f32;
  }

  let d65_white = [0.9547,1.0,1.08883];
  let rgb_to_xyz = [
  // sRGB D65
    [ 0.412453, 0.357580, 0.180423 ],
    [ 0.212671, 0.715160, 0.072169 ],
    [ 0.019334, 0.119193, 0.950227 ],
  ];

  // Multiply RGB matrix
  let mut rgb_to_cam = [[0.0;3];4];
  for i in 0..4 {
    for j in 0..3 {
      rgb_to_cam[i][j] = 0.0;
      for k in 0..3 {
        rgb_to_cam[i][j] += xyz_to_cam[i][k] * rgb_to_xyz[k][j];
      }
    }
  }

  // Normalize rgb_to_cam so that rgb_to_cam * (1,1,1) is (1,1,1,1)
  for i in 0..4 {
    let mut num = 0.0;
    for j in 0..3 {
      num += rgb_to_cam[i][j];
    }
    for j in 0..3 {
      rgb_to_cam[i][j] = if num == 0.0 {
        0.0
      }  else {
        rgb_to_cam[i][j] / num
      };
    }
  }

  let cam_to_rgb = pseudoinverse(rgb_to_cam);
  let mut cam_to_xyz = [[0.0;4];3];
  // Multiply RGB matrix and adjust white to get a cam_to_xyz
  for i in 0..3 {
    for j in 0..4 {
      cam_to_xyz[i][j] = 0.0;
      for k in 0..3 {
        cam_to_xyz[i][j] += cam_to_rgb[k][j] * rgb_to_xyz[i][k] / d65_white[i];
      }
    }
  }

  cam_to_xyz
}

fn xyz_to_rec709_matrix() -> [[f32;3];3] {
  let rgb_to_xyz = [
  // sRGB D65
    [ 0.412453, 0.357580, 0.180423 ],
    [ 0.212671, 0.715160, 0.072169 ],
    [ 0.019334, 0.119193, 0.950227 ],
  ];

  inverse(rgb_to_xyz)
}

fn xyz_to_lab(x: f32, y: f32, z: f32) -> (f32,f32,f32) {
  // D50 White
  let xw = 0.9642; let yw = 1.000; let zw = 0.8249;

  let l = 116.0 * labf(y/yw) - 16.0;
  let a = 500.0 * (labf(x/xw) - labf(y/yw));
  let b = 200.0 * (labf(y/yw) - labf(z/zw));

  (l/100.0,(a+128.0)/256.0,(b+128.0)/256.0)
}

fn labf(val: f32) -> f32 {
  let cutoff = (6.0/29.0)*(6.0/29.0)*(6.0/29.0);
  let multiplier = (1.0/3.0) * (29.0/6.0) * (29.0/6.0);
  let constant = 4.0 / 29.0;

  if val > cutoff {
    val.powf(1.0 / 3.0)
  } else {
    val * multiplier + constant
  }
}

fn lab_to_xyz(l: f32, a: f32, b: f32) -> (f32,f32,f32) {
  // D50 White
  let xw = 0.9642; let yw = 1.000; let zw = 0.8249;

  let cl = l * 100.0;
  let ca = (a * 256.0) - 128.0;
  let cb = (b * 256.0) - 128.0;

  let x = xw * labinvf((1.0/116.0) * (cl+16.0) + (1.0/500.0) * ca);
  let y = yw * labinvf((1.0/116.0) * (cl+16.0));
  let z = zw * labinvf((1.0/116.0) * (cl+16.0) - (1.0/200.0) * cb);

  (x,y,z)
}

fn labinvf(val: f32) -> f32 {
  let cutoff = 6.0 / 29.0;
  let multiplier = 3.0 * (6.0/29.0) * (6.0/29.0);
  let constant = multiplier * (-4.0 / 29.0);

  if val > cutoff {
    val.powf(3.0)
  } else {
    val * multiplier + constant
  }
}
<|endoftext|>


<commit_before>use args::Args;
use manifest::Manifest;

static DEFAULT_CARGO_TOML: &'static str = r#"[package]
authors = ["Some Guy"]
name = "lorem-ipsum"
version = "0.1.0"

[dependencies]
foo-bar = "0.1""#;

macro_rules! add_deps_test {
    ($name:ident: add $entry:expr => $section:expr) => {
        #[test]
        fn $name() {
            let opts = Args {
                arg_section: String::from($section),
                arg_dep: vec![String::from($entry)],
                ..Default::default()
            };

            let mut manifile = Manifest::from_str(DEFAULT_CARGO_TOML).unwrap();

            manifile.add_deps(
                &opts.get_section(),
                &opts.get_dependencies()
            ).unwrap();

            let entry = manifile.data.get(&opts.get_section()).expect("section not found")
                .lookup($entry).expect("entry not found")
                .as_str().expect("entry not a str");

            assert_eq!(
                entry,
                "*"
            )
        }
    };

    ($name:ident: add $entry:expr, version $version:expr => $section:expr) => {
        #[test]
        fn $name() {
            let opts = Args {
                arg_section: String::from($section),
                arg_dep: vec![String::from($entry)],
                arg_source: String::from($version),
                flag_version: true,
                ..Default::default()
            };

            let mut manifile = Manifest::from_str(DEFAULT_CARGO_TOML).unwrap();

            manifile.add_deps(
                &opts.get_section(),
                &opts.get_dependencies()
            ).unwrap();

            let entry = manifile.data.get(&opts.get_section()).expect("section not found")
                .lookup($entry).expect("entry not found")
                .as_str().expect("entry not a str");

            assert_eq!(
                entry,
                $version
            )
        }
    }
}

add_deps_test!(add_dependency: add "lorem-ipsum" => "dependencies");
add_deps_test!(add_dep: add "lorem-ipsum" => "deps");
add_deps_test!(add_dev_dependency: add "lorem-ipsum" => "dev-dependencies");
add_deps_test!(add_dev_dep: add "lorem-ipsum" => "dev-deps");
add_deps_test!(add_build_dependency: add "lorem-ipsum" => "build-dependencies");
add_deps_test!(add_build_dep: add "lorem-ipsum" => "build-deps");

add_deps_test!(add_dependency_version: add "lorem-ipsum", version "0.4.2" => "dependencies");
<commit_msg>Test: Multiple Deps; Git, Path Deps<commit_after>use args::Args;
use manifest::Manifest;

static DEFAULT_CARGO_TOML: &'static str = r#"[package]
authors = ["Some Guy"]
name = "lorem-ipsum"
version = "0.1.0"

[dependencies]
foo-bar = "0.1""#;

macro_rules! add_deps_test {
    ($name:ident: add $($entry:expr),+ => $section:expr) => {
        #[test]
        fn $name() {
            let opts = Args {
                arg_section: String::from($section),
                arg_dep: vec![ $(String::from($entry)),+ ],
                ..Default::default()
            };

            let mut manifile = Manifest::from_str(DEFAULT_CARGO_TOML).unwrap();

            manifile.add_deps(
                &opts.get_section(),
                &opts.get_dependencies()
            ).unwrap();

            $({
                let entry = manifile.data.get(&opts.get_section()).expect("section not found")
                    .lookup($entry).expect("entry not found")
                    .as_str().expect("entry not a str");

                assert_eq!(entry, "*");
            })+
        }
    };

    ($name:ident: add $entry:expr, version $version:expr => $section:expr) => {
        #[test]
        fn $name() {
            let opts = Args {
                arg_section: String::from($section),
                arg_dep: vec![String::from($entry)],
                arg_source: String::from($version),
                flag_version: true,
                ..Default::default()
            };

            let mut manifile = Manifest::from_str(DEFAULT_CARGO_TOML).unwrap();

            manifile.add_deps(
                &opts.get_section(),
                &opts.get_dependencies()
            ).unwrap();

            let entry = manifile.data.get(&opts.get_section()).expect("section not found")
                .lookup($entry).expect("entry not found")
                .as_str().expect("entry not a str");

            assert_eq!(entry, $version);
        }
    };
}

add_deps_test!(add_dependency:         add "lorem-ipsum" => "dependencies");
add_deps_test!(add_dependencies:       add "lorem-ipsum", "dolor-sit" => "dependencies");
add_deps_test!(add_dep:                add "lorem-ipsum" => "deps");
add_deps_test!(add_deps:               add "lorem-ipsum", "schinken-käse" => "deps");
add_deps_test!(add_dev_dependency:     add "lorem-ipsum" => "dev-dependencies");
add_deps_test!(add_dev_dep:            add "lorem-ipsum" => "dev-deps");
add_deps_test!(add_build_dependency:   add "lorem-ipsum" => "build-dependencies");
add_deps_test!(add_build_dep:          add "lorem-ipsum" => "build-deps");

add_deps_test!(add_dependency_version: add "lorem-ipsum", version "0.4.2" => "dependencies");

#[test]
fn add_dependency_from_git() {
    let opts = Args {
        arg_section: String::from("dev-dependencies"),
        arg_dep: vec![String::from("amet")],
        arg_source: String::from("https://localhost/amet.git"),
        flag_git: true,
        ..Default::default()
    };

    let mut manifile = Manifest::from_str(DEFAULT_CARGO_TOML).unwrap();

    manifile.add_deps(
        &opts.get_section(),
        &opts.get_dependencies()
    ).unwrap();

    let entry = manifile.data.get(&opts.get_section()).expect("section not found")
        .lookup("amet").expect("entry not found")
        .lookup("git").expect("git not found")
        .as_str().expect("entry not a str");

    assert_eq!(entry, "https://localhost/amet.git");
}

#[test]
fn add_dependency_from_path() {
    let opts = Args {
        arg_section: String::from("dev-dependencies"),
        arg_dep: vec![String::from("amet")],
        arg_source: String::from("../amet"),
        flag_path: true,
        ..Default::default()
    };

    let mut manifile = Manifest::from_str(DEFAULT_CARGO_TOML).unwrap();

    manifile.add_deps(
        &opts.get_section(),
        &opts.get_dependencies()
    ).unwrap();

    let entry = manifile.data.get(&opts.get_section()).expect("section not found")
        .lookup("amet").expect("entry not found")
        .lookup("path").expect("path not found")
        .as_str().expect("entry not a str");

    assert_eq!(entry, "../amet");
}
<|endoftext|>