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

extern crate libc;

use std::clone::Clone;
use std::task::try_future;
use std::io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::iter::Iterator;

use datalink::{datalink_channel, DataLinkChannelType};
use packet::Packet;
use packet::ethernet::{EtherTypes, EthernetHeader, MutableEthernetHeader, EthernetPacket};
use packet::ip::{IpNextHeaderProtocols, IpNextHeaderProtocol};
use packet::ipv4::{Ipv4Header, MutableIpv4Header, Ipv4Packet};
use packet::ipv6::{MutableIpv6Header, Ipv6Packet};
use packet::udp::{UdpHeader, MutableUdpHeader, UdpPacket};
use transport::{udp_header_iter, ipv4_header_iter, transport_channel, TransportProtocol,
                TransportChannelType};
use transport::TransportProtocol::{Ipv4, Ipv6};
use util::NetworkInterface;

const MIN_PACKET_SIZE: uint = 64;
const ETHERNET_HEADER_LEN: uint = 14;
const IPV4_HEADER_LEN: uint = 20;
const IPV6_HEADER_LEN: uint = 40;
const UDP_HEADER_LEN: uint = 8;
const TEST_DATA_LEN: uint = 4;

const IPV4_SOURCE: IpAddr = Ipv4Addr(127, 0, 0, 1);
const IPV4_DESTINATION: IpAddr = Ipv4Addr(127, 0, 0, 1);
const IPV6_SOURCE: IpAddr = Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1);
const IPV6_DESTINATION: IpAddr = Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1);

// Use a protocol which is unlikely to have other packets on
const TEST_PROTO: IpNextHeaderProtocol = IpNextHeaderProtocols::Test1;

fn build_ipv4_header(packet: &mut [u8], offset: uint) {
    let mut ip_header = MutableIpv4Header::new(packet.slice_from_mut(offset));

    let total_len = (IPV4_HEADER_LEN + UDP_HEADER_LEN + TEST_DATA_LEN) as u16;

    ip_header.set_version(4);
    ip_header.set_header_length(5);
    ip_header.set_total_length(total_len);
    ip_header.set_ttl(4);
    ip_header.set_next_level_protocol(TEST_PROTO);
    ip_header.set_source(IPV4_SOURCE);
    ip_header.set_destination(IPV4_DESTINATION);
    ip_header.checksum();
}

fn build_ipv6_header(packet: &mut [u8], offset: uint) {
    let mut ip_header = MutableIpv6Header::new(packet.slice_from_mut(offset));

    ip_header.set_version(6);
    ip_header.set_payload_length((UDP_HEADER_LEN + TEST_DATA_LEN) as u16);
    ip_header.set_next_header(TEST_PROTO);
    ip_header.set_hop_limit(4);
    ip_header.set_source(IPV6_SOURCE);
    ip_header.set_destination(IPV6_DESTINATION);
}

fn build_udp_header(packet: &mut [u8], offset: uint) {
    let mut udp_header = MutableUdpHeader::new(packet.slice_from_mut(offset));

    udp_header.set_source(1234); // Arbitary port number
    udp_header.set_destination(1234);
    udp_header.set_length((UDP_HEADER_LEN + TEST_DATA_LEN) as u16);
}

fn build_udp4_packet(packet: &mut [u8], start: uint, msg: &str) {
    build_ipv4_header(packet, start);
    build_udp_header(packet, start + IPV4_HEADER_LEN as uint);

    let data_start = start + IPV4_HEADER_LEN + UDP_HEADER_LEN;
    packet[data_start + 0] = msg.char_at(0) as u8;
    packet[data_start + 1] = msg.char_at(1) as u8;
    packet[data_start + 2] = msg.char_at(2) as u8;
    packet[data_start + 3] = msg.char_at(3) as u8;

    let slice = packet.slice_from_mut(start + IPV4_HEADER_LEN as uint);
    MutableUdpHeader::new(slice).checksum(IPV4_SOURCE, IPV4_DESTINATION, TEST_PROTO);
}

fn build_udp6_packet(packet: &mut [u8], start: uint, msg: &str) {
    build_ipv6_header(packet, start);
    build_udp_header(packet, start + IPV6_HEADER_LEN as uint);

    let data_start = start + IPV6_HEADER_LEN + UDP_HEADER_LEN;
    packet[data_start + 0] = msg.char_at(0) as u8;
    packet[data_start + 1] = msg.char_at(1) as u8;
    packet[data_start + 2] = msg.char_at(2) as u8;
    packet[data_start + 3] = msg.char_at(3) as u8;

    let slice = packet.slice_from_mut(start + IPV6_HEADER_LEN as uint);
    MutableUdpHeader::new(slice).checksum(IPV6_SOURCE, IPV6_DESTINATION, TEST_PROTO);
}

fn get_test_interface() -> NetworkInterface {
    use std::os::getenv;
    use util;

    (*util::get_network_interfaces()
        .as_slice().iter()
        .filter(|x| {
            match getenv("PNET_TEST_IFACE") {
                Some(name) => x.name == name,
                None => x.is_loopback()
            }
        })
        .next()
        .unwrap())
        .clone()
}

// OSes have a nasty habit of tweaking IP fields, so we only check
// the less volatile fields (identification, checksum)
fn check_ipv4_header(packet: &[u8], header: Ipv4Header) {
    let ipv4_header = Ipv4Header::new(packet);

    assert_eq!(header.get_version(), ipv4_header.get_version());
    assert_eq!(header.get_header_length(), ipv4_header.get_header_length());
    assert_eq!(header.get_dscp(), ipv4_header.get_dscp());
    assert_eq!(header.get_ecn(), ipv4_header.get_ecn());
    assert_eq!(header.get_total_length(), ipv4_header.get_total_length());
    assert_eq!(header.get_flags(), ipv4_header.get_flags());
    assert_eq!(header.get_fragment_offset(), ipv4_header.get_fragment_offset());
    assert_eq!(header.get_ttl(), ipv4_header.get_ttl());
    assert_eq!(header.get_next_level_protocol(), ipv4_header.get_next_level_protocol());
    assert_eq!(header.get_source(), ipv4_header.get_source());
    assert_eq!(header.get_destination(), ipv4_header.get_destination());
}

fn layer4(ip: IpAddr, header_len: uint) {
    let mut packet = [0u8, ..IPV6_HEADER_LEN + UDP_HEADER_LEN + TEST_DATA_LEN];
    let packet_len = header_len + UDP_HEADER_LEN + TEST_DATA_LEN;

    match ip {
        Ipv4Addr(..) => {
            build_udp4_packet(packet.as_mut_slice(), 0, "l4i4")
        },
        Ipv6Addr(..) => {
            build_udp6_packet(packet.as_mut_slice(), 0, "l4i6")
        }
    };

    let udp = UdpHeader::new(packet.slice(header_len, packet_len));

    let (tx, rx) = channel();

    let tc = transport_channel(128, TransportChannelType::Layer4(get_proto(ip)));
    let (mut ttx, mut trx) = match tc {
        Ok((tx, rx)) => (tx, rx),
        Err(e) => panic!("layer4: unable to create channel: {}", e),
    };

    let res = try_future( move || {
        tx.send(());
        pfor!((header, addr) in udp_header_iter(&mut trx) {
            assert_eq!(addr, ip);
            assert_eq!(header, UdpHeader::new(packet.slice(header_len, packet_len)));
            break;
        } on Err(e) {
            panic!("Receive failed for layer4_test(): {}", e);
        })
    });

    rx.recv();
    match ttx.send_to(udp, ip) {
        Ok(res) => assert_eq!(res as uint, UDP_HEADER_LEN + TEST_DATA_LEN),
        Err(e) => panic!("layer4_test failed: {}", e)
    }

    fn get_proto(ip: IpAddr) -> TransportProtocol {
        match ip {
            Ipv4Addr(..) => Ipv4(TEST_PROTO),
            Ipv6Addr(..) => Ipv6(TEST_PROTO)
        }
    }

    match res.into_inner() {
        Err(e) => panic!(e),
        _ => ()
    }
}

#[test]
fn layer4_ipv4() {
    layer4(Ipv4Addr(127, 0, 0, 1), IPV4_HEADER_LEN as uint);
}

#[test]
fn layer4_ipv6() {
    layer4(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1), IPV6_HEADER_LEN);
}

#[test]
fn layer3_ipv4() {
    let send_addr = Ipv4Addr(127, 0, 0, 1);
    let mut packet = [0u8, ..IPV4_HEADER_LEN + UDP_HEADER_LEN + TEST_DATA_LEN];

    build_udp4_packet(packet.as_mut_slice(), 0, "l3i4");

    let (tx, rx) = channel();

    let tc =  transport_channel(IPV4_HEADER_LEN + UDP_HEADER_LEN + TEST_DATA_LEN,
                                    TransportChannelType::Layer3(TEST_PROTO));
    let (mut ttx, mut trx) = match tc {
        Ok((tx, rx)) => (tx, rx),
        Err(e) => panic!("layer3: unable to create channel: {}", e),
    };

    let res = try_future( move || {
        tx.send(());
        pfor!((header, addr) in ipv4_header_iter(&mut trx) {
            assert_eq!(addr, send_addr);
            check_ipv4_header(packet.as_slice(), header);
            let udp_header = UdpHeader::new(header.packet().slice_from(
                                           header.get_header_length() as uint * 4u));
            assert_eq!(udp_header, UdpHeader::new(packet.slice_from(IPV4_HEADER_LEN)));

            assert_eq!(udp_header.packet().slice_from(UDP_HEADER_LEN),
                       packet.slice_from(IPV4_HEADER_LEN + UDP_HEADER_LEN))
            break;
        } on Err(e) {
            panic!("receive failed for layer3_ipv4_test(): {}", e);
        })
    });

    rx.recv();
    match ttx.send_to(Ipv4Header::new(packet.as_slice()), send_addr) {
        Ok(res) => assert_eq!(res as uint, packet.len()),
        Err(e) => panic!("layer3_ipv4_test failed: {}", e)
    }

    match res.into_inner() {
        Err(e) => panic!(e),
        _ => ()
    }

}

#[test]
fn layer2() {
    let interface = get_test_interface();

    let mut packet = [0u8, ..ETHERNET_HEADER_LEN +
                             IPV4_HEADER_LEN +
                             UDP_HEADER_LEN +
                             TEST_DATA_LEN];

    {
        let mut ethernet_header = MutableEthernetHeader::new(packet.as_mut_slice());
        ethernet_header.set_source(interface.mac_address());
        ethernet_header.set_destination(interface.mac_address());
        ethernet_header.set_ethertype(EtherTypes::Ipv4);
    }

    build_udp4_packet(packet.as_mut_slice(), ETHERNET_HEADER_LEN as uint, "l2tt");

    let (tx, rx) = channel();

    let dlc = datalink_channel(&interface,
                               MIN_PACKET_SIZE*2,
                               MIN_PACKET_SIZE*2,
                               DataLinkChannelType::Layer2);
    let (mut dltx, mut dlrx) = match dlc {
        Ok((tx, rx)) => (tx, rx),
        Err(e) => panic!("layer2: unable to create channel: {}", e)
    };

    let res = try_future( move || {
        tx.send(());
        let mut i = 0u;
        pfor!(eh in dlrx.iter() {
            if i == 10_000 {
                panic!("layer2: did not find matching packet after 10_000 iterations");
            }
            if EthernetHeader::new(packet.as_slice()) == eh {
                return;
            }
            i += 1;
        } on Err(e) {
            panic!("layer2 failed: {}", e);
        })
    });

    rx.recv();
    match dltx.send_to(EthernetHeader::new(packet.as_slice()), None) {
        Some(Ok(())) => (),
        Some(Err(e)) => panic!("layer2_test failed: {}", e),
        None => panic!("Provided buffer too small")
    }

    match res.into_inner() {
        Err(e) => panic!(e),
        _ => ()
    }
}

#[test]
fn check_test_environment() {
    use std::os;
    let tasks = os::getenv("RUST_TEST_TASKS");
    if !tasks.is_some() || tasks.unwrap().as_slice() != "1" {
        panic!("Tests must be run with environment variable RUST_TEST_TASKS=1");
    }

    test_iface();

    #[cfg(not(target_os = "linux"))]
    fn test_iface() {
        let iface = os::getenv("PNET_TEST_IFACE");
        if !iface.is_some() {
            panic!("The environment variable PNET_TEST_IFACE must be set.");
        }
    }

    #[cfg(target_os = "linux")]
    fn test_iface() {}
}
<commit_msg>Fixes for spawning threads.<commit_after>// Copyright (c) 2014 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate libc;

