<commit_before>// need to raise recursion limit because many combinators
#![recursion_limit = "128"]
#![deny(bare_trait_objects)]

use std::io::{BufRead as _, BufReader, Write as _};
use std::path::PathBuf;

use structopt::StructOpt;

use futures::{future, stream, Future as _, Sink as _, Stream as _};
use log::{error, info};

use gerritbot as bot;
use gerritbot_gerrit as gerrit;
use gerritbot_spark as spark;

#[derive(StructOpt, Debug)]
struct Args {
    /// Gerrit username
    #[structopt(short = "u")]
    username: String,
    /// Gerrit hostname
    hostname: String,
    /// Gerrit SSH port
    #[structopt(short = "p", default_value = "29418")]
    port: u32,
    /// Path to SSH private key
    #[structopt(short = "i", parse(from_os_str))]
    private_key_path: PathBuf,
    /// Enable verbose output
    #[structopt(short = "v")]
    verbose: bool,
    /// Gerrit user email address
    email: String,
    #[structopt(long = "format-script")]
    format_script: Option<String>,
}

#[derive(Clone)]
struct ConsoleSparkClient;

impl bot::SparkClient for ConsoleSparkClient {
    type ReplyFuture = future::FutureResult<(), spark::Error>;
    fn reply(&self, person_id: &spark::PersonId, msg: &str) -> Self::ReplyFuture {
        // Write synchronously and crash if writing fails. There's no point in
        // error handling here.
        write!(std::io::stdout(), "{}: {}\n", person_id, msg).expect("writing to stdout failed");
        future::ok(())
    }
}

fn main() {
    let args = Args::from_args();
    stderrlog::new()
        .module(module_path!())
        .module("gerritbot")
        .module("gerritbot_gerrit")
        .timestamp(stderrlog::Timestamp::Second)
        .verbosity(if args.verbose { 5 } else { 2 })
        .init()
        .unwrap();

    let connect_to_gerrit = || {
        info!(
            "Connecting to gerrit with username {} at {}:{}",
            args.username, args.hostname, args.port,
        );
        gerrit::Connection::connect(
            format!("{}:{}", args.hostname, args.port),
            args.username.clone(),
            args.private_key_path.clone(),
        )
        .unwrap_or_else(|e| {
            error!("failed to connect to gerrit: {}", e);
            std::process::exit(1);
        })
    };
    let gerrit_event_stream = gerrit::extended_event_stream(
        connect_to_gerrit(),
        connect_to_gerrit(),
        bot::request_extended_gerrit_info,
    );
    let gerrit_command_runner = gerrit::CommandRunner::new(connect_to_gerrit());
    let bot_builder = bot::Builder::new(bot::State::new());
    let bot_builder = {
        if let Some(format_script) = args.format_script {
            bot_builder
                .with_format_script(format_script)
                .unwrap_or_else(|err| {
                    error!("Failed to set format script: {:?}", err);
                    std::process::exit(1);
                })
        } else {
            bot_builder
        }
    };
    let email = args.email.clone();
    let (stdin_lines_sender, stdin_lines) = futures::sync::mpsc::channel::<String>(1);
    std::thread::spawn(move || {
        stream::iter_ok::<_, ()>(
            BufReader::new(std::io::stdin())
                .lines()
                .filter_map(Result::ok),
        )
        .forward(stdin_lines_sender.sink_map_err(|e| error!("sink error: {}", e)))
        .wait()
    });
    let console_spark_messages = stream::once(Ok("enable\n".to_string()))
        .chain(stdin_lines)
        .filter_map(|line| Some(line).filter(|line| !line.is_empty()))
        .map(move |line| {
            spark::Message::test_message(
                spark::Email::new(email.clone()),
                spark::PersonId::new(email.clone()),
                line,
            )
        });

    let bot = bot_builder.build(gerrit_command_runner, ConsoleSparkClient);
    tokio::run(bot.run(gerrit_event_stream, console_spark_messages));
}
<commit_msg>shorten a line<commit_after>// need to raise recursion limit because many combinators
#![recursion_limit = "128"]
#![deny(bare_trait_objects)]

use std::io::{BufRead as _, BufReader, Write as _};
use std::path::PathBuf;

use structopt::StructOpt;

use futures::{future, stream, sync::mpsc::channel, Future as _, Sink as _, Stream as _};
use log::{error, info};

use gerritbot as bot;
use gerritbot_gerrit as gerrit;
use gerritbot_spark as spark;

#[derive(StructOpt, Debug)]
struct Args {
    /// Gerrit username
    #[structopt(short = "u")]
    username: String,
    /// Gerrit hostname
    hostname: String,
    /// Gerrit SSH port
    #[structopt(short = "p", default_value = "29418")]
    port: u32,
    /// Path to SSH private key
    #[structopt(short = "i", parse(from_os_str))]
    private_key_path: PathBuf,
    /// Enable verbose output
    #[structopt(short = "v")]
    verbose: bool,
    /// Gerrit user email address
    email: String,
    #[structopt(long = "format-script")]
    format_script: Option<String>,
}

#[derive(Clone)]
struct ConsoleSparkClient;

impl bot::SparkClient for ConsoleSparkClient {
    type ReplyFuture = future::FutureResult<(), spark::Error>;
    fn reply(&self, person_id: &spark::PersonId, msg: &str) -> Self::ReplyFuture {
        // Write synchronously and crash if writing fails. There's no point in
        // error handling here.
        write!(std::io::stdout(), "{}: {}\n", person_id, msg).expect("writing to stdout failed");
        future::ok(())
    }
}

fn main() {
    let args = Args::from_args();
    stderrlog::new()
        .module(module_path!())
        .module("gerritbot")
        .module("gerritbot_gerrit")
        .timestamp(stderrlog::Timestamp::Second)
        .verbosity(if args.verbose { 5 } else { 2 })
        .init()
        .unwrap();

    let connect_to_gerrit = || {
        info!(
            "Connecting to gerrit with username {} at {}:{}",
            args.username, args.hostname, args.port,
        );
        gerrit::Connection::connect(
            format!("{}:{}", args.hostname, args.port),
            args.username.clone(),
            args.private_key_path.clone(),
        )
        .unwrap_or_else(|e| {
            error!("failed to connect to gerrit: {}", e);
            std::process::exit(1);
        })
    };
    let gerrit_event_stream = gerrit::extended_event_stream(
        connect_to_gerrit(),
        connect_to_gerrit(),
        bot::request_extended_gerrit_info,
    );
    let gerrit_command_runner = gerrit::CommandRunner::new(connect_to_gerrit());
    let bot_builder = bot::Builder::new(bot::State::new());
    let bot_builder = {
        if let Some(format_script) = args.format_script {
            bot_builder
                .with_format_script(format_script)
                .unwrap_or_else(|err| {
                    error!("Failed to set format script: {:?}", err);
                    std::process::exit(1);
                })
        } else {
            bot_builder
        }
    };
    let email = args.email.clone();
    let (stdin_lines_sender, stdin_lines) = channel(1);
    std::thread::spawn(move || {
        stream::iter_ok::<_, ()>(
            BufReader::new(std::io::stdin())
                .lines()
                .filter_map(Result::ok),
        )
        .forward(stdin_lines_sender.sink_map_err(|e| error!("sink error: {}", e)))
        .wait()
    });
    let console_spark_messages = stream::once(Ok("enable\n".to_string()))
        .chain(stdin_lines)
        .filter_map(|line| Some(line).filter(|line| !line.is_empty()))
        .map(move |line| {
            spark::Message::test_message(
                spark::Email::new(email.clone()),
                spark::PersonId::new(email.clone()),
                line,
            )
        });

    let bot = bot_builder.build(gerrit_command_runner, ConsoleSparkClient);
    tokio::run(bot.run(gerrit_event_stream, console_spark_messages));
}
<|endoftext|>


<commit_before>extern crate rand;

use std::convert::From;
use std::default::Default;
use std::iter::{FromIterator, Iterator, repeat};
use std::collections::VecDeque;
use std::collections::vec_deque::{Iter, IterMut};
use self::rand::Rng;

/// a little implementation of a random-wheel.
pub struct RouletteWheel<T> {
    /// the sum of all probabilities in this wheel.
    proba_sum: f32,
    /// all the (probability, data) in a linked-list to pop easily.
    cards: VecDeque<(f32, T)>
}

impl<T: Clone> Clone for RouletteWheel<T> {
    fn clone(&self) -> RouletteWheel<T> {
        RouletteWheel {
            proba_sum: self.proba_sum,
            cards: self.cards.clone()
        }
    }
}

impl<T> Default for RouletteWheel<T> {
    fn default() -> RouletteWheel<T> {
        RouletteWheel {
            proba_sum: 0.0,
            cards: VecDeque::new()
        }
    }
}

impl<'a, T: Clone> From<&'a [T]> for RouletteWheel<T> {
    fn from(s: &'a [T]) -> RouletteWheel<T> {
        RouletteWheel {
            proba_sum: s.len() as f32,
            cards: VecDeque::from_iter(repeat(1.0).zip(s.iter().cloned()))
        }
    }
}

impl<'a, T: Clone> From<&'a [(f32, T)]> for RouletteWheel<T> {
    fn from(s: &'a [(f32, T)]) -> RouletteWheel<T> {
        for &(proba, _) in s {
            assert!(proba >= 0.0, "probability '{}' is lower to zero!", proba);
        }
        let proba_sum = s.iter().fold(0.0, |acc, &(proba, _)| acc + proba);
        assert!(proba_sum > 0.0, "probabilities must not be all zero!");
        RouletteWheel {
            proba_sum: proba_sum,
            cards: VecDeque::from_iter(s.iter().cloned())
        }
    }
}

impl<T> RouletteWheel<T> {
    /// create a new empty random-wheel.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let rw: RouletteWheel<u8> = RouletteWheel::new();
    /// ```
    pub fn new() -> RouletteWheel<T> {
        RouletteWheel {
            proba_sum: 0.0,
            cards: VecDeque::new()
        }
    }

    /// Creates an empty RouletteWheel with space for at least n elements.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let numbers: Vec<_> = (0..20).collect();
    /// let rw: RouletteWheel<u8> = RouletteWheel::with_capacity(numbers.len());
    ///
    /// assert_eq!(rw.len(), 0);
    /// ```
    pub fn with_capacity(n: usize) -> RouletteWheel<T> {
        RouletteWheel {
            proba_sum: 0.0,
            cards: VecDeque::with_capacity(n)
        }
    }

    /// Reserves capacity for at least `additional` more elements to be inserted
    /// in the given `Ringbuf`.
    /// The collection may reserve more space to avoid frequent reallocations.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw: RouletteWheel<u8> = RouletteWheel::new();
    /// rw.reserve(20);
    ///
    /// assert_eq!(rw.len(), 0);
    /// ```
    pub fn reserve(&mut self, additional: usize) {
        self.cards.reserve(additional);
    }

    /// Returns the number of elements the RouletteWheel can hold without
    /// reallocating.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let rw: RouletteWheel<u8> = RouletteWheel::new();
    ///
    /// println!("actual capacity: {}", rw.capacity());
    /// ```
    pub fn capacity(&self) -> usize {
        self.cards.capacity()
    }

