<commit_before>use hyper::{Decoder, Encoder, Next, StatusCode};
use hyper::net::HttpStream;
use hyper::server::{Handler, Server, Request, Response};
use rustc_serialize::{json, Decodable, Encodable};
use std::{env, io, mem, thread};
use std::fmt::Debug;
use std::io::{ErrorKind, Write};
use std::sync::{Arc, Mutex, mpsc};
use std::sync::mpsc::{Sender, Receiver};
use std::time::Duration;

use super::gateway::{Gateway, Interpret};

pub struct Http<C: Clone, E: Clone> {
    irx: Arc<Mutex<Receiver<Interpret<C, E>>>>,
}

impl<C, E> Gateway<C, E> for Http<C, E>
    where C: Decodable + Send + Clone + Debug + 'static,
          E: Encodable + Send + Clone + 'static
{
    fn new() -> Http<C, E> {
        let (itx, irx): (Sender<Interpret<C, E>>, Receiver<Interpret<C, E>>) = mpsc::channel();
        let itx = Arc::new(Mutex::new(itx));
        let irx = Arc::new(Mutex::new(irx));

        let addr = env::var("OTA_PLUS_CLIENT_HTTP_ADDR").unwrap_or("127.0.0.1:8888".to_string());
        let server = Server::http(&addr.parse().unwrap()).unwrap();
        let (addr, server) = server.handle(move |_| HttpHandler::new(itx.clone())).unwrap();

        thread::spawn(move || { server.run() });
        info!("Listening on http://{}", addr);

        Http { irx: irx }
    }

    fn next(&self) -> Option<Interpret<C, E>> {
        match self.irx.lock().unwrap().recv() {
            Ok(i)    => Some(i),
            Err(err) => {
                error!("Error forwarding request: {}", err);
                None
            }
        }
    }
}

pub struct HttpHandler<C, E>
    where C: Decodable + Send + Clone + Debug,
          E: Encodable + Send + Clone
{
    itx:       Arc<Mutex<Sender<Interpret<C, E>>>>,
    erx:       Option<Receiver<E>>,
    req_body:  Vec<u8>,
    resp_body: Option<Vec<u8>>,
    written:   usize,
}

impl<C, E> HttpHandler<C, E>
    where C: Decodable + Send + Clone + Debug,
          E: Encodable + Send + Clone
{
    fn new(itx: Arc<Mutex<Sender<Interpret<C, E>>>>) -> HttpHandler<C, E> {
        HttpHandler {
            itx:       itx,
            erx:       None,
            req_body:  Vec::new(),
            resp_body: None,
            written:   0
        }
    }

    fn decode_request(&mut self) -> Next {
        let body = mem::replace(&mut self.req_body, Vec::new());

        match String::from_utf8(body) {
            Ok(body) => match json::decode::<C>(&body) {
                Ok(c) => {
                    info!("on_request_readable: decoded command: {:?}", c);

                    let (etx, erx): (Sender<E>, Receiver<E>) = mpsc::channel();
                    self.erx = Some(erx);
                    self.itx.lock().unwrap().send(Interpret {
                        cmd: c,
                        etx: Some(Arc::new(Mutex::new(etx))),
                    }).unwrap();

                    Next::write().timeout(Duration::from_secs(20))
                }

                Err(err) => {
                    error!("decode_request: parse json: {}", err);
                    Next::remove()
                }
            },

            Err(err) => {
                error!("decode_request: parse string: {}", err);
                Next::remove()
            }
        }
    }
}

