<commit_before>//! This module contains some standard interfaces and an easy way to call them.
//!
//! See the [D-Bus specification](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces) for more information about these standard interfaces.
//!
//! The code here was originally created by dbus-codegen.
//! Signal handling is not yet implemented here - use `Message::signal` to emit or `Connection.add_match` to receive, as usual.
//!
//! # Example
//! ```
//! use dbus::{Connection, BusType};
//! use dbus::stdintf::OrgFreedesktopDBusIntrospectable;
//! let c = Connection::get_private(BusType::Session).unwrap();
//! let p = c.with_path("org.freedesktop.DBus", "/", 10000);
//! println!("Introspection XML: {}", p.introspect().unwrap());
//! ```
//!

#![allow(missing_docs)]

use arg;

/// Methods of the [org.freedesktop.DBus.Peer](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-peer) interface.
pub trait OrgFreedesktopDBusPeer {
    type Err;
    fn ping(&self) -> Result<(), Self::Err>;
    fn get_machine_id(&self) -> Result<String, Self::Err>;
}

impl<'a, C: ::std::ops::Deref<Target=super::Connection>> OrgFreedesktopDBusPeer for super::ConnPath<'a, C> {
    type Err = super::Error;

    fn ping(&self) -> Result<(), Self::Err> {
        let mut m = try!(self.method_call_with_args(&"org.freedesktop.DBus.Peer".into(), &"Ping".into(), |_| {
        }));
        try!(m.as_result());
        Ok(())
    }

    fn get_machine_id(&self) -> Result<String, Self::Err> {
        let mut m = try!(self.method_call_with_args(&"org.freedesktop.DBus.Peer".into(), &"GetMachineId".into(), |_| {
        }));
        try!(m.as_result());
        let mut i = m.iter_init();
        let machine_uuid: String = try!(i.read());
        Ok(machine_uuid)
    }
}

/// Method of the [org.freedesktop.DBus.Introspectable](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-introspectable) interface.
pub trait OrgFreedesktopDBusIntrospectable {
    type Err;
    fn introspect(&self) -> Result<String, Self::Err>;
}

impl<'a, C: ::std::ops::Deref<Target=super::Connection>> OrgFreedesktopDBusIntrospectable for super::ConnPath<'a, C> {
    type Err = super::Error;

    fn introspect(&self) -> Result<String, Self::Err> {
        let mut m = try!(self.method_call_with_args(&"org.freedesktop.DBus.Introspectable".into(), &"Introspect".into(), |_| {
        }));
        try!(m.as_result());
        let mut i = m.iter_init();
        let arg0: String = try!(i.read());
        Ok(arg0)
    }
}

/// Methods of the [org.freedesktop.DBus.Properties](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties) interface.
pub trait OrgFreedesktopDBusProperties {
    type Err;
    fn get(&self, interface_name: &str, property_name: &str) -> Result<arg::Variant<Box<arg::RefArg>>, Self::Err>;
    fn get_all(&self, interface_name: &str) -> Result<::std::collections::HashMap<String, arg::Variant<Box<arg::RefArg>>>, Self::Err>;
    fn set(&self, interface_name: &str, property_name: &str, value: arg::Variant<Box<arg::RefArg>>) -> Result<(), Self::Err>;
}

impl<'a, C: ::std::ops::Deref<Target=super::Connection>> OrgFreedesktopDBusProperties for super::ConnPath<'a, C> {
    type Err = super::Error;

    fn get(&self, interface_name: &str, property_name: &str) -> Result<arg::Variant<Box<arg::RefArg>>, Self::Err> {
        let mut m = try!(self.method_call_with_args(&"org.freedesktop.DBus.Properties".into(), &"Get".into(), |msg| {
            let mut i = arg::IterAppend::new(msg);
            i.append(interface_name);
            i.append(property_name);
        }));
        try!(m.as_result());
        let mut i = m.iter_init();
        let value: arg::Variant<Box<arg::RefArg>> = try!(i.read());
        Ok(value)
    }

    fn get_all(&self, interface_name: &str) -> Result<::std::collections::HashMap<String, arg::Variant<Box<arg::RefArg>>>, Self::Err> {
        let mut m = try!(self.method_call_with_args(&"org.freedesktop.DBus.Properties".into(), &"GetAll".into(), |msg| {
            let mut i = arg::IterAppend::new(msg);
            i.append(interface_name);
        }));
        try!(m.as_result());
        let mut i = m.iter_init();
        let properties: ::std::collections::HashMap<String, arg::Variant<Box<arg::RefArg>>> = try!(i.read());
        Ok(properties)
    }

    fn set(&self, interface_name: &str, property_name: &str, value: arg::Variant<Box<arg::RefArg>>) -> Result<(), Self::Err> {
        let mut m = try!(self.method_call_with_args(&"org.freedesktop.DBus.Properties".into(), &"Set".into(), |msg| {
            let mut i = arg::IterAppend::new(msg);
            i.append(interface_name);
            i.append(property_name);
            i.append(value);
        }));
        try!(m.as_result());
        Ok(())
    }
}

/// Method of the [org.freedesktop.DBus.ObjectManager](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager) interface.
pub trait OrgFreedesktopDBusObjectManager {
    type Err;
    fn get_managed_objects(&self) -> Result<::std::collections::HashMap<super::Path<'static>, ::std::collections::HashMap<String, ::std::collections::HashMap<String, arg::Variant<Box<arg::RefArg>>>>>, Self::Err>;
}

impl<'a, C: ::std::ops::Deref<Target=super::Connection>> OrgFreedesktopDBusObjectManager for super::ConnPath<'a, C> {
    type Err = super::Error;

    fn get_managed_objects(&self) -> Result<::std::collections::HashMap<super::Path<'static>, ::std::collections::HashMap<String, ::std::collections::HashMap<String, arg::Variant<Box<arg::RefArg>>>>>, Self::Err> {
        let mut m = try!(self.method_call_with_args(&"org.freedesktop.DBus.ObjectManager".into(), &"GetManagedObjects".into(), |_| {
        }));
        try!(m.as_result());
        let mut i = m.iter_init();
        let objects: ::std::collections::HashMap<super::Path<'static>, ::std::collections::HashMap<String, ::std::collections::HashMap<String, arg::Variant<Box<arg::RefArg>>>>> = try!(i.read());
        Ok(objects)
    }
}

#[derive(Debug, Default)]
pub struct OrgFreedesktopDBusObjectManagerInterfacesAdded {
    pub object: super::Path<'static>,
    pub interfaces: ::std::collections::HashMap<String, ::std::collections::HashMap<String, arg::Variant<Box<arg::RefArg>>>>,
}

impl super::SignalArgs for OrgFreedesktopDBusObjectManagerInterfacesAdded {
    const NAME: &'static str = "InterfacesAdded";
    const INTERFACE: &'static str = "org.freedesktop.DBus.ObjectManager";
    fn append(&self, i: &mut arg::IterAppend) {
        (&self.object as &arg::RefArg).append(i);
        (&self.interfaces as &arg::RefArg).append(i);
    }
    fn get(&mut self, i: &mut arg::Iter) -> Result<(), arg::TypeMismatchError> {
        self.object = try!(i.read());
        self.interfaces = try!(i.read());
        Ok(())
    }
}

#[derive(Debug, Default)]
pub struct OrgFreedesktopDBusObjectManagerInterfacesRemoved {
    pub object: super::Path<'static>,
    pub interfaces: Vec<String>,
}

impl super::SignalArgs for OrgFreedesktopDBusObjectManagerInterfacesRemoved {
    const NAME: &'static str = "InterfacesRemoved";
    const INTERFACE: &'static str = "org.freedesktop.DBus.ObjectManager";
    fn append(&self, i: &mut arg::IterAppend) {
        (&self.object as &arg::RefArg).append(i);
        (&self.interfaces as &arg::RefArg).append(i);
    }
    fn get(&mut self, i: &mut arg::Iter) -> Result<(), arg::TypeMismatchError> {
        self.object = try!(i.read());
        self.interfaces = try!(i.read());
        Ok(())
    }
}

<commit_msg>dbus: Add PropertiesChanged signal to stdintf<commit_after>//! This module contains some standard interfaces and an easy way to call them.
//!
//! See the [D-Bus specification](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces) for more information about these standard interfaces.
//!
//! The code here was originally created by dbus-codegen.
//! Signal handling is not yet implemented here - use `Message::signal` to emit or `Connection.add_match` to receive, as usual.
//!
//! # Example
//! ```
//! use dbus::{Connection, BusType};
//! use dbus::stdintf::OrgFreedesktopDBusIntrospectable;
//! let c = Connection::get_private(BusType::Session).unwrap();
//! let p = c.with_path("org.freedesktop.DBus", "/", 10000);
//! println!("Introspection XML: {}", p.introspect().unwrap());
//! ```
//!

#![allow(missing_docs)]

use arg;

/// Methods of the [org.freedesktop.DBus.Peer](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-peer) interface.
pub trait OrgFreedesktopDBusPeer {
    type Err;
    fn ping(&self) -> Result<(), Self::Err>;
    fn get_machine_id(&self) -> Result<String, Self::Err>;
}

impl<'a, C: ::std::ops::Deref<Target=super::Connection>> OrgFreedesktopDBusPeer for super::ConnPath<'a, C> {
    type Err = super::Error;

    fn ping(&self) -> Result<(), Self::Err> {
        let mut m = try!(self.method_call_with_args(&"org.freedesktop.DBus.Peer".into(), &"Ping".into(), |_| {
        }));
        try!(m.as_result());
        Ok(())
    }

    fn get_machine_id(&self) -> Result<String, Self::Err> {
        let mut m = try!(self.method_call_with_args(&"org.freedesktop.DBus.Peer".into(), &"GetMachineId".into(), |_| {
        }));
        try!(m.as_result());
        let mut i = m.iter_init();
        let machine_uuid: String = try!(i.read());
        Ok(machine_uuid)
    }
}

/// Method of the [org.freedesktop.DBus.Introspectable](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-introspectable) interface.
pub trait OrgFreedesktopDBusIntrospectable {
    type Err;
    fn introspect(&self) -> Result<String, Self::Err>;
}

impl<'a, C: ::std::ops::Deref<Target=super::Connection>> OrgFreedesktopDBusIntrospectable for super::ConnPath<'a, C> {
    type Err = super::Error;

    fn introspect(&self) -> Result<String, Self::Err> {
        let mut m = try!(self.method_call_with_args(&"org.freedesktop.DBus.Introspectable".into(), &"Introspect".into(), |_| {
        }));
        try!(m.as_result());
        let mut i = m.iter_init();
        let arg0: String = try!(i.read());
        Ok(arg0)
    }
}

/// Methods of the [org.freedesktop.DBus.Properties](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties) interface.
pub trait OrgFreedesktopDBusProperties {
    type Err;
    fn get(&self, interface_name: &str, property_name: &str) -> Result<arg::Variant<Box<arg::RefArg>>, Self::Err>;
    fn get_all(&self, interface_name: &str) -> Result<::std::collections::HashMap<String, arg::Variant<Box<arg::RefArg>>>, Self::Err>;
    fn set(&self, interface_name: &str, property_name: &str, value: arg::Variant<Box<arg::RefArg>>) -> Result<(), Self::Err>;
}

impl<'a, C: ::std::ops::Deref<Target=super::Connection>> OrgFreedesktopDBusProperties for super::ConnPath<'a, C> {
    type Err = super::Error;

    fn get(&self, interface_name: &str, property_name: &str) -> Result<arg::Variant<Box<arg::RefArg>>, Self::Err> {
        let mut m = try!(self.method_call_with_args(&"org.freedesktop.DBus.Properties".into(), &"Get".into(), |msg| {
            let mut i = arg::IterAppend::new(msg);
            i.append(interface_name);
            i.append(property_name);
        }));
        try!(m.as_result());
        let mut i = m.iter_init();
        let value: arg::Variant<Box<arg::RefArg>> = try!(i.read());
        Ok(value)
    }

    fn get_all(&self, interface_name: &str) -> Result<::std::collections::HashMap<String, arg::Variant<Box<arg::RefArg>>>, Self::Err> {
        let mut m = try!(self.method_call_with_args(&"org.freedesktop.DBus.Properties".into(), &"GetAll".into(), |msg| {
            let mut i = arg::IterAppend::new(msg);
            i.append(interface_name);
        }));
        try!(m.as_result());
        let mut i = m.iter_init();
        let properties: ::std::collections::HashMap<String, arg::Variant<Box<arg::RefArg>>> = try!(i.read());
        Ok(properties)
    }

    fn set(&self, interface_name: &str, property_name: &str, value: arg::Variant<Box<arg::RefArg>>) -> Result<(), Self::Err> {
        let mut m = try!(self.method_call_with_args(&"org.freedesktop.DBus.Properties".into(), &"Set".into(), |msg| {
            let mut i = arg::IterAppend::new(msg);
            i.append(interface_name);
            i.append(property_name);
            i.append(value);
        }));
        try!(m.as_result());
        Ok(())
    }
}

