<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/. */

use dom::bindings::codegen::Bindings::StorageBinding;
use dom::bindings::codegen::Bindings::StorageBinding::StorageMethods;
use dom::bindings::error::{Error, ErrorResult};
use dom::bindings::global::{GlobalField, GlobalRef};
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{Root, RootedReference};
use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::event::{Event, EventBubbles, EventCancelable};
use dom::storageevent::StorageEvent;
use dom::urlhelper::UrlHelper;
use ipc_channel::ipc;
use net_traits::storage_thread::{StorageThread, StorageThreadMsg, StorageType};
use page::IterablePage;
use script_thread::{MainThreadRunnable, MainThreadScriptMsg, ScriptThread};
use std::sync::mpsc::channel;
use url::Url;
use util::str::DOMString;

#[dom_struct]
pub struct Storage {
    reflector_: Reflector,
    global: GlobalField,
    storage_type: StorageType
}

impl Storage {
    fn new_inherited(global: &GlobalRef, storage_type: StorageType) -> Storage {
        Storage {
            reflector_: Reflector::new(),
            global: GlobalField::from_rooted(global),
            storage_type: storage_type
        }
    }

    pub fn new(global: &GlobalRef, storage_type: StorageType) -> Root<Storage> {
        reflect_dom_object(box Storage::new_inherited(global, storage_type), *global, StorageBinding::Wrap)
    }

    fn get_url(&self) -> Url {
        let global_root = self.global.root();
        let global_ref = global_root.r();
        global_ref.get_url()
    }

    fn get_storage_thread(&self) -> StorageThread {
        let global_root = self.global.root();
        let global_ref = global_root.r();
        global_ref.as_window().storage_thread()
    }

}

impl StorageMethods for Storage {
    // https://html.spec.whatwg.org/multipage/#dom-storage-length
    fn Length(&self) -> u32 {
        let (sender, receiver) = ipc::channel().unwrap();

        self.get_storage_thread().send(StorageThreadMsg::Length(sender, self.get_url(), self.storage_type)).unwrap();
        receiver.recv().unwrap() as u32
    }

    // https://html.spec.whatwg.org/multipage/#dom-storage-key
    fn Key(&self, index: u32) -> Option<DOMString> {
        let (sender, receiver) = ipc::channel().unwrap();

        self.get_storage_thread()
            .send(StorageThreadMsg::Key(sender, self.get_url(), self.storage_type, index))
            .unwrap();
        receiver.recv().unwrap().map(DOMString::from)
    }

    // https://html.spec.whatwg.org/multipage/#dom-storage-getitem
    fn GetItem(&self, name: DOMString) -> Option<DOMString> {
        let (sender, receiver) = ipc::channel().unwrap();
        let name = String::from(name);

        let msg = StorageThreadMsg::GetItem(sender, self.get_url(), self.storage_type, name);
        self.get_storage_thread().send(msg).unwrap();
        receiver.recv().unwrap().map(DOMString::from)
    }

    // https://html.spec.whatwg.org/multipage/#dom-storage-setitem
    fn SetItem(&self, name: DOMString, value: DOMString) -> ErrorResult {
        let (sender, receiver) = ipc::channel().unwrap();
        let name = String::from(name);
        let value = String::from(value);

        let msg = StorageThreadMsg::SetItem(sender, self.get_url(), self.storage_type, name.clone(), value.clone());
        self.get_storage_thread().send(msg).unwrap();
        match receiver.recv().unwrap() {
            Err(_) => Err(Error::QuotaExceeded),
            Ok((changed, old_value)) => {
              if changed {
                  self.broadcast_change_notification(Some(name), old_value, Some(value));
              }
              Ok(())
            }
        }
    }

    // https://html.spec.whatwg.org/multipage/#dom-storage-removeitem
    fn RemoveItem(&self, name: DOMString) {
        let (sender, receiver) = ipc::channel().unwrap();
        let name = String::from(name);

        let msg = StorageThreadMsg::RemoveItem(sender, self.get_url(), self.storage_type, name.clone());
        self.get_storage_thread().send(msg).unwrap();
        if let Some(old_value) = receiver.recv().unwrap() {
            self.broadcast_change_notification(Some(name), Some(old_value), None);
        }
    }

    // https://html.spec.whatwg.org/multipage/#dom-storage-clear
    fn Clear(&self) {
        let (sender, receiver) = ipc::channel().unwrap();

        self.get_storage_thread().send(StorageThreadMsg::Clear(sender, self.get_url(), self.storage_type)).unwrap();
        if receiver.recv().unwrap() {
            self.broadcast_change_notification(None, None, None);
        }
    }

    // https://html.spec.whatwg.org/multipage/#the-storage-interface:supported-property-names
    fn SupportedPropertyNames(&self) -> Vec<DOMString> {
        let (sender, receiver) = ipc::channel().unwrap();

        self.get_storage_thread().send(StorageThreadMsg::Keys(sender, self.get_url(), self.storage_type)).unwrap();
        receiver.recv().unwrap().iter().cloned().map(DOMString::from).collect() // FIXME: inefficient?
    }

    // check-tidy: no specs after this line
    fn NamedGetter(&self, name: DOMString, found: &mut bool) -> Option<DOMString> {
        let item = self.GetItem(name);
        *found = item.is_some();
        item
    }

    fn NamedSetter(&self, name: DOMString, value: DOMString) -> ErrorResult {
        self.SetItem(name, value)
    }

    fn NamedDeleter(&self, name: DOMString) {
        self.RemoveItem(name);
    }
}

impl Storage {
    /// https://html.spec.whatwg.org/multipage/#send-a-storage-notification
    fn broadcast_change_notification(&self, key: Option<String>, old_value: Option<String>,
                                     new_value: Option<String>) {
        let global_root = self.global.root();
        let global_ref = global_root.r();
        let main_script_chan = global_ref.as_window().main_thread_script_chan();
        let script_chan = global_ref.dom_manipulation_thread_source();
        let trusted_storage = Trusted::new(self, script_chan);
        main_script_chan.send(MainThreadScriptMsg::MainThreadRunnableMsg(
            box StorageEventRunnable::new(trusted_storage, key, old_value, new_value))).unwrap();
    }
}

pub struct StorageEventRunnable {
    element: Trusted<Storage>,
    key: Option<String>,
    old_value: Option<String>,
    new_value: Option<String>
}

impl StorageEventRunnable {
    fn new(storage: Trusted<Storage>, key: Option<String>, old_value: Option<String>,
           new_value: Option<String>) -> StorageEventRunnable {
        StorageEventRunnable { element: storage, key: key, old_value: old_value, new_value: new_value }
    }
}

impl MainThreadRunnable for StorageEventRunnable {
    fn handler(self: Box<StorageEventRunnable>, script_thread: &ScriptThread) {
        let this = *self;
        let storage_root = this.element.root();
        let storage = storage_root.r();
        let global_root = storage.global.root();
        let global_ref = global_root.r();
        let ev_window = global_ref.as_window();
        let ev_url = storage.get_url();

        let storage_event = StorageEvent::new(
            global_ref,
            atom!("storage"),
            EventBubbles::DoesNotBubble, EventCancelable::NotCancelable,
            this.key.map(DOMString::from), this.old_value.map(DOMString::from), this.new_value.map(DOMString::from),
            DOMString::from(ev_url.to_string()),
            Some(storage)
        );

        let root_page = script_thread.root_page();
        for it_page in root_page.iter() {
            let it_window_root = it_page.window();
            let it_window = it_window_root.r();
            assert!(UrlHelper::SameOrigin(&ev_url, &it_window.get_url()));
            // TODO: Such a Document object is not necessarily fully active, but events fired on such
            // objects are ignored by the event loop until the Document becomes fully active again.
            if ev_window.pipeline() != it_window.pipeline() {
                storage_event.upcast::<Event>().fire(it_window.upcast());
            }
        }
    }
}
<commit_msg>Remove global field from Storage<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/. */

use dom::bindings::codegen::Bindings::StorageBinding;
use dom::bindings::codegen::Bindings::StorageBinding::StorageMethods;
use dom::bindings::error::{Error, ErrorResult};
use dom::bindings::global::{GlobalRef, global_root_from_reflector};
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{Root, RootedReference};
use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::event::{Event, EventBubbles, EventCancelable};
use dom::storageevent::StorageEvent;
use dom::urlhelper::UrlHelper;
use ipc_channel::ipc;
use net_traits::storage_thread::{StorageThread, StorageThreadMsg, StorageType};
use page::IterablePage;
use script_thread::{MainThreadRunnable, MainThreadScriptMsg, ScriptThread};
use std::sync::mpsc::channel;
use url::Url;
use util::str::DOMString;

#[dom_struct]
pub struct Storage {
    reflector_: Reflector,
    storage_type: StorageType
}

impl Storage {
    fn new_inherited(storage_type: StorageType) -> Storage {
        Storage {
            reflector_: Reflector::new(),
            storage_type: storage_type
        }
    }

    pub fn new(global: &GlobalRef, storage_type: StorageType) -> Root<Storage> {
        reflect_dom_object(box Storage::new_inherited(storage_type), *global, StorageBinding::Wrap)
    }

    fn get_url(&self) -> Url {
        let global_root = global_root_from_reflector(self);
        let global_ref = global_root.r();
        global_ref.get_url()
    }

    fn get_storage_thread(&self) -> StorageThread {
        let global_root = global_root_from_reflector(self);
        let global_ref = global_root.r();
        global_ref.as_window().storage_thread()
    }

}

impl StorageMethods for Storage {
    // https://html.spec.whatwg.org/multipage/#dom-storage-length
    fn Length(&self) -> u32 {
        let (sender, receiver) = ipc::channel().unwrap();

        self.get_storage_thread().send(StorageThreadMsg::Length(sender, self.get_url(), self.storage_type)).unwrap();
        receiver.recv().unwrap() as u32
    }

    // https://html.spec.whatwg.org/multipage/#dom-storage-key
    fn Key(&self, index: u32) -> Option<DOMString> {
        let (sender, receiver) = ipc::channel().unwrap();

        self.get_storage_thread()
            .send(StorageThreadMsg::Key(sender, self.get_url(), self.storage_type, index))
            .unwrap();
        receiver.recv().unwrap().map(DOMString::from)
    }

    // https://html.spec.whatwg.org/multipage/#dom-storage-getitem
    fn GetItem(&self, name: DOMString) -> Option<DOMString> {
        let (sender, receiver) = ipc::channel().unwrap();
        let name = String::from(name);

        let msg = StorageThreadMsg::GetItem(sender, self.get_url(), self.storage_type, name);
        self.get_storage_thread().send(msg).unwrap();
        receiver.recv().unwrap().map(DOMString::from)
    }

    // https://html.spec.whatwg.org/multipage/#dom-storage-setitem
    fn SetItem(&self, name: DOMString, value: DOMString) -> ErrorResult {
        let (sender, receiver) = ipc::channel().unwrap();
        let name = String::from(name);
        let value = String::from(value);

        let msg = StorageThreadMsg::SetItem(sender, self.get_url(), self.storage_type, name.clone(), value.clone());
        self.get_storage_thread().send(msg).unwrap();
        match receiver.recv().unwrap() {
            Err(_) => Err(Error::QuotaExceeded),
            Ok((changed, old_value)) => {
              if changed {
                  self.broadcast_change_notification(Some(name), old_value, Some(value));
              }
              Ok(())
            }
        }
    }

    // https://html.spec.whatwg.org/multipage/#dom-storage-removeitem
    fn RemoveItem(&self, name: DOMString) {
        let (sender, receiver) = ipc::channel().unwrap();
        let name = String::from(name);

        let msg = StorageThreadMsg::RemoveItem(sender, self.get_url(), self.storage_type, name.clone());
        self.get_storage_thread().send(msg).unwrap();
        if let Some(old_value) = receiver.recv().unwrap() {
            self.broadcast_change_notification(Some(name), Some(old_value), None);
        }
    }

