<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_01: Range<f32>,
    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_01: Range::new(0.0, 1.0),
            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_idx = 0;
        for i in 0..self.curr.len() {
            let cost_curr = self.curr[i].cost.unwrap();
            if let Some(cost_best) = self.best[i].cost {
                // if we already have a best, check if current is better.
                if cost_curr <= cost_best {
                    // swap is *much* faster than clone.
                    std::mem::swap(&mut self.best[i], &mut self.curr[i]);
                    // reset cost, so user is forced to update it.
                    self.curr[i].cost = None;
                }
            } else {
                // no best yet: swap current with best
                std::mem::swap(&mut self.best[i], &mut self.curr[i]);
            }

            // min best cost index
            if self.best[i].cost.unwrap() < self.best[new_best_idx].cost.unwrap() {
                new_best_idx = i;
            }
        }
        self.best_idx = Some(new_best_idx);

        // got a new best?
        last_best_cost.is_none() || self.best[new_best_idx].cost.unwrap() < last_best_cost.unwrap()
    }

    fn update_positions(&mut self) {
        let best_idx = self.best_idx.unwrap();
        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"
            curr.cr = best.cr;
            curr.f = best.f;
            if self.between_01.ind_sample(rng) < self.settings.cr_change_probability {
                curr.cr = self.between_cr.ind_sample(rng);
            }
            if self.between_01.ind_sample(rng) < self.settings.f_change_probability {
                curr.f = self.between_f.ind_sample(rng);
            }

            let forced_mutation_dim = self.between_dim.ind_sample(rng);
            for d in 0..self.dim {
                if d == forced_mutation_dim || self.between_01.ind_sample(rng) < curr.cr {

                    curr.pos[d] = self.best[best_idx].pos[d] +
                                  curr.f * (self.best[id1].pos[d] - self.best[id2].pos[d]);
                } else {
                    curr.pos[d] = self.best[i].pos[d];
                }
            }
        }
    }

    // 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::{black_box, 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);
            }
            black_box(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);
            black_box(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>simpler code<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_01: Range<f32>,
    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_01: Range::new(0.0, 1.0),
            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 = self.curr[0].cost.unwrap();
        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 curr.cost.unwrap() < new_best_cost {
                    self.best_idx = Some(i);
                    new_best_cost = curr.cost.unwrap();
                }

                // 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 < last_best_cost.unwrap()
    }

    fn update_positions(&mut self) {
        let best_idx = self.best_idx.unwrap();
        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"
            curr.cr = best.cr;
            curr.f = best.f;
            if self.between_01.ind_sample(rng) < self.settings.cr_change_probability {
                curr.cr = self.between_cr.ind_sample(rng);
            }
            if self.between_01.ind_sample(rng) < self.settings.f_change_probability {
                curr.f = self.between_f.ind_sample(rng);
            }

            let forced_mutation_dim = self.between_dim.ind_sample(rng);
            for d in 0..self.dim {
                if d == forced_mutation_dim || self.between_01.ind_sample(rng) < curr.cr {

                    curr.pos[d] = self.best[best_idx].pos[d] +
                                  curr.f * (self.best[id1].pos[d] - self.best[id2].pos[d]);
                } else {
                    curr.pos[d] = self.best[i].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::{black_box, 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);
            }
            black_box(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);
            black_box(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 libc;

use libc::c_void;
use std::ffi::CString;
use std::ptr;

pub mod ffi;
pub use ffi::{IPaddress, _TCPsocket, _SDLNet_SocketSet, _SDLNet_GenericSocket};

pub struct TCPsocket {
    opaque_ptr: *const _TCPsocket,
}
pub struct SocketSet {
    opaque_ptr: *const _SDLNet_SocketSet,
}
pub struct IPAddress {
    opaque_ptr: *mut IPaddress,
}
#[repr(C)]
pub struct CustTCPSocket {
    ready: i32,
}

pub fn init() -> bool { unsafe { ffi::SDLNet_Init() == 0 } }
pub fn quit() -> () { unsafe { ffi::SDLNet_Quit(); } }
pub fn get_error() -> String {
    unsafe {
        let raw = &ffi::SDLNet_GetError();
        std::str::from_utf8(std::ffi::c_str_to_bytes(raw)).unwrap().to_string()
    }
}

// Returns an IPaddress struct if successful in becoming a host on the given port
pub fn become_host(port: u16) -> Option<ffi::IPaddress> {
    let mut address = ffi::IPaddress { host: 0, port: 0};
    let result = unsafe { ffi::SDLNet_ResolveHost(&mut address, ptr::null() , port) };
    if result == 0 {
        Some(address)
    } else {
        None
    }
}

// Resolves the host from the given IP and porn
pub fn resolve_host(host: &str, port: u16) -> Option<ffi::IPaddress> {
    let mut address = ffi::IPaddress { host: 0, port: 0 };
    let result = unsafe { ffi::SDLNet_ResolveHost(&mut address, CString::from_slice(host.as_bytes()).as_ptr(), port) };
    if result == 0 {
        Some(address)
    } else {
        None
    }
}

// Resolves the given IP from the given IPaddress struct
pub fn resolve_ip(mut address: IPaddress) -> String {
    unsafe {
        let raw = &ffi::SDLNet_ResolveIP(&mut address);
        std::str::from_utf8(std::ffi::c_str_to_bytes(raw)).unwrap().to_string()
    }
}

// Returns a TCPsocket from the data given in the IPaddress object
pub fn tcp_open(address: &mut IPaddress) -> Option<TCPsocket> {
    unsafe {
        let socket = ffi::SDLNet_TCP_Open(address);
        if socket as *const _TCPsocket != ptr::null() {
            Some(TCPsocket { opaque_ptr: socket })
        } else {
            None
        }
    }
}

// Closes the given TCPsocket
pub fn tcp_close(sock: &TCPsocket) -> () {
    unsafe {
        ffi::SDLNet_TCP_Close(sock.opaque_ptr)
    }
}

// Accepts a TCP connection on the given socket, returning the new socket of the connection
pub fn tcp_accept(server: &TCPsocket) -> Option<TCPsocket> {
    unsafe {
        let socket =  ffi::SDLNet_TCP_Accept(server.opaque_ptr);
        if socket as *const _TCPsocket != ptr::null() {
            Some(TCPsocket { opaque_ptr: socket})
        } else {
            None
        }
    }
}

pub fn tcp_get_peer_address(sock: &TCPsocket) -> Option<IPaddress> {
    unsafe {
        let possible_addr = ffi::SDLNet_TCP_GetPeerAddress(sock.opaque_ptr);
        if possible_addr as *const IPaddress == ptr::null() {
            None
        } else {
            Some(ptr::read(possible_addr))
        }
    }
}

// Writes the data out
pub fn tcp_send(sock: &TCPsocket, data: *mut u8, len: u32) -> i32 {
    unsafe {
        ffi::SDLNet_TCP_Send(sock.opaque_ptr, data as *const c_void, len as i32)
    }
}

// Receives incoming data
pub fn tcp_recv(sock: &TCPsocket, data: *mut u8, maxlen: i32) -> i32 {//Vec<u8> {
    //let mut data: Vec<u8> = Vec::with_capacity(maxlen as usize);
    let mut read_amnt = 0;
    unsafe {
        read_amnt = ffi::SDLNet_TCP_Recv(sock.opaque_ptr, data as *mut c_void, maxlen as i32);
        //data.set_len(read_ammnt as usize);
    }
    //data
    read_amnt
}

// Allocates a socket set to hold the given number of sockets
pub fn alloc_socket_set(maxsockets: i32) -> SocketSet {
    unsafe {
        SocketSet { opaque_ptr: ffi::SDLNet_AllocSocketSet(maxsockets) }
    }
}

// Frees the given socket set
pub fn free_socket_set(set: &SocketSet) -> () {
    unsafe {
        ffi::SDLNet_FreeSocketSet(set.opaque_ptr);
    }
}

// Adds a given socket to the given socket set
pub fn add_socket(set: &SocketSet, sock: &TCPsocket) -> i32 {
    unsafe {
        ffi::SDLNet_AddSocket(set.opaque_ptr, sock.opaque_ptr)
    }
}

// Maybe should take in the box here as it may get deleted.... not sure
pub fn del_socket(set: &SocketSet, sock: &TCPsocket) -> i32 {
    unsafe {
        ffi::SDLNet_DelSocket(set.opaque_ptr, sock.opaque_ptr)
    }
}

// Returns the incoming data amount  on the given socketset
pub fn check_sockets(set: &SocketSet, timeout: u32) -> i32 {
    unsafe {
        ffi::SDLNet_CheckSockets(set.opaque_ptr, timeout)
    }
}

pub fn socket_ready(sock: &TCPsocket) -> bool {
    unsafe {
        (std::mem::transmute::<*const ffi::_TCPsocket,&CustTCPSocket>(sock.opaque_ptr)).ready != 0
    }
}
<commit_msg>move from raw pointers to slices<commit_after>#![feature(libc)]
#![feature(std_misc)]

extern crate libc;

use libc::c_void;
use std::ffi::CString;
use std::ptr;

pub mod ffi;
pub use ffi::{IPaddress, _TCPsocket, _SDLNet_SocketSet, _SDLNet_GenericSocket};

pub struct TCPsocket {
    opaque_ptr: *const _TCPsocket,
}
pub struct SocketSet {
    opaque_ptr: *const _SDLNet_SocketSet,
}
#[repr(C)]
pub struct CustTCPSocket {
    ready: i32,
}

pub fn init() -> bool { unsafe { ffi::SDLNet_Init() == 0 } }
pub fn quit() -> () { unsafe { ffi::SDLNet_Quit(); } }
pub fn get_error() -> String {
    unsafe {
        let raw = &ffi::SDLNet_GetError();
        std::str::from_utf8(std::ffi::c_str_to_bytes(raw)).unwrap().to_string()
    }
}

// Returns an IPaddress struct if successful in becoming a host on the given port
pub fn become_host(port: u16) -> Option<ffi::IPaddress> {
    let mut address = ffi::IPaddress { host: 0, port: 0};
    let result = unsafe { ffi::SDLNet_ResolveHost(&mut address, ptr::null() , port) };
    if result == 0 {
        Some(address)
    } else {
        None
    }
}

// Resolves the host from the given IP and port
pub fn resolve_host(host: &str, port: u16) -> Option<ffi::IPaddress> {
    let mut address = ffi::IPaddress { host: 0, port: 0 };
    let result = unsafe { ffi::SDLNet_ResolveHost(&mut address, CString::from_slice(host.as_bytes()).as_ptr(), port) };
    if result == 0 {
        Some(address)
    } else {
        None
    }
}

// Resolves the given IP from the given IPaddress struct
pub fn resolve_ip(mut address: IPaddress) -> String {
    unsafe {
        let raw = &ffi::SDLNet_ResolveIP(&mut address);
        std::str::from_utf8(std::ffi::c_str_to_bytes(raw)).unwrap().to_string()
    }
}

// Returns a TCPsocket from the data given in the IPaddress object
pub fn tcp_open(address: &mut IPaddress) -> Option<TCPsocket> {
    unsafe {
        let socket = ffi::SDLNet_TCP_Open(address);
        if socket as *const _TCPsocket != ptr::null() {
            Some(TCPsocket { opaque_ptr: socket })
        } else {
            None
        }
    }
}

// Closes the given TCPsocket
pub fn tcp_close(sock: &TCPsocket) -> () {
    unsafe {
        ffi::SDLNet_TCP_Close(sock.opaque_ptr)
    }
}

// Accepts a TCP connection on the given socket, returning the new socket of the connection
pub fn tcp_accept(server: &TCPsocket) -> Option<TCPsocket> {
    unsafe {
        let socket =  ffi::SDLNet_TCP_Accept(server.opaque_ptr);
        if socket as *const _TCPsocket != ptr::null() {
            Some(TCPsocket { opaque_ptr: socket})
        } else {
            None
        }
    }
}

pub fn tcp_get_peer_address(sock: &TCPsocket) -> Option<IPaddress> {
    unsafe {
        let possible_addr = ffi::SDLNet_TCP_GetPeerAddress(sock.opaque_ptr);
        if possible_addr as *const IPaddress == ptr::null() {
            None
        } else {
            Some(ptr::read(possible_addr))
        }
    }
}

// Writes the data out
pub fn tcp_send(sock: &TCPsocket, data: &mut [u8]) -> i32 {
    unsafe {
        ffi::SDLNet_TCP_Send(sock.opaque_ptr, &data[0] as *const u8 as *const c_void, data.len() as i32)
    }
}

// Receives incoming data
pub fn tcp_recv(sock: &TCPsocket, data: &mut [u8]) -> i32 {
    unsafe {
        ffi::SDLNet_TCP_Recv(sock.opaque_ptr, &mut data[0] as *mut u8 as *mut c_void, data.len() as i32)
    }
}

// Allocates a socket set to hold the given number of sockets
pub fn alloc_socket_set(maxsockets: i32) -> SocketSet {
    unsafe {
        SocketSet { opaque_ptr: ffi::SDLNet_AllocSocketSet(maxsockets) }
    }
}

// Frees the given socket set
pub fn free_socket_set(set: &SocketSet) -> () {
    unsafe {
        ffi::SDLNet_FreeSocketSet(set.opaque_ptr);
    }
}

// Adds a given socket to the given socket set
pub fn add_socket(set: &SocketSet, sock: &TCPsocket) -> i32 {
    unsafe {
        ffi::SDLNet_AddSocket(set.opaque_ptr, sock.opaque_ptr)
    }
}

// Maybe should take in the box here as it may get deleted.... not sure
pub fn del_socket(set: &SocketSet, sock: &TCPsocket) -> i32 {
    unsafe {
        ffi::SDLNet_DelSocket(set.opaque_ptr, sock.opaque_ptr)
    }
}

// Returns the incoming data amount  on the given socketset
pub fn check_sockets(set: &SocketSet, timeout: u32) -> i32 {
    unsafe {
        ffi::SDLNet_CheckSockets(set.opaque_ptr, timeout)
    }
}

pub fn socket_ready(sock: &TCPsocket) -> bool {
    unsafe {
        (std::mem::transmute::<*const ffi::_TCPsocket,&CustTCPSocket>(sock.opaque_ptr)).ready != 0
    }
}
<|endoftext|>


<commit_before>extern crate libc;
// export it for now

use libc::{c_int, c_char, c_void};
use std::ffi::CString;
use std::ptr;

pub mod ffi;
pub use ffi::{IPaddress, _TCPsocket, _SDLNet_SocketSet, _SDLNet_GenericSocket};

pub struct TCPsocket {
    opaquePtr: *mut _TCPsocket,
}
pub struct SocketSet {
    opaquePtr: *mut _SDLNet_SocketSet,
}
#[repr(C)]
pub struct CustTCPSocket {
    ready: i32,
}

pub fn init() -> () { unsafe { ffi::SDLNet_Init(); } }
pub fn quit() -> () { unsafe { ffi::SDLNet_Quit(); } }
pub fn get_error() -> String {
    unsafe {
        let raw = &ffi::SDLNet_GetError();
        std::str::from_utf8(std::ffi::c_str_to_bytes(raw)).unwrap().to_string()
    }
}

pub fn become_host(port: u16) -> Option<ffi::IPaddress> {
    let mut address = ffi::IPaddress { host: 0, port: 0};
    let mut result = 0;
    unsafe {
        result = ffi::SDLNet_ResolveHost(&mut address, ptr::null() , port)
    }
    if (result == 0){
        Some(address)
    } else {
        None
    }
}

pub fn resolve_host(host: &str, port: u16) -> Option<ffi::IPaddress> {
    let mut address = ffi::IPaddress { host: 0, port: 0 };
    let mut result = 0;
    unsafe {
        result = ffi::SDLNet_ResolveHost(&mut address, CString::from_slice(host.as_bytes()).as_ptr(), port)
    }
    if (result == 0) {
        Some(address)
    } else {
        None
    }
}

pub fn resolve_ip(mut address: IPaddress) -> String {
    unsafe {
        let raw = &ffi::SDLNet_ResolveIP(&mut address);
        std::str::from_utf8(std::ffi::c_str_to_bytes(raw)).unwrap().to_string()
    }
}

pub fn tcp_open() -> Option<TCPsocket> {
    let mut address = ffi::IPaddress { host: 0, port: 0};
    unsafe {
        let socket = ffi::SDLNet_TCP_Open(&mut address);
        if socket as *const _TCPsocket != ptr::null() {
            Some(TCPsocket { opaquePtr: socket })
        } else {
            None
        }
    }
}

pub fn tcp_close(sock: &TCPsocket) -> () {
    unsafe {
        ffi::SDLNet_TCP_Close(sock.opaquePtr)
    }
}

pub fn tcp_accept(server: &TCPsocket) -> TCPsocket {
    unsafe {
        TCPsocket { opaquePtr: ffi::SDLNet_TCP_Accept(server.opaquePtr) }
    }
}

pub fn tcp_get_peer_address(sock: &TCPsocket) -> Box<*mut IPaddress> {
    unsafe {
        Box::new(ffi::SDLNet_TCP_GetPeerAddress(sock.opaquePtr))
    }
}

pub fn tcp_send(sock: &TCPsocket, data: &[u8]) -> () {
    unsafe {
        ffi::SDLNet_TCP_Send(sock.opaquePtr, data.as_ptr() as *const c_void, data.len() as i32);
    }
}

pub fn tcp_recv(sock: &TCPsocket, maxlen: i32) -> Vec<u8> {
    let mut data: Vec<u8> = Vec::with_capacity(maxlen as usize);
    unsafe {
        let read_ammnt = ffi::SDLNet_TCP_Recv(sock.opaquePtr, data.as_mut_ptr() as *mut c_void, data.len() as i32);
        data.set_len(read_ammnt as usize);
    }
    data
}

pub fn alloc_socket_set(maxsockets: i32) -> SocketSet {
    unsafe {
        SocketSet { opaquePtr: ffi::SDLNet_AllocSocketSet(maxsockets) }
    }
}

pub fn free_socket_set(set: &SocketSet) -> () {
    unsafe {
        ffi::SDLNet_FreeSocketSet(set.opaquePtr);
    }
}

pub fn add_socket(set: &SocketSet, sock: &TCPsocket) -> i32 {
    unsafe {
        ffi::SDLNet_AddSocket(set.opaquePtr, sock.opaquePtr)
    }
}

// Maybe should take in the box here as it may get deleted.... not sure
pub fn del_socket(set: &SocketSet, sock: &TCPsocket) -> i32 {
    unsafe {
        ffi::SDLNet_DelSocket(set.opaquePtr, sock.opaquePtr)
    }
}

pub fn check_sockets(set: &SocketSet, timeout: u32) -> i32 {
    unsafe {
        ffi::SDLNet_CheckSockets(set.opaquePtr, timeout)
    }
}

pub fn socket_ready(sock: &TCPsocket) -> i32 {
    unsafe {
        (std::mem::transmute::<*mut ffi::_TCPsocket,&CustTCPSocket>(sock.opaquePtr)).ready
    }
}
<commit_msg>Added the IPaddress pass back to tcp_open<commit_after>extern crate libc;
// export it for now

use libc::{c_int, c_char, c_void};
use std::ffi::CString;
use std::ptr;

pub mod ffi;
pub use ffi::{IPaddress, _TCPsocket, _SDLNet_SocketSet, _SDLNet_GenericSocket};

pub struct TCPsocket {
    opaquePtr: *mut _TCPsocket,
}
pub struct SocketSet {
    opaquePtr: *mut _SDLNet_SocketSet,
}
pub struct IPAddress {
    opaquePtr: *mut IPaddress,
}
#[repr(C)]
pub struct CustTCPSocket {
    ready: i32,
}

pub fn init() -> () { unsafe { ffi::SDLNet_Init(); } }
pub fn quit() -> () { unsafe { ffi::SDLNet_Quit(); } }
pub fn get_error() -> String {
    unsafe {
        let raw = &ffi::SDLNet_GetError();
        std::str::from_utf8(std::ffi::c_str_to_bytes(raw)).unwrap().to_string()
    }
}

pub fn become_host(port: u16) -> Option<ffi::IPaddress> {
    let mut address = ffi::IPaddress { host: 0, port: 0};
    let mut result = 0;
    unsafe {
        result = ffi::SDLNet_ResolveHost(&mut address, ptr::null() , port)
    }
    if (result == 0){
        Some(address)
    } else {
        None
    }
}

pub fn resolve_host(host: &str, port: u16) -> Option<ffi::IPaddress> {
    let mut address = ffi::IPaddress { host: 0, port: 0 };
    let mut result = 0;
    unsafe {
        result = ffi::SDLNet_ResolveHost(&mut address, CString::from_slice(host.as_bytes()).as_ptr(), port)
    }
    if (result == 0) {
        Some(address)
    } else {
        None
    }
}

pub fn resolve_ip(mut address: IPaddress) -> String {
    unsafe {
        let raw = &ffi::SDLNet_ResolveIP(&mut address);
        std::str::from_utf8(std::ffi::c_str_to_bytes(raw)).unwrap().to_string()
    }
}

pub fn tcp_open(address: &mut IPaddress) -> Option<TCPsocket> {
    //let mut address = ffi::IPaddress { host: 0, port: 0};
    unsafe {
        let socket = ffi::SDLNet_TCP_Open(address);
        if socket as *const _TCPsocket != ptr::null() {
            Some(TCPsocket { opaquePtr: socket })
        } else {
            None
        }
    }
}

pub fn tcp_close(sock: &TCPsocket) -> () {
    unsafe {
        ffi::SDLNet_TCP_Close(sock.opaquePtr)
    }
}

pub fn tcp_accept(server: &TCPsocket) -> TCPsocket {
    unsafe {
        TCPsocket { opaquePtr: ffi::SDLNet_TCP_Accept(server.opaquePtr) }
    }
}

pub fn tcp_get_peer_address(sock: &TCPsocket) -> Box<*mut IPaddress> {
    unsafe {
        Box::new(ffi::SDLNet_TCP_GetPeerAddress(sock.opaquePtr))
    }
}

pub fn tcp_send(sock: &TCPsocket, data: &[u8]) -> () {
    unsafe {
        ffi::SDLNet_TCP_Send(sock.opaquePtr, data.as_ptr() as *const c_void, data.len() as i32);
    }
}

pub fn tcp_recv(sock: &TCPsocket, maxlen: i32) -> Vec<u8> {
    let mut data: Vec<u8> = Vec::with_capacity(maxlen as usize);
    unsafe {
        let read_ammnt = ffi::SDLNet_TCP_Recv(sock.opaquePtr, data.as_mut_ptr() as *mut c_void, data.len() as i32);
        data.set_len(read_ammnt as usize);
    }
    data
}

pub fn alloc_socket_set(maxsockets: i32) -> SocketSet {
    unsafe {
        SocketSet { opaquePtr: ffi::SDLNet_AllocSocketSet(maxsockets) }
    }
}

pub fn free_socket_set(set: &SocketSet) -> () {
    unsafe {
        ffi::SDLNet_FreeSocketSet(set.opaquePtr);
    }
}

pub fn add_socket(set: &SocketSet, sock: &TCPsocket) -> i32 {
    unsafe {
        ffi::SDLNet_AddSocket(set.opaquePtr, sock.opaquePtr)
    }
}

// Maybe should take in the box here as it may get deleted.... not sure
pub fn del_socket(set: &SocketSet, sock: &TCPsocket) -> i32 {
    unsafe {
        ffi::SDLNet_DelSocket(set.opaquePtr, sock.opaquePtr)
    }
}

pub fn check_sockets(set: &SocketSet, timeout: u32) -> i32 {
    unsafe {
        ffi::SDLNet_CheckSockets(set.opaquePtr, timeout)
    }
}

pub fn socket_ready(sock: &TCPsocket) -> i32 {
    unsafe {
        (std::mem::transmute::<*mut ffi::_TCPsocket,&CustTCPSocket>(sock.opaquePtr)).ready
    }
}
<|endoftext|>


<commit_before>//! A library for reading duplicity backups.
//!
//! This library provides utilities to manage duplicity backups [1]. Backup files could be prensent
//! in the local file system, or can be accessed remotely, provided that the right backend is
//! implemented. This is a rust version of the original duplicity project, that is written in
//! Python. The goal is to o provide a library to be used for different purposes (e.g. a command
//! line utility, a fusion filesystem, etc.) and to improve overall performances. Full
//! compatibility with the original duplicity is guaranteed.
//!
//! [1]: http://duplicity.nongnu.org/

#![deny(missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unstable_features,
        unused_import_braces, unused_qualifications)]

#![cfg_attr(feature = "nightly", allow(unstable_features))]
#![cfg_attr(feature = "lints", feature(plugin))]
#![cfg_attr(feature = "lints", plugin(clippy))]

extern crate byteorder;
extern crate flate2;
extern crate regex;
extern crate tabwriter;
extern crate tar;
extern crate time;
#[macro_use]
extern crate try_opt;

mod macros;
mod time_utils;
pub mod backend;
pub mod collections;
pub mod signatures;

use std::cell::{Ref, RefCell};
use std::io;

use time::Timespec;

pub use backend::Backend;
use collections::{BackupChain, BackupSet, Collections};
use signatures::Chain;

/// A top level representation of a duplicity backup.
#[derive(Debug)]
pub struct Backup<B> {
    backend: B,
    collections: Collections,
    signatures: Vec<RefCell<Option<Chain>>>,
}

/// An iterator over the snapshots in a backup.
pub struct Snapshots<'a> {
    set_iter: CollectionsIter<'a>,
    chain_id: usize,
    sig_id: usize,
    backup: &'a ResourceCache,
}