#[derive(Debug, Default)]
/// Struct to send/receive the PropertiesChanged signal of the
/// [org.freedesktop.DBus.Properties](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties) interface.
pub struct OrgFreedesktopDBusPropertiesPropertiesChanged {
    pub interface_name: String,
    pub changed_properties: ::std::collections::HashMap<String, arg::Variant<Box<arg::RefArg>>>,
    pub invalidated_properties: Vec<String>,
}

impl super::SignalArgs for OrgFreedesktopDBusPropertiesPropertiesChanged {
    const NAME: &'static str = "PropertiesChanged";
    const INTERFACE: &'static str = "org.freedesktop.DBus.Properties";
    fn append(&self, i: &mut arg::IterAppend) {
        (&self.interface_name as &arg::RefArg).append(i);
        (&self.changed_properties as &arg::RefArg).append(i);
        (&self.invalidated_properties as &arg::RefArg).append(i);
    }
    fn get(&mut self, i: &mut arg::Iter) -> Result<(), arg::TypeMismatchError> {
        self.interface_name = try!(i.read());
        self.changed_properties = try!(i.read());
        self.invalidated_properties = try!(i.read());
        Ok(())
    }
}

/// Method of the [org.freedesktop.DBus.ObjectManager](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager) interface.
pub trait OrgFreedesktopDBusObjectManager {
    type Err;
    fn get_managed_objects(&self) -> Result<::std::collections::HashMap<super::Path<'static>, ::std::collections::HashMap<String, ::std::collections::HashMap<String, arg::Variant<Box<arg::RefArg>>>>>, Self::Err>;
}

impl<'a, C: ::std::ops::Deref<Target=super::Connection>> OrgFreedesktopDBusObjectManager for super::ConnPath<'a, C> {
    type Err = super::Error;

    fn get_managed_objects(&self) -> Result<::std::collections::HashMap<super::Path<'static>, ::std::collections::HashMap<String, ::std::collections::HashMap<String, arg::Variant<Box<arg::RefArg>>>>>, Self::Err> {
        let mut m = try!(self.method_call_with_args(&"org.freedesktop.DBus.ObjectManager".into(), &"GetManagedObjects".into(), |_| {
        }));
        try!(m.as_result());
        let mut i = m.iter_init();
        let objects: ::std::collections::HashMap<super::Path<'static>, ::std::collections::HashMap<String, ::std::collections::HashMap<String, arg::Variant<Box<arg::RefArg>>>>> = try!(i.read());
        Ok(objects)
    }
}

#[derive(Debug, Default)]
/// Struct to send/receive the InterfacesAdded signal of the
/// [org.freedesktop.DBus.ObjectManager](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager) interface.
pub struct OrgFreedesktopDBusObjectManagerInterfacesAdded {
    pub object: super::Path<'static>,
    pub interfaces: ::std::collections::HashMap<String, ::std::collections::HashMap<String, arg::Variant<Box<arg::RefArg>>>>,
}

impl super::SignalArgs for OrgFreedesktopDBusObjectManagerInterfacesAdded {
    const NAME: &'static str = "InterfacesAdded";
    const INTERFACE: &'static str = "org.freedesktop.DBus.ObjectManager";
    fn append(&self, i: &mut arg::IterAppend) {
        (&self.object as &arg::RefArg).append(i);
        (&self.interfaces as &arg::RefArg).append(i);
    }
    fn get(&mut self, i: &mut arg::Iter) -> Result<(), arg::TypeMismatchError> {
        self.object = try!(i.read());
        self.interfaces = try!(i.read());
        Ok(())
    }
}

#[derive(Debug, Default)]
/// Struct to send/receive the InterfacesRemoved signal of the
/// [org.freedesktop.DBus.ObjectManager](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager) interface.
pub struct OrgFreedesktopDBusObjectManagerInterfacesRemoved {
    pub object: super::Path<'static>,
    pub interfaces: Vec<String>,
}

impl super::SignalArgs for OrgFreedesktopDBusObjectManagerInterfacesRemoved {
    const NAME: &'static str = "InterfacesRemoved";
    const INTERFACE: &'static str = "org.freedesktop.DBus.ObjectManager";
    fn append(&self, i: &mut arg::IterAppend) {
        (&self.object as &arg::RefArg).append(i);
        (&self.interfaces as &arg::RefArg).append(i);
    }
    fn get(&mut self, i: &mut arg::Iter) -> Result<(), arg::TypeMismatchError> {
        self.object = try!(i.read());
        self.interfaces = try!(i.read());
        Ok(())
    }
}

<|endoftext|>


<commit_before>// Test integration of zmq with a simple external event loop
//
// This excercises the `Socket::get_fd()` method in combination with
// `Socket::get_events()` to integrate with Unix `poll(2)` to check
// the basis for integration with external event loops works.

extern crate nix;
extern crate zmq;

use super::with_connection;
use self::nix::poll;

test!(test_external_poll_tcp, {
    with_connection("tcp://127.0.0.1:*",
                    zmq::REQ, poll_client,
                    zmq::REP, poll_worker);
});

fn poll_client(_ctx: zmq::Context, socket: zmq::Socket) {
    // TODO: we should use `poll::poll()` here as well.
    for i in 0..10 {
        let payload = format!("message {}", i);
        socket.send_str(&payload, 0).unwrap();
        let reply = socket.recv_msg(0).unwrap();
        assert_eq!(payload.as_bytes(), &reply[..]);
    }
    socket.send_str("", 0).unwrap();
    let last = socket.recv_msg(0).unwrap();
    assert_eq!(b"", &last[..]);
}

/// Keeps track of the polling state for the event signalling FD of a
/// single socket.
struct PollState<'a> {
    socket: &'a zmq::Socket,
    available: zmq::PollEvents,
    fds: [poll::PollFd; 1],
}

impl<'a> PollState<'a> {
    fn new(socket: &'a zmq::Socket) -> Self {
        let fd = socket.get_fd().unwrap();
        PollState {
            socket: socket,
            available: 0,
            fds: [poll::PollFd::new(fd, poll::POLLIN, poll::EventFlags::empty())],
        }
    }

    /// Wait for one of `events` to happen.
    fn wait(&mut self, events: zmq::PollEvents) {
        while (self.available & events) == 0 {
            // FIXME: this has ugly scoping
            {
                let fds = &mut self.fds;
                poll::poll(fds, -1).unwrap();
                debug!("poll done, events: {:?}", fds[0].revents());
                match fds[0].revents() {
                    Some(events) => {
                        if (events & poll::POLLIN).is_empty() {
                            continue;
                        }
                    },
                    _ => continue,
                }
            }
            self.update();
        }
    }

    /// This needs to be called after every sucessful receive or send
    /// on the socket.
    fn update(&mut self) {
        self.available = self.socket.get_events().unwrap() as zmq::PollEvents;
    }
}

fn poll_worker(_ctx: zmq::Context, socket: zmq::Socket) {
    let mut reply = None;
    let mut state = PollState::new(&socket);
    loop {
        match reply.take() {
            None => {
                state.wait(zmq::POLLIN);
                let msg = socket.recv_msg(zmq::DONTWAIT).unwrap();
                state.update();
                debug!("received msg: {:?}, events now: {:?}", msg, state.available);
                reply = Some(msg);
            },
            Some(msg) => {
                state.wait(zmq::POLLOUT);
                let done = msg.len() == 0;
                socket.send_msg(msg, zmq::DONTWAIT).unwrap();
                state.update();
                debug!("sent msg, events now: {:?}", state.available);
                if done {
                    break;
                }
            },
        }
    }
}
<commit_msg>Fix and simplify external poll test<commit_after>// Test integration of zmq with a simple external event loop
//
// This excercises the `Socket::get_fd()` method in combination with
// `Socket::get_events()` to integrate with Unix `poll(2)` to check
// the basis for integration with external event loops works.

extern crate nix;
extern crate zmq;

use super::with_connection;
use self::nix::poll;

test!(test_external_poll_inproc, {
    with_connection("inproc://test-poll",
                    zmq::REQ, poll_client,
                    zmq::REP, poll_worker);
});

test!(test_external_poll_ipc, {
    with_connection("ipc:///tmp/zmq-tokio-test",
                    zmq::REQ, poll_client,
                    zmq::REP, poll_worker);
});

test!(test_external_poll_tcp, {
    with_connection("tcp://127.0.0.1:*",
                    zmq::REQ, poll_client,
                    zmq::REP, poll_worker);
});

fn poll_client(_ctx: zmq::Context, socket: zmq::Socket) {
    // TODO: we should use `poll::poll()` here as well.
    for i in 0..10 {
        let payload = format!("message {}", i);
        socket.send_str(&payload, 0).unwrap();
        let reply = socket.recv_msg(0).unwrap();
        assert_eq!(payload.as_bytes(), &reply[..]);
    }
    socket.send_str("", 0).unwrap();
    let last = socket.recv_msg(0).unwrap();
    assert_eq!(b"", &last[..]);
}

/// Keeps track of the polling state for the event signalling FD of a
/// single socket.
struct PollState<'a> {
    socket: &'a zmq::Socket,
    fds: [poll::PollFd; 1],
}

impl<'a> PollState<'a> {
    fn new(socket: &'a zmq::Socket) -> Self {
        let fd = socket.get_fd().unwrap();
        PollState {
            socket: socket,
            fds: [poll::PollFd::new(fd, poll::POLLIN, poll::EventFlags::empty())],
        }
    }

    /// Wait for one of `events` to happen.
    fn wait(&mut self, events: zmq::PollEvents) {
        while (self.events() & events) == 0 {
            debug!("polling");
            let fds = &mut self.fds;
            poll::poll(fds, -1).unwrap();
            debug!("poll done, events: {:?}", fds[0].revents());
            match fds[0].revents() {
                Some(events) => {
                    if !events.contains(poll::POLLIN) {
                        continue;
                    }
                },
                _ => continue,
            }
        }
    }

    fn events(&self) -> zmq::PollEvents {
        self.socket.get_events().unwrap() as zmq::PollEvents
    }
}

fn poll_worker(_ctx: zmq::Context, socket: zmq::Socket) {
    let mut reply = None;
    let mut state = PollState::new(&socket);
    loop {
        match reply.take() {
            None => {
                state.wait(zmq::POLLIN);
                let msg = socket.recv_msg(zmq::DONTWAIT).unwrap();
                reply = Some(msg);
            },
            Some(msg) => {
                state.wait(zmq::POLLOUT);
                let done = msg.len() == 0;
                socket.send_msg(msg, zmq::DONTWAIT).unwrap();
                if done {
                    break;
                }
            },
        }
    }
}
<|endoftext|>


<commit_before>use std::cmp;

/*

  This struct essentially encapsulates the "instance variables"

*/
#[derive(Debug)]
pub struct SimpleHdrHistogram {
    pub leading_zeros_count_base: usize,
    pub sub_bucket_mask: u64,
    pub unit_magnitude: u32,
    pub sub_bucket_count: usize,
    pub sub_bucket_half_count: usize,
    pub sub_bucket_half_count_magnitude: u32,
    pub counts: Vec<u64>,
    pub counts_array_length: usize,
    pub normalizing_index_offset: usize,
    pub max_value: u64,
    pub min_non_zero_value: u64,
    pub unit_magnitude_mask: u64,
    pub total_count: u64,
}

/*

  Implementing this trait (Default) for our struct gives us a nice way to
  initialize an instance using default args instead of having to provide all of them

 */
impl Default for SimpleHdrHistogram {
    fn default () -> SimpleHdrHistogram {
        SimpleHdrHistogram {
            leading_zeros_count_base: 0,
            sub_bucket_mask: 0,
            unit_magnitude: 0,
            sub_bucket_count: 0,
            sub_bucket_half_count: 0,
            sub_bucket_half_count_magnitude: 0,
            counts: Vec::new(),
            counts_array_length: 0,
            normalizing_index_offset: 0,
            max_value: 0,
            min_non_zero_value: u64::max_value(),
            unit_magnitude_mask: 0,
            total_count: 0,
        }
    }
}

pub trait HistogramBase {

    //FIXME this stuff could be mostly unsigned

    //TODO this block should be default impl of this trait
    fn record_single_value(&mut self, value: u64) -> Result<(), String>;
    fn counts_array_index(&self, value: u64) -> usize;
    fn counts_array_index_sub(&self, bucket_index: usize, sub_bucket_index: usize) -> usize;
    fn get_bucket_index(&self, value: u64) -> usize;
    fn get_sub_bucket_index(&self, value: u64, bucket_index: usize) -> usize;
    fn get_count(&self) -> u64;
    fn get_max(&self) -> u64;
    fn update_min_and_max(&mut self, value: u64);
    fn update_max_value(&mut self, value: u64);
    fn update_min_non_zero_value(&mut self, value: u64);
    fn get_count_at_value(&mut self, value: u64) -> Result<u64, String>;
    // end TODO

    fn increment_count_at_index(&mut self, index: usize) -> Result<(), String>;
    fn normalize_index(&self, index: usize, normalizing_index_offset: usize, array_length: usize) ->
        Result<usize, String>;
    fn increment_total_count(&mut self);
    fn get_count_at_index(&mut self, index: usize) -> Result<u64, String>;

}

impl HistogramBase for SimpleHdrHistogram {

