<commit_before>#![feature(test)]

#![feature(plugin)]
#![plugin(clippy)]

extern crate test;
extern crate rand;

use rand::distributions::{IndependentSample, Range};

pub struct Settings<R>
    where R: rand::Rng
{
    pub min_pos: Vec<f32>,
    pub max_pos: Vec<f32>,

    pub cr_min: f32,
    pub cr_max: f32,
    pub cr_change_probability: f32,

    pub f_min: f32,
    pub f_max: f32,
    pub f_change_probability: f32,

    pub pop_size: usize,
    pub rng: R,
}

impl<R> Settings<R>
    where R: rand::Rng
{
    pub fn min_max_rng(min_pos: Vec<f32>, max_pos: Vec<f32>, rng: R) -> Settings<R> {
        // create settings for the algorithm
        Settings {
            min_pos: min_pos,
            max_pos: max_pos,

            cr_min: 0.0,
            cr_max: 1.0,
            cr_change_probability: 0.1,

            f_min: 0.1,
            f_max: 1.0,
            f_change_probability: 0.1,

            pop_size: 50,
            rng: rng,
        }
    }
}

impl Settings<rand::XorShiftRng> {
    pub fn new(min_pos: Vec<f32>, max_pos: Vec<f32>) -> Settings<rand::XorShiftRng> {
        Settings::min_max_rng(min_pos, max_pos, rand::weak_rng())
    }
}

#[derive(Clone,Debug)]
pub struct Individual {
    pub pos: Vec<f32>,
    // the lower, the better.
    pub cost: Option<f32>,

    // control parameters
    cr: f32,
    f: f32,
}

pub struct Population<R>
    where R: rand::Rng
{
    // TODO use a single vector for curr and best and controlparameters?
    pub curr: Vec<Individual>,
    best: Vec<Individual>,

    settings: Settings<R>,
    best_idx: Option<usize>,
    dim: usize,
    between_popsize: Range<usize>,
    between_dim: Range<usize>,
    between_cr: Range<f32>,
    between_f: Range<f32>,
}

