<commit_before>use std::thread;
use std::sync::mpsc::{self, sync_channel, TryRecvError};
use std::io::{Read, ErrorKind};
use std::collections::HashMap;

use mio::*;
use mio::tcp::TcpListener;

use ladspa::{PluginDescriptor, Plugin, PortConnection};

use super::BASE_PORT;
use super::packet::{BUFFER_SIZE, BYTE_BUFFER_SIZE, Packet};

type ClientPacket = (u64, Packet);

const SERVER: Token = Token(0);

pub struct Receiver {
    sample_rate: u64,
    channel: u16,
    packet_rx: Option<mpsc::Receiver<ClientPacket>>,
    active_packets: Vec<ClientPacket>,
    notify_tx: Option<Sender<<PacketReceiver as Handler>::Message>>,
    client_time_map: HashMap<u64, u64>,
}

impl Receiver {
    pub fn new(desc: &PluginDescriptor, sample_rate: u64) -> Box<Plugin + Send> {
        println!("receiver::new");
        Box::new(Receiver {
            sample_rate: sample_rate,
            channel: 0,
            packet_rx: None,
            active_packets: Vec::new(),
            notify_tx: None,
            client_time_map: HashMap::new(),
        })
    }

    fn init_server(&mut self) {
        let (data_tx, data_rx) = sync_channel(16);
        self.packet_rx = Some(data_rx);

        let channel = self.channel;
        let mut event_loop = EventLoop::new().unwrap();
        self.notify_tx = Some(event_loop.channel());
        thread::spawn(move || {
            let addr = format!("127.0.0.1:{}", BASE_PORT + channel).parse().unwrap();
            let server;
            loop {
                match TcpListener::bind(&addr) {
                    Ok(s) => {
                        server = s;
                        break;
                    }
                    Err(_) => {}
                }
            }
            event_loop.register(&server, SERVER).unwrap();
            event_loop.run(&mut PacketReceiver {
                          server: server,
                          data_tx: data_tx,
                          client_id: 0,
                      })
                      .unwrap();
        });
    }

    fn kill_server(&mut self) {
        self.notify_tx.as_ref().unwrap().send(()).unwrap();
    }
}

impl Plugin for Receiver {
    fn run<'a>(&mut self, sample_count: usize, ports: &[&'a PortConnection<'a>]) {
        let inputl = ports[0].unwrap_audio();
        let inputr = ports[1].unwrap_audio();
        let mut outputl = ports[2].unwrap_audio_mut();
        let mut outputr = ports[3].unwrap_audio_mut();

        let channel = *ports[4].unwrap_control() as u16;

        if channel != self.channel {
            self.channel = channel;
            println!("set channel {}", self.channel);
            self.kill_server();
            self.init_server();
            return;
        }

        loop {
            if self.active_packets.len() > 128 {
                break;
            }
            let packet = match self.packet_rx.as_ref().unwrap().try_recv() {
                Ok(packet) => packet,
                Err(TryRecvError::Disconnected) => {
                    println!("ladspa packet receive failed, dead channel!");
                    self.kill_server();
                    self.init_server();
                    break;
                }
                Err(TryRecvError::Empty) => {
                    break;
                }
            };
            self.active_packets.push(packet);
        }

        for i in 0..sample_count {
            outputl[i] = inputl[i];
            outputr[i] = inputl[i];
        }
        let mut read_clients = Vec::new();
        for &mut (ref client_id, ref mut packet) in &mut self.active_packets {
            let client_time = self.client_time_map.get(client_id).map(|x| *x).unwrap_or(0);
            for i in 0..sample_count {
                let (l, r) = packet.read(client_time + i as u64);
                outputl[i] += l;
                outputr[i] += r;
            }
            read_clients.push(*client_id);
        }
        for client_id in read_clients {
            let client_time = self.client_time_map.get(&client_id).map(|x| *x).unwrap_or(0);
            self.client_time_map.insert(client_id, client_time + BUFFER_SIZE as u64);
        }

        let client_time_map = self.client_time_map.clone();
        self.active_packets.retain(|&(ref client_id, ref packet)| {
            let client_time = client_time_map[client_id];
            println!("client {} time {}", client_id, client_time);
            !packet.complete(client_time)
        });
    }

    fn activate(&mut self) {
        println!("activate {}", self.channel);
        self.client_time_map.clear();
        self.init_server();
    }

    fn deactivate(&mut self) {
        println!("deactivate {}", self.channel);
        self.kill_server();
    }
}

struct PacketReceiver {
    server: TcpListener,
    data_tx: mpsc::SyncSender<ClientPacket>,
    client_id: u64,
}

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

    fn ready(&mut self, event_loop: &mut EventLoop<Self>, token: Token, events: EventSet) {
        match token {
            SERVER => {
                // Only receive readable events
                assert!(events.is_readable());

                println!("server wait");
                match self.server.accept() {
                    Ok(Some(mut socket)) => {
                        println!("server accept");
                        let tx = self.data_tx.clone();
                        let mut buf = [0; BYTE_BUFFER_SIZE];
                        let mut buf_pos = 0;
                        let client_id = self.client_id;
                        self.client_id += 1;
                        loop {
                            let res = socket.read(&mut buf[buf_pos..]);
                            match res {
                                Ok(num_read) => {
                                    // if we got a length zero read, the connection is done.
                                    if num_read == 0 {
                                        println!("read zero bytes");
                                        return;
                                    }

                                    // check if we've filled the buffer
                                    buf_pos += num_read;
                                    if buf_pos != BYTE_BUFFER_SIZE {
                                        continue;
                                    }
                                    buf_pos = 0;
                                }
                                Err(e) => {
                                    if e.kind() == ErrorKind::WouldBlock {
                                        continue;
                                    }
                                    panic!(e);
                                }
                            }
                            let mut packet = Packet::parse(&buf[..]);
                            if let Err(_) = tx.send((client_id, packet)) {
                                println!("send packet to ladspa error! channel is dead.");
                                return;
                            }
                        }
                    }
                    Ok(None) => {
                        println!("the server socket wasn't actually ready");
                    }
                    Err(e) => {
                        println!("listener.accept() errored: {}", e);
                        // event_loop.shutdown();
                    }
                }
            }
            _ => panic!("Received unknown token"),
        }
    }
    fn notify(&mut self, event_loop: &mut EventLoop<Self>, msg: Self::Message) {
        event_loop.shutdown();
    }
}
<commit_msg>fix typo that broke stereo<commit_after>use std::thread;
use std::sync::mpsc::{self, sync_channel, TryRecvError};
use std::io::{Read, ErrorKind};
use std::collections::HashMap;

use mio::*;
use mio::tcp::TcpListener;

use ladspa::{PluginDescriptor, Plugin, PortConnection};

use super::BASE_PORT;
use super::packet::{BUFFER_SIZE, BYTE_BUFFER_SIZE, Packet};

type ClientPacket = (u64, Packet);

const SERVER: Token = Token(0);

pub struct Receiver {
    sample_rate: u64,
    channel: u16,
    packet_rx: Option<mpsc::Receiver<ClientPacket>>,
    active_packets: Vec<ClientPacket>,
    notify_tx: Option<Sender<<PacketReceiver as Handler>::Message>>,
    client_time_map: HashMap<u64, u64>,
}

impl Receiver {
    pub fn new(desc: &PluginDescriptor, sample_rate: u64) -> Box<Plugin + Send> {
        println!("receiver::new");
        Box::new(Receiver {
            sample_rate: sample_rate,
            channel: 0,
            packet_rx: None,
            active_packets: Vec::new(),
            notify_tx: None,
            client_time_map: HashMap::new(),
        })
    }

    fn init_server(&mut self) {
        let (data_tx, data_rx) = sync_channel(16);
        self.packet_rx = Some(data_rx);

        let channel = self.channel;
        let mut event_loop = EventLoop::new().unwrap();
        self.notify_tx = Some(event_loop.channel());
        thread::spawn(move || {
            let addr = format!("127.0.0.1:{}", BASE_PORT + channel).parse().unwrap();
            let server;
            loop {
                match TcpListener::bind(&addr) {
                    Ok(s) => {
                        server = s;
                        break;
                    }
                    Err(_) => {}
                }
            }
            event_loop.register(&server, SERVER).unwrap();
            event_loop.run(&mut PacketReceiver {
                          server: server,
                          data_tx: data_tx,
                          client_id: 0,
                      })
                      .unwrap();
        });
    }

    fn kill_server(&mut self) {
        self.notify_tx.as_ref().unwrap().send(()).unwrap();
    }
}

impl Plugin for Receiver {
    fn run<'a>(&mut self, sample_count: usize, ports: &[&'a PortConnection<'a>]) {
        let inputl = ports[0].unwrap_audio();
        let inputr = ports[1].unwrap_audio();
        let mut outputl = ports[2].unwrap_audio_mut();
        let mut outputr = ports[3].unwrap_audio_mut();

        let channel = *ports[4].unwrap_control() as u16;

        if channel != self.channel {
            self.channel = channel;
            println!("set channel {}", self.channel);
            self.kill_server();
            self.init_server();
            return;
        }

        loop {
            if self.active_packets.len() > 128 {
                break;
            }
            let packet = match self.packet_rx.as_ref().unwrap().try_recv() {
                Ok(packet) => packet,
                Err(TryRecvError::Disconnected) => {
                    println!("ladspa packet receive failed, dead channel!");
                    self.kill_server();
                    self.init_server();
                    break;
                }
                Err(TryRecvError::Empty) => {
                    break;
                }
            };
            self.active_packets.push(packet);
        }

        for i in 0..sample_count {
            outputl[i] = inputl[i];
            outputr[i] = inputr[i];
        }
        let mut read_clients = Vec::new();
        for &mut (ref client_id, ref mut packet) in &mut self.active_packets {
            let client_time = self.client_time_map.get(client_id).map(|x| *x).unwrap_or(0);
            for i in 0..sample_count {
                let (l, r) = packet.read(client_time + i as u64);
                outputl[i] += l;
                outputr[i] += r;
            }
            read_clients.push(*client_id);
        }
        for client_id in read_clients {
            let client_time = self.client_time_map.get(&client_id).map(|x| *x).unwrap_or(0);
            self.client_time_map.insert(client_id, client_time + BUFFER_SIZE as u64);
        }

