<commit_before>use libc::{uint64_t, int64_t, c_void, c_char, c_double};
use std::ffi::CString;
use std::ptr;

pub type HeartbeatReadEnergyFn = unsafe extern fn() -> c_double;

#[link(name = "hbt-acc-pow")]
extern {
    fn heartbeat_acc_pow_init(parent: *mut c_void,
                              window_size: uint64_t,
                              buffer_depth: uint64_t,
                              log_name: *const c_char,
                              read_energy_fn: Option<HeartbeatReadEnergyFn>) -> *mut c_void;

    fn heartbeat_acc(hb: *mut c_void,
                     user_tag: uint64_t,
                     work: uint64_t,
                     accuracy: c_double,
                     hb_prev: *mut c_void) -> int64_t;

    fn heartbeat_finish(hb: *mut c_void);

    fn hb_get_user_tag(hb: *const c_void) -> uint64_t;

    fn hb_get_window_rate(hb: *const c_void) -> c_double;

    fn hb_get_window_power(hb: *const c_void) -> c_double;
}

/// A `Heartbeat` is used for tracking performance/accuracy/power of recurring jobs.
pub struct Heartbeat {
    /// The underlying C struct `heartbeat_t`.
    pub hb: *mut c_void,
}

impl Heartbeat {
    /// Allocate and initialize a new `Heartbeat` with its underlying C struct.
    pub fn new(parent: Option<&mut Heartbeat>,
               window_size: u64,
               buffer_depth: u64,
               log_name: Option<&CString>,
               read_energy_fn: Option<HeartbeatReadEnergyFn>) -> Result<Heartbeat, &'static str> {
        let parent_ptr: *mut c_void = match parent {
            Some(p) => p.hb,
            None => ptr::null_mut(),
        };
        let log_ptr: *const c_char = match log_name {
          Some(n) => n.as_ptr(),
          None => ptr::null(),
        };
        let heart: *mut c_void = unsafe {
            heartbeat_acc_pow_init(parent_ptr, window_size, buffer_depth, log_ptr, read_energy_fn)
        };
        if heart.is_null() {
            return Err("Failed to initialize heartbeat");
        }
        Ok(Heartbeat { hb: heart, })
    }

    /// Issue a heartbeat.
    pub fn heartbeat(&mut self,
                     tag: u64,
                     work: u64,
                     accuracy: f64,
                     hb_prev: Option<&Heartbeat>) -> i64 {
        let hb_prev: *mut c_void = match hb_prev {
            Some(p) => p.hb,
            None => ptr::null_mut(),
        };
        unsafe {
            heartbeat_acc(self.hb, tag, work, accuracy, hb_prev)
        }
    }

    /// Utility function to get the most recent user-specified tag
    pub fn get_tag(&mut self) -> u64 {
        unsafe {
            hb_get_user_tag(self.hb)
        }
    }

    /// Utility function to get the current window performance.
    pub fn get_window_perf(&mut self) -> f64 {
        unsafe {
            hb_get_window_rate(self.hb)
        }
    }

    /// Utility function to get the current window power.
    pub fn get_window_pwr(&mut self) -> f64 {
        unsafe {
            hb_get_window_power(self.hb)
        }
    }
}

impl Drop for Heartbeat {
    /// Cleans up and deallocates the underlying C struct.
    fn drop(&mut self) {
        unsafe {
            heartbeat_finish(self.hb);
        }
    }
}

#[cfg(test)]
mod test {
    use super::Heartbeat;
    use std::ffi::CString;

    #[test]
    fn test_no_energymon() {
        let mut hb = Heartbeat::new(None, 20, 20, None, None).unwrap();
        hb.heartbeat(1, 1, 1.0, None);
        assert!(hb.get_tag() == 1);
        // can't really test performance and power accurately
    }

    unsafe extern fn test_get_energy() -> f64 {
      static mut energy: f64 = 0.0;
      energy += 1.0;
      energy
    }

    #[test]
    fn test_energy() {
        let mut hb = Heartbeat::new(None, 20, 20, Some(&CString::new("heartbeat.log").unwrap()),
                                    Some(test_get_energy)).unwrap();
        hb.heartbeat(1, 1, 1.0, None);
        assert!(hb.get_tag() == 1);
        hb.heartbeat(2, 1, 1.0, None);
        // can't really test performance and power accurately
        // TODO: Add wrappers to utility functions to get energy, etc.
    }
}
<commit_msg>Update for heartbeats now allowing argument to fn that gets energy<commit_after>use libc::{uint64_t, int64_t, c_void, c_char, c_double};
use std::ffi::CString;
use std::ptr;

pub type HeartbeatReadEnergyFn = unsafe extern fn(*mut c_void) -> c_double;

#[link(name = "hbt-acc-pow")]
extern {
    fn heartbeat_acc_pow_init(parent: *mut c_void,
                              window_size: uint64_t,
                              buffer_depth: uint64_t,
                              log_name: *const c_char,
                              read_energy_fn: Option<HeartbeatReadEnergyFn>,
                              ref_arg: *mut c_void) -> *mut c_void;

    fn heartbeat_acc(hb: *mut c_void,
                     user_tag: uint64_t,
                     work: uint64_t,
                     accuracy: c_double,
                     hb_prev: *mut c_void) -> int64_t;

    fn heartbeat_finish(hb: *mut c_void);

    fn hb_get_user_tag(hb: *const c_void) -> uint64_t;

    fn hb_get_window_rate(hb: *const c_void) -> c_double;

    fn hb_get_window_power(hb: *const c_void) -> c_double;
}

/// A `Heartbeat` is used for tracking performance/accuracy/power of recurring jobs.
pub struct Heartbeat {
    /// The underlying C struct `heartbeat_t`.
    pub hb: *mut c_void,
}

impl Heartbeat {
    /// Allocate and initialize a new `Heartbeat` with its underlying C struct.
    pub fn new(parent: Option<&mut Heartbeat>,
               window_size: u64,
               buffer_depth: u64,
               log_name: Option<&CString>,
               read_energy_fn: Option<HeartbeatReadEnergyFn>,
               ref_arg: Option<*mut c_void>) -> Result<Heartbeat, &'static str> {
        let parent_ptr: *mut c_void = match parent {
            Some(p) => p.hb,
            None => ptr::null_mut(),
        };
        let log_ptr: *const c_char = match log_name {
            Some(n) => n.as_ptr(),
            None => ptr::null(),
        };
        let ref_arg_ptr: *mut c_void = match ref_arg {
            Some(r) => r,
            None => ptr::null_mut(),
        };
        let heart: *mut c_void = unsafe {
            heartbeat_acc_pow_init(parent_ptr, window_size, buffer_depth, log_ptr, read_energy_fn,
                                   ref_arg_ptr)
        };
        if heart.is_null() {
            return Err("Failed to initialize heartbeat");
        }
        Ok(Heartbeat { hb: heart, })
    }

    /// Issue a heartbeat.
    pub fn heartbeat(&mut self,
                     tag: u64,
                     work: u64,
                     accuracy: f64,
                     hb_prev: Option<&Heartbeat>) -> i64 {
        let hb_prev: *mut c_void = match hb_prev {
            Some(p) => p.hb,
            None => ptr::null_mut(),
        };
        unsafe {
            heartbeat_acc(self.hb, tag, work, accuracy, hb_prev)
        }
    }

    /// Utility function to get the most recent user-specified tag
    pub fn get_tag(&mut self) -> u64 {
        unsafe {
            hb_get_user_tag(self.hb)
        }
    }

    /// Utility function to get the current window performance.
    pub fn get_window_perf(&mut self) -> f64 {
        unsafe {
            hb_get_window_rate(self.hb)
        }
    }

    /// Utility function to get the current window power.
    pub fn get_window_pwr(&mut self) -> f64 {
        unsafe {
            hb_get_window_power(self.hb)
        }
    }
}

impl Drop for Heartbeat {
    /// Cleans up and deallocates the underlying C struct.
    fn drop(&mut self) {
        unsafe {
            heartbeat_finish(self.hb);
        }
    }
}

#[cfg(test)]
mod test {
    use super::Heartbeat;
    use std::ffi::CString;
    use libc::{c_void, c_double};

    #[test]
    fn test_no_energymon() {
        let mut hb = Heartbeat::new(None, 20, 20, None, None, None).unwrap();
        hb.heartbeat(1, 1, 1.0, None);
        assert!(hb.get_tag() == 1);
        // can't really test performance and power accurately
    }

    unsafe extern fn test_get_energy(ref_arg: *mut c_void) -> c_double {
        // our test is actually just updating the value of a c_double pointer passed to us
        let energy: *mut c_double = ref_arg as *mut c_double;
        *energy += 1.0;
        *energy
    }

    #[test]
    fn test_energy() {
        let mut energy = 0.0;
        let mut hb = Heartbeat::new(None, 20, 20, Some(&CString::new("heartbeat.log").unwrap()),
                                    Some(test_get_energy), Some(&mut energy as *mut f64 as *mut c_void)).unwrap();
        hb.heartbeat(1, 1, 1.0, None);
        assert!(hb.get_tag() == 1);
        hb.heartbeat(2, 1, 1.0, None);
        // can't really test performance and power accurately
        // TODO: Add wrappers to utility functions to get energy, etc.
    }
}
<|endoftext|>


<commit_before>use std::mem;
use httparse;
use http::{Version, HttpTryFrom, HeaderMap, StatusCode};
use http::header::{self, HeaderName, HeaderValue};
use bytes::{Bytes, BytesMut};
use futures::{Poll, Async};

use error::{ParseError, PayloadError};

use server::{utils, IoStream};
use server::h1::{Decoder, chunked};

use super::ClientResponse;
use super::response::ClientMessage;

const MAX_BUFFER_SIZE: usize = 131_072;
const MAX_HEADERS: usize = 96;

#[derive(Default)]
pub struct HttpResponseParser {
    decoder: Option<Decoder>,
}

#[derive(Debug, Fail)]
pub enum HttpResponseParserError {
    /// Server disconnected
    #[fail(display="Server disconnected")]
    Disconnect,
    #[fail(display="{}", _0)]
    Error(#[cause] ParseError),
}

impl HttpResponseParser {