use std::clone::Clone;
use std::thread::Thread;
use std::io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::iter::Iterator;

use datalink::{datalink_channel, DataLinkChannelType};
use packet::Packet;
use packet::ethernet::{EtherTypes, EthernetHeader, MutableEthernetHeader, EthernetPacket};
use packet::ip::{IpNextHeaderProtocols, IpNextHeaderProtocol};
use packet::ipv4::{Ipv4Header, MutableIpv4Header, Ipv4Packet};
use packet::ipv6::{MutableIpv6Header, Ipv6Packet};
use packet::udp::{UdpHeader, MutableUdpHeader, UdpPacket};
use transport::{udp_header_iter, ipv4_header_iter, transport_channel, TransportProtocol,
                TransportChannelType};
use transport::TransportProtocol::{Ipv4, Ipv6};
use util::NetworkInterface;

const MIN_PACKET_SIZE: uint = 64;
const ETHERNET_HEADER_LEN: uint = 14;
const IPV4_HEADER_LEN: uint = 20;
const IPV6_HEADER_LEN: uint = 40;
const UDP_HEADER_LEN: uint = 8;
const TEST_DATA_LEN: uint = 4;

const IPV4_SOURCE: IpAddr = Ipv4Addr(127, 0, 0, 1);
const IPV4_DESTINATION: IpAddr = Ipv4Addr(127, 0, 0, 1);
const IPV6_SOURCE: IpAddr = Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1);
const IPV6_DESTINATION: IpAddr = Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1);

// Use a protocol which is unlikely to have other packets on
const TEST_PROTO: IpNextHeaderProtocol = IpNextHeaderProtocols::Test1;

fn build_ipv4_header(packet: &mut [u8], offset: uint) {
    let mut ip_header = MutableIpv4Header::new(packet.slice_from_mut(offset));

    let total_len = (IPV4_HEADER_LEN + UDP_HEADER_LEN + TEST_DATA_LEN) as u16;

    ip_header.set_version(4);
    ip_header.set_header_length(5);
    ip_header.set_total_length(total_len);
    ip_header.set_ttl(4);
    ip_header.set_next_level_protocol(TEST_PROTO);
    ip_header.set_source(IPV4_SOURCE);
    ip_header.set_destination(IPV4_DESTINATION);
    ip_header.checksum();
}

fn build_ipv6_header(packet: &mut [u8], offset: uint) {
    let mut ip_header = MutableIpv6Header::new(packet.slice_from_mut(offset));

    ip_header.set_version(6);
    ip_header.set_payload_length((UDP_HEADER_LEN + TEST_DATA_LEN) as u16);
    ip_header.set_next_header(TEST_PROTO);
    ip_header.set_hop_limit(4);
    ip_header.set_source(IPV6_SOURCE);
    ip_header.set_destination(IPV6_DESTINATION);
}

fn build_udp_header(packet: &mut [u8], offset: uint) {
    let mut udp_header = MutableUdpHeader::new(packet.slice_from_mut(offset));

    udp_header.set_source(1234); // Arbitary port number
    udp_header.set_destination(1234);
    udp_header.set_length((UDP_HEADER_LEN + TEST_DATA_LEN) as u16);
}

fn build_udp4_packet(packet: &mut [u8], start: uint, msg: &str) {
    build_ipv4_header(packet, start);
    build_udp_header(packet, start + IPV4_HEADER_LEN as uint);

    let data_start = start + IPV4_HEADER_LEN + UDP_HEADER_LEN;
    packet[data_start + 0] = msg.char_at(0) as u8;
    packet[data_start + 1] = msg.char_at(1) as u8;
    packet[data_start + 2] = msg.char_at(2) as u8;
    packet[data_start + 3] = msg.char_at(3) as u8;

    let slice = packet.slice_from_mut(start + IPV4_HEADER_LEN as uint);
    MutableUdpHeader::new(slice).checksum(IPV4_SOURCE, IPV4_DESTINATION, TEST_PROTO);
}

fn build_udp6_packet(packet: &mut [u8], start: uint, msg: &str) {
    build_ipv6_header(packet, start);
    build_udp_header(packet, start + IPV6_HEADER_LEN as uint);

    let data_start = start + IPV6_HEADER_LEN + UDP_HEADER_LEN;
    packet[data_start + 0] = msg.char_at(0) as u8;
    packet[data_start + 1] = msg.char_at(1) as u8;
    packet[data_start + 2] = msg.char_at(2) as u8;
    packet[data_start + 3] = msg.char_at(3) as u8;

    let slice = packet.slice_from_mut(start + IPV6_HEADER_LEN as uint);
    MutableUdpHeader::new(slice).checksum(IPV6_SOURCE, IPV6_DESTINATION, TEST_PROTO);
}

fn get_test_interface() -> NetworkInterface {
    use std::os::getenv;
    use util;

    (*util::get_network_interfaces()
        .as_slice().iter()
        .filter(|x| {
            match getenv("PNET_TEST_IFACE") {
                Some(name) => x.name == name,
                None => x.is_loopback()
            }
        })
        .next()
        .unwrap())
        .clone()
}

// OSes have a nasty habit of tweaking IP fields, so we only check
// the less volatile fields (identification, checksum)
fn check_ipv4_header(packet: &[u8], header: Ipv4Header) {
    let ipv4_header = Ipv4Header::new(packet);

    assert_eq!(header.get_version(), ipv4_header.get_version());
    assert_eq!(header.get_header_length(), ipv4_header.get_header_length());
    assert_eq!(header.get_dscp(), ipv4_header.get_dscp());
    assert_eq!(header.get_ecn(), ipv4_header.get_ecn());
    assert_eq!(header.get_total_length(), ipv4_header.get_total_length());
    assert_eq!(header.get_flags(), ipv4_header.get_flags());
    assert_eq!(header.get_fragment_offset(), ipv4_header.get_fragment_offset());
    assert_eq!(header.get_ttl(), ipv4_header.get_ttl());
    assert_eq!(header.get_next_level_protocol(), ipv4_header.get_next_level_protocol());
    assert_eq!(header.get_source(), ipv4_header.get_source());
    assert_eq!(header.get_destination(), ipv4_header.get_destination());
}

fn layer4(ip: IpAddr, header_len: uint) {
    let mut packet = [0u8, ..IPV6_HEADER_LEN + UDP_HEADER_LEN + TEST_DATA_LEN];
    let packet_len = header_len + UDP_HEADER_LEN + TEST_DATA_LEN;

    match ip {
        Ipv4Addr(..) => {
            build_udp4_packet(packet.as_mut_slice(), 0, "l4i4")
        },
        Ipv6Addr(..) => {
            build_udp6_packet(packet.as_mut_slice(), 0, "l4i6")
        }
    };

    let udp = UdpHeader::new(packet.slice(header_len, packet_len));

    let (tx, rx) = channel();

    let tc = transport_channel(128, TransportChannelType::Layer4(get_proto(ip)));
    let (mut ttx, mut trx) = match tc {
        Ok((tx, rx)) => (tx, rx),
        Err(e) => panic!("layer4: unable to create channel: {}", e),
    };

    let res = Thread::spawn( move || {
        tx.send(());
        pfor!((header, addr) in udp_header_iter(&mut trx) {
            assert_eq!(addr, ip);
            assert_eq!(header, UdpHeader::new(packet.slice(header_len, packet_len)));
            break;
        } on Err(e) {
            panic!("Receive failed for layer4_test(): {}", e);
        })
    });

    rx.recv();
    match ttx.send_to(udp, ip) {
        Ok(res) => assert_eq!(res as uint, UDP_HEADER_LEN + TEST_DATA_LEN),
        Err(e) => panic!("layer4_test failed: {}", e)
    }

    fn get_proto(ip: IpAddr) -> TransportProtocol {
        match ip {
            Ipv4Addr(..) => Ipv4(TEST_PROTO),
            Ipv6Addr(..) => Ipv6(TEST_PROTO)
        }
    }

    match res.join() {
        Err(e) => panic!(e),
        _ => ()
    }
}

#[test]
fn layer4_ipv4() {
    layer4(Ipv4Addr(127, 0, 0, 1), IPV4_HEADER_LEN as uint);
}

#[test]
fn layer4_ipv6() {
    layer4(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1), IPV6_HEADER_LEN);
}

#[test]
fn layer3_ipv4() {
    let send_addr = Ipv4Addr(127, 0, 0, 1);
    let mut packet = [0u8, ..IPV4_HEADER_LEN + UDP_HEADER_LEN + TEST_DATA_LEN];

    build_udp4_packet(packet.as_mut_slice(), 0, "l3i4");

    let (tx, rx) = channel();

    let tc =  transport_channel(IPV4_HEADER_LEN + UDP_HEADER_LEN + TEST_DATA_LEN,
                                    TransportChannelType::Layer3(TEST_PROTO));
    let (mut ttx, mut trx) = match tc {
        Ok((tx, rx)) => (tx, rx),
        Err(e) => panic!("layer3: unable to create channel: {}", e),
    };

    let res = Thread::spawn( move || {
        tx.send(());
        pfor!((header, addr) in ipv4_header_iter(&mut trx) {
            assert_eq!(addr, send_addr);
            check_ipv4_header(packet.as_slice(), header);
            let udp_header = UdpHeader::new(header.packet().slice_from(
                                           header.get_header_length() as uint * 4u));
            assert_eq!(udp_header, UdpHeader::new(packet.slice_from(IPV4_HEADER_LEN)));

            assert_eq!(udp_header.packet().slice_from(UDP_HEADER_LEN),
                       packet.slice_from(IPV4_HEADER_LEN + UDP_HEADER_LEN));
            break;
        } on Err(e) {
            panic!("receive failed for layer3_ipv4_test(): {}", e);
        })
    });

    rx.recv();
    match ttx.send_to(Ipv4Header::new(packet.as_slice()), send_addr) {
        Ok(res) => assert_eq!(res as uint, packet.len()),
        Err(e) => panic!("layer3_ipv4_test failed: {}", e)
    }

    match res.join() {
        Err(e) => panic!(e),
        _ => ()
    }

}

#[test]
fn layer2() {
    let interface = get_test_interface();

    let mut packet = [0u8, ..ETHERNET_HEADER_LEN +
                             IPV4_HEADER_LEN +
                             UDP_HEADER_LEN +
                             TEST_DATA_LEN];

    {
        let mut ethernet_header = MutableEthernetHeader::new(packet.as_mut_slice());
        ethernet_header.set_source(interface.mac_address());
        ethernet_header.set_destination(interface.mac_address());
        ethernet_header.set_ethertype(EtherTypes::Ipv4);
    }

    build_udp4_packet(packet.as_mut_slice(), ETHERNET_HEADER_LEN as uint, "l2tt");

    let (tx, rx) = channel();

    let dlc = datalink_channel(&interface,
                               MIN_PACKET_SIZE*2,
                               MIN_PACKET_SIZE*2,
                               DataLinkChannelType::Layer2);
    let (mut dltx, mut dlrx) = match dlc {
        Ok((tx, rx)) => (tx, rx),
        Err(e) => panic!("layer2: unable to create channel: {}", e)
    };

    let res = Thread::spawn( move || {
        tx.send(());
        let mut i = 0u;
        pfor!(eh in dlrx.iter() {
            if i == 10_000 {
                panic!("layer2: did not find matching packet after 10_000 iterations");
            }
            if EthernetHeader::new(packet.as_slice()) == eh {
                return;
            }
            i += 1;
        } on Err(e) {
            panic!("layer2 failed: {}", e);
        })
    });

    rx.recv();
    match dltx.send_to(EthernetHeader::new(packet.as_slice()), None) {
        Some(Ok(())) => (),
        Some(Err(e)) => panic!("layer2_test failed: {}", e),
        None => panic!("Provided buffer too small")
    }

    match res.join() {
        Err(e) => panic!(e),
        _ => ()
    }
}