    // https://html.spec.whatwg.org/multipage/#dom-storage-clear
    fn Clear(&self) {
        let (sender, receiver) = ipc::channel().unwrap();

        self.get_storage_thread().send(StorageThreadMsg::Clear(sender, self.get_url(), self.storage_type)).unwrap();
        if receiver.recv().unwrap() {
            self.broadcast_change_notification(None, None, None);
        }
    }

    // https://html.spec.whatwg.org/multipage/#the-storage-interface:supported-property-names
    fn SupportedPropertyNames(&self) -> Vec<DOMString> {
        let (sender, receiver) = ipc::channel().unwrap();

        self.get_storage_thread().send(StorageThreadMsg::Keys(sender, self.get_url(), self.storage_type)).unwrap();
        receiver.recv().unwrap().iter().cloned().map(DOMString::from).collect() // FIXME: inefficient?
    }

    // check-tidy: no specs after this line
    fn NamedGetter(&self, name: DOMString, found: &mut bool) -> Option<DOMString> {
        let item = self.GetItem(name);
        *found = item.is_some();
        item
    }

    fn NamedSetter(&self, name: DOMString, value: DOMString) -> ErrorResult {
        self.SetItem(name, value)
    }

    fn NamedDeleter(&self, name: DOMString) {
        self.RemoveItem(name);
    }
}

impl Storage {
    /// https://html.spec.whatwg.org/multipage/#send-a-storage-notification
    fn broadcast_change_notification(&self, key: Option<String>, old_value: Option<String>,
                                     new_value: Option<String>) {
        let global_root = global_root_from_reflector(self);
        let global_ref = global_root.r();
        let main_script_chan = global_ref.as_window().main_thread_script_chan();
        let script_chan = global_ref.dom_manipulation_thread_source();
        let trusted_storage = Trusted::new(self, script_chan);
        main_script_chan.send(MainThreadScriptMsg::MainThreadRunnableMsg(
            box StorageEventRunnable::new(trusted_storage, key, old_value, new_value))).unwrap();
    }
}

pub struct StorageEventRunnable {
    element: Trusted<Storage>,
    key: Option<String>,
    old_value: Option<String>,
    new_value: Option<String>
}

impl StorageEventRunnable {
    fn new(storage: Trusted<Storage>, key: Option<String>, old_value: Option<String>,
           new_value: Option<String>) -> StorageEventRunnable {
        StorageEventRunnable { element: storage, key: key, old_value: old_value, new_value: new_value }
    }
}

