<commit_before>// Copyright (c) 2018, Alessandro Ghedini
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#[macro_use]
extern crate log;
extern crate mio;
extern crate rand;
extern crate docopt;
extern crate quiche;
extern crate env_logger;

use std::fs;
use std::io;
use std::net;
use std::path;

use std::collections::hash_map;
use std::collections::HashMap;

use docopt::Docopt;

use rand::Rng;

const LOCAL_CONN_ID_LEN: usize = 16;

const TRANSPORT_PARAMS: quiche::TransportParams = quiche::TransportParams {
    idle_timeout: 30,
    initial_max_data: 10_000_000,
    initial_max_bidi_streams: 100,
    initial_max_uni_streams: 100,
    max_packet_size: 1500,
    ack_delay_exponent: 3,
    disable_migration: true,
    max_ack_delay: 25,
    initial_max_stream_data_bidi_local: 1_000_000,
    initial_max_stream_data_bidi_remote: 1_000_000,
    initial_max_stream_data_uni: 1_000_000,
    stateless_reset_token_present: true,
    stateless_reset_token: [0xba; 16],
};

const USAGE: &str = "Usage: server [options]

Options:
  -h --help         Show this screen.
  --listen <addr>   Listen on the given IP:port [default: 127.0.0.1:4433]
  --cert <file>     TLS certificate path [default: examples/cert.crt]
  --key <file>      TLS certificate key path [default: examples/cert.key]
  --root <dir>      Root directory [default: examples/root/]
  --name <str>      Name of the server [default: quic.tech]
";

fn main() {
    let mut buf = [0; TRANSPORT_PARAMS.max_packet_size as usize];
    let mut out = [0; TRANSPORT_PARAMS.max_packet_size as usize];

    env_logger::init();

    let args = Docopt::new(USAGE)
                      .and_then(|dopt| dopt.parse())
                      .unwrap_or_else(|e| e.exit());

    let socket = net::UdpSocket::bind(args.get_str("--listen")).unwrap();

    let poll = mio::Poll::new().unwrap();
    let mut events = mio::Events::with_capacity(1024);

    let socket = mio::net::UdpSocket::from_socket(socket).unwrap();
    poll.register(&socket, mio::Token(0),
                  mio::Ready::readable(),
                  mio::PollOpt::edge()).unwrap();

    let mut connections: HashMap<net::SocketAddr, Box<quiche::Connection>> =
        HashMap::new();

    loop {
        // Garbage collect closed connections.
        connections.retain(|_, ref mut c| {
            debug!("Collecting garbage");

            if c.is_closed() {
                debug!("{} connection collected", c.trace_id());
            }

            !c.is_closed()
        });

        poll.poll(&mut events, None).unwrap();

        'read: loop {
            let (len, src) = match socket.recv_from(&mut buf) {
                Ok(v) => v,

                 Err(e) => {
                    if e.kind() == io::ErrorKind::WouldBlock {
                        debug!("recv() would block");
                        break 'read;
                    }

                    panic!("recv() failed: {:?}", e);
                },
            };

            let buf = &mut buf[..len];

            let hdr = match quiche::Header::from_slice(buf, LOCAL_CONN_ID_LEN) {
                Ok(v) => v,

                Err(e) => {
                    error!("Parsing packet header failed: {:?}", e);
                    continue
                }
            };

            if hdr.ty == quiche::Type::VersionNegotiation {
                error!("Version negotiation invalid on the server");
                continue;
            }

            let conn = match connections.entry(src) {
                hash_map::Entry::Vacant(v) => {
                    if hdr.version != quiche::VERSION_DRAFT15 {
                        warn!("Doing version negotiation");

                        let len = quiche::Connection::negotiate_version(&hdr, &mut out)
                                               .unwrap();
                        let out = &out[..len];

                        socket.send_to(out, &src).unwrap();
                        continue;
                    }

                    if hdr.ty != quiche::Type::Initial {
                        error!("Packet is not Initial");
                        continue;
                    }

                    let mut scid: [u8; LOCAL_CONN_ID_LEN] = [0; LOCAL_CONN_ID_LEN];
                    rand::thread_rng().fill(&mut scid[..]);

                    let config = quiche::Config {
                        version: quiche::VERSION_DRAFT15,

                        local_conn_id: &scid,

                        local_transport_params: &TRANSPORT_PARAMS,

                        tls_server_name: args.get_str("--name"),
                        tls_certificate: args.get_str("--cert"),
                        tls_certificate_key: args.get_str("--key"),
                    };

                    debug!("New connection: dcid={} scid={} lcid={}",
                           hex_dump(&hdr.dcid),
                           hex_dump(&hdr.scid),
                           hex_dump(&scid));

                    let conn = quiche::Connection::new(config, true).unwrap();

                    v.insert(conn)
                },

                hash_map::Entry::Occupied(v) => v.into_mut(),
            };

            let mut left = len;

            // Process potentially coalesced packets.
            while left > 0 {
                let read = match conn.recv(&mut buf[len - left..len]) {
                    Ok(v)  => v,

                    Err(e) => {
                        error!("{} recv failed: {:?}", conn.trace_id(), e);
                        conn.close(false, e.to_wire(), b"fail").unwrap();
                        break 'read;
                    },
                };

                left -= read;

                debug!("{} read {} bytes", conn.trace_id(), read);
            }

            let streams: Vec<u64> = conn.stream_iter().collect();
            for s in streams {
                info!("{} stream {} is readable", conn.trace_id(), s);
                handle_stream(conn, s, &args);
            }
        }

        for (src, conn) in &mut connections {
            loop {
                let write = match conn.send(&mut out) {
                    Ok(v) => v,

                    Err(quiche::Error::NothingToDo) => {
                        debug!("{} done writing", conn.trace_id());
                        break;
                    },

                    Err(e) => {
                        error!("{} send failed: {:?}", conn.trace_id(), e);
                        conn.close(false, e.to_wire(), b"fail").unwrap();
                        break;
                    },
                };

                // TODO: coalesce packets.
                socket.send_to(&out[..write], &src).unwrap();

                debug!("{} written {} bytes", conn.trace_id(), write);
            }
        }
    }
}

fn handle_stream(conn: &mut quiche::Connection, stream: u64, args: &docopt::ArgvMap) {
    let stream_data = match conn.stream_recv(stream) {
        Ok(v) => v,

        Err(quiche::Error::NothingToDo) => return,

        Err(e) => panic!("{} stream recv failed {:?}",
                         conn.trace_id(), e),
    };

    if &stream_data[..4] == b"GET " {
        let uri = &stream_data[4..stream_data.len()];
        let uri = String::from_utf8(uri.to_vec()).unwrap();
        let uri = String::from(uri.lines().next().unwrap());
        let uri = path::Path::new(&uri);
        let mut path = path::PathBuf::from(args.get_str("--root"));

        for c in uri.components() {
            if let path::Component::Normal(v) = c {
                path.push(v)
            }
        }

        info!("{} got GET request for {:?} on stream {}",
              conn.trace_id(), path, stream);

        let data = fs::read(path.as_path())
                      .unwrap_or_else(|_| Vec::from(String::from("Not Found!\r\n")));

        info!("{} sending response of size {} on stream {}",
              conn.trace_id(), data.len(), stream);

        if let Err(e) = conn.stream_send(stream, &data, true) {
            error!("{} stream send failed {:?}", conn.trace_id(), e);
        }
    }
}

fn hex_dump(buf: &[u8]) -> String {
    let vec: Vec<String> = buf.iter()
                              .map(|b| format!("{:02x}", b))
                              .collect();

    vec.join("")
}
<commit_msg>server: don't try to read more stream data than is available<commit_after>// Copyright (c) 2018, Alessandro Ghedini
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#[macro_use]
extern crate log;
extern crate mio;
extern crate rand;
extern crate docopt;
extern crate quiche;
extern crate env_logger;

use std::fs;
use std::io;
use std::net;
use std::path;

use std::collections::hash_map;
use std::collections::HashMap;

use docopt::Docopt;

use rand::Rng;

const LOCAL_CONN_ID_LEN: usize = 16;

const TRANSPORT_PARAMS: quiche::TransportParams = quiche::TransportParams {
    idle_timeout: 30,
    initial_max_data: 10_000_000,
    initial_max_bidi_streams: 100,
    initial_max_uni_streams: 100,
    max_packet_size: 1500,
    ack_delay_exponent: 3,
    disable_migration: true,
    max_ack_delay: 25,
    initial_max_stream_data_bidi_local: 1_000_000,
    initial_max_stream_data_bidi_remote: 1_000_000,
    initial_max_stream_data_uni: 1_000_000,
    stateless_reset_token_present: true,
    stateless_reset_token: [0xba; 16],
};

const USAGE: &str = "Usage: server [options]

Options:
  -h --help         Show this screen.
  --listen <addr>   Listen on the given IP:port [default: 127.0.0.1:4433]
  --cert <file>     TLS certificate path [default: examples/cert.crt]
  --key <file>      TLS certificate key path [default: examples/cert.key]
  --root <dir>      Root directory [default: examples/root/]
  --name <str>      Name of the server [default: quic.tech]
";

