<commit_before>// Copyright (c) 2014-2016 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::collections::VecDeque;
use std::cmp;
use std::ffi::CString;
use std::io;
use std::iter::repeat;
use std::mem;
use std::sync::Arc;

use bindings::bpf;
use packet::Packet;
use packet::ethernet::{EthernetPacket, MutableEthernetPacket};
use datalink::{EthernetDataLinkChannelIterator, DataLinkChannelType, EthernetDataLinkReceiver,
               EthernetDataLinkSender};
use datalink::DataLinkChannelType::{Layer2, Layer3};
use internal;
use util::NetworkInterface;

// NOTE buffer must be word aligned.
#[inline]
pub fn datalink_channel(network_interface: &NetworkInterface,
                        write_buffer_size: usize,
                        read_buffer_size: usize,
                        channel_type: DataLinkChannelType)
    -> io::Result<(Box<EthernetDataLinkSender>, Box<EthernetDataLinkReceiver>)> {
    #[cfg(target_os = "freebsd")]
    fn get_fd() -> libc::c_int {
        unsafe {
            libc::open(CString::new(&b"/dev/bpf"[..]).unwrap().as_ptr(),
                       libc::O_RDWR,
                       0)
        }
    }

    #[cfg(target_os = "macos")]
    fn get_fd() -> libc::c_int {
        // FIXME This is an arbitrary number of attempts
        for i in 0..1_000isize {
            let fd = unsafe {
                let file_name = format!("/dev/bpf{}", i);
                libc::open(CString::new(file_name.as_bytes()).unwrap().as_ptr(),
                           libc::O_RDWR,
                           0)
            };
            if fd != -1 {
                return fd;
            }
        }

        -1
    }

    #[cfg(target_os = "freebsd")]
    fn set_feedback(fd: libc::c_int) -> io::Result<()> {
        let one: libc::c_uint = 1;
        if unsafe { bpf::ioctl(fd, bpf::BIOCFEEDBACK, &one) } == -1 {
            let err = io::Error::last_os_error();
            unsafe {
                libc::close(fd);
            }
            return Err(err);
        }
        Ok(())
    }

    #[cfg(target_os = "macos")]
    fn set_feedback(_fd: libc::c_int) -> io::Result<()> {
        Ok(())
    }

    match channel_type {
        Layer2 => (),
        Layer3(_) => unimplemented!(),
    }

    let fd = get_fd();
    if fd == -1 {
        return Err(io::Error::last_os_error());
    }
    let mut iface: bpf::ifreq = unsafe { mem::zeroed() };
    for (i, c) in network_interface.name.bytes().enumerate() {
        iface.ifr_name[i] = c as i8;
    }

    let buflen = read_buffer_size as libc::c_uint;
    // NOTE Buffer length must be set before binding to an interface
    //      otherwise this will return Invalid Argument
    if unsafe { bpf::ioctl(fd, bpf::BIOCSBLEN, &buflen) } == -1 {
        let err = io::Error::last_os_error();
        unsafe {
            libc::close(fd);
        }
        return Err(err);
    }

    // Set the interface to use
    if unsafe { bpf::ioctl(fd, bpf::BIOCSETIF, &iface) } == -1 {
        let err = io::Error::last_os_error();
        unsafe {
            libc::close(fd);
        }
        return Err(err);
    }

    // Return from read as soon as packets are available - don't wait to fill the
    // buffer
    let one: libc::c_uint = 1;
    if unsafe { bpf::ioctl(fd, bpf::BIOCIMMEDIATE, &one) } == -1 {
        let err = io::Error::last_os_error();
        unsafe {
            libc::close(fd);
        }
        return Err(err);
    }

    let mut header_size = 0;

    // Get the device type
    let mut dlt: libc::c_uint = 0;
    if unsafe { bpf::ioctl(fd, bpf::BIOCGDLT, &mut dlt) } == -1 {
        let err = io::Error::last_os_error();
        unsafe {
            libc::close(fd);
        }
        return Err(err);
    }

    // The loopback device does weird things
    // FIXME This should really just be another L2 packet header type
    if dlt == bpf::DLT_NULL {
        header_size = 4;

        // Allow packets to be read back after they are written
        if let Err(e) = set_feedback(fd) {
            return Err(e);
        }

    } else {
        // Don't fill in source MAC
        if unsafe { bpf::ioctl(fd, bpf::BIOCSHDRCMPLT, &one) } == -1 {
            let err = io::Error::last_os_error();
            unsafe {
                libc::close(fd);
            }
            return Err(err);
        }
    }

    let fd = Arc::new(internal::FileDesc { fd: fd });
    let sender = Box::new(DataLinkSenderImpl {
        fd: fd.clone(),
        write_buffer: repeat(0u8).take(write_buffer_size).collect(),
        header_size: header_size,
    });
    let receiver = Box::new(DataLinkReceiverImpl {
        fd: fd,
        read_buffer: repeat(0u8).take(read_buffer_size).collect(),
        header_size: header_size,
    });

    Ok((sender, receiver))
}

pub struct DataLinkSenderImpl {
    fd: Arc<internal::FileDesc>,
    write_buffer: Vec<u8>,
    header_size: usize,
}

impl EthernetDataLinkSender for DataLinkSenderImpl {
    #[inline]
    fn build_and_send(&mut self,
                      num_packets: usize,
                      packet_size: usize,
                      func: &mut FnMut(MutableEthernetPacket))
        -> Option<io::Result<()>> {
        let len = num_packets * (packet_size + self.header_size);
        if len >= self.write_buffer.len() {
            None
        } else {
            let min = cmp::min(self.write_buffer.len(), len);
            for chunk in self.write_buffer[..min].chunks_mut(packet_size + self.header_size) {
                // If we're sending on the loopback device, the first 4 bytes must be set to
                // AF_INET
                if self.header_size == 4 {
                    unsafe {
                        *(chunk.as_mut_ptr() as *mut u32) = libc::AF_INET as u32;
                    }
                }
                {
                    let eh = MutableEthernetPacket::new(&mut chunk[self.header_size..]).unwrap();
                    func(eh);
                }
                match unsafe {
                    libc::write(self.fd.fd,
                                chunk.as_ptr() as *const libc::c_void,
                                chunk.len() as libc::size_t)
                } {
                    len if len == -1 => return Some(Err(io::Error::last_os_error())),
                    _ => (),
                }
            }
            Some(Ok(()))
        }
    }

    #[inline]
    fn send_to(&mut self,
               packet: &EthernetPacket,
               _dst: Option<NetworkInterface>)
        -> Option<io::Result<()>> {
        match unsafe {
            libc::write(self.fd.fd,
                        packet.packet().as_ptr() as *const libc::c_void,
                        packet.packet().len() as libc::size_t)
        } {
            len if len == -1 => Some(Err(io::Error::last_os_error())),
            _ => Some(Ok(())),
        }
    }
}

pub struct DataLinkReceiverImpl {
    fd: Arc<internal::FileDesc>,
    read_buffer: Vec<u8>,
    header_size: usize,
}

impl EthernetDataLinkReceiver for DataLinkReceiverImpl {
    fn iter<'a>(&'a mut self) -> Box<EthernetDataLinkChannelIterator + 'a> {
        let buflen = self.read_buffer.len();
        Box::new(DataLinkChannelIteratorImpl {
            pc: self,
            // Enough room for minimally sized packets without reallocating
            packets: VecDeque::with_capacity(buflen / 64),
        })
    }
}

pub struct DataLinkChannelIteratorImpl<'a> {
    pc: &'a mut DataLinkReceiverImpl,
    packets: VecDeque<(usize, usize)>,
}

impl<'a> EthernetDataLinkChannelIterator<'a> for DataLinkChannelIteratorImpl<'a> {
    fn next(&mut self) -> io::Result<EthernetPacket> {
        if self.packets.is_empty() {
            let buflen = match unsafe {
                libc::read(self.pc.fd.fd,
                           self.pc.read_buffer.as_ptr() as *mut libc::c_void,
                           self.pc.read_buffer.len() as libc::size_t)
            } {
                len if len > 0 => len,
                _ => return Err(io::Error::last_os_error()),
            };
            let mut ptr = self.pc.read_buffer.as_mut_ptr();
            let end = unsafe { self.pc.read_buffer.as_ptr().offset(buflen as isize) };
            while (ptr as *const u8) < end {
                unsafe {
                    let packet: *const bpf::bpf_hdr = mem::transmute(ptr);
                    let start = ptr as isize + (*packet).bh_hdrlen as isize -
                                self.pc.read_buffer.as_ptr() as isize;
                    self.packets.push_back((start as usize + self.pc.header_size,
                                            (*packet).bh_caplen as usize - self.pc.header_size));
                    let offset = (*packet).bh_hdrlen as isize + (*packet).bh_caplen as isize;
                    ptr = ptr.offset(bpf::BPF_WORDALIGN(offset));
                }
            }
        }
        let (start, len) = self.packets.pop_front().unwrap();
        Ok(EthernetPacket::new(&self.pc.read_buffer[start..start + len]).unwrap())
    }
}
<commit_msg>Auto merge of #171 - faern:bpf_loopback_fix, r=mrmonday<commit_after>// Copyright (c) 2014-2016 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::collections::VecDeque;
use std::ffi::CString;
use std::io;
use std::iter::repeat;
use std::mem;
use std::sync::Arc;

use bindings::bpf;
use packet::Packet;
use packet::ethernet::{EthernetPacket, MutableEthernetPacket};
use datalink::{EthernetDataLinkChannelIterator, DataLinkChannelType, EthernetDataLinkReceiver,
               EthernetDataLinkSender};
use datalink::DataLinkChannelType::{Layer2, Layer3};
use internal;
use util::NetworkInterface;

