<commit_before>use std::thread;
use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::collections::HashMap;
use std::sync::mpsc;
use std::sync::Arc;
use std::sync::Mutex;
use std::io;

use tokio_core::reactor;
use tokio_core::net::TcpListener;

use futures::future;
use futures::future::Future;
use futures::future::join_all;
use futures::stream;
use futures::stream::Stream;

use error::Error;
use result::Result;

use solicit_async::*;

use futures_misc::*;

use net2;

use tls_api::TlsAcceptor;
use tls_api_stub;

use super::server_conn::*;
use super::common::*;

use service::Service;

use server_conf::*;

pub use server_tls::ServerTlsOption;

struct LoopToServer {
    shutdown: ShutdownSignal,
    local_addr: SocketAddr,
}

pub struct Server {
    state: Arc<Mutex<ServerState>>,
    loop_to_server: LoopToServer,
    alive_rx: mpsc::Receiver<()>,
    thread_join_handle: Option<thread::JoinHandle<()>>,
}

#[derive(Default)]
struct ServerState {
    last_conn_id: u64,
    conns: HashMap<u64, ServerConnection>,
}

impl ServerState {
    fn snapshot(&self) -> HttpFutureSend<ServerStateSnapshot> {
        let futures: Vec<_> = self.conns.iter()
            .map(|(&id, conn)| conn.dump_state().map(move |state| (id, state)))
            .collect();

        Box::new(join_all(futures)
            .map(|states| ServerStateSnapshot {
                conns: states.into_iter().collect(),
            }))
    }
}

pub struct ServerStateSnapshot {
    pub conns: HashMap<u64, ConnectionStateSnapshot>,
}

impl ServerStateSnapshot {
    pub fn single_conn(&self) -> (u64, &ConnectionStateSnapshot) {
        let mut iter = self.conns.iter();
        let (&id, conn) = iter.next().expect("no conns");
        assert!(iter.next().is_none(), "more than one conn");
        (id, conn)
    }
}

#[cfg(unix)]
fn configure_tcp(tcp: &net2::TcpBuilder, conf: &ServerConf) -> io::Result<()> {
    use net2::unix::UnixTcpBuilderExt;
    if let Some(reuse_port) = conf.reuse_port {
        tcp.reuse_port(reuse_port)?;
    }
    Ok(())
}

#[cfg(windows)]
fn configure_tcp(_tcp: &net2::TcpBuilder, conf: &ServerConf) -> io::Result<()> {
    Ok(())
}

fn listener(
    addr: &SocketAddr,
    handle: &reactor::Handle,
    conf: &ServerConf)
        -> io::Result<TcpListener>
{
    let listener = match *addr {
        SocketAddr::V4(_) => net2::TcpBuilder::new_v4()?,
        SocketAddr::V6(_) => net2::TcpBuilder::new_v6()?,
    };
    configure_tcp(&listener, conf)?;
    listener.reuse_address(true)?;
    listener.bind(addr)?;
    let backlog = conf.backlog.unwrap_or(1024);
    let listener = listener.listen(backlog)?;
    TcpListener::from_listener(listener, addr, handle)
}

fn run_server_event_loop<S, A>(
    listen_addr: SocketAddr,
    state: Arc<Mutex<ServerState>>,
    tls: ServerTlsOption<A>,
    conf: ServerConf,
    service: S,
    send_to_back: mpsc::Sender<LoopToServer>,
    _alive_tx: mpsc::Sender<()>)
        where S : Service, A : TlsAcceptor,
{
    let service = Arc::new(service);

    let mut lp = reactor::Core::new().expect("http2server");

    let (shutdown_signal, shutdown_future) = shutdown_signal();

    let listen = listener(&listen_addr, &lp.handle(), &conf).unwrap();

    let stuff = stream::repeat((lp.handle(), service, state, tls, conf));

    let local_addr = listen.local_addr().unwrap();
    send_to_back
        .send(LoopToServer { shutdown: shutdown_signal, local_addr: local_addr })
        .expect("send back");

    let loop_run = listen.incoming().map_err(Error::from).zip(stuff)
        .for_each(move |((socket, peer_addr), (loop_handle, service, state, tls, conf))| {
            info!("accepted connection from {}", peer_addr);

            let no_delay = conf.no_delay.unwrap_or(true);
            socket.set_nodelay(no_delay).expect("failed to set TCP_NODELAY");

            let (conn, future) = ServerConnection::new(&loop_handle, socket, tls, conf, service);

            let conn_id = {
                let mut g = state.lock().expect("lock");
                g.last_conn_id += 1;
                let conn_id = g.last_conn_id;
                let prev = g.conns.insert(conn_id, conn);
                assert!(prev.is_none());
                conn_id
            };

            loop_handle.spawn(future
                .then(move |r| {
                    let mut g = state.lock().expect("lock");
                    let removed = g.conns.remove(&conn_id);
                    assert!(removed.is_some());
                    r
                })
                .map_err(|e| { warn!("connection end: {:?}", e); () }));
            Ok(())
        });

    let shutdown_future = shutdown_future
        .then(move |_| {
            // Must complete with error,
            // so `join` with this future cancels another future.
            future::failed::<(), _>(Error::Shutdown)
        });

    // Wait for either completion of connection (i. e. error)
    // or shutdown signal.
    let done = loop_run.join(shutdown_future);

    // TODO: do not ignore error
    lp.run(done).ok();
}

impl Server {
    pub fn new_plain<T, S>(addr: T, conf: ServerConf, service: S) -> Result<Server>
        where S : Service, T : ToSocketAddrs
    {
        let no_tls: ServerTlsOption<tls_api_stub::TlsAcceptor> = ServerTlsOption::Plain;
        Server::new(addr, no_tls, conf, service)
    }

    // TODO: result
    pub fn new<T, S, A>(addr: T, tls: ServerTlsOption<A>, conf: ServerConf, service: S)
        -> Result<Server>
        where S : Service, T : ToSocketAddrs, A : TlsAcceptor
    {
        let listen_addr = addr.to_socket_addrs()?.next().unwrap();

        let (get_from_loop_tx, get_from_loop_rx) = mpsc::channel();
        let (alive_tx, alive_rx) = mpsc::channel();

        let state: Arc<Mutex<ServerState>> = Default::default();

        let state_copy = state.clone();

        let join_handle = thread::Builder::new()
            .name(conf.thread_name.clone().unwrap_or_else(|| "http2-server-loop".to_owned()).to_string())
            .spawn(move || {
                run_server_event_loop(
                    listen_addr,
                    state_copy,
                    tls,
                    conf, service,
                    get_from_loop_tx,
                    alive_tx);
            })?;

        let loop_to_server = get_from_loop_rx.recv()
            .map_err(|_| Error::Other("failed to recv from event loop"))?;

        Ok(Server {
            state: state,
            loop_to_server: loop_to_server,
            thread_join_handle: Some(join_handle),
            alive_rx: alive_rx,
        })
    }

    pub fn local_addr(&self) -> &SocketAddr {
        &self.loop_to_server.local_addr
    }

    pub fn is_alive(&self) -> bool {
        self.alive_rx.try_recv() != Err(mpsc::TryRecvError::Disconnected)
    }

    // for tests
    pub fn dump_state(&self) -> HttpFutureSend<ServerStateSnapshot> {
        let g = self.state.lock().expect("lock");
        g.snapshot()
    }
}

// We shutdown the server in the destructor.
impl Drop for Server {
    fn drop(&mut self) {
        self.loop_to_server.shutdown.shutdown();

        // do not ignore errors of take
        // ignore errors of join, it means that server event loop crashed
        drop(self.thread_join_handle.take().unwrap().join());
    }
}

<commit_msg>Outdated TODO<commit_after>use std::thread;
use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::collections::HashMap;
use std::sync::mpsc;
use std::sync::Arc;
use std::sync::Mutex;
use std::io;

use tokio_core::reactor;
use tokio_core::net::TcpListener;

use futures::future;
use futures::future::Future;
use futures::future::join_all;
use futures::stream;
use futures::stream::Stream;

use error::Error;
use result::Result;

use solicit_async::*;

use futures_misc::*;

use net2;

use tls_api::TlsAcceptor;
use tls_api_stub;

use super::server_conn::*;
use super::common::*;

use service::Service;

use server_conf::*;

pub use server_tls::ServerTlsOption;

struct LoopToServer {
    shutdown: ShutdownSignal,
    local_addr: SocketAddr,
}

pub struct Server {
    state: Arc<Mutex<ServerState>>,
    loop_to_server: LoopToServer,
    alive_rx: mpsc::Receiver<()>,
    thread_join_handle: Option<thread::JoinHandle<()>>,
}

#[derive(Default)]
struct ServerState {
    last_conn_id: u64,
    conns: HashMap<u64, ServerConnection>,
}

impl ServerState {
    fn snapshot(&self) -> HttpFutureSend<ServerStateSnapshot> {
        let futures: Vec<_> = self.conns.iter()
            .map(|(&id, conn)| conn.dump_state().map(move |state| (id, state)))
            .collect();

        Box::new(join_all(futures)
            .map(|states| ServerStateSnapshot {
                conns: states.into_iter().collect(),
            }))
    }
}

pub struct ServerStateSnapshot {
    pub conns: HashMap<u64, ConnectionStateSnapshot>,
}

impl ServerStateSnapshot {
    pub fn single_conn(&self) -> (u64, &ConnectionStateSnapshot) {
        let mut iter = self.conns.iter();
        let (&id, conn) = iter.next().expect("no conns");
        assert!(iter.next().is_none(), "more than one conn");
        (id, conn)
    }
}

#[cfg(unix)]
fn configure_tcp(tcp: &net2::TcpBuilder, conf: &ServerConf) -> io::Result<()> {
    use net2::unix::UnixTcpBuilderExt;
    if let Some(reuse_port) = conf.reuse_port {
        tcp.reuse_port(reuse_port)?;
    }
    Ok(())
}

#[cfg(windows)]
fn configure_tcp(_tcp: &net2::TcpBuilder, conf: &ServerConf) -> io::Result<()> {
    Ok(())
}

fn listener(
    addr: &SocketAddr,
    handle: &reactor::Handle,
    conf: &ServerConf)
        -> io::Result<TcpListener>
{
    let listener = match *addr {
        SocketAddr::V4(_) => net2::TcpBuilder::new_v4()?,
        SocketAddr::V6(_) => net2::TcpBuilder::new_v6()?,
    };
    configure_tcp(&listener, conf)?;
    listener.reuse_address(true)?;
    listener.bind(addr)?;
    let backlog = conf.backlog.unwrap_or(1024);
    let listener = listener.listen(backlog)?;
    TcpListener::from_listener(listener, addr, handle)
}