impl<C, E> Handler<HttpStream> for HttpHandler<C, E>
    where C: Send + Decodable + Clone + Debug,
          E: Send + Encodable + Clone
{
    fn on_request(&mut self, req: Request) -> Next {
        info!("on_request: {} {}", req.method(), req.uri());
        Next::read()
    }

    fn on_request_readable(&mut self, transport: &mut Decoder<HttpStream>) -> Next {
        match io::copy(transport, &mut self.req_body) {
            Ok(0) => {
                debug!("on_request_readable bytes read: {:?}", self.req_body.len());
                self.decode_request()
            }

            Ok(n) => {
                trace!("{} more request bytes read", n);
                Next::read()
            }

            Err(ref err) if err.kind() == ErrorKind::WouldBlock => {
                trace!("retry on_request_readable");
                Next::read()
            }

            Err(err) => {
                error!("unable to read request body: {}", err);
                Next::remove()
            }
        }
    }

    fn on_response(&mut self, resp: &mut Response) -> Next {
        info!("on_response: status {}", resp.status());
        let rx = self.erx.as_ref().expect("Some receiver expected");

        match rx.recv() {
            Ok(e) => match json::encode(&e) {
                Ok(body) => {
                    resp.set_status(StatusCode::Ok);
                    self.resp_body = Some(body.into_bytes());
                    Next::write()
                }

                Err(err) => {
                    error!("on_response encoding json: {:?}", err);
                    resp.set_status(StatusCode::InternalServerError);
                    Next::end()
                }
            },

            Err(err) => {
                error!("on_response receiver: {}", err);
                resp.set_status(StatusCode::InternalServerError);
                Next::end()
            }
        }
    }

    fn on_response_writable(&mut self, transport: &mut Encoder<HttpStream>) -> Next {
        let body = self.resp_body.as_ref().expect("on_response_writable has empty body");

        match transport.write(&body[self.written..]) {
            Ok(0) => {
                debug!("{} bytes written to response body", self.written);
                Next::end()
            }

            Ok(n) => {
                self.written += n;
                trace!("{} bytes written to response body", n);
                Next::write()
            }

            Err(ref err) if err.kind() == ErrorKind::WouldBlock => {
                trace!("retry on_response_writable");
                Next::write()
            }

            Err(err) => {
                error!("unable to write response body: {}", err);
                Next::remove()
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use crossbeam;
    use rustc_serialize::json;
    use std::thread;
    use std::sync::mpsc::{channel, Sender, Receiver};

    use super::*;
    use super::super::gateway::Gateway;
    use super::super::super::datatype::{Auth, Command, Event, Method, Url};
    use super::super::super::http_client::{AuthClient, HttpClient, HttpRequest};
    use super::super::super::interpreter::Wrapped;

    #[test]
    fn multiple_connections() {
        let (_,   erx): (Sender<Event>,   Receiver<Event>)   = channel();
        let (wtx, wrx): (Sender<Wrapped>, Receiver<Wrapped>) = channel();
        Http::run(wtx, erx);

        thread::spawn(move || {
            loop {
                let w = wrx.recv().unwrap();
                match w.cmd {
                    Command::AcceptUpdate(id) => {
                        let ev = Event::Error(id);
                        match w.etx {
                            Some(etx) => etx.lock().unwrap().send(ev).unwrap(),
                            None      => panic!("expected transmitter"),
                        }
                    }
                    _ => panic!("expected AcceptUpdate"),
                }
            }
        });

        // wait for all scoped threads to complete
        crossbeam::scope(|scope| {
            for id in 0..10 {
                scope.spawn(move || {
                    let client   = AuthClient::new(Auth::None);
                    let cmd      = Command::AcceptUpdate(format!("{}", id));
                    let req_body = json::encode(&cmd).unwrap();

                    let req = HttpRequest {
                        method: Method::Post,
                        url:    Url::parse("http://127.0.0.1:8888").unwrap(),
                        body:   Some(req_body.into_bytes()),
                    };
                    let resp_rx = client.send_request(req);
                    let resp    = resp_rx.recv().unwrap().unwrap();

                    let text      = String::from_utf8(resp).unwrap();
                    let ev: Event = json::decode(&text).unwrap();
                    assert_eq!(ev, Event::Error(format!("{}", id)));
                });
            }
        });
    }
}
<commit_msg>Set ContentType Header on HTTP Server 200 Response<commit_after>use hyper::{Decoder, Encoder, Next, StatusCode};
use hyper::header::ContentType;
use hyper::mime::{Attr, Mime, TopLevel, SubLevel, Value};
use hyper::net::HttpStream;
use hyper::server::{Handler, Server, Request, Response};
use rustc_serialize::{json, Decodable, Encodable};
use std::{env, io, mem, thread};
use std::fmt::Debug;
use std::io::{ErrorKind, Write};
use std::sync::{Arc, Mutex, mpsc};
use std::sync::mpsc::{Sender, Receiver};
use std::time::Duration;

use super::gateway::{Gateway, Interpret};

pub struct Http<C: Clone, E: Clone> {
    irx: Arc<Mutex<Receiver<Interpret<C, E>>>>,
}

impl<C, E> Gateway<C, E> for Http<C, E>
    where C: Decodable + Send + Clone + Debug + 'static,
          E: Encodable + Send + Clone + 'static
{
    fn new() -> Http<C, E> {
        let (itx, irx): (Sender<Interpret<C, E>>, Receiver<Interpret<C, E>>) = mpsc::channel();
        let itx = Arc::new(Mutex::new(itx));
        let irx = Arc::new(Mutex::new(irx));

        let addr = env::var("OTA_PLUS_CLIENT_HTTP_ADDR").unwrap_or("127.0.0.1:8888".to_string());
        let server = Server::http(&addr.parse().unwrap()).unwrap();
        let (addr, server) = server.handle(move |_| HttpHandler::new(itx.clone())).unwrap();

        thread::spawn(move || { server.run() });
        info!("Listening on http://{}", addr);

        Http { irx: irx }
    }

    fn next(&self) -> Option<Interpret<C, E>> {
        match self.irx.lock().unwrap().recv() {
            Ok(i)    => Some(i),
            Err(err) => {
                error!("Error forwarding request: {}", err);
                None
            }
        }
    }
}

pub struct HttpHandler<C, E>
    where C: Decodable + Send + Clone + Debug,
          E: Encodable + Send + Clone
{
    itx:       Arc<Mutex<Sender<Interpret<C, E>>>>,
    erx:       Option<Receiver<E>>,
    req_body:  Vec<u8>,
    resp_body: Option<Vec<u8>>,
    written:   usize,
}

impl<C, E> HttpHandler<C, E>
    where C: Decodable + Send + Clone + Debug,
          E: Encodable + Send + Clone
{
    fn new(itx: Arc<Mutex<Sender<Interpret<C, E>>>>) -> HttpHandler<C, E> {
        HttpHandler {
            itx:       itx,
            erx:       None,
            req_body:  Vec::new(),
            resp_body: None,
            written:   0
        }
    }

    fn decode_request(&mut self) -> Next {
        let body = mem::replace(&mut self.req_body, Vec::new());

        match String::from_utf8(body) {
            Ok(body) => match json::decode::<C>(&body) {
                Ok(c) => {
                    info!("on_request_readable: decoded command: {:?}", c);

                    let (etx, erx): (Sender<E>, Receiver<E>) = mpsc::channel();
                    self.erx = Some(erx);
                    self.itx.lock().unwrap().send(Interpret {
                        cmd: c,
                        etx: Some(Arc::new(Mutex::new(etx))),
                    }).unwrap();

                    Next::write().timeout(Duration::from_secs(20))
                }

                Err(err) => {
                    error!("decode_request: parse json: {}", err);
                    Next::remove()
                }
            },

            Err(err) => {
                error!("decode_request: parse string: {}", err);
                Next::remove()
            }
        }
    }
}

impl<C, E> Handler<HttpStream> for HttpHandler<C, E>
    where C: Send + Decodable + Clone + Debug,
          E: Send + Encodable + Clone
{
    fn on_request(&mut self, req: Request) -> Next {
        info!("on_request: {} {}", req.method(), req.uri());
        Next::read()
    }

    fn on_request_readable(&mut self, transport: &mut Decoder<HttpStream>) -> Next {
        match io::copy(transport, &mut self.req_body) {
            Ok(0) => {
                debug!("on_request_readable bytes read: {:?}", self.req_body.len());
                self.decode_request()
            }

            Ok(n) => {
                trace!("{} more request bytes read", n);
                Next::read()
            }

            Err(ref err) if err.kind() == ErrorKind::WouldBlock => {
                trace!("retry on_request_readable");
                Next::read()
            }

            Err(err) => {
                error!("unable to read request body: {}", err);
                Next::remove()
            }
        }
    }

    fn on_response(&mut self, resp: &mut Response) -> Next {
        info!("on_response: status {}", resp.status());
        let rx = self.erx.as_ref().expect("Some receiver expected");

        match rx.recv() {
            Ok(e) => match json::encode(&e) {
                Ok(body) => {
                    resp.set_status(StatusCode::Ok);
                    resp.headers_mut().set(ContentType(Mime(TopLevel::Application, SubLevel::Json,
                                                            vec![(Attr::Charset, Value::Utf8)])));
                    self.resp_body = Some(body.into_bytes());
                    Next::write()
                }

                Err(err) => {
                    error!("on_response encoding json: {:?}", err);
                    resp.set_status(StatusCode::InternalServerError);
                    Next::end()
                }
            },

            Err(err) => {
                error!("on_response receiver: {}", err);
                resp.set_status(StatusCode::InternalServerError);
                Next::end()
            }
        }
    }

    fn on_response_writable(&mut self, transport: &mut Encoder<HttpStream>) -> Next {
        let body = self.resp_body.as_ref().expect("on_response_writable has empty body");

        match transport.write(&body[self.written..]) {
            Ok(0) => {
                debug!("{} bytes written to response body", self.written);
                Next::end()
            }

            Ok(n) => {
                self.written += n;
                trace!("{} bytes written to response body", n);
                Next::write()
            }

            Err(ref err) if err.kind() == ErrorKind::WouldBlock => {
                trace!("retry on_response_writable");
                Next::write()
            }

            Err(err) => {
                error!("unable to write response body: {}", err);
                Next::remove()
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use crossbeam;
    use rustc_serialize::json;
    use std::thread;
    use std::sync::mpsc::{channel, Sender, Receiver};

    use super::*;
    use super::super::gateway::Gateway;
    use super::super::super::datatype::{Auth, Command, Event, Method, Url};
    use super::super::super::http_client::{AuthClient, HttpClient, HttpRequest};
    use super::super::super::interpreter::Wrapped;

    #[test]
    fn multiple_connections() {
        let (_,   erx): (Sender<Event>,   Receiver<Event>)   = channel();
        let (wtx, wrx): (Sender<Wrapped>, Receiver<Wrapped>) = channel();
        Http::run(wtx, erx);

        thread::spawn(move || {
            loop {
                let w = wrx.recv().unwrap();
                match w.cmd {
                    Command::AcceptUpdate(id) => {
                        let ev = Event::Error(id);
                        match w.etx {
                            Some(etx) => etx.lock().unwrap().send(ev).unwrap(),
                            None      => panic!("expected transmitter"),
                        }
                    }
                    _ => panic!("expected AcceptUpdate"),
                }
            }
        });

        // wait for all scoped threads to complete
        crossbeam::scope(|scope| {
            for id in 0..10 {
                scope.spawn(move || {
                    let client   = AuthClient::new(Auth::None);
                    let cmd      = Command::AcceptUpdate(format!("{}", id));
                    let req_body = json::encode(&cmd).unwrap();

                    let req = HttpRequest {
                        method: Method::Post,
                        url:    Url::parse("http://127.0.0.1:8888").unwrap(),
                        body:   Some(req_body.into_bytes()),
                    };
                    let resp_rx = client.send_request(req);
                    let resp    = resp_rx.recv().unwrap().unwrap();

                    let text      = String::from_utf8(resp).unwrap();
                    let ev: Event = json::decode(&text).unwrap();
                    assert_eq!(ev, Event::Error(format!("{}", id)));
                });
            }
        });
    }
}
<|endoftext|>


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

//! An implementation of the [Cap'n Proto remote procedure call](https://capnproto.org/rpc.html)
//! protocol. Includes all [Level 1](https://capnproto.org/rpc.html#protocol-features) features.
//!
//! # Example
//!
//! ```capnp
//! # Cap'n Proto schema
//! interface Foo {
//!     identity @0 (x: UInt32) -> (y: UInt32);
//! }
//! ```
//!
//! ```ignore
//! // Rust server defining an implementation of Foo.
//! struct FooImpl;
//! impl foo::Server for FooImpl {
//!     fn identity(&mut self,
//!                 params: foo::IdentityParams,
//!                 mut results: foo::IdentityResults)
//!                 -> Promise<(), ::capnp::Error>
//!     {
//!         let x = pry!(params.get()).get_x();
//!         results.get().set_y(x);
//!         Promise::ok(())
//!     }
//! }
//! ```
//!
//! ```ignore
//! // Rust client calling a remote implementation of Foo.
//! let mut request = foo_client.identity_request();
//! request.get().set_x(123);
//! let promise = request.send().promise.and_then(|response| {
//!     println!("results = {}", response.get()?.get_y());
//!     Ok(())
//! });
//! ```
//!
//! For a more complete example, see https://github.com/capnproto/capnproto-rust/tree/master/capnp-rpc/examples/calculator

use std::pin::Pin;
use std::task::{Context, Poll};
use futures::{Future, FutureExt, TryFutureExt};
use futures::channel::oneshot;
use capnp::Error;
use capnp::capability::Promise;
use capnp::private::capability::{ClientHook};
use std::cell::{RefCell};
use std::rc::{Rc};

use crate::task_set::TaskSet;
pub use crate::rpc::Disconnector;

/// Code generated from [rpc.capnp]
/// (https://github.com/sandstorm-io/capnproto/blob/master/c%2B%2B/src/capnp/rpc.capnp).
pub mod rpc_capnp;

/// Code generated from [rpc-twoparty.capnp]
/// (https://github.com/sandstorm-io/capnproto/blob/master/c%2B%2B/src/capnp/rpc-twoparty.capnp).
pub mod rpc_twoparty_capnp;

/// Like `try!()`, but for functions that return a `Promise<T, E>` rather than a `Result<T, E>`.
///
/// Unwraps a `Result<T, E>`. In the case of an error `Err(e)`, immediately returns from the
/// enclosing function with `Promise::err(e)`.
#[macro_export]
macro_rules! pry {
    ($expr:expr) => (
        match $expr {
            ::std::result::Result::Ok(val) => val,
            ::std::result::Result::Err(err) => {
                return ::capnp::capability::Promise::err(::std::convert::From::from(err))
            }
        })
}

mod broken;
mod local;
mod queued;
mod rpc;
mod attach;
mod sender_queue;
mod split;
mod task_set;
pub mod twoparty;

pub trait OutgoingMessage {
    fn get_body<'a>(&'a mut self) -> ::capnp::Result<::capnp::any_pointer::Builder<'a>>;
    fn get_body_as_reader<'a>(&'a self) -> ::capnp::Result<::capnp::any_pointer::Reader<'a>>;

    /// Sends the message. Returns a promise for the message that resolves once the send has completed.
    /// Dropping the returned promise does *not* cancel the send.
    fn send(self: Box<Self>)
            -> (Promise<Rc<::capnp::message::Builder<::capnp::message::HeapAllocator>>, ::capnp::Error>,
                Rc<::capnp::message::Builder<::capnp::message::HeapAllocator>>);

    fn take(self: Box<Self>) -> ::capnp::message::Builder<::capnp::message::HeapAllocator>;
}

pub trait IncomingMessage {
    fn get_body<'a>(&'a self) -> ::capnp::Result<::capnp::any_pointer::Reader<'a>>;
}

pub trait Connection<VatId> {
    fn get_peer_vat_id(&self) -> VatId;
    fn new_outgoing_message(&mut self, first_segment_word_size: u32) -> Box<dyn OutgoingMessage>;

    /// Waits for a message to be received and returns it.  If the read stream cleanly terminates,
    /// returns None. If any other problem occurs, returns an Error.
    fn receive_incoming_message(&mut self) -> Promise<Option<Box<dyn IncomingMessage>>, Error>;

    // Waits until all outgoing messages have been sent, then shuts down the outgoing stream. The
    // returned promise resolves after shutdown is complete.
    fn shutdown(&mut self, result: ::capnp::Result<()>) -> Promise<(), Error>;
}

pub trait VatNetwork<VatId> {
    /// Returns None if `hostId` refers to the local vat.
    fn connect(&mut self, host_id: VatId) -> Option<Box<dyn Connection<VatId>>>;

    /// Waits for the next incoming connection and return it.
    fn accept(&mut self) -> Promise<Box<dyn Connection<VatId>>, ::capnp::Error>;

    fn drive_until_shutdown(&mut self) -> Promise<(), Error>;
}

/// A portal to objects available on the network.
///
/// The RPC implemententation sits on top of an implementation of `VatNetwork`, which
/// determines how to form connections between vats. The RPC implementation determines
/// how to use such connections to manage object references and make method calls.
///
/// At the moment, this is all rather more general than it needs to be, because the only
/// implementation of `VatNetwork` is `twoparty::VatNetwork`. However, eventually we
/// will need to have more sophisticated `VatNetwork` implementations, in order to support
/// [level 3](https://capnproto.org/rpc.html#protocol-features) features.
///
/// An `RpcSystem` is a `Future` and needs to be driven by a task executor. A common way
/// accomplish that is to pass the `RpcSystem` to `tokio_core::reactor::Handle::spawn()`.
#[must_use = "futures do nothing unless polled"]
pub struct RpcSystem<VatId> where VatId: 'static {
    network: Box<dyn crate::VatNetwork<VatId>>,

    bootstrap_cap: Box<dyn ClientHook>,

    // XXX To handle three or more party networks, this should be a map from connection pointers
    // to connection states.
    connection_state: Rc<RefCell<Option<Rc<rpc::ConnectionState<VatId>>>>>,

    tasks: TaskSet<Error>,
    handle: crate::task_set::TaskSetHandle<Error>
}

impl <VatId> RpcSystem <VatId> {
    /// Constructs a new `RpcSystem` with the given network and bootstrap capability.
    pub fn new(
        mut network: Box<dyn crate::VatNetwork<VatId>>,
        bootstrap: Option<::capnp::capability::Client>) -> RpcSystem<VatId>
    {
        let bootstrap_cap = match bootstrap {
            Some(cap) => cap.hook,
            None => broken::new_cap(Error::failed("no bootstrap capability".to_string())),
        };
        let (mut handle, tasks) = TaskSet::new(Box::new(SystemTaskReaper));

        let mut handle1 = handle.clone();
        handle.add(network.drive_until_shutdown().then(move |r| {
            let r = match r {
                Ok(()) => Ok(()),
                Err(e) => {
                    if e.kind != ::capnp::ErrorKind::Disconnected {
                        // Don't report disconnects as an error.
                        Err(e)
                    } else {
                        Ok(())
                    }
                }
            };

            handle1.terminate(r);
            Promise::ok(())
        }));

        let mut result = RpcSystem {
            network: network,
            bootstrap_cap: bootstrap_cap,
            connection_state: Rc::new(RefCell::new(None)),

            tasks: tasks,
            handle: handle.clone(),
        };

        let accept_loop = result.accept_loop();
        handle.add(accept_loop);
        result
    }

    /// Connects to the given vat and returns its bootstrap interface.
    pub fn bootstrap<T>(&mut self, vat_id: VatId) -> T
        where T: ::capnp::capability::FromClientHook
    {
        let connection = match self.network.connect(vat_id) {
            Some(connection) => connection,
            None => {
                return T::new(self.bootstrap_cap.clone());
            }
        };
        let connection_state =
            RpcSystem::get_connection_state(self.connection_state.clone(),
                                            self.bootstrap_cap.clone(),
                                            connection, self.handle.clone());

        let hook = rpc::ConnectionState::bootstrap(connection_state.clone());
        T::new(hook)
    }

    // not really a loop, because it doesn't need to be for the two party case
    fn accept_loop(&mut self) -> Promise<(), Error> {
        let connection_state_ref = self.connection_state.clone();
        let bootstrap_cap = self.bootstrap_cap.clone();
        let handle = self.handle.clone();
        Promise::from_future(self.network.accept().map_ok(move |connection| {
            RpcSystem::get_connection_state(connection_state_ref,
                                            bootstrap_cap,
                                            connection,
                                            handle);
        }))
    }

    // If `connection_state_ref` is not already populated, populates it with a new
    // `ConnectionState` built from a local bootstrap capability and `connection`,
    // spawning any background tasks onto `handle`. Returns the resulting value
    // held in `connection_state_ref`.
    fn get_connection_state(connection_state_ref: Rc<RefCell<Option<Rc<rpc::ConnectionState<VatId>>>>>,
                            bootstrap_cap: Box<dyn ClientHook>,
                            connection: Box<dyn crate::Connection<VatId>>,
                            mut handle: crate::task_set::TaskSetHandle<Error>)
                            -> Rc<rpc::ConnectionState<VatId>>
    {
        // TODO this needs to be updated once we allow more general VatNetworks.
        let (tasks, result) = match *connection_state_ref.borrow() {
            Some(ref connection_state) => {
                // return early.
                return connection_state.clone()
            }
            None => {
                let (on_disconnect_fulfiller, on_disconnect_promise) =
                    oneshot::channel::<Promise<(), Error>>();
                let connection_state_ref1 = connection_state_ref.clone();
                handle.add(on_disconnect_promise.then(move |shutdown_promise| {
                    *connection_state_ref1.borrow_mut() = None;
                    match shutdown_promise {
                        Ok(s) => s,
                        Err(e) => Promise::err(Error::failed(format!("{}", e))),
                    }
                }));
                rpc::ConnectionState::new(bootstrap_cap, connection, on_disconnect_fulfiller)
            }
        };
        *connection_state_ref.borrow_mut() = Some(result.clone());
        handle.add(tasks);
        result
    }

    /// Returns a `Disconnector` future that can be run to cleanly close the connection to this `RpcSystem`'s network.
    /// You should get the `Disconnector` before you spawn the `RpcSystem`.
    pub fn get_disconnector(&self) -> rpc::Disconnector<VatId> {
        rpc::Disconnector::new(self.connection_state.clone())
    }
}

impl <VatId> Future for RpcSystem<VatId> where VatId: 'static {
    type Output = Result<(),Error>;
    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
        Pin::new(&mut self.tasks).poll(cx)
    }
}