#[test]
fn check_test_environment() {
    use std::os;
    let tasks = os::getenv("RUST_TEST_TASKS");
    if !tasks.is_some() || tasks.unwrap().as_slice() != "1" {
        panic!("Tests must be run with environment variable RUST_TEST_TASKS=1");
    }

    test_iface();

    #[cfg(not(target_os = "linux"))]
    fn test_iface() {
        let iface = os::getenv("PNET_TEST_IFACE");
        if !iface.is_some() {
            panic!("The environment variable PNET_TEST_IFACE must be set.");
        }
    }

    #[cfg(target_os = "linux")]
    fn test_iface() {}
}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::iter::FromIterator;
use {Trie, TrieCommon};

const TEST_DATA: [(&'static str, u32); 7] = [("abcdefgh", 19),
                                             ("abcdef", 18),
                                             ("abcd", 17),
                                             ("ab", 16),
                                             ("a", 15),
                                             ("acbdef", 30),
                                             ("bcdefgh", 29)];

fn test_trie() -> Trie<&'static str, u32> {
    let mut trie = Trie::new();

    for &(key, val) in &TEST_DATA {
        trie.insert(key, val);
        assert!(trie.check_integrity());
    }

    trie
}

#[test]
fn get_nonexistant() {
    let trie = test_trie();
    assert!(trie.get(&"nonexistant").is_none());
    assert!(trie.get(&"").is_none());
}

#[test]
fn subtrie_nonexistant() {
    let trie = test_trie();
    assert!(trie.subtrie(&"nonexistant").is_none());
    assert!(trie.subtrie(&"").is_some());
}

#[test]
fn subtrie() {
    let mut trie = Trie::new();
    trie.insert("hello", 55);
    assert!(trie.subtrie(&"h").is_none());
    assert!(trie.subtrie(&"hello").is_some());
}
#[test]
fn subtrie_string() {
    let mut trie = Trie::new();
    trie.insert("hello".to_string(), 55);

    let h = "h".to_string();
    let hello = "hello".to_string();

    assert!(trie.subtrie(&h).is_none());
    assert!(trie.subtrie(&hello).is_some());
}

#[test]
fn empty_key() {
    let mut trie = test_trie();
    trie.insert(&"", 99);
    assert_eq!(*trie.get(&"").unwrap(), 99);
    assert_eq!(trie.remove(&""), Some(99));
}

#[test]
fn insert() {
    let trie = test_trie();

    for &(key, val) in &TEST_DATA {
        assert_eq!(*trie.get(&key).unwrap(), val);
    }

    assert!(trie.check_integrity());
    assert_eq!(trie.len(), TEST_DATA.len());
}

#[test]
fn insert_replace() {
    let mut trie = Trie::new();
    assert_eq!(trie.insert("haskell", 18), None);
    let length = trie.len();
    assert_eq!(trie.insert("haskell", 36), Some(18));
    assert_eq!(trie.len(), length);
}

#[test]
fn map_with_default() {
    let mut trie = test_trie();
    trie.map_with_default(&"abcd",
                          {
                              |x| *x = *x + 1
                          },
                          42);
    assert_eq!(*trie.get(&"abcd").unwrap(), 17 + 1);
    trie.map_with_default(&"zzz",
                          {
                              |x| *x = *x + 1
                          },
                          42);
    assert_eq!(*trie.get(&"zzz").unwrap(), 42);
}

#[test]
fn remove() {
    let mut trie = test_trie();

    // Remove.
    for &(key, val) in &TEST_DATA {
        let res = trie.remove(&key);
        assert_eq!(res, Some(val));
        assert!(trie.check_integrity());
    }

    // Check non-existance.
    for &(key, _) in &TEST_DATA {
        assert!(trie.get(&key).is_none());
    }
}

#[test]
fn remove_simple() {
    let mut trie = Trie::new();

    trie.insert("HELL", 66);
    trie.insert("HELLO", 77);
    let val = trie.remove(&"HELLO");
    assert_eq!(val, Some(77));
}

#[test]
fn nearest_ancestor_root() {
    let mut trie = Trie::new();
    trie.insert("", 55);
    assert_eq!(trie.get_ancestor_value(&""), Some(&55));
}

#[test]
fn nearest_ancestor() {
    let trie = test_trie();
    assert_eq!(trie.get_ancestor_value(&""), None);

    // Test identity prefixes.
    for &(key, val) in &TEST_DATA {
        assert_eq!(trie.get_ancestor_value(&key), Some(&val));
    }

    assert_eq!(trie.get_ancestor_value(&"abcdefg"), trie.get(&"abcdef"));
    assert_eq!(trie.get_ancestor_value(&"abcde"), trie.get(&"abcd"));
    assert_eq!(trie.get_ancestor_value(&"aauksdjk"), trie.get(&"a"));
}

#[test]
fn nearest_ancestor_no_child_fn() {
    let mut t = Trie::new();
    t.insert("ab", 5);
    let anc = t.get_ancestor(&"abc").unwrap();
    assert_eq!(*anc.value().unwrap(), 5);
}

#[test]
fn raw_ancestor() {
    let mut t = Trie::new();

    for &(key, _) in &TEST_DATA {
        assert_eq!(t.get_raw_ancestor(&key).key(), t.key());
    }

    t.insert("wow", 0);
    t.insert("hella", 1);
    t.insert("hellb", 2);

    // Ancestor should be "hell" node.
    let anc = t.get_raw_ancestor(&"hello");
    assert_eq!(anc.len(), 2);
}