fn run_server_event_loop<S, A>(
    listen_addr: SocketAddr,
    state: Arc<Mutex<ServerState>>,
    tls: ServerTlsOption<A>,
    conf: ServerConf,
    service: S,
    send_to_back: mpsc::Sender<LoopToServer>,
    _alive_tx: mpsc::Sender<()>)
        where S : Service, A : TlsAcceptor,
{
    let service = Arc::new(service);

    let mut lp = reactor::Core::new().expect("http2server");

    let (shutdown_signal, shutdown_future) = shutdown_signal();

    let listen = listener(&listen_addr, &lp.handle(), &conf).unwrap();

    let stuff = stream::repeat((lp.handle(), service, state, tls, conf));

    let local_addr = listen.local_addr().unwrap();
    send_to_back
        .send(LoopToServer { shutdown: shutdown_signal, local_addr: local_addr })
        .expect("send back");

    let loop_run = listen.incoming().map_err(Error::from).zip(stuff)
        .for_each(move |((socket, peer_addr), (loop_handle, service, state, tls, conf))| {
            info!("accepted connection from {}", peer_addr);

            let no_delay = conf.no_delay.unwrap_or(true);
            socket.set_nodelay(no_delay).expect("failed to set TCP_NODELAY");

            let (conn, future) = ServerConnection::new(&loop_handle, socket, tls, conf, service);

            let conn_id = {
                let mut g = state.lock().expect("lock");
                g.last_conn_id += 1;
                let conn_id = g.last_conn_id;
                let prev = g.conns.insert(conn_id, conn);
                assert!(prev.is_none());
                conn_id
            };

            loop_handle.spawn(future
                .then(move |r| {
                    let mut g = state.lock().expect("lock");
                    let removed = g.conns.remove(&conn_id);
                    assert!(removed.is_some());
                    r
                })
                .map_err(|e| { warn!("connection end: {:?}", e); () }));
            Ok(())
        });

    let shutdown_future = shutdown_future
        .then(move |_| {
            // Must complete with error,
            // so `join` with this future cancels another future.
            future::failed::<(), _>(Error::Shutdown)
        });

    // Wait for either completion of connection (i. e. error)
    // or shutdown signal.
    let done = loop_run.join(shutdown_future);

    // TODO: do not ignore error
    lp.run(done).ok();
}

impl Server {
    pub fn new_plain<T, S>(addr: T, conf: ServerConf, service: S) -> Result<Server>
        where S : Service, T : ToSocketAddrs
    {
        let no_tls: ServerTlsOption<tls_api_stub::TlsAcceptor> = ServerTlsOption::Plain;
        Server::new(addr, no_tls, conf, service)
    }

    pub fn new<T, S, A>(addr: T, tls: ServerTlsOption<A>, conf: ServerConf, service: S)
        -> Result<Server>
        where S : Service, T : ToSocketAddrs, A : TlsAcceptor
    {
        let listen_addr = addr.to_socket_addrs()?.next().unwrap();

        let (get_from_loop_tx, get_from_loop_rx) = mpsc::channel();
        let (alive_tx, alive_rx) = mpsc::channel();

        let state: Arc<Mutex<ServerState>> = Default::default();

        let state_copy = state.clone();

        let join_handle = thread::Builder::new()
            .name(conf.thread_name.clone().unwrap_or_else(|| "http2-server-loop".to_owned()).to_string())
            .spawn(move || {
                run_server_event_loop(
                    listen_addr,
                    state_copy,
                    tls,
                    conf, service,
                    get_from_loop_tx,
                    alive_tx);
            })?;

        let loop_to_server = get_from_loop_rx.recv()
            .map_err(|_| Error::Other("failed to recv from event loop"))?;

        Ok(Server {
            state: state,
            loop_to_server: loop_to_server,
            thread_join_handle: Some(join_handle),
            alive_rx: alive_rx,
        })
    }

    pub fn local_addr(&self) -> &SocketAddr {
        &self.loop_to_server.local_addr
    }

    pub fn is_alive(&self) -> bool {
        self.alive_rx.try_recv() != Err(mpsc::TryRecvError::Disconnected)
    }

    // for tests
    pub fn dump_state(&self) -> HttpFutureSend<ServerStateSnapshot> {
        let g = self.state.lock().expect("lock");
        g.snapshot()
    }
}

// We shutdown the server in the destructor.
impl Drop for Server {
    fn drop(&mut self) {
        self.loop_to_server.shutdown.shutdown();

        // do not ignore errors of take
        // ignore errors of join, it means that server event loop crashed
        drop(self.thread_join_handle.take().unwrap().join());
    }
}

<|endoftext|>


<commit_before>use grain_capnp::{PowerboxCapability, UiView, UiSession};
use web_session_capnp::{WebSession};

use capnp::capability::{ClientHook, FromServer};
use capnp::AnyPointer;
use capnp_rpc::rpc::{RpcConnectionState, SturdyRefRestorer};
use capnp_rpc::capability::{LocalClient};

pub struct UiViewImpl;

impl PowerboxCapability::Server for UiViewImpl {
    fn get_powerbox_info(&mut self, context : PowerboxCapability::GetPowerboxInfoContext) {
        context.done()
    }
}

impl UiView::Server for UiViewImpl {
    fn get_view_info(&mut self, context : UiView::GetViewInfoContext) {
        context.done()
    }

    fn new_session(&mut self, mut context : UiView::NewSessionContext) {
        println!("asked for a new session!");
        let (_, results) = context.get();

        let client : WebSession::Client = FromServer::new(None::<LocalClient>, ~WebSessionImpl);
        // we need to do this dance to upcast.
        results.set_session(UiSession::Client { client : client.client});

        context.done()
    }
}

pub struct WebSessionImpl;

impl UiSession::Server for WebSessionImpl {

}

static main_css : &'static str =
    "body { font-family: Helvetica, Sans, Arial;
            font-size: medium;
             margin-left: auto;
             margin-right: auto;
             width: 600px;
     }";

static header : &'static str =
  r#"<title> acronymy </title><link rel="stylesheet" type="text/css" href="main.css" >
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
  "#;

fn html_body(body :&str) -> ~str {
    format!("{}{}", header, body)
}

struct Path {
    path : ~str,
    query : Vec<(~str,Vec<~str>)>,
}

impl Path {
    fn new() -> Path {
        Path { path : ~"", query : Vec::new() }
    }
}

fn parse_path(path : &str) -> Path {
    let mut result = Path::new();

    let v : ~[&str] = path.splitn('?', 2).collect();
    if v.len() == 0 {
        return result;
    }
    if v.len() == 1 {
        result.path = v[0].into_owned();
        return result;
    }
    for attr in v[1].split('&') {
        let a : ~[&str] = attr.splitn('=', 2).collect();
        if a.len() == 2 {
            result.query.push((a[0].into_owned(),
                               a[1].split('+').map(|s| {s.into_owned() }).collect()));
        }
    }
    return result;
}

impl WebSession::Server for WebSessionImpl {
    fn get(&mut self, mut context : WebSession::GetContext) {
        println!("GET");
        let (params, results) = context.get();
        let raw_path = params.get_path();
        let content = results.init_content();
        content.set_mime_type("text/html");

        let path = parse_path(raw_path);
        println!("path = {}", raw_path);
        println!("{}, {}", path.path, path.query);

        if raw_path == "main.css" {
            content.get_body().set_bytes(main_css.as_bytes())
        } else if path.path.as_slice() == "define" {
            if path.query.len() != 1 {
                return context.fail();
            }
            let &(_, ref v) = path.query.get(0);

            content.get_body().set_bytes(
                html_body(
                    "
AWESOME

                     <form action=\"define\" method=\"get\">
                     <input name=\"word\"/><button>go</button></form>").as_bytes());

        } else {
            content.get_body().set_bytes(
                html_body(
                    "<form action=\"define\" method=\"get\">
                     <input name=\"word\"/><button>go</button></form>").as_bytes());
        }
        context.done()
    }
    fn post(&mut self, context : WebSession::PostContext) {
        println!("POST");
        context.done()
    }
    fn put(&mut self, context : WebSession::PutContext) {
        println!("PUT");
        context.done()
    }
    fn delete(&mut self, context : WebSession::DeleteContext) {
        println!("DELETE");
        context.done()
    }
    fn open_web_socket(&mut self, context : WebSession::OpenWebSocketContext) {
        println!("OPEN WEB SOCKET");
        context.done()
    }
}

pub struct FdStream {
    inner : ~::std::rt::rtio::RtioFileStream:Send,
}

impl FdStream {
    pub fn new(fd : ::libc::c_int) -> ::std::io::IoResult<FdStream> {
        ::std::rt::rtio::LocalIo::maybe_raise(|io| {
            Ok (FdStream { inner : io.fs_from_raw_fd(fd, ::std::rt::rtio::DontClose) })
        })
    }
}

impl Reader for FdStream {
    fn read(&mut self, buf : &mut [u8]) -> ::std::io::IoResult<uint> {
        self.inner.read(buf).map(|i| i as uint)
    }
}

impl Writer for FdStream {
    fn write(&mut self, buf : &[u8]) -> ::std::io::IoResult<()> {
        self.inner.write(buf)
    }
}

pub struct Restorer;

impl SturdyRefRestorer for Restorer {
    fn restore(&self, obj_id : AnyPointer::Reader) -> Option<~ClientHook:Send> {
        if obj_id.is_null() {
            let client : UiView::Client = FromServer::new(None::<LocalClient>, ~UiViewImpl);
            Some(client.client.hook)
        } else {
            None
        }
    }
}

pub fn main() -> ::std::io::IoResult<()> {
    let ifs = try!(FdStream::new(3));
    let ofs = try!(FdStream::new(3));

    let connection_state = RpcConnectionState::new();
    connection_state.run(ifs, ofs, Restorer);

    Ok(())
}

<commit_msg>bugfix<commit_after>use grain_capnp::{PowerboxCapability, UiView, UiSession};
use web_session_capnp::{WebSession};

use capnp::capability::{ClientHook, FromServer};
use capnp::AnyPointer;
use capnp_rpc::rpc::{RpcConnectionState, SturdyRefRestorer};
use capnp_rpc::capability::{LocalClient};

pub struct UiViewImpl;

impl PowerboxCapability::Server for UiViewImpl {
    fn get_powerbox_info(&mut self, context : PowerboxCapability::GetPowerboxInfoContext) {
        context.done()
    }
}

impl UiView::Server for UiViewImpl {
    fn get_view_info(&mut self, context : UiView::GetViewInfoContext) {
        context.done()
    }

    fn new_session(&mut self, mut context : UiView::NewSessionContext) {
        println!("asked for a new session!");
        let (_, results) = context.get();

        let client : WebSession::Client = FromServer::new(None::<LocalClient>, ~WebSessionImpl);
        // we need to do this dance to upcast.
        results.set_session(UiSession::Client { client : client.client});

        context.done()
    }
}

pub struct WebSessionImpl;

impl UiSession::Server for WebSessionImpl {

}

static main_css : &'static str =
    "body { font-family: Helvetica, Sans, Arial;
            font-size: medium;
             margin-left: auto;
             margin-right: auto;
             width: 600px;
     }";

static header : &'static str =
  r#"<title> acronymy </title><link rel="stylesheet" type="text/css" href="main.css" >
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
  "#;

fn html_body(body :&str) -> ~str {
    format!("{}{}", header, body)
}

struct Path {
    path : ~str,
    query : Vec<(~str,Vec<~str>)>,
}

impl Path {
    fn new() -> Path {
        Path { path : ~"", query : Vec::new() }
    }
}

fn parse_path(path : &str) -> Path {
    let mut result = Path::new();

    let v : ~[&str] = path.splitn('?', 2).collect();
    if v.len() == 0 {
        return result;
    }
    result.path = v[0].into_owned();
    if v.len() == 1 {
        return result;
    }
    for attr in v[1].split('&') {
        let a : ~[&str] = attr.splitn('=', 2).collect();
        if a.len() == 2 {
            result.query.push((a[0].into_owned(),
                               a[1].split('+').map(|s| {s.into_owned() }).collect()));
        }
    }
    return result;
}

