<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::sync::mpsc::channel;
use std::thread::Thread;
use std::old_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: usize = 64;
const ETHERNET_HEADER_LEN: usize = 14;
const IPV4_HEADER_LEN: usize = 20;
const IPV6_HEADER_LEN: usize = 40;
const UDP_HEADER_LEN: usize = 8;
const TEST_DATA_LEN: usize = 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: usize) {
    let mut ip_header = MutableIpv4Header::new(&mut packet[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: usize) {
    let mut ip_header = MutableIpv6Header::new(&mut packet[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: usize) {
    let mut udp_header = MutableUdpHeader::new(&mut packet[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: usize, msg: &str) {
    build_ipv4_header(packet, start);
    build_udp_header(packet, start + IPV4_HEADER_LEN as usize);

    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 = &mut packet[(start + IPV4_HEADER_LEN as usize)..];
    MutableUdpHeader::new(slice).checksum(IPV4_SOURCE, IPV4_DESTINATION, TEST_PROTO);
}

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

    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 = &mut packet[(start + IPV6_HEADER_LEN as usize)..];
    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: usize) {
    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[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::scoped( move || {
        tx.send(()).unwrap();
        let mut iter = udp_header_iter(&mut trx);
        loop {
            let next = iter.next();
            match next {
                Ok((header, addr)) => {
                    assert_eq!(addr, ip);
                    assert_eq!(header, UdpHeader::new(&packet[header_len .. packet_len]));
                    break;
                },
                Err(e) => {
                    panic!("Receive failed for layer4_test(): {}", e);
                }
            }

        }
    });

    rx.recv().unwrap();
    match ttx.send_to(udp, ip) {
        Ok(res) => assert_eq!(res as usize, 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 usize);
}

#[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::scoped( move || {
        tx.send(()).unwrap();
        let mut iter = ipv4_header_iter(&mut trx);
        loop {
            let next = iter.next();
            match next {
                Ok((header, addr)) => {
                    assert_eq!(addr, send_addr);
                    check_ipv4_header(packet.as_slice(), header);
                    let udp_header = UdpHeader::new(&header.packet()[
                                                   (header.get_header_length() as usize * 4us) ..]);
                    assert_eq!(udp_header, UdpHeader::new(&packet[IPV4_HEADER_LEN..]));

                    assert_eq!(&udp_header.packet()[UDP_HEADER_LEN..],
                               &packet[IPV4_HEADER_LEN + UDP_HEADER_LEN..]);
                    break;
                },
                Err(e) => {
                    panic!("receive failed for layer3_ipv4_test(): {}", e);
                }
            }
        }
    });

    rx.recv().unwrap();
    match ttx.send_to(Ipv4Header::new(packet.as_slice()), send_addr) {
        Ok(res) => assert_eq!(res as usize, 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 usize, "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::scoped( move || {
        tx.send(()).unwrap();
        let mut i = 0us;
        let mut iter = dlrx.iter();
        loop {
            let next = iter.next();
            match next {
                Ok(eh) => {
                    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;
                },
                Err(e) => {
                    panic!("layer2 failed: {}", e);
                }
            }
        }
    });

    rx.recv().unwrap();
    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() {}
}
<commit_msg>Ignore layer 2 tests for netmap for now.<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::sync::mpsc::channel;
use std::thread::Thread;
use std::old_io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::iter::Iterator;

use packet::Packet;
use packet::ethernet::{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};

const IPV4_HEADER_LEN: usize = 20;
const IPV6_HEADER_LEN: usize = 40;
const UDP_HEADER_LEN: usize = 8;
const TEST_DATA_LEN: usize = 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: usize) {
    let mut ip_header = MutableIpv4Header::new(&mut packet[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: usize) {
    let mut ip_header = MutableIpv6Header::new(&mut packet[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: usize) {
    let mut udp_header = MutableUdpHeader::new(&mut packet[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: usize, msg: &str) {
    build_ipv4_header(packet, start);
    build_udp_header(packet, start + IPV4_HEADER_LEN as usize);

    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 = &mut packet[(start + IPV4_HEADER_LEN as usize)..];
    MutableUdpHeader::new(slice).checksum(IPV4_SOURCE, IPV4_DESTINATION, TEST_PROTO);
}

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

    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 = &mut packet[(start + IPV6_HEADER_LEN as usize)..];
    MutableUdpHeader::new(slice).checksum(IPV6_SOURCE, IPV6_DESTINATION, TEST_PROTO);
}

// 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: usize) {
    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[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::scoped( move || {
        tx.send(()).unwrap();
        let mut iter = udp_header_iter(&mut trx);
        loop {
            let next = iter.next();
            match next {
                Ok((header, addr)) => {
                    assert_eq!(addr, ip);
                    assert_eq!(header, UdpHeader::new(&packet[header_len .. packet_len]));
                    break;
                },
                Err(e) => {
                    panic!("Receive failed for layer4_test(): {}", e);
                }
            }

        }
    });

    rx.recv().unwrap();
    match ttx.send_to(udp, ip) {
        Ok(res) => assert_eq!(res as usize, 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 usize);
}

#[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::scoped( move || {
        tx.send(()).unwrap();
        let mut iter = ipv4_header_iter(&mut trx);
        loop {
            let next = iter.next();
            match next {
                Ok((header, addr)) => {
                    assert_eq!(addr, send_addr);
                    check_ipv4_header(packet.as_slice(), header);
                    let udp_header = UdpHeader::new(&header.packet()[
                                                   (header.get_header_length() as usize * 4us) ..]);
                    assert_eq!(udp_header, UdpHeader::new(&packet[IPV4_HEADER_LEN..]));

                    assert_eq!(&udp_header.packet()[UDP_HEADER_LEN..],
                               &packet[IPV4_HEADER_LEN + UDP_HEADER_LEN..]);
                    break;
                },
                Err(e) => {
                    panic!("receive failed for layer3_ipv4_test(): {}", e);
                }
            }
        }
    });

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

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

}

// FIXME Find a way to test this with netmap
#[cfg(not(feature = "netmap"))]
#[test]
fn layer2() {
    use datalink::{datalink_channel, DataLinkChannelType};
    use packet::ethernet::{EtherTypes, EthernetHeader, MutableEthernetHeader};
    use util;

    const MIN_PACKET_SIZE: usize = 64;
    const ETHERNET_HEADER_LEN: usize = 14;

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

        (*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()
    }

    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 usize, "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::scoped( move || {
        tx.send(()).unwrap();
        let mut i = 0us;
        let mut iter = dlrx.iter();
        loop {
            let next = iter.next();
            match next {
                Ok(eh) => {
                    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;
                },
                Err(e) => {
                    panic!("layer2 failed: {}", e);
                }
            }
        }
    });

    rx.recv().unwrap();
    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>#[test]
fn parse_basic_wind() {
    let wind = ::parse_wind("3127", 3000u32).unwrap();

    assert_eq!(wind.speed, 27u32);
    assert_eq!(wind.direction, 310u32);
}

#[test]
fn parse_bad_wind() {
    let wind = ::parse_wind("invalid", 3000u32);
    let parsed = match wind {
        Some(_) => true,
        None => false,
    };

    assert_eq!(parsed, false);
}

#[test]
fn parse_wind_with_negative_temp() {
    let wind = ::parse_wind("3127-32", 3000u32).unwrap();

    assert_eq!(wind.speed, 27u32);
    assert_eq!(wind.direction, 310u32);
}

#[test]
fn parse_wind_with_positive_temp() {
    let wind = ::parse_wind("3127+32", 3000u32).unwrap();

    assert_eq!(wind.speed, 27u32);
    assert_eq!(wind.direction, 310u32);
}

#[test]
fn need_update_0_12() {
    let forecast = ::WindsAloftForecast {
        forecast_time: 0000u32,
        time_retrieved: 0000u32,
        forecasts: Vec::new(),
    };

    assert!(forecast.needs_refresh_time_given(1200u32));
    assert!(forecast.needs_refresh_time_given(1250u32));
}

#[test]
fn need_update_12_12() {
    let forecast = ::WindsAloftForecast {
        forecast_time: 1200u32,
        time_retrieved: 1200u32,
        forecasts: Vec::new(),
    };

    assert!(!forecast.needs_refresh_time_given(1200u32));
    assert!(!forecast.needs_refresh_time_given(1250u32));
}

#[test]
fn need_update_12_10() {
    let forecast = ::WindsAloftForecast {
        forecast_time: 1200u32,
        time_retrieved: 1200u32,
        forecasts: Vec::new(),
    };

    assert!(forecast.needs_refresh_time_given(1000u32));
    assert!(forecast.needs_refresh_time_given(1050u32));
}

#[test]
fn need_update_12_0() {
    let forecast = ::WindsAloftForecast {
        forecast_time: 1200u32,
        time_retrieved: 1200u32,
        forecasts: Vec::new(),
    };

    assert!(forecast.needs_refresh_time_given(0000u32));
    assert!(forecast.needs_refresh_time_given(0050u32));
}

#[test]
fn need_update_18_0() {
    let forecast = ::WindsAloftForecast {
        forecast_time: 1800u32,
        time_retrieved: 1800u32,
        forecasts: Vec::new(),
    };

    assert!(forecast.needs_refresh_time_given(0000u32));
    assert!(forecast.needs_refresh_time_given(0050u32));
}

#[test]
fn test_parse_12_time_from_body() {
    let body = "
        000
        FBUS31 KWNO 061406
        FD1US1
        DATA BASED ON 061200Z
        VALID 061800Z   FOR USE 1400-2100Z. TEMPS NEG ABV 24000

        FT  3000    6000    9000   12000   18000   24000  30000  34000  39000
    ";

    assert_eq!(::WindsAloftForecast::parse_time_from_body(body), 1200u32);
}

#[test]
fn test_parse_1432_time_from_body() {
    let body = "
        000
        FBUS31 KWNO 061406
        FD1US1
        DATA BASED ON 061432Z
        VALID 061800Z   FOR USE 1400-2100Z. TEMPS NEG ABV 24000

        FT  3000    6000    9000   12000   18000   24000  30000  34000  39000
    ";

    assert_eq!(::WindsAloftForecast::parse_time_from_body(body), 1432u32);
}
<commit_msg>add new test<commit_after>#[test]
fn parse_basic_wind() {
    let wind = ::parse_wind("3127", 3000u32).unwrap();

    assert_eq!(wind.speed, 27u32);
    assert_eq!(wind.direction, 310u32);
}

#[test]
fn parse_bad_wind() {
    let wind = ::parse_wind("invalid", 3000u32);
    let parsed = match wind {
        Some(_) => true,
        None => false,
    };

    assert_eq!(parsed, false);
}

#[test]
fn parse_wind_with_negative_temp() {
    let wind = ::parse_wind("3127-32", 3000u32).unwrap();

    assert_eq!(wind.speed, 27u32);
    assert_eq!(wind.direction, 310u32);
}

#[test]
fn parse_wind_with_positive_temp() {
    let wind = ::parse_wind("3127+32", 3000u32).unwrap();

    assert_eq!(wind.speed, 27u32);
    assert_eq!(wind.direction, 310u32);
}

#[test]
fn need_update_0_12() {
    let forecast = ::WindsAloftForecast {
        forecast_time: 0000u32,
        time_retrieved: 0000u32,
        forecasts: Vec::new(),
    };

    assert!(forecast.needs_refresh_time_given(1200u32));
    assert!(forecast.needs_refresh_time_given(1250u32));
}

#[test]
fn need_update_12_12() {
    let forecast = ::WindsAloftForecast {
        forecast_time: 1200u32,
        time_retrieved: 1200u32,
        forecasts: Vec::new(),
    };

    assert!(!forecast.needs_refresh_time_given(1200u32));
    assert!(!forecast.needs_refresh_time_given(1250u32));
}

#[test]
fn need_update_12_10() {
    let forecast = ::WindsAloftForecast {
        forecast_time: 1200u32,
        time_retrieved: 1200u32,
        forecasts: Vec::new(),
    };

    assert!(forecast.needs_refresh_time_given(1000u32));
    assert!(forecast.needs_refresh_time_given(1050u32));
}

#[test]
fn need_update_12_0() {
    let forecast = ::WindsAloftForecast {
        forecast_time: 1200u32,
        time_retrieved: 1200u32,
        forecasts: Vec::new(),
    };

    assert!(forecast.needs_refresh_time_given(0000u32));
    assert!(forecast.needs_refresh_time_given(0050u32));
}

#[test]
fn need_update_18_0() {
    let forecast = ::WindsAloftForecast {
        forecast_time: 1800u32,
        time_retrieved: 1800u32,
        forecasts: Vec::new(),
    };

    assert!(forecast.needs_refresh_time_given(0000u32));
    assert!(forecast.needs_refresh_time_given(0050u32));
}

#[test]
fn test_parse_12_time_from_body() {
    let body = "
        000
        FBUS31 KWNO 061406
        FD1US1
        DATA BASED ON 061200Z
        VALID 061800Z   FOR USE 1400-2100Z. TEMPS NEG ABV 24000

        FT  3000    6000    9000   12000   18000   24000  30000  34000  39000
    ";

    assert_eq!(::WindsAloftForecast::parse_time_from_body(body), 1200u32);
}

#[test]
fn test_parse_1432_time_from_body() {
    let body = "
        000
        FBUS31 KWNO 061406
        FD1US1
        DATA BASED ON 061432Z
        VALID 061800Z   FOR USE 1400-2100Z. TEMPS NEG ABV 24000

        FT  3000    6000    9000   12000   18000   24000  30000  34000  39000
    ";

    assert_eq!(::WindsAloftForecast::parse_time_from_body(body), 1432u32);
}

#[test]
fn test_immediate_need_refresh() {
    let forecast = ::WindsAloftForecast::new();
    assert!(!forecast.needs_refresh());
}
<|endoftext|>


<commit_before>//! Functions to read time stamp counters on x86.

use crate::arch::{__rdtscp, _rdtsc};

/// Read the time stamp counter.
///
/// The RDTSC instruction is not a serializing instruction.
/// It does not necessarily wait until all previous instructions
/// have been executed before reading the counter. Similarly,
/// subsequent instructions may begin execution before the
/// read operation is performed. If software requires RDTSC to be
/// executed only after all previous instructions have completed locally,
/// it can either use RDTSCP or execute the sequence LFENCE;RDTSC.
///
/// # Safety
/// * Causes a GP fault if the TSD flag in register CR4 is set and the CPL
///   is greater than 0.
pub unsafe fn rdtsc() -> u64 {
    _rdtsc() as u64
}

/// Read the time stamp counter.
///
/// The RDTSCP instruction waits until all previous instructions
/// have been executed before reading the counter.
/// However, subsequent instructions may begin execution
/// before the read operation is performed.
///
/// Volatile is used here because the function may be used to act as
/// an instruction barrier.
///
/// # Safety
/// * Causes a GP fault if the TSD flag in register CR4 is set and the
///   CPL is greater than 0.
pub unsafe fn rdtscp() -> u64 {
    let mut _aux = 0;
    __rdtscp(&mut _aux)
}

#[cfg(all(test, feature = "utest"))]
mod test {
    use super::*;

    #[test]
    fn check_rdtsc() {
        unsafe {
            assert!(rdtsc() > 0, "rdtsc returned 0, unlikely!");
        }
    }

    #[test]
    fn check_rdtscp() {
        unsafe {
            assert!(rdtscp() > 0, "rdtscp returned 0, unlikely!");
        }
    }
}
<commit_msg>Fix rdtsc/p tests.<commit_after>//! Functions to read time stamp counters on x86.

use crate::arch::{__rdtscp, _rdtsc};

/// Read the time stamp counter.
///
/// The RDTSC instruction is not a serializing instruction.
/// It does not necessarily wait until all previous instructions
/// have been executed before reading the counter. Similarly,
/// subsequent instructions may begin execution before the
/// read operation is performed. If software requires RDTSC to be
/// executed only after all previous instructions have completed locally,
/// it can either use RDTSCP or execute the sequence LFENCE;RDTSC.
///
/// # Safety
/// * Causes a GP fault if the TSD flag in register CR4 is set and the CPL
///   is greater than 0.
pub unsafe fn rdtsc() -> u64 {
    _rdtsc() as u64
}

/// Read the time stamp counter.
///
/// The RDTSCP instruction waits until all previous instructions
/// have been executed before reading the counter.
/// However, subsequent instructions may begin execution
/// before the read operation is performed.
///
/// Volatile is used here because the function may be used to act as
/// an instruction barrier.
///
/// # Safety
/// * Causes a GP fault if the TSD flag in register CR4 is set and the
///   CPL is greater than 0.
pub unsafe fn rdtscp() -> u64 {
    let mut _aux = 0;
    __rdtscp(&mut _aux)
}

#[cfg(all(test, feature = "utest"))]
mod test {
    use super::*;

    #[test]
    fn check_rdtsc() {
        let cpuid = crate::cpuid::CpuId::new();
        let has_tsc = cpuid
            .get_feature_info()
            .map_or(false, |finfo| finfo.has_tsc());

        if has_tsc {
            unsafe {
                assert!(rdtsc() > 0, "rdtsc returned 0, unlikely!");
            }
        }
    }

    #[test]
    fn check_rdtscp() {
        let cpuid = crate::cpuid::CpuId::new();
        let has_tsc = cpuid
            .get_feature_info()
            .map_or(false, |finfo| finfo.has_tsc());

        if has_tsc {
            unsafe {
                assert!(rdtscp() > 0, "rdtscp returned 0, unlikely!");
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate uuid;

use self::uuid::Uuid;

use super::value::{
    Value,
    FromValue,
    ConvIr,
};
use super::error::{
    Error,
    Result as MyResult,
};

impl Into<Value> for Uuid {
    fn into(self) -> Value {
        Value::Bytes(self.as_bytes().to_vec())
    }
}

#[derive(Debug)]
pub struct UuidIr {
    val: Uuid,
    bytes: Vec<u8>,
}

impl ConvIr<Uuid> for UuidIr {
    fn new(v: Value) -> MyResult<UuidIr> {
        match v {
            Value::Bytes(bytes) => match Uuid::from_bytes(bytes.as_slice()) {
                Ok(val) => Ok(UuidIr { val: val, bytes: bytes }),
                Err(_) => Err(Error::FromValueError(Value::Bytes(bytes))),
            },
            v => Err(Error::FromValueError(v)),
        }
    }
    fn commit(self) -> Uuid {
        self.val
    }
    fn rollback(self) -> Value {
        Value::Bytes(self.bytes)
    }
}

impl FromValue for Uuid {
    type Intermediate = UuidIr;
}

#[cfg(test)]
mod test {
    use super::super::value::Value::Bytes;
    use super::super::from_value;
    use super::uuid::Uuid;

    #[test]
    fn should_convert_Bytes_to_Uuid() {
        let bytes = vec![0x0e, 0x87, 0x6d, 0x72, 0xc7, 0xb2, 0x4c, 0x00, 0x8c, 0x56, 0x44, 0xee, 0xac, 0x10, 0x15, 0xd1];
        assert_eq!(
            Uuid::parse_str("0e876d72-c7b2-4c00-8c56-44eeac1015d1").unwrap(),
            from_value::<Uuid>(Bytes(bytes))
        );
    }

    #[test]
    fn should_convert_Uuid_to_Bytes() {
        let bytes = vec![0x0e, 0x87, 0x6d, 0x72, 0xc7, 0xb2, 0x4c, 0x00, 0x8c, 0x56, 0x44, 0xee, 0xac, 0x10, 0x15, 0xd1];
        assert_eq!(
            Bytes(bytes),
            Uuid::parse_str("0e876d72-c7b2-4c00-8c56-44eeac1015d1").unwrap().into()
        );
    }
}
<commit_msg>Remove compiler warnings<commit_after>extern crate uuid;

use self::uuid::Uuid;

use super::value::{
    Value,
    FromValue,
    ConvIr,
};
use super::error::{
    Error,
    Result as MyResult,
};

impl Into<Value> for Uuid {
    fn into(self) -> Value {
        Value::Bytes(self.as_bytes().to_vec())
    }
}

#[derive(Debug)]
pub struct UuidIr {
    val: Uuid,
    bytes: Vec<u8>,
}

impl ConvIr<Uuid> for UuidIr {
    fn new(v: Value) -> MyResult<UuidIr> {
        match v {
            Value::Bytes(bytes) => match Uuid::from_bytes(bytes.as_slice()) {
                Ok(val) => Ok(UuidIr { val: val, bytes: bytes }),
                Err(_) => Err(Error::FromValueError(Value::Bytes(bytes))),
            },
            v => Err(Error::FromValueError(v)),
        }
    }
    fn commit(self) -> Uuid {
        self.val
    }
    fn rollback(self) -> Value {
        Value::Bytes(self.bytes)
    }
}

impl FromValue for Uuid {
    type Intermediate = UuidIr;
}

#[cfg(test)]
mod test {
    use super::super::value::Value::Bytes;
    use super::super::from_value;
    use super::uuid::Uuid;

    #[test]
    fn should_convert_bytes_to_uuid() {
        let bytes = vec![0x0e, 0x87, 0x6d, 0x72, 0xc7, 0xb2, 0x4c, 0x00, 0x8c, 0x56, 0x44, 0xee, 0xac, 0x10, 0x15, 0xd1];
        assert_eq!(
            Uuid::parse_str("0e876d72-c7b2-4c00-8c56-44eeac1015d1").unwrap(),
            from_value::<Uuid>(Bytes(bytes))
        );
    }

    #[test]
    fn should_convert_uuid_to_bytes() {
        let bytes = vec![0x0e, 0x87, 0x6d, 0x72, 0xc7, 0xb2, 0x4c, 0x00, 0x8c, 0x56, 0x44, 0xee, 0xac, 0x10, 0x15, 0xd1];
        assert_eq!(
            Bytes(bytes),
            Uuid::parse_str("0e876d72-c7b2-4c00-8c56-44eeac1015d1").unwrap().into()
        );
    }
}
<|endoftext|>


<commit_before>use parse::IrcMsg;

pub trait FromIrcMsg {
    fn from_irc_msg(msg: IrcMsg) -> Result<Self, IrcMsg>;
}<commit_msg>Add Sized bound to FromIrcMsg to fix warning<commit_after>use parse::IrcMsg;

pub trait FromIrcMsg: Sized {
    fn from_irc_msg(msg: IrcMsg) -> Result<Self, IrcMsg>;
}<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::ErrorCode;
use serde::Deserialize;
use serde_json::Value;
use std::fs::File;
use std::io::BufReader;
use std::path::Path;
use std::process::Command;

pub trait Loader<T> {
    fn load(&self, path: &Path) -> Result<Option<T>, ErrorCode>;
}

pub struct PackageJsonLoader<'a> {
    pub key: &'a str,
}
impl<'a, T: for<'de> Deserialize<'de>> Loader<T> for PackageJsonLoader<'a> {
    fn load(&self, path: &Path) -> Result<Option<T>, ErrorCode> {
        let file = File::open(&path).unwrap();
        let reader = BufReader::new(file);
        let mut package_json: Value = serde_json::from_reader(reader)
            .map_err(|error| ErrorCode::PackageJsonParseError { error })?;
        if let Some(config_value) = package_json.get_mut(self.key) {
            match serde_json::from_value::<T>(config_value.take()) {
                Ok(config) => Ok(Some(config)),
                Err(error) => Err(ErrorCode::PackageJsonInvalidValue {
                    key: self.key.into(),
                    error,
                }),
            }
        } else {
            Ok(None)
        }
    }
}

pub struct YamlLoader;
impl<T> Loader<T> for YamlLoader {
    fn load(&self, _path: &Path) -> Result<Option<T>, ErrorCode> {
        Err(ErrorCode::YamlFileUnsupported)
    }
}

pub struct JsonLoader;
impl<T: for<'de> Deserialize<'de> + 'static> Loader<T> for JsonLoader {
    fn load(&self, path: &Path) -> Result<Option<T>, ErrorCode> {
        let file = File::open(&path).unwrap();
        let reader = BufReader::new(file);
        let config = serde_json::from_reader(reader)?;
        Ok(Some(config))
    }
}

pub struct JsLoader;
impl<T: for<'de> Deserialize<'de> + 'static> Loader<T> for JsLoader {
    fn load(&self, path: &Path) -> Result<Option<T>, ErrorCode> {
        let output = Command::new("node")
            .arg("-e")
            .arg(r#"process.stdout.write(JSON.stringify(require(process.argv[1])))"#)
            .arg(&path)
            .output()
            .expect("failed to execute process");

        if output.status.success() {
            let value = serde_json::from_slice::<T>(&output.stdout);
            Ok(Some(value.unwrap()))
        } else {
            Err(ErrorCode::NodeExecuteError { output })
        }
    }
}
<commit_msg>Error message for missing node<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::ErrorCode;
use serde::Deserialize;
use serde_json::Value;
use std::fs::File;
use std::io::BufReader;
use std::path::Path;
use std::process::Command;

pub trait Loader<T> {
    fn load(&self, path: &Path) -> Result<Option<T>, ErrorCode>;
}

pub struct PackageJsonLoader<'a> {
    pub key: &'a str,
}
impl<'a, T: for<'de> Deserialize<'de>> Loader<T> for PackageJsonLoader<'a> {
    fn load(&self, path: &Path) -> Result<Option<T>, ErrorCode> {
        let file = File::open(&path).unwrap();
        let reader = BufReader::new(file);
        let mut package_json: Value = serde_json::from_reader(reader)
            .map_err(|error| ErrorCode::PackageJsonParseError { error })?;
        if let Some(config_value) = package_json.get_mut(self.key) {
            match serde_json::from_value::<T>(config_value.take()) {
                Ok(config) => Ok(Some(config)),
                Err(error) => Err(ErrorCode::PackageJsonInvalidValue {
                    key: self.key.into(),
                    error,
                }),
            }
        } else {
            Ok(None)
        }
    }
}

pub struct YamlLoader;
impl<T> Loader<T> for YamlLoader {
    fn load(&self, _path: &Path) -> Result<Option<T>, ErrorCode> {
        Err(ErrorCode::YamlFileUnsupported)
    }
}

pub struct JsonLoader;
impl<T: for<'de> Deserialize<'de> + 'static> Loader<T> for JsonLoader {
    fn load(&self, path: &Path) -> Result<Option<T>, ErrorCode> {
        let file = File::open(&path).unwrap();
        let reader = BufReader::new(file);
        let config = serde_json::from_reader(reader)?;
        Ok(Some(config))
    }
}

pub struct JsLoader;
impl<T: for<'de> Deserialize<'de> + 'static> Loader<T> for JsLoader {
    fn load(&self, path: &Path) -> Result<Option<T>, ErrorCode> {
        let output = Command::new("node")
            .arg("-e")
            .arg(r#"process.stdout.write(JSON.stringify(require(process.argv[1])))"#)
            .arg(&path)
            .output()
            .expect("failed to execute process. Make sure you have Node installed.");

        if output.status.success() {
            let value = serde_json::from_slice::<T>(&output.stdout);
            Ok(Some(value.unwrap()))
        } else {
            Err(ErrorCode::NodeExecuteError { output })
        }
    }
}
<|endoftext|>


<commit_before>//! Just a dumping ground for cli stuff

use multirust::{Cfg, Result, Notification, Toolchain, Error, UpdateStatus};
use multirust_utils::{self, utils};
use multirust_utils::notify::NotificationLevel;
use self_update;
use std::ffi::OsStr;
use std::io::{Write, Read, BufRead};
use std::process::{self, Command};
use std::{cmp, iter};
use std::str::FromStr;
use std;
use term2;

pub fn confirm(question: &str, default: bool) -> Result<bool> {
    print!("{} ", question);
    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    let r = match &*input {
        "y" | "Y" => true,
        "n" | "N" => false,
        "" => default,
        _ => false,
    };

    println!("");

    Ok(r)
}

pub fn read_line() -> Result<String> {
    let stdin = std::io::stdin();
    let stdin = stdin.lock();
    let mut lines = stdin.lines();
    lines.next().and_then(|l| l.ok()).ok_or(Error::ReadStdin)
}

pub fn set_globals(verbose: bool) -> Result<Cfg> {
    use download_tracker::DownloadTracker;
    use std::cell::RefCell;

    let download_tracker = RefCell::new(DownloadTracker::new());

    Cfg::from_env(shared_ntfy!(move |n: Notification| {
        if download_tracker.borrow_mut().handle_notification(&n) {
            return;
        }

        match n.level() {
            NotificationLevel::Verbose => {
                if verbose {
                    verbose!("{}", n);
                }
            }
            NotificationLevel::Info => {
                info!("{}", n);
            }
            NotificationLevel::Warn => {
                warn!("{}", n);
            }
            NotificationLevel::Error => {
                err!("{}", n);
            }
        }
    }))

}

pub fn run_inner<S: AsRef<OsStr>>(mut command: Command,
                                  args: &[S]) -> Result<()> {
    command.args(&args[1..]);
    // FIXME rust-lang/rust#32254. It's not clear to me
    // when and why this is needed.
    command.stdin(process::Stdio::inherit());

    let status = command.status();

    match status {
        Ok(status) => {
            // Ensure correct exit code is returned
            let code = status.code().unwrap_or(1);
            process::exit(code);
        }
        Err(e) => {
            Err(multirust_utils::Error::RunningCommand {
                name: args[0].as_ref().to_owned(),
                error: multirust_utils::raw::CommandError::Io(e),
            }.into())
        }
    }
}

pub fn show_channel_update(cfg: &Cfg, name: &str,
                           updated: Result<UpdateStatus>) -> Result<()> {
    show_channel_updates(cfg, vec![(name.to_string(), updated)])
}

fn show_channel_updates(cfg: &Cfg, toolchains: Vec<(String, Result<UpdateStatus>)>) -> Result<()> {
    let data = toolchains.into_iter().map(|(name, result)| {
        let ref toolchain = cfg.get_toolchain(&name, false).expect("");
        let version = rustc_version(toolchain);

        let banner;
        let color;
        match result {
            Ok(UpdateStatus::Installed) => {
                banner = "installed";
                color = Some(term2::color::BRIGHT_GREEN);
            }
            Ok(UpdateStatus::Updated) => {
                banner = "updated";
                color = Some(term2::color::BRIGHT_GREEN);
            }
            Ok(UpdateStatus::Unchanged) => {
                banner = "unchanged";
                color = None;
            }
            Err(_) => {
                banner = "update failed";
                color = Some(term2::color::BRIGHT_RED);
            }
        }

        let width = name.len() + 1 + banner.len();

        (name, banner, width, color, version)
    });

    let mut t = term2::stdout();

    let data: Vec<_> = data.collect();
    let max_width = data.iter().fold(0, |a, &(_, _, width, _, _)| cmp::max(a, width));

    for (name, banner, width, color, version) in data {
        let padding = max_width - width;
        let padding: String = iter::repeat(' ').take(padding).collect();
        let _ = write!(t, "  {}", padding);
        let _ = t.attr(term2::Attr::Bold);
        if let Some(color) = color {
            let _ = t.fg(color);
        }
        let _ = write!(t, "{} ", name);
        let _ = write!(t, "{}", banner);
        let _ = t.reset();
        let _ = writeln!(t, " - {}", version);
    }
    let _ = writeln!(t, "");

    Ok(())
}

pub fn update_all_channels(cfg: &Cfg, self_update: bool) -> Result<()> {

    let toolchains = try!(cfg.update_all_channels());

    if toolchains.is_empty() {
        info!("no updatable toolchains installed");
    }

    let setup_path = if self_update {
        try!(self_update::prepare_update())
    } else {
        None
    };

    if !toolchains.is_empty() {
        println!("");

        try!(show_channel_updates(cfg, toolchains));
    }

    if let Some(ref setup_path) = setup_path {
        try!(self_update::run_update(setup_path));

        unreachable!(); // update exits on success
    }

    Ok(())
}

fn rustc_version(toolchain: &Toolchain) -> String {
    if toolchain.exists() {
        let rustc_path = toolchain.binary_file("rustc");
        if utils::is_file(&rustc_path) {
            let mut cmd = Command::new(&rustc_path);
            cmd.arg("--version");
            toolchain.set_ldpath(&mut cmd);

            let out= cmd.output().ok();
            let out = out.into_iter().filter(|o| o.status.success()).next();
            let stdout = out.and_then(|o| String::from_utf8(o.stdout).ok());
            let line1 = stdout.and_then(|o| o.lines().next().map(|l| l.to_owned()));

            if let Some(line1) = line1 {
                line1.to_owned()
            } else {
                String::from("(error reading rustc version)")
            }
        } else {
            String::from("(rustc does not exist)")
        }
    } else {
        String::from("(toolchain not installed)")
    }
}

pub fn show_tool_versions(toolchain: &Toolchain) -> Result<()> {
    if toolchain.exists() {
        let rustc_path = toolchain.binary_file("rustc");
        let cargo_path = toolchain.binary_file("cargo");

        if utils::is_file(&rustc_path) {
            let mut cmd = Command::new(&rustc_path);
            cmd.arg("--version");
            toolchain.set_ldpath(&mut cmd);

            if utils::cmd_status("rustc", &mut cmd).is_err() {
                println!("(failed to run rustc)");
            }
        } else {
            println!("(no rustc command in toolchain?)");
        }
        if utils::is_file(&cargo_path) {
            let mut cmd = Command::new(&cargo_path);
            cmd.arg("--version");
            // cargo invokes rustc during --version, this
            // makes sure it can find it since it may not
            // be on the `PATH` and multirust does not
            // manipulate `PATH`.
            cmd.env("RUSTC", rustc_path);
            toolchain.set_ldpath(&mut cmd);

            if utils::cmd_status("cargo", &mut cmd).is_err() {
                println!("(failed to run cargo)");
            }
        } else {
            println!("(no cargo command in toolchain?)");
        }
    } else {
        println!("(toolchain not installed)");
    }
    Ok(())
}

pub fn list_targets(toolchain: &Toolchain) -> Result<()> {
    for component in try!(toolchain.list_components()) {
        if component.component.pkg == "rust-std" {
            if component.required {
                println!("{} (default)", component.component.target);
            } else if component.installed {
                println!("{} (installed)", component.component.target);
            } else {
                println!("{}", component.component.target);
            }
        }
    }

    Ok(())
}

pub fn list_toolchains(cfg: &Cfg) -> Result<()> {
    let mut toolchains = try!(cfg.list_toolchains());

    toolchains.sort();

    if toolchains.is_empty() {
        println!("no installed toolchains");
    } else {
        for toolchain in toolchains {
            println!("{}", &toolchain);
        }
    }
    Ok(())
}

pub fn list_overrides(cfg: &Cfg) -> Result<()> {
    let mut overrides = try!(cfg.override_db.list());

    overrides.sort();

    if overrides.is_empty() {
        println!("no overrides");
    } else {
        for o in overrides {
            split_override::<String>(&o, ';').map(|li|
                println!("{:<40}\t{:<20}",
                         utils::format_path_for_display(&li.0),
                         li.1)
            );
        }
    }
    Ok(())
}

pub fn version() -> &'static str {
    option_env!("CARGO_PKG_VERSION").unwrap_or("unknown")
}

fn split_override<T: FromStr>(s: &str, separator: char) -> Option<(T, T)> {
    s.find(separator).and_then(|index| {
        match (T::from_str(&s[..index]), T::from_str(&s[index + 1..])) {
            (Ok(l), Ok(r)) => Some((l, r)),
            _ => None
        }
    })
}
<commit_msg>'rustup toolchain list' now denotes default toolchain<commit_after>//! Just a dumping ground for cli stuff

use multirust::{Cfg, Result, Notification, Toolchain, Error, UpdateStatus};
use multirust_utils::{self, utils};
use multirust_utils::notify::NotificationLevel;
use self_update;
use std::ffi::OsStr;
use std::io::{Write, Read, BufRead};
use std::process::{self, Command};
use std::{cmp, iter};
use std::str::FromStr;
use std;
use term2;

pub fn confirm(question: &str, default: bool) -> Result<bool> {
    print!("{} ", question);
    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    let r = match &*input {
        "y" | "Y" => true,
        "n" | "N" => false,
        "" => default,
        _ => false,
    };

    println!("");

    Ok(r)
}

pub fn read_line() -> Result<String> {
    let stdin = std::io::stdin();
    let stdin = stdin.lock();
    let mut lines = stdin.lines();
    lines.next().and_then(|l| l.ok()).ok_or(Error::ReadStdin)
}

pub fn set_globals(verbose: bool) -> Result<Cfg> {
    use download_tracker::DownloadTracker;
    use std::cell::RefCell;

    let download_tracker = RefCell::new(DownloadTracker::new());

    Cfg::from_env(shared_ntfy!(move |n: Notification| {
        if download_tracker.borrow_mut().handle_notification(&n) {
            return;
        }

        match n.level() {
            NotificationLevel::Verbose => {
                if verbose {
                    verbose!("{}", n);
                }
            }
            NotificationLevel::Info => {
                info!("{}", n);
            }
            NotificationLevel::Warn => {
                warn!("{}", n);
            }
            NotificationLevel::Error => {
                err!("{}", n);
            }
        }
    }))

}

pub fn run_inner<S: AsRef<OsStr>>(mut command: Command,
                                  args: &[S]) -> Result<()> {
    command.args(&args[1..]);
    // FIXME rust-lang/rust#32254. It's not clear to me
    // when and why this is needed.
    command.stdin(process::Stdio::inherit());

    let status = command.status();

    match status {
        Ok(status) => {
            // Ensure correct exit code is returned
            let code = status.code().unwrap_or(1);
            process::exit(code);
        }
        Err(e) => {
            Err(multirust_utils::Error::RunningCommand {
                name: args[0].as_ref().to_owned(),
                error: multirust_utils::raw::CommandError::Io(e),
            }.into())
        }
    }
}

pub fn show_channel_update(cfg: &Cfg, name: &str,
                           updated: Result<UpdateStatus>) -> Result<()> {
    show_channel_updates(cfg, vec![(name.to_string(), updated)])
}

fn show_channel_updates(cfg: &Cfg, toolchains: Vec<(String, Result<UpdateStatus>)>) -> Result<()> {
    let data = toolchains.into_iter().map(|(name, result)| {
        let ref toolchain = cfg.get_toolchain(&name, false).expect("");
        let version = rustc_version(toolchain);

        let banner;
        let color;
        match result {
            Ok(UpdateStatus::Installed) => {
                banner = "installed";
                color = Some(term2::color::BRIGHT_GREEN);
            }
            Ok(UpdateStatus::Updated) => {
                banner = "updated";
                color = Some(term2::color::BRIGHT_GREEN);
            }
            Ok(UpdateStatus::Unchanged) => {
                banner = "unchanged";
                color = None;
            }
            Err(_) => {
                banner = "update failed";
                color = Some(term2::color::BRIGHT_RED);
            }
        }

        let width = name.len() + 1 + banner.len();

        (name, banner, width, color, version)
    });

    let mut t = term2::stdout();

    let data: Vec<_> = data.collect();
    let max_width = data.iter().fold(0, |a, &(_, _, width, _, _)| cmp::max(a, width));

    for (name, banner, width, color, version) in data {
        let padding = max_width - width;
        let padding: String = iter::repeat(' ').take(padding).collect();
        let _ = write!(t, "  {}", padding);
        let _ = t.attr(term2::Attr::Bold);
        if let Some(color) = color {
            let _ = t.fg(color);
        }
        let _ = write!(t, "{} ", name);
        let _ = write!(t, "{}", banner);
        let _ = t.reset();
        let _ = writeln!(t, " - {}", version);
    }
    let _ = writeln!(t, "");

    Ok(())
}

pub fn update_all_channels(cfg: &Cfg, self_update: bool) -> Result<()> {

    let toolchains = try!(cfg.update_all_channels());

    if toolchains.is_empty() {
        info!("no updatable toolchains installed");
    }

    let setup_path = if self_update {
        try!(self_update::prepare_update())
    } else {
        None
    };

    if !toolchains.is_empty() {
        println!("");

        try!(show_channel_updates(cfg, toolchains));
    }

    if let Some(ref setup_path) = setup_path {
        try!(self_update::run_update(setup_path));

        unreachable!(); // update exits on success
    }

    Ok(())
}

fn rustc_version(toolchain: &Toolchain) -> String {
    if toolchain.exists() {
        let rustc_path = toolchain.binary_file("rustc");
        if utils::is_file(&rustc_path) {
            let mut cmd = Command::new(&rustc_path);
            cmd.arg("--version");
            toolchain.set_ldpath(&mut cmd);

            let out= cmd.output().ok();
            let out = out.into_iter().filter(|o| o.status.success()).next();
            let stdout = out.and_then(|o| String::from_utf8(o.stdout).ok());
            let line1 = stdout.and_then(|o| o.lines().next().map(|l| l.to_owned()));

            if let Some(line1) = line1 {
                line1.to_owned()
            } else {
                String::from("(error reading rustc version)")
            }
        } else {
            String::from("(rustc does not exist)")
        }
    } else {
        String::from("(toolchain not installed)")
    }
}

pub fn show_tool_versions(toolchain: &Toolchain) -> Result<()> {
    if toolchain.exists() {
        let rustc_path = toolchain.binary_file("rustc");
        let cargo_path = toolchain.binary_file("cargo");

        if utils::is_file(&rustc_path) {
            let mut cmd = Command::new(&rustc_path);
            cmd.arg("--version");
            toolchain.set_ldpath(&mut cmd);

            if utils::cmd_status("rustc", &mut cmd).is_err() {
                println!("(failed to run rustc)");
            }
        } else {
            println!("(no rustc command in toolchain?)");
        }
        if utils::is_file(&cargo_path) {
            let mut cmd = Command::new(&cargo_path);
            cmd.arg("--version");
            // cargo invokes rustc during --version, this
            // makes sure it can find it since it may not
            // be on the `PATH` and multirust does not
            // manipulate `PATH`.
            cmd.env("RUSTC", rustc_path);
            toolchain.set_ldpath(&mut cmd);

            if utils::cmd_status("cargo", &mut cmd).is_err() {
                println!("(failed to run cargo)");
            }
        } else {
            println!("(no cargo command in toolchain?)");
        }
    } else {
        println!("(toolchain not installed)");
    }
    Ok(())
}

pub fn list_targets(toolchain: &Toolchain) -> Result<()> {
    for component in try!(toolchain.list_components()) {
        if component.component.pkg == "rust-std" {
            if component.required {
                println!("{} (default)", component.component.target);
            } else if component.installed {
                println!("{} (installed)", component.component.target);
            } else {
                println!("{}", component.component.target);
            }
        }
    }

    Ok(())
}

pub fn list_toolchains(cfg: &Cfg) -> Result<()> {
    let mut toolchains = try!(cfg.list_toolchains());

    toolchains.sort();

    if toolchains.is_empty() {
        println!("no installed toolchains");
    } else {
        if let Ok(Some(def_toolchain)) = cfg.find_default() {
            for toolchain in toolchains {
                let if_default = if def_toolchain.name() == &*toolchain {
                    " (default)"
                } else {
                    ""
                };
                println!("{}{}", &toolchain, if_default);
            }

        } else {
            for toolchain in toolchains {
                println!("{}", &toolchain);
            }
        }
    }
    Ok(())
}

pub fn list_overrides(cfg: &Cfg) -> Result<()> {
    let mut overrides = try!(cfg.override_db.list());

    overrides.sort();

    if overrides.is_empty() {
        println!("no overrides");
    } else {
        for o in overrides {
            split_override::<String>(&o, ';').map(|li|
                println!("{:<40}\t{:<20}",
                         utils::format_path_for_display(&li.0),
                         li.1)
            );
        }
    }
    Ok(())
}

pub fn version() -> &'static str {
    option_env!("CARGO_PKG_VERSION").unwrap_or("unknown")
}

fn split_override<T: FromStr>(s: &str, separator: char) -> Option<(T, T)> {
    s.find(separator).and_then(|index| {
        match (T::from_str(&s[..index]), T::from_str(&s[index + 1..])) {
            (Ok(l), Ok(r)) => Some((l, r)),
            _ => None
        }
    })
}
<|endoftext|>


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

use app_units::Au;
use core_graphics::data_provider::CGDataProvider;
use core_graphics::font::CGFont;
use core_text;
use core_text::font::CTFont;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde::de::{Error, Visitor};
use servo_atoms::Atom;
use servo_url::ServoUrl;
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::fmt;
use std::fs::File;
use std::io::{Read, Error as IoError};
use std::ops::Deref;
use std::sync::Mutex;

/// Platform specific font representation for mac.
/// The identifier is a PostScript font name. The
/// CTFont object is cached here for use by the
/// paint functions that create CGFont references.
#[derive(Deserialize, Serialize, Debug)]
pub struct FontTemplateData {
    /// The `CTFont` object, if present. This is cached here so that we don't have to keep creating
    /// `CTFont` instances over and over. It can always be recreated from the `identifier` and/or
    /// `font_data` fields.
    ///
    /// When sending a `FontTemplateData` instance across processes, this will be cleared out on
    /// the other side, because `CTFont` instances cannot be sent across processes. This is
    /// harmless, however, because it can always be recreated.
    ctfont: CachedCTFont,

    pub identifier: Atom,
    pub font_data: Option<Vec<u8>>
}

unsafe impl Send for FontTemplateData {}
unsafe impl Sync for FontTemplateData {}

impl FontTemplateData {
    pub fn new(identifier: Atom, font_data: Option<Vec<u8>>) -> Result<FontTemplateData, IoError> {
        Ok(FontTemplateData {
            ctfont: CachedCTFont(Mutex::new(HashMap::new())),
            identifier: identifier.to_owned(),
            font_data: font_data
        })
    }

    /// Retrieves the Core Text font instance, instantiating it if necessary.
    pub fn ctfont(&self, pt_size: f64) -> Option<CTFont> {
        let mut ctfonts = self.ctfont.lock().unwrap();
        let pt_size_key = Au::from_f64_px(pt_size);
        if !ctfonts.contains_key(&pt_size_key) {
            // If you pass a zero font size to one of the Core Text APIs, it'll replace it with
            // 12.0. We don't want that! (Issue #10492.)
            let clamped_pt_size = pt_size.max(0.01);
            let ctfont = match self.font_data {
                Some(ref bytes) => {
                    let fontprov = CGDataProvider::from_buffer(bytes);
                    let cgfont_result = CGFont::from_data_provider(fontprov);
                    match cgfont_result {
                        Ok(cgfont) => {
                            Some(core_text::font::new_from_CGFont(&cgfont, clamped_pt_size))
                        }
                        Err(_) => None
                    }
                }
                None => core_text::font::new_from_name(&*self.identifier, clamped_pt_size).ok(),
            };
            if let Some(ctfont) = ctfont {
                ctfonts.insert(pt_size_key, ctfont);
            }
        }
        ctfonts.get(&pt_size_key).map(|ctfont| (*ctfont).clone())
    }

    /// Returns a clone of the data in this font. This may be a hugely expensive
    /// operation (depending on the platform) which performs synchronous disk I/O
    /// and should never be done lightly.
    pub fn bytes(&self) -> Vec<u8> {
        if let Some(font_data) = self.bytes_if_in_memory() {
            return font_data;
        }

        let path = ServoUrl::parse(&*self.ctfont(0.0)
                                    .expect("No Core Text font available!")
                                    .url()
                                    .expect("No URL for Core Text font!")
                                    .get_string()
                                    .to_string()).expect("Couldn't parse Core Text font URL!")
                                                 .as_url().to_file_path()
                                                 .expect("Core Text font didn't name a path!");
        let mut bytes = Vec::new();
        File::open(path).expect("Couldn't open font file!").read_to_end(&mut bytes).unwrap();
        bytes
    }

    /// Returns a clone of the bytes in this font if they are in memory. This function never
    /// performs disk I/O.
    pub fn bytes_if_in_memory(&self) -> Option<Vec<u8>> {
        self.font_data.clone()
    }

    /// Returns the native font that underlies this font template, if applicable.
    pub fn native_font(&self) -> Option<CGFont> {
        self.ctfont(0.0).map(|ctfont| ctfont.copy_to_CGFont())
    }
}

#[derive(Debug)]
pub struct CachedCTFont(Mutex<HashMap<Au, CTFont>>);

impl Deref for CachedCTFont {
    type Target = Mutex<HashMap<Au, CTFont>>;
    fn deref(&self) -> &Mutex<HashMap<Au, CTFont>> {
        &self.0
    }
}

impl Serialize for CachedCTFont {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
        serializer.serialize_none()
    }
}

impl Deserialize for CachedCTFont {
    fn deserialize<D>(deserializer: D) -> Result<CachedCTFont, D::Error>
                      where D: Deserializer {
        struct NoneOptionVisitor;

        impl Visitor for NoneOptionVisitor {
            type Value = CachedCTFont;

            fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
                write!(fmt, "none")
            }

            #[inline]
            fn visit_none<E>(self) -> Result<CachedCTFont, E> where E: Error {
                Ok(CachedCTFont(Mutex::new(HashMap::new())))
            }
        }

        deserializer.deserialize_option(NoneOptionVisitor)
    }
}
<commit_msg>Use NativeFontHandle instead of CGFont<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use app_units::Au;
use core_graphics::data_provider::CGDataProvider;
use core_graphics::font::CGFont;
use core_text;
use core_text::font::CTFont;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde::de::{Error, Visitor};
use servo_atoms::Atom;
use servo_url::ServoUrl;
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::fmt;
use std::fs::File;
use std::io::{Read, Error as IoError};
use std::ops::Deref;
use std::sync::Mutex;
use webrender_traits::NativeFontHandle;

/// Platform specific font representation for mac.
/// The identifier is a PostScript font name. The
/// CTFont object is cached here for use by the
/// paint functions that create CGFont references.
#[derive(Deserialize, Serialize, Debug)]
pub struct FontTemplateData {
    /// The `CTFont` object, if present. This is cached here so that we don't have to keep creating
    /// `CTFont` instances over and over. It can always be recreated from the `identifier` and/or
    /// `font_data` fields.
    ///
    /// When sending a `FontTemplateData` instance across processes, this will be cleared out on
    /// the other side, because `CTFont` instances cannot be sent across processes. This is
    /// harmless, however, because it can always be recreated.
    ctfont: CachedCTFont,

    pub identifier: Atom,
    pub font_data: Option<Vec<u8>>
}

unsafe impl Send for FontTemplateData {}
unsafe impl Sync for FontTemplateData {}

impl FontTemplateData {
    pub fn new(identifier: Atom, font_data: Option<Vec<u8>>) -> Result<FontTemplateData, IoError> {
        Ok(FontTemplateData {
            ctfont: CachedCTFont(Mutex::new(HashMap::new())),
            identifier: identifier.to_owned(),
            font_data: font_data
        })
    }

    /// Retrieves the Core Text font instance, instantiating it if necessary.
    pub fn ctfont(&self, pt_size: f64) -> Option<CTFont> {
        let mut ctfonts = self.ctfont.lock().unwrap();
        let pt_size_key = Au::from_f64_px(pt_size);
        if !ctfonts.contains_key(&pt_size_key) {
            // If you pass a zero font size to one of the Core Text APIs, it'll replace it with
            // 12.0. We don't want that! (Issue #10492.)
            let clamped_pt_size = pt_size.max(0.01);
            let ctfont = match self.font_data {
                Some(ref bytes) => {
                    let fontprov = CGDataProvider::from_buffer(bytes);
                    let cgfont_result = CGFont::from_data_provider(fontprov);
                    match cgfont_result {
                        Ok(cgfont) => {
                            Some(core_text::font::new_from_CGFont(&cgfont, clamped_pt_size))
                        }
                        Err(_) => None
                    }
                }
                None => core_text::font::new_from_name(&*self.identifier, clamped_pt_size).ok(),
            };
            if let Some(ctfont) = ctfont {
                ctfonts.insert(pt_size_key, ctfont);
            }
        }
        ctfonts.get(&pt_size_key).map(|ctfont| (*ctfont).clone())
    }

    /// Returns a clone of the data in this font. This may be a hugely expensive
    /// operation (depending on the platform) which performs synchronous disk I/O
    /// and should never be done lightly.
    pub fn bytes(&self) -> Vec<u8> {
        if let Some(font_data) = self.bytes_if_in_memory() {
            return font_data;
        }

        let path = ServoUrl::parse(&*self.ctfont(0.0)
                                    .expect("No Core Text font available!")
                                    .url()
                                    .expect("No URL for Core Text font!")
                                    .get_string()
                                    .to_string()).expect("Couldn't parse Core Text font URL!")
                                                 .as_url().to_file_path()
                                                 .expect("Core Text font didn't name a path!");
        let mut bytes = Vec::new();
        File::open(path).expect("Couldn't open font file!").read_to_end(&mut bytes).unwrap();
        bytes
    }

    /// Returns a clone of the bytes in this font if they are in memory. This function never
    /// performs disk I/O.
    pub fn bytes_if_in_memory(&self) -> Option<Vec<u8>> {
        self.font_data.clone()
    }

    /// Returns the native font that underlies this font template, if applicable.
    pub fn native_font(&self) -> Option<NativeFontHandle> {
        self.ctfont(0.0).map(|ctfont| NativeFontHandle(ctfont.copy_to_CGFont()))
    }
}

#[derive(Debug)]
pub struct CachedCTFont(Mutex<HashMap<Au, CTFont>>);

impl Deref for CachedCTFont {
    type Target = Mutex<HashMap<Au, CTFont>>;
    fn deref(&self) -> &Mutex<HashMap<Au, CTFont>> {
        &self.0
    }
}

impl Serialize for CachedCTFont {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
        serializer.serialize_none()
    }
}