    fn get_count_at_index(&mut self, index: usize) -> Result<u64, String> {
        let normalized_index =
            self.normalize_index(index, self.normalizing_index_offset, self.counts_array_length);
        match normalized_index {
            Ok(the_index) =>
                Ok(self.counts[the_index]),
            Err(err) =>
                Err(err)
        }
    }

    fn get_count_at_value(&mut self, value: u64) -> Result<u64, String> {
        let index = cmp::min(cmp::max(0, self.counts_array_index(value)), self.counts_array_length - 1);
        self.get_count_at_index(index)
    }

    fn increment_total_count(&mut self) {
        self.total_count += 1;
    }

    fn update_max_value(&mut self, value: u64) {
        let internal_value = value | self.unit_magnitude_mask;
        self.max_value = internal_value;
    }

    fn update_min_non_zero_value(&mut self, value: u64) {
        if value <= self.unit_magnitude_mask {
            return
        }
        let internal_value = value & !self.unit_magnitude_mask;
        self.min_non_zero_value = internal_value;
    }

    fn update_min_and_max(&mut self, value: u64) {
        if value > self.max_value {
            self.update_max_value(value);
        }
        if value < self.min_non_zero_value && value != 0 {
            self.update_min_non_zero_value(value);
        }
    }

    fn normalize_index(&self, index: usize, normalizing_index_offset: usize, array_length: usize) ->
        Result<usize, String> {
        match normalizing_index_offset {
            0 => Ok(index),
            _ =>
                if index > array_length {
                    Err(String::from("index out of covered range"))
                } else {
                    let mut normalized_index: usize = index - normalizing_index_offset;
                    if normalized_index >= array_length {
                        normalized_index -=array_length;
                    }
                    Ok(normalized_index)
                }
        }
    }

    fn increment_count_at_index(&mut self, index: usize) -> Result<(), String> {
        let normalized_index =
            self.normalize_index(index, self.normalizing_index_offset, self.counts_array_length);
        match normalized_index {
            Ok(the_index) => {
                self.counts[the_index] += 1;
                Ok(())
            }
            Err(err) =>
                Err(err)
        }
    }

    fn get_sub_bucket_index(&self, value: u64, bucket_index: usize) -> usize {
        let sum = bucket_index as u32 + self.unit_magnitude;
        value.rotate_right(sum) as usize
    }

    fn get_bucket_index(&self, value: u64) -> usize {
        let value_orred = value | self.sub_bucket_mask;
        self.leading_zeros_count_base - (value_orred.leading_zeros() as usize)
    }

    fn record_single_value(&mut self, value: u64) -> Result<(), String> {
        let counts_index = self.counts_array_index(value);
            match self.increment_count_at_index(counts_index) {
                Ok(_) => {
                    self.update_min_and_max(value);
                    self.increment_total_count();
                    Ok(())
                }
                Err(err) => {
                    Err(String::from(format!("Could not increment count at index due to: {}", err)))
                }
            }
    }

    fn get_max(&self) -> u64 {
        self.max_value
    }

    fn get_count(&self) -> u64 {
        self.total_count
    }

    fn counts_array_index(&self, value: u64) -> usize {
        let bucket_index = self.get_bucket_index(value);
        let sub_bucket_index = self.get_sub_bucket_index(value, bucket_index);
        return self.counts_array_index_sub(bucket_index, sub_bucket_index);
    }

    fn counts_array_index_sub(&self, bucket_index: usize, sub_bucket_index: usize) -> usize {
        assert!(sub_bucket_index < self.sub_bucket_count);
        assert!(bucket_index == 0 || (sub_bucket_index >= self.sub_bucket_half_count));

        let bucket_base_index = (bucket_index + 1) << self.sub_bucket_half_count_magnitude;
        let offset_in_bucket = sub_bucket_index - self.sub_bucket_half_count;

        bucket_base_index + offset_in_bucket
    }
}

#[test]
fn can_get_count_after_record() {
    let mut the_hist = init_histo(1, 100000, 3);
    let result = the_hist.record_single_value(5000);
    match result {
        Ok(_) => (),
        Err(err) => panic!(format!("could not add single record to histogram because error: {}", err))
    }

    let count = the_hist.get_count();
    assert_eq!(count, 1);
}

#[test]
fn can_get_max_after_record() {
    let mut the_hist = init_histo(1, 100000, 3);
    let result = the_hist.record_single_value(5000);
    match result {
        Ok(_) => (),
        Err(err) => panic!(format!("could not add single record to histogram because error: {}", err))
    }

    let max = the_hist.get_max();
    assert_eq!(max, 5000);
}

#[test]
fn can_record_single_value() {
    let mut the_hist = init_histo(1, 100000, 3);
    let result = the_hist.record_single_value(5000);

    match result {
        Ok(_) => (),
        Err(err) => panic!(format!("could not add single record to histogram because error: {}", err))
    }
}

#[test]
fn can_compute_counts_array_index() {
    let the_hist = init_histo(1, 100000, 3);
    let result = the_hist.counts_array_index(5000);

    assert_eq!(result, 3298);
}

#[test]
fn can_get_bucket_index() {
    let the_hist = init_histo(1, 100000, 3);
    let result = the_hist.get_bucket_index(5000);
    assert_eq!(result, 2)
}

#[test]
fn can_get_sub_bucket_index() {
    let the_hist = init_histo(1, 100000, 3);
    let result = the_hist.get_sub_bucket_index(5000, 2);
    assert_eq!(result, 1250)
}

/// lowest_discernible_value: must be >= 1
/// highest_trackable_value: must be >= 2 * lowest_discernible_value
/// num_significant_digits: must be <= 5
fn init_histo(lowest_discernible_value: u64, highest_trackable_value: u64, num_significant_digits: u32) -> SimpleHdrHistogram {

    assert!(lowest_discernible_value >= 1);
    assert!(highest_trackable_value >= 2 * lowest_discernible_value);
    assert!(num_significant_digits <= 5);

    let mut hist =  SimpleHdrHistogram { ..Default::default() };

    let largest_value_with_single_unit_resolution = 2_u64 * 10_u64.pow(num_significant_digits);

    let unit_magnitude = ((lowest_discernible_value as f64).ln() / 2_f64.ln()) as u32;
    let unit_magnitude_mask: u64  = 1_u64.rotate_left(unit_magnitude) - 1;

    // find nearest power of 2 to largest_value_with_single_unit_resolution
    let sub_bucket_count_magnitude: u32 =
        ((largest_value_with_single_unit_resolution as f64).ln() / 2_f64.ln()).ceil() as u32;

    // ugly looking... how should ternaries be done?
    let sub_bucket_half_count_magnitude: u32 = (if sub_bucket_count_magnitude > 1 { sub_bucket_count_magnitude } else { 1 }) - 1;
    let sub_bucket_count: usize = 2_usize.pow(sub_bucket_half_count_magnitude + 1);
    let sub_bucket_half_count: usize = sub_bucket_count / 2;
    // TODO is this cast OK?
    let sub_bucket_mask = (sub_bucket_count - 1).rotate_left(unit_magnitude) as u64;

    let counts_arr_len = counts_arr_len(highest_trackable_value, sub_bucket_count, unit_magnitude);
    let bucket_count = buckets_needed_for_value(highest_trackable_value, sub_bucket_count, unit_magnitude);

    let leading_zero_count_base: usize = (64_u32 - unit_magnitude - sub_bucket_half_count_magnitude - 1) as usize;

    hist.leading_zeros_count_base = leading_zero_count_base;
    hist.sub_bucket_mask = sub_bucket_mask;
    hist.unit_magnitude = unit_magnitude;
    hist.sub_bucket_count = sub_bucket_count;
    hist.sub_bucket_half_count = sub_bucket_half_count;
    hist.sub_bucket_half_count_magnitude = sub_bucket_half_count_magnitude;
    hist.counts = vec![10; counts_arr_len];
    hist.counts_array_length = counts_arr_len;
    hist.normalizing_index_offset = 0_usize; // 0 for normal Histogram ctor in Java impl

    println!("hist: {:?}", hist);

    hist
}

fn buckets_needed_for_value(value: u64, sub_bucket_count: usize, unit_magnitude: u32) -> usize {

    // TODO is this cast ok?
    let mut smallest_untrackable_value: u64 = sub_bucket_count.rotate_left(unit_magnitude) as u64;
    let mut buckets_needed: usize = 1;

    while smallest_untrackable_value <= value {
        if smallest_untrackable_value > u64::max_value() / 2 {
            return buckets_needed + 1;
        }

        smallest_untrackable_value = smallest_untrackable_value.rotate_left(1);
        buckets_needed += 1;
    }

    return buckets_needed;
}

fn counts_arr_len_for_buckets(buckets: usize, sub_bucket_count: usize) -> usize {
    (buckets + 1) * (sub_bucket_count / 2)
}

fn counts_arr_len(value: u64, sub_bucket_count: usize, unit_magnitude: u32) -> usize {
    counts_arr_len_for_buckets(buckets_needed_for_value(value, sub_bucket_count, unit_magnitude), sub_bucket_count)
}<commit_msg>more tests around index calculation<commit_after>use std::cmp;

/*

  This struct essentially encapsulates the "instance variables"

*/
#[derive(Debug)]
pub struct SimpleHdrHistogram {
    pub leading_zeros_count_base: usize,
    pub sub_bucket_mask: u64,
    pub unit_magnitude: u32,
    pub sub_bucket_count: usize,
    pub sub_bucket_half_count: usize,
    pub sub_bucket_half_count_magnitude: u32,
    pub counts: Vec<u64>,
    pub counts_array_length: usize,
    pub normalizing_index_offset: usize,
    pub max_value: u64,
    pub min_non_zero_value: u64,
    pub unit_magnitude_mask: u64,
    pub total_count: u64,
}

/*

  Implementing this trait (Default) for our struct gives us a nice way to
  initialize an instance using default args instead of having to provide all of them

 */
impl Default for SimpleHdrHistogram {
    fn default () -> SimpleHdrHistogram {
        SimpleHdrHistogram {
            leading_zeros_count_base: 0,
            sub_bucket_mask: 0,
            unit_magnitude: 0,
            sub_bucket_count: 0,
            sub_bucket_half_count: 0,
            sub_bucket_half_count_magnitude: 0,
            counts: Vec::new(),
            counts_array_length: 0,
            normalizing_index_offset: 0,
            max_value: 0,
            min_non_zero_value: u64::max_value(),
            unit_magnitude_mask: 0,
            total_count: 0,
        }
    }
}

pub trait HistogramBase {

    //FIXME this stuff could be mostly unsigned

    //TODO this block should be default impl of this trait
    fn record_single_value(&mut self, value: u64) -> Result<(), String>;
    fn counts_array_index(&self, value: u64) -> usize;
    fn counts_array_index_sub(&self, bucket_index: usize, sub_bucket_index: usize) -> usize;
    fn get_bucket_index(&self, value: u64) -> usize;
    fn get_sub_bucket_index(&self, value: u64, bucket_index: usize) -> usize;
    fn get_count(&self) -> u64;
    fn get_max(&self) -> u64;
    fn update_min_and_max(&mut self, value: u64);
    fn update_max_value(&mut self, value: u64);
    fn update_min_non_zero_value(&mut self, value: u64);
    fn get_count_at_value(&mut self, value: u64) -> Result<u64, String>;
    // end TODO

    fn increment_count_at_index(&mut self, index: usize) -> Result<(), String>;
    fn normalize_index(&self, index: usize, normalizing_index_offset: usize, array_length: usize) ->
        Result<usize, String>;
    fn increment_total_count(&mut self);
    fn get_count_at_index(&mut self, index: usize) -> Result<u64, String>;

}

impl HistogramBase for SimpleHdrHistogram {

    fn get_count_at_index(&mut self, index: usize) -> Result<u64, String> {
        let normalized_index =
            self.normalize_index(index, self.normalizing_index_offset, self.counts_array_length);
        match normalized_index {
            Ok(the_index) =>
                Ok(self.counts[the_index]),
            Err(err) =>
                Err(err)
        }
    }

    fn get_count_at_value(&mut self, value: u64) -> Result<u64, String> {
        let index = cmp::min(cmp::max(0, self.counts_array_index(value)), self.counts_array_length - 1);
        self.get_count_at_index(index)
    }

    fn increment_total_count(&mut self) {
        self.total_count += 1;
    }

    fn update_max_value(&mut self, value: u64) {
        let internal_value = value | self.unit_magnitude_mask;
        self.max_value = internal_value;
    }

    fn update_min_non_zero_value(&mut self, value: u64) {
        if value <= self.unit_magnitude_mask {
            return
        }
        let internal_value = value & !self.unit_magnitude_mask;
        self.min_non_zero_value = internal_value;
    }

    fn update_min_and_max(&mut self, value: u64) {
        if value > self.max_value {
            self.update_max_value(value);
        }
        if value < self.min_non_zero_value && value != 0 {
            self.update_min_non_zero_value(value);
        }
    }

    fn normalize_index(&self, index: usize, normalizing_index_offset: usize, array_length: usize) ->
        Result<usize, String> {
        match normalizing_index_offset {
            0 => Ok(index),
            _ =>
                if index > array_length {
                    Err(String::from("index out of covered range"))
                } else {
                    let mut normalized_index: usize = index - normalizing_index_offset;
                    if normalized_index >= array_length {
                        normalized_index -=array_length;
                    }
                    Ok(normalized_index)
                }
        }
    }