    pub fn parse<T>(&mut self, io: &mut T, buf: &mut BytesMut)
                    -> Poll<ClientResponse, HttpResponseParserError>
        where T: IoStream
    {
        // if buf is empty parse_message will always return NotReady, let's avoid that
        if buf.is_empty() {
            match utils::read_from_io(io, buf) {
                Ok(Async::Ready(0)) =>
                    return Err(HttpResponseParserError::Disconnect),
                Ok(Async::Ready(_)) => (),
                Ok(Async::NotReady) =>
                    return Ok(Async::NotReady),
                Err(err) =>
                    return Err(HttpResponseParserError::Error(err.into()))
            }
        }

        loop {
            match HttpResponseParser::parse_message(buf)
                .map_err(HttpResponseParserError::Error)?
            {
                Async::Ready((msg, decoder)) => {
                    self.decoder = decoder;
                    return Ok(Async::Ready(msg));
                },
                Async::NotReady => {
                    if buf.capacity() >= MAX_BUFFER_SIZE {
                        return Err(HttpResponseParserError::Error(ParseError::TooLarge));
                    }
                    match utils::read_from_io(io, buf) {
                        Ok(Async::Ready(0)) =>
                            return Err(HttpResponseParserError::Disconnect),
                        Ok(Async::Ready(_)) => (),
                        Ok(Async::NotReady) => return Ok(Async::NotReady),
                        Err(err) =>
                            return Err(HttpResponseParserError::Error(err.into())),
                    }
                },
            }
        }
    }

    pub fn parse_payload<T>(&mut self, io: &mut T, buf: &mut BytesMut)
                            -> Poll<Option<Bytes>, PayloadError>
        where T: IoStream
    {
        if self.decoder.is_some() {
            loop {
                // read payload
                let not_ready = match utils::read_from_io(io, buf) {
                    Ok(Async::Ready(0)) => {
                        if buf.is_empty() {
                            return Err(PayloadError::Incomplete)
                        }
                        true
                    }
                    Err(err) => return Err(err.into()),
                    Ok(Async::NotReady) => true,
                    _ => false,
                };

                match self.decoder.as_mut().unwrap().decode(buf) {
                    Ok(Async::Ready(Some(b))) =>
                        return Ok(Async::Ready(Some(b))),
                    Ok(Async::Ready(None)) => {
                        self.decoder.take();
                        return Ok(Async::Ready(None))
                    }
                    Ok(Async::NotReady) => {
                        if not_ready {
                            return Ok(Async::NotReady)
                        }
                    }
                    Err(err) => return Err(err.into()),
                }
            }
        } else {
            Ok(Async::Ready(None))
        }
    }

    fn parse_message(buf: &mut BytesMut)
                     -> Poll<(ClientResponse, Option<Decoder>), ParseError>
    {
        // Parse http message
        let bytes_ptr = buf.as_ref().as_ptr() as usize;
        let mut headers: [httparse::Header; MAX_HEADERS] =
            unsafe{mem::uninitialized()};

        let (len, version, status, headers_len) = {
            let b = unsafe{ let b: &[u8] = buf; mem::transmute(b) };
            let mut resp = httparse::Response::new(&mut headers);
            match resp.parse(b)? {
                httparse::Status::Complete(len) => {
                    let version = if resp.version.unwrap_or(1) == 1 {
                        Version::HTTP_11
                    } else {
                        Version::HTTP_10
                    };
                    let status = StatusCode::from_u16(resp.code.unwrap())
                        .map_err(|_| ParseError::Status)?;

                    (len, version, status, resp.headers.len())
                }
                httparse::Status::Partial => return Ok(Async::NotReady),
            }
        };

        let slice = buf.split_to(len).freeze();

        // convert headers
        let mut hdrs = HeaderMap::new();
        for header in headers[..headers_len].iter() {
            if let Ok(name) = HeaderName::try_from(header.name) {
                let v_start = header.value.as_ptr() as usize - bytes_ptr;
                let v_end = v_start + header.value.len();
                let value = unsafe {
                    HeaderValue::from_shared_unchecked(slice.slice(v_start, v_end)) };
                hdrs.append(name, value);
            } else {
                return Err(ParseError::Header)
            }
        }

        let decoder = if status == StatusCode::SWITCHING_PROTOCOLS {
            Some(Decoder::eof())
        } else if let Some(len) = hdrs.get(header::CONTENT_LENGTH) {
            // Content-Length
            if let Ok(s) = len.to_str() {
                if let Ok(len) = s.parse::<u64>() {
                    Some(Decoder::length(len))
                } else {
                    debug!("illegal Content-Length: {:?}", len);
                    return Err(ParseError::Header)
                }
            } else {
                debug!("illegal Content-Length: {:?}", len);
                return Err(ParseError::Header)
            }
        } else if chunked(&hdrs)? {
            // Chunked encoding
            Some(Decoder::chunked())
        } else {
            None
        };

        if let Some(decoder) = decoder {
            Ok(Async::Ready(
                (ClientResponse::new(
                    ClientMessage{status, version,
                                  headers: hdrs, cookies: None}), Some(decoder))))
        } else {
            Ok(Async::Ready(
                (ClientResponse::new(
                    ClientMessage{status, version,
                                  headers: hdrs, cookies: None}), None)))
        }
    }
}
<commit_msg>fix end-of-stream handling in parse_payload<commit_after>use std::mem;
use httparse;
use http::{Version, HttpTryFrom, HeaderMap, StatusCode};
use http::header::{self, HeaderName, HeaderValue};
use bytes::{Bytes, BytesMut};
use futures::{Poll, Async};

use error::{ParseError, PayloadError};

use server::{utils, IoStream};
use server::h1::{Decoder, chunked};

use super::ClientResponse;
use super::response::ClientMessage;

const MAX_BUFFER_SIZE: usize = 131_072;
const MAX_HEADERS: usize = 96;

#[derive(Default)]
pub struct HttpResponseParser {
    decoder: Option<Decoder>,
}

#[derive(Debug, Fail)]
pub enum HttpResponseParserError {
    /// Server disconnected
    #[fail(display="Server disconnected")]
    Disconnect,
    #[fail(display="{}", _0)]
    Error(#[cause] ParseError),
}

impl HttpResponseParser {

    pub fn parse<T>(&mut self, io: &mut T, buf: &mut BytesMut)
                    -> Poll<ClientResponse, HttpResponseParserError>
        where T: IoStream
    {
        // if buf is empty parse_message will always return NotReady, let's avoid that
        if buf.is_empty() {
            match utils::read_from_io(io, buf) {
                Ok(Async::Ready(0)) =>
                    return Err(HttpResponseParserError::Disconnect),
                Ok(Async::Ready(_)) => (),
                Ok(Async::NotReady) =>
                    return Ok(Async::NotReady),
                Err(err) =>
                    return Err(HttpResponseParserError::Error(err.into()))
            }
        }

        loop {
            match HttpResponseParser::parse_message(buf)
                .map_err(HttpResponseParserError::Error)?
            {
                Async::Ready((msg, decoder)) => {
                    self.decoder = decoder;
                    return Ok(Async::Ready(msg));
                },
                Async::NotReady => {
                    if buf.capacity() >= MAX_BUFFER_SIZE {
                        return Err(HttpResponseParserError::Error(ParseError::TooLarge));
                    }
                    match utils::read_from_io(io, buf) {
                        Ok(Async::Ready(0)) =>
                            return Err(HttpResponseParserError::Disconnect),
                        Ok(Async::Ready(_)) => (),
                        Ok(Async::NotReady) => return Ok(Async::NotReady),
                        Err(err) =>
                            return Err(HttpResponseParserError::Error(err.into())),
                    }
                },
            }
        }
    }

    pub fn parse_payload<T>(&mut self, io: &mut T, buf: &mut BytesMut)
                            -> Poll<Option<Bytes>, PayloadError>
        where T: IoStream
    {
        if self.decoder.is_some() {
            loop {
                // read payload
                let (not_ready, stream_finished) = match utils::read_from_io(io, buf) {
                    Ok(Async::Ready(0)) => (false, true),
                    Err(err) => return Err(err.into()),
                    Ok(Async::NotReady) => (true, false),
                    _ => (false, false),
                };

                match self.decoder.as_mut().unwrap().decode(buf) {
                    Ok(Async::Ready(Some(b))) =>
                        return Ok(Async::Ready(Some(b))),
                    Ok(Async::Ready(None)) => {
                        self.decoder.take();
                        return Ok(Async::Ready(None))
                    }
                    Ok(Async::NotReady) => {
                        if not_ready {
                            return Ok(Async::NotReady)
                        }
                        if stream_finished {
                            return Err(PayloadError::Incomplete)
                        }
                    }
                    Err(err) => return Err(err.into()),
                }
            }
        } else {
            Ok(Async::Ready(None))
        }
    }