#[test]
fn iter() {
    type Set = HashSet<(&'static str, u32)>;
    let trie = test_trie();
    let expected = TEST_DATA.iter().map(|&x| x).collect::<Set>();
    let observed = trie.iter().map(|(&k, &v)| (k, v)).collect::<Set>();
    assert_eq!(expected, observed);
}

#[test]
fn get_raw_descendant() {
    let trie = test_trie();
    assert_eq!(trie.get_raw_descendant(&"abcdefgh").and_then(|t| t.value()),
               Some(&19));
    assert_eq!(trie.get_raw_descendant(&"abcdefg").and_then(|t| t.value()),
               Some(&19));
    assert!(trie.get_raw_descendant(&"acbg").is_none());
}

#[test]
fn get_prefix_bug() {
    let mut trie = Trie::new();
    trie.insert("abdc", 5);
    trie.insert("abde", 6);
    assert!(trie.get(&"abc").is_none());
}

#[test]
fn get_ancestor_bug() {
    let mut trie = Trie::new();
    trie.insert("abc", 1);
    trie.insert("abcde", 2);
    assert_eq!(trie.get_ancestor_value(&"abcdz"), Some(&1));
}

#[test]
fn root_replace_bug() {
    let mut trie = Trie::new();
    trie.insert("a", ());
    trie.insert("p", ());
    trie.remove(&"a");
    assert_eq!(trie.len(), 1);
    trie.remove(&"p");
    assert_eq!(trie.len(), 0);
}

#[test]
fn subtrie_insert() {
    let mut trie = Trie::new();
    trie.insert("abc", 3);
    {
        let mut subtrie = trie.subtrie_mut(&"abc").unwrap();
        assert_eq!(subtrie.insert("somerandomshit", 666), Err(()));
        assert_eq!(subtrie.insert("abcdef", 6), Ok(None));
        assert_eq!(subtrie.insert("abc", 9), Ok(Some(3)));
    }
    assert_eq!(trie.get(&"abc"), Some(&9));
    assert_eq!(trie.get(&"abcdef"), Some(&6));
    assert_eq!(trie.len(), 2);
}

#[test]
fn subtrie_len() {
    let trie = test_trie();
    assert_eq!(trie.subtrie(&"ab").unwrap().len(), 4);
    assert_eq!(trie.subtrie(&"a").unwrap().len(), 6);
    assert_eq!(trie.subtrie(&"").unwrap().len(), trie.len());
    assert_eq!(trie.subtrie(&"bcdefgh").unwrap().len(), 1);
}

// Subtrie functions that return references should return references valid for
// the lifetime of the *original trie* from which they were borrowed, NOT
// just the lifetime of the subtrie (which may be shorter).
#[test]
fn subtrie_lifetime() {
    let trie = test_trie();
    let subtrie_value = {
        let subtrie = trie.subtrie(&"ab").unwrap();
        subtrie.value()
    };
    assert_eq!(*subtrie_value.unwrap(), 16);
}

#[test]
fn subtrie_mut_lifetime() {
    let mut trie = test_trie();
    let subtrie_value = {
        let mut subtrie = trie.subtrie_mut(&"ab").unwrap();
        *subtrie.value_mut().unwrap() = 999;
        subtrie.value()
    };
    assert_eq!(*subtrie_value.unwrap(), 999);
}

#[test]
fn ancestor_key() {
    let trie = test_trie();
    let subtrie = trie.get_ancestor(&"abcde").unwrap();
    assert_eq!(*subtrie.key().unwrap(), "abcd");
    assert_eq!(*subtrie.get(&"abcdef").unwrap().unwrap(), 18);
    assert_eq!(*subtrie.get(&"abcdefgh").unwrap().unwrap(), 19);
}

#[test]
fn child_subtrie_keys() {
    let trie = test_trie();
    let subtrie = trie.subtrie(&"abcd").unwrap();
    for subsubtrie in subtrie.children() {
        // This subtrie should be for "abcde".
        assert_eq!(*subsubtrie.get(&"abcdef").unwrap().unwrap(), 18);
        assert_eq!(*subsubtrie.get(&"abcdefgh").unwrap().unwrap(), 19);
    }
}

#[test]
fn int_keys() {
    let mut trie = Trie::new();
    trie.insert(0x00ffu64, "asdf");
    trie.insert(0xdeadbeefu64, "asdf");
    assert!(trie.check_integrity());
}

#[test]
fn from_iter() {
    let trie: Trie<&str, u32> = Trie::from_iter(vec![
        ("test", 10), ("hello", 12)
    ]);
    assert_eq!(*trie.get(&"test").unwrap(), 10);
    assert_eq!(*trie.get(&"hello").unwrap(), 12);
    assert_eq!(trie.len(), 2);
}
<commit_msg>Start implementing tests for borrow<commit_after>use std::collections::HashSet;
use std::iter::FromIterator;
use {Trie, TrieCommon};

const TEST_DATA: [(&'static str, u32); 7] = [("abcdefgh", 19),
                                             ("abcdef", 18),
                                             ("abcd", 17),
                                             ("ab", 16),
                                             ("a", 15),
                                             ("acbdef", 30),
                                             ("bcdefgh", 29)];

fn test_trie() -> Trie<&'static str, u32> {
    let mut trie = Trie::new();

    for &(key, val) in &TEST_DATA {
        trie.insert(key, val);
        assert!(trie.check_integrity());
    }

    trie
}

#[test]
fn get_nonexistant() {
    let trie = test_trie();
    assert!(trie.get(&"nonexistant").is_none());
    assert!(trie.get(&"").is_none());
}

#[test]
fn subtrie_nonexistant() {
    let trie = test_trie();
    assert!(trie.subtrie(&"nonexistant").is_none());
    assert!(trie.subtrie(&"").is_some());
}

#[test]
fn subtrie() {
    let mut trie = Trie::new();
    trie.insert("hello", 55);
    assert!(trie.subtrie(&"h").is_none());
    assert!(trie.subtrie(&"hello").is_some());
}
#[test]
fn subtrie_string() {
    let mut trie = Trie::new();
    trie.insert("hello".to_string(), 55);

    let h = "h".to_string();
    let hello = "hello".to_string();

    assert!(trie.subtrie(&h).is_none());
    assert!(trie.subtrie(&hello).is_some());
}

#[test]
fn empty_key() {
    let mut trie = test_trie();
    trie.insert(&"", 99);
    assert_eq!(*trie.get(&"").unwrap(), 99);
    assert_eq!(trie.remove(&""), Some(99));
}

#[test]
fn insert() {
    let trie = test_trie();

    for &(key, val) in &TEST_DATA {
        assert_eq!(*trie.get(&key).unwrap(), val);
    }

    assert!(trie.check_integrity());
    assert_eq!(trie.len(), TEST_DATA.len());
}

#[test]
fn insert_replace() {
    let mut trie = Trie::new();
    assert_eq!(trie.insert("haskell", 18), None);
    let length = trie.len();
    assert_eq!(trie.insert("haskell", 36), Some(18));
    assert_eq!(trie.len(), length);
}

#[test]
fn map_with_default() {
    let mut trie = test_trie();
    trie.map_with_default(&"abcd",
                          {
                              |x| *x = *x + 1
                          },
                          42);
    assert_eq!(*trie.get(&"abcd").unwrap(), 17 + 1);
    trie.map_with_default(&"zzz",
                          {
                              |x| *x = *x + 1
                          },
                          42);
    assert_eq!(*trie.get(&"zzz").unwrap(), 42);
}

#[test]
fn remove() {
    let mut trie = test_trie();

    // Remove.
    for &(key, val) in &TEST_DATA {
        let res = trie.remove(&key);
        assert_eq!(res, Some(val));
        assert!(trie.check_integrity());
    }

    // Check non-existance.
    for &(key, _) in &TEST_DATA {
        assert!(trie.get(&key).is_none());
    }
}

#[test]
fn remove_simple() {
    let mut trie = Trie::new();

    trie.insert("HELL", 66);
    trie.insert("HELLO", 77);
    let val = trie.remove(&"HELLO");
    assert_eq!(val, Some(77));
}

#[test]
fn nearest_ancestor_root() {
    let mut trie = Trie::new();
    trie.insert("", 55);
    assert_eq!(trie.get_ancestor_value(&""), Some(&55));
}

#[test]
fn nearest_ancestor() {
    let trie = test_trie();
    assert_eq!(trie.get_ancestor_value(&""), None);

    // Test identity prefixes.
    for &(key, val) in &TEST_DATA {
        assert_eq!(trie.get_ancestor_value(&key), Some(&val));
    }

    assert_eq!(trie.get_ancestor_value(&"abcdefg"), trie.get(&"abcdef"));
    assert_eq!(trie.get_ancestor_value(&"abcde"), trie.get(&"abcd"));
    assert_eq!(trie.get_ancestor_value(&"aauksdjk"), trie.get(&"a"));
}

#[test]
fn nearest_ancestor_no_child_fn() {
    let mut t = Trie::new();
    t.insert("ab", 5);
    let anc = t.get_ancestor(&"abc").unwrap();
    assert_eq!(*anc.value().unwrap(), 5);
}

#[test]
fn raw_ancestor() {
    let mut t = Trie::new();

    for &(key, _) in &TEST_DATA {
        assert_eq!(t.get_raw_ancestor(&key).key(), t.key());
    }

    t.insert("wow", 0);
    t.insert("hella", 1);
    t.insert("hellb", 2);

    // Ancestor should be "hell" node.
    let anc = t.get_raw_ancestor(&"hello");
    assert_eq!(anc.len(), 2);
}

#[test]
fn iter() {
    type Set = HashSet<(&'static str, u32)>;
    let trie = test_trie();
    let expected = TEST_DATA.iter().map(|&x| x).collect::<Set>();
    let observed = trie.iter().map(|(&k, &v)| (k, v)).collect::<Set>();
    assert_eq!(expected, observed);
}

#[test]
fn get_raw_descendant() {
    let trie = test_trie();
    assert_eq!(trie.get_raw_descendant(&"abcdefgh").and_then(|t| t.value()),
               Some(&19));
    assert_eq!(trie.get_raw_descendant(&"abcdefg").and_then(|t| t.value()),
               Some(&19));
    assert!(trie.get_raw_descendant(&"acbg").is_none());
}

#[test]
fn get_prefix_bug() {
    let mut trie = Trie::new();
    trie.insert("abdc", 5);
    trie.insert("abde", 6);
    assert!(trie.get(&"abc").is_none());
}

#[test]
fn get_ancestor_bug() {
    let mut trie = Trie::new();
    trie.insert("abc", 1);
    trie.insert("abcde", 2);
    assert_eq!(trie.get_ancestor_value(&"abcdz"), Some(&1));
}

#[test]
fn root_replace_bug() {
    let mut trie = Trie::new();
    trie.insert("a", ());
    trie.insert("p", ());
    trie.remove(&"a");
    assert_eq!(trie.len(), 1);
    trie.remove(&"p");
    assert_eq!(trie.len(), 0);
}

#[test]
fn subtrie_insert() {
    let mut trie = Trie::new();
    trie.insert("abc", 3);
    {
        let mut subtrie = trie.subtrie_mut(&"abc").unwrap();
        assert_eq!(subtrie.insert("somerandomshit", 666), Err(()));
        assert_eq!(subtrie.insert("abcdef", 6), Ok(None));
        assert_eq!(subtrie.insert("abc", 9), Ok(Some(3)));
    }
    assert_eq!(trie.get(&"abc"), Some(&9));
    assert_eq!(trie.get(&"abcdef"), Some(&6));
    assert_eq!(trie.len(), 2);
}

#[test]
fn subtrie_len() {
    let trie = test_trie();
    assert_eq!(trie.subtrie(&"ab").unwrap().len(), 4);
    assert_eq!(trie.subtrie(&"a").unwrap().len(), 6);
    assert_eq!(trie.subtrie(&"").unwrap().len(), trie.len());
    assert_eq!(trie.subtrie(&"bcdefgh").unwrap().len(), 1);
}

// Subtrie functions that return references should return references valid for
// the lifetime of the *original trie* from which they were borrowed, NOT
// just the lifetime of the subtrie (which may be shorter).
#[test]
fn subtrie_lifetime() {
    let trie = test_trie();
    let subtrie_value = {
        let subtrie = trie.subtrie(&"ab").unwrap();
        subtrie.value()
    };
    assert_eq!(*subtrie_value.unwrap(), 16);
}

#[test]
fn subtrie_mut_lifetime() {
    let mut trie = test_trie();
    let subtrie_value = {
        let mut subtrie = trie.subtrie_mut(&"ab").unwrap();
        *subtrie.value_mut().unwrap() = 999;
        subtrie.value()
    };
    assert_eq!(*subtrie_value.unwrap(), 999);
}

#[test]
fn ancestor_key() {
    let trie = test_trie();
    let subtrie = trie.get_ancestor(&"abcde").unwrap();
    assert_eq!(*subtrie.key().unwrap(), "abcd");
    assert_eq!(*subtrie.get(&"abcdef").unwrap().unwrap(), 18);
    assert_eq!(*subtrie.get(&"abcdefgh").unwrap().unwrap(), 19);
}

#[test]
fn child_subtrie_keys() {
    let trie = test_trie();
    let subtrie = trie.subtrie(&"abcd").unwrap();
    for subsubtrie in subtrie.children() {
        // This subtrie should be for "abcde".
        assert_eq!(*subsubtrie.get(&"abcdef").unwrap().unwrap(), 18);
        assert_eq!(*subsubtrie.get(&"abcdefgh").unwrap().unwrap(), 19);
    }
}

#[test]
fn int_keys() {
    let mut trie = Trie::new();
    trie.insert(0x00ffu64, "asdf");
    trie.insert(0xdeadbeefu64, "asdf");
    assert!(trie.check_integrity());
}

#[test]
fn from_iter() {
    let trie: Trie<&str, u32> = Trie::from_iter(vec![
        ("test", 10), ("hello", 12)
    ]);
    assert_eq!(*trie.get(&"test").unwrap(), 10);
    assert_eq!(*trie.get(&"hello").unwrap(), 12);
    assert_eq!(trie.len(), 2);
}

#[test]
fn test_get_borrow() {
    let mut trie = Trie::new();
    trie.insert("/boot".to_string(), "dir");
    assert_eq!(*trie.get("/boot").unwrap(), "dir");
}

#[test]
fn test_get_mut_borrow() {
    let mut trie = Trie::new();
    trie.insert("/boot".to_string(), "dir");
    assert_eq!(*trie.get_mut("/boot").unwrap(), "dir");
}

#[test]
fn test_remove_borrow() {
    let mut trie = Trie::new();
    trie.insert("/boot".to_string(), "dir");
    assert_eq!(trie.remove("/boot").unwrap(), "dir");
}

#[test]
fn test_subtrie_borrow() {
    let mut trie = Trie::new();
    trie.insert("/boot".to_string(), "dir");
    trie.insert("/boot/lol".to_string(), "dir");
    trie.insert("/bleh".to_string(), "ohi");
    let subtrie = trie.subtrie("/boot").unwrap();
}

#[test]
fn test_subtrie_mut_borrow() {
    let mut trie = Trie::new();
    trie.insert("/boot".to_string(), "dir");
    trie.insert("/boot/lol".to_string(), "dir");
    trie.insert("/bleh".to_string(), "ohi");
    let subtrie = trie.subtrie_mut("/boot").unwrap();
    // TODO: Compare subtrie
}

#[test]
fn test_get_ancestor_borrow() {
    let mut trie = Trie::new();
    trie.insert("/boot".to_string(), "dir");
    trie.insert("/boot/lol".to_string(), "dir");
    trie.insert("/bleh".to_string(), "ohi");
    let subtrie = trie.get_ancestor("/boot/lo").unwrap();
}

#[test]
fn test_get_ancestor_value_borrow() {
    let mut trie = Trie::new();
    trie.insert("/boot".to_string(), "dir");
    trie.insert("/boot/lol".to_string(), "dir");
    trie.insert("/bleh".to_string(), "ohi");
    let subtrie = trie.get_ancestor_value("/boot/lo").unwrap();
}

#[test]
fn test_get_raw_ancestor_borrow() {
    let mut trie = Trie::new();
    trie.insert("/boot".to_string(), "dir");
    trie.insert("/boot/lol".to_string(), "dir");
    trie.insert("/bleh".to_string(), "ohi");
    let subtrie = trie.get_raw_ancestor("/boot/lo");
}

#[test]
fn test_get_raw_descendant_borrow() {
    let mut trie = Trie::new();
    trie.insert("/boot".to_string(), "dir");
    trie.insert("/boot/lol".to_string(), "dir");
    trie.insert("/bleh".to_string(), "ohi");
    let subtrie = trie.get_raw_descendant("/boot/lo").unwrap();
}
<|endoftext|>


<commit_before>use rustc_serialize::json;
use sdl2::render::Texture;
use sdl2::render::Renderer;
use sdl2::surface::Surface;
use sdl2::rect::Rect;
use std::path::Path;

use assets::TILE_SIZE;
use assets::ASSET_STR;

#[derive(RustcDecodable, RustcEncodable)]
pub struct Tile {
  pub tile_x: i32,
  pub tile_y: i32,
  tile_type: TileEnum,
//  tile_rect: Option<Rect>, can't have a Rect with Rustc*odable
  pass_up: bool,
  pass_left: bool,
  pass_right: bool,
  pass_down: bool,
}

#[derive(RustcDecodable, RustcEncodable)]
enum TileEnum {
  Ladder,
  Floor,
  Prisoner,
}

impl Tile {
  pub fn debug_new_tile(x: i32, y: i32, r: &Renderer) -> Tile {
    let asset_path = Path::new(ASSET_STR);
    let full_pathbuf = asset_path.join("sonic.bmp");
    let full_path = full_pathbuf.as_path();

    //load surface
    let surf = Surface::from_bmp(full_path)
      .ok().expect("Failed to load asset.");

    //create a texture from the surface
    let texture = r.create_texture_from_surface(&surf)
      .ok().expect("Failed to create texture");
    return Tile{ tile_x: x,
      tile_y: y,
      tile_type: TileEnum::Floor,
      //tile_rect: Some(Rect::new(TILE_SIZE * x, TILE_SIZE * y, TILE_SIZE, TILE_SIZE)),
      pass_up: false,
      pass_right: false,
      pass_left: false,
      pass_down: false};
  }
}<commit_msg>SaveTiles<commit_after>use rustc_serialize::json;
use sdl2::render::Texture;
use sdl2::render::Renderer;
use sdl2::surface::Surface;
use sdl2::rect::Rect;
use std::path::Path;

use assets::TILE_SIZE;
use assets::ASSET_STR;

///A tile for saving to the disc
///
///Since various SDL types aren't RustcDecodable-friendly, it's necessary to have an simpler type
///for purposes of saving to disc.
#[derive(RustcDecodable, RustcEncodable)]
struct SaveTile {
  pub tile_x: i32,
  pub tile_y: i32,
  tile_type: TileEnum,
  pass_up: bool,
  pass_down: bool,
  pass_left: bool,
  pass_right: bool,
}

impl SaveTile {
  fn toTile(&self, r: &Renderer) -> Tile {
    let asset_path = Path::new(ASSET_STR);
    let mut full_pathbuf = asset_path.join("");
    match self.tile_type{
      TileEnum::Floor => {
        full_pathbuf = asset_path.join("sonic.bmp");
      }
      _ => {
        full_pathbuf = asset_path.join("sonic.bmp");
      }
    }
    let full_path = full_pathbuf.as_path();

    //load surface
    let surf = Surface::from_bmp(full_path)
      .ok().expect("Failed to load asset.");

    //create a texture from the surface
    let texture = r.create_texture_from_surface(&surf)
      .ok().expect("Failed to create texture");
    return Tile{ tile_x: self.tile_x,
      tile_y: self.tile_y,
      tile_type: self.tile_type.clone(),
      tile_rect: Some(Rect::new(TILE_SIZE * self.tile_x, TILE_SIZE * self.tile_y, TILE_SIZE, TILE_SIZE)),
      tile_texture: texture,
      pass_up: self.pass_up,
      pass_down: self.pass_down,
      pass_left: self.pass_left,
      pass_right: self.pass_right};
  }
}

pub struct Tile {
  pub tile_x: i32,
  pub tile_y: i32,
  tile_type: TileEnum,
  tile_rect: Option<Rect>,
  tile_texture: Texture,
  pass_up: bool,
  pass_left: bool,
  pass_right: bool,
  pass_down: bool,
}

#[derive(RustcDecodable, RustcEncodable,Clone)]
enum TileEnum {
  Ladder,
  Floor,
  Prisoner,
}

impl Tile {
  pub fn debug_new_tile(x: i32, y: i32, r: &Renderer) -> Tile {
    let asset_path = Path::new(ASSET_STR);
    let full_pathbuf = asset_path.join("sonic.bmp");
    let full_path = full_pathbuf.as_path();

    //load surface
    let surf = Surface::from_bmp(full_path)
      .ok().expect("Failed to load asset.");

    //create a texture from the surface
    let texture = r.create_texture_from_surface(&surf)
      .ok().expect("Failed to create texture");
    return Tile{ tile_x: x,
      tile_y: y,
      tile_type: TileEnum::Floor,
      tile_rect: Some(Rect::new(TILE_SIZE * x, TILE_SIZE * y, TILE_SIZE, TILE_SIZE)),
      tile_texture: texture,
      pass_up: false,
      pass_right: false,
      pass_left: false,
      pass_down: false};
  }
}<|endoftext|>


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

//! Miscellaneous utilities for low level networking

use packet::PrimitiveValues;
use packet::ip::IpNextHeaderProtocol;
use pnet_macros_support::types::u16be;

use std::fmt;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::slice;
use std::str::FromStr;
use std::u8;

/// A MAC address
#[derive(PartialEq, Eq, Clone, Copy, Hash)]
pub struct MacAddr(pub u8, pub u8, pub u8, pub u8, pub u8, pub u8);

impl MacAddr {
    /// Construct a new MacAddr
    pub fn new(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8) -> MacAddr {
        MacAddr(a, b, c, d, e, f)
    }
}

impl PrimitiveValues for MacAddr {
    type T = (u8, u8, u8, u8, u8, u8);
    fn to_primitive_values(&self) -> (u8, u8, u8, u8, u8, u8) {
        (self.0, self.1, self.2, self.3, self.4, self.5)
    }
}

impl fmt::Display for MacAddr {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt,
               "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
               self.0,
               self.1,
               self.2,
               self.3,
               self.4,
               self.5)
    }
}

