<commit_before>//! Transports for communicating with the docker daemon

extern crate hyper;
extern crate mime;
extern crate unix_socket;

use hyper::Client;
use hyper::client;
use self::hyper::buffer::BufReader;
use self::hyper::http::{ parse_response, RawStatus };
use self::hyper::http::HttpReader::EofReader;
use self::hyper::header::ContentType;
use self::hyper::status::StatusCode;
use hyper::method::Method;
use self::mime::{ Attr, Mime, Value };
use self::mime::TopLevel::Application;
use self::mime::SubLevel::Json;
use std::ops::DerefMut;
use std::io::{ Error, ErrorKind, Read, Result, Write };
use unix_socket::UnixStream;

fn lift_status_err(status: u16) -> Result<Box<Read>> {
  match status {
    400 => Err(Error::new(ErrorKind::InvalidInput, "bad parameter")),
    404 => Err(Error::new(ErrorKind::InvalidInput, "not found")),
    406 => Err(Error::new(ErrorKind::InvalidInput, "not acceptable")),
    409 => Err(Error::new(ErrorKind::InvalidInput, "conflict found")),
    500 => Err(Error::new(ErrorKind::InvalidInput, "interal server error")),
     _  => unreachable!()
  }
}

#[doc(hidden)]
pub struct Body<'a> {
 read: &'a mut Box<&'a mut Read>,
 size: u64
}

impl<'a> Body<'a> {
  /// Create a new body instance
  pub fn new(read: &'a mut Box<&'a mut Read>, size: u64) -> Body<'a> {
    Body { read: read, size: size }
  }
}

/// Primary interface for communicating with docker daemon
pub trait Transport {
  fn request(&mut self, method: Method, endpoint: &str, body: Option<Body>) -> Result<String> {
    let mut res = match self.stream(method, endpoint, body) {
      Ok(r) => r,
      Err(e) => panic!("failed request {:?}", e)
    };
    let mut body = String::new();
    res.read_to_string(&mut body).map(|_| body)
  }

  fn stream(&mut self, method: Method, endpoint: &str, body: Option<Body>) -> Result<Box<Read>>;
}

impl Transport for UnixStream {
  fn stream(&mut self, method: Method, endpoint: &str, body: Option<Body>) -> Result<Box<Read>> {
    let method_str = match method {
      Method::Put    => "PUT",
      Method::Post   => "POST",
      Method::Delete => "DELETE",
               _     => "GET"
    };
    let req = format!("{} {} HTTP/1.0\r\n\r\n", method_str, endpoint);
    try!(self.write_all(req.as_bytes()));
    // read the body -- https://github.com/hyperium/hyper/blob/06d072bca1b4af3507af370cbd0ca2ac8f64fc00/src/client/response.rs#L36-L74
    let cloned = try!(self.try_clone());
    let mut stream = BufReader::new(cloned);
    let res = parse_response(&mut stream).unwrap();
    match res.subject {
      RawStatus(200, _) | RawStatus(201, _) =>
        Ok(Box::new(EofReader(stream))),
      RawStatus(204, _) =>
        Ok(Box::new(BufReader::new("".as_bytes()))),
      RawStatus(status, _) =>
        lift_status_err(status)
    }
  }
}

impl Transport for (Client, String) {
  fn stream(&mut self, method: Method, endpoint: &str, body: Option<Body>) -> Result<Box<Read>> {
    let uri = format!("{}{}", self.1, endpoint);
    let req = match method {
      Method::Put    => self.0.put(&uri[..]),
      Method::Post   => self.0.post(&uri[..]),
      Method::Delete => self.0.delete(&uri[..]),
                   _ => self.0.get(&uri[..])
    };
    let embodied = match body {
      Some(Body { read: r, size: l }) => {
        let reader: &mut Read = *r.deref_mut();
        let content_type: Mime = Mime(Application, Json, vec![(Attr::Charset, Value::Utf8)]);
        req.header(ContentType(content_type)).body(client::Body::SizedBody(reader, l))
      },
      _ => req
    };
    let res = match embodied.send() {
      Ok(r) => r,
      Err(e) => panic!("failed request {:?}", e)
    };
    println!("status {:?}", res.status);
    match res.status {
      StatusCode::Ok | StatusCode::Created =>
        Ok(Box::new(res)),
      StatusCode::NoContent =>
        Ok(Box::new(BufReader::new("".as_bytes()))),
      status =>
        lift_status_err(status.to_u16())
    }
  }
}
<commit_msg>handle 101<commit_after>//! Transports for communicating with the docker daemon

extern crate hyper;
extern crate mime;
extern crate unix_socket;

use hyper::Client;
use hyper::client;
use self::hyper::buffer::BufReader;
use self::hyper::http::{ parse_response, RawStatus };
use self::hyper::http::HttpReader::EofReader;
use self::hyper::header::ContentType;
use self::hyper::status::StatusCode;
use hyper::method::Method;
use self::mime::{ Attr, Mime, Value };
use self::mime::TopLevel::Application;
use self::mime::SubLevel::Json;
use std::ops::DerefMut;
use std::io::{ Error, ErrorKind, Read, Result, Write };
use unix_socket::UnixStream;

fn lift_status_err(status: u16) -> Result<Box<Read>> {
  match status {
    400 => Err(Error::new(ErrorKind::InvalidInput, "bad parameter")),
    404 => Err(Error::new(ErrorKind::InvalidInput, "not found")),
    406 => Err(Error::new(ErrorKind::InvalidInput, "not acceptable")),
    409 => Err(Error::new(ErrorKind::InvalidInput, "conflict found")),
    500 => Err(Error::new(ErrorKind::InvalidInput, "interal server error")),
     _  => unreachable!()
  }
}

#[doc(hidden)]
pub struct Body<'a> {
 read: &'a mut Box<&'a mut Read>,
 size: u64
}

impl<'a> Body<'a> {
  /// Create a new body instance
  pub fn new(read: &'a mut Box<&'a mut Read>, size: u64) -> Body<'a> {
    Body { read: read, size: size }
  }
}

/// Primary interface for communicating with docker daemon
pub trait Transport {
  fn request(&mut self, method: Method, endpoint: &str, body: Option<Body>) -> Result<String> {
    let mut res = match self.stream(method, endpoint, body) {
      Ok(r) => r,
      Err(e) => panic!("failed request {:?}", e)
    };
    let mut body = String::new();
    res.read_to_string(&mut body).map(|_| body)
  }

  fn stream(&mut self, method: Method, endpoint: &str, body: Option<Body>) -> Result<Box<Read>>;
}

impl Transport for UnixStream {
  fn stream(&mut self, method: Method, endpoint: &str, body: Option<Body>) -> Result<Box<Read>> {
    let method_str = match method {
      Method::Put    => "PUT",
      Method::Post   => "POST",
      Method::Delete => "DELETE",
               _     => "GET"
    };
    let req = format!("{} {} HTTP/1.0\r\n\r\n", method_str, endpoint);
    try!(self.write_all(req.as_bytes()));
    // read the body -- https://github.com/hyperium/hyper/blob/06d072bca1b4af3507af370cbd0ca2ac8f64fc00/src/client/response.rs#L36-L74
    let cloned = try!(self.try_clone());
    let mut stream = BufReader::new(cloned);
    let res = parse_response(&mut stream).unwrap();
    match res.subject {
      RawStatus(200, _) | RawStatus(201, _) | RawStatus(101, _) =>
        Ok(Box::new(EofReader(stream))),
      RawStatus(204, _) =>
        Ok(Box::new(BufReader::new("".as_bytes()))),
      RawStatus(status, _) =>
        lift_status_err(status)
    }
  }
}