    fn parse_message(buf: &mut BytesMut)
                     -> Poll<(ClientResponse, Option<Decoder>), ParseError>
    {
        // Parse http message
        let bytes_ptr = buf.as_ref().as_ptr() as usize;
        let mut headers: [httparse::Header; MAX_HEADERS] =
            unsafe{mem::uninitialized()};

        let (len, version, status, headers_len) = {
            let b = unsafe{ let b: &[u8] = buf; mem::transmute(b) };
            let mut resp = httparse::Response::new(&mut headers);
            match resp.parse(b)? {
                httparse::Status::Complete(len) => {
                    let version = if resp.version.unwrap_or(1) == 1 {
                        Version::HTTP_11
                    } else {
                        Version::HTTP_10
                    };
                    let status = StatusCode::from_u16(resp.code.unwrap())
                        .map_err(|_| ParseError::Status)?;

                    (len, version, status, resp.headers.len())
                }
                httparse::Status::Partial => return Ok(Async::NotReady),
            }
        };

        let slice = buf.split_to(len).freeze();

        // convert headers
        let mut hdrs = HeaderMap::new();
        for header in headers[..headers_len].iter() {
            if let Ok(name) = HeaderName::try_from(header.name) {
                let v_start = header.value.as_ptr() as usize - bytes_ptr;
                let v_end = v_start + header.value.len();
                let value = unsafe {
                    HeaderValue::from_shared_unchecked(slice.slice(v_start, v_end)) };
                hdrs.append(name, value);
            } else {
                return Err(ParseError::Header)
            }
        }

        let decoder = if status == StatusCode::SWITCHING_PROTOCOLS {
            Some(Decoder::eof())
        } else if let Some(len) = hdrs.get(header::CONTENT_LENGTH) {
            // Content-Length
            if let Ok(s) = len.to_str() {
                if let Ok(len) = s.parse::<u64>() {
                    Some(Decoder::length(len))
                } else {
                    debug!("illegal Content-Length: {:?}", len);
                    return Err(ParseError::Header)
                }
            } else {
                debug!("illegal Content-Length: {:?}", len);
                return Err(ParseError::Header)
            }
        } else if chunked(&hdrs)? {
            // Chunked encoding
            Some(Decoder::chunked())
        } else {
            None
        };

        if let Some(decoder) = decoder {
            Ok(Async::Ready(
                (ClientResponse::new(
                    ClientMessage{status, version,
                                  headers: hdrs, cookies: None}), Some(decoder))))
        } else {
            Ok(Async::Ready(
                (ClientResponse::new(
                    ClientMessage{status, version,
                                  headers: hdrs, cookies: None}), None)))
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017-2018 Ben Ashford
 *
 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 * option. This file may not be copied, modified, or distributed
 * except according to those terms.
 */

use std::collections::HashMap;
use std::net::SocketAddr;
use std::sync::{Arc, Mutex};

use futures::{future, Future, Poll, Sink, Stream, sync::{mpsc, oneshot}};

use error;
use resp;
use resp::FromResp;
use super::connect::connect;

fn err<S>(msg: S) -> Box<Future<Item = (), Error = error::Error> + Send>
where
    S: Into<String>,
{
    Box::new(future::err(error::internal(msg)))
}

/// Used for Redis's PUBSUB functionality.
///
/// Returns a future that resolves to a `PubsubConnection`.
pub fn pubsub_connect(
    addr: &SocketAddr,
) -> Box<Future<Item = PubsubConnection, Error = error::Error> + Send> {
    // let pubsub_con = connect(addr).map_err(|e| e.into()).map(move |connection| {
    //     let ClientConnection { sender, receiver } = connection;
    //     let (out_tx, out_rx) = mpsc::unbounded();

    //     let sender = Box::new(
    //         sender
    //             .sink_map_err(|e| error!("Sending socket error: {}", e))
    //             .send_all(out_rx.map_err(|()| error!("Outgoing message channel error")))
    //             .map(|_| debug!("Send all completed successfully")),
    //     ) as Box<Future<Item = (), Error = ()> + Send>;

    //     let subs = Arc::new(Mutex::new(PubsubSubscriptions {
    //         pending: HashMap::new(),
    //         confirmed: HashMap::new(),
    //     }));
    //     let subs_reader = subs.clone();

    //     let receiver_raw = receiver.for_each(move |msg| {
    //         let (message_type, topic, msg) = match msg {
    //             resp::RespValue::Array(mut messages) => match (
    //                 messages.pop(),
    //                 messages.pop(),
    //                 messages.pop(),
    //                 messages.pop(),
    //             ) {
    //                 (Some(msg), Some(topic), Some(message_type), None) => {
    //                     match (msg, String::from_resp(topic), message_type) {
    //                         (msg, Ok(topic), resp::RespValue::BulkString(bytes)) => {
    //                             (bytes, topic, msg)
    //                         }
    //                         _ => return err("RESP Message structure invalid"),
    //                     }
    //                 }
    //                 _ => {
    //                     return err(format!(
    //                         "Incorrect number of records in PUBSUB message: {}",
    //                         messages.len()
    //                     ))
    //                 }
    //             },
    //             _ => return err("Incorrect message type"),
    //         };
    //         let mut subs = subs_reader.lock().expect("Lock is tainted");
    //         if message_type == b"subscribe" {
    //             if let Some((tx, notification_tx)) = subs.pending.remove(&topic) {
    //                 subs.confirmed.insert(topic, tx);
    //                 match notification_tx.send(()) {
    //                     Ok(()) => {
    //                         let ok = future::ok(()).map_err(|_: ()| error::internal("unreachable"));
    //                         Box::new(ok)
    //                     }
    //                     Err(()) => err("Cannot send notification of subscription"),
    //                 }
    //             } else {
    //                 err("Received subscribe notification that wasn't expected")
    //             }
    //         } else if message_type == b"unsubscribe" {
    //             if let Some(_) = subs.confirmed.remove(&topic) {
    //                 let result = if subs.confirmed.is_empty() {
    //                     future::err(error::Error::EndOfStream)
    //                 } else {
    //                     future::ok(())
    //                 };
    //                 Box::new(result)
    //             } else {
    //                 err("Receieved unsubscription notification from a topic we're not subscribed to")
    //             }
    //         } else if message_type == b"message" {
    //             match subs.confirmed.get(&topic) {
    //                 Some(tx) => {
    //                     let future = tx.clone().send(msg).map(|_| ()).map_err(|e| e.into());
    //                     Box::new(future)
    //                 }
    //                 None => {
    //                     let ok = future::ok(()).map_err(|_: ()| error::internal("unreachable"));
    //                     Box::new(ok)
    //                 }
    //             }
    //         } else {
    //             return err(format!("Unexpected message type: {:?}", message_type));
    //         }
    //     });
    //     let receiver = Box::new(
    //         receiver_raw
    //             .then(|result| match result {
    //                 Ok(_) => future::ok(()),
    //                 Err(error::Error::EndOfStream) => future::ok(()),
    //                 Err(e) => future::err(e),
    //             })
    //             .map(|_| debug!("End of PUBSUB connection, successful"))
    //             .map_err(|e| error!("PUBSUB Receiver error: {}", e)),
    //     ) as Box<Future<Item = (), Error = ()> + Send>;

    //     let _ = tokio::spawn(sender);
    //     let _ = tokio::spawn(receiver);

    //     PubsubConnection {
    //         out_tx: out_tx,
    //         subscriptions: subs,
    //     }
    // });
    // Box::new(pubsub_con)

    unimplemented!()
}

struct PubsubSubscriptions {
    pending: HashMap<String, (mpsc::Sender<resp::RespValue>, oneshot::Sender<()>)>,
    confirmed: HashMap<String, mpsc::Sender<resp::RespValue>>,
}

#[derive(Clone)]
pub struct PubsubConnection {
    out_tx: mpsc::UnboundedSender<resp::RespValue>,
    subscriptions: Arc<Mutex<PubsubSubscriptions>>,
}

impl PubsubConnection {
    /// Subscribes to a particular PUBSUB topic.
    ///
    /// Returns a future that resolves to a `Stream` that contains all the messages published on
    /// that particular topic.
    pub fn subscribe<T: Into<String>>(
        &self,
        topic: T,
    ) -> Box<Future<Item = PubsubStream, Error = error::Error> + Send> {
        let topic = topic.into();
        let mut subs = self.subscriptions.lock().expect("Lock is tainted");

        // TODO - check arbitrary buffer size
        let (tx, rx) = mpsc::channel(10);
        if subs.confirmed.contains_key(&topic) || subs.pending.contains_key(&topic) {
            return Box::new(future::err(error::internal("Already subscribed")));
        }

        let (notification_tx, notification_rx) = oneshot::channel();
        let subscribe_msg = resp_array!["SUBSCRIBE", &topic];
        subs.pending.insert(topic.clone(), (tx, notification_tx));
        let new_out_tx = self.out_tx.clone();
        match self.out_tx.unbounded_send(subscribe_msg) {
            Ok(_) => {
                let done = notification_rx
                    .map(|_| PubsubStream::new(topic, rx, new_out_tx))
                    .map_err(|e| e.into());
                Box::new(done)
            }
            Err(e) => Box::new(future::err(e.into())),
        }
    }
}

pub struct PubsubStream {
    topic: String,
    underlying: mpsc::Receiver<resp::RespValue>,
    out_tx: mpsc::UnboundedSender<resp::RespValue>,
}

impl PubsubStream {
    fn new(
        topic: String,
        stream: mpsc::Receiver<resp::RespValue>,
        out_tx: mpsc::UnboundedSender<resp::RespValue>,
    ) -> Self {
        PubsubStream {
            topic: topic,
            underlying: stream,
            out_tx: out_tx,
        }
    }
}

impl Stream for PubsubStream {
    type Item = resp::RespValue;
    type Error = ();

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        self.underlying.poll()
    }
}

impl Drop for PubsubStream {
    fn drop(&mut self) {
        let send_f = self.out_tx
            .clone()
            .send(resp_array!["UNSUBSCRIBE", &self.topic]);
        match send_f.wait() {
            Ok(_) => debug!("Send unsubscribe command for topic: {}", self.topic),
            Err(e) => error!(
                "Failed to send unsubscribe command for topic: {}, error: {}",
                self.topic, e
            ),
        }
    }
}
<commit_msg>Re-implement pubsub<commit_after>/*
 * Copyright 2017-2018 Ben Ashford
 *
 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 * option. This file may not be copied, modified, or distributed
 * except according to those terms.
 */

use std::collections::{HashMap, hash_map::Entry};
use std::net::SocketAddr;

use futures::{future, Async, AsyncSink, Future, Poll, Sink, Stream, stream::Fuse,
              sync::{mpsc, oneshot}};

use tokio_executor::{DefaultExecutor, Executor};

use error;
use resp;
use resp::FromResp;
use super::connect::{connect, RespConnection};

fn err<S>(msg: S) -> Box<Future<Item = (), Error = error::Error> + Send>
where
    S: Into<String>,
{
    Box::new(future::err(error::internal(msg)))
}

enum PubsubEvent {
    Subscribe(String, PubsubSink),
    Unsubscribe(String),
}

pub type PubsubStreamInner = mpsc::UnboundedReceiver<resp::RespValue>;
pub type PubsubSink = mpsc::UnboundedSender<resp::RespValue>;

struct PubsubConnectionInner {
    connection: RespConnection,
    out_rx: Fuse<mpsc::UnboundedReceiver<PubsubEvent>>,
    subscriptions: HashMap<String, PubsubSink>,
    send_pending: Option<resp::RespValue>,
}

impl PubsubConnectionInner {
    fn new(con: RespConnection, out_rx: mpsc::UnboundedReceiver<PubsubEvent>) -> Self {
        PubsubConnectionInner {
            connection: con,
            out_rx: out_rx.fuse(),
            subscriptions: HashMap::new(),
            send_pending: None,
        }
    }

    /// Returns true = OK, more can be sent, or false = sink is full, needs flushing
    fn do_send(&mut self, msg: resp::RespValue) -> Result<bool, ()> {
        match self.connection
            .start_send(msg)
            .map_err(|e| error!("Cannot send subscription request to Redis: {}", e))?
        {
            AsyncSink::Ready => Ok(true),
            AsyncSink::NotReady(msg) => {
                self.send_pending = Some(msg);
                Ok(false)
            }
        }
    }

    fn do_flush(&mut self) -> Result<(), ()> {
        self.connection
            .poll_complete()
            .map(|_| ())
            .map_err(|e| error!("Error polling for completeness: {}", e))
    }

    // Returns true = flushing required.  false = no flushing required
    fn handle_new_subs(&mut self) -> Result<bool, ()> {
        if let Some(msg) = self.send_pending.take() {
            if !self.do_send(msg)? {
                return Ok(true);
            }
        }
        loop {
            match self.out_rx
                .poll()
                .map_err(|_| error!("Cannot poll for new subscriptions"))?
            {
                Async::Ready(None) => return Ok(false),
                Async::Ready(Some(pubsub_event)) => {
                    let message = match pubsub_event {
                        PubsubEvent::Subscribe(topic, sender) => {
                            self.subscriptions.insert(topic.clone(), sender);
                            resp_array!["SUBSCRIBE", topic]
                        }
                        PubsubEvent::Unsubscribe(topic) => resp_array!["UNSUBSCRIBE", topic],
                    };
                    if !self.do_send(message)? {
                        return Ok(true);
                    }
                }
                Async::NotReady => return Ok(false),
            }
        }
    }

    fn handle_message(&mut self, msg: resp::RespValue) -> Result<bool, ()> {
        let (message_type, topic, msg) = match msg {
            resp::RespValue::Array(mut messages) => match (
                messages.pop(),
                messages.pop(),
                messages.pop(),
                messages.pop(),
            ) {
                (Some(msg), Some(topic), Some(message_type), None) => {
                    match (msg, String::from_resp(topic), message_type) {
                        (msg, Ok(topic), resp::RespValue::BulkString(bytes)) => (bytes, topic, msg),
                        _ => {
                            error!("Incorrect format of PUBSUB message");
                            return Err(());
                        }
                    }
                }
                _ => {
                    error!("Wrong number of parts for a PUBSUB message");
                    return Err(());
                }
            },
            _ => {
                error!("PUBSUB message should be encoded as an array");
                return Err(());
            }
        };

        if message_type == b"subscribe" {
            debug!("Subscription confirmed for: {}", topic);
        } else if message_type == b"unsubscribe" {
            if let Entry::Occupied(entry) = self.subscriptions.entry(topic) {
                entry.remove_entry();
            }
            if self.subscriptions.is_empty() {
                return Ok(false);
            }
        } else if message_type == b"message" {
            if let Some(sender) = self.subscriptions.get(&topic) {
                sender.unbounded_send(msg).expect("Cannot send message");
            }
        }

        Ok(true)
    }

    /// Returns true, if there are still valid subscriptions at the end, or false if not, i.e. the whole thing can be dropped.
    fn handle_messages(&mut self) -> Result<bool, ()> {
        loop {
            match self.connection
                .poll()
                .map_err(|e| error!("Polling error for messages: {}", e))?
            {
                Async::Ready(None) => return Ok(false),
                Async::Ready(Some(message)) => {
                    let message_result = self.handle_message(message)?;
                    if !message_result {
                        return Ok(false);
                    }
                }
                Async::NotReady => return Ok(true),
            }
        }
    }
}

impl Future for PubsubConnectionInner {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let flush_req = self.handle_new_subs()?;
        if flush_req {
            self.do_flush()?;
        }
        let cont = self.handle_messages()?;
        if cont {
            Ok(Async::NotReady)
        } else {
            Ok(Async::Ready(()))
        }
    }
}

/// A shareable reference to subscribe to PUBSUB topics
#[derive(Clone)]
pub struct PubsubConnection {
    out_tx: mpsc::UnboundedSender<PubsubEvent>,
}

/// Used for Redis's PUBSUB functionality.
///
/// Returns a future that resolves to a `PubsubConnection`.
pub fn pubsub_connect(
    addr: &SocketAddr,
) -> Box<Future<Item = PubsubConnection, Error = error::Error> + Send> {
    let pc_f = connect(addr).map_err(|e| e.into()).map(|connection| {
        let (out_tx, out_rx) = mpsc::unbounded();
        let pubsub_connection_inner = Box::new(PubsubConnectionInner::new(connection, out_rx));
        let mut default_executor = DefaultExecutor::current();
        default_executor
            .spawn(pubsub_connection_inner)
            .expect("Cannot spawn pubsub connection");
        PubsubConnection { out_tx }
    });
    Box::new(pc_f)
}

impl PubsubConnection {
    /// Subscribes to a particular PUBSUB topic.
    ///
    /// Returns a future that resolves to a `Stream` that contains all the messages published on
    /// that particular topic.
    pub fn subscribe<T: Into<String>>(&self, topic: T) -> PubsubStream {
        let topic = topic.into();
        let (tx, rx) = mpsc::unbounded();
        self.out_tx
            .unbounded_send(PubsubEvent::Subscribe(topic.clone(), tx))
            .expect("Cannot queue subscription request");

        PubsubStream {
            topic: topic,
            underlying: rx,
            con: self.clone(),
        }
    }