/// A snapshot in a backup.
pub struct Snapshot<'a> {
    set: &'a BackupSet,
    // the number of the parent backup chain, starting from zero
    chain_id: usize,
    sig_id: usize,
    backup: &'a ResourceCache,
}

/// Contains the files present in a certain backup snapshot.
pub struct SnapshotFiles<'a> {
    chain: Ref<'a, Option<Chain>>,
    sig_id: usize,
}

struct CollectionsIter<'a> {
    chain_iter: collections::ChainIter<'a, BackupChain>,
    incset_iter: Option<collections::BackupSetIter<'a>>,
}

/// Allows to be used as an interface for `Backup` struct without generic parameters. This allows
/// to reduce code size, since we don't have to godegen the entire module for different Backend
/// generic parameters. This trait is used as an interface between `Backup` and its inner
/// components.
trait ResourceCache {
    fn _collections(&self) -> &Collections;
    fn _signature_chain(&self, chain_id: usize) -> io::Result<Ref<Option<Chain>>>;
}

impl<B: Backend> Backup<B> {
    /// Opens an existig backup by using the given backend.
    ///
    /// # Errors
    /// This function will return an error whenever the backend returns an error in a file
    /// operation. If the backend can't provide access to backup files, because they are
    /// unavailable or non-existing, an empty backup could be returned.
    ///
    /// # Examples
    /// ```no_run
    /// use ruplicity::{Backend, Backup};
    /// use ruplicity::backend::local::LocalBackend;
    ///
    /// // use the local backend to open a path in the file system containing a backup
    /// let backend = LocalBackend::new("/path/to/backup");
    /// let backup = Backup::new(backend);
    /// ```
    pub fn new(backend: B) -> io::Result<Self> {
        let files = try!(backend.file_names());
        let collections = Collections::from_filenames(files);
        let signatures = {
            // initialize signatures with empty signatures
            // to be loaded lazily
            let mut signatures = Vec::new();
            for _ in collections.signature_chains() {
                signatures.push(RefCell::new(None));
            }
            signatures
        };
        Ok(Backup {
            backend: backend,
            collections: collections,
            signatures: signatures,
        })
    }