impl<R> Population<R>
    where R: rand::Rng
{
    // Creates a new population based on the given settings.
    pub fn new(s: Settings<R>) -> Population<R> {
        assert_eq!(s.min_pos.len(),
                   s.max_pos.len(),
                   "min_pos and max_pos need to have the same number of elements");
        assert!(s.min_pos.len() >= 1,
                "need at least one element to optimize");

        // create a vector of randomly initialized individuals for current.
        let dim = s.min_pos.len();

        // Empty individual, with no cost value (yet)
        let dummy_individual = Individual {
            pos: vec![0.0; dim],
            cost: None,
            cr: 0.0,
            f: 0.0,
        };

        // creates all the empty individuals
        let mut pop = Population {
            curr: vec![dummy_individual.clone(); s.pop_size],
            best: vec![dummy_individual; s.pop_size],
            best_idx: None,
            dim: dim,
            between_popsize: Range::new(0, s.pop_size),
            between_dim: Range::new(0, dim),
            between_cr: Range::new(s.cr_min, s.cr_max),
            between_f: Range::new(s.f_min, s.f_max),
            settings: s,
        };

        for ind in &mut pop.curr {
            // init control parameters
            ind.cr = pop.between_cr.ind_sample(&mut pop.settings.rng);
            ind.f = pop.between_f.ind_sample(&mut pop.settings.rng);

            // random range for each dimension
            for d in 0..dim {
                let between_min_max = Range::new(pop.settings.min_pos[d], pop.settings.max_pos[d]);
                ind.pos[d] = between_min_max.ind_sample(&mut pop.settings.rng);
            }
        }

        pop
    }

    fn update_best(&mut self) -> bool {
        let last_best_cost: Option<f32>;
        if let Some(last_best_idx) = self.best_idx {
            last_best_cost = self.best[last_best_idx].cost;
        } else {
            last_best_cost = None;
        }

        let mut new_best_cost = last_best_cost;
        for i in 0..self.curr.len() {
            let curr = &mut self.curr[i];
            let best = &mut self.best[i];

            // we use <= here, so that the individual moves even if the cost
            // stays the same.
            if best.cost.is_none() || curr.cost.unwrap() <= best.cost.unwrap() {
                // find global best. We use < here so that global only updates when fitness changes.
                if new_best_cost.is_none() || curr.cost.unwrap() < new_best_cost.unwrap() {
                    self.best_idx = Some(i);
                    new_best_cost = curr.cost;
                }

                // replace individual's best. swap is *much* faster than clone.
                std::mem::swap(curr, best);
            }
        }

        // got a new best?
        last_best_cost.is_none() || new_best_cost.unwrap() < last_best_cost.unwrap()
    }

    fn update_positions(&mut self) {
        let global_best_pos = &self.best[self.best_idx.unwrap()].pos;
        let rng = &mut self.settings.rng;
        for i in 0..self.curr.len() {
            let mut id1 = i;
            while id1 == i {
                id1 = self.between_popsize.ind_sample(rng);
            }

            let mut id2 = i;
            while id2 == i || id2 == id1 {
                id2 = self.between_popsize.ind_sample(rng);
            }

            let curr = &mut self.curr[i];
            let best = &self.best[i];

            // see "Self-Adapting Control Parameters in Differential Evolution:
            // A Comparative Study on Numerical Benchmark Problems"
            if rng.gen::<f32>() < self.settings.cr_change_probability {
                curr.cr = self.between_cr.ind_sample(rng);
            } else {
                curr.cr = best.cr;
            }
            if rng.gen::<f32>() < self.settings.f_change_probability {
                curr.f = self.between_f.ind_sample(rng);
            } else {
                curr.f = best.f;
            }

            let curr_pos = &mut curr.pos;
            let best_pos = &best.pos;
            let best1_pos = &self.best[id1].pos;
            let best2_pos = &self.best[id2].pos;

            let forced_mutation_dim = self.between_dim.ind_sample(rng);
            for d in 0..self.dim {
                if d == forced_mutation_dim || rng.gen::<f32>() < curr.cr {
                    curr_pos[d] = global_best_pos[d] + curr.f * (best1_pos[d] - best2_pos[d]);
                } else {
                    curr_pos[d] = best_pos[d];
                }
            }

            // reset cost, has to be updated by the user.
            curr.cost = None;
        }
    }

    // Uses updated cost values to update positions of individuals.
    pub fn evolve(&mut self) -> Option<&Individual> {
        let found_new_best = self.update_best();
        self.update_positions();

        if found_new_best {
            Some(&self.best[self.best_idx.unwrap()])
        } else {
            None
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate rand;
    use super::*;
    use test::Bencher;
    use rand::{XorShiftRng, StdRng, IsaacRng, Isaac64Rng, Rng};
    use rand::{OsRng, weak_rng};

    fn setup<R: rand::Rng>(dim: usize, rng: R) -> Population<R> {
        let settings = Settings::min_max_rng(vec![-20.0; dim], vec![20.0; dim], rng);
        Population::new(settings)
    }

    fn dummy_fitness(individuals: &mut Vec<Individual>) {
        for ind in individuals {
            ind.cost = Some(1.234);
        }
    }

    #[bench]
    fn bench_square_fitness_opt(b: &mut Bencher) {
        let rng: XorShiftRng = OsRng::new().unwrap().gen();
        let mut pop = setup(5, rng);
        b.iter(|| {
            for ind in &mut pop.curr {
                let mut f = 0.0;
                for x in &ind.pos {
                    f += x * x;
                }
                ind.cost = Some(f);
            }
            pop.evolve();
        });
    }

    #[bench]
    fn rand_thread_rng(b: &mut Bencher) {
        let mut pop = setup(5, rand::thread_rng());
        b.iter(|| {
            dummy_fitness(&mut pop.curr);
            pop.evolve();
        });
    }

    #[bench]
    fn rand_xor_shift(b: &mut Bencher) {
        let rng: XorShiftRng = OsRng::new().unwrap().gen();
        let mut pop = setup(5, rng);
        b.iter(|| {
            dummy_fitness(&mut pop.curr);
            pop.evolve();
        });
    }

    #[bench]
    fn rand_isaac(b: &mut Bencher) {
        let rng: IsaacRng = OsRng::new().unwrap().gen();
        let mut pop = setup(5, rng);
        b.iter(|| {
            dummy_fitness(&mut pop.curr);
            pop.evolve();
        });
    }

    #[bench]
    fn rand_isaac64(b: &mut Bencher) {
        let rng: Isaac64Rng = OsRng::new().unwrap().gen();
        let mut pop = setup(5, rng);
        b.iter(|| {
            dummy_fitness(&mut pop.curr);
            pop.evolve();
        });
    }

    #[bench]
    fn rand_std(b: &mut Bencher) {
        let rng: StdRng = StdRng::new().unwrap();
        let mut pop = setup(5, rng);
        b.iter(|| {
            dummy_fitness(&mut pop.curr);
            pop.evolve();
        });
    }

    #[bench]
    fn rand_weak_rng(b: &mut Bencher) {
        let rng = weak_rng();
        let mut pop = setup(5, rng);
        b.iter(|| {
            dummy_fitness(&mut pop.curr);
            pop.evolve();
        });
    }

}
<commit_msg>minor speedup<commit_after>#![feature(test)]

#![feature(plugin)]
#![plugin(clippy)]

extern crate test;
extern crate rand;

use rand::distributions::{IndependentSample, Range};

pub struct Settings<R>
    where R: rand::Rng
{
    pub min_pos: Vec<f32>,
    pub max_pos: Vec<f32>,

    pub cr_min: f32,
    pub cr_max: f32,
    pub cr_change_probability: f32,

    pub f_min: f32,
    pub f_max: f32,
    pub f_change_probability: f32,

    pub pop_size: usize,
    pub rng: R,
}

impl<R> Settings<R>
    where R: rand::Rng
{
    pub fn min_max_rng(min_pos: Vec<f32>, max_pos: Vec<f32>, rng: R) -> Settings<R> {
        // create settings for the algorithm
        Settings {
            min_pos: min_pos,
            max_pos: max_pos,

            cr_min: 0.0,
            cr_max: 1.0,
            cr_change_probability: 0.1,

            f_min: 0.1,
            f_max: 1.0,
            f_change_probability: 0.1,

            pop_size: 50,
            rng: rng,
        }
    }
}

impl Settings<rand::XorShiftRng> {
    pub fn new(min_pos: Vec<f32>, max_pos: Vec<f32>) -> Settings<rand::XorShiftRng> {
        Settings::min_max_rng(min_pos, max_pos, rand::weak_rng())
    }
}

#[derive(Clone,Debug)]
pub struct Individual {
    pub pos: Vec<f32>,
    // the lower, the better.
    pub cost: Option<f32>,

    // control parameters
    cr: f32,
    f: f32,
}

pub struct Population<R>
    where R: rand::Rng
{
    // TODO use a single vector for curr and best and controlparameters?
    pub curr: Vec<Individual>,
    best: Vec<Individual>,

    settings: Settings<R>,
    best_idx: Option<usize>,
    dim: usize,
    between_popsize: Range<usize>,
    between_dim: Range<usize>,
    between_cr: Range<f32>,
    between_f: Range<f32>,
}

impl<R> Population<R>
    where R: rand::Rng
{
    // Creates a new population based on the given settings.
    pub fn new(s: Settings<R>) -> Population<R> {
        assert_eq!(s.min_pos.len(),
                   s.max_pos.len(),
                   "min_pos and max_pos need to have the same number of elements");
        assert!(s.min_pos.len() >= 1,
                "need at least one element to optimize");

        // create a vector of randomly initialized individuals for current.
        let dim = s.min_pos.len();

        // Empty individual, with no cost value (yet)
        let dummy_individual = Individual {
            pos: vec![0.0; dim],
            cost: None,
            cr: 0.0,
            f: 0.0,
        };

        // creates all the empty individuals
        let mut pop = Population {
            curr: vec![dummy_individual.clone(); s.pop_size],
            best: vec![dummy_individual; s.pop_size],
            best_idx: None,
            dim: dim,
            between_popsize: Range::new(0, s.pop_size),
            between_dim: Range::new(0, dim),
            between_cr: Range::new(s.cr_min, s.cr_max),
            between_f: Range::new(s.f_min, s.f_max),
            settings: s,
        };

        for ind in &mut pop.curr {
            // init control parameters
            ind.cr = pop.between_cr.ind_sample(&mut pop.settings.rng);
            ind.f = pop.between_f.ind_sample(&mut pop.settings.rng);

            // random range for each dimension
            for d in 0..dim {
                let between_min_max = Range::new(pop.settings.min_pos[d], pop.settings.max_pos[d]);
                ind.pos[d] = between_min_max.ind_sample(&mut pop.settings.rng);
            }
        }

        pop
    }

    fn update_best(&mut self) -> bool {
        let last_best_cost: Option<f32>;
        if let Some(last_best_idx) = self.best_idx {
            last_best_cost = self.best[last_best_idx].cost;
        } else {
            last_best_cost = None;
        }

        let mut new_best_cost = last_best_cost;
        for i in 0..self.curr.len() {
            let curr = &mut self.curr[i];
            let best = &mut self.best[i];

            // we use <= here, so that the individual moves even if the cost
            // stays the same.
            if best.cost.is_none() || curr.cost.unwrap() <= best.cost.unwrap() {
                // find global best. We use < here so that global only updates when fitness changes.
                if new_best_cost.is_none() || curr.cost.unwrap() < new_best_cost.unwrap() {
                    self.best_idx = Some(i);
                    new_best_cost = curr.cost;
                }

                // replace individual's best. swap is *much* faster than clone.
                std::mem::swap(curr, best);
            }
        }

        // got a new best?
        last_best_cost.is_none() || new_best_cost.unwrap() < last_best_cost.unwrap()
    }

    fn update_positions(&mut self) {
        let global_best_pos = &self.best[self.best_idx.unwrap()].pos;
        let rng = &mut self.settings.rng;
        for i in 0..self.curr.len() {
            let mut id1 = self.between_popsize.ind_sample(rng);
            while id1 == i {
                id1 = self.between_popsize.ind_sample(rng);
            }

            let mut id2 = self.between_popsize.ind_sample(rng);
            while id2 == i || id2 == id1 {
                id2 = self.between_popsize.ind_sample(rng);
            }

            let curr = &mut self.curr[i];
            let best = &self.best[i];

            // see "Self-Adapting Control Parameters in Differential Evolution:
            // A Comparative Study on Numerical Benchmark Problems"
            if rng.gen::<f32>() < self.settings.cr_change_probability {
                curr.cr = self.between_cr.ind_sample(rng);
            } else {
                curr.cr = best.cr;
            }
            if rng.gen::<f32>() < self.settings.f_change_probability {
                curr.f = self.between_f.ind_sample(rng);
            } else {
                curr.f = best.f;
            }

            let curr_pos = &mut curr.pos;
            let best_pos = &best.pos;
            let best1_pos = &self.best[id1].pos;
            let best2_pos = &self.best[id2].pos;

            let forced_mutation_dim = self.between_dim.ind_sample(rng);
            for d in 0..self.dim {
                if d == forced_mutation_dim || rng.gen::<f32>() < curr.cr {
                    curr_pos[d] = global_best_pos[d] + curr.f * (best1_pos[d] - best2_pos[d]);
                } else {
                    curr_pos[d] = best_pos[d];
                }
            }

            // reset cost, has to be updated by the user.
            curr.cost = None;
        }
    }

    // Uses updated cost values to update positions of individuals.
    pub fn evolve(&mut self) -> Option<&Individual> {
        let found_new_best = self.update_best();
        self.update_positions();

        if found_new_best {
            Some(&self.best[self.best_idx.unwrap()])
        } else {
            None
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate rand;
    use super::*;
    use test::Bencher;
    use rand::{XorShiftRng, StdRng, IsaacRng, Isaac64Rng, Rng};
    use rand::{OsRng, weak_rng};

    fn setup<R: rand::Rng>(dim: usize, rng: R) -> Population<R> {
        let settings = Settings::min_max_rng(vec![-20.0; dim], vec![20.0; dim], rng);
        Population::new(settings)
    }

    fn dummy_fitness(individuals: &mut Vec<Individual>) {
        for ind in individuals {
            ind.cost = Some(1.234);
        }
    }

    #[bench]
    fn bench_square_fitness_opt(b: &mut Bencher) {
        let rng: XorShiftRng = OsRng::new().unwrap().gen();
        let mut pop = setup(5, rng);
        b.iter(|| {
            for ind in &mut pop.curr {
                let mut f = 0.0;
                for x in &ind.pos {
                    f += x * x;
                }
                ind.cost = Some(f);
            }
            pop.evolve();
        });
    }

    #[bench]
    fn rand_thread_rng(b: &mut Bencher) {
        let mut pop = setup(5, rand::thread_rng());
        b.iter(|| {
            dummy_fitness(&mut pop.curr);
            pop.evolve();
        });
    }

    #[bench]
    fn rand_xor_shift(b: &mut Bencher) {
        let rng: XorShiftRng = OsRng::new().unwrap().gen();
        let mut pop = setup(5, rng);
        b.iter(|| {
            dummy_fitness(&mut pop.curr);
            pop.evolve();
        });
    }

    #[bench]
    fn rand_isaac(b: &mut Bencher) {
        let rng: IsaacRng = OsRng::new().unwrap().gen();
        let mut pop = setup(5, rng);
        b.iter(|| {
            dummy_fitness(&mut pop.curr);
            pop.evolve();
        });
    }

    #[bench]
    fn rand_isaac64(b: &mut Bencher) {
        let rng: Isaac64Rng = OsRng::new().unwrap().gen();
        let mut pop = setup(5, rng);
        b.iter(|| {
            dummy_fitness(&mut pop.curr);
            pop.evolve();
        });
    }

    #[bench]
    fn rand_std(b: &mut Bencher) {
        let rng: StdRng = StdRng::new().unwrap();
        let mut pop = setup(5, rng);
        b.iter(|| {
            dummy_fitness(&mut pop.curr);
            pop.evolve();
        });
    }

    #[bench]
    fn rand_weak_rng(b: &mut Bencher) {
        let rng = weak_rng();
        let mut pop = setup(5, rng);
        b.iter(|| {
            dummy_fitness(&mut pop.curr);
            pop.evolve();
        });
    }

}
<|endoftext|>


<commit_before>extern crate mio;

use mio::tcp::*;
use mio::TryWrite;
use std::net::SocketAddr;
use std::io::Result;
use mio::{EventSet, EventLoop, Token, Handler, PollOpt};
//use std::thread;
//use std::thread::JoinHandle;
//use std::sync::{Arc, RwLock, Condvar};
//use std::sync::atomic::{AtomicBool, Ordering};

pub struct Client{
    socket: TcpStream,

    pub token: Token,

    interest: EventSet,

    send_queue: Vec<String>
}

impl Client{
    pub fn new(event_loop: &mut EventLoop<Client>, address: &SocketAddr) -> Result<Client>{
        let stream = TcpStream::connect(address);
        if stream.is_ok(){
            let mut client = Client {
                socket: stream.unwrap(),
                send_queue: Vec::new(),
                token: Token(0),
                interest: EventSet::readable()
            };

            client.register(event_loop).ok();

            return Ok(client);
        }
        else{
            Err(stream.unwrap_err())
        }
    }

    fn register(&mut self, event_loop: &mut EventLoop<Client>) -> Result<()>{
        event_loop.register(
            &self.socket,
            self.token,
            self.interest,
            PollOpt::edge()
        ).or_else(|e| {
            println!("Failed to register server! {:?}", e);
            Err(e)
        })
    }
}

impl Handler for Client{
    type Timeout = ();
    type Message = ();
}

#[test]
fn connect(){
    let addr = "127.0.0.1:6969".parse().unwrap();

    let mut event_loop = EventLoop::new().ok().expect("Failed to create event loop!");
    Client::new(&mut event_loop, &addr);
}

#[cfg(test)]
mod test {
    use mio::tcp::*;
    use mio::TryWrite;
    use std::net::SocketAddr;
    //use lag_client::Client;

}
<commit_msg>ok, I'm tired. At least this is sending stuff. Now just need to make it threaded or something<commit_after>extern crate mio;

use mio::tcp::*;
use mio::TryWrite;
use std::net::SocketAddr;
use std::io::Result;
use mio::{EventSet, EventLoop, Token, Handler, PollOpt};
//use std::thread;
//use std::thread::JoinHandle;
//use std::sync::{Arc, RwLock, Condvar};
//use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::atomic::{AtomicUsize, Ordering};

const CLIENT_TOKEN: mio::Token = mio::Token(1);

pub struct Client{
    socket: TcpStream,

    pub token: Token,

    interest: EventSet,

    send_queue: Vec<String>,

    debug: AtomicUsize
}

impl Client{
    pub fn new(event_loop: &mut EventLoop<Client>, address: &SocketAddr) -> Result<Client>{
        let stream = TcpStream::connect(address);
        if stream.is_ok(){
            let mut client = Client {
                socket: stream.unwrap(),
                send_queue: Vec::new(),
                token: CLIENT_TOKEN,
                interest: EventSet::readable() | EventSet::writable(),
                debug: AtomicUsize::new(0)
            };

            client.register(event_loop).ok();

            client.send_queue.push(String::from("Hell fucking yeah motherfucker"));
            client.send_queue.push(String::from("And so I wake in the morning"));
            client.send_queue.push(String::from("And I step outside"));
            client.send_queue.push(String::from("And I take a deep breath and I get real high"));
            client.send_queue.push(String::from("And I scream from the top of my lungs"));
            client.send_queue.push(String::from("What's going on?"));

            event_loop.run(&mut client).or_else(|e|{
                println!("Failed to start event loop!");
                Err(e)
            });

            return Ok(client);
        }
        else{
            Err(stream.unwrap_err())
        }
    }

    fn register(&mut self, event_loop: &mut EventLoop<Client>) -> Result<()>{
        event_loop.register(
            &self.socket,
            self.token,
            self.interest,
            PollOpt::edge() | PollOpt::oneshot()
        ).or_else(|e| {
            println!("Failed to register server! {:?}", e);
            Err(e)
        })
    }

    fn reregister(&mut self, event_loop: &mut EventLoop<Client>) -> Result<()>{
        event_loop.reregister(&self.socket, self.token, self.interest, PollOpt::edge())
            .or_else(|e|{
                println!("I am a sad panda, {:?}", e);
                Err(e)
        })
    }
}

impl Handler for Client{
    type Timeout = ();
    type Message = ();

    fn tick(&mut self, _: &mut EventLoop<Client>) {
        println!("Begin client tick");

        println!("End client tick");
    }

    fn ready(&mut self, event_loop: &mut EventLoop<Client>, token: Token, events: EventSet) {
        assert!(token != Token(0), "Token 0, y?????");

        if events.is_error(){
            println!("Client received error for token {:?}", token);
            return;
        }

        if events.is_hup(){
            println!("Oh shit, did the server crash or some shit?!");
            return;
        }

        if events.is_writable(){
            println!("TIME TO TALK MOTHERFUCKER");

            if !self.send_queue.is_empty(){
                if let Some(message) = self.send_queue.pop(){
                    match self.socket.try_write(message.as_bytes()){
                        Ok(Some(n)) => {
                            println!("Wrote {} bytes", n);
                        },
                        Ok(None) => {
                            println!("Nothing happened but it's okay I guess?");
                            self.send_queue.push(message);
                        },
                        Err(e) => {
                            println!("Oh fuck me god fucking damn it fucking shit fuck: {:?}", e);
                            self.send_queue.push(message);
                        }
                    };
                }
                else{
                    println!("Failed to pop message from queue!");
                }
                self.reregister(event_loop);
            }
            else{
                println!("WTF do you mean there's no messages for me?");
            }
        }

        if events.is_readable(){
            println!("OH shit, what've you got to say?");
        }

        self.debug.fetch_add(1, Ordering::SeqCst);
    }

    fn notify(&mut self, _: &mut EventLoop<Self>, _: Self::Message) {
        println!("Received notify!");
    }

    fn timeout(&mut self, _: &mut EventLoop<Self>, _: Self::Timeout) {
        println!("Received timeout");
    }
    fn interrupted(&mut self, _: &mut EventLoop<Self>) {
        println!("Interrupted! :O");
    }
}

#[test]
fn connect(){
    let addr = "127.0.0.1:6969".parse().unwrap();

    let mut event_loop = EventLoop::new().ok().expect("Failed to create event loop!");
    if let Ok(mut client) = Client::new(&mut event_loop, &addr){
        println!("Starting debug loop");

        loop{
            if client.debug.load(Ordering::Relaxed) > 0{
                break;
            }
        }

        println!("Done with this shit");
    }
    else{
        println!("Y u no client??");
    }
}

#[cfg(test)]
mod test {
    use mio::tcp::*;
    use mio::TryWrite;
    use std::net::SocketAddr;
    //use lag_client::Client;

}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//! Interface for the GPIO peripheral.
//!
//! To ensure fast performance, RPPAL interfaces with the GPIO peripheral by
//! directly accessing the registers through either `/dev/gpiomem` or `/dev/mem`.
//! GPIO interrupts are controlled using the `/dev/gpiochipN` character device.
//!
//! On a typical up-to-date Raspbian installation, any user that's a member of the
//! `gpio` group can access `/dev/gpiomem`, while `/dev/mem` requires
//! superuser privileges.
//!
//! Pins are addressed by their BCM GPIO pin numbers, rather than their
//! physical location.
//!
//! By default, all pins are reset to their original state when [`Gpio`] goes out
//! of scope. Use [`set_clear_on_drop(false)`] to disable this behavior. Note that
//! drop methods aren't called when a program is abnormally terminated (for
//! instance when a SIGINT isn't caught).
//!
//! Only a single instance of [`Gpio`] can exist at any time. Multiple instances of [`Gpio`]
//! can cause race conditions or pin configuration issues when several threads write to
//! the same register simultaneously. While other applications can't be prevented from
//! writing to the GPIO registers at the same time, limiting [`Gpio`] to a single instance
//! will at least make the Rust interface less error-prone.
//!
//! Constructing another instance before the existing one goes out of scope will return
//! an [`Error::InstanceExists`]. You can share a [`Gpio`] instance with other
//! threads using channels, cloning an `Arc<Mutex<Gpio>>` or globally sharing
//! a `Mutex<Gpio>`.
//!
//! [`Gpio`]: struct.Gpio.html
//! [`set_clear_on_drop(false)`]: struct.Gpio.html#method.set_clear_on_drop
//! [`Error::InstanceExists`]: enum.Error.html#variant.InstanceExists

use std::fmt;
use std::io;
use std::os::unix::io::AsRawFd;
use std::result;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;
use std::sync::{Arc, Mutex, MutexGuard};

use quick_error::quick_error;

mod epoll;
mod interrupt;
mod ioctl;
mod mem;
mod pin;

pub use self::pin::{InputPin, OutputPin};

// Used to limit Gpio to a single instance
static mut GPIO_INSTANCED: AtomicBool = AtomicBool::new(false);

quick_error! {
/// Errors that can occur when accessing the GPIO peripheral.
    #[derive(Debug)]
    pub enum Error {
/// Invalid GPIO pin number.
///
/// The GPIO pin number is not available on this Raspberry Pi model.
        InvalidPin(pin: u8) { description("invalid GPIO pin number") }
/// Unknown GPIO pin mode.
///
/// The GPIO pin is set to an unknown mode.
        UnknownMode(mode: u8) { description("unknown mode") }
/// Unknown SoC.
///
/// It wasn't possible to automatically identify the Raspberry Pi's SoC.
        UnknownSoC { description("unknown SoC") }
/// Permission denied when opening `/dev/gpiomem` and/or `/dev/mem` for read/write access.
///
/// Make sure the user has read and write access to `/dev/gpiomem`.
/// Common causes are either incorrect file permissions on `/dev/gpiomem`, or
/// the user isn't a member of the `gpio` group. If `/dev/gpiomem` is missing, upgrade to a more
/// recent version of Raspbian.
///
/// `/dev/mem` is a fallback when `/dev/gpiomem` can't be accessed. Getting read and write
/// access to `/dev/mem` is typically accomplished by executing the program as a
/// privileged user through `sudo`. A better solution that doesn't require `sudo` would be
/// to upgrade to a version of Raspbian that implements `/dev/gpiomem`.
        PermissionDenied { description("/dev/gpiomem and/or /dev/mem insufficient permissions") }
/// An instance of [`Gpio`] already exists.
///
/// Multiple instances of [`Gpio`] can cause race conditions or pin configuration issues when
/// several threads write to the same register simultaneously. While other applications
/// can't be prevented from writing to the GPIO registers at the same time, limiting [`Gpio`]
/// to a single instance will at least make the Rust interface less error-prone.
///
/// You can share a [`Gpio`] instance with other threads using channels, or cloning an
/// `Arc<Mutex<Gpio>>`. Although discouraged, you could also share it globally
/// wrapped in a `Mutex` using the `lazy_static` crate.
///
/// [`Gpio`]: struct.Gpio.html
        InstanceExists { description("an instance of Gpio already exists") }
/// IO error.
        Io(err: io::Error) { description(err.description()) from() }
/// Interrupt polling thread panicked.
        ThreadPanic { description("interrupt polling thread panicked") }
    }
}

/// Result type returned from methods that can have `rppal::gpio::Error`s.
pub type Result<T> = result::Result<T, Error>;

/// Pin modes.
#[derive(Debug, PartialEq, Copy, Clone)]
#[repr(u8)]
pub enum Mode {
    Input = 0b000,
    Output = 0b001,
    Alt5 = 0b010, // PWM
    Alt4 = 0b011, // SPI
    Alt0 = 0b100, // PCM
    Alt1 = 0b101, // SMI
    Alt2 = 0b110, // ---
    Alt3 = 0b111, // BSC-SPI
}

impl fmt::Display for Mode {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Mode::Input => write!(f, "In"),
            Mode::Output => write!(f, "Out"),
            Mode::Alt0 => write!(f, "Alt0"),
            Mode::Alt1 => write!(f, "Alt1"),
            Mode::Alt2 => write!(f, "Alt2"),
            Mode::Alt3 => write!(f, "Alt3"),
            Mode::Alt4 => write!(f, "Alt4"),
            Mode::Alt5 => write!(f, "Alt5"),
        }
    }
}

/// Pin logic levels.
#[derive(Debug, PartialEq, Copy, Clone)]
#[repr(u8)]
pub enum Level {
    Low = 0,
    High = 1,
}

impl fmt::Display for Level {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Level::Low => write!(f, "Low"),
            Level::High => write!(f, "High"),
        }
    }
}