    fn increment_count_at_index(&mut self, index: usize) -> Result<(), String> {
        let normalized_index =
            self.normalize_index(index, self.normalizing_index_offset, self.counts_array_length);
        match normalized_index {
            Ok(the_index) => {
                self.counts[the_index] += 1;
                Ok(())
            }
            Err(err) =>
                Err(err)
        }
    }

    fn get_sub_bucket_index(&self, value: u64, bucket_index: usize) -> usize {
        let sum = bucket_index as u32 + self.unit_magnitude;
        value.rotate_right(sum) as usize
    }

    fn get_bucket_index(&self, value: u64) -> usize {
        let value_orred = value | self.sub_bucket_mask;
        self.leading_zeros_count_base - (value_orred.leading_zeros() as usize)
    }

    fn record_single_value(&mut self, value: u64) -> Result<(), String> {
        let counts_index = self.counts_array_index(value);
            match self.increment_count_at_index(counts_index) {
                Ok(_) => {
                    self.update_min_and_max(value);
                    self.increment_total_count();
                    Ok(())
                }
                Err(err) => {
                    Err(String::from(format!("Could not increment count at index due to: {}", err)))
                }
            }
    }

    fn get_max(&self) -> u64 {
        self.max_value
    }

    fn get_count(&self) -> u64 {
        self.total_count
    }

    fn counts_array_index(&self, value: u64) -> usize {
        let bucket_index = self.get_bucket_index(value);
        let sub_bucket_index = self.get_sub_bucket_index(value, bucket_index);
        return self.counts_array_index_sub(bucket_index, sub_bucket_index);
    }

    fn counts_array_index_sub(&self, bucket_index: usize, sub_bucket_index: usize) -> usize {
        assert!(sub_bucket_index < self.sub_bucket_count);
        assert!(bucket_index == 0 || (sub_bucket_index >= self.sub_bucket_half_count));

        let bucket_base_index = (bucket_index + 1) << self.sub_bucket_half_count_magnitude;
        println!("bi: {}, sbi: {}, bbi: {}", bucket_index, sub_bucket_index, bucket_base_index);
        let offset_in_bucket = sub_bucket_index - self.sub_bucket_half_count;

        bucket_base_index + offset_in_bucket
    }
}

#[test]
fn count_at_value_on_empty() {
    let mut the_hist = init_histo(1, 100000, 3);

    assert_eq!(the_hist.get_count_at_value(1).unwrap(), 0);
//    assert_eq!(the_hist.get_count_at_value(5000).unwrap(), 0);
//    assert_eq!(the_hist.get_count_at_value(100000).unwrap(), 0);
}

#[test]
fn count_at_value_after_record() {
    let mut the_hist = init_histo(1, 100000, 3);

    let result = the_hist.record_single_value(5000);
    match result {
        Ok(_) => (),
        Err(err) => panic!(format!("could not add single record to histogram because error: {}", err))
    }

    assert_eq!(the_hist.get_count_at_value(1).unwrap(), 0);
    assert_eq!(the_hist.get_count_at_value(5000).unwrap(), 1);
    assert_eq!(the_hist.get_count_at_value(100000).unwrap(), 0);
}

#[test]
fn can_get_count_after_record() {
    let mut the_hist = init_histo(1, 100000, 3);
    let result = the_hist.record_single_value(5000);
    match result {
        Ok(_) => (),
        Err(err) => panic!(format!("could not add single record to histogram because error: {}", err))
    }

    let count = the_hist.get_count();
    assert_eq!(count, 1);
}

#[test]
fn can_get_max_after_record() {
    let mut the_hist = init_histo(1, 100000, 3);
    let result = the_hist.record_single_value(5000);
    match result {
        Ok(_) => (),
        Err(err) => panic!(format!("could not add single record to histogram because error: {}", err))
    }

    let max = the_hist.get_max();
    assert_eq!(max, 5000);
}

#[test]
fn can_record_single_value() {
    let mut the_hist = init_histo(1, 100000, 3);
    let result = the_hist.record_single_value(5000);

    match result {
        Ok(_) => (),
        Err(err) => panic!(format!("could not add single record to histogram because error: {}", err))
    }
}

#[test]
fn can_compute_indexes_for_smallest_value() {
    let the_hist = init_histo(1, 100000, 3);
    let value = 1;
    assert_eq!(the_hist.get_bucket_index(value), 0);
    assert_eq!(the_hist.get_sub_bucket_index(value, 0), 1);
    assert_eq!(the_hist.counts_array_index(value), 1);
}

#[test]
fn can_compute_counts_array_index() {
    let the_hist = init_histo(1, 100000, 3);
    let result = the_hist.counts_array_index(5000);

    assert_eq!(result, 3298);
}

#[test]
fn can_get_bucket_index() {
    let the_hist = init_histo(1, 100000, 3);
    let result = the_hist.get_bucket_index(5000);
    assert_eq!(result, 2)
}

#[test]
fn can_get_sub_bucket_index() {
    let the_hist = init_histo(1, 100000, 3);
    let result = the_hist.get_sub_bucket_index(5000, 2);
    assert_eq!(result, 1250)
}

/// lowest_discernible_value: must be >= 1
/// highest_trackable_value: must be >= 2 * lowest_discernible_value
/// num_significant_digits: must be <= 5
fn init_histo(lowest_discernible_value: u64, highest_trackable_value: u64, num_significant_digits: u32) -> SimpleHdrHistogram {

    assert!(lowest_discernible_value >= 1);
    assert!(highest_trackable_value >= 2 * lowest_discernible_value);
    assert!(num_significant_digits <= 5);

    let mut hist =  SimpleHdrHistogram { ..Default::default() };

    let largest_value_with_single_unit_resolution = 2_u64 * 10_u64.pow(num_significant_digits);

    let unit_magnitude = ((lowest_discernible_value as f64).ln() / 2_f64.ln()) as u32;
    let unit_magnitude_mask: u64  = 1_u64.rotate_left(unit_magnitude) - 1;

    // find nearest power of 2 to largest_value_with_single_unit_resolution
    let sub_bucket_count_magnitude: u32 =
        ((largest_value_with_single_unit_resolution as f64).ln() / 2_f64.ln()).ceil() as u32;

    // ugly looking... how should ternaries be done?
    let sub_bucket_half_count_magnitude: u32 = (if sub_bucket_count_magnitude > 1 { sub_bucket_count_magnitude } else { 1 }) - 1;
    let sub_bucket_count: usize = 2_usize.pow(sub_bucket_half_count_magnitude + 1);
    let sub_bucket_half_count: usize = sub_bucket_count / 2;
    // TODO is this cast OK?
    let sub_bucket_mask = (sub_bucket_count - 1).rotate_left(unit_magnitude) as u64;

    let counts_arr_len = counts_arr_len(highest_trackable_value, sub_bucket_count, unit_magnitude);
    let bucket_count = buckets_needed_for_value(highest_trackable_value, sub_bucket_count, unit_magnitude);

    let leading_zero_count_base: usize = (64_u32 - unit_magnitude - sub_bucket_half_count_magnitude - 1) as usize;

    hist.leading_zeros_count_base = leading_zero_count_base;
    hist.sub_bucket_mask = sub_bucket_mask;
    hist.unit_magnitude = unit_magnitude;
    hist.sub_bucket_count = sub_bucket_count;
    hist.sub_bucket_half_count = sub_bucket_half_count;
    hist.sub_bucket_half_count_magnitude = sub_bucket_half_count_magnitude;
    hist.counts = vec![0; counts_arr_len];
    hist.counts_array_length = counts_arr_len;
    hist.normalizing_index_offset = 0_usize; // 0 for normal Histogram ctor in Java impl

    println!("hist: {:?}", hist);

    hist
}

fn buckets_needed_for_value(value: u64, sub_bucket_count: usize, unit_magnitude: u32) -> usize {

    // TODO is this cast ok?
    let mut smallest_untrackable_value: u64 = sub_bucket_count.rotate_left(unit_magnitude) as u64;
    let mut buckets_needed: usize = 1;

    while smallest_untrackable_value <= value {
        if smallest_untrackable_value > u64::max_value() / 2 {
            return buckets_needed + 1;
        }

        smallest_untrackable_value = smallest_untrackable_value.rotate_left(1);
        buckets_needed += 1;
    }

    return buckets_needed;
}

fn counts_arr_len_for_buckets(buckets: usize, sub_bucket_count: usize) -> usize {
    (buckets + 1) * (sub_bucket_count / 2)
}

fn counts_arr_len(value: u64, sub_bucket_count: usize, unit_magnitude: u32) -> usize {
    counts_arr_len_for_buckets(buckets_needed_for_value(value, sub_bucket_count, unit_magnitude), sub_bucket_count)
}<|endoftext|>


<commit_before>/* automatically generated by rust-bindgen */

import bindgen::{glutCreateWindow, glutDestroyWindow, glutDisplayFunc, glutGetWindow, glutInit};
import bindgen::{glutInitDisplayMode, glutPostRedisplay, glutReshapeFunc, glutReshapeWindow};
import bindgen::{glutSetWindow, glutSwapBuffers, glutTimerFunc};
import libc::*;
import dvec::DVec;
import ptr::{addr_of, null};
import str::to_bytes;
import task::{local_data_get, local_data_set};
import unsafe::reinterpret_cast;
import vec::unsafe::to_ptr;

/* FIXME: global variable glutStrokeRoman */

/* FIXME: global variable glutStrokeMonoRoman */

/* FIXME: global variable glutBitmap9By15 */

/* FIXME: global variable glutBitmap8By13 */

/* FIXME: global variable glutBitmapTimesRoman10 */

/* FIXME: global variable glutBitmapTimesRoman24 */

/* FIXME: global variable glutBitmapHelvetica10 */

/* FIXME: global variable glutBitmapHelvetica12 */

/* FIXME: global variable glutBitmapHelvetica18 */

type GLenum = i32;
type GLint = i32;
type GLfloat = f32;
type GLdouble = f64;

enum Window = c_int;

const DOUBLE: c_uint = 2 as c_uint;

fn destroy<T>(-_value: ~[T]) {
    // let it drop
}

fn init() unsafe {
    let argc = 0 as c_int;
    let command = to_bytes(~"glut");
    let argv: (*u8, *u8) = (to_ptr(command), null());
    let argv_p = reinterpret_cast(addr_of(argv));

    glutInit(addr_of(argc), argv_p);

    destroy(command);
}

fn create_window(name: ~str) -> Window unsafe {
    let bytes = to_bytes(name);
    return Window(glutCreateWindow(to_ptr(bytes) as *c_char));
}

fn destroy_window(window: Window) unsafe {
    glutDestroyWindow(*window);
}

fn reshape_window(window: Window, width: c_int, height: c_int) unsafe {
    let current_window = glutGetWindow();
    glutSetWindow(*window);
    glutReshapeWindow(width, height);
    glutSetWindow(current_window);
}

fn display_callback_tls_key(+_callback: @fn@()) {
    // Empty.
}

extern fn display_callback() unsafe {
    let callback = local_data_get(display_callback_tls_key).get();
    (*callback)();
}

fn display_func(callback: fn@()) unsafe {
    local_data_set(display_callback_tls_key, @callback);
    glutDisplayFunc(display_callback);
}

fn timer_callback_tls_key(+_callback: @DVec<fn@()>) {
    // Empty.
}

extern fn timer_callback(index: int) unsafe {
    let callbacks = local_data_get(timer_callback_tls_key).get();
    ((*callbacks)[index as uint])();
}

fn timer_func(msecs: u32, callback: fn@()) unsafe {
    let callbacks;
    match local_data_get(timer_callback_tls_key) {
        None => {
            callbacks = @DVec();
            local_data_set(timer_callback_tls_key, copy callbacks);
        }
        Some(existing_callbacks) => {
            callbacks = existing_callbacks;
        }
    }

    callbacks.push(callback);
    let index = (callbacks.len() - 1) as c_int;
    glutTimerFunc(msecs, timer_callback, index);
}

fn reshape_callback_tls_key(+_callback: @fn@(++c_int, ++c_int)) {
    // Empty.
}

extern fn reshape_callback(++width: c_int, ++height: c_int) unsafe {
    let callback = local_data_get(reshape_callback_tls_key).get();
    (*callback)(width, height);
}

fn reshape_func(_window: Window, callback: fn@(++c_int, ++c_int)) unsafe {
    local_data_set(reshape_callback_tls_key, @callback);
    glutReshapeFunc(reshape_callback);
}

#[cfg(target_os="macos")]
fn check_loop() unsafe {
    ext::glutCheckLoop();
}

#[cfg(target_os="linux")]
fn check_loop() unsafe {
    ext::glutMainLoopEvent();
}

fn init_display_mode(mode: c_uint) unsafe {
    glutInitDisplayMode(mode);
}

fn swap_buffers() unsafe {
    glutSwapBuffers();
}

fn post_redisplay() unsafe {
    glutPostRedisplay();
}

#[cfg(target_os="macos")]
#[nolink]
#[link_args="-framework GLUT"]
extern mod dummy {
}