    pub fn unsubscribe<T: Into<String>>(&self, topic: T) {
        self.out_tx
            .unbounded_send(PubsubEvent::Unsubscribe(topic.into()))
            .expect("Cannot queue unsubscription request");
    }
}

pub struct PubsubStream {
    topic: String,
    underlying: PubsubStreamInner,
    con: PubsubConnection,
}

impl Stream for PubsubStream {
    type Item = resp::RespValue;
    type Error = ();

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        self.underlying.poll()
    }
}

impl Drop for PubsubStream {
    fn drop(&mut self) {
        self.con.unsubscribe(self.topic.as_ref());
    }
}
<|endoftext|>


<commit_before>use cpu::Reg;
use cpu::arm64::reg::*;
use jit::buffer::Buffer;

pub fn ret() -> u32 {
    cls_uncond_branch_reg(0b0010, 0b11111, 0, REG_LR, 0)
}

pub fn ret_reg(rn: Reg) -> u32 {
    cls_uncond_branch_reg(0b0010, 0b11111, 0, rn, 0)
}

pub fn br(rn: Reg) -> u32 {
    cls_uncond_branch_reg(0b0000, 0b11111, 0, rn, 0)
}

pub fn blr(rn: Reg) -> u32 {
    cls_uncond_branch_reg(0b0001, 0b11111, 0, rn, 0)
}

fn cls_uncond_branch_reg(opc: u32, op2: u32, op3: u32, rn: Reg, op4: u32) -> u32 {
    assert!(fits_u4(opc));
    assert!(fits_u5(op2));
    assert!(fits_u6(op3));
    assert!(rn.is_gpr());
    assert!(fits_u5(op4));

    (0b1101011 as u32) << 25 | opc << 21 | op2 << 16 |
        op3 << 10 | rn.u32() << 5 | op4
}

pub fn nop() -> u32 {
    cls_system(0)
}

fn cls_system(imm: u32) -> u32 {
    assert!(fits_u7(imm));

    0xD503201F | imm << 5
}

pub fn add_imm(sf: u32, rd: Reg, rn: Reg, imm12: u32, shift: u32) -> u32 {
    cls_addsub_imm(sf, 0, 0, shift, imm12, rn, rd)
}

pub fn sub_imm(sf: u32, rd: Reg, rn: Reg, imm12: u32, shift: u32) -> u32 {
    cls_addsub_imm(sf, 1, 0, shift, imm12, rn, rd)
}

fn cls_addsub_imm(sf: u32, op: u32, s: u32, shift: u32, imm12: u32, rn: Reg, rd: Reg) -> u32 {
    assert!(fits_bit(sf));
    assert!(fits_bit(op));
    assert!(fits_bit(s));
    assert!(fits_bit(shift));
    assert!(fits_u12(imm12));
    assert!(rn.is_gpr());
    assert!(rd.is_gpr());

    (0b10001 as u32) << 24 | sf << 31 | op << 30 | s << 29 |
        shift << 22 | imm12 << 10 | rn.u32() << 5 | rd.u32()
}

pub fn add_reg(sf: u32, rd: Reg, rn: Reg, rm: Reg) -> u32 {
    cls_addsub_shreg(sf, 0, 0, Shift::Lsl, rm, 0, rn, rd)
}

pub fn sub_reg(sf: u32, rd: Reg, rn: Reg, rm: Reg) -> u32 {
    cls_addsub_shreg(sf, 1, 0, Shift::Lsl, rm, 0, rn, rd)
}

pub fn add_shreg(sf: u32, rd: Reg, rn: Reg, rm: Reg, shift: Shift, amount: u32) -> u32 {
    cls_addsub_shreg(sf, 0, 0, shift, rm, amount, rn, rd)
}

pub fn sub_shreg(sf: u32, rd: Reg, rn: Reg, rm: Reg, shift: Shift, amount: u32) -> u32 {
    cls_addsub_shreg(sf, 1, 0, shift, rm, amount, rn, rd)
}

fn cls_addsub_shreg(sf: u32, op: u32, s: u32, shift: Shift, rm: Reg,
                    imm6: u32, rn: Reg, rd: Reg) -> u32 {
    assert!(fits_bit(sf));
    assert!(fits_bit(op));
    assert!(fits_bit(s));
    assert!(rm.is_gpr());
    assert!(rn.is_gpr());
    assert!(rd.is_gpr());
    assert!(fits_u5(imm6));

    (0b01011 as u32) << 24 | sf << 31 | op << 30 | s << 29 |
        shift.u32() << 22 | rm.u32() << 16 | imm6 << 10 | rn.u32() << 5 | rd.u32()
}

#[derive(Copy, Clone)]
pub enum Shift {
    Lsl, Lsr, Asr
}

impl Shift {
    fn u32(self) -> u32 {
        match self {
            Shift::Lsl => 0,
            Shift::Lsr => 1,
            Shift::Asr => 2,
        }
    }
}

fn fits_bit(imm: u32) -> bool {
    imm < 2
}

fn fits_u4(imm: u32) -> bool {
    imm < 16
}

fn fits_u5(imm: u32) -> bool {
    imm < 32
}

fn fits_u6(imm: u32) -> bool {
    imm < 64
}

fn fits_u7(imm: u32) -> bool {
    imm < 128
}

fn fits_u12(imm: u32) -> bool {
    imm < 4096
}

fn fits_i12(imm: i32) -> bool {
    -2048 <= imm && imm < 2048
}

#[cfg(test)]
mod tests {
    use super::*;
    use cpu::arm64::reg::*;

    macro_rules! assert_emit {
        (
            $exp:expr;
            $val:expr
        ) => {{
            let exp: u32 = $exp;
            let val: u32 = $val;

            if exp != val {
                panic!("0x{:08X} != 0x{:08X}", exp, val);
            }
        }};
    }

    #[test]
    fn test_fits_bit() {
        assert!(fits_bit(0));
        assert!(fits_bit(1));
        assert!(!fits_bit(2));
    }

    #[test]
    fn test_fits_u4() {
        assert!(fits_u4(0));
        assert!(fits_u4(1));
        assert!(fits_u4(14));
        assert!(fits_u4(15));
        assert!(!fits_u4(16));
        assert!(!fits_u4(17));
    }

    #[test]
    fn test_fits_u5() {
        assert!(fits_u5(0));
        assert!(fits_u5(31));
        assert!(!fits_u5(32));
        assert!(!fits_u5(33));
    }

    #[test]
    fn test_fits_u7() {
        assert!(fits_u7(0));
        assert!(fits_u7(31));
        assert!(fits_u7(126));
        assert!(fits_u7(127));
        assert!(!fits_u7(128));
        assert!(!fits_u7(129));
    }

    #[test]
    fn test_fits_u12() {
        assert!(fits_u12(0));
        assert!(fits_u12(4095));
        assert!(!fits_u12(4096));
        assert!(!fits_u12(4097));
    }