    /// returns the number of elements in the wheel.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// assert_eq!(rw.len(), 0);
    ///
    /// rw.push(1.0, 'r');
    /// rw.push(1.0, 'c');
    /// rw.push(1.0, 'a');
    ///
    /// assert_eq!(rw.len(), 3);
    /// ```
    pub fn len(&self) -> usize {
        self.cards.len()
    }

    /// returns `true` if empty else return `false`.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// assert_eq!(rw.is_empty(), true);
    ///
    /// rw.push(1.0, 'r');
    /// rw.push(1.0, 'c');
    /// rw.push(1.0, 'a');
    ///
    /// assert_eq!(rw.is_empty(), false);
    /// ```
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// remove all elements in this wheel.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1.0, 'r');
    /// rw.push(1.0, 'c');
    /// rw.push(1.0, 'a');
    ///
    /// assert_eq!(rw.len(), 3);
    ///
    /// rw.clear();
    ///
    /// assert_eq!(rw.len(), 0);
    /// ```
    pub fn clear(&mut self) {
        self.cards.clear()
    }

    /// add an element associated with a probability.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1.0, 'r');
    /// rw.push(1.0, 'c');
    /// rw.push(1.0, 'a');
    ///
    /// assert_eq!(rw.len(), 3);
    /// ```
    pub fn push(&mut self, proba: f32, data: T) {
        assert!(proba >= 0.0, "proba {} is lower to zero!", proba);
        self.cards.push_back((proba, data));
        self.proba_sum += proba;
        assert!(!self.proba_sum.is_infinite(), "Probability sum reached an Inf value!");
    }

    /// Will recompute the probabilities sum
    /// use it when you iterate through this vector and change proba values
    /// TODO check if proba become Inf too
    pub fn update_proba_sum(&mut self) {
        self.proba_sum = 0.0;
        for &(proba, _) in self.cards.iter() {
            assert!(proba >= 0.0, "probability '{}' is lower to zero!", proba);
            self.proba_sum += proba;
        }
        assert!(!self.proba_sum.is_infinite(), "Probability sum reached an Inf value!");
    }

    /// returns total of luck you pushed.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1.5, 'r');
    /// rw.push(2., 'c');
    /// rw.push(3., 'a');
    ///
    /// assert_eq!(rw.proba_sum(), 6.5);
    /// ```
    pub fn proba_sum(&self) -> f32 {
        self.proba_sum
    }

    /// returns a random distance to browser between 0 and the probabilities sum.
    fn gen_random_dist(&self) -> f32 {
        match self.proba_sum {
            sum if sum > 0. => rand::thread_rng().gen_range(0., sum),
            _ => 0.
        }
    }

    /// returns a random index in self.cards.
    fn get_random_index(&self) -> Option<usize> {
        if self.is_empty() == false {
            let mut dist = self.gen_random_dist();
            for (id, &(ref proba, _)) in self.cards.iter().enumerate() {
                dist -= *proba;
                if dist <= 0. {
                    return Some(id);
                }
            }
            None
        }
        else { None }
    }

    /// returns a ref to the randomly peeked element with
    /// it's probality to be peeked.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1.0, 'r');
    ///
    /// assert_eq!(rw.peek(), Some((1.0, &'r')));
    /// assert_eq!(rw.peek(), Some((1.0, &'r')));
    /// ```
    pub fn peek(&self) -> Option<(f32, &T)> {
        if let Some(index) = self.get_random_index() {
            if let Some(&(proba, ref data)) = self.cards.get(index) {
                Some((proba, data))
            }
            else { None }
        }
        else { None }
    }

    /// returns a mutable ref to the randomly peeked element with
    /// it's probality to be peeked.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1.0, 'r');
    ///
    /// match rw.peek_mut() {
    ///     Some((_, val)) => *val = 'b',
    ///     None => {}
    /// }
    ///
    /// assert_eq!(rw.peek(), Some((1.0, &'b')));
    /// ```
    pub fn peek_mut(&mut self) -> Option<(f32, &mut T)> {
        if let Some(index) = self.get_random_index() {
            if let Some(&mut (proba, ref mut data)) = self.cards.get_mut(index) {
                Some((proba, data))
            }
            else { None }
        }
        else { None }
    }

    /// removes a randomly peeked element and return it with
    /// it's probality to be peeked.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1.0, 'r');
    ///
    /// assert_eq!(rw.pop(), Some((1.0, 'r')));
    ///
    /// // once you pop the value, it doesn't exist anymore
    /// assert_eq!(rw.peek(), None);
    /// assert_eq!(rw.pop(), None);
    /// ```
    pub fn pop(&mut self) -> Option<(f32, T)> {
        if let Some(index) = self.get_random_index() {
            if let Some((proba, data)) = self.cards.remove(index) {
                self.proba_sum -= proba;
                Some((proba, data))
            }
            else { None }
        }
        else { None }
    }

    /// Returns an iterator over the slice, giving &(proba, elem).
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1.0, 'r');
    /// rw.push(1.0, 'c');
    /// rw.push(1.0, 'a');
    ///
    /// let mut iter = rw.iter();
    ///
    /// assert_eq!(iter.next(), Some(&(1.0, 'r')));
    /// assert_eq!(iter.next(), Some(&(1.0, 'c')));
    /// assert_eq!(iter.next(), Some(&(1.0, 'a')));
    /// assert_eq!(iter.next(), None);
    /// ```
    pub fn iter(&self) -> Iter<(f32, T)> {
        self.cards.iter()
    }

    /// Returns a mutable iterator over the slice, giving &mut (proba, elem).
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1.0, 'r');
    /// rw.push(1.0, 'c');
    /// rw.push(1.0, 'a');
    ///
    /// let mut iter = rw.iter();
    ///
    /// assert_eq!(iter.next(), Some(&(1.0, 'r')));
    /// assert_eq!(iter.next(), Some(&(1.0, 'c')));
    /// assert_eq!(iter.next(), Some(&(1.0, 'a')));
    /// assert_eq!(iter.next(), None);
    /// ```
    pub fn iter_mut(&mut self) -> IterMut<(f32, T)> {
        self.cards.iter_mut()
    }
}
<commit_msg>rework: Add first draft of the rework plan<commit_after>extern crate rand;

use std::iter::{FromIterator, Iterator, repeat};
use std::collections::VecDeque;
use std::collections::vec_deque::{Iter, IterMut};
use self::rand::Rng;

/// A roulette-wheel container
pub struct RouletteWheel<T> {
    total_fitness: f32,
    fitnesses: Vec<f32>,
    population: Vec<T>
}

impl<T: Clone> Clone for RouletteWheel<T> {
    fn clone(&self) -> RouletteWheel<T> {
        RouletteWheel {
            total_fitness: self.total_fitness,
            fitnesses: self.fitnesses.clone(),
            population: self.population.clone()
        }
    }
}

impl<T> FromIterator<(f32, T)> for RouletteWheel<T> {
    fn from_iter<A>(iter: A) -> Self where A: IntoIterator<Item=(f32, T)> {
        let iter = iter.into_iter();
        let cap = iter.size_hint().1.unwrap_or(0);
        let mut total_fitness = 0.0;
        let mut fitnesses = Vec::with_capacity(cap);
        let mut population = Vec::with_capacity(cap);

        for (fitness, individual) in iter {
            total_fitness += fitness;
            fitnesses.push(fitness);
            population.push(individual);
        }

        RouletteWheel {
            total_fitness: total_fitness,
            fitnesses: fitnesses,
            population: population
        }

        // #![feature(field_init_shorthand)]
        // RouletteWheel { total_fitness, fitnesses, population }
    }
}

impl<T> RouletteWheel<T> {
    /// create a new empty random-wheel.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let rw: RouletteWheel<u8> = RouletteWheel::new();
    /// ```
    pub fn new() -> RouletteWheel<T> {
        RouletteWheel {
            total_fitness: 0.0,
            fitnesses: Vec::new(),
            population: Vec::new()
        }
    }

    /// Creates an empty RouletteWheel with space for at least n elements.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let numbers: Vec<_> = (0..20).collect();
    /// let rw: RouletteWheel<u8> = RouletteWheel::with_capacity(numbers.len());
    ///
    /// assert_eq!(rw.len(), 0);
    /// ```
    pub fn with_capacity(cap: usize) -> RouletteWheel<T> {
        RouletteWheel {
            total_fitness: 0.0,
            fitnesses: Vec::with_capacity(cap),
            population: Vec::with_capacity(cap)
        }
    }

    /// Reserves capacity for at least `additional` more elements to be inserted
    /// in the given `Ringbuf`.
    /// The collection may reserve more space to avoid frequent reallocations.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw: RouletteWheel<u8> = RouletteWheel::new();
    /// rw.reserve(20);
    ///
    /// assert_eq!(rw.len(), 0);
    /// ```
    pub fn reserve(&mut self, additional: usize) {
        self.fitnesses.reserve(additional);
        self.population.reserve(additional);
    }

    // /// Returns the number of elements the RouletteWheel can hold without
    // /// reallocating.
    // /// # Example
    // ///
    // /// ```
    // /// use roulette_wheel::RouletteWheel;
    // ///
    // /// let rw: RouletteWheel<u8> = RouletteWheel::new();
    // ///
    // /// println!("actual capacity: {}", rw.capacity());
    // /// ```
    // pub fn capacity(&self) -> usize {
    //     self.population.capacity()
    // }

    /// returns the number of elements in the wheel.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// assert_eq!(rw.len(), 0);
    ///
    /// rw.push(1.0, 'r');
    /// rw.push(1.0, 'c');
    /// rw.push(1.0, 'a');
    ///
    /// assert_eq!(rw.len(), 3);
    /// ```
    pub fn len(&self) -> usize {
        self.population.len()
    }

    /// returns `true` if empty else return `false`.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// assert_eq!(rw.is_empty(), true);
    ///
    /// rw.push(1.0, 'r');
    /// rw.push(1.0, 'c');
    /// rw.push(1.0, 'a');
    ///
    /// assert_eq!(rw.is_empty(), false);
    /// ```
    pub fn is_empty(&self) -> bool {
        self.population.is_empty()
    }

    /// remove all elements in this wheel.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1.0, 'r');
    /// rw.push(1.0, 'c');
    /// rw.push(1.0, 'a');
    ///
    /// assert_eq!(rw.len(), 3);
    ///
    /// rw.clear();
    ///
    /// assert_eq!(rw.len(), 0);
    /// ```
    pub fn clear(&mut self) {
        self.fitnesses.clear();
        self.population.clear();
    }

    /// add an element associated with a probability.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1.0, 'r');
    /// rw.push(1.0, 'c');
    /// rw.push(1.0, 'a');
    ///
    /// assert_eq!(rw.len(), 3);
    /// ```
    pub fn push(&mut self, fitness: f32, individual: T) {
        assert!(fitness.is_finite(), "Can't push non-finite fitness {:?}", fitness);
        assert!(fitness >= 0.0, "Can't push negative fitness {:?}", fitness);

        self.fitnesses.push(fitness);
        self.population.push(individual);
        self.total_fitness += fitness;

        assert!(self.total_fitness.is_finite(), "Fitnesses sum reached a non-finite state!");
    }

    /// Returns sum of all individual fitnesses.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(3.0, 'r');
    /// rw.push(2.0, 'c');
    /// rw.push(1.5, 'a');
    ///
    /// assert_eq!(rw.total_fitness(), 6.5);
    /// ```
    pub fn total_fitness(&self) -> f32 {
        self.total_fitness
    }