/// Creates a new local RPC client of type `C` out of an object that implements a server trait `S`.
pub fn new_client<C, S>(s: S) -> C where C: capnp::capability::FromServer<S> {
    capnp::capability::FromClientHook::new(Box::new(
        local::Client::new(Box::new(<C as capnp::capability::FromServer::<S>>::from_server(s)))))
}

/// Converts a promise for a client into a client that queues up any calls that arrive
/// before the promise resolves.
// TODO: figure out a better way to allow construction of promise clients.
pub fn new_promise_client<T, F>(client_promise: F) -> T
    where T: ::capnp::capability::FromClientHook,
          F: ::futures::Future<Output=Result<capnp::capability::Client,Error>>,
          F: 'static + Unpin
{
    let mut queued_client = crate::queued::Client::new(None);
    let weak_client = Rc::downgrade(&queued_client.inner);

    queued_client.drive(client_promise.then(move |r| {
        if let Some(queued_inner) = weak_client.upgrade() {
            crate::queued::ClientInner::resolve(&queued_inner, r.map(|c| c.hook));
        }
        Promise::ok(())
    }));

    T::new(Box::new(queued_client))
}

struct SystemTaskReaper;
impl crate::task_set::TaskReaper<Error> for SystemTaskReaper {
    fn task_failed(&mut self, error: Error) {
        println!("ERROR: {}", error);
    }
}