// NOTE buffer must be word aligned.
#[inline]
pub fn datalink_channel(network_interface: &NetworkInterface,
                        write_buffer_size: usize,
                        read_buffer_size: usize,
                        channel_type: DataLinkChannelType)
    -> io::Result<(Box<EthernetDataLinkSender>, Box<EthernetDataLinkReceiver>)> {
    #[cfg(target_os = "freebsd")]
    fn get_fd() -> libc::c_int {
        unsafe {
            libc::open(CString::new(&b"/dev/bpf"[..]).unwrap().as_ptr(),
                       libc::O_RDWR,
                       0)
        }
    }

    #[cfg(target_os = "macos")]
    fn get_fd() -> libc::c_int {
        // FIXME This is an arbitrary number of attempts
        for i in 0..1_000isize {
            let fd = unsafe {
                let file_name = format!("/dev/bpf{}", i);
                libc::open(CString::new(file_name.as_bytes()).unwrap().as_ptr(),
                           libc::O_RDWR,
                           0)
            };
            if fd != -1 {
                return fd;
            }
        }

        -1
    }

    #[cfg(target_os = "freebsd")]
    fn set_feedback(fd: libc::c_int) -> io::Result<()> {
        let one: libc::c_uint = 1;
        if unsafe { bpf::ioctl(fd, bpf::BIOCFEEDBACK, &one) } == -1 {
            let err = io::Error::last_os_error();
            unsafe {
                libc::close(fd);
            }
            return Err(err);
        }
        Ok(())
    }

    #[cfg(target_os = "macos")]
    fn set_feedback(_fd: libc::c_int) -> io::Result<()> {
        Ok(())
    }

    match channel_type {
        Layer2 => (),
        Layer3(_) => unimplemented!(),
    }

    let fd = get_fd();
    if fd == -1 {
        return Err(io::Error::last_os_error());
    }
    let mut iface: bpf::ifreq = unsafe { mem::zeroed() };
    for (i, c) in network_interface.name.bytes().enumerate() {
        iface.ifr_name[i] = c as i8;
    }

    let buflen = read_buffer_size as libc::c_uint;
    // NOTE Buffer length must be set before binding to an interface
    //      otherwise this will return Invalid Argument
    if unsafe { bpf::ioctl(fd, bpf::BIOCSBLEN, &buflen) } == -1 {
        let err = io::Error::last_os_error();
        unsafe {
            libc::close(fd);
        }
        return Err(err);
    }

    // Set the interface to use
    if unsafe { bpf::ioctl(fd, bpf::BIOCSETIF, &iface) } == -1 {
        let err = io::Error::last_os_error();
        unsafe {
            libc::close(fd);
        }
        return Err(err);
    }

    // Return from read as soon as packets are available - don't wait to fill the
    // buffer
    let one: libc::c_uint = 1;
    if unsafe { bpf::ioctl(fd, bpf::BIOCIMMEDIATE, &one) } == -1 {
        let err = io::Error::last_os_error();
        unsafe {
            libc::close(fd);
        }
        return Err(err);
    }

    // Get the device type
    let mut dlt: libc::c_uint = 0;
    if unsafe { bpf::ioctl(fd, bpf::BIOCGDLT, &mut dlt) } == -1 {
        let err = io::Error::last_os_error();
        unsafe {
            libc::close(fd);
        }
        return Err(err);
    }

    let mut loopback = false;
    let mut allocated_read_buffer_size = read_buffer_size;
    // The loopback device does weird things
    // FIXME This should really just be another L2 packet header type
    if dlt == bpf::DLT_NULL {
        loopback = true;
        // So we can guaranatee that we can have a header before the packet.
        // Loopback packets arrive without the header.
        allocated_read_buffer_size += EthernetPacket::minimum_packet_size();

        // Allow packets to be read back after they are written
        if let Err(e) = set_feedback(fd) {
            return Err(e);
        }
    } else {
        // Don't fill in source MAC
        if unsafe { bpf::ioctl(fd, bpf::BIOCSHDRCMPLT, &one) } == -1 {
            let err = io::Error::last_os_error();
            unsafe {
                libc::close(fd);
            }
            return Err(err);
        }
    }

    let fd = Arc::new(internal::FileDesc { fd: fd });
    let sender = Box::new(DataLinkSenderImpl {
        fd: fd.clone(),
        write_buffer: repeat(0u8).take(write_buffer_size).collect(),
        loopback: loopback,
    });
    let receiver = Box::new(DataLinkReceiverImpl {
        fd: fd,
        read_buffer: repeat(0u8).take(allocated_read_buffer_size).collect(),
        loopback: loopback,
    });

    Ok((sender, receiver))
}

pub struct DataLinkSenderImpl {
    fd: Arc<internal::FileDesc>,
    write_buffer: Vec<u8>,
    loopback: bool,
}

impl EthernetDataLinkSender for DataLinkSenderImpl {
    #[inline]
    fn build_and_send(&mut self,
                      num_packets: usize,
                      packet_size: usize,
                      func: &mut FnMut(MutableEthernetPacket))
                      -> Option<io::Result<()>> {
        let len = num_packets * packet_size;
        if len >= self.write_buffer.len() {
            None
        } else {
            // If we're sending on the loopback device, discard the ethernet header.
            // The OS will prepend the packet with 4 bytes set to AF_INET.
            let offset = if self.loopback {
                MutableEthernetPacket::minimum_packet_size()
            } else {
                0
            };
            for chunk in self.write_buffer[..len].chunks_mut(packet_size) {
                {
                    let eh = MutableEthernetPacket::new(chunk).unwrap();
                    func(eh);
                }
                match unsafe {
                    libc::write(self.fd.fd,
                                chunk.as_ptr().offset(offset as isize) as *const libc::c_void,
                                (chunk.len() - offset) as libc::size_t)
                } {
                    len if len == -1 => return Some(Err(io::Error::last_os_error())),
                    _ => (),
                }
            }
            Some(Ok(()))
        }
    }

    #[inline]
    fn send_to(&mut self,
               packet: &EthernetPacket,
               _dst: Option<NetworkInterface>)
               -> Option<io::Result<()>> {
        // If we're sending on the loopback device, discard the ethernet header.
        // The OS will prepend the packet with 4 bytes set to AF_INET.
        let offset = if self.loopback {
            MutableEthernetPacket::minimum_packet_size()
        } else {
            0
        };
        match unsafe {
            libc::write(self.fd.fd,
                        packet.packet().as_ptr().offset(offset as isize) as *const libc::c_void,
                        (packet.packet().len() - offset) as libc::size_t)
        } {
            len if len == -1 => Some(Err(io::Error::last_os_error())),
            _ => Some(Ok(())),
        }
    }
}

pub struct DataLinkReceiverImpl {
    fd: Arc<internal::FileDesc>,
    read_buffer: Vec<u8>,
    loopback: bool,
}

impl EthernetDataLinkReceiver for DataLinkReceiverImpl {
    fn iter<'a>(&'a mut self) -> Box<EthernetDataLinkChannelIterator + 'a> {
        let buflen = self.read_buffer.len();
        Box::new(DataLinkChannelIteratorImpl {
            pc: self,
            // Enough room for minimally sized packets without reallocating
            packets: VecDeque::with_capacity(buflen / 64),
        })
    }
}

pub struct DataLinkChannelIteratorImpl<'a> {
    pc: &'a mut DataLinkReceiverImpl,
    packets: VecDeque<(usize, usize)>,
}

impl<'a> EthernetDataLinkChannelIterator<'a> for DataLinkChannelIteratorImpl<'a> {
    fn next(&mut self) -> io::Result<EthernetPacket> {
        // Loopback packets arrive with a 4 byte header instead of normal ethernet header.
        // Discard that header and replace with zeroed out ethernet header.
        let (header_size, buffer_offset) = if self.pc.loopback {
            (4, EthernetPacket::minimum_packet_size())
        } else {
            (0, 0)
        };
        if self.packets.is_empty() {
            let buffer = &mut self.pc.read_buffer[buffer_offset..];
            let buflen = match unsafe {
                libc::read(self.pc.fd.fd,
                           buffer.as_ptr() as *mut libc::c_void,
                           buffer.len() as libc::size_t)
            } {
                len if len > 0 => len,
                _ => return Err(io::Error::last_os_error()),
            };
            let mut ptr = buffer.as_mut_ptr();
            let end = unsafe { buffer.as_ptr().offset(buflen as isize) };
            while (ptr as *const u8) < end {
                unsafe {
                    let packet: *const bpf::bpf_hdr = mem::transmute(ptr);
                    let start = ptr as isize + (*packet).bh_hdrlen as isize -
                                buffer.as_ptr() as isize;
                    self.packets.push_back((start as usize + header_size,
                                            (*packet).bh_caplen as usize - header_size));
                    let offset = (*packet).bh_hdrlen as isize + (*packet).bh_caplen as isize;
                    ptr = ptr.offset(bpf::BPF_WORDALIGN(offset));
                }
            }
        }
        let (start, mut len) = self.packets.pop_front().unwrap();
        len += buffer_offset;
        // Zero out part that will become fake ethernet header if on loopback.
        for i in (&mut self.pc.read_buffer[start..start + buffer_offset]).iter_mut() {
            *i = 0;
        }
        Ok(EthernetPacket::new(&self.pc.read_buffer[start..start + len]).unwrap())
    }
}
<|endoftext|>


<commit_before>//! Using MIDI, verify that the user is able to play a given exercise correctly.  The question
//! should be enough of a description to uniquely describe what should be played.  The answer
//! should be a parseable description of what needs to be played.
//!
//! The answer should be a JSON description of what to play, of one of the following types:
//!
//! { "type": "scale", "base": "C♯", "intervals": "WWHWWWH",
//!   "hands": 1, "octaves": 2, "style": "updown" }
//!
//! This describes a scale.  The base is the first note of the scale.  Sharps and flags can either
//! be "#" and "b" or Unicode characters "♯", and "♭".  The intervals describe the intervals
//! between each note.  Valid characters are 'H' for a half step, 'W' for a whole step, 'm' for a
//! minor third, 'M' for a major third, and '4' for a fourth.  It will be checked that the
//! intervals cover a full octabe.  Hands describes how many hands should be playing the exercise,
//! and octaves are how many octaves to play.  The currently only supported style is "updown",
//! which requires the scale be played from base to base, for the given number of octaves and then
//! back down.  Scales can be played starting in any octave.
//!
//! { "type": "voicing", "chords": [
//!    { "base": "D", "notes": [ "3", "7", "9", "5" },
//!    { "base": "G", "notes": [ "7", "3", "#9", "#5" },
//!    { "base": "C", "notes": [ "3", "7", "9", "5", "11" } ] }
//!
//! This describes a voicing exercise, which is a series of chords to be played.  Each chord has a
//! base, which may or may not actually be played.  The notes in the chord are described in musical
//! notation (again with text or Unicode sharp/flat indicators).  The chord will be built using the
//! next note of the given function.  The octave will be chosen so that the lowest non-root note
//! will be between F#-F surrounding middle C.

#![deny(missing_docs)]

extern crate editdistancewf;
extern crate portmidi;
extern crate timelearn;
#[macro_use] extern crate lazy_static;
extern crate serde;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate serde_json;

use portmidi::{PortMidi, InputPort};
use serde_json::{Value};
use std::error;
use std::io::{self, Write};
use std::result;
use std::thread;
use std::time::Duration;
pub use timelearn::{Problem, Status, User};

mod note;
use note::Note;

mod scales;
use scales::{Scale, ScaleSeq};

/// Just box the errors for now.  TODO: Use a proper error type.
pub type Result<T> = result::Result<T, Box<error::Error + Send + Sync>>;

/// A learner based on playing the exercises on a MIDI device.
pub struct MidiLearn {
    input: InputPort,
}

impl MidiLearn {
    /// Construct a new MIDI learning, using the default MIDI port.  Invokes `f` with the
    /// MidiLearn.
    pub fn with_new<F, R>(f: F) -> Result<R>
        where F: FnOnce(&mut MidiLearn) -> R
    {
        let pm = PortMidi::new()?;
        let input = pm.default_input_port(4096)?;
        let mut learn = MidiLearn {
            input: input,
        };
        let result = f(&mut learn);
        Ok(result)
    }

}