impl Deserialize for CachedCTFont {
    fn deserialize<D>(deserializer: D) -> Result<CachedCTFont, D::Error>
                      where D: Deserializer {
        struct NoneOptionVisitor;

        impl Visitor for NoneOptionVisitor {
            type Value = CachedCTFont;

            fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
                write!(fmt, "none")
            }

            #[inline]
            fn visit_none<E>(self) -> Result<CachedCTFont, E> where E: Error {
                Ok(CachedCTFont(Mutex::new(HashMap::new())))
            }
        }

        deserializer.deserialize_option(NoneOptionVisitor)
    }
}
<|endoftext|>


<commit_before>//! `StructureTerminal` data description.
use super::super::resources::ResourceType;
use super::super::resources::Store;
use crate::data::RoomName;

with_base_fields_and_update_struct! {
    /// A terminal structure - a structure that has a medium capacity for storing multiple resources,
    /// and can spend energy to send any resources to another room with a terminal instantly.
    // Note: there's a field "send" which seems to always be null. It will be non-existent on a
    // terminal which has never sent any resources, and then will be updated to "null" on the first send.
    #[derive(Clone, Debug, PartialEq)]
    #[serde(rename_all = "camelCase")]
    pub struct StructureTerminal {
        /// The current number of hit-points this structure has.
        #[serde(default)]
        pub hits: i32,
        /// The maximum number of hit-points this structure has.
        #[serde(default)]
        pub hits_max: i32,
        /// The user ID of the owner of this structure.
        pub user: String,
        /// Whether or not this structure is non-functional due to a degraded controller.
        #[serde(default, rename = "off")]
        pub disabled: bool,
        /// Total capacity for this structure.
        #[serde(rename = "storeCapacity")]
        pub capacity: i32,
        /// The game time at which this terminal will next be able to send minerals.
        #[serde(default)]
        pub cooldown_time: u32,
        /// Whether or not an attack on this structure will send an email to the owner automatically.
        pub notify_when_attacked: bool,
        /// The resources and amounts of each resource some game object holds.
        pub store: Store,
    }

    /// The update structure for an extension structure.
    #[derive(Clone, Debug)]
    #[serde(rename_all = "camelCase")]
    pub struct StructureTerminalUpdate {
        - hits: i32,
        - hits_max: i32,
        - user: String,
        #[serde(rename = "off")]
        - disabled: bool,
        #[serde(rename = "energyCapacity")]
        - capacity: i32,
        - cooldown_time: u32,
        - notify_when_attacked: bool,
        - store: Store,
    }
}