        let client_time_map = self.client_time_map.clone();
        self.active_packets.retain(|&(ref client_id, ref packet)| {
            let client_time = client_time_map[client_id];
            println!("client {} time {}", client_id, client_time);
            !packet.complete(client_time)
        });
    }

    fn activate(&mut self) {
        println!("activate {}", self.channel);
        self.client_time_map.clear();
        self.init_server();
    }

    fn deactivate(&mut self) {
        println!("deactivate {}", self.channel);
        self.kill_server();
    }
}

struct PacketReceiver {
    server: TcpListener,
    data_tx: mpsc::SyncSender<ClientPacket>,
    client_id: u64,
}

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

    fn ready(&mut self, event_loop: &mut EventLoop<Self>, token: Token, events: EventSet) {
        match token {
            SERVER => {
                // Only receive readable events
                assert!(events.is_readable());

                println!("server wait");
                match self.server.accept() {
                    Ok(Some(mut socket)) => {
                        println!("server accept");
                        let tx = self.data_tx.clone();
                        let mut buf = [0; BYTE_BUFFER_SIZE];
                        let mut buf_pos = 0;
                        let client_id = self.client_id;
                        self.client_id += 1;
                        loop {
                            let res = socket.read(&mut buf[buf_pos..]);
                            match res {
                                Ok(num_read) => {
                                    // if we got a length zero read, the connection is done.
                                    if num_read == 0 {
                                        println!("read zero bytes");
                                        return;
                                    }

                                    // check if we've filled the buffer
                                    buf_pos += num_read;
                                    if buf_pos != BYTE_BUFFER_SIZE {
                                        continue;
                                    }
                                    buf_pos = 0;
                                }
                                Err(e) => {
                                    if e.kind() == ErrorKind::WouldBlock {
                                        continue;
                                    }
                                    panic!(e);
                                }
                            }
                            let mut packet = Packet::parse(&buf[..]);
                            if let Err(_) = tx.send((client_id, packet)) {
                                println!("send packet to ladspa error! channel is dead.");
                                return;
                            }
                        }
                    }
                    Ok(None) => {
                        println!("the server socket wasn't actually ready");
                    }
                    Err(e) => {
                        println!("listener.accept() errored: {}", e);
                        // event_loop.shutdown();
                    }
                }
            }
            _ => panic!("Received unknown token"),
        }
    }
    fn notify(&mut self, event_loop: &mut EventLoop<Self>, msg: Self::Message) {
        event_loop.shutdown();
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
use std::io::Error;
use std::str::from_utf8;
use std::sync::mpsc::channel;
use std::time::Duration;
use super::Method;
use curl::easy::{Easy, List};
use futures::{BoxFuture, failed, Future};
use response::Response;
use tokio_core::LoopPin;
use tokio_curl::Session;
use url::Url;

#[cfg(feature = "rustc-serialization")]
use rustc_serialize;

/// The default low byte rate threshold. See [`Request::lowspeed_limit`](struct.Request.html#method.lowspeed_limit)
/// for more information.
pub const LOW_SPEED_LIMIT: u32 = 10;

/// The default low speed time threshold. See [`Request::lowspeed_limit`](struct.Request.html#method.lowspeed_limit)
/// for more information.
pub const LOW_SPEED_MILLIS: u32 = 10_000;

/// The maximum amount of redirects for a single request that cURL will follow.
pub const MAX_REDIRECTS: u32 = 100;

/// Represents an HTTP request.
///
/// While this can be used directly (and _must_ be for special HTTP verbs, it is
/// preferred to use the [`get`](fn.get.html), [`post`](fn.post.html), etc. functions
/// since they are shorter.
pub struct Request {
    body: Option<Vec<u8>>,
    follow_redirects: bool,
    handle: Option<Easy>,
    headers: HashMap<String, String>,
    lowspeed_limits: Option<(u32, u32)>,
    method: Method,
    params: HashMap<String, Vec<String>>,
    url: Url
}

impl Request {
    /// Creates a new instance of `Request`.
    pub fn new(url: &Url, method: Method) -> Request {
        Request {
            body: None,
            follow_redirects: true,
            handle: None,
            headers: HashMap::new(),
            lowspeed_limits: Some((LOW_SPEED_LIMIT, LOW_SPEED_MILLIS)),
            method: method,
            params: HashMap::new(),
            url: url.clone()
        }
    }

    /// Sets the body of the request as raw byte array.
    pub fn body(mut self, body: &AsRef<[u8]>) -> Request {
        self.body = Some(Vec::from(body.as_ref()));
        self
    }

    /// Sets the option whether to follow 3xx-redirects or not.
    ///
    /// Defaults to `true`.
    pub fn follow_redirects(mut self, follow: bool) -> Request {
        self.follow_redirects = follow;
        self
    }

    /// Sets an HTTP header for the request. Remove headers by passing
    /// an empty value.
    ///
    /// ## Duplicates
    /// In spite of the W3C allowing multiple headers with the same name
    /// (https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2),
    /// we do not so that we get a cleaner and leaner API.
    ///
    /// If you really need to specify multiple header values for a single
    /// header, just set a comma-separated list here, as that, as per standards,
    /// is equivalent to sending multiple headers with the same name (see link).
    /// If your server code can't deal with that, go and burn. :P
    pub fn header(mut self, name: &str, value: &str) -> Request {
        if value.is_empty() {
            self.headers.remove(name);
        } else {
            let value = value.to_owned();
            match self.headers.entry(name.to_owned()) {
                Entry::Occupied(mut e) => { e.insert(value); () }
                Entry::Vacant(e) => { e.insert(value); () }
            }
        }
        self
    }

    /// Serializes the given object to JSON and uses that as the request body.
    /// Also automatically sets the `Content-Type` to `application/json`.
    #[cfg(feature = "rustc-serialization")]
    pub fn json<T: rustc_serialize::Encodable>(self, body: &T) -> Request {
        self.set_json(rustc_serialize::json::encode(body).unwrap().into_bytes())
    }

    /// Sets the thresholds which, when reached, abort a download due to too low speeds.
    /// Pass 0 for the either parameter to disable lowspeed limiting.
    ///
    /// ## Remarks
    /// `bytes` sets the minimum average amount of bytes transferred in `per_milliseconds`
    /// time. If this number is not reached, cURL will abort the transfer because the transfer
    /// speed is too low.
    ///
    /// The values here default to `LOW_SPEED_LIMIT` and `LOW_SPEED_MILLIS`.
    pub fn lowspeed_limit(mut self, bytes: u32, per_milliseconds: u32) -> Request {
        self.lowspeed_limits = if bytes > 0 && per_milliseconds > 0 {
            Some((bytes, per_milliseconds))
        } else {
            None
        };
        self
    }

    /// Adds a URL parameter to the request.
    ///
    /// ## Duplicates
    /// Duplicates are allowed to enable things like query parameters that use
    /// PHP array syntax (`&key[]=value`).
    pub fn param(mut self, name: &str, value: &str) -> Request {
        let value = value.to_owned();
        match self.params.entry(name.to_owned()) {
            Entry::Occupied(mut e) => e.get_mut().push(value),
            Entry::Vacant(e) => { e.insert(vec![value]); () }
        };
        self
    }

    /// Creates a new `Session` on the specified event loop to send the HTTP request through
    /// and returns a future that fires off the request, parses the response and resolves to
    /// a `Response`-struct on success.
    pub fn send(self, lp: LoopPin) -> BoxFuture<Response, Error> {
        self.send_with_session(&Session::new(lp))
    }

    /// Uses the given `Session` to send the HTTP request through and returns a future that
    /// fires off the request, parses the response and resolves to a `Response`-struct on success.
    pub fn send_with_session(mut self, session: &Session) -> BoxFuture<Response, Error> {
        {
            let mut query_pairs = self.url.query_pairs_mut();
            for (key, values) in self.params {
                for value in values {
                    query_pairs.append_pair(&key, &value);
                }
            }
        }
        let headers = {
            let mut list = List::new();
            for (key, value) in self.headers {
                list.append(&format!("{}: {}", key.trim(), value.trim())).expect("Failed to append header value to (native cURL) header list.");
            }
            list
        };

        let mut easy = self.handle.unwrap_or_else(|| Easy::new());
        let (header_tx, header_rx) = channel();
        let (body_tx, body_rx) = channel();

        let config_res = {
            // Make the borrow checker happy
            let body = self.body;
            let follow_redirects = self.follow_redirects;
            let lowspeed_limits = self.lowspeed_limits;
            let method = self.method;
            let url = self.url;
            let mut first_header = true; // First header is HTTP status line

            // We cannot use try! here, since we're dealing with futures, not with Results
            Ok(())
                .and_then(|_| easy.accept_encoding(""))
                .and_then(|_| easy.custom_request(method.as_ref()))
                .and_then(|_| if follow_redirects {
                    easy.follow_location(true)
                } else {
                    Ok(())
                })
                .and_then(|_| easy.header_function(move |header| {
                    match from_utf8(header) {
                        Ok(s) => {
                            let s = s.trim(); // Headers are \n-separated
                            if !first_header && s.len() > 0 {
                                let _ = header_tx.send(s.to_owned());
                            }
                            first_header = false;
                            true
                        },
                        Err(_) => false
                    }
                }))
                .and_then(|_| easy.http_headers(headers))
                .and_then(|_| if let Some((bytes, per_millis)) = lowspeed_limits {
                    easy.low_speed_limit(bytes)
                        .and_then(|_| easy.low_speed_time(Duration::from_millis(per_millis as u64)))
                } else {
                    Ok(())
                })
                .and_then(|_| easy.max_redirections(MAX_REDIRECTS))
                .and_then(|_| if method == Method::Head {
                    easy.nobody(true)
                } else {
                    Ok(())
                })
                .and_then(|_| if let Some(ref body) = body {
                    easy.post_fields_copy(body)
                } else {
                    Ok(())
                })
                .and_then(|_| easy.url(url.as_str()))
                .and_then(|_| easy.write_function(move |data| {
                    let _ = body_tx.send(Vec::from(data));
                    Ok(data.len())
                }))
        };

        match config_res {
            Ok(_) => session.perform(easy)
                            .map(move |ez| {
                                let body = body_rx.try_iter().fold(Vec::new(), |mut data, slice| {
                                    data.extend(slice);
                                    data
                                });
                                let headers = header_rx.try_iter().collect::<Vec<_>>();
                                (ez, headers, body)
                            })
                            .map(|(ez, headers, body)| Response::new(ez, headers, body))
                            .map_err(|err| err.into_error())
                            .boxed(),
            Err(error) => failed(error.into()).boxed()
        }
    }

    /// Uses the given cURL handle in the request process reusing its resources
    /// and improving performance.
    ///
    /// This is solely a way to improve performance, it is not necessary to call
    /// this method prior to firing off the request. The easy handle will be created
    /// automatically if necessary.
    pub fn use_handle(mut self, handle: Easy) -> Request {
        self.handle = Some(handle);
        self
    }

    #[cfg(feature = "rustc-serialization")]
    fn set_json(mut self, body: Vec<u8>) -> Request {
        self.body = Some(body);
        self.header("Content-Type", "application/json")
    }
}

impl Debug for Request {
    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
        let len = if let Some(ref body) = self.body {
            body.len() as isize
        } else {
            -1isize
        };
        fmt.debug_struct(nameof!(Request))
            .field("body_len", &len)
            .field("follow_redirects", &self.follow_redirects)
            .field("headers", &self.headers)
            .field("method", &self.method)
            .field("params", &self.params)
            .field("reuses_handle", &self.handle.is_some())
            .field("url", &self.url)
            .finish()
    }
}

