<commit_before>// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::net::Ipv4Addr;
use std::str::FromStr;

use anyhow::{anyhow, bail, Context};
use base::{error, warn, Event};
use cros_async::{EventAsync, Executor, IoSourceExt};
use data_model::DataInit;
use devices::virtio;
use devices::virtio::net::{
    build_config, process_rx, process_tx, validate_and_configure_tap,
    virtio_features_to_tap_offload, NetError,
};
use devices::ProtectionType;
use futures::future::{AbortHandle, Abortable};
use getopts::Options;
use net_util::{MacAddress, Tap, TapT};
use once_cell::sync::OnceCell;
use vhost_user_devices::{CallEvent, DeviceRequestHandler, VhostUserBackend};
use virtio_sys::virtio_net;
use vm_memory::GuestMemory;
use vmm_vhost::vhost_user::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures};

static NET_EXECUTOR: OnceCell<Executor> = OnceCell::new();

async fn run_tx_queue(
    mut queue: virtio::Queue,
    mem: GuestMemory,
    mut tap: Tap,
    call_evt: CallEvent,
    kick_evt: EventAsync,
) {
    loop {
        if let Err(e) = kick_evt.next_val().await {
            error!("Failed to read kick event for tx queue: {}", e);
            break;
        }

        process_tx(&call_evt, &mut queue, &mem, &mut tap);
    }
}

async fn run_rx_queue(
    mut queue: virtio::Queue,
    mem: GuestMemory,
    mut tap: Box<dyn IoSourceExt<Tap>>,
    call_evt: CallEvent,
    kick_evt: EventAsync,
) {
    loop {
        if let Err(e) = tap.wait_readable().await {
            error!("Failed to wait for tap device to become readable: {}", e);
            break;
        }

        match process_rx(&call_evt, &mut queue, &mem, tap.as_source_mut()) {
            Ok(()) => {}
            Err(NetError::RxDescriptorsExhausted) => {
                if let Err(e) = kick_evt.next_val().await {
                    error!("Failed to read kick event for rx queue: {}", e);
                    break;
                }
            }
            Err(e) => {
                error!("Failed to process rx queue: {}", e);
                break;
            }
        }
    }
}

struct NetBackend {
    tap: Tap,
    avail_features: u64,
    acked_features: u64,
    acked_protocol_features: VhostUserProtocolFeatures,
    workers: [Option<AbortHandle>; Self::MAX_QUEUE_NUM],
}

impl NetBackend {
    pub fn new(
        host_ip: Ipv4Addr,
        netmask: Ipv4Addr,
        mac_address: MacAddress,
    ) -> anyhow::Result<Self> {
        // TODO(keiichiw): Support CTRL_VQ and MQ.
        // Note that MQ cannot be enabled without CTRL_VQ.
        let avail_features = virtio::base_features(ProtectionType::Unprotected)
            | 1 << virtio_net::VIRTIO_NET_F_GUEST_CSUM
            | 1 << virtio_net::VIRTIO_NET_F_CSUM
            | 1 << virtio_net::VIRTIO_NET_F_CTRL_GUEST_OFFLOADS
            | 1 << virtio_net::VIRTIO_NET_F_GUEST_TSO4
            | 1 << virtio_net::VIRTIO_NET_F_GUEST_UFO
            | 1 << virtio_net::VIRTIO_NET_F_HOST_TSO4
            | 1 << virtio_net::VIRTIO_NET_F_HOST_UFO
            | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();

        let vq_pairs = Self::max_vq_pairs();

        // Create a tap device.
        let tap = Tap::new(true /* vnet_hdr */, true /* multi_queue */)
            .context("failed to create tap device")?;
        tap.set_ip_addr(host_ip)
            .context("failed to set IP address")?;
        tap.set_netmask(netmask).context("failed to set netmask")?;
        tap.set_mac_address(mac_address)
            .context("failed to set MAC address")?;
        tap.enable().context("failed to enable tap")?;
        validate_and_configure_tap(&tap, vq_pairs as u16)
            .context("failed to validate and configure tap")?;

        Ok(Self {
            tap,
            avail_features,
            acked_features: 0,
            acked_protocol_features: VhostUserProtocolFeatures::empty(),
            workers: Default::default(),
        })
    }

    fn max_vq_pairs() -> usize {
        Self::MAX_QUEUE_NUM / 2
    }
}

impl VhostUserBackend for NetBackend {
    // TODO(keiichiw): Support multiple queue pairs.
    const MAX_QUEUE_NUM: usize = 2; /* 1 rx and 1 tx */
    const MAX_VRING_LEN: u16 = 256;

    type Error = anyhow::Error;

    fn features(&self) -> u64 {
        self.avail_features
    }

    fn ack_features(&mut self, value: u64) -> anyhow::Result<()> {
        let unrequested_features = value & !self.avail_features;
        if unrequested_features != 0 {
            bail!("invalid features are given: {:#x}", unrequested_features);
        }

        self.acked_features |= value;

        self.tap
            .set_offload(virtio_features_to_tap_offload(self.acked_features))
            .context("failed to set tap offload to match features")?;

        Ok(())
    }

    fn acked_features(&self) -> u64 {
        self.acked_features
    }

    fn protocol_features(&self) -> VhostUserProtocolFeatures {
        // TODO(keiichiw): Support MQ.
        VhostUserProtocolFeatures::CONFIG
    }

    fn ack_protocol_features(&mut self, features: u64) -> anyhow::Result<()> {
        let features = VhostUserProtocolFeatures::from_bits(features)
            .ok_or_else(|| anyhow!("invalid protocol features are given: {:#x}", features))?;
        let supported = self.protocol_features();
        self.acked_protocol_features = features & supported;
        Ok(())
    }

    fn acked_protocol_features(&self) -> u64 {
        self.acked_protocol_features.bits()
    }

    fn read_config(&self, offset: u64, data: &mut [u8]) {
        let config_space = build_config(Self::max_vq_pairs() as u16);
        virtio::copy_config(data, 0, config_space.as_slice(), offset);
    }

    fn reset(&mut self) {}

    fn start_queue(
        &mut self,
        idx: usize,
        queue: virtio::Queue,
        mem: GuestMemory,
        call_evt: CallEvent,
        kick_evt: Event,
    ) -> anyhow::Result<()> {
        if let Some(handle) = self.workers.get_mut(idx).and_then(Option::take) {
            warn!("Starting new queue handler without stopping old handler");
            handle.abort();
        }

        // Safe because the executor is initialized in main() below.
        let ex = NET_EXECUTOR.get().expect("Executor not initialized");

        let kick_evt =
            EventAsync::new(kick_evt.0, ex).context("failed to create EventAsync for kick_evt")?;
        let tap = self.tap.try_clone().context("failed to clone tap device")?;
        let (handle, registration) = AbortHandle::new_pair();
        match idx {
            0 => {
                let tap = ex
                    .async_from(tap)
                    .context("failed to create async tap device")?;

                ex.spawn_local(Abortable::new(
                    run_rx_queue(queue, mem, tap, call_evt, kick_evt),
                    registration,
                ))
                .detach();
            }
            1 => {
                ex.spawn_local(Abortable::new(
                    run_tx_queue(queue, mem, tap, call_evt, kick_evt),
                    registration,
                ))
                .detach();
            }
            _ => bail!("attempted to start unknown queue: {}", idx),
        }

        self.workers[idx] = Some(handle);
        Ok(())
    }

    fn stop_queue(&mut self, idx: usize) {
        if let Some(handle) = self.workers.get_mut(idx).and_then(Option::take) {
            handle.abort();
        }
    }
}

struct TapConfig {
    host_ip: Ipv4Addr,
    netmask: Ipv4Addr,
    mac: MacAddress,
}

impl FromStr for TapConfig {
    type Err = String;

    fn from_str(arg: &str) -> Result<Self, Self::Err> {
        let args: Vec<&str> = arg.split(',').collect();
        if args.len() != 3 {
            return Err(format!(
                "TAP config must consist of 3 parts but {}",
                args.len()
            ));
        }
        let host_ip: Ipv4Addr = args[0]
            .parse()
            .map_err(|e| format!("invalid IP address: {}", e))?;
        let netmask: Ipv4Addr = args[1]
            .parse()
            .map_err(|e| format!("invalid net mask: {}", e))?;
        let mac: MacAddress = args[2]
            .parse()
            .map_err(|e| format!("invalid MAC address: {}", e))?;

        Ok(Self {
            host_ip,
            netmask,
            mac,
        })
    }
}

fn main() -> anyhow::Result<()> {
    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help menu");
    opts.reqopt("", "socket", "path to a socket", "PATH");
    // TODO(keiichiw): Support tap-fd option.
    // TODO(keiichiw): Support multiple TAP devices.
    opts.reqopt(
        "",
        "tap",
        "TAP device config. (e.g. \"10.0.2.2,255.255.255.0,12:34:56:78:9a:bc\")",
        "IP_ADDR,NET_MASK,MAC_ADDR",
    );

    let mut args = std::env::args();
    let program_name = args.next().expect("args is empty");
    let matches = match opts.parse(args) {
        Ok(m) => m,
        Err(e) => {
            println!("{}", e);
            println!("{}", opts.short_usage(&program_name));
            return Ok(());
        }
    };

    if matches.opt_present("h") {
        println!("{}", opts.usage(&program_name));
        return Ok(());
    }

    base::syslog::init().context("failed to initialize syslog")?;

    // We can unwrap after `opt_str()` safely because they are required options.
    let socket = matches.opt_str("socket").unwrap();
    let tap_cfg: TapConfig = match matches.opt_str("tap").unwrap().parse() {
        Ok(cfg) => cfg,
        Err(e) => {
            println!("invalid TAP config: {}", e);
            return Ok(());
        }
    };

    let ex = Executor::new().context("failed to create executor")?;
    let _ = NET_EXECUTOR.set(ex.clone());

    let net = NetBackend::new(tap_cfg.host_ip, tap_cfg.netmask, tap_cfg.mac)
        .context("failed to create NetBackend")?;
    let handler = DeviceRequestHandler::new(net);

    if let Err(e) = ex.run_until(handler.run(socket, &ex)) {
        error!("error occurred: {}", e);
    }

    Ok(())
}
<commit_msg>vhost_user_devices: net: Change format of command line argument<commit_after>// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::net::Ipv4Addr;
use std::str::FromStr;

use anyhow::{anyhow, bail, Context};
use base::{error, warn, Event};
use cros_async::{EventAsync, Executor, IoSourceExt};
use data_model::DataInit;
use devices::virtio;
use devices::virtio::net::{
    build_config, process_rx, process_tx, validate_and_configure_tap,
    virtio_features_to_tap_offload, NetError,
};
use devices::ProtectionType;
use futures::future::{AbortHandle, Abortable};
use getopts::Options;
use net_util::{MacAddress, Tap, TapT};
use once_cell::sync::OnceCell;
use vhost_user_devices::{CallEvent, DeviceRequestHandler, VhostUserBackend};
use virtio_sys::virtio_net;
use vm_memory::GuestMemory;
use vmm_vhost::vhost_user::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures};

static NET_EXECUTOR: OnceCell<Executor> = OnceCell::new();