/// Built-in pull-up/pull-down resistor states.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum PullUpDown {
    Off = 0b00,
    PullDown = 0b01,
    PullUp = 0b10,
}

impl fmt::Display for PullUpDown {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            PullUpDown::Off => write!(f, "Off"),
            PullUpDown::PullDown => write!(f, "PullDown"),
            PullUpDown::PullUp => write!(f, "PullUp"),
        }
    }
}

/// Interrupt trigger conditions.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Trigger {
    Disabled = 0,
    RisingEdge = 1,
    FallingEdge = 2,
    Both = 3,
}

impl fmt::Display for Trigger {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Trigger::Disabled => write!(f, "Disabled"),
            Trigger::RisingEdge => write!(f, "RisingEdge"),
            Trigger::FallingEdge => write!(f, "FallingEdge"),
            Trigger::Both => write!(f, "Both"),
        }
    }
}

/// Provides access to the Raspberry Pi's GPIO peripheral.
pub struct Gpio {
    clear_on_drop: bool,
    pub(crate) gpio_mem: Arc<mem::GpioMem>,
    pins: [Arc<Mutex<pin::Pin>>; pin::MAX],
    sync_interrupts: Arc<Mutex<interrupt::EventLoop>>,
}

impl Gpio {
    /// Constructs a new `Gpio`.
    ///
    /// Only a single instance of `Gpio` can exist at any time. Constructing
    /// another instance before the existing one goes out of scope will return
    /// an [`Error::InstanceExists`]. You can share a `Gpio` instance with other
    /// threads using channels, cloning an `Arc<Mutex<Gpio>>` or globally sharing
    /// a `Mutex<Gpio>`.
    ///
    /// [`Error::InstanceExists`]: enum.Error.html#variant.InstanceExists
    pub fn new() -> Result<Gpio> {
        // Check if a Gpio instance already exists before initializing everything
        unsafe {
            if GPIO_INSTANCED.load(Ordering::SeqCst) {
                return Err(Error::InstanceExists);
            }
        }

        let cdev = ioctl::find_driver()?;
        let cdev_fd = cdev.as_raw_fd();

        let cdev = Arc::new(cdev);
        let event_loop = Arc::new(Mutex::new(interrupt::EventLoop::new(cdev_fd, pin::MAX)?));
        let gpio_mem = Arc::new(mem::GpioMem::open()?);

        let pins = unsafe {
            let mut pins: [Arc<Mutex<pin::Pin>>; pin::MAX] = std::mem::uninitialized();

            for (i, element) in pins.iter_mut().enumerate() {
                let pin = Arc::new(Mutex::new(pin::Pin::new(i as u8, event_loop.clone(), gpio_mem.clone(), cdev.clone())));
                std::ptr::write(element, pin)
            }

            pins
        };

        let gpio = Gpio {
            clear_on_drop: true,
            gpio_mem: gpio_mem,
            pins: pins,
            sync_interrupts: event_loop,
        };

        unsafe {
            // Returns true if GPIO_INSTANCED was set to true on a different thread
            // while we were still initializing ourselves, otherwise atomically sets
            // it to true here
            if GPIO_INSTANCED.compare_and_swap(false, true, Ordering::SeqCst) {
                return Err(Error::InstanceExists);
            }
        }

        Ok(gpio)
    }