pub struct ImbuedMessageBuilder<A> where A: ::capnp::message::Allocator {
    builder: ::capnp::message::Builder<A>,
    cap_table: Vec<Option<Box<dyn (::capnp::private::capability::ClientHook)>>>,
}

impl <A> ImbuedMessageBuilder<A> where A: ::capnp::message::Allocator {
    pub fn new(allocator: A) -> Self {
        ImbuedMessageBuilder {
            builder: ::capnp::message::Builder::new(allocator),
            cap_table: Vec::new(),
        }
    }

    pub fn get_root<'a, T>(&'a mut self) -> ::capnp::Result<T>
        where T: ::capnp::traits::FromPointerBuilder<'a>
    {
        use capnp::traits::ImbueMut;
        let mut root: ::capnp::any_pointer::Builder = self.builder.get_root()?;
        root.imbue_mut(&mut self.cap_table);
        root.get_as()
    }

    pub fn set_root<From>(&mut self, value: From) -> ::capnp::Result<()>
        where From: ::capnp::traits::SetPointerBuilder
    {
        use capnp::traits::ImbueMut;
        let mut root: ::capnp::any_pointer::Builder = self.builder.get_root()?;
        root.imbue_mut(&mut self.cap_table);
        root.set_as(value)
    }
}

fn canceled_to_error(_e: futures::channel::oneshot::Canceled) -> Error {
        Error::failed(format!("oneshot was canceled"))
}
<commit_msg>Fix broken link syntax in documentation<commit_after>// Copyright (c) 2013-2017 Sandstorm Development Group, Inc. and contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! An implementation of the [Cap'n Proto remote procedure call](https://capnproto.org/rpc.html)
//! protocol. Includes all [Level 1](https://capnproto.org/rpc.html#protocol-features) features.
//!
//! # Example
//!
//! ```capnp
//! # Cap'n Proto schema
//! interface Foo {
//!     identity @0 (x: UInt32) -> (y: UInt32);
//! }
//! ```
//!
//! ```ignore
//! // Rust server defining an implementation of Foo.
//! struct FooImpl;
//! impl foo::Server for FooImpl {
//!     fn identity(&mut self,
//!                 params: foo::IdentityParams,
//!                 mut results: foo::IdentityResults)
//!                 -> Promise<(), ::capnp::Error>
//!     {
//!         let x = pry!(params.get()).get_x();
//!         results.get().set_y(x);
//!         Promise::ok(())
//!     }
//! }
//! ```
//!
//! ```ignore
//! // Rust client calling a remote implementation of Foo.
//! let mut request = foo_client.identity_request();
//! request.get().set_x(123);
//! let promise = request.send().promise.and_then(|response| {
//!     println!("results = {}", response.get()?.get_y());
//!     Ok(())
//! });
//! ```
//!
//! For a more complete example, see https://github.com/capnproto/capnproto-rust/tree/master/capnp-rpc/examples/calculator

use std::pin::Pin;
use std::task::{Context, Poll};
use futures::{Future, FutureExt, TryFutureExt};
use futures::channel::oneshot;
use capnp::Error;
use capnp::capability::Promise;
use capnp::private::capability::{ClientHook};
use std::cell::{RefCell};
use std::rc::{Rc};

use crate::task_set::TaskSet;
pub use crate::rpc::Disconnector;

/// Code generated from
/// [rpc.capnp](https://github.com/sandstorm-io/capnproto/blob/master/c%2B%2B/src/capnp/rpc.capnp).
pub mod rpc_capnp;

/// Code generated from
/// [rpc-twoparty.capnp](https://github.com/sandstorm-io/capnproto/blob/master/c%2B%2B/src/capnp/rpc-twoparty.capnp).
pub mod rpc_twoparty_capnp;

/// Like `try!()`, but for functions that return a `Promise<T, E>` rather than a `Result<T, E>`.
///
/// Unwraps a `Result<T, E>`. In the case of an error `Err(e)`, immediately returns from the
/// enclosing function with `Promise::err(e)`.
#[macro_export]
macro_rules! pry {
    ($expr:expr) => (
        match $expr {
            ::std::result::Result::Ok(val) => val,
            ::std::result::Result::Err(err) => {
                return ::capnp::capability::Promise::err(::std::convert::From::from(err))
            }
        })
}

mod broken;
mod local;
mod queued;
mod rpc;
mod attach;
mod sender_queue;
mod split;
mod task_set;
pub mod twoparty;

pub trait OutgoingMessage {
    fn get_body<'a>(&'a mut self) -> ::capnp::Result<::capnp::any_pointer::Builder<'a>>;
    fn get_body_as_reader<'a>(&'a self) -> ::capnp::Result<::capnp::any_pointer::Reader<'a>>;

    /// Sends the message. Returns a promise for the message that resolves once the send has completed.
    /// Dropping the returned promise does *not* cancel the send.
    fn send(self: Box<Self>)
            -> (Promise<Rc<::capnp::message::Builder<::capnp::message::HeapAllocator>>, ::capnp::Error>,
                Rc<::capnp::message::Builder<::capnp::message::HeapAllocator>>);

    fn take(self: Box<Self>) -> ::capnp::message::Builder<::capnp::message::HeapAllocator>;
}

pub trait IncomingMessage {
    fn get_body<'a>(&'a self) -> ::capnp::Result<::capnp::any_pointer::Reader<'a>>;
}

pub trait Connection<VatId> {
    fn get_peer_vat_id(&self) -> VatId;
    fn new_outgoing_message(&mut self, first_segment_word_size: u32) -> Box<dyn OutgoingMessage>;

    /// Waits for a message to be received and returns it.  If the read stream cleanly terminates,
    /// returns None. If any other problem occurs, returns an Error.
    fn receive_incoming_message(&mut self) -> Promise<Option<Box<dyn IncomingMessage>>, Error>;

    // Waits until all outgoing messages have been sent, then shuts down the outgoing stream. The
    // returned promise resolves after shutdown is complete.
    fn shutdown(&mut self, result: ::capnp::Result<()>) -> Promise<(), Error>;
}

pub trait VatNetwork<VatId> {
    /// Returns None if `hostId` refers to the local vat.
    fn connect(&mut self, host_id: VatId) -> Option<Box<dyn Connection<VatId>>>;

    /// Waits for the next incoming connection and return it.
    fn accept(&mut self) -> Promise<Box<dyn Connection<VatId>>, ::capnp::Error>;

    fn drive_until_shutdown(&mut self) -> Promise<(), Error>;
}

/// A portal to objects available on the network.
///
/// The RPC implemententation sits on top of an implementation of `VatNetwork`, which
/// determines how to form connections between vats. The RPC implementation determines
/// how to use such connections to manage object references and make method calls.
///
/// At the moment, this is all rather more general than it needs to be, because the only
/// implementation of `VatNetwork` is `twoparty::VatNetwork`. However, eventually we
/// will need to have more sophisticated `VatNetwork` implementations, in order to support
/// [level 3](https://capnproto.org/rpc.html#protocol-features) features.
///
/// An `RpcSystem` is a `Future` and needs to be driven by a task executor. A common way
/// accomplish that is to pass the `RpcSystem` to `tokio_core::reactor::Handle::spawn()`.
#[must_use = "futures do nothing unless polled"]
pub struct RpcSystem<VatId> where VatId: 'static {
    network: Box<dyn crate::VatNetwork<VatId>>,

    bootstrap_cap: Box<dyn ClientHook>,

    // XXX To handle three or more party networks, this should be a map from connection pointers
    // to connection states.
    connection_state: Rc<RefCell<Option<Rc<rpc::ConnectionState<VatId>>>>>,

    tasks: TaskSet<Error>,
    handle: crate::task_set::TaskSetHandle<Error>
}