async fn run_tx_queue(
    mut queue: virtio::Queue,
    mem: GuestMemory,
    mut tap: Tap,
    call_evt: CallEvent,
    kick_evt: EventAsync,
) {
    loop {
        if let Err(e) = kick_evt.next_val().await {
            error!("Failed to read kick event for tx queue: {}", e);
            break;
        }

        process_tx(&call_evt, &mut queue, &mem, &mut tap);
    }
}

async fn run_rx_queue(
    mut queue: virtio::Queue,
    mem: GuestMemory,
    mut tap: Box<dyn IoSourceExt<Tap>>,
    call_evt: CallEvent,
    kick_evt: EventAsync,
) {
    loop {
        if let Err(e) = tap.wait_readable().await {
            error!("Failed to wait for tap device to become readable: {}", e);
            break;
        }

        match process_rx(&call_evt, &mut queue, &mem, tap.as_source_mut()) {
            Ok(()) => {}
            Err(NetError::RxDescriptorsExhausted) => {
                if let Err(e) = kick_evt.next_val().await {
                    error!("Failed to read kick event for rx queue: {}", e);
                    break;
                }
            }
            Err(e) => {
                error!("Failed to process rx queue: {}", e);
                break;
            }
        }
    }
}

struct TapConfig {
    host_ip: Ipv4Addr,
    netmask: Ipv4Addr,
    mac: MacAddress,
}

impl FromStr for TapConfig {
    type Err = anyhow::Error;

    fn from_str(arg: &str) -> Result<Self, Self::Err> {
        let args: Vec<&str> = arg.split(',').collect();
        if args.len() != 3 {
            bail!("TAP config must consist of 3 parts but {}", args.len());
        }

        let host_ip: Ipv4Addr = args[0]
            .parse()
            .map_err(|e| anyhow!("invalid IP address: {}", e))?;
        let netmask: Ipv4Addr = args[1]
            .parse()
            .map_err(|e| anyhow!("invalid net mask: {}", e))?;
        let mac: MacAddress = args[2]
            .parse()
            .map_err(|e| anyhow!("invalid MAC address: {}", e))?;

        Ok(Self {
            host_ip,
            netmask,
            mac,
        })
    }
}

struct NetBackend {
    tap: Tap,
    avail_features: u64,
    acked_features: u64,
    acked_protocol_features: VhostUserProtocolFeatures,
    workers: [Option<AbortHandle>; Self::MAX_QUEUE_NUM],
}

impl NetBackend {
    pub fn new(config: &TapConfig) -> anyhow::Result<Self> {
        // Create a tap device.
        let tap = Tap::new(true /* vnet_hdr */, false /* multi_queue */)
            .context("failed to create tap device")?;
        tap.set_ip_addr(config.host_ip)
            .context("failed to set IP address")?;
        tap.set_netmask(config.netmask)
            .context("failed to set netmask")?;
        tap.set_mac_address(config.mac)
            .context("failed to set MAC address")?;

        let vq_pairs = Self::max_vq_pairs();
        tap.enable().context("failed to enable tap")?;
        validate_and_configure_tap(&tap, vq_pairs as u16)
            .context("failed to validate and configure tap")?;

        // TODO(keiichiw): Support CTRL_VQ and MQ.
        // Note that MQ cannot be enabled without CTRL_VQ.
        let avail_features = virtio::base_features(ProtectionType::Unprotected)
            | 1 << virtio_net::VIRTIO_NET_F_GUEST_CSUM
            | 1 << virtio_net::VIRTIO_NET_F_CSUM
            | 1 << virtio_net::VIRTIO_NET_F_CTRL_GUEST_OFFLOADS
            | 1 << virtio_net::VIRTIO_NET_F_GUEST_TSO4
            | 1 << virtio_net::VIRTIO_NET_F_GUEST_UFO
            | 1 << virtio_net::VIRTIO_NET_F_HOST_TSO4
            | 1 << virtio_net::VIRTIO_NET_F_HOST_UFO
            | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();

        Ok(Self {
            tap,
            avail_features,
            acked_features: 0,
            acked_protocol_features: VhostUserProtocolFeatures::empty(),
            workers: Default::default(),
        })
    }

    fn max_vq_pairs() -> usize {
        Self::MAX_QUEUE_NUM / 2
    }
}

impl VhostUserBackend for NetBackend {
    // TODO(keiichiw): Support multiple queue pairs.
    const MAX_QUEUE_NUM: usize = 2; /* 1 rx and 1 tx */
    const MAX_VRING_LEN: u16 = 256;

    type Error = anyhow::Error;

    fn features(&self) -> u64 {
        self.avail_features
    }

    fn ack_features(&mut self, value: u64) -> anyhow::Result<()> {
        let unrequested_features = value & !self.avail_features;
        if unrequested_features != 0 {
            bail!("invalid features are given: {:#x}", unrequested_features);
        }

        self.acked_features |= value;

        self.tap
            .set_offload(virtio_features_to_tap_offload(self.acked_features))
            .context("failed to set tap offload to match features")?;

        Ok(())
    }

    fn acked_features(&self) -> u64 {
        self.acked_features
    }

    fn protocol_features(&self) -> VhostUserProtocolFeatures {
        // TODO(keiichiw): Support MQ.
        VhostUserProtocolFeatures::CONFIG
    }

    fn ack_protocol_features(&mut self, features: u64) -> anyhow::Result<()> {
        let features = VhostUserProtocolFeatures::from_bits(features)
            .ok_or_else(|| anyhow!("invalid protocol features are given: {:#x}", features))?;
        let supported = self.protocol_features();
        self.acked_protocol_features = features & supported;
        Ok(())
    }

    fn acked_protocol_features(&self) -> u64 {
        self.acked_protocol_features.bits()
    }

    fn read_config(&self, offset: u64, data: &mut [u8]) {
        let config_space = build_config(Self::max_vq_pairs() as u16);
        virtio::copy_config(data, 0, config_space.as_slice(), offset);
    }

    fn reset(&mut self) {}

    fn start_queue(
        &mut self,
        idx: usize,
        queue: virtio::Queue,
        mem: GuestMemory,
        call_evt: CallEvent,
        kick_evt: Event,
    ) -> anyhow::Result<()> {
        if let Some(handle) = self.workers.get_mut(idx).and_then(Option::take) {
            warn!("Starting new queue handler without stopping old handler");
            handle.abort();
        }

        // Safe because the executor is initialized in main() below.
        let ex = NET_EXECUTOR.get().expect("Executor not initialized");

        let kick_evt =
            EventAsync::new(kick_evt.0, ex).context("failed to create EventAsync for kick_evt")?;
        let tap = self.tap.try_clone().context("failed to clone tap device")?;
        let (handle, registration) = AbortHandle::new_pair();
        match idx {
            0 => {
                let tap = ex
                    .async_from(tap)
                    .context("failed to create async tap device")?;

                ex.spawn_local(Abortable::new(
                    run_rx_queue(queue, mem, tap, call_evt, kick_evt),
                    registration,
                ))
                .detach();
            }
            1 => {
                ex.spawn_local(Abortable::new(
                    run_tx_queue(queue, mem, tap, call_evt, kick_evt),
                    registration,
                ))
                .detach();
            }
            _ => bail!("attempted to start unknown queue: {}", idx),
        }

        self.workers[idx] = Some(handle);
        Ok(())
    }

    fn stop_queue(&mut self, idx: usize) {
        if let Some(handle) = self.workers.get_mut(idx).and_then(Option::take) {
            handle.abort();
        }
    }
}

fn main() -> anyhow::Result<()> {
    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help menu");
    // TODO(keiichiw): Support tap-fd option.
    // TODO(keiichiw): Support multiple TAP devices.
    opts.reqopt(
        "",
        "device",
        "TAP device config. (e.g. \"/path/to/sock,10.0.2.2,255.255.255.0,12:34:56:78:9a:bc\")",
        "SOCKET_PATH,IP_ADDR,NET_MASK,MAC_ADDR",
    );

    let mut args = std::env::args();
    let program_name = args.next().expect("args is empty");
    let matches = match opts.parse(args) {
        Ok(m) => m,
        Err(e) => {
            println!("{}", e);
            println!("{}", opts.short_usage(&program_name));
            return Ok(());
        }
    };

    if matches.opt_present("h") {
        println!("{}", opts.usage(&program_name));
        return Ok(());
    }

    base::syslog::init().context("failed to initialize syslog")?;

    // We can unwrap after `opt_str()` safely because it's a required option.
    let arg = matches.opt_str("device").unwrap();
    let pos = match arg.find(',') {
        Some(p) => p,
        None => {
            bail!("device must take comma-separated argument");
        }
    };
    let socket = &arg[0..pos];
    let cfg = &arg[pos + 1..]
        .parse::<TapConfig>()
        .context("failed to parse tap config")?;
    let backend = NetBackend::new(&cfg).context("failed to create NetBackend")?;
    let handler = DeviceRequestHandler::new(backend);

    let ex = Executor::new().context("failed to create executor")?;
    let _ = NET_EXECUTOR.set(ex.clone());
    if let Err(e) = ex.run_until(handler.run(socket, &ex)) {
        error!("error occurred: {}", e);
    }

    Ok(())
}
<|endoftext|>


<commit_before>extern crate herder;
extern crate serde_json;

use herder::api::v1::{
    Application,
    Attachment,
    Card
};

#[test]
fn account_deserialize_from_json() {
    let ojson = r#"{
                    "name": "MYNAME",
                    "website": "MYURI"
                 }"#;
    let application: Application = serde_json::from_str(ojson).unwrap();
    assert_eq!(application, Application {
                        name: String::from("MYNAME"),
                        website: Some(String::from("MYURI"))
    });
}

#[test]
fn attachment_deserialize_from_json() {
    let ojson = r#"{
                    "id": 1234,
                    "type": "video",
                    "url": "MYURL",
                    "remote_url": "MYURL",
                    "preview_url": "MYURL",
                    "text_url": "MYURL"
                 }"#;
    let attachment: Attachment = serde_json::from_str(ojson).unwrap();
    assert_eq!(attachment, Attachment {
                        attachment_id: 1234,
                        attachment_type: String::from("video"),
                        url: String::from("MYURL"),
                        remote_url: String::from("MYURL"),
                        preview_url: String::from("MYURL"),
                        text_url: String::from("MYURL")
    });
}

#[test]
fn card_deserialize_from_json() {
    let ojson = r#"{
                    "url": "MYURL",
                    "title": "My Title",
                    "description": "My description",
                    "image": "MYIMG.png"
                 }"#;
    let card: Card = serde_json::from_str(ojson).unwrap();
    assert_eq!(card, Card {
                        url: String::from("MYURL"),
                        title: String::from("My Title"),
                        description: String::from("My description"),
                        image: String::from("MYIMG.png")
    });
}
<commit_msg>setup to test all api entities json deserialization<commit_after>extern crate herder;
extern crate serde_json;

use herder::api::v1::{
    Application,
    Attachment,
    Card,
    Context,
    Error,
    Instance,
    Mention,
    Notification,
    Relationship,
    Report,
    Results,
    Status,
    Tag
};

#[test]
fn account_deserialize_from_json() {
    let ojson = r#"{
                    "name": "MYNAME",
                    "website": "MYURI"
                 }"#;
    let application: Application = serde_json::from_str(ojson).unwrap();
    assert_eq!(application, Application {
                        name: String::from("MYNAME"),
                        website: Some(String::from("MYURI"))
    });
}