    pub fn get_pin(&self, pin: u8) -> Option<MutexGuard<pin::Pin>> {
        if pin as usize >= pin::MAX {
            None
        } else {
            Some(self.pins[pin as usize].lock().unwrap())
        }
    }

    /// Blocks until a synchronous interrupt is triggered on any of the specified pins, or a timeout occurs.
    ///
    /// `poll_interrupts` only works for pins that have been configured for synchronous interrupts using
    /// [`set_interrupt`]. Asynchronous interrupt triggers are automatically polled on a separate thread.
    ///
    /// Setting `reset` to `false` causes `poll_interrupts` to return immediately if any of the interrupts
    /// has been triggered since the previous call to [`set_interrupt`] or `poll_interrupts`.
    /// Setting `reset` to `true` clears any cached trigger events for the pins.
    ///
    /// The `timeout` duration indicates how long the call to `poll_interrupts` will block while waiting
    /// for interrupt trigger events, after which an `Ok(None))` is returned.
    /// `timeout` can be set to `None` to wait indefinitely.
    ///
    /// When an interrupt event is triggered, `poll_interrupts` returns
    /// `Ok((u8, Level))` containing the corresponding pin number and logic level. If multiple events trigger
    /// at the same time, only the first one is returned. The remaining events are cached and will be returned
    /// the next time `poll_interrupts` is called.
    ///
    /// [`set_interrupt`]: #method.set_interrupt
    pub fn poll_interrupts<'a>(
      &self,
      pins: &[&'a InputPin<'a>],
      reset: bool,
      timeout: Option<Duration>,
    ) -> Result<Option<(&'a InputPin<'a>, Level)>> {
      (*self.sync_interrupts.lock().unwrap()).poll(pins, reset, timeout)
    }
  }

impl Drop for Gpio {
    fn drop(&mut self) {
        unsafe {
            GPIO_INSTANCED.store(false, Ordering::SeqCst);
        }
    }
}

impl fmt::Debug for Gpio {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Gpio")
            .field("clear_on_drop", &self.clear_on_drop)
            .field("gpio_mem", &*self.gpio_mem)
            .field("sync_interrupts", &format_args!("{{ .. }}"))
            .finish()
    }
}
<commit_msg>Also re-export `Pin` and `AltPin`.<commit_after>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//! Interface for the GPIO peripheral.
//!
//! To ensure fast performance, RPPAL interfaces with the GPIO peripheral by
//! directly accessing the registers through either `/dev/gpiomem` or `/dev/mem`.
//! GPIO interrupts are controlled using the `/dev/gpiochipN` character device.
//!
//! On a typical up-to-date Raspbian installation, any user that's a member of the
//! `gpio` group can access `/dev/gpiomem`, while `/dev/mem` requires
//! superuser privileges.
//!
//! Pins are addressed by their BCM GPIO pin numbers, rather than their
//! physical location.
//!
//! By default, all pins are reset to their original state when [`Gpio`] goes out
//! of scope. Use [`set_clear_on_drop(false)`] to disable this behavior. Note that
//! drop methods aren't called when a program is abnormally terminated (for
//! instance when a SIGINT isn't caught).
//!
//! Only a single instance of [`Gpio`] can exist at any time. Multiple instances of [`Gpio`]
//! can cause race conditions or pin configuration issues when several threads write to
//! the same register simultaneously. While other applications can't be prevented from
//! writing to the GPIO registers at the same time, limiting [`Gpio`] to a single instance
//! will at least make the Rust interface less error-prone.
//!
//! Constructing another instance before the existing one goes out of scope will return
//! an [`Error::InstanceExists`]. You can share a [`Gpio`] instance with other
//! threads using channels, cloning an `Arc<Mutex<Gpio>>` or globally sharing
//! a `Mutex<Gpio>`.
//!
//! [`Gpio`]: struct.Gpio.html
//! [`set_clear_on_drop(false)`]: struct.Gpio.html#method.set_clear_on_drop
//! [`Error::InstanceExists`]: enum.Error.html#variant.InstanceExists

use std::fmt;
use std::io;
use std::os::unix::io::AsRawFd;
use std::result;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;
use std::sync::{Arc, Mutex, MutexGuard};

use quick_error::quick_error;

mod epoll;
mod interrupt;
mod ioctl;
mod mem;
mod pin;

pub use self::pin::{Pin, InputPin, OutputPin, AltPin};

// Used to limit Gpio to a single instance
static mut GPIO_INSTANCED: AtomicBool = AtomicBool::new(false);

quick_error! {
/// Errors that can occur when accessing the GPIO peripheral.
    #[derive(Debug)]
    pub enum Error {
/// Invalid GPIO pin number.
///
/// The GPIO pin number is not available on this Raspberry Pi model.
        InvalidPin(pin: u8) { description("invalid GPIO pin number") }
/// Unknown GPIO pin mode.
///
/// The GPIO pin is set to an unknown mode.
        UnknownMode(mode: u8) { description("unknown mode") }
/// Unknown SoC.
///
/// It wasn't possible to automatically identify the Raspberry Pi's SoC.
        UnknownSoC { description("unknown SoC") }
/// Permission denied when opening `/dev/gpiomem` and/or `/dev/mem` for read/write access.
///
/// Make sure the user has read and write access to `/dev/gpiomem`.
/// Common causes are either incorrect file permissions on `/dev/gpiomem`, or
/// the user isn't a member of the `gpio` group. If `/dev/gpiomem` is missing, upgrade to a more
/// recent version of Raspbian.
///
/// `/dev/mem` is a fallback when `/dev/gpiomem` can't be accessed. Getting read and write
/// access to `/dev/mem` is typically accomplished by executing the program as a
/// privileged user through `sudo`. A better solution that doesn't require `sudo` would be
/// to upgrade to a version of Raspbian that implements `/dev/gpiomem`.
        PermissionDenied { description("/dev/gpiomem and/or /dev/mem insufficient permissions") }
/// An instance of [`Gpio`] already exists.
///
/// Multiple instances of [`Gpio`] can cause race conditions or pin configuration issues when
/// several threads write to the same register simultaneously. While other applications
/// can't be prevented from writing to the GPIO registers at the same time, limiting [`Gpio`]
/// to a single instance will at least make the Rust interface less error-prone.
///
/// You can share a [`Gpio`] instance with other threads using channels, or cloning an
/// `Arc<Mutex<Gpio>>`. Although discouraged, you could also share it globally
/// wrapped in a `Mutex` using the `lazy_static` crate.
///
/// [`Gpio`]: struct.Gpio.html
        InstanceExists { description("an instance of Gpio already exists") }
/// IO error.
        Io(err: io::Error) { description(err.description()) from() }
/// Interrupt polling thread panicked.
        ThreadPanic { description("interrupt polling thread panicked") }
    }
}

/// Result type returned from methods that can have `rppal::gpio::Error`s.
pub type Result<T> = result::Result<T, Error>;

/// Pin modes.
#[derive(Debug, PartialEq, Copy, Clone)]
#[repr(u8)]
pub enum Mode {
    Input = 0b000,
    Output = 0b001,
    Alt5 = 0b010, // PWM
    Alt4 = 0b011, // SPI
    Alt0 = 0b100, // PCM
    Alt1 = 0b101, // SMI
    Alt2 = 0b110, // ---
    Alt3 = 0b111, // BSC-SPI
}

impl fmt::Display for Mode {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Mode::Input => write!(f, "In"),
            Mode::Output => write!(f, "Out"),
            Mode::Alt0 => write!(f, "Alt0"),
            Mode::Alt1 => write!(f, "Alt1"),
            Mode::Alt2 => write!(f, "Alt2"),
            Mode::Alt3 => write!(f, "Alt3"),
            Mode::Alt4 => write!(f, "Alt4"),
            Mode::Alt5 => write!(f, "Alt5"),
        }
    }
}

/// Pin logic levels.
#[derive(Debug, PartialEq, Copy, Clone)]
#[repr(u8)]
pub enum Level {
    Low = 0,
    High = 1,
}

impl fmt::Display for Level {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Level::Low => write!(f, "Low"),
            Level::High => write!(f, "High"),
        }
    }
}

/// Built-in pull-up/pull-down resistor states.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum PullUpDown {
    Off = 0b00,
    PullDown = 0b01,
    PullUp = 0b10,
}

impl fmt::Display for PullUpDown {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            PullUpDown::Off => write!(f, "Off"),
            PullUpDown::PullDown => write!(f, "PullDown"),
            PullUpDown::PullUp => write!(f, "PullUp"),
        }
    }
}

/// Interrupt trigger conditions.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Trigger {
    Disabled = 0,
    RisingEdge = 1,
    FallingEdge = 2,
    Both = 3,
}

impl fmt::Display for Trigger {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Trigger::Disabled => write!(f, "Disabled"),
            Trigger::RisingEdge => write!(f, "RisingEdge"),
            Trigger::FallingEdge => write!(f, "FallingEdge"),
            Trigger::Both => write!(f, "Both"),
        }
    }
}