#[cfg(target_os="linux")]
#[link_name="glut"]
extern mod dummy {
}

#[cfg(target_os="macos")]
#[nolink]
extern mod ext {
    // Mac GLUT extension.
    fn glutCheckLoop();
}

#[cfg(target_os="linux")]
#[nolink]
extern mod ext {
    // freeglut extension.
    fn glutMainLoopEvent();
}

#[nolink]
extern mod bindgen {

fn glutInit(++argcp: *c_int, ++argv: **c_char);

fn glutInitDisplayMode(++mode: c_uint);

fn glutInitDisplayString(++string: *c_char);

fn glutInitWindowPosition(++x: c_int, ++y: c_int);

fn glutInitWindowSize(++width: c_int, ++height: c_int);

fn glutMainLoop();

fn glutCreateWindow(++title: *c_char) -> c_int;

fn glutCreateSubWindow(++win: c_int, ++x: c_int, ++y: c_int, ++width: c_int, ++height: c_int) -> c_int;

fn glutDestroyWindow(++win: c_int);

fn glutPostRedisplay();

fn glutPostWindowRedisplay(++win: c_int);

fn glutSwapBuffers();

fn glutGetWindow() -> c_int;

fn glutSetWindow(++win: c_int);

fn glutSetWindowTitle(++title: *c_char);

fn glutSetIconTitle(++title: *c_char);

fn glutPositionWindow(++x: c_int, ++y: c_int);

fn glutReshapeWindow(++width: c_int, ++height: c_int);

fn glutPopWindow();

fn glutPushWindow();

fn glutIconifyWindow();

fn glutShowWindow();

fn glutHideWindow();

fn glutFullScreen();

fn glutSetCursor(++cursor: c_int);

fn glutWarpPointer(++x: c_int, ++y: c_int);

fn glutEstablishOverlay();

fn glutRemoveOverlay();

fn glutUseLayer(++layer: GLenum);

fn glutPostOverlayRedisplay();

fn glutPostWindowOverlayRedisplay(++win: c_int);

fn glutShowOverlay();

fn glutHideOverlay();

fn glutCreateMenu(++arg1: *u8) -> c_int;

fn glutDestroyMenu(++menu: c_int);

fn glutGetMenu() -> c_int;

fn glutSetMenu(++menu: c_int);

fn glutAddMenuEntry(++label: *c_char, ++value: c_int);

fn glutAddSubMenu(++label: *c_char, ++submenu: c_int);

fn glutChangeToMenuEntry(++item: c_int, ++label: *c_char, ++value: c_int);

fn glutChangeToSubMenu(++item: c_int, ++label: *c_char, ++submenu: c_int);

fn glutRemoveMenuItem(++item: c_int);

fn glutAttachMenu(++button: c_int);

fn glutDetachMenu(++button: c_int);

fn glutDisplayFunc(++func: *u8);

fn glutReshapeFunc(++func: *u8);

fn glutKeyboardFunc(++func: *u8);

fn glutMouseFunc(++func: *u8);

fn glutMotionFunc(++func: *u8);

fn glutPassiveMotionFunc(++func: *u8);

fn glutEntryFunc(++func: *u8);

fn glutVisibilityFunc(++func: *u8);

fn glutIdleFunc(++func: *u8);

fn glutTimerFunc(++millis: c_uint, ++func: *u8, ++value: c_int);

fn glutMenuStateFunc(++func: *u8);

fn glutSpecialFunc(++func: *u8);

fn glutSpaceballMotionFunc(++func: *u8);

fn glutSpaceballRotateFunc(++func: *u8);

fn glutSpaceballButtonFunc(++func: *u8);

fn glutButtonBoxFunc(++func: *u8);

fn glutDialsFunc(++func: *u8);

fn glutTabletMotionFunc(++func: *u8);

fn glutTabletButtonFunc(++func: *u8);

fn glutMenuStatusFunc(++func: *u8);

fn glutOverlayDisplayFunc(++func: *u8);

fn glutWindowStatusFunc(++func: *u8);

fn glutKeyboardUpFunc(++func: *u8);

fn glutSpecialUpFunc(++func: *u8);

fn glutJoystickFunc(++func: *u8, ++pollInterval: c_int);

fn glutSetColor(++arg1: c_int, ++red: GLfloat, ++green: GLfloat, ++blue: GLfloat);

fn glutGetColor(++ndx: c_int, ++component: c_int) -> GLfloat;

fn glutCopyColormap(++win: c_int);

fn glutGet(++_type: GLenum) -> c_int;

fn glutDeviceGet(++_type: GLenum) -> c_int;

fn glutExtensionSupported(++name: *c_char) -> c_int;

fn glutGetModifiers() -> c_int;

fn glutLayerGet(++_type: GLenum) -> c_int;

fn glutGetProcAddress(++procName: *c_char) -> *c_void;

fn glutBitmapCharacter(++font: *c_void, ++character: c_int);

fn glutBitmapWidth(++font: *c_void, ++character: c_int) -> c_int;

fn glutStrokeCharacter(++font: *c_void, ++character: c_int);

fn glutStrokeWidth(++font: *c_void, ++character: c_int) -> c_int;

fn glutBitmapLength(++font: *c_void, ++string: *c_uchar) -> c_int;

fn glutStrokeLength(++font: *c_void, ++string: *c_uchar) -> c_int;

fn glutWireSphere(++radius: GLdouble, ++slices: GLint, ++stacks: GLint);

fn glutSolidSphere(++radius: GLdouble, ++slices: GLint, ++stacks: GLint);

fn glutWireCone(++base: GLdouble, ++height: GLdouble, ++slices: GLint, ++stacks: GLint);

fn glutSolidCone(++base: GLdouble, ++height: GLdouble, ++slices: GLint, ++stacks: GLint);

fn glutWireCube(++size: GLdouble);

fn glutSolidCube(++size: GLdouble);

fn glutWireTorus(++innerRadius: GLdouble, ++outerRadius: GLdouble, ++sides: GLint, ++rings: GLint);

fn glutSolidTorus(++innerRadius: GLdouble, ++outerRadius: GLdouble, ++sides: GLint, ++rings: GLint);

fn glutWireDodecahedron();

fn glutSolidDodecahedron();

fn glutWireTeapot(++size: GLdouble);

fn glutSolidTeapot(++size: GLdouble);

fn glutWireOctahedron();

fn glutSolidOctahedron();

fn glutWireTetrahedron();

fn glutSolidTetrahedron();

fn glutWireIcosahedron();

fn glutSolidIcosahedron();

fn glutVideoResizeGet(++param: GLenum) -> c_int;

fn glutSetupVideoResizing();

fn glutStopVideoResizing();

fn glutVideoResize(++x: c_int, ++y: c_int, ++width: c_int, ++height: c_int);

fn glutVideoPan(++x: c_int, ++y: c_int, ++width: c_int, ++height: c_int);

fn glutReportErrors();

fn glutIgnoreKeyRepeat(++ignore: c_int);

fn glutSetKeyRepeat(++repeatMode: c_int);

fn glutForceJoystickFunc();

fn glutGameModeString(++string: *c_char);

fn glutEnterGameMode() -> c_int;

fn glutLeaveGameMode();

fn glutGameModeGet(++mode: GLenum) -> c_int;

}
<commit_msg>Fix upstream build breaks by changing uses of reinterpret_cast to pass by reference.<commit_after>/* automatically generated by rust-bindgen */

import bindgen::{glutCreateWindow, glutDestroyWindow, glutDisplayFunc, glutGetWindow, glutInit};
import bindgen::{glutInitDisplayMode, glutPostRedisplay, glutReshapeFunc, glutReshapeWindow};
import bindgen::{glutSetWindow, glutSwapBuffers, glutTimerFunc};
import libc::*;
import dvec::DVec;
import ptr::{addr_of, null};
import str::to_bytes;
import task::{local_data_get, local_data_set};
import unsafe::reinterpret_cast;
import vec::unsafe::to_ptr;

/* FIXME: global variable glutStrokeRoman */

/* FIXME: global variable glutStrokeMonoRoman */

/* FIXME: global variable glutBitmap9By15 */

/* FIXME: global variable glutBitmap8By13 */

/* FIXME: global variable glutBitmapTimesRoman10 */

/* FIXME: global variable glutBitmapTimesRoman24 */

/* FIXME: global variable glutBitmapHelvetica10 */

/* FIXME: global variable glutBitmapHelvetica12 */

/* FIXME: global variable glutBitmapHelvetica18 */

type GLenum = i32;
type GLint = i32;
type GLfloat = f32;
type GLdouble = f64;

enum Window = c_int;

const DOUBLE: c_uint = 2 as c_uint;

fn destroy<T>(-_value: ~[T]) {
    // let it drop
}

fn init() unsafe {
    let argc = 0 as c_int;
    let command = to_bytes(~"glut");
    let argv: (*u8, *u8) = (to_ptr(command), null());
    let argv_p = reinterpret_cast(&addr_of(argv));

    glutInit(addr_of(argc), argv_p);

    destroy(command);
}

fn create_window(name: ~str) -> Window unsafe {
    let bytes = to_bytes(name);
    return Window(glutCreateWindow(to_ptr(bytes) as *c_char));
}

fn destroy_window(window: Window) unsafe {
    glutDestroyWindow(*window);
}

fn reshape_window(window: Window, width: c_int, height: c_int) unsafe {
    let current_window = glutGetWindow();
    glutSetWindow(*window);
    glutReshapeWindow(width, height);
    glutSetWindow(current_window);
}

fn display_callback_tls_key(+_callback: @fn@()) {
    // Empty.
}

extern fn display_callback() unsafe {
    let callback = local_data_get(display_callback_tls_key).get();
    (*callback)();
}

fn display_func(callback: fn@()) unsafe {
    local_data_set(display_callback_tls_key, @callback);
    glutDisplayFunc(display_callback);
}

fn timer_callback_tls_key(+_callback: @DVec<fn@()>) {
    // Empty.
}

extern fn timer_callback(index: int) unsafe {
    let callbacks = local_data_get(timer_callback_tls_key).get();
    ((*callbacks)[index as uint])();
}

fn timer_func(msecs: u32, callback: fn@()) unsafe {
    let callbacks;
    match local_data_get(timer_callback_tls_key) {
        None => {
            callbacks = @DVec();
            local_data_set(timer_callback_tls_key, copy callbacks);
        }
        Some(existing_callbacks) => {
            callbacks = existing_callbacks;
        }
    }

    callbacks.push(callback);
    let index = (callbacks.len() - 1) as c_int;
    glutTimerFunc(msecs, timer_callback, index);
}

fn reshape_callback_tls_key(+_callback: @fn@(++c_int, ++c_int)) {
    // Empty.
}

extern fn reshape_callback(++width: c_int, ++height: c_int) unsafe {
    let callback = local_data_get(reshape_callback_tls_key).get();
    (*callback)(width, height);
}

fn reshape_func(_window: Window, callback: fn@(++c_int, ++c_int)) unsafe {
    local_data_set(reshape_callback_tls_key, @callback);
    glutReshapeFunc(reshape_callback);
}

#[cfg(target_os="macos")]
fn check_loop() unsafe {
    ext::glutCheckLoop();
}

#[cfg(target_os="linux")]
fn check_loop() unsafe {
    ext::glutMainLoopEvent();
}

fn init_display_mode(mode: c_uint) unsafe {
    glutInitDisplayMode(mode);
}

fn swap_buffers() unsafe {
    glutSwapBuffers();
}

fn post_redisplay() unsafe {
    glutPostRedisplay();
}

#[cfg(target_os="macos")]
#[nolink]
#[link_args="-framework GLUT"]
extern mod dummy {
}

#[cfg(target_os="linux")]
#[link_name="glut"]
extern mod dummy {
}

#[cfg(target_os="macos")]
#[nolink]
extern mod ext {
    // Mac GLUT extension.
    fn glutCheckLoop();
}

#[cfg(target_os="linux")]
#[nolink]
extern mod ext {
    // freeglut extension.
    fn glutMainLoopEvent();
}