impl User for MidiLearn {
    /// Practice a single exercise.  Waits for the user to play the exercise, and then returns a
    /// status indicating how well it was played.
    fn single(&mut self, word: &Problem) -> Result<Status> {
        let st1 = self.single_once(word)?;

        let mut stn = st1;
        loop {
            match stn {
                // If good, return the initial status.
                Status::Continue(4) => return Ok(st1),
                Status::Stopped => return Ok(Status::Stopped),
                _ => (),
            }
            println!("** Mistakes made, please play again **");
            stn = self.single_once(word)?;
        }
    }
}

impl MidiLearn {
    /// Ask the user once to play.
    fn single_once(&mut self, word: &Problem) -> Result<Status> {
        println!("Play: {}", word.question);

        let json: Value = serde_json::from_str(&word.answer)?;
        // println!("Json: {:?}, {:?}", json, json["typr"]);
        if is_type(&json, "scale") {
            let scale: Scale = serde_json::from_value(json)?;

            let mut seq = ScaleSeq::from_scale(&scale)?;
            // println!("scale: {:?}", seq);

            self.drain()?;
            let user = self.record_scale()?;
            // println!("Played: {:?}", user);
            if seq.adjust_octave(&user) {
                // println!("First note good: {:?}", seq);
                let diff_count = seq.differences(&user);
                println!("There are {} differences", diff_count);
                if diff_count <= 3 {
                    Ok(Status::Continue(4 - diff_count as u8))
                } else {
                    Ok(Status::Continue(1))
                }
            } else {
                println!("First note mismatch, stopping");
                Ok(Status::Stopped)
            }

        } else {
            return Err(format!("Invalid type: {:?}", json["type"].as_str()).into());
        }
    }
}

impl MidiLearn {
    /// Drain any queued midi events.
    fn drain(&mut self) -> Result<()> {
        loop {
            match self.input.read()? {
                Some(_) => (),
                None => break,
            }
        }
        Ok(())
    }

    /// Record the user playing a scale.  Consider the scale done after a small pause of no
    /// playing.
    fn record_scale(&mut self) -> Result<Vec<Vec<Note>>> {
        let mut notes: Vec<Vec<Note>> = vec![];
        let mut idle_count = 0;
        let mut last_time = 0;
        loop {
            match self.input.read()? {
                Some(ev) => {
                    // We only care about note down events here.
                    if ev.message.status & 0xf0 == 0x80 {
                        if !notes.is_empty() && ev.timestamp - last_time < 80 {
                            notes.last_mut().unwrap().push(Note(ev.message.data1));
                            // println!("chord : {:?}", notes);
                        } else {
                            // Individual note.
                            notes.push(vec![Note(ev.message.data1)]);
                            // println!("single: {:?}", notes);
                        }
                        idle_count = 0;
                        last_time = ev.timestamp;
                    }
                },
                None => {
                    idle_count += 1;
                    if notes.is_empty() {
                        idle_count = 0;
                    }
                    if idle_count >= 6 {
                        println!("Timing out");
                        break;
                    }
                    thread::sleep(Duration::from_millis(250));
                }
            }
        }

        // Sort the chords, since the incoming order could differ.
        for ch in notes.iter_mut() {
            ch.sort();
        }

        Ok(notes)
    }
}

impl Write for MidiLearn {
    fn flush(&mut self) -> io::Result<()> {
        io::stdout().flush()
    }

    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        io::stdout().write(buf)
    }
}

// Determine if the json has a the given type.
fn is_type(json: &Value, t: &str) -> bool {
    json["type"] == json!(t)
}
<commit_msg>midilearn: Use note down instead of up<commit_after>//! Using MIDI, verify that the user is able to play a given exercise correctly.  The question
//! should be enough of a description to uniquely describe what should be played.  The answer
//! should be a parseable description of what needs to be played.
//!
//! The answer should be a JSON description of what to play, of one of the following types:
//!
//! { "type": "scale", "base": "C♯", "intervals": "WWHWWWH",
//!   "hands": 1, "octaves": 2, "style": "updown" }
//!
//! This describes a scale.  The base is the first note of the scale.  Sharps and flags can either
//! be "#" and "b" or Unicode characters "♯", and "♭".  The intervals describe the intervals
//! between each note.  Valid characters are 'H' for a half step, 'W' for a whole step, 'm' for a
//! minor third, 'M' for a major third, and '4' for a fourth.  It will be checked that the
//! intervals cover a full octabe.  Hands describes how many hands should be playing the exercise,
//! and octaves are how many octaves to play.  The currently only supported style is "updown",
//! which requires the scale be played from base to base, for the given number of octaves and then
//! back down.  Scales can be played starting in any octave.
//!
//! { "type": "voicing", "chords": [
//!    { "base": "D", "notes": [ "3", "7", "9", "5" },
//!    { "base": "G", "notes": [ "7", "3", "#9", "#5" },
//!    { "base": "C", "notes": [ "3", "7", "9", "5", "11" } ] }
//!
//! This describes a voicing exercise, which is a series of chords to be played.  Each chord has a
//! base, which may or may not actually be played.  The notes in the chord are described in musical
//! notation (again with text or Unicode sharp/flat indicators).  The chord will be built using the
//! next note of the given function.  The octave will be chosen so that the lowest non-root note
//! will be between F#-F surrounding middle C.

#![deny(missing_docs)]

extern crate editdistancewf;
extern crate portmidi;
extern crate timelearn;
#[macro_use] extern crate lazy_static;
extern crate serde;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate serde_json;

use portmidi::{PortMidi, InputPort};
use serde_json::{Value};
use std::error;
use std::io::{self, Write};
use std::result;
use std::thread;
use std::time::Duration;
pub use timelearn::{Problem, Status, User};

mod note;
use note::Note;

mod scales;
use scales::{Scale, ScaleSeq};

/// Just box the errors for now.  TODO: Use a proper error type.
pub type Result<T> = result::Result<T, Box<error::Error + Send + Sync>>;

/// A learner based on playing the exercises on a MIDI device.
pub struct MidiLearn {
    input: InputPort,
}

impl MidiLearn {
    /// Construct a new MIDI learning, using the default MIDI port.  Invokes `f` with the
    /// MidiLearn.
    pub fn with_new<F, R>(f: F) -> Result<R>
        where F: FnOnce(&mut MidiLearn) -> R
    {
        let pm = PortMidi::new()?;
        let input = pm.default_input_port(4096)?;
        let mut learn = MidiLearn {
            input: input,
        };
        let result = f(&mut learn);
        Ok(result)
    }

}

impl User for MidiLearn {
    /// Practice a single exercise.  Waits for the user to play the exercise, and then returns a
    /// status indicating how well it was played.
    fn single(&mut self, word: &Problem) -> Result<Status> {
        let st1 = self.single_once(word)?;

        let mut stn = st1;
        loop {
            match stn {
                // If good, return the initial status.
                Status::Continue(4) => return Ok(st1),
                Status::Stopped => return Ok(Status::Stopped),
                _ => (),
            }
            println!("** Mistakes made, please play again **");
            stn = self.single_once(word)?;
        }
    }
}

impl MidiLearn {
    /// Ask the user once to play.
    fn single_once(&mut self, word: &Problem) -> Result<Status> {
        println!("Play: {}", word.question);

        let json: Value = serde_json::from_str(&word.answer)?;
        // println!("Json: {:?}, {:?}", json, json["typr"]);
        if is_type(&json, "scale") {
            let scale: Scale = serde_json::from_value(json)?;

            let mut seq = ScaleSeq::from_scale(&scale)?;
            // println!("scale: {:?}", seq);

            self.drain()?;
            let user = self.record_scale()?;
            // println!("Played: {:?}", user);
            if seq.adjust_octave(&user) {
                // println!("First note good: {:?}", seq);
                let diff_count = seq.differences(&user);
                println!("There are {} differences", diff_count);
                if diff_count <= 3 {
                    Ok(Status::Continue(4 - diff_count as u8))
                } else {
                    Ok(Status::Continue(1))
                }
            } else {
                println!("First note mismatch, stopping");
                Ok(Status::Stopped)
            }

        } else {
            return Err(format!("Invalid type: {:?}", json["type"].as_str()).into());
        }
    }
}

impl MidiLearn {
    /// Drain any queued midi events.
    fn drain(&mut self) -> Result<()> {
        loop {
            match self.input.read()? {
                Some(_) => (),
                None => break,
            }
        }
        Ok(())
    }

    /// Record the user playing a scale.  Consider the scale done after a small pause of no
    /// playing.
    fn record_scale(&mut self) -> Result<Vec<Vec<Note>>> {
        let mut notes: Vec<Vec<Note>> = vec![];
        let mut idle_count = 0;
        let mut last_time = 0;
        loop {
            match self.input.read()? {
                Some(ev) => {
                    // We only care about note down events here.
                    if ev.message.status & 0xf0 == 0x90 {
                        if !notes.is_empty() && ev.timestamp - last_time < 80 {
                            notes.last_mut().unwrap().push(Note(ev.message.data1));
                            // println!("chord : {:?}", notes);
                        } else {
                            // Individual note.
                            notes.push(vec![Note(ev.message.data1)]);
                            // println!("single: {:?}", notes);
                        }
                        idle_count = 0;
                        last_time = ev.timestamp;
                    }
                },
                None => {
                    idle_count += 1;
                    if notes.is_empty() {
                        idle_count = 0;
                    }
                    if idle_count >= 6 {
                        println!("Timing out");
                        break;
                    }
                    thread::sleep(Duration::from_millis(250));
                }
            }
        }

        // Sort the chords, since the incoming order could differ.
        for ch in notes.iter_mut() {
            ch.sort();
        }

        Ok(notes)
    }
}

impl Write for MidiLearn {
    fn flush(&mut self) -> io::Result<()> {
        io::stdout().flush()
    }

    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        io::stdout().write(buf)
    }
}

// Determine if the json has a the given type.
fn is_type(json: &Value, t: &str) -> bool {
    json["type"] == json!(t)
}
<|endoftext|>


<commit_before>//! User (postfix)-snippet definitions.
//!
//! Actual logic is implemented in [`crate::completions::postfix`] and [`crate::completions::snippet`] respectively.