    #[test]
    fn test_fits_i12() {
        assert!(fits_i12(0));
        assert!(fits_i12(-2048));
        assert!(fits_i12(2047));
        assert!(!fits_i12(-2049));
        assert!(!fits_i12(2048));
    }

    #[test]
    fn test_br_blr() {
        assert_emit!(0xd61f0000; br(R0));
        assert_emit!(0xd61f03c0; br(R30));
        assert_emit!(0xd63f0000; blr(R0));
        assert_emit!(0xd63f03c0; blr(R30));
    }

    #[test]
    fn test_nop() {
        assert_emit!(0xd503201f; nop());
    }

    #[test]
    fn test_ret() {
        assert_emit!(0xd65f03c0; ret());
        assert_emit!(0xd65f0000; ret_reg(R0));
        assert_emit!(0xd65f0140; ret_reg(R10));
    }

    #[test]
    fn test_add_imm() {
//    4:	91000420 	add	x0, x1, #0x1
//    8:	91400c62 	add	x2, x3, #0x3, lsl #12

        assert_emit!(0x11000420; add_imm(0, R0, R1, 1, 0));
        assert_emit!(0x11400c62; add_imm(0, R2, R3, 3, 1));
        assert_emit!(0x91000420; add_imm(1, R0, R1, 1, 0));
        assert_emit!(0x91400c62; add_imm(1, R2, R3, 3, 1));
    }

    #[test]
    fn test_sub_imm() {
        assert_emit!(0x51000420; sub_imm(0, R0, R1, 1, 0));
        assert_emit!(0x51400c62; sub_imm(0, R2, R3, 3, 1));
        assert_emit!(0xd1000420; sub_imm(1, R0, R1, 1, 0));
        assert_emit!(0xd1400c62; sub_imm(1, R2, R3, 3, 1));
    }

    #[test]
    fn test_add_shreg() {
        assert_emit!(0x0b030441; add_shreg(0, R1, R2, R3, Shift::Lsl, 1));
        assert_emit!(0x8b0608a4; add_shreg(1, R4, R5, R6, Shift::Lsl, 2));
        assert_emit!(0x0b430441; add_shreg(0, R1, R2, R3, Shift::Lsr, 1));
        assert_emit!(0x8b8608a4; add_shreg(1, R4, R5, R6, Shift::Asr, 2));
    }

    #[test]
    fn test_sub_shreg() {
        assert_emit!(0x4b030441; sub_shreg(0, R1, R2, R3, Shift::Lsl, 1));
        assert_emit!(0xcb0608a4; sub_shreg(1, R4, R5, R6, Shift::Lsl, 2));
        assert_emit!(0x4b430441; sub_shreg(0, R1, R2, R3, Shift::Lsr, 1));
        assert_emit!(0xcb8608a4; sub_shreg(1, R4, R5, R6, Shift::Asr, 2));
    }

    #[test]
    fn test_add_reg() {
        assert_emit!(0x0b010000; add_reg(0, R0, R0, R1));
        assert_emit!(0x8b010000; add_reg(1, R0, R0, R1));
        assert_emit!(0x0b030041; add_reg(0, R1, R2, R3));
        assert_emit!(0x8b030041; add_reg(1, R1, R2, R3));
    }

    #[test]
    fn test_sub_reg() {
        assert_emit!(0x4b010000; sub_reg(0, R0, R0, R1));
        assert_emit!(0xcb010000; sub_reg(1, R0, R0, R1));
        assert_emit!(0x4b030041; sub_reg(0, R1, R2, R3));
        assert_emit!(0xcb030041; sub_reg(1, R1, R2, R3));
    }
}<commit_msg>implemented ldrw_ind, ldrx_ind<commit_after>use cpu::Reg;
use cpu::arm64::reg::*;
use jit::buffer::Buffer;

pub fn ret() -> u32 {
    cls_uncond_branch_reg(0b0010, 0b11111, 0, REG_LR, 0)
}

pub fn ret_reg(rn: Reg) -> u32 {
    cls_uncond_branch_reg(0b0010, 0b11111, 0, rn, 0)
}

pub fn br(rn: Reg) -> u32 {
    cls_uncond_branch_reg(0b0000, 0b11111, 0, rn, 0)
}

pub fn blr(rn: Reg) -> u32 {
    cls_uncond_branch_reg(0b0001, 0b11111, 0, rn, 0)
}

fn cls_uncond_branch_reg(opc: u32, op2: u32, op3: u32, rn: Reg, op4: u32) -> u32 {
    assert!(fits_u4(opc));
    assert!(fits_u5(op2));
    assert!(fits_u6(op3));
    assert!(rn.is_gpr());
    assert!(fits_u5(op4));

    (0b1101011 as u32) << 25 | opc << 21 | op2 << 16 |
        op3 << 10 | rn.u32() << 5 | op4
}

pub fn nop() -> u32 {
    cls_system(0)
}

fn cls_system(imm: u32) -> u32 {
    assert!(fits_u7(imm));

    0xD503201F | imm << 5
}

pub fn add_imm(sf: u32, rd: Reg, rn: Reg, imm12: u32, shift: u32) -> u32 {
    cls_addsub_imm(sf, 0, 0, shift, imm12, rn, rd)
}

pub fn sub_imm(sf: u32, rd: Reg, rn: Reg, imm12: u32, shift: u32) -> u32 {
    cls_addsub_imm(sf, 1, 0, shift, imm12, rn, rd)
}

fn cls_addsub_imm(sf: u32, op: u32, s: u32, shift: u32, imm12: u32, rn: Reg, rd: Reg) -> u32 {
    assert!(fits_bit(sf));
    assert!(fits_bit(op));
    assert!(fits_bit(s));
    assert!(fits_bit(shift));
    assert!(fits_u12(imm12));
    assert!(rn.is_gpr());
    assert!(rd.is_gpr());

    (0b10001 as u32) << 24 | sf << 31 | op << 30 | s << 29 |
        shift << 22 | imm12 << 10 | rn.u32() << 5 | rd.u32()
}

pub fn add_reg(sf: u32, rd: Reg, rn: Reg, rm: Reg) -> u32 {
    cls_addsub_shreg(sf, 0, 0, Shift::Lsl, rm, 0, rn, rd)
}

pub fn sub_reg(sf: u32, rd: Reg, rn: Reg, rm: Reg) -> u32 {
    cls_addsub_shreg(sf, 1, 0, Shift::Lsl, rm, 0, rn, rd)
}

pub fn add_shreg(sf: u32, rd: Reg, rn: Reg, rm: Reg, shift: Shift, amount: u32) -> u32 {
    cls_addsub_shreg(sf, 0, 0, shift, rm, amount, rn, rd)
}

pub fn sub_shreg(sf: u32, rd: Reg, rn: Reg, rm: Reg, shift: Shift, amount: u32) -> u32 {
    cls_addsub_shreg(sf, 1, 0, shift, rm, amount, rn, rd)
}

fn cls_addsub_shreg(sf: u32, op: u32, s: u32, shift: Shift, rm: Reg,
                    imm6: u32, rn: Reg, rd: Reg) -> u32 {
    assert!(fits_bit(sf));
    assert!(fits_bit(op));
    assert!(fits_bit(s));
    assert!(rm.is_gpr());
    assert!(rn.is_gpr());
    assert!(rd.is_gpr());
    assert!(fits_u5(imm6));

    0b01011u32 << 24 | sf << 31 | op << 30 | s << 29 |
        shift.u32() << 22 | rm.u32() << 16 | imm6 << 10 | rn.u32() << 5 | rd.u32()
}

pub fn ldrw_ind(rt: Reg, rn: Reg, rm: Reg, extend: Extend, amount: u32) -> u32 {
    cls_ldst_regoffset(0b10, 0, 0b01, rm, extend.u32(), amount, rn, rt)
}

pub fn ldrx_ind(rt: Reg, rn: Reg, rm: Reg, extend: Extend, amount: u32) -> u32 {
    cls_ldst_regoffset(0b11, 0, 0b01, rm, extend.u32(), amount, rn, rt)
}

fn cls_ldst_regoffset(size: u32, v: u32, opc: u32, rm: Reg, option: u32,
                      s: u32, rn: Reg, rt: Reg) -> u32 {
    assert!(fits_u2(size));
    assert!(fits_bit(v));
    assert!(fits_u2(opc));
    assert!(rm.is_gpr());
    assert!(fits_u3(option));
    assert!(fits_bit(s));
    assert!(rn.is_gpr());
    assert!(rt.is_gpr());

    0b111u32 << 27 | 1u32 << 21 | 0b10u32 << 10 | size << 30 |
        v << 26 | opc << 22 | rm.u32() << 16 | option << 13 | s << 12 |
        rn.u32() << 5 | rt.u32()
}

#[derive(Copy, Clone)]
pub enum Extend {
    UXTW, LSL, SXTW, SXTX
}

impl Extend {
    fn u32(self) -> u32 {
        match self {
            Extend::UXTW => 0b010,
            Extend::LSL => 0b011,
            Extend::SXTW => 0b110,
            Extend::SXTX => 0b111,
        }
    }
}

#[derive(Copy, Clone)]
pub enum Shift {
    Lsl, Lsr, Asr
}

impl Shift {
    fn u32(self) -> u32 {
        match self {
            Shift::Lsl => 0,
            Shift::Lsr => 1,
            Shift::Asr => 2,
        }
    }
}

fn fits_bit(imm: u32) -> bool {
    imm < 2
}

fn fits_u2(imm: u32) -> bool {
    imm < 4
}

fn fits_u3(imm: u32) -> bool {
    imm < 8
}

fn fits_u4(imm: u32) -> bool {
    imm < 16
}

fn fits_u5(imm: u32) -> bool {
    imm < 32
}

fn fits_u6(imm: u32) -> bool {
    imm < 64
}

fn fits_u7(imm: u32) -> bool {
    imm < 128
}

fn fits_u12(imm: u32) -> bool {
    imm < 4096
}

fn fits_i12(imm: i32) -> bool {
    -2048 <= imm && imm < 2048
}

#[cfg(test)]
mod tests {
    use super::*;
    use cpu::arm64::reg::*;

    macro_rules! assert_emit {
        (
            $exp:expr;
            $val:expr
        ) => {{
            let exp: u32 = $exp;
            let val: u32 = $val;

            if exp != val {
                panic!("0x{:08X} != 0x{:08X}", exp, val);
            }
        }};
    }

    #[test]
    fn test_fits_bit() {
        assert!(fits_bit(0));
        assert!(fits_bit(1));
        assert!(!fits_bit(2));
    }

    #[test]
    fn test_fits_u4() {
        assert!(fits_u4(0));
        assert!(fits_u4(1));
        assert!(fits_u4(14));
        assert!(fits_u4(15));
        assert!(!fits_u4(16));
        assert!(!fits_u4(17));
    }