    // pub fn select_one_iter(&self) -> SelectOneIter<T> {
    //     SelectOneIter { aaa: self.population[0] }
    // }
}

pub struct SelectOneIter<T> {
    aaa: T
}

impl<T> Iterator for SelectOneIter<T> {
    type Item = (f32, T);

    fn next(&mut self) -> Option<Self::Item> {
        None
    }
}
<|endoftext|>


<commit_before>// Traits can have associated types:

// I thought that associated types could be used to encode existential
// types, as attempted below.  The trait T has associated type t.  I
// define two implementations for this trait, with different
// definitions of t.  Then, I try to create a packed up pair where the
// first and second components of the pair look "the same" (both just
// mention trait T, and each leaves t abstract, via an (implicit)
// existential quantifier.

// Apparently, this is not allowed:

// examples/assoctypes.rs:24:16: 24:17 error: the value of the associated type `t` (from the trait `T`) must be specified [E0191]
//    examples/assoctypes.rs:24     two : (Box<T>,Box<T>)
//
// examples/assoctypes.rs:24:23: 24:24 error: the value of the associated type `t` (from the trait `T`) must be specified [E0191]
//    examples/assoctypes.rs:24     two : (Box<T>,Box<T>)

trait T {
    type t;
    fn get (self:&Self) -> Self::t ;
    fn foo ( Self::t ) -> String ;
}

pub enum Foo { Foo }
pub enum Bar { Bar }

impl T for Foo {
    type t = String;
    fn get (self) { "foo" }
    fn foo (s:Self::t) { s }
}

impl T for Bar {
    type t = u32;
    fn get (self) { 0 }
    fn foo (s:Self::t) { "bar" }
}

struct Packed {
    two : (Box<T>,Box<T>)
}

pub fn main () {
    let a = Packed { two : (Box::new(Foo::Foo),
                            Box::new(Bar::Bar)) } ;
    ()
}
<commit_msg>associated types example compiles<commit_after>// Traits can have associated types:
#![feature(collections)]

use std::fmt::Debug;
//use std::string;

// I thought that associated types could be used to encode existential
// types, as attempted below.  The trait T has associated type t.  I
// define two implementations for this trait, with different
// definitions of t.  Then, I try to create a packed up pair where the
// first and second components of the pair look "the same" (both just
// mention trait T, and each leaves t abstract, via an (implicit)
// existential quantifier.

// Apparently, this is not allowed:

// examples/assoctypes.rs:24:16: 24:17 error: the value of the associated type `t` (from the trait `T`) must be specified [E0191]
//    examples/assoctypes.rs:24     two : (Box<T>,Box<T>)
//
// examples/assoctypes.rs:24:23: 24:24 error: the value of the associated type `t` (from the trait `T`) must be specified [E0191]
//    examples/assoctypes.rs:24     two : (Box<T>,Box<T>)

trait T : Debug {
    type t;
    fn get (self:&Self) -> Self::t ;
    fn foo (self:&Self, Self::t ) -> String ;
}

#[derive(Debug)]
pub enum Foo { Foo }

#[derive(Debug)]
pub enum Bar { Bar }

impl T for Foo {
    type t = String;
    fn get (self:&Self) -> String { String::from_str("foo") }
    fn foo (self:&Self, s:Self::t) -> String { s }
}

impl T for Bar {
    type t = u32;
    fn get (self:&Self) -> u32 { 0 }
    fn foo (self:&Self, _s:Self::t) -> String { String::from_str("bar") }
}

#[derive(Debug)]
struct Packed {
    two : (Box<T<t=String>>,Box<T<t=u32>>)
}