impl Transport for (Client, String) {
  fn stream(&mut self, method: Method, endpoint: &str, body: Option<Body>) -> Result<Box<Read>> {
    let uri = format!("{}{}", self.1, endpoint);
    let req = match method {
      Method::Put    => self.0.put(&uri[..]),
      Method::Post   => self.0.post(&uri[..]),
      Method::Delete => self.0.delete(&uri[..]),
                   _ => self.0.get(&uri[..])
    };
    let embodied = match body {
      Some(Body { read: r, size: l }) => {
        let reader: &mut Read = *r.deref_mut();
        let content_type: Mime = Mime(Application, Json, vec![(Attr::Charset, Value::Utf8)]);
        req.header(ContentType(content_type)).body(client::Body::SizedBody(reader, l))
      },
      _ => req
    };
    let res = match embodied.send() {
      Ok(r) => r,
      Err(e) => panic!("failed request {:?}", e)
    };
    println!("status {:?}", res.status);
    match res.status {
      StatusCode::Ok | StatusCode::Created | StatusCode::SwitchingProtocols =>
        Ok(Box::new(res)),
      StatusCode::NoContent =>
        Ok(Box::new(BufReader::new("".as_bytes()))),
      status =>
        lift_status_err(status.to_u16())
    }
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Support for implementing transport layer protocols
//!
//! The transport module provides the ability to send and receive packets at
//! the transport layer using IPv4 or IPv6. It also enables layer 3 networking
//! for specific transport protocols, using IPv4 only.
//!
//! Note that this is limited by operating system support - for example, on OS
//! X and FreeBSD, it is impossible to implement protocols which are already
//! implemented in the kernel such as TCP and UDP.

#![macro_use]

extern crate libc;

use self::TransportProtocol::{Ipv4, Ipv6};
use self::TransportChannelType::{Layer3, Layer4};

use std::io;
use std::io::Error;
use std::iter::repeat;
use std::net::{self, IpAddr};
use std::mem;
use std::sync::Arc;

use packet::Packet;
use packet::ip::IpNextHeaderProtocol;
use packet::ipv4::Ipv4Packet;
use packet::udp::UdpPacket;

use internal;
use sockets;

/// Represents a transport layer protocol
#[derive(Clone, Copy)]
pub enum TransportProtocol {
    /// Represents a transport protocol built on top of IPv4
    Ipv4(IpNextHeaderProtocol),
    /// Represents a transport protocol built on top of IPv6
    Ipv6(IpNextHeaderProtocol),
}

/// Type of transport channel to present
#[derive(Clone, Copy)]
pub enum TransportChannelType {
    /// The application will send and receive transport layer packets
    Layer4(TransportProtocol),
    /// The application will send and receive IPv4 packets, with the specified transport protocol
    Layer3(IpNextHeaderProtocol),
}

/// Structure used for sending at the transport layer. Should be created with transport_channel()
pub struct TransportSender {
    socket: Arc<internal::FileDesc>,
    _channel_type: TransportChannelType,
}

/// Structure used for receiving at the transport layer. Should be created with transport_channel()
pub struct TransportReceiver {
    socket: Arc<internal::FileDesc>,
    buffer: Vec<u8>,
    channel_type: TransportChannelType,
}

/// Create a new (TransportSender, TransportReceiver) pair
///
/// This allows for sending and receiving packets at the transport layer. The buffer size should be
/// large enough to handle the largest packet you wish to receive.
///
/// The channel type specifies what layer to send and receive packets at, and the transport
/// protocol you wish to implement. For example, `Layer4(Ipv4(IpNextHeaderProtocols::Udp))` would
/// allow sending and receiving UDP packets using IPv4; whereas Layer3(IpNextHeaderProtocols::Udp)
/// would include the IPv4 Header in received values, and require manual construction of an IP
/// header when sending.
pub fn transport_channel(buffer_size: usize,
                         channel_type: TransportChannelType)
    -> io::Result<(TransportSender, TransportReceiver)> {
    use std::net;

    // This hack makes sure that winsock is initialised
    let _ = {
        let ip = net::Ipv4Addr::new(255, 255, 255, 255);
        let sockaddr = net::SocketAddr::V4(net::SocketAddrV4::new(ip, 0));

        net::UdpSocket::bind(sockaddr)
    };

    let socket = unsafe {
        match channel_type {
            Layer4(Ipv4(IpNextHeaderProtocol(proto))) | Layer3(IpNextHeaderProtocol(proto)) =>
                sockets::socket(sockets::AF_INET, sockets::SOCK_RAW, proto as libc::c_int),
            Layer4(Ipv6(IpNextHeaderProtocol(proto))) =>
                sockets::socket(sockets::AF_INET6, sockets::SOCK_RAW, proto as libc::c_int),
        }
    };
    if socket == sockets::INVALID_SOCKET {
        return Err(Error::last_os_error());
    }

    if match channel_type {
        Layer3(_) | Layer4(Ipv4(_)) => true,
        _ => false,
    } {
        let hincl: libc::c_int = match channel_type {
            Layer4(..) => 0,
            _ => 1,
        };
        let res = unsafe {
            sockets::setsockopt(socket,
                                sockets::IPPROTO_IP,
                                sockets::IP_HDRINCL,
                                (&hincl as *const libc::c_int) as sockets::Buf,
                                mem::size_of::<libc::c_int>() as sockets::SockLen)
        };
        if res == -1 {
            let err = Error::last_os_error();
            unsafe {
                sockets::close(socket);
            }
            return Err(err);
        }
    }

    let sock = Arc::new(internal::FileDesc { fd: socket });
    let sender = TransportSender {
        socket: sock.clone(),
        _channel_type: channel_type,
    };
    let receiver = TransportReceiver {
        socket: sock,
        buffer: repeat(0u8).take(buffer_size).collect(),
        channel_type: channel_type,
    };

    Ok((sender, receiver))
}

impl TransportSender {
    fn send<T: Packet>(&mut self, packet: T, dst: IpAddr) -> io::Result<usize> {
        let mut caddr = unsafe { mem::zeroed() };
        let sockaddr = match dst {
            IpAddr::V4(ip_addr) => net::SocketAddr::V4(net::SocketAddrV4::new(ip_addr, 0)),
            IpAddr::V6(ip_addr) => net::SocketAddr::V6(net::SocketAddrV6::new(ip_addr, 0, 0, 0)),
        };
        let slen = internal::addr_to_sockaddr(sockaddr, &mut caddr);
        let caddr_ptr = (&caddr as *const sockets::SockAddrStorage) as *const sockets::SockAddr;

        internal::send_to(self.socket.fd, packet.packet(), caddr_ptr, slen)
    }

    /// Send a packet to the provided destination
    #[inline]
    pub fn send_to<T: Packet>(&mut self, packet: T, destination: IpAddr) -> io::Result<usize> {
        self.send_to_impl(packet, destination)
    }

    #[cfg(all(not(target_os = "freebsd"), not(target_os = "macos")))]
    fn send_to_impl<T: Packet>(&mut self, packet: T, dst: IpAddr) -> io::Result<usize> {
        self.send(packet, dst)
    }

    #[cfg(any(target_os = "freebsd", target_os = "macos"))]
    fn send_to_impl<T: Packet>(&mut self, packet: T, dst: IpAddr) -> io::Result<usize> {
        use packet::MutablePacket;
        use packet::ipv4::MutableIpv4Packet;

        // FreeBSD and OS X expect total length and fragment offset fields of IPv4
        // packets to be in host byte order rather than network byte order. Fragment offset is the
        // ip_off field in the ip struct and contains both the offset and the three flag bits.
        // See `man 4 ip`/Raw IP Sockets)
        if let Layer3(_) = self._channel_type {
            let mut mut_slice: Vec<u8> = repeat(0u8).take(packet.packet().len()).collect();

            let mut new_packet = MutableIpv4Packet::new(&mut mut_slice[..]).unwrap();
            new_packet.clone_from(&packet);
            let length = new_packet.get_total_length().to_be();
            new_packet.set_total_length(length);
            {
                // Turn fragment offset into host order
                let d = new_packet.packet_mut();
                let host_order = u16::from_be((d[6] as u16) << 8 | d[7] as u16);
                d[6] = (host_order >> 8) as u8;
                d[7] = host_order as u8;
            }
            return self.send(new_packet, dst);
        }

        self.send(packet, dst)
    }
}

/// Create an iterator for some packet type.
///
/// Usage:
/// ```
/// transport_channel_iterator!(Ipv4Packet, // Type to iterate over
///                             Ipv4TransportChannelIterator, // Name for iterator struct
///                             ipv4_packet_iter) // Name of function to create iterator
/// ```
#[macro_export]
macro_rules! transport_channel_iterator {
    ($ty:ident, $iter:ident, $func:ident) => (
        /// An iterator over packets of type $ty
        pub struct $iter<'a> {
            tr: &'a mut TransportReceiver
        }
        /// Return a packet iterator with packets of type $ty for some transport receiver
        pub fn $func(tr: &mut TransportReceiver) -> $iter {
            $iter {
                tr: tr
            }
        }
        impl<'a> $iter<'a> {
            /// Get the next ($ty, IpAddr) pair for the given channel
            pub fn next(&mut self) -> io::Result<($ty, IpAddr)> {
                let mut caddr: sockets::SockAddrStorage = unsafe { mem::zeroed() };
                let res = internal::recv_from(self.tr.socket.fd,
                                              &mut self.tr.buffer[..],
                                              &mut caddr);

                let offset = match self.tr.channel_type {
                    Layer4(Ipv4(_)) => {
                        let ip_header = Ipv4Packet::new(&self.tr.buffer[..]).unwrap();

                        ip_header.get_header_length() as usize * 4usize
                    },
                    Layer3(_) => {
                        fixup_packet(&mut self.tr.buffer[..]);

                        0
                    },
                    _ => 0
                };
                return match res {
                    Ok(len) => {
                        let packet = $ty::new(&self.tr.buffer[offset..len]).unwrap();
                        let addr = internal::sockaddr_to_addr(
                                        &caddr,
                                        mem::size_of::<sockets::SockAddrStorage>()
                                   );
                        let ip = match addr.unwrap() {
                            net::SocketAddr::V4(sa) => IpAddr::V4(*sa.ip()),
                            net::SocketAddr::V6(sa) => IpAddr::V6(*sa.ip()),
                        };
                        Ok((packet, ip))
                    },
                    Err(e) => Err(e),
                };

                #[cfg(any(target_os = "freebsd", target_os = "macos"))]
                fn fixup_packet(buffer: &mut [u8]) {
                    use packet::ipv4::MutableIpv4Packet;

                    let buflen = buffer.len();
                    let mut new_packet = MutableIpv4Packet::new(buffer).unwrap();

                    let length = u16::from_be(new_packet.get_total_length());
                    new_packet.set_total_length(length);

                    // OS X does this awesome thing where it removes the header length
                    // from the total length sometimes.
                    let length = new_packet.get_total_length() as usize +
                                 (new_packet.get_header_length() as usize * 4usize);
                    if length == buflen {
                        new_packet.set_total_length(length as u16)
                    }

                    let offset = u16::from_be(new_packet.get_fragment_offset());
                    new_packet.set_fragment_offset(offset);
                }

                #[cfg(all(not(target_os = "freebsd"), not(target_os = "macos")))]
                fn fixup_packet(_buffer: &mut [u8]) {}
            }
        }
    )
}

transport_channel_iterator!(Ipv4Packet,
                            Ipv4TransportChannelIterator,
                            ipv4_packet_iter);

transport_channel_iterator!(UdpPacket,
                            UdpTransportChannelIterator,
                            udp_packet_iter);
<commit_msg>Add tcp_packet_iter function.<commit_after>// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Support for implementing transport layer protocols
//!
//! The transport module provides the ability to send and receive packets at
//! the transport layer using IPv4 or IPv6. It also enables layer 3 networking
//! for specific transport protocols, using IPv4 only.
//!
//! Note that this is limited by operating system support - for example, on OS
//! X and FreeBSD, it is impossible to implement protocols which are already
//! implemented in the kernel such as TCP and UDP.

#![macro_use]

extern crate libc;

use self::TransportProtocol::{Ipv4, Ipv6};
use self::TransportChannelType::{Layer3, Layer4};

use std::io;
use std::io::Error;
use std::iter::repeat;
use std::net::{self, IpAddr};
use std::mem;
use std::sync::Arc;

use packet::Packet;
use packet::ip::IpNextHeaderProtocol;
use packet::ipv4::Ipv4Packet;
use packet::udp::UdpPacket;
use packet::tcp::TcpPacket;

use internal;
use sockets;

/// Represents a transport layer protocol
#[derive(Clone, Copy)]
pub enum TransportProtocol {
    /// Represents a transport protocol built on top of IPv4
    Ipv4(IpNextHeaderProtocol),
    /// Represents a transport protocol built on top of IPv6
    Ipv6(IpNextHeaderProtocol),
}

/// Type of transport channel to present
#[derive(Clone, Copy)]
pub enum TransportChannelType {
    /// The application will send and receive transport layer packets
    Layer4(TransportProtocol),
    /// The application will send and receive IPv4 packets, with the specified transport protocol
    Layer3(IpNextHeaderProtocol),
}

/// Structure used for sending at the transport layer. Should be created with transport_channel()
pub struct TransportSender {
    socket: Arc<internal::FileDesc>,
    _channel_type: TransportChannelType,
}

/// Structure used for receiving at the transport layer. Should be created with transport_channel()
pub struct TransportReceiver {
    socket: Arc<internal::FileDesc>,
    buffer: Vec<u8>,
    channel_type: TransportChannelType,
}

/// Create a new (TransportSender, TransportReceiver) pair
///
/// This allows for sending and receiving packets at the transport layer. The buffer size should be
/// large enough to handle the largest packet you wish to receive.
///
/// The channel type specifies what layer to send and receive packets at, and the transport
/// protocol you wish to implement. For example, `Layer4(Ipv4(IpNextHeaderProtocols::Udp))` would
/// allow sending and receiving UDP packets using IPv4; whereas Layer3(IpNextHeaderProtocols::Udp)
/// would include the IPv4 Header in received values, and require manual construction of an IP
/// header when sending.
pub fn transport_channel(buffer_size: usize,
                         channel_type: TransportChannelType)
    -> io::Result<(TransportSender, TransportReceiver)> {
    use std::net;

    // This hack makes sure that winsock is initialised
    let _ = {
        let ip = net::Ipv4Addr::new(255, 255, 255, 255);
        let sockaddr = net::SocketAddr::V4(net::SocketAddrV4::new(ip, 0));

        net::UdpSocket::bind(sockaddr)
    };

    let socket = unsafe {
        match channel_type {
            Layer4(Ipv4(IpNextHeaderProtocol(proto))) | Layer3(IpNextHeaderProtocol(proto)) =>
                sockets::socket(sockets::AF_INET, sockets::SOCK_RAW, proto as libc::c_int),
            Layer4(Ipv6(IpNextHeaderProtocol(proto))) =>
                sockets::socket(sockets::AF_INET6, sockets::SOCK_RAW, proto as libc::c_int),
        }
    };
    if socket == sockets::INVALID_SOCKET {
        return Err(Error::last_os_error());
    }

    if match channel_type {
        Layer3(_) | Layer4(Ipv4(_)) => true,
        _ => false,
    } {
        let hincl: libc::c_int = match channel_type {
            Layer4(..) => 0,
            _ => 1,
        };
        let res = unsafe {
            sockets::setsockopt(socket,
                                sockets::IPPROTO_IP,
                                sockets::IP_HDRINCL,
                                (&hincl as *const libc::c_int) as sockets::Buf,
                                mem::size_of::<libc::c_int>() as sockets::SockLen)
        };
        if res == -1 {
            let err = Error::last_os_error();
            unsafe {
                sockets::close(socket);
            }
            return Err(err);
        }
    }

    let sock = Arc::new(internal::FileDesc { fd: socket });
    let sender = TransportSender {
        socket: sock.clone(),
        _channel_type: channel_type,
    };
    let receiver = TransportReceiver {
        socket: sock,
        buffer: repeat(0u8).take(buffer_size).collect(),
        channel_type: channel_type,
    };

    Ok((sender, receiver))
}

impl TransportSender {
    fn send<T: Packet>(&mut self, packet: T, dst: IpAddr) -> io::Result<usize> {
        let mut caddr = unsafe { mem::zeroed() };
        let sockaddr = match dst {
            IpAddr::V4(ip_addr) => net::SocketAddr::V4(net::SocketAddrV4::new(ip_addr, 0)),
            IpAddr::V6(ip_addr) => net::SocketAddr::V6(net::SocketAddrV6::new(ip_addr, 0, 0, 0)),
        };
        let slen = internal::addr_to_sockaddr(sockaddr, &mut caddr);
        let caddr_ptr = (&caddr as *const sockets::SockAddrStorage) as *const sockets::SockAddr;

        internal::send_to(self.socket.fd, packet.packet(), caddr_ptr, slen)
    }