impl <VatId> RpcSystem <VatId> {
    /// Constructs a new `RpcSystem` with the given network and bootstrap capability.
    pub fn new(
        mut network: Box<dyn crate::VatNetwork<VatId>>,
        bootstrap: Option<::capnp::capability::Client>) -> RpcSystem<VatId>
    {
        let bootstrap_cap = match bootstrap {
            Some(cap) => cap.hook,
            None => broken::new_cap(Error::failed("no bootstrap capability".to_string())),
        };
        let (mut handle, tasks) = TaskSet::new(Box::new(SystemTaskReaper));

        let mut handle1 = handle.clone();
        handle.add(network.drive_until_shutdown().then(move |r| {
            let r = match r {
                Ok(()) => Ok(()),
                Err(e) => {
                    if e.kind != ::capnp::ErrorKind::Disconnected {
                        // Don't report disconnects as an error.
                        Err(e)
                    } else {
                        Ok(())
                    }
                }
            };

            handle1.terminate(r);
            Promise::ok(())
        }));

        let mut result = RpcSystem {
            network: network,
            bootstrap_cap: bootstrap_cap,
            connection_state: Rc::new(RefCell::new(None)),

            tasks: tasks,
            handle: handle.clone(),
        };

        let accept_loop = result.accept_loop();
        handle.add(accept_loop);
        result
    }

    /// Connects to the given vat and returns its bootstrap interface.
    pub fn bootstrap<T>(&mut self, vat_id: VatId) -> T
        where T: ::capnp::capability::FromClientHook
    {
        let connection = match self.network.connect(vat_id) {
            Some(connection) => connection,
            None => {
                return T::new(self.bootstrap_cap.clone());
            }
        };
        let connection_state =
            RpcSystem::get_connection_state(self.connection_state.clone(),
                                            self.bootstrap_cap.clone(),
                                            connection, self.handle.clone());

        let hook = rpc::ConnectionState::bootstrap(connection_state.clone());
        T::new(hook)
    }

    // not really a loop, because it doesn't need to be for the two party case
    fn accept_loop(&mut self) -> Promise<(), Error> {
        let connection_state_ref = self.connection_state.clone();
        let bootstrap_cap = self.bootstrap_cap.clone();
        let handle = self.handle.clone();
        Promise::from_future(self.network.accept().map_ok(move |connection| {
            RpcSystem::get_connection_state(connection_state_ref,
                                            bootstrap_cap,
                                            connection,
                                            handle);
        }))
    }

    // If `connection_state_ref` is not already populated, populates it with a new
    // `ConnectionState` built from a local bootstrap capability and `connection`,
    // spawning any background tasks onto `handle`. Returns the resulting value
    // held in `connection_state_ref`.
    fn get_connection_state(connection_state_ref: Rc<RefCell<Option<Rc<rpc::ConnectionState<VatId>>>>>,
                            bootstrap_cap: Box<dyn ClientHook>,
                            connection: Box<dyn crate::Connection<VatId>>,
                            mut handle: crate::task_set::TaskSetHandle<Error>)
                            -> Rc<rpc::ConnectionState<VatId>>
    {
        // TODO this needs to be updated once we allow more general VatNetworks.
        let (tasks, result) = match *connection_state_ref.borrow() {
            Some(ref connection_state) => {
                // return early.
                return connection_state.clone()
            }
            None => {
                let (on_disconnect_fulfiller, on_disconnect_promise) =
                    oneshot::channel::<Promise<(), Error>>();
                let connection_state_ref1 = connection_state_ref.clone();
                handle.add(on_disconnect_promise.then(move |shutdown_promise| {
                    *connection_state_ref1.borrow_mut() = None;
                    match shutdown_promise {
                        Ok(s) => s,
                        Err(e) => Promise::err(Error::failed(format!("{}", e))),
                    }
                }));
                rpc::ConnectionState::new(bootstrap_cap, connection, on_disconnect_fulfiller)
            }
        };
        *connection_state_ref.borrow_mut() = Some(result.clone());
        handle.add(tasks);
        result
    }

    /// Returns a `Disconnector` future that can be run to cleanly close the connection to this `RpcSystem`'s network.
    /// You should get the `Disconnector` before you spawn the `RpcSystem`.
    pub fn get_disconnector(&self) -> rpc::Disconnector<VatId> {
        rpc::Disconnector::new(self.connection_state.clone())
    }
}

impl <VatId> Future for RpcSystem<VatId> where VatId: 'static {
    type Output = Result<(),Error>;
    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
        Pin::new(&mut self.tasks).poll(cx)
    }
}

/// Creates a new local RPC client of type `C` out of an object that implements a server trait `S`.
pub fn new_client<C, S>(s: S) -> C where C: capnp::capability::FromServer<S> {
    capnp::capability::FromClientHook::new(Box::new(
        local::Client::new(Box::new(<C as capnp::capability::FromServer::<S>>::from_server(s)))))
}

/// Converts a promise for a client into a client that queues up any calls that arrive
/// before the promise resolves.
// TODO: figure out a better way to allow construction of promise clients.
pub fn new_promise_client<T, F>(client_promise: F) -> T
    where T: ::capnp::capability::FromClientHook,
          F: ::futures::Future<Output=Result<capnp::capability::Client,Error>>,
          F: 'static + Unpin
{
    let mut queued_client = crate::queued::Client::new(None);
    let weak_client = Rc::downgrade(&queued_client.inner);

    queued_client.drive(client_promise.then(move |r| {
        if let Some(queued_inner) = weak_client.upgrade() {
            crate::queued::ClientInner::resolve(&queued_inner, r.map(|c| c.hook));
        }
        Promise::ok(())
    }));

    T::new(Box::new(queued_client))
}

struct SystemTaskReaper;
impl crate::task_set::TaskReaper<Error> for SystemTaskReaper {
    fn task_failed(&mut self, error: Error) {
        println!("ERROR: {}", error);
    }
}

pub struct ImbuedMessageBuilder<A> where A: ::capnp::message::Allocator {
    builder: ::capnp::message::Builder<A>,
    cap_table: Vec<Option<Box<dyn (::capnp::private::capability::ClientHook)>>>,
}

impl <A> ImbuedMessageBuilder<A> where A: ::capnp::message::Allocator {
    pub fn new(allocator: A) -> Self {
        ImbuedMessageBuilder {
            builder: ::capnp::message::Builder::new(allocator),
            cap_table: Vec::new(),
        }
    }

    pub fn get_root<'a, T>(&'a mut self) -> ::capnp::Result<T>
        where T: ::capnp::traits::FromPointerBuilder<'a>
    {
        use capnp::traits::ImbueMut;
        let mut root: ::capnp::any_pointer::Builder = self.builder.get_root()?;
        root.imbue_mut(&mut self.cap_table);
        root.get_as()
    }

    pub fn set_root<From>(&mut self, value: From) -> ::capnp::Result<()>
        where From: ::capnp::traits::SetPointerBuilder
    {
        use capnp::traits::ImbueMut;
        let mut root: ::capnp::any_pointer::Builder = self.builder.get_root()?;
        root.imbue_mut(&mut self.cap_table);
        root.set_as(value)
    }
}

fn canceled_to_error(_e: futures::channel::oneshot::Canceled) -> Error {
        Error::failed(format!("oneshot was canceled"))
}
<|endoftext|>


<commit_before>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! # Translation of inline assembly.

use llvm;
use trans::build::*;
use trans::callee;
use trans::common::*;
use trans::cleanup;
use trans::cleanup::CleanupMethods;
use trans::expr;
use trans::type_of;
use trans::type_::Type;

use std::c_str::ToCStr;
use std::string::String;
use syntax::ast;
use libc::{c_uint, c_char};