impl fmt::Debug for MacAddr {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, fmt)
    }
}

// FIXME Is this the right way to do this? Which occurs is an implementation
//       issue rather than actually defined - is it useful to provide these
//       errors, or would it be better to just give ()?
/// Represents an error which occurred whilst parsing a MAC address
#[derive(Copy, Debug, PartialEq, Eq, Clone)]
pub enum ParseMacAddrErr {
    /// The MAC address has too many components, eg. 00:11:22:33:44:55:66
    TooManyComponents,
    /// The MAC address has too few components, eg. 00:11
    TooFewComponents,
    /// One of the components contains an invalid value, eg. 00:GG:22:33:44:55
    InvalidComponent,
}

impl FromStr for MacAddr {
    type Err = ParseMacAddrErr;
    fn from_str(s: &str) -> Result<MacAddr, ParseMacAddrErr> {
        let mut parts = [0u8; 6];
        let splits = s.split(':');
        let mut i = 0;
        for split in splits {
            if i == 6 {
                return Err(ParseMacAddrErr::TooManyComponents);
            }
            match u8::from_str_radix(split, 16) {
                Ok(b) if split.len() != 0 => parts[i] = b,
                _ => return Err(ParseMacAddrErr::InvalidComponent),
            }
            i += 1;
        }

        if i == 6 {
            Ok(MacAddr(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5]))
        } else {
            Err(ParseMacAddrErr::TooFewComponents)
        }
    }
}