    /// Send a packet to the provided destination
    #[inline]
    pub fn send_to<T: Packet>(&mut self, packet: T, destination: IpAddr) -> io::Result<usize> {
        self.send_to_impl(packet, destination)
    }

    #[cfg(all(not(target_os = "freebsd"), not(target_os = "macos")))]
    fn send_to_impl<T: Packet>(&mut self, packet: T, dst: IpAddr) -> io::Result<usize> {
        self.send(packet, dst)
    }

    #[cfg(any(target_os = "freebsd", target_os = "macos"))]
    fn send_to_impl<T: Packet>(&mut self, packet: T, dst: IpAddr) -> io::Result<usize> {
        use packet::MutablePacket;
        use packet::ipv4::MutableIpv4Packet;

        // FreeBSD and OS X expect total length and fragment offset fields of IPv4
        // packets to be in host byte order rather than network byte order. Fragment offset is the
        // ip_off field in the ip struct and contains both the offset and the three flag bits.
        // See `man 4 ip`/Raw IP Sockets)
        if let Layer3(_) = self._channel_type {
            let mut mut_slice: Vec<u8> = repeat(0u8).take(packet.packet().len()).collect();

            let mut new_packet = MutableIpv4Packet::new(&mut mut_slice[..]).unwrap();
            new_packet.clone_from(&packet);
            let length = new_packet.get_total_length().to_be();
            new_packet.set_total_length(length);
            {
                // Turn fragment offset into host order
                let d = new_packet.packet_mut();
                let host_order = u16::from_be((d[6] as u16) << 8 | d[7] as u16);
                d[6] = (host_order >> 8) as u8;
                d[7] = host_order as u8;
            }
            return self.send(new_packet, dst);
        }

        self.send(packet, dst)
    }
}

/// Create an iterator for some packet type.
///
/// Usage:
/// ```
/// transport_channel_iterator!(Ipv4Packet, // Type to iterate over
///                             Ipv4TransportChannelIterator, // Name for iterator struct
///                             ipv4_packet_iter) // Name of function to create iterator
/// ```
#[macro_export]
macro_rules! transport_channel_iterator {
    ($ty:ident, $iter:ident, $func:ident) => (
        /// An iterator over packets of type $ty
        pub struct $iter<'a> {
            tr: &'a mut TransportReceiver
        }
        /// Return a packet iterator with packets of type $ty for some transport receiver
        pub fn $func(tr: &mut TransportReceiver) -> $iter {
            $iter {
                tr: tr
            }
        }
        impl<'a> $iter<'a> {
            /// Get the next ($ty, IpAddr) pair for the given channel
            pub fn next(&mut self) -> io::Result<($ty, IpAddr)> {
                let mut caddr: sockets::SockAddrStorage = unsafe { mem::zeroed() };
                let res = internal::recv_from(self.tr.socket.fd,
                                              &mut self.tr.buffer[..],
                                              &mut caddr);

                let offset = match self.tr.channel_type {
                    Layer4(Ipv4(_)) => {
                        let ip_header = Ipv4Packet::new(&self.tr.buffer[..]).unwrap();

                        ip_header.get_header_length() as usize * 4usize
                    },
                    Layer3(_) => {
                        fixup_packet(&mut self.tr.buffer[..]);

                        0
                    },
                    _ => 0
                };
                return match res {
                    Ok(len) => {
                        let packet = $ty::new(&self.tr.buffer[offset..len]).unwrap();
                        let addr = internal::sockaddr_to_addr(
                                        &caddr,
                                        mem::size_of::<sockets::SockAddrStorage>()
                                   );
                        let ip = match addr.unwrap() {
                            net::SocketAddr::V4(sa) => IpAddr::V4(*sa.ip()),
                            net::SocketAddr::V6(sa) => IpAddr::V6(*sa.ip()),
                        };
                        Ok((packet, ip))
                    },
                    Err(e) => Err(e),
                };

                #[cfg(any(target_os = "freebsd", target_os = "macos"))]
                fn fixup_packet(buffer: &mut [u8]) {
                    use packet::ipv4::MutableIpv4Packet;

                    let buflen = buffer.len();
                    let mut new_packet = MutableIpv4Packet::new(buffer).unwrap();

                    let length = u16::from_be(new_packet.get_total_length());
                    new_packet.set_total_length(length);

                    // OS X does this awesome thing where it removes the header length
                    // from the total length sometimes.
                    let length = new_packet.get_total_length() as usize +
                                 (new_packet.get_header_length() as usize * 4usize);
                    if length == buflen {
                        new_packet.set_total_length(length as u16)
                    }

                    let offset = u16::from_be(new_packet.get_fragment_offset());
                    new_packet.set_fragment_offset(offset);
                }

                #[cfg(all(not(target_os = "freebsd"), not(target_os = "macos")))]
                fn fixup_packet(_buffer: &mut [u8]) {}
            }
        }
    )
}

transport_channel_iterator!(Ipv4Packet,
                            Ipv4TransportChannelIterator,
                            ipv4_packet_iter);

transport_channel_iterator!(UdpPacket,
                            UdpTransportChannelIterator,
                            udp_packet_iter);

transport_channel_iterator!(TcpPacket,
                            TcpTransportChannelIterator,
                            tcp_packet_iter);

<|endoftext|>


<commit_before>
use vertex::{RawVertex, Vertex};
use edge::{Edge, EdgeProxy};
use graph::TraversableToVertex;
// define a traversal as a series of stages

struct VertexVisit {
    vertex: Vertex
}

struct EdgeVisit {
    edge: EdgeProxy
}

enum TraversalStage {

}

#[derive(Clone)]
pub enum GraphElement {
    RawVertex(Vertex),
    Edge(EdgeProxy)
}

// used to track a single graph traversal
// will be used in conjunction with a GraphQuery

pub struct Path {
    path: Vec<GraphElement>
}

impl Path {
    pub fn new(vertex: Vertex) -> Path {
		Path{path:vec![GraphElement::RawVertex(vertex)]}
    }
	pub fn new_empty() -> Path {
		Path{path:vec![]}
	}

	/*
	takes the current path and a vector of elements
	and returns a vector of new paths,
	each of which extends the existing path
	 */
	pub fn permute(&self, elements_to_add: &[GraphElement]) -> Vec<Path> {
		let mut result: Vec<Path> = Vec::new();
		for element in elements_to_add.iter() {
			// construct a new path
			let mut p = self.clone();
			p.path.push(element.clone());
			result.push(p);
		}

		result
	}

}

impl Clone for Path {
	fn clone(&self) -> Path {
		Path::new_empty()
	}

	fn clone_from(&mut self, source: &Self ) {

	}
}

pub struct GraphQuery {
	// many paths
    pub paths: Vec<Path>
}

impl GraphQuery {
    pub fn new(vertices: Vec<Vertex>) -> GraphQuery {
        // create a new path for each proxy, add the proxy
        let mut paths = Vec::new();
        for p in vertices {
			let mut path = Path::new(p);
            paths.push(path)
        }
        GraphQuery{paths:paths}
    }

    pub fn empty() -> GraphQuery {
        // return an empty graph query
        GraphQuery{paths:Vec::new()}
    }

	pub fn get_paths(&self) -> &Vec<Path> {
		&self.paths
	}
	pub fn push(&mut self, path:Path) {
		self.paths.push(path)
	}

	/*
	generic mapper for our queries
	future this may use worker threads to perform
	traversals
	 */
    fn full_map<F: Fn(&Path) -> Vec<Path>>(&self, closure: F) -> GraphQuery  {
        let mut result = GraphQuery::empty(); // result
		for x in self.paths.iter() {
			let mut tmp = closure(x);
			result.paths.append(&mut tmp)
		}
		result
    }

	/*
	accepts a proxy and a closure, per
	takes the last element
	 */
	fn map<F: Fn(&GraphElement) -> Vec<GraphElement>>(&self, closure: F)
		-> GraphQuery {
		let mut result = GraphQuery::empty();
		for path in self.paths.iter() {
			// apply the closure to the last element in each map
			// if nothing is returned, we should not use the path anymore
			let element = path.path.last().unwrap();
			let mut tmp = closure(element);
			let new_path = path.clone();
			result.push(new_path);
		}

		result

	}

	/*

	 */
    pub fn outV(&self) -> GraphQuery {
		let f = |path: &Path| {
			println!("applying outV");
			let mut result : Vec<Path> = Vec::new();
			//take the final element in the path
			let element = path.path.last().unwrap();

			match element {
				&GraphElement::RawVertex(ref v) => {
					println!("matched vertex");
					let mut tmp = v.outV();
					for vertex in tmp {
						println!("adding path based on vertex match");
						let new_path = path.clone();
						result.push(new_path);
					}
				},
				&GraphElement::Edge(ref e) => {

				}
			}
			// apply outV

			result
		};
		self.full_map(f)
    }

//	pub fn inV(&self) -> GraphQuery {
//		let g = GraphQuery::empty();
//		let f = |element: &GraphElement| {
//			element.inV()
//		};
//		self.map(f)
//	}
}
<commit_msg>removed unused structs<commit_after>
use vertex::{RawVertex, Vertex};
use edge::{Edge, EdgeProxy};
use graph::TraversableToVertex;
// define a traversal as a series of stages

enum TraversalStage {

}

#[derive(Clone)]
pub enum GraphElement {
    RawVertex(Vertex),
    Edge(EdgeProxy)
}