// Feature: User Snippet Completions
//
// rust-analyzer allows the user to define custom (postfix)-snippets that may depend on items to be accessible for the current scope to be applicable.
//
// A custom snippet can be defined by adding it to the `rust-analyzer.completion.snippets` object respectively.
//
// [source,json]
// ----
// {
//   "rust-analyzer.completion.snippets": {
//     "thread spawn": {
//       "prefix": ["spawn", "tspawn"],
//       "body": [
//         "thread::spawn(move || {",
//         "\t$0",
//         ")};",
//       ],
//       "description": "Insert a thread::spawn call",
//       "requires": "std::thread",
//       "scope": "expr",
//     }
//   }
// }
// ----
//
// In the example above:
//
// * `"thread spawn"` is the name of the snippet.
//
// * `prefix` defines one or more trigger words that will trigger the snippets completion.
// Using `postfix` will instead create a postfix snippet.
//
// * `body` is one or more lines of content joined via newlines for the final output.
//
// * `description` is an optional description of the snippet, if unset the snippet name will be used.
//
// * `requires` is an optional list of item paths that have to be resolvable in the current crate where the completion is rendered.
// On failure of resolution the snippet won't be applicable, otherwise the snippet will insert an import for the items on insertion if
// the items aren't yet in scope.
//
// * `scope` is an optional filter for when the snippet should be applicable. Possible values are:
// ** for Snippet-Scopes: `expr`, `item` (default: `item`)
// ** for Postfix-Snippet-Scopes: `expr`, `type` (default: `expr`)
//
// The `body` field also has access to placeholders as visible in the example as `$0`.
// These placeholders take the form of `$number` or `${number:placeholder_text}` which can be traversed as tabstop in ascending order starting from 1,
// with `$0` being a special case that always comes last.
//
// There is also a special placeholder, `${receiver}`, which will be replaced by the receiver expression for postfix snippets, or a `$0` tabstop in case of normal snippets.
// This replacement for normal snippets allows you to reuse a snippet for both post- and prefix in a single definition.
//
// For the VSCode editor, rust-analyzer also ships with a small set of defaults which can be removed
// by overwriting the settings object mentioned above, the defaults are:
// [source,json]
// ----
// {
//     "Arc::new": {
//         "postfix": "arc",
//         "body": "Arc::new(${receiver})",
//         "requires": "std::sync::Arc",
//         "description": "Put the expression into an `Arc`",
//         "scope": "expr"
//     },
//     "Rc::new": {
//         "postfix": "rc",
//         "body": "Rc::new(${receiver})",
//         "requires": "std::rc::Rc",
//         "description": "Put the expression into an `Rc`",
//         "scope": "expr"
//     },
//     "Box::pin": {
//         "postfix": "pinbox",
//         "body": "Box::pin(${receiver})",
//         "requires": "std::boxed::Box",
//         "description": "Put the expression into a pinned `Box`",
//         "scope": "expr"
//     },
//     "Ok": {
//         "postfix": "ok",
//         "body": "Ok(${receiver})",
//         "description": "Wrap the expression in a `Result::Ok`",
//         "scope": "expr"
//     },
//     "Err": {
//         "postfix": "err",
//         "body": "Err(${receiver})",
//         "description": "Wrap the expression in a `Result::Err`",
//         "scope": "expr"
//     },
//     "Some": {
//         "postfix": "some",
//         "body": "Some(${receiver})",
//         "description": "Wrap the expression in an `Option::Some`",
//         "scope": "expr"
//     }
// }
// ----

use ide_db::imports::import_assets::LocatedImport;
use itertools::Itertools;
use syntax::{ast, AstNode, GreenNode, SyntaxNode};

use crate::context::CompletionContext;

/// A snippet scope describing where a snippet may apply to.
/// These may differ slightly in meaning depending on the snippet trigger.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum SnippetScope {
    Item,
    Expr,
    Type,
}

/// A user supplied snippet.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Snippet {
    pub postfix_triggers: Box<[Box<str>]>,
    pub prefix_triggers: Box<[Box<str>]>,
    pub scope: SnippetScope,
    pub description: Option<Box<str>>,
    snippet: String,
    // These are `ast::Path`'s but due to SyntaxNodes not being Send we store these
    // and reconstruct them on demand instead. This is cheaper than reparsing them
    // from strings
    requires: Box<[GreenNode]>,
}

impl Snippet {
    pub fn new(
        prefix_triggers: &[String],
        postfix_triggers: &[String],
        snippet: &[String],
        description: &str,
        requires: &[String],
        scope: SnippetScope,
    ) -> Option<Self> {
        if prefix_triggers.is_empty() && postfix_triggers.is_empty() {
            return None;
        }
        let (requires, snippet, description) = validate_snippet(snippet, description, requires)?;
        Some(Snippet {
            // Box::into doesn't work as that has a Copy bound 😒
            postfix_triggers: postfix_triggers.iter().map(String::as_str).map(Into::into).collect(),
            prefix_triggers: prefix_triggers.iter().map(String::as_str).map(Into::into).collect(),
            scope,
            snippet,
            description,
            requires,
        })
    }

    /// Returns [`None`] if the required items do not resolve.
    pub(crate) fn imports(&self, ctx: &CompletionContext) -> Option<Vec<LocatedImport>> {
        import_edits(ctx, &self.requires)
    }

    pub fn snippet(&self) -> String {
        self.snippet.replace("${receiver}", "$0")
    }

    pub fn postfix_snippet(&self, receiver: &str) -> String {
        self.snippet.replace("${receiver}", receiver)
    }
}

fn import_edits(ctx: &CompletionContext, requires: &[GreenNode]) -> Option<Vec<LocatedImport>> {
    let resolve = |import: &GreenNode| {
        let path = ast::Path::cast(SyntaxNode::new_root(import.clone()))?;
        let item = match ctx.scope.speculative_resolve(&path)? {
            hir::PathResolution::Def(def) => def.into(),
            _ => return None,
        };
        let path =
            ctx.module.find_use_path_prefixed(ctx.db, item, ctx.config.insert_use.prefix_kind)?;
        Some((path.len() > 1).then(|| LocatedImport::new(path.clone(), item, item, None)))
    };
    let mut res = Vec::with_capacity(requires.len());
    for import in requires {
        match resolve(import) {
            Some(first) => res.extend(first),
            None => return None,
        }
    }
    Some(res)
}

fn validate_snippet(
    snippet: &[String],
    description: &str,
    requires: &[String],
) -> Option<(Box<[GreenNode]>, String, Option<Box<str>>)> {
    let mut imports = Vec::with_capacity(requires.len());
    for path in requires.iter() {
        let use_path = ast::SourceFile::parse(&format!("use {};", path))
            .syntax_node()
            .descendants()
            .find_map(ast::Path::cast)?;
        if use_path.syntax().text() != path.as_str() {
            return None;
        }
        let green = use_path.syntax().green().into_owned();
        imports.push(green);
    }
    let snippet = snippet.iter().join("\n");
    let description = (!description.is_empty())
        .then(|| description.split_once('\n').map_or(description, |(it, _)| it))
        .map(ToOwned::to_owned)
        .map(Into::into);
    Some((imports.into_boxed_slice(), snippet, description))
}
<commit_msg>Fix obsolete `completion.snippets` config<commit_after>//! User (postfix)-snippet definitions.
//!
//! Actual logic is implemented in [`crate::completions::postfix`] and [`crate::completions::snippet`] respectively.

// Feature: User Snippet Completions
//
// rust-analyzer allows the user to define custom (postfix)-snippets that may depend on items to be accessible for the current scope to be applicable.
//
// A custom snippet can be defined by adding it to the `rust-analyzer.completion.snippets.custom` object respectively.
//
// [source,json]
// ----
// {
//   "rust-analyzer.completion.snippets.custom": {
//     "thread spawn": {
//       "prefix": ["spawn", "tspawn"],
//       "body": [
//         "thread::spawn(move || {",
//         "\t$0",
//         ")};",
//       ],
//       "description": "Insert a thread::spawn call",
//       "requires": "std::thread",
//       "scope": "expr",
//     }
//   }
// }
// ----
//
// In the example above:
//
// * `"thread spawn"` is the name of the snippet.
//
// * `prefix` defines one or more trigger words that will trigger the snippets completion.
// Using `postfix` will instead create a postfix snippet.
//
// * `body` is one or more lines of content joined via newlines for the final output.
//
// * `description` is an optional description of the snippet, if unset the snippet name will be used.
//
// * `requires` is an optional list of item paths that have to be resolvable in the current crate where the completion is rendered.
// On failure of resolution the snippet won't be applicable, otherwise the snippet will insert an import for the items on insertion if
// the items aren't yet in scope.
//
// * `scope` is an optional filter for when the snippet should be applicable. Possible values are:
// ** for Snippet-Scopes: `expr`, `item` (default: `item`)
// ** for Postfix-Snippet-Scopes: `expr`, `type` (default: `expr`)
//
// The `body` field also has access to placeholders as visible in the example as `$0`.
// These placeholders take the form of `$number` or `${number:placeholder_text}` which can be traversed as tabstop in ascending order starting from 1,
// with `$0` being a special case that always comes last.
//
// There is also a special placeholder, `${receiver}`, which will be replaced by the receiver expression for postfix snippets, or a `$0` tabstop in case of normal snippets.
// This replacement for normal snippets allows you to reuse a snippet for both post- and prefix in a single definition.
//
// For the VSCode editor, rust-analyzer also ships with a small set of defaults which can be removed
// by overwriting the settings object mentioned above, the defaults are:
// [source,json]
// ----
// {
//     "Arc::new": {
//         "postfix": "arc",
//         "body": "Arc::new(${receiver})",
//         "requires": "std::sync::Arc",
//         "description": "Put the expression into an `Arc`",
//         "scope": "expr"
//     },
//     "Rc::new": {
//         "postfix": "rc",
//         "body": "Rc::new(${receiver})",
//         "requires": "std::rc::Rc",
//         "description": "Put the expression into an `Rc`",
//         "scope": "expr"
//     },
//     "Box::pin": {
//         "postfix": "pinbox",
//         "body": "Box::pin(${receiver})",
//         "requires": "std::boxed::Box",
//         "description": "Put the expression into a pinned `Box`",
//         "scope": "expr"
//     },
//     "Ok": {
//         "postfix": "ok",
//         "body": "Ok(${receiver})",
//         "description": "Wrap the expression in a `Result::Ok`",
//         "scope": "expr"
//     },
//     "Err": {
//         "postfix": "err",
//         "body": "Err(${receiver})",
//         "description": "Wrap the expression in a `Result::Err`",
//         "scope": "expr"
//     },
//     "Some": {
//         "postfix": "some",
//         "body": "Some(${receiver})",
//         "description": "Wrap the expression in an `Option::Some`",
//         "scope": "expr"
//     }
// }
// ----

use ide_db::imports::import_assets::LocatedImport;
use itertools::Itertools;
use syntax::{ast, AstNode, GreenNode, SyntaxNode};

use crate::context::CompletionContext;

/// A snippet scope describing where a snippet may apply to.
/// These may differ slightly in meaning depending on the snippet trigger.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum SnippetScope {
    Item,
    Expr,
    Type,
}

/// A user supplied snippet.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Snippet {
    pub postfix_triggers: Box<[Box<str>]>,
    pub prefix_triggers: Box<[Box<str>]>,
    pub scope: SnippetScope,
    pub description: Option<Box<str>>,
    snippet: String,
    // These are `ast::Path`'s but due to SyntaxNodes not being Send we store these
    // and reconstruct them on demand instead. This is cheaper than reparsing them
    // from strings
    requires: Box<[GreenNode]>,
}