impl WebSession::Server for WebSessionImpl {
    fn get(&mut self, mut context : WebSession::GetContext) {
        println!("GET");
        let (params, results) = context.get();
        let raw_path = params.get_path();
        let content = results.init_content();
        content.set_mime_type("text/html");

        let path = parse_path(raw_path);
        println!("path = {}", raw_path);
        println!("{}, {}", path.path, path.query);

        if raw_path == "main.css" {
            content.get_body().set_bytes(main_css.as_bytes())
        } else if path.path.as_slice() == "define" {
            if path.query.len() != 1 {
                return context.fail();
            }
            let &(_, ref v) = path.query.get(0);

            content.get_body().set_bytes(
                html_body(
                    "
AWESOME

                     <form action=\"define\" method=\"get\">
                     <input name=\"word\"/><button>go</button></form>").as_bytes());

        } else {
            content.get_body().set_bytes(
                html_body(
                    "<form action=\"define\" method=\"get\">
                     <input name=\"word\"/><button>go</button></form>").as_bytes());
        }
        context.done()
    }
    fn post(&mut self, context : WebSession::PostContext) {
        println!("POST");
        context.done()
    }
    fn put(&mut self, context : WebSession::PutContext) {
        println!("PUT");
        context.done()
    }
    fn delete(&mut self, context : WebSession::DeleteContext) {
        println!("DELETE");
        context.done()
    }
    fn open_web_socket(&mut self, context : WebSession::OpenWebSocketContext) {
        println!("OPEN WEB SOCKET");
        context.done()
    }
}

pub struct FdStream {
    inner : ~::std::rt::rtio::RtioFileStream:Send,
}

impl FdStream {
    pub fn new(fd : ::libc::c_int) -> ::std::io::IoResult<FdStream> {
        ::std::rt::rtio::LocalIo::maybe_raise(|io| {
            Ok (FdStream { inner : io.fs_from_raw_fd(fd, ::std::rt::rtio::DontClose) })
        })
    }
}

impl Reader for FdStream {
    fn read(&mut self, buf : &mut [u8]) -> ::std::io::IoResult<uint> {
        self.inner.read(buf).map(|i| i as uint)
    }
}

impl Writer for FdStream {
    fn write(&mut self, buf : &[u8]) -> ::std::io::IoResult<()> {
        self.inner.write(buf)
    }
}

pub struct Restorer;

impl SturdyRefRestorer for Restorer {
    fn restore(&self, obj_id : AnyPointer::Reader) -> Option<~ClientHook:Send> {
        if obj_id.is_null() {
            let client : UiView::Client = FromServer::new(None::<LocalClient>, ~UiViewImpl);
            Some(client.client.hook)
        } else {
            None
        }
    }
}

pub fn main() -> ::std::io::IoResult<()> {
    let ifs = try!(FdStream::new(3));
    let ofs = try!(FdStream::new(3));

    let connection_state = RpcConnectionState::new();
    connection_state.run(ifs, ofs, Restorer);

    Ok(())
}

<|endoftext|>


<commit_before>// TODO: Implement a reader and writer from the client / server relationship.
// Then try and get clients to talk to everyone -> specific clients.
// Once that's done, move on to formatting messages via tokio::Encode / Decode.
// Example TCP

#[allow(unused_imports)]
use std::net::SocketAddr;
use std::collections::{HashMap};
use std::rc::Rc;
use std::cell::RefCell;

use std::io;

use futures::AsyncSink;
use futures::sink::{Sink};
use futures::sync::*;

use futures::future::{Future};
use futures::stream::{Stream};

use tokio_core::io::Io;
use tokio_core::net::{TcpListener};
use tokio_core::reactor::{Core};

use client::TctClient;
use stanza::{Stanza, StanzaCodec, UserID};

pub struct TctServer {
    clients: Rc<RefCell<HashMap<UserID, mpsc::UnboundedSender<Stanza>>>>,
    #[allow(dead_code)]
    groups: Rc<RefCell<HashMap<UserID, mpsc::UnboundedSender<Stanza>>>>,
    channel: (mpsc::UnboundedSender<Stanza>, mpsc::UnboundedReceiver<Stanza>),
    core: Core,
    addr: SocketAddr,
}

// Ixnay on the private client, defeats the purpose and actually breaks the design
// in the first place lulz.

impl TctServer {
    /// Creates a new TctServer to be run.
    pub fn new(addr: SocketAddr) -> TctServer {
        let core = Core::new().unwrap();
        TctServer {
            // Odd way of doing this but yeah, core needs to be defined after
            // channel.
            channel: mpsc::unbounded(),
            core: core,
            addr: addr,
            groups: Rc::new(RefCell::new(HashMap::new())),
            clients: Rc::new(RefCell::new(HashMap::new()))
        }
    }

    /// Execute the server, runs in foreground for any application...
    /// This is a temporary design to get something off the ground.
    pub fn run(&mut self) {
        let socket =
            TcpListener::bind(&self.addr, &self.core.handle().clone()).unwrap();
        let handle = self.core.handle();
        let clients = self.clients.clone();
        let sender = self.channel.0.clone();

        println!("Chat service running at port : {}", self.addr.port());

        // For each incoming client connection at address 'addr'
        let server = socket.incoming().for_each(|(stream, addr)| {

            println!("Connected to client : {}", addr);

            let mut server_sender = sender.clone();

            // (writer, reader) == (sink, stream)
            // reader   -> sender
            // receiver -> writer
            let (mut writer, reader) = TctClient::new(stream, addr)
                .framed(StanzaCodec).split();
            let (sender, receiver) = mpsc::unbounded();

            let clients_inner = clients.clone();

            // Every message received over the stream, from client
            let reader = reader.into_future().map_err(|(err, _)| err).and_then(
                |(creds, stream)| {
                    if let Some(Stanza::LoginCredentials{ user, psw: _ }) = creds {
                        if user.len() == 0 {
                            println!("No username supplied. \
                                      Closing stream...");
                        } else {
                            println!("User {} logged in!", user);
                            clients_inner.borrow_mut().insert(user, sender);
                            // TODO: System of verification that a user is in the db.
                        }
                    } else if let Some(Stanza::Register{ user, psw: _ }) = creds {
                        println!("New user {} logged in!", user);
                        clients_inner.borrow_mut().insert(user, sender);
                    } else {
                        println!("No login credentials supplied from client. \
                                  Closing stream...");
                        // By not giving resources for sender into HashMap,
                        // data does not persist for this client, connection
                        // will then time-out.
                    }
                    stream.for_each(move |msg: Stanza| {
                        println!("Read made for"); // TODO: Give addr here
                        if let Some(to) = msg.to() {
                            clients_inner.borrow_mut().get_mut(&to)
                                .unwrap_or(&mut server_sender) // TODO:
                                .send(msg)
                                .or_else(
                                    |err| Err(io::Error::new(
                                            io::ErrorKind::Other, err)))

                        } else { panic!("Client reported error") }
                    })
                }).map_err(|_| ());

            let receiver = receiver.for_each(move |msg| {
                println!("Writing message to {}", addr);
                let response = match writer.start_send(msg) { // handle it like 'send'
                    Ok(AsyncSink::Ready) => Ok(()),
                    Ok(AsyncSink::NotReady(_)) => panic!("failed to send"),
                    Err(_) => Err(())
                };
                writer.poll_complete().unwrap();
                response
            });

            //let clients = self.clients.clone();
            // TODO: 'select' combinator
            handle.spawn(receiver);
            handle.spawn(reader);

            Ok(())
        });
        self.core.run(server).unwrap();
    }
}

<commit_msg>Commit<commit_after>// TODO: Implement a reader and writer from the client / server relationship.
// Then try and get clients to talk to everyone -> specific clients.
// Once that's done, move on to formatting messages via tokio::Encode / Decode.
// Example TCP

#[allow(unused_imports)]
use std::net::SocketAddr;
use std::collections::{HashMap};
use std::rc::Rc;
use std::cell::RefCell;

use std::io;

use futures::AsyncSink;
use futures::sink::{Sink};
use futures::sync::mpsc;

use futures::future::{Future};
use futures::stream::{Stream};

use tokio_core::io::Io;
use tokio_core::net::{TcpListener};
use tokio_core::reactor::{Core};

use client::TctClient;
use stanza::{Stanza, StanzaCodec, UserID};

pub struct TctServer {
    clients: Rc<RefCell<HashMap<UserID, mpsc::UnboundedSender<Stanza>>>>,
    #[allow(dead_code)]
    groups: Rc<RefCell<HashMap<UserID, mpsc::UnboundedSender<Stanza>>>>,
    channel: (mpsc::UnboundedSender<Stanza>, mpsc::UnboundedReceiver<Stanza>),
    core: Core,
    addr: SocketAddr,
}

// Ixnay on the private client, defeats the purpose and actually breaks the design
// in the first place lulz.

impl TctServer {
    /// Creates a new TctServer to be run.
    pub fn new(addr: SocketAddr) -> TctServer {
        let core = Core::new().unwrap();
        TctServer {
            // Odd way of doing this but yeah, core needs to be defined after
            // channel.
            channel: mpsc::unbounded(),
            core: core,
            addr: addr,
            groups: Rc::new(RefCell::new(HashMap::new())),
            clients: Rc::new(RefCell::new(HashMap::new()))
        }
    }

    /// Execute the server, runs in foreground for any application...
    /// This is a temporary design to get something off the ground.
    pub fn run(&mut self) {
        let socket =
            TcpListener::bind(&self.addr, &self.core.handle().clone()).unwrap();
        let handle = self.core.handle();
        let clients = self.clients.clone();
        let sender = self.channel.0.clone();

        println!("Chat service running at port : {}", self.addr.port());

        // For each incoming client connection at address 'addr'
        let server = socket.incoming().for_each(|(stream, addr)| {

            println!("Connected to client : {}", addr);

            let mut server_sender = sender.clone();

            // (writer, reader) == (sink, stream)
            // reader   -> sender
            // receiver -> writer
            let (mut writer, reader) = TctClient::new(stream, addr)
                .framed(StanzaCodec).split();
            let (sender, receiver) = mpsc::unbounded();

            let clients_inner = clients.clone();

            // Every message received over the stream, from client
            let reader = reader.into_future().map_err(|(err, _)| err).and_then(
                |(creds, stream)| {
                    if let Some(Stanza::LoginCredentials{ user, psw: _ }) = creds {
                        if user.len() == 0 {
                            println!("No username supplied. \
                                      Closing stream...");
                        } else {
                            println!("User {} logged in!", user);
                            clients_inner.borrow_mut().insert(user, sender);
                            // TODO: System of verification that a user is in the db.
                        }
                    } else if let Some(Stanza::Register{ user, psw: _ }) = creds {
                        println!("New user {} logged in!", user);
                        clients_inner.borrow_mut().insert(user, sender);
                    } else {
                        println!("No login credentials supplied from client. \
                                  Closing stream...");
                        // By not giving resources for sender into HashMap,
                        // data does not persist for this client, connection
                        // will then time-out.
                    }
                    stream.for_each(move |msg: Stanza| {
                        println!("Read made for"); // TODO: Give addr here
                        if let Some(to) = msg.to() {
                            clients_inner.borrow_mut().get_mut(&to)
                                .unwrap_or(&mut server_sender) // TODO:
                                .send(msg)
                                .or_else(
                                    |err| Err(io::Error::new(
                                            io::ErrorKind::Other, err)))

                        } else { panic!("Client reported error") }
                    })
                }).map_err(|_| ());

            let receiver = receiver.for_each(move |msg| {
                println!("Writing message to {}", addr);
                let response = match writer.start_send(msg) { // handle it like 'send'
                    Ok(AsyncSink::Ready) => Ok(()),
                    Ok(AsyncSink::NotReady(_)) => panic!("failed to send"),
                    Err(_) => Err(())
                };
                writer.poll_complete().unwrap();
                response
            });

            //let clients = self.clients.clone();
            // TODO: 'select' combinator
            handle.spawn(receiver);
            handle.spawn(reader);

            Ok(())
        });
        self.core.run(server).unwrap();
    }
}