impl StructureTerminal {
    /// Iterates over this structure's resources.
    pub fn resources(&self) -> impl Iterator<Item = (ResourceType, i32)> + '_ {
        self.store.iter()
    }
}

#[cfg(test)]
mod test {
    use serde::Deserialize;

    use super::StructureTerminal;
    use crate::websocket::types::room::resources::ResourceType;

    #[test]
    fn parse_terminal() {
        let json = json!({
            "store": {
                "XLHO2": 0,
                "XZH2O": 0,
                "energy": 1321,
            },
            "_id": "59675fbfb554456b195342e7",
            "cooldownTime": 20236024,
            "energyCapacity": 300000,
            "hits": 3000,
            "hitsMax": 3000,
            "notifyWhenAttacked": true,
            "room": "W65N19",
            "type": "terminal",
            "user": "57874d42d0ae911e3bd15bbc",
            "x": 30,
            "y": 35
        });

        let obj = StructureTerminal::deserialize(json).unwrap();

        match obj {
            StructureTerminal {
                capacity: 300000,
                hits: 3000,
                hits_max: 3000,
                notify_when_attacked: true,
                cooldown_time: 20236024,
                disabled: false,
                x: 30,
                y: 35,
                ref user,
                ref id,
                ref store,
                ..
            } if user == "57874d42d0ae911e3bd15bbc"
                && id == "59675fbfb554456b195342e7"
                && *store == store! {Energy: 1321} =>
            {
                ()
            }

            other => panic!(
                "expected pre-set StructureTerminal to match, found {:#?}",
                other
            ),
        }

        assert_eq!(
            {
                let mut contents = obj.resources().collect::<Vec<_>>();
                contents.sort();
                contents
            },
            {
                let mut expected = vec![(ResourceType::Energy, 1321)];
                expected.sort();
                expected
            }
        );
    }