impl Snippet {
    pub fn new(
        prefix_triggers: &[String],
        postfix_triggers: &[String],
        snippet: &[String],
        description: &str,
        requires: &[String],
        scope: SnippetScope,
    ) -> Option<Self> {
        if prefix_triggers.is_empty() && postfix_triggers.is_empty() {
            return None;
        }
        let (requires, snippet, description) = validate_snippet(snippet, description, requires)?;
        Some(Snippet {
            // Box::into doesn't work as that has a Copy bound 😒
            postfix_triggers: postfix_triggers.iter().map(String::as_str).map(Into::into).collect(),
            prefix_triggers: prefix_triggers.iter().map(String::as_str).map(Into::into).collect(),
            scope,
            snippet,
            description,
            requires,
        })
    }

    /// Returns [`None`] if the required items do not resolve.
    pub(crate) fn imports(&self, ctx: &CompletionContext) -> Option<Vec<LocatedImport>> {
        import_edits(ctx, &self.requires)
    }

    pub fn snippet(&self) -> String {
        self.snippet.replace("${receiver}", "$0")
    }

    pub fn postfix_snippet(&self, receiver: &str) -> String {
        self.snippet.replace("${receiver}", receiver)
    }
}

fn import_edits(ctx: &CompletionContext, requires: &[GreenNode]) -> Option<Vec<LocatedImport>> {
    let resolve = |import: &GreenNode| {
        let path = ast::Path::cast(SyntaxNode::new_root(import.clone()))?;
        let item = match ctx.scope.speculative_resolve(&path)? {
            hir::PathResolution::Def(def) => def.into(),
            _ => return None,
        };
        let path =
            ctx.module.find_use_path_prefixed(ctx.db, item, ctx.config.insert_use.prefix_kind)?;
        Some((path.len() > 1).then(|| LocatedImport::new(path.clone(), item, item, None)))
    };
    let mut res = Vec::with_capacity(requires.len());
    for import in requires {
        match resolve(import) {
            Some(first) => res.extend(first),
            None => return None,
        }
    }
    Some(res)
}

fn validate_snippet(
    snippet: &[String],
    description: &str,
    requires: &[String],
) -> Option<(Box<[GreenNode]>, String, Option<Box<str>>)> {
    let mut imports = Vec::with_capacity(requires.len());
    for path in requires.iter() {
        let use_path = ast::SourceFile::parse(&format!("use {};", path))
            .syntax_node()
            .descendants()
            .find_map(ast::Path::cast)?;
        if use_path.syntax().text() != path.as_str() {
            return None;
        }
        let green = use_path.syntax().green().into_owned();
        imports.push(green);
    }
    let snippet = snippet.iter().join("\n");
    let description = (!description.is_empty())
        .then(|| description.split_once('\n').map_or(description, |(it, _)| it))
        .map(ToOwned::to_owned)
        .map(Into::into);
    Some((imports.into_boxed_slice(), snippet, description))
}
<|endoftext|>


<commit_before>//! Data structure for a small block of terrain.

use cgmath::{Point3, Vector3, Aabb3};

use entity::EntityId;
use serialize::{Flatten, MemStream, EOF};

// TODO: Move the server-only parts to the server, like BLOCK_WIDTH and sample_info.

/// lg(WIDTH)
pub const LG_WIDTH: i16 = 3;
/// The width of a block of terrain.
pub const WIDTH: i32 = 1 << LG_WIDTH;

/// lg(EDGE_SAMPLES)
pub const LG_EDGE_SAMPLES: [u16; 4] = [5, 2, 1, 0];
/// The number of voxels along an axis within a block, indexed by LOD.
pub const EDGE_SAMPLES: [u16; 4] = [
  1 << LG_EDGE_SAMPLES[0],
  1 << LG_EDGE_SAMPLES[1],
  1 << LG_EDGE_SAMPLES[2],
  1 << LG_EDGE_SAMPLES[3],
];

/// The width of a voxel within a block, indexed by LOD.
pub const LG_SAMPLE_SIZE: [i16; 4] = [
  LG_WIDTH - LG_EDGE_SAMPLES[0] as i16,
  LG_WIDTH - LG_EDGE_SAMPLES[1] as i16,
  LG_WIDTH - LG_EDGE_SAMPLES[2] as i16,
  LG_WIDTH - LG_EDGE_SAMPLES[3] as i16,
];

#[derive(Debug, Copy, Clone)]
/// [T; 3], but serializable.
pub struct Triangle<T> {
  #[allow(missing_docs)]
  pub v1: T,
  #[allow(missing_docs)]
  pub v2: T,
  #[allow(missing_docs)]
  pub v3: T,
}

/// Construct a triangle.
pub fn tri<T>(v1: T, v2: T, v3: T) -> Triangle<T> {
  Triangle {
    v1: v1,
    v2: v2,
    v3: v3,
  }
}

#[derive(Debug, Clone)]
/// A small continguous chunk of terrain.
pub struct TerrainBlock {
  // These Vecs must all be ordered the same way; each entry is the next triangle.

  /// Position of each vertex.
  pub vertex_coordinates: Vec<Triangle<Point3<f32>>>,
  /// Vertex normals. These should be normalized!
  pub normals: Vec<Triangle<Vector3<f32>>>,
  /// Entity IDs for each triangle.
  pub ids: Vec<EntityId>,
  // TODO: Change this back to a HashMap once initial capacity is zero for those.
  /// Per-triangle bounding boxes.
  pub bounds: Vec<(EntityId, Aabb3<f32>)>,
}

impl TerrainBlock {
  /// Construct an empty `TerrainBlock`.
  pub fn empty() -> TerrainBlock {
    TerrainBlock {
      vertex_coordinates: Vec::new(),
      normals: Vec::new(),

      ids: Vec::new(),
      bounds: Vec::new(),
    }
  }
}

flatten_struct_impl!(TerrainBlock, vertex_coordinates, normals, ids, bounds);
<commit_msg>Fewer samples in the most detailed LOD<commit_after>//! Data structure for a small block of terrain.

use cgmath::{Point3, Vector3, Aabb3};

use entity::EntityId;
use serialize::{Flatten, MemStream, EOF};

// TODO: Move the server-only parts to the server, like BLOCK_WIDTH and sample_info.

/// lg(WIDTH)
pub const LG_WIDTH: i16 = 3;
/// The width of a block of terrain.
pub const WIDTH: i32 = 1 << LG_WIDTH;

/// lg(EDGE_SAMPLES)
pub const LG_EDGE_SAMPLES: [u16; 4] = [3, 2, 1, 0];
/// The number of voxels along an axis within a block, indexed by LOD.
pub const EDGE_SAMPLES: [u16; 4] = [
  1 << LG_EDGE_SAMPLES[0],
  1 << LG_EDGE_SAMPLES[1],
  1 << LG_EDGE_SAMPLES[2],
  1 << LG_EDGE_SAMPLES[3],
];

/// The width of a voxel within a block, indexed by LOD.
pub const LG_SAMPLE_SIZE: [i16; 4] = [
  LG_WIDTH - LG_EDGE_SAMPLES[0] as i16,
  LG_WIDTH - LG_EDGE_SAMPLES[1] as i16,
  LG_WIDTH - LG_EDGE_SAMPLES[2] as i16,
  LG_WIDTH - LG_EDGE_SAMPLES[3] as i16,
];

#[derive(Debug, Copy, Clone)]
/// [T; 3], but serializable.
pub struct Triangle<T> {
  #[allow(missing_docs)]
  pub v1: T,
  #[allow(missing_docs)]
  pub v2: T,
  #[allow(missing_docs)]
  pub v3: T,
}

/// Construct a triangle.
pub fn tri<T>(v1: T, v2: T, v3: T) -> Triangle<T> {
  Triangle {
    v1: v1,
    v2: v2,
    v3: v3,
  }
}

#[derive(Debug, Clone)]
/// A small continguous chunk of terrain.
pub struct TerrainBlock {
  // These Vecs must all be ordered the same way; each entry is the next triangle.

  /// Position of each vertex.
  pub vertex_coordinates: Vec<Triangle<Point3<f32>>>,
  /// Vertex normals. These should be normalized!
  pub normals: Vec<Triangle<Vector3<f32>>>,
  /// Entity IDs for each triangle.
  pub ids: Vec<EntityId>,
  // TODO: Change this back to a HashMap once initial capacity is zero for those.
  /// Per-triangle bounding boxes.
  pub bounds: Vec<(EntityId, Aabb3<f32>)>,
}

impl TerrainBlock {
  /// Construct an empty `TerrainBlock`.
  pub fn empty() -> TerrainBlock {
    TerrainBlock {
      vertex_coordinates: Vec::new(),
      normals: Vec::new(),

      ids: Vec::new(),
      bounds: Vec::new(),
    }
  }
}

flatten_struct_impl!(TerrainBlock, vertex_coordinates, normals, ids, bounds);
<|endoftext|>


<commit_before>//! Runs decompiler stages on main function of /bin/ls

#[macro_use] extern crate radeco_lib;
extern crate r2pipe;
extern crate r2api;
extern crate serde_json;
extern crate petgraph;

use std::fs::File;
use std::io::prelude::*;

use petgraph::graph::NodeIndex;

use r2api::structs::{LFunctionInfo, LRegInfo};

use radeco_lib::frontend::bindings::{RadecoBindings, RBind, RBindings, Binding};
use radeco_lib::frontend::containers::{RadecoFunction, RFunction};
use radeco_lib::frontend::containers::{RadecoModule, RModule};
use radeco_lib::frontend::source::FileSource;
use radeco_lib::middle::ssa::memoryssa::MemorySSA;
use radeco_lib::middle::ssa::ssastorage::SSAStorage;
use radeco_lib::middle::ssa::verifier;
use radeco_lib::middle::ir_writer::IRWriter;
use radeco_lib::middle::{dce, dot};
use radeco_lib::analysis::sccp;
use radeco_lib::analysis::cse::cse::CSE;
use radeco_lib::analysis::interproc::fixcall::CallFixer;

pub type DefaultFnTy = RadecoFunction<RadecoBindings<Binding<NodeIndex>>>;

fn run_dce(rmod: &mut RadecoModule<DefaultFnTy>)
{
    let functions = rmod.functions.clone();
    let mut matched_func_vec: Vec<u64> =
        functions.iter().map(|(fn_addr, rfn)| fn_addr.clone()).collect();
    for fn_addr in &matched_func_vec {
        let rfn = rmod.functions.get_mut(fn_addr)
                        .expect("RadecoFunction Not Found!");
        let ssa = rfn.ssa_mut();
        dce::collect(ssa);
        verifier::verify(ssa).unwrap()
    }
}

fn run_sccp(rmod: &mut RadecoModule<DefaultFnTy>)
{
    let functions = rmod.functions.clone();
    let mut matched_func_vec: Vec<u64> =
        functions.iter().map(|(fn_addr, rfn)| fn_addr.clone()).collect();
    for fn_addr in &matched_func_vec {
        let mut writer: IRWriter = Default::default();
        let rfn = rmod.functions.get_mut(fn_addr)
                        .expect("RadecoFunction Not Found!");
        let mut ssa = rfn.ssa_mut().clone();
        let mut analyzer = sccp::Analyzer::new(&mut ssa);
        analyzer.analyze();
        rfn.ssa = analyzer.emit_ssa();
        verifier::verify(&rfn.ssa).unwrap();
    }
}