<|endoftext|>


<commit_before>extern crate dbus;
use self::dbus::{Connection, ConnectionItem, Message, NameFlag, ReleaseNameReply};

use super::error::DBusError;
use super::interface::DBusInterface;
use super::object::DBusObject;
use super::target::DBusTarget;

use std::collections::btree_map::{BTreeMap, Entry};
use std::error::Error;

pub struct DBusServer<'a> {
    conn: &'a Connection,
    name: String,

    objects: BTreeMap<String, DBusObject<'a>>,
    signals: BTreeMap<DBusTarget, Vec<fn (&Connection, &DBusTarget) -> ()>>
}

impl<'a> DBusServer<'a> {
    pub fn new(conn: &'a Connection, name: &str) -> Result<DBusServer<'a>, dbus::Error> {
        try!(conn.register_name(name, NameFlag::DoNotQueue as u32));

        Ok(DBusServer {
            conn: conn,
            name: name.to_string(),

            objects: BTreeMap::new(),
            signals: BTreeMap::new(),
        })
    }

    pub fn add_object(&mut self, path: &str, ifaces: BTreeMap<String, Box<DBusInterface>>) -> Result<&DBusObject<'a>, Box<Error>> {
        match self.objects.entry(path.to_string()) {
            Entry::Vacant(v)    => Ok(v.insert(try!(DBusObject::new(self.conn, ifaces, path)))),
            Entry::Occupied(_)  => Err(Box::new(DBusError::PathAlreadyRegistered(path.to_string()))),
        }
    }

    pub fn remove_object(&mut self, path: &str) -> Result<(), DBusError> {
        match self.objects.remove(path) {
            Some(_) => Ok(()),
            None    => Err(DBusError::NoSuchPath(path.to_string())),
        }
    }

    pub fn connect(&mut self, signal: DBusTarget, callback: fn (&Connection, &DBusTarget) -> ()) -> () {
        match self.signals.entry(signal) {
            Entry::Vacant(v)    => { v.insert(vec![callback]); },
            Entry::Occupied(o)  => o.into_mut().push(callback),
        };
    }

    pub fn run(&mut self) -> () {
        self.conn.iter(100).fold((), |_, item| {
            match item {
                ConnectionItem::MethodCall(m)   => self._call_method(m),
                ConnectionItem::Signal(s)       => self._match_signal(s),
                ConnectionItem::Nothing         => (),
            }
        });
    }

    fn _call_method(&mut self, m: Message) -> () {
        // TODO: Implement.
    }

    fn _match_signal(&self, m: Message) -> () {
        // TODO: Implement.
    }
}

impl<'a> Drop for DBusServer<'a> {
    fn drop(&mut self) {
        let res = self.conn.release_name(&self.name);
        match res {
            Ok(reply) =>
                match reply {
                    ReleaseNameReply::Released    => (),
                    ReleaseNameReply::NonExistent => panic!("internal error: non-existent name {}?!", self.name),
                    ReleaseNameReply::NotOwner    => panic!("internal error: not the owner of {}?!", self.name),
                },
            Err(err) => println!("failed to release {}: {:?}: {:?}", self.name, err.name(), err.message()),
        }
    }
}
<commit_msg>server: implement calling a method<commit_after>extern crate dbus;
use self::dbus::{Connection, ConnectionItem, Message, NameFlag, ReleaseNameReply};

use super::error::DBusError;
use super::interface::DBusInterface;
use super::object::DBusObject;
use super::target::{DBusTarget, extract_target};

use std::collections::btree_map::{BTreeMap, Entry};
use std::error::Error;

pub struct DBusServer<'a> {
    conn: &'a Connection,
    name: String,

    objects: BTreeMap<String, DBusObject<'a>>,
    signals: BTreeMap<DBusTarget, Vec<fn (&Connection, &DBusTarget) -> ()>>
}

impl<'a> DBusServer<'a> {
    pub fn new(conn: &'a Connection, name: &str) -> Result<DBusServer<'a>, dbus::Error> {
        try!(conn.register_name(name, NameFlag::DoNotQueue as u32));

        Ok(DBusServer {
            conn: conn,
            name: name.to_string(),

            objects: BTreeMap::new(),
            signals: BTreeMap::new(),
        })
    }

    pub fn add_object(&mut self, path: &str, ifaces: BTreeMap<String, Box<DBusInterface>>) -> Result<&DBusObject<'a>, Box<Error>> {
        match self.objects.entry(path.to_string()) {
            Entry::Vacant(v)    => Ok(v.insert(try!(DBusObject::new(self.conn, ifaces, path)))),
            Entry::Occupied(_)  => Err(Box::new(DBusError::PathAlreadyRegistered(path.to_string()))),
        }
    }

    pub fn remove_object(&mut self, path: &str) -> Result<(), DBusError> {
        match self.objects.remove(path) {
            Some(_) => Ok(()),
            None    => Err(DBusError::NoSuchPath(path.to_string())),
        }
    }

    pub fn connect(&mut self, signal: DBusTarget, callback: fn (&Connection, &DBusTarget) -> ()) -> () {
        match self.signals.entry(signal) {
            Entry::Vacant(v)    => { v.insert(vec![callback]); },
            Entry::Occupied(o)  => o.into_mut().push(callback),
        };
    }

    pub fn run(&mut self) -> () {
        self.conn.iter(100).fold((), |_, item| {
            match item {
                ConnectionItem::MethodCall(m)   => self._call_method(m),
                ConnectionItem::Signal(s)       => self._match_signal(s),
                ConnectionItem::Nothing         => (),
            }
        });
    }

    fn _call_method(&mut self, m: Message) -> () {
        let conn = self.conn;

        self._find_interface(&m).map(|(ref mut iface, ref method)| {
            iface.call_method(&method, conn, &m).map(|result| {
                conn.send(result)
            })
        });
    }

    fn _find_interface(&mut self, m: &Message) -> Option<(&mut DBusInterface, String)> {
        let ref mut objects = self.objects;

        extract_target(&m).and_then(move |method| {
            objects.get_mut(&method.1).and_then(|dbus_object| {
                dbus_object.get_interface_mut(&method.0).map(|dbus_interface| {
                    (dbus_interface, method.2.clone())
                })
            })
        })
    }

    fn _match_signal(&self, m: Message) -> () {
        // TODO: Implement.
    }
}

impl<'a> Drop for DBusServer<'a> {
    fn drop(&mut self) {
        let res = self.conn.release_name(&self.name);
        match res {
            Ok(reply) =>
                match reply {
                    ReleaseNameReply::Released    => (),
                    ReleaseNameReply::NonExistent => panic!("internal error: non-existent name {}?!", self.name),
                    ReleaseNameReply::NotOwner    => panic!("internal error: not the owner of {}?!", self.name),
                },
            Err(err) => println!("failed to release {}: {:?}: {:?}", self.name, err.name(), err.message()),
        }
    }
}
<|endoftext|>


<commit_before>//! Handles the `Enter` key press. At the momently, this only continues
//! comments, but should handle indent some time in the future as well.

use ide_db::base_db::{FilePosition, SourceDatabase};
use ide_db::RootDatabase;
use syntax::{
    ast::{self, AstToken},
    AstNode, SmolStr, SourceFile,
    SyntaxKind::*,
    SyntaxToken, TextRange, TextSize, TokenAtOffset,
};

use text_edit::TextEdit;

// Feature: On Enter
//
// rust-analyzer can override kbd:[Enter] key to make it smarter:
//
// - kbd:[Enter] inside triple-slash comments automatically inserts `///`
// - kbd:[Enter] in the middle or after a trailing space in `//` inserts `//`
// - kbd:[Enter] inside `//!` doc comments automatically inserts `//!`
//
// This action needs to be assigned to shortcut explicitly.
//
// VS Code::
//
// Add the following to `keybindings.json`:
// [source,json]
// ----
// {
//   "key": "Enter",
//   "command": "rust-analyzer.onEnter",
//   "when": "editorTextFocus && !suggestWidgetVisible && editorLangId == rust"
// }
// ----
//
// image::https://user-images.githubusercontent.com/48062697/113065578-04c21800-91b1-11eb-82b8-22b8c481e645.gif[]
pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> {
    let parse = db.parse(position.file_id);
    let file = parse.tree();
    let comment = file
        .syntax()
        .token_at_offset(position.offset)
        .left_biased()
        .and_then(ast::Comment::cast)?;

    if comment.kind().shape.is_block() {
        return None;
    }

    let prefix = comment.prefix();
    let comment_range = comment.syntax().text_range();
    if position.offset < comment_range.start() + TextSize::of(prefix) {
        return None;
    }

    let mut remove_trailing_whitespace = false;
    // Continuing single-line non-doc comments (like this one :) ) is annoying
    if prefix == "//" && comment_range.end() == position.offset {
        if comment.text().ends_with(' ') {
            cov_mark::hit!(continues_end_of_line_comment_with_space);
            remove_trailing_whitespace = true;
        } else if !followed_by_comment(&comment) {
            return None;
        }
    }

    let indent = node_indent(&file, comment.syntax())?;
    let inserted = format!("\n{}{} $0", indent, prefix);
    let delete = if remove_trailing_whitespace {
        let trimmed_len = comment.text().trim_end().len() as u32;
        let trailing_whitespace_len = comment.text().len() as u32 - trimmed_len;
        TextRange::new(position.offset - TextSize::from(trailing_whitespace_len), position.offset)
    } else {
        TextRange::empty(position.offset)
    };
    let edit = TextEdit::replace(delete, inserted);
    Some(edit)
}

fn followed_by_comment(comment: &ast::Comment) -> bool {
    let ws = match comment.syntax().next_token().and_then(ast::Whitespace::cast) {
        Some(it) => it,
        None => return false,
    };
    if ws.spans_multiple_lines() {
        return false;
    }
    ws.syntax().next_token().and_then(ast::Comment::cast).is_some()
}

fn node_indent(file: &SourceFile, token: &SyntaxToken) -> Option<SmolStr> {
    let ws = match file.syntax().token_at_offset(token.text_range().start()) {
        TokenAtOffset::Between(l, r) => {
            assert!(r == *token);
            l
        }
        TokenAtOffset::Single(n) => {
            assert!(n == *token);
            return Some("".into());
        }
        TokenAtOffset::None => unreachable!(),
    };
    if ws.kind() != WHITESPACE {
        return None;
    }
    let text = ws.text();
    let pos = text.rfind('\n').map(|it| it + 1).unwrap_or(0);
    Some(text[pos..].into())
}

#[cfg(test)]
mod tests {
    use stdx::trim_indent;
    use test_utils::assert_eq_text;

    use crate::fixture;

    fn apply_on_enter(before: &str) -> Option<String> {
        let (analysis, position) = fixture::position(&before);
        let result = analysis.on_enter(position).unwrap()?;

        let mut actual = analysis.file_text(position.file_id).unwrap().to_string();
        result.apply(&mut actual);
        Some(actual)
    }

    fn do_check(ra_fixture_before: &str, ra_fixture_after: &str) {
        let ra_fixture_after = &trim_indent(ra_fixture_after);
        let actual = apply_on_enter(ra_fixture_before).unwrap();
        assert_eq_text!(ra_fixture_after, &actual);
    }

    fn do_check_noop(ra_fixture_text: &str) {
        assert!(apply_on_enter(ra_fixture_text).is_none())
    }