    /// Constructs an iterator over the snapshots currently present in this backup.
    pub fn snapshots(&self) -> io::Result<Snapshots> {
        let set_iter = CollectionsIter {
            chain_iter: self.collections.backup_chains(),
            incset_iter: None,
        };
        // in future, when we will add lazy collections,
        // this could fail, so we add a Result in advance
        Ok(Snapshots {
            set_iter: set_iter,
            chain_id: 0,
            sig_id: 0,
            backup: self,
        })
    }
}

impl<'a> Iterator for Snapshots<'a> {
    type Item = Snapshot<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        // first test if we have a valid iterator to an incset
        if let Some(ref mut incset_iter) = self.set_iter.incset_iter {
            // we have a set iter, so return the next element if present
            if let Some(inc_set) = incset_iter.next() {
                self.sig_id += 1;
                return Some(Snapshot {
                    set: inc_set,
                    chain_id: self.chain_id - 1,
                    sig_id: self.sig_id,
                    backup: self.backup,
                });
            }
        }
        // the current incset is exausted or not present,
        // we need to advance the chain and return the next full set if present,
        // otherwise the job is finished
        if let Some(chain) = self.set_iter.chain_iter.next() {
            self.chain_id += 1;
            self.sig_id = 0;
            self.set_iter.incset_iter = Some(chain.inc_sets());
            Some(Snapshot {
                set: chain.full_set(),
                chain_id: self.chain_id - 1,
                sig_id: self.sig_id,
                backup: self.backup,
            })
        } else {
            None
        }
    }
}

impl<'a> AsRef<Collections> for Snapshots<'a> {
    fn as_ref(&self) -> &Collections {
        self.backup._collections()
    }
}

impl<'a> Snapshot<'a> {
    /// Returns the time in which the snapshot has been taken.
    pub fn time(&self) -> Timespec {
        self.set.end_time()
    }

    /// Returns true if the snapshot is a full backup.
    ///
    /// A full snapshot does not depend on previous snapshots.
    pub fn is_full(&self) -> bool {
        self.set.is_full()
    }

    /// Returns true if the snapshot is an incremental backup.
    ///
    /// An incremental snapshot depends on all the previous incremental snapshots and the first
    /// previous full snapshot. This set of dependent snapshots is called "chain".
    pub fn is_incremental(&self) -> bool {
        self.set.is_incremental()
    }

    /// Returns the number of volumes contained in the snapshot.
    pub fn num_volumes(&self) -> usize {
        self.set.num_volumes()
    }

    /// Returns the files present in the snapshot.
    ///
    /// Be aware that using this functionality means that all the signature files in the current
    /// backup chain must be loaded, and this could take some time, depending on the file access
    /// provided by the backend.
    pub fn files(&self) -> io::Result<SnapshotFiles> {
        let sig = try!(self.backup._signature_chain(self.chain_id));
        if self.sig_id < sig.as_ref().unwrap().snapshots().len() {
            Ok(SnapshotFiles {
                chain: sig,
                sig_id: self.sig_id,
            })
        } else {
            Err(io::Error::new(io::ErrorKind::NotFound, "The signature chain is incomplete"))
        }
    }
}

impl<'a> AsRef<BackupSet> for Snapshot<'a> {
    fn as_ref(&self) -> &BackupSet {
        self.set
    }
}

impl<'a> SnapshotFiles<'a> {
    /// Converts the snapshot files into the signature representation.
    ///
    /// This function can be used to retrieve lower level informations about the files in the
    /// snapshot.
    pub fn as_signature_info(&self) -> signatures::SnapshotFiles {
        self.chain.as_ref().unwrap().snapshots().nth(self.sig_id).unwrap().files()
    }
}