    #[test]
    fn test_fits_u5() {
        assert!(fits_u5(0));
        assert!(fits_u5(31));
        assert!(!fits_u5(32));
        assert!(!fits_u5(33));
    }

    #[test]
    fn test_fits_u7() {
        assert!(fits_u7(0));
        assert!(fits_u7(31));
        assert!(fits_u7(126));
        assert!(fits_u7(127));
        assert!(!fits_u7(128));
        assert!(!fits_u7(129));
    }

    #[test]
    fn test_fits_u12() {
        assert!(fits_u12(0));
        assert!(fits_u12(4095));
        assert!(!fits_u12(4096));
        assert!(!fits_u12(4097));
    }

    #[test]
    fn test_fits_i12() {
        assert!(fits_i12(0));
        assert!(fits_i12(-2048));
        assert!(fits_i12(2047));
        assert!(!fits_i12(-2049));
        assert!(!fits_i12(2048));
    }

    #[test]
    fn test_br_blr() {
        assert_emit!(0xd61f0000; br(R0));
        assert_emit!(0xd61f03c0; br(R30));
        assert_emit!(0xd63f0000; blr(R0));
        assert_emit!(0xd63f03c0; blr(R30));
    }

    #[test]
    fn test_nop() {
        assert_emit!(0xd503201f; nop());
    }

    #[test]
    fn test_ret() {
        assert_emit!(0xd65f03c0; ret());
        assert_emit!(0xd65f0000; ret_reg(R0));
        assert_emit!(0xd65f0140; ret_reg(R10));
    }

    #[test]
    fn test_add_imm() {
        assert_emit!(0x11000420; add_imm(0, R0, R1, 1, 0));
        assert_emit!(0x11400c62; add_imm(0, R2, R3, 3, 1));
        assert_emit!(0x91000420; add_imm(1, R0, R1, 1, 0));
        assert_emit!(0x91400c62; add_imm(1, R2, R3, 3, 1));
    }

    #[test]
    fn test_sub_imm() {
        assert_emit!(0x51000420; sub_imm(0, R0, R1, 1, 0));
        assert_emit!(0x51400c62; sub_imm(0, R2, R3, 3, 1));
        assert_emit!(0xd1000420; sub_imm(1, R0, R1, 1, 0));
        assert_emit!(0xd1400c62; sub_imm(1, R2, R3, 3, 1));
    }

    #[test]
    fn test_add_shreg() {
        assert_emit!(0x0b030441; add_shreg(0, R1, R2, R3, Shift::Lsl, 1));
        assert_emit!(0x8b0608a4; add_shreg(1, R4, R5, R6, Shift::Lsl, 2));
        assert_emit!(0x0b430441; add_shreg(0, R1, R2, R3, Shift::Lsr, 1));
        assert_emit!(0x8b8608a4; add_shreg(1, R4, R5, R6, Shift::Asr, 2));
    }

    #[test]
    fn test_sub_shreg() {
        assert_emit!(0x4b030441; sub_shreg(0, R1, R2, R3, Shift::Lsl, 1));
        assert_emit!(0xcb0608a4; sub_shreg(1, R4, R5, R6, Shift::Lsl, 2));
        assert_emit!(0x4b430441; sub_shreg(0, R1, R2, R3, Shift::Lsr, 1));
        assert_emit!(0xcb8608a4; sub_shreg(1, R4, R5, R6, Shift::Asr, 2));
    }

    #[test]
    fn test_add_reg() {
        assert_emit!(0x0b010000; add_reg(0, R0, R0, R1));
        assert_emit!(0x8b010000; add_reg(1, R0, R0, R1));
        assert_emit!(0x0b030041; add_reg(0, R1, R2, R3));
        assert_emit!(0x8b030041; add_reg(1, R1, R2, R3));
    }

    #[test]
    fn test_sub_reg() {
        assert_emit!(0x4b010000; sub_reg(0, R0, R0, R1));
        assert_emit!(0xcb010000; sub_reg(1, R0, R0, R1));
        assert_emit!(0x4b030041; sub_reg(0, R1, R2, R3));
        assert_emit!(0xcb030041; sub_reg(1, R1, R2, R3));
    }

    #[test]
    fn test_ldrw_ind() {
        assert_emit!(0xb8626820; ldrw_ind(R0, R1, R2, Extend::LSL, 0));
        assert_emit!(0xb8657883; ldrw_ind(R3, R4, R5, Extend::LSL, 1));
        assert_emit!(0xb86858e6; ldrw_ind(R6, R7, R8, Extend::UXTW, 1));
        assert_emit!(0xb86bd949; ldrw_ind(R9, R10, R11, Extend::SXTW, 1));
    }

    #[test]
    fn test_ldrx_ind() {
        assert_emit!(0xf8626820; ldrx_ind(R0, R1, R2, Extend::LSL, 0));
        assert_emit!(0xf8657883; ldrx_ind(R3, R4, R5, Extend::LSL, 1));
        assert_emit!(0xf86858e6; ldrx_ind(R6, R7, R8, Extend::UXTW, 1));
        assert_emit!(0xf86bd949; ldrx_ind(R9, R10, R11, Extend::SXTW, 1));
    }
}<|endoftext|>


<commit_before>// compile-flags: -C no-prepopulate-passes

pub fn main() {

    // We want to make sure that closures get 'internal' linkage instead of
    // 'weak_odr' when they are not shared between codegen units
    // FIXME(eddyb) `legacy` mangling uses `{{closure}}`, while `v0`
    // uses `{closure#0}`, switch to the latter once `legacy` is gone.
    // CHECK-LABEL: ; internalize_closures::main::{{.*}}closure
    // CHECK-NEXT: ; Function Attrs:
    // CHECK-NEXT: define internal
    let c = |x:i32| { x + 1 };
    let _ = c(1);
}
<commit_msg>Ensure that closure call is not removed by MIR optimizations in a test<commit_after>// compile-flags: -C no-prepopulate-passes -Zmir-opt-level=0

pub fn main() {

    // We want to make sure that closures get 'internal' linkage instead of
    // 'weak_odr' when they are not shared between codegen units
    // FIXME(eddyb) `legacy` mangling uses `{{closure}}`, while `v0`
    // uses `{closure#0}`, switch to the latter once `legacy` is gone.
    // CHECK-LABEL: ; internalize_closures::main::{{.*}}closure
    // CHECK-NEXT: ; Function Attrs:
    // CHECK-NEXT: define internal
    let c = |x:i32| { x + 1 };
    let _ = c(1);
}
<|endoftext|>


<commit_before>use once_cell::sync::OnceCell;
use failure::Fail;
use super::Cryptographer;

static CRYPTOGRAPHER: OnceCell<&'static dyn Cryptographer> = OnceCell::INIT;

#[derive(Debug, Fail)]
#[fail(display = "Cryptographer already initialized")]
pub struct SetCryptographerError(());

/// Sets the global object that will be used for cryptographic operations.
///
/// This is a convenience wrapper over [`set_cryptographer`],
/// but takes a `Box<dyn Cryptographer>` instead.
#[cfg(not(any(feature = "use_ring", feature = "use_openssl")))]
pub fn set_boxed_cryptographer(c: Box<dyn Cryptographer>) -> Result<(), SetCryptographerError> {
    set_cryptographer(Box::leak(c))
}

/// Sets the global object that will be used for cryptographic operations.
///
/// This function may only be called once in the lifetime of a program.
///
/// Any calls into this crate that perform cryptography prior to calling this
/// function will panic.
pub fn set_cryptographer(c: &'static dyn Cryptographer) -> Result<(), SetCryptographerError> {
    CRYPTOGRAPHER.set(c).map_err(|_| SetCryptographerError(()))
}

pub(crate) fn get_crypographer() -> &'static dyn Cryptographer {
    autoinit_crypto();
    *CRYPTOGRAPHER.get().expect("`hawk` cryptographer not initialized!")
}

#[cfg(feature = "use_ring")]
#[inline]
fn autoinit_crypto() {
    let _ = set_cryptographer(&super::ring::RingCryptographer);
}

#[cfg(feature = "use_openssl")]
#[inline]
fn autoinit_crypto() {
    let _ = set_cryptographer(&super::openssl::OpensslCryptographer);
}

#[cfg(not(any(feature = "use_openssl", feature = "use_ring")))]
#[inline]
fn autoinit_crypto() {
}
<commit_msg>Add a comment about Box::leak usage<commit_after>use once_cell::sync::OnceCell;
use failure::Fail;
use super::Cryptographer;

static CRYPTOGRAPHER: OnceCell<&'static dyn Cryptographer> = OnceCell::INIT;

#[derive(Debug, Fail)]
#[fail(display = "Cryptographer already initialized")]
pub struct SetCryptographerError(());

/// Sets the global object that will be used for cryptographic operations.
///
/// This is a convenience wrapper over [`set_cryptographer`],
/// but takes a `Box<dyn Cryptographer>` instead.
#[cfg(not(any(feature = "use_ring", feature = "use_openssl")))]
pub fn set_boxed_cryptographer(c: Box<dyn Cryptographer>) -> Result<(), SetCryptographerError> {
    // Just leak the Box. It wouldn't be freed as a `static` anyway, and we
    // never allow this to be re-assigned (so it's not a meaningful memory leak).
    set_cryptographer(Box::leak(c))
}

/// Sets the global object that will be used for cryptographic operations.
///
/// This function may only be called once in the lifetime of a program.
///
/// Any calls into this crate that perform cryptography prior to calling this
/// function will panic.
pub fn set_cryptographer(c: &'static dyn Cryptographer) -> Result<(), SetCryptographerError> {
    CRYPTOGRAPHER.set(c).map_err(|_| SetCryptographerError(()))
}

pub(crate) fn get_crypographer() -> &'static dyn Cryptographer {
    autoinit_crypto();
    *CRYPTOGRAPHER.get().expect("`hawk` cryptographer not initialized!")
}

#[cfg(feature = "use_ring")]
#[inline]
fn autoinit_crypto() {
    let _ = set_cryptographer(&super::ring::RingCryptographer);
}

#[cfg(feature = "use_openssl")]
#[inline]
fn autoinit_crypto() {
    let _ = set_cryptographer(&super::openssl::OpensslCryptographer);
}

#[cfg(not(any(feature = "use_openssl", feature = "use_ring")))]
#[inline]
fn autoinit_crypto() {
}
<|endoftext|>


<commit_before>//! Ethereum 2.0 types