pub fn main () {
    let a = Packed { two : (Box::new(Foo::Foo),
                            Box::new(Bar::Bar)) } ;
     println!("{:?}", a);
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate mio;
extern crate term_input;
extern crate termbox_simple;
extern crate time;
extern crate tiny;

use mio::Events;
use mio::Poll;
use mio::PollOpt;
use mio::Ready;
use mio::Token;
use mio::unix::EventedFd;
use std::fs::File;
use std::io::Read;

use term_input::{Input, Event};
use tiny::config::Colors;
use tiny::tui::{TUI, TUIRet, MsgTarget, Timestamp};

fn main() {
    let mut tui = TUI::new(Colors::default());
    tui.new_server_tab("debug");
    let debug_tab = MsgTarget::Server { serv_name: "debug" };

    tui.add_msg("Loading word list for auto-completion ...",
                Timestamp::now(),
                &debug_tab);
    tui.draw();

    {
        let mut contents = String::new();
        let mut file = File::open("/usr/share/dict/american").unwrap();
        file.read_to_string(&mut contents).unwrap();
        for word in contents.lines() {
            tui.add_nick(word, None, &debug_tab);
        }
    }

    tui.add_msg("Done.", Timestamp::now(), &debug_tab);
    tui.draw();

    let poll = Poll::new().unwrap();
    poll.register(
        &EventedFd(&libc::STDIN_FILENO),
        Token(libc::STDIN_FILENO as usize),
        Ready::readable(),
        PollOpt::level()).unwrap();

    let mut input = Input::new();
    let mut ev_buffer: Vec<Event> = Vec::new();
    let mut events = Events::with_capacity(10);
    'mainloop:
    loop {
        match poll.poll(&mut events, None) {
            Err(_) => {
                tui.resize();
                tui.draw();
            }
            Ok(_) => {
                input.read_input_events(&mut ev_buffer);
                for ev in ev_buffer.drain(0..) {
                    match tui.handle_input_event(ev) {
                        TUIRet::Input { msg, .. } => {
                            tui.add_msg(&msg.into_iter().collect::<String>(),
                            Timestamp::now(),
                            &debug_tab);
                        },
                        TUIRet::Abort => {
                            break 'mainloop;
                        },
                        _ => {}
                    }
                }
                tui.draw();
            }
        }
    }
}
<commit_msg>completion example: fix dict path, remove unused dep<commit_after>extern crate libc;
extern crate mio;
extern crate term_input;
extern crate termbox_simple;
extern crate tiny;

use mio::Events;
use mio::Poll;
use mio::PollOpt;
use mio::Ready;
use mio::Token;
use mio::unix::EventedFd;
use std::fs::File;
use std::io::Read;

use term_input::{Input, Event};
use tiny::config::Colors;
use tiny::tui::{TUI, TUIRet, MsgTarget, Timestamp};

fn main() {
    let mut tui = TUI::new(Colors::default());
    tui.new_server_tab("debug");
    let debug_tab = MsgTarget::Server { serv_name: "debug" };

    tui.add_msg("Loading word list for auto-completion ...",
                Timestamp::now(),
                &debug_tab);
    tui.draw();

    {
        let mut contents = String::new();
        let mut file = File::open("/usr/share/dict/american-english").unwrap();
        file.read_to_string(&mut contents).unwrap();
        for word in contents.lines() {
            tui.add_nick(word, None, &debug_tab);
        }
    }

    tui.add_msg("Done.", Timestamp::now(), &debug_tab);
    tui.draw();

    let poll = Poll::new().unwrap();
    poll.register(
        &EventedFd(&libc::STDIN_FILENO),
        Token(libc::STDIN_FILENO as usize),
        Ready::readable(),
        PollOpt::level()).unwrap();

    let mut input = Input::new();
    let mut ev_buffer: Vec<Event> = Vec::new();
    let mut events = Events::with_capacity(10);
    'mainloop:
    loop {
        match poll.poll(&mut events, None) {
            Err(_) => {
                tui.resize();
                tui.draw();
            }
            Ok(_) => {
                input.read_input_events(&mut ev_buffer);
                for ev in ev_buffer.drain(0..) {
                    match tui.handle_input_event(ev) {
                        TUIRet::Input { msg, .. } => {
                            tui.add_msg(&msg.into_iter().collect::<String>(),
                            Timestamp::now(),
                            &debug_tab);
                        },
                        TUIRet::Abort => {
                            break 'mainloop;
                        },
                        _ => {}
                    }
                }
                tui.draw();
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Look and print the credentials specified on the command line.

extern crate credentials;
extern crate env_logger;

use std::env;
use std::io::{self, Write};
use std::process;

fn main() {
    // Enable logging.  To see what's happening, set `RUST_LOG=trace`.
    env_logger::init().unwrap();

    // Print our each credential specified on the command line.
    for secret in env::args().skip(1) {
        match credentials::get(&secret) {
            Ok(ref value) => println!("{}={}", &secret, value),
            Err(err) => {
                writeln!(&mut io::stderr(), "Error: {}", err).unwrap();
                process::exit(1);
            }
        }
    }
}
<commit_msg>Recommend activating logging in programs using credentials<commit_after>//! Look and print the credentials specified on the command line.

extern crate credentials;
extern crate env_logger;

use std::env;
use std::io::{self, Write};
use std::process;

fn main() {
    // Enable logging.  To see what's happening, set `RUST_LOG=trace`.  It
    // is recommended that you include and initialie `env_logger` in your
    // programs using credentials.
    env_logger::init().unwrap();

    // Print our each credential specified on the command line.
    for secret in env::args().skip(1) {
        match credentials::get(&secret) {
            Ok(ref value) => println!("{}={}", &secret, value),
            Err(err) => {
                writeln!(&mut io::stderr(), "Error: {}", err).unwrap();
                process::exit(1);
            }
        }
    }
}
<|endoftext|>


<commit_before>use collections::string::String;
use collections::btree_map::BTreeMap;
use collections::vec::Vec;

use spin::RwLockWriteGuard;

use super::namespace::{ AmlValue, ObjectReference };
use super::AmlError;

use acpi::ACPI_TABLE;

pub type ParseResult = Result<AmlParseType, AmlError>;
pub type AmlParseType = AmlParseTypeGeneric<AmlValue>;

pub struct AmlParseTypeGeneric<T> {
    pub val: T,
    pub len: usize
}

pub enum ExecutionState {
    EXECUTING,
    CONTINUE,
    BREAK,
    RETURN(AmlValue)
}

pub struct AmlExecutionContext {
    pub scope: String,
    pub local_vars: [AmlValue; 8],
    pub arg_vars: [AmlValue; 8],
    pub state: ExecutionState,
    pub namespace_delta: Vec<String>,
    pub ctx_id: u64,
    pub sync_level: u8
}

impl AmlExecutionContext {
    pub fn new(scope: String) -> AmlExecutionContext {
        let mut idptr = ACPI_TABLE.next_ctx.write();
        let id: u64 = *idptr;

        *idptr += 1;

        AmlExecutionContext {
            scope: scope,
            local_vars: [AmlValue::Uninitialized,
                         AmlValue::Uninitialized,
                         AmlValue::Uninitialized,
                         AmlValue::Uninitialized,
                         AmlValue::Uninitialized,
                         AmlValue::Uninitialized,
                         AmlValue::Uninitialized,
                         AmlValue::Uninitialized],
            arg_vars: [AmlValue::Uninitialized,
                       AmlValue::Uninitialized,
                       AmlValue::Uninitialized,
                       AmlValue::Uninitialized,
                       AmlValue::Uninitialized,
                       AmlValue::Uninitialized,
                       AmlValue::Uninitialized,
                       AmlValue::Uninitialized],
            state: ExecutionState::EXECUTING,
            namespace_delta: vec!(),
            ctx_id: id,
            sync_level: 0
        }
    }

    pub fn wait_for_event(&mut self, event_ptr: AmlValue) -> Result<bool, AmlError> {
        let mut namespace_ptr = self.prelock();
        let mut namespace = match *namespace_ptr {
            Some(ref mut n) => n,
            None => return Err(AmlError::AmlHardFatal)
        };

        let mutex_idx = match event_ptr {
            AmlValue::String(ref s) => s.clone(),
            AmlValue::ObjectReference(ref o) => match *o {
                ObjectReference::Object(ref s) => s.clone(),
                _ => return Err(AmlError::AmlValueError)
            },
            _ => return Err(AmlError::AmlValueError)
        };

        let mutex = match namespace.get(&mutex_idx) {
            Some(s) => s.clone(),
            None => return Err(AmlError::AmlValueError)
        };

        match mutex {
            AmlValue::Event(count) => {
                if count > 0 {
                    namespace.insert(mutex_idx, AmlValue::Event(count - 1));
                    return Ok(true);
                }
            },
            _ => return Err(AmlError::AmlValueError)
        }

        Ok(false)
    }

    pub fn signal_event(&mut self, event_ptr: AmlValue) -> Result<(), AmlError> {
        let mut namespace_ptr = self.prelock();
        let mut namespace = match *namespace_ptr {
            Some(ref mut n) => n,
            None => return Err(AmlError::AmlHardFatal)
        };

        let mutex_idx = match event_ptr {
            AmlValue::String(ref s) => s.clone(),
            AmlValue::ObjectReference(ref o) => match *o {
                ObjectReference::Object(ref s) => s.clone(),
                _ => return Err(AmlError::AmlValueError)
            },
            _ => return Err(AmlError::AmlValueError)
        };

        let mutex = match namespace.get(&mutex_idx) {
            Some(s) => s.clone(),
            None => return Err(AmlError::AmlValueError)
        };

        match mutex {
            AmlValue::Event(count) => {
                namespace.insert(mutex_idx, AmlValue::Event(count + 1));
                return Ok(());
            },
            _ => return Err(AmlError::AmlValueError)
        }

        Ok(())
    }

    pub fn release_mutex(&mut self, mutex_ptr: AmlValue) -> Result<(), AmlError> {
        let id = self.ctx_id;

        let mut namespace_ptr = self.prelock();
        let mut namespace = match *namespace_ptr {
            Some(ref mut n) => n,
            None => return Err(AmlError::AmlHardFatal)
        };

        let mutex_idx = match mutex_ptr {
            AmlValue::String(ref s) => s.clone(),
            AmlValue::ObjectReference(ref o) => match *o {
                ObjectReference::Object(ref s) => s.clone(),
                _ => return Err(AmlError::AmlValueError)
            },
            _ => return Err(AmlError::AmlValueError)
        };

        let mutex = match namespace.get(&mutex_idx) {
            Some(s) => s.clone(),
            None => return Err(AmlError::AmlValueError)
        };

        match mutex {
            AmlValue::Mutex((sync_level, owner)) => {
                if let Some(o) = owner {
                    if o == id {
                        if sync_level == self.sync_level {
                            namespace.insert(mutex_idx, AmlValue::Mutex((sync_level, None)));
                            return Ok(());
                        } else {
                            return Err(AmlError::AmlValueError);
                        }
                    } else {
                        return Err(AmlError::AmlHardFatal);
                    }
                }
            },
            AmlValue::OperationRegion(ref region) => {
                if let Some(o) = region.accessed_by {
                    if o == id {
                        let mut new_region = region.clone();
                        new_region.accessed_by = None;

                        namespace.insert(mutex_idx, AmlValue::OperationRegion(new_region));
                        return Ok(());
                    } else {
                        return Err(AmlError::AmlHardFatal);
                    }
                }
            },
            _ => return Err(AmlError::AmlValueError)
        }

        Ok(())
    }

    pub fn acquire_mutex(&mut self, mutex_ptr: AmlValue) -> Result<bool, AmlError> {
        let id = self.ctx_id;

        let mut namespace_ptr = self.prelock();
        let mut namespace = match *namespace_ptr {
            Some(ref mut n) => n,
            None => return Err(AmlError::AmlHardFatal)
        };
        let mutex_idx = match mutex_ptr {
            AmlValue::String(ref s) => s.clone(),
            AmlValue::ObjectReference(ref o) => match *o {
                ObjectReference::Object(ref s) => s.clone(),
                _ => return Err(AmlError::AmlValueError)
            },
            _ => return Err(AmlError::AmlValueError)
        };

        let mutex = match namespace.get(&mutex_idx) {
            Some(s) => s.clone(),
            None => return Err(AmlError::AmlValueError)
        };

        match mutex {
            AmlValue::Mutex((sync_level, owner)) => {
                if owner == None {
                    if sync_level < self.sync_level {
                        return Err(AmlError::AmlValueError);
                    }

                    namespace.insert(mutex_idx, AmlValue::Mutex((sync_level, Some(id))));
                    self.sync_level = sync_level;

                    return Ok(true);
                }
            },
            AmlValue::OperationRegion(ref o) => {
                if o.accessed_by == None {
                    let mut new_region = o.clone();
                    new_region.accessed_by = Some(id);

                    namespace.insert(mutex_idx, AmlValue::OperationRegion(new_region));
                    return Ok(true);
                }
            },
            _ => return Err(AmlError::AmlValueError)
        }

        Ok(false)
    }

    pub fn add_to_namespace(&mut self, name: String, value: AmlValue) -> Result<(), AmlError> {
        let mut namespace = ACPI_TABLE.namespace.write();

        if let Some(ref mut namespace) = *namespace {
            if namespace.contains_key(&name) {
                return Err(AmlError::AmlValueError);
            }

            self.namespace_delta.push(name.clone());
            namespace.insert(name, value);

            Ok(())
        } else {
            Err(AmlError::AmlValueError)
        }
    }

    pub fn clean_namespace(&mut self) {
        let mut namespace = ACPI_TABLE.namespace.write();

        if let Some(ref mut namespace) = *namespace {
            for k in &self.namespace_delta {
                namespace.remove(k);
            }
        }
    }

    pub fn init_arg_vars(&mut self, parameters: Vec<AmlValue>) {
        if parameters.len() > 8 {
            return;
        }

        let mut cur = 0;
        while cur < parameters.len() {
            self.arg_vars[cur] = parameters[cur].clone();
            cur += 1;
        }
    }

    pub fn prelock(&mut self) -> RwLockWriteGuard<'static, Option<BTreeMap<String, AmlValue>>> {
        ACPI_TABLE.namespace.write()
    }

    fn modify_local_obj(&mut self, local: usize, value: AmlValue) -> Result<(), AmlError> {
        self.local_vars[local] = value;
        Ok(())
    }

    fn modify_object(&mut self, name: String, value: AmlValue) -> Result<(), AmlError> {
        if let Some(ref mut namespace) = *ACPI_TABLE.namespace.write() {
            namespace.insert(name, value);
            Ok(())
        } else {
            Err(AmlError::AmlHardFatal)
        }
    }

    fn modify_index_final(&mut self, name: String, value: AmlValue, indices: Vec<u64>) -> Result<(), AmlError> {
        if let Some(ref mut namespace) = *ACPI_TABLE.namespace.write() {
            let mut obj = if let Some(s) = namespace.get(&name) {
                s.clone()
            } else {
                return Err(AmlError::AmlValueError);
            };

            obj = self.modify_index_core(obj, value, indices)?;

            namespace.insert(name, obj);
            Ok(())
        } else {
            Err(AmlError::AmlValueError)
        }
    }

    fn modify_index_core(&self, obj: AmlValue, value: AmlValue, indices: Vec<u64>) -> Result<AmlValue, AmlError> {
        match obj {
            AmlValue::String(ref string) => {
                if indices.len() != 1 {
                    return Err(AmlError::AmlValueError);
                }

                let mut bytes = string.clone().into_bytes();
                bytes[indices[0] as usize] = value.get_as_integer()? as u8;

                let string = String::from_utf8(bytes).unwrap();

                Ok(AmlValue::String(string))
            },
            AmlValue::Buffer(ref b) => {
                if indices.len() != 1 {
                    return Err(AmlError::AmlValueError);
                }

                let mut b = b.clone();
                b[indices[0] as usize] = value.get_as_integer()? as u8;

                Ok(AmlValue::Buffer(b))
            },
            AmlValue::Package(ref p) => {
                if indices.len() < 0 {
                    return Err(AmlError::AmlValueError);
                }

                let mut p = p.clone();

                if indices.len() == 1 {
                    p[indices[0] as usize] = value;
                } else {
                    p[indices[0] as usize] = self.modify_index_core(p[indices[0] as usize].clone(), value, indices[1..].to_vec())?;
                }

                Ok(AmlValue::Package(p))
            },
            _ => return Err(AmlError::AmlValueError)
        }
    }

    pub fn modify_index(&mut self, name: AmlValue, value: AmlValue, indices: Vec<u64>) -> Result<(), AmlError>{
        match name {
            AmlValue::ObjectReference(r) => match r {
                ObjectReference::Object(s) => self.modify_index_final(s, value, indices),
                ObjectReference::Index(c, v) => {
                    let mut indices = indices.clone();
                    indices.push(v.get_as_integer()?);

                    self.modify_index(*c, value, indices)
                },
                _ => Err(AmlError::AmlValueError)
            },
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn modify(&mut self, name: AmlValue, value: AmlValue) -> Result<(), AmlError> {
        match name {
            AmlValue::ObjectReference(r) => match r {
                ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError),
                ObjectReference::LocalObj(i) => self.modify_local_obj(i as usize, value),
                ObjectReference::Object(s) => self.modify_object(s, value),
                ObjectReference::Index(c, v) => self.modify_index(*c, value, vec!(v.get_as_integer()?))
            },
            AmlValue::String(s) => self.modify_object(s, value),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get(&self, name: AmlValue) -> Result<AmlValue, AmlError> {
        Ok(match name {
            AmlValue::ObjectReference(r) => match r {
                ObjectReference::ArgObj(i) => self.arg_vars[i as usize].clone(),
                ObjectReference::LocalObj(i) => self.local_vars[i as usize].clone(),
                ObjectReference::Object(ref s) => if let Some(ref namespace) = *ACPI_TABLE.namespace.read() {
                    if let Some(o) = namespace.get(s) {
                        o.clone()
                    } else {
                        AmlValue::None
                    }
                } else { AmlValue::None },
                ObjectReference::Index(c, v) => if let Some(ref mut namespace) = *ACPI_TABLE.namespace.write() {
                    let idx = v.get_as_integer()? as usize;
                    match *c {
                        AmlValue::Package(p) => p[idx].clone(),
                        _ => AmlValue::None
                    }
                } else {
                    AmlValue::None
                }
            },
            AmlValue::String(ref s) => if let Some(ref namespace) = *ACPI_TABLE.namespace.read() {
                if let Some(o) = namespace.get(s) {
                    o.clone()
                } else {
                    AmlValue::None
                }
            } else { AmlValue::None },
            _ => AmlValue::None
        })
    }
}
<commit_msg>Implemented buffer field index modify<commit_after>use collections::string::String;
use collections::btree_map::BTreeMap;
use collections::vec::Vec;
use alloc::boxed::Box;

use spin::RwLockWriteGuard;

use super::namespace::{ AmlValue, ObjectReference };
use super::AmlError;

use acpi::ACPI_TABLE;

pub type ParseResult = Result<AmlParseType, AmlError>;
pub type AmlParseType = AmlParseTypeGeneric<AmlValue>;

pub struct AmlParseTypeGeneric<T> {
    pub val: T,
    pub len: usize
}

pub enum ExecutionState {
    EXECUTING,
    CONTINUE,
    BREAK,
    RETURN(AmlValue)
}

pub struct AmlExecutionContext {
    pub scope: String,
    pub local_vars: [AmlValue; 8],
    pub arg_vars: [AmlValue; 8],
    pub state: ExecutionState,
    pub namespace_delta: Vec<String>,
    pub ctx_id: u64,
    pub sync_level: u8
}

impl AmlExecutionContext {
    pub fn new(scope: String) -> AmlExecutionContext {
        let mut idptr = ACPI_TABLE.next_ctx.write();
        let id: u64 = *idptr;

        *idptr += 1;

        AmlExecutionContext {
            scope: scope,
            local_vars: [AmlValue::Uninitialized,
                         AmlValue::Uninitialized,
                         AmlValue::Uninitialized,
                         AmlValue::Uninitialized,
                         AmlValue::Uninitialized,
                         AmlValue::Uninitialized,
                         AmlValue::Uninitialized,
                         AmlValue::Uninitialized],
            arg_vars: [AmlValue::Uninitialized,
                       AmlValue::Uninitialized,
                       AmlValue::Uninitialized,
                       AmlValue::Uninitialized,
                       AmlValue::Uninitialized,
                       AmlValue::Uninitialized,
                       AmlValue::Uninitialized,
                       AmlValue::Uninitialized],
            state: ExecutionState::EXECUTING,
            namespace_delta: vec!(),
            ctx_id: id,
            sync_level: 0
        }
    }

    pub fn wait_for_event(&mut self, event_ptr: AmlValue) -> Result<bool, AmlError> {
        let mut namespace_ptr = self.prelock();
        let mut namespace = match *namespace_ptr {
            Some(ref mut n) => n,
            None => return Err(AmlError::AmlHardFatal)
        };

        let mutex_idx = match event_ptr {
            AmlValue::String(ref s) => s.clone(),
            AmlValue::ObjectReference(ref o) => match *o {
                ObjectReference::Object(ref s) => s.clone(),
                _ => return Err(AmlError::AmlValueError)
            },
            _ => return Err(AmlError::AmlValueError)
        };

        let mutex = match namespace.get(&mutex_idx) {
            Some(s) => s.clone(),
            None => return Err(AmlError::AmlValueError)
        };

        match mutex {
            AmlValue::Event(count) => {
                if count > 0 {
                    namespace.insert(mutex_idx, AmlValue::Event(count - 1));
                    return Ok(true);
                }
            },
            _ => return Err(AmlError::AmlValueError)
        }

        Ok(false)
    }

    pub fn signal_event(&mut self, event_ptr: AmlValue) -> Result<(), AmlError> {
        let mut namespace_ptr = self.prelock();
        let mut namespace = match *namespace_ptr {
            Some(ref mut n) => n,
            None => return Err(AmlError::AmlHardFatal)
        };

        let mutex_idx = match event_ptr {
            AmlValue::String(ref s) => s.clone(),
            AmlValue::ObjectReference(ref o) => match *o {
                ObjectReference::Object(ref s) => s.clone(),
                _ => return Err(AmlError::AmlValueError)
            },
            _ => return Err(AmlError::AmlValueError)
        };

        let mutex = match namespace.get(&mutex_idx) {
            Some(s) => s.clone(),
            None => return Err(AmlError::AmlValueError)
        };

        match mutex {
            AmlValue::Event(count) => {
                namespace.insert(mutex_idx, AmlValue::Event(count + 1));
                return Ok(());
            },
            _ => return Err(AmlError::AmlValueError)
        }

        Ok(())
    }

    pub fn release_mutex(&mut self, mutex_ptr: AmlValue) -> Result<(), AmlError> {
        let id = self.ctx_id;

        let mut namespace_ptr = self.prelock();
        let mut namespace = match *namespace_ptr {
            Some(ref mut n) => n,
            None => return Err(AmlError::AmlHardFatal)
        };

        let mutex_idx = match mutex_ptr {
            AmlValue::String(ref s) => s.clone(),
            AmlValue::ObjectReference(ref o) => match *o {
                ObjectReference::Object(ref s) => s.clone(),
                _ => return Err(AmlError::AmlValueError)
            },
            _ => return Err(AmlError::AmlValueError)
        };

        let mutex = match namespace.get(&mutex_idx) {
            Some(s) => s.clone(),
            None => return Err(AmlError::AmlValueError)
        };

        match mutex {
            AmlValue::Mutex((sync_level, owner)) => {
                if let Some(o) = owner {
                    if o == id {
                        if sync_level == self.sync_level {
                            namespace.insert(mutex_idx, AmlValue::Mutex((sync_level, None)));
                            return Ok(());
                        } else {
                            return Err(AmlError::AmlValueError);
                        }
                    } else {
                        return Err(AmlError::AmlHardFatal);
                    }
                }
            },
            AmlValue::OperationRegion(ref region) => {
                if let Some(o) = region.accessed_by {
                    if o == id {
                        let mut new_region = region.clone();
                        new_region.accessed_by = None;

                        namespace.insert(mutex_idx, AmlValue::OperationRegion(new_region));
                        return Ok(());
                    } else {
                        return Err(AmlError::AmlHardFatal);
                    }
                }
            },
            _ => return Err(AmlError::AmlValueError)
        }

        Ok(())
    }

    pub fn acquire_mutex(&mut self, mutex_ptr: AmlValue) -> Result<bool, AmlError> {
        let id = self.ctx_id;

        let mut namespace_ptr = self.prelock();
        let mut namespace = match *namespace_ptr {
            Some(ref mut n) => n,
            None => return Err(AmlError::AmlHardFatal)
        };
        let mutex_idx = match mutex_ptr {
            AmlValue::String(ref s) => s.clone(),
            AmlValue::ObjectReference(ref o) => match *o {
                ObjectReference::Object(ref s) => s.clone(),
                _ => return Err(AmlError::AmlValueError)
            },
            _ => return Err(AmlError::AmlValueError)
        };

        let mutex = match namespace.get(&mutex_idx) {
            Some(s) => s.clone(),
            None => return Err(AmlError::AmlValueError)
        };

        match mutex {
            AmlValue::Mutex((sync_level, owner)) => {
                if owner == None {
                    if sync_level < self.sync_level {
                        return Err(AmlError::AmlValueError);
                    }

                    namespace.insert(mutex_idx, AmlValue::Mutex((sync_level, Some(id))));
                    self.sync_level = sync_level;

                    return Ok(true);
                }
            },
            AmlValue::OperationRegion(ref o) => {
                if o.accessed_by == None {
                    let mut new_region = o.clone();
                    new_region.accessed_by = Some(id);

                    namespace.insert(mutex_idx, AmlValue::OperationRegion(new_region));
                    return Ok(true);
                }
            },
            _ => return Err(AmlError::AmlValueError)
        }

        Ok(false)
    }

    pub fn add_to_namespace(&mut self, name: String, value: AmlValue) -> Result<(), AmlError> {
        let mut namespace = ACPI_TABLE.namespace.write();

        if let Some(ref mut namespace) = *namespace {
            if namespace.contains_key(&name) {
                return Err(AmlError::AmlValueError);
            }

            self.namespace_delta.push(name.clone());
            namespace.insert(name, value);

            Ok(())
        } else {
            Err(AmlError::AmlValueError)
        }
    }

    pub fn clean_namespace(&mut self) {
        let mut namespace = ACPI_TABLE.namespace.write();

        if let Some(ref mut namespace) = *namespace {
            for k in &self.namespace_delta {
                namespace.remove(k);
            }
        }
    }

    pub fn init_arg_vars(&mut self, parameters: Vec<AmlValue>) {
        if parameters.len() > 8 {
            return;
        }

        let mut cur = 0;
        while cur < parameters.len() {
            self.arg_vars[cur] = parameters[cur].clone();
            cur += 1;
        }
    }

    pub fn prelock(&mut self) -> RwLockWriteGuard<'static, Option<BTreeMap<String, AmlValue>>> {
        ACPI_TABLE.namespace.write()
    }

    fn modify_local_obj(&mut self, local: usize, value: AmlValue) -> Result<(), AmlError> {
        self.local_vars[local] = value;
        Ok(())
    }

    fn modify_object(&mut self, name: String, value: AmlValue) -> Result<(), AmlError> {
        if let Some(ref mut namespace) = *ACPI_TABLE.namespace.write() {
            namespace.insert(name, value);
            Ok(())
        } else {
            Err(AmlError::AmlHardFatal)
        }
    }

    fn modify_index_final(&mut self, name: String, value: AmlValue, indices: Vec<u64>) -> Result<(), AmlError> {
        if let Some(ref mut namespace) = *ACPI_TABLE.namespace.write() {
            let mut obj = if let Some(s) = namespace.get(&name) {
                s.clone()
            } else {
                return Err(AmlError::AmlValueError);
            };

            obj = self.modify_index_core(obj, value, indices)?;

            namespace.insert(name, obj);
            Ok(())
        } else {
            Err(AmlError::AmlValueError)
        }
    }

    fn modify_index_core(&mut self, obj: AmlValue, value: AmlValue, indices: Vec<u64>) -> Result<AmlValue, AmlError> {
        match obj {
            AmlValue::String(ref string) => {
                if indices.len() != 1 {
                    return Err(AmlError::AmlValueError);
                }

                let mut bytes = string.clone().into_bytes();
                bytes[indices[0] as usize] = value.get_as_integer()? as u8;

                let string = String::from_utf8(bytes).unwrap();

                Ok(AmlValue::String(string))
            },
            AmlValue::Buffer(ref b) => {
                if indices.len() != 1 {
                    return Err(AmlError::AmlValueError);
                }

                let mut b = b.clone();
                b[indices[0] as usize] = value.get_as_integer()? as u8;

                Ok(AmlValue::Buffer(b))
            },
            AmlValue::BufferField(ref b) => {
                if indices.len() != 1 {
                    return Err(AmlError::AmlValueError);
                }

                let mut idx = indices[0];
                idx += b.index.get_as_integer()?;

                self.modify(AmlValue::ObjectReference(ObjectReference::Index(b.source_buf.clone(), Box::new(AmlValue::Integer(idx.clone())))), value);

                Ok(AmlValue::BufferField(b.clone()))
            },
            AmlValue::Package(ref p) => {
                if indices.len() < 0 {
                    return Err(AmlError::AmlValueError);
                }

                let mut p = p.clone();

                if indices.len() == 1 {
                    p[indices[0] as usize] = value;
                } else {
                    p[indices[0] as usize] = self.modify_index_core(p[indices[0] as usize].clone(), value, indices[1..].to_vec())?;
                }

                Ok(AmlValue::Package(p))
            },
            _ => return Err(AmlError::AmlValueError)
        }
    }

    pub fn modify_index(&mut self, name: AmlValue, value: AmlValue, indices: Vec<u64>) -> Result<(), AmlError>{
        match name {
            AmlValue::ObjectReference(r) => match r {
                ObjectReference::Object(s) => self.modify_index_final(s, value, indices),
                ObjectReference::Index(c, v) => {
                    let mut indices = indices.clone();
                    indices.push(v.get_as_integer()?);

                    self.modify_index(*c, value, indices)
                },
                ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError),
                ObjectReference::LocalObj(i) => {
                    let v = self.local_vars[i as usize].clone();
                    self.local_vars[i as usize] = self.modify_index_core(v, value, indices)?;

                    Ok(())
                }
            },
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn modify(&mut self, name: AmlValue, value: AmlValue) -> Result<(), AmlError> {
        match name {
            AmlValue::ObjectReference(r) => match r {
                ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError),
                ObjectReference::LocalObj(i) => self.modify_local_obj(i as usize, value),
                ObjectReference::Object(s) => self.modify_object(s, value),
                ObjectReference::Index(c, v) => self.modify_index(*c, value, vec!(v.get_as_integer()?))
            },
            AmlValue::String(s) => self.modify_object(s, value),
            _ => Err(AmlError::AmlValueError)
        }
    }

    pub fn get(&self, name: AmlValue) -> Result<AmlValue, AmlError> {
        Ok(match name {
            AmlValue::ObjectReference(r) => match r {
                ObjectReference::ArgObj(i) => self.arg_vars[i as usize].clone(),
                ObjectReference::LocalObj(i) => self.local_vars[i as usize].clone(),
                ObjectReference::Object(ref s) => if let Some(ref namespace) = *ACPI_TABLE.namespace.read() {
                    if let Some(o) = namespace.get(s) {
                        o.clone()
                    } else {
                        AmlValue::None
                    }
                } else { AmlValue::None },
                ObjectReference::Index(c, v) => if let Some(ref mut namespace) = *ACPI_TABLE.namespace.write() {
                    let idx = v.get_as_integer()? as usize;
                    match *c {
                        AmlValue::Package(p) => p[idx].clone(),
                        _ => AmlValue::None
                    }
                } else {
                    AmlValue::None
                }
            },
            AmlValue::String(ref s) => if let Some(ref namespace) = *ACPI_TABLE.namespace.read() {
                if let Some(o) = namespace.get(s) {
                    o.clone()
                } else {
                    AmlValue::None
                }
            } else { AmlValue::None },
            _ => AmlValue::None
        })
    }
}
<|endoftext|>


<commit_before>use std::ffi::OsStr;
use std::fs::File;
use std::io::{self, Write, BufRead, BufReader, Seek, SeekFrom};
use std::process::{self, Command, Stdio};
use std::time::Instant;
use regex::Regex;
use tempfile::tempfile;

use Cfg;
use errors::*;
use notifications::*;
use rustup_utils;
use telemetry::{Telemetry, TelemetryEvent};

pub fn run_command_for_dir<S: AsRef<OsStr>>(cmd: Command,
                                            arg0: &str,
                                            args: &[S],
                                            cfg: &Cfg) -> Result<()> {
    if (arg0 == "rustc" || arg0 == "rustc.exe") && try!(cfg.telemetry_enabled()) {
        return telemetry_rustc(cmd, arg0, args, cfg);
    }

    run_command_for_dir_without_telemetry(cmd, arg0, args)
}

fn telemetry_rustc<S: AsRef<OsStr>>(mut cmd: Command,
                                    arg0: &str,
                                    args: &[S], cfg: &Cfg) -> Result<()> {
    #[cfg(unix)]
    fn file_as_stdio(file: &File) -> Stdio {
        use std::os::unix::io::{AsRawFd, FromRawFd};
        unsafe { Stdio::from_raw_fd(file.as_raw_fd()) }
    }

    #[cfg(windows)]
    fn file_as_stdio(file: &File) -> Stdio {
        use std::os::windows::io::{AsRawHandle, FromRawHandle};
        unsafe { Stdio::from_raw_handle(file.as_raw_handle()) }
    }

    let now = Instant::now();

    cmd.args(args);

    let has_color_args = args.iter().any(|e| {
        let e = e.as_ref().to_str().unwrap_or("");
        e.starts_with("--color")
    });

    if stderr_isatty() && !has_color_args
    {
        cmd.arg("--color");
        cmd.arg("always");
    }

    let mut cmd_err_file = tempfile().unwrap();
    let cmd_err_stdio = file_as_stdio(&cmd_err_file);

    // FIXME rust-lang/rust#32254. It's not clear to me
    // when and why this is needed.
    let mut cmd = cmd.stdin(Stdio::inherit())
                    .stdout(Stdio::inherit())
                    .stderr(cmd_err_stdio)
                    .spawn()
                    .unwrap();

    let status = cmd.wait();

    let duration = now.elapsed();

    let ms = (duration.as_secs() as u64 * 1000) + (duration.subsec_nanos() as u64 / 1000 / 1000);

    let t = Telemetry::new(cfg.multirust_dir.join("telemetry"));

    match status {
        Ok(status) => {
            let exit_code = status.code().unwrap_or(1);

            let re = Regex::new(r"\[(?P<error>E.{4})\]").unwrap();

            let mut buffer = String::new();
            // Chose a HashSet instead of a Vec to avoid calls to sort() and dedup().
            // The HashSet should be faster if there are a lot of errors, too.
            let mut errors: Vec<String> = Vec::new();

            let stderr = io::stderr();
            let mut handle = stderr.lock();

            cmd_err_file.seek(SeekFrom::Start(0)).unwrap();

            let mut buffered_stderr = BufReader::new(cmd_err_file);

            while buffered_stderr.read_line(&mut buffer).unwrap() > 0 {
                let b = buffer.to_owned();
                buffer.clear();
                let _ = handle.write(b.as_bytes());

                if let Some(caps) = re.captures(&b) {
                    if !caps.is_empty() {
                        errors.push(caps.name("error").unwrap_or("").to_owned());
                    }
                };
            }

            let e = if errors.is_empty() { None } else { Some(errors) };

            let te = TelemetryEvent::RustcRun { duration_ms: ms,
                                                exit_code: exit_code,
                                                errors: e };

            let _ = t.log_telemetry(te).map_err(|xe| {
                (cfg.notify_handler)(Notification::TelemetryCleanupError(&xe));
            });

            process::exit(exit_code);
        },
        Err(e) => {
            let exit_code = e.raw_os_error().unwrap_or(1);
            let te = TelemetryEvent::RustcRun { duration_ms: ms,
                                                exit_code: exit_code,
                                                errors: None };

            let _ = t.log_telemetry(te).map_err(|xe| {
                (cfg.notify_handler)(Notification::TelemetryCleanupError(&xe));
            });

            Err(e).chain_err(|| rustup_utils::ErrorKind::RunningCommand {
                name: OsStr::new(arg0).to_owned(),
            })
        },
    }
}

fn run_command_for_dir_without_telemetry<S: AsRef<OsStr>>(
    mut cmd: Command, arg0: &str, args: &[S]) -> Result<()>
{
    cmd.args(&args);

    // FIXME rust-lang/rust#32254. It's not clear to me
    // when and why this is needed.
    cmd.stdin(process::Stdio::inherit());

    match cmd.status() {
        Ok(status) => {
            // Ensure correct exit code is returned
            let code = status.code().unwrap_or(1);
            process::exit(code);
        }
        Err(e) => {
            Err(e).chain_err(|| rustup_utils::ErrorKind::RunningCommand {
                name: OsStr::new(arg0).to_owned(),
            })
        }
    }
}

#[cfg(unix)]
fn stderr_isatty() -> bool {
    use libc;
    unsafe { libc::isatty(libc::STDERR_FILENO) != 0 }
}

#[cfg(windows)]
fn stderr_isatty() -> bool {
    type DWORD = u32;
    type BOOL = i32;
    type HANDLE = *mut u8;
    const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD;
    extern "system" {
        fn GetStdHandle(which: DWORD) -> HANDLE;
        fn GetConsoleMode(hConsoleHandle: HANDLE,
                          lpMode: *mut DWORD) -> BOOL;
    }
    unsafe {
        let handle = GetStdHandle(STD_ERROR_HANDLE);
        let mut out = 0;
        GetConsoleMode(handle, &mut out) != 0
    }
}
<commit_msg>Auto merge of #968 - nrc:build-fix, r=brson<commit_after>use std::ffi::OsStr;
use std::fs::File;
use std::io::{self, Write, BufRead, BufReader, Seek, SeekFrom};
use std::process::{self, Command, Stdio};
use std::time::Instant;
use regex::Regex;
use tempfile::tempfile;

use Cfg;
use errors::*;
use notifications::*;
use rustup_utils;
use telemetry::{Telemetry, TelemetryEvent};

pub fn run_command_for_dir<S: AsRef<OsStr>>(cmd: Command,
                                            arg0: &str,
                                            args: &[S],
                                            cfg: &Cfg) -> Result<()> {
    if (arg0 == "rustc" || arg0 == "rustc.exe") && try!(cfg.telemetry_enabled()) {
        return telemetry_rustc(cmd, arg0, args, cfg);
    }

    run_command_for_dir_without_telemetry(cmd, arg0, args)
}

fn telemetry_rustc<S: AsRef<OsStr>>(mut cmd: Command,
                                    arg0: &str,
                                    args: &[S], cfg: &Cfg) -> Result<()> {
    #[cfg(unix)]
    fn file_as_stdio(file: &File) -> Stdio {
        use std::os::unix::io::{AsRawFd, FromRawFd};
        unsafe { Stdio::from_raw_fd(file.as_raw_fd()) }
    }

    #[cfg(windows)]
    fn file_as_stdio(file: &File) -> Stdio {
        use std::os::windows::io::{AsRawHandle, FromRawHandle};
        unsafe { Stdio::from_raw_handle(file.as_raw_handle()) }
    }

    let now = Instant::now();

    cmd.args(args);

    let has_color_args = args.iter().any(|e| {
        let e = e.as_ref().to_str().unwrap_or("");
        e.starts_with("--color")
    });

    if stderr_isatty() && !has_color_args
    {
        cmd.arg("--color");
        cmd.arg("always");
    }

    let mut cmd_err_file = tempfile().unwrap();
    let cmd_err_stdio = file_as_stdio(&cmd_err_file);

    // FIXME rust-lang/rust#32254. It's not clear to me
    // when and why this is needed.
    let mut cmd = cmd.stdin(Stdio::inherit())
                    .stdout(Stdio::inherit())
                    .stderr(cmd_err_stdio)
                    .spawn()
                    .unwrap();

    let status = cmd.wait();

    let duration = now.elapsed();

    let ms = (duration.as_secs() as u64 * 1000) + (duration.subsec_nanos() as u64 / 1000 / 1000);

    let t = Telemetry::new(cfg.multirust_dir.join("telemetry"));

    match status {
        Ok(status) => {
            let exit_code = status.code().unwrap_or(1);

            let re = Regex::new(r"\[(?P<error>E.{4})\]").unwrap();

            let mut buffer = String::new();
            // Chose a HashSet instead of a Vec to avoid calls to sort() and dedup().
            // The HashSet should be faster if there are a lot of errors, too.
            let mut errors: Vec<String> = Vec::new();

            let stderr = io::stderr();
            let mut handle = stderr.lock();

            cmd_err_file.seek(SeekFrom::Start(0)).unwrap();

            let mut buffered_stderr = BufReader::new(cmd_err_file);

            while buffered_stderr.read_line(&mut buffer).unwrap() > 0 {
                let b = buffer.to_owned();
                buffer.clear();
                let _ = handle.write(b.as_bytes());

                if let Some(caps) = re.captures(&b) {
                    if !caps.is_empty() {
                        errors.push(caps.name("error").unwrap_or("").to_owned());
                    }
                };
            }

            let e = if errors.is_empty() { None } else { Some(errors) };

            let te = TelemetryEvent::RustcRun { duration_ms: ms,
                                                exit_code: exit_code,
                                                errors: e };

            let _ = t.log_telemetry(te).map_err(|xe| {
                (cfg.notify_handler)(Notification::TelemetryCleanupError(&xe));
            });

            process::exit(exit_code);
        },
        Err(e) => {
            let exit_code = e.raw_os_error().unwrap_or(1);
            let te = TelemetryEvent::RustcRun { duration_ms: ms,
                                                exit_code: exit_code,
                                                errors: None };

            let _ = t.log_telemetry(te).map_err(|xe| {
                (cfg.notify_handler)(Notification::TelemetryCleanupError(&xe));
            });

            Err(e).chain_err(|| rustup_utils::ErrorKind::RunningCommand {
                name: OsStr::new(arg0).to_owned(),
            })
        },
    }
}

fn run_command_for_dir_without_telemetry<S: AsRef<OsStr>>(
    mut cmd: Command, arg0: &str, args: &[S]) -> Result<()>
{
    cmd.args(args);

    // FIXME rust-lang/rust#32254. It's not clear to me
    // when and why this is needed.
    cmd.stdin(process::Stdio::inherit());

    match cmd.status() {
        Ok(status) => {
            // Ensure correct exit code is returned
            let code = status.code().unwrap_or(1);
            process::exit(code);
        }
        Err(e) => {
            Err(e).chain_err(|| rustup_utils::ErrorKind::RunningCommand {
                name: OsStr::new(arg0).to_owned(),
            })
        }
    }
}

#[cfg(unix)]
fn stderr_isatty() -> bool {
    use libc;
    unsafe { libc::isatty(libc::STDERR_FILENO) != 0 }
}

#[cfg(windows)]
fn stderr_isatty() -> bool {
    type DWORD = u32;
    type BOOL = i32;
    type HANDLE = *mut u8;
    const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD;
    extern "system" {
        fn GetStdHandle(which: DWORD) -> HANDLE;
        fn GetConsoleMode(hConsoleHandle: HANDLE,
                          lpMode: *mut DWORD) -> BOOL;
    }
    unsafe {
        let handle = GetStdHandle(STD_ERROR_HANDLE);
        let mut out = 0;
        GetConsoleMode(handle, &mut out) != 0
    }
}
<|endoftext|>


<commit_before>#![feature(plugin_registrar, rustc_private, plugin, slice_patterns)]

extern crate syntax;
extern crate rustc;
extern crate clang;

use clang::*;

use std::ffi::{CString, CStr};
use std::fmt::Write;
use std::mem::transmute;
use std::str::from_utf8;

use syntax::codemap::{Span, BytePos, Spanned, mk_sp};
use syntax::parse::token::{self, intern, InternedString};
use syntax::ast::{TokenTree, TtToken, TtDelimited, TtSequence, Ident, Arg, Ty, FnDecl};
use syntax::ast::{ForeignItem, LitStr};
use syntax::ast::Mutability::*;
use syntax::{ast, abi, ast_util};
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::ext::build::AstBuilder;  // trait for expr_usize
use syntax::util::small_vector::SmallVector;
use syntax::ptr::P;
use syntax::ast::{Item, StructDef};
use rustc::plugin::Registry;

struct Helper<'cx, 'a: 'cx> {
    cx: &'cx mut ExtCtxt<'a>,
    v: SmallVector<P<Item>>,
    fns: Vec<P<ForeignItem>>,
    sp: Span,
}

fn expand_include_cpp<'cx, 'a>(
    cx: &'cx mut ExtCtxt<'a>,
    sp: Span,
    args: &[TokenTree]
    ) -> Box<MacResult + 'static>
{
    let (filename, sp) = match args {
        [TtToken(sp, token::Literal(token::Lit::Str_(s), _))] => (s, sp),
        [..] => {
            cx.span_err(sp, "expected a single string literal");
            return DummyResult::any(sp);
        }
    };
    let filename = filename.as_str();
    let idx = unsafe { clang_createIndex(1, 1) };
    let filename = CString::new(filename).unwrap();
    let args: Vec<&'static str> = vec!["-I", "."];
    let args: Vec<_> = args.iter().map(|&s| CString::new(s).unwrap()).collect();
    let args: Vec<_> = args.iter().map(|s| s.as_ptr()).collect();
    let tu = unsafe { clang_parseTranslationUnit(
        idx,
        filename.as_ptr(),
        args.as_ptr(),
        args.len() as i32,
        std::ptr::null(),
        0,
        0,
    ) };
    assert!(tu as *const CXTranslationUnitImpl != std::ptr::null());
    let cursor = unsafe { clang_getTranslationUnitCursor(tu) };
    let libc = cx.item(
        sp,
        Ident::new(intern("libc")),
        vec![],
        ast::ItemExternCrate(None),
    );
    let (mut v, fns) = {
        let mut helper = Helper {
            v: SmallVector::one(libc),
            cx: cx,
            fns: vec![],
            sp: sp,
        };
        assert_eq!(0, unsafe { clang_visitChildren(cursor, cb, transmute(&mut helper)) });
        (helper.v, helper.fns)
    };
    let externs = ast::ForeignMod {
        abi: abi::Abi::C,
        items: fns,
    };
    v.push(cx.item(
        sp,
        Ident::new(intern("something_extern_something")),
        vec![],
        ast::ItemForeignMod(externs),
    ));
    MacEager::items(v)
}

struct FunargHelper<'cx, 'a: 'cx> {
    cx: &'cx mut ExtCtxt<'a>,
    sp: Span,
    args: Vec<Arg>,
}

#[allow(unconditional_recursion)]
extern fn cb_funargs(
    cursor: CXCursor,
    _parent: CXCursor,
    client_data: CXClientData,
    ) -> CXChildVisitResult
{
    use clang::CXCursorKind::*;
    let &mut FunargHelper {
        ref mut cx,
        sp,
        ref mut args,
    } = unsafe { transmute(client_data) };
    args.push(parse_arg(cx, sp, cursor));
    CXChildVisitResult::CXChildVisit_Continue
}

fn parse_ty(cx: &mut ExtCtxt, sp: Span, ty: CXType) -> P<Ty> {
    use clang::CXTypeKind::*;
    println!("{:?}", ty.kind);
    let name = unsafe { clang_getTypeSpelling(ty.clone()) };
    let name = unsafe { from_utf8(CStr::from_ptr(clang_getCString(name)).to_bytes()).unwrap() };
    println!("name: {:?}", name);
    match ty.kind {
        CXType_Typedef => {
            let ident = Ident::new(intern(name));
            cx.ty_ident(sp, ident)
        }
        CXType_Pointer => {
            let inner = unsafe { clang_getPointeeType(ty.clone()) };
            let inner = parse_ty(cx, sp, inner);
            let muta = if unsafe { clang_isConstQualifiedType(ty.clone()) } == 1 {
                MutImmutable
            } else {
                MutMutable
            };
            cx.ty_ptr(sp, inner, muta)
        }
        CXType_Char_S => {
            let path = vec!["libc", "c_char"];
            let path = path.iter().map(|p| Ident::new(intern(p))).collect();
            let path = cx.path(sp, path);
            cx.ty_path(path)
        }
        _ => unimplemented!(),
    }
}

fn parse_arg(cx: &mut ExtCtxt, sp: Span, cursor: CXCursor) -> Arg {
    let name = unsafe { clang_getCursorSpelling(cursor.clone()) };
    let name = unsafe { from_utf8(CStr::from_ptr(clang_getCString(name)).to_bytes()).unwrap() };
    println!("funarg: {:?}", name);
    let ident = Ident::new(intern(name));
    let ty = parse_ty(cx, sp, unsafe { clang_getCursorType(cursor) });
    cx.arg(sp, ident, ty)
}

fn parse_fn(cx: &mut ExtCtxt, name: &str, sp: Span, cursor: CXCursor) -> P<ForeignItem> {
    use clang::CXTypeKind::*;
    let t = unsafe { clang_getCursorType(cursor.clone()) };
    let ret = unsafe { clang_getResultType(t.clone()) };
    let args = {
        let mut help = FunargHelper {
            cx: cx,
            sp: sp,
            args: vec![],
        };
        assert_eq!(0, unsafe { clang_visitChildren(cursor, cb_funargs, transmute(&mut help)) });
        help.args
    };
    let ret = match ret.kind {
        CXType_Void => ast::NoReturn(sp),
        _ => ast::Return(parse_ty(cx, sp, ret)),
    };
    let f = P(ast::FnDecl {
        inputs: args,
        output: ret,
        variadic: false
    });
    P(ForeignItem {
        ident: intern(name).ident(),
        attrs: vec![],
        id: ast::DUMMY_NODE_ID, // FIXME
        span: sp,
        vis: ast::Visibility::Public,
        node: ast::ForeignItemFn(f, ast_util::empty_generics()),
    })
}

fn parse_struct(cx: &mut ExtCtxt, name: &str, sp: Span, cursor: CXCursor) -> P<Item> {
    let ident = Ident::new(intern(name));
    let fields = vec![];
    let struct_def = StructDef {
        fields: fields,
        ctor_id: None, // FIXME
    };
    cx.item_struct(sp, ident, struct_def)
}

struct TypedefHelper<'cx, 'a: 'cx> {
    cx: &'cx mut ExtCtxt<'a>,
    sp: Span,
    name: &'a str,
    item: Option<P<Item>>,
}

#[allow(unconditional_recursion)]
extern fn cb_typedef(
    cursor: CXCursor,
    _parent: CXCursor,
    client_data: CXClientData,
    ) -> CXChildVisitResult
{
    use clang::CXCursorKind::*;
    let &mut TypedefHelper {
        ref mut cx,
        ref name,
        sp,
        ref mut item,
    } = unsafe { transmute(client_data) };
    match cursor.kind {
        CXCursor_StructDecl => *item = Some(parse_struct(cx, name, sp, cursor)),
        _ => unimplemented!(),
    }
    CXChildVisitResult::CXChildVisit_Continue
}

#[allow(unconditional_recursion)]
extern fn cb(cursor: CXCursor, _parent: CXCursor, client_data: CXClientData) -> CXChildVisitResult
{
    use clang::CXCursorKind::*;
    let client_data: &mut Helper = unsafe { transmute(client_data) };
    let t = unsafe { clang_getCursorType(cursor.clone()) };
    let mangled = unsafe { clang_Cursor_getMangling(cursor.clone()) };
    let mangled = unsafe { from_utf8(CStr::from_ptr(clang_getCString(mangled)).to_bytes()).unwrap() };
    let name = unsafe { clang_getCursorSpelling(cursor.clone()) };
    let name = unsafe { from_utf8(CStr::from_ptr(clang_getCString(name)).to_bytes()).unwrap() };
    println!("{:?}: {:?} {:?} {:?}", cursor.kind, t.kind, mangled, name);
    match cursor.kind {
        CXCursor_StructDecl => {
            // typedef struct {.. } <Name>
            if name == "" { return CXChildVisitResult::CXChildVisit_Continue; }
            client_data.v.push(parse_struct(client_data.cx, name, client_data.sp, cursor));
        }
        CXCursor_TypedefDecl => {
            assert!(name != "");
            let mut help = TypedefHelper {
                cx: client_data.cx,
                sp: client_data.sp,
                name: name,
                item: None,
            };
            assert_eq!(0, unsafe { clang_visitChildren(cursor, cb_typedef, transmute(&mut help)) });
            client_data.v.push(help.item.unwrap());
        }
        CXCursor_FunctionDecl if mangled.ends_with(name) => {
            // c-function b/c mangled name ends with unmangled name
            // FIXME: find better method of detection
            client_data.fns.push(parse_fn(client_data.cx, name, client_data.sp, cursor));
        }
        _ => unimplemented!(),
    };
    CXChildVisitResult::CXChildVisit_Continue
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("include_cpp", expand_include_cpp);
}
<commit_msg>attribute repr C<commit_after>#![feature(plugin_registrar, rustc_private, plugin, slice_patterns)]

extern crate syntax;
extern crate rustc;
extern crate clang;

use clang::*;

use std::ffi::{CString, CStr};
use std::fmt::Write;
use std::mem::transmute;
use std::str::from_utf8;

use syntax::codemap::{Span, BytePos, Spanned, mk_sp};
use syntax::parse::token::{self, intern, InternedString};
use syntax::ast::{TokenTree, TtToken, TtDelimited, TtSequence, Ident, Arg, Ty, FnDecl};
use syntax::ast::{ForeignItem, LitStr};
use syntax::ast::Mutability::*;
use syntax::{ast, abi, ast_util};
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::ext::build::AstBuilder;  // trait for expr_usize
use syntax::util::small_vector::SmallVector;
use syntax::ptr::P;
use syntax::ast::{Item, StructDef};
use rustc::plugin::Registry;

struct Helper<'cx, 'a: 'cx> {
    cx: &'cx mut ExtCtxt<'a>,
    v: SmallVector<P<Item>>,
    fns: Vec<P<ForeignItem>>,
    sp: Span,
}

fn expand_include_cpp<'cx, 'a>(
    cx: &'cx mut ExtCtxt<'a>,
    sp: Span,
    args: &[TokenTree]
    ) -> Box<MacResult + 'static>
{
    let (filename, sp) = match args {
        [TtToken(sp, token::Literal(token::Lit::Str_(s), _))] => (s, sp),
        [..] => {
            cx.span_err(sp, "expected a single string literal");
            return DummyResult::any(sp);
        }
    };
    let filename = filename.as_str();
    let idx = unsafe { clang_createIndex(1, 1) };
    let filename = CString::new(filename).unwrap();
    let args: Vec<&'static str> = vec!["-I", "."];
    let args: Vec<_> = args.iter().map(|&s| CString::new(s).unwrap()).collect();
    let args: Vec<_> = args.iter().map(|s| s.as_ptr()).collect();
    let tu = unsafe { clang_parseTranslationUnit(
        idx,
        filename.as_ptr(),
        args.as_ptr(),
        args.len() as i32,
        std::ptr::null(),
        0,
        0,
    ) };
    assert!(tu as *const CXTranslationUnitImpl != std::ptr::null());
    let cursor = unsafe { clang_getTranslationUnitCursor(tu) };
    let libc = cx.item(
        sp,
        Ident::new(intern("libc")),
        vec![],
        ast::ItemExternCrate(None),
    );
    let (mut v, fns) = {
        let mut helper = Helper {
            v: SmallVector::one(libc),
            cx: cx,
            fns: vec![],
            sp: sp,
        };
        assert_eq!(0, unsafe { clang_visitChildren(cursor, cb, transmute(&mut helper)) });
        (helper.v, helper.fns)
    };
    let externs = ast::ForeignMod {
        abi: abi::Abi::C,
        items: fns,
    };
    v.push(cx.item(
        sp,
        Ident::new(intern("something_extern_something")),
        vec![],
        ast::ItemForeignMod(externs),
    ));
    MacEager::items(v)
}

struct FunargHelper<'cx, 'a: 'cx> {
    cx: &'cx mut ExtCtxt<'a>,
    sp: Span,
    args: Vec<Arg>,
}

#[allow(unconditional_recursion)]
extern fn cb_funargs(
    cursor: CXCursor,
    _parent: CXCursor,
    client_data: CXClientData,
    ) -> CXChildVisitResult
{
    use clang::CXCursorKind::*;
    let &mut FunargHelper {
        ref mut cx,
        sp,
        ref mut args,
    } = unsafe { transmute(client_data) };
    args.push(parse_arg(cx, sp, cursor));
    CXChildVisitResult::CXChildVisit_Continue
}

fn parse_ty(cx: &mut ExtCtxt, sp: Span, ty: CXType) -> P<Ty> {
    use clang::CXTypeKind::*;
    println!("{:?}", ty.kind);
    let name = unsafe { clang_getTypeSpelling(ty.clone()) };
    let name = unsafe { from_utf8(CStr::from_ptr(clang_getCString(name)).to_bytes()).unwrap() };
    println!("name: {:?}", name);
    match ty.kind {
        CXType_Typedef => {
            let ident = Ident::new(intern(name));
            cx.ty_ident(sp, ident)
        }
        CXType_Pointer => {
            let inner = unsafe { clang_getPointeeType(ty.clone()) };
            let inner = parse_ty(cx, sp, inner);
            let muta = if unsafe { clang_isConstQualifiedType(ty.clone()) } == 1 {
                MutImmutable
            } else {
                MutMutable
            };
            cx.ty_ptr(sp, inner, muta)
        }
        CXType_Char_S => {
            let path = vec!["libc", "c_char"];
            let path = path.iter().map(|p| Ident::new(intern(p))).collect();
            let path = cx.path(sp, path);
            cx.ty_path(path)
        }
        _ => unimplemented!(),
    }
}

fn parse_arg(cx: &mut ExtCtxt, sp: Span, cursor: CXCursor) -> Arg {
    let name = unsafe { clang_getCursorSpelling(cursor.clone()) };
    let name = unsafe { from_utf8(CStr::from_ptr(clang_getCString(name)).to_bytes()).unwrap() };
    println!("funarg: {:?}", name);
    let ident = Ident::new(intern(name));
    let ty = parse_ty(cx, sp, unsafe { clang_getCursorType(cursor) });
    cx.arg(sp, ident, ty)
}

fn parse_fn(cx: &mut ExtCtxt, name: &str, sp: Span, cursor: CXCursor) -> P<ForeignItem> {
    use clang::CXTypeKind::*;
    let t = unsafe { clang_getCursorType(cursor.clone()) };
    let ret = unsafe { clang_getResultType(t.clone()) };
    let args = {
        let mut help = FunargHelper {
            cx: cx,
            sp: sp,
            args: vec![],
        };
        assert_eq!(0, unsafe { clang_visitChildren(cursor, cb_funargs, transmute(&mut help)) });
        help.args
    };
    let ret = match ret.kind {
        CXType_Void => ast::NoReturn(sp),
        _ => ast::Return(parse_ty(cx, sp, ret)),
    };
    let f = P(ast::FnDecl {
        inputs: args,
        output: ret,
        variadic: false
    });
    P(ForeignItem {
        ident: intern(name).ident(),
        attrs: vec![],
        id: ast::DUMMY_NODE_ID, // FIXME
        span: sp,
        vis: ast::Visibility::Public,
        node: ast::ForeignItemFn(f, ast_util::empty_generics()),
    })
}

fn parse_struct(cx: &mut ExtCtxt, name: &str, sp: Span, cursor: CXCursor) -> P<Item> {
    let ident = Ident::new(intern(name));
    let fields = vec![];
    let struct_def = StructDef {
        fields: fields,
        ctor_id: None, // FIXME
    };
    let s = cx.item_struct(sp, ident, struct_def);
    let c = cx.meta_word(sp, InternedString::new("C"));
    let meta = cx.meta_list(
        sp,
        InternedString::new("repr"),
        vec![c],
    );
    s.map(|mut s| {
        s.attrs.push(cx.attribute(sp, meta));
        s
    })
}

struct TypedefHelper<'cx, 'a: 'cx> {
    cx: &'cx mut ExtCtxt<'a>,
    sp: Span,
    name: &'a str,
    item: Option<P<Item>>,
}