fn run_cse(rmod: &mut RadecoModule<DefaultFnTy>)
{
    let functions = rmod.functions.clone();
    let mut matched_func_vec: Vec<u64> =
        functions.iter().map(|(fn_addr, rfn)| fn_addr.clone()).collect();
    for fn_addr in &matched_func_vec {
        let rfn = rmod.functions.get_mut(fn_addr)
                        .expect("RadecoFunction Not Found!");
        let ssa = rfn.ssa_mut();
        {
            let mut cse = CSE::new(ssa);
            cse.run();
        }
        verifier::verify(ssa).unwrap();
    }
}

fn run_memory_ssa(rmod: &RadecoModule<DefaultFnTy>)
{
    let functions = rmod.functions.clone();
    let mut matched_func_vec: Vec<u64> =
        functions.iter().map(|(fn_addr, rfn)| fn_addr.clone()).collect();
    for fn_addr in &matched_func_vec {
        let rfn = rmod.functions.get(fn_addr)
                        .expect("RadecoFunction Not Found!");
        let mut memory_ssa = {
            let mut mssa = MemorySSA::new(&rfn.ssa);
            mssa.gather_variables(&rfn.datarefs, &rfn.locals,
                    &Some(rfn.call_ctx.iter().cloned()
                          .map(|x| if x.ssa_ref.is_some() {
                              x.ssa_ref.unwrap() } else {
                                NodeIndex::end()
                              }).collect()));
            mssa.run();
            mssa
        };
    }
}

fn run_write(rmod: &RadecoModule<DefaultFnTy>)
{
    let functions = rmod.functions.clone();
    let mut matched_func_vec: Vec<u64> =
        functions.iter().map(|(fn_addr, rfn)| fn_addr.clone()).collect();
    for fn_addr in &matched_func_vec {
        let mut writer: IRWriter = Default::default();
        let rfn = rmod.functions.get(fn_addr)
                        .expect("RadecoFunction Not Found!");
        let ssa = rfn.ssa_ref();
        println!("{}", writer.emit_il(Some("main".to_owned()), ssa));
    }
}

#[test]
fn bin_file_construction() {
    let mut fsource = FileSource::open(Some("./test_files/bin_file/bin_file"));
    let mut rmod = RadecoModule::from(&mut fsource);

    run_write(&rmod);
}

#[test]
fn bin_file_dce() {
    let mut fsource = FileSource::open(Some("./test_files/bin_file/bin_file"));
    let mut rmod = RadecoModule::from(&mut fsource);

    run_dce(&mut rmod);
    run_write(&rmod);
}

#[test]
fn bin_file_dce_sccp() {
    let mut fsource = FileSource::open(Some("./test_files/bin_file/bin_file"));
    let mut rmod = RadecoModule::from(&mut fsource);

    run_dce(&mut rmod);
    run_sccp(&mut rmod);
    run_write(&rmod);
}

#[test]
fn bin_file_dce_cse() {
    let mut fsource = FileSource::open(Some("./test_files/bin_file/bin_file"));
    let mut rmod = RadecoModule::from(&mut fsource);

    run_dce(&mut rmod);
    run_cse(&mut rmod);
    run_write(&rmod);
}

#[test]
fn bin_file_dce_cse_sccp() {
    let mut fsource = FileSource::open(Some("./test_files/bin_file/bin_file"));
    let mut rmod = RadecoModule::from(&mut fsource);

    run_dce(&mut rmod);
    run_cse(&mut rmod);
    run_sccp(&mut rmod);
    run_write(&rmod);
}

#[test]
fn bin_file_dce_fix() {
    let mut fsource = FileSource::open(Some("./test_files/bin_file/bin_file"));
    let mut rmod = RadecoModule::from(&mut fsource);

    run_dce(&mut rmod);
    {
        let mut callfixer = CallFixer::new(&mut rmod);
        callfixer.rounded_analysis();
    }
    run_write(&rmod);
}

#[test]
fn bin_file_dce_fix_sccp() {
    let mut fsource = FileSource::open(Some("./test_files/bin_file/bin_file"));
    let mut rmod = RadecoModule::from(&mut fsource);

    run_dce(&mut rmod);
    {
        let mut callfixer = CallFixer::new(&mut rmod);
        callfixer.rounded_analysis();
    }
    run_sccp(&mut rmod);
    run_write(&rmod);
}

#[test]
fn bin_file_dce_fix_cse() {
    let mut fsource = FileSource::open(Some("./test_files/bin_file/bin_file"));
    let mut rmod = RadecoModule::from(&mut fsource);

    run_dce(&mut rmod);
    {
        let mut callfixer = CallFixer::new(&mut rmod);
        callfixer.rounded_analysis();
    }
    run_cse(&mut rmod);
    run_write(&rmod);
}

#[test]
fn bin_file_dce_fix_cse_sccp() {
    let mut fsource = FileSource::open(Some("./test_files/bin_file/bin_file"));
    let mut rmod = RadecoModule::from(&mut fsource);

    run_dce(&mut rmod);
    {
        let mut callfixer = CallFixer::new(&mut rmod);
        callfixer.rounded_analysis();
    }
    run_cse(&mut rmod);
    run_sccp(&mut rmod);
    run_write(&rmod);
}

#[test]
fn bin_file_MemorySSA() {
    let mut fsource = FileSource::open(Some("./test_files/bin_file/bin_file"));
    let mut rmod = RadecoModule::from(&mut fsource);

    run_dce(&mut rmod);
    {
        let mut callfixer = CallFixer::new(&mut rmod);
        callfixer.rounded_analysis();
    }
    run_cse(&mut rmod);
    run_dce(&mut rmod);
    run_sccp(&mut rmod);
    run_dce(&mut rmod);
    run_write(&rmod);
    run_memory_ssa(&rmod);
}
<commit_msg>Remove compile warning in test<commit_after>//! Runs decompiler stages on main function of /bin/ls

extern crate radeco_lib;
extern crate r2pipe;
extern crate r2api;
extern crate serde_json;
extern crate petgraph;

use petgraph::graph::NodeIndex;

use radeco_lib::frontend::bindings::{RadecoBindings, Binding};
use radeco_lib::frontend::containers::{RadecoFunction, RFunction};
use radeco_lib::frontend::containers::RadecoModule;
use radeco_lib::frontend::source::FileSource;
use radeco_lib::middle::ssa::memory_ssa::memory_ssa;
use radeco_lib::middle::ssa::verifier;
use radeco_lib::middle::ir_writer::IRWriter;
use radeco_lib::middle::dce;
use radeco_lib::analysis::sccp;
use radeco_lib::analysis::cse::cse::CSE;
use radeco_lib::analysis::interproc::fixcall::CallFixer;

pub type DefaultFnTy = RadecoFunction<RadecoBindings<Binding<NodeIndex>>>;

fn run_dce(rmod: &mut RadecoModule<DefaultFnTy>)
{
    let functions = rmod.functions.clone();
    let matched_func_vec: Vec<u64> =
        functions.iter().map(|(fn_addr, _)| fn_addr.clone()).collect();
    for fn_addr in &matched_func_vec {
        let rfn = rmod.functions.get_mut(fn_addr)
                        .expect("RadecoFunction Not Found!");
        let ssa = rfn.ssa_mut();
        dce::collect(ssa);
        verifier::verify(ssa).unwrap()
    }
}

fn run_sccp(rmod: &mut RadecoModule<DefaultFnTy>)
{
    let functions = rmod.functions.clone();
    let matched_func_vec: Vec<u64> =
        functions.iter().map(|(fn_addr, _)| fn_addr.clone()).collect();
    for fn_addr in &matched_func_vec {
        let writer: IRWriter = Default::default();
        let rfn = rmod.functions.get_mut(fn_addr)
                        .expect("RadecoFunction Not Found!");
        let mut ssa = rfn.ssa_mut().clone();
        let mut analyzer = sccp::Analyzer::new(&mut ssa);
        analyzer.analyze();
        rfn.ssa = analyzer.emit_ssa();
        verifier::verify(&rfn.ssa).unwrap();
    }
}

fn run_cse(rmod: &mut RadecoModule<DefaultFnTy>)
{
    let functions = rmod.functions.clone();
    let matched_func_vec: Vec<u64> =
        functions.iter().map(|(fn_addr, _)| fn_addr.clone()).collect();
    for fn_addr in &matched_func_vec {
        let rfn = rmod.functions.get_mut(fn_addr)
                        .expect("RadecoFunction Not Found!");
        let ssa = rfn.ssa_mut();
        {
            let mut cse = CSE::new(ssa);
            cse.run();
        }
        verifier::verify(ssa).unwrap();
    }
}

fn run_memory_ssa(rmod: &RadecoModule<DefaultFnTy>)
{
    let functions = rmod.functions.clone();
    let matched_func_vec: Vec<u64> =
        functions.iter().map(|(fn_addr, _)| fn_addr.clone()).collect();
    for fn_addr in &matched_func_vec {
        let rfn = rmod.functions.get(fn_addr)
                        .expect("RadecoFunction Not Found!");
        let memory_ssa = {
            let mut mssa = memory_ssa::new(&rfn.ssa);
            mssa.gather_variables(&rfn.datarefs, &rfn.locals,
                    &Some(rfn.call_ctx.iter().cloned()
                          .map(|x| if x.ssa_ref.is_some() {
                              x.ssa_ref.unwrap() } else {
                                NodeIndex::end()
                              }).collect()));
            mssa.run();
            mssa
        };
    }
}

fn run_write(rmod: &RadecoModule<DefaultFnTy>)
{
    let functions = rmod.functions.clone();
    let matched_func_vec: Vec<u64> =
        functions.iter().map(|(fn_addr, _)| fn_addr.clone()).collect();
    for fn_addr in &matched_func_vec {
        let writer: IRWriter = Default::default();
        let rfn = rmod.functions.get(fn_addr)
                        .expect("RadecoFunction Not Found!");
        let ssa = rfn.ssa_ref();
        println!("{}", writer.emit_il(Some("main".to_owned()), ssa));
    }
}

#[test]
fn bin_file_construction() {
    let mut fsource = FileSource::open(Some("./test_files/bin_file/bin_file"));
    let rmod = RadecoModule::from(&mut fsource);

    run_write(&rmod);
}

#[test]
fn bin_file_dce() {
    let mut fsource = FileSource::open(Some("./test_files/bin_file/bin_file"));
    let mut rmod = RadecoModule::from(&mut fsource);

    run_dce(&mut rmod);
    run_write(&rmod);
}

#[test]
fn bin_file_dce_sccp() {
    let mut fsource = FileSource::open(Some("./test_files/bin_file/bin_file"));
    let mut rmod = RadecoModule::from(&mut fsource);

    run_dce(&mut rmod);
    run_sccp(&mut rmod);
    run_write(&rmod);
}