#[macro_use]
pub mod test_utils;
pub mod attestation;
pub mod attestation_data;
pub mod attestation_data_and_custody_bit;
pub mod attester_slashing;
pub mod beacon_block;
pub mod beacon_block_body;
pub mod beacon_state;
pub mod chain_spec;
pub mod crosslink;
pub mod deposit;
pub mod deposit_data;
pub mod deposit_input;
pub mod eth1_data;
pub mod eth1_data_vote;
pub mod fork;
pub mod free_attestation;
pub mod pending_attestation;
pub mod proposal;
pub mod proposer_slashing;
pub mod readers;
pub mod shard_reassignment_record;
pub mod slashable_attestation;
pub mod test_utils;
pub mod transfer;
pub mod voluntary_exit;
#[macro_use]
pub mod slot_epoch_macros;
pub mod slot_epoch;
pub mod slot_height;
pub mod validator;
pub mod validator_registry;

use ethereum_types::{H160, H256, U256};
use std::collections::HashMap;

pub use crate::attestation::Attestation;
pub use crate::attestation_data::AttestationData;
pub use crate::attestation_data_and_custody_bit::AttestationDataAndCustodyBit;
pub use crate::attester_slashing::AttesterSlashing;
pub use crate::beacon_block::BeaconBlock;
pub use crate::beacon_block_body::BeaconBlockBody;
pub use crate::beacon_state::{BeaconState, Error as BeaconStateError, RelativeEpoch};
pub use crate::chain_spec::{ChainSpec, Domain};
pub use crate::crosslink::Crosslink;
pub use crate::deposit::Deposit;
pub use crate::deposit_data::DepositData;
pub use crate::deposit_input::DepositInput;
pub use crate::eth1_data::Eth1Data;
pub use crate::eth1_data_vote::Eth1DataVote;
pub use crate::fork::Fork;
pub use crate::free_attestation::FreeAttestation;
pub use crate::pending_attestation::PendingAttestation;
pub use crate::proposal::Proposal;
pub use crate::proposer_slashing::ProposerSlashing;
pub use crate::slashable_attestation::SlashableAttestation;
pub use crate::slot_epoch::{Epoch, Slot};
pub use crate::slot_height::SlotHeight;
pub use crate::transfer::Transfer;
pub use crate::validator::Validator;
pub use crate::voluntary_exit::VoluntaryExit;

pub type Hash256 = H256;
pub type Address = H160;
pub type EthBalance = U256;
pub type Bitfield = boolean_bitfield::BooleanBitfield;
pub type BitfieldError = boolean_bitfield::Error;

/// Maps a (slot, shard_id) to attestation_indices.
pub type AttesterMap = HashMap<(u64, u64), Vec<usize>>;

/// Maps a slot to a block proposer.
pub type ProposerMap = HashMap<u64, usize>;

pub use bls::{AggregatePublicKey, AggregateSignature, Keypair, PublicKey, SecretKey, Signature};
<commit_msg>Fix test_utils macro definition<commit_after>//! Ethereum 2.0 types

#[macro_use]
pub mod test_utils;

pub mod attestation;
pub mod attestation_data;
pub mod attestation_data_and_custody_bit;
pub mod attester_slashing;
pub mod beacon_block;
pub mod beacon_block_body;
pub mod beacon_state;
pub mod chain_spec;
pub mod crosslink;
pub mod deposit;
pub mod deposit_data;
pub mod deposit_input;
pub mod eth1_data;
pub mod eth1_data_vote;
pub mod fork;
pub mod free_attestation;
pub mod pending_attestation;
pub mod proposal;
pub mod proposer_slashing;
pub mod readers;
pub mod shard_reassignment_record;
pub mod slashable_attestation;
pub mod transfer;
pub mod voluntary_exit;
#[macro_use]
pub mod slot_epoch_macros;
pub mod slot_epoch;
pub mod slot_height;
pub mod validator;
pub mod validator_registry;

use ethereum_types::{H160, H256, U256};
use std::collections::HashMap;

pub use crate::attestation::Attestation;
pub use crate::attestation_data::AttestationData;
pub use crate::attestation_data_and_custody_bit::AttestationDataAndCustodyBit;
pub use crate::attester_slashing::AttesterSlashing;
pub use crate::beacon_block::BeaconBlock;
pub use crate::beacon_block_body::BeaconBlockBody;
pub use crate::beacon_state::{BeaconState, Error as BeaconStateError, RelativeEpoch};
pub use crate::chain_spec::{ChainSpec, Domain};
pub use crate::crosslink::Crosslink;
pub use crate::deposit::Deposit;
pub use crate::deposit_data::DepositData;
pub use crate::deposit_input::DepositInput;
pub use crate::eth1_data::Eth1Data;
pub use crate::eth1_data_vote::Eth1DataVote;
pub use crate::fork::Fork;
pub use crate::free_attestation::FreeAttestation;
pub use crate::pending_attestation::PendingAttestation;
pub use crate::proposal::Proposal;
pub use crate::proposer_slashing::ProposerSlashing;
pub use crate::slashable_attestation::SlashableAttestation;
pub use crate::slot_epoch::{Epoch, Slot};
pub use crate::slot_height::SlotHeight;
pub use crate::transfer::Transfer;
pub use crate::validator::Validator;
pub use crate::voluntary_exit::VoluntaryExit;

pub type Hash256 = H256;
pub type Address = H160;
pub type EthBalance = U256;
pub type Bitfield = boolean_bitfield::BooleanBitfield;
pub type BitfieldError = boolean_bitfield::Error;

/// Maps a (slot, shard_id) to attestation_indices.
pub type AttesterMap = HashMap<(u64, u64), Vec<usize>>;

/// Maps a slot to a block proposer.
pub type ProposerMap = HashMap<u64, usize>;

pub use bls::{AggregatePublicKey, AggregateSignature, Keypair, PublicKey, SecretKey, Signature};
<|endoftext|>


<commit_before>extern crate ggez;
extern crate clap;
use clap::{Arg, App};
use ggez::*;
use ggez::graphics::{DrawMode, Point2, Drawable};
use ggez::event::{Keycode, Mod};
use std::time::Duration;

enum WindowToggle {
    NONE,
    FORWARD,
    REVERSE
}

struct WindowSettings {
    window_size_toggle: WindowToggle,
    toggle_fullscreen: bool,
    is_fullscreen: usize,
    num_of_resolutions: usize,
    resolution_index: usize,
}

struct MainState {
    pos_x: f32,
    angle: f32, // in radians
    window_settings: WindowSettings,
}

impl MainState {
    fn new(_ctx: &mut Context) -> GameResult<MainState> {
        let mut s = MainState {
            pos_x: 0.0,
            angle: 0.0,
            window_settings: WindowSettings {
                toggle_fullscreen: false,
                window_size_toggle: WindowToggle::NONE,
                is_fullscreen: 0,
                resolution_index: 0,
                num_of_resolutions: 0,
            }
        };

        let resolutions = ggez::graphics::get_fullscreen_modes(_ctx, 0)?;
        s.window_settings.num_of_resolutions = resolutions.len();

        Ok(s)
    }
}

impl event::EventHandler for MainState {
    fn update(&mut self, ctx: &mut Context) -> GameResult<()> {
        const DESIRED_FPS: u32 = 60;
        while timer::check_update_time(ctx, DESIRED_FPS) {
            self.pos_x = self.pos_x % 800.0 + 1.0;
            self.angle = self.angle + 0.01;

            if self.window_settings.toggle_fullscreen {
                ggez::graphics::set_fullscreen(ctx, self.window_settings.is_fullscreen != 0)?;
                self.window_settings.toggle_fullscreen = false;
            }

            match self.window_settings.window_size_toggle {
                WindowToggle::FORWARD | WindowToggle::REVERSE => {
                    let resolutions = ggez::graphics::get_fullscreen_modes(ctx, 0)?;
                    let (width, height) = resolutions[self.window_settings.resolution_index];

                    ggez::graphics::set_resolution(ctx, width, height)?;

                    self.window_settings.window_size_toggle = WindowToggle::NONE;
                }
                _ => {},
            }
      }
        Ok(())
    }

    fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
        graphics::clear(ctx);

        let rot_circle = graphics::Mesh::new_circle(ctx, DrawMode::Line(3.0), Point2::new(0.0, 0.0), 100.0, 4.0)?;
        rot_circle.draw(ctx, Point2::new(400.0, 300.0), self.angle)?;

        graphics::present(ctx);
        Ok(())
    }

    fn key_up_event(&mut self, ctx: &mut Context, keycode: Keycode, _keymod: Mod, repeat: bool) {

        if !repeat {
            match keycode {
                Keycode::F => {
                    self.window_settings.toggle_fullscreen = true;
                    self.window_settings.is_fullscreen ^= 1;
                }
                Keycode::H => {
                    self.window_settings.window_size_toggle = WindowToggle::FORWARD;
                    self.window_settings.resolution_index += 1;
                    self.window_settings.resolution_index %= self.window_settings.num_of_resolutions;
                }
                Keycode::G => {
                    if self.window_settings.resolution_index > 0 {
                        self.window_settings.window_size_toggle = WindowToggle::REVERSE;
                        self.window_settings.resolution_index -= 1;
                        self.window_settings.resolution_index %= self.window_settings.num_of_resolutions;
                    }
                }
                _ => {},
            }
        }
    }
}

pub fn main() {
    let matches = App::new("graphics settings example")
        .arg(Arg::with_name("msaa")
                 .short("m")
                 .value_name("N")
                 .help("Number of MSAA samples to do (powers of 2 from 1 to 16)")
                 .takes_value(true))
        .get_matches();

    let msaa: u32 = matches
        .value_of("msaa")
        .unwrap_or("1")
        .parse()
        .expect("Option msaa needs to be a number!");
    let mut c = conf::Conf::new();
    c.window_mode.samples =
        conf::NumSamples::from_u32(msaa).expect("Option msaa needs to be 1, 2, 4, 8 or 16!");
    let ctx = &mut Context::load_from_conf("super_simple", "ggez", c).unwrap();
    let state = &mut MainState::new(ctx).unwrap();
    event::run(ctx, state).unwrap();
}
<commit_msg>Corrected type of is_fullscreen<commit_after>extern crate ggez;
extern crate clap;
use clap::{Arg, App};
use ggez::*;
use ggez::graphics::{DrawMode, Point2, Drawable};
use ggez::event::{Keycode, Mod};
use std::time::Duration;

enum WindowToggle {
    NONE,
    FORWARD,
    REVERSE
}

struct WindowSettings {
    window_size_toggle: WindowToggle,
    toggle_fullscreen: bool,
    is_fullscreen: bool,
    num_of_resolutions: usize,
    resolution_index: usize,
}

struct MainState {
    pos_x: f32,
    angle: f32, // in radians
    window_settings: WindowSettings,
}