fn main() {
    let mut buf = [0; TRANSPORT_PARAMS.max_packet_size as usize];
    let mut out = [0; TRANSPORT_PARAMS.max_packet_size as usize];

    env_logger::init();

    let args = Docopt::new(USAGE)
                      .and_then(|dopt| dopt.parse())
                      .unwrap_or_else(|e| e.exit());

    let socket = net::UdpSocket::bind(args.get_str("--listen")).unwrap();

    let poll = mio::Poll::new().unwrap();
    let mut events = mio::Events::with_capacity(1024);

    let socket = mio::net::UdpSocket::from_socket(socket).unwrap();
    poll.register(&socket, mio::Token(0),
                  mio::Ready::readable(),
                  mio::PollOpt::edge()).unwrap();

    let mut connections: HashMap<net::SocketAddr, Box<quiche::Connection>> =
        HashMap::new();

    loop {
        // Garbage collect closed connections.
        connections.retain(|_, ref mut c| {
            debug!("Collecting garbage");

            if c.is_closed() {
                debug!("{} connection collected", c.trace_id());
            }

            !c.is_closed()
        });

        poll.poll(&mut events, None).unwrap();

        'read: loop {
            let (len, src) = match socket.recv_from(&mut buf) {
                Ok(v) => v,

                 Err(e) => {
                    if e.kind() == io::ErrorKind::WouldBlock {
                        debug!("recv() would block");
                        break 'read;
                    }

                    panic!("recv() failed: {:?}", e);
                },
            };

            let buf = &mut buf[..len];

            let hdr = match quiche::Header::from_slice(buf, LOCAL_CONN_ID_LEN) {
                Ok(v) => v,

                Err(e) => {
                    error!("Parsing packet header failed: {:?}", e);
                    continue
                }
            };

            if hdr.ty == quiche::Type::VersionNegotiation {
                error!("Version negotiation invalid on the server");
                continue;
            }

            let conn = match connections.entry(src) {
                hash_map::Entry::Vacant(v) => {
                    if hdr.version != quiche::VERSION_DRAFT15 {
                        warn!("Doing version negotiation");

                        let len = quiche::Connection::negotiate_version(&hdr, &mut out)
                                               .unwrap();
                        let out = &out[..len];

                        socket.send_to(out, &src).unwrap();
                        continue;
                    }

                    if hdr.ty != quiche::Type::Initial {
                        error!("Packet is not Initial");
                        continue;
                    }

                    let mut scid: [u8; LOCAL_CONN_ID_LEN] = [0; LOCAL_CONN_ID_LEN];
                    rand::thread_rng().fill(&mut scid[..]);

                    let config = quiche::Config {
                        version: quiche::VERSION_DRAFT15,

                        local_conn_id: &scid,

                        local_transport_params: &TRANSPORT_PARAMS,

                        tls_server_name: args.get_str("--name"),
                        tls_certificate: args.get_str("--cert"),
                        tls_certificate_key: args.get_str("--key"),
                    };

                    debug!("New connection: dcid={} scid={} lcid={}",
                           hex_dump(&hdr.dcid),
                           hex_dump(&hdr.scid),
                           hex_dump(&scid));

                    let conn = quiche::Connection::new(config, true).unwrap();

                    v.insert(conn)
                },

                hash_map::Entry::Occupied(v) => v.into_mut(),
            };

            let mut left = len;

            // Process potentially coalesced packets.
            while left > 0 {
                let read = match conn.recv(&mut buf[len - left..len]) {
                    Ok(v)  => v,

                    Err(e) => {
                        error!("{} recv failed: {:?}", conn.trace_id(), e);
                        conn.close(false, e.to_wire(), b"fail").unwrap();
                        break 'read;
                    },
                };

                left -= read;

                debug!("{} read {} bytes", conn.trace_id(), read);
            }

            let streams: Vec<u64> = conn.stream_iter().collect();
            for s in streams {
                info!("{} stream {} is readable", conn.trace_id(), s);
                handle_stream(conn, s, &args);
            }
        }

        for (src, conn) in &mut connections {
            loop {
                let write = match conn.send(&mut out) {
                    Ok(v) => v,

                    Err(quiche::Error::NothingToDo) => {
                        debug!("{} done writing", conn.trace_id());
                        break;
                    },

                    Err(e) => {
                        error!("{} send failed: {:?}", conn.trace_id(), e);
                        conn.close(false, e.to_wire(), b"fail").unwrap();
                        break;
                    },
                };

                // TODO: coalesce packets.
                socket.send_to(&out[..write], &src).unwrap();

                debug!("{} written {} bytes", conn.trace_id(), write);
            }
        }
    }
}

fn handle_stream(conn: &mut quiche::Connection, stream: u64, args: &docopt::ArgvMap) {
    let stream_data = match conn.stream_recv(stream) {
        Ok(v) => v,

        Err(quiche::Error::NothingToDo) => return,

        Err(e) => panic!("{} stream recv failed {:?}",
                         conn.trace_id(), e),
    };

    info!("{} stream {} has {} bytes (fin? {})", conn.trace_id(),
          stream, stream_data.len(), stream_data.fin());

    if stream_data.len() > 4 && &stream_data[..4] == b"GET " {
        let uri = &stream_data[4..stream_data.len()];
        let uri = String::from_utf8(uri.to_vec()).unwrap();
        let uri = String::from(uri.lines().next().unwrap());
        let uri = path::Path::new(&uri);
        let mut path = path::PathBuf::from(args.get_str("--root"));

        for c in uri.components() {
            if let path::Component::Normal(v) = c {
                path.push(v)
            }
        }

        info!("{} got GET request for {:?} on stream {}",
              conn.trace_id(), path, stream);

        let data = fs::read(path.as_path())
                      .unwrap_or_else(|_| Vec::from(String::from("Not Found!\r\n")));

        info!("{} sending response of size {} on stream {}",
              conn.trace_id(), data.len(), stream);

        if let Err(e) = conn.stream_send(stream, &data, true) {
            error!("{} stream send failed {:?}", conn.trace_id(), e);
        }
    }
}

fn hex_dump(buf: &[u8]) -> String {
    let vec: Vec<String> = buf.iter()
                              .map(|b| format!("{:02x}", b))
                              .collect();

    vec.join("")
}
<|endoftext|>


<commit_before>#![feature(core)]
extern crate amqp;

use amqp::session::Session;
use amqp::protocol;
use amqp::table;
use amqp::basic::Basic;
use amqp::channel::Channel;
use std::default::Default;
//table types:
//use table::{FieldTable, Table, Bool, ShortShortInt, ShortShortUint, ShortInt, ShortUint, LongInt, LongUint, LongLongInt, LongLongUint, Float, Double, DecimalValue, LongString, FieldArray, Timestamp};

fn consumer_function(channel: &Channel, deliver: protocol::basic::Deliver, headers: protocol::basic::BasicProperties, body: Vec<u8>){
    println!("Got a delivery:");
    println!("Deliver info: {:?}", deliver);
    println!("Content headers: {:?}", headers);
    println!("Content body: {:?}", body);
    channel.basic_ack(deliver.delivery_tag, false);
}

fn main() {
    let mut session = Session::open_url("amqp://localhost/").ok().unwrap();
    let mut channel = session.open_channel(1).ok().unwrap();
    println!("Openned channel: {}", channel.id);

    let queue_name = "test_queue";
    //queue: &str, passive: bool, durable: bool, exclusive: bool, auto_delete: bool, nowait: bool, arguments: Table
    let queue_declare = channel.queue_declare(queue_name, false, true, false, false, false, table::new());
    println!("Queue declare: {:?}", queue_declare);
    for get_result in channel.basic_get(queue_name, false) {
        println!("Headers: {:?}", get_result.headers);
        println!("Reply: {:?}", get_result.reply);
        println!("Body: {:?}", String::from_utf8_lossy(&get_result.body[]));
        channel.basic_ack(get_result.reply.delivery_tag, false);
    }

    //queue: &str, consumer_tag: &str, no_local: bool, no_ack: bool, exclusive: bool, nowait: bool, arguments: Table
    println!("Declaring consumer...");
    let consumer_name = channel.basic_consume(consumer_function, queue_name, "", false, false, false, false, table::new());
    println!("Starting consumer {:?}", consumer_name);
    channel.start_consuming();

    channel.basic_publish("", queue_name, true, false,
        protocol::basic::BasicProperties{ content_type: Some("text".to_string()), ..Default::default()},
        (b"Hello from rust!").to_vec());
    channel.close(200, "Bye".to_string());
    session.close(200, "Good Bye".to_string());
}
<commit_msg>Fix warning.<commit_after>extern crate amqp;

use amqp::session::Session;
use amqp::protocol;
use amqp::table;
use amqp::basic::Basic;
use amqp::channel::Channel;
use std::default::Default;
//table types:
//use table::{FieldTable, Table, Bool, ShortShortInt, ShortShortUint, ShortInt, ShortUint, LongInt, LongUint, LongLongInt, LongLongUint, Float, Double, DecimalValue, LongString, FieldArray, Timestamp};

fn consumer_function(channel: &Channel, deliver: protocol::basic::Deliver, headers: protocol::basic::BasicProperties, body: Vec<u8>){
    println!("Got a delivery:");
    println!("Deliver info: {:?}", deliver);
    println!("Content headers: {:?}", headers);
    println!("Content body: {:?}", body);
    channel.basic_ack(deliver.delivery_tag, false);
}

fn main() {
    let mut session = Session::open_url("amqp://localhost/").ok().unwrap();
    let mut channel = session.open_channel(1).ok().unwrap();
    println!("Openned channel: {}", channel.id);

    let queue_name = "test_queue";
    //queue: &str, passive: bool, durable: bool, exclusive: bool, auto_delete: bool, nowait: bool, arguments: Table
    let queue_declare = channel.queue_declare(queue_name, false, true, false, false, false, table::new());
    println!("Queue declare: {:?}", queue_declare);
    for get_result in channel.basic_get(queue_name, false) {
        println!("Headers: {:?}", get_result.headers);
        println!("Reply: {:?}", get_result.reply);
        println!("Body: {:?}", String::from_utf8_lossy(&get_result.body[]));
        channel.basic_ack(get_result.reply.delivery_tag, false);
    }

    //queue: &str, consumer_tag: &str, no_local: bool, no_ack: bool, exclusive: bool, nowait: bool, arguments: Table
    println!("Declaring consumer...");
    let consumer_name = channel.basic_consume(consumer_function, queue_name, "", false, false, false, false, table::new());
    println!("Starting consumer {:?}", consumer_name);
    channel.start_consuming();

    channel.basic_publish("", queue_name, true, false,
        protocol::basic::BasicProperties{ content_type: Some("text".to_string()), ..Default::default()},
        (b"Hello from rust!").to_vec());
    channel.close(200, "Bye".to_string());
    session.close(200, "Good Bye".to_string());
}
<|endoftext|>


<commit_before>use std::mem;
use std::ptr;
use std::os::raw::c_void;
use std::sync::Arc;

use instance::MemoryType;
use device::Device;
use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Represents memory that has been allocated.
pub struct DeviceMemory {
    device: Arc<Device>,
    memory: vk::DeviceMemory,
    size: usize,
    memory_type_index: u32,
}

impl DeviceMemory {
    /// Allocates a chunk of memory from the device.
    ///
    /// # Panic
    ///
    /// - Panicks if `memory_type` doesn't belong to the same physical device as `device`.
    ///
    #[inline]
    pub fn alloc(device: &Arc<Device>, memory_type: &MemoryType, size: usize)
                 -> Result<DeviceMemory, OomError>
    {
        assert_eq!(device.physical_device().internal_object(),
                   memory_type.physical_device().internal_object());

        let vk = device.pointers();

        let memory = unsafe {
            let infos = vk::MemoryAllocateInfo {
                sType: vk::STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
                pNext: ptr::null(),
                allocationSize: size as u64,
                memoryTypeIndex: memory_type.id(),
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.AllocateMemory(device.internal_object(), &infos,
                                                ptr::null(), &mut output)));
            output
        };

        Ok(DeviceMemory {
            device: device.clone(),
            memory: memory,
            size: size,
            memory_type_index: memory_type.id(),
        })
    }

    /// Allocates a chunk of memory and maps it.
    ///
    /// # Panic
    ///
    /// - Panicks if `memory_type` doesn't belong to the same physical device as `device`.
    /// - Panicks if the memory type is not host-visible.
    ///
    pub fn alloc_and_map(device: &Arc<Device>, memory_type: &MemoryType, size: usize)
                         -> Result<MappedDeviceMemory, OomError>
    {
        let vk = device.pointers();

        assert!(memory_type.is_host_visible());
        let mem = try!(DeviceMemory::alloc(device, memory_type, size));

        let ptr = unsafe {
            let mut output = mem::uninitialized();
            try!(check_errors(vk.MapMemory(device.internal_object(), mem.memory, 0,
                                           mem.size as vk::DeviceSize, 0 /* reserved flags */,
                                           &mut output)));
            output
        };

        Ok(MappedDeviceMemory {
            memory: mem,
            pointer: ptr,
        })
    }

    /// Returns the memory type this chunk was allocated on.
    #[inline]
    pub fn memory_type(&self) -> MemoryType {
        self.device.physical_device().memory_type_by_id(self.memory_type_index).unwrap()
    }

    /// Returns the size in bytes of that memory chunk.
    #[inline]
    pub fn size(&self) -> usize {
        self.size
    }

    /// Returns the device associated with this allocation.
    #[inline]
    pub fn device(&self) -> &Arc<Device> {
        &self.device
    }
}