// Take an inline assembly expression and splat it out via LLVM
pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
                                    -> Block<'blk, 'tcx> {
    let fcx = bcx.fcx;
    let mut bcx = bcx;
    let mut constraints = Vec::new();
    let mut output_types = Vec::new();

    let temp_scope = fcx.push_custom_cleanup_scope();

    let mut ext_inputs = Vec::new();
    let mut ext_constraints = Vec::new();

    // Prepare the output operands
    let outputs = ia.outputs.iter().enumerate().map(|(i, &(ref c, ref out, is_rw))| {
        constraints.push((*c).clone());

        let out_datum = unpack_datum!(bcx, expr::trans(bcx, &**out));
        output_types.push(type_of::type_of(bcx.ccx(), out_datum.ty));
        let val = out_datum.val;
        if is_rw {
            ext_inputs.push(unpack_result!(bcx, {
                callee::trans_arg_datum(bcx,
                                       expr_ty(bcx, &**out),
                                       out_datum,
                                       cleanup::CustomScope(temp_scope),
                                       callee::DontAutorefArg)
            }));
            ext_constraints.push(i.to_string());
        }
        val

    }).collect::<Vec<_>>();

    // Now the input operands
    let mut inputs = ia.inputs.iter().map(|&(ref c, ref input)| {
        constraints.push((*c).clone());

        let in_datum = unpack_datum!(bcx, expr::trans(bcx, &**input));
        unpack_result!(bcx, {
            callee::trans_arg_datum(bcx,
                                    expr_ty(bcx, &**input),
                                    in_datum,
                                    cleanup::CustomScope(temp_scope),
                                    callee::DontAutorefArg)
        })
    }).collect::<Vec<_>>();
    inputs.push_all(ext_inputs.as_slice());

    // no failure occurred preparing operands, no need to cleanup
    fcx.pop_custom_cleanup_scope(temp_scope);

    let mut constraints =
        String::from_str(constraints.iter()
                                    .map(|s| s.get().to_string())
                                    .chain(ext_constraints.into_iter())
                                    .collect::<Vec<String>>()
                                    .connect(",")
                                    .as_slice());

    let mut clobbers =
        String::from_str(ia.clobbers.iter()
                                    .map(|s| format!("~{{{}}}", s.get()))
                                    .collect::<Vec<String>>()
                                    .connect(",")
                                    .as_slice());
    let more_clobbers = get_clobbers();
    if !more_clobbers.is_empty() {
        if !clobbers.is_empty() {
            clobbers.push(',');
        }
        clobbers.push_str(more_clobbers.as_slice());
    }

    // Add the clobbers to our constraints list
    if clobbers.len() != 0 && constraints.len() != 0 {
        constraints.push(',');
        constraints.push_str(clobbers.as_slice());
    } else {
        constraints.push_str(clobbers.as_slice());
    }

    debug!("Asm Constraints: {}", constraints.as_slice());

    let num_outputs = outputs.len();

    // Depending on how many outputs we have, the return type is different
    let output_type = if num_outputs == 0 {
        Type::void(bcx.ccx())
    } else if num_outputs == 1 {
        output_types[0]
    } else {
        Type::struct_(bcx.ccx(), output_types.as_slice(), false)
    };

    let dialect = match ia.dialect {
        ast::AsmAtt   => llvm::AD_ATT,
        ast::AsmIntel => llvm::AD_Intel
    };

    let r = ia.asm.get().with_c_str(|a| {
        constraints.as_slice().with_c_str(|c| {
            InlineAsmCall(bcx,
                          a,
                          c,
                          inputs.as_slice(),
                          output_type,
                          ia.volatile,
                          ia.alignstack,
                          dialect)
        })
    });

    // Again, based on how many outputs we have
    if num_outputs == 1 {
        Store(bcx, r, outputs[0]);
    } else {
        for (i, o) in outputs.iter().enumerate() {
            let v = ExtractValue(bcx, r, i);
            Store(bcx, v, *o);
        }
    }

    // Store expn_id in a metadata node so we can map LLVM errors
    // back to source locations.  See #17552.
    unsafe {
        let key = "srcloc";
        let kind = llvm::LLVMGetMDKindIDInContext(bcx.ccx().llcx(),
            key.as_ptr() as *const c_char, key.len() as c_uint);

        let val: llvm::ValueRef = C_i32(bcx.ccx(), ia.expn_id.to_llvm_cookie());

        llvm::LLVMSetMetadata(r, kind,
            llvm::LLVMMDNodeInContext(bcx.ccx().llcx(), &val, 1));
    }

    return bcx;

}

// Default per-arch clobbers
// Basically what clang does

#[cfg(any(target_arch = "arm",
          target_arch = "mips",
          target_arch = "mipsel"))]
fn get_clobbers() -> String {
    "".to_string()
}

#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn get_clobbers() -> String {
    "~{dirflag},~{fpsr},~{flags}".to_string()
}
<commit_msg>trans: Eliminated redundant allocations.<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! # Translation of inline assembly.

use llvm;
use trans::build::*;
use trans::callee;
use trans::common::*;
use trans::cleanup;
use trans::cleanup::CleanupMethods;
use trans::expr;
use trans::type_of;
use trans::type_::Type;

use std::c_str::ToCStr;
use std::string::String;
use syntax::ast;
use libc::{c_uint, c_char};

// Take an inline assembly expression and splat it out via LLVM
pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
                                    -> Block<'blk, 'tcx> {
    let fcx = bcx.fcx;
    let mut bcx = bcx;
    let mut constraints = Vec::new();
    let mut output_types = Vec::new();

    let temp_scope = fcx.push_custom_cleanup_scope();

    let mut ext_inputs = Vec::new();
    let mut ext_constraints = Vec::new();

    // Prepare the output operands
    let outputs = ia.outputs.iter().enumerate().map(|(i, &(ref c, ref out, is_rw))| {
        constraints.push((*c).clone());

        let out_datum = unpack_datum!(bcx, expr::trans(bcx, &**out));
        output_types.push(type_of::type_of(bcx.ccx(), out_datum.ty));
        let val = out_datum.val;
        if is_rw {
            ext_inputs.push(unpack_result!(bcx, {
                callee::trans_arg_datum(bcx,
                                       expr_ty(bcx, &**out),
                                       out_datum,
                                       cleanup::CustomScope(temp_scope),
                                       callee::DontAutorefArg)
            }));
            ext_constraints.push(i.to_string());
        }
        val

    }).collect::<Vec<_>>();

    // Now the input operands
    let mut inputs = ia.inputs.iter().map(|&(ref c, ref input)| {
        constraints.push((*c).clone());

        let in_datum = unpack_datum!(bcx, expr::trans(bcx, &**input));
        unpack_result!(bcx, {
            callee::trans_arg_datum(bcx,
                                    expr_ty(bcx, &**input),
                                    in_datum,
                                    cleanup::CustomScope(temp_scope),
                                    callee::DontAutorefArg)
        })
    }).collect::<Vec<_>>();
    inputs.push_all(ext_inputs.as_slice());

    // no failure occurred preparing operands, no need to cleanup
    fcx.pop_custom_cleanup_scope(temp_scope);

    let mut constraints = constraints.iter()
                                     .map(|s| s.get().to_string())
                                     .chain(ext_constraints.into_iter())
                                     .collect::<Vec<String>>()
                                     .connect(",");

    let mut clobbers = ia.clobbers.iter()
                                  .map(|s| format!("~{{{}}}", s.get()))
                                  .collect::<Vec<String>>()
                                  .connect(",");
    let more_clobbers = get_clobbers();
    if !more_clobbers.is_empty() {
        if !clobbers.is_empty() {
            clobbers.push(',');
        }
        clobbers.push_str(more_clobbers.as_slice());
    }

    // Add the clobbers to our constraints list
    if clobbers.len() != 0 && constraints.len() != 0 {
        constraints.push(',');
        constraints.push_str(clobbers.as_slice());
    } else {
        constraints.push_str(clobbers.as_slice());
    }

    debug!("Asm Constraints: {}", constraints.as_slice());

    let num_outputs = outputs.len();

    // Depending on how many outputs we have, the return type is different
    let output_type = if num_outputs == 0 {
        Type::void(bcx.ccx())
    } else if num_outputs == 1 {
        output_types[0]
    } else {
        Type::struct_(bcx.ccx(), output_types.as_slice(), false)
    };

    let dialect = match ia.dialect {
        ast::AsmAtt   => llvm::AD_ATT,
        ast::AsmIntel => llvm::AD_Intel
    };

    let r = ia.asm.get().with_c_str(|a| {
        constraints.as_slice().with_c_str(|c| {
            InlineAsmCall(bcx,
                          a,
                          c,
                          inputs.as_slice(),
                          output_type,
                          ia.volatile,
                          ia.alignstack,
                          dialect)
        })
    });

    // Again, based on how many outputs we have
    if num_outputs == 1 {
        Store(bcx, r, outputs[0]);
    } else {
        for (i, o) in outputs.iter().enumerate() {
            let v = ExtractValue(bcx, r, i);
            Store(bcx, v, *o);
        }
    }

    // Store expn_id in a metadata node so we can map LLVM errors
    // back to source locations.  See #17552.
    unsafe {
        let key = "srcloc";
        let kind = llvm::LLVMGetMDKindIDInContext(bcx.ccx().llcx(),
            key.as_ptr() as *const c_char, key.len() as c_uint);

        let val: llvm::ValueRef = C_i32(bcx.ccx(), ia.expn_id.to_llvm_cookie());

        llvm::LLVMSetMetadata(r, kind,
            llvm::LLVMMDNodeInContext(bcx.ccx().llcx(), &val, 1));
    }

    return bcx;

}

// Default per-arch clobbers
// Basically what clang does

#[cfg(any(target_arch = "arm",
          target_arch = "mips",
          target_arch = "mipsel"))]
fn get_clobbers() -> String {
    "".to_string()
}