#[test]
fn bin_file_dce_cse() {
    let mut fsource = FileSource::open(Some("./test_files/bin_file/bin_file"));
    let mut rmod = RadecoModule::from(&mut fsource);

    run_dce(&mut rmod);
    run_cse(&mut rmod);
    run_write(&rmod);
}

#[test]
fn bin_file_dce_cse_sccp() {
    let mut fsource = FileSource::open(Some("./test_files/bin_file/bin_file"));
    let mut rmod = RadecoModule::from(&mut fsource);

    run_dce(&mut rmod);
    run_cse(&mut rmod);
    run_sccp(&mut rmod);
    run_write(&rmod);
}

#[test]
fn bin_file_dce_fix() {
    let mut fsource = FileSource::open(Some("./test_files/bin_file/bin_file"));
    let mut rmod = RadecoModule::from(&mut fsource);

    run_dce(&mut rmod);
    {
        let mut callfixer = CallFixer::new(&mut rmod);
        callfixer.rounded_analysis();
    }
    run_write(&rmod);
}

#[test]
fn bin_file_dce_fix_sccp() {
    let mut fsource = FileSource::open(Some("./test_files/bin_file/bin_file"));
    let mut rmod = RadecoModule::from(&mut fsource);

    run_dce(&mut rmod);
    {
        let mut callfixer = CallFixer::new(&mut rmod);
        callfixer.rounded_analysis();
    }
    run_sccp(&mut rmod);
    run_write(&rmod);
}

#[test]
fn bin_file_dce_fix_cse() {
    let mut fsource = FileSource::open(Some("./test_files/bin_file/bin_file"));
    let mut rmod = RadecoModule::from(&mut fsource);

    run_dce(&mut rmod);
    {
        let mut callfixer = CallFixer::new(&mut rmod);
        callfixer.rounded_analysis();
    }
    run_cse(&mut rmod);
    run_write(&rmod);
}

#[test]
fn bin_file_dce_fix_cse_sccp() {
    let mut fsource = FileSource::open(Some("./test_files/bin_file/bin_file"));
    let mut rmod = RadecoModule::from(&mut fsource);

    run_dce(&mut rmod);
    {
        let mut callfixer = CallFixer::new(&mut rmod);
        callfixer.rounded_analysis();
    }
    run_cse(&mut rmod);
    run_sccp(&mut rmod);
    run_write(&rmod);
}

#[test]
fn bin_file_memory_ssa() {
    let mut fsource = FileSource::open(Some("./test_files/bin_file/bin_file"));
    let mut rmod = RadecoModule::from(&mut fsource);

    run_dce(&mut rmod);
    {
        let mut callfixer = CallFixer::new(&mut rmod);
        callfixer.rounded_analysis();
    }
    run_cse(&mut rmod);
    run_dce(&mut rmod);
    run_sccp(&mut rmod);
    run_dce(&mut rmod);
    run_write(&rmod);
    run_memory_ssa(&rmod);
}
<|endoftext|>


<commit_before>use super::command;
use super::chain;

pub fn create_droplet_by_name(name: &str) {

    let ssh_key_mapping_func = |res: &command::Result, cmd_str: String| -> String {
        let ids : Vec<&str> = res.stdout.lines().collect();
        let new_cmd = str::replace(&cmd_str, "%ssh_keys%", &ids.join(","));
        new_cmd.to_string()
    };

    let ip_address_mapping_func = |res: &command::Result, cmd_str: String| -> String {
        let new_cmd = str::replace(&cmd_str, "%ip_address%", &res.stdout);
        new_cmd.to_string()
    };

    // Get ip address from stdout
    let ip_address_extractor = |res: &command::Result| -> command::Result {
        let mut ip_address : Option<String> = None;
        let res_stdout = res.stdout.clone();
        let lines = res_stdout.lines();
        for line in lines {
            if line.starts_with(name) {
                debug!("Found: {}", line);
                let fields : Vec<&str> = line.split_whitespace().collect();
                if fields.len() < 2 {
                    warn!("Couldn't find ip address in line: {}", line);
                }
                ip_address = Some(fields[1].to_string());
                break;
            }
        }
        if ip_address == None {
            error!("Couldn't locate droplet in output: {}", res_stdout);
            return command::Result {
                exit_code: None,
                success: false,
                stdout: "".to_string(),
                stderr: res.stderr.clone()
            }
        }

        command::Result {
            exit_code: res.exit_code,
            success: res.success,
            // We check for None above
            stdout: ip_address.unwrap().trim().to_string(),
            stderr: res.stderr.clone()
        }
    };

    let create_str = format!("doctl compute droplet create {} --image=ubuntu-16-04-x64 --region=sfo1 --size=512mb --ssh-keys=\"%ssh_keys%\" --wait", name);
    let record_str = format!("doctl compute domain records create one.haus --record-type=A --record-data=%ip_address% --record-name={}", name);

    let chain = chain::CommandChain::new()
        .cmd("doctl compute ssh-key list --no-header --format=ID")
        .result_mapped_cmd(&ssh_key_mapping_func, &create_str)
        .cmd("doctl compute droplet list --format Name,PublicIPv4,PublicIPv6,Status")
        .result_proc(&ip_address_extractor)
        .result_mapped_cmd(&ip_address_mapping_func, &record_str)
        .execute();
}

pub fn destroy_droplet_by_name(name: &str) {
    let create_str = format!("doctl compute droplet delete -f {}", name);
    println!("Running command:\n\t\t{}", create_str);
    // Create the actual droplet
    let result = command::run_host_cmd(&create_str);
    if !result.success {
        println!("Failed with stderr:\n\n{}", result.stderr);
        return
    }
    let get_record_cmd = "doctl compute domain records list one.haus --format Name,ID --no-header";
    // Get A record and delete it!
    let record_result = command::run_host_cmd(&get_record_cmd);
    if !record_result.success {
        println!("Failed with stderr:\n\n{}", record_result.stderr);
        return
    }
    let lines = record_result.stdout.lines();
    let mut record_to_delete = "";
    for line in lines {
        let fields : Vec<&str> = line.split_whitespace().collect();
        if fields.len() < 2 {
            println!("Invalid output line: {}", line);
            continue;
        }
        if fields[0].starts_with(name) {
            println!("Found: {}", line);
            record_to_delete = fields[1];
            break;
        }
    }
    if record_to_delete.len() == 0 {
        println!("Couldn't locate record for [{}] in output:\n\n{}", name, record_result.stdout);
        return;
    }
    // Create a DNS record to point to the droplet
    let delete_record_cmd = format!("doctl compute domain records delete one.haus {}", record_to_delete);
    println!("Deleting DNS record:\n\t\t{}", delete_record_cmd);
    let delete_result = command::run_host_cmd(&delete_record_cmd);
    if !delete_result.success {
        println!("Failed with stderr:\n\n{}", delete_result.stderr);
        return
    }
}

pub fn create_sshkey(name: &str) {
    // By default, always attempt to add a new key with [name] mapping to ~/.ssh/id_rsa.pub
    let create_key_str = format!("doctl compute ssh-key create {} --public-key=\"$(cat ~/.ssh/id_rsa.pub)\"", name);
    println!("Running command:\n\t\t{}", create_key_str);
    // Create the actual droplet
    let result = command::run_host_cmd(&create_key_str);
    if !result.success {
        println!("Failed with stderr:\n\n{}", result.stderr);
    }
}
<commit_msg>more efficient port of create_droplet<commit_after>use super::command;
use super::chain;

pub fn create_droplet_by_name(name: &str) {

    let ssh_key_mapping_func = |res: &command::Result, cmd_str: String| -> String {
        let ids : Vec<&str> = res.stdout.lines().collect();
        let new_cmd = str::replace(&cmd_str, "%ssh_keys%", &ids.join(","));
        new_cmd.to_string()
    };

    let ip_address_mapping_func = |res: &command::Result, cmd_str: String| -> String {
        let mut ip_address : Option<String> = None;
        let res_stdout = res.stdout.clone();
        let lines = res_stdout.lines();
        for line in lines {
            if line.starts_with(name) {
                debug!("Found: {}", line);
                let fields : Vec<&str> = line.split_whitespace().collect();
                if fields.len() < 2 {
                    warn!("Couldn't find ip address in line: {}", line);
                }
                ip_address = Some(fields[1].to_string());
                break;
            }
        }
        if ip_address == None {
            error!("Couldn't locate droplet in output: {}", res_stdout);
            return "--will fail--".to_string()
        }

        let new_cmd = str::replace(&cmd_str, "%ip_address%", &ip_address.unwrap());
        new_cmd.to_string()
    };

    let create_str = format!("doctl compute droplet create {} --image=ubuntu-16-04-x64 --region=sfo1 --size=512mb --ssh-keys=\"%ssh_keys%\" --wait", name);
    let record_str = format!("doctl compute domain records create one.haus --record-type=A --record-data=%ip_address% --record-name={}", name);

    let chain = chain::CommandChain::new()
        .cmd("doctl compute ssh-key list --no-header --format=ID")
        .result_mapped_cmd(&ssh_key_mapping_func, &create_str)
        .cmd("doctl compute droplet list --format Name,PublicIPv4,PublicIPv6,Status")
        .result_mapped_cmd(&ip_address_mapping_func, &record_str)
        .execute();
}

pub fn destroy_droplet_by_name(name: &str) {
    let create_str = format!("doctl compute droplet delete -f {}", name);
    println!("Running command:\n\t\t{}", create_str);
    // Create the actual droplet
    let result = command::run_host_cmd(&create_str);
    if !result.success {
        println!("Failed with stderr:\n\n{}", result.stderr);
        return
    }
    let get_record_cmd = "doctl compute domain records list one.haus --format Name,ID --no-header";
    // Get A record and delete it!
    let record_result = command::run_host_cmd(&get_record_cmd);
    if !record_result.success {
        println!("Failed with stderr:\n\n{}", record_result.stderr);
        return
    }
    let lines = record_result.stdout.lines();
    let mut record_to_delete = "";
    for line in lines {
        let fields : Vec<&str> = line.split_whitespace().collect();
        if fields.len() < 2 {
            println!("Invalid output line: {}", line);
            continue;
        }
        if fields[0].starts_with(name) {
            println!("Found: {}", line);
            record_to_delete = fields[1];
            break;
        }
    }
    if record_to_delete.len() == 0 {
        println!("Couldn't locate record for [{}] in output:\n\n{}", name, record_result.stdout);
        return;
    }
    // Create a DNS record to point to the droplet
    let delete_record_cmd = format!("doctl compute domain records delete -f one.haus {}", record_to_delete);
    println!("Deleting DNS record:\n\t\t{}", delete_record_cmd);
    let delete_result = command::run_host_cmd(&delete_record_cmd);
    if !delete_result.success {
        println!("Failed with stderr:\n\n{}", delete_result.stderr);
        return
    }
}