unsafe impl VulkanObject for DeviceMemory {
    type Object = vk::DeviceMemory;

    #[inline]
    fn internal_object(&self) -> vk::DeviceMemory {
        self.memory
    }
}

impl Drop for DeviceMemory {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.FreeMemory(self.device.internal_object(), self.memory, ptr::null());
        }
    }
}

/// Represents memory that has been allocated and mapped in CPU accessible space.
pub struct MappedDeviceMemory {
    memory: DeviceMemory,
    pointer: *mut c_void,
}

impl MappedDeviceMemory {
    /// Returns the underlying `DeviceMemory`.
    #[inline]
    pub fn memory(&self) -> &DeviceMemory {
        &self.memory
    }

    /// Returns a pointer to the mapping.
    ///
    /// Note that access to this pointer is not safe at all.
    pub fn mapping_pointer(&self) -> *mut c_void {
        self.pointer
    }
}

impl Drop for MappedDeviceMemory {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.memory.device.pointers();
            vk.UnmapMemory(self.memory.device.internal_object(), self.memory.memory);
        }
    }
}
<commit_msg>Add some tests and cleanup device_memory.rs<commit_after>use std::mem;
use std::ptr;
use std::os::raw::c_void;
use std::sync::Arc;

use instance::MemoryType;
use device::Device;
use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Represents memory that has been allocated.
pub struct DeviceMemory {
    device: Arc<Device>,
    memory: vk::DeviceMemory,
    size: usize,
    memory_type_index: u32,
}

impl DeviceMemory {
    /// Allocates a chunk of memory from the device.
    ///
    /// Some platforms may have a limit on the maximum size of a single allocation. For example,
    /// certain systems may fail to create allocations with a size greater than or equal to 4GB.
    ///
    /// # Panic
    ///
    /// - Panicks if `size` is 0.
    /// - Panicks if `memory_type` doesn't belong to the same physical device as `device`.
    ///
    // TODO: VK_ERROR_TOO_MANY_OBJECTS error
    #[inline]
    pub fn alloc(device: &Arc<Device>, memory_type: &MemoryType, size: usize)
                 -> Result<DeviceMemory, OomError>
    {
        assert!(size >= 1);
        assert_eq!(device.physical_device().internal_object(),
                   memory_type.physical_device().internal_object());

        if size > memory_type.heap().size() {
            return Err(OomError::OutOfDeviceMemory);
        }

        let vk = device.pointers();

        let memory = unsafe {
            let infos = vk::MemoryAllocateInfo {
                sType: vk::STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
                pNext: ptr::null(),
                allocationSize: size as u64,
                memoryTypeIndex: memory_type.id(),
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.AllocateMemory(device.internal_object(), &infos,
                                                ptr::null(), &mut output)));
            output
        };

        Ok(DeviceMemory {
            device: device.clone(),
            memory: memory,
            size: size,
            memory_type_index: memory_type.id(),
        })
    }

    /// Allocates a chunk of memory and maps it.
    ///
    /// # Panic
    ///
    /// - Panicks if `memory_type` doesn't belong to the same physical device as `device`.
    /// - Panicks if the memory type is not host-visible.
    ///
    pub fn alloc_and_map(device: &Arc<Device>, memory_type: &MemoryType, size: usize)
                         -> Result<MappedDeviceMemory, OomError>
    {
        let vk = device.pointers();

        assert!(memory_type.is_host_visible());
        let mem = try!(DeviceMemory::alloc(device, memory_type, size));

        let ptr = unsafe {
            let mut output = mem::uninitialized();
            try!(check_errors(vk.MapMemory(device.internal_object(), mem.memory, 0,
                                           mem.size as vk::DeviceSize, 0 /* reserved flags */,
                                           &mut output)));
            output
        };

        Ok(MappedDeviceMemory {
            memory: mem,
            pointer: ptr,
        })
    }

    /// Returns the memory type this chunk was allocated on.
    #[inline]
    pub fn memory_type(&self) -> MemoryType {
        self.device.physical_device().memory_type_by_id(self.memory_type_index).unwrap()
    }

    /// Returns the size in bytes of that memory chunk.
    #[inline]
    pub fn size(&self) -> usize {
        self.size
    }

    /// Returns the device associated with this allocation.
    #[inline]
    pub fn device(&self) -> &Arc<Device> {
        &self.device
    }
}

unsafe impl VulkanObject for DeviceMemory {
    type Object = vk::DeviceMemory;

    #[inline]
    fn internal_object(&self) -> vk::DeviceMemory {
        self.memory
    }
}

impl Drop for DeviceMemory {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.FreeMemory(self.device.internal_object(), self.memory, ptr::null());
        }
    }
}

/// Represents memory that has been allocated and mapped in CPU accessible space.
pub struct MappedDeviceMemory {
    memory: DeviceMemory,
    pointer: *mut c_void,
}

impl MappedDeviceMemory {
    /// Returns the underlying `DeviceMemory`.
    #[inline]
    pub fn memory(&self) -> &DeviceMemory {
        &self.memory
    }

    /// Returns a pointer to the mapping.
    ///
    /// Note that access to this pointer is not safe at all.
    pub fn mapping_pointer(&self) -> *mut c_void {
        self.pointer
    }
}

impl Drop for MappedDeviceMemory {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.memory.device.pointers();
            vk.UnmapMemory(self.memory.device.internal_object(), self.memory.memory);
        }
    }
}

#[cfg(test)]
mod tests {
    use OomError;
    use memory::DeviceMemory;

    #[test]
    fn create() {
        let (device, _) = gfx_dev_and_queue!();
        let mem_ty = device.physical_device().memory_types().next().unwrap();
        let _ = DeviceMemory::alloc(&device, &mem_ty, 256).unwrap();
    }

    #[test]
    #[should_panic]
    fn zero_size() {
        let (device, _) = gfx_dev_and_queue!();
        let mem_ty = device.physical_device().memory_types().next().unwrap();
        let _ = DeviceMemory::alloc(&device, &mem_ty, 0);
    }

    #[test]
    #[cfg(target_pointer_width = "64")]
    fn oom() {
        let (device, _) = gfx_dev_and_queue!();
        let mem_ty = device.physical_device().memory_types().filter(|m| !m.is_lazily_allocated())
                           .next().unwrap();

        match DeviceMemory::alloc(&device, &mem_ty, 0xffffffffffffffff) {
            Err(OomError::OutOfDeviceMemory) => (),
            Err(OomError::OutOfHostMemory) => (),
            _ => panic!()
        }
    }
}
<|endoftext|>


<commit_before>#![feature(test)]
#![feature(alloc)]
#![feature(heap_api)]
#[macro_use]
extern crate adapton ;

// mod AAAzip {
//     fn doit() {
//             let mut st = &mut (AdaptonState::new()) ;
//             for _ in 1..(n-1) {
//                 memo!(st, fib, x:x );
//             }
//             memo!(st, fib, x:x )
//     }
//     #[bench]
//     fn bench(b:&mut Bencher) {
//         b.iter(||doit());
//     }
// }

mod fib {
    const INPUT_SIZE:u64 = 20;
    const REPEAT_COUNT:u64 = 100;

    #[cfg(test)]
    mod rust {
        use super::INPUT_SIZE;
        use super::REPEAT_COUNT;

        extern crate test;
        use self::test::Bencher;

        pub fn fib (x:u64) -> u64 { test::black_box (
            match x {
                0 => 0,
                1 => 1,
                x => fib(x-1) + fib(x-2)
            })
        }

        pub fn fib_repeat (x:u64, n:u64) -> u64 {
            for _ in 1..(n-1) {
                test::black_box(fib(x));
            }
            test::black_box(fib(x))
        }

        #[test]
        fn it_works() {
            assert_eq!(5 as u64, fib(5));
        }

        #[bench]
        fn bench_fib(b: &mut Bencher) {
            b.iter(|| test::black_box(fib(INPUT_SIZE)));
        }