impl<B: Backend> ResourceCache for Backup<B> {
    fn _collections(&self) -> &Collections {
        &self.collections
    }

    fn _signature_chain(&self, chain_id: usize) -> io::Result<Ref<Option<Chain>>> {
        {
            // check if there is a cached value
            let mut sig = self.signatures[chain_id].borrow_mut();
            if sig.is_none() {
                // compute signatures now
                if let Some(sigchain) = self.collections.signature_chains().nth(chain_id) {
                    let new_sig = try!(Chain::from_sigchain(sigchain, &self.backend));
                    *sig = Some(new_sig);
                } else {
                    return Err(io::Error::new(io::ErrorKind::NotFound,
                                              "The given backup snapshot does not have a \
                                              corresponding signature"));
                }
            }
        }

        // need to close previous scope to borrow again
        // return the cached value
        Ok(self.signatures[chain_id].borrow())
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use backend::local::LocalBackend;
    use collections::{BackupSet, Collections};
    use signatures::{Chain, File};

    use std::path::PathBuf;

    use time::Timespec;

    #[derive(Debug, Eq, PartialEq)]
    struct SnapshotTest {
        time: Timespec,
        is_full: bool,
        num_volumes: usize,
    }

    #[derive(Debug, Clone, Eq, PartialEq)]
    struct FileTest {
        path: PathBuf,
        mtime: Timespec,
        uname: String,
        gname: String,
    }

    impl FileTest {
        pub fn from_file(file: &File) -> Self {
            FileTest {
                path: file.path().to_owned(),
                mtime: file.mtime(),
                uname: file.username().unwrap().to_owned(),
                gname: file.groupname().unwrap().to_owned(),
            }
        }
    }

    fn from_backup_set(set: &BackupSet, full: bool) -> SnapshotTest {
        SnapshotTest {
            time: set.end_time(),
            is_full: full,
            num_volumes: set.num_volumes(),
        }
    }

    fn from_collection(coll: &Collections) -> Vec<SnapshotTest> {
        let mut result = Vec::new();
        for chain in coll.backup_chains() {
            result.push(from_backup_set(chain.full_set(), true));
            for set in chain.inc_sets() {
                result.push(from_backup_set(set, false));
            }
        }
        result
    }

    fn to_test_snapshot<B: Backend>(backup: &Backup<B>) -> Vec<SnapshotTest> {
        backup.snapshots()
              .unwrap()
              .map(|s| {
                  assert!(s.is_full() != s.is_incremental());
                  SnapshotTest {
                      time: s.time(),
                      is_full: s.is_full(),
                      num_volumes: s.num_volumes(),
                  }
              })
              .collect()
    }

    fn single_vol_signature_chain() -> Chain {
        let backend = LocalBackend::new("tests/backups/single_vol");
        let filenames = backend.file_names().unwrap();
        let coll = Collections::from_filenames(filenames);
        Chain::from_sigchain(coll.signature_chains().next().unwrap(), &backend).unwrap()
    }

    fn from_sigchain(chain: &Chain) -> Vec<Vec<FileTest>> {
        chain.snapshots()
             .map(|s| {
                 s.files()
                  .map(|f| FileTest::from_file(&f))
                  .filter(|f| f.path.to_str().is_some())
                  .collect::<Vec<_>>()
             })
             .collect::<Vec<_>>()
    }

    #[test]
    fn same_collections() {
        let backend = LocalBackend::new("tests/backups/single_vol");
        let filenames = backend.file_names().unwrap();
        let coll = Collections::from_filenames(filenames);
        let backup = Backup::new(backend).unwrap();

        let expected = from_collection(&coll);
        let actual = to_test_snapshot(&backup);
        assert_eq!(actual, expected);
    }

    #[test]
    fn same_files() {
        let sigchain = single_vol_signature_chain();
        let expected = from_sigchain(&sigchain);

        let backend = LocalBackend::new("tests/backups/single_vol");
        let backup = Backup::new(backend).unwrap();
        let actual = backup.snapshots()
                           .unwrap()
                           .map(|s| {
                               s.files()
                                .unwrap()
                                .as_signature_info()
                                .map(|f| FileTest::from_file(&f))
                                .filter(|f| f.path.to_str().is_some())
                                .collect::<Vec<_>>()
                           })
                           .collect::<Vec<_>>();
        assert_eq!(actual, expected);
    }
}
<commit_msg>Fixed doc-tests warning<commit_after>//! A library for reading duplicity backups.
//!
//! This library provides utilities to manage duplicity backups [1]. Backup files could be prensent
//! in the local file system, or can be accessed remotely, provided that the right backend is
//! implemented. This is a rust version of the original duplicity project, that is written in
//! Python. The goal is to o provide a library to be used for different purposes (e.g. a command
//! line utility, a fusion filesystem, etc.) and to improve overall performances. Full
//! compatibility with the original duplicity is guaranteed.
//!
//! [1]: http://duplicity.nongnu.org/

#![deny(missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unstable_features,
        unused_import_braces, unused_qualifications)]

#![cfg_attr(feature = "nightly", allow(unstable_features))]
#![cfg_attr(feature = "lints", feature(plugin))]
#![cfg_attr(feature = "lints", plugin(clippy))]

extern crate byteorder;
extern crate flate2;
extern crate regex;
extern crate tabwriter;
extern crate tar;
extern crate time;
#[macro_use]
extern crate try_opt;

mod macros;
mod time_utils;
pub mod backend;
pub mod collections;
pub mod signatures;

use std::cell::{Ref, RefCell};
use std::io;

use time::Timespec;

pub use backend::Backend;
use collections::{BackupChain, BackupSet, Collections};
use signatures::Chain;

/// A top level representation of a duplicity backup.
#[derive(Debug)]
pub struct Backup<B> {
    backend: B,
    collections: Collections,
    signatures: Vec<RefCell<Option<Chain>>>,
}

/// An iterator over the snapshots in a backup.
pub struct Snapshots<'a> {
    set_iter: CollectionsIter<'a>,
    chain_id: usize,
    sig_id: usize,
    backup: &'a ResourceCache,
}

/// A snapshot in a backup.
pub struct Snapshot<'a> {
    set: &'a BackupSet,
    // the number of the parent backup chain, starting from zero
    chain_id: usize,
    sig_id: usize,
    backup: &'a ResourceCache,
}

/// Contains the files present in a certain backup snapshot.
pub struct SnapshotFiles<'a> {
    chain: Ref<'a, Option<Chain>>,
    sig_id: usize,
}

struct CollectionsIter<'a> {
    chain_iter: collections::ChainIter<'a, BackupChain>,
    incset_iter: Option<collections::BackupSetIter<'a>>,
}

/// Allows to be used as an interface for `Backup` struct without generic parameters. This allows
/// to reduce code size, since we don't have to godegen the entire module for different Backend
/// generic parameters. This trait is used as an interface between `Backup` and its inner
/// components.
trait ResourceCache {
    fn _collections(&self) -> &Collections;
    fn _signature_chain(&self, chain_id: usize) -> io::Result<Ref<Option<Chain>>>;
}

impl<B: Backend> Backup<B> {
    /// Opens an existig backup by using the given backend.
    ///
    /// # Errors
    /// This function will return an error whenever the backend returns an error in a file
    /// operation. If the backend can't provide access to backup files, because they are
    /// unavailable or non-existing, an empty backup could be returned.
    ///
    /// # Examples
    /// ```
    /// use ruplicity::Backup;
    /// use ruplicity::backend::local::LocalBackend;
    ///
    /// // use the local backend to open a path in the file system containing a backup
    /// let backend = LocalBackend::new("tests/backup/single_vol");
    /// let backup = Backup::new(backend);
    /// ```
    pub fn new(backend: B) -> io::Result<Self> {
        let files = try!(backend.file_names());
        let collections = Collections::from_filenames(files);
        let signatures = {
            // initialize signatures with empty signatures
            // to be loaded lazily
            let mut signatures = Vec::new();
            for _ in collections.signature_chains() {
                signatures.push(RefCell::new(None));
            }
            signatures
        };
        Ok(Backup {
            backend: backend,
            collections: collections,
            signatures: signatures,
        })
    }

    /// Constructs an iterator over the snapshots currently present in this backup.
    pub fn snapshots(&self) -> io::Result<Snapshots> {
        let set_iter = CollectionsIter {
            chain_iter: self.collections.backup_chains(),
            incset_iter: None,
        };
        // in future, when we will add lazy collections,
        // this could fail, so we add a Result in advance
        Ok(Snapshots {
            set_iter: set_iter,
            chain_id: 0,
            sig_id: 0,
            backup: self,
        })
    }
}

impl<'a> Iterator for Snapshots<'a> {
    type Item = Snapshot<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        // first test if we have a valid iterator to an incset
        if let Some(ref mut incset_iter) = self.set_iter.incset_iter {
            // we have a set iter, so return the next element if present
            if let Some(inc_set) = incset_iter.next() {
                self.sig_id += 1;
                return Some(Snapshot {
                    set: inc_set,
                    chain_id: self.chain_id - 1,
                    sig_id: self.sig_id,
                    backup: self.backup,
                });
            }
        }
        // the current incset is exausted or not present,
        // we need to advance the chain and return the next full set if present,
        // otherwise the job is finished
        if let Some(chain) = self.set_iter.chain_iter.next() {
            self.chain_id += 1;
            self.sig_id = 0;
            self.set_iter.incset_iter = Some(chain.inc_sets());
            Some(Snapshot {
                set: chain.full_set(),
                chain_id: self.chain_id - 1,
                sig_id: self.sig_id,
                backup: self.backup,
            })
        } else {
            None
        }
    }
}

impl<'a> AsRef<Collections> for Snapshots<'a> {
    fn as_ref(&self) -> &Collections {
        self.backup._collections()
    }
}

impl<'a> Snapshot<'a> {
    /// Returns the time in which the snapshot has been taken.
    pub fn time(&self) -> Timespec {
        self.set.end_time()
    }

    /// Returns true if the snapshot is a full backup.
    ///
    /// A full snapshot does not depend on previous snapshots.
    pub fn is_full(&self) -> bool {
        self.set.is_full()
    }

    /// Returns true if the snapshot is an incremental backup.
    ///
    /// An incremental snapshot depends on all the previous incremental snapshots and the first
    /// previous full snapshot. This set of dependent snapshots is called "chain".
    pub fn is_incremental(&self) -> bool {
        self.set.is_incremental()
    }

    /// Returns the number of volumes contained in the snapshot.
    pub fn num_volumes(&self) -> usize {
        self.set.num_volumes()
    }