// used to track a single graph traversal
// will be used in conjunction with a GraphQuery

pub struct Path {
    path: Vec<GraphElement>
}

impl Path {
    pub fn new(vertex: Vertex) -> Path {
		Path{path:vec![GraphElement::RawVertex(vertex)]}
    }
	pub fn new_empty() -> Path {
		Path{path:vec![]}
	}

	/*
	takes the current path and a vector of elements
	and returns a vector of new paths,
	each of which extends the existing path
	 */
	pub fn permute(&self, elements_to_add: &[GraphElement]) -> Vec<Path> {
		let mut result: Vec<Path> = Vec::new();
		for element in elements_to_add.iter() {
			// construct a new path
			let mut p = self.clone();
			p.path.push(element.clone());
			result.push(p);
		}

		result
	}

}

impl Clone for Path {
	fn clone(&self) -> Path {
		Path::new_empty()
	}

	fn clone_from(&mut self, source: &Self ) {

	}
}

pub struct GraphQuery {
	// many paths
    pub paths: Vec<Path>
}

impl GraphQuery {
    pub fn new(vertices: Vec<Vertex>) -> GraphQuery {
        // create a new path for each proxy, add the proxy
        let mut paths = Vec::new();
        for p in vertices {
			let mut path = Path::new(p);
            paths.push(path)
        }
        GraphQuery{paths:paths}
    }

    pub fn empty() -> GraphQuery {
        // return an empty graph query
        GraphQuery{paths:Vec::new()}
    }

	pub fn get_paths(&self) -> &Vec<Path> {
		&self.paths
	}
	pub fn push(&mut self, path:Path) {
		self.paths.push(path)
	}

	/*
	generic mapper for our queries
	future this may use worker threads to perform
	traversals
	 */
    fn full_map<F: Fn(&Path) -> Vec<Path>>(&self, closure: F) -> GraphQuery  {
        let mut result = GraphQuery::empty(); // result
		for x in self.paths.iter() {
			let mut tmp = closure(x);
			result.paths.append(&mut tmp)
		}
		result
    }

	/*
	accepts a proxy and a closure, per
	takes the last element
	 */
	fn map<F: Fn(&GraphElement) -> Vec<GraphElement>>(&self, closure: F)
		-> GraphQuery {
		let mut result = GraphQuery::empty();
		for path in self.paths.iter() {
			// apply the closure to the last element in each map
			// if nothing is returned, we should not use the path anymore
			let element = path.path.last().unwrap();
			let mut tmp = closure(element);
			let new_path = path.clone();
			result.push(new_path);
		}
		result
	}

	/*
        TODO: rewrite to use map()
	 */
    pub fn outV(&self) -> GraphQuery {
		let f = |path: &Path| {
			println!("applying outV");
			let mut result : Vec<Path> = Vec::new();
			//take the final element in the path
			let element = path.path.last().unwrap();

			match element {
				&GraphElement::RawVertex(ref v) => {
					println!("matched vertex");
					let mut tmp = v.outV();
					for vertex in tmp {
						println!("adding path based on vertex match");
						let new_path = path.clone();
						result.push(new_path);
					}
				},
				&GraphElement::Edge(ref e) => {

				}
			}
			// apply outV

			result
		};
		self.full_map(f)
    }

//	pub fn inV(&self) -> GraphQuery {
//		let g = GraphQuery::empty();
//		let f = |element: &GraphElement| {
//			element.inV()
//		};
//		self.map(f)
//	}
}
<|endoftext|>


<commit_before>// Copyright 2019 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(dead_code)]
use crate::{util::LazyUsize, Error};
use core::{num::NonZeroU32, ptr::NonNull};

cfg_if! {
    if #[cfg(any(target_os = "netbsd", target_os = "openbsd", target_os = "android"))] {
        use libc::__errno as errno_location;
    } else if #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "redox"))] {
        use libc::__errno_location as errno_location;
    } else if #[cfg(any(target_os = "solaris", target_os = "illumos"))] {
        use libc::___errno as errno_location;
    } else if #[cfg(any(target_os = "macos", target_os = "freebsd"))] {
        use libc::__error as errno_location;
    } else if #[cfg(target_os = "haiku")] {
        use libc::_errnop as errno_location;
    }
}

cfg_if! {
    if #[cfg(target_os = "vxworks")] {
        use libc::errnoGet as get_errno;
    } else if #[cfg(target_os = "dragonfly")] {
        // Until rust-lang/rust#29594 is stable, we cannot get the errno value
        // on DragonFlyBSD. So we just return an out-of-range errno.
        unsafe fn get_errno() -> libc::c_int { -1 }
    } else {
        unsafe fn get_errno() -> libc::c_int { *errno_location() }
    }
}

pub fn last_os_error() -> Error {
    let errno = unsafe { get_errno() };
    if errno > 0 {
        Error::from(NonZeroU32::new(errno as u32).unwrap())
    } else {
        Error::ERRNO_NOT_POSITIVE
    }
}

// Fill a buffer by repeatedly invoking a system call. The `sys_fill` function:
//   - should return -1 and set errno on failure
//   - should return the number of bytes written on success
pub fn sys_fill_exact(
    mut buf: &mut [u8],
    sys_fill: impl Fn(&mut [u8]) -> libc::ssize_t,
) -> Result<(), Error> {
    while !buf.is_empty() {
        let res = sys_fill(buf);
        if res < 0 {
            let err = last_os_error();
            // We should try again if the call was interrupted.
            if err.raw_os_error() != Some(libc::EINTR) {
                return Err(err);
            }
        } else {
            // We don't check for EOF (ret = 0) as the data we are reading
            // should be an infinite stream of random bytes.
            buf = &mut buf[(res as usize)..];
        }
    }
    Ok(())
}

// A "weak" binding to a C function that may or may not be present at runtime.
// Used for supporting newer OS features while still building on older systems.
// F must be a function pointer of type `unsafe extern "C" fn`. Based off of the
// weak! macro in libstd.
pub struct Weak {
    name: &'static str,
    addr: LazyUsize,
}

impl Weak {
    // Construct a binding to a C function with a given name. This function is
    // unsafe because `name` _must_ be null terminated.
    pub const unsafe fn new(name: &'static str) -> Self {
        Self {
            name,
            addr: LazyUsize::new(),
        }
    }

    // Return a function pointer if present at runtime. Otherwise, return null.
    pub fn ptr(&self) -> Option<NonNull<libc::c_void>> {
        let addr = self.addr.unsync_init(|| unsafe {
            libc::dlsym(libc::RTLD_DEFAULT, self.name.as_ptr() as *const _) as usize
        });
        NonNull::new(addr as *mut _)
    }
}

cfg_if! {
    if #[cfg(any(target_os = "linux", target_os = "emscripten"))] {
        use libc::open64 as open;
    } else {
        use libc::open;
    }
}

// SAFETY: path must be null terminated, FD must be manually closed.
pub unsafe fn open_readonly(path: &str) -> Result<libc::c_int, Error> {
    debug_assert_eq!(path.as_bytes().last(), Some(&0));
    let fd = open(path.as_ptr() as *const _, libc::O_RDONLY | libc::O_CLOEXEC);
    if fd < 0 {
        return Err(last_os_error());
    }
    // O_CLOEXEC works on all Unix targets except for older Linux kernels (pre
    // 2.6.23), so we also use an ioctl to make sure FD_CLOEXEC is set.
    #[cfg(target_os = "linux")]
    libc::ioctl(fd, libc::FIOCLEX);
    Ok(fd)
}
<commit_msg>Remove workaround for older Linux kernels<commit_after>// Copyright 2019 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(dead_code)]
use crate::{util::LazyUsize, Error};
use core::{num::NonZeroU32, ptr::NonNull};

cfg_if! {
    if #[cfg(any(target_os = "netbsd", target_os = "openbsd", target_os = "android"))] {
        use libc::__errno as errno_location;
    } else if #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "redox"))] {
        use libc::__errno_location as errno_location;
    } else if #[cfg(any(target_os = "solaris", target_os = "illumos"))] {
        use libc::___errno as errno_location;
    } else if #[cfg(any(target_os = "macos", target_os = "freebsd"))] {
        use libc::__error as errno_location;
    } else if #[cfg(target_os = "haiku")] {
        use libc::_errnop as errno_location;
    }
}

cfg_if! {
    if #[cfg(target_os = "vxworks")] {
        use libc::errnoGet as get_errno;
    } else if #[cfg(target_os = "dragonfly")] {
        // Until rust-lang/rust#29594 is stable, we cannot get the errno value
        // on DragonFlyBSD. So we just return an out-of-range errno.
        unsafe fn get_errno() -> libc::c_int { -1 }
    } else {
        unsafe fn get_errno() -> libc::c_int { *errno_location() }
    }
}

pub fn last_os_error() -> Error {
    let errno = unsafe { get_errno() };
    if errno > 0 {
        Error::from(NonZeroU32::new(errno as u32).unwrap())
    } else {
        Error::ERRNO_NOT_POSITIVE
    }
}

// Fill a buffer by repeatedly invoking a system call. The `sys_fill` function:
//   - should return -1 and set errno on failure
//   - should return the number of bytes written on success
pub fn sys_fill_exact(
    mut buf: &mut [u8],
    sys_fill: impl Fn(&mut [u8]) -> libc::ssize_t,
) -> Result<(), Error> {
    while !buf.is_empty() {
        let res = sys_fill(buf);
        if res < 0 {
            let err = last_os_error();
            // We should try again if the call was interrupted.
            if err.raw_os_error() != Some(libc::EINTR) {
                return Err(err);
            }
        } else {
            // We don't check for EOF (ret = 0) as the data we are reading
            // should be an infinite stream of random bytes.
            buf = &mut buf[(res as usize)..];
        }
    }
    Ok(())
}

// A "weak" binding to a C function that may or may not be present at runtime.
// Used for supporting newer OS features while still building on older systems.
// F must be a function pointer of type `unsafe extern "C" fn`. Based off of the
// weak! macro in libstd.
pub struct Weak {
    name: &'static str,
    addr: LazyUsize,
}

impl Weak {
    // Construct a binding to a C function with a given name. This function is
    // unsafe because `name` _must_ be null terminated.
    pub const unsafe fn new(name: &'static str) -> Self {
        Self {
            name,
            addr: LazyUsize::new(),
        }
    }

    // Return a function pointer if present at runtime. Otherwise, return null.
    pub fn ptr(&self) -> Option<NonNull<libc::c_void>> {
        let addr = self.addr.unsync_init(|| unsafe {
            libc::dlsym(libc::RTLD_DEFAULT, self.name.as_ptr() as *const _) as usize
        });
        NonNull::new(addr as *mut _)
    }
}

cfg_if! {
    if #[cfg(any(target_os = "linux", target_os = "emscripten"))] {
        use libc::open64 as open;
    } else {
        use libc::open;
    }
}