#[nolink]
extern mod bindgen {

fn glutInit(++argcp: *c_int, ++argv: **c_char);

fn glutInitDisplayMode(++mode: c_uint);

fn glutInitDisplayString(++string: *c_char);

fn glutInitWindowPosition(++x: c_int, ++y: c_int);

fn glutInitWindowSize(++width: c_int, ++height: c_int);

fn glutMainLoop();

fn glutCreateWindow(++title: *c_char) -> c_int;

fn glutCreateSubWindow(++win: c_int, ++x: c_int, ++y: c_int, ++width: c_int, ++height: c_int) -> c_int;

fn glutDestroyWindow(++win: c_int);

fn glutPostRedisplay();

fn glutPostWindowRedisplay(++win: c_int);

fn glutSwapBuffers();

fn glutGetWindow() -> c_int;

fn glutSetWindow(++win: c_int);

fn glutSetWindowTitle(++title: *c_char);

fn glutSetIconTitle(++title: *c_char);

fn glutPositionWindow(++x: c_int, ++y: c_int);

fn glutReshapeWindow(++width: c_int, ++height: c_int);

fn glutPopWindow();

fn glutPushWindow();

fn glutIconifyWindow();

fn glutShowWindow();

fn glutHideWindow();

fn glutFullScreen();

fn glutSetCursor(++cursor: c_int);

fn glutWarpPointer(++x: c_int, ++y: c_int);

fn glutEstablishOverlay();

fn glutRemoveOverlay();

fn glutUseLayer(++layer: GLenum);

fn glutPostOverlayRedisplay();

fn glutPostWindowOverlayRedisplay(++win: c_int);

fn glutShowOverlay();

fn glutHideOverlay();

fn glutCreateMenu(++arg1: *u8) -> c_int;

fn glutDestroyMenu(++menu: c_int);

fn glutGetMenu() -> c_int;

fn glutSetMenu(++menu: c_int);

fn glutAddMenuEntry(++label: *c_char, ++value: c_int);

fn glutAddSubMenu(++label: *c_char, ++submenu: c_int);

fn glutChangeToMenuEntry(++item: c_int, ++label: *c_char, ++value: c_int);

fn glutChangeToSubMenu(++item: c_int, ++label: *c_char, ++submenu: c_int);

fn glutRemoveMenuItem(++item: c_int);

fn glutAttachMenu(++button: c_int);

fn glutDetachMenu(++button: c_int);

fn glutDisplayFunc(++func: *u8);

fn glutReshapeFunc(++func: *u8);

fn glutKeyboardFunc(++func: *u8);

fn glutMouseFunc(++func: *u8);

fn glutMotionFunc(++func: *u8);

fn glutPassiveMotionFunc(++func: *u8);

fn glutEntryFunc(++func: *u8);

fn glutVisibilityFunc(++func: *u8);

fn glutIdleFunc(++func: *u8);

fn glutTimerFunc(++millis: c_uint, ++func: *u8, ++value: c_int);

fn glutMenuStateFunc(++func: *u8);

fn glutSpecialFunc(++func: *u8);

fn glutSpaceballMotionFunc(++func: *u8);

fn glutSpaceballRotateFunc(++func: *u8);

fn glutSpaceballButtonFunc(++func: *u8);

fn glutButtonBoxFunc(++func: *u8);

fn glutDialsFunc(++func: *u8);

fn glutTabletMotionFunc(++func: *u8);

fn glutTabletButtonFunc(++func: *u8);

fn glutMenuStatusFunc(++func: *u8);

fn glutOverlayDisplayFunc(++func: *u8);

fn glutWindowStatusFunc(++func: *u8);

fn glutKeyboardUpFunc(++func: *u8);

fn glutSpecialUpFunc(++func: *u8);

fn glutJoystickFunc(++func: *u8, ++pollInterval: c_int);

fn glutSetColor(++arg1: c_int, ++red: GLfloat, ++green: GLfloat, ++blue: GLfloat);

fn glutGetColor(++ndx: c_int, ++component: c_int) -> GLfloat;

fn glutCopyColormap(++win: c_int);

fn glutGet(++_type: GLenum) -> c_int;

fn glutDeviceGet(++_type: GLenum) -> c_int;

fn glutExtensionSupported(++name: *c_char) -> c_int;

fn glutGetModifiers() -> c_int;

fn glutLayerGet(++_type: GLenum) -> c_int;

fn glutGetProcAddress(++procName: *c_char) -> *c_void;

fn glutBitmapCharacter(++font: *c_void, ++character: c_int);

fn glutBitmapWidth(++font: *c_void, ++character: c_int) -> c_int;

fn glutStrokeCharacter(++font: *c_void, ++character: c_int);

fn glutStrokeWidth(++font: *c_void, ++character: c_int) -> c_int;

fn glutBitmapLength(++font: *c_void, ++string: *c_uchar) -> c_int;

fn glutStrokeLength(++font: *c_void, ++string: *c_uchar) -> c_int;

fn glutWireSphere(++radius: GLdouble, ++slices: GLint, ++stacks: GLint);

fn glutSolidSphere(++radius: GLdouble, ++slices: GLint, ++stacks: GLint);

fn glutWireCone(++base: GLdouble, ++height: GLdouble, ++slices: GLint, ++stacks: GLint);

fn glutSolidCone(++base: GLdouble, ++height: GLdouble, ++slices: GLint, ++stacks: GLint);

fn glutWireCube(++size: GLdouble);

fn glutSolidCube(++size: GLdouble);

fn glutWireTorus(++innerRadius: GLdouble, ++outerRadius: GLdouble, ++sides: GLint, ++rings: GLint);

fn glutSolidTorus(++innerRadius: GLdouble, ++outerRadius: GLdouble, ++sides: GLint, ++rings: GLint);

fn glutWireDodecahedron();

fn glutSolidDodecahedron();

fn glutWireTeapot(++size: GLdouble);

fn glutSolidTeapot(++size: GLdouble);

fn glutWireOctahedron();

fn glutSolidOctahedron();

fn glutWireTetrahedron();

fn glutSolidTetrahedron();

fn glutWireIcosahedron();

fn glutSolidIcosahedron();

fn glutVideoResizeGet(++param: GLenum) -> c_int;

fn glutSetupVideoResizing();

fn glutStopVideoResizing();

fn glutVideoResize(++x: c_int, ++y: c_int, ++width: c_int, ++height: c_int);

fn glutVideoPan(++x: c_int, ++y: c_int, ++width: c_int, ++height: c_int);

fn glutReportErrors();

fn glutIgnoreKeyRepeat(++ignore: c_int);

fn glutSetKeyRepeat(++repeatMode: c_int);

fn glutForceJoystickFunc();

fn glutGameModeString(++string: *c_char);

fn glutEnterGameMode() -> c_int;

fn glutLeaveGameMode();

fn glutGameModeGet(++mode: GLenum) -> c_int;

}
<|endoftext|>


<commit_before>#![allow(dead_code)]

extern crate rand;
#[macro_use]
extern crate rand_macros;

use rand::Rng;

#[derive(Rand)]
struct Struct {
    x: u16,
    y: Option<f64>,
}

#[derive(Rand)]
struct Tuple(i16, Option<f64>);

#[derive(Rand)]
struct Unit;

#[derive(Rand)]
enum Enum {
    X { x: u8, y: isize },
    Y([bool; 4]),
    Z,
}

#[test]
fn smoke() {
    let mut rng = rand::XorShiftRng::new_unseeded();

    // check nothing horrible happens internally:
    for _ in 0..100 {
        let _ = rng.gen::<Struct>();
        let _ = rng.gen::<Tuple>();
        let _ = rng.gen::<Unit>();
        let _ = rng.gen::<Enum>();
    }
}
<commit_msg>Fix rand-derive test<commit_after>#![allow(dead_code)]

extern crate rand;
#[macro_use]
extern crate rand_derive;

use rand::Rng;

#[derive(Rand)]
struct Struct {
    x: u16,
    y: Option<f64>,
}

#[derive(Rand)]
struct Tuple(i16, Option<f64>);

#[derive(Rand)]
struct Unit;

#[derive(Rand)]
enum Enum {
    X { x: u8, y: isize },
    Y([bool; 4]),
    Z,
}