impl Display for Request {
    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
        write!(fmt, "{} {}", self.method, self.url)
    }
}

#[cfg(test)]
mod tests {
    use ::{Method, Request};
    use tokio_core::Loop;
    use url::Url;

    #[cfg(feature = "rustc-serialization")]
    use rustc_serialize;

    #[cfg(feature = "rustc-serialization")]
    #[derive(RustcEncodable)]
    struct TestPayload {
        a: u32,
        b: u32
    }

    #[test]
    #[cfg(feature = "rustc-serialization")]
    fn test_payload() {
        let r = Request::new(&Url::parse("http://google.com/").unwrap(), Method::Get)
            .body(&get_serialized_payload());
        assert!(r.body.is_some());
    }

    #[test]
    fn test_request () {
        let mut evloop = Loop::new().unwrap();
        let future = Request::new(&Url::parse("https://httpbin.org/get").unwrap(), Method::Get)
                            .header("User-Agent", "tokio-request")
                            .param("Hello", "This is Rust")
                            .param("Hello2", "This is also from Rust")
                            .send(evloop.pin());
        let result = evloop.run(future).expect("HTTP Request failed!");
        assert!(result.is_success());
        assert!(result.body().len() > 0);
        assert!(result.headers().len() > 0);
    }

    #[cfg(feature = "rustc-serialization")]
    fn get_serialized_payload() -> Vec<u8> {
        rustc_serialize::json::encode(&TestPayload { a: 10, b: 15 }).unwrap().into_bytes()
    }
}<commit_msg>Fix some typos in lowspeed_limit docs<commit_after>use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
use std::io::Error;
use std::str::from_utf8;
use std::sync::mpsc::channel;
use std::time::Duration;
use super::Method;
use curl::easy::{Easy, List};
use futures::{BoxFuture, failed, Future};
use response::Response;
use tokio_core::LoopPin;
use tokio_curl::Session;
use url::Url;

#[cfg(feature = "rustc-serialization")]
use rustc_serialize;

/// The default low byte rate threshold. See [`Request::lowspeed_limit`](struct.Request.html#method.lowspeed_limit)
/// for more information.
pub const LOW_SPEED_LIMIT: u32 = 10;

/// The default low speed time threshold. See [`Request::lowspeed_limit`](struct.Request.html#method.lowspeed_limit)
/// for more information.
pub const LOW_SPEED_MILLIS: u32 = 10_000;

/// The maximum amount of redirects for a single request that cURL will follow.
pub const MAX_REDIRECTS: u32 = 100;

/// Represents an HTTP request.
///
/// While this can be used directly (and _must_ be for special HTTP verbs, it is
/// preferred to use the [`get`](fn.get.html), [`post`](fn.post.html), etc. functions
/// since they are shorter.
pub struct Request {
    body: Option<Vec<u8>>,
    follow_redirects: bool,
    handle: Option<Easy>,
    headers: HashMap<String, String>,
    lowspeed_limits: Option<(u32, u32)>,
    method: Method,
    params: HashMap<String, Vec<String>>,
    url: Url
}

impl Request {
    /// Creates a new instance of `Request`.
    pub fn new(url: &Url, method: Method) -> Request {
        Request {
            body: None,
            follow_redirects: true,
            handle: None,
            headers: HashMap::new(),
            lowspeed_limits: Some((LOW_SPEED_LIMIT, LOW_SPEED_MILLIS)),
            method: method,
            params: HashMap::new(),
            url: url.clone()
        }
    }

    /// Sets the body of the request as raw byte array.
    pub fn body(mut self, body: &AsRef<[u8]>) -> Request {
        self.body = Some(Vec::from(body.as_ref()));
        self
    }

    /// Sets the option whether to follow 3xx-redirects or not.
    ///
    /// Defaults to `true`.
    pub fn follow_redirects(mut self, follow: bool) -> Request {
        self.follow_redirects = follow;
        self
    }

    /// Sets an HTTP header for the request. Remove headers by passing
    /// an empty value.
    ///
    /// ## Duplicates
    /// In spite of the W3C allowing multiple headers with the same name
    /// (https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2),
    /// we do not so that we get a cleaner and leaner API.
    ///
    /// If you really need to specify multiple header values for a single
    /// header, just set a comma-separated list here, as that, as per standards,
    /// is equivalent to sending multiple headers with the same name (see link).
    /// If your server code can't deal with that, go and burn. :P
    pub fn header(mut self, name: &str, value: &str) -> Request {
        if value.is_empty() {
            self.headers.remove(name);
        } else {
            let value = value.to_owned();
            match self.headers.entry(name.to_owned()) {
                Entry::Occupied(mut e) => { e.insert(value); () }
                Entry::Vacant(e) => { e.insert(value); () }
            }
        }
        self
    }

    /// Serializes the given object to JSON and uses that as the request body.
    /// Also automatically sets the `Content-Type` to `application/json`.
    #[cfg(feature = "rustc-serialization")]
    pub fn json<T: rustc_serialize::Encodable>(self, body: &T) -> Request {
        self.set_json(rustc_serialize::json::encode(body).unwrap().into_bytes())
    }

    /// Sets the thresholds which, when reached, aborts a download due to too
    /// low speeds.
    ///
    /// Pass 0 for either parameter to disable lowspeed limiting.
    ///
    /// ## Remarks
    /// `bytes` sets the minimum average amount of bytes transferred in `per_milliseconds`
    /// time. If this number is not reached, cURL will abort the transfer because the transfer
    /// speed is too low.
    ///
    /// The values here default to `LOW_SPEED_LIMIT` and `LOW_SPEED_MILLIS`.
    pub fn lowspeed_limit(mut self, bytes: u32, per_milliseconds: u32) -> Request {
        self.lowspeed_limits = if bytes > 0 && per_milliseconds > 0 {
            Some((bytes, per_milliseconds))
        } else {
            None
        };
        self
    }

    /// Adds a URL parameter to the request.
    ///
    /// ## Duplicates
    /// Duplicates are allowed to enable things like query parameters that use
    /// PHP array syntax (`&key[]=value`).
    pub fn param(mut self, name: &str, value: &str) -> Request {
        let value = value.to_owned();
        match self.params.entry(name.to_owned()) {
            Entry::Occupied(mut e) => e.get_mut().push(value),
            Entry::Vacant(e) => { e.insert(vec![value]); () }
        };
        self
    }

    /// Creates a new `Session` on the specified event loop to send the HTTP request through
    /// and returns a future that fires off the request, parses the response and resolves to
    /// a `Response`-struct on success.
    pub fn send(self, lp: LoopPin) -> BoxFuture<Response, Error> {
        self.send_with_session(&Session::new(lp))
    }

    /// Uses the given `Session` to send the HTTP request through and returns a future that
    /// fires off the request, parses the response and resolves to a `Response`-struct on success.
    pub fn send_with_session(mut self, session: &Session) -> BoxFuture<Response, Error> {
        {
            let mut query_pairs = self.url.query_pairs_mut();
            for (key, values) in self.params {
                for value in values {
                    query_pairs.append_pair(&key, &value);
                }
            }
        }
        let headers = {
            let mut list = List::new();
            for (key, value) in self.headers {
                list.append(&format!("{}: {}", key.trim(), value.trim())).expect("Failed to append header value to (native cURL) header list.");
            }
            list
        };

        let mut easy = self.handle.unwrap_or_else(|| Easy::new());
        let (header_tx, header_rx) = channel();
        let (body_tx, body_rx) = channel();

        let config_res = {
            // Make the borrow checker happy
            let body = self.body;
            let follow_redirects = self.follow_redirects;
            let lowspeed_limits = self.lowspeed_limits;
            let method = self.method;
            let url = self.url;
            let mut first_header = true; // First header is HTTP status line

            // We cannot use try! here, since we're dealing with futures, not with Results
            Ok(())
                .and_then(|_| easy.accept_encoding(""))
                .and_then(|_| easy.custom_request(method.as_ref()))
                .and_then(|_| if follow_redirects {
                    easy.follow_location(true)
                } else {
                    Ok(())
                })
                .and_then(|_| easy.header_function(move |header| {
                    match from_utf8(header) {
                        Ok(s) => {
                            let s = s.trim(); // Headers are \n-separated
                            if !first_header && s.len() > 0 {
                                let _ = header_tx.send(s.to_owned());
                            }
                            first_header = false;
                            true
                        },
                        Err(_) => false
                    }
                }))
                .and_then(|_| easy.http_headers(headers))
                .and_then(|_| if let Some((bytes, per_millis)) = lowspeed_limits {
                    easy.low_speed_limit(bytes)
                        .and_then(|_| easy.low_speed_time(Duration::from_millis(per_millis as u64)))
                } else {
                    Ok(())
                })
                .and_then(|_| easy.max_redirections(MAX_REDIRECTS))
                .and_then(|_| if method == Method::Head {
                    easy.nobody(true)
                } else {
                    Ok(())
                })
                .and_then(|_| if let Some(ref body) = body {
                    easy.post_fields_copy(body)
                } else {
                    Ok(())
                })
                .and_then(|_| easy.url(url.as_str()))
                .and_then(|_| easy.write_function(move |data| {
                    let _ = body_tx.send(Vec::from(data));
                    Ok(data.len())
                }))
        };

        match config_res {
            Ok(_) => session.perform(easy)
                            .map(move |ez| {
                                let body = body_rx.try_iter().fold(Vec::new(), |mut data, slice| {
                                    data.extend(slice);
                                    data
                                });
                                let headers = header_rx.try_iter().collect::<Vec<_>>();
                                (ez, headers, body)
                            })
                            .map(|(ez, headers, body)| Response::new(ez, headers, body))
                            .map_err(|err| err.into_error())
                            .boxed(),
            Err(error) => failed(error.into()).boxed()
        }
    }