#[allow(unconditional_recursion)]
extern fn cb_typedef(
    cursor: CXCursor,
    _parent: CXCursor,
    client_data: CXClientData,
    ) -> CXChildVisitResult
{
    use clang::CXCursorKind::*;
    let &mut TypedefHelper {
        ref mut cx,
        ref name,
        sp,
        ref mut item,
    } = unsafe { transmute(client_data) };
    match cursor.kind {
        CXCursor_StructDecl => *item = Some(parse_struct(cx, name, sp, cursor)),
        _ => unimplemented!(),
    }
    CXChildVisitResult::CXChildVisit_Continue
}

#[allow(unconditional_recursion)]
extern fn cb(cursor: CXCursor, _parent: CXCursor, client_data: CXClientData) -> CXChildVisitResult
{
    use clang::CXCursorKind::*;
    let client_data: &mut Helper = unsafe { transmute(client_data) };
    let t = unsafe { clang_getCursorType(cursor.clone()) };
    let mangled = unsafe { clang_Cursor_getMangling(cursor.clone()) };
    let mangled = unsafe { from_utf8(CStr::from_ptr(clang_getCString(mangled)).to_bytes()).unwrap() };
    let name = unsafe { clang_getCursorSpelling(cursor.clone()) };
    let name = unsafe { from_utf8(CStr::from_ptr(clang_getCString(name)).to_bytes()).unwrap() };
    println!("{:?}: {:?} {:?} {:?}", cursor.kind, t.kind, mangled, name);
    match cursor.kind {
        CXCursor_StructDecl => {
            // typedef struct {.. } <Name>
            if name == "" { return CXChildVisitResult::CXChildVisit_Continue; }
            client_data.v.push(parse_struct(client_data.cx, name, client_data.sp, cursor));
        }
        CXCursor_TypedefDecl => {
            assert!(name != "");
            let mut help = TypedefHelper {
                cx: client_data.cx,
                sp: client_data.sp,
                name: name,
                item: None,
            };
            assert_eq!(0, unsafe { clang_visitChildren(cursor, cb_typedef, transmute(&mut help)) });
            client_data.v.push(help.item.unwrap());
        }
        CXCursor_FunctionDecl if mangled.ends_with(name) => {
            // c-function b/c mangled name ends with unmangled name
            // FIXME: find better method of detection
            client_data.fns.push(parse_fn(client_data.cx, name, client_data.sp, cursor));
        }
        _ => unimplemented!(),
    };
    CXChildVisitResult::CXChildVisit_Continue
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("include_cpp", expand_include_cpp);
}
<|endoftext|>