    #[test]
    fn parse_with_null_cooldown() {
        let json = json!({
            "_id": "5c78d9793b60c54624032734",
            "energy": 0,
            "energyCapacity": 300000,
            "hits": 3000,
            "hitsMax": 3000,
            "notifyWhenAttacked": true,
            "room": "E8S22",
            "type": "terminal",
            "user": "5867dc91c04c074e4f1bdd08",
            "x": 18,
            "y": 17,
        });

        let obj = StructureTerminal::deserialize(json).unwrap();

        assert_eq!(obj.cooldown_time, 0);
    }
}
<commit_msg>Fix terminal tests<commit_after>//! `StructureTerminal` data description.
use super::super::resources::ResourceType;
use super::super::resources::Store;
use crate::data::RoomName;

with_base_fields_and_update_struct! {
    /// A terminal structure - a structure that has a medium capacity for storing multiple resources,
    /// and can spend energy to send any resources to another room with a terminal instantly.
    // Note: there's a field "send" which seems to always be null. It will be non-existent on a
    // terminal which has never sent any resources, and then will be updated to "null" on the first send.
    #[derive(Clone, Debug, PartialEq)]
    #[serde(rename_all = "camelCase")]
    pub struct StructureTerminal {
        /// The current number of hit-points this structure has.
        #[serde(default)]
        pub hits: i32,
        /// The maximum number of hit-points this structure has.
        #[serde(default)]
        pub hits_max: i32,
        /// The user ID of the owner of this structure.
        pub user: String,
        /// Whether or not this structure is non-functional due to a degraded controller.
        #[serde(default, rename = "off")]
        pub disabled: bool,
        /// Total capacity for this structure.
        #[serde(rename = "storeCapacity")]
        pub capacity: i32,
        /// The game time at which this terminal will next be able to send minerals.
        #[serde(default)]
        pub cooldown_time: u32,
        /// Whether or not an attack on this structure will send an email to the owner automatically.
        pub notify_when_attacked: bool,
        /// The resources and amounts of each resource some game object holds.
        pub store: Store,
    }

    /// The update structure for an extension structure.
    #[derive(Clone, Debug)]
    #[serde(rename_all = "camelCase")]
    pub struct StructureTerminalUpdate {
        - hits: i32,
        - hits_max: i32,
        - user: String,
        #[serde(rename = "off")]
        - disabled: bool,
        #[serde(rename = "energyCapacity")]
        - capacity: i32,
        - cooldown_time: u32,
        - notify_when_attacked: bool,
        - store: Store,
    }
}