    #[test]
    fn continues_doc_comment() {
        do_check(
            r"
/// Some docs$0
fn foo() {
}
",
            r"
/// Some docs
/// $0
fn foo() {
}
",
        );

        do_check(
            r"
impl S {
    /// Some$0 docs.
    fn foo() {}
}
",
            r"
impl S {
    /// Some
    /// $0 docs.
    fn foo() {}
}
",
        );

        do_check(
            r"
///$0 Some docs
fn foo() {
}
",
            r"
///
/// $0 Some docs
fn foo() {
}
",
        );
    }

    #[test]
    fn does_not_continue_before_doc_comment() {
        do_check_noop(r"$0//! docz");
    }

    #[test]
    fn continues_another_doc_comment() {
        do_check(
            r#"
fn main() {
    //! Documentation for$0 on enter
    let x = 1 + 1;
}
"#,
            r#"
fn main() {
    //! Documentation for
    //! $0 on enter
    let x = 1 + 1;
}
"#,
        );
    }

    #[test]
    fn continues_code_comment_in_the_middle_of_line() {
        do_check(
            r"
fn main() {
    // Fix$0 me
    let x = 1 + 1;
}
",
            r"
fn main() {
    // Fix
    // $0 me
    let x = 1 + 1;
}
",
        );
    }

    #[test]
    fn continues_code_comment_in_the_middle_several_lines() {
        do_check(
            r"
fn main() {
    // Fix$0
    // me
    let x = 1 + 1;
}
",
            r"
fn main() {
    // Fix
    // $0
    // me
    let x = 1 + 1;
}
",
        );
    }

    #[test]
    fn does_not_continue_end_of_line_comment() {
        do_check_noop(
            r"
fn main() {
    // Fix me$0
    let x = 1 + 1;
}
",
        );
    }

    #[test]
    fn continues_end_of_line_comment_with_space() {
        cov_mark::check!(continues_end_of_line_comment_with_space);
        do_check(
            r#"
fn main() {
    // Fix me $0
    let x = 1 + 1;
}
"#,
            r#"
fn main() {
    // Fix me
    // $0
    let x = 1 + 1;
}
"#,
        );
    }

    #[test]
    fn trims_all_trailing_whitespace() {
        do_check(
            "
fn main() {
    // Fix me  \t\t   $0
    let x = 1 + 1;
}
",
            "
fn main() {
    // Fix me
    // $0
    let x = 1 + 1;
}
",
        );
    }
}
<commit_msg>Indent block expressions on enter<commit_after>//! Handles the `Enter` key press. At the momently, this only continues
//! comments, but should handle indent some time in the future as well.

use std::sync::Arc;

use ide_db::RootDatabase;
use ide_db::{
    base_db::{FilePosition, SourceDatabase},
    line_index::LineIndex,
    LineIndexDatabase,
};
use syntax::{
    algo::find_node_at_offset,
    ast::{self, edit::IndentLevel, AstToken},
    AstNode, SmolStr, SourceFile,
    SyntaxKind::*,
    SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset,
};

use text_edit::TextEdit;

// Feature: On Enter
//
// rust-analyzer can override kbd:[Enter] key to make it smarter:
//
// - kbd:[Enter] inside triple-slash comments automatically inserts `///`
// - kbd:[Enter] in the middle or after a trailing space in `//` inserts `//`
// - kbd:[Enter] inside `//!` doc comments automatically inserts `//!`
// - kbd:[Enter] after `{` indents contents and closing `}` of single-line block
//
// This action needs to be assigned to shortcut explicitly.
//
// VS Code::
//
// Add the following to `keybindings.json`:
// [source,json]
// ----
// {
//   "key": "Enter",
//   "command": "rust-analyzer.onEnter",
//   "when": "editorTextFocus && !suggestWidgetVisible && editorLangId == rust"
// }
// ----
//
// image::https://user-images.githubusercontent.com/48062697/113065578-04c21800-91b1-11eb-82b8-22b8c481e645.gif[]
pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> {
    let parse = db.parse(position.file_id);
    let file = parse.tree();
    let token = file.syntax().token_at_offset(position.offset).left_biased()?;

    if let Some(comment) = ast::Comment::cast(token.clone()) {
        return on_enter_in_comment(&comment, &file, position.offset);
    }

    if token.kind() == L_CURLY {
        // Typing enter after the `{` of a block expression, where the `}` is on the same line
        if let Some(edit) = find_node_at_offset(file.syntax(), position.offset - TextSize::of('{'))
            .and_then(|block| on_enter_in_block(db, block, position))
        {
            return Some(edit);
        }
    }

    None
}

fn on_enter_in_comment(
    comment: &ast::Comment,
    file: &ast::SourceFile,
    offset: TextSize,
) -> Option<TextEdit> {
    if comment.kind().shape.is_block() {
        return None;
    }

    let prefix = comment.prefix();
    let comment_range = comment.syntax().text_range();
    if offset < comment_range.start() + TextSize::of(prefix) {
        return None;
    }

    let mut remove_trailing_whitespace = false;
    // Continuing single-line non-doc comments (like this one :) ) is annoying
    if prefix == "//" && comment_range.end() == offset {
        if comment.text().ends_with(' ') {
            cov_mark::hit!(continues_end_of_line_comment_with_space);
            remove_trailing_whitespace = true;
        } else if !followed_by_comment(&comment) {
            return None;
        }
    }

    let indent = node_indent(&file, comment.syntax())?;
    let inserted = format!("\n{}{} $0", indent, prefix);
    let delete = if remove_trailing_whitespace {
        let trimmed_len = comment.text().trim_end().len() as u32;
        let trailing_whitespace_len = comment.text().len() as u32 - trimmed_len;
        TextRange::new(offset - TextSize::from(trailing_whitespace_len), offset)
    } else {
        TextRange::empty(offset)
    };
    let edit = TextEdit::replace(delete, inserted);
    Some(edit)
}

fn on_enter_in_block(
    db: &RootDatabase,
    block: ast::BlockExpr,
    position: FilePosition,
) -> Option<TextEdit> {
    let contents = block_contents(&block)?;

    let line_index: Arc<LineIndex> = db.line_index(position.file_id);
    let (open, close) = (block.l_curly_token()?, block.r_curly_token()?);
    let start = line_index.line_col(open.text_range().start()).line;
    let end = line_index.line_col(close.text_range().end()).line;
    if start != end {
        return None;
    }

    let indent = IndentLevel::from_node(block.syntax());
    let mut edit = TextEdit::insert(position.offset, format!("\n{}$0", indent + 1));
    edit.union(TextEdit::insert(contents.text_range().end(), format!("\n{}", indent))).ok()?;
    Some(edit)
}

fn block_contents(block: &ast::BlockExpr) -> Option<SyntaxNode> {
    let mut node = block.tail_expr().map(|e| e.syntax().clone());

    for stmt in block.statements() {
        if node.is_some() {
            // More than 1 node in the block
            return None;
        }

        node = Some(stmt.syntax().clone());
    }

    node
}

fn followed_by_comment(comment: &ast::Comment) -> bool {
    let ws = match comment.syntax().next_token().and_then(ast::Whitespace::cast) {
        Some(it) => it,
        None => return false,
    };
    if ws.spans_multiple_lines() {
        return false;
    }
    ws.syntax().next_token().and_then(ast::Comment::cast).is_some()
}

fn node_indent(file: &SourceFile, token: &SyntaxToken) -> Option<SmolStr> {
    let ws = match file.syntax().token_at_offset(token.text_range().start()) {
        TokenAtOffset::Between(l, r) => {
            assert!(r == *token);
            l
        }
        TokenAtOffset::Single(n) => {
            assert!(n == *token);
            return Some("".into());
        }
        TokenAtOffset::None => unreachable!(),
    };
    if ws.kind() != WHITESPACE {
        return None;
    }
    let text = ws.text();
    let pos = text.rfind('\n').map(|it| it + 1).unwrap_or(0);
    Some(text[pos..].into())
}

#[cfg(test)]
mod tests {
    use stdx::trim_indent;
    use test_utils::assert_eq_text;

    use crate::fixture;

    fn apply_on_enter(before: &str) -> Option<String> {
        let (analysis, position) = fixture::position(&before);
        let result = analysis.on_enter(position).unwrap()?;

        let mut actual = analysis.file_text(position.file_id).unwrap().to_string();
        result.apply(&mut actual);
        Some(actual)
    }

    fn do_check(ra_fixture_before: &str, ra_fixture_after: &str) {
        let ra_fixture_after = &trim_indent(ra_fixture_after);
        let actual = apply_on_enter(ra_fixture_before).unwrap();
        assert_eq_text!(ra_fixture_after, &actual);
    }

    fn do_check_noop(ra_fixture_text: &str) {
        assert!(apply_on_enter(ra_fixture_text).is_none())
    }

    #[test]
    fn continues_doc_comment() {
        do_check(
            r"
/// Some docs$0
fn foo() {
}
",
            r"
/// Some docs
/// $0
fn foo() {
}
",
        );

        do_check(
            r"
impl S {
    /// Some$0 docs.
    fn foo() {}
}
",
            r"
impl S {
    /// Some
    /// $0 docs.
    fn foo() {}
}
",
        );

        do_check(
            r"
///$0 Some docs
fn foo() {
}
",
            r"
///
/// $0 Some docs
fn foo() {
}
",
        );
    }

    #[test]
    fn does_not_continue_before_doc_comment() {
        do_check_noop(r"$0//! docz");
    }

    #[test]
    fn continues_another_doc_comment() {
        do_check(
            r#"
fn main() {
    //! Documentation for$0 on enter
    let x = 1 + 1;
}
"#,
            r#"
fn main() {
    //! Documentation for
    //! $0 on enter
    let x = 1 + 1;
}
"#,
        );
    }

    #[test]
    fn continues_code_comment_in_the_middle_of_line() {
        do_check(
            r"
fn main() {
    // Fix$0 me
    let x = 1 + 1;
}
",
            r"
fn main() {
    // Fix
    // $0 me
    let x = 1 + 1;
}
",
        );
    }

    #[test]
    fn continues_code_comment_in_the_middle_several_lines() {
        do_check(
            r"
fn main() {
    // Fix$0
    // me
    let x = 1 + 1;
}
",
            r"
fn main() {
    // Fix
    // $0
    // me
    let x = 1 + 1;
}
",
        );
    }

    #[test]
    fn does_not_continue_end_of_line_comment() {
        do_check_noop(
            r"
fn main() {
    // Fix me$0
    let x = 1 + 1;
}
",
        );
    }

    #[test]
    fn continues_end_of_line_comment_with_space() {
        cov_mark::check!(continues_end_of_line_comment_with_space);
        do_check(
            r#"
fn main() {
    // Fix me $0
    let x = 1 + 1;
}
"#,
            r#"
fn main() {
    // Fix me
    // $0
    let x = 1 + 1;
}
"#,
        );
    }

    #[test]
    fn trims_all_trailing_whitespace() {
        do_check(
            "
fn main() {
    // Fix me  \t\t   $0
    let x = 1 + 1;
}
",
            "
fn main() {
    // Fix me
    // $0
    let x = 1 + 1;
}
",
        );
    }

    #[test]
    fn indents_fn_body_block() {
        do_check(
            r#"
fn f() {$0()}
        "#,
            r#"
fn f() {
    $0()
}
        "#,
        );
    }

    #[test]
    fn indents_block_expr() {
        do_check(
            r#"
fn f() {
    let x = {$0()};
}
        "#,
            r#"
fn f() {
    let x = {
        $0()
    };
}
        "#,
        );
    }

    #[test]
    fn indents_match_arm() {
        do_check(
            r#"
fn f() {
    match 6 {
        1 => {$0f()},
        _ => (),
    }
}
        "#,
            r#"
fn f() {
    match 6 {
        1 => {
            $0f()
        },
        _ => (),
    }
}
        "#,
        );
    }