// SAFETY: path must be null terminated, FD must be manually closed.
pub unsafe fn open_readonly(path: &str) -> Result<libc::c_int, Error> {
    debug_assert_eq!(path.as_bytes().last(), Some(&0));
    let fd = open(path.as_ptr() as *const _, libc::O_RDONLY | libc::O_CLOEXEC);
    if fd < 0 {
        return Err(last_os_error());
    }
    Ok(fd)
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
use std::error::Error;
use std::io::prelude::*;
use std::fs::File;
use std::io::SeekFrom;
use std::path::Path;

use c64::cpu;
use c64::opcodes;

// helper macros to easily extract references from Option<RefCell<...>>
macro_rules! as_ref {
    ($x:expr) => ($x.as_ref().unwrap().borrow_mut())
}

macro_rules! as_mut {
    ($x:expr) => ($x.as_mut().unwrap().borrow_mut())
}

pub fn open_file(filename: &str, offset: u64) -> Vec<u8>
{
    let path = Path::new(&filename);

    let mut file = match File::open(&path) {
        Err(why) => panic!("Couldn't open {}: {}", path.display(), Error::description(&why)),
        Ok(file) => file,
    };

    let mut file_data = Vec::<u8>::new();

    let _ = file.seek(SeekFrom::Start(offset));
    let result = file.read_to_end(&mut file_data);

    match result {
        Err(why)   => panic!("Error reading file: {}", Error::description(&why)),
        Ok(result) => println!("Read {}: {} bytes", path.display(), result),
    };

    file_data
}

// set 8 consecutive buffer elements to single value for faster update of
// a single 8-pixel screen chunk
pub fn memset8(buffer: &mut [u32], start: usize, value: u32)
{
    buffer[start]   = value;
    buffer[start+1] = buffer[start];
    buffer[start+2] = buffer[start];
    buffer[start+3] = buffer[start];
    buffer[start+4] = buffer[start];
    buffer[start+5] = buffer[start];
    buffer[start+6] = buffer[start];
    buffer[start+7] = buffer[start];
}

// TODO: prepare for more palettes?
pub fn fetch_c64_color_rgba(idx: u8) -> u32
{
    // palette RGB values copied from WinVICE
    match idx & 0x0F
    {
        0x00  => 0x00000000,
        0x01  => 0x00FFFFFF,
        0x02  => 0x00894036,
        0x03  => 0x007ABFC7,
        0x04  => 0x008A46AE,
        0x05  => 0x0068A941,
        0x06  => 0x003E31A2,
        0x07  => 0x00D0DC71,
        0x08  => 0x00905F25,
        0x09  => 0x005C4700,
        0x0A  => 0x00BB776D,
        0x0B  => 0x00555555,
        0x0C  => 0x00808080,
        0x0D  => 0x00ACEA88,
        0x0E  => 0x007C70DA,
        0x0F  => 0x00ABABAB,
        _ => panic!("Unknown color!"),
    }
}

// instruction debugging
pub struct OpDebugger
{
    pub jump_queue: Vec<u8>
}

impl OpDebugger
{
    pub fn new() -> OpDebugger
    {
        OpDebugger
        {
            jump_queue: Vec::<u8>::new()
        }
    }
}

pub fn debug_instruction(opcode: u8, cpu: &mut cpu::CPU)
{
    cpu.prev_PC = cpu.PC;
    let prev_pc = cpu.prev_PC;

    let operand_hex: String;
    let operand: String;
    let mut extra_cycle = false;
    let debug_loops = false; // true;

    // RTS? pop from queue to continue logging
    if !debug_loops
    {
        match cpu.curr_instr.op
        {
            opcodes::Op::RTS => { let _ = cpu.op_debugger.jump_queue.pop(); return; },
            opcodes::Op::JSR => if !cpu.op_debugger.jump_queue.is_empty() { cpu.op_debugger.jump_queue.push(opcode); return; },
            _ => if !cpu.op_debugger.jump_queue.is_empty() { return; }
        }
    }

    match cpu.curr_instr.addr_mode {
        opcodes::AddrMode::Implied => {
            operand_hex = format!("       ");
            operand = format!("       ");
        },
        opcodes::AddrMode::Accumulator => {
            operand_hex = format!("       ");
            operand = format!("A      ");
        },
        opcodes::AddrMode::Immediate => {
            operand_hex = format!(" {:02X}    ", cpu.read_byte(prev_pc));
            operand = format!("#${:02X}   ", cpu.read_byte(prev_pc));
        },
        opcodes::AddrMode::Absolute => {
            operand_hex = format!(" {:02X} {:02X} ", cpu.read_byte(prev_pc), cpu.read_byte(prev_pc + 0x01));
            operand = format!("${:04X}  ", cpu.read_word_le(cpu.prev_PC));
        },
        opcodes::AddrMode::AbsoluteIndexedX(ec) => {
            extra_cycle = ec;
            operand_hex = format!(" {:02X} {:02X} ", cpu.read_byte(prev_pc), cpu.read_byte(prev_pc + 0x01));
            operand = format!("${:04X},X", cpu.read_word_le(cpu.prev_PC));
        },
        opcodes::AddrMode::AbsoluteIndexedY(ec) => {
            extra_cycle = ec;
            operand_hex = format!(" {:02X} {:02X} ", cpu.read_byte(prev_pc), cpu.read_byte(prev_pc + 0x01));
            operand = format!("${:04X},Y", cpu.read_word_le(cpu.prev_PC));
        },
        opcodes::AddrMode::Zeropage => {
            operand_hex = format!(" {:02X}    ", cpu.read_byte(prev_pc));
            operand = format!("${:02X}    ", cpu.read_byte(prev_pc));
        },
        opcodes::AddrMode::ZeropageIndexedX => {
            operand_hex = format!(" {:02X}    ", cpu.read_byte(prev_pc));
            operand = format!("${:02X},X  ", cpu.read_byte(prev_pc));
        },
        opcodes::AddrMode::ZeropageIndexedY => {
            operand_hex = format!(" {:02X}    ", cpu.read_byte(prev_pc));
            operand = format!("${:02X},Y", cpu.read_byte(prev_pc));
        },
        opcodes::AddrMode::Relative => {
            operand_hex = format!(" {:02X}    ", cpu.read_byte(prev_pc));
            let b: i8 = cpu.read_byte(prev_pc) as i8;
            operand = format!("${:04X}  ", ((cpu.prev_PC + 1) as i16 + b as i16) as u16);
        },
        opcodes::AddrMode::Indirect => {
            operand_hex = format!(" {:02X} {:02X} ", cpu.read_byte(prev_pc), cpu.read_byte(prev_pc + 0x01));
            operand = format!("(${:04X})", cpu.read_word_le(cpu.prev_PC));
        },
        opcodes::AddrMode::IndexedIndirectX => {
            operand_hex = format!(" {:02X}    ", cpu.read_byte(prev_pc));
            operand = format!("(${:02X},X)", cpu.read_byte(prev_pc));
        },
        opcodes::AddrMode::IndirectIndexedY(ec) => {
            extra_cycle = ec;
            operand_hex = format!(" {:02X}    ", cpu.read_byte(prev_pc));
            operand = format!("(${:02X}),Y", cpu.read_byte(prev_pc));
        },
    }

    let byte0 = cpu.read_byte(0x0000);
    let byte1 = cpu.read_byte(0x0001);

    let mut total_cycles = cpu.curr_instr.cycles_to_fetch + cpu.curr_instr.cycles_to_run + cpu.curr_instr.cycles_to_rmw;
    let mut fetch_cycles = cpu.curr_instr.cycles_to_fetch;
    let mut extra_cycle_mark = "*";

    if !extra_cycle
    {
        extra_cycle_mark = " ";
        total_cycles += 1;
        fetch_cycles += 1;
    }

    let rmw_mark = if cpu.curr_instr.cycles_to_rmw > 0 { "+" } else { " " };

    println!("${:04X}: {:02X}{}{}{} {}  {}<- A: {:02X} X: {:02X} Y: {:02X} SP: {:02X} 00: {:02X} 01: {:02X} NV-BDIZC: [{:08b}] ({} cls, f: {}, r: {})", cpu.prev_PC - 1, opcode, operand_hex, extra_cycle_mark, cpu.curr_instr, operand,rmw_mark, cpu.A, cpu.X, cpu.Y, cpu.SP, byte0, byte1, cpu.P, total_cycles, fetch_cycles, cpu.curr_instr.cycles_to_run);

    // JSR? push on queue to supress logging
    if !debug_loops
    {
        match cpu.curr_instr.op
        {
            opcodes::Op::JSR => cpu.op_debugger.jump_queue.push(opcode),
            _ => ()
        }
    }
}

<commit_msg>permanently debug loops in instruction debugger<commit_after>#![allow(dead_code)]
use std::error::Error;
use std::io::prelude::*;
use std::fs::File;
use std::io::SeekFrom;
use std::path::Path;

use c64::cpu;
use c64::opcodes;

// helper macros to easily extract references from Option<RefCell<...>>
macro_rules! as_ref {
    ($x:expr) => ($x.as_ref().unwrap().borrow_mut())
}

macro_rules! as_mut {
    ($x:expr) => ($x.as_mut().unwrap().borrow_mut())
}

pub fn open_file(filename: &str, offset: u64) -> Vec<u8>
{
    let path = Path::new(&filename);

    let mut file = match File::open(&path) {
        Err(why) => panic!("Couldn't open {}: {}", path.display(), Error::description(&why)),
        Ok(file) => file,
    };

    let mut file_data = Vec::<u8>::new();

    let _ = file.seek(SeekFrom::Start(offset));
    let result = file.read_to_end(&mut file_data);

    match result {
        Err(why)   => panic!("Error reading file: {}", Error::description(&why)),
        Ok(result) => println!("Read {}: {} bytes", path.display(), result),
    };

    file_data
}

// set 8 consecutive buffer elements to single value for faster update of
// a single 8-pixel screen chunk
pub fn memset8(buffer: &mut [u32], start: usize, value: u32)
{
    buffer[start]   = value;
    buffer[start+1] = buffer[start];
    buffer[start+2] = buffer[start];
    buffer[start+3] = buffer[start];
    buffer[start+4] = buffer[start];
    buffer[start+5] = buffer[start];
    buffer[start+6] = buffer[start];
    buffer[start+7] = buffer[start];
}

// TODO: prepare for more palettes?
pub fn fetch_c64_color_rgba(idx: u8) -> u32
{
    // palette RGB values copied from WinVICE
    match idx & 0x0F
    {
        0x00  => 0x00000000,
        0x01  => 0x00FFFFFF,
        0x02  => 0x00894036,
        0x03  => 0x007ABFC7,
        0x04  => 0x008A46AE,
        0x05  => 0x0068A941,
        0x06  => 0x003E31A2,
        0x07  => 0x00D0DC71,
        0x08  => 0x00905F25,
        0x09  => 0x005C4700,
        0x0A  => 0x00BB776D,
        0x0B  => 0x00555555,
        0x0C  => 0x00808080,
        0x0D  => 0x00ACEA88,
        0x0E  => 0x007C70DA,
        0x0F  => 0x00ABABAB,
        _ => panic!("Unknown color!"),
    }
}

// instruction debugging
pub struct OpDebugger
{
    pub jump_queue: Vec<u8>
}

impl OpDebugger
{
    pub fn new() -> OpDebugger
    {
        OpDebugger
        {
            jump_queue: Vec::<u8>::new()
        }
    }
}

pub fn debug_instruction(opcode: u8, cpu: &mut cpu::CPU)
{
    cpu.prev_PC = cpu.PC;
    let prev_pc = cpu.prev_PC;

    let operand_hex: String;
    let operand: String;
    let mut extra_cycle = false;
    let debug_loops = true;

    // RTS? pop from queue to continue logging
    if !debug_loops
    {
        match cpu.curr_instr.op
        {
            opcodes::Op::RTS => { let _ = cpu.op_debugger.jump_queue.pop(); return; },
            opcodes::Op::JSR => if !cpu.op_debugger.jump_queue.is_empty() { cpu.op_debugger.jump_queue.push(opcode); return; },
            _ => if !cpu.op_debugger.jump_queue.is_empty() { return; }
        }
    }

    match cpu.curr_instr.addr_mode {
        opcodes::AddrMode::Implied => {
            operand_hex = format!("       ");
            operand = format!("       ");
        },
        opcodes::AddrMode::Accumulator => {
            operand_hex = format!("       ");
            operand = format!("A      ");
        },
        opcodes::AddrMode::Immediate => {
            operand_hex = format!(" {:02X}    ", cpu.read_byte(prev_pc));
            operand = format!("#${:02X}   ", cpu.read_byte(prev_pc));
        },
        opcodes::AddrMode::Absolute => {
            operand_hex = format!(" {:02X} {:02X} ", cpu.read_byte(prev_pc), cpu.read_byte(prev_pc + 0x01));
            operand = format!("${:04X}  ", cpu.read_word_le(cpu.prev_PC));
        },
        opcodes::AddrMode::AbsoluteIndexedX(ec) => {
            extra_cycle = ec;
            operand_hex = format!(" {:02X} {:02X} ", cpu.read_byte(prev_pc), cpu.read_byte(prev_pc + 0x01));
            operand = format!("${:04X},X", cpu.read_word_le(cpu.prev_PC));
        },
        opcodes::AddrMode::AbsoluteIndexedY(ec) => {
            extra_cycle = ec;
            operand_hex = format!(" {:02X} {:02X} ", cpu.read_byte(prev_pc), cpu.read_byte(prev_pc + 0x01));
            operand = format!("${:04X},Y", cpu.read_word_le(cpu.prev_PC));
        },
        opcodes::AddrMode::Zeropage => {
            operand_hex = format!(" {:02X}    ", cpu.read_byte(prev_pc));
            operand = format!("${:02X}    ", cpu.read_byte(prev_pc));
        },
        opcodes::AddrMode::ZeropageIndexedX => {
            operand_hex = format!(" {:02X}    ", cpu.read_byte(prev_pc));
            operand = format!("${:02X},X  ", cpu.read_byte(prev_pc));
        },
        opcodes::AddrMode::ZeropageIndexedY => {
            operand_hex = format!(" {:02X}    ", cpu.read_byte(prev_pc));
            operand = format!("${:02X},Y  ", cpu.read_byte(prev_pc));
        },
        opcodes::AddrMode::Relative => {
            operand_hex = format!(" {:02X}    ", cpu.read_byte(prev_pc));
            let b: i8 = cpu.read_byte(prev_pc) as i8;
            operand = format!("${:04X}  ", ((cpu.prev_PC + 1) as i16 + b as i16) as u16);
        },
        opcodes::AddrMode::Indirect => {
            operand_hex = format!(" {:02X} {:02X} ", cpu.read_byte(prev_pc), cpu.read_byte(prev_pc + 0x01));
            operand = format!("(${:04X})", cpu.read_word_le(cpu.prev_PC));
        },
        opcodes::AddrMode::IndexedIndirectX => {
            operand_hex = format!(" {:02X}    ", cpu.read_byte(prev_pc));
            operand = format!("(${:02X},X)", cpu.read_byte(prev_pc));
        },
        opcodes::AddrMode::IndirectIndexedY(ec) => {
            extra_cycle = ec;
            operand_hex = format!(" {:02X}    ", cpu.read_byte(prev_pc));
            operand = format!("(${:02X}),Y", cpu.read_byte(prev_pc));
        },
    }

    let byte0 = cpu.read_byte(0x0000);
    let byte1 = cpu.read_byte(0x0001);

    let mut total_cycles = cpu.curr_instr.cycles_to_fetch + cpu.curr_instr.cycles_to_run + cpu.curr_instr.cycles_to_rmw;
    let mut fetch_cycles = cpu.curr_instr.cycles_to_fetch;
    let mut extra_cycle_mark = "*";

    if !extra_cycle
    {
        extra_cycle_mark = " ";
        total_cycles += 1;
        fetch_cycles += 1;
    }

    let rmw_mark = if cpu.curr_instr.cycles_to_rmw > 0 { "+" } else { " " };

    println!("${:04X}: {:02X}{}{}{} {}  {}<- A: {:02X} X: {:02X} Y: {:02X} SP: {:02X} 00: {:02X} 01: {:02X} NV-BDIZC: [{:08b}] ({} cls, f: {}, r: {})", cpu.prev_PC - 1, opcode, operand_hex, extra_cycle_mark, cpu.curr_instr, operand,rmw_mark, cpu.A, cpu.X, cpu.Y, cpu.SP, byte0, byte1, cpu.P, total_cycles, fetch_cycles, cpu.curr_instr.cycles_to_run);

    // JSR? push on queue to supress logging
    if !debug_loops
    {
        match cpu.curr_instr.op
        {
            opcodes::Op::JSR => cpu.op_debugger.jump_queue.push(opcode),
            _ => ()
        }
    }
}

<|endoftext|>


<commit_before>#![cfg(target_os = "macos")]

use CreationError;
use ContextError;
use GlAttributes;
use PixelFormat;
use PixelFormatRequirements;
use Robustness;

use objc::runtime::{BOOL, NO};

use cgl::{CGLEnable, kCGLCECrashOnRemovedFunctions, CGLSetParameter, kCGLCPSurfaceOpacity};

use cocoa::base::{id, nil};
use cocoa::foundation::NSAutoreleasePool;
use cocoa::appkit::{self, NSOpenGLContext, NSOpenGLPixelFormat};

use core_foundation::base::TCFType;
use core_foundation::string::CFString;
use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName};