impl StructureTerminal {
    /// Iterates over this structure's resources.
    pub fn resources(&self) -> impl Iterator<Item = (ResourceType, i32)> + '_ {
        self.store.iter()
    }
}

#[cfg(test)]
mod test {
    use serde::Deserialize;

    use super::StructureTerminal;

    #[test]
    fn parse_terminal() {
        let json = json!({
            "_id": "59a5cc4f4733bb4c785ec4e7",
            "cooldownTime": 38432852,
            "hits": 3000,
            "hitsMax": 3000,
            "notifyWhenAttacked": true,
            "room": "W39N49",
            "send": null,
            "store": {
                "X": 50189,
                "XGH2O": 0,
                "energy": 25000
            },
            "storeCapacity": 300000,
            "type": "terminal",
            "user": "5788389e3fd9069e6b546e2d",
            "x": 4,
            "y": 9
        });

        let obj = StructureTerminal::deserialize(json).unwrap();

        match obj {
            StructureTerminal {
                capacity: 300000,
                hits: 3000,
                hits_max: 3000,
                notify_when_attacked: true,
                cooldown_time: 38432852,
                disabled: false,
                x: 4,
                y: 9,
                ref user,
                ref id,
                ref store,
                ..
            } if user == "5788389e3fd9069e6b546e2d"
                && id == "59a5cc4f4733bb4c785ec4e7"
                && *store == store! {Energy: 25000, Catalyst: 50189, CatalyzedGhodiumAcid: 0} =>
            {
                ()
            }

            other => panic!(
                "expected pre-set StructureTerminal to match, found {:#?}",
                other
            ),
        }
    }