    /// Uses the given cURL handle in the request process reusing its resources
    /// and improving performance.
    ///
    /// This is solely a way to improve performance, it is not necessary to call
    /// this method prior to firing off the request. The easy handle will be created
    /// automatically if necessary.
    pub fn use_handle(mut self, handle: Easy) -> Request {
        self.handle = Some(handle);
        self
    }

    #[cfg(feature = "rustc-serialization")]
    fn set_json(mut self, body: Vec<u8>) -> Request {
        self.body = Some(body);
        self.header("Content-Type", "application/json")
    }
}

impl Debug for Request {
    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
        let len = if let Some(ref body) = self.body {
            body.len() as isize
        } else {
            -1isize
        };
        fmt.debug_struct(nameof!(Request))
            .field("body_len", &len)
            .field("follow_redirects", &self.follow_redirects)
            .field("headers", &self.headers)
            .field("method", &self.method)
            .field("params", &self.params)
            .field("reuses_handle", &self.handle.is_some())
            .field("url", &self.url)
            .finish()
    }
}

impl Display for Request {
    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
        write!(fmt, "{} {}", self.method, self.url)
    }
}

#[cfg(test)]
mod tests {
    use ::{Method, Request};
    use tokio_core::Loop;
    use url::Url;

    #[cfg(feature = "rustc-serialization")]
    use rustc_serialize;

    #[cfg(feature = "rustc-serialization")]
    #[derive(RustcEncodable)]
    struct TestPayload {
        a: u32,
        b: u32
    }

    #[test]
    #[cfg(feature = "rustc-serialization")]
    fn test_payload() {
        let r = Request::new(&Url::parse("http://google.com/").unwrap(), Method::Get)
            .body(&get_serialized_payload());
        assert!(r.body.is_some());
    }

    #[test]
    fn test_request () {
        let mut evloop = Loop::new().unwrap();
        let future = Request::new(&Url::parse("https://httpbin.org/get").unwrap(), Method::Get)
                            .header("User-Agent", "tokio-request")
                            .param("Hello", "This is Rust")
                            .param("Hello2", "This is also from Rust")
                            .send(evloop.pin());
        let result = evloop.run(future).expect("HTTP Request failed!");
        assert!(result.is_success());
        assert!(result.body().len() > 0);
        assert!(result.headers().len() > 0);
    }

    #[cfg(feature = "rustc-serialization")]
    fn get_serialized_payload() -> Vec<u8> {
        rustc_serialize::json::encode(&TestPayload { a: 10, b: 15 }).unwrap().into_bytes()
    }
}<|endoftext|>


<commit_before>use super::*;

pub trait Request {
    type Params;
    type Result;
    const METHOD: &'static str;
}

#[macro_export]
macro_rules! lsp_request {
    ("initialize") => { $crate::request::Initialize };
    ("shutdown") => { $crate::request::Shutdown };

    ("window/showMessageRequest") => { $crate::request::ShowMessageRequest };

    ("client/registerCapability") => { $crate::request::RegisterCapability };
    ("client/unregisterCapability") => { $crate::request::UnregisterCapability };

    ("workspace/symbol") => { $crate::request::WorkspaceSymbol };
    ("workspace/executeCommand") => { $crate::request::ExecuteCommand };

    ("textDocument/willSaveWaitUntil") => { $crate::request::WillSaveWaitUntil };
    ("textDocument/completion") => { $crate::request::Completion };
    ("completionItem/resolve") => { $crate::request::ResolveCompletionItem };
    ("textDocument/hover") => { $crate::request::HoverRequest };
    ("textDocument/signatureHelp") => { $crate::request::SignatureHelpRequest };
    ("textDocument/definition") => { $crate::request::GotoDefinition };
    ("textDocument/references") => { $crate::request::References };
    ("textDocument/documentHighlight") => { $crate::request::DocumentHighlightRequest };
    ("textDocument/documentSymbol") => { $crate::request::DocumentSymbol };
    ("textDocument/codeAction") => { $crate::request::CodeAction };
    ("textDocument/codeLens") => { $crate::request::CodeLensRequest };
    ("codeLens/resolve") => { $crate::request::CodeLensResolve };
    ("textDocument/documentLink") => { $crate::request::DocumentLink };
    ("documentLink/resolve") => { $crate::request::DocumentLinkResolve };
    ("textDocument/applyEdit") => { $crate::request::ApplyEdit };
    ("textDocument/rangeFormatting") => { $crate::request::RangeFormatting };
    ("textDocument/onTypeFormatting") => { $crate::request::OnTypeFormatting };
    ("textDocument/formatting") => { $crate::request::Formatting };
    ("textDocument/rename") => { $crate::request::Rename };
}

/**

 The initialize request is sent as the first request from the client to the server.
 If the server receives request or notification before the `initialize` request it should act as follows:

 * for a request the respond should be errored with `code: -32001`. The message can be picked by the server.
 * notifications should be dropped.

*/
#[derive(Debug)]
pub enum Initialize {}

impl Request for Initialize {
    type Params = InitializeParams;
    type Result = InitializeResult;
    const METHOD: &'static str = "initialize";
}

/**
 * The shutdown request is sent from the client to the server. It asks the server to shut down,
 * but to not exit (otherwise the response might not be delivered correctly to the client).
 * There is a separate exit notification that asks the server to exit.
 */
#[derive(Debug)]
pub enum Shutdown {}

impl Request for Shutdown {
    type Params = ();
    type Result = ();
    const METHOD: &'static str = "shutdown";
}

/**
 * The show message request is sent from a server to a client to ask the client to display a particular message
 * in the user interface. In addition to the show message notification the request allows to pass actions and to
 * wait for an answer from the client.
 */
#[derive(Debug)]
pub enum ShowMessageRequest {}

impl Request for ShowMessageRequest {
    type Params = ShowMessageRequestParams;
    type Result = Option<MessageActionItem>;
    const METHOD: &'static str = "window/showMessageRequest";
}

/**
 * The client/registerCapability request is sent from the server to the client to register for a new capability on the client side. Not all clients need to support dynamic capability registration. A client opts in via the ClientCapabilities.GenericCapability property.
 */
#[derive(Debug)]
pub enum RegisterCapability {}

impl Request for RegisterCapability {
    type Params = RegistrationParams;
    type Result = ();
    const METHOD: &'static str = "client/registerCapability";
}

/// The client/unregisterCapability request is sent from the server to the client to unregister a
/// previously register capability.
#[derive(Debug)]
pub enum UnregisterCapability {}

impl Request for UnregisterCapability {
    type Params = UnregistrationParams;
    type Result = ();
    const METHOD: &'static str = "client/unregisterCapability";
}

/**
 The Completion request is sent from the client to the server to compute completion items at a given cursor position.
 Completion items are presented in the IntelliSense user interface. If computing full completion items is expensive,
 servers can additionally provide a handler for the completion item resolve request ('completionItem/resolve').
 This request is sent when a completion item is selected in the user interface. A typically use case is for example:
 the 'textDocument/completion' request doesn't fill in the documentation property for returned completion items
 since it is expensive to compute. When the item is selected in the user interface then a 'completionItem/resolve'
 request is sent with the selected completion item as a param. The returned completion item should have the
 documentation property filled in.
*/
#[derive(Debug)]
pub enum Completion {}

impl Request for Completion {
    type Params = CompletionParams;
    type Result = Option<CompletionResponse>;
    const METHOD: &'static str = "textDocument/completion";
}

/// The request is sent from the client to the server to resolve additional information for a given completion item.
#[derive(Debug)]
pub enum ResolveCompletionItem {}

impl Request for ResolveCompletionItem {
    type Params = CompletionItem;
    type Result = CompletionItem;
    const METHOD: &'static str = "completionItem/resolve";
}

/// The hover request is sent from the client to the server to request hover information at a given text
/// document position.
#[derive(Debug)]
pub enum HoverRequest {}

impl Request for HoverRequest {
    type Params = TextDocumentPositionParams;
    type Result = Option<Hover>;
    const METHOD: &'static str = "textDocument/hover";
}

/// The signature help request is sent from the client to the server to request signature information at
/// a given cursor position.
#[derive(Debug)]
pub enum SignatureHelpRequest {}

impl Request for SignatureHelpRequest {
    type Params = TextDocumentPositionParams;
    type Result = Option<SignatureHelp>;
    const METHOD: &'static str = "textDocument/signatureHelp";
}

/// The goto definition request is sent from the client to the server to resolve the definition location of
/// a symbol at a given text document position.
#[derive(Debug)]
pub enum GotoDefinition {}

impl Request for GotoDefinition {
    type Params = TextDocumentPositionParams;
    type Result = Option<GotoDefinitionResponse>;
    const METHOD: &'static str = "textDocument/definition";
}

/**
 * GotoDefinition response can be single location or multiple ones.
 */
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GotoDefinitionResponse {
    Scalar(Location),
    Array(Vec<Location>),
}

/// The references request is sent from the client to the server to resolve project-wide references for the
/// symbol denoted by the given text document position.
pub enum References {}

impl Request for References {
    type Params = ReferenceParams;
    type Result = Option<Vec<Location>>;
    const METHOD: &'static str = "textDocument/references";
}

/**
 The document highlight request is sent from the client to the server to resolve a document highlights
 for a given text document position.
 For programming languages this usually highlights all references to the symbol scoped to this file.
 However we kept 'textDocument/documentHighlight' and 'textDocument/references' separate requests since
 the first one is allowed to be more fuzzy.
 Symbol matches usually have a DocumentHighlightKind of Read or Write whereas fuzzy or textual matches
 use Textas the kind.
*/
#[derive(Debug)]
pub enum DocumentHighlightRequest {}

impl Request for DocumentHighlightRequest {
    type Params = TextDocumentPositionParams;
    type Result = Option<Vec<DocumentHighlight>>;
    const METHOD: &'static str = "textDocument/documentHighlight";
}