use std::str::FromStr;
use std::ops::Deref;

use winit;
use winit::os::macos::WindowExt;
pub use winit::{MonitorId, NativeMonitorId, get_available_monitors, get_primary_monitor};
pub use self::headless::HeadlessContext;
pub use self::headless::PlatformSpecificHeadlessBuilderAttributes;

mod headless;
mod helpers;

pub struct Context {
    // NSOpenGLContext
    gl: IdRef,
    pixel_format: PixelFormat,
}

impl Context {

    pub fn new(
        window_builder: winit::WindowBuilder,
        events_loop: &winit::EventsLoop,
        pf_reqs: &PixelFormatRequirements,
        gl_attr: &GlAttributes<&Context>,
    ) -> Result<(winit::Window, Self), CreationError>
    {
        let transparent = window_builder.window.transparent;
        let window = try!(window_builder.build(events_loop));

        if gl_attr.sharing.is_some() {
            unimplemented!()
        }

        match gl_attr.robustness {
            Robustness::RobustNoResetNotification |
            Robustness::RobustLoseContextOnReset => {
                return Err(CreationError::RobustnessNotSupported);
            }
            _ => (),
        }

        let view = window.get_nsview() as id;

        let attributes = try!(helpers::build_nsattributes(pf_reqs, gl_attr));
        unsafe {
            let pixel_format = IdRef::new(NSOpenGLPixelFormat::alloc(nil)
                .initWithAttributes_(&attributes));
            let pixel_format = match pixel_format.non_nil() {
                None => return Err(CreationError::NoAvailablePixelFormat),
                Some(pf) => pf,
            };

            // TODO: Add context sharing
            let gl_context = IdRef::new(NSOpenGLContext::alloc(nil)
                .initWithFormat_shareContext_(*pixel_format, nil));
            let gl_context = match gl_context.non_nil() {
                Some(gl_context) => gl_context,
                None => return Err(CreationError::NotSupported),
            };

            let pixel_format = {
                let get_attr = |attrib: appkit::NSOpenGLPixelFormatAttribute| -> i32 {
                    let mut value = 0;
                    NSOpenGLPixelFormat::getValues_forAttribute_forVirtualScreen_(
                        *pixel_format,
                        &mut value,
                        attrib,
                        NSOpenGLContext::currentVirtualScreen(*gl_context));
                    value
                };

                PixelFormat {
                    hardware_accelerated: get_attr(appkit::NSOpenGLPFAAccelerated) != 0,
                    color_bits: (get_attr(appkit::NSOpenGLPFAColorSize) - get_attr(appkit::NSOpenGLPFAAlphaSize)) as u8,
                    alpha_bits: get_attr(appkit::NSOpenGLPFAAlphaSize) as u8,
                    depth_bits: get_attr(appkit::NSOpenGLPFADepthSize) as u8,
                    stencil_bits: get_attr(appkit::NSOpenGLPFAStencilSize) as u8,
                    stereoscopy: get_attr(appkit::NSOpenGLPFAStereo) != 0,
                    double_buffer: get_attr(appkit::NSOpenGLPFADoubleBuffer) != 0,
                    multisampling: if get_attr(appkit::NSOpenGLPFAMultisample) > 0 {
                        Some(get_attr(appkit::NSOpenGLPFASamples) as u16)
                    } else {
                        None
                    },
                    srgb: true,
                }
            };

            gl_context.setView_(view);
            let value = if gl_attr.vsync { 1 } else { 0 };
            gl_context.setValues_forParameter_(&value, appkit::NSOpenGLContextParameter::NSOpenGLCPSwapInterval);

            if transparent {
                let mut opacity = 0;
                CGLSetParameter(gl_context.CGLContextObj() as *mut _, kCGLCPSurfaceOpacity, &mut opacity);
            }

            CGLEnable(gl_context.CGLContextObj() as *mut _, kCGLCECrashOnRemovedFunctions);

            let context = Context { gl: gl_context, pixel_format: pixel_format };
            Ok((window, context))
        }
    }

    pub fn resize(&self, _width: u32, _height: u32) {
        unsafe { self.gl.update(); }
    }

    #[inline]
    pub unsafe fn make_current(&self) -> Result<(), ContextError> {
        let _: () = msg_send![*self.gl, update];
        self.gl.makeCurrentContext();
        Ok(())
    }

    #[inline]
    pub fn is_current(&self) -> bool {
        unsafe {
            let current = NSOpenGLContext::currentContext(nil);
            if current != nil {
                let is_equal: BOOL = msg_send![current, isEqual:*self.gl];
                is_equal != NO
            } else {
                false
            }
        }
    }

    pub fn get_proc_address(&self, addr: &str) -> *const () {
        let symbol_name: CFString = FromStr::from_str(addr).unwrap();
        let framework_name: CFString = FromStr::from_str("com.apple.opengl").unwrap();
        let framework =
            unsafe { CFBundleGetBundleWithIdentifier(framework_name.as_concrete_TypeRef()) };
        let symbol = unsafe {
            CFBundleGetFunctionPointerForName(framework, symbol_name.as_concrete_TypeRef())
        };
        symbol as *const _
    }

    #[inline]
    pub fn swap_buffers(&self) -> Result<(), ContextError> {
        unsafe {
            let pool = NSAutoreleasePool::new(nil);
            self.gl.flushBuffer();
            let _: () = msg_send![pool, release];
        }
        Ok(())
    }

    #[inline]
    pub fn get_api(&self) -> ::Api {
        ::Api::OpenGl
    }

    #[inline]
    pub fn get_pixel_format(&self) -> PixelFormat {
        self.pixel_format.clone()
    }
}

struct IdRef(id);