    #[test]
    fn parse_with_null_cooldown() {
        // note: not actual server data, reconstructed from two instances
        //  - it's hard to find a null terminal cooldown.
        let json = json!({
            "_id": "59a5cc4f4733bb4c785ec4e7",
            "hits": 3000,
            "hitsMax": 3000,
            "notifyWhenAttacked": true,
            "room": "W39N49",
            "send": null,
            "store": {},
            "storeCapacity": 300000,
            "type": "terminal",
            "user": "5788389e3fd9069e6b546e2d",
            "x": 4,
            "y": 9
        });

        let obj = StructureTerminal::deserialize(json).unwrap();

        assert_eq!(obj.cooldown_time, 0);
    }
}
<|endoftext|>


<commit_before>use std::convert::TryInto;
use array_init::array_init;
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use uu_factor::{table::*, Factors};

fn table(c: &mut Criterion) {
    const INPUT_SIZE: usize = 128;
    assert!(
        INPUT_SIZE % CHUNK_SIZE == 0,
        "INPUT_SIZE ({}) is not divisible by CHUNK_SIZE ({})",
        INPUT_SIZE,
        CHUNK_SIZE
    );
    let inputs = {
        // Deterministic RNG; use an explicitely-named RNG to guarantee stability
        use rand::{RngCore, SeedableRng};
        use rand_chacha::ChaCha8Rng;
        const SEED: u64 = 0xdead_bebe_ea75_cafe;
        let mut rng = ChaCha8Rng::seed_from_u64(SEED);

        std::iter::repeat_with(move || array_init::<_, _, INPUT_SIZE>(|_| rng.next_u64()))
    };

    let mut group = c.benchmark_group("table");
    for a in inputs.take(10) {
        let a_str = format!("{:?}", a);
        group.bench_with_input(
            BenchmarkId::from_parameter("chunked_".to_owned() + &a_str),
            &a,
            |b, &a| {
                b.iter(|| {
                    let mut n_s = a.clone();
                    let mut f_s: [_; INPUT_SIZE] = array_init(|_| Factors::one());
                    for (n_s, f_s) in n_s.chunks_mut(CHUNK_SIZE).zip(f_s.chunks_mut(CHUNK_SIZE)) {
                        factor_chunk(n_s.try_into().unwrap(), f_s.try_into().unwrap())
                    }
                })
            },
        );
        group.bench_with_input(
            BenchmarkId::from_parameter("seq_".to_owned() + &a_str),
            &a,
            |b, &a| {
                b.iter(|| {
                    let mut n_s = a.clone();
                    let mut f_s: [_; INPUT_SIZE] = array_init(|_| Factors::one());
                    for (n, f) in n_s.iter_mut().zip(f_s.iter_mut()) {
                        factor(n, f)
                    }
                })
            },
        );
    }
    group.finish()
}