/**
 * The document symbol request is sent from the client to the server to list all symbols found in a given
 * text document.
 */
#[derive(Debug)]
pub enum DocumentSymbol {}

impl Request for DocumentSymbol {
    type Params = DocumentSymbolParams;
    type Result = Option<Vec<SymbolInformation>>;
    const METHOD: &'static str = "textDocument/documentSymbol";
}

/**
 * The workspace symbol request is sent from the client to the server to list project-wide symbols
 * matching the query string.
 */
#[derive(Debug)]
pub enum WorkspaceSymbol {}

impl Request for WorkspaceSymbol {
    type Params = WorkspaceSymbolParams;
    type Result = Option<Vec<SymbolInformation>>;
    const METHOD: &'static str = "workspace/symbol";
}

/// The workspace/executeCommand request is sent from the client to the server to trigger command execution on the server. In most cases the server creates a WorkspaceEdit structure and applies the changes to the workspace using the request workspace/applyEdit which is sent from the server to the client.
#[derive(Debug)]
pub enum ExecuteCommand {}

impl Request for ExecuteCommand {
    type Params = ExecuteCommandParams;
    type Result = Option<Value>;
    const METHOD: &'static str = "workspace/executeCommand";
}

/// The workspace/applyEdit request is sent from the server to the client to modify resource on the
/// client side.
#[derive(Debug)]
pub enum ApplyWorkspaceEdit {}

impl Request for ApplyWorkspaceEdit {
    type Params = ApplyWorkspaceEditParams;
    type Result = ApplyWorkspaceEditResponse;
    const METHOD: &'static str = "workspace/applyEdit";
}

/**
 * The code action request is sent from the client to the server to compute commands for a given text document
 * and range. The request is triggered when the user moves the cursor into a problem marker in the editor or
 * presses the lightbulb associated with a marker.
 */
#[derive(Debug)]
pub enum CodeActionRequest {}

impl Request for CodeActionRequest {
    type Params = CodeActionParams;
    type Result = Option<Vec<Command>>;
    const METHOD: &'static str = "textDocument/codeAction";
}

/**
 * The code lens request is sent from the client to the server to compute code lenses for a given text document.
 */
#[derive(Debug)]
pub enum CodeLensRequest {}

impl Request for CodeLensRequest {
    type Params = CodeLensParams;
    type Result = Option<Vec<CodeLens>>;
    const METHOD: &'static str = "textDocument/codeLens";
}

/**
 * The code lens resolve request is sent from the client to the server to resolve the command for a
 * given code lens item.
 */
#[derive(Debug)]
pub enum CodeLensResolve {}

impl Request for CodeLensResolve {
    type Params = CodeLens;
    type Result = CodeLens;
    const METHOD: &'static str = "codeLens/resolve";
}

/// The document links request is sent from the client to the server to request the location of links in a document.
#[derive(Debug)]
pub enum DocumentLinkRequest {}

impl Request for DocumentLinkRequest {
    type Params = DocumentLinkParams;
    type Result = Option<Vec<DocumentLink>>;
    const METHOD: &'static str = "textDocument/documentLink";
}

/**

 The document link resolve request is sent from the client to the server to resolve the target of
 a given document link.

*/
#[derive(Debug)]
pub enum DocumentLinkResolve {}

impl Request for DocumentLinkResolve {
    type Params = DocumentLink;
    type Result = DocumentLink;
    const METHOD: &'static str = "documentLink/resolve";
}

/**
 * The document formatting request is sent from the server to the client to format a whole document.
 */
#[derive(Debug)]
pub enum Formatting {}

impl Request for Formatting {
    type Params = DocumentFormattingParams;
    type Result = Option<Vec<TextEdit>>;
    const METHOD: &'static str = "textDocument/formatting";
}

/// The document range formatting request is sent from the client to the server to format a given range in a document.
#[derive(Debug)]
pub enum RangeFormatting {}

impl Request for RangeFormatting {
    type Params = DocumentRangeFormattingParams;
    type Result = Option<Vec<TextEdit>>;
    const METHOD: &'static str = "textDocument/rangeFormatting";
}

/**
 * The document on type formatting request is sent from the client to the server to format parts of
 * the document during typing.
 */
#[derive(Debug)]
pub enum OnTypeFormatting {}

impl Request for OnTypeFormatting {
    type Params = DocumentOnTypeFormattingParams;
    type Result = Option<Vec<TextEdit>>;
    const METHOD: &'static str = "textDocument/onTypeFormatting";
}

/**
 * The rename request is sent from the client to the server to perform a workspace-wide rename of a symbol.
 */
#[derive(Debug)]
pub enum Rename {}

impl Request for Rename {
    type Params = RenameParams;
    type Result = Option<WorkspaceEdit>;
    const METHOD: &'static str = "textDocument/rename";
}
<commit_msg>Add textDocument/typeDefinition and textDocument/implementation.<commit_after>use super::*;

pub trait Request {
    type Params;
    type Result;
    const METHOD: &'static str;
}

#[macro_export]
macro_rules! lsp_request {
    ("initialize") => { $crate::request::Initialize };
    ("shutdown") => { $crate::request::Shutdown };

    ("window/showMessageRequest") => { $crate::request::ShowMessageRequest };

    ("client/registerCapability") => { $crate::request::RegisterCapability };
    ("client/unregisterCapability") => { $crate::request::UnregisterCapability };

    ("workspace/symbol") => { $crate::request::WorkspaceSymbol };
    ("workspace/executeCommand") => { $crate::request::ExecuteCommand };

    ("textDocument/willSaveWaitUntil") => { $crate::request::WillSaveWaitUntil };
    ("textDocument/completion") => { $crate::request::Completion };
    ("completionItem/resolve") => { $crate::request::ResolveCompletionItem };
    ("textDocument/hover") => { $crate::request::HoverRequest };
    ("textDocument/signatureHelp") => { $crate::request::SignatureHelpRequest };
    ("textDocument/definition") => { $crate::request::GotoDefinition };
    ("textDocument/references") => { $crate::request::References };
    ("textDocument/documentHighlight") => { $crate::request::DocumentHighlightRequest };
    ("textDocument/documentSymbol") => { $crate::request::DocumentSymbol };
    ("textDocument/codeAction") => { $crate::request::CodeAction };
    ("textDocument/codeLens") => { $crate::request::CodeLensRequest };
    ("codeLens/resolve") => { $crate::request::CodeLensResolve };
    ("textDocument/documentLink") => { $crate::request::DocumentLink };
    ("documentLink/resolve") => { $crate::request::DocumentLinkResolve };
    ("textDocument/applyEdit") => { $crate::request::ApplyEdit };
    ("textDocument/rangeFormatting") => { $crate::request::RangeFormatting };
    ("textDocument/onTypeFormatting") => { $crate::request::OnTypeFormatting };
    ("textDocument/formatting") => { $crate::request::Formatting };
    ("textDocument/rename") => { $crate::request::Rename };
}

/**

 The initialize request is sent as the first request from the client to the server.
 If the server receives request or notification before the `initialize` request it should act as follows:

 * for a request the respond should be errored with `code: -32001`. The message can be picked by the server.
 * notifications should be dropped.

*/
#[derive(Debug)]
pub enum Initialize {}

impl Request for Initialize {
    type Params = InitializeParams;
    type Result = InitializeResult;
    const METHOD: &'static str = "initialize";
}

/**
 * The shutdown request is sent from the client to the server. It asks the server to shut down,
 * but to not exit (otherwise the response might not be delivered correctly to the client).
 * There is a separate exit notification that asks the server to exit.
 */
#[derive(Debug)]
pub enum Shutdown {}

impl Request for Shutdown {
    type Params = ();
    type Result = ();
    const METHOD: &'static str = "shutdown";
}

/**
 * The show message request is sent from a server to a client to ask the client to display a particular message
 * in the user interface. In addition to the show message notification the request allows to pass actions and to
 * wait for an answer from the client.
 */
#[derive(Debug)]
pub enum ShowMessageRequest {}

impl Request for ShowMessageRequest {
    type Params = ShowMessageRequestParams;
    type Result = Option<MessageActionItem>;
    const METHOD: &'static str = "window/showMessageRequest";
}

/**
 * The client/registerCapability request is sent from the server to the client to register for a new capability on the client side. Not all clients need to support dynamic capability registration. A client opts in via the ClientCapabilities.GenericCapability property.
 */
#[derive(Debug)]
pub enum RegisterCapability {}

impl Request for RegisterCapability {
    type Params = RegistrationParams;
    type Result = ();
    const METHOD: &'static str = "client/registerCapability";
}

/// The client/unregisterCapability request is sent from the server to the client to unregister a
/// previously register capability.
#[derive(Debug)]
pub enum UnregisterCapability {}

impl Request for UnregisterCapability {
    type Params = UnregistrationParams;
    type Result = ();
    const METHOD: &'static str = "client/unregisterCapability";
}

/**
 The Completion request is sent from the client to the server to compute completion items at a given cursor position.
 Completion items are presented in the IntelliSense user interface. If computing full completion items is expensive,
 servers can additionally provide a handler for the completion item resolve request ('completionItem/resolve').
 This request is sent when a completion item is selected in the user interface. A typically use case is for example:
 the 'textDocument/completion' request doesn't fill in the documentation property for returned completion items
 since it is expensive to compute. When the item is selected in the user interface then a 'completionItem/resolve'
 request is sent with the selected completion item as a param. The returned completion item should have the
 documentation property filled in.
*/
#[derive(Debug)]
pub enum Completion {}

impl Request for Completion {
    type Params = CompletionParams;
    type Result = Option<CompletionResponse>;
    const METHOD: &'static str = "textDocument/completion";
}

/// The request is sent from the client to the server to resolve additional information for a given completion item.
#[derive(Debug)]
pub enum ResolveCompletionItem {}

impl Request for ResolveCompletionItem {
    type Params = CompletionItem;
    type Result = CompletionItem;
    const METHOD: &'static str = "completionItem/resolve";
}

/// The hover request is sent from the client to the server to request hover information at a given text
/// document position.
#[derive(Debug)]
pub enum HoverRequest {}

impl Request for HoverRequest {
    type Params = TextDocumentPositionParams;
    type Result = Option<Hover>;
    const METHOD: &'static str = "textDocument/hover";
}