#[test]
fn mac_addr_from_str() {
    assert_eq!("00:00:00:00:00:00".parse(), Ok(MacAddr(0, 0, 0, 0, 0, 0)));
    assert_eq!("ff:ff:ff:ff:ff:ff".parse(),
               Ok(MacAddr(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF)));
    assert_eq!("12:34:56:78:90:ab".parse(),
               Ok(MacAddr(0x12, 0x34, 0x56, 0x78, 0x90, 0xAB)));
    assert_eq!("::::::".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("0::::::".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("::::0::".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("12:34:56:78".parse::<MacAddr>(),
               Err(ParseMacAddrErr::TooFewComponents));
    assert_eq!("12:34:56:78:".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("12:34:56:78:90".parse::<MacAddr>(),
               Err(ParseMacAddrErr::TooFewComponents));
    assert_eq!("12:34:56:78:90:".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("12:34:56:78:90:00:00".parse::<MacAddr>(),
               Err(ParseMacAddrErr::TooManyComponents));
    assert_eq!("xx:xx:xx:xx:xx:xx".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
}

#[test]
fn str_from_mac_addr() {
    assert_eq!(format!("{}", MacAddr(0, 0, 0, 0, 0, 0)),
               "00:00:00:00:00:00");
    assert_eq!(format!("{}", MacAddr(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF)),
               "ff:ff:ff:ff:ff:ff");
    assert_eq!(format!("{}", MacAddr(0x12, 0x34, 0x56, 0x78, 0x09, 0xAB)),
               "12:34:56:78:09:ab");
}

/// Convert value to byte array
pub trait Octets {
    /// Output type - bytes array
    type Output;

    /// Return value as bytes (big-endian order)
    fn octets(&self) -> Self::Output;
}

impl Octets for u64 {
    type Output = [u8; 8];

    fn octets(&self) -> Self::Output {
        [(*self >> 56) as u8,
         (*self >> 48) as u8,
         (*self >> 40) as u8,
         (*self >> 32) as u8,
         (*self >> 24) as u8,
         (*self >> 16) as u8,
         (*self >> 8) as u8,
         *self as u8]
    }
}

impl Octets for u32 {
    type Output = [u8; 4];

    fn octets(&self) -> Self::Output {
        [(*self >> 24) as u8, (*self >> 16) as u8, (*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u16 {
    type Output = [u8; 2];

    fn octets(&self) -> Self::Output {
        [(*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u8 {
    type Output = [u8; 1];

    fn octets(&self) -> Self::Output {
        [*self]
    }
}

/// Calculates a checksum. Used by ipv4 and icmp. The two bytes starting at `skipword * 2` will be
/// ignored. Supposed to be the checksum field, which is regarded as zero during calculation.
pub fn checksum(data: &[u8], skipword: usize) -> u16be {
    let sum = sum_be_words(data, skipword);
    finalize_checksum(sum)
}

fn finalize_checksum(mut sum: u32) -> u16be {
    while sum >> 16 != 0 {
        sum = (sum >> 16) + (sum & 0xFFFF);
    }
    !sum as u16
}

/// Calculate the checksum for a packet built on IPv4. Used by udp and tcp.
pub fn ipv4_checksum(data: &[u8],
                     skipword: usize,
                     extra_data: &[u8],
                     source: Ipv4Addr,
                     destination: Ipv4Addr,
                     next_level_protocol: IpNextHeaderProtocol)
    -> u16be {
    let mut sum = 0u32;

    // Checksum pseudo-header
    sum += ipv4_word_sum(source);
    sum += ipv4_word_sum(destination);

    let IpNextHeaderProtocol(next_level_protocol) = next_level_protocol;
    sum += next_level_protocol as u32;

    let len = data.len() + extra_data.len();
    sum += len as u32;

    // Checksum packet header and data
    sum += sum_be_words(data, skipword);
    sum += sum_be_words(extra_data, extra_data.len() / 2);

    finalize_checksum(sum)
}

fn ipv4_word_sum(ip: Ipv4Addr) -> u32 {
    let octets = ip.octets();
    ((octets[0] as u32) << 8 | octets[1] as u32) + ((octets[2] as u32) << 8 | octets[3] as u32)
}

/// Calculate the checksum for a packet built on IPv6
pub fn ipv6_checksum(data: &[u8],
                     skipword: usize,
                     extra_data: &[u8],
                     source: Ipv6Addr,
                     destination: Ipv6Addr,
                     next_level_protocol: IpNextHeaderProtocol)
    -> u16be {
    let mut sum = 0u32;

    // Checksum pseudo-header
    sum += ipv6_word_sum(source);
    sum += ipv6_word_sum(destination);

    let IpNextHeaderProtocol(next_level_protocol) = next_level_protocol;
    sum += next_level_protocol as u32;

    let len = data.len() + extra_data.len();
    sum += len as u32;

    // Checksum packet header and data
    sum += sum_be_words(data, skipword);
    sum += sum_be_words(extra_data, extra_data.len() / 2);

    finalize_checksum(sum)
}

fn ipv6_word_sum(ip: Ipv6Addr) -> u32 {
    ip.segments().iter().map(|x| *x as u32).sum()
}

/// Sum all words (16 bit chunks) in the given data. The word at word offset
/// `skipword` will be skipped. Each word is treated as big endian.
fn sum_be_words(data: &[u8], mut skipword: usize) -> u32 {
    let len = data.len();
    let wdata: &[u16] = unsafe { slice::from_raw_parts(data.as_ptr() as *const u16, len / 2) };
    skipword = ::std::cmp::min(skipword, wdata.len());

    let mut sum = 0u32;
    let mut i = 0;
    while i < skipword {
        sum += u16::from_be(unsafe { *wdata.get_unchecked(i) }) as u32;
        i += 1;
    }
    i += 1;
    while i < wdata.len() {
        sum += u16::from_be(unsafe { *wdata.get_unchecked(i) }) as u32;
        i += 1;
    }
    // If the length is odd, make sure to checksum the final byte
    if len & 1 != 0 {
        sum += (unsafe { *data.get_unchecked(len - 1) } as u32) << 8;
    }

    sum
}

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

    #[test]
    fn sum_be_words_different_skipwords() {
        let data = (0..11).collect::<Vec<u8>>();
        assert_eq!(7190, sum_be_words(&data, 1));
        assert_eq!(6676, sum_be_words(&data, 2));
        // Assert having the skipword outside the range gives correct and equal
        // results
        assert_eq!(7705, sum_be_words(&data, 99));
        assert_eq!(7705, sum_be_words(&data, 101));
    }
}

#[cfg(all(test, feature = "benchmark"))]
mod checksum_benchmarks {
    use super::checksum;
    use test::{Bencher, black_box};

    #[bench]
    fn bench_checksum_small(b: &mut Bencher) {
        let data = vec![99u8; 20];
        b.iter(|| checksum(black_box(&data), 5));
    }

    #[bench]
    fn bench_checksum_large(b: &mut Bencher) {
        let data = vec![123u8; 1024];
        b.iter(|| checksum(black_box(&data), 5));
    }
}
<commit_msg>Remove MacAddr from utils and re-export the one in base<commit_after>// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Miscellaneous utilities for low level networking

use packet::ip::IpNextHeaderProtocol;
use pnet_macros_support::types::u16be;

use std::net::{Ipv4Addr, Ipv6Addr};
use std::slice;
use std::u8;

pub use pnet_base::{MacAddr, ParseMacAddrErr};

/// Convert value to byte array
pub trait Octets {
    /// Output type - bytes array
    type Output;

    /// Return value as bytes (big-endian order)
    fn octets(&self) -> Self::Output;
}

impl Octets for u64 {
    type Output = [u8; 8];

    fn octets(&self) -> Self::Output {
        [(*self >> 56) as u8,
         (*self >> 48) as u8,
         (*self >> 40) as u8,
         (*self >> 32) as u8,
         (*self >> 24) as u8,
         (*self >> 16) as u8,
         (*self >> 8) as u8,
         *self as u8]
    }
}

impl Octets for u32 {
    type Output = [u8; 4];

    fn octets(&self) -> Self::Output {
        [(*self >> 24) as u8, (*self >> 16) as u8, (*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u16 {
    type Output = [u8; 2];

    fn octets(&self) -> Self::Output {
        [(*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u8 {
    type Output = [u8; 1];

    fn octets(&self) -> Self::Output {
        [*self]
    }
}

/// Calculates a checksum. Used by ipv4 and icmp. The two bytes starting at `skipword * 2` will be
/// ignored. Supposed to be the checksum field, which is regarded as zero during calculation.
pub fn checksum(data: &[u8], skipword: usize) -> u16be {
    let sum = sum_be_words(data, skipword);
    finalize_checksum(sum)
}

fn finalize_checksum(mut sum: u32) -> u16be {
    while sum >> 16 != 0 {
        sum = (sum >> 16) + (sum & 0xFFFF);
    }
    !sum as u16
}

/// Calculate the checksum for a packet built on IPv4. Used by udp and tcp.
pub fn ipv4_checksum(data: &[u8],
                     skipword: usize,
                     extra_data: &[u8],
                     source: Ipv4Addr,
                     destination: Ipv4Addr,
                     next_level_protocol: IpNextHeaderProtocol)
    -> u16be {
    let mut sum = 0u32;

    // Checksum pseudo-header
    sum += ipv4_word_sum(source);
    sum += ipv4_word_sum(destination);

    let IpNextHeaderProtocol(next_level_protocol) = next_level_protocol;
    sum += next_level_protocol as u32;

    let len = data.len() + extra_data.len();
    sum += len as u32;

    // Checksum packet header and data
    sum += sum_be_words(data, skipword);
    sum += sum_be_words(extra_data, extra_data.len() / 2);

    finalize_checksum(sum)
}

fn ipv4_word_sum(ip: Ipv4Addr) -> u32 {
    let octets = ip.octets();
    ((octets[0] as u32) << 8 | octets[1] as u32) + ((octets[2] as u32) << 8 | octets[3] as u32)
}

/// Calculate the checksum for a packet built on IPv6
pub fn ipv6_checksum(data: &[u8],
                     skipword: usize,
                     extra_data: &[u8],
                     source: Ipv6Addr,
                     destination: Ipv6Addr,
                     next_level_protocol: IpNextHeaderProtocol)
    -> u16be {
    let mut sum = 0u32;

    // Checksum pseudo-header
    sum += ipv6_word_sum(source);
    sum += ipv6_word_sum(destination);

    let IpNextHeaderProtocol(next_level_protocol) = next_level_protocol;
    sum += next_level_protocol as u32;

    let len = data.len() + extra_data.len();
    sum += len as u32;

    // Checksum packet header and data
    sum += sum_be_words(data, skipword);
    sum += sum_be_words(extra_data, extra_data.len() / 2);

    finalize_checksum(sum)
}

fn ipv6_word_sum(ip: Ipv6Addr) -> u32 {
    ip.segments().iter().map(|x| *x as u32).sum()
}

/// Sum all words (16 bit chunks) in the given data. The word at word offset
/// `skipword` will be skipped. Each word is treated as big endian.
fn sum_be_words(data: &[u8], mut skipword: usize) -> u32 {
    let len = data.len();
    let wdata: &[u16] = unsafe { slice::from_raw_parts(data.as_ptr() as *const u16, len / 2) };
    skipword = ::std::cmp::min(skipword, wdata.len());

    let mut sum = 0u32;
    let mut i = 0;
    while i < skipword {
        sum += u16::from_be(unsafe { *wdata.get_unchecked(i) }) as u32;
        i += 1;
    }
    i += 1;
    while i < wdata.len() {
        sum += u16::from_be(unsafe { *wdata.get_unchecked(i) }) as u32;
        i += 1;
    }
    // If the length is odd, make sure to checksum the final byte
    if len & 1 != 0 {
        sum += (unsafe { *data.get_unchecked(len - 1) } as u32) << 8;
    }

    sum
}

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

    #[test]
    fn sum_be_words_different_skipwords() {
        let data = (0..11).collect::<Vec<u8>>();
        assert_eq!(7190, sum_be_words(&data, 1));
        assert_eq!(6676, sum_be_words(&data, 2));
        // Assert having the skipword outside the range gives correct and equal
        // results
        assert_eq!(7705, sum_be_words(&data, 99));
        assert_eq!(7705, sum_be_words(&data, 101));
    }
}

#[cfg(all(test, feature = "benchmark"))]
mod checksum_benchmarks {
    use super::checksum;
    use test::{Bencher, black_box};

    #[bench]
    fn bench_checksum_small(b: &mut Bencher) {
        let data = vec![99u8; 20];
        b.iter(|| checksum(black_box(&data), 5));
    }

    #[bench]
    fn bench_checksum_large(b: &mut Bencher) {
        let data = vec![123u8; 1024];
        b.iter(|| checksum(black_box(&data), 5));
    }
}
<|endoftext|>


<commit_before>use super::{CharRange, Capture, RegexThen, RegexContinuation};

#[derive(Clone, Debug)]
pub struct Accept;

impl RegexThen for Accept {
    fn match_then<'text,C>(&self,
                           text: &'text str,
                           position: usize,
                           captures: &mut Vec<Capture<'text>>,
                           continuation: &C)
                           -> Option<usize>
        where C: RegexContinuation
    {
        continuation.match_continue(text, position, captures)
    }
}

impl RegexContinuation for Accept {
    fn match_continue<'text>(&self,
                             _text: &'text str,
                             position: usize,
                             _captures: &mut Vec<Capture<'text>>)
                             -> Option<usize>
    {
        Some(position)
    }
}

#[derive(Clone, Debug)]
pub struct End;

impl RegexThen for End {
    fn match_then<'text,C>(&self,
                           text: &'text str,
                           position: usize,
                           captures: &mut Vec<Capture<'text>>,
                           continuation: &C)
                           -> Option<usize>
        where C: RegexContinuation
    {
        if position == text.len() {
            continuation.match_continue(text, position, captures)
        } else {
            None
        }
    }
}

impl<R,U> RegexThen for (R,U)
    where R: RegexThen, U: RegexThen
{
    fn match_then<'text,C>(&self,
                           text: &'text str,
                           position: usize,
                           captures: &mut Vec<Capture<'text>>,
                           continuation: &C)
                           -> Option<usize>
        where C: RegexContinuation
    {
        let state = SeqMidState { next: &self.1, continuation: continuation };
        self.0.match_then(text, position, captures, &state)
    }
}

struct SeqMidState<'r,R:'r,C:'r> {
    next: &'r R,
    continuation: &'r C,
}

impl<'r,R,C> RegexContinuation for SeqMidState<'r,R,C>
    where R: RegexThen, C: RegexContinuation
{
    fn match_continue<'text>(&self,
                             text: &'text str,
                             position: usize,
                             captures: &mut Vec<Capture<'text>>)
                             -> Option<usize>
    {
        self.next.match_then(text, position, captures, self.continuation)
    }
}

#[derive(Clone, Debug)]
pub struct StarMax<R>(pub R);

impl<R> RegexThen for StarMax<R>
    where R: RegexThen
{
    fn match_then<'text,C>(&self,
                           text: &'text str,
                           position: usize,
                           captures: &mut Vec<Capture<'text>>,
                           continuation: &C)
                           -> Option<usize>
        where C: RegexContinuation
    {
        let state = StarMaxState { repeat: &self.0, continuation: continuation };
        state.match_continue(text, position, captures)
    }
}

#[derive(Clone, Debug)]
pub struct PlusMax<R>(pub R);

impl<R> RegexThen for PlusMax<R>
    where R: RegexThen
{
    fn match_then<'text,C>(&self,
                           text: &'text str,
                           position: usize,
                           captures: &mut Vec<Capture<'text>>,
                           continuation: &C)
                           -> Option<usize>
        where C: RegexContinuation
    {
        let state = StarMaxState { repeat: &self.0, continuation: continuation };
        self.0.match_then(text, position, captures, &state)
    }
}

struct StarMaxState<'a,R:'a,C:'a> {
    repeat: &'a R,
    continuation: &'a C,
}

impl<'a,R,C> RegexContinuation for StarMaxState<'a,R,C>
    where R: RegexThen, C: RegexContinuation
{
    fn match_continue<'text>(&self,
                             text: &'text str,
                             start: usize,
                             captures: &mut Vec<Capture<'text>>)
                             -> Option<usize>
    {
        // You may be wondering "where is the loop?" The answer is
        // that the loop occurs by passing `self` as the
        // *continuation* for `self.repeat`. This means that after we
        // match the repeating part, we will resume in the same state,
        // ready to try again, but with a different start point.  Only
        // once we fail will we fallback to `self.continuation`.
        let captures_len = captures.len();
        match self.repeat.match_then(text, start, captures, self) {
            Some(end) => Some(end),
            None => {
                captures.truncate(captures_len);
                self.continuation.match_continue(text, start, captures)
            }
        }
    }
}

#[derive(Clone, Debug)]
pub struct StarMin<R>(pub R);

impl<R> RegexThen for StarMin<R>
    where R: RegexThen
{
    fn match_then<'text,C>(&self,
                           text: &'text str,
                           position: usize,
                           captures: &mut Vec<Capture<'text>>,
                           continuation: &C)
                           -> Option<usize>
        where C: RegexContinuation
    {
        let state = StarMinState { repeat: &self.0, continuation: continuation };
        state.match_continue(text, position, captures)
    }
}

#[derive(Clone, Debug)]
pub struct PlusMin<R>(pub R);

impl<R> RegexThen for PlusMin<R>
    where R: RegexThen
{
    fn match_then<'text,C>(&self,
                           text: &'text str,
                           position: usize,
                           captures: &mut Vec<Capture<'text>>,
                           continuation: &C)
                           -> Option<usize>
        where C: RegexContinuation
    {
        let state = StarMinState { repeat: &self.0, continuation: continuation };
        self.0.match_then(text, position, captures, &state)
    }
}

struct StarMinState<'a,R:'a,C:'a> {
    repeat: &'a R,
    continuation: &'a C,
}

impl<'a,R,C> RegexContinuation for StarMinState<'a,R,C>
    where R: RegexThen, C: RegexContinuation
{
    fn match_continue<'text>(&self,
                             text: &'text str,
                             start: usize,
                             captures: &mut Vec<Capture<'text>>)
                             -> Option<usize>
    {
        // First try what comes after us:
        let captures_len = captures.len();
        match self.continuation.match_continue(text, start, captures) {
            Some(end) => Some(end),
            None => {
                // If that fails, then try the repeat and come back to this point:
                captures.truncate(captures_len);
                self.repeat.match_then(text, start, captures, self)
            }
        }
    }
}

#[derive(Clone, Debug)]
pub struct Question<R>(pub R);

impl<R> RegexThen for Question<R>
    where R: RegexThen
{
    fn match_then<'text,C>(&self,
                           text: &'text str,
                           position: usize,
                           captures: &mut Vec<Capture<'text>>,
                           continuation: &C)
                           -> Option<usize>
        where C: RegexContinuation
    {
        match self.0.match_then(text, position, captures, continuation) {
            Some(end) => Some(end),
            None => continuation.match_continue(text, position, captures),
        }
    }
}

#[derive(Clone, Debug)]
pub struct CaptureRe<R>(pub R);

impl<R> RegexThen for CaptureRe<R>
    where R: RegexThen
{
    fn match_then<'text,C>(&self,
                           text: &'text str,
                           position: usize,
                           captures: &mut Vec<Capture<'text>>,
                           continuation: &C)
                           -> Option<usize>
        where C: RegexContinuation
    {
        let index = captures.len();

        let post_capture = PostCaptureRe {
            index: index,
            continuation: continuation,
        };

        captures.push(Capture { text: text, start: position, end: position });

        self.0.match_then(text, position, captures, &post_capture)
    }
}

struct PostCaptureRe<'r, C:'r> {
    index: usize,
    continuation: &'r C
}

impl<'r, C> RegexContinuation for PostCaptureRe<'r, C>
    where C: RegexContinuation
{
    fn match_continue<'text>(&self,
                             text: &'text str,
                             position: usize,
                             captures: &mut Vec<Capture<'text>>)
                             -> Option<usize>
    {
        captures[self.index].end = position;
        self.continuation.match_continue(text, position, captures)
    }
}

#[derive(Clone, Debug)]
pub struct Literal(pub &'static str);

impl RegexThen for Literal {
    fn match_then<'text,C>(&self,
                           text: &'text str,
                           position: usize,
                           captures: &mut Vec<Capture<'text>>,
                           continuation: &C)
                           -> Option<usize>
        where C: RegexContinuation
    {
        if text[position..].starts_with(self.0) {
            let len = self.0.len();
            continuation.match_continue(text, position + len, captures)
        } else {
            None
        }
    }
}

#[derive(Clone, Debug)]
pub struct Choice<CR:CharRange>(pub CR);

impl<CR> RegexThen for Choice<CR>
    where CR: CharRange
{
    fn match_then<'text,C>(&self,
                           text: &'text str,
                           position: usize,
                           captures: &mut Vec<Capture<'text>>,
                           continuation: &C)
                           -> Option<usize>
        where C: RegexContinuation
    {
        if let Some(c) = text[position..].chars().next() {
            if self.0.test(c) {
                let l = c.len_utf8();
                return continuation.match_continue(text, position + l, captures);
            }
        }

        None
    }
}

#[derive(Clone, Debug)]
pub struct CharChoice(pub char);

impl CharRange for CharChoice {
    fn test(&self, c: char) -> bool {
        self.0 == c
    }
}

#[derive(Clone, Debug)]
pub struct RangeChoice(char, char);

impl CharRange for RangeChoice {
    fn test(&self, c: char) -> bool {
        let lo = self.0 as u32;
        let hi = self.1 as u32;
        let c = c as u32;
        (lo <= c) && (c <= hi)
    }
}

#[derive(Clone, Debug)]
pub struct NotChoice<CR>(pub CR);

impl<CR:CharRange> CharRange for NotChoice<CR> {
    fn test(&self, c: char) -> bool {
        !self.0.test(c)
    }
}

#[derive(Clone, Debug)]
pub struct OrChoice<CR1,CR2>(pub CR1, pub CR2);

impl<CR1:CharRange,CR2:CharRange> CharRange for OrChoice<CR1,CR2> {
    fn test(&self, c: char) -> bool {
        self.0.test(c) || self.1.test(c)
    }
}

#[derive(Clone, Debug)]
pub struct NoChoice;

impl CharRange for NoChoice {
    fn test(&self, _: char) -> bool {
        false
    }
}

#[derive(Clone, Debug)]
pub struct YesChoice;

impl CharRange for YesChoice {
    fn test(&self, _: char) -> bool {
        true
    }
}

pub mod named_choices {
    #![allow(non_camel_case_types)]
    use CharRange;

    pub struct alpha;

    impl CharRange for alpha {
        fn test(&self, c: char) -> bool {
            char::is_alphabetic(c)
        }
    }

    pub struct digit;

    impl CharRange for digit {
        fn test(&self, c: char) -> bool {
            c >= '0' && c <= '9'
        }
    }

    pub struct space;

    impl CharRange for space {
        fn test(&self, c: char) -> bool {
            char::is_whitespace(c)
        }
    }
}

<commit_msg>make public<commit_after>use super::{CharRange, Capture, RegexThen, RegexContinuation};

#[derive(Clone, Debug)]
pub struct Accept;

impl RegexThen for Accept {
    fn match_then<'text,C>(&self,
                           text: &'text str,
                           position: usize,
                           captures: &mut Vec<Capture<'text>>,
                           continuation: &C)
                           -> Option<usize>
        where C: RegexContinuation
    {
        continuation.match_continue(text, position, captures)
    }
}

impl RegexContinuation for Accept {
    fn match_continue<'text>(&self,
                             _text: &'text str,
                             position: usize,
                             _captures: &mut Vec<Capture<'text>>)
                             -> Option<usize>
    {
        Some(position)
    }
}

#[derive(Clone, Debug)]
pub struct End;

impl RegexThen for End {
    fn match_then<'text,C>(&self,
                           text: &'text str,
                           position: usize,
                           captures: &mut Vec<Capture<'text>>,
                           continuation: &C)
                           -> Option<usize>
        where C: RegexContinuation
    {
        if position == text.len() {
            continuation.match_continue(text, position, captures)
        } else {
            None
        }
    }
}

impl<R,U> RegexThen for (R,U)
    where R: RegexThen, U: RegexThen
{
    fn match_then<'text,C>(&self,
                           text: &'text str,
                           position: usize,
                           captures: &mut Vec<Capture<'text>>,
                           continuation: &C)
                           -> Option<usize>
        where C: RegexContinuation
    {
        let state = SeqMidState { next: &self.1, continuation: continuation };
        self.0.match_then(text, position, captures, &state)
    }
}

struct SeqMidState<'r,R:'r,C:'r> {
    next: &'r R,
    continuation: &'r C,
}

impl<'r,R,C> RegexContinuation for SeqMidState<'r,R,C>
    where R: RegexThen, C: RegexContinuation
{
    fn match_continue<'text>(&self,
                             text: &'text str,
                             position: usize,
                             captures: &mut Vec<Capture<'text>>)
                             -> Option<usize>
    {
        self.next.match_then(text, position, captures, self.continuation)
    }
}

#[derive(Clone, Debug)]
pub struct StarMax<R>(pub R);

impl<R> RegexThen for StarMax<R>
    where R: RegexThen
{
    fn match_then<'text,C>(&self,
                           text: &'text str,
                           position: usize,
                           captures: &mut Vec<Capture<'text>>,
                           continuation: &C)
                           -> Option<usize>
        where C: RegexContinuation
    {
        let state = StarMaxState { repeat: &self.0, continuation: continuation };
        state.match_continue(text, position, captures)
    }
}

#[derive(Clone, Debug)]
pub struct PlusMax<R>(pub R);

impl<R> RegexThen for PlusMax<R>
    where R: RegexThen
{
    fn match_then<'text,C>(&self,
                           text: &'text str,
                           position: usize,
                           captures: &mut Vec<Capture<'text>>,
                           continuation: &C)
                           -> Option<usize>
        where C: RegexContinuation
    {
        let state = StarMaxState { repeat: &self.0, continuation: continuation };
        self.0.match_then(text, position, captures, &state)
    }
}

struct StarMaxState<'a,R:'a,C:'a> {
    repeat: &'a R,
    continuation: &'a C,
}