/// Provides access to the Raspberry Pi's GPIO peripheral.
pub struct Gpio {
    clear_on_drop: bool,
    pub(crate) gpio_mem: Arc<mem::GpioMem>,
    pins: [Arc<Mutex<pin::Pin>>; pin::MAX],
    sync_interrupts: Arc<Mutex<interrupt::EventLoop>>,
}

impl Gpio {
    /// Constructs a new `Gpio`.
    ///
    /// Only a single instance of `Gpio` can exist at any time. Constructing
    /// another instance before the existing one goes out of scope will return
    /// an [`Error::InstanceExists`]. You can share a `Gpio` instance with other
    /// threads using channels, cloning an `Arc<Mutex<Gpio>>` or globally sharing
    /// a `Mutex<Gpio>`.
    ///
    /// [`Error::InstanceExists`]: enum.Error.html#variant.InstanceExists
    pub fn new() -> Result<Gpio> {
        // Check if a Gpio instance already exists before initializing everything
        unsafe {
            if GPIO_INSTANCED.load(Ordering::SeqCst) {
                return Err(Error::InstanceExists);
            }
        }

        let cdev = ioctl::find_driver()?;
        let cdev_fd = cdev.as_raw_fd();

        let cdev = Arc::new(cdev);
        let event_loop = Arc::new(Mutex::new(interrupt::EventLoop::new(cdev_fd, pin::MAX)?));
        let gpio_mem = Arc::new(mem::GpioMem::open()?);

        let pins = unsafe {
            let mut pins: [Arc<Mutex<pin::Pin>>; pin::MAX] = std::mem::uninitialized();

            for (i, element) in pins.iter_mut().enumerate() {
                let pin = Arc::new(Mutex::new(pin::Pin::new(i as u8, event_loop.clone(), gpio_mem.clone(), cdev.clone())));
                std::ptr::write(element, pin)
            }

            pins
        };

        let gpio = Gpio {
            clear_on_drop: true,
            gpio_mem: gpio_mem,
            pins: pins,
            sync_interrupts: event_loop,
        };

        unsafe {
            // Returns true if GPIO_INSTANCED was set to true on a different thread
            // while we were still initializing ourselves, otherwise atomically sets
            // it to true here
            if GPIO_INSTANCED.compare_and_swap(false, true, Ordering::SeqCst) {
                return Err(Error::InstanceExists);
            }
        }

        Ok(gpio)
    }

    pub fn get_pin(&self, pin: u8) -> Option<MutexGuard<pin::Pin>> {
        if pin as usize >= pin::MAX {
            None
        } else {
            Some(self.pins[pin as usize].lock().unwrap())
        }
    }

    /// Blocks until a synchronous interrupt is triggered on any of the specified pins, or a timeout occurs.
    ///
    /// `poll_interrupts` only works for pins that have been configured for synchronous interrupts using
    /// [`set_interrupt`]. Asynchronous interrupt triggers are automatically polled on a separate thread.
    ///
    /// Setting `reset` to `false` causes `poll_interrupts` to return immediately if any of the interrupts
    /// has been triggered since the previous call to [`set_interrupt`] or `poll_interrupts`.
    /// Setting `reset` to `true` clears any cached trigger events for the pins.
    ///
    /// The `timeout` duration indicates how long the call to `poll_interrupts` will block while waiting
    /// for interrupt trigger events, after which an `Ok(None))` is returned.
    /// `timeout` can be set to `None` to wait indefinitely.
    ///
    /// When an interrupt event is triggered, `poll_interrupts` returns
    /// `Ok((u8, Level))` containing the corresponding pin number and logic level. If multiple events trigger
    /// at the same time, only the first one is returned. The remaining events are cached and will be returned
    /// the next time `poll_interrupts` is called.
    ///
    /// [`set_interrupt`]: #method.set_interrupt
    pub fn poll_interrupts<'a>(
      &self,
      pins: &[&'a InputPin<'a>],
      reset: bool,
      timeout: Option<Duration>,
    ) -> Result<Option<(&'a InputPin<'a>, Level)>> {
      (*self.sync_interrupts.lock().unwrap()).poll(pins, reset, timeout)
    }
  }

impl Drop for Gpio {
    fn drop(&mut self) {
        unsafe {
            GPIO_INSTANCED.store(false, Ordering::SeqCst);
        }
    }
}

impl fmt::Debug for Gpio {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Gpio")
            .field("clear_on_drop", &self.clear_on_drop)
            .field("gpio_mem", &*self.gpio_mem)
            .field("sync_interrupts", &format_args!("{{ .. }}"))
            .finish()
    }
}
<|endoftext|>


<commit_before>extern crate libloading as libl;

use std::collections::HashMap;
use std::ffi::CString;
use std::io;
use std::os::raw::{c_char, c_int, c_uint, c_void};

fn to_c_str<T: Into<Vec<u8>>>(t: T) -> *const c_char {
    CString::new(t).unwrap().as_ptr() as *const c_char
}

pub struct CoreClr {
    host_handle: *const c_void,
    domain_id: c_uint
}

pub type CoreClrInitializeFn = unsafe extern fn(
    *const c_char,
    *const c_char,
    c_int,
    *const *const c_char,
    *const *const c_char,
    *const *const c_void,
    *const c_uint) -> c_int;

pub type CoreClrShutdownFn = unsafe extern fn(*const c_void, c_uint) -> c_int;
pub type CoreClrShutdown2Fn = unsafe extern fn(*const c_void, c_uint, *const c_int) -> c_int;

impl CoreClr {
    fn library() -> libl::Result<libl::Library> {
        libl::Library::new("/usr/local/share/dotnet/shared/Microsoft.NETCore.App/2.0.0")
    }

    pub fn init(
        exe_path: &str,
        app_domain_friendly_name: &str,
        properties_option: Option<HashMap<&str, &str>>) -> libl::Result<CoreClr>
    {
        // Create the host handle and its ref
        let host_handle = 0 as *const c_void;
        let host_handle_ref = &host_handle as *const *const c_void;

        // Create the domain id and its ref
        let domain_id = 0 as c_uint;
        let domain_id_ref = &domain_id as *const c_uint;

        // Raw C string refs from exe_path and app_domain_friendly_name slices
        let exe_path_raw = to_c_str(exe_path);
        let app_domain_friendly_name_raw = to_c_str(app_domain_friendly_name);

        // Either use the provided option or a blank hashmap
        let properties = properties_option.unwrap_or_else(HashMap::new);

        // Count for upcoming vecs
        let properties_count = properties.len() as c_int;

        // Collect property keys into a vec
        let properties_keys: Vec<*const c_char> = properties.keys()
                .map(|&k| to_c_str(k))
                .collect();

        // Collect equivalent property values into another vec
        let properties_values: Vec<*const c_char> = properties.values()
                .map(|&v| to_c_str(v))
                .collect();

        // Grab refs of the two to pass into the actual function call
        let properties_keys_ref = &properties_keys[0] as *const *const c_char;
        let properties_values_ref = &properties_values[0] as *const *const c_char;

        unsafe {
            let coreclr_library = CoreClr::library()?;
            let coreclr_initialize_fn: libl::Symbol<CoreClrInitializeFn> = coreclr_library.get(b"coreclr_initialize")?;

            match coreclr_initialize_fn(
                exe_path_raw,
                app_domain_friendly_name_raw,
                properties_count,
                properties_keys_ref,
                properties_values_ref,
                host_handle_ref,
                domain_id_ref)
            {
                0 => Ok(CoreClr {
                    host_handle: host_handle,
                    domain_id: domain_id
                }),
                _ => panic!("Failed to initialize")
            }
        }
    }

    pub fn shutdown(self: Self) -> io::Result<()> {
        unsafe {
            let coreclr_library = CoreClr::library()?;
            let coreclr_shutdown_fn: libl::Symbol<CoreClrShutdownFn> = coreclr_library.get(b"coreclr_shutdown")?;

            match coreclr_shutdown_fn(self.host_handle, self.domain_id) {
                0 => Ok(()),
                _ => panic!("Failed to shutdown")
            }
        }
    }

    pub fn shutdown_2(self: Self) -> io::Result<c_int> {
        let latched_exit_code = -1 as c_int;
        let latched_exit_code_ref = &latched_exit_code as *const c_int;

        unsafe {
            let coreclr_library = CoreClr::library()?;
            let coreclr_shutdown_2_fn: libl::Symbol<CoreClrShutdown2Fn> = coreclr_library.get(b"coreclr_shutdown_2")?;

            match coreclr_shutdown_2_fn(self.host_handle, self.domain_id, latched_exit_code_ref) {
                0 => Ok(latched_exit_code),
                _ => panic!("Failed to shutdown")
            }
        }
    }
}<commit_msg>Organizing code before documentation<commit_after>extern crate libloading as libl;

use std::collections::HashMap;
use std::ffi::CString;
use std::io;
use std::os::raw::{c_char, c_int, c_uint, c_void};

// -- Private utility functions -- //
fn to_c_str<T: Into<Vec<u8>>>(t: T) -> *const c_char {
    CString::new(t).unwrap().as_ptr() as *const c_char
}

// -- Model the functions we'll dynamically load -- //
pub type CoreClrInitializeFn = unsafe extern fn(
    *const c_char,
    *const c_char,
    c_int,
    *const *const c_char,
    *const *const c_char,
    *const *const c_void,
    *const c_uint) -> c_int;

pub type CoreClrShutdownFn = unsafe extern fn(*const c_void, c_uint) -> c_int;

pub type CoreClrShutdown2Fn = unsafe extern fn(*const c_void, c_uint, *const c_int) -> c_int;

// -- Model the CLR -- //
pub struct CoreClr {
    host_handle: *const c_void,
    domain_id: c_uint
}

impl CoreClr {
    fn library() -> libl::Result<libl::Library> {
        libl::Library::new("/usr/local/share/dotnet/shared/Microsoft.NETCore.App/2.0.0")
    }