#[test]
fn smoke() {
    let mut rng = rand::XorShiftRng::new_unseeded();

    // check nothing horrible happens internally:
    for _ in 0..100 {
        let _ = rng.gen::<Struct>();
        let _ = rng.gen::<Tuple>();
        let _ = rng.gen::<Unit>();
        let _ = rng.gen::<Enum>();
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::ptr;
use std::sync::{
    Arc,
    Mutex,
};
use std::thread;
use std::time::Duration;

use winapi::winsock2::{
    fd_set,
    SOCKET_ERROR,
    timeval,
    WSADATA,
};
use ws2_32::{
    select,
    WSACleanup,
    WSAStartup,
};

use c_ares;
use mio;
use mio_more;

use error::Error;
use eventloop::EventLoopHandle;

// The EventLoop will use select() to check on the status of file descriptors
// that c-ares cares about.
//
// It also waits for a message telling it to shut down.  We use a mio channel
// here only for consistency with the unix interface.
pub struct EventLoop {
    tx_msg_channel: mio_more::channel::Sender<Message>,
    rx_msg_channel: mio_more::channel::Receiver<Message>,
    pub ares_channel: Arc<Mutex<c_ares::Channel>>,
    quit: bool,
}

// Messages for the event loop.
#[derive(Debug)]
pub enum Message {
    // 'Shut down'.
    ShutDown,
}

impl EventLoop {
    // Create a new event loop.
    pub fn new(options: c_ares::Options) -> Result<EventLoop, Error> {
        // Initialize sockets.
        unsafe {
            let mut wsadata: WSADATA = mem::uninitialized();
            WSAStartup(0x101, &mut wsadata);
        }

        // Create the message channel.
        let (tx, rx) = mio_more::channel::channel();

        // Create the c-ares channel.
        let ares_channel = c_ares::Channel::with_options(options)?;
        let locked_channel = Arc::new(Mutex::new(ares_channel));

        // Create and return the event loop.
        let event_loop = EventLoop {
            tx_msg_channel: tx,
            rx_msg_channel: rx,
            ares_channel: locked_channel,
            quit: false,
        };
        Ok(event_loop)
    }

    // Run the event loop.
    pub fn run(self) -> EventLoopHandle {
        let tx_clone = self.tx_msg_channel.clone();
        let join_handle = thread::spawn(|| self.event_loop_thread());
        EventLoopHandle::new(join_handle, tx_clone)
    }

    // Event loop thread - waits for events, and handles them.
    fn event_loop_thread(mut self) {
        let mut read_fds: fd_set = unsafe { mem::uninitialized() };
        let mut write_fds: fd_set = unsafe { mem::uninitialized() };

        // Loop round, asking c-ares what it cares about and doing as asked.
        loop {
            read_fds.fd_count = 0;
            write_fds.fd_count = 0;
            let count = self.ares_channel.lock().unwrap()
                .fds(&mut read_fds, &mut write_fds);

            if count == 0 {
                thread::sleep(Duration::from_millis(100));
            } else {
                let timeout = timeval {
                    tv_sec: 0,
                    tv_usec: 100000,
                };
                let results = unsafe {
                    select(
                        0,
                        &mut read_fds,
                        &mut write_fds,
                        ptr::null_mut(),
                        &timeout
                    )
                };

                // Process whatever happened.
                match results {
                    SOCKET_ERROR => panic!("Socket error"),
                    _ => self.ares_channel.lock().unwrap()
                        .process(&mut read_fds, &mut write_fds),
                }
            }

            // Check whether we've been asked to quit.
            self.handle_messages();
            if self.quit { break }
        }
    }

    // Process messages incoming on the channel.
    fn handle_messages(&mut self) {
        // The only possible message is an instruction to shut down.
        if let Ok(Message::ShutDown) = self.rx_msg_channel.try_recv() {
            self.quit = true;
        }
    }
}

impl Drop for EventLoop {
    fn drop(&mut self) {
        unsafe { WSACleanup(); }
    }
}
<commit_msg>unused import<commit_after>use std::mem;
use std::ptr;
use std::sync::{
    Arc,
    Mutex,
};
use std::thread;
use std::time::Duration;

use winapi::winsock2::{
    fd_set,
    SOCKET_ERROR,
    timeval,
    WSADATA,
};
use ws2_32::{
    select,
    WSACleanup,
    WSAStartup,
};

use c_ares;
use mio_more;

use error::Error;
use eventloop::EventLoopHandle;

// The EventLoop will use select() to check on the status of file descriptors
// that c-ares cares about.
//
// It also waits for a message telling it to shut down.  We use a mio channel
// here only for consistency with the unix interface.
pub struct EventLoop {
    tx_msg_channel: mio_more::channel::Sender<Message>,
    rx_msg_channel: mio_more::channel::Receiver<Message>,
    pub ares_channel: Arc<Mutex<c_ares::Channel>>,
    quit: bool,
}

// Messages for the event loop.
#[derive(Debug)]
pub enum Message {
    // 'Shut down'.
    ShutDown,
}

impl EventLoop {
    // Create a new event loop.
    pub fn new(options: c_ares::Options) -> Result<EventLoop, Error> {
        // Initialize sockets.
        unsafe {
            let mut wsadata: WSADATA = mem::uninitialized();
            WSAStartup(0x101, &mut wsadata);
        }

        // Create the message channel.
        let (tx, rx) = mio_more::channel::channel();

        // Create the c-ares channel.
        let ares_channel = c_ares::Channel::with_options(options)?;
        let locked_channel = Arc::new(Mutex::new(ares_channel));

        // Create and return the event loop.
        let event_loop = EventLoop {
            tx_msg_channel: tx,
            rx_msg_channel: rx,
            ares_channel: locked_channel,
            quit: false,
        };
        Ok(event_loop)
    }

    // Run the event loop.
    pub fn run(self) -> EventLoopHandle {
        let tx_clone = self.tx_msg_channel.clone();
        let join_handle = thread::spawn(|| self.event_loop_thread());
        EventLoopHandle::new(join_handle, tx_clone)
    }

    // Event loop thread - waits for events, and handles them.
    fn event_loop_thread(mut self) {
        let mut read_fds: fd_set = unsafe { mem::uninitialized() };
        let mut write_fds: fd_set = unsafe { mem::uninitialized() };

        // Loop round, asking c-ares what it cares about and doing as asked.
        loop {
            read_fds.fd_count = 0;
            write_fds.fd_count = 0;
            let count = self.ares_channel.lock().unwrap()
                .fds(&mut read_fds, &mut write_fds);

            if count == 0 {
                thread::sleep(Duration::from_millis(100));
            } else {
                let timeout = timeval {
                    tv_sec: 0,
                    tv_usec: 100000,
                };
                let results = unsafe {
                    select(
                        0,
                        &mut read_fds,
                        &mut write_fds,
                        ptr::null_mut(),
                        &timeout
                    )
                };

                // Process whatever happened.
                match results {
                    SOCKET_ERROR => panic!("Socket error"),
                    _ => self.ares_channel.lock().unwrap()
                        .process(&mut read_fds, &mut write_fds),
                }
            }

            // Check whether we've been asked to quit.
            self.handle_messages();
            if self.quit { break }
        }
    }

    // Process messages incoming on the channel.
    fn handle_messages(&mut self) {
        // The only possible message is an instruction to shut down.
        if let Ok(Message::ShutDown) = self.rx_msg_channel.try_recv() {
            self.quit = true;
        }
    }
}

impl Drop for EventLoop {
    fn drop(&mut self) {
        unsafe { WSACleanup(); }
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 The Grin Developers
//
// 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
//
//     http://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.

use std::cmp;
use std::env;
use std::fs::File;
use std::io::{self, BufWriter};
use std::net::{SocketAddr, TcpStream};
use std::sync::Arc;
use std::time;

use chrono::prelude::Utc;
use conn::{Message, MessageHandler, Response};
use core::core::{self, hash::Hash, CompactBlock};
use core::{global, ser};

use msg::{
	read_exact, BanReason, GetPeerAddrs, Headers, Locator, PeerAddrs, Ping, Pong, SockAddr,
	TxHashSetArchive, TxHashSetRequest, Type,
};
use types::{Error, NetAdapter};
use util::LOGGER;

pub struct Protocol {
	adapter: Arc<NetAdapter>,
	addr: SocketAddr,
}

impl Protocol {
	pub fn new(adapter: Arc<NetAdapter>, addr: SocketAddr) -> Protocol {
		Protocol { adapter, addr }
	}
}

impl MessageHandler for Protocol {
	fn consume<'a>(&self, mut msg: Message<'a>) -> Result<Option<Response<'a>>, Error> {
		let adapter = &self.adapter;

		// If we received a msg from a banned peer then log and drop it.
		// If we are getting a lot of these then maybe we are not cleaning
		// banned peers up correctly?
		if adapter.is_banned(self.addr.clone()) {
			debug!(
				LOGGER,
				"handler: consume: peer {:?} banned, received: {:?}, dropping.",
				self.addr,
				msg.header.msg_type,
			);
			return Ok(None);
		}

		match msg.header.msg_type {
			Type::Ping => {
				let ping: Ping = msg.body()?;
				adapter.peer_difficulty(self.addr, ping.total_difficulty, ping.height);

				Ok(Some(msg.respond(
					Type::Pong,
					Pong {
						total_difficulty: adapter.total_difficulty(),
						height: adapter.total_height(),
					},
				)))
			}

			Type::Pong => {
				let pong: Pong = msg.body()?;
				adapter.peer_difficulty(self.addr, pong.total_difficulty, pong.height);
				Ok(None)
			}

			Type::BanReason => {
				let ban_reason: BanReason = msg.body()?;
				error!(LOGGER, "handle_payload: BanReason {:?}", ban_reason);
				Ok(None)
			}

			Type::Transaction => {
				debug!(
					LOGGER,
					"handle_payload: received tx: msg_len: {}", msg.header.msg_len
				);
				let tx: core::Transaction = msg.body()?;
				adapter.transaction_received(tx, false);
				Ok(None)
			}

			Type::StemTransaction => {
				debug!(
					LOGGER,
					"handle_payload: received stem tx: msg_len: {}", msg.header.msg_len
				);
				let tx: core::Transaction = msg.body()?;
				adapter.transaction_received(tx, true);
				Ok(None)
			}

			Type::GetBlock => {
				let h: Hash = msg.body()?;
				trace!(
					LOGGER,
					"handle_payload: Getblock: {}, msg_len: {}",
					h,
					msg.header.msg_len,
				);

				let bo = adapter.get_block(h);
				if let Some(b) = bo {
					return Ok(Some(msg.respond(Type::Block, b)));
				}
				Ok(None)
			}

			Type::Block => {
				debug!(
					LOGGER,
					"handle_payload: received block: msg_len: {}", msg.header.msg_len
				);
				let b: core::Block = msg.body()?;

				adapter.block_received(b, self.addr);
				Ok(None)
			}

			Type::GetCompactBlock => {
				let h: Hash = msg.body()?;
				if let Some(b) = adapter.get_block(h) {
					let cb: CompactBlock = b.into();
					Ok(Some(msg.respond(Type::CompactBlock, cb)))
				} else {
					Ok(None)
				}
			}

			Type::CompactBlock => {
				debug!(
					LOGGER,
					"handle_payload: received compact block: msg_len: {}", msg.header.msg_len
				);
				let b: core::CompactBlock = msg.body()?;

				adapter.compact_block_received(b, self.addr);
				Ok(None)
			}

			Type::GetHeaders => {
				// load headers from the locator
				let loc: Locator = msg.body()?;
				let headers = adapter.locate_headers(loc.hashes);

				// serialize and send all the headers over
				Ok(Some(
					msg.respond(Type::Headers, Headers { headers: headers }),
				))
			}

			// "header first" block propagation - if we have not yet seen this block
			// we can go request it from some of our peers
			Type::Header => {
				let header: core::BlockHeader = msg.body()?;

				adapter.header_received(header, self.addr);

				// we do not return a hash here as we never request a single header
				// a header will always arrive unsolicited
				Ok(None)
			}

			Type::Headers => {
				let conn = &mut msg.get_conn();

				let header_size: u64 = headers_header_size(conn, msg.header.msg_len)?;
				let mut total_read: u64 = 2;
				let mut reserved: Vec<u8> = vec![];

				while total_read < msg.header.msg_len || reserved.len() > 0 {
					let headers: Headers = headers_streaming_body(
						conn,
						msg.header.msg_len,
						32,
						&mut total_read,
						&mut reserved,
						header_size,
					)?;
					adapter.headers_received(headers.headers, self.addr);
				}
				Ok(None)
			}

			Type::GetPeerAddrs => {
				let get_peers: GetPeerAddrs = msg.body()?;
				let peer_addrs = adapter.find_peer_addrs(get_peers.capabilities);
				Ok(Some(msg.respond(
					Type::PeerAddrs,
					PeerAddrs {
						peers: peer_addrs.iter().map(|sa| SockAddr(*sa)).collect(),
					},
				)))
			}

			Type::PeerAddrs => {
				let peer_addrs: PeerAddrs = msg.body()?;
				adapter.peer_addrs_received(peer_addrs.peers.iter().map(|pa| pa.0).collect());
				Ok(None)
			}

			Type::TxHashSetRequest => {
				let sm_req: TxHashSetRequest = msg.body()?;
				debug!(
					LOGGER,
					"handle_payload: txhashset req for {} at {}", sm_req.hash, sm_req.height
				);

				let txhashset = self.adapter.txhashset_read(sm_req.hash);

				if let Some(txhashset) = txhashset {
					let file_sz = txhashset.reader.metadata()?.len();
					let mut resp = msg.respond(
						Type::TxHashSetArchive,
						&TxHashSetArchive {
							height: sm_req.height as u64,
							hash: sm_req.hash,
							bytes: file_sz,
						},
					);
					resp.add_attachment(txhashset.reader);
					Ok(Some(resp))
				} else {
					Ok(None)
				}
			}

			Type::TxHashSetArchive => {
				let sm_arch: TxHashSetArchive = msg.body()?;
				debug!(
					LOGGER,
					"handle_payload: txhashset archive for {} at {}. size={}",
					sm_arch.hash,
					sm_arch.height,
					sm_arch.bytes,
				);
				if !self.adapter.txhashset_receive_ready() {
					error!(
						LOGGER,
						"handle_payload: txhashset archive received but SyncStatus not on TxHashsetDownload",
					);
					return Err(Error::BadMessage);
				}

				let download_start_time = Utc::now();
				self.adapter
					.txhashset_download_update(download_start_time, 0, sm_arch.bytes);

				let mut tmp = env::temp_dir();
				tmp.push("txhashset.zip");
				let mut save_txhashset_to_file = |file| -> Result<(), Error> {
					let mut tmp_zip = BufWriter::new(File::create(file)?);
					let total_size = sm_arch.bytes as usize;
					let mut downloaded_size: usize = 0;
					let mut request_size = 48_000;
					while request_size > 0 {
						downloaded_size += msg.copy_attachment(request_size, &mut tmp_zip)?;
						request_size = cmp::min(48_000, total_size - downloaded_size);
						self.adapter.txhashset_download_update(
							download_start_time,
							downloaded_size as u64,
							total_size as u64,
						);
					}
					tmp_zip.into_inner().unwrap().sync_all()?;
					Ok(())
				};

				if let Err(e) = save_txhashset_to_file(tmp.clone()) {
					error!(
						LOGGER,
						"handle_payload: txhashset archive save to file fail. err={:?}", e
					);
					return Err(e);
				}

				trace!(
					LOGGER,
					"handle_payload: txhashset archive save to file {:?} success",
					tmp,
				);

				let tmp_zip = File::open(tmp)?;
				let res = self
					.adapter
					.txhashset_write(sm_arch.hash, tmp_zip, self.addr);

				debug!(
					LOGGER,
					"handle_payload: txhashset archive for {} at {}, DONE. Data Ok: {}",
					sm_arch.hash,
					sm_arch.height,
					res
				);

				Ok(None)
			}

			_ => {
				debug!(LOGGER, "unknown message type {:?}", msg.header.msg_type);
				Ok(None)
			}
		}
	}
}

/// Read the Headers Vec size from the underlying connection, and calculate maximum header_size of one Header
fn headers_header_size(conn: &mut TcpStream, msg_len: u64) -> Result<u64, Error> {
	let mut size = vec![0u8; 2];
	// read size of Vec<BlockHeader>
	read_exact(conn, &mut size, time::Duration::from_millis(10), true)?;

	let total_headers = size[0] as u64 * 256 + size[1] as u64;
	if total_headers == 0 || total_headers > 10_000 {
		return Err(Error::Connection(io::Error::new(
			io::ErrorKind::InvalidData,
			"headers_header_size",
		)));
	}
	let average_header_size = (msg_len - 2) / total_headers;

	// support size of Cuckoo: from Cuckoo 30 to Cuckoo 36, with version 2
	// having slightly larger headers
	let minimum_size = core::serialized_size_of_header(1, global::min_sizeshift());
	let maximum_size = core::serialized_size_of_header(2, global::min_sizeshift() + 6);
	if average_header_size < minimum_size as u64 || average_header_size > maximum_size as u64 {
		debug!(
			LOGGER,
			"headers_header_size - size of Vec: {}, average_header_size: {}, min: {}, max: {}",
			total_headers,
			average_header_size,
			minimum_size,
			maximum_size,
		);
		return Err(Error::Connection(io::Error::new(
			io::ErrorKind::InvalidData,
			"headers_header_size",
		)));
	}
	return Ok(maximum_size as u64);
}

/// Read the Headers streaming body from the underlying connection
fn headers_streaming_body(
	conn: &mut TcpStream,   // (i) underlying connection
	msg_len: u64,           // (i) length of whole 'Headers'
	headers_num: u64,       // (i) how many BlockHeader(s) do you want to read
	total_read: &mut u64,   // (i/o) how many bytes already read on this 'Headers' message
	reserved: &mut Vec<u8>, // (i/o) reserved part of previous read, which is not a whole header
	max_header_size: u64,   // (i) maximum possible size of single BlockHeader
) -> Result<Headers, Error> {
	if headers_num == 0 || msg_len < *total_read || *total_read < 2 {
		return Err(Error::Connection(io::Error::new(
			io::ErrorKind::InvalidInput,
			"headers_streaming_body",
		)));
	}

	// Note:
	// As we allow Cuckoo sizes greater than 30 now, the proof of work part of the header
	// could be 30*42 bits, 31*42 bits, 32*42 bits, etc.
	// So, for compatibility with variable size of block header, we read max possible size, for
	// up to Cuckoo 36.
	//
	let mut read_size = headers_num * max_header_size - reserved.len() as u64;
	if *total_read + read_size > msg_len {
		read_size = msg_len - *total_read;
	}

	// 1st part
	let mut body = vec![0u8; 2]; // for Vec<> size
	let mut final_headers_num = (read_size + reserved.len() as u64) / max_header_size;
	let remaining = msg_len - *total_read - read_size;
	if final_headers_num == 0 && remaining == 0 {
		final_headers_num = 1;
	}
	body[0] = (final_headers_num >> 8) as u8;
	body[1] = (final_headers_num & 0x00ff) as u8;

	// 2nd part
	body.append(reserved);

	// 3rd part
	let mut read_body = vec![0u8; read_size as usize];
	if read_size > 0 {
		read_exact(conn, &mut read_body, time::Duration::from_secs(20), true)?;
		*total_read += read_size;
	}
	body.append(&mut read_body);

	// deserialize these assembled 3 parts
	let result: Result<Headers, Error> = ser::deserialize(&mut &body[..]).map_err(From::from);
	let headers = result?;

	// remaining data
	let mut deserialized_size = 2; // for Vec<> size
	for header in &headers.headers {
		deserialized_size += header.serialized_size();
	}
	*reserved = body[deserialized_size..].to_vec();

	Ok(headers)
}
<commit_msg>Fix small txhashset download timeouts (#1735)<commit_after>// Copyright 2018 The Grin Developers
//
// 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
//
//     http://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.

use std::cmp;
use std::env;
use std::fs::File;
use std::io::{self, BufWriter};
use std::net::{SocketAddr, TcpStream};
use std::sync::Arc;
use std::time;

use chrono::prelude::Utc;
use conn::{Message, MessageHandler, Response};
use core::core::{self, hash::Hash, CompactBlock};
use core::{global, ser};

use msg::{
	read_exact, BanReason, GetPeerAddrs, Headers, Locator, PeerAddrs, Ping, Pong, SockAddr,
	TxHashSetArchive, TxHashSetRequest, Type,
};
use types::{Error, NetAdapter};
use util::LOGGER;

pub struct Protocol {
	adapter: Arc<NetAdapter>,
	addr: SocketAddr,
}

impl Protocol {
	pub fn new(adapter: Arc<NetAdapter>, addr: SocketAddr) -> Protocol {
		Protocol { adapter, addr }
	}
}

impl MessageHandler for Protocol {
	fn consume<'a>(&self, mut msg: Message<'a>) -> Result<Option<Response<'a>>, Error> {
		let adapter = &self.adapter;

		// If we received a msg from a banned peer then log and drop it.
		// If we are getting a lot of these then maybe we are not cleaning
		// banned peers up correctly?
		if adapter.is_banned(self.addr.clone()) {
			debug!(
				LOGGER,
				"handler: consume: peer {:?} banned, received: {:?}, dropping.",
				self.addr,
				msg.header.msg_type,
			);
			return Ok(None);
		}

		match msg.header.msg_type {
			Type::Ping => {
				let ping: Ping = msg.body()?;
				adapter.peer_difficulty(self.addr, ping.total_difficulty, ping.height);

				Ok(Some(msg.respond(
					Type::Pong,
					Pong {
						total_difficulty: adapter.total_difficulty(),
						height: adapter.total_height(),
					},
				)))
			}

			Type::Pong => {
				let pong: Pong = msg.body()?;
				adapter.peer_difficulty(self.addr, pong.total_difficulty, pong.height);
				Ok(None)
			}

			Type::BanReason => {
				let ban_reason: BanReason = msg.body()?;
				error!(LOGGER, "handle_payload: BanReason {:?}", ban_reason);
				Ok(None)
			}

			Type::Transaction => {
				debug!(
					LOGGER,
					"handle_payload: received tx: msg_len: {}", msg.header.msg_len
				);
				let tx: core::Transaction = msg.body()?;
				adapter.transaction_received(tx, false);
				Ok(None)
			}

			Type::StemTransaction => {
				debug!(
					LOGGER,
					"handle_payload: received stem tx: msg_len: {}", msg.header.msg_len
				);
				let tx: core::Transaction = msg.body()?;
				adapter.transaction_received(tx, true);
				Ok(None)
			}

			Type::GetBlock => {
				let h: Hash = msg.body()?;
				trace!(
					LOGGER,
					"handle_payload: Getblock: {}, msg_len: {}",
					h,
					msg.header.msg_len,
				);

				let bo = adapter.get_block(h);
				if let Some(b) = bo {
					return Ok(Some(msg.respond(Type::Block, b)));
				}
				Ok(None)
			}

			Type::Block => {
				debug!(
					LOGGER,
					"handle_payload: received block: msg_len: {}", msg.header.msg_len
				);
				let b: core::Block = msg.body()?;

				adapter.block_received(b, self.addr);
				Ok(None)
			}

			Type::GetCompactBlock => {
				let h: Hash = msg.body()?;
				if let Some(b) = adapter.get_block(h) {
					let cb: CompactBlock = b.into();
					Ok(Some(msg.respond(Type::CompactBlock, cb)))
				} else {
					Ok(None)
				}
			}

			Type::CompactBlock => {
				debug!(
					LOGGER,
					"handle_payload: received compact block: msg_len: {}", msg.header.msg_len
				);
				let b: core::CompactBlock = msg.body()?;

				adapter.compact_block_received(b, self.addr);
				Ok(None)
			}

			Type::GetHeaders => {
				// load headers from the locator
				let loc: Locator = msg.body()?;
				let headers = adapter.locate_headers(loc.hashes);

				// serialize and send all the headers over
				Ok(Some(
					msg.respond(Type::Headers, Headers { headers: headers }),
				))
			}

			// "header first" block propagation - if we have not yet seen this block
			// we can go request it from some of our peers
			Type::Header => {
				let header: core::BlockHeader = msg.body()?;

				adapter.header_received(header, self.addr);

				// we do not return a hash here as we never request a single header
				// a header will always arrive unsolicited
				Ok(None)
			}

			Type::Headers => {
				let conn = &mut msg.get_conn();

				let header_size: u64 = headers_header_size(conn, msg.header.msg_len)?;
				let mut total_read: u64 = 2;
				let mut reserved: Vec<u8> = vec![];

				while total_read < msg.header.msg_len || reserved.len() > 0 {
					let headers: Headers = headers_streaming_body(
						conn,
						msg.header.msg_len,
						32,
						&mut total_read,
						&mut reserved,
						header_size,
					)?;
					adapter.headers_received(headers.headers, self.addr);
				}
				Ok(None)
			}

			Type::GetPeerAddrs => {
				let get_peers: GetPeerAddrs = msg.body()?;
				let peer_addrs = adapter.find_peer_addrs(get_peers.capabilities);
				Ok(Some(msg.respond(
					Type::PeerAddrs,
					PeerAddrs {
						peers: peer_addrs.iter().map(|sa| SockAddr(*sa)).collect(),
					},
				)))
			}

			Type::PeerAddrs => {
				let peer_addrs: PeerAddrs = msg.body()?;
				adapter.peer_addrs_received(peer_addrs.peers.iter().map(|pa| pa.0).collect());
				Ok(None)
			}

			Type::TxHashSetRequest => {
				let sm_req: TxHashSetRequest = msg.body()?;
				debug!(
					LOGGER,
					"handle_payload: txhashset req for {} at {}", sm_req.hash, sm_req.height
				);

				let txhashset = self.adapter.txhashset_read(sm_req.hash);

				if let Some(txhashset) = txhashset {
					let file_sz = txhashset.reader.metadata()?.len();
					let mut resp = msg.respond(
						Type::TxHashSetArchive,
						&TxHashSetArchive {
							height: sm_req.height as u64,
							hash: sm_req.hash,
							bytes: file_sz,
						},
					);
					resp.add_attachment(txhashset.reader);
					Ok(Some(resp))
				} else {
					Ok(None)
				}
			}

			Type::TxHashSetArchive => {
				let sm_arch: TxHashSetArchive = msg.body()?;
				debug!(
					LOGGER,
					"handle_payload: txhashset archive for {} at {}. size={}",
					sm_arch.hash,
					sm_arch.height,
					sm_arch.bytes,
				);
				if !self.adapter.txhashset_receive_ready() {
					error!(
						LOGGER,
						"handle_payload: txhashset archive received but SyncStatus not on TxHashsetDownload",
					);
					return Err(Error::BadMessage);
				}

				let download_start_time = Utc::now();
				self.adapter
					.txhashset_download_update(download_start_time, 0, sm_arch.bytes);

				let mut tmp = env::temp_dir();
				tmp.push("txhashset.zip");
				let mut save_txhashset_to_file = |file| -> Result<(), Error> {
					let mut tmp_zip = BufWriter::new(File::create(file)?);
					let total_size = sm_arch.bytes as usize;
					let mut downloaded_size: usize = 0;
					let mut request_size = cmp::min(48_000, sm_arch.bytes) as usize;
					while request_size > 0 {
						downloaded_size += msg.copy_attachment(request_size, &mut tmp_zip)?;
						request_size = cmp::min(48_000, total_size - downloaded_size);
						self.adapter.txhashset_download_update(
							download_start_time,
							downloaded_size as u64,
							total_size as u64,
						);
					}
					tmp_zip.into_inner().unwrap().sync_all()?;
					Ok(())
				};

				if let Err(e) = save_txhashset_to_file(tmp.clone()) {
					error!(
						LOGGER,
						"handle_payload: txhashset archive save to file fail. err={:?}", e
					);
					return Err(e);
				}

				trace!(
					LOGGER,
					"handle_payload: txhashset archive save to file {:?} success",
					tmp,
				);

				let tmp_zip = File::open(tmp)?;
				let res = self
					.adapter
					.txhashset_write(sm_arch.hash, tmp_zip, self.addr);

				debug!(
					LOGGER,
					"handle_payload: txhashset archive for {} at {}, DONE. Data Ok: {}",
					sm_arch.hash,
					sm_arch.height,
					res
				);

				Ok(None)
			}

			_ => {
				debug!(LOGGER, "unknown message type {:?}", msg.header.msg_type);
				Ok(None)
			}
		}
	}
}

/// Read the Headers Vec size from the underlying connection, and calculate maximum header_size of one Header
fn headers_header_size(conn: &mut TcpStream, msg_len: u64) -> Result<u64, Error> {
	let mut size = vec![0u8; 2];
	// read size of Vec<BlockHeader>
	read_exact(conn, &mut size, time::Duration::from_millis(10), true)?;

	let total_headers = size[0] as u64 * 256 + size[1] as u64;
	if total_headers == 0 || total_headers > 10_000 {
		return Err(Error::Connection(io::Error::new(
			io::ErrorKind::InvalidData,
			"headers_header_size",
		)));
	}
	let average_header_size = (msg_len - 2) / total_headers;

	// support size of Cuckoo: from Cuckoo 30 to Cuckoo 36, with version 2
	// having slightly larger headers
	let minimum_size = core::serialized_size_of_header(1, global::min_sizeshift());
	let maximum_size = core::serialized_size_of_header(2, global::min_sizeshift() + 6);
	if average_header_size < minimum_size as u64 || average_header_size > maximum_size as u64 {
		debug!(
			LOGGER,
			"headers_header_size - size of Vec: {}, average_header_size: {}, min: {}, max: {}",
			total_headers,
			average_header_size,
			minimum_size,
			maximum_size,
		);
		return Err(Error::Connection(io::Error::new(
			io::ErrorKind::InvalidData,
			"headers_header_size",
		)));
	}
	return Ok(maximum_size as u64);
}

/// Read the Headers streaming body from the underlying connection
fn headers_streaming_body(
	conn: &mut TcpStream,   // (i) underlying connection
	msg_len: u64,           // (i) length of whole 'Headers'
	headers_num: u64,       // (i) how many BlockHeader(s) do you want to read
	total_read: &mut u64,   // (i/o) how many bytes already read on this 'Headers' message
	reserved: &mut Vec<u8>, // (i/o) reserved part of previous read, which is not a whole header
	max_header_size: u64,   // (i) maximum possible size of single BlockHeader
) -> Result<Headers, Error> {
	if headers_num == 0 || msg_len < *total_read || *total_read < 2 {
		return Err(Error::Connection(io::Error::new(
			io::ErrorKind::InvalidInput,
			"headers_streaming_body",
		)));
	}

	// Note:
	// As we allow Cuckoo sizes greater than 30 now, the proof of work part of the header
	// could be 30*42 bits, 31*42 bits, 32*42 bits, etc.
	// So, for compatibility with variable size of block header, we read max possible size, for
	// up to Cuckoo 36.
	//
	let mut read_size = headers_num * max_header_size - reserved.len() as u64;
	if *total_read + read_size > msg_len {
		read_size = msg_len - *total_read;
	}

	// 1st part
	let mut body = vec![0u8; 2]; // for Vec<> size
	let mut final_headers_num = (read_size + reserved.len() as u64) / max_header_size;
	let remaining = msg_len - *total_read - read_size;
	if final_headers_num == 0 && remaining == 0 {
		final_headers_num = 1;
	}
	body[0] = (final_headers_num >> 8) as u8;
	body[1] = (final_headers_num & 0x00ff) as u8;

	// 2nd part
	body.append(reserved);

	// 3rd part
	let mut read_body = vec![0u8; read_size as usize];
	if read_size > 0 {
		read_exact(conn, &mut read_body, time::Duration::from_secs(20), true)?;
		*total_read += read_size;
	}
	body.append(&mut read_body);

	// deserialize these assembled 3 parts
	let result: Result<Headers, Error> = ser::deserialize(&mut &body[..]).map_err(From::from);
	let headers = result?;

	// remaining data
	let mut deserialized_size = 2; // for Vec<> size
	for header in &headers.headers {
		deserialized_size += header.serialized_size();
	}
	*reserved = body[deserialized_size..].to_vec();

	Ok(headers)
}
<|endoftext|>