/// The signature help request is sent from the client to the server to request signature information at
/// a given cursor position.
#[derive(Debug)]
pub enum SignatureHelpRequest {}

impl Request for SignatureHelpRequest {
    type Params = TextDocumentPositionParams;
    type Result = Option<SignatureHelp>;
    const METHOD: &'static str = "textDocument/signatureHelp";
}

/// The goto definition request is sent from the client to the server to resolve the definition location of
/// a symbol at a given text document position.
#[derive(Debug)]
pub enum GotoDefinition {}

impl Request for GotoDefinition {
    type Params = TextDocumentPositionParams;
    type Result = Option<GotoDefinitionResponse>;
    const METHOD: &'static str = "textDocument/definition";
}

/**
 * GotoDefinition response can be single location or multiple ones.
 */
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GotoDefinitionResponse {
    Scalar(Location),
    Array(Vec<Location>),
}

/// The references request is sent from the client to the server to resolve project-wide references for the
/// symbol denoted by the given text document position.
#[derive(Debug)]
pub enum References {}

impl Request for References {
    type Params = ReferenceParams;
    type Result = Option<Vec<Location>>;
    const METHOD: &'static str = "textDocument/references";
}

/// The goto type definition request is sent from the client to the
/// server to resolve the type definition location of a symbol at a
/// given text document position.
#[derive(Debug)]
pub enum GotoTypeDefinition {}

pub type GotoTypeDefinitionResponse = GotoDefinitionResponse;

impl Request for GotoTypeDefinition {
    type Params = TextDocumentPositionParams;
    type Result = Option<GotoTypeDefinitionResponse>;
    const METHOD: &'static str = "textDocument/typeDefinition";
}

/// The goto implementation request is sent from the client to the
/// server to resolve the implementation location of a symbol at a
/// given text document position.
#[derive(Debug)]
pub enum GotoImplementation {}

pub type GotoImplementationResponse = GotoDefinitionResponse;

impl Request for GotoImplementation {
    type Params = TextDocumentPositionParams;
    type Result = Option<GotoImplementationResponse>;
    const METHOD: &'static str = "textDocument/implementation";
}

/**
 The document highlight request is sent from the client to the server to resolve a document highlights
 for a given text document position.
 For programming languages this usually highlights all references to the symbol scoped to this file.
 However we kept 'textDocument/documentHighlight' and 'textDocument/references' separate requests since
 the first one is allowed to be more fuzzy.
 Symbol matches usually have a DocumentHighlightKind of Read or Write whereas fuzzy or textual matches
 use Textas the kind.
*/
#[derive(Debug)]
pub enum DocumentHighlightRequest {}

impl Request for DocumentHighlightRequest {
    type Params = TextDocumentPositionParams;
    type Result = Option<Vec<DocumentHighlight>>;
    const METHOD: &'static str = "textDocument/documentHighlight";
}

/**
 * The document symbol request is sent from the client to the server to list all symbols found in a given
 * text document.
 */
#[derive(Debug)]
pub enum DocumentSymbol {}

impl Request for DocumentSymbol {
    type Params = DocumentSymbolParams;
    type Result = Option<Vec<SymbolInformation>>;
    const METHOD: &'static str = "textDocument/documentSymbol";
}

/**
 * The workspace symbol request is sent from the client to the server to list project-wide symbols
 * matching the query string.
 */
#[derive(Debug)]
pub enum WorkspaceSymbol {}

impl Request for WorkspaceSymbol {
    type Params = WorkspaceSymbolParams;
    type Result = Option<Vec<SymbolInformation>>;
    const METHOD: &'static str = "workspace/symbol";
}

/// The workspace/executeCommand request is sent from the client to the server to trigger command execution on the server. In most cases the server creates a WorkspaceEdit structure and applies the changes to the workspace using the request workspace/applyEdit which is sent from the server to the client.
#[derive(Debug)]
pub enum ExecuteCommand {}

impl Request for ExecuteCommand {
    type Params = ExecuteCommandParams;
    type Result = Option<Value>;
    const METHOD: &'static str = "workspace/executeCommand";
}

/// The workspace/applyEdit request is sent from the server to the client to modify resource on the
/// client side.
#[derive(Debug)]
pub enum ApplyWorkspaceEdit {}

impl Request for ApplyWorkspaceEdit {
    type Params = ApplyWorkspaceEditParams;
    type Result = ApplyWorkspaceEditResponse;
    const METHOD: &'static str = "workspace/applyEdit";
}

/**
 * The code action request is sent from the client to the server to compute commands for a given text document
 * and range. The request is triggered when the user moves the cursor into a problem marker in the editor or
 * presses the lightbulb associated with a marker.
 */
#[derive(Debug)]
pub enum CodeActionRequest {}

impl Request for CodeActionRequest {
    type Params = CodeActionParams;
    type Result = Option<Vec<Command>>;
    const METHOD: &'static str = "textDocument/codeAction";
}

/**
 * The code lens request is sent from the client to the server to compute code lenses for a given text document.
 */
#[derive(Debug)]
pub enum CodeLensRequest {}

impl Request for CodeLensRequest {
    type Params = CodeLensParams;
    type Result = Option<Vec<CodeLens>>;
    const METHOD: &'static str = "textDocument/codeLens";
}

/**
 * The code lens resolve request is sent from the client to the server to resolve the command for a
 * given code lens item.
 */
#[derive(Debug)]
pub enum CodeLensResolve {}

impl Request for CodeLensResolve {
    type Params = CodeLens;
    type Result = CodeLens;
    const METHOD: &'static str = "codeLens/resolve";
}

/// The document links request is sent from the client to the server to request the location of links in a document.
#[derive(Debug)]
pub enum DocumentLinkRequest {}

impl Request for DocumentLinkRequest {
    type Params = DocumentLinkParams;
    type Result = Option<Vec<DocumentLink>>;
    const METHOD: &'static str = "textDocument/documentLink";
}

/**

 The document link resolve request is sent from the client to the server to resolve the target of
 a given document link.

*/
#[derive(Debug)]
pub enum DocumentLinkResolve {}

impl Request for DocumentLinkResolve {
    type Params = DocumentLink;
    type Result = DocumentLink;
    const METHOD: &'static str = "documentLink/resolve";
}

/**
 * The document formatting request is sent from the server to the client to format a whole document.
 */
#[derive(Debug)]
pub enum Formatting {}

impl Request for Formatting {
    type Params = DocumentFormattingParams;
    type Result = Option<Vec<TextEdit>>;
    const METHOD: &'static str = "textDocument/formatting";
}

/// The document range formatting request is sent from the client to the server to format a given range in a document.
#[derive(Debug)]
pub enum RangeFormatting {}

impl Request for RangeFormatting {
    type Params = DocumentRangeFormattingParams;
    type Result = Option<Vec<TextEdit>>;
    const METHOD: &'static str = "textDocument/rangeFormatting";
}

/**
 * The document on type formatting request is sent from the client to the server to format parts of
 * the document during typing.
 */
#[derive(Debug)]
pub enum OnTypeFormatting {}

impl Request for OnTypeFormatting {
    type Params = DocumentOnTypeFormattingParams;
    type Result = Option<Vec<TextEdit>>;
    const METHOD: &'static str = "textDocument/onTypeFormatting";
}

/**
 * The rename request is sent from the client to the server to perform a workspace-wide rename of a symbol.
 */
#[derive(Debug)]
pub enum Rename {}

impl Request for Rename {
    type Params = RenameParams;
    type Result = Option<WorkspaceEdit>;
    const METHOD: &'static str = "textDocument/rename";
}
<|endoftext|>


<commit_before>#[macro_use]
pub mod proto;

use std::collections::HashMap;
use std::sync::Arc;
use std::io;
use std::time::Duration;
use parking_lot::{Mutex, RwLock};
use std::thread;
use bincode::{SizeLimit, serde as bincode};
use tcp;
use utils::time;
use utils::u8vec::*;
use futures::Future;
use bifrost_hasher::hash_str;

lazy_static! {
    pub static ref DEFAULT_CLIENT_POOL: ClientPool = ClientPool::new();
}

#[derive(Serialize, Deserialize, Debug)]
pub enum RPCRequestError {
    FunctionIdNotFound,
    ServiceIdNotFound,
    Other,
}

#[derive(Debug)]
pub enum RPCError {
    IOError(io::Error),
    RequestError(RPCRequestError),
}

pub trait RPCService: Sync + Send {
    fn dispatch(&self, data: Vec<u8>) -> Result<Vec<u8>, RPCRequestError>;
    fn register_shortcut_service(&self, service_ptr: usize, server_id: u64, service_id: u64);
}

pub struct Server {
    services: RwLock<HashMap<u64, Arc<RPCService>>>,
    address: String,
    server_id: u64
}

pub struct ClientPool {
    clients: Mutex<HashMap<String, Arc<RPCClient>>>
}

fn encode_res(res: Result<Vec<u8>, RPCRequestError>) -> Vec<u8> {
    match res {
        Ok(vec) => {
            [0u8; 1].iter().cloned().chain(vec.into_iter()).collect()
        },
        Err(e) => {
            let err_id = match e {
                RPCRequestError::FunctionIdNotFound => 1u8,
                RPCRequestError::ServiceIdNotFound => 2u8,
                _ => 255u8
            };
            vec!(err_id)
        }
    }
}

fn decode_res(res: io::Result<Vec<u8>>) -> Result<Vec<u8>, RPCError> {
    match res {
        Ok(res) => {
            if res[0] == 0u8 {
                Ok(res.into_iter().skip(1).collect())
            } else {
                match res[0] {
                    1u8 => Err(RPCError::RequestError(RPCRequestError::FunctionIdNotFound)),
                    2u8 => Err(RPCError::RequestError(RPCRequestError::ServiceIdNotFound)),
                    _ => Err(RPCError::RequestError(RPCRequestError::Other)),
                }
            }
        },
        Err(e) => Err(RPCError::IOError(e))
    }
}