impl MainThreadRunnable for StorageEventRunnable {
    fn handler(self: Box<StorageEventRunnable>, script_thread: &ScriptThread) {
        let this = *self;
        let storage_root = this.element.root();
        let storage = storage_root.r();
        let global_root = global_root_from_reflector(storage);
        let global_ref = global_root.r();
        let ev_window = global_ref.as_window();
        let ev_url = storage.get_url();

        let storage_event = StorageEvent::new(
            global_ref,
            atom!("storage"),
            EventBubbles::DoesNotBubble, EventCancelable::NotCancelable,
            this.key.map(DOMString::from), this.old_value.map(DOMString::from), this.new_value.map(DOMString::from),
            DOMString::from(ev_url.to_string()),
            Some(storage)
        );

        let root_page = script_thread.root_page();
        for it_page in root_page.iter() {
            let it_window_root = it_page.window();
            let it_window = it_window_root.r();
            assert!(UrlHelper::SameOrigin(&ev_url, &it_window.get_url()));
            // TODO: Such a Document object is not necessarily fully active, but events fired on such
            // objects are ignored by the event loop until the Document becomes fully active again.
            if ev_window.pipeline() != it_window.pipeline() {
                storage_event.upcast::<Event>().fire(it_window.upcast());
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.

use std::sync::{Arc, Mutex};
use std::str::FromStr;
use std::net::SocketAddr;
use std::thread;

use tokio_core::reactor::{Core, Timeout};
use tokio_core::net::TcpStream;
use tokio_core::io;
use futures::{Future, future};

use jsonrpc::{MetaIoHandler, Value, Metadata};
use Server;
use MetaExtractor;
use RequestContext;

fn casual_server(socket_addr: &SocketAddr) -> Server {
    let mut io = MetaIoHandler::<()>::new();
    io.add_method("say_hello", |_params| {
        Ok(Value::String("hello".to_string()))
    });
    Server::new(socket_addr.clone(), Arc::new(io))
}

fn wait(millis: u64) {
    thread::sleep(::std::time::Duration::from_millis(millis));
}

#[test]
fn doc_test() {
    ::logger::init_log();

    let mut io = MetaIoHandler::<()>::new();
    io.add_method("say_hello", |_params| {
        Ok(Value::String("hello".to_string()))
    });
    let server = Server::new(SocketAddr::from_str("0.0.0.0:17770").unwrap(), Arc::new(io));
    thread::spawn(move || server.run().expect("Server must run with no issues"));
}

#[test]
fn doc_test_connect() {
    ::logger::init_log();
    let addr: SocketAddr = "127.0.0.1:17775".parse().unwrap();
    let server = casual_server(&addr);
    thread::spawn(move || server.run().expect("Server must run with no issues"));
    wait(100);

    let mut core = Core::new().expect("Tokio Core should be created with no errors");
    let stream = TcpStream::connect(&addr, &core.handle());
    let result = core.run(stream);

    assert!(result.is_ok());
}

fn dummy_request(addr: &SocketAddr, data: &[u8]) -> Vec<u8> {
    let mut core = Core::new().expect("Tokio Core should be created with no errors");
    let mut buffer = vec![0u8; 1024];

    let stream = TcpStream::connect(addr, &core.handle())
        .and_then(|stream| {
            io::write_all(stream, data)
        })
        .and_then(|(stream, _)| {
            io::read(stream, &mut buffer)
        })
        .and_then(|(_, read_buf, len)| {
            future::ok(read_buf[0..len].to_vec())
        });
    let result = core.run(stream).expect("Core should run with no errors");

    result
}

fn dummy_request_str(addr: &SocketAddr, data: &[u8]) -> String {
    String::from_utf8(dummy_request(addr, data)).expect("String should be utf-8")
}

#[test]
fn doc_test_handle() {
    ::logger::init_log();
    let addr: SocketAddr = "127.0.0.1:17780".parse().unwrap();
    let server = casual_server(&addr);
    thread::spawn(move || server.run().expect("Server must run with no issues"));
    wait(100);

    let result = dummy_request_str(
        &addr,
        b"{\"jsonrpc\": \"2.0\", \"method\": \"say_hello\", \"params\": [42, 23], \"id\": 1}\n",
    );

    assert_eq!(
        result,
        "{\"jsonrpc\":\"2.0\",\"result\":\"hello\",\"id\":1}\n",
        "Response does not exactly much the expected response",
    );
}

#[derive(Clone)]
pub struct SocketMetadata {
    addr: SocketAddr,
}

impl Default for SocketMetadata {
    fn default() -> Self {
        SocketMetadata { addr: "0.0.0.0:0".parse().unwrap() }
    }
}

impl SocketMetadata {
    pub fn addr(&self) -> &SocketAddr {
        &self.addr
    }
}

impl Metadata for SocketMetadata { }

impl From<SocketAddr> for SocketMetadata {
    fn from(addr: SocketAddr) -> SocketMetadata {
        SocketMetadata { addr: addr }
    }
}

pub struct PeerMetaExtractor;

impl MetaExtractor<SocketMetadata> for PeerMetaExtractor {
    fn extract(&self, context: &RequestContext) -> SocketMetadata {
        context.peer_addr.into()
    }
}

fn meta_server(socket_addr: &SocketAddr) -> Server<SocketMetadata> {
    let mut io = MetaIoHandler::<SocketMetadata>::new();
    io.add_method_with_meta("say_hello", |_params, meta: SocketMetadata| {
        future::ok(Value::String(format!("hello, {}", meta.addr()))).boxed()
    });
    Server::new(socket_addr.clone(), Arc::new(io)).extractor(Arc::new(PeerMetaExtractor) as Arc<MetaExtractor<SocketMetadata>>)
}

#[test]
fn peer_meta() {
    ::logger::init_log();
    let addr: SocketAddr = "127.0.0.1:17785".parse().unwrap();
    let server = meta_server(&addr);
    thread::spawn(move || server.run().expect("Server must run with no issues"));
    wait(100);

    let result = dummy_request_str(
        &addr,
        b"{\"jsonrpc\": \"2.0\", \"method\": \"say_hello\", \"params\": [42, 23], \"id\": 1}\n"
    );

    // contains random port, so just smoky comparing response length
    assert_eq!(
        59,
        result.len()
    );
}

#[derive(Default)]
pub struct PeerListMetaExtractor {
    peers: Mutex<Vec<SocketAddr>>,
}

impl MetaExtractor<SocketMetadata> for PeerListMetaExtractor {
    fn extract(&self, context: &RequestContext) -> SocketMetadata {
        trace!(target: "tcp", "extracting to peer list...");
        self.peers.lock().unwrap().push(context.peer_addr.clone());
        context.peer_addr.into()
    }
}

#[test]
fn message() {

    /// MASSIVE SETUP
    ::logger::init_log();
    let addr: SocketAddr = "127.0.0.1:17790".parse().unwrap();
    let mut io = MetaIoHandler::<SocketMetadata>::new();
    io.add_method_with_meta("say_hello", |_params, _: SocketMetadata| {
        future::ok(Value::String("hello".to_owned())).boxed()
    });
    let peer_list = Arc::new(PeerListMetaExtractor::default());
    let server = Server::new(addr.clone(), Arc::new(io))
        .extractor(peer_list.clone() as Arc<MetaExtractor<SocketMetadata>>);
    let dispatcher = server.dispatcher();

    thread::spawn(move || server.run().expect("Server must run with no issues"));
    wait(100);

    let mut core = Core::new().expect("Tokio Core should be created with no errors");
    let timeout = Timeout::new(::std::time::Duration::from_millis(100), &core.handle())
        .expect("There should be a timeout produced in message test");
    let mut buffer = vec![0u8; 1024];
    let mut buffer2 = vec![0u8; 1024];
    let executed_dispatch = Mutex::new(false);
    let executed_request = Mutex::new(false);

    /// CLIENT RUN
    let stream = TcpStream::connect(&addr, &core.handle())
        .and_then(|stream| {
            future::ok(stream).join(timeout)
        })
        .and_then(|stream| {
            let peer_addr = peer_list.peers.lock().unwrap()[0].clone();
            dispatcher.push_message(
                &peer_addr,
                "ping".to_owned(),
            ).expect("Should be sent with no errors");
            trace!(target: "tcp", "Dispatched message for {}", peer_addr);
            future::ok(stream)
        })
        .and_then(|(stream, _)| {
            io::read(stream, &mut buffer)
        })
        .and_then(|(stream, read_buf, len)| {
            trace!(target: "tcp", "Read ping message");
            let ping_signal = read_buf[0..len].to_vec();

            assert_eq!(
                "ping\n",
                String::from_utf8(ping_signal).expect("String should be utf-8"),
                "Sent request does not match received by the peer",
            );
            // ensure tat the above assert was actually triggered
            *executed_dispatch.lock().unwrap() = true;

            future::ok(stream)
        })
        .and_then(|stream| {
            // make request AFTER message dispatches
            let data = b"{\"jsonrpc\": \"2.0\", \"method\": \"say_hello\", \"params\": [42, 23], \"id\": 1}\n";
            io::write_all(stream, &data[..])
        })
        .and_then(|(stream, _)| {
            io::read(stream, &mut buffer2)
        })
        .and_then(|(_, read_buf, len)| {
            trace!(target: "tcp", "Read response message");
            let response_signal = read_buf[0..len].to_vec();
            assert_eq!(
                "{\"jsonrpc\":\"2.0\",\"result\":\"hello\",\"id\":1}\n",
                String::from_utf8(response_signal).expect("String should be utf-8"),
                "Response does not match the expected handling",
            );
            *executed_request.lock().unwrap() = true;

            future::ok(())
        });

    core.run(stream).expect("Should be the payload in message test");
    assert!(*executed_dispatch.lock().unwrap());
    assert!(*executed_request.lock().unwrap());
}
<commit_msg>mutex -> refcell<commit_after>// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.

use std::sync::{Arc, Mutex};
use std::cell::RefCell;
use std::str::FromStr;
use std::net::SocketAddr;
use std::thread;

use tokio_core::reactor::{Core, Timeout};
use tokio_core::net::TcpStream;
use tokio_core::io;
use futures::{Future, future};

use jsonrpc::{MetaIoHandler, Value, Metadata};
use Server;
use MetaExtractor;
use RequestContext;

fn casual_server(socket_addr: &SocketAddr) -> Server {
    let mut io = MetaIoHandler::<()>::new();
    io.add_method("say_hello", |_params| {
        Ok(Value::String("hello".to_string()))
    });
    Server::new(socket_addr.clone(), Arc::new(io))
}

fn wait(millis: u64) {
    thread::sleep(::std::time::Duration::from_millis(millis));
}

#[test]
fn doc_test() {
    ::logger::init_log();

    let mut io = MetaIoHandler::<()>::new();
    io.add_method("say_hello", |_params| {
        Ok(Value::String("hello".to_string()))
    });
    let server = Server::new(SocketAddr::from_str("0.0.0.0:17770").unwrap(), Arc::new(io));
    thread::spawn(move || server.run().expect("Server must run with no issues"));
}

#[test]
fn doc_test_connect() {
    ::logger::init_log();
    let addr: SocketAddr = "127.0.0.1:17775".parse().unwrap();
    let server = casual_server(&addr);
    thread::spawn(move || server.run().expect("Server must run with no issues"));
    wait(100);

    let mut core = Core::new().expect("Tokio Core should be created with no errors");
    let stream = TcpStream::connect(&addr, &core.handle());
    let result = core.run(stream);

    assert!(result.is_ok());
}

fn dummy_request(addr: &SocketAddr, data: &[u8]) -> Vec<u8> {
    let mut core = Core::new().expect("Tokio Core should be created with no errors");
    let mut buffer = vec![0u8; 1024];

    let stream = TcpStream::connect(addr, &core.handle())
        .and_then(|stream| {
            io::write_all(stream, data)
        })
        .and_then(|(stream, _)| {
            io::read(stream, &mut buffer)
        })
        .and_then(|(_, read_buf, len)| {
            future::ok(read_buf[0..len].to_vec())
        });
    let result = core.run(stream).expect("Core should run with no errors");

    result
}

fn dummy_request_str(addr: &SocketAddr, data: &[u8]) -> String {
    String::from_utf8(dummy_request(addr, data)).expect("String should be utf-8")
}

#[test]
fn doc_test_handle() {
    ::logger::init_log();
    let addr: SocketAddr = "127.0.0.1:17780".parse().unwrap();
    let server = casual_server(&addr);
    thread::spawn(move || server.run().expect("Server must run with no issues"));
    wait(100);

    let result = dummy_request_str(
        &addr,
        b"{\"jsonrpc\": \"2.0\", \"method\": \"say_hello\", \"params\": [42, 23], \"id\": 1}\n",
    );

    assert_eq!(
        result,
        "{\"jsonrpc\":\"2.0\",\"result\":\"hello\",\"id\":1}\n",
        "Response does not exactly much the expected response",
    );
}

#[derive(Clone)]
pub struct SocketMetadata {
    addr: SocketAddr,
}

impl Default for SocketMetadata {
    fn default() -> Self {
        SocketMetadata { addr: "0.0.0.0:0".parse().unwrap() }
    }
}

impl SocketMetadata {
    pub fn addr(&self) -> &SocketAddr {
        &self.addr
    }
}

impl Metadata for SocketMetadata { }

impl From<SocketAddr> for SocketMetadata {
    fn from(addr: SocketAddr) -> SocketMetadata {
        SocketMetadata { addr: addr }
    }
}

pub struct PeerMetaExtractor;

impl MetaExtractor<SocketMetadata> for PeerMetaExtractor {
    fn extract(&self, context: &RequestContext) -> SocketMetadata {
        context.peer_addr.into()
    }
}

fn meta_server(socket_addr: &SocketAddr) -> Server<SocketMetadata> {
    let mut io = MetaIoHandler::<SocketMetadata>::new();
    io.add_method_with_meta("say_hello", |_params, meta: SocketMetadata| {
        future::ok(Value::String(format!("hello, {}", meta.addr()))).boxed()
    });
    Server::new(socket_addr.clone(), Arc::new(io)).extractor(Arc::new(PeerMetaExtractor) as Arc<MetaExtractor<SocketMetadata>>)
}

#[test]
fn peer_meta() {
    ::logger::init_log();
    let addr: SocketAddr = "127.0.0.1:17785".parse().unwrap();
    let server = meta_server(&addr);
    thread::spawn(move || server.run().expect("Server must run with no issues"));
    wait(100);

    let result = dummy_request_str(
        &addr,
        b"{\"jsonrpc\": \"2.0\", \"method\": \"say_hello\", \"params\": [42, 23], \"id\": 1}\n"
    );

    // contains random port, so just smoky comparing response length
    assert_eq!(
        59,
        result.len()
    );
}

#[derive(Default)]
pub struct PeerListMetaExtractor {
    peers: Mutex<Vec<SocketAddr>>,
}

impl MetaExtractor<SocketMetadata> for PeerListMetaExtractor {
    fn extract(&self, context: &RequestContext) -> SocketMetadata {
        trace!(target: "tcp", "extracting to peer list...");
        self.peers.lock().unwrap().push(context.peer_addr.clone());
        context.peer_addr.into()
    }
}

#[test]
fn message() {

    /// MASSIVE SETUP
    ::logger::init_log();
    let addr: SocketAddr = "127.0.0.1:17790".parse().unwrap();
    let mut io = MetaIoHandler::<SocketMetadata>::new();
    io.add_method_with_meta("say_hello", |_params, _: SocketMetadata| {
        future::ok(Value::String("hello".to_owned())).boxed()
    });
    let peer_list = Arc::new(PeerListMetaExtractor::default());
    let server = Server::new(addr.clone(), Arc::new(io))
        .extractor(peer_list.clone() as Arc<MetaExtractor<SocketMetadata>>);
    let dispatcher = server.dispatcher();

    thread::spawn(move || server.run().expect("Server must run with no issues"));
    wait(100);

    let mut core = Core::new().expect("Tokio Core should be created with no errors");
    let timeout = Timeout::new(::std::time::Duration::from_millis(100), &core.handle())
        .expect("There should be a timeout produced in message test");
    let mut buffer = vec![0u8; 1024];
    let mut buffer2 = vec![0u8; 1024];
    let executed_dispatch = RefCell::new(false);
    let executed_request = RefCell::new(false);

    /// CLIENT RUN
    let stream = TcpStream::connect(&addr, &core.handle())
        .and_then(|stream| {
            future::ok(stream).join(timeout)
        })
        .and_then(|stream| {
            let peer_addr = peer_list.peers.lock().unwrap()[0].clone();
            dispatcher.push_message(
                &peer_addr,
                "ping".to_owned(),
            ).expect("Should be sent with no errors");
            trace!(target: "tcp", "Dispatched message for {}", peer_addr);
            future::ok(stream)
        })
        .and_then(|(stream, _)| {
            io::read(stream, &mut buffer)
        })
        .and_then(|(stream, read_buf, len)| {
            trace!(target: "tcp", "Read ping message");
            let ping_signal = read_buf[0..len].to_vec();

            assert_eq!(
                "ping\n",
                String::from_utf8(ping_signal).expect("String should be utf-8"),
                "Sent request does not match received by the peer",
            );
            // ensure tat the above assert was actually triggered
            *executed_dispatch.borrow_mut() = true;

            future::ok(stream)
        })
        .and_then(|stream| {
            // make request AFTER message dispatches
            let data = b"{\"jsonrpc\": \"2.0\", \"method\": \"say_hello\", \"params\": [42, 23], \"id\": 1}\n";
            io::write_all(stream, &data[..])
        })
        .and_then(|(stream, _)| {
            io::read(stream, &mut buffer2)
        })
        .and_then(|(_, read_buf, len)| {
            trace!(target: "tcp", "Read response message");
            let response_signal = read_buf[0..len].to_vec();
            assert_eq!(
                "{\"jsonrpc\":\"2.0\",\"result\":\"hello\",\"id\":1}\n",
                String::from_utf8(response_signal).expect("String should be utf-8"),
                "Response does not match the expected handling",
            );
            *executed_request.borrow_mut() = true;

            future::ok(())
        });

    core.run(stream).expect("Should be the payload in message test");
    assert!(*executed_dispatch.borrow_mut());
    assert!(*executed_request.borrow_mut());
}
<|endoftext|>


<commit_before>/// There are utilities that can be used to do an inner join between
/// ordered iterators. This can be useful to do selects between multiple
/// tables of items

use std::iter::Peekable;
use std::collections::{
    btree_map, btree_set,
    tree_map, tree_set,
    trie_map, trie_set,
    vec_map,
    bitv_set
};

/// Allows an iterator to be do an inner join with another
/// iterator to combine their values or filter based on their keys.
/// this trait is applied to an iterator over a map like structure
pub trait OrderedMapIterator<K, A>: Iterator<(K, A)> {
    /// join two ordered maps together
    fn inner_join_map<B, T: OrderedMapIterator<K, B>>(self, map: T)
        -> InnerJoinMapIterator<Self, T> {
        InnerJoinMapIterator {
            a: self,
            b: map
        }
    }

    /// filter an ordered map with an ordered set
    fn inner_join_set<B, T: OrderedSetIterator<K>>(self, set: T)
        -> InnerJoinMapSetIterator<Self, T> {
        InnerJoinMapSetIterator {
            map: self,
            set: set
        }
    }

    /// Join an ordered iterator with the right ordered iterator. The
    /// new iterator will return a key value pair for every key in
    /// either iterator. If a key is present in both iterators they
    /// will be returned together (two values). If a value is in the Right,
    /// but not the left iterator it will be return without the value in the
    /// left iterator. If the value is in the left iterator by not the right
    /// that will be return without the value from the left iterator.
    fn outer_join<B, T: OrderedMapIterator<K, B>>(self, right: T)
        -> OuterJoinIterator<Self, T, (K, A), (K, B)> {
        OuterJoinIterator {
            left: self.peekable(),
            right: right.peekable()
        }
    }
}

/// Allows an iterator to be do an inner join with another
/// iterator to combine their values or filter based on their keys.
/// this trait is applied to an iterator over a set like structure
pub trait OrderedSetIterator<K>: Iterator<K> {
    /// join two ordered maps together
    fn inner_join_map<B, T: OrderedMapIterator<K, B>>(self, map: T)
        -> InnerJoinMapSetIterator<T, Self> {
        InnerJoinMapSetIterator {
            map: map,
            set: self
        }
    }

    /// filter an ordered map with an ordered set
    fn inner_join_set<T: OrderedSetIterator<K>>(self, map: T)
        -> InnerJoinSetIterator<Self, T> {
        InnerJoinSetIterator {
            a: self,
            b: map
        }
    }
}

pub struct InnerJoinMapIterator<A, B> {a: A, b: B}
pub struct InnerJoinMapSetIterator<A, B> {map: A, set: B}
pub struct InnerJoinSetIterator<A, B> {a: A, b: B}
pub struct OuterJoinIterator<A, B, VA, VB> {
    left: Peekable<VA, A>,
    right: Peekable<VB, B>
}

impl<K: Ord, DataA, DataB,
     A: OrderedMapIterator<K, DataA>,
     B: OrderedMapIterator<K, DataB>>
     Iterator<(K, (DataA, DataB))> for InnerJoinMapIterator<A, B> {

    fn next(&mut self) -> Option<(K, (DataA, DataB))> {
        let (mut key_a, mut data_a) = match self.a.next() {
            None => return None,
            Some((key, data)) => (key, data)
        };

        let (mut key_b, mut data_b) = match self.b.next() {
            None => return None,
            Some((key, data)) => (key, data)
        };

        loop {
            match key_a.cmp(&key_b) {
                Less => {
                    match self.a.next() {
                        None => return None,
                        Some((key, data)) => {
                            key_a = key;
                            data_a = data;
                        }
                    };
                },
                Equal => return Some((key_a, (data_a, data_b))),
                Greater => {
                    match self.b.next() {
                        None => return None,
                        Some((key, data)) => {
                            key_b = key;
                            data_b = data;
                        }
                    };
                }
            }
        }
    }
}

impl<K: Ord,
     A: OrderedSetIterator<K>,
     B: OrderedSetIterator<K>>
     Iterator<K> for InnerJoinSetIterator<A, B> {
    fn next(&mut self) -> Option<K> {
        let mut key_a = match self.a.next() {
            None => return None,
            Some(key) => key
        };

        let mut key_b = match self.b.next() {
            None => return None,
            Some(key) => key
        };

        loop {
            match key_a.cmp(&key_b) {
                Less => {
                    match self.a.next() {
                        None => return None,
                        Some(key) => { key_a = key; }
                    };
                },
                Equal => return Some(key_a),
                Greater => {
                    match self.b.next() {
                        None => return None,
                        Some(key) => { key_b = key; }
                    };
                }
            }
        }
    }
}

impl<K: Ord,
     V,
     SetIter: OrderedSetIterator<K>,
     MapIter: OrderedMapIterator<K, V>>
     Iterator<(K, V)> for InnerJoinMapSetIterator<MapIter, SetIter> {
    fn next(&mut self) -> Option<(K, V)> {
        let mut key_set = match self.set.next() {
            None => return None,
            Some(key) => key
        };

        let (mut key_map, mut data) = match self.map.next() {
            None => return None,
            Some((key, data)) => (key, data)
        };

        loop {
            match key_set.cmp(&key_map) {
                Less => {
                    match self.set.next() {
                        None => return None,
                        Some(key) => { key_set = key; }
                    };
                },
                Equal => return Some((key_set, data)),
                Greater => {
                    match self.map.next() {
                        None => return None,
                        Some((key, d)) => {
                            key_map = key;
                            data = d;
                        }
                    };
                }
            }
        }
    }
}

impl<K: Ord+Eq,
     VA, VB,
     A: OrderedMapIterator<K, VA>,
     B: OrderedMapIterator<K, VB>>
     Iterator<(K, (Option<VA>, Option<VB>))> for OuterJoinIterator<A, B, (K, VA), (K, VB)> {

    fn next(&mut self) -> Option<(K, (Option<VA>, Option<VB>))> {
        let which = match (self.left.peek(), self.right.peek()) {
            (Some(&(ref ka, _)), Some(&(ref kb, _))) => kb.cmp(ka),
            (None, Some(_)) => Less,
            (Some(_), None) => Greater,
            (None, None) => return None
        };

        match which {
            Equal => {
                let ((k, a), (_, b)) =
                    (self.left.next().expect("no value found"),
                     self.right.next().expect("no value found"));

                Some((k, (Some(a), Some(b))))
            }
            Less => {
                let (k, v) = self.right.next().expect("no value found");
                Some((k, (None, Some(v))))
            }
            Greater => {
                let (k, v) = self.left.next().expect("no value found");
                Some((k, (Some(v), None)))
            }
        }
    }
}

impl<'a, K: Ord> OrderedSetIterator<&'a K> for btree_set::Items<'a, K> {}
impl<'a, K: Ord, V> OrderedMapIterator<&'a K, &'a V> for btree_map::Entries<'a, K, V> {}
impl<'a, K: Ord> OrderedSetIterator<&'a K> for tree_set::SetItems<'a, K> {}
impl<'a, K: Ord, V> OrderedMapIterator<&'a K, &'a V> for tree_map::Entries<'a, K, V> {}
impl<'a> OrderedSetIterator<uint> for trie_set::SetItems<'a> {}
impl<'a, V> OrderedMapIterator<uint, &'a V> for trie_map::Entries<'a, V> {}
impl<'a, V> OrderedMapIterator<uint, &'a V> for vec_map::Entries<'a, V> {}
impl<'a> OrderedSetIterator<uint> for bitv_set::BitPositions<'a> {}

impl<K: Ord, VA, VB,
     A: OrderedMapIterator<K, VA>,
     B: OrderedMapIterator<K, VB>> OrderedMapIterator<K, (VA, VB)> for InnerJoinMapIterator<A, B> {}
impl<K: Ord, V,
     A: OrderedSetIterator<K>,
     B: OrderedMapIterator<K, V>> OrderedMapIterator<K, V> for InnerJoinMapSetIterator<B, A> {}
impl<K: Ord,
     A: OrderedSetIterator<K>,
     B: OrderedSetIterator<K>> OrderedSetIterator<K> for InnerJoinSetIterator<A, B> {}

#[cfg(test)]
mod tests {
    use test::Bencher;
    use test;

    use super::{OrderedSetIterator, OrderedMapIterator};

    #[test]
    fn join_two_sets() {
        use std::collections::BTreeSet;

        let powers_of_two: BTreeSet<int> = range(1, 10).map(|x| x * 2).collect();
        let powers_of_three: BTreeSet<int> = range(1, 10).map(|x| x * 3).collect();

        let expected = vec![6i, 12, 18];

        let powers_of_two_and_three: Vec<int> =
            powers_of_two.iter()
            .inner_join_set(powers_of_three.iter())
            .map(|&x| x)
            .collect();

        assert_eq!(expected, powers_of_two_and_three);
    }

    #[test]
    fn join_three_sets() {
        use std::collections::BTreeSet;

        let powers_of_two: BTreeSet<int> = range(1, 100).map(|x| x * 2).collect();
        let powers_of_three: BTreeSet<int> = range(1, 100).map(|x| x * 3).collect();
        let powers_of_five: BTreeSet<int> = range(1, 100).map(|x| x * 5).collect();

        let expected = vec![30, 60, 90, 120, 150, 180];

        let powers_of_two_and_three: Vec<int> =
            powers_of_two.iter()
            .inner_join_set(powers_of_three.iter())
            .inner_join_set(powers_of_five.iter())
            .map(|&x| x)
            .collect();

        assert_eq!(expected, powers_of_two_and_three);
    }

    #[test]
    fn join_two_maps() {
        use std::collections::BTreeMap;

        let powers_of_two: BTreeMap<int, int> = range(1i, 10).map(|x| (x * 2, x)).collect();
        let powers_of_three: BTreeMap<int, int> = range(1i, 10).map(|x| (x * 3, x)).collect();

        let mut powers_of_two_and_three =
            powers_of_two.iter().inner_join_map(powers_of_three.iter())
            .map(|(&k, (&a, &b))| (k, a, b));

        assert_eq!(Some((6, 3, 2)), powers_of_two_and_three.next())
        assert_eq!(Some((12, 6, 4)), powers_of_two_and_three.next())
        assert_eq!(Some((18, 9, 6)), powers_of_two_and_three.next())
        assert_eq!(None, powers_of_two_and_three.next())
    }

    #[test]
    fn join_two_maps_to_set() {
        use std::collections::{BTreeMap, BTreeSet};

        let powers_of_two: BTreeSet<int> = range(1, 10).map(|x| x * 2).collect();
        let powers_of_three: BTreeMap<int, int> = range(1i, 10).map(|x| (x * 3, x)).collect();

        let mut powers_of_two_and_three =
            powers_of_two.iter().inner_join_map(powers_of_three.iter())
            .map(|(&k, &a)| (k, a));

        assert_eq!(Some((6, 2)), powers_of_two_and_three.next())
        assert_eq!(Some((12, 4)), powers_of_two_and_three.next())
        assert_eq!(Some((18, 6)), powers_of_two_and_three.next())
        assert_eq!(None, powers_of_two_and_three.next())
    }

    #[test]
    fn outer_join_fizz_buzz() {
        use std::collections::BTreeMap;

        let mul_of_three: BTreeMap<int, int> = range(0, 100).map(|x| (x*3, x)).collect();
        let mul_of_five: BTreeMap<int, int> = range(0, 100).map(|x| (x*5, x)).collect();

        let mut fizz_buzz = BTreeMap::new();

        for (key, (three, five)) in mul_of_three.iter()
                                                .outer_join(mul_of_five.iter()) {
            fizz_buzz.insert(key, (three.is_some(), five.is_some()));
        }

        let res: BTreeMap<int, String> = range(1, 100).map(|i|
            (i, match fizz_buzz.get(&i) {
                None => format!("{}", i),
                Some(&(true, false)) => format!("Fizz"),
                Some(&(false, true)) => format!("Buzz"),
                Some(&(true, true)) => format!("FizzBuzz"),
                Some(&(false, false)) => panic!("Outer join failed...")
            })).collect();

        for i in range(1, 100) {
            match (i % 3, i % 5) {
                (0, 0) => assert_eq!("FizzBuzz", res[i].as_slice()),
                (0, _) => assert_eq!("Fizz", res[i].as_slice()),
                (_, 0) => assert_eq!("Buzz", res[i].as_slice()),
                _ => assert_eq!(format!("{}", i).as_slice(), res[i].as_slice())
            }
        }
    }

    #[bench]
    pub fn inner_join_map(b: &mut test::Bencher) {
        use std::collections::BTreeSet;

        let powers_of_two: BTreeSet<uint> = range(1u, 1000000).map(|x| x * 2).collect();
        let powers_of_three: BTreeSet<uint> = range(1u, 1000000).map(|x| x * 3).collect();

        b.iter(||{
            for x in powers_of_two.iter()
                .inner_join_set(powers_of_three.iter()) {

                test::black_box(x);
            }
        })
    }
}<commit_msg>Fixup macros being used as statements.<commit_after>/// There are utilities that can be used to do an inner join between
/// ordered iterators. This can be useful to do selects between multiple
/// tables of items

use std::iter::Peekable;
use std::collections::{
    btree_map, btree_set,
    tree_map, tree_set,
    trie_map, trie_set,
    vec_map,
    bitv_set
};

/// Allows an iterator to be do an inner join with another
/// iterator to combine their values or filter based on their keys.
/// this trait is applied to an iterator over a map like structure
pub trait OrderedMapIterator<K, A>: Iterator<(K, A)> {
    /// join two ordered maps together
    fn inner_join_map<B, T: OrderedMapIterator<K, B>>(self, map: T)
        -> InnerJoinMapIterator<Self, T> {
        InnerJoinMapIterator {
            a: self,
            b: map
        }
    }

    /// filter an ordered map with an ordered set
    fn inner_join_set<B, T: OrderedSetIterator<K>>(self, set: T)
        -> InnerJoinMapSetIterator<Self, T> {
        InnerJoinMapSetIterator {
            map: self,
            set: set
        }
    }

    /// Join an ordered iterator with the right ordered iterator. The
    /// new iterator will return a key value pair for every key in
    /// either iterator. If a key is present in both iterators they
    /// will be returned together (two values). If a value is in the Right,
    /// but not the left iterator it will be return without the value in the
    /// left iterator. If the value is in the left iterator by not the right
    /// that will be return without the value from the left iterator.
    fn outer_join<B, T: OrderedMapIterator<K, B>>(self, right: T)
        -> OuterJoinIterator<Self, T, (K, A), (K, B)> {
        OuterJoinIterator {
            left: self.peekable(),
            right: right.peekable()
        }
    }
}

/// Allows an iterator to be do an inner join with another
/// iterator to combine their values or filter based on their keys.
/// this trait is applied to an iterator over a set like structure
pub trait OrderedSetIterator<K>: Iterator<K> {
    /// join two ordered maps together
    fn inner_join_map<B, T: OrderedMapIterator<K, B>>(self, map: T)
        -> InnerJoinMapSetIterator<T, Self> {
        InnerJoinMapSetIterator {
            map: map,
            set: self
        }
    }

    /// filter an ordered map with an ordered set
    fn inner_join_set<T: OrderedSetIterator<K>>(self, map: T)
        -> InnerJoinSetIterator<Self, T> {
        InnerJoinSetIterator {
            a: self,
            b: map
        }
    }
}

pub struct InnerJoinMapIterator<A, B> {a: A, b: B}
pub struct InnerJoinMapSetIterator<A, B> {map: A, set: B}
pub struct InnerJoinSetIterator<A, B> {a: A, b: B}
pub struct OuterJoinIterator<A, B, VA, VB> {
    left: Peekable<VA, A>,
    right: Peekable<VB, B>
}

impl<K: Ord, DataA, DataB,
     A: OrderedMapIterator<K, DataA>,
     B: OrderedMapIterator<K, DataB>>
     Iterator<(K, (DataA, DataB))> for InnerJoinMapIterator<A, B> {

    fn next(&mut self) -> Option<(K, (DataA, DataB))> {
        let (mut key_a, mut data_a) = match self.a.next() {
            None => return None,
            Some((key, data)) => (key, data)
        };

        let (mut key_b, mut data_b) = match self.b.next() {
            None => return None,
            Some((key, data)) => (key, data)
        };

        loop {
            match key_a.cmp(&key_b) {
                Less => {
                    match self.a.next() {
                        None => return None,
                        Some((key, data)) => {
                            key_a = key;
                            data_a = data;
                        }
                    };
                },
                Equal => return Some((key_a, (data_a, data_b))),
                Greater => {
                    match self.b.next() {
                        None => return None,
                        Some((key, data)) => {
                            key_b = key;
                            data_b = data;
                        }
                    };
                }
            }
        }
    }
}

impl<K: Ord,
     A: OrderedSetIterator<K>,
     B: OrderedSetIterator<K>>
     Iterator<K> for InnerJoinSetIterator<A, B> {
    fn next(&mut self) -> Option<K> {
        let mut key_a = match self.a.next() {
            None => return None,
            Some(key) => key
        };

        let mut key_b = match self.b.next() {
            None => return None,
            Some(key) => key
        };

        loop {
            match key_a.cmp(&key_b) {
                Less => {
                    match self.a.next() {
                        None => return None,
                        Some(key) => { key_a = key; }
                    };
                },
                Equal => return Some(key_a),
                Greater => {
                    match self.b.next() {
                        None => return None,
                        Some(key) => { key_b = key; }
                    };
                }
            }
        }
    }
}

impl<K: Ord,
     V,
     SetIter: OrderedSetIterator<K>,
     MapIter: OrderedMapIterator<K, V>>
     Iterator<(K, V)> for InnerJoinMapSetIterator<MapIter, SetIter> {
    fn next(&mut self) -> Option<(K, V)> {
        let mut key_set = match self.set.next() {
            None => return None,
            Some(key) => key
        };

        let (mut key_map, mut data) = match self.map.next() {
            None => return None,
            Some((key, data)) => (key, data)
        };

        loop {
            match key_set.cmp(&key_map) {
                Less => {
                    match self.set.next() {
                        None => return None,
                        Some(key) => { key_set = key; }
                    };
                },
                Equal => return Some((key_set, data)),
                Greater => {
                    match self.map.next() {
                        None => return None,
                        Some((key, d)) => {
                            key_map = key;
                            data = d;
                        }
                    };
                }
            }
        }
    }
}

impl<K: Ord+Eq,
     VA, VB,
     A: OrderedMapIterator<K, VA>,
     B: OrderedMapIterator<K, VB>>
     Iterator<(K, (Option<VA>, Option<VB>))> for OuterJoinIterator<A, B, (K, VA), (K, VB)> {

    fn next(&mut self) -> Option<(K, (Option<VA>, Option<VB>))> {
        let which = match (self.left.peek(), self.right.peek()) {
            (Some(&(ref ka, _)), Some(&(ref kb, _))) => kb.cmp(ka),
            (None, Some(_)) => Less,
            (Some(_), None) => Greater,
            (None, None) => return None
        };

        match which {
            Equal => {
                let ((k, a), (_, b)) =
                    (self.left.next().expect("no value found"),
                     self.right.next().expect("no value found"));

                Some((k, (Some(a), Some(b))))
            }
            Less => {
                let (k, v) = self.right.next().expect("no value found");
                Some((k, (None, Some(v))))
            }
            Greater => {
                let (k, v) = self.left.next().expect("no value found");
                Some((k, (Some(v), None)))
            }
        }
    }
}

impl<'a, K: Ord> OrderedSetIterator<&'a K> for btree_set::Items<'a, K> {}
impl<'a, K: Ord, V> OrderedMapIterator<&'a K, &'a V> for btree_map::Entries<'a, K, V> {}
impl<'a, K: Ord> OrderedSetIterator<&'a K> for tree_set::SetItems<'a, K> {}
impl<'a, K: Ord, V> OrderedMapIterator<&'a K, &'a V> for tree_map::Entries<'a, K, V> {}
impl<'a> OrderedSetIterator<uint> for trie_set::SetItems<'a> {}
impl<'a, V> OrderedMapIterator<uint, &'a V> for trie_map::Entries<'a, V> {}
impl<'a, V> OrderedMapIterator<uint, &'a V> for vec_map::Entries<'a, V> {}
impl<'a> OrderedSetIterator<uint> for bitv_set::BitPositions<'a> {}

impl<K: Ord, VA, VB,
     A: OrderedMapIterator<K, VA>,
     B: OrderedMapIterator<K, VB>> OrderedMapIterator<K, (VA, VB)> for InnerJoinMapIterator<A, B> {}
impl<K: Ord, V,
     A: OrderedSetIterator<K>,
     B: OrderedMapIterator<K, V>> OrderedMapIterator<K, V> for InnerJoinMapSetIterator<B, A> {}
impl<K: Ord,
     A: OrderedSetIterator<K>,
     B: OrderedSetIterator<K>> OrderedSetIterator<K> for InnerJoinSetIterator<A, B> {}

#[cfg(test)]
mod tests {
    use test::Bencher;
    use test;

    use super::{OrderedSetIterator, OrderedMapIterator};

    #[test]
    fn join_two_sets() {
        use std::collections::BTreeSet;

        let powers_of_two: BTreeSet<int> = range(1, 10).map(|x| x * 2).collect();
        let powers_of_three: BTreeSet<int> = range(1, 10).map(|x| x * 3).collect();

        let expected = vec![6i, 12, 18];

        let powers_of_two_and_three: Vec<int> =
            powers_of_two.iter()
            .inner_join_set(powers_of_three.iter())
            .map(|&x| x)
            .collect();

        assert_eq!(expected, powers_of_two_and_three);
    }

    #[test]
    fn join_three_sets() {
        use std::collections::BTreeSet;

        let powers_of_two: BTreeSet<int> = range(1, 100).map(|x| x * 2).collect();
        let powers_of_three: BTreeSet<int> = range(1, 100).map(|x| x * 3).collect();
        let powers_of_five: BTreeSet<int> = range(1, 100).map(|x| x * 5).collect();

        let expected = vec![30, 60, 90, 120, 150, 180];

        let powers_of_two_and_three: Vec<int> =
            powers_of_two.iter()
            .inner_join_set(powers_of_three.iter())
            .inner_join_set(powers_of_five.iter())
            .map(|&x| x)
            .collect();

        assert_eq!(expected, powers_of_two_and_three);
    }

    #[test]
    fn join_two_maps() {
        use std::collections::BTreeMap;

        let powers_of_two: BTreeMap<int, int> = range(1i, 10).map(|x| (x * 2, x)).collect();
        let powers_of_three: BTreeMap<int, int> = range(1i, 10).map(|x| (x * 3, x)).collect();

        let mut powers_of_two_and_three =
            powers_of_two.iter().inner_join_map(powers_of_three.iter())
            .map(|(&k, (&a, &b))| (k, a, b));

        assert_eq!(Some((6, 3, 2)), powers_of_two_and_three.next());
        assert_eq!(Some((12, 6, 4)), powers_of_two_and_three.next());
        assert_eq!(Some((18, 9, 6)), powers_of_two_and_three.next());
        assert_eq!(None, powers_of_two_and_three.next());
    }

    #[test]
    fn join_two_maps_to_set() {
        use std::collections::{BTreeMap, BTreeSet};

        let powers_of_two: BTreeSet<int> = range(1, 10).map(|x| x * 2).collect();
        let powers_of_three: BTreeMap<int, int> = range(1i, 10).map(|x| (x * 3, x)).collect();

        let mut powers_of_two_and_three =
            powers_of_two.iter().inner_join_map(powers_of_three.iter())
            .map(|(&k, &a)| (k, a));

        assert_eq!(Some((6, 2)), powers_of_two_and_three.next());
        assert_eq!(Some((12, 4)), powers_of_two_and_three.next());
        assert_eq!(Some((18, 6)), powers_of_two_and_three.next());
        assert_eq!(None, powers_of_two_and_three.next());
    }

    #[test]
    fn outer_join_fizz_buzz() {
        use std::collections::BTreeMap;

        let mul_of_three: BTreeMap<int, int> = range(0, 100).map(|x| (x*3, x)).collect();
        let mul_of_five: BTreeMap<int, int> = range(0, 100).map(|x| (x*5, x)).collect();

        let mut fizz_buzz = BTreeMap::new();

        for (key, (three, five)) in mul_of_three.iter()
                                                .outer_join(mul_of_five.iter()) {
            fizz_buzz.insert(key, (three.is_some(), five.is_some()));
        }

        let res: BTreeMap<int, String> = range(1, 100).map(|i|
            (i, match fizz_buzz.get(&i) {
                None => format!("{}", i),
                Some(&(true, false)) => format!("Fizz"),
                Some(&(false, true)) => format!("Buzz"),
                Some(&(true, true)) => format!("FizzBuzz"),
                Some(&(false, false)) => panic!("Outer join failed...")
            })).collect();

        for i in range(1, 100) {
            match (i % 3, i % 5) {
                (0, 0) => assert_eq!("FizzBuzz", res[i].as_slice()),
                (0, _) => assert_eq!("Fizz", res[i].as_slice()),
                (_, 0) => assert_eq!("Buzz", res[i].as_slice()),
                _ => assert_eq!(format!("{}", i).as_slice(), res[i].as_slice())
            }
        }
    }

    #[bench]
    pub fn inner_join_map(b: &mut test::Bencher) {
        use std::collections::BTreeSet;

        let powers_of_two: BTreeSet<uint> = range(1u, 1000000).map(|x| x * 2).collect();
        let powers_of_three: BTreeSet<uint> = range(1u, 1000000).map(|x| x * 3).collect();

        b.iter(||{
            for x in powers_of_two.iter()
                .inner_join_set(powers_of_three.iter()) {

                test::black_box(x);
            }
        })
    }
}
<|endoftext|>


<commit_before>#![feature(rustc_private)]

extern crate clippy_lints;
extern crate syntax;
use std::collections::Bound;

#[test]
fn test_overlapping() {
    use clippy_lints::matches::overlapping;
    use syntax::source_map::DUMMY_SP;

    let sp = |s, e| clippy_lints::matches::SpannedRange {
        span: DUMMY_SP,
        node: (s, e),
    };

    assert_eq!(None, overlapping::<u8>(&[]));
    assert_eq!(None, overlapping(&[sp(1, Bound::Included(4))]));
    assert_eq!(
        None,
        overlapping(&[sp(1, Bound::Included(4)), sp(5, Bound::Included(6))])
    );
    assert_eq!(
        None,
        overlapping(&[
            sp(1, Bound::Included(4)),
            sp(5, Bound::Included(6)),
            sp(10, Bound::Included(11))
        ],)
    );
    assert_eq!(
        Some((&sp(1, Bound::Included(4)), &sp(3, Bound::Included(6)))),
        overlapping(&[sp(1, Bound::Included(4)), sp(3, Bound::Included(6))])
    );
    assert_eq!(
        Some((&sp(5, Bound::Included(6)), &sp(6, Bound::Included(11)))),
        overlapping(&[
            sp(1, Bound::Included(4)),
            sp(5, Bound::Included(6)),
            sp(6, Bound::Included(11))
        ],)
    );
}
<commit_msg>Reintroduce `extern crate` for non-Cargo dependencies, in tests.<commit_after>#![feature(rustc_private)]

extern crate clippy_lints;
extern crate syntax;
use std::collections::Bound;

#[test]
fn test_overlapping() {
    use clippy_lints::matches::overlapping;
    use crate::syntax::source_map::DUMMY_SP;

    let sp = |s, e| clippy_lints::matches::SpannedRange {
        span: DUMMY_SP,
        node: (s, e),
    };

    assert_eq!(None, overlapping::<u8>(&[]));
    assert_eq!(None, overlapping(&[sp(1, Bound::Included(4))]));
    assert_eq!(
        None,
        overlapping(&[sp(1, Bound::Included(4)), sp(5, Bound::Included(6))])
    );
    assert_eq!(
        None,
        overlapping(&[
            sp(1, Bound::Included(4)),
            sp(5, Bound::Included(6)),
            sp(10, Bound::Included(11))
        ],)
    );
    assert_eq!(
        Some((&sp(1, Bound::Included(4)), &sp(3, Bound::Included(6)))),
        overlapping(&[sp(1, Bound::Included(4)), sp(3, Bound::Included(6))])
    );
    assert_eq!(
        Some((&sp(5, Bound::Included(6)), &sp(6, Bound::Included(11)))),
        overlapping(&[
            sp(1, Bound::Included(4)),
            sp(5, Bound::Included(6)),
            sp(6, Bound::Included(11))
        ],)
    );
}
<|endoftext|>


<commit_before>// Copyright 2013 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.

/*! Synchronous I/O

This module defines the Rust interface for synchronous I/O.
It supports file access,

This will likely live in core::io, not core::rt::io.

# Examples

Some examples of obvious things you might want to do

* Read lines from stdin

    for stdin().each_line |line| {
        println(line)
    }

* Read a complete file to a string, (converting newlines?)

    let contents = open("message.txt").read_to_str(); // read_to_str??

* Write a line to a file

    let file = FileStream::open("message.txt", Create, Write);
    file.write_line("hello, file!");

* Iterate over the lines of a file

* Pull the lines of a file into a vector of strings

* Connect based on URL? Requires thinking about where the URL type lives
  and how to make protocol handlers extensible, e.g. the "tcp" protocol
  yields a `TcpStream`.

    connect("tcp://localhost:8080").write_line("HTTP 1.0 GET /");

# Terms

* reader
* writer
* stream
* Blocking vs. non-blocking
* synchrony and asynchrony

I tend to call this implementation non-blocking, because performing I/O
doesn't block the progress of other tasks. Is that how we want to present
it, 'synchronous but non-blocking'?

# Error Handling

# Resource management

* `close` vs. RAII

# Paths and URLs

# std

Some I/O things don't belong in core

  - url
  - net - `fn connect`
    - http
  - flate

# XXX

* Should default constructors take `Path` or `&str`? `Path` makes simple cases verbose.
  Overloading would be nice.
* Add overloading for Path and &str and Url &str
* stdin/err/out
* print, println, etc.
* fsync
* relationship with filesystem querying, Directory, File types etc.
* Rename Reader/Writer to ByteReader/Writer, make Reader/Writer generic?
* Trait for things that are both readers and writers, Stream?
* How to handle newline conversion
* String conversion
* File vs. FileStream? File is shorter but could also be used for getting file info
  - maybe File is for general file querying and *also* has a static `open` method
* open vs. connect for generic stream opening
* Do we need `close` at all? dtors might be good enough
* How does I/O relate to the Iterator trait?
* std::base64 filters

*/

use prelude::*;

// Reexports
pub use self::stdio::stdin;
pub use self::stdio::stdout;
pub use self::stdio::stderr;
pub use self::stdio::print;
pub use self::stdio::println;

pub use self::file::FileStream;
pub use self::net::Listener;
pub use self::net::ip::IpAddr;
pub use self::net::tcp::TcpListener;
pub use self::net::tcp::TcpStream;
pub use self::net::udp::UdpStream;

// Some extension traits that all Readers and Writers get.
pub use self::extensions::ReaderUtil;
pub use self::extensions::ReaderByteConversions;
pub use self::extensions::WriterByteConversions;

/// Synchronous, non-blocking file I/O.
pub mod file;

/// Synchronous, non-blocking network I/O.
#[path = "net/mod.rs"]
pub mod net;

/// Readers and Writers for memory buffers and strings.
#[cfg(not(stage0))] // XXX Using unsnapshotted features
pub mod mem;

/// Non-blocking access to stdin, stdout, stderr
pub mod stdio;

/// Basic stream compression. XXX: Belongs with other flate code
#[cfg(not(stage0))] // XXX Using unsnapshotted features
pub mod flate;

/// Interop between byte streams and pipes. Not sure where it belongs
#[cfg(not(stage0))] // XXX "
pub mod comm_adapters;

/// Extension traits
mod extensions;

/// Non-I/O things needed by the I/O module
mod support;

/// Thread-blocking implementations
pub mod native {
    /// Posix file I/O
    pub mod file;
    /// # XXX - implement this
    pub mod stdio { }
    /// Sockets
    /// # XXX - implement this
    pub mod net {
        pub mod tcp { }
        pub mod udp { }
        #[cfg(unix)]
        pub mod unix { }
    }
}

/// The type passed to I/O condition handlers to indicate error
///
/// # XXX
///
/// Is something like this sufficient? It's kind of archaic
pub struct IoError {
    kind: IoErrorKind,
    desc: &'static str,
    detail: Option<~str>
}

pub enum IoErrorKind {
    FileNotFound,
    FilePermission,
    ConnectionFailed,
    Closed,
    OtherIoError
}

// XXX: Can't put doc comments on macros
// Raised by `I/O` operations on error.
condition! {
    io_error: super::IoError -> ();
}

pub trait Reader {
    /// Read bytes, up to the length of `buf` and place them in `buf`.
    /// Returns the number of bytes read, or `None` on EOF.
    ///
    /// # Failure
    ///
    /// Raises the `io_error` condition on error, then returns `None`.
    ///
    /// # XXX
    ///
    /// This doesn't take a `len` argument like the old `read`.
    /// Will people often need to slice their vectors to call this
    /// and will that be annoying?
    fn read(&mut self, buf: &mut [u8]) -> Option<uint>;

    /// Return whether the Reader has reached the end of the stream.
    ///
    /// # Example
    ///
    ///     let reader = FileStream::new()
    ///     while !reader.eof() {
    ///         println(reader.read_line());
    ///     }
    ///
    /// # XXX
    ///
    /// What does this return if the Reader is in an error state?
    fn eof(&mut self) -> bool;
}

pub trait Writer {
    /// Write the given buffer
    ///
    /// # Failure
    ///
    /// Raises the `io_error` condition on error
    fn write(&mut self, buf: &[u8]);

    /// Flush output
    fn flush(&mut self);
}

/// I/O types that may be closed
///
/// Any further operations performed on a closed resource will raise
/// on `io_error`
pub trait Close {
    /// Close the I/O resource
    fn close(&mut self);
}

pub trait Stream: Reader + Writer + Close { }

pub enum SeekStyle {
    /// Seek from the beginning of the stream
    SeekSet,
    /// Seek from the end of the stream
    SeekEnd,
    /// Seek from the current position
    SeekCur,
}

/// # XXX
/// * Are `u64` and `i64` the right choices?
pub trait Seek {
    fn tell(&self) -> u64;
    fn seek(&mut self, pos: i64, style: SeekStyle);
}

/// Common trait for decorator types.
///
/// Provides accessors to get the inner, 'decorated' values. The I/O library
/// uses decorators to add functionality like compression and encryption to I/O
/// streams.
///
/// # XXX
///
/// Is this worth having a trait for? May be overkill
pub trait Decorator<T> {
    /// Destroy the decorator and extract the decorated value
    ///
    /// # XXX
    ///
    /// Because this takes `self' one could never 'undecorate' a Reader/Writer
    /// that has been boxed. Is that ok? This feature is mostly useful for
    /// extracting the buffer from MemWriter
    fn inner(self) -> T;

    /// Take an immutable reference to the decorated value
    fn inner_ref<'a>(&'a self) -> &'a T;

    /// Take a mutable reference to the decorated value
    fn inner_mut_ref<'a>(&'a mut self) -> &'a mut T;
}
<commit_msg>core::rt: Just some poking at the I/O docs<commit_after>// Copyright 2013 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.

/*! Synchronous I/O

This module defines the Rust interface for synchronous I/O.  It is
build around Reader and Writer traits that define byte stream sources
and sinks.  Implementations are provided for common I/O streams like
file, TCP, UDP, Unix domain sockets, multiple types of memory bufers.
Readers and Writers may be composed to add things like string parsing,
and compression.

This will likely live in core::io, not core::rt::io.

# Examples

Some examples of obvious things you might want to do

* Read lines from stdin

    for stdin().each_line |line| {
        println(line)
    }

* Read a complete file to a string, (converting newlines?)

    let contents = FileStream::open("message.txt").read_to_str(); // read_to_str??

* Write a line to a file

    let file = FileStream::open("message.txt", Create, Write);
    file.write_line("hello, file!");

* Iterate over the lines of a file

    do FileStream::open("message.txt").each_line |line| {
        println(line)
    }

* Pull the lines of a file into a vector of strings

    let lines = FileStream::open("message.txt").line_iter().to_vec();

* Make an simple HTTP request

    let socket = TcpStream::open("localhost:8080");
    socket.write_line("GET / HTTP/1.0");
    socket.write_line("");
    let response = socket.read_to_end();

* Connect based on URL? Requires thinking about where the URL type lives
  and how to make protocol handlers extensible, e.g. the "tcp" protocol
  yields a `TcpStream`.

    connect("tcp://localhost:8080");

# Terms

* reader
* writer
* stream
* Blocking vs. non-blocking
* synchrony and asynchrony

I tend to call this implementation non-blocking, because performing I/O
doesn't block the progress of other tasks. Is that how we want to present
it, 'synchronous but non-blocking'?

# Error Handling

# Resource management

* `close` vs. RAII

# Paths and URLs

# std

Some I/O things don't belong in core

  - url
  - net - `fn connect`
    - http
  - flate

# XXX

* Should default constructors take `Path` or `&str`? `Path` makes simple cases verbose.
  Overloading would be nice.
* Add overloading for Path and &str and Url &str
* stdin/err/out
* print, println, etc.
* fsync
* relationship with filesystem querying, Directory, File types etc.
* Rename Reader/Writer to ByteReader/Writer, make Reader/Writer generic?
* Trait for things that are both readers and writers, Stream?
* How to handle newline conversion
* String conversion
* File vs. FileStream? File is shorter but could also be used for getting file info
  - maybe File is for general file querying and *also* has a static `open` method
* open vs. connect for generic stream opening
* Do we need `close` at all? dtors might be good enough
* How does I/O relate to the Iterator trait?
* std::base64 filters

*/

use prelude::*;

// Reexports
pub use self::stdio::stdin;
pub use self::stdio::stdout;
pub use self::stdio::stderr;
pub use self::stdio::print;
pub use self::stdio::println;

pub use self::file::FileStream;
pub use self::net::Listener;
pub use self::net::ip::IpAddr;
pub use self::net::tcp::TcpListener;
pub use self::net::tcp::TcpStream;
pub use self::net::udp::UdpStream;

// Some extension traits that all Readers and Writers get.
pub use self::extensions::ReaderUtil;
pub use self::extensions::ReaderByteConversions;
pub use self::extensions::WriterByteConversions;

/// Synchronous, non-blocking file I/O.
pub mod file;

/// Synchronous, non-blocking network I/O.
#[path = "net/mod.rs"]
pub mod net;

/// Readers and Writers for memory buffers and strings.
#[cfg(not(stage0))] // XXX Using unsnapshotted features
pub mod mem;

/// Non-blocking access to stdin, stdout, stderr
pub mod stdio;

/// Basic stream compression. XXX: Belongs with other flate code
#[cfg(not(stage0))] // XXX Using unsnapshotted features
pub mod flate;

/// Interop between byte streams and pipes. Not sure where it belongs
#[cfg(not(stage0))] // XXX "
pub mod comm_adapters;

/// Extension traits
mod extensions;

/// Non-I/O things needed by the I/O module
mod support;

/// Thread-blocking implementations
pub mod native {
    /// Posix file I/O
    pub mod file;
    /// # XXX - implement this
    pub mod stdio { }
    /// Sockets
    /// # XXX - implement this
    pub mod net {
        pub mod tcp { }
        pub mod udp { }
        #[cfg(unix)]
        pub mod unix { }
    }
}

/// The type passed to I/O condition handlers to indicate error
///
/// # XXX
///
/// Is something like this sufficient? It's kind of archaic
pub struct IoError {
    kind: IoErrorKind,
    desc: &'static str,
    detail: Option<~str>
}

pub enum IoErrorKind {
    FileNotFound,
    FilePermission,
    ConnectionFailed,
    Closed,
    OtherIoError
}

// XXX: Can't put doc comments on macros
// Raised by `I/O` operations on error.
condition! {
    io_error: super::IoError -> ();
}

pub trait Reader {
    /// Read bytes, up to the length of `buf` and place them in `buf`.
    /// Returns the number of bytes read, or `None` on EOF.
    ///
    /// # Failure
    ///
    /// Raises the `io_error` condition on error, then returns `None`.
    ///
    /// # XXX
    ///
    /// This doesn't take a `len` argument like the old `read`.
    /// Will people often need to slice their vectors to call this
    /// and will that be annoying?
    fn read(&mut self, buf: &mut [u8]) -> Option<uint>;

    /// Return whether the Reader has reached the end of the stream.
    ///
    /// # Example
    ///
    ///     let reader = FileStream::new()
    ///     while !reader.eof() {
    ///         println(reader.read_line());
    ///     }
    ///
    /// # XXX
    ///
    /// What does this return if the Reader is in an error state?
    fn eof(&mut self) -> bool;
}

pub trait Writer {
    /// Write the given buffer
    ///
    /// # Failure
    ///
    /// Raises the `io_error` condition on error
    fn write(&mut self, buf: &[u8]);

    /// Flush output
    fn flush(&mut self);
}

/// I/O types that may be closed
///
/// Any further operations performed on a closed resource will raise
/// on `io_error`
pub trait Close {
    /// Close the I/O resource
    fn close(&mut self);
}

pub trait Stream: Reader + Writer + Close { }

pub enum SeekStyle {
    /// Seek from the beginning of the stream
    SeekSet,
    /// Seek from the end of the stream
    SeekEnd,
    /// Seek from the current position
    SeekCur,
}

/// # XXX
/// * Are `u64` and `i64` the right choices?
pub trait Seek {
    fn tell(&self) -> u64;
    fn seek(&mut self, pos: i64, style: SeekStyle);
}

/// Common trait for decorator types.
///
/// Provides accessors to get the inner, 'decorated' values. The I/O library
/// uses decorators to add functionality like compression and encryption to I/O
/// streams.
///
/// # XXX
///
/// Is this worth having a trait for? May be overkill
pub trait Decorator<T> {
    /// Destroy the decorator and extract the decorated value
    ///
    /// # XXX
    ///
    /// Because this takes `self' one could never 'undecorate' a Reader/Writer
    /// that has been boxed. Is that ok? This feature is mostly useful for
    /// extracting the buffer from MemWriter
    fn inner(self) -> T;

    /// Take an immutable reference to the decorated value
    fn inner_ref<'a>(&'a self) -> &'a T;

    /// Take a mutable reference to the decorated value
    fn inner_mut_ref<'a>(&'a mut self) -> &'a mut T;
}
<|endoftext|>