        #[bench]
        fn bench_fib_repeat(b: &mut Bencher) {
            b.iter(|| test::black_box(fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
        }
    }

    #[cfg(test)]
    mod adapton {
        mod fs {
            extern crate test;
            use self::test::Bencher;

            extern crate alloc;
            use std::rc::Rc;
            use adapton::adapton_syntax::* ;
            use adapton::adapton_sigs::* ;
            //use adapton::adapton_state::* ;
            use adapton::adapton_fromscratch::* ;
            use super::super::INPUT_SIZE;
            use super::super::REPEAT_COUNT;

            pub fn fib<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
                match x {
                    0 => 0,
                    1 => 1,
                    x => { memo!(st, fib, x:x-1)
                           +
                           memo!(st, fib, x:x-2) }}
            }

            pub fn run_fib (x:u64) -> u64 {
                let mut st = &mut AdaptonFromScratch::new() ;
                memo!(st, fib, x:x )
            }

            pub fn run_fib_repeat (x:u64, n:u64) -> u64 {
                let mut st = &mut AdaptonFromScratch::new() ;
                for _ in 1..(n-1) {
                    memo!(st, fib, x:x );
                }
                memo!(st, fib, x:x )
            }

            #[test]
            fn it_works() {
                assert_eq!(5 as u64, run_fib(5));
            }

            #[bench]
            fn bench_fib(b: &mut Bencher) {
                b.iter(|| test::black_box(run_fib(INPUT_SIZE)));
            }

            #[bench]
            fn bench_fib_repeat(b: &mut Bencher) {
                b.iter(|| test::black_box(run_fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
            }

        }

        mod state {
            extern crate test;
            use self::test::Bencher;

            extern crate alloc;
            use std::rc::Rc;
            use adapton::adapton_syntax::* ;
            use adapton::adapton_sigs::* ;
            use adapton::adapton_state::* ;
            //use adapton::adapton_fromscratch::* ;
            use super::super::INPUT_SIZE;
            use super::super::REPEAT_COUNT;

            pub fn fib<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
                match x {
                    0 => 0,
                    1 => 1,
                    x => { memo!(st, fib, x:x-1)
                           +
                           memo!(st, fib, x:x-2) }}
            }

            pub fn run_fib (x:u64) -> u64 {
                let mut st = &mut AdaptonState::new() ;
                memo!(st, fib, x:x )
            }

            pub fn run_fib_repeat (x:u64, n:u64) -> u64 {
                let mut st = &mut AdaptonState::new() ;
                for _ in 1..(n-1) {
                    memo!(st, fib, x:x );
                }
                memo!(st, fib, x:x )
            }

            #[test]
            fn it_works() {
                assert_eq!(5 as u64, run_fib(5));
            }

            #[bench]
            fn bench_fib(b: &mut Bencher) {
                b.iter(|| test::black_box(run_fib(INPUT_SIZE)));
            }

            #[bench]
            fn bench_fib_repeat(b: &mut Bencher) {
                b.iter(|| test::black_box(run_fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
            }
        }
    }
}

mod fact {
    const INPUT_SIZE:u64 = 100;
    const REPEAT_COUNT:u64 = 100;

    #[cfg(test)]
    mod no_caching {
        use super::INPUT_SIZE;
        use super::REPEAT_COUNT;

        extern crate test;
        use self::test::Bencher;

        pub fn fact (x:u64) -> u64 {
            if x == 0 { 1 } else { test::black_box(x) * fact(x-1) }
        }

        pub fn fact_repeat (x:u64, n:u64) -> u64 {
            for _ in 1..(n-1) {
                test::black_box(fact(x));
            }
            fact(x)
        }

        #[test]
        fn it_works() {
            assert_eq!(120 as u64, fact(5));
        }

        #[bench]
        fn bench_fact(b: &mut Bencher) {
            b.iter(|| test::black_box(fact(INPUT_SIZE)));
        }

        #[bench]
        fn bench_fact_repeat(b: &mut Bencher) {
            b.iter(|| test::black_box(fact_repeat(INPUT_SIZE, REPEAT_COUNT)));
        }
    }

    #[cfg(test)]
    mod pure_caching {
        use super::INPUT_SIZE;
        use super::REPEAT_COUNT;

        extern crate test;
        use self::test::Bencher;

        use std::rc::Rc;

        use adapton::adapton_syntax::* ;
        use adapton::adapton_sigs::* ;
        use adapton::adapton_state::* ;

        pub fn fact<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
            if x == 0 { 1 } else { x * (memo!(st, fact, x:x-1 )) }
        }

        pub fn run_fact (x:u64) -> u64 {
            let mut st = &mut (AdaptonState::new()) ;
            memo!(st, fact, x:x )
        }

        pub fn run_fact_repeat (x:u64, n:u64) -> u64 {
            let mut st = &mut (AdaptonState::new()) ;
            for _ in 1..(n-1) {
                memo!(st, fact, x:x );
            }
            memo!(st, fact, x:x )
        }

        #[test]
        fn it_works() {
            assert_eq!(120 as u64, run_fact(5));
        }

        #[bench]
        fn bench_fact(b: &mut Bencher) {
            b.iter(|| test::black_box(run_fact(INPUT_SIZE)));
        }

        #[bench]
        fn bench_fact_repeat(b: &mut Bencher) {
            b.iter(|| test::black_box(run_fact_repeat(INPUT_SIZE, REPEAT_COUNT)));
        }
    }
}
<commit_msg>pasted Kyle's code<commit_after>#![feature(test)]
#![feature(alloc)]
#![feature(heap_api)]
#[macro_use]
extern crate adapton ;

// mod AAAzip {
//     fn doit() {
//             let mut st = &mut (AdaptonState::new()) ;
//             for _ in 1..(n-1) {
//                 memo!(st, fib, x:x );
//             }
//             memo!(st, fib, x:x )
//     }
//     #[bench]
//     fn bench(b:&mut Bencher) {
//         b.iter(||doit());
//     }
// }

// mod fib {
//     const INPUT_SIZE:u64 = 20;
//     const REPEAT_COUNT:u64 = 100;

//     #[cfg(test)]
//     mod rust {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         pub fn fib (x:u64) -> u64 { test::black_box (
//             match x {
//                 0 => 0,
//                 1 => 1,
//                 x => fib(x-1) + fib(x-2)
//             })
//         }

//         pub fn fib_repeat (x:u64, n:u64) -> u64 {
//             for _ in 1..(n-1) {
//                 test::black_box(fib(x));
//             }
//             test::black_box(fib(x))
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(5 as u64, fib(5));
//         }

//         #[bench]
//         fn bench_fib(b: &mut Bencher) {
//             b.iter(|| test::black_box(fib(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fib_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }

//     #[cfg(test)]
//     mod adapton {
//         mod fs {
//             extern crate test;
//             use self::test::Bencher;

//             extern crate alloc;
//             use std::rc::Rc;
//             use adapton::adapton_syntax::* ;
//             use adapton::adapton_sigs::* ;
//             //use adapton::adapton_state::* ;
//             use adapton::adapton_fromscratch::* ;
//             use super::super::INPUT_SIZE;
//             use super::super::REPEAT_COUNT;

//             pub fn fib<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//                 match x {
//                     0 => 0,
//                     1 => 1,
//                     x => { memo!(st, fib, x:x-1)
//                            +
//                            memo!(st, fib, x:x-2) }}
//             }

//             pub fn run_fib (x:u64) -> u64 {
//                 let mut st = &mut AdaptonFromScratch::new() ;
//                 memo!(st, fib, x:x )
//             }

//             pub fn run_fib_repeat (x:u64, n:u64) -> u64 {
//                 let mut st = &mut AdaptonFromScratch::new() ;
//                 for _ in 1..(n-1) {
//                     memo!(st, fib, x:x );
//                 }
//                 memo!(st, fib, x:x )
//             }

//             #[test]
//             fn it_works() {
//                 assert_eq!(5 as u64, run_fib(5));
//             }

//             #[bench]
//             fn bench_fib(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib(INPUT_SIZE)));
//             }

//             #[bench]
//             fn bench_fib_repeat(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//             }

//         }

//         mod state {
//             extern crate test;
//             use self::test::Bencher;

//             extern crate alloc;
//             use std::rc::Rc;
//             use adapton::adapton_syntax::* ;
//             use adapton::adapton_sigs::* ;
//             use adapton::adapton_state::* ;
//             //use adapton::adapton_fromscratch::* ;
//             use super::super::INPUT_SIZE;
//             use super::super::REPEAT_COUNT;

//             pub fn fib<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//                 match x {
//                     0 => 0,
//                     1 => 1,
//                     x => { memo!(st, fib, x:x-1)
//                            +
//                            memo!(st, fib, x:x-2) }}
//             }

//             pub fn run_fib (x:u64) -> u64 {
//                 let mut st = &mut AdaptonState::new() ;
//                 memo!(st, fib, x:x )
//             }

//             pub fn run_fib_repeat (x:u64, n:u64) -> u64 {
//                 let mut st = &mut AdaptonState::new() ;
//                 for _ in 1..(n-1) {
//                     memo!(st, fib, x:x );
//                 }
//                 memo!(st, fib, x:x )
//             }

//             #[test]
//             fn it_works() {
//                 assert_eq!(5 as u64, run_fib(5));
//             }

//             #[bench]
//             fn bench_fib(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib(INPUT_SIZE)));
//             }

//             #[bench]
//             fn bench_fib_repeat(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//             }
//         }
//     }
// }

// mod fact {
//     const INPUT_SIZE:u64 = 100;
//     const REPEAT_COUNT:u64 = 100;

//     #[cfg(test)]
//     mod no_caching {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         pub fn fact (x:u64) -> u64 {
//             if x == 0 { 1 } else { test::black_box(x) * fact(x-1) }
//         }

//         pub fn fact_repeat (x:u64, n:u64) -> u64 {
//             for _ in 1..(n-1) {
//                 test::black_box(fact(x));
//             }
//             fact(x)
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(120 as u64, fact(5));
//         }

//         #[bench]
//         fn bench_fact(b: &mut Bencher) {
//             b.iter(|| test::black_box(fact(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fact_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(fact_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }

//     #[cfg(test)]
//     mod pure_caching {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         use std::rc::Rc;

//         use adapton::adapton_syntax::* ;
//         use adapton::adapton_sigs::* ;
//         use adapton::adapton_state::* ;

//         pub fn fact<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//             if x == 0 { 1 } else { x * (memo!(st, fact, x:x-1 )) }
//         }

//         pub fn run_fact (x:u64) -> u64 {
//             let mut st = &mut (AdaptonState::new()) ;
//             memo!(st, fact, x:x )
//         }

//         pub fn run_fact_repeat (x:u64, n:u64) -> u64 {
//             let mut st = &mut (AdaptonState::new()) ;
//             for _ in 1..(n-1) {
//                 memo!(st, fact, x:x );
//             }
//             memo!(st, fact, x:x )
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(120 as u64, run_fact(5));
//         }

//         #[bench]
//         fn bench_fact(b: &mut Bencher) {
//             b.iter(|| test::black_box(run_fact(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fact_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(run_fact_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }
// }

mod hourglass {
    //const INPUT_ARRAY:Vec<u64> = vec![2; 64];
    const REPEAT_COUNT:u64 = 100;

    #[cfg(test)]
    mod eager_ids {
        //use super::INPUT_ARRAY;
        use super::REPEAT_COUNT;

        extern crate test;
        use self::test::Bencher;

        use std::rc::Rc;

        use adapton::adapton_syntax::* ;
        use adapton::adapton_sigs::* ;
        use adapton::adapton_fromscratch::* ;

        fn ident<A:Adapton,T>(st:&mut A, x:T) -> T {x}

        fn depend_mult<A:Adapton>(st:&mut A, x: &Art<u64,A::Loc>,y: &Art<u64,A::Loc>) -> u64 {
            st.force(x) * st.force(y)
        }

        fn depend_add<A:Adapton>(st:&mut A, x: &Art<u64,A::Loc>,y: &Art<u64,A::Loc>) -> u64 {
            st.force(x) + st.force(y)
        }

        pub fn hourglass<A:Adapton> (st:&mut A) -> u64 {
            let cells = vec![2;64];
            let mut nodes = vec![];
            for i in 0..64 {
                nodes.push(thunk!(st, ident, x:cells[i]));
            }
            let mut item_num = 0;
            loop {
                if nodes.len() == 126 { break; }
                let first = nodes[item_num].clone();
                let second = nodes[item_num+1].clone();
                println!("{} --> {}, {}", nodes.len()-1, item_num, item_num+1);
                //why don't we have lifetime issues here?
                nodes.push(thunk!(st, depend_add, x:&first, y:&second));
                if item_num < 122 { item_num += 2 } else { item_num += 1 }
            }
            //this line gives an index out of bounds error!!
            let thk = &nodes[nodes.len()-1];
            //let thk = &nodes[&nodes.len()-2];
            println!("past checkpoint");
            st.force(thk)
        }

        pub fn run_hourglass () -> u64 {
            let mut st = &mut (AdaptonFromScratch::new());
            hourglass(st)
        }

        pub fn run_hourglass_repeat (n:u64) -> u64 {
            let mut st = &mut (AdaptonFromScratch::new());
            for _ in 1..(n-1) {
                test::black_box(hourglass(st));
            }
            hourglass(st)
        }

        #[test]
        fn it_works() {
            assert_eq!(2 as u64, run_hourglass());
        }

        #[bench]
        fn bench_hourglass(b: &mut Bencher) {
            b.iter(|| test::black_box(run_hourglass()));
        }

        #[bench]
        fn bench_hourglass_repeat(b: &mut Bencher) {
            b.iter(|| test::black_box(run_hourglass_repeat(REPEAT_COUNT)));
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate bencher;
extern crate kdtree;
extern crate rand;

use bencher::Bencher;

#[derive(Copy, Clone, PartialEq)]
pub struct Point2WithId {
    dims: [f64; 2],
    pub id: i32,
}

impl Point2WithId {
    pub fn new(id: i32, x: f64, y: f64) -> Point2WithId {
        Point2WithId {
            dims: [x, y],
            id: id,
        }
    }
}

impl kdtree::kdtree::KdtreePointTrait for Point2WithId {
    fn dims(&self) -> &[f64] {
        return &self.dims;
    }
}

#[derive(Copy, Clone, PartialEq)]
pub struct Point3WithId {
    dims: [f64; 3],
    pub id: i32,
}

impl Point3WithId {
    pub fn new(id: i32, x: f64, y: f64, z: f64) -> Point3WithId {
        Point3WithId {
            dims: [x, y, z],
            id: id,
        }
    }
}

impl kdtree::kdtree::KdtreePointTrait for Point3WithId {
    fn dims(&self) -> &[f64] {
        return &self.dims;
    }
}

fn bench_creating_1000_node_tree(b: &mut Bencher) {
    let len = 1000usize;
    let mut points : Vec<Point2WithId> = vec![];
    //let mut kdtree = KdTree::new_with_capacity(3, 16);
    for id in 0..len {
        let x : f64 = rand::random();
        points.push(Point2WithId::new(id as i32, x, x));
        //   points.push(rand_data());
    }

    b.iter(|| {
        let tree = kdtree::kdtree::Kdtree::new(points.clone());
    });
}

fn bench_single_loop_times_for_1000_node_tree(b: &mut Bencher) {
    let len = 1000usize;
    let mut points : Vec<Point3WithId> = vec![];
    //let mut kdtree = KdTree::new_with_capacity(3, 16);

    for i in 0..len {
        points.push(Point3WithId::new(i as i32, rand::random(),rand::random(),rand::random()))

    }

    let tree = kdtree::kdtree::Kdtree::new(points.clone());

    b.iter(||  tree.nearest_search(&points[0]));
}

benchmark_group!(benches, a,b);
benchmark_main!(benches);<commit_msg>benches renames<commit_after>#[macro_use]
extern crate bencher;
extern crate kdtree;
extern crate rand;

use bencher::Bencher;

#[derive(Copy, Clone, PartialEq)]
pub struct Point2WithId {
    dims: [f64; 2],
    pub id: i32,
}

impl Point2WithId {
    pub fn new(id: i32, x: f64, y: f64) -> Point2WithId {
        Point2WithId {
            dims: [x, y],
            id: id,
        }
    }
}

impl kdtree::kdtree::KdtreePointTrait for Point2WithId {
    fn dims(&self) -> &[f64] {
        return &self.dims;
    }
}

#[derive(Copy, Clone, PartialEq)]
pub struct Point3WithId {
    dims: [f64; 3],
    pub id: i32,
}

impl Point3WithId {
    pub fn new(id: i32, x: f64, y: f64, z: f64) -> Point3WithId {
        Point3WithId {
            dims: [x, y, z],
            id: id,
        }
    }
}

impl kdtree::kdtree::KdtreePointTrait for Point3WithId {
    fn dims(&self) -> &[f64] {
        return &self.dims;
    }
}

fn bench_creating_1000_node_tree(b: &mut Bencher) {
    let len = 1000usize;
    let mut points : Vec<Point2WithId> = vec![];
    for id in 0..len {
        let x : f64 = rand::random();
        points.push(Point2WithId::new(id as i32, x, x));
    }

    b.iter(|| {
        kdtree::kdtree::Kdtree::new(points.clone());
    });
}

fn bench_single_loop_times_for_1000_node_tree(b: &mut Bencher) {
    let len = 1000usize;
    let mut points : Vec<Point3WithId> = vec![];

    for i in 0..len {
        points.push(Point3WithId::new(i as i32, rand::random(),rand::random(),rand::random()))

    }

    let tree = kdtree::kdtree::Kdtree::new(points.clone());

    b.iter(||  tree.nearest_search(&points[0]));
}

benchmark_group!(benches, bench_creating_1000_node_tree,bench_single_loop_times_for_1000_node_tree);
benchmark_main!(benches);<|endoftext|>


<commit_before>use std::convert::TryFrom;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::{thread, time};
use std::thread::JoinHandle;

use instruction::Instruction;
use peripherals::Peripherals;

use rand::{thread_rng, Rng};

const FONT_BASE_ADDR: usize = 0x0;
const NUM_FONTS: usize = 16;
const FONT_SIZE: usize = 5;
const FONT_MAP: [u8; NUM_FONTS * FONT_SIZE] =
    [0xF0, 0x90, 0x90, 0x90, 0xF0, 0x20, 0x60, 0x20, 0x20, 0x70, 0xF0, 0x10, 0xF0, 0x80, 0xF0,
     0xF0, 0x10, 0xF0, 0x10, 0xF0, 0x90, 0x90, 0xF0, 0x10, 0x10, 0xF0, 0x80, 0xF0, 0x10, 0xF0,
     0xF0, 0x80, 0xF0, 0x90, 0xF0, 0xF0, 0x10, 0x20, 0x40, 0x40, 0xF0, 0x90, 0xF0, 0x90, 0xF0,
     0xF0, 0x90, 0xF0, 0x10, 0xF0, 0xF0, 0x90, 0xF0, 0x90, 0x90, 0xE0, 0x90, 0xE0, 0x90, 0xE0,
     0xF0, 0x80, 0x80, 0x80, 0xF0, 0xF0, 0x80, 0x80, 0x80, 0xF0, 0xF0, 0x80, 0xF0, 0x80, 0xF0,
     0xF0, 0x80, 0xF0, 0x80, 0x80];

pub struct Chip8 {
    mem: Vec<u8>,
    reg_v: Vec<u8>,
    reg_i: u16,
    reg_delay_timer: Arc<AtomicUsize>,
    reg_sound_timer: u8,
    pc: usize,
    sp: usize,
    stack: Vec<usize>,

}

impl Chip8 {
    pub fn new(rom: &Vec<u8>) -> Chip8 {
        let mut chip8 = Chip8 {
            mem: vec![0; 0xFFF],
            reg_v: vec![0; 16],
            reg_i: 0,
            reg_delay_timer: Arc::new(AtomicUsize::new(0)),
            reg_sound_timer: 0,
            pc: 0x200,
            sp: 0,
            stack: vec![0; 16],

        };
        chip8.load_fonts();
        chip8.load_rom(rom);
        chip8
    }

    fn load_fonts(&mut self) {
        for i in FONT_BASE_ADDR..FONT_MAP.len() {
            self.mem[i] = FONT_MAP[i - FONT_BASE_ADDR]
        }
    }

    fn load_rom(&mut self, rom: &Vec<u8>) {
        for (b, buf_i) in rom.iter().enumerate() {
            self.mem[0x200 + b] = *buf_i;
        }
    }

    pub fn step(&mut self, peripherals: &mut Peripherals) {
        let hi_nibble = self.mem[self.pc] as u16;
        let lo_nibble = self.mem[self.pc + 1] as u16;
        let opcode = (hi_nibble << 8) | lo_nibble;
        match Instruction::try_from(opcode) {
            Err(msg) => panic!("Error decoding instruction at 0x{0:03x}: {1}", self.pc, msg),
            Ok(instruction) => self.step_instruction(instruction, peripherals),
        }
    }

    fn memory_read(&self, pos: usize) -> u8 {
        self.mem[pos]
    }

    fn memory_write(&mut self, pos: usize, data: u8) {
        self.mem[pos] = data;
        // println!("[W][0x{:03x}] 0x{:03x}", pos, data);
    }

    fn step_instruction(&mut self, instruction: Instruction, peripherals: &mut Peripherals) {
        match instruction {
            Instruction::Cls => peripherals.video_engine.cls(),
            Instruction::Ret => {
                assert!(self.sp > 0);
                self.sp -= 1;
                let old_pc = self.stack[self.sp];
                println!("Resuming execution at PC 0x{:x}", old_pc);
                self.pc = old_pc; // Jump to the instruction immediately after
            }
            Instruction::Jmp { addr } => self.pc = addr - 2, // Correct for pc increment later
            Instruction::Jsr { addr } => {
                self.stack[self.sp] = self.pc;
                self.sp += 1;
                self.pc = addr - 2
            } // Correct for pc increment later
            Instruction::Mov { vr, k } => self.reg_v[vr] = k,
            Instruction::Movr { vr, vy } => self.reg_v[vr] = self.reg_v[vy],
            Instruction::Shr { vr } => {
                let current_val = self.reg_v[vr];
                self.reg_v[0xF] = current_val & 1;
                self.reg_v[vr] = current_val >> 1;
            }
            Instruction::Skeq { vr, k } => {
                if self.reg_v[vr] == k {
                    self.pc += 2
                }
            }
            Instruction::Add { vr, k } => {
                let old_val = self.reg_v[vr];
                self.reg_v[vr] = old_val.wrapping_add(k);
            }
            Instruction::Addr { vr, vy } => {
                let old_r = self.reg_v[vr];
                let old_y = self.reg_v[vy];
                let (result, overflow) = old_r.overflowing_add(old_y);
                if overflow {
                    self.reg_v[0xF] = 1
                } else {
                    self.reg_v[0xF] = 0
                }
                self.reg_v[vr] = result;
            }
            Instruction::Mvi { k } => self.reg_i = k,
            Instruction::Rnd { vr, k } => {
                let mut buffer = [0u8; 1];
                thread_rng().fill_bytes(&mut buffer);
                self.reg_v[vr] = buffer[0] & k;
            }
            Instruction::Sprite { rx, ry, s } => {
                let x = self.reg_v[rx] as usize;
                let y = self.reg_v[ry] as usize;
                let height = s;
                self.reg_v[0xF] = 0;
                for yline in 0..height {
                    let mem_pos = self.reg_i as usize + yline as usize;
                    let pixel = self.memory_read(mem_pos);
                    for xline in 0..8 {
                        if pixel & (0x80 >> xline) != 0 {
                            let collision = peripherals.video_engine
                                .set_pixel_to_1(x + xline, y + yline);
                            if collision {
                                self.reg_v[0xF] = 1;
                            }
                        }

                    }
                }
            }
            Instruction::Skp { k } => {
                println!("Waiting for key {:?} to skip", k);
                let key = peripherals.keypad.get_current_key_input();
                match key {
                    Some(x) if x == k => self.pc += 2,
                    _ => {}
                }
            }
            Instruction::Key { vr } => {
                println!("Waiting for a key to be pressed");
                let key = peripherals.keypad.get_current_key_input();
                match key {
                    Some(x) => {
                        println!(" ... Got {:?}", x);
                        self.reg_v[vr] = x
                    },
                    _ => {
                        println!(" ... Waiting more");
                        self.pc -= 2; // Emulate a SLEEP
                    }
                }

            }
            Instruction::Adi { vr } => {
                self.reg_i += self.reg_v[vr] as u16;
            }
            Instruction::Font { vr } => {
                let character = self.reg_v[vr] as usize;
                self.reg_i = (FONT_BASE_ADDR + (character * FONT_SIZE)) as u16;
                println!("Font draw for character: {:x}", character);
            }
            Instruction::Bcd { vr } => {
                let value = self.reg_v[vr];
                println!("BCD DECODING OF {}", value);
                let i = self.reg_i as usize;
                self.mem[i] = value / 100;
                self.mem[i + 1] = (value / 10) % 10;
                self.mem[i + 2] = (value % 100) % 100;
            }
            Instruction::Str { vr } => {
                for idx in 0..(vr + 1) {
                    let target_pos = self.reg_i as usize + idx;
                    let data = self.reg_v[idx];
                    self.memory_write(target_pos, data);
                }
            }
            Instruction::Ldr { vr } => {
                for idx in 0..(vr + 1) {
                    self.reg_v[idx] = self.memory_read(self.reg_i as usize + idx)
                }
            }
            Instruction::Gdelay { vr } => {
                let amount = self.reg_delay_timer();
                self.reg_v[vr] = amount;
            }
            Instruction::Sdelay { vr } => {
                let amount = self.reg_v[vr];
                self.reg_delay_timer.store((amount + 1) as _, Ordering::SeqCst);
                let timer_clone = self.reg_delay_timer.clone();
                thread::spawn(move || loop {
                    let ticks_left = timer_clone.fetch_sub(1, Ordering::SeqCst) - 1;
                    if ticks_left > 0 {
                        println!("Still {} ticks left", ticks_left);
                        thread::sleep(time::Duration::from_millis(1000/60));
                    } else {
                        break;
                    }
                });
            }
        }
        self.pc += 2;
    }

    pub fn pc(&self) -> usize {
        self.pc
    }

    pub fn mem(&self) -> &Vec<u8> {
        &self.mem
    }

    pub fn reg_v(&self) -> &Vec<u8> {
        &self.reg_v
    }

    pub fn reg_i(&self) -> u16 {
        self.reg_i
    }

    pub fn reg_delay_timer(&self) -> u8 {
        self.reg_delay_timer.load(Ordering::SeqCst) as _
    }

    pub fn reg_sound_timer(&self) -> u8 {
        self.reg_sound_timer
    }

    pub fn stack(&self) -> &Vec<usize> {
        &self.stack
    }

    pub fn sp(&self) -> usize {
        self.sp
    }
}
<commit_msg>Fix font map for 'D' character<commit_after>use std::convert::TryFrom;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::{thread, time};
use std::thread::JoinHandle;

use instruction::Instruction;
use peripherals::Peripherals;

use rand::{thread_rng, Rng};

const FONT_BASE_ADDR: usize = 0x0;
const NUM_FONTS: usize = 16;
const FONT_SIZE: usize = 5;
const FONT_MAP: [u8; NUM_FONTS * FONT_SIZE] =
    [0xF0, 0x90, 0x90, 0x90, 0xF0, 0x20, 0x60, 0x20, 0x20, 0x70, 0xF0, 0x10, 0xF0, 0x80, 0xF0,
     0xF0, 0x10, 0xF0, 0x10, 0xF0, 0x90, 0x90, 0xF0, 0x10, 0x10, 0xF0, 0x80, 0xF0, 0x10, 0xF0,
     0xF0, 0x80, 0xF0, 0x90, 0xF0, 0xF0, 0x10, 0x20, 0x40, 0x40, 0xF0, 0x90, 0xF0, 0x90, 0xF0,
     0xF0, 0x90, 0xF0, 0x10, 0xF0, 0xF0, 0x90, 0xF0, 0x90, 0x90, 0xE0, 0x90, 0xE0, 0x90, 0xE0,
     0xF0, 0x80, 0x80, 0x80, 0xF0, 0xE0, 0x90, 0x90, 0x90, 0xE0, 0xF0, 0x80, 0xF0, 0x80, 0xF0,
     0xF0, 0x80, 0xF0, 0x80, 0x80];

pub struct Chip8 {
    mem: Vec<u8>,
    reg_v: Vec<u8>,
    reg_i: u16,
    reg_delay_timer: Arc<AtomicUsize>,
    reg_sound_timer: u8,
    pc: usize,
    sp: usize,
    stack: Vec<usize>,

}

impl Chip8 {
    pub fn new(rom: &Vec<u8>) -> Chip8 {
        let mut chip8 = Chip8 {
            mem: vec![0; 0xFFF],
            reg_v: vec![0; 16],
            reg_i: 0,
            reg_delay_timer: Arc::new(AtomicUsize::new(0)),
            reg_sound_timer: 0,
            pc: 0x200,
            sp: 0,
            stack: vec![0; 16],

        };
        chip8.load_fonts();
        chip8.load_rom(rom);
        chip8
    }

    fn load_fonts(&mut self) {
        for i in FONT_BASE_ADDR..FONT_MAP.len() {
            self.mem[i] = FONT_MAP[i - FONT_BASE_ADDR]
        }
    }

    fn load_rom(&mut self, rom: &Vec<u8>) {
        for (b, buf_i) in rom.iter().enumerate() {
            self.mem[0x200 + b] = *buf_i;
        }
    }

    pub fn step(&mut self, peripherals: &mut Peripherals) {
        let hi_nibble = self.mem[self.pc] as u16;
        let lo_nibble = self.mem[self.pc + 1] as u16;
        let opcode = (hi_nibble << 8) | lo_nibble;
        match Instruction::try_from(opcode) {
            Err(msg) => panic!("Error decoding instruction at 0x{0:03x}: {1}", self.pc, msg),
            Ok(instruction) => self.step_instruction(instruction, peripherals),
        }
    }

    fn memory_read(&self, pos: usize) -> u8 {
        self.mem[pos]
    }

    fn memory_write(&mut self, pos: usize, data: u8) {
        self.mem[pos] = data;
        // println!("[W][0x{:03x}] 0x{:03x}", pos, data);
    }

    fn step_instruction(&mut self, instruction: Instruction, peripherals: &mut Peripherals) {
        match instruction {
            Instruction::Cls => peripherals.video_engine.cls(),
            Instruction::Ret => {
                assert!(self.sp > 0);
                self.sp -= 1;
                let old_pc = self.stack[self.sp];
                println!("Resuming execution at PC 0x{:x}", old_pc);
                self.pc = old_pc; // Jump to the instruction immediately after
            }
            Instruction::Jmp { addr } => self.pc = addr - 2, // Correct for pc increment later
            Instruction::Jsr { addr } => {
                self.stack[self.sp] = self.pc;
                self.sp += 1;
                self.pc = addr - 2
            } // Correct for pc increment later
            Instruction::Mov { vr, k } => self.reg_v[vr] = k,
            Instruction::Movr { vr, vy } => self.reg_v[vr] = self.reg_v[vy],
            Instruction::Shr { vr } => {
                let current_val = self.reg_v[vr];
                self.reg_v[0xF] = current_val & 1;
                self.reg_v[vr] = current_val >> 1;
            }
            Instruction::Skeq { vr, k } => {
                if self.reg_v[vr] == k {
                    self.pc += 2
                }
            }
            Instruction::Add { vr, k } => {
                let old_val = self.reg_v[vr];
                self.reg_v[vr] = old_val.wrapping_add(k);
            }
            Instruction::Addr { vr, vy } => {
                let old_r = self.reg_v[vr];
                let old_y = self.reg_v[vy];
                let (result, overflow) = old_r.overflowing_add(old_y);
                if overflow {
                    self.reg_v[0xF] = 1
                } else {
                    self.reg_v[0xF] = 0
                }
                self.reg_v[vr] = result;
            }
            Instruction::Mvi { k } => self.reg_i = k,
            Instruction::Rnd { vr, k } => {
                let mut buffer = [0u8; 1];
                thread_rng().fill_bytes(&mut buffer);
                self.reg_v[vr] = buffer[0] & k;
            }
            Instruction::Sprite { rx, ry, s } => {
                let x = self.reg_v[rx] as usize;
                let y = self.reg_v[ry] as usize;
                let height = s;
                self.reg_v[0xF] = 0;
                for yline in 0..height {
                    let mem_pos = self.reg_i as usize + yline as usize;
                    let pixel = self.memory_read(mem_pos);
                    for xline in 0..8 {
                        if pixel & (0x80 >> xline) != 0 {
                            let collision = peripherals.video_engine
                                .set_pixel_to_1(x + xline, y + yline);
                            if collision {
                                self.reg_v[0xF] = 1;
                            }
                        }

                    }
                }
            }
            Instruction::Skp { k } => {
                println!("Waiting for key {:?} to skip", k);
                let key = peripherals.keypad.get_current_key_input();
                match key {
                    Some(x) if x == k => self.pc += 2,
                    _ => {}
                }
            }
            Instruction::Key { vr } => {
                println!("Waiting for a key to be pressed");
                let key = peripherals.keypad.get_current_key_input();
                match key {
                    Some(x) => {
                        println!(" ... Got {:?}", x);
                        self.reg_v[vr] = x
                    },
                    _ => {
                        println!(" ... Waiting more");
                        self.pc -= 2; // Emulate a SLEEP
                    }
                }

            }
            Instruction::Adi { vr } => {
                self.reg_i += self.reg_v[vr] as u16;
            }
            Instruction::Font { vr } => {
                let character = self.reg_v[vr] as usize;
                self.reg_i = (FONT_BASE_ADDR + (character * FONT_SIZE)) as u16;
                println!("Font draw for character: {:x}", character);
            }
            Instruction::Bcd { vr } => {
                let value = self.reg_v[vr];
                println!("BCD DECODING OF {}", value);
                let i = self.reg_i as usize;
                self.mem[i] = value / 100;
                self.mem[i + 1] = (value / 10) % 10;
                self.mem[i + 2] = (value % 100) % 100;
            }
            Instruction::Str { vr } => {
                for idx in 0..(vr + 1) {
                    let target_pos = self.reg_i as usize + idx;
                    let data = self.reg_v[idx];
                    self.memory_write(target_pos, data);
                }
            }
            Instruction::Ldr { vr } => {
                for idx in 0..(vr + 1) {
                    self.reg_v[idx] = self.memory_read(self.reg_i as usize + idx)
                }
            }
            Instruction::Gdelay { vr } => {
                let amount = self.reg_delay_timer();
                self.reg_v[vr] = amount;
            }
            Instruction::Sdelay { vr } => {
                let amount = self.reg_v[vr];
                self.reg_delay_timer.store((amount + 1) as _, Ordering::SeqCst);
                let timer_clone = self.reg_delay_timer.clone();
                thread::spawn(move || loop {
                    let ticks_left = timer_clone.fetch_sub(1, Ordering::SeqCst) - 1;
                    if ticks_left > 0 {
                        println!("Still {} ticks left", ticks_left);
                        thread::sleep(time::Duration::from_millis(1000/60));
                    } else {
                        break;
                    }
                });
            }
        }
        self.pc += 2;
    }

    pub fn pc(&self) -> usize {
        self.pc
    }

    pub fn mem(&self) -> &Vec<u8> {
        &self.mem
    }

    pub fn reg_v(&self) -> &Vec<u8> {
        &self.reg_v
    }

    pub fn reg_i(&self) -> u16 {
        self.reg_i
    }

    pub fn reg_delay_timer(&self) -> u8 {
        self.reg_delay_timer.load(Ordering::SeqCst) as _
    }

    pub fn reg_sound_timer(&self) -> u8 {
        self.reg_sound_timer
    }

    pub fn stack(&self) -> &Vec<usize> {
        &self.stack
    }

    pub fn sp(&self) -> usize {
        self.sp
    }
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::fmt;
use std::iter::{FromIterator, IntoIterator};
use std::rc::Rc;

use number::Number;
use parser::SPECIAL_TOKEN_MAP;

/// Datum is the primary data type of Scheme
/// Datum is a generic type here to make parser somewhat independent from runtime
/// Ext can hold runtime data not representable in datum syntax, such as primitive function or I/O
/// ports
#[derive(PartialEq, Clone)]
pub enum Datum<T> {
    /// Symbol
    Sym(Cow<'static, str>),
    /// Boolean
    Bool(bool),
    /// Character
    Char(char),
    /// String
    String(Rc<String>),
    /// Vector
    Vector(Rc<Vec<Datum<T>>>),
    /// Byte vector
    Bytes(Rc<Vec<u8>>),
    /// Numeric value
    Num(Number),
    /// `()`
    Nil,
    /// Pair
    Cons(Rc<(Datum<T>, Datum<T>)>),
    /// Extra values
    Ext(T)
}

fn format_char(c: char, f: &mut fmt::Formatter) -> fmt::Result {
    try!(write!(f, "#\\"));
    match c {
        '\0' => write!(f, "nul"),
        '\x08' => write!(f, "backspace"),
        '\t' => write!(f, "tab"),
        '\x0c' => write!(f, "page"),
        '\r' => write!(f, "return"),
        ' ' => write!(f, "space"),
        '!'...'~' => write!(f, "{}", c),
        _ => write!(f, "x{:x}", c as usize)
    }
}

trait DatumFormatter<T> {
    fn ext_fmt(&self, &T, &mut fmt::Formatter) -> fmt::Result;

    fn datum_fmt(&self, datum: &Datum<T>, f: &mut fmt::Formatter) -> fmt::Result {
        match *datum {
            Datum::Sym(ref s) => write!(f, "{}", s),
            Datum::Bool(true) => write!(f, "#t"),
            Datum::Bool(false) => write!(f, "#f"),
            Datum::Char(c) => format_char(c, f),
            Datum::String(ref s) => write!(f, "{:?}", s),
            Datum::Vector(ref vec) => {
                if vec.is_empty() {
                    write!(f, "#()")
                } else {
                    try!(write!(f, "#("));
                    try!(self.datum_fmt(&vec[0], f));
                    for x in vec[1..].iter() {
                        try!(f.write_str(" "));
                        try!(self.datum_fmt(x, f));
                    }
                    write!(f, ")")
                }
            },
            Datum::Bytes(ref vec) => {
                if vec.is_empty() {
                    write!(f, "#vu8()")
                } else {
                    try!(write!(f, "#vu8({}", vec[0]));
                    for x in vec[1..].iter() {
                        try!(write!(f, " {}", x));
                    }
                    write!(f, ")")
                }
            },
            Datum::Num(ref n) => write!(f, "{}", n),
            Datum::Ext(ref x) => self.ext_fmt(x, f),
            Datum::Nil => write!(f, "()"),
            Datum::Cons(ref pair) => {
                if let Datum::Sym(ref s) = pair.0 {
                    match SPECIAL_TOKEN_MAP.get(s.as_ref()) {
                        Some(ch) => if let Datum::Cons(ref tail) = pair.1 {
                            if let Datum::Nil = tail.1 {
                                try!(write!(f, "{}", ch));
                                return self.datum_fmt(&tail.0, f);
                            }
                        },
                        _ => ()
                    }
                }
                try!(write!(f, "("));
                try!(self.datum_fmt(&pair.0, f));
                self.write_cons(&pair.1, f)
            }
        }
    }

    fn write_cons(&self, tail: &Datum<T>, f: &mut fmt::Formatter) -> fmt::Result {
        match tail {
            &Datum::Nil => {
                write!(f, ")")
            },
            &Datum::Cons(ref pair) => {
                try!(write!(f, " "));
                try!(self.datum_fmt(&pair.0, f));
                self.write_cons(&pair.1, f)
            },
            _ => {
                try!(write!(f, " . "));
                try!(self.datum_fmt(&tail, f));
                write!(f, ")")
            }
        }
    }
}

struct DebugFormatter;

impl<T: fmt::Debug> DatumFormatter<T> for DebugFormatter {
    fn ext_fmt(&self, ext: &T, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", ext)
    }
}

impl<T: fmt::Debug> fmt::Debug for Datum<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let debug_fmt = DebugFormatter;

        debug_fmt.datum_fmt(self, f)
    }
}

struct DisplayFormatter;

impl<T: fmt::Display> DatumFormatter<T> for DisplayFormatter {
    fn ext_fmt(&self, ext: &T, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", ext)
    }
}

impl<T: fmt::Display> fmt::Display for Datum<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let debug_fmt = DisplayFormatter;

        debug_fmt.datum_fmt(self, f)
    }
}

impl<T: Clone> Datum<T> {
    /// Iterate the values if it's a proper list
    pub fn iter(&self) -> DatumIter<T> {
        DatumIter { ptr: self.clone() }
    }
}

pub trait TryConv<T, E> {
    fn try_conv(&self) -> Result<T, E>;
}

impl<E> TryConv<(), E> for () {
    fn try_conv(&self) -> Result<(), E> {
        Ok(())
    }
}

impl<S, T, E> TryConv<Datum<T>, E> for Datum<S> where S: TryConv<T, E> {
    fn try_conv(&self) -> Result<Datum<T>, E> {
        match self {
            &Datum::Sym(ref v) => Ok(Datum::Sym(v.clone())),
            &Datum::Bool(ref v) => Ok(Datum::Bool(*v)),
            &Datum::Char(ref v) => Ok(Datum::Char(*v)),
            &Datum::String(ref v) => Ok(Datum::String(v.clone())),
            &Datum::Vector(ref v) => {
                let res: Result<Vec<Datum<T>>, E> = v.iter().map(|x| x.try_conv()).collect();
                res.map(|v| Datum::Vector(Rc::new(v)))
            },
            &Datum::Bytes(ref v) => Ok(Datum::Bytes(v.clone())),
            &Datum::Num(ref v) => Ok(Datum::Num(v.clone())),
            &Datum::Nil => Ok(Datum::Nil),
            &Datum::Cons(ref v) => {
                let h = try!(v.0.try_conv());
                let t = try!(v.1.try_conv());
                Ok(Datum::Cons(Rc::new((h, t))))
            },
            &Datum::Ext(ref v) => v.try_conv().map(Datum::Ext)
        }
    }
}

/// If the datum is a proper list, iterate the values in the list.
/// If it's not a list, returns Err(()) when the iterator meets non-null cdr
pub struct DatumIter<T> {
    ptr: Datum<T>
}

impl<T: Clone> Iterator for DatumIter<T> {
    type Item = Result<Datum<T>, ()>;

    fn next(&mut self) -> Option<Result<Datum<T>, ()>> {
        let (val, next) = match self.ptr {
            Datum::Nil => return None,
            Datum::Cons(ref pair) => {
                (pair.0.clone(), pair.1.clone())
            }
            _ => return Some(Err(()))
        };

        self.ptr = next;

        Some(Ok(val))
    }
}

impl<T> FromIterator<Datum<T>> for Datum<T> {
    fn from_iter<Iter: IntoIterator<Item=Datum<T>> >(iterator: Iter) -> Datum<T> {
        let list:Vec<Datum<T>> = FromIterator::from_iter(iterator);
        let mut res = Datum::Nil;
        for d in list.into_iter().rev() {
            res = cons(d, res);
        }
        return res;
    }
}

/// `cons` the values into a pair
pub fn cons<T>(head: Datum<T>, tail: Datum<T>) -> Datum<T> {
    Datum::Cons(Rc::new((head, tail)))
}

pub fn concat<T: Clone>(x: Datum<T>, y: Datum<T>) -> Result<Datum<T>, ()> {
    match x {
        Datum::Nil => Ok(y),
        Datum::Cons(pair) => {
            concat(pair.1.clone(), y).map(|new_y| cons(pair.0.clone(), new_y))
        },
        _ => Err(())
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum SimpleDatum {
    Sym(Cow<'static, str>),
    Bool(bool),
    Char(char),
    String(Rc<String>),
    Bytes(Rc<Vec<u8>>),
    Num(Number),
    Nil
}

impl SimpleDatum {
    pub fn from_datum<T>(datum: Datum<T>) -> Option<SimpleDatum> {
        match datum {
            Datum::Sym(s) => Some(SimpleDatum::Sym(s)),
            Datum::Bool(b) => Some(SimpleDatum::Bool(b)),
            Datum::Char(c) => Some(SimpleDatum::Char(c)),
            Datum::String(s) => Some(SimpleDatum::String(s)),
            Datum::Bytes(v) => Some(SimpleDatum::Bytes(v)),
            Datum::Num(n) => Some(SimpleDatum::Num(n)),
            Datum::Nil => Some(SimpleDatum::Nil),
            _ => None
        }
    }
}

#[cfg(test)]
mod test {
    use super::{Datum, cons};
    use number::Number;
    use std::borrow::Cow;
    use std::rc::Rc;

    use num::FromPrimitive;

    fn compare_fmt(s: &str, datum: Datum<()>) {
        assert_eq!(s.to_string(), format!("{:?}", datum))
    }

    #[test]
    fn test_fmt() {
        compare_fmt("a", sym!("a"));
        compare_fmt("()", list!());
        compare_fmt("(a)", list!(sym!("a")));
        compare_fmt("(a b)", list!(sym!("a"), sym!("b")));
        compare_fmt("(a . b)", cons(sym!("a"), sym!("b")));
    }

    #[test]
    fn test_vec_fmt() {
        compare_fmt("#(a b)", Datum::Vector(Rc::new(vec![sym!("a"), sym!("b")])));
        compare_fmt("#()", Datum::Vector(Rc::new(Vec::new())));
    }

    #[test]
    fn test_bytes_fmt() {
        compare_fmt("#vu8(1 2 3)", Datum::Bytes(Rc::new(vec![1, 2, 3])));
        compare_fmt("#vu8()", Datum::Bytes(Rc::new(Vec::new())));
    }

    #[test]
    fn test_quote_abbrev() {
        compare_fmt("'a", list!(sym!("quote"), sym!("a")));
        compare_fmt("'(a b)", list!(sym!("quote"), list!(sym!("a"), sym!("b"))));
        compare_fmt("`a", list!(sym!("quasiquote"), sym!("a")));
        compare_fmt(",a", list!(sym!("unquote"), sym!("a")));
        compare_fmt(",@a", list!(sym!("unquote-splicing"), sym!("a")));

        compare_fmt("#'a", list!(sym!("syntax"), sym!("a")));
        compare_fmt("#'(a b)", list!(sym!("syntax"), list!(sym!("a"), sym!("b"))));
        compare_fmt("#`a", list!(sym!("quasisyntax"), sym!("a")));
        compare_fmt("#,a", list!(sym!("unsyntax"), sym!("a")));
        compare_fmt("#,@a", list!(sym!("unsyntax-splicing"), sym!("a")));
    }

    #[test]
    fn test_iter() {
        let n1 = FromPrimitive::from_isize(1).unwrap();
        let n2 = FromPrimitive::from_isize(2).unwrap();
        let list: Datum<()> = list!(num!(1), num!(2));

        assert_eq!(Ok(vec![Datum::Num(n1), Datum::Num(n2)]), list.iter().collect());
    }
}
<commit_msg>Datum::improper_list<commit_after>use std::borrow::Cow;
use std::fmt;
use std::iter::{FromIterator, IntoIterator};
use std::rc::Rc;

use number::Number;
use parser::SPECIAL_TOKEN_MAP;

/// Datum is the primary data type of Scheme
/// Datum is a generic type here to make parser somewhat independent from runtime
/// Ext can hold runtime data not representable in datum syntax, such as primitive function or I/O
/// ports
#[derive(PartialEq, Clone)]
pub enum Datum<T> {
    /// Symbol
    Sym(Cow<'static, str>),
    /// Boolean
    Bool(bool),
    /// Character
    Char(char),
    /// String
    String(Rc<String>),
    /// Vector
    Vector(Rc<Vec<Datum<T>>>),
    /// Byte vector
    Bytes(Rc<Vec<u8>>),
    /// Numeric value
    Num(Number),
    /// `()`
    Nil,
    /// Pair
    Cons(Rc<(Datum<T>, Datum<T>)>),
    /// Extra values
    Ext(T)
}

fn format_char(c: char, f: &mut fmt::Formatter) -> fmt::Result {
    try!(write!(f, "#\\"));
    match c {
        '\0' => write!(f, "nul"),
        '\x08' => write!(f, "backspace"),
        '\t' => write!(f, "tab"),
        '\x0c' => write!(f, "page"),
        '\r' => write!(f, "return"),
        ' ' => write!(f, "space"),
        '!'...'~' => write!(f, "{}", c),
        _ => write!(f, "x{:x}", c as usize)
    }
}

trait DatumFormatter<T> {
    fn ext_fmt(&self, &T, &mut fmt::Formatter) -> fmt::Result;

    fn datum_fmt(&self, datum: &Datum<T>, f: &mut fmt::Formatter) -> fmt::Result {
        match *datum {
            Datum::Sym(ref s) => write!(f, "{}", s),
            Datum::Bool(true) => write!(f, "#t"),
            Datum::Bool(false) => write!(f, "#f"),
            Datum::Char(c) => format_char(c, f),
            Datum::String(ref s) => write!(f, "{:?}", s),
            Datum::Vector(ref vec) => {
                if vec.is_empty() {
                    write!(f, "#()")
                } else {
                    try!(write!(f, "#("));
                    try!(self.datum_fmt(&vec[0], f));
                    for x in vec[1..].iter() {
                        try!(f.write_str(" "));
                        try!(self.datum_fmt(x, f));
                    }
                    write!(f, ")")
                }
            },
            Datum::Bytes(ref vec) => {
                if vec.is_empty() {
                    write!(f, "#vu8()")
                } else {
                    try!(write!(f, "#vu8({}", vec[0]));
                    for x in vec[1..].iter() {
                        try!(write!(f, " {}", x));
                    }
                    write!(f, ")")
                }
            },
            Datum::Num(ref n) => write!(f, "{}", n),
            Datum::Ext(ref x) => self.ext_fmt(x, f),
            Datum::Nil => write!(f, "()"),
            Datum::Cons(ref pair) => {
                if let Datum::Sym(ref s) = pair.0 {
                    match SPECIAL_TOKEN_MAP.get(s.as_ref()) {
                        Some(ch) => if let Datum::Cons(ref tail) = pair.1 {
                            if let Datum::Nil = tail.1 {
                                try!(write!(f, "{}", ch));
                                return self.datum_fmt(&tail.0, f);
                            }
                        },
                        _ => ()
                    }
                }
                try!(write!(f, "("));
                try!(self.datum_fmt(&pair.0, f));
                self.write_cons(&pair.1, f)
            }
        }
    }

    fn write_cons(&self, tail: &Datum<T>, f: &mut fmt::Formatter) -> fmt::Result {
        match tail {
            &Datum::Nil => {
                write!(f, ")")
            },
            &Datum::Cons(ref pair) => {
                try!(write!(f, " "));
                try!(self.datum_fmt(&pair.0, f));
                self.write_cons(&pair.1, f)
            },
            _ => {
                try!(write!(f, " . "));
                try!(self.datum_fmt(&tail, f));
                write!(f, ")")
            }
        }
    }
}

struct DebugFormatter;

impl<T: fmt::Debug> DatumFormatter<T> for DebugFormatter {
    fn ext_fmt(&self, ext: &T, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", ext)
    }
}

impl<T: fmt::Debug> fmt::Debug for Datum<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let debug_fmt = DebugFormatter;

        debug_fmt.datum_fmt(self, f)
    }
}

struct DisplayFormatter;

impl<T: fmt::Display> DatumFormatter<T> for DisplayFormatter {
    fn ext_fmt(&self, ext: &T, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", ext)
    }
}

impl<T: fmt::Display> fmt::Display for Datum<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let debug_fmt = DisplayFormatter;

        debug_fmt.datum_fmt(self, f)
    }
}

impl<T: Clone> Datum<T> {
    /// Iterate the values if it's a proper list
    pub fn iter(&self) -> DatumIter<T> {
        DatumIter { ptr: self.clone() }
    }

    pub fn improper_list(&self) -> (Vec<Datum<T>>, Option<Datum<T>>) {
        let mut list = Vec::new();
        let mut iter = self.clone();

        loop {
            let next = match iter {
                Datum::Cons(ref pair) => {
                    list.push(pair.0.clone());
                    pair.1.clone()
                },
                Datum::Nil => return (list, None),
                _ => return (list, Some(iter))
            };
            iter = next;
        }
    }
}

pub trait TryConv<T, E> {
    fn try_conv(&self) -> Result<T, E>;
}

impl<E> TryConv<(), E> for () {
    fn try_conv(&self) -> Result<(), E> {
        Ok(())
    }
}

impl<S, T, E> TryConv<Datum<T>, E> for Datum<S> where S: TryConv<T, E> {
    fn try_conv(&self) -> Result<Datum<T>, E> {
        match self {
            &Datum::Sym(ref v) => Ok(Datum::Sym(v.clone())),
            &Datum::Bool(ref v) => Ok(Datum::Bool(*v)),
            &Datum::Char(ref v) => Ok(Datum::Char(*v)),
            &Datum::String(ref v) => Ok(Datum::String(v.clone())),
            &Datum::Vector(ref v) => {
                let res: Result<Vec<Datum<T>>, E> = v.iter().map(|x| x.try_conv()).collect();
                res.map(|v| Datum::Vector(Rc::new(v)))
            },
            &Datum::Bytes(ref v) => Ok(Datum::Bytes(v.clone())),
            &Datum::Num(ref v) => Ok(Datum::Num(v.clone())),
            &Datum::Nil => Ok(Datum::Nil),
            &Datum::Cons(ref v) => {
                let h = try!(v.0.try_conv());
                let t = try!(v.1.try_conv());
                Ok(Datum::Cons(Rc::new((h, t))))
            },
            &Datum::Ext(ref v) => v.try_conv().map(Datum::Ext)
        }
    }
}

/// If the datum is a proper list, iterate the values in the list.
/// If it's not a list, returns Err(()) when the iterator meets non-null cdr
pub struct DatumIter<T> {
    ptr: Datum<T>
}

impl<T: Clone> Iterator for DatumIter<T> {
    type Item = Result<Datum<T>, ()>;

    fn next(&mut self) -> Option<Result<Datum<T>, ()>> {
        let (val, next) = match self.ptr {
            Datum::Nil => return None,
            Datum::Cons(ref pair) => {
                (pair.0.clone(), pair.1.clone())
            }
            _ => return Some(Err(()))
        };

        self.ptr = next;

        Some(Ok(val))
    }
}

impl<T> FromIterator<Datum<T>> for Datum<T> {
    fn from_iter<Iter: IntoIterator<Item=Datum<T>> >(iterator: Iter) -> Datum<T> {
        let list:Vec<Datum<T>> = FromIterator::from_iter(iterator);
        let mut res = Datum::Nil;
        for d in list.into_iter().rev() {
            res = cons(d, res);
        }
        return res;
    }
}

/// `cons` the values into a pair
pub fn cons<T>(head: Datum<T>, tail: Datum<T>) -> Datum<T> {
    Datum::Cons(Rc::new((head, tail)))
}

pub fn concat<T: Clone>(x: Datum<T>, y: Datum<T>) -> Result<Datum<T>, ()> {
    match x {
        Datum::Nil => Ok(y),
        Datum::Cons(pair) => {
            concat(pair.1.clone(), y).map(|new_y| cons(pair.0.clone(), new_y))
        },
        _ => Err(())
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum SimpleDatum {
    Sym(Cow<'static, str>),
    Bool(bool),
    Char(char),
    String(Rc<String>),
    Bytes(Rc<Vec<u8>>),
    Num(Number),
    Nil
}

impl SimpleDatum {
    pub fn from_datum<T>(datum: Datum<T>) -> Option<SimpleDatum> {
        match datum {
            Datum::Sym(s) => Some(SimpleDatum::Sym(s)),
            Datum::Bool(b) => Some(SimpleDatum::Bool(b)),
            Datum::Char(c) => Some(SimpleDatum::Char(c)),
            Datum::String(s) => Some(SimpleDatum::String(s)),
            Datum::Bytes(v) => Some(SimpleDatum::Bytes(v)),
            Datum::Num(n) => Some(SimpleDatum::Num(n)),
            Datum::Nil => Some(SimpleDatum::Nil),
            _ => None
        }
    }
}

#[cfg(test)]
mod test {
    use super::{Datum, cons};
    use number::Number;
    use std::borrow::Cow;
    use std::rc::Rc;

    use num::FromPrimitive;

    fn compare_fmt(s: &str, datum: Datum<()>) {
        assert_eq!(s.to_string(), format!("{:?}", datum))
    }

    #[test]
    fn test_fmt() {
        compare_fmt("a", sym!("a"));
        compare_fmt("()", list!());
        compare_fmt("(a)", list!(sym!("a")));
        compare_fmt("(a b)", list!(sym!("a"), sym!("b")));
        compare_fmt("(a . b)", cons(sym!("a"), sym!("b")));
    }

    #[test]
    fn test_vec_fmt() {
        compare_fmt("#(a b)", Datum::Vector(Rc::new(vec![sym!("a"), sym!("b")])));
        compare_fmt("#()", Datum::Vector(Rc::new(Vec::new())));
    }

    #[test]
    fn test_bytes_fmt() {
        compare_fmt("#vu8(1 2 3)", Datum::Bytes(Rc::new(vec![1, 2, 3])));
        compare_fmt("#vu8()", Datum::Bytes(Rc::new(Vec::new())));
    }

    #[test]
    fn test_quote_abbrev() {
        compare_fmt("'a", list!(sym!("quote"), sym!("a")));
        compare_fmt("'(a b)", list!(sym!("quote"), list!(sym!("a"), sym!("b"))));
        compare_fmt("`a", list!(sym!("quasiquote"), sym!("a")));
        compare_fmt(",a", list!(sym!("unquote"), sym!("a")));
        compare_fmt(",@a", list!(sym!("unquote-splicing"), sym!("a")));

        compare_fmt("#'a", list!(sym!("syntax"), sym!("a")));
        compare_fmt("#'(a b)", list!(sym!("syntax"), list!(sym!("a"), sym!("b"))));
        compare_fmt("#`a", list!(sym!("quasisyntax"), sym!("a")));
        compare_fmt("#,a", list!(sym!("unsyntax"), sym!("a")));
        compare_fmt("#,@a", list!(sym!("unsyntax-splicing"), sym!("a")));
    }

    #[test]
    fn test_iter() {
        let n1 = FromPrimitive::from_isize(1).unwrap();
        let n2 = FromPrimitive::from_isize(2).unwrap();
        let list: Datum<()> = list!(num!(1), num!(2));

        assert_eq!(Ok(vec![Datum::Num(n1), Datum::Num(n2)]), list.iter().collect());
    }

    #[test]
    fn test_improper_list() {
        let data: Datum<()> = Datum::Cons(Rc::new((
            sym!("a"),
            Datum::Cons(Rc::new((sym!("b"), sym!("c"))))
        )));

        assert_eq!((vec![sym!("a"), sym!("b")], Some(sym!("c"))), data.improper_list());
    }
}
<|endoftext|>