impl Server {
    pub fn new(address: &String) -> Arc<Server> {
        Arc::new(Server {
            services: RwLock::new(HashMap::new()),
            address: address.clone(),
            server_id: hash_str(address)
        })
    }
    pub fn listen(server: &Arc<Server>) {
        let address = &server.address;
        let server = server.clone();
        tcp::server::Server::new(address, Box::new(move |data| {
            let (svr_id, data) = extract_u64_head(data);
            let t = time::get_time();
            let svr_map = server.services.read();
            let service = svr_map.get(&svr_id);
            let res = match service {
                Some(service) => {
                    encode_res(service.dispatch(data))
                },
                None => encode_res(Err(RPCRequestError::ServiceIdNotFound) as Result<Vec<u8>, RPCRequestError>)
            };
            //println!("SVR RPC: {} - {}ms", svr_id, time::get_time() - t);
            res
        }));
    }
    pub fn listen_and_resume(server: &Arc<Server>) {
        let server = server.clone();
        thread::spawn(move|| {
            let server = server;
            Server::listen(&server);
        });
    }
    pub fn register_service<T>(&self, service_id: u64,  service: &Arc<T>)
    where T: RPCService + Sized + 'static{
        let service = service.clone();
        let service_ptr = Arc::into_raw(service.clone()) as usize;
        service.register_shortcut_service(service_ptr, self.server_id, service_id);
        self.services.write().insert(service_id, service.clone());
    }
    pub fn remove_service(&self, service_id: u64) {
        self.services.write().remove(&service_id);
    }
    pub fn address(&self) -> &String {
        &self.address
    }
}

pub struct RPCClient {
    client: Mutex<tcp::client::Client>,
    pub server_id: u64,
    pub address: String
}

impl RPCClient {
    pub fn send(&self, svr_id: u64, data: Vec<u8>) -> Result<Vec<u8>, RPCError> {
        decode_res(self.client.lock().send(prepend_u64(svr_id, data)))
    }
    pub fn send_async(&self, svr_id: u64, data: Vec<u8>) -> Box<Future<Item = Vec<u8>, Error = RPCError>> {
        Box::new(self.client.lock()
            .send_async(prepend_u64(svr_id, data))
            .then(move |res| decode_res(res)))
    }
    pub fn new(addr: &String) -> io::Result<Arc<RPCClient>> {
        let client = tcp::client::Client::connect(addr)?;
        Ok(Arc::new(RPCClient {
            server_id: client.server_id,
            client: Mutex::new(client),
            address: addr.clone()
        }))
    }
    pub fn with_timeout(addr: &String, timeout: Duration) -> io::Result<Arc<RPCClient>> {
        let client = tcp::client::Client::connect_with_timeout(addr, timeout)?;
        Ok(Arc::new(RPCClient {
            server_id: client.server_id,
            client: Mutex::new(client),
            address: addr.clone()
        }))
    }
}

impl ClientPool {
    pub fn new() -> ClientPool {
        ClientPool {
            clients: Mutex::new(HashMap::new())
        }
    }

    pub fn get(&self, addr: &String) -> io::Result<Arc<RPCClient>> {
        let mut clients = self.clients.lock();
        if clients.contains_key(addr) {
            Ok(clients.get(addr).unwrap().clone())
        } else {
            let client = RPCClient::new(addr);
            if let Ok(client) = client {
                clients.insert(addr.clone(), client.clone());
                Ok(client)
            } else {
                Err(client.err().unwrap())
            }
        }
    }
}<commit_msg>get rid of extra service clone<commit_after>#[macro_use]
pub mod proto;

use std::collections::HashMap;
use std::sync::Arc;
use std::io;
use std::time::Duration;
use parking_lot::{Mutex, RwLock};
use std::thread;
use bincode::{SizeLimit, serde as bincode};
use tcp;
use utils::time;
use utils::u8vec::*;
use futures::Future;
use bifrost_hasher::hash_str;

lazy_static! {
    pub static ref DEFAULT_CLIENT_POOL: ClientPool = ClientPool::new();
}

#[derive(Serialize, Deserialize, Debug)]
pub enum RPCRequestError {
    FunctionIdNotFound,
    ServiceIdNotFound,
    Other,
}

#[derive(Debug)]
pub enum RPCError {
    IOError(io::Error),
    RequestError(RPCRequestError),
}

pub trait RPCService: Sync + Send {
    fn dispatch(&self, data: Vec<u8>) -> Result<Vec<u8>, RPCRequestError>;
    fn register_shortcut_service(&self, service_ptr: usize, server_id: u64, service_id: u64);
}

pub struct Server {
    services: RwLock<HashMap<u64, Arc<RPCService>>>,
    address: String,
    server_id: u64
}

pub struct ClientPool {
    clients: Mutex<HashMap<String, Arc<RPCClient>>>
}

fn encode_res(res: Result<Vec<u8>, RPCRequestError>) -> Vec<u8> {
    match res {
        Ok(vec) => {
            [0u8; 1].iter().cloned().chain(vec.into_iter()).collect()
        },
        Err(e) => {
            let err_id = match e {
                RPCRequestError::FunctionIdNotFound => 1u8,
                RPCRequestError::ServiceIdNotFound => 2u8,
                _ => 255u8
            };
            vec!(err_id)
        }
    }
}

fn decode_res(res: io::Result<Vec<u8>>) -> Result<Vec<u8>, RPCError> {
    match res {
        Ok(res) => {
            if res[0] == 0u8 {
                Ok(res.into_iter().skip(1).collect())
            } else {
                match res[0] {
                    1u8 => Err(RPCError::RequestError(RPCRequestError::FunctionIdNotFound)),
                    2u8 => Err(RPCError::RequestError(RPCRequestError::ServiceIdNotFound)),
                    _ => Err(RPCError::RequestError(RPCRequestError::Other)),
                }
            }
        },
        Err(e) => Err(RPCError::IOError(e))
    }
}

impl Server {
    pub fn new(address: &String) -> Arc<Server> {
        Arc::new(Server {
            services: RwLock::new(HashMap::new()),
            address: address.clone(),
            server_id: hash_str(address)
        })
    }
    pub fn listen(server: &Arc<Server>) {
        let address = &server.address;
        let server = server.clone();
        tcp::server::Server::new(address, Box::new(move |data| {
            let (svr_id, data) = extract_u64_head(data);
            let t = time::get_time();
            let svr_map = server.services.read();
            let service = svr_map.get(&svr_id);
            let res = match service {
                Some(service) => {
                    encode_res(service.dispatch(data))
                },
                None => encode_res(Err(RPCRequestError::ServiceIdNotFound) as Result<Vec<u8>, RPCRequestError>)
            };
            //println!("SVR RPC: {} - {}ms", svr_id, time::get_time() - t);
            res
        }));
    }
    pub fn listen_and_resume(server: &Arc<Server>) {
        let server = server.clone();
        thread::spawn(move|| {
            let server = server;
            Server::listen(&server);
        });
    }
    pub fn register_service<T>(&self, service_id: u64,  service: &Arc<T>)
    where T: RPCService + Sized + 'static{
        let service = service.clone();
        let service_ptr = Arc::into_raw(service.clone()) as usize;
        service.register_shortcut_service(service_ptr, self.server_id, service_id);
        self.services.write().insert(service_id, service);
    }
    pub fn remove_service(&self, service_id: u64) {
        self.services.write().remove(&service_id);
    }
    pub fn address(&self) -> &String {
        &self.address
    }
}

pub struct RPCClient {
    client: Mutex<tcp::client::Client>,
    pub server_id: u64,
    pub address: String
}

impl RPCClient {
    pub fn send(&self, svr_id: u64, data: Vec<u8>) -> Result<Vec<u8>, RPCError> {
        decode_res(self.client.lock().send(prepend_u64(svr_id, data)))
    }
    pub fn send_async(&self, svr_id: u64, data: Vec<u8>) -> Box<Future<Item = Vec<u8>, Error = RPCError>> {
        Box::new(self.client.lock()
            .send_async(prepend_u64(svr_id, data))
            .then(move |res| decode_res(res)))
    }
    pub fn new(addr: &String) -> io::Result<Arc<RPCClient>> {
        let client = tcp::client::Client::connect(addr)?;
        Ok(Arc::new(RPCClient {
            server_id: client.server_id,
            client: Mutex::new(client),
            address: addr.clone()
        }))
    }
    pub fn with_timeout(addr: &String, timeout: Duration) -> io::Result<Arc<RPCClient>> {
        let client = tcp::client::Client::connect_with_timeout(addr, timeout)?;
        Ok(Arc::new(RPCClient {
            server_id: client.server_id,
            client: Mutex::new(client),
            address: addr.clone()
        }))
    }
}

impl ClientPool {
    pub fn new() -> ClientPool {
        ClientPool {
            clients: Mutex::new(HashMap::new())
        }
    }

    pub fn get(&self, addr: &String) -> io::Result<Arc<RPCClient>> {
        let mut clients = self.clients.lock();
        if clients.contains_key(addr) {
            Ok(clients.get(addr).unwrap().clone())
        } else {
            let client = RPCClient::new(addr);
            if let Ok(client) = client {
                clients.insert(addr.clone(), client.clone());
                Ok(client)
            } else {
                Err(client.err().unwrap())
            }
        }
    }
}<|endoftext|>


<commit_before>use ::Key;
use ::rudymap::RudyMap;

pub struct RudySet<K: Key> {
    map: RudyMap<K, ()>
}

impl<K: Key> RudySet<K> {
    pub fn new() -> RudySet<K> {
        RudySet {
            map: RudyMap::new()
        }
    }

    pub fn insert(&mut self, value: K) -> bool {
        self.map.insert(value, ()).is_some()
    }

    pub fn remove(&mut self, value: K) -> bool {
        self.map.remove(value).is_some()
    }

    pub fn contains(&self, value: K) -> bool {
        self.map.contains_key(value)
    }

    pub fn clear(&mut self) {
        self.map = RudyMap::new();
    }

    pub fn is_empty(&self) -> bool {
        self.map.is_empty()
    }

    pub fn len(&self) -> usize {
        self.map.len()
    }

    /*
    pub fn iter(&self) -> Iter<'a, K> {
        Iter { iter: self.map.iter() }
    }

    pub fn iter_mut(&mut self) -> IterMut<'a, K> {
        IterMut { iter: self.map.iter() }
    }
    */
}