impl<'a,R,C> RegexContinuation for StarMaxState<'a,R,C>
    where R: RegexThen, C: RegexContinuation
{
    fn match_continue<'text>(&self,
                             text: &'text str,
                             start: usize,
                             captures: &mut Vec<Capture<'text>>)
                             -> Option<usize>
    {
        // You may be wondering "where is the loop?" The answer is
        // that the loop occurs by passing `self` as the
        // *continuation* for `self.repeat`. This means that after we
        // match the repeating part, we will resume in the same state,
        // ready to try again, but with a different start point.  Only
        // once we fail will we fallback to `self.continuation`.
        let captures_len = captures.len();
        match self.repeat.match_then(text, start, captures, self) {
            Some(end) => Some(end),
            None => {
                captures.truncate(captures_len);
                self.continuation.match_continue(text, start, captures)
            }
        }
    }
}

#[derive(Clone, Debug)]
pub struct StarMin<R>(pub R);

impl<R> RegexThen for StarMin<R>
    where R: RegexThen
{
    fn match_then<'text,C>(&self,
                           text: &'text str,
                           position: usize,
                           captures: &mut Vec<Capture<'text>>,
                           continuation: &C)
                           -> Option<usize>
        where C: RegexContinuation
    {
        let state = StarMinState { repeat: &self.0, continuation: continuation };
        state.match_continue(text, position, captures)
    }
}

#[derive(Clone, Debug)]
pub struct PlusMin<R>(pub R);

impl<R> RegexThen for PlusMin<R>
    where R: RegexThen
{
    fn match_then<'text,C>(&self,
                           text: &'text str,
                           position: usize,
                           captures: &mut Vec<Capture<'text>>,
                           continuation: &C)
                           -> Option<usize>
        where C: RegexContinuation
    {
        let state = StarMinState { repeat: &self.0, continuation: continuation };
        self.0.match_then(text, position, captures, &state)
    }
}

struct StarMinState<'a,R:'a,C:'a> {
    repeat: &'a R,
    continuation: &'a C,
}

impl<'a,R,C> RegexContinuation for StarMinState<'a,R,C>
    where R: RegexThen, C: RegexContinuation
{
    fn match_continue<'text>(&self,
                             text: &'text str,
                             start: usize,
                             captures: &mut Vec<Capture<'text>>)
                             -> Option<usize>
    {
        // First try what comes after us:
        let captures_len = captures.len();
        match self.continuation.match_continue(text, start, captures) {
            Some(end) => Some(end),
            None => {
                // If that fails, then try the repeat and come back to this point:
                captures.truncate(captures_len);
                self.repeat.match_then(text, start, captures, self)
            }
        }
    }
}

#[derive(Clone, Debug)]
pub struct Question<R>(pub R);

impl<R> RegexThen for Question<R>
    where R: RegexThen
{
    fn match_then<'text,C>(&self,
                           text: &'text str,
                           position: usize,
                           captures: &mut Vec<Capture<'text>>,
                           continuation: &C)
                           -> Option<usize>
        where C: RegexContinuation
    {
        match self.0.match_then(text, position, captures, continuation) {
            Some(end) => Some(end),
            None => continuation.match_continue(text, position, captures),
        }
    }
}

#[derive(Clone, Debug)]
pub struct CaptureRe<R>(pub R);

impl<R> RegexThen for CaptureRe<R>
    where R: RegexThen
{
    fn match_then<'text,C>(&self,
                           text: &'text str,
                           position: usize,
                           captures: &mut Vec<Capture<'text>>,
                           continuation: &C)
                           -> Option<usize>
        where C: RegexContinuation
    {
        let index = captures.len();

        let post_capture = PostCaptureRe {
            index: index,
            continuation: continuation,
        };

        captures.push(Capture { text: text, start: position, end: position });

        self.0.match_then(text, position, captures, &post_capture)
    }
}

struct PostCaptureRe<'r, C:'r> {
    index: usize,
    continuation: &'r C
}

impl<'r, C> RegexContinuation for PostCaptureRe<'r, C>
    where C: RegexContinuation
{
    fn match_continue<'text>(&self,
                             text: &'text str,
                             position: usize,
                             captures: &mut Vec<Capture<'text>>)
                             -> Option<usize>
    {
        captures[self.index].end = position;
        self.continuation.match_continue(text, position, captures)
    }
}

#[derive(Clone, Debug)]
pub struct Literal(pub &'static str);

impl RegexThen for Literal {
    fn match_then<'text,C>(&self,
                           text: &'text str,
                           position: usize,
                           captures: &mut Vec<Capture<'text>>,
                           continuation: &C)
                           -> Option<usize>
        where C: RegexContinuation
    {
        if text[position..].starts_with(self.0) {
            let len = self.0.len();
            continuation.match_continue(text, position + len, captures)
        } else {
            None
        }
    }
}

#[derive(Clone, Debug)]
pub struct Choice<CR:CharRange>(pub CR);

impl<CR> RegexThen for Choice<CR>
    where CR: CharRange
{
    fn match_then<'text,C>(&self,
                           text: &'text str,
                           position: usize,
                           captures: &mut Vec<Capture<'text>>,
                           continuation: &C)
                           -> Option<usize>
        where C: RegexContinuation
    {
        if let Some(c) = text[position..].chars().next() {
            if self.0.test(c) {
                let l = c.len_utf8();
                return continuation.match_continue(text, position + l, captures);
            }
        }

        None
    }
}

#[derive(Clone, Debug)]
pub struct CharChoice(pub char);