impl IdRef {
    fn new(i: id) -> IdRef {
        IdRef(i)
    }

    #[allow(dead_code)]
    fn retain(i: id) -> IdRef {
        if i != nil {
            let _: id = unsafe { msg_send![i, retain] };
        }
        IdRef(i)
    }

    fn non_nil(self) -> Option<IdRef> {
        if self.0 == nil { None } else { Some(self) }
    }
}

impl Drop for IdRef {
    fn drop(&mut self) {
        if self.0 != nil {
            let _: () = unsafe { msg_send![self.0, release] };
        }
    }
}

impl Deref for IdRef {
    type Target = id;
    fn deref<'a>(&'a self) -> &'a id {
        &self.0
    }
}

impl Clone for IdRef {
    fn clone(&self) -> IdRef {
        if self.0 != nil {
            let _: id = unsafe { msg_send![self.0, retain] };
        }
        IdRef(self.0)
    }
}
<commit_msg>macos: is_current needs NSAutoreleasePool<commit_after>#![cfg(target_os = "macos")]

use CreationError;
use ContextError;
use GlAttributes;
use PixelFormat;
use PixelFormatRequirements;
use Robustness;

use objc::runtime::{BOOL, NO};

use cgl::{CGLEnable, kCGLCECrashOnRemovedFunctions, CGLSetParameter, kCGLCPSurfaceOpacity};

use cocoa::base::{id, nil};
use cocoa::foundation::NSAutoreleasePool;
use cocoa::appkit::{self, NSOpenGLContext, NSOpenGLPixelFormat};

use core_foundation::base::TCFType;
use core_foundation::string::CFString;
use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName};

use std::str::FromStr;
use std::ops::Deref;

use winit;
use winit::os::macos::WindowExt;
pub use winit::{MonitorId, NativeMonitorId, get_available_monitors, get_primary_monitor};
pub use self::headless::HeadlessContext;
pub use self::headless::PlatformSpecificHeadlessBuilderAttributes;

mod headless;
mod helpers;

pub struct Context {
    // NSOpenGLContext
    gl: IdRef,
    pixel_format: PixelFormat,
}

impl Context {

    pub fn new(
        window_builder: winit::WindowBuilder,
        events_loop: &winit::EventsLoop,
        pf_reqs: &PixelFormatRequirements,
        gl_attr: &GlAttributes<&Context>,
    ) -> Result<(winit::Window, Self), CreationError>
    {
        let transparent = window_builder.window.transparent;
        let window = try!(window_builder.build(events_loop));

        if gl_attr.sharing.is_some() {
            unimplemented!()
        }

        match gl_attr.robustness {
            Robustness::RobustNoResetNotification |
            Robustness::RobustLoseContextOnReset => {
                return Err(CreationError::RobustnessNotSupported);
            }
            _ => (),
        }

        let view = window.get_nsview() as id;

        let attributes = try!(helpers::build_nsattributes(pf_reqs, gl_attr));
        unsafe {
            let pixel_format = IdRef::new(NSOpenGLPixelFormat::alloc(nil)
                .initWithAttributes_(&attributes));
            let pixel_format = match pixel_format.non_nil() {
                None => return Err(CreationError::NoAvailablePixelFormat),
                Some(pf) => pf,
            };

            // TODO: Add context sharing
            let gl_context = IdRef::new(NSOpenGLContext::alloc(nil)
                .initWithFormat_shareContext_(*pixel_format, nil));
            let gl_context = match gl_context.non_nil() {
                Some(gl_context) => gl_context,
                None => return Err(CreationError::NotSupported),
            };

            let pixel_format = {
                let get_attr = |attrib: appkit::NSOpenGLPixelFormatAttribute| -> i32 {
                    let mut value = 0;
                    NSOpenGLPixelFormat::getValues_forAttribute_forVirtualScreen_(
                        *pixel_format,
                        &mut value,
                        attrib,
                        NSOpenGLContext::currentVirtualScreen(*gl_context));
                    value
                };

                PixelFormat {
                    hardware_accelerated: get_attr(appkit::NSOpenGLPFAAccelerated) != 0,
                    color_bits: (get_attr(appkit::NSOpenGLPFAColorSize) - get_attr(appkit::NSOpenGLPFAAlphaSize)) as u8,
                    alpha_bits: get_attr(appkit::NSOpenGLPFAAlphaSize) as u8,
                    depth_bits: get_attr(appkit::NSOpenGLPFADepthSize) as u8,
                    stencil_bits: get_attr(appkit::NSOpenGLPFAStencilSize) as u8,
                    stereoscopy: get_attr(appkit::NSOpenGLPFAStereo) != 0,
                    double_buffer: get_attr(appkit::NSOpenGLPFADoubleBuffer) != 0,
                    multisampling: if get_attr(appkit::NSOpenGLPFAMultisample) > 0 {
                        Some(get_attr(appkit::NSOpenGLPFASamples) as u16)
                    } else {
                        None
                    },
                    srgb: true,
                }
            };

            gl_context.setView_(view);
            let value = if gl_attr.vsync { 1 } else { 0 };
            gl_context.setValues_forParameter_(&value, appkit::NSOpenGLContextParameter::NSOpenGLCPSwapInterval);

            if transparent {
                let mut opacity = 0;
                CGLSetParameter(gl_context.CGLContextObj() as *mut _, kCGLCPSurfaceOpacity, &mut opacity);
            }

            CGLEnable(gl_context.CGLContextObj() as *mut _, kCGLCECrashOnRemovedFunctions);

            let context = Context { gl: gl_context, pixel_format: pixel_format };
            Ok((window, context))
        }
    }

    pub fn resize(&self, _width: u32, _height: u32) {
        unsafe { self.gl.update(); }
    }

    #[inline]
    pub unsafe fn make_current(&self) -> Result<(), ContextError> {
        let _: () = msg_send![*self.gl, update];
        self.gl.makeCurrentContext();
        Ok(())
    }

    #[inline]
    pub fn is_current(&self) -> bool {
        unsafe {
            let pool = NSAutoreleasePool::new(nil);
            let current = NSOpenGLContext::currentContext(nil);
            let mut res = false;
            if current != nil {
                let is_equal: BOOL = msg_send![current, isEqual:*self.gl];
                res = is_equal != NO
            } else {
                res = false
            }
            let _: () = msg_send![pool, release];
            res
        }
    }

    pub fn get_proc_address(&self, addr: &str) -> *const () {
        let symbol_name: CFString = FromStr::from_str(addr).unwrap();
        let framework_name: CFString = FromStr::from_str("com.apple.opengl").unwrap();
        let framework =
            unsafe { CFBundleGetBundleWithIdentifier(framework_name.as_concrete_TypeRef()) };
        let symbol = unsafe {
            CFBundleGetFunctionPointerForName(framework, symbol_name.as_concrete_TypeRef())
        };
        symbol as *const _
    }

    #[inline]
    pub fn swap_buffers(&self) -> Result<(), ContextError> {
        unsafe {
            let pool = NSAutoreleasePool::new(nil);
            self.gl.flushBuffer();
            let _: () = msg_send![pool, release];
        }
        Ok(())
    }

    #[inline]
    pub fn get_api(&self) -> ::Api {
        ::Api::OpenGl
    }

    #[inline]
    pub fn get_pixel_format(&self) -> PixelFormat {
        self.pixel_format.clone()
    }
}

struct IdRef(id);

impl IdRef {
    fn new(i: id) -> IdRef {
        IdRef(i)
    }

    #[allow(dead_code)]
    fn retain(i: id) -> IdRef {
        if i != nil {
            let _: id = unsafe { msg_send![i, retain] };
        }
        IdRef(i)
    }

    fn non_nil(self) -> Option<IdRef> {
        if self.0 == nil { None } else { Some(self) }
    }
}

impl Drop for IdRef {
    fn drop(&mut self) {
        if self.0 != nil {
            let _: () = unsafe { msg_send![self.0, release] };
        }
    }
}

impl Deref for IdRef {
    type Target = id;
    fn deref<'a>(&'a self) -> &'a id {
        &self.0
    }
}

impl Clone for IdRef {
    fn clone(&self) -> IdRef {
        if self.0 != nil {
            let _: id = unsafe { msg_send![self.0, retain] };
        }
        IdRef(self.0)
    }
}
<|endoftext|>


<commit_before>extern crate askama;
extern crate proc_macro;
extern crate syn;

use proc_macro::TokenStream;

fn get_path_from_attrs(attrs: &Vec<syn::Attribute>) -> String {
    for attr in attrs {
        if attr.name() == "template" {
            match attr.value {
                syn::MetaItem::List(_, ref inner) => {
                    match inner[0] {
                        syn::NestedMetaItem::MetaItem(ref item) => {
                            match item {
                                &syn::MetaItem::NameValue(ref key, ref val) => {
                                    assert_eq!(key.as_ref(), "path");
                                    match val {
                                        &syn::Lit::Str(ref s, _) => { return s.clone(); },
                                        _ => panic!("template path must be a string"),
                                    }
                                },
                                _ => panic!("template annotation must contain key/value pair"),
                            }
                        },
                        _ => panic!("template annotation must contain item"),
                    }
                },
                _ => panic!("template annotation must be of List type"),
            }
        }
    }
    panic!("template annotation not found");
}

#[proc_macro_derive(Template, attributes(template))]
pub fn derive_template(input: TokenStream) -> TokenStream {
    let source = input.to_string();

    let ast = syn::parse_derive_input(&source).unwrap();
    let _ctx = match ast.body {
        syn::Body::Struct(ref data) => data,
        _ => panic!("#[derive(Template)] can only be used with structs"),
    };

    let path = get_path_from_attrs(&ast.attrs);
    askama::build_template(&path, &ast).parse().unwrap()
}
<commit_msg>Simplify code to find template path<commit_after>extern crate askama;
extern crate proc_macro;
extern crate syn;

use proc_macro::TokenStream;

fn get_path_from_attrs(attrs: &[syn::Attribute]) -> String {
    let attr = attrs.iter().find(|a| a.name() == "template").unwrap();
    if let syn::MetaItem::List(_, ref inner) = attr.value {
        if let syn::NestedMetaItem::MetaItem(ref item) = inner[0] {
            if let &syn::MetaItem::NameValue(ref key, ref val) = item {
                assert_eq!(key.as_ref(), "path");
                if let &syn::Lit::Str(ref s, _) = val {
                    return s.clone();
                }
            }
        }
    }
    panic!("template path not found in struct attributes");
}

#[proc_macro_derive(Template, attributes(template))]
pub fn derive_template(input: TokenStream) -> TokenStream {
    let source = input.to_string();

    let ast = syn::parse_derive_input(&source).unwrap();
    let _ctx = match ast.body {
        syn::Body::Struct(ref data) => data,
        _ => panic!("#[derive(Template)] can only be used with structs"),
    };

    let path = get_path_from_attrs(&ast.attrs);
    askama::build_template(&path, &ast).parse().unwrap()
}
<|endoftext|>


<commit_before>use rand;

use irc::parse::IrcMsg;
use irc::message_types::{server, client};

use command_mapper::{Replier, RustBotPlugin};

pub struct FetwgrkifgPlugin;

impl FetwgrkifgPlugin {
    pub fn new() -> FetwgrkifgPlugin {
        FetwgrkifgPlugin
    }

    pub fn get_plugin_name() -> &'static str {
        "fetwgrkifg"
    }
}