#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn get_clobbers() -> String {
    "~{dirflag},~{fpsr},~{flags}".to_string()
}
<|endoftext|>


<commit_before>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Support for parsing unsupported, old syntaxes, for the purpose of reporting errors. Parsing of
//! these syntaxes is tested by compile-test/obsolete-syntax.rs.
//!
//! Obsolete syntax that becomes too hard to parse can be removed.

use ast::{Expr, ExprTup};
use codemap::Span;
use parse::parser;
use parse::token;
use ptr::P;

/// The specific types of unsupported syntax
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum ObsoleteSyntax {
    ClosureKind,
    ExternCrateString,
}

pub trait ParserObsoleteMethods {
    /// Reports an obsolete syntax non-fatal error.
    fn obsolete(&mut self, sp: Span, kind: ObsoleteSyntax);
    /// Reports an obsolete syntax non-fatal error, and returns
    /// a placeholder expression
    fn obsolete_expr(&mut self, sp: Span, kind: ObsoleteSyntax) -> P<Expr>;
    fn report(&mut self,
              sp: Span,
              kind: ObsoleteSyntax,
              kind_str: &str,
              desc: &str,
              error: bool);
    fn is_obsolete_ident(&mut self, ident: &str) -> bool;
    fn eat_obsolete_ident(&mut self, ident: &str) -> bool;
}

impl<'a> ParserObsoleteMethods for parser::Parser<'a> {
    /// Reports an obsolete syntax non-fatal error.
    fn obsolete(&mut self, sp: Span, kind: ObsoleteSyntax) {
        let (kind_str, desc, error) = match kind {
            ObsoleteSyntax::ClosureKind => (
                "`:`, `&mut:`, or `&:`",
                "rely on inference instead",
                true,
            ),
            ObsoleteSyntax::ExternCrateString => (
                "\"crate-name\"",
                "use an identifier not in quotes instead",
                false, // warning for now
            ),
        };

        self.report(sp, kind, kind_str, desc, error);
    }

    /// Reports an obsolete syntax non-fatal error, and returns
    /// a placeholder expression
    fn obsolete_expr(&mut self, sp: Span, kind: ObsoleteSyntax) -> P<Expr> {
        self.obsolete(sp, kind);
        self.mk_expr(sp.lo, sp.hi, ExprTup(vec![]))
    }

    fn report(&mut self,
              sp: Span,
              kind: ObsoleteSyntax,
              kind_str: &str,
              desc: &str,
              error: bool) {
        if error {
            self.span_err(sp, &format!("obsolete syntax: {}", kind_str));
        } else {
            self.span_warn(sp, &format!("obsolete syntax: {}", kind_str));
        }

        if !self.obsolete_set.contains(&kind) &&
            (error || self.sess.span_diagnostic.handler().can_emit_warnings) {
            self.sess
                .span_diagnostic
                .handler()
                .note(&format!("{}", desc));
            self.obsolete_set.insert(kind);
        }
    }

    fn is_obsolete_ident(&mut self, ident: &str) -> bool {
        match self.token {
            token::Ident(sid, _) => sid.name == ident,
            _ => false,
        }
    }

    fn eat_obsolete_ident(&mut self, ident: &str) -> bool {
        if self.is_obsolete_ident(ident) {
            panictry!(self.bump());
            true
        } else {
            false
        }
    }
}
<commit_msg>Remove unused code in parser.<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Support for parsing unsupported, old syntaxes, for the purpose of reporting errors. Parsing of
//! these syntaxes is tested by compile-test/obsolete-syntax.rs.
//!
//! Obsolete syntax that becomes too hard to parse can be removed.

use codemap::Span;
use parse::parser;

/// The specific types of unsupported syntax
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum ObsoleteSyntax {
    ClosureKind,
    ExternCrateString,
}

pub trait ParserObsoleteMethods {
    /// Reports an obsolete syntax non-fatal error.
    fn obsolete(&mut self, sp: Span, kind: ObsoleteSyntax);
    fn report(&mut self,
              sp: Span,
              kind: ObsoleteSyntax,
              kind_str: &str,
              desc: &str,
              error: bool);
}

impl<'a> ParserObsoleteMethods for parser::Parser<'a> {
    /// Reports an obsolete syntax non-fatal error.
    fn obsolete(&mut self, sp: Span, kind: ObsoleteSyntax) {
        let (kind_str, desc, error) = match kind {
            ObsoleteSyntax::ClosureKind => (
                "`:`, `&mut:`, or `&:`",
                "rely on inference instead",
                true,
            ),
            ObsoleteSyntax::ExternCrateString => (
                "\"crate-name\"",
                "use an identifier not in quotes instead",
                false, // warning for now
            ),
        };

        self.report(sp, kind, kind_str, desc, error);
    }