    #[test]
    fn indents_block_with_statement() {
        do_check(
            r#"
fn f() {$0a = b}
        "#,
            r#"
fn f() {
    $0a = b
}
        "#,
        );
        do_check(
            r#"
fn f() {$0fn f() {}}
        "#,
            r#"
fn f() {
    $0fn f() {}
}
        "#,
        );
    }

    #[test]
    fn indents_nested_blocks() {
        do_check(
            r#"
fn f() {$0{}}
        "#,
            r#"
fn f() {
    $0{}
}
        "#,
        );
    }

    #[test]
    fn does_not_indent_empty_block() {
        do_check_noop(
            r#"
fn f() {$0}
        "#,
        );
        do_check_noop(
            r#"
fn f() {{$0}}
        "#,
        );
    }

    #[test]
    fn does_not_indent_block_with_too_much_content() {
        do_check_noop(
            r#"
fn f() {$0 a = b; ()}
        "#,
        );
        do_check_noop(
            r#"
fn f() {$0 a = b; a = b; }
        "#,
        );
    }

    #[test]
    fn does_not_indent_multiline_block() {
        do_check_noop(
            r#"
fn f() {$0
}
        "#,
        );
        do_check_noop(
            r#"
fn f() {$0

}
        "#,
        );
    }
}
<|endoftext|>


<commit_before>use super::structure::{Program,Condition,Command,Expression,Sensor};

/// Representation of an `ast::structure::Program`
pub trait Source {
	fn source(&self) -> String;
}

impl Source for Program {
	fn source(&self) -> String {
		match *self {
			Program::If(ref condition, ref left, ref right) => format!("iff!({},{},{})", condition.source(), left.source(), right.source()),
			Program::Command(ref command)                   => command.source(),
		}
	}
}

impl Source for Condition {
	fn source(&self) -> String {
		match *self {
			Condition::True                              => format!("T!()"),
			Condition::False                             => format!("F!()"),
			Condition::Not(ref condition)                => format!("not!({})", (*condition).source()),
			Condition::Or(ref left, ref right)           => format!("or!({},{})", (*left).source(), (*right).source()),
			Condition::And(ref left, ref right)          => format!("and!({},{})", (*left).source(), (*right).source()),

			Condition::Less(ref left, ref right)         => format!("less!({},{})", (*left).source(), (*right).source()),
			Condition::LessEqual(ref left, ref right)    => format!("less_equal!({},{})", (*left).source(), (*right).source()),
			Condition::Equal(ref left, ref right)        => format!("equal!({},{})", (*left).source(), (*right).source()),
			Condition::GreaterEqual(ref left, ref right) => format!("greater_equal!({},{})", (*left).source(), (*right).source()),
			Condition::Greater(ref left, ref right)      => format!("greater!({},{})", (*left).source(), (*right).source()),
		}
	}
}

impl Source for Expression {
	fn source(&self) -> String {
		match *self {
			Expression::Constant(value)               => format!("constant!({:.*})", 4, value),
			Expression::Sensor(ref sensor)            => sensor.source(),
			Expression::Plus(ref left, ref right)     => format!("plus!({},{})", (*left).source(), (*right).source()),
			Expression::Minus(ref left, ref right)    => format!("minus!({},{})", (*left).source(), (*right).source()),
			Expression::Multiply(ref left, ref right) => format!("multiply!({},{})", (*left).source(), (*right).source()),
			Expression::Divide(ref left, ref right)   => format!("divide!({},{})", (*left).source(), (*right).source()),
		}
	}
}

impl Source for Sensor {
	fn source(&self) -> String {
		match *self {
			Sensor::X  => format!("x!()"),
			Sensor::Y  => format!("u!()"),
			Sensor::Vx => format!("vx!()"),
			Sensor::Vy => format!("vy!()"),
			Sensor::O  => format!("o!()"),
			Sensor::W  => format!("w!()"),
		}
	}
}

impl Source for Command {
	fn source(&self) -> String {
		match *self {
			Command::Skip  => format!("skip!()"),
			Command::Left  => format!("left!()"),
			Command::Right => format!("right!()"),
			Command::Up    => format!("up!()"),
		}
	}
}

#[test]
fn should_correctly_source_programs() {
	assert_eq!("iff!(T!(),skip!(),left!())",
		Program::If(Condition::True, Box::new(Program::Command(Command::Skip)), Box::new(Program::Command(Command::Left))).source());
	assert_eq!("skip!()", Program::Command(Command::Skip).source());
}

#[test]
fn should_correctly_source_conditions() {
	assert_eq!("T!()", Condition::True.source());
	assert_eq!("F!()", Condition::False.source());
	assert_eq!("not!(T!())", Condition::Not(Box::new(Condition::True)).source());
	assert_eq!("or!(T!(),F!())", Condition::Or(Box::new(Condition::True), Box::new(Condition::False)).source());
	assert_eq!("and!(F!(),T!())", Condition::And(Box::new(Condition::False), Box::new(Condition::True)).source());
	assert_eq!("less!(constant!(1.0000),constant!(2.0000))",
		Condition::Less(Box::new(Expression::Constant(1.0)), Box::new(Expression::Constant(2.0))).source());
	assert_eq!("less_equal!(constant!(1.0000),constant!(2.0000))",
		Condition::LessEqual(Box::new(Expression::Constant(1.0)), Box::new(Expression::Constant(2.0))).source());
	assert_eq!("equal!(constant!(1.0000),constant!(2.0000))",
		Condition::Equal(Box::new(Expression::Constant(1.0)), Box::new(Expression::Constant(2.0))).source());
	assert_eq!("greater_equal!(constant!(1.0000),constant!(2.0000))",
		Condition::GreaterEqual(Box::new(Expression::Constant(1.0)), Box::new(Expression::Constant(2.0))).source());
	assert_eq!("greater!(constant!(1.0000),constant!(2.0000))",
		Condition::Greater(Box::new(Expression::Constant(1.0)), Box::new(Expression::Constant(2.0))).source());
}

#[test]
fn should_correctly_source_expressions() {
	assert_eq!("constant!(1.0000)", Expression::Constant(1.0).source());
	assert_eq!("vx!()", Expression::Sensor(Sensor::Vx).source());
	assert_eq!("plus!(constant!(1.0000),vy!())",
		Expression::Plus(Box::new(Expression::Constant(1.0)),Box::new(Expression::Sensor(Sensor::Vy))).source());
	assert_eq!("minus!(constant!(1.0000),constant!(2.0000))",
		Expression::Minus(Box::new(Expression::Constant(1.0)),Box::new(Expression::Constant(2.0))).source());
	assert_eq!("multiply!(constant!(1.0000),constant!(2.0000))",
		Expression::Multiply(Box::new(Expression::Constant(1.0)),Box::new(Expression::Constant(2.0))).source());
	assert_eq!("divide!(constant!(1.0000),constant!(2.0000))",
		Expression::Divide(Box::new(Expression::Constant(1.0)),Box::new(Expression::Constant(2.0))).source());
}

#[test]
fn should_correctly_source_sensors() {
	assert_eq!("x!()",  Sensor::X.source());
	assert_eq!("u!()",  Sensor::Y.source());
	assert_eq!("vx!()", Sensor::Vx.source());
	assert_eq!("vy!()", Sensor::Vy.source());
	assert_eq!("o!()",  Sensor::O.source());
	assert_eq!("w!()",  Sensor::W.source());
}

#[test]
fn should_correctly_source_commands() {
	assert_eq!("skip!()",  Command::Skip.source());
	assert_eq!("left!()",  Command::Left.source());
	assert_eq!("right!()", Command::Right.source());
	assert_eq!("up!()",    Command::Up.source());
}<commit_msg>Remove superfluous whitespace from source.rs<commit_after>use super::structure::{Program,Condition,Command,Expression,Sensor};

/// Representation of an `ast::structure::Program`
pub trait Source {
	fn source(&self) -> String;
}

impl Source for Program {
	fn source(&self) -> String {
		match *self {
			Program::If(ref condition, ref left, ref right) => format!("iff!({},{},{})", condition.source(), left.source(), right.source()),
			Program::Command(ref command)                   => command.source(),
		}
	}
}

impl Source for Condition {
	fn source(&self) -> String {
		match *self {
			Condition::True                              => format!("T!()"),
			Condition::False                             => format!("F!()"),
			Condition::Not(ref condition)                => format!("not!({})", (*condition).source()),
			Condition::Or(ref left, ref right)           => format!("or!({},{})", (*left).source(), (*right).source()),
			Condition::And(ref left, ref right)          => format!("and!({},{})", (*left).source(), (*right).source()),

			Condition::Less(ref left, ref right)         => format!("less!({},{})", (*left).source(), (*right).source()),
			Condition::LessEqual(ref left, ref right)    => format!("less_equal!({},{})", (*left).source(), (*right).source()),
			Condition::Equal(ref left, ref right)        => format!("equal!({},{})", (*left).source(), (*right).source()),
			Condition::GreaterEqual(ref left, ref right) => format!("greater_equal!({},{})", (*left).source(), (*right).source()),
			Condition::Greater(ref left, ref right)      => format!("greater!({},{})", (*left).source(), (*right).source()),
		}
	}
}

impl Source for Expression {
	fn source(&self) -> String {
		match *self {
			Expression::Constant(value)               => format!("constant!({:.*})", 4, value),
			Expression::Sensor(ref sensor)            => sensor.source(),
			Expression::Plus(ref left, ref right)     => format!("plus!({},{})", (*left).source(), (*right).source()),
			Expression::Minus(ref left, ref right)    => format!("minus!({},{})", (*left).source(), (*right).source()),
			Expression::Multiply(ref left, ref right) => format!("multiply!({},{})", (*left).source(), (*right).source()),
			Expression::Divide(ref left, ref right)   => format!("divide!({},{})", (*left).source(), (*right).source()),
		}
	}
}

impl Source for Sensor {
	fn source(&self) -> String {
		match *self {
			Sensor::X  => format!("x!()"),
			Sensor::Y  => format!("u!()"),
			Sensor::Vx => format!("vx!()"),
			Sensor::Vy => format!("vy!()"),
			Sensor::O  => format!("o!()"),
			Sensor::W  => format!("w!()"),
		}
	}
}

impl Source for Command {
	fn source(&self) -> String {
		match *self {
			Command::Skip  => format!("skip!()"),
			Command::Left  => format!("left!()"),
			Command::Right => format!("right!()"),
			Command::Up    => format!("up!()"),
		}
	}
}

#[test]
fn should_correctly_source_programs() {
	assert_eq!("iff!(T!(),skip!(),left!())",
		Program::If(Condition::True, Box::new(Program::Command(Command::Skip)), Box::new(Program::Command(Command::Left))).source());
	assert_eq!("skip!()", Program::Command(Command::Skip).source());
}

#[test]
fn should_correctly_source_conditions() {
	assert_eq!("T!()", Condition::True.source());
	assert_eq!("F!()", Condition::False.source());
	assert_eq!("not!(T!())", Condition::Not(Box::new(Condition::True)).source());
	assert_eq!("or!(T!(),F!())", Condition::Or(Box::new(Condition::True), Box::new(Condition::False)).source());
	assert_eq!("and!(F!(),T!())", Condition::And(Box::new(Condition::False), Box::new(Condition::True)).source());
	assert_eq!("less!(constant!(1.0000),constant!(2.0000))",
		Condition::Less(Box::new(Expression::Constant(1.0)), Box::new(Expression::Constant(2.0))).source());
	assert_eq!("less_equal!(constant!(1.0000),constant!(2.0000))",
		Condition::LessEqual(Box::new(Expression::Constant(1.0)), Box::new(Expression::Constant(2.0))).source());
	assert_eq!("equal!(constant!(1.0000),constant!(2.0000))",
		Condition::Equal(Box::new(Expression::Constant(1.0)), Box::new(Expression::Constant(2.0))).source());
	assert_eq!("greater_equal!(constant!(1.0000),constant!(2.0000))",
		Condition::GreaterEqual(Box::new(Expression::Constant(1.0)), Box::new(Expression::Constant(2.0))).source());
	assert_eq!("greater!(constant!(1.0000),constant!(2.0000))",
		Condition::Greater(Box::new(Expression::Constant(1.0)), Box::new(Expression::Constant(2.0))).source());
}