<commit_before>// Copyright 2020 lowRISC contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

//! Kernel interface

use core::convert::TryFrom;
use core::default::Default;

/// Handler mode.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum HandlerMode {
    /// Do not handle request.
    Disabled = 0,

    /// Handle request in user space.
    UserSpace = 1,

    /// Handle request in kernel space.
    KernelSpace = 2,
}

impl Default for HandlerMode {
    fn default() -> Self { Self::Disabled }
}

/// Error for invalid handler mode conversion.
pub struct InvalidHandlerMode;

impl TryFrom<usize> for HandlerMode {
    type Error = InvalidHandlerMode;

    fn try_from(item: usize) -> Result<HandlerMode, Self::Error> {
        match item {
            0 => Ok(HandlerMode::Disabled),
            1 => Ok(HandlerMode::UserSpace),
            2 => Ok(HandlerMode::KernelSpace),
            _ => Err(InvalidHandlerMode),
        }
    }
}
<commit_msg>spiutils: Add AddressConfig.<commit_after>// Copyright 2020 lowRISC contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

//! Kernel interface

use crate::io::Read;
use crate::io::Write;
use crate::protocol::wire::FromWireError;
use crate::protocol::wire::FromWire;
use crate::protocol::wire::ToWireError;
use crate::protocol::wire::ToWire;