    fn report(&mut self,
              sp: Span,
              kind: ObsoleteSyntax,
              kind_str: &str,
              desc: &str,
              error: bool) {
        if error {
            self.span_err(sp, &format!("obsolete syntax: {}", kind_str));
        } else {
            self.span_warn(sp, &format!("obsolete syntax: {}", kind_str));
        }

        if !self.obsolete_set.contains(&kind) &&
            (error || self.sess.span_diagnostic.handler().can_emit_warnings) {
            self.sess
                .span_diagnostic
                .handler()
                .note(&format!("{}", desc));
            self.obsolete_set.insert(kind);
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate net_traits;

use net_traits::pub_domains::{is_pub_domain, is_reg_domain, pub_suffix, reg_suffix};

// These tests may need to be updated if the PSL changes.

#[test]
fn test_is_pub_domain_plain() {
    assert!(is_pub_domain("com"));
    assert!(is_pub_domain(".org"));
    assert!(is_pub_domain("za.org"));
    assert!(is_pub_domain("xn--od0alg.hk"));
    assert!(is_pub_domain("xn--krdsherad-m8a.no"));
}

#[test]
fn test_is_pub_domain_wildcard() {
    assert!(is_pub_domain("hello.bd"));
    assert!(is_pub_domain("world.jm"));
    assert!(is_pub_domain("toto.kobe.jp"));
}

#[test]
fn test_is_pub_domain_exception() {
    assert_eq!(is_pub_domain("www.ck"), false);
    assert_eq!(is_pub_domain("city.kawasaki.jp"), false);
    assert_eq!(is_pub_domain("city.nagoya.jp"), false);
    assert_eq!(is_pub_domain("teledata.mz"), false);
}

#[test]
fn test_is_pub_domain_not() {
    assert_eq!(is_pub_domain(""), false);
    assert_eq!(is_pub_domain("."), false);
    assert_eq!(is_pub_domain("..."), false);
    assert_eq!(is_pub_domain(".servo.org"), false);
    assert_eq!(is_pub_domain("www.mozilla.org"), false);
    assert_eq!(is_pub_domain("publicsuffix.org"), false);
    assert_eq!(is_pub_domain("hello.world.jm"), false);
    assert_eq!(is_pub_domain("toto.toto.kobe.jp"), false);
}

#[test]
fn test_is_pub_domain() {
    assert!(!is_pub_domain("city.yokohama.jp"));
    assert!(!is_pub_domain("foo.bar.baz.yokohama.jp"));
    assert!(!is_pub_domain("foo.bar.city.yokohama.jp"));
    assert!(!is_pub_domain("foo.bar.com"));
    assert!(!is_pub_domain("foo.bar.tokyo.jp"));
    assert!(!is_pub_domain("foo.bar.yokohama.jp"));
    assert!(!is_pub_domain("foo.city.yokohama.jp"));
    assert!(!is_pub_domain("foo.com"));
    assert!(!is_pub_domain("foo.tokyo.jp"));
    assert!(!is_pub_domain("yokohama.jp"));
    assert!(is_pub_domain("com"));
    assert!(is_pub_domain("foo.yokohama.jp"));
    assert!(is_pub_domain("jp"));
    assert!(is_pub_domain("tokyo.jp"));
}

#[test]
fn test_is_reg_domain() {
    assert!(!is_reg_domain("com"));
    assert!(!is_reg_domain("foo.bar.baz.yokohama.jp"));
    assert!(!is_reg_domain("foo.bar.com"));
    assert!(!is_reg_domain("foo.bar.tokyo.jp"));
    assert!(!is_reg_domain("foo.city.yokohama.jp"));
    assert!(!is_reg_domain("foo.yokohama.jp"));
    assert!(!is_reg_domain("jp"));
    assert!(!is_reg_domain("tokyo.jp"));
    assert!(is_reg_domain("city.yokohama.jp"));
    assert!(is_reg_domain("foo.bar.yokohama.jp"));
    assert!(is_reg_domain("foo.com"));
    assert!(is_reg_domain("foo.tokyo.jp"));
    assert!(is_reg_domain("yokohama.jp"));
}

#[test]
fn test_pub_suffix() {
    assert_eq!(pub_suffix("city.yokohama.jp"), "yokohama.jp");
    assert_eq!(pub_suffix("com"), "com");
    assert_eq!(pub_suffix("foo.bar.baz.yokohama.jp"), "baz.yokohama.jp");
    assert_eq!(pub_suffix("foo.bar.com"), "com");
    assert_eq!(pub_suffix("foo.bar.tokyo.jp"), "tokyo.jp");
    assert_eq!(pub_suffix("foo.bar.yokohama.jp"), "bar.yokohama.jp");
    assert_eq!(pub_suffix("foo.city.yokohama.jp"), "yokohama.jp");
    assert_eq!(pub_suffix("foo.com"), "com");
    assert_eq!(pub_suffix("foo.tokyo.jp"), "tokyo.jp");
    assert_eq!(pub_suffix("foo.yokohama.jp"), "foo.yokohama.jp");
    assert_eq!(pub_suffix("jp"), "jp");
    assert_eq!(pub_suffix("tokyo.jp"), "tokyo.jp");
    assert_eq!(pub_suffix("yokohama.jp"), "jp");
}

#[test]
fn test_reg_suffix() {
    assert_eq!(reg_suffix("city.yokohama.jp"), "city.yokohama.jp");
    assert_eq!(reg_suffix("com"), "com");
    assert_eq!(reg_suffix("foo.bar.baz.yokohama.jp"), "bar.baz.yokohama.jp");
    assert_eq!(reg_suffix("foo.bar.com"), "bar.com");
    assert_eq!(reg_suffix("foo.bar.tokyo.jp"), "bar.tokyo.jp");
    assert_eq!(reg_suffix("foo.bar.yokohama.jp"), "foo.bar.yokohama.jp");
    assert_eq!(reg_suffix("foo.city.yokohama.jp"), "city.yokohama.jp");
    assert_eq!(reg_suffix("foo.com"), "foo.com");
    assert_eq!(reg_suffix("foo.tokyo.jp"), "foo.tokyo.jp");
    assert_eq!(reg_suffix("foo.yokohama.jp"), "foo.yokohama.jp");
    assert_eq!(reg_suffix("jp"), "jp");
    assert_eq!(reg_suffix("tokyo.jp"), "tokyo.jp");
    assert_eq!(reg_suffix("yokohama.jp"), "yokohama.jp");
}

#[test]
fn test_weirdness() {
    // These are weird results, but AFAICT they are spec-compliant.
    assert!(pub_suffix("city.yokohama.jp") != pub_suffix(pub_suffix("city.yokohama.jp")));
    assert!(!is_pub_domain(pub_suffix("city.yokohama.jp")));
}
<commit_msg>Use specific negative assertion for unit tests of net trait pub_domain<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate net_traits;

use net_traits::pub_domains::{is_pub_domain, is_reg_domain, pub_suffix, reg_suffix};

// These tests may need to be updated if the PSL changes.

#[test]
fn test_is_pub_domain_plain() {
    assert!(is_pub_domain("com"));
    assert!(is_pub_domain(".org"));
    assert!(is_pub_domain("za.org"));
    assert!(is_pub_domain("xn--od0alg.hk"));
    assert!(is_pub_domain("xn--krdsherad-m8a.no"));
}

#[test]
fn test_is_pub_domain_wildcard() {
    assert!(is_pub_domain("hello.bd"));
    assert!(is_pub_domain("world.jm"));
    assert!(is_pub_domain("toto.kobe.jp"));
}

#[test]
fn test_is_pub_domain_exception() {
    assert_eq!(is_pub_domain("www.ck"), false);
    assert_eq!(is_pub_domain("city.kawasaki.jp"), false);
    assert_eq!(is_pub_domain("city.nagoya.jp"), false);
    assert_eq!(is_pub_domain("teledata.mz"), false);
}

#[test]
fn test_is_pub_domain_not() {
    assert_eq!(is_pub_domain(""), false);
    assert_eq!(is_pub_domain("."), false);
    assert_eq!(is_pub_domain("..."), false);
    assert_eq!(is_pub_domain(".servo.org"), false);
    assert_eq!(is_pub_domain("www.mozilla.org"), false);
    assert_eq!(is_pub_domain("publicsuffix.org"), false);
    assert_eq!(is_pub_domain("hello.world.jm"), false);
    assert_eq!(is_pub_domain("toto.toto.kobe.jp"), false);
}

#[test]
fn test_is_pub_domain() {
    assert!(!is_pub_domain("city.yokohama.jp"));
    assert!(!is_pub_domain("foo.bar.baz.yokohama.jp"));
    assert!(!is_pub_domain("foo.bar.city.yokohama.jp"));
    assert!(!is_pub_domain("foo.bar.com"));
    assert!(!is_pub_domain("foo.bar.tokyo.jp"));
    assert!(!is_pub_domain("foo.bar.yokohama.jp"));
    assert!(!is_pub_domain("foo.city.yokohama.jp"));
    assert!(!is_pub_domain("foo.com"));
    assert!(!is_pub_domain("foo.tokyo.jp"));
    assert!(!is_pub_domain("yokohama.jp"));
    assert!(is_pub_domain("com"));
    assert!(is_pub_domain("foo.yokohama.jp"));
    assert!(is_pub_domain("jp"));
    assert!(is_pub_domain("tokyo.jp"));
}

#[test]
fn test_is_reg_domain() {
    assert!(!is_reg_domain("com"));
    assert!(!is_reg_domain("foo.bar.baz.yokohama.jp"));
    assert!(!is_reg_domain("foo.bar.com"));
    assert!(!is_reg_domain("foo.bar.tokyo.jp"));
    assert!(!is_reg_domain("foo.city.yokohama.jp"));
    assert!(!is_reg_domain("foo.yokohama.jp"));
    assert!(!is_reg_domain("jp"));
    assert!(!is_reg_domain("tokyo.jp"));
    assert!(is_reg_domain("city.yokohama.jp"));
    assert!(is_reg_domain("foo.bar.yokohama.jp"));
    assert!(is_reg_domain("foo.com"));
    assert!(is_reg_domain("foo.tokyo.jp"));
    assert!(is_reg_domain("yokohama.jp"));
}

#[test]
fn test_pub_suffix() {
    assert_eq!(pub_suffix("city.yokohama.jp"), "yokohama.jp");
    assert_eq!(pub_suffix("com"), "com");
    assert_eq!(pub_suffix("foo.bar.baz.yokohama.jp"), "baz.yokohama.jp");
    assert_eq!(pub_suffix("foo.bar.com"), "com");
    assert_eq!(pub_suffix("foo.bar.tokyo.jp"), "tokyo.jp");
    assert_eq!(pub_suffix("foo.bar.yokohama.jp"), "bar.yokohama.jp");
    assert_eq!(pub_suffix("foo.city.yokohama.jp"), "yokohama.jp");
    assert_eq!(pub_suffix("foo.com"), "com");
    assert_eq!(pub_suffix("foo.tokyo.jp"), "tokyo.jp");
    assert_eq!(pub_suffix("foo.yokohama.jp"), "foo.yokohama.jp");
    assert_eq!(pub_suffix("jp"), "jp");
    assert_eq!(pub_suffix("tokyo.jp"), "tokyo.jp");
    assert_eq!(pub_suffix("yokohama.jp"), "jp");
}

#[test]
fn test_reg_suffix() {
    assert_eq!(reg_suffix("city.yokohama.jp"), "city.yokohama.jp");
    assert_eq!(reg_suffix("com"), "com");
    assert_eq!(reg_suffix("foo.bar.baz.yokohama.jp"), "bar.baz.yokohama.jp");
    assert_eq!(reg_suffix("foo.bar.com"), "bar.com");
    assert_eq!(reg_suffix("foo.bar.tokyo.jp"), "bar.tokyo.jp");
    assert_eq!(reg_suffix("foo.bar.yokohama.jp"), "foo.bar.yokohama.jp");
    assert_eq!(reg_suffix("foo.city.yokohama.jp"), "city.yokohama.jp");
    assert_eq!(reg_suffix("foo.com"), "foo.com");
    assert_eq!(reg_suffix("foo.tokyo.jp"), "foo.tokyo.jp");
    assert_eq!(reg_suffix("foo.yokohama.jp"), "foo.yokohama.jp");
    assert_eq!(reg_suffix("jp"), "jp");
    assert_eq!(reg_suffix("tokyo.jp"), "tokyo.jp");
    assert_eq!(reg_suffix("yokohama.jp"), "yokohama.jp");
}

#[test]
fn test_weirdness() {
    // These are weird results, but AFAICT they are spec-compliant.
    assert_ne!(pub_suffix("city.yokohama.jp"), pub_suffix(pub_suffix("city.yokohama.jp")));
    assert!(!is_pub_domain(pub_suffix("city.yokohama.jp")));
}
<|endoftext|>