pub fn create_sshkey(name: &str) {
    // By default, always attempt to add a new key with [name] mapping to ~/.ssh/id_rsa.pub
    let create_key_str = format!("doctl compute ssh-key create {} --public-key=\"$(cat ~/.ssh/id_rsa.pub)\"", name);
    println!("Running command:\n\t\t{}", create_key_str);
    // Create the actual droplet
    let result = command::run_host_cmd(&create_key_str);
    if !result.success {
        println!("Failed with stderr:\n\n{}", result.stderr);
    }
}
<|endoftext|>


<commit_before>use byteorder::{ByteOrder, LittleEndian};

use opcodes::{AddressingMode, OpCode};

pub struct Disassembler;

impl Disassembler {
    pub fn disassemble(raw: &[u8]) -> String {
        let mut result = String::new();

        let mut i: usize = 0;
        while i < raw.len() {
            let opcode = OpCode::from_raw_byte(raw[i]);
            let val = match opcode.mode {
                AddressingMode::Implied |
                AddressingMode::Accumulator => String::from(""),
                AddressingMode::Immediate => format!(" #${:02X}", raw[i + 0x01]),
                AddressingMode::Indirect => {
                    format!(" (${:04X})", LittleEndian::read_u16(&raw[i + 0x01..]))
                }
                AddressingMode::Relative => {
                    let mut offset = raw[i + 0x01] as i8;
                    println!("i: {}, Offset: {}, op: {}", i, offset, opcode.mnemonic);
                    let addr = if offset < 0 {
                        i - (-offset - 0x02) as usize
                    } else {
                        i + (offset as usize) + 0x02
                    };
                    format!(" ${:04X}", addr)
                }
                AddressingMode::ZeroPage => format!(" ${:02X}", raw[i + 0x01]),
                AddressingMode::ZeroPageX => format!(" ${:02X},X", raw[i + 0x01]),
                AddressingMode::ZeroPageY => format!(" ${:02X},Y", raw[i + 0x01]),
                AddressingMode::Absolute => {
                    format!(" ${:04X}", LittleEndian::read_u16(&raw[i + 0x01..]))
                }
                AddressingMode::AbsoluteX => {
                    format!(" ${:04X},X", LittleEndian::read_u16(&raw[i + 0x01..]))
                }
                AddressingMode::AbsoluteY => {
                    format!(" ${:04X},Y", LittleEndian::read_u16(&raw[i + 0x01..]))
                }
                AddressingMode::IndirectX => format!(" (${:02X},X)", raw[i + 0x01]),
                AddressingMode::IndirectY => format!(" (${:02X}),Y", raw[i + 0x01]),
            };
            let opcode_text = format!("{:04X} {}{}\n", i, opcode.mnemonic, val);
            result.push_str(&opcode_text);
            i += opcode.length as usize;
        }

        result
    }

    /// Returns a Vector of Strings where each entry
    /// is a non-empty line from some text input, with
    /// all leading and trailing whitespace removed.
    fn clean_asm<I>(input: I) -> Vec<String>
        where I: Into<String>
    {
        input.into()
            .lines()
            .map(|line| line.trim())
            .map(String::from)
            .filter(|line| line.len() > 0)
            .collect()
    }
}

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

    #[test]
    fn can_disassemble_basic_instructions() {
        let code: Vec<u8> = vec![0xA9, 0x20, 0x8D, 0x00, 0x44];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 LDA #$20
            0002 STA $4400

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_indirect_jmp() {
        let code: Vec<u8> = vec![0x6C, 0x00, 0x44];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 JMP ($4400)

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_relative_addressing() {
        let code: Vec<u8> = vec![0xA9, 0x20, 0x69, 0x10, 0xD0, 0xFA];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 LDA #$20
            0002 ADC #$10
            0004 BNE $0000

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_zero_page_addressing() {
        let code: Vec<u8> = vec![0xA5, 0x35];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 LDA $35

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_zero_page_indexed_addressing() {
        let code: Vec<u8> = vec![0x95, 0x44, 0x96, 0xFE];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 STA $44,X
            0002 STX $FE,Y

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_absolute_addressing() {
        let code: Vec<u8> = vec![0x8D, 0x00, 0x44];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 STA $4400

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_absolute_indexed_addressing() {
        let code: Vec<u8> = vec![0x9D, 0x00, 0x44, 0x99, 0xFE, 0xFF];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 STA $4400,X
            0003 STA $FFFE,Y

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_indirect_indexed_addressing() {
        let code: Vec<u8> = vec![0x81, 0x44, 0x91, 0xFE];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 STA ($44,X)
            0002 STA ($FE),Y

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn move_memory_down_test() {
        let code: Vec<u8> = vec![0xA0, 0x00, 0xAE, 0x00, 0x00, 0xF0, 0x10, 0xB1, 0x02, 0x91, 0x03,
                                 0xC8, 0xD0, 0xF9, 0xEE, 0x02, 0x00, 0xEE, 0x03, 0x00, 0xCA, 0xD0,
                                 0xF0, 0xAE, 0x01, 0x00, 0xF0, 0x08, 0xB1, 0x02, 0x91, 0x03, 0xC8,
                                 0xCA, 0xD0, 0xF8, 0x60];

        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 LDY #$00
            0002 LDX $0000
            0005 BEQ $0017
            0007 LDA ($02),Y
            0009 STA ($03),Y
            000B INY
            000C BNE $0007
            000E INC $0002
            0011 INC $0003
            0014 DEX
            0015 BNE $0007
            0017 LDX $0001
            001A BEQ $0024
            001C LDA ($02),Y
            001E STA ($03),Y
            0020 INY
            0021 DEX
            0022 BNE $001C
            0024 RTS

        "),
                   Disassembler::clean_asm(asm));
    }
}
<commit_msg>Add memset implementation test<commit_after>use byteorder::{ByteOrder, LittleEndian};

use opcodes::{AddressingMode, OpCode};

pub struct Disassembler;

impl Disassembler {
    pub fn disassemble(raw: &[u8]) -> String {
        let mut result = String::new();

        let mut i: usize = 0;
        while i < raw.len() {
            let opcode = OpCode::from_raw_byte(raw[i]);
            let val = match opcode.mode {
                AddressingMode::Immediate => format!(" #${:02X}", raw[i + 0x01]),
                AddressingMode::Indirect => {
                    format!(" (${:04X})", LittleEndian::read_u16(&raw[i + 0x01..]))
                }
                AddressingMode::Relative => {
                    let mut offset = raw[i + 0x01] as i8;
                    let addr = if offset < 0 {
                        i - (-offset - 0x02) as usize
                    } else {
                        i + (offset as usize) + 0x02
                    };
                    format!(" ${:04X}", addr)
                }
                AddressingMode::ZeroPage => format!(" ${:02X}", raw[i + 0x01]),
                AddressingMode::ZeroPageX => format!(" ${:02X},X", raw[i + 0x01]),
                AddressingMode::ZeroPageY => format!(" ${:02X},Y", raw[i + 0x01]),
                AddressingMode::Absolute => {
                    format!(" ${:04X}", LittleEndian::read_u16(&raw[i + 0x01..]))
                }
                AddressingMode::AbsoluteX => {
                    format!(" ${:04X},X", LittleEndian::read_u16(&raw[i + 0x01..]))
                }
                AddressingMode::AbsoluteY => {
                    format!(" ${:04X},Y", LittleEndian::read_u16(&raw[i + 0x01..]))
                }
                AddressingMode::IndirectX => format!(" (${:02X},X)", raw[i + 0x01]),
                AddressingMode::IndirectY => format!(" (${:02X}),Y", raw[i + 0x01]),
                _ => "".into(),
            };
            let opcode_text = format!("{:04X} {}{}\n", i, opcode.mnemonic, val);
            result.push_str(&opcode_text);
            i += opcode.length as usize;
        }

        result
    }

    /// Returns a Vector of Strings where each entry
    /// is a non-empty line from some text input, with
    /// all leading and trailing whitespace removed.
    fn clean_asm<I>(input: I) -> Vec<String>
        where I: Into<String>
    {
        input.into()
            .lines()
            .map(|line| line.trim())
            .map(String::from)
            .filter(|line| line.len() > 0)
            .collect()
    }
}

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

    #[test]
    fn can_disassemble_basic_instructions() {
        let code: Vec<u8> = vec![0xA9, 0x20, 0x8D, 0x00, 0x44];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 LDA #$20
            0002 STA $4400

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_indirect_jmp() {
        let code: Vec<u8> = vec![0x6C, 0x00, 0x44];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 JMP ($4400)

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_relative_addressing() {
        let code: Vec<u8> = vec![0xA9, 0x20, 0x69, 0x10, 0xD0, 0xFA];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 LDA #$20
            0002 ADC #$10
            0004 BNE $0000

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_zero_page_addressing() {
        let code: Vec<u8> = vec![0xA5, 0x35];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 LDA $35

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_zero_page_indexed_addressing() {
        let code: Vec<u8> = vec![0x95, 0x44, 0x96, 0xFE];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 STA $44,X
            0002 STX $FE,Y

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_absolute_addressing() {
        let code: Vec<u8> = vec![0x8D, 0x00, 0x44];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 STA $4400

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_absolute_indexed_addressing() {
        let code: Vec<u8> = vec![0x9D, 0x00, 0x44, 0x99, 0xFE, 0xFF];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 STA $4400,X
            0003 STA $FFFE,Y

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_indirect_indexed_addressing() {
        let code: Vec<u8> = vec![0x81, 0x44, 0x91, 0xFE];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 STA ($44,X)
            0002 STA ($FE),Y

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn move_memory_down_test() {
        let code: Vec<u8> = vec![0xA0, 0x00, 0xAE, 0x00, 0x00, 0xF0, 0x10, 0xB1, 0x02, 0x91, 0x03,
                                 0xC8, 0xD0, 0xF9, 0xEE, 0x02, 0x00, 0xEE, 0x03, 0x00, 0xCA, 0xD0,
                                 0xF0, 0xAE, 0x01, 0x00, 0xF0, 0x08, 0xB1, 0x02, 0x91, 0x03, 0xC8,
                                 0xCA, 0xD0, 0xF8, 0x60];

        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 LDY #$00
            0002 LDX $0000
            0005 BEQ $0017
            0007 LDA ($02),Y
            0009 STA ($03),Y
            000B INY
            000C BNE $0007
            000E INC $0002
            0011 INC $0003
            0014 DEX
            0015 BNE $0007
            0017 LDX $0001
            001A BEQ $0024
            001C LDA ($02),Y
            001E STA ($03),Y
            0020 INY
            0021 DEX
            0022 BNE $001C
            0024 RTS

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn test_memset_implementation() {
        let code: Vec<u8> = vec![0xA9, 0x00, 0xA8, 0x91, 0xFF, 0xC8, 0xCA, 0xD0, 0xFA, 0x60];
        let asm = Disassembler::disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 LDA #$00
            0002 TAY
            0003 STA ($FF),Y
            0005 INY
            0006 DEX
            0007 BNE $0003
            0009 RTS

        "),
                   Disassembler::clean_asm(asm));
    }
}
<|endoftext|>