#[test]
fn should_correctly_source_expressions() {
	assert_eq!("constant!(1.0000)", Expression::Constant(1.0).source());
	assert_eq!("vx!()", Expression::Sensor(Sensor::Vx).source());
	assert_eq!("plus!(constant!(1.0000),vy!())",
		Expression::Plus(Box::new(Expression::Constant(1.0)),Box::new(Expression::Sensor(Sensor::Vy))).source());
	assert_eq!("minus!(constant!(1.0000),constant!(2.0000))",
		Expression::Minus(Box::new(Expression::Constant(1.0)),Box::new(Expression::Constant(2.0))).source());
	assert_eq!("multiply!(constant!(1.0000),constant!(2.0000))",
		Expression::Multiply(Box::new(Expression::Constant(1.0)),Box::new(Expression::Constant(2.0))).source());
	assert_eq!("divide!(constant!(1.0000),constant!(2.0000))",
		Expression::Divide(Box::new(Expression::Constant(1.0)),Box::new(Expression::Constant(2.0))).source());
}

#[test]
fn should_correctly_source_sensors() {
	assert_eq!("x!()",  Sensor::X.source());
	assert_eq!("u!()",  Sensor::Y.source());
	assert_eq!("vx!()", Sensor::Vx.source());
	assert_eq!("vy!()", Sensor::Vy.source());
	assert_eq!("o!()",  Sensor::O.source());
	assert_eq!("w!()",  Sensor::W.source());
}

#[test]
fn should_correctly_source_commands() {
	assert_eq!("skip!()",  Command::Skip.source());
	assert_eq!("left!()",  Command::Left.source());
	assert_eq!("right!()", Command::Right.source());
	assert_eq!("up!()",    Command::Up.source());
}
<|endoftext|>


<commit_before>// because we reuse the type names as idents in the macros as a dirty hack to
// work around `concat_idents!` being unstable.
#![allow(non_snake_case)]

///! Automatically serialize and deserialize parameters around a strongly-typed function.

use futures::{self, BoxFuture, Future};
use jsonrpc_core::{Error, Params, Value, to_value};
use serde::{Serialize, Deserialize};
use util::{invalid_params, expect_no_params};