criterion_group!(benches, table);
criterion_main!(benches);
<commit_msg>factor::benches::table: Report throughput (in numbers/s)<commit_after>use array_init::array_init;
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use std::convert::TryInto;
use uu_factor::{table::*, Factors};

fn table(c: &mut Criterion) {
    const INPUT_SIZE: usize = 128;
    assert!(
        INPUT_SIZE % CHUNK_SIZE == 0,
        "INPUT_SIZE ({}) is not divisible by CHUNK_SIZE ({})",
        INPUT_SIZE,
        CHUNK_SIZE
    );
    let inputs = {
        // Deterministic RNG; use an explicitely-named RNG to guarantee stability
        use rand::{RngCore, SeedableRng};
        use rand_chacha::ChaCha8Rng;
        const SEED: u64 = 0xdead_bebe_ea75_cafe;
        let mut rng = ChaCha8Rng::seed_from_u64(SEED);

        std::iter::repeat_with(move || array_init::<_, _, INPUT_SIZE>(|_| rng.next_u64()))
    };

    let mut group = c.benchmark_group("table");
    group.throughput(Throughput::Elements(INPUT_SIZE as _));
    for a in inputs.take(10) {
        let a_str = format!("{:?}", a);
        group.bench_with_input(
            BenchmarkId::from_parameter("chunked_".to_owned() + &a_str),
            &a,
            |b, &a| {
                b.iter(|| {
                    let mut n_s = a.clone();
                    let mut f_s: [_; INPUT_SIZE] = array_init(|_| Factors::one());
                    for (n_s, f_s) in n_s.chunks_mut(CHUNK_SIZE).zip(f_s.chunks_mut(CHUNK_SIZE)) {
                        factor_chunk(n_s.try_into().unwrap(), f_s.try_into().unwrap())
                    }
                })
            },
        );
        group.bench_with_input(
            BenchmarkId::from_parameter("seq_".to_owned() + &a_str),
            &a,
            |b, &a| {
                b.iter(|| {
                    let mut n_s = a.clone();
                    let mut f_s: [_; INPUT_SIZE] = array_init(|_| Factors::one());
                    for (n, f) in n_s.iter_mut().zip(f_s.iter_mut()) {
                        factor(n, f)
                    }
                })
            },
        );
    }
    group.finish()
}

criterion_group!(benches, table);
criterion_main!(benches);
<|endoftext|>