use core::convert::TryFrom;
use core::default::Default;

/// Handler mode.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum HandlerMode {
    /// Do not handle request.
    Disabled = 0,

    /// Handle request in user space.
    UserSpace = 1,

    /// Handle request in kernel space.
    KernelSpace = 2,
}

impl Default for HandlerMode {
    fn default() -> Self { Self::Disabled }
}

/// Error for invalid handler mode conversion.
pub struct InvalidHandlerMode;

impl TryFrom<usize> for HandlerMode {
    type Error = InvalidHandlerMode;

    fn try_from(item: usize) -> Result<HandlerMode, Self::Error> {
        match item {
            0 => Ok(HandlerMode::Disabled),
            1 => Ok(HandlerMode::UserSpace),
            2 => Ok(HandlerMode::KernelSpace),
            _ => Err(InvalidHandlerMode),
        }
    }
}

/// Address configuration for SPI device hardware.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct AddressConfig {
    /// The address on the SPI device bus that the external flash is accessible at.
    pub flash_virtual_base: u32,

    /// The base address in the external flash device on the SPI host bus.
    pub flash_physical_base: u32,

    /// The size of the external flash device.
    /// This must be a 2^N.
    pub flash_physical_size: u32,

    /// The address on the SPI device bus that the RAM (mailbox) is accessible at.
    pub ram_virtual_base: u32,

    /// The total size available on the SPI device bus.
    /// This must be a 2^N.
    pub virtual_size: u32,
}