/// Auto-generates an RPC trait from trait definition.
///
/// This just copies out all the methods, docs, and adds another
/// function `to_delegate` which will automatically wrap each strongly-typed
/// function in a wrapper which handles parameter and output type serialization.
///
/// RPC functions may come in a couple forms: async and synchronous.
/// These are parsed with the custom `#[rpc]` attribute, which must follow
/// documentation.
///
/// ## The #[rpc] attribute
///
/// Valid forms:
///  - `#[rpc(name = "name_here")]` (a synchronous rpc function which should be bound to the given name)
///  - `#[rpc(async, name = "name_here")]` (an async rpc function which should be bound to the given name)
///
/// Synchronous function format:
/// `fn foo(&self, Param1, Param2, Param3) -> Result<Out, Error>`.
///
/// Asynchronous RPC functions must come in this form:
/// `fn foo(&self, Param1, Param2, Param3) -> BoxFuture<Out, Error>;
///
/// Anything else will be rejected by the code generator.
#[macro_export]
macro_rules! build_rpc_trait {
	// entry-point. todo: make another for traits w/ bounds.
	(
		$(#[$t_attr: meta])*
		pub trait $name: ident {
			$(
				$( #[doc=$m_doc:expr] )*
				#[ rpc( $($t:tt)* ) ]
				fn $m_name: ident ( $($p: tt)* ) $( -> $result: tt <$out: ty, Error> )* ;
			)*
		}
	) => {
		$(#[$t_attr])*
		pub trait $name: Sized + Send + Sync + 'static {
			$(
				$(#[doc=$m_doc])*
				fn $m_name ( $($p)* ) $( -> $result<$out, Error> )* ;
			)*

			/// Transform this into an `IoDelegate`, automatically wrapping
			/// the parameters.
			fn to_delegate<M: ::jsonrpc_core::Metadata>(self) -> $crate::delegates::IoDelegate<Self, M> {
				let mut del = $crate::delegates::IoDelegate::new(self.into());
				$(
					build_rpc_trait!(WRAP del =>
						( $($t)* )
						fn $m_name ( $($p)* ) $( -> $result <$out, Error> )*
					);
				)*
				del
			}
		}
	};

	( WRAP $del: expr =>
		(name = $name: expr)
		fn $method: ident (&self $(, $param: ty)*) -> $result: tt <$out: ty, Error>
	) => {
		$del.add_method($name, move |base, params| {
			$crate::Wrap::wrap_rpc(&(Self::$method as fn(&_ $(, $param)*) -> $result <$out, Error>), base, params)
		})
	};

	( WRAP $del: expr =>
		(async, name = $name: expr)
		fn $method: ident (&self $(, $param: ty)*) -> $result: tt <$out: ty, Error>
	) => {
		$del.add_async_method($name, move |base, params| {
			$crate::WrapAsync::wrap_rpc(&(Self::$method as fn(&_ $(, $param)*) -> $result <$out, Error>), base, params)
		})
	};
}

/// A wrapper type without an implementation of `Deserialize`
/// which allows a special implementation of `Wrap` for functions
/// that take a trailing default parameter.
pub struct Trailing<T: Default + Deserialize>(pub T);

/// Wrapper trait for synchronous RPC functions.
pub trait Wrap<B: Send + Sync + 'static> {
	fn wrap_rpc(&self, base: &B, params: Params) -> Result<Value, Error>;
}

/// Wrapper trait for asynchronous RPC functions.
pub trait WrapAsync<B: Send + Sync + 'static> {
	fn wrap_rpc(&self, base: &B, params: Params) -> BoxFuture<Value, Error>;
}

// special impl for no parameters.
impl<B, OUT> Wrap<B> for fn(&B) -> Result<OUT, Error>
	where B: Send + Sync + 'static, OUT: Serialize + 'static
{
	fn wrap_rpc(&self, base: &B, params: Params) -> Result<Value, Error> {
		expect_no_params(params)
			.and_then(|()| (self)(base))
			.map(to_value)
	}
}

impl<B, OUT> WrapAsync<B> for fn(&B) -> BoxFuture<OUT, Error>
	where B: Send + Sync + 'static, OUT: Serialize + 'static
{
	fn wrap_rpc(&self, base: &B, params: Params) -> BoxFuture<Value, Error> {
		match expect_no_params(params) {
			Ok(()) => (self)(base).map(to_value).boxed(),
			Err(e) => futures::failed(e).boxed(),
		}
	}
}

// creates a wrapper implementation which deserializes the parameters,
// calls the function with concrete type, and serializes the output.
macro_rules! wrap {
	($($x: ident),+) => {

		// synchronous implementation
		impl <
			BASE: Send + Sync + 'static,
			OUT: Serialize + 'static,
			$($x: Deserialize,)+
		> Wrap<BASE> for fn(&BASE, $($x,)+) -> Result<OUT, Error> {
			fn wrap_rpc(&self, base: &BASE, params: Params) -> Result<Value, Error> {
				params.parse::<($($x,)+)>().and_then(|($($x,)+)| {
					(self)(base, $($x,)+)
				}).map(to_value)
			}
		}

		// asynchronous implementation
		impl <
			BASE: Send + Sync + 'static,
			OUT: Serialize + 'static,
			$($x: Deserialize,)+
		> WrapAsync<BASE> for fn(&BASE, $($x,)+ ) -> BoxFuture<OUT, Error> {
			fn wrap_rpc(&self, base: &BASE, params: Params) -> BoxFuture<Value, Error> {
				match params.parse::<($($x,)+)>() {
					Ok(($($x,)+)) => (self)(base, $($x,)+).map(to_value).boxed(),
					Err(e) => futures::failed(e).boxed(),
				}
			}
		}
	}
}

// special impl for no parameters other than block parameter.
impl<B, OUT, T> Wrap<B> for fn(&B, Trailing<T>) -> Result<OUT, Error>
	where B: Send + Sync + 'static, OUT: Serialize + 'static, T: Default + Deserialize
{
	fn wrap_rpc(&self, base: &B, params: Params) -> Result<Value, Error> {
		let len = match params {
			Params::Array(ref v) => v.len(),
			Params::None => 0,
			_ => return Err(invalid_params("not an array", "")),
		};

		let (id,) = match len {
			0 => (T::default(),),
			1 => try!(params.parse::<(T,)>()),
			_ => return Err(Error::invalid_params()),
		};

		(self)(base, Trailing(id)).map(to_value)
	}
}

impl<B, OUT, T> WrapAsync<B> for fn(&B, Trailing<T>) -> BoxFuture<OUT, Error>
	where B: Send + Sync + 'static, OUT: Serialize + 'static, T: Default + Deserialize
{
	fn wrap_rpc(&self, base: &B, params: Params) -> BoxFuture<Value, Error> {
		let len = match params {
			Params::Array(ref v) => v.len(),
			Params::None => 0,
			_ => return futures::failed(invalid_params("not an array", "")).boxed(),
		};

		let id = match len {
			0 => Ok((T::default(),)),
			1 => params.parse::<(T,)>(),
			_ => Err(Error::invalid_params()),
		};

		match id {
			Ok((id,)) => (self)(base, Trailing(id)).map(to_value).boxed(),
			Err(e) => futures::failed(e).boxed(),
		}
	}
}

// similar to `wrap!`, but handles a single default trailing parameter
// accepts an additional argument indicating the number of non-trailing parameters.
macro_rules! wrap_with_trailing {
	($num: expr, $($x: ident),+) => {
		// synchronous implementation
		impl <
			BASE: Send + Sync + 'static,
			OUT: Serialize + 'static,
			$($x: Deserialize,)+
			TRAILING: Default + Deserialize,
		> Wrap<BASE> for fn(&BASE, $($x,)+ Trailing<TRAILING>) -> Result<OUT, Error> {
			fn wrap_rpc(&self, base: &BASE, params: Params) -> Result<Value, Error> {
				let len = match params {
					Params::Array(ref v) => v.len(),
					Params::None => 0,
					_ => return Err(invalid_params("not an array", "")),
				};

				let params = match len - $num {
					0 => params.parse::<($($x,)+)>()
						.map(|($($x,)+)| ($($x,)+ TRAILING::default())),
					1 => params.parse::<($($x,)+ TRAILING)>()
						.map(|($($x,)+ id)| ($($x,)+ id)),
					_ => Err(Error::invalid_params()),
				};

				let ($($x,)+ id) = try!(params);
				(self)(base, $($x,)+ Trailing(id)).map(to_value)
			}
		}

		// asynchronous implementation
		impl <
			BASE: Send + Sync + 'static,
			OUT: Serialize + 'static,
			$($x: Deserialize,)+
			TRAILING: Default + Deserialize,
		> WrapAsync<BASE> for fn(&BASE, $($x,)+ Trailing<TRAILING>) -> BoxFuture<OUT, Error> {
			fn wrap_rpc(&self, base: &BASE, params: Params) -> BoxFuture<Value, Error> {
				let len = match params {
					Params::Array(ref v) => v.len(),
					Params::None => 0,
					_ => return futures::failed(invalid_params("not an array", "")).boxed(),
				};

				let params = match len - $num {
					0 => params.parse::<($($x,)+)>()
						.map(|($($x,)+)| ($($x,)+ TRAILING::default())),
					1 => params.parse::<($($x,)+ TRAILING)>()
						.map(|($($x,)+ id)| ($($x,)+ id)),
					_ => Err(Error::invalid_params()),
				};

				match params {
					Ok(($($x,)+ id)) => (self)(base, $($x,)+ Trailing(id)).map(to_value).boxed(),
					Err(e) => futures::failed(e).boxed(),
				}
			}
		}
	}
}

wrap!(A, B, C, D, E);
wrap!(A, B, C, D);
wrap!(A, B, C);
wrap!(A, B);
wrap!(A);

wrap_with_trailing!(5, A, B, C, D, E);
wrap_with_trailing!(4, A, B, C, D);
wrap_with_trailing!(3, A, B, C);
wrap_with_trailing!(2, A, B);
wrap_with_trailing!(1, A);

<commit_msg>Removing superflous repetition pattern<commit_after>// because we reuse the type names as idents in the macros as a dirty hack to
// work around `concat_idents!` being unstable.
#![allow(non_snake_case)]

///! Automatically serialize and deserialize parameters around a strongly-typed function.

use futures::{self, BoxFuture, Future};
use jsonrpc_core::{Error, Params, Value, to_value};
use serde::{Serialize, Deserialize};
use util::{invalid_params, expect_no_params};

/// Auto-generates an RPC trait from trait definition.
///
/// This just copies out all the methods, docs, and adds another
/// function `to_delegate` which will automatically wrap each strongly-typed
/// function in a wrapper which handles parameter and output type serialization.
///
/// RPC functions may come in a couple forms: async and synchronous.
/// These are parsed with the custom `#[rpc]` attribute, which must follow
/// documentation.
///
/// ## The #[rpc] attribute
///
/// Valid forms:
///  - `#[rpc(name = "name_here")]` (a synchronous rpc function which should be bound to the given name)
///  - `#[rpc(async, name = "name_here")]` (an async rpc function which should be bound to the given name)
///
/// Synchronous function format:
/// `fn foo(&self, Param1, Param2, Param3) -> Result<Out, Error>`.
///
/// Asynchronous RPC functions must come in this form:
/// `fn foo(&self, Param1, Param2, Param3) -> BoxFuture<Out, Error>;
///
/// Anything else will be rejected by the code generator.
#[macro_export]
macro_rules! build_rpc_trait {
	// entry-point. todo: make another for traits w/ bounds.
	(
		$(#[$t_attr: meta])*
		pub trait $name: ident {
			$(
				$( #[doc=$m_doc:expr] )*
				#[ rpc( $($t:tt)* ) ]
				fn $m_name: ident ( $($p: tt)* ) -> $result: tt <$out: ty, Error>;
			)*
		}
	) => {
		$(#[$t_attr])*
		pub trait $name: Sized + Send + Sync + 'static {
			$(
				$(#[doc=$m_doc])*
				fn $m_name ( $($p)* ) -> $result<$out, Error> ;
			)*

			/// Transform this into an `IoDelegate`, automatically wrapping
			/// the parameters.
			fn to_delegate<M: ::jsonrpc_core::Metadata>(self) -> $crate::delegates::IoDelegate<Self, M> {
				let mut del = $crate::delegates::IoDelegate::new(self.into());
				$(
					build_rpc_trait!(WRAP del =>
						( $($t)* )
						fn $m_name ( $($p)* ) -> $result <$out, Error>
					);
				)*
				del
			}
		}
	};

	( WRAP $del: expr =>
		(name = $name: expr)
		fn $method: ident (&self $(, $param: ty)*) -> $result: tt <$out: ty, Error>
	) => {
		$del.add_method($name, move |base, params| {
			$crate::Wrap::wrap_rpc(&(Self::$method as fn(&_ $(, $param)*) -> $result <$out, Error>), base, params)
		})
	};

	( WRAP $del: expr =>
		(async, name = $name: expr)
		fn $method: ident (&self $(, $param: ty)*) -> $result: tt <$out: ty, Error>
	) => {
		$del.add_async_method($name, move |base, params| {
			$crate::WrapAsync::wrap_rpc(&(Self::$method as fn(&_ $(, $param)*) -> $result <$out, Error>), base, params)
		})
	};
}

/// A wrapper type without an implementation of `Deserialize`
/// which allows a special implementation of `Wrap` for functions
/// that take a trailing default parameter.
pub struct Trailing<T: Default + Deserialize>(pub T);

/// Wrapper trait for synchronous RPC functions.
pub trait Wrap<B: Send + Sync + 'static> {
	fn wrap_rpc(&self, base: &B, params: Params) -> Result<Value, Error>;
}

/// Wrapper trait for asynchronous RPC functions.
pub trait WrapAsync<B: Send + Sync + 'static> {
	fn wrap_rpc(&self, base: &B, params: Params) -> BoxFuture<Value, Error>;
}

// special impl for no parameters.
impl<B, OUT> Wrap<B> for fn(&B) -> Result<OUT, Error>
	where B: Send + Sync + 'static, OUT: Serialize + 'static
{
	fn wrap_rpc(&self, base: &B, params: Params) -> Result<Value, Error> {
		expect_no_params(params)
			.and_then(|()| (self)(base))
			.map(to_value)
	}
}

impl<B, OUT> WrapAsync<B> for fn(&B) -> BoxFuture<OUT, Error>
	where B: Send + Sync + 'static, OUT: Serialize + 'static
{
	fn wrap_rpc(&self, base: &B, params: Params) -> BoxFuture<Value, Error> {
		match expect_no_params(params) {
			Ok(()) => (self)(base).map(to_value).boxed(),
			Err(e) => futures::failed(e).boxed(),
		}
	}
}

// creates a wrapper implementation which deserializes the parameters,
// calls the function with concrete type, and serializes the output.
macro_rules! wrap {
	($($x: ident),+) => {

		// synchronous implementation
		impl <
			BASE: Send + Sync + 'static,
			OUT: Serialize + 'static,
			$($x: Deserialize,)+
		> Wrap<BASE> for fn(&BASE, $($x,)+) -> Result<OUT, Error> {
			fn wrap_rpc(&self, base: &BASE, params: Params) -> Result<Value, Error> {
				params.parse::<($($x,)+)>().and_then(|($($x,)+)| {
					(self)(base, $($x,)+)
				}).map(to_value)
			}
		}

		// asynchronous implementation
		impl <
			BASE: Send + Sync + 'static,
			OUT: Serialize + 'static,
			$($x: Deserialize,)+
		> WrapAsync<BASE> for fn(&BASE, $($x,)+ ) -> BoxFuture<OUT, Error> {
			fn wrap_rpc(&self, base: &BASE, params: Params) -> BoxFuture<Value, Error> {
				match params.parse::<($($x,)+)>() {
					Ok(($($x,)+)) => (self)(base, $($x,)+).map(to_value).boxed(),
					Err(e) => futures::failed(e).boxed(),
				}
			}
		}
	}
}

// special impl for no parameters other than block parameter.
impl<B, OUT, T> Wrap<B> for fn(&B, Trailing<T>) -> Result<OUT, Error>
	where B: Send + Sync + 'static, OUT: Serialize + 'static, T: Default + Deserialize
{
	fn wrap_rpc(&self, base: &B, params: Params) -> Result<Value, Error> {
		let len = match params {
			Params::Array(ref v) => v.len(),
			Params::None => 0,
			_ => return Err(invalid_params("not an array", "")),
		};

		let (id,) = match len {
			0 => (T::default(),),
			1 => try!(params.parse::<(T,)>()),
			_ => return Err(Error::invalid_params()),
		};

		(self)(base, Trailing(id)).map(to_value)
	}
}

impl<B, OUT, T> WrapAsync<B> for fn(&B, Trailing<T>) -> BoxFuture<OUT, Error>
	where B: Send + Sync + 'static, OUT: Serialize + 'static, T: Default + Deserialize
{
	fn wrap_rpc(&self, base: &B, params: Params) -> BoxFuture<Value, Error> {
		let len = match params {
			Params::Array(ref v) => v.len(),
			Params::None => 0,
			_ => return futures::failed(invalid_params("not an array", "")).boxed(),
		};

		let id = match len {
			0 => Ok((T::default(),)),
			1 => params.parse::<(T,)>(),
			_ => Err(Error::invalid_params()),
		};

		match id {
			Ok((id,)) => (self)(base, Trailing(id)).map(to_value).boxed(),
			Err(e) => futures::failed(e).boxed(),
		}
	}
}

// similar to `wrap!`, but handles a single default trailing parameter
// accepts an additional argument indicating the number of non-trailing parameters.
macro_rules! wrap_with_trailing {
	($num: expr, $($x: ident),+) => {
		// synchronous implementation
		impl <
			BASE: Send + Sync + 'static,
			OUT: Serialize + 'static,
			$($x: Deserialize,)+
			TRAILING: Default + Deserialize,
		> Wrap<BASE> for fn(&BASE, $($x,)+ Trailing<TRAILING>) -> Result<OUT, Error> {
			fn wrap_rpc(&self, base: &BASE, params: Params) -> Result<Value, Error> {
				let len = match params {
					Params::Array(ref v) => v.len(),
					Params::None => 0,
					_ => return Err(invalid_params("not an array", "")),
				};

				let params = match len - $num {
					0 => params.parse::<($($x,)+)>()
						.map(|($($x,)+)| ($($x,)+ TRAILING::default())),
					1 => params.parse::<($($x,)+ TRAILING)>()
						.map(|($($x,)+ id)| ($($x,)+ id)),
					_ => Err(Error::invalid_params()),
				};

				let ($($x,)+ id) = try!(params);
				(self)(base, $($x,)+ Trailing(id)).map(to_value)
			}
		}

		// asynchronous implementation
		impl <
			BASE: Send + Sync + 'static,
			OUT: Serialize + 'static,
			$($x: Deserialize,)+
			TRAILING: Default + Deserialize,
		> WrapAsync<BASE> for fn(&BASE, $($x,)+ Trailing<TRAILING>) -> BoxFuture<OUT, Error> {
			fn wrap_rpc(&self, base: &BASE, params: Params) -> BoxFuture<Value, Error> {
				let len = match params {
					Params::Array(ref v) => v.len(),
					Params::None => 0,
					_ => return futures::failed(invalid_params("not an array", "")).boxed(),
				};

				let params = match len - $num {
					0 => params.parse::<($($x,)+)>()
						.map(|($($x,)+)| ($($x,)+ TRAILING::default())),
					1 => params.parse::<($($x,)+ TRAILING)>()
						.map(|($($x,)+ id)| ($($x,)+ id)),
					_ => Err(Error::invalid_params()),
				};

				match params {
					Ok(($($x,)+ id)) => (self)(base, $($x,)+ Trailing(id)).map(to_value).boxed(),
					Err(e) => futures::failed(e).boxed(),
				}
			}
		}
	}
}

wrap!(A, B, C, D, E);
wrap!(A, B, C, D);
wrap!(A, B, C);
wrap!(A, B);
wrap!(A);

wrap_with_trailing!(5, A, B, C, D, E);
wrap_with_trailing!(4, A, B, C, D);
wrap_with_trailing!(3, A, B, C);
wrap_with_trailing!(2, A, B);
wrap_with_trailing!(1, A);

<|endoftext|>