    /// Returns the files present in the snapshot.
    ///
    /// Be aware that using this functionality means that all the signature files in the current
    /// backup chain must be loaded, and this could take some time, depending on the file access
    /// provided by the backend.
    pub fn files(&self) -> io::Result<SnapshotFiles> {
        let sig = try!(self.backup._signature_chain(self.chain_id));
        if self.sig_id < sig.as_ref().unwrap().snapshots().len() {
            Ok(SnapshotFiles {
                chain: sig,
                sig_id: self.sig_id,
            })
        } else {
            Err(io::Error::new(io::ErrorKind::NotFound, "The signature chain is incomplete"))
        }
    }
}

impl<'a> AsRef<BackupSet> for Snapshot<'a> {
    fn as_ref(&self) -> &BackupSet {
        self.set
    }
}

impl<'a> SnapshotFiles<'a> {
    /// Converts the snapshot files into the signature representation.
    ///
    /// This function can be used to retrieve lower level informations about the files in the
    /// snapshot.
    pub fn as_signature_info(&self) -> signatures::SnapshotFiles {
        self.chain.as_ref().unwrap().snapshots().nth(self.sig_id).unwrap().files()
    }
}

impl<B: Backend> ResourceCache for Backup<B> {
    fn _collections(&self) -> &Collections {
        &self.collections
    }