impl MainState {
    fn new(_ctx: &mut Context) -> GameResult<MainState> {
        let mut s = MainState {
            pos_x: 0.0,
            angle: 0.0,
            window_settings: WindowSettings {
                toggle_fullscreen: false,
                window_size_toggle: WindowToggle::NONE,
                is_fullscreen: false,
                resolution_index: 0,
                num_of_resolutions: 0,
            }
        };

        let resolutions = ggez::graphics::get_fullscreen_modes(_ctx, 0)?;
        s.window_settings.num_of_resolutions = resolutions.len();

        Ok(s)
    }
}

impl event::EventHandler for MainState {
    fn update(&mut self, ctx: &mut Context) -> GameResult<()> {
        const DESIRED_FPS: u32 = 60;
        while timer::check_update_time(ctx, DESIRED_FPS) {
            self.pos_x = self.pos_x % 800.0 + 1.0;
            self.angle = self.angle + 0.01;

            if self.window_settings.toggle_fullscreen {
                ggez::graphics::set_fullscreen(ctx, self.window_settings.is_fullscreen)?;
                self.window_settings.toggle_fullscreen = false;
            }

            match self.window_settings.window_size_toggle {
                WindowToggle::FORWARD | WindowToggle::REVERSE => {
                    let resolutions = ggez::graphics::get_fullscreen_modes(ctx, 0)?;
                    let (width, height) = resolutions[self.window_settings.resolution_index];

                    ggez::graphics::set_resolution(ctx, width, height)?;

                    self.window_settings.window_size_toggle = WindowToggle::NONE;
                }
                _ => {},
            }
      }
        Ok(())
    }

    fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
        graphics::clear(ctx);

        let rot_circle = graphics::Mesh::new_circle(ctx, DrawMode::Line(3.0), Point2::new(0.0, 0.0), 100.0, 4.0)?;
        rot_circle.draw(ctx, Point2::new(400.0, 300.0), self.angle)?;

        graphics::present(ctx);
        Ok(())
    }

    fn key_up_event(&mut self, ctx: &mut Context, keycode: Keycode, _keymod: Mod, repeat: bool) {

        if !repeat {
            match keycode {
                Keycode::F => {
                    self.window_settings.toggle_fullscreen = true;
                    self.window_settings.is_fullscreen = !self.window_settings.is_fullscreen;
                }
                Keycode::H => {
                    self.window_settings.window_size_toggle = WindowToggle::FORWARD;
                    self.window_settings.resolution_index += 1;
                    self.window_settings.resolution_index %= self.window_settings.num_of_resolutions;
                }
                Keycode::G => {
                    if self.window_settings.resolution_index > 0 {
                        self.window_settings.window_size_toggle = WindowToggle::REVERSE;
                        self.window_settings.resolution_index -= 1;
                        self.window_settings.resolution_index %= self.window_settings.num_of_resolutions;
                    }
                }
                _ => {},
            }
        }
    }
}

pub fn main() {
    let matches = App::new("graphics settings example")
        .arg(Arg::with_name("msaa")
                 .short("m")
                 .value_name("N")
                 .help("Number of MSAA samples to do (powers of 2 from 1 to 16)")
                 .takes_value(true))
        .get_matches();

    let msaa: u32 = matches
        .value_of("msaa")
        .unwrap_or("1")
        .parse()
        .expect("Option msaa needs to be a number!");
    let mut c = conf::Conf::new();
    c.window_mode.samples =
        conf::NumSamples::from_u32(msaa).expect("Option msaa needs to be 1, 2, 4, 8 or 16!");
    let ctx = &mut Context::load_from_conf("super_simple", "ggez", c).unwrap();
    let state = &mut MainState::new(ctx).unwrap();
    event::run(ctx, state).unwrap();
}
<|endoftext|>


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

use std::ffi::OsStr;
use std::io;
use std::ops::{Deref, DerefMut};
use std::os::windows::ffi::OsStrExt;

use super::device::*;
use super::ffi::*;

pub struct Serial {
    dev: Device
}

impl Serial {

    pub fn open(port: &str) -> io::Result<Serial> {
        let encoded_port: Vec<u16> = OsStr::new(port)
        	.encode_wide()
        	.chain(Some(0).into_iter())
        	.collect();
        let handle = checked_handle! { valid =>
            CreateFileW(
                encoded_port.as_ptr() as LPCWSTR,
          		GENERIC_READ | GENERIC_WRITE,
          		0,
          		0 as LPSECURITY_ATTRIBUTES,
           		OPEN_EXISTING,
          		FILE_FLAG_OVERLAPPED,
          		0 as HANDLE)
        };

        Ok(Serial {
            dev: Device::from_handle(handle)
        })
    }

    pub fn open_arduino(port: &str, baud_rate: usize) ->io::Result<Serial> {
        let mut port = try!(Serial::open(port));

        // Set the serial settings for Arduino
    	let mut dcb = try!(port.dcb());
		dcb.BaudRate = baud_rate as DWORD;
		dcb.ByteSize = 8;
		dcb.StopBits = 1;
		dcb.Parity = 0;
		dcb.setDtrControl();
		try!(port.set_dcb(&dcb));

		// Purge the buffers to eliminate accumulated messages prior to reset
        checked_result!(PurgeComm(port.handle(), PURGE_TXCLEAR | PURGE_RXCLEAR));
		Ok(port)
    }

    pub fn set_timeouts(&mut self, timeouts: &COMMTIMEOUTS) -> io::Result<()> {
		checked_result!(SetCommTimeouts(self.dev.handle(), timeouts as LPCCOMMTIMEOUTS));
		Ok(())
    }

    pub fn dcb(&self) -> io::Result<DCB> {
        let mut dcb = DCB::new();
        checked_result!(GetCommState(self.dev.handle(), &mut dcb as LPDCB));
        Ok(dcb)
    }

    pub fn set_dcb(&mut self, dcb: &DCB) -> io::Result<()> {
        checked_result!(SetCommState(self.dev.handle(), dcb as LPCDCB));
        Ok(())
    }
}

impl Deref for Serial {
    type Target = Device;

    fn deref(&self) -> &Device {
        &self.dev
    }
}

impl DerefMut for Serial {
    fn deref_mut(&mut self) -> &mut Device {
        &mut self.dev
    }
}

#[cfg(test)]
mod test {

	use std::time::Duration;

	use io::device::*;
	use io::iocp::*;
	use io::ffi::*;

	use super::*;

	#[test]
	fn should_read_and_write() {
	    let mut iocp = CompletionPort::new().unwrap();
		let mut port = Serial::open_arduino("COM3", 9600).unwrap();
		port.set_timeouts(&COMMTIMEOUTS::wait_to_fill()).unwrap();
		iocp.attach(&port).unwrap();
		port.request_read_bytes(6).unwrap();
		let dev = iocp.process_event(&Duration::from_millis(5000)).unwrap();
		assert_eq!(dev, port.id());
		let event = port.process_event();
		assert_eq!(event, Event::BytesRead(6));
		assert_eq!(port.recv_bytes(), b"Hello\n");
	}
}<commit_msg>Remove external dependency to `io::ffi`<commit_after>//
// FlightVars
// Copyright (c) 2015, 2016 Alvaro Polo
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::ffi::OsStr;
use std::io;
use std::ops::{Deref, DerefMut};
use std::os::windows::ffi::OsStrExt;

use super::device::*;
use super::ffi::*;

pub enum SerialTimeouts {
    /// Read any byte upon available in input buffers
    ReadUponAvailable,

    /// Wait for all requested bytes to be available
    WaitToFill,
}

impl SerialTimeouts {
    fn as_raw(&self) -> COMMTIMEOUTS {
        match *self {
            SerialTimeouts::ReadUponAvailable => COMMTIMEOUTS::read_upon_available(),
            SerialTimeouts::WaitToFill => COMMTIMEOUTS::wait_to_fill(),
        }
    }
}

pub struct Serial {
    dev: Device
}

impl Serial {

    pub fn open(port: &str) -> io::Result<Serial> {
        let encoded_port: Vec<u16> = OsStr::new(port)
        	.encode_wide()
        	.chain(Some(0).into_iter())
        	.collect();
        let handle = checked_handle! { valid =>
            CreateFileW(
                encoded_port.as_ptr() as LPCWSTR,
          		GENERIC_READ | GENERIC_WRITE,
          		0,
          		0 as LPSECURITY_ATTRIBUTES,
           		OPEN_EXISTING,
          		FILE_FLAG_OVERLAPPED,
          		0 as HANDLE)
        };

        Ok(Serial {
            dev: Device::from_handle(handle)
        })
    }

    pub fn open_arduino(port: &str, baud_rate: usize) ->io::Result<Serial> {
        let mut port = try!(Serial::open(port));

        // Set the serial settings for Arduino
    	let mut dcb = try!(port.dcb());
		dcb.BaudRate = baud_rate as DWORD;
		dcb.ByteSize = 8;
		dcb.StopBits = 1;
		dcb.Parity = 0;
		dcb.setDtrControl();
		try!(port.set_dcb(&dcb));

		// Purge the buffers to eliminate accumulated messages prior to reset
        checked_result!(PurgeComm(port.handle(), PURGE_TXCLEAR | PURGE_RXCLEAR));
		Ok(port)
    }

    pub fn set_timeouts(&mut self, timeouts: &SerialTimeouts) -> io::Result<()> {
        let raw = timeouts.as_raw();
		checked_result!(SetCommTimeouts(self.dev.handle(), &raw as LPCCOMMTIMEOUTS));
		Ok(())
    }

    pub fn dcb(&self) -> io::Result<DCB> {
        let mut dcb = DCB::new();
        checked_result!(GetCommState(self.dev.handle(), &mut dcb as LPDCB));
        Ok(dcb)
    }

    pub fn set_dcb(&mut self, dcb: &DCB) -> io::Result<()> {
        checked_result!(SetCommState(self.dev.handle(), dcb as LPCDCB));
        Ok(())
    }
}

impl Deref for Serial {
    type Target = Device;

    fn deref(&self) -> &Device {
        &self.dev
    }
}

impl DerefMut for Serial {
    fn deref_mut(&mut self) -> &mut Device {
        &mut self.dev
    }
}

#[cfg(test)]
mod test {

	use std::time::Duration;

	use io::device::*;
	use io::iocp::*;

	use super::*;

	#[test]
	fn should_read_and_write() {
	    let mut iocp = CompletionPort::new().unwrap();
		let mut port = Serial::open_arduino("COM3", 9600).unwrap();
		port.set_timeouts(&SerialTimeouts::WaitToFill).unwrap();
		iocp.attach(&port).unwrap();
		port.request_read_bytes(6).unwrap();
		let dev = iocp.process_event(&Duration::from_millis(5000)).unwrap();
		assert_eq!(dev, port.id());
		let event = port.process_event();
		assert_eq!(event, Event::BytesRead(6));
		assert_eq!(port.recv_bytes(), b"Hello\n");
	}
}<|endoftext|>