fn apply_bitflips(input: &mut [u8]) {
    let and_mask = [0xFF, 0xFF, 0xFF, 0xF7];
    let and_cycle = and_mask.iter().cloned().cycle();
    for (flip, input_byte) in Iterator::zip(and_cycle, input.iter_mut()) {
        *input_byte &= flip;
    }
}

impl RustBotPlugin for FetwgrkifgPlugin {
    fn on_message(&mut self, replier: &mut Replier, msg: &IrcMsg) {
        if let server::IncomingMsg::Privmsg(ref privmsg) = server::IncomingMsg::from_msg(msg.clone()) {
            if privmsg.get_target().starts_with("#") && rand::random::<f64>() < 0.006 {
                let mut out = privmsg.get_body_raw().to_vec();
                apply_bitflips(&mut out[..]);
                if privmsg.get_body_raw() != &out[..] {
                    let _ = replier.reply(client::Privmsg::new(privmsg.get_target(), &out[..]).into_irc_msg());
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::apply_bitflips;
    use std::slice::bytes::copy_memory;

    #[test]
    fn test_bitflip() {
        let mut networking = [0; 13];
        copy_memory(b"   networking", &mut networking);
        apply_bitflips(&mut networking);
        assert_eq!(&networking, b"   fetwgrkifg");
    }
}
<commit_msg>fetwgrkifg: reduce probability from 0.6% to 0.03%<commit_after>use rand;

use irc::parse::IrcMsg;
use irc::message_types::{server, client};

use command_mapper::{Replier, RustBotPlugin};

pub struct FetwgrkifgPlugin;

impl FetwgrkifgPlugin {
    pub fn new() -> FetwgrkifgPlugin {
        FetwgrkifgPlugin
    }

    pub fn get_plugin_name() -> &'static str {
        "fetwgrkifg"
    }
}

fn apply_bitflips(input: &mut [u8]) {
    let and_mask = [0xFF, 0xFF, 0xFF, 0xF7];
    let and_cycle = and_mask.iter().cloned().cycle();
    for (flip, input_byte) in Iterator::zip(and_cycle, input.iter_mut()) {
        *input_byte &= flip;
    }
}

impl RustBotPlugin for FetwgrkifgPlugin {
    fn on_message(&mut self, replier: &mut Replier, msg: &IrcMsg) {
        if let server::IncomingMsg::Privmsg(ref privmsg) = server::IncomingMsg::from_msg(msg.clone()) {
            if privmsg.get_target().starts_with("#") && rand::random::<f64>() < 0.0003 {
                let mut out = privmsg.get_body_raw().to_vec();
                apply_bitflips(&mut out[..]);
                if privmsg.get_body_raw() != &out[..] {
                    let _ = replier.reply(client::Privmsg::new(privmsg.get_target(), &out[..]).into_irc_msg());
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::apply_bitflips;
    use std::slice::bytes::copy_memory;

    #[test]
    fn test_bitflip() {
        let mut networking = [0; 13];
        copy_memory(b"   networking", &mut networking);
        apply_bitflips(&mut networking);
        assert_eq!(&networking, b"   fetwgrkifg");
    }
}
<|endoftext|>


<commit_before>use winapi::ctypes::c_ulong;
use winapi::shared::minwindef::FALSE;
use winapi::um::fileapi::{GetDiskFreeSpaceExW, GetLogicalDriveStringsW, GetVolumeInformationW};
use winapi::um::winnt::ULARGE_INTEGER;

use super::{last_os_error, u16_array_to_string};
use data::*;

use std::char::{decode_utf16, REPLACEMENT_CHARACTER};
use std::{io, mem, ptr};

pub fn drives() -> io::Result<Vec<Filesystem>> {
    let logical_drives = unsafe { GetLogicalDriveStringsW(0, ptr::null_mut()) };

    let mut u16s = Vec::with_capacity(logical_drives as usize);
    let p_u16s = u16s.as_mut_ptr();

    let get_logical_drives = unsafe { GetLogicalDriveStringsW(logical_drives, p_u16s) };

    // (X://\0)*\0
    if get_logical_drives + 1 != logical_drives {
        last_os_error()?;
    }

    unsafe { u16s.set_len(logical_drives as usize) };

    // (X://\0)*\0
    let drives = u16s.split(|c| *c == 0).filter(|iter| !iter.is_empty());

    let mut vec: Vec<Filesystem> = Vec::new();

    for us in drives {
        let name = decode_utf16(us.iter().cloned())
            .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
            .collect::<String>();

        let (max, fs, tag) = get_volume_information(us)?;
        let (total, avail, free) = get_disk_space_ext(us)?;

        let tmp = Filesystem {
            name_max: max as _,
            fs_type: fs,
            fs_mounted_from: tag,
            fs_mounted_on: name,
            total: ByteSize::b(total as usize),
            avail: ByteSize::b(avail as usize),
            free: ByteSize::b(free as usize),
            files: 0, // don't find..
            files_total: 0,
            files_avail: 0,
        };

        vec.push(tmp);
    }

    Ok(vec)
}

// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364993(v=vs.85).aspx
fn get_volume_information(name: &[u16]) -> io::Result<(c_ulong, String, String)> {
    let p_name = name.as_ptr();

    let mut volume_name = Vec::with_capacity(255);
    let p_volume_name = volume_name.as_mut_ptr();

    let mut fs_name = Vec::with_capacity(255);
    let p_fs_name = fs_name.as_mut_ptr();

    let mut volume_serial = Vec::with_capacity(255);
    let p_volume_serial = volume_serial.as_mut_ptr();

    let mut max_component_length: c_ulong = 0;
    let mut fs_flags: c_ulong = 0;

    if FALSE == unsafe {
        GetVolumeInformationW(
            p_name,
            p_volume_name,
            255,
            p_volume_serial,
            &mut max_component_length as *mut _,
            &mut fs_flags as *mut _,
            p_fs_name,
            255,
        )
    } {
        last_os_error()?;
    }

    Ok((
        max_component_length,
        u16_array_to_string(p_fs_name),
        u16_array_to_string(p_volume_name),
    ))
}

fn get_disk_space_ext(name: &[u16]) -> io::Result<(u64, u64, u64)> {
    let p_name = name.as_ptr();

    let mut avail: ULARGE_INTEGER = unsafe { mem::uninitialized() };
    let mut total: ULARGE_INTEGER = unsafe { mem::uninitialized() };
    let mut free: ULARGE_INTEGER = unsafe { mem::uninitialized() };

    if FALSE == unsafe {
        GetDiskFreeSpaceExW(
            p_name,
            &mut avail as *mut _,
            &mut total as *mut _,
            &mut free as *mut _,
        )
    } {
        last_os_error()?;
    }

    unsafe { Ok((*total.QuadPart(), *avail.QuadPart(), *free.QuadPart())) }
}
<commit_msg>Fix for Windows < 10 and Removable/CDROM drives<commit_after>use winapi::ctypes::c_ulong;
use winapi::shared::minwindef::FALSE;
use winapi::um::fileapi::{GetDiskFreeSpaceExW, GetLogicalDriveStringsW, GetVolumeInformationW, GetDriveTypeW};
use winapi::um::winnt::ULARGE_INTEGER;

use super::{last_os_error, u16_array_to_string};
use data::*;

use std::char::{decode_utf16, REPLACEMENT_CHARACTER};
use std::{io, mem, ptr};

pub fn drives() -> io::Result<Vec<Filesystem>> {
    let logical_drives = unsafe { GetLogicalDriveStringsW(0, ptr::null_mut()) };

    let mut u16s = Vec::with_capacity(logical_drives as usize);
    let p_u16s = u16s.as_mut_ptr();

    let get_logical_drives = unsafe { GetLogicalDriveStringsW(logical_drives, p_u16s) };

    // (X://\0)*\0
    if get_logical_drives + 1 != logical_drives {
        last_os_error()?;
    }

    unsafe { u16s.set_len(logical_drives as usize) };

    // (X://\0)*\0
    let drives = u16s.split(|c| *c == 0).filter(|iter| !iter.is_empty());

    let mut vec: Vec<Filesystem> = Vec::new();

    for us in drives {
        let name = decode_utf16(us.iter().cloned())
            .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
            .collect::<String>();

        let (max, fs, tag) = get_volume_information(us)?;

        let tmp;
        if max == 0 {
            tmp = Filesystem {
                name_max: max as _,
                fs_type: fs,
                fs_mounted_from: tag,
                fs_mounted_on: name,
                total: ByteSize::b(0),
                avail: ByteSize::b(0),
                free: ByteSize::b(0),
                files: 0,
                files_total: 0,
                files_avail: 0
            };
        } else {
            let (total, avail, free) = get_disk_space_ext(us)?;

            tmp = Filesystem {
                name_max: max as _,
                fs_type: fs,
                fs_mounted_from: tag,
                fs_mounted_on: name,
                total: ByteSize::b(total as usize),
                avail: ByteSize::b(avail as usize),
                free: ByteSize::b(free as usize),
                files: 0, // don't find..
                files_total: 0,
                files_avail: 0,
            };
        }

        vec.push(tmp);
    }

    Ok(vec)
}

// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364993(v=vs.85).aspx
fn get_volume_information(name: &[u16]) -> io::Result<(c_ulong, String, String)> {
    let p_name = name.as_ptr();

    let mut volume_name = Vec::with_capacity(255);
    let p_volume_name = volume_name.as_mut_ptr();

    let mut fs_name = Vec::with_capacity(255);
    let p_fs_name = fs_name.as_mut_ptr();

    let mut volume_serial = Vec::with_capacity(255);
    let p_volume_serial = volume_serial.as_mut_ptr();

    let mut max_component_length: c_ulong = 0;
    let mut fs_flags: c_ulong = 0;

    if FALSE == unsafe {
        GetVolumeInformationW(
            p_name,
            p_volume_name,
            255,
            p_volume_serial,
            &mut max_component_length as *mut _,
            &mut fs_flags as *mut _,
            p_fs_name,
            255,
        )
    } {
        match unsafe { GetDriveTypeW(p_name) } {
            2 => { // REMOVABLE DRIVE (Floppy, USB, etc)
                return Ok((
                    max_component_length,
                    String::from("REM"),
                    u16_array_to_string(p_volume_name)
                ))
            },
            5 => { // DRIVE_CDROM
                return Ok((
                    max_component_length,
                    String::from("CDROM"),
                    u16_array_to_string(p_volume_name)
                ))
            },
            _ => last_os_error()?
        };
    }

    Ok((
        max_component_length,
        u16_array_to_string(p_fs_name),
        u16_array_to_string(p_volume_name),
    ))
}

fn get_disk_space_ext(name: &[u16]) -> io::Result<(u64, u64, u64)> {
    let p_name = name.as_ptr();

    let mut avail: ULARGE_INTEGER = unsafe { mem::uninitialized() };
    let mut total: ULARGE_INTEGER = unsafe { mem::uninitialized() };
    let mut free: ULARGE_INTEGER = unsafe { mem::uninitialized() };

    if FALSE == unsafe {
        GetDiskFreeSpaceExW(
            p_name,
            &mut avail as *mut _,
            &mut total as *mut _,
            &mut free as *mut _,
        )
    } {
        last_os_error()?;
    }

    unsafe { Ok((*total.QuadPart(), *avail.QuadPart(), *free.QuadPart())) }
}
<|endoftext|>