    pub fn init(
        exe_path: &str,
        app_domain_friendly_name: &str,
        properties_option: Option<HashMap<&str, &str>>) -> libl::Result<CoreClr>
    {
        // Create the host handle and its ref
        let host_handle = 0 as *const c_void;
        let host_handle_ref = &host_handle as *const *const c_void;

        // Create the domain id and its ref
        let domain_id = 0 as c_uint;
        let domain_id_ref = &domain_id as *const c_uint;

        // Raw C string refs from exe_path and app_domain_friendly_name slices
        let exe_path_raw = to_c_str(exe_path);
        let app_domain_friendly_name_raw = to_c_str(app_domain_friendly_name);

        // Either use the provided option or a blank hashmap
        let properties = properties_option.unwrap_or_else(HashMap::new);

        // Count for upcoming vecs
        let properties_count = properties.len() as c_int;

        // Collect property keys into a vec
        let properties_keys: Vec<*const c_char> = properties.keys()
                .map(|&k| to_c_str(k))
                .collect();

        // Collect equivalent property values into another vec
        let properties_values: Vec<*const c_char> = properties.values()
                .map(|&v| to_c_str(v))
                .collect();

        // Grab refs of the two to pass into the actual function call
        let properties_keys_ref = &properties_keys[0] as *const *const c_char;
        let properties_values_ref = &properties_values[0] as *const *const c_char;

        // Open up an unsafe block for actually loading functions from the CLR libs
        unsafe {
            let coreclr_library = CoreClr::library()?;
            let coreclr_initialize: libl::Symbol<CoreClrInitializeFn> = coreclr_library.get(b"coreclr_initialize")?;

            // Initialize the CLR
            match coreclr_initialize(
                exe_path_raw,
                app_domain_friendly_name_raw,
                properties_count,
                properties_keys_ref,
                properties_values_ref,
                host_handle_ref,
                domain_id_ref)
            {
                // If healthy exit code, return a model of the CLR
                0 => Ok(CoreClr {
                    host_handle: host_handle,
                    domain_id: domain_id
                }),
                // Else panic
                _ => panic!("Failed to initialize")
            }
        }
    }

    pub fn shutdown(self: Self) -> io::Result<()> {
        unsafe {
            let coreclr_library = CoreClr::library()?;
            let coreclr_shutdown_fn: libl::Symbol<CoreClrShutdownFn> = coreclr_library.get(b"coreclr_shutdown")?;

            // Shutdown the CLR
            match coreclr_shutdown_fn(self.host_handle, self.domain_id) {
                // If healthy exit code, return unit
                0 => Ok(()),
                // Else panic
                _ => panic!("Failed to shutdown")
            }
        }
    }

    pub fn shutdown_2(self: Self) -> io::Result<c_int> {
        let latched_exit_code = -1 as c_int;
        let latched_exit_code_ref = &latched_exit_code as *const c_int;

        unsafe {
            let coreclr_library = CoreClr::library()?;
            let coreclr_shutdown_2_fn: libl::Symbol<CoreClrShutdown2Fn> = coreclr_library.get(b"coreclr_shutdown_2")?;

            // Shutdown the CLR
            match coreclr_shutdown_2_fn(self.host_handle, self.domain_id, latched_exit_code_ref) {
                // If healthy exit code, return the resulting exit code
                0 => Ok(latched_exit_code),
                // Else panic
                _ => panic!("Failed to shutdown")
            }
        }
    }
}<|endoftext|>


<commit_before>//! Low level and internal http and https implementation.

use std::collections::HashMap;

use async_std::io::{stderr, Read, Result as IoResult, Write};
use async_std::net::{SocketAddr, TcpStream};
use async_std::prelude::*;
use log::Level::Info;

use super::asynctls::TLSStream;
use super::constants;
use super::dns::Resolver;
use super::request::Request;
use super::results::{CabotError, CabotResult};

#[derive(Debug, PartialEq)]
enum TransferEncoding {
    ContentLength(usize),
    Chunked,
    Unkown,
    None,
}

#[derive(Debug, PartialEq)]
enum TransferEncodingStatus {
    ReadingHeader,
    ChunkHeader,
    ReadingBody(usize),
}

impl From<&[u8]> for TransferEncoding {
    fn from(hdr: &[u8]) -> Self {
        let hdr = String::from_utf8_lossy(hdr);
        let hdrup = hdr.to_ascii_uppercase();
        match hdrup.as_str() {
            "CHUNKED" => TransferEncoding::Chunked,
            _ => TransferEncoding::Unkown,
        }
    }
}

struct HttpDecoder<'a> {
    reader: &'a mut (dyn Read + Unpin), // tls require Write
    writer: &'a mut (dyn Write + Unpin),
    buffer: Vec<u8>,
    transfer_encoding: TransferEncoding,
    transfer_encoding_status: TransferEncodingStatus,
}

impl<'a> HttpDecoder<'a> {
    fn new(writer: &'a mut (dyn Write + Unpin), reader: &'a mut (dyn Read + Unpin)) -> Self {
        HttpDecoder {
            writer,
            reader,
            buffer: Vec::with_capacity(constants::BUFFER_PAGE_SIZE),
            transfer_encoding: TransferEncoding::None,
            transfer_encoding_status: TransferEncodingStatus::ReadingHeader,
        }
    }

    async fn chunk_read(&mut self) -> IoResult<usize> {
        let mut buf = [0; constants::BUFFER_PAGE_SIZE];
        let ret = self.reader.read(&mut buf[..]).await;
        if let Ok(count) = ret {
            if count > 0 {
                self.buffer.extend_from_slice(&buf[0..count]);
            }
        }
        ret
    }
    async fn read_write_headers(&mut self) -> IoResult<()> {
        info!("Reading headers");
        loop {
            let _count = self.chunk_read().await?;
            if let Some(_) = self.process_headers().await {
                break;
            }
        }
        Ok(())
    }

    async fn read_write_no_transfer_encoding(&mut self) -> IoResult<()> {
        loop {
            self.writer.write(self.buffer.as_slice()).await.unwrap();
            self.buffer.clear();
            let cnt = self.chunk_read().await?;
            if cnt == 0 {
                break;
            }
        }

        Ok(())
    }

    async fn read_content_length(&mut self, size: usize) -> IoResult<()> {
        let mut read_count = self.buffer.len();
        loop {
            self.writer.write(self.buffer.as_slice()).await.unwrap();
            self.buffer.clear();

            if read_count >= size {
                break;
            }
            read_count = read_count + self.chunk_read().await?;
            warn!("< {}", read_count);
        }
        Ok(())
    }

    async fn read_write_chunk(&mut self) -> IoResult<()> {
        loop {
            let done = self.process_chunk().await?;
            if done {
                break;
            }
            let cnt = self.chunk_read().await?;
            if cnt == 0 {
                break;
            }
        }

        Ok(())
    }

    async fn read_write_body(&mut self) -> IoResult<()> {
        info!("Reading body");
        match self.transfer_encoding {
            TransferEncoding::ContentLength(size) => {
                self.read_content_length(size).await?;
            }
            TransferEncoding::Chunked => {
                self.read_write_chunk().await?;
            }
            _ => {
                warn!("Neither Content-Length, not chunk is response header");
                self.read_write_no_transfer_encoding().await?;
            }
        }

        if self.buffer.len() > 0 {
            let b = String::from_utf8_lossy(self.buffer.as_slice());
            error!("Buffer not clear: {}", b);
        }

        Ok(())
    }

    async fn read_write(&mut self) -> IoResult<()> {
        self.read_write_headers().await?;
        self.read_write_body().await?;
        self.writer.flush().await
    }

    async fn process_headers(&mut self) -> Option<usize> {
        let ret = {
            let resp_header: Vec<&[u8]> = constants::SPLIT_HEADERS_RE
                .splitn(self.buffer.as_slice(), 2)
                .collect();
            if resp_header.len() == 2 {
                // We have headers
                let headers = resp_header.get(0).unwrap();
                if let Some(header) = constants::TRANSFER_ENCODING.captures(headers) {
                    if let Some(tenc) = header.get(1) {
                        self.transfer_encoding = TransferEncoding::from(tenc.as_bytes());
                    }
                } else if let Some(header) = constants::CONTENT_LENGTH.captures(headers) {
                    if let Some(clength) = header.get(1) {
                        let clength = String::from_utf8_lossy(clength.as_bytes()).into_owned();
                        let clength = usize::from_str_radix(clength.as_str(), 10).unwrap();
                        self.transfer_encoding = TransferEncoding::ContentLength(clength);
                    }
                }
                let resp = headers.len();
                self.writer.write(headers).await.unwrap();
                Some(resp + 4) // + CRLF CRLF
            } else {
                None
            }
        };
        if let Some(to_drain) = ret {
            let buffer = self.buffer.drain(to_drain..).collect();
            self.buffer = buffer;
            info!("End of Headers readched");
            debug!("Transfer encoding: {:?}", self.transfer_encoding);
            debug!("{:?}", String::from_utf8_lossy(self.buffer.as_slice()));
        }
        ret
    }
    async fn process_chunk(&mut self) -> IoResult<bool> {
        debug!(
            "transfer_encoding_status: {:?}",
            self.transfer_encoding_status
        );
        let mut can_process_buffer = self.buffer.len() > 0;
        let mut body_chunk_size = 0;
        let mut header_len: usize;
        while can_process_buffer {
            header_len = 0;
            if self.transfer_encoding_status == TransferEncodingStatus::ReadingHeader {
                // we read the chunk size to drain
                let header: Vec<&[u8]> = constants::SPLIT_HEADER_BRE
                    .splitn(self.buffer.as_slice(), 2)
                    .collect();
                if header.len() == 2 {
                    if let Some(header) = constants::GET_CHUNK_SIZE.captures(header[0]) {
                        if let Some(size) = header.get(1) {
                            let size = size.as_bytes();
                            header_len = size.len() + 2;
                            let size = String::from_utf8_lossy(size).into_owned();
                            body_chunk_size = usize::from_str_radix(size.as_str(), 16).unwrap();
                            self.transfer_encoding_status = TransferEncodingStatus::ChunkHeader;
                        }
                    } else {
                        // else return Error
                        // break;
                    }
                } else {
                    debug!(
                        "Chunked not complete: {}",
                        String::from_utf8_lossy(self.buffer.as_slice())
                    );
                }
            }

            if self.transfer_encoding_status == TransferEncodingStatus::ChunkHeader {
                if body_chunk_size == 0 {
                    debug!(
                        "0 chunked size received: {}",
                        String::from_utf8_lossy(self.buffer.as_slice())
                    );
                    self.buffer.clear(); // should we check that it is '0\r\n' ?
                    return Ok(true);
                }

                debug!(
                    "Before header cleanup: {}",
                    String::from_utf8_lossy(self.buffer.as_slice())
                );
                let buffer: Vec<u8> = self.buffer.drain(header_len..).collect();
                self.buffer = buffer;
                debug!(
                    "After header cleanup: {}",
                    String::from_utf8_lossy(self.buffer.as_slice())
                );
                self.transfer_encoding_status =
                    TransferEncodingStatus::ReadingBody(body_chunk_size);
            }

            if let TransferEncodingStatus::ReadingBody(body_chunk_size) =
                self.transfer_encoding_status
            {
                error!("!! {} > {}", self.buffer.len(), body_chunk_size);
                if self.buffer.len() > body_chunk_size {
                    let mut buffer: Vec<u8> = self.buffer.drain(body_chunk_size..).collect();
                    self.writer.write(self.buffer.as_slice()).await?;

                    let buffer2 = buffer.drain(2..).collect(); // CRLF
                    self.buffer = buffer2;
                    self.transfer_encoding_status = TransferEncodingStatus::ReadingHeader;
                } else {
                    can_process_buffer = false;
                }
            } else {
                can_process_buffer = false;
            }
        }

        return Ok(false);
    }
}