impl<'a> FromWire<'a> for AddressConfig {
    fn from_wire<R: Read<'a>>(mut r: R) -> Result<Self, FromWireError> {
        let flash_virtual_base = r.read_be::<u32>()?;
        let flash_physical_base = r.read_be::<u32>()?;
        let flash_physical_size = r.read_be::<u32>()?;
        let ram_virtual_base = r.read_be::<u32>()?;
        let virtual_size = r.read_be::<u32>()?;
        Ok(Self {
            flash_virtual_base,
            flash_physical_base,
            flash_physical_size,
            ram_virtual_base,
            virtual_size,
        })
    }
}

impl ToWire for AddressConfig {
    fn to_wire<W: Write>(&self, mut w: W) -> Result<(), ToWireError> {
        w.write_be(self.flash_virtual_base)?;
        w.write_be(self.flash_physical_base)?;
        w.write_be(self.flash_physical_size)?;
        w.write_be(self.ram_virtual_base)?;
        w.write_be(self.virtual_size)?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate nom;
#[macro_use] extern crate clap;
#[macro_use] extern crate serde_derive;
extern crate mio;
extern crate mio_uds;
extern crate serde_json;
extern crate time;
extern crate libc;
extern crate slab;
extern crate rand;
extern crate nix;
#[macro_use] extern crate sozu_lib as sozu;
extern crate sozu_command_lib as sozu_command;

#[cfg(target_os = "linux")]
extern crate num_cpus;
#[cfg(target_os = "linux")]
extern crate procinfo;

mod command;
mod worker;
mod logging;
mod upgrade;

use std::net::ToSocketAddrs;
use std::env;
use sozu_command::config::Config;
use clap::{App,Arg,SubCommand};

#[cfg(target_os = "linux")]
use libc::{cpu_set_t,pid_t};

use command::Worker;
use worker::{begin_worker_process,start_workers};
use upgrade::begin_new_master_process;

fn main() {
  let matches = App::new("sozu")
                        .version(crate_version!())
                        .about("hot reconfigurable proxy")
                        .subcommand(SubCommand::with_name("start")
                                    .about("launch the master process")
                                    .arg(Arg::with_name("config")
                                        .short("c")
                                        .long("config")
                                        .value_name("FILE")
                                        .help("Sets a custom config file")
                                        .takes_value(true)
                                        .required(option_env!("SOZU_CONFIG").is_none())))
                        .subcommand(SubCommand::with_name("worker")
                                    .about("start a worker (internal command, should not be used directly)")
                                    .arg(Arg::with_name("id").long("id")
                                         .takes_value(true).required(true).help("worker identifier"))
                                    .arg(Arg::with_name("fd").long("fd")
                                         .takes_value(true).required(true).help("IPC file descriptor"))
                                    .arg(Arg::with_name("channel-buffer-size").long("channel-buffer-size")
                                         .takes_value(true).required(false).help("Worker's channel buffer size")))
                        .subcommand(SubCommand::with_name("upgrade")
                                    .about("start a new master process (internal command, should not be used directly)")
                                    .arg(Arg::with_name("fd").long("fd")
                                         .takes_value(true).required(true).help("IPC file descriptor"))
                                    .arg(Arg::with_name("channel-buffer-size").long("channel-buffer-size")
                                         .takes_value(true).required(false).help("Worker's channel buffer size")))
                        .get_matches();

  if let Some(matches) = matches.subcommand_matches("worker") {
    let fd  = matches.value_of("fd").expect("needs a file descriptor")
      .parse::<i32>().expect("the file descriptor must be a number");
    let id  = matches.value_of("id").expect("needs a worker id")
      .parse::<i32>().expect("the worker id must be a number");;
    let buffer_size = matches.value_of("channel-buffer-size")
      .and_then(|size| size.parse::<usize>().ok())
      .unwrap_or(1_000_000);

    begin_worker_process(fd, id, buffer_size);
    return;
  }

  if let Some(matches) = matches.subcommand_matches("upgrade") {
    let fd  = matches.value_of("fd").expect("needs a file descriptor")
      .parse::<i32>().expect("the file descriptor must be a number");
    let buffer_size = matches.value_of("channel-buffer-size")
      .and_then(|size| size.parse::<usize>().ok())
      .unwrap_or(1_000_000);

    begin_new_master_process(fd, buffer_size);
    return;
  }

  let submatches = matches.subcommand_matches("start").expect("unknown subcommand");
  let config_file = match submatches.value_of("config"){
                      Some(config_file) => config_file,
                      None => option_env!("SOZU_CONFIG").expect("could not find `SOZU_CONFIG` env var at build"),
                    };

  if let Ok(config) = Config::load_from_path(config_file) {
    //FIXME: should have an id for the master too
    logging::setup("MASTER".to_string(), &config.log_level, &config.log_target);
    info!("starting up");

    if let Some(ref metrics) = config.metrics.as_ref() {
      metrics_set_up!(&metrics.address[..], metrics.port);
      gauge!("sozu.main.TEST", 42);
    }

    // define this here so we can stop before launching workers if necessary
    let command_socket_path = config.command_socket_path();

    if check_process_limits(config.clone()) {
      match start_workers(&config) {
        Ok(workers) => {
          info!("created workers: {:?}", workers);

          if cfg!(target_os = "linux") && config.handle_process_affinity {
            set_workers_affinity(&workers);
          }

          command::start(config, command_socket_path, workers);
        },
        Err(e) => error!("Error while creating workers: {}", e)
      }
    }

    info!("master process stopped");
  } else {
    error!("could not load configuration file at '{}', stopping", config_file);
  }
}

/// Set workers process affinity, see man sched_setaffinity
/// Bind each worker (including the master) process to a CPU core.
/// Can bind multiple processes to a CPU core if there are more processes
/// than CPU cores. Only works on Linux.
#[cfg(target_os = "linux")]
fn set_workers_affinity(workers: &Vec<Worker>) {
  let mut cpu_count = 0;
  let max_cpu = num_cpus::get();

  // +1 for the master process that will also be bound to its CPU core
  if (workers.len() + 1) > max_cpu {
    warn!("There are more workers than available CPU cores, \
          multiple workers will be bound to the same CPU core. \
          This may impact performances");
  }

  let master_pid = unsafe { libc::getpid() };
  set_process_affinity(master_pid, cpu_count);
  cpu_count = cpu_count + 1;

  for ref worker in workers {
    if cpu_count >= max_cpu {
      cpu_count = 0;
    }

    set_process_affinity(worker.pid, cpu_count);

    cpu_count = cpu_count + 1;
  }
}

/// Set workers process affinity, see man sched_setaffinity
/// Bind each worker (including the master) process to a CPU core.
/// Can bind multiple processes to a CPU core if there are more processes
/// than CPU cores. Only works on Linux.
#[cfg(not(target_os = "linux"))]
fn set_workers_affinity(_: &Vec<Worker>) {
}

/// Set a specific process to run onto a specific CPU core
#[cfg(target_os = "linux")]
use std::mem;
#[cfg(target_os = "linux")]
fn set_process_affinity(pid: pid_t, cpu: usize) {
  unsafe {
    let mut cpu_set: cpu_set_t = mem::zeroed();
    let size_cpu_set = mem::size_of::<cpu_set_t>();
    libc::CPU_SET(cpu, &mut cpu_set);
    libc::sched_setaffinity(pid, size_cpu_set, &mut cpu_set);

    debug!("Worker {} bound to CPU core {}", pid, cpu);
  };
}

#[cfg(target_os="linux")]
// We check the hard_limit. The soft_limit can be changed at runtime
// by the process or any user. hard_limit can only be changed by root
fn check_process_limits(config: Config) -> bool {
  let process_limits = procinfo::pid::limits_self()
    .expect("Couldn't read /proc/self/limits to determine max open file descriptors limit");

  // If limit is "unlimited"
  if process_limits.max_open_files.hard.is_none() {
    return true;
  }

  let hard_limit = process_limits.max_open_files.hard.unwrap();

  // check if all proxies are under the hard limit
  if config.max_connections > hard_limit {
    error!("At least one proxy can't have that much of connections. \
            Current max file descriptor hard limit is: {}", hard_limit);
    return false;
  }

  let total_proxies_connections = http_max_cons + https_max_cons;
  let system_max_fd = procinfo::sys::fs::file_max::file_max()
    .expect("Couldn't read /proc/sys/fs/file-max") as usize;

  if config.max_connections > system_max_fd {
    error!("Proxies total max_connections can't be higher than system's file-max limit. \
            Current limit: {}, current value: {}", system_max_fd, config.max_connections);
    return false;
  }

  true
}

#[cfg(not(target_os = "linux"))]
fn check_process_limits(_: Config) -> bool {
  true
}
<commit_msg>fix compilation<commit_after>#[macro_use] extern crate nom;
#[macro_use] extern crate clap;
#[macro_use] extern crate serde_derive;
extern crate mio;
extern crate mio_uds;
extern crate serde_json;
extern crate time;
extern crate libc;
extern crate slab;
extern crate rand;
extern crate nix;
#[macro_use] extern crate sozu_lib as sozu;
extern crate sozu_command_lib as sozu_command;

#[cfg(target_os = "linux")]
extern crate num_cpus;
#[cfg(target_os = "linux")]
extern crate procinfo;

mod command;
mod worker;
mod logging;
mod upgrade;

use std::net::ToSocketAddrs;
use std::env;
use sozu_command::config::Config;
use clap::{App,Arg,SubCommand};

#[cfg(target_os = "linux")]
use libc::{cpu_set_t,pid_t};

use command::Worker;
use worker::{begin_worker_process,start_workers};
use upgrade::begin_new_master_process;

fn main() {
  let matches = App::new("sozu")
                        .version(crate_version!())
                        .about("hot reconfigurable proxy")
                        .subcommand(SubCommand::with_name("start")
                                    .about("launch the master process")
                                    .arg(Arg::with_name("config")
                                        .short("c")
                                        .long("config")
                                        .value_name("FILE")
                                        .help("Sets a custom config file")
                                        .takes_value(true)
                                        .required(option_env!("SOZU_CONFIG").is_none())))
                        .subcommand(SubCommand::with_name("worker")
                                    .about("start a worker (internal command, should not be used directly)")
                                    .arg(Arg::with_name("id").long("id")
                                         .takes_value(true).required(true).help("worker identifier"))
                                    .arg(Arg::with_name("fd").long("fd")
                                         .takes_value(true).required(true).help("IPC file descriptor"))
                                    .arg(Arg::with_name("channel-buffer-size").long("channel-buffer-size")
                                         .takes_value(true).required(false).help("Worker's channel buffer size")))
                        .subcommand(SubCommand::with_name("upgrade")
                                    .about("start a new master process (internal command, should not be used directly)")
                                    .arg(Arg::with_name("fd").long("fd")
                                         .takes_value(true).required(true).help("IPC file descriptor"))
                                    .arg(Arg::with_name("channel-buffer-size").long("channel-buffer-size")
                                         .takes_value(true).required(false).help("Worker's channel buffer size")))
                        .get_matches();

  if let Some(matches) = matches.subcommand_matches("worker") {
    let fd  = matches.value_of("fd").expect("needs a file descriptor")
      .parse::<i32>().expect("the file descriptor must be a number");
    let id  = matches.value_of("id").expect("needs a worker id")
      .parse::<i32>().expect("the worker id must be a number");;
    let buffer_size = matches.value_of("channel-buffer-size")
      .and_then(|size| size.parse::<usize>().ok())
      .unwrap_or(1_000_000);

    begin_worker_process(fd, id, buffer_size);
    return;
  }

  if let Some(matches) = matches.subcommand_matches("upgrade") {
    let fd  = matches.value_of("fd").expect("needs a file descriptor")
      .parse::<i32>().expect("the file descriptor must be a number");
    let buffer_size = matches.value_of("channel-buffer-size")
      .and_then(|size| size.parse::<usize>().ok())
      .unwrap_or(1_000_000);

    begin_new_master_process(fd, buffer_size);
    return;
  }

  let submatches = matches.subcommand_matches("start").expect("unknown subcommand");
  let config_file = match submatches.value_of("config"){
                      Some(config_file) => config_file,
                      None => option_env!("SOZU_CONFIG").expect("could not find `SOZU_CONFIG` env var at build"),
                    };

  if let Ok(config) = Config::load_from_path(config_file) {
    //FIXME: should have an id for the master too
    logging::setup("MASTER".to_string(), &config.log_level, &config.log_target);
    info!("starting up");

    if let Some(ref metrics) = config.metrics.as_ref() {
      metrics_set_up!(&metrics.address[..], metrics.port);
      gauge!("sozu.main.TEST", 42);
    }

    // define this here so we can stop before launching workers if necessary
    let command_socket_path = config.command_socket_path();

    if check_process_limits(config.clone()) {
      match start_workers(&config) {
        Ok(workers) => {
          info!("created workers: {:?}", workers);

          if cfg!(target_os = "linux") && config.handle_process_affinity {
            set_workers_affinity(&workers);
          }

          command::start(config, command_socket_path, workers);
        },
        Err(e) => error!("Error while creating workers: {}", e)
      }
    }

    info!("master process stopped");
  } else {
    error!("could not load configuration file at '{}', stopping", config_file);
  }
}

/// Set workers process affinity, see man sched_setaffinity
/// Bind each worker (including the master) process to a CPU core.
/// Can bind multiple processes to a CPU core if there are more processes
/// than CPU cores. Only works on Linux.
#[cfg(target_os = "linux")]
fn set_workers_affinity(workers: &Vec<Worker>) {
  let mut cpu_count = 0;
  let max_cpu = num_cpus::get();

  // +1 for the master process that will also be bound to its CPU core
  if (workers.len() + 1) > max_cpu {
    warn!("There are more workers than available CPU cores, \
          multiple workers will be bound to the same CPU core. \
          This may impact performances");
  }

  let master_pid = unsafe { libc::getpid() };
  set_process_affinity(master_pid, cpu_count);
  cpu_count = cpu_count + 1;

  for ref worker in workers {
    if cpu_count >= max_cpu {
      cpu_count = 0;
    }

    set_process_affinity(worker.pid, cpu_count);

    cpu_count = cpu_count + 1;
  }
}

/// Set workers process affinity, see man sched_setaffinity
/// Bind each worker (including the master) process to a CPU core.
/// Can bind multiple processes to a CPU core if there are more processes
/// than CPU cores. Only works on Linux.
#[cfg(not(target_os = "linux"))]
fn set_workers_affinity(_: &Vec<Worker>) {
}

/// Set a specific process to run onto a specific CPU core
#[cfg(target_os = "linux")]
use std::mem;
#[cfg(target_os = "linux")]
fn set_process_affinity(pid: pid_t, cpu: usize) {
  unsafe {
    let mut cpu_set: cpu_set_t = mem::zeroed();
    let size_cpu_set = mem::size_of::<cpu_set_t>();
    libc::CPU_SET(cpu, &mut cpu_set);
    libc::sched_setaffinity(pid, size_cpu_set, &mut cpu_set);

    debug!("Worker {} bound to CPU core {}", pid, cpu);
  };
}

#[cfg(target_os="linux")]
// We check the hard_limit. The soft_limit can be changed at runtime
// by the process or any user. hard_limit can only be changed by root
fn check_process_limits(config: Config) -> bool {
  let process_limits = procinfo::pid::limits_self()
    .expect("Couldn't read /proc/self/limits to determine max open file descriptors limit");

  // If limit is "unlimited"
  if process_limits.max_open_files.hard.is_none() {
    return true;
  }

  let hard_limit = process_limits.max_open_files.hard.unwrap();

  // check if all proxies are under the hard limit
  if config.max_connections > hard_limit {
    error!("At least one proxy can't have that much of connections. \
            Current max file descriptor hard limit is: {}", hard_limit);
    return false;
  }

  let system_max_fd = procinfo::sys::fs::file_max::file_max()
    .expect("Couldn't read /proc/sys/fs/file-max") as usize;

  if config.max_connections > system_max_fd {
    error!("Proxies total max_connections can't be higher than system's file-max limit. \
            Current limit: {}, current value: {}", system_max_fd, config.max_connections);
    return false;
  }

  true
}

#[cfg(not(target_os = "linux"))]
fn check_process_limits(_: Config) -> bool {
  true
}
<|endoftext|>