#[test]
fn attachment_deserialize_from_json() {
    let ojson = r#"{
                    "id": 1234,
                    "type": "video",
                    "url": "MYURL",
                    "remote_url": "MYURL",
                    "preview_url": "MYURL",
                    "text_url": "MYURL"
                 }"#;
    let attachment: Attachment = serde_json::from_str(ojson).unwrap();
    assert_eq!(attachment, Attachment {
                        attachment_id: 1234,
                        attachment_type: String::from("video"),
                        url: String::from("MYURL"),
                        remote_url: String::from("MYURL"),
                        preview_url: String::from("MYURL"),
                        text_url: String::from("MYURL")
    });
}

#[test]
fn card_deserialize_from_json() {
    let ojson = r#"{
                    "url": "MYURL",
                    "title": "My Title",
                    "description": "My description",
                    "image": "MYIMG.png"
                 }"#;
    let card: Card = serde_json::from_str(ojson).unwrap();
    assert_eq!(card, Card {
                        url: String::from("MYURL"),
                        title: String::from("My Title"),
                        description: String::from("My description"),
                        image: String::from("MYIMG.png")
    });
}

#[test]
fn context_deserialize_from_json() {
    unimplemented!();
}

#[test]
fn error_deserialize_from_json() {
    let ojson = r#"{
                    "error": "Error message"
                 }"#;
    let error: Error = serde_json::from_str(ojson).unwrap();
    assert_eq!(error, Error {
                        error: String::from("Error message")
    });
}
<|endoftext|>


<commit_before>use cocoa::base::{id, nil};
use cocoa::foundation::{NSString, NSUInteger};
use core_foundation::base::TCFType;
use core_foundation::number::CFNumber;
use core_foundation::string::CFString;
use objc::runtime::BOOL;
use objc_bringup::NSDictionary;
use std::collections::HashMap;
use std::convert::{From, Into};
use std::default::Default;
use sys::{MTLCompileOptions, MTLLanguageVersion};

#[derive(Clone, Debug, Default, PartialEq)]
pub struct CompileOptions {
    /// Is fast math enabled. Set this option to `None` to use the system default setting.
    pub fast_math_enabled: Option<bool>,

    /// The language version used. Either use the latest by default, or set this to a specific
    /// version.
    pub language_version: LanguageVersion,

    /// A map of preprocessor macro names to values. Each entry of (`MacroName`, `MacroValue`) corresponds
    /// to `#define MacroName MacroValue`
    pub preprocessor_macros: HashMap<String, PreprocessorMacroValue>
}

impl CompileOptions {
    pub fn fast_math_enabled(self, fast_math: bool) -> Self {
        let opts = CompileOptions { fast_math_enabled: Some(fast_math), .. self };
        opts
    }

    pub fn language_version(self, language_version: LanguageVersion) -> Self {
        let opts = CompileOptions { language_version: language_version, .. self };
        opts
    }

    pub fn with_macro<S: Into<String>>(mut self, mac_name: S, mac_val: PreprocessorMacroValue) -> Self {
        self.preprocessor_macros.insert(mac_name.into(), mac_val);
        self
    }

    pub fn with_floating_macro<S: Into<String>>(mut self, mac_name: S, mac_val: f64) -> Self {
        self.preprocessor_macros.insert(mac_name.into(), PreprocessorMacroValue::Floating(mac_val));
        self
    }

    pub fn with_integer_macro<S: Into<String>>(mut self, mac_name: S, mac_val: i64) -> Self {
        self.preprocessor_macros.insert(mac_name.into(), PreprocessorMacroValue::Integral(mac_val));
        self
    }

    pub fn with_string_macro<S0: Into<String>, S1: Into<String>>(mut self, mac_name: S0, mac_val: S1) -> Self {
        self.preprocessor_macros.insert(mac_name.into(), PreprocessorMacroValue::String(mac_val.into()));
        self
    }