    fn _signature_chain(&self, chain_id: usize) -> io::Result<Ref<Option<Chain>>> {
        {
            // check if there is a cached value
            let mut sig = self.signatures[chain_id].borrow_mut();
            if sig.is_none() {
                // compute signatures now
                if let Some(sigchain) = self.collections.signature_chains().nth(chain_id) {
                    let new_sig = try!(Chain::from_sigchain(sigchain, &self.backend));
                    *sig = Some(new_sig);
                } else {
                    return Err(io::Error::new(io::ErrorKind::NotFound,
                                              "The given backup snapshot does not have a \
                                              corresponding signature"));
                }
            }
        }

        // need to close previous scope to borrow again
        // return the cached value
        Ok(self.signatures[chain_id].borrow())
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use backend::local::LocalBackend;
    use collections::{BackupSet, Collections};
    use signatures::{Chain, File};

    use std::path::PathBuf;

    use time::Timespec;

    #[derive(Debug, Eq, PartialEq)]
    struct SnapshotTest {
        time: Timespec,
        is_full: bool,
        num_volumes: usize,
    }

    #[derive(Debug, Clone, Eq, PartialEq)]
    struct FileTest {
        path: PathBuf,
        mtime: Timespec,
        uname: String,
        gname: String,
    }

    impl FileTest {
        pub fn from_file(file: &File) -> Self {
            FileTest {
                path: file.path().to_owned(),
                mtime: file.mtime(),
                uname: file.username().unwrap().to_owned(),
                gname: file.groupname().unwrap().to_owned(),
            }
        }
    }

    fn from_backup_set(set: &BackupSet, full: bool) -> SnapshotTest {
        SnapshotTest {
            time: set.end_time(),
            is_full: full,
            num_volumes: set.num_volumes(),
        }
    }

    fn from_collection(coll: &Collections) -> Vec<SnapshotTest> {
        let mut result = Vec::new();
        for chain in coll.backup_chains() {
            result.push(from_backup_set(chain.full_set(), true));
            for set in chain.inc_sets() {
                result.push(from_backup_set(set, false));
            }
        }
        result
    }

    fn to_test_snapshot<B: Backend>(backup: &Backup<B>) -> Vec<SnapshotTest> {
        backup.snapshots()
              .unwrap()
              .map(|s| {
                  assert!(s.is_full() != s.is_incremental());
                  SnapshotTest {
                      time: s.time(),
                      is_full: s.is_full(),
                      num_volumes: s.num_volumes(),
                  }
              })
              .collect()
    }

    fn single_vol_signature_chain() -> Chain {
        let backend = LocalBackend::new("tests/backups/single_vol");
        let filenames = backend.file_names().unwrap();
        let coll = Collections::from_filenames(filenames);
        Chain::from_sigchain(coll.signature_chains().next().unwrap(), &backend).unwrap()
    }

    fn from_sigchain(chain: &Chain) -> Vec<Vec<FileTest>> {
        chain.snapshots()
             .map(|s| {
                 s.files()
                  .map(|f| FileTest::from_file(&f))
                  .filter(|f| f.path.to_str().is_some())
                  .collect::<Vec<_>>()
             })
             .collect::<Vec<_>>()
    }

    #[test]
    fn same_collections() {
        let backend = LocalBackend::new("tests/backups/single_vol");
        let filenames = backend.file_names().unwrap();
        let coll = Collections::from_filenames(filenames);
        let backup = Backup::new(backend).unwrap();

        let expected = from_collection(&coll);
        let actual = to_test_snapshot(&backup);
        assert_eq!(actual, expected);
    }

    #[test]
    fn same_files() {
        let sigchain = single_vol_signature_chain();
        let expected = from_sigchain(&sigchain);

        let backend = LocalBackend::new("tests/backups/single_vol");
        let backup = Backup::new(backend).unwrap();
        let actual = backup.snapshots()
                           .unwrap()
                           .map(|s| {
                               s.files()
                                .unwrap()
                                .as_signature_info()
                                .map(|f| FileTest::from_file(&f))
                                .filter(|f| f.path.to_str().is_some())
                                .collect::<Vec<_>>()
                           })
                           .collect::<Vec<_>>();
        assert_eq!(actual, expected);
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! A Piston 2D graphics back-end using gfx-rs.

#[macro_use]
extern crate gfx;
extern crate gfx_texture;
extern crate graphics;
extern crate shaders_graphics2d as shaders;

pub use gfx_texture::*;

pub use back_end::{ Gfx2d, GfxGraphics };
pub use glyph::GlyphCache;

mod back_end;
mod glyph;
<commit_msg>pub use glyph::Error as GlyphError<commit_after>#![deny(missing_docs)]

//! A Piston 2D graphics back-end using gfx-rs.

#[macro_use]
extern crate gfx;
extern crate gfx_texture;
extern crate graphics;
extern crate shaders_graphics2d as shaders;

pub use gfx_texture::*;

pub use back_end::{ Gfx2d, GfxGraphics };
pub use glyph::Error as GlyphError;
pub use glyph::GlyphCache;

mod back_end;
mod glyph;
<|endoftext|>


<commit_before>#![feature(unboxed_closures, macro_rules, globs)]

extern crate shader_version;
extern crate event;
extern crate event_loop;
extern crate conrod;
extern crate graphics;
extern crate window;
extern crate opengl_graphics;
extern crate current;

use conrod::*;

use current::Set;

use event::Event;
use event_loop::{Events, Ups, MaxFps};

use opengl_graphics::Gl;
use opengl_graphics::glyph_cache::GlyphCache as Font;

use shader_version::opengl::OpenGL;

use window::{Window, WindowSettings};

use std::comm::TryRecvError;

use std::default::Default;

use std::io::fs::{mod, PathExtensions};
use std::io::IoResult;

use std::os;

use std::cell::Cell;

pub struct FileDialog {
    title: String,
    dimen: [u32, ..2],
    samples: u8,
    background: Color,
    select: SelectType,
    starting_path: Path,
    font: Font,
    filter_hidden: bool,
}

macro_rules! setter(
    ($field:ident: $ty:ty -> $ret:ident) => (
        fn $field(mut self, $field: $ty) -> $ret {
            self.$field = $field;
            self
        }
    );
)

impl FileDialog {
    pub fn new<S: StrAllocating>(title: S, font: Font) -> FileDialog {
        FileDialog {
            title: title.into_string(),
            dimen: [640, 480],
            samples: 4,
            background: Color::new(0.9, 0.9, 0.9, 1.0), // Should be a nice light-grey
            select: SelectType::File,
            // Possible panic! here, but unlikely.
            starting_path: os::homedir().unwrap_or_else(|| os::getcwd().unwrap()),
            font: font,
            filter_hidden: true,
        }
    }

    pub fn width(mut self, width: u32) -> FileDialog {
        self.dimen[0] = width;
        self
    }

    pub fn height(mut self, height: u32) -> FileDialog {
        self.dimen[1] = height;
        self
    }

    pub fn dimensions(mut self, width: u32, height: u32) -> FileDialog {
        self.dimen = [width, height];
        self
    }

    setter!(samples: u8 -> FileDialog)

    setter!(background: Color -> FileDialog)

    setter!(select: SelectType -> FileDialog)

    setter!(starting_path: Path -> FileDialog)

    setter!(filter_hidden: bool -> FileDialog)

    // How should we format the trait bounds here?
    /// Show the dialog
    pub fn show<W: Window, F: FnOnce(OpenGL, WindowSettings) -> W + Send>
    (self, win_fn: F, gl: OpenGL) -> FilePromise {
        let (promise, tx) = FilePromise::new();
        let (dialog, window) = self.explode(tx);

        spawn(proc() render_file_dialog(dialog, window, gl, win_fn));

        promise
    }

    fn explode(self, tx: Sender<Path>) -> (DialogSettings, WindowSettings) {
        (
            DialogSettings {
                background: self.background,
                select: self.select,
                starting_path: self.starting_path,
                font: self.font,
                tx: tx,
                filter_hidden: self.filter_hidden,
            },
            WindowSettings {
                title: self.title,
                size: self.dimen,
                samples: self.samples,
                fullscreen: false,
                exit_on_esc: true,
            }
        )
    }
}

/// An enum describing the file selection behavior.
pub enum SelectType {
    /// User must select an existing file on the filesystem.
    File,
    /// User must select an existing folder on the filesystem, or create a new one.
    Folder,
    /// User must select the location to save a file, and the filename.
    /// The contained `Option<String>` is the default filename, if any.
    SaveFile(Option<String>),
}

impl SelectType {
    fn show_files(&self) -> bool {
        match *self {
            SelectType::File | SelectType::SaveFile(_) => true,
            _ => false,
        }
    }
}

struct DialogSettings {
    background: Color,
    select: SelectType,
    starting_path: Path,
    font: Font,
    tx: Sender<Path>,
    filter_hidden: bool,
}

impl DialogSettings {
    fn into_state(self) -> (DialogState, Font) {
        (
            DialogState {
                dir: self.starting_path,
                selected: None,
                paths: Vec::new(),
                background: self.background,
                select: self.select,
                dir_changed: false,
                pages: 0,
                cur_page: 0,
                tx: self.tx,
                exit: false,
                filter_hidden: self.filter_hidden,
            },
            self.font,
        )
    }
}

fn render_file_dialog<W: Window, F: FnOnce(OpenGL, WindowSettings) -> W>
(dialog: DialogSettings, window: WindowSettings, gl: OpenGL, win_fn: F) {
    let (mut state, font) = dialog.into_state();
    state.update_paths();

    let ref mut state = state;

    let window = win_fn(gl, window);
    let mut event_loop = Events::new(window).set(Ups(120)).set(MaxFps(60));
    let mut gl = Gl::new(gl);

    let ref mut uic = UiContext::new(font, Theme::default());
    let ref mut buf = Default::default();

    for event in event_loop {
        if state.exit { break; }

        uic.handle_event(&event);
        match event {
            Event::Render(args) => {
                gl.draw([0, 0, args.width as i32, args.height as i32], |_, gl| {
                    draw_dialog_ui(gl, uic, state, buf);
                });
            },
            _ => {}
        }
    }
}

#[deriving(Default)]
struct Buffers {
    dir: String,
    page: String,
}

impl Buffers {
    fn set_page(&mut self, page: uint, total: uint) {
        self.page = format!("Page: {} Total: {}", page, total);
    }
}

struct DialogState {
    dir: Path,
    selected: Option<uint>,
    paths: Vec<Path>,
    background: Color,
    select: SelectType,
    dir_changed: bool,
    pages: uint,
    cur_page: uint,
    tx: Sender<Path>,
    exit: bool,
    filter_hidden: bool,
}

impl DialogState {
    fn update_dir(&mut self, new_dir: Path) {
        self.dir_changed = if new_dir.is_dir() {
            self.dir = new_dir;
            self.update_paths();
            true
        } else {
            false
        }
    }

    fn update_paths(&mut self) {
        self.selected = None;
        self.paths = entries(&self.dir, self.select.show_files(), self.filter_hidden).unwrap();

        let count = self.paths.len();
        self.pages = count / PER_PAGE;

        if count % PER_PAGE != 0 { self.pages += 1; }
    }

    fn up_dir(&mut self) {
        self.dir_changed = self.dir.pop();
        self.update_paths();
    }

    fn select(&mut self, num: uint) {
        // Double-clicked
        if self.selected == Some(num) {
            let path = self.paths.remove(num).unwrap();

            if self.select.show_files() && !path.is_dir() {
                self.tx.send(path);
                self.exit = true;
            } else {
                self.update_dir(path);
            }
        } else {
            self.selected = Some(num);
        }
    }
}

const COLS: uint = 5;
const ROWS: uint = 8;
const PER_PAGE: uint = COLS * ROWS;

fn draw_dialog_ui(gl: &mut Gl, uic: &mut UiContext, state: &mut DialogState, buf: &mut Buffers) {
    uic.background().color(state.background).draw(gl);

    if state.dir_changed {
        buf.dir.clear();
    }

    if buf.dir.is_empty() {
        state.dir.as_str().map(|s| buf.dir.push_str(s));
    }

    thread_local!(static CUR_PAGE: Cell<uint> = Cell::new(1))

    CUR_PAGE.with(|cur_page| {
        let page = cur_page.get();
        if page != state.cur_page {
            state.cur_page = page;
            buf.set_page(page, state.pages);
        }
    });

    const BUTTON_ID: u64 = 78;

    uic.button(BUTTON_ID)
        .position(605.0, 5.0)
        .dimensions(30.0, 30.0)
        .label("Up")
        .callback(|| state.up_dir())
        .draw(gl);

    uic.label(&*buf.dir)
        .position(5.0, 5.0)
        .size(24)
        .draw(gl);

    const PREV_PAGE: u64 = 199;

    uic.button(PREV_PAGE)
        .position(30.0, 445.0)
        .dimensions(90.0, 30.0)
        .label("Previous")
        .callback(|| CUR_PAGE.with(|cur_page| {
            let page = cur_page.get();
            if page > 1 { cur_page.set(page - 1); }
        }))
        .draw(gl);

    uic.button(PREV_PAGE + 1)
        .right_from(PREV_PAGE, 125.0)
        .dimensions(90.0, 30.0)
        .label("Next")
        .callback(|| CUR_PAGE.with(|cur_page| {
            let page = cur_page.get();
            if page < state.pages { cur_page.set(page + 1); }
        }))
        .draw(gl);

    uic.label(&*buf.page)
        .right_from(PREV_PAGE, 30.0)
        .size(24)
        .draw(gl);

    const FILE_START_ID: u64 = 365;
    uic.widget_matrix(COLS, ROWS)
        .position(5.0, 35.0)
        .dimensions(600.0, 400.0)
        .cell_padding(5.0, 5.0)
        .each_widget(|uic, num, _, _, pt, dimen| {
            let idx = (state.cur_page - 1) * PER_PAGE + num;

            if idx >= state.paths.len() { return; }

            let label = state.paths[idx].filename_str().unwrap().into_string();

            let button = uic.button(FILE_START_ID + num as u64)
                .point(pt)
                .dimensions(dimen[0], dimen[1])
                .label(&*label).label_font_size(18);

                if state.selected == Some(num) {
                    button.color(Color::new(0.5, 0.9, 0.5, 1.0))
                } else { button }
                .callback(|| state.select(num))
                .draw(gl);
        });
}

fn entries(path: &Path, keep_files: bool, filter_hidden: bool) -> IoResult<Vec<Path>> {
    let mut entries = try!(fs::readdir(path));
    entries.retain(|file|
        (filter_hidden && !file.filename_str().unwrap().starts_with(".")) &&
        (keep_files || file.is_dir())
    );
    entries.sort();

    Ok(entries)
}

pub struct FilePromise {
    opt: Option<Path>,
    rx: Receiver<Path>,
}

impl FilePromise {
    pub fn new() -> (FilePromise, Sender<Path>) {
        let (tx, rx) = channel();

        (
            FilePromise {
                opt: None,
                rx: rx,
            },
            tx,
        )
    }

    pub fn poll(&mut self) -> Option<&Path> {
        match self.rx.try_recv() {
            Ok(val) => self.opt = Some(val),
            Err(TryRecvError::Empty) => return None,
            Err(TryRecvError::Disconnected) if self.opt.is_none() =>
                panic!("Promised value never received; processing task ended prematurely!"),
            _ => (),
        }

        self.opt.as_ref()
    }

    pub fn unwrap(mut self) -> Path {
        while self.poll().is_none() {}

        self.opt.unwrap()
    }
}
<commit_msg>Fix fill order of file listings<commit_after>#![feature(unboxed_closures, macro_rules, globs)]

extern crate shader_version;
extern crate event;
extern crate event_loop;
extern crate conrod;
extern crate graphics;
extern crate window;
extern crate opengl_graphics;
extern crate current;

use conrod::*;

use current::Set;

use event::Event;
use event_loop::{Events, Ups, MaxFps};

use opengl_graphics::Gl;
use opengl_graphics::glyph_cache::GlyphCache as Font;

use shader_version::opengl::OpenGL;

use window::{Window, WindowSettings};

use std::comm::TryRecvError;

use std::default::Default;

use std::io::fs::{mod, PathExtensions};
use std::io::IoResult;

use std::os;

use std::cell::Cell;

pub struct FileDialog {
    title: String,
    dimen: [u32, ..2],
    samples: u8,
    background: Color,
    select: SelectType,
    starting_path: Path,
    font: Font,
    filter_hidden: bool,
}

macro_rules! setter(
    ($field:ident: $ty:ty -> $ret:ident) => (
        fn $field(mut self, $field: $ty) -> $ret {
            self.$field = $field;
            self
        }
    );
)

impl FileDialog {
    pub fn new<S: StrAllocating>(title: S, font: Font) -> FileDialog {
        FileDialog {
            title: title.into_string(),
            dimen: [640, 480],
            samples: 4,
            background: Color::new(0.9, 0.9, 0.9, 1.0), // Should be a nice light-grey
            select: SelectType::File,
            // Possible panic! here, but unlikely.
            starting_path: os::homedir().unwrap_or_else(|| os::getcwd().unwrap()),
            font: font,
            filter_hidden: true,
        }
    }

    pub fn width(mut self, width: u32) -> FileDialog {
        self.dimen[0] = width;
        self
    }

    pub fn height(mut self, height: u32) -> FileDialog {
        self.dimen[1] = height;
        self
    }

    pub fn dimensions(mut self, width: u32, height: u32) -> FileDialog {
        self.dimen = [width, height];
        self
    }

    setter!(samples: u8 -> FileDialog)

    setter!(background: Color -> FileDialog)

    setter!(select: SelectType -> FileDialog)

    setter!(starting_path: Path -> FileDialog)

    setter!(filter_hidden: bool -> FileDialog)

    // How should we format the trait bounds here?
    /// Show the dialog
    pub fn show<W: Window, F: FnOnce(OpenGL, WindowSettings) -> W + Send>
    (self, win_fn: F, gl: OpenGL) -> FilePromise {
        let (promise, tx) = FilePromise::new();
        let (dialog, window) = self.explode(tx);

        spawn(proc() render_file_dialog(dialog, window, gl, win_fn));

        promise
    }

    fn explode(self, tx: Sender<Path>) -> (DialogSettings, WindowSettings) {
        (
            DialogSettings {
                background: self.background,
                select: self.select,
                starting_path: self.starting_path,
                font: self.font,
                tx: tx,
                filter_hidden: self.filter_hidden,
            },
            WindowSettings {
                title: self.title,
                size: self.dimen,
                samples: self.samples,
                fullscreen: false,
                exit_on_esc: true,
            }
        )
    }
}

/// An enum describing the file selection behavior.
pub enum SelectType {
    /// User must select an existing file on the filesystem.
    File,
    /// User must select an existing folder on the filesystem, or create a new one.
    Folder,
    /// User must select the location to save a file, and the filename.
    /// The contained `Option<String>` is the default filename, if any.
    SaveFile(Option<String>),
}

impl SelectType {
    fn show_files(&self) -> bool {
        match *self {
            SelectType::File | SelectType::SaveFile(_) => true,
            _ => false,
        }
    }
}

struct DialogSettings {
    background: Color,
    select: SelectType,
    starting_path: Path,
    font: Font,
    tx: Sender<Path>,
    filter_hidden: bool,
}

impl DialogSettings {
    fn into_state(self) -> (DialogState, Font) {
        (
            DialogState {
                dir: self.starting_path,
                selected: None,
                paths: Vec::new(),
                background: self.background,
                select: self.select,
                dir_changed: false,
                pages: 0,
                cur_page: 0,
                tx: self.tx,
                exit: false,
                filter_hidden: self.filter_hidden,
            },
            self.font,
        )
    }
}

fn render_file_dialog<W: Window, F: FnOnce(OpenGL, WindowSettings) -> W>
(dialog: DialogSettings, window: WindowSettings, gl: OpenGL, win_fn: F) {
    let (mut state, font) = dialog.into_state();
    state.update_paths();

    let ref mut state = state;

    let window = win_fn(gl, window);
    let mut event_loop = Events::new(window).set(Ups(120)).set(MaxFps(60));
    let mut gl = Gl::new(gl);

    let ref mut uic = UiContext::new(font, Theme::default());
    let ref mut buf = Default::default();

    for event in event_loop {
        if state.exit { break; }

        uic.handle_event(&event);
        match event {
            Event::Render(args) => {
                gl.draw([0, 0, args.width as i32, args.height as i32], |_, gl| {
                    draw_dialog_ui(gl, uic, state, buf);
                });
            },
            _ => {}
        }
    }
}

#[deriving(Default)]
struct Buffers {
    dir: String,
    page: String,
}

impl Buffers {
    fn set_page(&mut self, page: uint, total: uint) {
        self.page = format!("Page: {} Total: {}", page, total);
    }
}

struct DialogState {
    dir: Path,
    selected: Option<uint>,
    paths: Vec<Path>,
    background: Color,
    select: SelectType,
    dir_changed: bool,
    pages: uint,
    cur_page: uint,
    tx: Sender<Path>,
    exit: bool,
    filter_hidden: bool,
}

impl DialogState {
    fn update_dir(&mut self, new_dir: Path) {
        self.dir_changed = if new_dir.is_dir() {
            self.dir = new_dir;
            self.update_paths();
            true
        } else {
            false
        }
    }

    fn update_paths(&mut self) {
        self.selected = None;
        self.paths = entries(&self.dir, self.select.show_files(), self.filter_hidden).unwrap();

        let count = self.paths.len();
        self.pages = count / PER_PAGE;
        self.cur_page = 1;

        if count % PER_PAGE != 0 { self.pages += 1; }
    }

    fn up_dir(&mut self) {
        self.dir_changed = self.dir.pop();
        self.update_paths();
    }

    fn select(&mut self, num: uint) {
        // Double-clicked
        if self.selected == Some(num) {
            let path = self.paths.remove(num).unwrap();

            if self.select.show_files() && !path.is_dir() {
                self.tx.send(path);
                self.exit = true;
            } else {
                self.update_dir(path);
            }
        } else {
            self.selected = Some(num);
        }
    }
}

const COLS: uint = 5;
const ROWS: uint = 8;
const PER_PAGE: uint = COLS * ROWS;
const CHAR_LIMIT: uint = 24;

fn draw_dialog_ui(gl: &mut Gl, uic: &mut UiContext, state: &mut DialogState, buf: &mut Buffers) {
    uic.background().color(state.background).draw(gl);

    CUR_PAGE.with(|cur_page| {
        let page = cur_page.get();
        if page != state.cur_page {
            state.cur_page = page;
            buf.set_page(state.cur_page, state.pages);
        }
    });

    if state.dir_changed {
        buf.dir.clear();
        buf.set_page(state.cur_page, state.pages);
        state.dir_changed = false;
    }

    if buf.dir.is_empty() {
        state.dir.as_str().map(|s| buf.dir.push_str(s));
        buf.set_page(state.cur_page, state.pages);
    }

    thread_local!(static CUR_PAGE: Cell<uint> = Cell::new(1))

    const BUTTON_ID: u64 = 78;

    uic.button(BUTTON_ID)
        .position(605.0, 5.0)
        .dimensions(30.0, 30.0)
        .label("Up")
        .callback(|| state.up_dir())
        .draw(gl);

    uic.label(&*buf.dir)
        .position(5.0, 5.0)
        .size(24)
        .draw(gl);

    const PREV_PAGE: u64 = 199;

    uic.button(PREV_PAGE)
        .position(5.0, 445.0)
        .dimensions(90.0, 30.0)
        .label("Previous")
        .callback(|| CUR_PAGE.with(|cur_page| {
            let page = cur_page.get();
            if page > 1 { cur_page.set(page - 1); }
        }))
        .draw(gl);

    uic.button(PREV_PAGE + 1)
        .right_from(PREV_PAGE, 125.0)
        .dimensions(90.0, 30.0)
        .label("Next")
        .callback(|| CUR_PAGE.with(|cur_page| {
            let page = cur_page.get();
            if page < state.pages { cur_page.set(page + 1); }
        }))
        .draw(gl);

    uic.label(&*buf.page)
        .right_from(PREV_PAGE, 15.0)
        .size(24)
        .draw(gl);

    const FILE_START_ID: u64 = 365;
    uic.widget_matrix(COLS, ROWS)
        .position(5.0, 35.0)
        .dimensions(600.0, 400.0)
        .cell_padding(5.0, 5.0)
        .each_widget(|uic, _, x, y, pt, dimen| {
            use std::cmp;
            let idx = y * COLS + x;

            if idx >= state.paths.len() { return; }

            let label = state.paths[idx].filename_str().unwrap().into_string();

            let button = uic.button(FILE_START_ID + idx as u64)
                .point(pt)
                .dimensions(dimen[0], dimen[1])
                .label(label.slice_to(cmp::min(label.len(), CHAR_LIMIT))).label_font_size(18);

                if state.selected == Some(idx) {
                    button.color(Color::new(0.5, 0.9, 0.5, 1.0))
                } else { button }
                .callback(|| state.select(idx))
                .draw(gl);
        });
}

fn entries(path: &Path, keep_files: bool, filter_hidden: bool) -> IoResult<Vec<Path>> {
    let mut entries = try!(fs::readdir(path));
    entries.retain(|file|
        (filter_hidden && !file.filename_str().unwrap().starts_with(".")) &&
        (keep_files || file.is_dir())
    );
    entries.sort();

    Ok(entries)
}

pub struct FilePromise {
    opt: Option<Path>,
    rx: Receiver<Path>,
}

impl FilePromise {
    pub fn new() -> (FilePromise, Sender<Path>) {
        let (tx, rx) = channel();

        (
            FilePromise {
                opt: None,
                rx: rx,
            },
            tx,
        )
    }

    pub fn poll(&mut self) -> Option<&Path> {
        match self.rx.try_recv() {
            Ok(val) => self.opt = Some(val),
            Err(TryRecvError::Empty) => return None,
            Err(TryRecvError::Disconnected) if self.opt.is_none() =>
                panic!("Promised value never received; processing task ended prematurely!"),
            _ => (),
        }

        self.opt.as_ref()
    }

    pub fn unwrap(mut self) -> Path {
        while self.poll().is_none() {}

        self.opt.unwrap()
    }
}
<|endoftext|>


<commit_before>extern crate crossbeam;

use crossbeam::mem::epoch::{Atomic, Owned, pin};
use std::sync::atomic::Ordering::*;

use std::ops::Deref;

pub struct Pinboard<T: Clone>(Atomic<T>);

impl<T: Clone> Pinboard<T> {
    pub fn new(t: T) -> Pinboard<T> {
        let t = Owned::new(t);
        let p = Pinboard::default();
        p.0.store(Some(t), Release);
        p
    }

    pub fn set(&self, t: T) {
        let guard = pin();
        let t = Owned::new(t);
        if let Some(t) = self.0.swap(Some(t), Release, &guard) {
            unsafe { guard.unlinked(t); }
        }
    }

    pub fn clear(&self) {
        let guard = pin();
        if let Some(t) = self.0.swap(None, Release, &guard) {
            unsafe { guard.unlinked(t); }
        }
    }

    pub fn read(&self) -> Option<T> {
        let guard = pin();
        let t = self.0.load(Acquire, &guard);
        t.map(|t| -> &T { t.deref() }).cloned()
    }
}

impl<T: Clone> Default for Pinboard<T> {
    fn default() -> Pinboard<T> {
        Pinboard(Atomic::null())
    }
}

impl<T: Clone> Drop for Pinboard<T> {
    fn drop(&mut self) {
        // Make sure any stored data is marked for deletion
        self.clear();
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fmt::Display;

    fn consume<T: Clone + Display>(t: &Pinboard<T>) {
        loop {
            match t.read() {
                Some(_) => {},
                None => break,
            }
            std::thread::sleep(std::time::Duration::from_millis(1));
        }
    }

    fn produce(t: &Pinboard<u32>) {
        for i in 1..100 {
            t.set(i);
            std::thread::sleep(std::time::Duration::from_millis(2));
        }
        t.clear();
    }

    #[test]
    fn it_works() {
        let t = Pinboard::<u32>::default();
        assert_eq!(None, t.read());
        t.set(3);
        assert_eq!(Some(3), t.read());
        t.clear();
        assert_eq!(None, t.read());
    }

    #[test]
    fn single_producer_single_consumer() {
        let t = Pinboard::<u32>::new(0);

        crossbeam::scope(|scope| {
            scope.spawn(|| produce(&t));
            scope.spawn(|| consume(&t));
        })
    }

    #[test]
    fn multi_producer_single_consumer() {
        let t = Pinboard::<u32>::new(0);

        crossbeam::scope(|scope| {
            scope.spawn(|| produce(&t));
            scope.spawn(|| produce(&t));
            scope.spawn(|| produce(&t));
            scope.spawn(|| consume(&t));
        })
    }

    #[test]
    fn single_producer_multi_consumer() {
        let t = Pinboard::<u32>::new(0);

        crossbeam::scope(|scope| {
            scope.spawn(|| produce(&t));
            scope.spawn(|| consume(&t));
            scope.spawn(|| consume(&t));
            scope.spawn(|| consume(&t));
        })
    }

    #[test]
    fn multi_producer_multi_consumer() {
        let t = Pinboard::<u32>::new(0);

        crossbeam::scope(|scope| {
            scope.spawn(|| produce(&t));
            scope.spawn(|| produce(&t));
            scope.spawn(|| produce(&t));
            scope.spawn(|| consume(&t));
            scope.spawn(|| consume(&t));
            scope.spawn(|| consume(&t));
        })
    }
}
<commit_msg>Update docs<commit_after>#![warn(missing_docs)]

//! A `Pinboard` is a shared, mutable, eventually consistent, lock-free data-structure.  This
//! allows multiple threads to communicate in a decoupled way by publishing data to the pinboard
//! which other threads can then read in an eventually consistent way.
//!
//! This is not a silver bullet though, there are various limitations of `Pinboard` that trade off
//! the nice behaviour described above.
//!
//! * Eventual consistency:
//!     * Writes from one thread are not guaranteed to be seen by reads from another thread
//!     * Writes from one thread can overwrite writes from another thread
//! * No in-place mutation:
//!     * The only write primitive completely overwrites the data on the `Pinboard`
//! * Requires `Clone`:
//!     * All reads return a clone of the data, decoupling the lifetime of the read value from the
//!     data stored in the global reference.

extern crate crossbeam;

use crossbeam::mem::epoch::{Atomic, Owned, pin};
use std::sync::atomic::Ordering::*;

use std::ops::Deref;

/// An instance of a `Pinboard`, holds a shared, mutable, eventually-consistent reference to a `T`.
pub struct Pinboard<T: Clone>(Atomic<T>);

impl<T: Clone> Pinboard<T> {
    /// Create a new `Pinboard` instance holding the given value.
    pub fn new(t: T) -> Pinboard<T> {
        let t = Owned::new(t);
        let p = Pinboard::default();
        p.0.store(Some(t), Release);
        p
    }

    /// Update the value stored in the `Pinboard`.
    pub fn set(&self, t: T) {
        let guard = pin();
        let t = Owned::new(t);
        if let Some(t) = self.0.swap(Some(t), Release, &guard) {
            unsafe { guard.unlinked(t); }
        }
    }

    /// Clear out the `Pinboard` so its no longer holding any data.
    pub fn clear(&self) {
        let guard = pin();
        if let Some(t) = self.0.swap(None, Release, &guard) {
            unsafe { guard.unlinked(t); }
        }
    }

    /// Get a copy of the latest (well, recent) version of the posted data.
    pub fn read(&self) -> Option<T> {
        let guard = pin();
        let t = self.0.load(Acquire, &guard);
        t.map(|t| -> &T { t.deref() }).cloned()
    }
}

impl<T: Clone> Default for Pinboard<T> {
    fn default() -> Pinboard<T> {
        Pinboard(Atomic::null())
    }
}

impl<T: Clone> Drop for Pinboard<T> {
    fn drop(&mut self) {
        // Make sure any stored data is marked for deletion
        self.clear();
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fmt::Display;

    fn consume<T: Clone + Display>(t: &Pinboard<T>) {
        loop {
            match t.read() {
                Some(_) => {},
                None => break,
            }
            std::thread::sleep(std::time::Duration::from_millis(1));
        }
    }

    fn produce(t: &Pinboard<u32>) {
        for i in 1..100 {
            t.set(i);
            std::thread::sleep(std::time::Duration::from_millis(2));
        }
        t.clear();
    }

    #[test]
    fn it_works() {
        let t = Pinboard::<u32>::default();
        assert_eq!(None, t.read());
        t.set(3);
        assert_eq!(Some(3), t.read());
        t.clear();
        assert_eq!(None, t.read());
    }

    #[test]
    fn single_producer_single_consumer() {
        let t = Pinboard::<u32>::new(0);

        crossbeam::scope(|scope| {
            scope.spawn(|| produce(&t));
            scope.spawn(|| consume(&t));
        })
    }

    #[test]
    fn multi_producer_single_consumer() {
        let t = Pinboard::<u32>::new(0);

        crossbeam::scope(|scope| {
            scope.spawn(|| produce(&t));
            scope.spawn(|| produce(&t));
            scope.spawn(|| produce(&t));
            scope.spawn(|| consume(&t));
        })
    }

    #[test]
    fn single_producer_multi_consumer() {
        let t = Pinboard::<u32>::new(0);

        crossbeam::scope(|scope| {
            scope.spawn(|| produce(&t));
            scope.spawn(|| consume(&t));
            scope.spawn(|| consume(&t));
            scope.spawn(|| consume(&t));
        })
    }

    #[test]
    fn multi_producer_multi_consumer() {
        let t = Pinboard::<u32>::new(0);

        crossbeam::scope(|scope| {
            scope.spawn(|| produce(&t));
            scope.spawn(|| produce(&t));
            scope.spawn(|| produce(&t));
            scope.spawn(|| consume(&t));
            scope.spawn(|| consume(&t));
            scope.spawn(|| consume(&t));
        })
    }
}
<|endoftext|>


<commit_before>//! An XML-RPC implementation in Rust.
//!
//! The `xmlrpc` crate provides a minimal implementation of the [XML-RPC specification].
//!
//! [XML-RPC specification]: http://xmlrpc.scripting.com/spec.html

#![doc(html_root_url = "https://docs.rs/xmlrpc/0.9.0")]

extern crate base64;
extern crate iso8601;
extern crate xml;

mod error;
mod parser;
mod request;
mod value;
mod utils;
mod transport;

pub use error::{Error, Fault};
pub use request::Request;
pub use value::{Value, Index};
pub use transport::Transport;

#[cfg(feature = "reqwest")]
pub use transport::http;
<commit_msg>Warn on missing debug implementations<commit_after>//! An XML-RPC implementation in Rust.
//!
//! The `xmlrpc` crate provides a minimal implementation of the [XML-RPC specification].
//!
//! [XML-RPC specification]: http://xmlrpc.scripting.com/spec.html

#![doc(html_root_url = "https://docs.rs/xmlrpc/0.9.0")]
#![warn(missing_debug_implementations)]

extern crate base64;
extern crate iso8601;
extern crate xml;

mod error;
mod parser;
mod request;
mod value;
mod utils;
mod transport;

pub use error::{Error, Fault};
pub use request::Request;
pub use value::{Value, Index};
pub use transport::Transport;

#[cfg(feature = "reqwest")]
pub use transport::http;
<|endoftext|>


<commit_before>//! A trait alias for [`Service`](tower_service::Service).

pub(crate) use private::IntoService;

use std::future::Future;
use std::task::{Context, Poll};

use http::{Request, Response};
use http_body::Body;
use tower_service::Service;

use private::Sealed;

/// An HTTP client (like [`hyper::Client`](hyper_pkg::client::Client)).
///
/// This is just an alias for [`tower_service::Service`](tower_service::Service)
/// introduced to reduce the number of type parameters in `Builder::listen_with_client`.
pub trait HttpService<B>: Sealed<B> {
    /// Body of the responses given by the service.
    type ResponseBody: Body;
    /// Alias for `Service::Error`.
    type Error;
    #[doc(hidden)]
    type Future: Future<Output = Result<Response<Self::ResponseBody>, Self::Error>>;

    #[doc(hidden)]
    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>;
    #[doc(hidden)]
    fn call(&mut self, req: Request<B>) -> Self::Future;
}

impl<S, ReqB, ResB> HttpService<ReqB> for S
where
    S: Service<Request<ReqB>, Response = Response<ResB>> + ?Sized,
    ResB: Body,
{
    type ResponseBody = ResB;
    type Error = <Self as Service<Request<ReqB>>>::Error;
    type Future = <Self as Service<Request<ReqB>>>::Future;

    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        Service::poll_ready(self, cx)
    }

    fn call(&mut self, req: Request<ReqB>) -> Self::Future {
        Service::call(self, req)
    }
}

mod private {
    use std::task::{Context, Poll};

    use http::{Request, Response};
    use http_body::Body;
    use tower_service::Service;

    use super::HttpService;

    pub trait Sealed<B> {
        fn into_service(self) -> IntoService<Self>
        where
            Self: Sized;
    }

    pub struct IntoService<S>(S);

    impl<S, ReqB, ResB> Sealed<ReqB> for S
    where
        S: Service<Request<ReqB>, Response = Response<ResB>> + ?Sized,
        ResB: Body,
    {
        fn into_service(self) -> IntoService<Self>
        where
            Self: Sized,
        {
            IntoService(self)
        }
    }

    impl<S, B> Service<Request<B>> for IntoService<S>
    where
        S: HttpService<B>,
    {
        type Response = Response<S::ResponseBody>;
        type Error = <S as HttpService<B>>::Error;
        type Future = <S as HttpService<B>>::Future;

        fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
            self.0.poll_ready(cx)
        }

        fn call(&mut self, req: Request<B>) -> Self::Future {
            self.0.call(req)
        }
    }
}
<commit_msg>Fix CI failure<commit_after>//! A trait alias for [`Service`](tower_service::Service).

pub(crate) use private::IntoService;

use std::future::Future;
use std::task::{Context, Poll};

use http::{Request, Response};
use http_body::Body;
use tower_service::Service;

use private::Sealed;

#[cfg_attr(not(feature = "hyper"), allow(intra_doc_link_resolution_failure))]
/// An HTTP client (like [`hyper::Client`](hyper_pkg::client::Client)).
///
/// This is just an alias for [`tower_service::Service`](tower_service::Service)
/// introduced to reduce the number of type parameters in `Builder::listen_with_client`.
pub trait HttpService<B>: Sealed<B> {
    /// Body of the responses given by the service.
    type ResponseBody: Body;
    /// Alias for `Service::Error`.
    type Error;
    #[doc(hidden)]
    type Future: Future<Output = Result<Response<Self::ResponseBody>, Self::Error>>;

    #[doc(hidden)]
    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>;
    #[doc(hidden)]
    fn call(&mut self, req: Request<B>) -> Self::Future;
}

impl<S, ReqB, ResB> HttpService<ReqB> for S
where
    S: Service<Request<ReqB>, Response = Response<ResB>> + ?Sized,
    ResB: Body,
{
    type ResponseBody = ResB;
    type Error = <Self as Service<Request<ReqB>>>::Error;
    type Future = <Self as Service<Request<ReqB>>>::Future;

    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        Service::poll_ready(self, cx)
    }

    fn call(&mut self, req: Request<ReqB>) -> Self::Future {
        Service::call(self, req)
    }
}

mod private {
    use std::task::{Context, Poll};

    use http::{Request, Response};
    use http_body::Body;
    use tower_service::Service;

    use super::HttpService;

    pub trait Sealed<B> {
        fn into_service(self) -> IntoService<Self>
        where
            Self: Sized;
    }

    pub struct IntoService<S>(S);

    impl<S, ReqB, ResB> Sealed<ReqB> for S
    where
        S: Service<Request<ReqB>, Response = Response<ResB>> + ?Sized,
        ResB: Body,
    {
        fn into_service(self) -> IntoService<Self>
        where
            Self: Sized,
        {
            IntoService(self)
        }
    }

    impl<S, B> Service<Request<B>> for IntoService<S>
    where
        S: HttpService<B>,
    {
        type Response = Response<S::ResponseBody>;
        type Error = <S as HttpService<B>>::Error;
        type Future = <S as HttpService<B>>::Future;

        fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
            self.0.poll_ready(cx)
        }

        fn call(&mut self, req: Request<B>) -> Self::Future {
            self.0.call(req)
        }
    }
}
<|endoftext|>