async fn log_request(request: &[u8], verbose: bool) {
    if !log_enabled!(Info) && !verbose {
        return;
    }
    let request: Vec<&[u8]> = constants::SPLIT_HEADERS_RE.splitn(request, 2).collect();
    let headers = String::from_utf8_lossy(&request[0]);
    let headers: Vec<&str> = constants::SPLIT_HEADER_RE.split(&headers).collect();
    let bodylen = if request.len() == 2 {
        let body = &request[1];
        body.len()
    } else {
        0
    };
    if log_enabled!(Info) {
        for header in headers {
            info!("> {}", header);
        }
        if bodylen > 0 {
            info!("> [{} bytes]", bodylen);
        }
        info!(">");
    } else if verbose {
        for header in headers {
            writeln!(&mut stderr(), "> {}", header).await.unwrap();
        }
        if bodylen > 0 {
            writeln!(&mut stderr(), "> [{} bytes]", bodylen)
                .await
                .unwrap();
        }
        writeln!(&mut stderr(), ">").await.unwrap();
    }
}

async fn from_http(
    request: &Request,
    client: &mut TcpStream,
    out: &mut (dyn Write + Unpin),
    verbose: bool,
) -> CabotResult<()> {
    let request_bytes = request.to_bytes();
    let raw_request = request_bytes.as_slice();
    log_request(&raw_request, verbose).await;

    debug!("Sending request...");
    client.write_all(&raw_request).await?;

    debug!("Reading response headers...");

    let mut http_decoder = HttpDecoder::new(out, client);
    http_decoder.read_write().await?;
    Ok(())
}

async fn from_https(
    request: &Request,
    client: &mut TcpStream,
    out: &mut (dyn Write + Unpin),
    verbose: bool,
) -> CabotResult<()> {
    let request_bytes = request.to_bytes();
    let raw_request = request_bytes.as_slice();
    log_request(&raw_request, verbose).await;

    let mut tls_client = TLSStream::new(client, request.host())?;
    tls_client.starttls().await?;

    debug!("Sending request...");
    tls_client.write_all(&raw_request).await?;
    debug!("Request sent");

    debug!("Decoding response...");
    let mut http_decoder = HttpDecoder::new(out, &mut tls_client);
    http_decoder.read_write().await?;
    Ok(())
}

pub async fn http_query(
    request: &Request,
    mut out: &mut (dyn Write + Unpin),
    authorities: &HashMap<String, SocketAddr>,
    verbose: bool,
    ipv4: bool,
    ipv6: bool,
) -> CabotResult<()> {
    debug!(
        "HTTP Query {} {}",
        request.http_method(),
        request.request_uri()
    );

    let authority = request.authority();

    let addr = match authorities.get(authority) {
        Some(val) => {
            info!("Fetch authority {} using autorities map", authority);
            *val
        }
        None => {
            info!("Fetch authority {} using resolver", authority);
            let resolver = Resolver::new(verbose);
            resolver.get_addr(authority, ipv4, ipv6).await?
        }
    };

    info!("Connecting to {}", addr);
    let mut client = TcpStream::connect(addr).await?;

    // client.set_read_timeout(Some(Duration::new(5, 0))).unwrap();

    match request.scheme() {
        "http" => from_http(request, &mut client, &mut out, verbose).await?,
        "https" => from_https(request, &mut client, &mut out, verbose).await?,
        _ => {
            return Err(CabotError::SchemeError(format!(
                "Unrecognized scheme {}",
                request.scheme()
            )))
        }
    };

    out.flush().await.unwrap();

    Ok(())
}
<commit_msg>Add a timeout on chunk read<commit_after>//! Low level and internal http and https implementation.

use std::collections::HashMap;
use std::time::Duration;

use async_std::io::{self, stderr, Read, Result as IoResult, Write};
use async_std::net::{SocketAddr, TcpStream};
use async_std::prelude::*;
use log::Level::Info;

use super::asynctls::TLSStream;
use super::constants;
use super::dns::Resolver;
use super::request::Request;
use super::results::{CabotError, CabotResult};

#[derive(Debug, PartialEq)]
enum TransferEncoding {
    ContentLength(usize),
    Chunked,
    Unkown,
    None,
}

#[derive(Debug, PartialEq)]
enum TransferEncodingStatus {
    ReadingHeader,
    ChunkHeader,
    ReadingBody(usize),
}

impl From<&[u8]> for TransferEncoding {
    fn from(hdr: &[u8]) -> Self {
        let hdr = String::from_utf8_lossy(hdr);
        let hdrup = hdr.to_ascii_uppercase();
        match hdrup.as_str() {
            "CHUNKED" => TransferEncoding::Chunked,
            _ => TransferEncoding::Unkown,
        }
    }
}

struct HttpDecoder<'a> {
    reader: &'a mut (dyn Read + Unpin), // tls require Write
    writer: &'a mut (dyn Write + Unpin),
    buffer: Vec<u8>,
    transfer_encoding: TransferEncoding,
    transfer_encoding_status: TransferEncodingStatus,
}

impl<'a> HttpDecoder<'a> {
    fn new(writer: &'a mut (dyn Write + Unpin), reader: &'a mut (dyn Read + Unpin)) -> Self {
        HttpDecoder {
            writer,
            reader,
            buffer: Vec::with_capacity(constants::BUFFER_PAGE_SIZE),
            transfer_encoding: TransferEncoding::None,
            transfer_encoding_status: TransferEncodingStatus::ReadingHeader,
        }
    }

    async fn chunk_read(&mut self) -> IoResult<usize> {
        let ret = io::timeout(Duration::from_secs(5), async {
            let mut buf = [0; constants::BUFFER_PAGE_SIZE];
            let ret = self.reader.read(&mut buf[..]).await;
            if let Ok(count) = ret {
                if count > 0 {
                    self.buffer.extend_from_slice(&buf[0..count]);
                }
            }
            ret
        });
        ret.await
    }
    async fn read_write_headers(&mut self) -> IoResult<()> {
        info!("Reading headers");
        loop {
            let _count = self.chunk_read().await?;
            if let Some(_) = self.process_headers().await {
                break;
            }
        }
        Ok(())
    }

    async fn read_write_no_transfer_encoding(&mut self) -> IoResult<()> {
        loop {
            self.writer.write(self.buffer.as_slice()).await.unwrap();
            self.buffer.clear();
            let cnt = self.chunk_read().await?;
            if cnt == 0 {
                break;
            }
        }

        Ok(())
    }

    async fn read_content_length(&mut self, size: usize) -> IoResult<()> {
        let mut read_count = self.buffer.len();
        loop {
            self.writer.write(self.buffer.as_slice()).await.unwrap();
            self.buffer.clear();

            if read_count >= size {
                break;
            }
            read_count = read_count + self.chunk_read().await?;
            warn!("< {}", read_count);
        }
        Ok(())
    }

    async fn read_write_chunk(&mut self) -> IoResult<()> {
        loop {
            let done = self.process_chunk().await?;
            if done {
                break;
            }
            let cnt = self.chunk_read().await?;
            if cnt == 0 {
                break;
            }
        }

        Ok(())
    }

    async fn read_write_body(&mut self) -> IoResult<()> {
        info!("Reading body");
        match self.transfer_encoding {
            TransferEncoding::ContentLength(size) => {
                self.read_content_length(size).await?;
            }
            TransferEncoding::Chunked => {
                self.read_write_chunk().await?;
            }
            _ => {
                warn!("Neither Content-Length, not chunk is response header");
                self.read_write_no_transfer_encoding().await?;
            }
        }

        if self.buffer.len() > 0 {
            let b = String::from_utf8_lossy(self.buffer.as_slice());
            error!("Buffer not clear: {}", b);
        }

        Ok(())
    }

    async fn read_write(&mut self) -> IoResult<()> {
        self.read_write_headers().await?;
        self.read_write_body().await?;
        self.writer.flush().await
    }

    async fn process_headers(&mut self) -> Option<usize> {
        let ret = {
            let resp_header: Vec<&[u8]> = constants::SPLIT_HEADERS_RE
                .splitn(self.buffer.as_slice(), 2)
                .collect();
            if resp_header.len() == 2 {
                // We have headers
                let headers = resp_header.get(0).unwrap();
                if let Some(header) = constants::TRANSFER_ENCODING.captures(headers) {
                    if let Some(tenc) = header.get(1) {
                        self.transfer_encoding = TransferEncoding::from(tenc.as_bytes());
                    }
                } else if let Some(header) = constants::CONTENT_LENGTH.captures(headers) {
                    if let Some(clength) = header.get(1) {
                        let clength = String::from_utf8_lossy(clength.as_bytes()).into_owned();
                        let clength = usize::from_str_radix(clength.as_str(), 10).unwrap();
                        self.transfer_encoding = TransferEncoding::ContentLength(clength);
                    }
                }
                let resp = headers.len();
                self.writer.write(headers).await.unwrap();
                Some(resp + 4) // + CRLF CRLF
            } else {
                None
            }
        };
        if let Some(to_drain) = ret {
            let buffer = self.buffer.drain(to_drain..).collect();
            self.buffer = buffer;
            info!("End of Headers readched");
            debug!("Transfer encoding: {:?}", self.transfer_encoding);
            debug!("{:?}", String::from_utf8_lossy(self.buffer.as_slice()));
        }
        ret
    }
    async fn process_chunk(&mut self) -> IoResult<bool> {
        debug!(
            "transfer_encoding_status: {:?}",
            self.transfer_encoding_status
        );
        let mut can_process_buffer = self.buffer.len() > 0;
        let mut body_chunk_size = 0;
        let mut header_len: usize;
        while can_process_buffer {
            header_len = 0;
            if self.transfer_encoding_status == TransferEncodingStatus::ReadingHeader {
                // we read the chunk size to drain
                let header: Vec<&[u8]> = constants::SPLIT_HEADER_BRE
                    .splitn(self.buffer.as_slice(), 2)
                    .collect();
                if header.len() == 2 {
                    if let Some(header) = constants::GET_CHUNK_SIZE.captures(header[0]) {
                        if let Some(size) = header.get(1) {
                            let size = size.as_bytes();
                            header_len = size.len() + 2;
                            let size = String::from_utf8_lossy(size).into_owned();
                            body_chunk_size = usize::from_str_radix(size.as_str(), 16).unwrap();
                            self.transfer_encoding_status = TransferEncodingStatus::ChunkHeader;
                        }
                    } else {
                        // else return Error
                        // break;
                    }
                } else {
                    debug!(
                        "Chunked not complete: {}",
                        String::from_utf8_lossy(self.buffer.as_slice())
                    );
                }
            }

            if self.transfer_encoding_status == TransferEncodingStatus::ChunkHeader {
                if body_chunk_size == 0 {
                    debug!(
                        "0 chunked size received: {}",
                        String::from_utf8_lossy(self.buffer.as_slice())
                    );
                    self.buffer.clear(); // should we check that it is '0\r\n' ?
                    return Ok(true);
                }

                debug!(
                    "Before header cleanup: {}",
                    String::from_utf8_lossy(self.buffer.as_slice())
                );
                let buffer: Vec<u8> = self.buffer.drain(header_len..).collect();
                self.buffer = buffer;
                debug!(
                    "After header cleanup: {}",
                    String::from_utf8_lossy(self.buffer.as_slice())
                );
                self.transfer_encoding_status =
                    TransferEncodingStatus::ReadingBody(body_chunk_size);
            }

            if let TransferEncodingStatus::ReadingBody(body_chunk_size) =
                self.transfer_encoding_status
            {
                error!("!! {} > {}", self.buffer.len(), body_chunk_size);
                if self.buffer.len() > body_chunk_size {
                    let mut buffer: Vec<u8> = self.buffer.drain(body_chunk_size..).collect();
                    self.writer.write(self.buffer.as_slice()).await?;

                    let buffer2 = buffer.drain(2..).collect(); // CRLF
                    self.buffer = buffer2;
                    self.transfer_encoding_status = TransferEncodingStatus::ReadingHeader;
                } else {
                    can_process_buffer = false;
                }
            } else {
                can_process_buffer = false;
            }
        }

        return Ok(false);
    }
}