/*
struct Iter<'a, K> {
    iter: rudymap::Iter<'a, K, ()>
}

impl<'a, K: Key> Iterator<K> for Iter<'a, K> {
    #[inline]
    fn next(&mut self) -> Option<K> {
        self.iter.next().map(|(k, _)| k)
    }
}

struct IterMut<'a, K> {
    iter: rudymap::IterMut<'a, K, ()>
}

impl<'a, K: Key> Iterator<K> for IterMut<'a, K> {
    #[inline]
    fn next(&mut self) -> Option<K> {
        self.iter.next().map(|(k, _)| k)
    }
}

impl<K: Key + PartialEq> PartialEq for RudySet<K> {
    fn eq(&self, other: &RudySet<K>) -> bool {
        if self.len() != other.len() {
            return false;
        }
        self.iter().zip(other.iter())
            .all(|(a, b)| a == b)
    }
}

impl<K: Key + Eq> Eq for RudySet<K> {}

 */

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_insert_empty() {
        let mut set = RudySet::<usize>::new();
        assert_eq!(set.insert(4usize), false);
    }

    #[test]
    fn test_insert_exists() {
        let mut set = RudySet::<usize>::new();
        set.insert(4usize);
        assert_eq!(set.insert(4usize), true);
    }

    #[test]
    fn test_remove_empty() {
        let mut set = RudySet::<usize>::new();
        assert_eq!(set.remove(4usize), false);
    }

    #[test]
    fn test_remove_exists() {
        let mut set = RudySet::<usize>::new();
        set.insert(4usize);
        assert_eq!(set.remove(4usize), true);
    }

    #[test]
    fn test_insert_contains_1() {
        let mut set = RudySet::<usize>::new();
        set.insert(4usize);
        assert_eq!(set.contains(4), true);
        assert_eq!(set.contains(10), false);
    }

    #[test]
    fn test_insert_contains_2() {
        let mut set = RudySet::<usize>::new();
        set.insert(0);
        set.insert(1);
        assert_eq!(set.contains(0), true);
        assert_eq!(set.contains(1), true);
        assert_eq!(set.contains(2), false);
    }

    #[test]
    fn test_contains_key() {
        let mut set = RudySet::<u32>::new();
        assert_eq!(set.contains(0), false);
        assert_eq!(set.contains(1), false);

        assert_eq!(set.insert(0), false);
        assert_eq!(set.contains(0), true);
        assert_eq!(set.contains(1), false);

        assert_eq!(set.remove(0), true);
        assert_eq!(set.contains(0), false);
        assert_eq!(set.contains(1), false);
    }

    #[test]
    fn test_len() {
        let mut set = RudySet::<u32>::new();
        assert_eq!(set.len(), 0);
        assert_eq!(set.is_empty(), true);

        assert_eq!(set.insert(0), false);
        assert_eq!(set.len(), 1);
        assert_eq!(set.is_empty(), false);

        assert_eq!(set.insert(1), false);
        assert_eq!(set.len(), 2);
        assert_eq!(set.is_empty(), false);

        assert_eq!(set.insert(0), true);
        assert_eq!(set.len(), 2);
        assert_eq!(set.is_empty(), false);

        assert_eq!(set.remove(0), true);
        assert_eq!(set.len(), 1);
        assert_eq!(set.is_empty(), false);

        assert_eq!(set.remove(1), true);
        assert_eq!(set.len(), 0);
        assert_eq!(set.is_empty(), true);
    }

    #[test]
    fn test_clear() {
        let mut set = RudySet::<u32>::new();
        assert_eq!(set.insert(0), false);
        assert_eq!(set.len(), 1);

        set.clear();
        assert_eq!(set.len(), 0);
        assert_eq!(set.is_empty(), true);
    }
}
<commit_msg>Add docs and doctests for RudySet<commit_after>use ::Key;
use ::rudymap::RudyMap;

pub struct RudySet<K: Key> {
    map: RudyMap<K, ()>
}

impl<K: Key> RudySet<K> {
    /// Return an empty RudySet. There are no initial allocations.
    ///
    /// # Examples
    ///
    /// ```
    /// use ::rudy::RudySet;
    ///
    /// let mut set = RudySet::<u32>::new();
    /// ```
    pub fn new() -> RudySet<K> {
        RudySet {
            map: RudyMap::new()
        }
    }

    /// Insert a value. Returns whether the set currently contains
    /// the value.
    ///
    /// # Examples
    ///
    /// ```
    /// use ::rudy::RudySet;
    ///
    /// let mut set = RudySet::<u32>::new();
    /// assert_eq!(set.insert(4), false);
    /// assert_eq!(set.insert(4), true);
    /// ```
    pub fn insert(&mut self, value: K) -> bool {
        self.map.insert(value, ()).is_some()
    }

    /// Remove a value. Returns whether the set currently contains
    /// the value.
    ///
    /// # Examples
    ///
    /// ```
    /// use ::rudy::RudySet;
    ///
    /// let mut set = RudySet::<u32>::new();
    /// assert_eq!(set.remove(4), false);
    /// set.insert(4);
    /// assert_eq!(set.remove(4), true);
    /// assert_eq!(set.remove(4), false);
    /// ```
    pub fn remove(&mut self, value: K) -> bool {
        self.map.remove(value).is_some()
    }

    /// Return `true` if the set contains a value.
    ///
    /// # Examples
    ///
    /// ```
    /// use ::rudy::RudySet;
    ///
    /// let mut set = RudySet::<u32>::new();
    /// assert_eq!(set.contains(4), false);
    /// set.insert(4);
    /// assert_eq!(set.contains(4), true);
    /// ```
    pub fn contains(&self, value: K) -> bool {
        self.map.contains_key(value)
    }

    /// Clear the set.
    ///
    /// # Examples
    ///
    /// ```
    /// use ::rudy::RudySet;
    ///
    /// let mut set = RudySet::<u32>::new();
    /// set.insert(4);
    /// assert_eq!(set.contains(4), true);
    /// set.clear();
    /// assert_eq!(set.contains(4), false);
    /// ```
    pub fn clear(&mut self) {
        self.map = RudyMap::new();
    }

    /// Returns `true` if the set is empty.
    ///
    /// # Examples
    ///
    /// ```
    /// use ::rudy::RudySet;
    ///
    /// let mut set = RudySet::<u32>::new();
    /// assert_eq!(set.is_empty(), true);
    /// set.insert(4);
    /// assert_eq!(set.is_empty(), false);
    /// ```
    pub fn is_empty(&self) -> bool {
        self.map.is_empty()
    }

    /// Returns the number of elements in the set.
    ///
    /// # Examples
    ///
    /// ```
    /// use ::rudy::RudySet;
    ///
    /// let mut set = RudySet::<u32>::new();
    /// set.insert(4);
    /// assert_eq!(set.len(), 1);
    /// ```
    pub fn len(&self) -> usize {
        self.map.len()
    }

    /*
    pub fn iter(&self) -> Iter<'a, K> {
        Iter { iter: self.map.iter() }
    }

    pub fn iter_mut(&mut self) -> IterMut<'a, K> {
        IterMut { iter: self.map.iter() }
    }
    */
}

/*
struct Iter<'a, K> {
    iter: rudymap::Iter<'a, K, ()>
}

impl<'a, K: Key> Iterator<K> for Iter<'a, K> {
    #[inline]
    fn next(&mut self) -> Option<K> {
        self.iter.next().map(|(k, _)| k)
    }
}

struct IterMut<'a, K> {
    iter: rudymap::IterMut<'a, K, ()>
}

impl<'a, K: Key> Iterator<K> for IterMut<'a, K> {
    #[inline]
    fn next(&mut self) -> Option<K> {
        self.iter.next().map(|(k, _)| k)
    }
}

impl<K: Key + PartialEq> PartialEq for RudySet<K> {
    fn eq(&self, other: &RudySet<K>) -> bool {
        if self.len() != other.len() {
            return false;
        }
        self.iter().zip(other.iter())
            .all(|(a, b)| a == b)
    }
}

impl<K: Key + Eq> Eq for RudySet<K> {}

 */

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_insert_empty() {
        let mut set = RudySet::<usize>::new();
        assert_eq!(set.insert(4usize), false);
    }

    #[test]
    fn test_insert_exists() {
        let mut set = RudySet::<usize>::new();
        set.insert(4usize);
        assert_eq!(set.insert(4usize), true);
    }

    #[test]
    fn test_remove_empty() {
        let mut set = RudySet::<usize>::new();
        assert_eq!(set.remove(4usize), false);
    }

    #[test]
    fn test_remove_exists() {
        let mut set = RudySet::<usize>::new();
        set.insert(4usize);
        assert_eq!(set.remove(4usize), true);
    }

    #[test]
    fn test_insert_contains_1() {
        let mut set = RudySet::<usize>::new();
        set.insert(4usize);
        assert_eq!(set.contains(4), true);
        assert_eq!(set.contains(10), false);
    }

    #[test]
    fn test_insert_contains_2() {
        let mut set = RudySet::<usize>::new();
        set.insert(0);
        set.insert(1);
        assert_eq!(set.contains(0), true);
        assert_eq!(set.contains(1), true);
        assert_eq!(set.contains(2), false);
    }

    #[test]
    fn test_contains_key() {
        let mut set = RudySet::<u32>::new();
        assert_eq!(set.contains(0), false);
        assert_eq!(set.contains(1), false);

        assert_eq!(set.insert(0), false);
        assert_eq!(set.contains(0), true);
        assert_eq!(set.contains(1), false);

        assert_eq!(set.remove(0), true);
        assert_eq!(set.contains(0), false);
        assert_eq!(set.contains(1), false);
    }

    #[test]
    fn test_len() {
        let mut set = RudySet::<u32>::new();
        assert_eq!(set.len(), 0);
        assert_eq!(set.is_empty(), true);

        assert_eq!(set.insert(0), false);
        assert_eq!(set.len(), 1);
        assert_eq!(set.is_empty(), false);

        assert_eq!(set.insert(1), false);
        assert_eq!(set.len(), 2);
        assert_eq!(set.is_empty(), false);

        assert_eq!(set.insert(0), true);
        assert_eq!(set.len(), 2);
        assert_eq!(set.is_empty(), false);

        assert_eq!(set.remove(0), true);
        assert_eq!(set.len(), 1);
        assert_eq!(set.is_empty(), false);

        assert_eq!(set.remove(1), true);
        assert_eq!(set.len(), 0);
        assert_eq!(set.is_empty(), true);
    }

    #[test]
    fn test_clear() {
        let mut set = RudySet::<u32>::new();
        assert_eq!(set.insert(0), false);
        assert_eq!(set.len(), 1);

        set.clear();
        assert_eq!(set.len(), 0);
        assert_eq!(set.is_empty(), true);
    }
}
<|endoftext|>