    pub fn mtl_compile_options(&self) -> id {
        unsafe {
            let ll_compile_opts = MTLCompileOptions::new(nil);

            if let Some(fast_math_enabled) = self.fast_math_enabled {
                ll_compile_opts.setFastMathEnabled(fast_math_enabled as BOOL);
            }

            if let LanguageVersion::Specific(version) = self.language_version {
                ll_compile_opts.setLanguageVersion(version.into());
            }

            if !self.preprocessor_macros.is_empty() {
                let mut keys = self.preprocessor_macros
                                   .keys()
                                   .map(|k| NSString::alloc(nil).init_str(k.as_ref()))
                                   .collect::<Vec<_>>();

                let mut objs =
                    self.preprocessor_macros
                        .values()
                        .map(|v| {
                            match v {
                                &PreprocessorMacroValue::Floating(f) => {
                                    CFNumber::from_f64(f).as_CFTypeRef() as id
                                }
                                &PreprocessorMacroValue::Integral(i) => {
                                    CFNumber::from_i64(i).as_CFTypeRef() as id
                                }
                                &PreprocessorMacroValue::String(ref s) => {
                                    CFString::new(s.as_ref()).as_CFTypeRef() as id
                                }
                            }
                        })
                        .collect::<Vec<_>>();

                let num_macros = self.preprocessor_macros.len() as NSUInteger;

                let macros = NSDictionary::dictionaryWithObjects_forKeys_count(objs.as_mut_ptr(),
                                                                               keys.as_mut_ptr(),
                                                                               num_macros);
                ll_compile_opts.setPreprocessorMacros(macros);
            }

            ll_compile_opts
        }
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum LanguageVersion {
    Latest,
    Specific(SpecificLanguageVersion)
}

impl Default for LanguageVersion {
    fn default() -> Self {
        LanguageVersion::Latest
    }
}

/// Used to choose a specific version of the Metal shader language to use
// An underscore is a good separator for numbers
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum SpecificLanguageVersion {
    /// Version 1.0
    Version_1_0,

    /// Version 1.1
    Version_1_1
}

impl From<MTLLanguageVersion> for SpecificLanguageVersion {
    fn from(language_version: MTLLanguageVersion) -> Self {
        match language_version {
            MTLLanguageVersion::MTLLanguageVersion1_0 => SpecificLanguageVersion::Version_1_0,
            MTLLanguageVersion::MTLLanguageVersion1_1 => SpecificLanguageVersion::Version_1_1,
        }
    }
}

impl Into<MTLLanguageVersion> for SpecificLanguageVersion {
    fn into(self) -> MTLLanguageVersion {
        match self {
            SpecificLanguageVersion::Version_1_0 => MTLLanguageVersion::MTLLanguageVersion1_0,
            SpecificLanguageVersion::Version_1_1 => MTLLanguageVersion::MTLLanguageVersion1_1,
        }
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum PreprocessorMacroValue {
    Floating(f64),
    Integral(i64),
    String(String)
}
<commit_msg>Rename PreprocessorMacroValue::Integral to PreprocessorMacroValue::Integer<commit_after>use cocoa::base::{id, nil};
use cocoa::foundation::{NSString, NSUInteger};
use core_foundation::base::TCFType;
use core_foundation::number::CFNumber;
use core_foundation::string::CFString;
use objc::runtime::BOOL;
use objc_bringup::NSDictionary;
use std::collections::HashMap;
use std::convert::{From, Into};
use std::default::Default;
use sys::{MTLCompileOptions, MTLLanguageVersion};

#[derive(Clone, Debug, Default, PartialEq)]
pub struct CompileOptions {
    /// Is fast math enabled. Set this option to `None` to use the system default setting.
    pub fast_math_enabled: Option<bool>,

    /// The language version used. Either use the latest by default, or set this to a specific
    /// version.
    pub language_version: LanguageVersion,

    /// A map of preprocessor macro names to values. Each entry of (`MacroName`, `MacroValue`) corresponds
    /// to `#define MacroName MacroValue`
    pub preprocessor_macros: HashMap<String, PreprocessorMacroValue>
}

impl CompileOptions {
    pub fn fast_math_enabled(self, fast_math: bool) -> Self {
        let opts = CompileOptions { fast_math_enabled: Some(fast_math), .. self };
        opts
    }

    pub fn language_version(self, language_version: LanguageVersion) -> Self {
        let opts = CompileOptions { language_version: language_version, .. self };
        opts
    }

    pub fn with_macro<S: Into<String>>(mut self, mac_name: S, mac_val: PreprocessorMacroValue) -> Self {
        self.preprocessor_macros.insert(mac_name.into(), mac_val);
        self
    }

    pub fn with_floating_macro<S: Into<String>>(mut self, mac_name: S, mac_val: f64) -> Self {
        self.preprocessor_macros.insert(mac_name.into(), PreprocessorMacroValue::Floating(mac_val));
        self
    }

    pub fn with_integer_macro<S: Into<String>>(mut self, mac_name: S, mac_val: i64) -> Self {
        self.preprocessor_macros.insert(mac_name.into(), PreprocessorMacroValue::Integer(mac_val));
        self
    }

    pub fn with_string_macro<S0: Into<String>, S1: Into<String>>(mut self, mac_name: S0, mac_val: S1) -> Self {
        self.preprocessor_macros.insert(mac_name.into(), PreprocessorMacroValue::String(mac_val.into()));
        self
    }

    pub fn mtl_compile_options(&self) -> id {
        unsafe {
            let ll_compile_opts = MTLCompileOptions::new(nil);

            if let Some(fast_math_enabled) = self.fast_math_enabled {
                ll_compile_opts.setFastMathEnabled(fast_math_enabled as BOOL);
            }

            if let LanguageVersion::Specific(version) = self.language_version {
                ll_compile_opts.setLanguageVersion(version.into());
            }

            if !self.preprocessor_macros.is_empty() {
                let mut keys = self.preprocessor_macros
                                   .keys()
                                   .map(|k| NSString::alloc(nil).init_str(k.as_ref()))
                                   .collect::<Vec<_>>();

                let mut objs =
                    self.preprocessor_macros
                        .values()
                        .map(|v| {
                            match v {
                                &PreprocessorMacroValue::Floating(f) => {
                                    CFNumber::from_f64(f).as_CFTypeRef() as id
                                }
                                &PreprocessorMacroValue::Integer(i) => {
                                    CFNumber::from_i64(i).as_CFTypeRef() as id
                                }
                                &PreprocessorMacroValue::String(ref s) => {
                                    CFString::new(s.as_ref()).as_CFTypeRef() as id
                                }
                            }
                        })
                        .collect::<Vec<_>>();

                let num_macros = self.preprocessor_macros.len() as NSUInteger;

                let macros = NSDictionary::dictionaryWithObjects_forKeys_count(objs.as_mut_ptr(),
                                                                               keys.as_mut_ptr(),
                                                                               num_macros);
                ll_compile_opts.setPreprocessorMacros(macros);
            }

            ll_compile_opts
        }
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum LanguageVersion {
    Latest,
    Specific(SpecificLanguageVersion)
}

impl Default for LanguageVersion {
    fn default() -> Self {
        LanguageVersion::Latest
    }
}

/// Used to choose a specific version of the Metal shader language to use
// An underscore is a good separator for numbers
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum SpecificLanguageVersion {
    /// Version 1.0
    Version_1_0,

    /// Version 1.1
    Version_1_1
}

impl From<MTLLanguageVersion> for SpecificLanguageVersion {
    fn from(language_version: MTLLanguageVersion) -> Self {
        match language_version {
            MTLLanguageVersion::MTLLanguageVersion1_0 => SpecificLanguageVersion::Version_1_0,
            MTLLanguageVersion::MTLLanguageVersion1_1 => SpecificLanguageVersion::Version_1_1,
        }
    }
}

impl Into<MTLLanguageVersion> for SpecificLanguageVersion {
    fn into(self) -> MTLLanguageVersion {
        match self {
            SpecificLanguageVersion::Version_1_0 => MTLLanguageVersion::MTLLanguageVersion1_0,
            SpecificLanguageVersion::Version_1_1 => MTLLanguageVersion::MTLLanguageVersion1_1,
        }
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum PreprocessorMacroValue {
    Floating(f64),
    Integer(i64),
    String(String)
}
<|endoftext|>


<commit_before>#![feature(collections)] // for escape_default()
extern crate zaldinar_core;

use std::borrow::Cow;

use zaldinar_core::client::PluginRegister;
use zaldinar_core::events::CommandEvent;

const MAX_ITERATIONS: u32 = 134217728u32;
const MAX_OUTPUT: usize = 256usize;

#[derive(Debug)]
enum Instruction {
    /// Increment the memory pointer by one
    MoveRight,
    /// Decrement the memory pointer by one
    MoveLeft,
    /// Increment the memory value at the memory pointer by one
    Increment,
    /// Decrement the memory value at the memory pointer by one
    Decrement,
    /// Output the value of the current memory pointer as a char
    Output,
    /// This is the left side of a loop.
    /// If the memory value at the memory pointer is zero, set the next instruction to the
    /// contained value.
    JumpToLeft(usize),
    /// This is the right side of a loop.
    /// If the memory value at the memory pointer is non-zero, set the next instruction to the
    /// contained value.
    JumpToRight(usize),
}

fn parse_instructions(event: &CommandEvent) -> Result<Vec<Instruction>, Cow<'static, str>> {
    // Vec of opening jumps waiting for a closing jump to find
    // each u16 is a position in the instructions vec.
    let mut waiting_opening_jumps = Vec::new();
    let mut instructions = Vec::new();
    let mut current_parsing_position = 0u64;
    for arg in &event.args {
        for c in arg.chars() {
            current_parsing_position += 1;
            let instruction = match c {
                '>' => Instruction::MoveRight,
                '<' => Instruction::MoveLeft,
                '+' => Instruction::Increment,
                '-' => Instruction::Decrement,
                '.' => Instruction::Output,
                ',' => {
                    return Err(Cow::Owned(format!("Error: Unsupported command `,` found at \
                        position {}.", current_parsing_position)));
                },
                '[' => {
                    // instructions.len() is the position where JumpTo is going to end up
                    waiting_opening_jumps.push(instructions.len());
                    // This is a placeholder, this is guaranteed to be replaced when the
                    // corresponding `]` is found.
                    Instruction::JumpToLeft(0usize)
                },
                ']' => {
                    match waiting_opening_jumps.pop() {
                        Some(left_jump) => {
                            // instructions.len() is the position where the right JumpTo
                            instructions[left_jump] = Instruction::JumpToLeft(instructions.len());
                            Instruction::JumpToRight(left_jump)
                        },
                        None => {
                            return Err(Cow::Owned(format!("Error: Unbalanced `]` found at \
                                position {}, no matching `[` found.", current_parsing_position)));
                        }
                    }
                },
                _ => continue, // treat invalid characters as comments
            };
            instructions.push(instruction);
        }
        current_parsing_position += 1; // because each argument was originally separated by a space
    }

    if !waiting_opening_jumps.is_empty() {
        return Err(Cow::Borrowed("Error: Unbalanced `[`, no matching `]` found."));
    }

    return Ok(instructions);
}

fn brainfuck(event: &CommandEvent) {
    let instructions = match parse_instructions(event) {
        Ok(instructions) => instructions,
        Err(e) => {
            event.client.send_message(event.channel(), e);
            return;
        }
    };

    // Program memory, max size is 2^15
    let mut memory = [0u8; 32768];
    // Current position in memory
    let mut memory_position = 0u16;
    // Next instruction to run
    let mut next_instruction = 0usize;
    // Output string buffer
    let mut output = String::new();
    // Whether or not we finished cleanly (if false, output error for maximum iterations reached)
    let mut done = false;

    // u32::MAX as a limit to the number of iterations to run for a single program.
    for _ in 0..MAX_ITERATIONS {
        if next_instruction >= instructions.len() {
            done = true;
            break;
        }
        match instructions[next_instruction] {
            Instruction::MoveRight => {
                memory_position += 1;
                memory_position %= 32768;
            },
            Instruction::MoveLeft => {
                memory_position -= 1;
                memory_position %= 32768;
            },
            Instruction::Increment => memory[memory_position as usize] += 1,
            Instruction::Decrement => memory[memory_position as usize] -= 1,
            Instruction::Output => {
                output.push(memory[memory_position as usize] as char);

                if output.len() > MAX_OUTPUT {
                    event.client.send_message(event.channel(),
                            "Reached maximum output length. (256)");
                    done = true;
                    break;
                }
            },
            Instruction::JumpToLeft(target_position) => {
                if memory[memory_position as usize] == 0 {
                    next_instruction = target_position;
                    continue; // this avoids the automatic incrementing of next_instruction below.
                }
            },
            Instruction::JumpToRight(target_position) => {
                if memory[memory_position as usize] != 0 {
                    next_instruction = target_position;
                    continue; // this avoids the automatic incrementing of next_instruction below.
                }
            },
        }
        next_instruction += 1;
    }

    if !done {
        event.client.send_message(event.channel(), "Reached maximum iterations. (134217728)");
    }

    if output.is_empty() {
        event.client.send_message(event.channel(), "No output produced.");
    } else {
        event.client.send_message(event.channel(), format!("Output: {}", output.escape_default()));
    }
}

pub fn register(register: &mut PluginRegister) {
    register.register_command("brainfuck", brainfuck);
}
<commit_msg>Update brainfuck plugin to an error enum for error handling<commit_after>#![feature(collections)] // for str.escape_default()
extern crate zaldinar_core;

use std::fmt;

use zaldinar_core::client::PluginRegister;
use zaldinar_core::events::CommandEvent;

const MAX_ITERATIONS: u32 = 134217728u32;
const MAX_OUTPUT: usize = 256usize;

#[derive(Debug)]
pub enum Error {
    /// A right bracket was found with no unmatched left brackets preceding it.
    UnbalancedRightBracket,
    /// The input ended before right brackets were found to match all left brackets.
    UnbalancedLeftBracket,
    /// `,` is unsupported
    CommaUnsupported,
}

impl fmt::Display for Error {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self {
            &Error::UnbalancedRightBracket => {
                write!(formatter, "Expected matching `[` before `]`, found lone `]` first.")
            },
            &Error::UnbalancedLeftBracket => {
                write!(formatter, "Unbalanced `[`. Expected matching `]`, found end of file.")
            },
            &Error::CommaUnsupported => {
                write!(formatter, "Unsupported command: `,`.")
            }
        }
    }
}

#[derive(Debug)]
enum Instruction {
    /// Increment the memory pointer by one
    MoveRight,
    /// Decrement the memory pointer by one
    MoveLeft,
    /// Increment the memory value at the memory pointer by one
    Increment,
    /// Decrement the memory value at the memory pointer by one
    Decrement,
    /// Output the value of the current memory pointer as a char
    Output,
    /// This is the left side of a loop.
    /// If the memory value at the memory pointer is zero, set the next instruction to the
    /// contained value.
    JumpToLeft(usize),
    /// This is the right side of a loop.
    /// If the memory value at the memory pointer is non-zero, set the next instruction to the
    /// contained value.
    JumpToRight(usize),
}

fn parse_instructions(event: &CommandEvent) -> Result<Vec<Instruction>, Error> {
    // Vec of opening jumps waiting for a closing jump to find
    // each u16 is a position in the instructions vec.
    let mut waiting_opening_jumps = Vec::new();
    let mut instructions = Vec::new();

    for arg in &event.args {
        for c in arg.chars() {
            let instruction = match c {
                '>' => Instruction::MoveRight,
                '<' => Instruction::MoveLeft,
                '+' => Instruction::Increment,
                '-' => Instruction::Decrement,
                '.' => Instruction::Output,
                ',' => {
                    return Err(Error::CommaUnsupported);
                },
                '[' => {
                    // instructions.len() is the position where JumpTo is going to end up
                    waiting_opening_jumps.push(instructions.len());
                    // This is a placeholder, this is guaranteed to be replaced when the
                    // corresponding `]` is found.
                    Instruction::JumpToLeft(0usize)
                },
                ']' => {
                    match waiting_opening_jumps.pop() {
                        Some(left_jump) => {
                            // instructions.len() is the position where the right JumpTo
                            instructions[left_jump] = Instruction::JumpToLeft(instructions.len());
                            Instruction::JumpToRight(left_jump)
                        },
                        None => {
                            return Err(Error::UnbalancedRightBracket);
                        }
                    }
                },
                _ => continue, // treat invalid characters as comments
            };
            instructions.push(instruction);
        }
    }

    if !waiting_opening_jumps.is_empty() {
        return Err(Error::UnbalancedLeftBracket);
    }

    return Ok(instructions);
}

fn brainfuck(event: &CommandEvent) {
    let instructions = match parse_instructions(event) {
        Ok(instructions) => instructions,
        Err(e) => {
            event.client.send_message(event.channel(), format!("Error: {}", e));
            return;
        }
    };

    // Program memory, max size is 2^15
    let mut memory = [0u8; 32768];
    // Current position in memory
    let mut memory_position = 0u16;
    // Next instruction to run
    let mut next_instruction = 0usize;
    // Output string buffer
    let mut output = String::new();
    // Whether or not we finished cleanly (if false, output error for maximum iterations reached)
    let mut done = false;

    // u32::MAX as a limit to the number of iterations to run for a single program.
    for _ in 0..MAX_ITERATIONS {
        if next_instruction >= instructions.len() {
            done = true;
            break;
        }
        match instructions[next_instruction] {
            Instruction::MoveRight => {
                memory_position += 1;
                memory_position %= 32768;
            },
            Instruction::MoveLeft => {
                memory_position -= 1;
                memory_position %= 32768;
            },
            Instruction::Increment => memory[memory_position as usize] += 1,
            Instruction::Decrement => memory[memory_position as usize] -= 1,
            Instruction::Output => {
                output.push(memory[memory_position as usize] as char);

                if output.len() > MAX_OUTPUT {
                    event.client.send_message(event.channel(),
                            "Reached maximum output length. (256)");
                    done = true;
                    break;
                }
            },
            Instruction::JumpToLeft(target_position) => {
                if memory[memory_position as usize] == 0 {
                    next_instruction = target_position;
                    continue; // this avoids the automatic incrementing of next_instruction below.
                }
            },
            Instruction::JumpToRight(target_position) => {
                if memory[memory_position as usize] != 0 {
                    next_instruction = target_position;
                    continue; // this avoids the automatic incrementing of next_instruction below.
                }
            },
        }
        next_instruction += 1;
    }

    if !done {
        event.client.send_message(event.channel(), "Reached maximum iterations. (134217728)");
    }

    if output.is_empty() {
        event.client.send_message(event.channel(), "No output produced.");
    } else {
        event.client.send_message(event.channel(), format!("Output: {}", output.escape_default()));
    }
}

pub fn register(register: &mut PluginRegister) {
    register.register_command("brainfuck", brainfuck);
}
<|endoftext|>


<commit_before>use definitions::program::{Instruction, Program, Target, Value};
use definitions::typedef::*;
use error::*;

const STACK_COUNT: usize = 2;
const REGISTER_COUNT: usize = 4;

#[derive(PartialEq)]
enum CompareResult {
    LowerThan,
    GreaterThan,
    Equal,
    None,
}

/// The whole state of the VM
pub struct VM {
    image_data: Vec<Instruction>,
    pc: Address,
    data_stacks: [Vec<Value>; STACK_COUNT],
    data_registers: [Value; REGISTER_COUNT],
    compare_result: CompareResult,
    call_stack: Vec<Address>,
    skip_advance: bool,
}

impl VM {
    /// Creates a new VM state for executing programs
    pub fn new() -> VM {
        VM {
            image_data: Vec::new(),
            pc: 0,
            data_stacks: [Vec::new(), Vec::new()],
            data_registers: [Value::Nil, Value::Nil, Value::Nil, Value::Nil],
            compare_result: CompareResult::None,
            call_stack: Vec::new(),
            skip_advance: false,
        }
    }

    // # Maintainance functions

    /// Executes te given program
    pub fn exec(&mut self, program: Program) -> VMResult<()> {
        self.reset();
        self.load_program(program);

        while self.pc < self.image_data.len() {
            let current_instruction = self.image_data[self.pc].clone();

            match current_instruction {
                Instruction::Halt => break,
                Instruction::Add(dest, src) => self.add(dest, src)?,
                Instruction::Sub(dest, src) => self.sub(dest, src)?,
                Instruction::Div(dest, src) => self.div(dest, src)?,
                Instruction::Mul(dest, src) => self.mul(dest, src)?,
                Instruction::Mod(dest, src) => self.modulo(dest, src)?,

                Instruction::Cmp(target_a, target_b) => self.cmp(target_a, target_b)?,
                Instruction::Jmp(addr) => self.jmp(addr),
                Instruction::JmpLt(addr) => self.jmp_lt(addr),
                Instruction::JmpGt(addr) => self.jmp_gt(addr),
                Instruction::JmpEq(addr) => self.jmp_eq(addr),

                Instruction::Push(dest, value) => self.push(dest, value),
                Instruction::Mov(dest, src) => self.mov(dest, src)?,
                Instruction::Swp(target_a, target_b) => self.swp(target_a, target_b)?,

                Instruction::Call(addr) => self.call(addr),
                Instruction::Ret => self.ret()?,
            }

            self.advance_pc();
        }

        Ok(())
    }

    /// Loads the instructions of the given program to the VM's state
    fn load_program(&mut self, program: Program) {
        self.image_data = program.instructions;
    }

    /// Resets the VM to a clean state
    fn reset(&mut self) {
        *self = VM::new();
    }

    fn reset_cmp(&mut self) {
        self.compare_result = CompareResult::None;
    }

    /// Advances the program counter
    fn advance_pc(&mut self) {
        if !self.skip_advance {
            self.pc += 1;
        } else {
            self.skip_advance = false;
        }
    }

    /// Return the value at the specified target. The value will be consumed
    /// from the target.
    fn pop(&mut self, target: &Target) -> VMResult<Value> {
        match target {
            &Target::Register(index) => {
                let value = self.data_registers[index].clone();
                self.data_registers[index] = Value::Nil;

                Ok(value)
            }
            &Target::Stack(index) => {
                if let Some(value) = self.data_stacks[index].pop() {
                    Ok(value)
                } else {
                    bail!("unable to pop value off an empty stack");
                }
            }
        }
    }

    // # Instruction functions

    /// Adds the value of the src target to the value of the dest target
    fn add(&mut self, dest: Target, src: Target) -> VMResult<()> {
        let dest_value = self.pop(&dest)?;
        let src_value = self.pop(&src)?;

        self.push(dest, dest_value + src_value);

        Ok(())
    }

    /// Subtracts the value of the src target from the value of the dest target
    fn sub(&mut self, dest: Target, src: Target) -> VMResult<()> {
        let dest_value = self.pop(&dest)?;
        let src_value = self.pop(&src)?;

        self.push(dest, dest_value - src_value);

        Ok(())
    }

    /// Divides the value of the dest target through the value of the src target
    fn div(&mut self, dest: Target, src: Target) -> VMResult<()> {
        let dest_value = self.pop(&dest)?;
        let src_value = self.pop(&src)?;

        self.push(dest, dest_value / src_value);

        Ok(())
    }

    /// Multiplies the value of the dest target with the value of the src target
    fn mul(&mut self, dest: Target, src: Target) -> VMResult<()> {
        let dest_value = self.pop(&dest)?;
        let src_value = self.pop(&src)?;

        self.push(dest, dest_value * src_value);

        Ok(())
    }

    /// Applies the modulo operator on the value of the dest target using the
    /// value of the src target
    fn modulo(&mut self, dest: Target, src: Target) -> VMResult<()> {
        let dest_value = self.pop(&dest)?;
        let src_value = self.pop(&src)?;

        self.push(dest, dest_value * src_value);

        Ok(())
    }

    /// Compares the top values of the two targets and saves the result to
    /// `self.compare_result`
    fn cmp(&mut self, target_a: Target, target_b: Target) -> VMResult<()> {
        self.reset_cmp();

        let target_a_value = self.pop(&target_a)?;
        let target_b_value = self.pop(&target_b)?;

        if target_a_value < target_b_value {
            self.compare_result = CompareResult::LowerThan;
        } else if target_a_value > target_b_value {
            self.compare_result = CompareResult::GreaterThan;
        } else if target_a_value == target_b_value {
            self.compare_result = CompareResult::Equal;
        }

        Ok(())
    }

    /// Jumps unconditionally to the specified address
    fn jmp(&mut self, addr: Address) {
        self.pc = addr;
        self.skip_advance = true;
    }

    /// Jumps if the last compare got the result `CompareResult::LowerThan`
    fn jmp_lt(&mut self, addr: Address) {
        if self.compare_result == CompareResult::LowerThan {
            self.jmp(addr);
            self.reset_cmp();
        }
    }

    /// Jumps if the last compare got the result `CompareResult::GreaterThan`
    fn jmp_gt(&mut self, addr: Address) {
        if self.compare_result == CompareResult::GreaterThan {
            self.jmp(addr);
            self.reset_cmp();
        }
    }

    /// Jumps if the last compare got the result `CompareResult::Equal`
    fn jmp_eq(&mut self, addr: Address) {
        if self.compare_result == CompareResult::Equal {
            self.jmp(addr);
            self.reset_cmp();
        }
    }

    /// Pushes the given value to the given target
    fn push(&mut self, dest: Target, value: Value) {
        match dest {
            Target::Register(index) => self.data_registers[index] = value,
            Target::Stack(index) => self.data_stacks[index].push(value),
        }
    }

    /// Moves the top value of the src target to the dest target
    fn mov(&mut self, dest: Target, src: Target) -> VMResult<()> {
        let src_value = self.pop(&src)?;
        self.push(dest, src_value);

        Ok(())
    }

    /// Swaps the top values of the targets
    fn swp(&mut self, target_a: Target, target_b: Target) -> VMResult<()> {
        let a_value = self.pop(&target_a)?;
        let b_value = self.pop(&target_b)?;

        self.push(target_a, b_value);
        self.push(target_b, a_value);

        Ok(())
    }

    /// Calls the function at the specified address saving the return address
    /// to the call stack
    fn call(&mut self, addr: Address) {
        self.call_stack.push(self.pc + 1);
        self.jmp(addr);
    }

    /// Returns from an ongoing function call
    fn ret(&mut self) -> VMResult<()> {
        if self.call_stack.is_empty() {
            bail!("unable to return from an empty call stack");
        }

        let retur_addr = self.call_stack.pop().unwrap();

        self.jmp(retur_addr);

        Ok(())
    }
}
<commit_msg>Adjusted cmp result to hold native Ordering value<commit_after>use definitions::program::{Instruction, Program, Target, Value};
use definitions::typedef::*;
use error::*;
use std::cmp::Ordering;

const STACK_COUNT: usize = 2;
const REGISTER_COUNT: usize = 4;

/// The whole state of the VM
pub struct VM {
    image_data: Vec<Instruction>,
    pc: Address,
    data_stacks: [Vec<Value>; STACK_COUNT],
    data_registers: [Value; REGISTER_COUNT],
    cmp_reg: Option<Ordering>,
    call_stack: Vec<Address>,
    skip_advance: bool,
}

impl VM {
    /// Creates a new VM state for executing programs
    pub fn new() -> VM {
        VM {
            image_data: Vec::new(),
            pc: 0,
            data_stacks: [Vec::new(), Vec::new()],
            data_registers: [Value::Nil, Value::Nil, Value::Nil, Value::Nil],
            cmp_reg: None,
            call_stack: Vec::new(),
            skip_advance: false,
        }
    }

    // # Maintainance functions

    /// Executes te given program
    pub fn exec(&mut self, program: Program) -> VMResult<()> {
        self.reset();
        self.load_program(program);

        while self.pc < self.image_data.len() {
            let current_instruction = self.image_data[self.pc].clone();

            match current_instruction {
                Instruction::Halt => break,
                Instruction::Add(dest, src) => self.add(dest, src)?,
                Instruction::Sub(dest, src) => self.sub(dest, src)?,
                Instruction::Div(dest, src) => self.div(dest, src)?,
                Instruction::Mul(dest, src) => self.mul(dest, src)?,
                Instruction::Mod(dest, src) => self.modulo(dest, src)?,

                Instruction::Cmp(target_a, target_b) => self.cmp(target_a, target_b)?,
                Instruction::Jmp(addr) => self.jmp(addr),
                Instruction::JmpLt(addr) => self.jmp_lt(addr),
                Instruction::JmpGt(addr) => self.jmp_gt(addr),
                Instruction::JmpEq(addr) => self.jmp_eq(addr),

                Instruction::Push(dest, value) => self.push(dest, value),
                Instruction::Mov(dest, src) => self.mov(dest, src)?,
                Instruction::Swp(target_a, target_b) => self.swp(target_a, target_b)?,

                Instruction::Call(addr) => self.call(addr),
                Instruction::Ret => self.ret()?,
            }

            self.advance_pc();
        }

        Ok(())
    }

    /// Loads the instructions of the given program to the VM's state
    fn load_program(&mut self, program: Program) {
        self.image_data = program.instructions;
    }

    /// Resets the VM to a clean state
    fn reset(&mut self) {
        *self = VM::new();
    }

    fn reset_cmp(&mut self) {
        self.cmp_reg = None;
    }

    /// Advances the program counter
    fn advance_pc(&mut self) {
        if !self.skip_advance {
            self.pc += 1;
        } else {
            self.skip_advance = false;
        }
    }

    /// Return the value at the specified target. The value will be consumed
    /// from the target.
    fn pop(&mut self, target: &Target) -> VMResult<Value> {
        match target {
            &Target::Register(index) => {
                let value = self.data_registers[index].clone();
                self.data_registers[index] = Value::Nil;

                Ok(value)
            }
            &Target::Stack(index) => {
                if let Some(value) = self.data_stacks[index].pop() {
                    Ok(value)
                } else {
                    bail!("unable to pop value off an empty stack");
                }
            }
        }
    }

    // # Instruction functions

    /// Adds the value of the src target to the value of the dest target
    fn add(&mut self, dest: Target, src: Target) -> VMResult<()> {
        let dest_value = self.pop(&dest)?;
        let src_value = self.pop(&src)?;

        self.push(dest, dest_value + src_value);

        Ok(())
    }

    /// Subtracts the value of the src target from the value of the dest target
    fn sub(&mut self, dest: Target, src: Target) -> VMResult<()> {
        let dest_value = self.pop(&dest)?;
        let src_value = self.pop(&src)?;

        self.push(dest, dest_value - src_value);

        Ok(())
    }

    /// Divides the value of the dest target through the value of the src target
    fn div(&mut self, dest: Target, src: Target) -> VMResult<()> {
        let dest_value = self.pop(&dest)?;
        let src_value = self.pop(&src)?;

        self.push(dest, dest_value / src_value);

        Ok(())
    }

    /// Multiplies the value of the dest target with the value of the src target
    fn mul(&mut self, dest: Target, src: Target) -> VMResult<()> {
        let dest_value = self.pop(&dest)?;
        let src_value = self.pop(&src)?;

        self.push(dest, dest_value * src_value);

        Ok(())
    }

    /// Applies the modulo operator on the value of the dest target using the
    /// value of the src target
    fn modulo(&mut self, dest: Target, src: Target) -> VMResult<()> {
        let dest_value = self.pop(&dest)?;
        let src_value = self.pop(&src)?;

        self.push(dest, dest_value * src_value);

        Ok(())
    }

    /// Compares the top values of the two targets and saves the result to
    /// `self.cmp_reg`
    fn cmp(&mut self, target_a: Target, target_b: Target) -> VMResult<()> {
        self.reset_cmp();

        let target_a_value = self.pop(&target_a)?;
        let target_b_value = self.pop(&target_b)?;

        if target_a_value < target_b_value {
            self.cmp_reg = Some(Ordering::Less);
        } else if target_a_value > target_b_value {
            self.cmp_reg = Some(Ordering::Greater);
        } else if target_a_value == target_b_value {
            self.cmp_reg = Some(Ordering::Equal);
        }

        Ok(())
    }

    /// Jumps unconditionally to the specified address
    fn jmp(&mut self, addr: Address) {
        self.pc = addr;
        self.skip_advance = true;
    }

    /// Jumps if the last compare got the result `Some(Ordering::Less)`
    fn jmp_lt(&mut self, addr: Address) {
        if self.cmp_reg == Some(Ordering::Less) {
            self.jmp(addr);
            self.reset_cmp();
        }
    }

    /// Jumps if the last compare got the result `Some(Ordering::Greater)`
    fn jmp_gt(&mut self, addr: Address) {
        if self.cmp_reg == Some(Ordering::Greater) {
            self.jmp(addr);
            self.reset_cmp();
        }
    }

    /// Jumps if the last compare got the result `Some(Ordering::Equal)`
    fn jmp_eq(&mut self, addr: Address) {
        if self.cmp_reg == Some(Ordering::Equal) {
            self.jmp(addr);
            self.reset_cmp();
        }
    }

    /// Pushes the given value to the given target
    fn push(&mut self, dest: Target, value: Value) {
        match dest {
            Target::Register(index) => self.data_registers[index] = value,
            Target::Stack(index) => self.data_stacks[index].push(value),
        }
    }

    /// Moves the top value of the src target to the dest target
    fn mov(&mut self, dest: Target, src: Target) -> VMResult<()> {
        let src_value = self.pop(&src)?;
        self.push(dest, src_value);

        Ok(())
    }

    /// Swaps the top values of the targets
    fn swp(&mut self, target_a: Target, target_b: Target) -> VMResult<()> {
        let a_value = self.pop(&target_a)?;
        let b_value = self.pop(&target_b)?;

        self.push(target_a, b_value);
        self.push(target_b, a_value);

        Ok(())
    }

    /// Calls the function at the specified address saving the return address
    /// to the call stack
    fn call(&mut self, addr: Address) {
        self.call_stack.push(self.pc + 1);
        self.jmp(addr);
    }

    /// Returns from an ongoing function call
    fn ret(&mut self) -> VMResult<()> {
        if self.call_stack.is_empty() {
            bail!("unable to return from an empty call stack");
        }

        let retur_addr = self.call_stack.pop().unwrap();

        self.jmp(retur_addr);

        Ok(())
    }
}
<|endoftext|>


<commit_before>use dns_parser::{self, QueryClass, QueryType, Name, RRData};
use std::collections::VecDeque;
use std::io;
use std::io::ErrorKind::WouldBlock;
use std::marker::PhantomData;
use std::net::{IpAddr, SocketAddr};
use futures::{Poll, Async, Future, Stream};
use futures::sync::mpsc;
use tokio::net::UdpSocket;
use tokio::reactor::Handle;

use super::{DEFAULT_TTL, MDNS_PORT};
use address_family::AddressFamily;
use net;
use services::{Services, ServiceData};

pub type AnswerBuilder = dns_parser::Builder<dns_parser::Answers>;

#[derive(Clone, Debug)]
pub enum Command {
    SendUnsolicited {
        svc: ServiceData,
        ttl: u32,
        include_ip: bool
    },
    Shutdown,
}

pub struct FSM<AF: AddressFamily> {
    socket: UdpSocket,
    services: Services,
    commands: mpsc::UnboundedReceiver<Command>,
    outgoing: VecDeque<(Vec<u8>, SocketAddr)>,
    _af: PhantomData<AF>,
}

impl <AF: AddressFamily> FSM<AF> {
    pub fn new(handle: &Handle, services: &Services)
        -> io::Result<(FSM<AF>, mpsc::UnboundedSender<Command>)>
    {
        let std_socket = AF::bind()?;
        let socket = UdpSocket::from_socket(std_socket, handle)?;
        let (tx, rx) = mpsc::unbounded();

        let fsm = FSM {
            socket: socket,
            services: services.clone(),
            commands: rx,
            outgoing: VecDeque::new(),
            _af: PhantomData,
        };

        Ok((fsm, tx))
    }

    fn recv_packets(&mut self) -> io::Result<()> {
        let mut buf = [0u8; 4096];
        loop {
            let (bytes, addr) = match self.socket.recv_from(&mut buf) {
                Ok((bytes, addr)) => (bytes, addr),
                Err(ref ioerr) if ioerr.kind() == WouldBlock => break,
                Err(err) => return Err(err),
            };

            if bytes >= buf.len() {
                warn!("buffer too small for packet from {:?}", addr);
                continue;
            }

            self.handle_packet(&buf[..bytes], addr);
        }
        Ok(())
    }

    fn handle_packet(&mut self, buffer: &[u8], addr: SocketAddr) {
        trace!("received packet from {:?}", addr);

        let packet = match dns_parser::Packet::parse(buffer) {
            Ok(packet) => packet,
            Err(error) => {
                warn!("couldn't parse packet from {:?}: {}", addr, error);
                return;
            }
        };

        if !packet.header.query {
            trace!("received packet from {:?} with no query", addr);
            return;
        }

        if packet.header.truncated {
            warn!("dropping truncated packet from {:?}", addr);
            return;
        }

        let mut unicast_builder = dns_parser::Builder::new_response(packet.header.id, false).move_to::<dns_parser::Answers>();
        let mut multicast_builder = dns_parser::Builder::new_response(packet.header.id, false).move_to::<dns_parser::Answers>();
        unicast_builder.set_max_size(None);
        multicast_builder.set_max_size(None);

        for question in packet.questions {
            if question.qclass == QueryClass::IN || question.qclass == QueryClass::Any {
                if question.qu {
                    unicast_builder = self.handle_question(&question, unicast_builder);
                } else {
                    multicast_builder = self.handle_question(&question, multicast_builder);
                }
            }
        }

        if !multicast_builder.is_empty() {
            let response = multicast_builder.build().unwrap_or_else(|x| x);
            let addr = SocketAddr::new(AF::mdns_group(), MDNS_PORT);
            self.outgoing.push_back((response, addr));
        }

        if !unicast_builder.is_empty() {
            let response = unicast_builder.build().unwrap_or_else(|x| x);
            self.outgoing.push_back((response, addr));
        }
    }

    fn handle_question(&self, question: &dns_parser::Question, mut builder: AnswerBuilder) -> AnswerBuilder {
        let services = self.services.read().unwrap();

        match question.qtype {
            QueryType::A |
            QueryType::AAAA |
            QueryType::All if question.qname == *services.get_hostname() => {
                builder = self.add_ip_rr(services.get_hostname(), builder, DEFAULT_TTL);
            }
            QueryType::PTR => {
                for svc in services.find_by_type(&question.qname) {
                    builder = svc.add_ptr_rr(builder, DEFAULT_TTL);
                    builder = svc.add_srv_rr(services.get_hostname(), builder, DEFAULT_TTL);
                    builder = svc.add_txt_rr(builder, DEFAULT_TTL);
                    builder = self.add_ip_rr(services.get_hostname(), builder, DEFAULT_TTL);
                }
            }
            QueryType::SRV => {
                if let Some(svc) = services.find_by_name(&question.qname) {
                    builder = svc.add_srv_rr(services.get_hostname(), builder, DEFAULT_TTL);
                    builder = self.add_ip_rr(services.get_hostname(), builder, DEFAULT_TTL);
                }
            }
            QueryType::TXT => {
                if let Some(svc) = services.find_by_name(&question.qname) {
                    builder = svc.add_txt_rr(builder, DEFAULT_TTL);
                }
            }
            _ => ()
        }

        builder
    }

    fn add_ip_rr(&self, hostname: &Name, mut builder: AnswerBuilder, ttl: u32) -> AnswerBuilder {
        for iface in net::getifaddrs() {
            if iface.is_loopback() {
                continue;
            }

            match iface.ip() {
                Some(IpAddr::V4(ip)) if !AF::v6() => {
                    builder = builder.add_answer(hostname, QueryClass::IN, ttl, &RRData::A(ip))
                }
                Some(IpAddr::V6(ip)) if AF::v6() => {
                    builder = builder.add_answer(hostname, QueryClass::IN, ttl, &RRData::AAAA(ip))
                }
                _ => ()
            }
        }

        builder
    }

    fn send_unsolicited(&mut self, svc: &ServiceData, ttl: u32, include_ip: bool) {
        let mut builder = dns_parser::Builder::new_response(0, false).move_to::<dns_parser::Answers>();
        builder.set_max_size(None);

        let services = self.services.read().unwrap();

        builder = svc.add_ptr_rr(builder, ttl);
        builder = svc.add_srv_rr(services.get_hostname(), builder, ttl);
        builder = svc.add_txt_rr(builder, ttl);
        if include_ip {
            builder = self.add_ip_rr(services.get_hostname(), builder, ttl);
        }

        if !builder.is_empty() {
            let response = builder.build().unwrap_or_else(|x| x);
            let addr = SocketAddr::new(AF::mdns_group(), MDNS_PORT);
            self.outgoing.push_back((response, addr));
        }
    }
}

/*
   impl rotor::Machine for FSM {
    type Context = ();
    type Seed = void::Void;

    fn create(seed: Self::Seed, _scope: &mut Scope<Self::Context>) -> rotor::Response<Self, rotor::Void> {
        void::unreachable(seed)
    }

    fn ready(self, _events: EventSet, _scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> {
        self.recv_packets().unwrap();
        rotor::Response::ok(self)
    }

    fn spawned(self, _scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> {
        unimplemented!()
    }

    fn timeout(self, _scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> {
        unimplemented!()
    }

    fn wakeup(self, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> {
        loop {
            match self.rx.try_recv() {
                Ok(Command::Shutdown) => {
                    scope.shutdown_loop();
                    return rotor::Response::done();
                }
                Ok(Command::SendUnsolicited { svc, ttl, include_ip }) => {
                    match self.send_unsolicited(&svc, ttl, include_ip) {
                        Ok(_) => (),
                        Err(e) => {
                            warn!("Error sending unsolicited: {:?}", e);
                            return rotor::Response::error(Box::new(e));
                        }
                    }
                }
                Err(TryRecvError::Disconnected) => {
                    warn!("responder disconnected without shutdown");
                    scope.shutdown_loop();
                    return rotor::Response::done();
                }
                Err(TryRecvError::Empty) => {
                    break;
                }
            }
        }

        rotor::Response::ok(self)
    }
}
*/

impl <AF: AddressFamily> Future for FSM<AF> {
    type Item = ();
    type Error = io::Error;
    fn poll(&mut self) -> Poll<(), io::Error> {
        while let Async::Ready(cmd) = self.commands.poll().unwrap() {
            match cmd {
                Some(Command::Shutdown) => return Ok(Async::Ready(())),
                Some(Command::SendUnsolicited { svc, ttl, include_ip }) => {
                    self.send_unsolicited(&svc, ttl, include_ip);
                }
                None => {
                    warn!("responder disconnected without shutdown");
                    return Ok(Async::Ready(()));
                }
            }
        }

        while let Async::Ready(()) = self.socket.poll_read() {
            self.recv_packets()?;
        }

        loop {
            if let Some(&(ref response, ref addr)) = self.outgoing.front() {
                trace!("sending packet to {:?}", addr);

                match self.socket.send_to(response, addr) {
                    Ok(_) => (),
                    Err(ref ioerr) if ioerr.kind() == WouldBlock => break,
                    Err(err) => warn!("error sending packet {:?}", err),
                }
            } else {
                break;
            }

            self.outgoing.pop_front();
        }

        Ok(Async::NotReady)
    }
}
<commit_msg>Remove old rotor code.<commit_after>use dns_parser::{self, QueryClass, QueryType, Name, RRData};
use std::collections::VecDeque;
use std::io;
use std::io::ErrorKind::WouldBlock;
use std::marker::PhantomData;
use std::net::{IpAddr, SocketAddr};
use futures::{Poll, Async, Future, Stream};
use futures::sync::mpsc;
use tokio::net::UdpSocket;
use tokio::reactor::Handle;

use super::{DEFAULT_TTL, MDNS_PORT};
use address_family::AddressFamily;
use net;
use services::{Services, ServiceData};

pub type AnswerBuilder = dns_parser::Builder<dns_parser::Answers>;

#[derive(Clone, Debug)]
pub enum Command {
    SendUnsolicited {
        svc: ServiceData,
        ttl: u32,
        include_ip: bool
    },
    Shutdown,
}

pub struct FSM<AF: AddressFamily> {
    socket: UdpSocket,
    services: Services,
    commands: mpsc::UnboundedReceiver<Command>,
    outgoing: VecDeque<(Vec<u8>, SocketAddr)>,
    _af: PhantomData<AF>,
}

impl <AF: AddressFamily> FSM<AF> {
    pub fn new(handle: &Handle, services: &Services)
        -> io::Result<(FSM<AF>, mpsc::UnboundedSender<Command>)>
    {
        let std_socket = AF::bind()?;
        let socket = UdpSocket::from_socket(std_socket, handle)?;
        let (tx, rx) = mpsc::unbounded();

        let fsm = FSM {
            socket: socket,
            services: services.clone(),
            commands: rx,
            outgoing: VecDeque::new(),
            _af: PhantomData,
        };

        Ok((fsm, tx))
    }

    fn recv_packets(&mut self) -> io::Result<()> {
        let mut buf = [0u8; 4096];
        loop {
            let (bytes, addr) = match self.socket.recv_from(&mut buf) {
                Ok((bytes, addr)) => (bytes, addr),
                Err(ref ioerr) if ioerr.kind() == WouldBlock => break,
                Err(err) => return Err(err),
            };

            if bytes >= buf.len() {
                warn!("buffer too small for packet from {:?}", addr);
                continue;
            }

            self.handle_packet(&buf[..bytes], addr);
        }
        Ok(())
    }

    fn handle_packet(&mut self, buffer: &[u8], addr: SocketAddr) {
        trace!("received packet from {:?}", addr);

        let packet = match dns_parser::Packet::parse(buffer) {
            Ok(packet) => packet,
            Err(error) => {
                warn!("couldn't parse packet from {:?}: {}", addr, error);
                return;
            }
        };

        if !packet.header.query {
            trace!("received packet from {:?} with no query", addr);
            return;
        }

        if packet.header.truncated {
            warn!("dropping truncated packet from {:?}", addr);
            return;
        }

        let mut unicast_builder = dns_parser::Builder::new_response(packet.header.id, false).move_to::<dns_parser::Answers>();
        let mut multicast_builder = dns_parser::Builder::new_response(packet.header.id, false).move_to::<dns_parser::Answers>();
        unicast_builder.set_max_size(None);
        multicast_builder.set_max_size(None);

        for question in packet.questions {
            if question.qclass == QueryClass::IN || question.qclass == QueryClass::Any {
                if question.qu {
                    unicast_builder = self.handle_question(&question, unicast_builder);
                } else {
                    multicast_builder = self.handle_question(&question, multicast_builder);
                }
            }
        }

        if !multicast_builder.is_empty() {
            let response = multicast_builder.build().unwrap_or_else(|x| x);
            let addr = SocketAddr::new(AF::mdns_group(), MDNS_PORT);
            self.outgoing.push_back((response, addr));
        }

        if !unicast_builder.is_empty() {
            let response = unicast_builder.build().unwrap_or_else(|x| x);
            self.outgoing.push_back((response, addr));
        }
    }

    fn handle_question(&self, question: &dns_parser::Question, mut builder: AnswerBuilder) -> AnswerBuilder {
        let services = self.services.read().unwrap();

        match question.qtype {
            QueryType::A |
            QueryType::AAAA |
            QueryType::All if question.qname == *services.get_hostname() => {
                builder = self.add_ip_rr(services.get_hostname(), builder, DEFAULT_TTL);
            }
            QueryType::PTR => {
                for svc in services.find_by_type(&question.qname) {
                    builder = svc.add_ptr_rr(builder, DEFAULT_TTL);
                    builder = svc.add_srv_rr(services.get_hostname(), builder, DEFAULT_TTL);
                    builder = svc.add_txt_rr(builder, DEFAULT_TTL);
                    builder = self.add_ip_rr(services.get_hostname(), builder, DEFAULT_TTL);
                }
            }
            QueryType::SRV => {
                if let Some(svc) = services.find_by_name(&question.qname) {
                    builder = svc.add_srv_rr(services.get_hostname(), builder, DEFAULT_TTL);
                    builder = self.add_ip_rr(services.get_hostname(), builder, DEFAULT_TTL);
                }
            }
            QueryType::TXT => {
                if let Some(svc) = services.find_by_name(&question.qname) {
                    builder = svc.add_txt_rr(builder, DEFAULT_TTL);
                }
            }
            _ => ()
        }

        builder
    }

    fn add_ip_rr(&self, hostname: &Name, mut builder: AnswerBuilder, ttl: u32) -> AnswerBuilder {
        for iface in net::getifaddrs() {
            if iface.is_loopback() {
                continue;
            }

            match iface.ip() {
                Some(IpAddr::V4(ip)) if !AF::v6() => {
                    builder = builder.add_answer(hostname, QueryClass::IN, ttl, &RRData::A(ip))
                }
                Some(IpAddr::V6(ip)) if AF::v6() => {
                    builder = builder.add_answer(hostname, QueryClass::IN, ttl, &RRData::AAAA(ip))
                }
                _ => ()
            }
        }

        builder
    }

    fn send_unsolicited(&mut self, svc: &ServiceData, ttl: u32, include_ip: bool) {
        let mut builder = dns_parser::Builder::new_response(0, false).move_to::<dns_parser::Answers>();
        builder.set_max_size(None);

        let services = self.services.read().unwrap();

        builder = svc.add_ptr_rr(builder, ttl);
        builder = svc.add_srv_rr(services.get_hostname(), builder, ttl);
        builder = svc.add_txt_rr(builder, ttl);
        if include_ip {
            builder = self.add_ip_rr(services.get_hostname(), builder, ttl);
        }

        if !builder.is_empty() {
            let response = builder.build().unwrap_or_else(|x| x);
            let addr = SocketAddr::new(AF::mdns_group(), MDNS_PORT);
            self.outgoing.push_back((response, addr));
        }
    }
}

impl <AF: AddressFamily> Future for FSM<AF> {
    type Item = ();
    type Error = io::Error;
    fn poll(&mut self) -> Poll<(), io::Error> {
        while let Async::Ready(cmd) = self.commands.poll().unwrap() {
            match cmd {
                Some(Command::Shutdown) => return Ok(Async::Ready(())),
                Some(Command::SendUnsolicited { svc, ttl, include_ip }) => {
                    self.send_unsolicited(&svc, ttl, include_ip);
                }
                None => {
                    warn!("responder disconnected without shutdown");
                    return Ok(Async::Ready(()));
                }
            }
        }

        while let Async::Ready(()) = self.socket.poll_read() {
            self.recv_packets()?;
        }

        loop {
            if let Some(&(ref response, ref addr)) = self.outgoing.front() {
                trace!("sending packet to {:?}", addr);

                match self.socket.send_to(response, addr) {
                    Ok(_) => (),
                    Err(ref ioerr) if ioerr.kind() == WouldBlock => break,
                    Err(err) => warn!("error sending packet {:?}", err),
                }
            } else {
                break;
            }

            self.outgoing.pop_front();
        }

        Ok(Async::NotReady)
    }
}
<|endoftext|>


<commit_before>//! Read ASPRS las files.

#![deny(missing_copy_implementations, missing_debug_implementations, missing_docs, trivial_casts,
        trivial_numeric_casts, unsafe_code, unstable_features, unused_extern_crates,
        unused_import_braces, unused_qualifications)]

extern crate byteorder;
#[macro_use]
extern crate enum_primitive;
extern crate num;
extern crate rustc_serialize;

use std::result;

// Macros
#[macro_use]
pub mod macros;

// Public modules
pub mod header;
pub mod io;
pub mod point;
pub mod reader;
pub mod util;
pub mod vlr;

pub use header::Header;
pub use point::Point;
pub use reader::Reader;
pub use vlr::Vlr;

#[derive(Debug)]
pub enum Error {
    ByteorderError(byteorder::Error),
    CharacterAfterNullByte,
    IoError(std::io::Error),
    ReadError(String),
}

impl From<std::io::Error> for Error {
    fn from(err: std::io::Error) -> Error {
        Error::IoError(err)
    }
}

impl From<byteorder::Error> for Error {
    fn from(err: byteorder::Error) -> Error {
        Error::ByteorderError(err)
    }
}

pub type Result<T> = result::Result<T, Error>;
<commit_msg>Minor formatting in lib.rs<commit_after>//! Read ASPRS las files.

#![deny(missing_copy_implementations, missing_debug_implementations, missing_docs, trivial_casts,
        trivial_numeric_casts, unsafe_code, unstable_features, unused_extern_crates,
        unused_import_braces, unused_qualifications)]

extern crate byteorder;
#[macro_use] extern crate enum_primitive;
extern crate num;
extern crate rustc_serialize;

use std::result;

#[macro_use] pub mod macros;
pub mod header;
pub mod io;
pub mod point;
pub mod reader;
pub mod util;
pub mod vlr;

pub use header::Header;
pub use point::Point;
pub use reader::Reader;
pub use vlr::Vlr;

#[derive(Debug)]
pub enum Error {
    ByteorderError(byteorder::Error),
    CharacterAfterNullByte,
    IoError(std::io::Error),
    ReadError(String),
}

impl From<std::io::Error> for Error {
    fn from(err: std::io::Error) -> Error {
        Error::IoError(err)
    }
}

impl From<byteorder::Error> for Error {
    fn from(err: byteorder::Error) -> Error {
        Error::ByteorderError(err)
    }
}

pub type Result<T> = result::Result<T, Error>;
<|endoftext|>


<commit_before>// Copyright 2016 Kyle Mayes
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! A micro-benchmarking library.

#![feature(test)]

#![warn(missing_copy_implementations, missing_debug_implementations, missing_docs)]

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#![cfg_attr(feature="clippy", warn(clippy))]
#![cfg_attr(feature="clippy", allow(new_without_default_derive))]

extern crate test;
extern crate time;

use std::time::{Duration};

//================================================
// Structs
//================================================

// GeometricSequence _____________________________

/// Generates unique values from a geometric sequence.
#[derive(Copy, Clone, Debug)]
pub struct GeometricSequence {
    current: f64,
    factor: f64,
}

impl GeometricSequence {
    //- Constructors -----------------------------

    /// Constructs a new `GeometricSequence`.
    pub fn new(start: u64, factor: f64) -> Self {
        GeometricSequence { current: start as f64, factor: factor }
    }
}

impl Iterator for GeometricSequence {
    type Item = u64;

    fn next(&mut self) -> Option<Self::Item> {
        let start = self.current as u64;
        while self.current as u64 == start { self.current *= self.factor; }
        Some(start)
    }
}

// Measurement ___________________________________

/// A measurement of the execution time of a function.
#[derive(Copy, Clone, Debug)]
pub struct Measurement {
    /// The number of times the function was called.
    pub iterations: u64,
    /// The number of nanoseconds that elapsed while calling the function.
    pub nanoseconds: u64,
}

impl Measurement {
    //- Constructors -----------------------------

    /// Constructs a new `Measurement`.
    pub fn new(iterations: u64, nanoseconds: u64) -> Self {
        Measurement { iterations: iterations, nanoseconds: nanoseconds }
    }
}

// Options _______________________________________

/// Micro-benchmarking options.
#[derive(Copy, Clone, Debug)]
pub struct Options {
    factor: f64,
    maximum: u64,
}

impl Default for Options {
    fn default() -> Options {
        Options { factor: 1.01, maximum: 5_000_000_000 }
    }
}

impl Options {
    //- Consumers --------------------------------

    /// Sets the geometric growth factor.
    ///
    /// **Default:** `1.01`
    pub fn factor(mut self, factor: f64) -> Self {
        self.factor = factor;
        self
    }

    /// Sets the maximum amount of time a micro-benchmark will run for.
    ///
    /// **Default:** `Duration::new(5, 0)`
    pub fn maximum(mut self, maximum: Duration) -> Self {
        self.maximum = (maximum.as_secs() * 1_000_000_000) + maximum.subsec_nanos() as u64;
        self
    }
}

// Stopwatch _____________________________________

/// A high-precision stopwatch.
#[derive(Clone, Copy, Debug)]
pub struct Stopwatch {
    start: u64,
}

impl Stopwatch {
    //- Constructors -----------------------------

    /// Constructs a new `Stopwatch`.
    pub fn new() -> Self {
        Stopwatch { start: time::precise_time_ns() }
    }

    //- Accessors --------------------------------

    /// Returns the elapsed nanoseconds since this stopwatch was constructed or reset.
    pub fn elapsed(&self) -> u64 {
        time::precise_time_ns() - self.start
    }

    //- Mutators ---------------------------------

    /// Resets this stopwatch.
    pub fn reset(&mut self) {
        self.start = time::precise_time_ns();
    }
}

//================================================
// Functions
//================================================

/// Measures the execution time of the supplied function and returns the resulting samples.
pub fn measure<T, F>(options: &Options, mut f: F) -> Vec<Measurement> where F: FnMut() -> T {
    let mut measurements = vec![];
    let mut sequence = GeometricSequence::new(1, options.factor);
    let total = Stopwatch::new();
    while total.elapsed() < options.maximum {
        let iterations = sequence.next().unwrap();
        let sample = Stopwatch::new();
        for _ in 0..iterations { retain(f()); }
        measurements.push(Measurement::new(iterations, sample.elapsed()));
    }
    measurements
}

/// A function that prevents the optimizer from eliminating the supplied value.
pub fn retain<T>(value: T) -> T {
    test::black_box(value)
}
<commit_msg>Add analyze function<commit_after>// Copyright 2016 Kyle Mayes
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! A micro-benchmarking library.

#![feature(test)]

#![warn(missing_copy_implementations, missing_debug_implementations, missing_docs)]

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#![cfg_attr(feature="clippy", warn(clippy))]
#![cfg_attr(feature="clippy", allow(new_without_default_derive))]

extern crate test;
extern crate time;

use std::time::{Duration};

//================================================
// Structs
//================================================

// Analysis ______________________________________

/// An analysis of a set of timing data.
#[derive(Copy, Clone, Debug)]
pub struct Analysis {
    /// The slope of the linear regression estimator.
    pub beta: f64,
    /// The goodness of fit of the linear regression estimator.
    pub r2: f64,
}

// GeometricSequence _____________________________

/// Generates unique values from a geometric sequence.
#[derive(Copy, Clone, Debug)]
pub struct GeometricSequence {
    current: f64,
    factor: f64,
}

impl GeometricSequence {
    //- Constructors -----------------------------

    /// Constructs a new `GeometricSequence`.
    pub fn new(start: u64, factor: f64) -> Self {
        GeometricSequence { current: start as f64, factor: factor }
    }
}

impl Iterator for GeometricSequence {
    type Item = u64;

    fn next(&mut self) -> Option<Self::Item> {
        let start = self.current as u64;
        while self.current as u64 == start { self.current *= self.factor; }
        Some(start)
    }
}

// Measurement ___________________________________

/// A measurement of the execution time of a function.
#[derive(Copy, Clone, Debug)]
pub struct Measurement {
    /// The number of times the function was called.
    pub iterations: u64,
    /// The number of nanoseconds that elapsed while calling the function.
    pub nanoseconds: u64,
}

impl Measurement {
    //- Constructors -----------------------------

    /// Constructs a new `Measurement`.
    pub fn new(iterations: u64, nanoseconds: u64) -> Self {
        Measurement { iterations: iterations, nanoseconds: nanoseconds }
    }
}

// Options _______________________________________

/// Micro-benchmarking options.
#[derive(Copy, Clone, Debug)]
pub struct Options {
    factor: f64,
    maximum: u64,
}

impl Default for Options {
    fn default() -> Options {
        Options { factor: 1.01, maximum: 5_000_000_000 }
    }
}

impl Options {
    //- Consumers --------------------------------

    /// Sets the geometric growth factor.
    ///
    /// **Default:** `1.01`
    pub fn factor(mut self, factor: f64) -> Self {
        self.factor = factor;
        self
    }

    /// Sets the maximum amount of time a micro-benchmark will run for.
    ///
    /// **Default:** `Duration::new(5, 0)`
    pub fn maximum(mut self, maximum: Duration) -> Self {
        self.maximum = (maximum.as_secs() * 1_000_000_000) + maximum.subsec_nanos() as u64;
        self
    }
}

// Stopwatch _____________________________________

/// A high-precision stopwatch.
#[derive(Clone, Copy, Debug)]
pub struct Stopwatch {
    start: u64,
}

impl Stopwatch {
    //- Constructors -----------------------------

    /// Constructs a new `Stopwatch`.
    pub fn new() -> Self {
        Stopwatch { start: time::precise_time_ns() }
    }

    //- Accessors --------------------------------

    /// Returns the elapsed nanoseconds since this stopwatch was constructed or reset.
    pub fn elapsed(&self) -> u64 {
        time::precise_time_ns() - self.start
    }

    //- Mutators ---------------------------------

    /// Resets this stopwatch.
    pub fn reset(&mut self) {
        self.start = time::precise_time_ns();
    }
}

//================================================
// Functions
//================================================

fn mean<I>(iterator: I) -> f64 where I: Iterator<Item=f64> {
    let (sum, len) = iterator.fold((0.0, 0), |a, f| (a.0 + f, a.1 + 1));
    sum / len as f64
}

/// Analyzes the supplied timing data and returns the resulting analysis.
pub fn analyze(measurements: &[Measurement]) -> Analysis {
    let xmean = mean(measurements.iter().map(|m| m.iterations as f64));
    let ymean = mean(measurements.iter().map(|m| m.nanoseconds as f64));

    // Ordinary least squares estimator.
    let numerator = measurements.iter().map(|m| {
        (m.iterations as f64 - xmean) * (m.nanoseconds as f64 - ymean)
    }).sum::<f64>();
    let denominator = measurements.iter().map(|m| {
        (m.iterations as f64 - xmean).powf(2.0)
    }).sum::<f64>();
    let beta = numerator / denominator;
    let alpha = ymean - (beta * xmean);
    let estimator = |x: u64| (beta * x as f64) + alpha;

    // Ordinary least squares goodness of fit.
    let numerator = measurements.iter().map(|m| {
        (estimator(m.iterations) - ymean).powf(2.0)
    }).sum::<f64>();
    let denominator = measurements.iter().map(|m| {
        (m.nanoseconds as f64 - ymean).powf(2.0)
    }).sum::<f64>();
    let r2 = numerator / denominator;

    Analysis { beta: beta, r2: r2 }
}

/// Measures the execution time of the supplied function and returns the resulting samples.
pub fn measure<T, F>(options: &Options, mut f: F) -> Vec<Measurement> where F: FnMut() -> T {
    let mut measurements = vec![];
    let mut sequence = GeometricSequence::new(1, options.factor);
    let total = Stopwatch::new();
    while total.elapsed() < options.maximum {
        let iterations = sequence.next().unwrap();
        let sample = Stopwatch::new();
        for _ in 0..iterations { retain(f()); }
        measurements.push(Measurement::new(iterations, sample.elapsed()));
    }
    measurements
}

/// A function that prevents the optimizer from eliminating the supplied value.
pub fn retain<T>(value: T) -> T {
    test::black_box(value)
}
<|endoftext|>