impl CharRange for CharChoice {
    fn test(&self, c: char) -> bool {
        self.0 == c
    }
}

#[derive(Clone, Debug)]
pub struct RangeChoice(pub char, pub char);

impl CharRange for RangeChoice {
    fn test(&self, c: char) -> bool {
        let lo = self.0 as u32;
        let hi = self.1 as u32;
        let c = c as u32;
        (lo <= c) && (c <= hi)
    }
}

#[derive(Clone, Debug)]
pub struct NotChoice<CR>(pub CR);

impl<CR:CharRange> CharRange for NotChoice<CR> {
    fn test(&self, c: char) -> bool {
        !self.0.test(c)
    }
}

#[derive(Clone, Debug)]
pub struct OrChoice<CR1,CR2>(pub CR1, pub CR2);

impl<CR1:CharRange,CR2:CharRange> CharRange for OrChoice<CR1,CR2> {
    fn test(&self, c: char) -> bool {
        self.0.test(c) || self.1.test(c)
    }
}

#[derive(Clone, Debug)]
pub struct NoChoice;

impl CharRange for NoChoice {
    fn test(&self, _: char) -> bool {
        false
    }
}

#[derive(Clone, Debug)]
pub struct YesChoice;

impl CharRange for YesChoice {
    fn test(&self, _: char) -> bool {
        true
    }
}

pub mod named_choices {
    #![allow(non_camel_case_types)]
    use CharRange;

    pub struct alpha;

    impl CharRange for alpha {
        fn test(&self, c: char) -> bool {
            char::is_alphabetic(c)
        }
    }

    pub struct digit;

    impl CharRange for digit {
        fn test(&self, c: char) -> bool {
            c >= '0' && c <= '9'
        }
    }

    pub struct space;

    impl CharRange for space {
        fn test(&self, c: char) -> bool {
            char::is_whitespace(c)
        }
    }
}

<|endoftext|>


<commit_before>trait Mbc {
    fn read(&self, address: u16) -> u8;
    fn write(&mut self, address: u16, v: u8);
}

struct Mbc0 {
    data: Vec<u8>,
    ram: [u8; 8192],
}

impl Mbc0 {
    pub fn new(data: Vec<u8>) -> Mbc0 {
        Mbc0 {
            data: data,
            ram: [0; 8192],
        }
    }
}

impl Mbc for Mbc0 {
    fn read(&self, address: u16) -> u8 {
        match address {
            0x0000 ... 0x7FFF => self.data[address as usize],
            0xA000 ... 0xBFFF => self.ram[(address as usize) - 0xA000],
            _ => unimplemented!(),
        }
    }

    fn write(&mut self, address: u16, v: u8) {
        // println!("Writing {:02X} to {:04X}", v, address);
        // match address {
        //    0xA000 ... 0xBFFF => self.ram[(address as usize) - 0xA000] = v,
        //    _ => unimplemented!(),
        //}
    }
}

#[derive(PartialEq, Eq)]
enum MemoryMode {
    C4_32,
    C16_8,
}

struct Mbc3 {
    selected_bank: usize,
    data: Vec<u8>,
    offset: usize,
    ram: [u8; 32768], // Up to 4 x 8KB banks
    memory_mode: MemoryMode,

    ram_offset: usize,
    ram_enabled: bool,
}

impl Mbc3 {
    pub fn new(data: Vec<u8>) -> Mbc3 {
        Mbc3 {
            selected_bank: 1,
            data: data,
            offset: 0,
            ram: [0; 32768],
            memory_mode: MemoryMode::C4_32,

            ram_offset: 0,
            ram_enabled: false,
        }
    }

    fn write_ram(&mut self, address: u16, v: u8) {
        if !self.ram_enabled {
            panic!("MBC3 RAM has not been enabled.");
        }

        self.ram[(address - 0xA000) as usize + self.ram_offset] = v;
    }

    fn read_ram(&self, address: u16) -> u8 {
        if !self.ram_enabled {
            panic!("MBC3 RAM has not been enabled.");
        }

        self.ram[(address - 0xA000) as usize + self.ram_offset]
    }
}

impl Mbc for Mbc3 {
    fn read(&self, address: u16) -> u8 {
        match address {
            0x0000 ... 0x3FFF => self.data[address as usize],
            0x4000 ... 0x7FFF => self.data[address as usize + self.offset],
            0xA000 ... 0xBFFF => self.read_ram(address),
            _ => unimplemented!(),
        }
    }

    fn write(&mut self, address: u16, v: u8) {
        match address {
            0x0000 ... 0x1FFF => {
                match v {
                    0x00 => self.ram_enabled = false,
                    0x0A => self.ram_enabled = true,
                    _    => panic!("Unrecognized value for RAM enablement."),
                }
            },
            0x2000 ... 0x3FFF => {
                // Any write to this area will enable the bank of memory contained in v
                // if 0 is selected we will select 1 because 0 is already available
                // statically in 0 0000 - 3FFF
                if v > 0 {
                    self.offset = ((v - 1) as usize) * 0x4000;
                } else {
                    self.offset = 0x0000;
                }
                // println!("Setting offset to {:06X}", self.offset);
            },
            0x4000 ... 0x5FFF => {
                match v {
                    0x00 => self.ram_offset = 0,
                    0x01 => self.ram_offset = 8192,
                    0x02 => self.ram_offset = 16384,
                    0x03 => self.ram_offset = 24576,
                    _ => unimplemented!(),
                }
            },
            0x6000 ... 0x7FFF => {
                println!("Attempt to write {:02X} to {:04X}", v, address);
                /* match v & 0x1 {
                    0x0 => self.memory_mode = MemoryMode::C16_8, // Memory mode 16_8,
                    0x1 => self.memory_mode = MemoryMode::C4_32,
                    _   => panic!(),
                }*/
            },
            0xA000 ... 0xBFFF => { self.write_ram(address, v); },
            _ => unimplemented!(),
        }
    }
}

pub struct MemoryController {
    controller: Box<Mbc>,
}

impl MemoryController {
    pub fn from_bytes(bytes: Vec<u8>) -> MemoryController {
        let controller = match bytes[0x147] {
            0x00 => Box::new(Mbc0::new(bytes)) as Box<Mbc>,
            0x0F | 0x10 | 0x11 | 0x12 | 0x13 | 0x01 => Box::new(Mbc3::new(bytes)) as Box<Mbc>,
            _ => {
                println!("Unrecognized type {:02X}", bytes[0x147]);
                panic!();
            }
        };

        MemoryController {
            controller: controller,
        }
    }

    pub fn read(&self, address: u16) -> u8 {
        self.controller.read(address)
    }

    pub fn write(&mut self, address: u16, v: u8) {
        self.controller.write(address, v);
    }
}
<commit_msg>Implement save functionality for MBC3<commit_after>use std::fs::{File, OpenOptions};
use std::io::{Read, Write, Seek, SeekFrom};
use std::cell::RefCell;

trait Mbc {
    fn read(&self, address: u16) -> u8;
    fn write(&mut self, address: u16, v: u8);
}

struct Mbc0 {
    data: Vec<u8>,
    ram: [u8; 8192],
}

impl Mbc0 {
    pub fn new(data: Vec<u8>) -> Mbc0 {
        Mbc0 {
            data: data,
            ram: [0; 8192],
        }
    }
}

impl Mbc for Mbc0 {
    fn read(&self, address: u16) -> u8 {
        match address {
            0x0000 ... 0x7FFF => self.data[address as usize],
            0xA000 ... 0xBFFF => self.ram[(address as usize) - 0xA000],
            _ => unimplemented!(),
        }
    }

    fn write(&mut self, address: u16, v: u8) {
        // println!("Writing {:02X} to {:04X}", v, address);
        // match address {
        //    0xA000 ... 0xBFFF => self.ram[(address as usize) - 0xA000] = v,
        //    _ => unimplemented!(),
        //}
    }
}

#[derive(PartialEq, Eq)]
enum MemoryMode {
    C4_32,
    C16_8,
}

struct Mbc3 {
    selected_bank: usize,
    data: Vec<u8>,
    offset: usize,
    ram: RefCell<File>,
    memory_mode: MemoryMode,

    ram_offset: usize,
    ram_enabled: bool,
}

impl Mbc3 {
    pub fn new(data: Vec<u8>) -> Mbc3 {
        let mut disk = OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .open("save.dat")
            .unwrap();

        let mut ram = vec![];
        disk.read_to_end(&mut ram);

        if ram.len() < 32768 {
            println!("Warning: invalid file size, blanking ram.");
            disk.seek(SeekFrom::Start(0));
            disk.write_all(&[0; 32768]);
        }

        Mbc3 {
            selected_bank: 1,
            data: data,
            offset: 0,
            ram: RefCell::new(disk),
            memory_mode: MemoryMode::C4_32,

            ram_offset: 0,
            ram_enabled: false,
        }
    }

    fn write_ram(&mut self, address: u16, v: u8) {
        if !self.ram_enabled {
            panic!("MBC3 RAM has not been enabled.");
        }

        let address = (address - 0xA000) as usize + self.ram_offset;
        self.ram.borrow_mut().seek(SeekFrom::Start(address as u64));
        self.ram.borrow_mut().write_all(&[v]);
    }

    fn read_ram(&self, address: u16) -> u8 {
        if !self.ram_enabled {
            panic!("MBC3 RAM has not been enabled.");
        }

        let address = (address - 0xA000) as usize + self.ram_offset;
        self.ram.borrow_mut().seek(SeekFrom::Start(address as u64));
        let mut buffer = [0; 1];
        self.ram.borrow_mut().read_exact(&mut buffer).unwrap();

        buffer[0]
    }
}

impl Mbc for Mbc3 {
    fn read(&self, address: u16) -> u8 {
        match address {
            0x0000 ... 0x3FFF => self.data[address as usize],
            0x4000 ... 0x7FFF => self.data[address as usize + self.offset],
            0xA000 ... 0xBFFF => self.read_ram(address),
            _ => unimplemented!(),
        }
    }

    fn write(&mut self, address: u16, v: u8) {
        match address {
            0x0000 ... 0x1FFF => {
                match v {
                    0x00 => self.ram_enabled = false,
                    0x0A => self.ram_enabled = true,
                    _    => panic!("Unrecognized value for RAM enablement."),
                }
            },
            0x2000 ... 0x3FFF => {
                // Any write to this area will enable the bank of memory contained in v
                // if 0 is selected we will select 1 because 0 is already available
                // statically in 0 0000 - 3FFF
                if v > 0 {
                    self.offset = ((v - 1) as usize) * 0x4000;
                } else {
                    self.offset = 0x0000;
                }
                // println!("Setting offset to {:06X}", self.offset);
            },
            0x4000 ... 0x5FFF => {
                match v {
                    0x00 => self.ram_offset = 0,
                    0x01 => self.ram_offset = 8192,
                    0x02 => self.ram_offset = 16384,
                    0x03 => self.ram_offset = 24576,
                    _ => unimplemented!(),
                }
            },
            0x6000 ... 0x7FFF => {
                println!("Attempt to write {:02X} to {:04X}", v, address);
                /* match v & 0x1 {
                    0x0 => self.memory_mode = MemoryMode::C16_8, // Memory mode 16_8,
                    0x1 => self.memory_mode = MemoryMode::C4_32,
                    _   => panic!(),
                }*/
            },
            0xA000 ... 0xBFFF => { self.write_ram(address, v); },
            _ => unimplemented!(),
        }
    }
}

pub struct MemoryController {
    controller: Box<Mbc>,
}

impl MemoryController {
    pub fn from_bytes(bytes: Vec<u8>) -> MemoryController {
        let controller = match bytes[0x147] {
            0x00 => Box::new(Mbc0::new(bytes)) as Box<Mbc>,
            0x0F | 0x10 | 0x11 | 0x12 | 0x13 | 0x01 => Box::new(Mbc3::new(bytes)) as Box<Mbc>,
            _ => {
                println!("Unrecognized type {:02X}", bytes[0x147]);
                panic!();
            }
        };

        MemoryController {
            controller: controller,
        }
    }

    pub fn read(&self, address: u16) -> u8 {
        self.controller.read(address)
    }

    pub fn write(&mut self, address: u16, v: u8) {
        self.controller.write(address, v);
    }
}
<|endoftext|>