async fn log_request(request: &[u8], verbose: bool) {
    if !log_enabled!(Info) && !verbose {
        return;
    }
    let request: Vec<&[u8]> = constants::SPLIT_HEADERS_RE.splitn(request, 2).collect();
    let headers = String::from_utf8_lossy(&request[0]);
    let headers: Vec<&str> = constants::SPLIT_HEADER_RE.split(&headers).collect();
    let bodylen = if request.len() == 2 {
        let body = &request[1];
        body.len()
    } else {
        0
    };
    if log_enabled!(Info) {
        for header in headers {
            info!("> {}", header);
        }
        if bodylen > 0 {
            info!("> [{} bytes]", bodylen);
        }
        info!(">");
    } else if verbose {
        for header in headers {
            writeln!(&mut stderr(), "> {}", header).await.unwrap();
        }
        if bodylen > 0 {
            writeln!(&mut stderr(), "> [{} bytes]", bodylen)
                .await
                .unwrap();
        }
        writeln!(&mut stderr(), ">").await.unwrap();
    }
}

async fn from_http(
    request: &Request,
    client: &mut TcpStream,
    out: &mut (dyn Write + Unpin),
    verbose: bool,
) -> CabotResult<()> {
    let request_bytes = request.to_bytes();
    let raw_request = request_bytes.as_slice();
    log_request(&raw_request, verbose).await;

    debug!("Sending request...");
    client.write_all(&raw_request).await?;

    debug!("Reading response headers...");

    let mut http_decoder = HttpDecoder::new(out, client);
    http_decoder.read_write().await?;
    Ok(())
}

async fn from_https(
    request: &Request,
    client: &mut TcpStream,
    out: &mut (dyn Write + Unpin),
    verbose: bool,
) -> CabotResult<()> {
    let request_bytes = request.to_bytes();
    let raw_request = request_bytes.as_slice();
    log_request(&raw_request, verbose).await;

    let mut tls_client = TLSStream::new(client, request.host())?;
    tls_client.starttls().await?;

    debug!("Sending request...");
    tls_client.write_all(&raw_request).await?;
    debug!("Request sent");

    debug!("Decoding response...");
    let mut http_decoder = HttpDecoder::new(out, &mut tls_client);
    http_decoder.read_write().await?;
    Ok(())
}

pub async fn http_query(
    request: &Request,
    mut out: &mut (dyn Write + Unpin),
    authorities: &HashMap<String, SocketAddr>,
    verbose: bool,
    ipv4: bool,
    ipv6: bool,
) -> CabotResult<()> {
    debug!(
        "HTTP Query {} {}",
        request.http_method(),
        request.request_uri()
    );

    let authority = request.authority();

    let addr = match authorities.get(authority) {
        Some(val) => {
            info!("Fetch authority {} using autorities map", authority);
            *val
        }
        None => {
            info!("Fetch authority {} using resolver", authority);
            let resolver = Resolver::new(verbose);
            resolver.get_addr(authority, ipv4, ipv6).await?
        }
    };

    info!("Connecting to {}", addr);
    let mut client = TcpStream::connect(addr).await?;

    // client.set_read_timeout(Some(Duration::new(5, 0))).unwrap();

    match request.scheme() {
        "http" => from_http(request, &mut client, &mut out, verbose).await?,
        "https" => from_https(request, &mut client, &mut out, verbose).await?,
        _ => {
            return Err(CabotError::SchemeError(format!(
                "Unrecognized scheme {}",
                request.scheme()
            )))
        }
    };

    out.flush().await.unwrap();

    Ok(())
}
<|endoftext|>


<commit_before>use std::cmp::Ordering::{Greater, Equal, Less};

pub struct Slide<T: Iterator<Item=A>, A> {
  iter: T,
  n: usize,
  window: Vec
}

macro_rules! return_if(
  ($cond:expr, $value:expr) => (
    if $cond {
      return $value;
    }
  );
);

impl<A: Clone, T: Iterator<Item=A>> Slide<T, A> {
  fn push_window(&mut self) -> bool {
    let iter_next = self.iter.next();
    let is_some = iter_next.is_some();

    if is_some {
      self.window.push(iter_next.unwrap());
    }

    is_some
  }

  fn new(iter: T, n: usize) -> Slide<T, A> {
    Slide{
      iter: iter,
      n: n,
      window: Vec::with_capacity(n + 1)
    }
  }
}

impl<A: Clone, T: Iterator<Item=A>> Iterator for Slide<T, A> {
  type Item = Vec;

  fn next(&mut self) -> Option<Vec> {
    return_if!(self.n == 0, None);
    return_if!(!self.push_window(), None);

    loop {
      let window_status = self.window.len().cmp(&self.n);

      match window_status {
        Greater => { self.window.remove(0); }
        Equal => { return Some(self.window.clone()); }
        Less => { return_if!(!self.push_window(), None); }
      }
    }
  }
}

pub trait SlideIterator<T: Iterator<Item=A>, A> {
  fn slide(self, n: usize) -> Slide<T, A>;
}

impl<A: Clone, T: Iterator<Item=A>> SlideIterator<T, A> for T {
  fn slide(self, n: usize) -> Slide<T, A> {
    Slide::new(self, n)
  }
}

#[test]
fn test_slide() {
  let mut slide_iter = vec![1i8, 2, 3, 4, 5].into_iter().slide(3);
  assert_eq!(slide_iter.next().unwrap(), vec![1, 2, 3]);
  assert_eq!(slide_iter.next().unwrap(), vec![2, 3, 4]);
  assert_eq!(slide_iter.next().unwrap(), vec![3, 4, 5]);
  assert!(slide_iter.next().is_none());
}

#[test]
fn test_slide_equal_window() {
  let mut slide_iter = vec![1i8, 2, 3, 4, 5].into_iter().slide(5);
  assert_eq!(slide_iter.next().unwrap(), vec![1, 2, 3, 4, 5]);
  assert!(slide_iter.next().is_none());
}

#[test]
fn test_slide_zero_window() {
  let mut slide_iter = vec![1i8, 2, 3, 4, 5].into_iter().slide(0);
  assert!(slide_iter.next().is_none());
}

#[test]
fn test_slide_overlong_window() {
  let mut slide_iter = vec![1i8, 2, 3, 4, 5].into_iter().slide(7);
  assert!(slide_iter.next().is_none());
}
<commit_msg>Fix formatting (indentation, space before brace)<commit_after>use std::cmp::Ordering::{Greater, Equal, Less};

pub struct Slide<T: Iterator<Item=A>, A> {
    iter: T,
    n: usize,
    window: Vec
}

macro_rules! return_if(
    ($cond:expr, $value:expr) => (
        if $cond {
            return $value;
        }
    );
);

impl<A: Clone, T: Iterator<Item=A>> Slide<T, A> {
    fn push_window(&mut self) -> bool {
        let iter_next = self.iter.next();
        let is_some = iter_next.is_some();

        if is_some {
            self.window.push(iter_next.unwrap());
        }

        is_some
    }

    fn new(iter: T, n: usize) -> Slide<T, A> {
        Slide {
            iter: iter,
            n: n,
            window: Vec::with_capacity(n + 1)
        }
    }
}

impl<A: Clone, T: Iterator<Item=A>> Iterator for Slide<T, A> {
    type Item = Vec;

    fn next(&mut self) -> Option<Vec> {
        return_if!(self.n == 0, None);
        return_if!(!self.push_window(), None);

        loop {
            let window_status = self.window.len().cmp(&self.n);

            match window_status {
                Greater => { self.window.remove(0); }
                Equal => { return Some(self.window.clone()); }
                Less => { return_if!(!self.push_window(), None); }
            }
        }
    }
}

pub trait SlideIterator<T: Iterator<Item=A>, A> {
    fn slide(self, n: usize) -> Slide<T, A>;
}

impl<A: Clone, T: Iterator<Item=A>> SlideIterator<T, A> for T {
    fn slide(self, n: usize) -> Slide<T, A> {
        Slide::new(self, n)
    }
}

#[test]
fn test_slide() {
    let mut slide_iter = vec![1i8, 2, 3, 4, 5].into_iter().slide(3);
    assert_eq!(slide_iter.next().unwrap(), vec![1, 2, 3]);
    assert_eq!(slide_iter.next().unwrap(), vec![2, 3, 4]);
    assert_eq!(slide_iter.next().unwrap(), vec![3, 4, 5]);
    assert!(slide_iter.next().is_none());
}

#[test]
fn test_slide_equal_window() {
    let mut slide_iter = vec![1i8, 2, 3, 4, 5].into_iter().slide(5);
    assert_eq!(slide_iter.next().unwrap(), vec![1, 2, 3, 4, 5]);
    assert!(slide_iter.next().is_none());
}

#[test]
fn test_slide_zero_window() {
    let mut slide_iter = vec![1i8, 2, 3, 4, 5].into_iter().slide(0);
    assert!(slide_iter.next().is_none());
}

#[test]
fn test_slide_overlong_window() {
    let mut slide_iter = vec![1i8, 2, 3, 4, 5].into_iter().slide(7);
    assert!(slide_iter.next().is_none());
}
<|endoftext|>