<commit_before>use address::Address;
use messages::outgoing;
use mio;
use node;
use routing_table::{InsertOutcome, InsertionResult, RoutingTable};
use std::collections::HashMap;
use std::io::Cursor;
use std::net::{UdpSocket, ToSocketAddrs, SocketAddr};
use std::sync::mpsc;
use std::thread;
use stun;
use transaction::{TransactionId, TransactionIdGenerator};

#[derive(Debug)]
pub enum Event {
    ReceivedPacket(Address, Vec<u8>),
    Shutdown
}

pub enum OneshotTask {
    Incoming(Vec<u8>),
    StartBootstrap,
    SendPacket(Address, Vec<u8>),
    Shutdown
}

pub enum ScheduledTask {
    ContinueBootstrap,
    ContinueHealthCheck,
    ContinueRefresh
}

enum TableAction {
    Bootstrap(mio::Timeout),
    HealthCheck(mio::Timeout),
    RefreshBucket(mio::Timeout)
}

pub type TaskSender = mio::Sender<OneshotTask>;

enum Status {
    Bootstrapping,
    Idle
}

pub struct Network {
    host: SocketAddr,
    routing_table: RoutingTable,
    self_node: Box<node::Node + 'static>,
    transaction_ids: TransactionIdGenerator,
    status: Status,
    pending_actions: HashMap<TransactionId, TableAction>,
    event_listeners: Vec<mpsc::Sender<Event>>,
    shutdown_signals: Vec<mpsc::Sender<mpsc::Sender<()>>>
}

impl Network {
    pub fn new<T: ToSocketAddrs>(self_address: Address, host: T, routers: Vec<Box<node::Node>>) -> Network {
        let host = host.to_socket_addrs().unwrap().next().unwrap();
        let mapped_host = stun::get_mapped_address(host).unwrap();
        let self_node = node::UdpNode::new(self_address, mapped_host);
        let routing_table = RoutingTable::new(8, self_address, routers);

        Network {
            host: host,
            routing_table: routing_table,
            self_node: Box::new(self_node),
            transaction_ids: TransactionIdGenerator::new(),
            status: Status::Idle,
            pending_actions: HashMap::new(),
            event_listeners: vec![],
            shutdown_signals: vec![]
        }
    }

    pub fn run(mut self) -> TaskSender {
        let mut event_loop_config = mio::EventLoopConfig::new();
        event_loop_config.notify_capacity(16384);
        let mut event_loop = mio::EventLoop::configured(event_loop_config).unwrap();

        let shutdown_signal = create_incoming_udp_channel(self.host, event_loop.channel());
        self.shutdown_signals.push(shutdown_signal);

        event_loop.channel().send(OneshotTask::StartBootstrap).unwrap();
        info!("Running server at {:?}", self.self_node);
        let mut handler = Handler::new(self);
        let task_sender = event_loop.channel();
        thread::spawn(move|| event_loop.run(&mut handler).unwrap());
        task_sender
    }

    pub fn register_event_listener(&mut self, event_listener: mpsc::Sender<Event>) {
        self.event_listeners.push(event_listener);
    }

    fn handle_incoming(&mut self, data: Vec<u8>, event_loop: &mut mio::EventLoop<Handler>) {
        use messages::incoming::{Message, Query, Response, self};
        let mut data = Cursor::new(data);
        let message = incoming::parse_from_reader(&mut data).unwrap();

        match message {
            Message::Query(transaction_id, origin, query) => {
                let origin_address = origin.address();

                match query {
                    Query::FindNode(target) => {
                        let response: Vec<u8> = outgoing::create_find_node_response(
                                transaction_id,
                                &self.self_node,
                                self.routing_table.nearest_to(&target, false));
                        origin.send(response);
                    },
                    Query::Packet(payload) => {
                        for listener in &self.event_listeners {
                            listener.send(Event::ReceivedPacket(origin_address, payload.clone())).unwrap();
                        }
                        let response = outgoing::create_packet_response(
                            transaction_id, &self.self_node);
                        origin.send(response);
                    },
                    Query::Ping => {
                        let response = outgoing::create_ping_response(
                            transaction_id,
                            &self.self_node);
                        origin.send(response);
                    }
                }

                self.insert_node(origin).unwrap();
                if let Some(origin) = self.routing_table.find_node(&origin_address) {
                    origin.received_query(transaction_id);
                }
            }

            Message::Response(transaction_id, origin, response) => {
                let origin_address = origin.address();
                match response {
                    Response::FindNode(mut nodes) => {
                        let mut encounted_new_node = false;
                        let mut tail = vec![origin];
                        for node in nodes.drain(..).chain(tail.drain(..)) {
                            match self.insert_node(node) {
                                Ok(InsertOutcome::Inserted) => {
                                    encounted_new_node = true;
                                }
                                Err(error) => { panic!(error) }
                                _ => { }
                            }
                        }

                        {
                            if let Some(mut origin) = self.routing_table.find_node(&origin_address) {
                                origin.received_response(transaction_id);
                            }
                        }

                        match self.pending_actions.remove(&transaction_id) {
                            Some(TableAction::Bootstrap(timeout)) => {
                                event_loop.clear_timeout(timeout);
                                if encounted_new_node {
                                    self.continue_bootstrap(event_loop);
                                } else {
                                    self.continue_health_check(event_loop);
                                    self.continue_refresh(event_loop)
                                }
                            }
                            Some(TableAction::HealthCheck(_)) => {
                                // Does not clear timeout. Let's Healthcheck proceed at regular
                                // interval.
                            },
                            Some(TableAction::RefreshBucket(_)) => {
                            }
                            None => { }
                        }

                        match self.status {
                            Status::Bootstrapping => {
                                self.status = Status::Idle;
                            }
                            _ => { }
                        }
                    }
                    Response::Packet => {
                        if let Some(mut origin) = self.routing_table.find_node(&origin_address) {
                            origin.received_response(transaction_id);
                        }
                    }
                    Response::Ping => {
                        if let Some(mut origin) = self.routing_table.find_node(&origin_address) {
                            origin.received_response(transaction_id);
                        }
                    }
                }
            }
        }
    }

    fn start_bootstrap(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        self.status = Status::Bootstrapping;
        self.continue_bootstrap(event_loop);
    }

    fn continue_bootstrap(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        let address = &self.self_node.address();
        let transaction_id = self.find_node(address);
        let timeout = event_loop.timeout_ms(ScheduledTask::ContinueBootstrap, 1000).unwrap();
        self.pending_actions.insert(transaction_id, TableAction::Bootstrap(timeout));
    }

    fn continue_health_check(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        let transaction_id = self.health_check();
        let timeout = event_loop.timeout_ms(ScheduledTask::ContinueHealthCheck, 1000).unwrap();
        self.pending_actions.insert(transaction_id, TableAction::HealthCheck(timeout));
    }

    fn continue_refresh(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        let timeout = event_loop.timeout_ms(ScheduledTask::ContinueRefresh, 1000).unwrap();

        match self.refresh_bucket() {
            Some(transaction_id) => {
                self.pending_actions.insert(transaction_id, TableAction::RefreshBucket(timeout));
            }
            None => { }
        }
    }

    fn find_node(&mut self, address: &Address) -> TransactionId {
        let transaction_id = self.transaction_ids.generate();
        let query = outgoing::create_find_node_query(
            transaction_id,
            &self.self_node,
            address);
        for node in self.routing_table.nearest() {
            node.sent_query(transaction_id);
            node.send(query.clone());
        }
        transaction_id
    }

    fn health_check(&mut self) -> TransactionId {
        self.routing_table.remove_bad_nodes();
        let transaction_id = self.transaction_ids.generate();
        if let Some(node) = self.routing_table.questionable_nodes().get_mut(0) {
            let query = outgoing::create_ping_query(
                transaction_id, &self.self_node);
            node.sent_query(transaction_id);
            node.send(query);
        }
        transaction_id
    }

    fn refresh_bucket(&mut self) -> Option<TransactionId> {
        if let Some(address) = self.address_to_find_for_refresh() {
            Some(self.find_node(&address))
        } else {
            None
        }
    }

    fn address_to_find_for_refresh(&self) -> Option<Address> {
        match self.routing_table.bucket_needing_refresh() {
            Some(bucket) => {
                Some(bucket.random_address_in_space())
            }
            None => None
        }
    }

    fn insert_node(&mut self, node: Box<node::Node>) -> InsertionResult {
        self.routing_table.insert(node, &self.self_node, &mut self.transaction_ids)
    }

    fn send_packet(&mut self, recipient: Address, payload: Vec<u8>, _event_loop: &mut mio::EventLoop<Handler>) {
        for node in self.routing_table.nearest_to(&recipient, false) {
            let transaction_id = self.transaction_ids.generate();
            let query = outgoing::create_packet_query(
                transaction_id, &self.self_node, payload.clone());
            node.sent_query(transaction_id);
            node.send(query.clone());
        }
    }

    fn shutdown(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        let sentinels: Vec<mpsc::Receiver<()>> = self.shutdown_signals.iter().map(|signal| {
            let (sentinal_sender, sentinal_receiver) = mpsc::channel();
            signal.send(sentinal_sender).expect("couldn't send shutdown signal");
            sentinal_receiver
        }).collect();
        for sentinel in sentinels {
            sentinel.recv().unwrap();
        }
        event_loop.shutdown();
        for listener in &self.event_listeners {
            listener.send(Event::Shutdown).unwrap();
        }
    }
}

struct Handler {
    network: Network
}

impl Handler {
    fn new(network: Network) -> Handler {
        Handler {
            network: network
        }
    }
}

impl mio::Handler for Handler {
    type Timeout = ScheduledTask;
    type Message = OneshotTask;

    fn notify(&mut self, event_loop: &mut mio::EventLoop<Handler>, task: OneshotTask) {
        match task {
            OneshotTask::Incoming(data) => self.network.handle_incoming(data, event_loop),
            OneshotTask::StartBootstrap => self.network.start_bootstrap(event_loop),
            OneshotTask::SendPacket(recipient, payload) =>
                self.network.send_packet(recipient, payload, event_loop),
            OneshotTask::Shutdown => self.network.shutdown(event_loop)
        }
    }

    fn timeout(&mut self, event_loop: &mut mio::EventLoop<Handler>, timeout: ScheduledTask) {
        match timeout {
            ScheduledTask::ContinueBootstrap => self.network.continue_bootstrap(event_loop),
            ScheduledTask::ContinueHealthCheck => self.network.continue_health_check(event_loop),
            ScheduledTask::ContinueRefresh => self.network.continue_refresh(event_loop)
        }
    }
}

// TODO: I'd rather have some kind of select on two channels instead of this nested non-blocking
// recv. It only works because of the 10ms timeout on the socket.
fn create_incoming_udp_channel(host: SocketAddr, sender: TaskSender) -> mpsc::Sender<mpsc::Sender<()>> {
    use std::time::Duration;

    let (shutdown_sender, shutdown_receiver) = mpsc::channel::<mpsc::Sender<()>>();

    thread::spawn(move || {
        let host = ("0.0.0.0", host.port());
        let socket = UdpSocket::bind(host).unwrap();
        socket.set_read_timeout(Some(Duration::from_millis(10))).unwrap();

        loop {
            match shutdown_receiver.try_recv() {
                Err(mpsc::TryRecvError::Empty) => {
                    let mut buf = [0; 4096];
                    match socket.recv(&mut buf) {
                        Ok(size) => {
                            sender.send(OneshotTask::Incoming(buf[..size].iter().cloned().collect()))
                                .unwrap_or_else(|err| info!("Couldn't handling incoming: {:?}", err));
                        }
                        Err(_) => {
                            //warn!("Error receiving from server: {}", e)
                        }
                    }
                }

                Err(mpsc::TryRecvError::Disconnected) => {
                    // The other end of the shutdown_receiver was dropped
                    break
                }

                Ok(sentinel) => {
                    sentinel.send(()).unwrap();
                    break;
                }
            }
        }

    });
    shutdown_sender
}
<commit_msg>Refresh all questionable nodes during health check, not just first<commit_after>use address::Address;
use messages::outgoing;
use mio;
use node;
use routing_table::{InsertOutcome, InsertionResult, RoutingTable};
use std::collections::HashMap;
use std::io::Cursor;
use std::net::{UdpSocket, ToSocketAddrs, SocketAddr};
use std::sync::mpsc;
use std::thread;
use stun;
use transaction::{TransactionId, TransactionIdGenerator};

#[derive(Debug)]
pub enum Event {
    ReceivedPacket(Address, Vec<u8>),
    Shutdown
}

pub enum OneshotTask {
    Incoming(Vec<u8>),
    StartBootstrap,
    SendPacket(Address, Vec<u8>),
    Shutdown
}

pub enum ScheduledTask {
    ContinueBootstrap,
    ContinueHealthCheck,
    ContinueRefresh
}

enum TableAction {
    Bootstrap(mio::Timeout),
    HealthCheck(mio::Timeout),
    RefreshBucket(mio::Timeout)
}

pub type TaskSender = mio::Sender<OneshotTask>;

enum Status {
    Bootstrapping,
    Idle
}

pub struct Network {
    host: SocketAddr,
    routing_table: RoutingTable,
    self_node: Box<node::Node + 'static>,
    transaction_ids: TransactionIdGenerator,
    status: Status,
    pending_actions: HashMap<TransactionId, TableAction>,
    event_listeners: Vec<mpsc::Sender<Event>>,
    shutdown_signals: Vec<mpsc::Sender<mpsc::Sender<()>>>
}

impl Network {
    pub fn new<T: ToSocketAddrs>(self_address: Address, host: T, routers: Vec<Box<node::Node>>) -> Network {
        let host = host.to_socket_addrs().unwrap().next().unwrap();
        let mapped_host = stun::get_mapped_address(host).unwrap();
        let self_node = node::UdpNode::new(self_address, mapped_host);
        let routing_table = RoutingTable::new(8, self_address, routers);

        Network {
            host: host,
            routing_table: routing_table,
            self_node: Box::new(self_node),
            transaction_ids: TransactionIdGenerator::new(),
            status: Status::Idle,
            pending_actions: HashMap::new(),
            event_listeners: vec![],
            shutdown_signals: vec![]
        }
    }

    pub fn run(mut self) -> TaskSender {
        let mut event_loop_config = mio::EventLoopConfig::new();
        event_loop_config.notify_capacity(16384);
        let mut event_loop = mio::EventLoop::configured(event_loop_config).unwrap();

        let shutdown_signal = create_incoming_udp_channel(self.host, event_loop.channel());
        self.shutdown_signals.push(shutdown_signal);

        event_loop.channel().send(OneshotTask::StartBootstrap).unwrap();
        info!("Running server at {:?}", self.self_node);
        let mut handler = Handler::new(self);
        let task_sender = event_loop.channel();
        thread::spawn(move|| event_loop.run(&mut handler).unwrap());
        task_sender
    }

    pub fn register_event_listener(&mut self, event_listener: mpsc::Sender<Event>) {
        self.event_listeners.push(event_listener);
    }

    fn handle_incoming(&mut self, data: Vec<u8>, event_loop: &mut mio::EventLoop<Handler>) {
        use messages::incoming::{Message, Query, Response, self};
        let mut data = Cursor::new(data);
        let message = incoming::parse_from_reader(&mut data).unwrap();

        match message {
            Message::Query(transaction_id, origin, query) => {
                let origin_address = origin.address();

                match query {
                    Query::FindNode(target) => {
                        let response: Vec<u8> = outgoing::create_find_node_response(
                                transaction_id,
                                &self.self_node,
                                self.routing_table.nearest_to(&target, false));
                        origin.send(response);
                    },
                    Query::Packet(payload) => {
                        for listener in &self.event_listeners {
                            listener.send(Event::ReceivedPacket(origin_address, payload.clone())).unwrap();
                        }
                        let response = outgoing::create_packet_response(
                            transaction_id, &self.self_node);
                        origin.send(response);
                    },
                    Query::Ping => {
                        let response = outgoing::create_ping_response(
                            transaction_id,
                            &self.self_node);
                        origin.send(response);
                    }
                }

                self.insert_node(origin).unwrap();
                if let Some(origin) = self.routing_table.find_node(&origin_address) {
                    origin.received_query(transaction_id);
                }
            }

            Message::Response(transaction_id, origin, response) => {
                let origin_address = origin.address();
                match response {
                    Response::FindNode(mut nodes) => {
                        let mut encounted_new_node = false;
                        let mut tail = vec![origin];
                        for node in nodes.drain(..).chain(tail.drain(..)) {
                            match self.insert_node(node) {
                                Ok(InsertOutcome::Inserted) => {
                                    encounted_new_node = true;
                                }
                                Err(error) => { panic!(error) }
                                _ => { }
                            }
                        }

                        {
                            if let Some(mut origin) = self.routing_table.find_node(&origin_address) {
                                origin.received_response(transaction_id);
                            }
                        }

                        match self.pending_actions.remove(&transaction_id) {
                            Some(TableAction::Bootstrap(timeout)) => {
                                event_loop.clear_timeout(timeout);
                                if encounted_new_node {
                                    self.continue_bootstrap(event_loop);
                                } else {
                                    self.continue_health_check(event_loop);
                                    self.continue_refresh(event_loop)
                                }
                            }
                            Some(TableAction::HealthCheck(_)) => {
                                // Does not clear timeout. Let's Healthcheck proceed at regular
                                // interval.
                            },
                            Some(TableAction::RefreshBucket(_)) => {
                            }
                            None => { }
                        }

                        match self.status {
                            Status::Bootstrapping => {
                                self.status = Status::Idle;
                            }
                            _ => { }
                        }
                    }
                    Response::Packet => {
                        if let Some(mut origin) = self.routing_table.find_node(&origin_address) {
                            origin.received_response(transaction_id);
                        }
                    }
                    Response::Ping => {
                        if let Some(mut origin) = self.routing_table.find_node(&origin_address) {
                            origin.received_response(transaction_id);
                        }
                    }
                }
            }
        }
    }

    fn start_bootstrap(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        self.status = Status::Bootstrapping;
        self.continue_bootstrap(event_loop);
    }

    fn continue_bootstrap(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        let address = &self.self_node.address();
        let transaction_id = self.find_node(address);
        let timeout = event_loop.timeout_ms(ScheduledTask::ContinueBootstrap, 1000).unwrap();
        self.pending_actions.insert(transaction_id, TableAction::Bootstrap(timeout));
    }

    fn continue_health_check(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        let transaction_id = self.health_check();
        let timeout = event_loop.timeout_ms(ScheduledTask::ContinueHealthCheck, 1000).unwrap();
        self.pending_actions.insert(transaction_id, TableAction::HealthCheck(timeout));
    }

    fn continue_refresh(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        let timeout = event_loop.timeout_ms(ScheduledTask::ContinueRefresh, 1000).unwrap();

        match self.refresh_bucket() {
            Some(transaction_id) => {
                self.pending_actions.insert(transaction_id, TableAction::RefreshBucket(timeout));
            }
            None => { }
        }
    }

    fn find_node(&mut self, address: &Address) -> TransactionId {
        let transaction_id = self.transaction_ids.generate();
        let query = outgoing::create_find_node_query(
            transaction_id,
            &self.self_node,
            address);
        for node in self.routing_table.nearest() {
            node.sent_query(transaction_id);
            node.send(query.clone());
        }
        transaction_id
    }

    fn health_check(&mut self) -> TransactionId {
        self.routing_table.remove_bad_nodes();
        let transaction_id = self.transaction_ids.generate();
        for node in self.routing_table.questionable_nodes().iter_mut() {
            let query = outgoing::create_ping_query(
                transaction_id, &self.self_node);
            node.sent_query(transaction_id);
            node.send(query);
        }
        transaction_id
    }

    fn refresh_bucket(&mut self) -> Option<TransactionId> {
        if let Some(address) = self.address_to_find_for_refresh() {
            Some(self.find_node(&address))
        } else {
            None
        }
    }

    fn address_to_find_for_refresh(&self) -> Option<Address> {
        match self.routing_table.bucket_needing_refresh() {
            Some(bucket) => {
                Some(bucket.random_address_in_space())
            }
            None => None
        }
    }

    fn insert_node(&mut self, node: Box<node::Node>) -> InsertionResult {
        self.routing_table.insert(node, &self.self_node, &mut self.transaction_ids)
    }

    fn send_packet(&mut self, recipient: Address, payload: Vec<u8>, _event_loop: &mut mio::EventLoop<Handler>) {
        for node in self.routing_table.nearest_to(&recipient, false) {
            let transaction_id = self.transaction_ids.generate();
            let query = outgoing::create_packet_query(
                transaction_id, &self.self_node, payload.clone());
            node.sent_query(transaction_id);
            node.send(query.clone());
        }
    }

    fn shutdown(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        let sentinels: Vec<mpsc::Receiver<()>> = self.shutdown_signals.iter().map(|signal| {
            let (sentinal_sender, sentinal_receiver) = mpsc::channel();
            signal.send(sentinal_sender).expect("couldn't send shutdown signal");
            sentinal_receiver
        }).collect();
        for sentinel in sentinels {
            sentinel.recv().unwrap();
        }
        event_loop.shutdown();
        for listener in &self.event_listeners {
            listener.send(Event::Shutdown).unwrap();
        }
    }
}

struct Handler {
    network: Network
}

impl Handler {
    fn new(network: Network) -> Handler {
        Handler {
            network: network
        }
    }
}

impl mio::Handler for Handler {
    type Timeout = ScheduledTask;
    type Message = OneshotTask;

    fn notify(&mut self, event_loop: &mut mio::EventLoop<Handler>, task: OneshotTask) {
        match task {
            OneshotTask::Incoming(data) => self.network.handle_incoming(data, event_loop),
            OneshotTask::StartBootstrap => self.network.start_bootstrap(event_loop),
            OneshotTask::SendPacket(recipient, payload) =>
                self.network.send_packet(recipient, payload, event_loop),
            OneshotTask::Shutdown => self.network.shutdown(event_loop)
        }
    }

    fn timeout(&mut self, event_loop: &mut mio::EventLoop<Handler>, timeout: ScheduledTask) {
        match timeout {
            ScheduledTask::ContinueBootstrap => self.network.continue_bootstrap(event_loop),
            ScheduledTask::ContinueHealthCheck => self.network.continue_health_check(event_loop),
            ScheduledTask::ContinueRefresh => self.network.continue_refresh(event_loop)
        }
    }
}

// TODO: I'd rather have some kind of select on two channels instead of this nested non-blocking
// recv. It only works because of the 10ms timeout on the socket.
fn create_incoming_udp_channel(host: SocketAddr, sender: TaskSender) -> mpsc::Sender<mpsc::Sender<()>> {
    use std::time::Duration;

    let (shutdown_sender, shutdown_receiver) = mpsc::channel::<mpsc::Sender<()>>();

    thread::spawn(move || {
        let host = ("0.0.0.0", host.port());
        let socket = UdpSocket::bind(host).unwrap();
        socket.set_read_timeout(Some(Duration::from_millis(10))).unwrap();

        loop {
            match shutdown_receiver.try_recv() {
                Err(mpsc::TryRecvError::Empty) => {
                    let mut buf = [0; 4096];
                    match socket.recv(&mut buf) {
                        Ok(size) => {
                            sender.send(OneshotTask::Incoming(buf[..size].iter().cloned().collect()))
                                .unwrap_or_else(|err| info!("Couldn't handling incoming: {:?}", err));
                        }
                        Err(_) => {
                            //warn!("Error receiving from server: {}", e)
                        }
                    }
                }

                Err(mpsc::TryRecvError::Disconnected) => {
                    // The other end of the shutdown_receiver was dropped
                    break
                }

                Ok(sentinel) => {
                    sentinel.send(()).unwrap();
                    break;
                }
            }
        }

    });
    shutdown_sender
}
<|endoftext|>


<commit_before>/// Sure tree scanning from the filesystem.
use crate::{
    escape::Escape, node::SureNode, progress::ScanProgress, surefs::encode_atts, suretree::AttMap,
    Error, Result,
};
use log::error;
use std::{
    collections::VecDeque,
    fs::{self, symlink_metadata, Metadata},
    os::unix::prelude::*,
    path::{Path, PathBuf},
};

pub fn walk<P: AsRef<Path>>(root: P) -> Result<()> {
    for entry in scan_fs(root)? {
        let entry = entry?;
        println!("{:?}", entry);
    }

    Ok(())
}

/// A filesystem scanner walks a filesystem, iterating over a tree as it is
/// encountered.
pub fn scan_fs<P: AsRef<Path>>(root: P) -> Result<ScanIterator> {
    let root = root.as_ref().to_path_buf();
    let meta = symlink_metadata(&root)?;

    if !meta.is_dir() {
        return Err(Error::RootMustBeDir);
    }

    let atts = encode_atts(&root, &meta);
    let root_dev = meta.dev();
    let mut todo = VecDeque::new();
    todo.push_back(AugNode::SubDir {
        path: root,
        name: "__root__".to_string(),
        meta,
        atts,
    });

    let si = ScanIterator {
        todo,
        root_dev,
        progress: ScanProgress::new(),
    };

    Ok(si)
}

pub struct ScanIterator {
    todo: VecDeque<AugNode>,
    root_dev: u64,
    progress: ScanProgress,
}

impl Iterator for ScanIterator {
    type Item = Result<SureNode>;

    fn next(&mut self) -> Option<Result<SureNode>> {
        match self.todo.pop_front() {
            None => None,
            Some(AugNode::Normal(e)) => Some(Ok(e)),
            Some(AugNode::SubDir {
                path,
                name,
                atts,
                meta,
            }) => {
                // Push the contents of this directory.  Unless we have
                // crossed a mountpoint.
                if !meta.is_dir() || meta.dev() == self.root_dev {
                    match self.push_dir(&path) {
                        Ok(()) => (),
                        Err(e) => return Some(Err(e)),
                    };
                } else {
                    self.push_empty_dir();
                }

                Some(Ok(SureNode::Enter {
                    name,
                    atts,
                }))
            }
        }
    }
}

impl ScanIterator {
    fn push_dir(&mut self, path: &Path) -> Result<()> {
        let mut entries = vec![];

        for entry in fs::read_dir(path)? {
            let entry = entry?;
            entries.push(entry);
        }

        // Sort by inode first.  This helps performance on some filesystems
        // (such as ext4).
        entries.sort_by(|a, b| a.ino().cmp(&b.ino()));

        let mut files: Vec<_> = entries
            .iter()
            .filter_map(|e| match e.metadata() {
                Ok(m) => {
                    let path = e.path();
                    let atts = encode_atts(&path, &m);

                    Some(OneFile {
                        path,
                        meta: m,
                        atts,
                    })
                }
                Err(err) => {
                    error!("Unable to stat file: {:?} ({})", e.path(), err);
                    None
                }
            })
            .collect();

        // Sort them back by name.
        files.sort_by(|a, b| a.path.file_name().cmp(&b.path.file_name()));

        let (dirs, files): (Vec<_>, Vec<_>) = files.into_iter().partition(|n| n.meta.is_dir());

        self.progress.update(
            dirs.len() as u64,
            files.len() as u64,
            files.iter().map(|x| x.meta.len()).sum(),
        );

        self.todo.push_front(AugNode::Normal(SureNode::Leave));

        // The files in reverse order.
        for f in files.into_iter().rev() {
            self.todo.push_front(AugNode::Normal(SureNode::File {
                name: f.path.file_name().unwrap().as_bytes().escaped(),
                atts: f.atts,
            }));
        }

        self.todo.push_front(AugNode::Normal(SureNode::Sep));

        // The dirs in reverse order.
        for d in dirs.into_iter().rev() {
            let name = d.path.file_name().unwrap().as_bytes().escaped();
            self.todo.push_front(AugNode::SubDir {
                path: d.path,
                name,
                meta: d.meta,
                atts: d.atts,
            });
        }

        Ok(())
    }

    /// Pushes the Sep and Leave needed to make an empty directory work.
    /// Used when skipping directories that cross mountpoints.
    fn push_empty_dir(&mut self) {
        self.todo.push_front(AugNode::Normal(SureNode::Leave));
        self.todo.push_front(AugNode::Normal(SureNode::Sep));
    }
}

struct OneFile {
    path: PathBuf,
    meta: Metadata,
    atts: AttMap,
}

/// Augmented entries.  This intersperses regular nodes with special ones
/// containing enough information to add subdirectories.
enum AugNode {
    Normal(SureNode),
    SubDir {
        path: PathBuf,
        name: String,
        meta: Metadata,
        atts: AttMap,
    },
}
<commit_msg>clippy: Use .sort_by_key() to simplify sort<commit_after>/// Sure tree scanning from the filesystem.
use crate::{
    escape::Escape, node::SureNode, progress::ScanProgress, surefs::encode_atts, suretree::AttMap,
    Error, Result,
};
use log::error;
use std::{
    collections::VecDeque,
    fs::{self, symlink_metadata, Metadata},
    os::unix::prelude::*,
    path::{Path, PathBuf},
};

pub fn walk<P: AsRef<Path>>(root: P) -> Result<()> {
    for entry in scan_fs(root)? {
        let entry = entry?;
        println!("{:?}", entry);
    }

    Ok(())
}

/// A filesystem scanner walks a filesystem, iterating over a tree as it is
/// encountered.
pub fn scan_fs<P: AsRef<Path>>(root: P) -> Result<ScanIterator> {
    let root = root.as_ref().to_path_buf();
    let meta = symlink_metadata(&root)?;

    if !meta.is_dir() {
        return Err(Error::RootMustBeDir);
    }

    let atts = encode_atts(&root, &meta);
    let root_dev = meta.dev();
    let mut todo = VecDeque::new();
    todo.push_back(AugNode::SubDir {
        path: root,
        name: "__root__".to_string(),
        meta,
        atts,
    });

    let si = ScanIterator {
        todo,
        root_dev,
        progress: ScanProgress::new(),
    };

    Ok(si)
}

pub struct ScanIterator {
    todo: VecDeque<AugNode>,
    root_dev: u64,
    progress: ScanProgress,
}

impl Iterator for ScanIterator {
    type Item = Result<SureNode>;

    fn next(&mut self) -> Option<Result<SureNode>> {
        match self.todo.pop_front() {
            None => None,
            Some(AugNode::Normal(e)) => Some(Ok(e)),
            Some(AugNode::SubDir {
                path,
                name,
                atts,
                meta,
            }) => {
                // Push the contents of this directory.  Unless we have
                // crossed a mountpoint.
                if !meta.is_dir() || meta.dev() == self.root_dev {
                    match self.push_dir(&path) {
                        Ok(()) => (),
                        Err(e) => return Some(Err(e)),
                    };
                } else {
                    self.push_empty_dir();
                }

                Some(Ok(SureNode::Enter {
                    name,
                    atts,
                }))
            }
        }
    }
}

impl ScanIterator {
    fn push_dir(&mut self, path: &Path) -> Result<()> {
        let mut entries = vec![];

        for entry in fs::read_dir(path)? {
            let entry = entry?;
            entries.push(entry);
        }

        // Sort by inode first.  This helps performance on some filesystems
        // (such as ext4).
        entries.sort_by_key(|a| a.ino());

        let mut files: Vec<_> = entries
            .iter()
            .filter_map(|e| match e.metadata() {
                Ok(m) => {
                    let path = e.path();
                    let atts = encode_atts(&path, &m);

                    Some(OneFile {
                        path,
                        meta: m,
                        atts,
                    })
                }
                Err(err) => {
                    error!("Unable to stat file: {:?} ({})", e.path(), err);
                    None
                }
            })
            .collect();

        // Sort them back by name.
        files.sort_by(|a, b| a.path.file_name().cmp(&b.path.file_name()));

        let (dirs, files): (Vec<_>, Vec<_>) = files.into_iter().partition(|n| n.meta.is_dir());

        self.progress.update(
            dirs.len() as u64,
            files.len() as u64,
            files.iter().map(|x| x.meta.len()).sum(),
        );

        self.todo.push_front(AugNode::Normal(SureNode::Leave));

        // The files in reverse order.
        for f in files.into_iter().rev() {
            self.todo.push_front(AugNode::Normal(SureNode::File {
                name: f.path.file_name().unwrap().as_bytes().escaped(),
                atts: f.atts,
            }));
        }

        self.todo.push_front(AugNode::Normal(SureNode::Sep));

        // The dirs in reverse order.
        for d in dirs.into_iter().rev() {
            let name = d.path.file_name().unwrap().as_bytes().escaped();
            self.todo.push_front(AugNode::SubDir {
                path: d.path,
                name,
                meta: d.meta,
                atts: d.atts,
            });
        }

        Ok(())
    }

    /// Pushes the Sep and Leave needed to make an empty directory work.
    /// Used when skipping directories that cross mountpoints.
    fn push_empty_dir(&mut self) {
        self.todo.push_front(AugNode::Normal(SureNode::Leave));
        self.todo.push_front(AugNode::Normal(SureNode::Sep));
    }
}

struct OneFile {
    path: PathBuf,
    meta: Metadata,
    atts: AttMap,
}

/// Augmented entries.  This intersperses regular nodes with special ones
/// containing enough information to add subdirectories.
enum AugNode {
    Normal(SureNode),
    SubDir {
        path: PathBuf,
        name: String,
        meta: Metadata,
        atts: AttMap,
    },
}
<|endoftext|>


<commit_before>use std::{
    future::Future,
    pin::Pin,
    sync::Arc,
    task::{Context, Poll, Waker},
};

use parking_lot::{Condvar, Mutex};

use super::Result;

#[derive(Debug)]
struct OneShotState<T> {
    filled: bool,
    fused: bool,
    item: Option<T>,
    waker: Option<Waker>,
}

impl<T> Default for OneShotState<T> {
    fn default() -> OneShotState<T> {
        OneShotState { filled: false, fused: false, item: None, waker: None }
    }
}

/// A Future value which may or may not be filled
#[derive(Debug)]
pub struct OneShot<T> {
    mu: Arc<Mutex<OneShotState<T>>>,
    cv: Arc<Condvar>,
}

/// The completer side of the Future
pub struct OneShotFiller<T> {
    mu: Arc<Mutex<OneShotState<T>>>,
    cv: Arc<Condvar>,
}

impl<T> OneShot<T> {
    /// Create a new OneShotFiller and the OneShot
    /// that will be filled by its completion.
    pub fn pair() -> (OneShotFiller<T>, Self) {
        let mu = Arc::new(Mutex::new(OneShotState::default()));
        let cv = Arc::new(Condvar::new());
        let future = Self { mu: mu.clone(), cv: cv.clone() };
        let filler = OneShotFiller { mu, cv };

        (filler, future)
    }

    /// Block on the OneShot's completion
    /// or dropping of the OneShotFiller
    pub fn wait(self) -> Option<T> {
        let mut inner = self.mu.lock();
        while !inner.filled {
            self.cv.wait(&mut inner);
        }
        inner.item.take()
    }

    /// Block on the OneShot's completion
    /// or dropping of the OneShotFiller.
    ///
    /// # Panics
    /// panics if the OneShotFiller is dropped
    /// without completing the promise.
    pub fn unwrap(self) -> T {
        self.wait().unwrap()
    }
}

impl<T> Future for OneShot<Result<T>> {
    type Output = Result<T>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let mut state = self.mu.lock();
        if state.fused {
            return Poll::Pending;
        }
        if state.filled {
            state.fused = true;
            Poll::Ready(state.item.take().unwrap())
        } else {
            state.waker = Some(cx.waker().clone());
            Poll::Pending
        }
    }
}

impl<T> OneShotFiller<T> {
    /// Complete the OneShot
    pub fn fill(self, inner: T) {
        let mut state = self.mu.lock();

        if let Some(waker) = state.waker.take() {
            waker.wake();
        }

        state.filled = true;
        state.item = Some(inner);

        let _notified = self.cv.notify_all();
    }
}

impl<T> Drop for OneShotFiller<T> {
    fn drop(&mut self) {
        let mut state = self.mu.lock();

        if state.filled {
            return;
        }

        if let Some(waker) = state.waker.take() {
            waker.wake();
        }

        state.filled = true;

        let _notified = self.cv.notify_all();
    }
}
<commit_msg>Put more types in backticks in docs<commit_after>use std::{
    future::Future,
    pin::Pin,
    sync::Arc,
    task::{Context, Poll, Waker},
};

use parking_lot::{Condvar, Mutex};

use super::Result;

#[derive(Debug)]
struct OneShotState<T> {
    filled: bool,
    fused: bool,
    item: Option<T>,
    waker: Option<Waker>,
}

impl<T> Default for OneShotState<T> {
    fn default() -> OneShotState<T> {
        OneShotState { filled: false, fused: false, item: None, waker: None }
    }
}

/// A Future value which may or may not be filled
#[derive(Debug)]
pub struct OneShot<T> {
    mu: Arc<Mutex<OneShotState<T>>>,
    cv: Arc<Condvar>,
}

/// The completer side of the Future
pub struct OneShotFiller<T> {
    mu: Arc<Mutex<OneShotState<T>>>,
    cv: Arc<Condvar>,
}

impl<T> OneShot<T> {
    /// Create a new `OneShotFiller` and the OneShot
    /// that will be filled by its completion.
    pub fn pair() -> (OneShotFiller<T>, Self) {
        let mu = Arc::new(Mutex::new(OneShotState::default()));
        let cv = Arc::new(Condvar::new());
        let future = Self { mu: mu.clone(), cv: cv.clone() };
        let filler = OneShotFiller { mu, cv };

        (filler, future)
    }

    /// Block on the `OneShot`'s completion
    /// or dropping of the OneShotFiller
    pub fn wait(self) -> Option<T> {
        let mut inner = self.mu.lock();
        while !inner.filled {
            self.cv.wait(&mut inner);
        }
        inner.item.take()
    }

    /// Block on the `OneShot`'s completion
    /// or dropping of the OneShotFiller.
    ///
    /// # Panics
    /// panics if the `OneShotFiller` is dropped
    /// without completing the promise.
    pub fn unwrap(self) -> T {
        self.wait().unwrap()
    }
}

impl<T> Future for OneShot<Result<T>> {
    type Output = Result<T>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let mut state = self.mu.lock();
        if state.fused {
            return Poll::Pending;
        }
        if state.filled {
            state.fused = true;
            Poll::Ready(state.item.take().unwrap())
        } else {
            state.waker = Some(cx.waker().clone());
            Poll::Pending
        }
    }
}

impl<T> OneShotFiller<T> {
    /// Complete the `OneShot`
    `pub fn fill(self, inner: T) {
        let mut state = self.mu.lock();

        if let Some(waker) = state.waker.take() {
            waker.wake();
        }

        state.filled = true;
        state.item = Some(inner);

        let _notified = self.cv.notify_all();
    }
}

impl<T> Drop for OneShotFiller<T> {
    fn drop(&mut self) {
        let mut state = self.mu.lock();

        if state.filled {
            return;
        }

        if let Some(waker) = state.waker.take() {
            waker.wake();
        }

        state.filled = true;

        let _notified = self.cv.notify_all();
    }
}
<|endoftext|>


<commit_before>/*!
Hypervisor API for OSX

To use this library, you need

* OS X Yosemite (10.10) or newer

* an Intel processor with the VT-x feature set that includes Extended Page
Tables (EPT) and Unrestricted Mode. To verify this, run and expect the following
in your Terminal:

  ```shell
  $ sysctl kern.hv_support
  kern.hv_support: 1
  ```
!*/
//extern crate core;

use super::core::fmt;
use libc::*;

#[allow(non_camel_case_types)]
pub mod ffi;

use self::ffi::*;
use self::ffi::consts::*;

/// Error returned after every call
pub enum Error {
    /// Success
    Success,
    /// Error
    Error,
    /// Busy
    Busy,
    /// Bad argument
    BadArg,
    /// No resources
    NoRes,
    /// No device
    NoDev,
    /// Unsupported
    Unsupp
}

impl fmt::Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Success => write!(f, "Success"),
            Error::Error => write!(f, "Error"),
            Error::Busy => write!(f, "Busy"),
            Error::BadArg => write!(f, "Bad argument"),
            Error::NoRes => write!(f, "No resources"),
            Error::NoDev => write!(f, "No device"),
            Error::Unsupp => write!(f, "Unsupported"),
        }
    }
}

fn match_error_code(code: hv_return_t) -> Error {
    match code {
        HV_SUCCESS => Error::Success,
        HV_BUSY => Error::Busy,
        HV_BAD_ARGUMENT => Error::BadArg,
        HV_NO_RESOURCES => Error::NoRes,
        HV_NO_DEVICE => Error::NoDev,
        HV_UNSUPPORTED => Error::Unsupp,
        _ => Error::Error
    }
}

/// Creates a VM instance for the current task
pub fn create_vm() -> Error {
    match_error_code(unsafe {
        hv_vm_create(0)
    })
}

/// Destroys the VM instance associated with the current task
pub fn destory_vm() -> Error {
    match_error_code(unsafe {
        hv_vm_destroy()
    })
}

/// Synchronizes the guest Timestamp-Counters (TSC) across all vCPUs
///
/// `tsc` Guest TSC value
pub fn sync_tsc(tsc: u64) -> Error {
    match_error_code(unsafe {
        hv_vm_sync_tsc(tsc as uint64_t)
    })
}

/// Virtual CPU
#[allow(non_camel_case_types)]
pub struct vCPU {
    /// Virtual CPU ID
    pub id: u32
}

impl vCPU {
    /// Creates a vCPU instance for the current thread
    pub fn new() -> Result<vCPU, Error> {
        let mut vcpuid: hv_vcpuid_t = 0;

        let error = match_error_code(unsafe {
            hv_vcpu_create(&mut vcpuid, 0)
        });

        match error {
            Error::Success => Ok(vCPU {
                id: vcpuid as u32
            }),
            _ => Err(error)
        }
    }

    /// Destroys the vCPU instance associated with the current thread
    pub fn destory(&self) -> Error {
        match_error_code(unsafe {
            hv_vcpu_destroy(self.id as hv_vcpuid_t)
        })
    }

    /// Executes the vCPU
    pub fn run(&self) -> Error {
        match_error_code(unsafe {
            hv_vcpu_run(self.id as hv_vcpuid_t)
        })
    }

    /// Returns the cumulative execution time of the vCPU in nanoseconds
    pub fn exec_time(&self) -> Result<u64, Error> {
        let mut exec_time: uint64_t = 0;

        let error = match_error_code(unsafe {
            hv_vcpu_get_exec_time(self.id, &mut exec_time)
        });

        match error {
            Error::Success => Ok(exec_time as u64),
            _ => Err(error)
        }
    }

    /// Forces flushing of cached vCPU state
    pub fn flush(&self) -> Error {
        match_error_code(unsafe {
            hv_vcpu_flush(self.id as hv_vcpuid_t)
        })
    }

    /// Invalidates the translation lookaside buffer (TLB) of a vCPU
    pub fn invalidate_tlb(&self) -> Error {
        match_error_code(unsafe {
            hv_vcpu_invalidate_tlb(self.id as hv_vcpuid_t)
        })
    }

}

impl fmt::Debug for vCPU {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "vCPU ID: {}", (*self).id)
    }
}
<commit_msg>Add functions to osx module to read and write MSRs and x86 registers<commit_after>/*!
Hypervisor API for OSX

To use this library, you need

* OS X Yosemite (10.10) or newer

* an Intel processor with the VT-x feature set that includes Extended Page
Tables (EPT) and Unrestricted Mode. To verify this, run and expect the following
in your Terminal:

  ```shell
  $ sysctl kern.hv_support
  kern.hv_support: 1
  ```
!*/
//extern crate core;

use super::core::fmt;
use libc::*;

#[allow(non_camel_case_types)]
pub mod ffi;

use self::ffi::*;
use self::ffi::consts::*;

/// Error returned after every call
pub enum Error {
    /// Success
    Success,
    /// Error
    Error,
    /// Busy
    Busy,
    /// Bad argument
    BadArg,
    /// No resources
    NoRes,
    /// No device
    NoDev,
    /// Unsupported
    Unsupp
}

impl fmt::Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Success => write!(f, "Success"),
            Error::Error => write!(f, "Error"),
            Error::Busy => write!(f, "Busy"),
            Error::BadArg => write!(f, "Bad argument"),
            Error::NoRes => write!(f, "No resources"),
            Error::NoDev => write!(f, "No device"),
            Error::Unsupp => write!(f, "Unsupported"),
        }
    }
}

fn match_error_code(code: hv_return_t) -> Error {
    match code {
        HV_SUCCESS => Error::Success,
        HV_BUSY => Error::Busy,
        HV_BAD_ARGUMENT => Error::BadArg,
        HV_NO_RESOURCES => Error::NoRes,
        HV_NO_DEVICE => Error::NoDev,
        HV_UNSUPPORTED => Error::Unsupp,
        _ => Error::Error
    }
}

/// Creates a VM instance for the current task
pub fn create_vm() -> Error {
    match_error_code(unsafe {
        hv_vm_create(0)
    })
}

/// Destroys the VM instance associated with the current task
pub fn destory_vm() -> Error {
    match_error_code(unsafe {
        hv_vm_destroy()
    })
}

/// Synchronizes the guest Timestamp-Counters (TSC) across all vCPUs
///
/// `tsc` Guest TSC value
pub fn sync_tsc(tsc: u64) -> Error {
    match_error_code(unsafe {
        hv_vm_sync_tsc(tsc as uint64_t)
    })
}

/// Virtual CPU
#[allow(non_camel_case_types)]
pub struct vCPU {
    /// Virtual CPU ID
    pub id: u32
}

/// x86 architectural register
#[allow(non_camel_case_types)]
pub enum x86Reg {
	RIP,
	RFLAGS,
	RAX,
	RCX,
	RDX,
	RBX,
	RSI,
	RDI,
	RSP,
	RBP,
	R8,
	R9,
	R10,
	R11,
	R12,
	R13,
	R14,
	R15,
	CS,
	SS,
	DS,
	ES,
	FS,
	GS,
	IDT_BASE,
	IDT_LIMIT,
	GDT_BASE,
	GDT_LIMIT,
	LDTR,
	LDT_BASE,
	LDT_LIMIT,
	LDT_AR,
	TR,
	TSS_BASE,
	TSS_LIMIT,
	TSS_AR,
	CR0,
	CR1,
	CR2,
	CR3,
	CR4,
	DR0,
	DR1,
	DR2,
	DR3,
	DR4,
	DR5,
	DR6,
	DR7,
	TPR,
	XCR0,
	REGISTERS_MAX,
}

#[allow(non_snake_case)]
fn match_x86Reg(reg_id: &x86Reg) -> hv_x86_reg_t {
    match reg_id {
        &x86Reg::RIP           => hv_x86_reg_t::HV_X86_RIP,
        &x86Reg::RFLAGS        => hv_x86_reg_t::HV_X86_RFLAGS,
        &x86Reg::RAX           => hv_x86_reg_t::HV_X86_RAX,
        &x86Reg::RCX           => hv_x86_reg_t::HV_X86_RCX,
        &x86Reg::RDX           => hv_x86_reg_t::HV_X86_RDX,
        &x86Reg::RBX           => hv_x86_reg_t::HV_X86_RBX,
        &x86Reg::RSI           => hv_x86_reg_t::HV_X86_RSI,
        &x86Reg::RDI           => hv_x86_reg_t::HV_X86_RDI,
        &x86Reg::RSP           => hv_x86_reg_t::HV_X86_RSP,
        &x86Reg::RBP           => hv_x86_reg_t::HV_X86_RBP,
        &x86Reg::R8            => hv_x86_reg_t::HV_X86_R8,
        &x86Reg::R9            => hv_x86_reg_t::HV_X86_R9,
        &x86Reg::R10           => hv_x86_reg_t::HV_X86_R10,
        &x86Reg::R11           => hv_x86_reg_t::HV_X86_R11,
        &x86Reg::R12           => hv_x86_reg_t::HV_X86_R12,
        &x86Reg::R13           => hv_x86_reg_t::HV_X86_R13,
        &x86Reg::R14           => hv_x86_reg_t::HV_X86_R14,
        &x86Reg::R15           => hv_x86_reg_t::HV_X86_R15,
        &x86Reg::CS            => hv_x86_reg_t::HV_X86_CS,
        &x86Reg::SS            => hv_x86_reg_t::HV_X86_SS,
        &x86Reg::DS            => hv_x86_reg_t::HV_X86_DS,
        &x86Reg::ES            => hv_x86_reg_t::HV_X86_ES,
        &x86Reg::FS            => hv_x86_reg_t::HV_X86_FS,
        &x86Reg::GS            => hv_x86_reg_t::HV_X86_GS,
        &x86Reg::IDT_BASE      => hv_x86_reg_t::HV_X86_IDT_BASE,
        &x86Reg::IDT_LIMIT     => hv_x86_reg_t::HV_X86_IDT_LIMIT,
        &x86Reg::GDT_BASE      => hv_x86_reg_t::HV_X86_GDT_BASE,
        &x86Reg::GDT_LIMIT     => hv_x86_reg_t::HV_X86_GDT_LIMIT,
        &x86Reg::LDTR          => hv_x86_reg_t::HV_X86_LDTR,
        &x86Reg::LDT_BASE      => hv_x86_reg_t::HV_X86_LDT_BASE,
        &x86Reg::LDT_LIMIT     => hv_x86_reg_t::HV_X86_LDT_LIMIT,
        &x86Reg::LDT_AR        => hv_x86_reg_t::HV_X86_LDT_AR,
        &x86Reg::TR            => hv_x86_reg_t::HV_X86_TR,
        &x86Reg::TSS_BASE      => hv_x86_reg_t::HV_X86_TSS_BASE,
        &x86Reg::TSS_LIMIT     => hv_x86_reg_t::HV_X86_TSS_LIMIT,
        &x86Reg::TSS_AR        => hv_x86_reg_t::HV_X86_TSS_AR,
        &x86Reg::CR0           => hv_x86_reg_t::HV_X86_CR0,
        &x86Reg::CR1           => hv_x86_reg_t::HV_X86_CR1,
        &x86Reg::CR2           => hv_x86_reg_t::HV_X86_CR2,
        &x86Reg::CR3           => hv_x86_reg_t::HV_X86_CR3,
        &x86Reg::CR4           => hv_x86_reg_t::HV_X86_CR4,
        &x86Reg::DR0           => hv_x86_reg_t::HV_X86_DR0,
        &x86Reg::DR1           => hv_x86_reg_t::HV_X86_DR1,
        &x86Reg::DR2           => hv_x86_reg_t::HV_X86_DR2,
        &x86Reg::DR3           => hv_x86_reg_t::HV_X86_DR3,
        &x86Reg::DR4           => hv_x86_reg_t::HV_X86_DR4,
        &x86Reg::DR5           => hv_x86_reg_t::HV_X86_DR5,
        &x86Reg::DR6           => hv_x86_reg_t::HV_X86_DR6,
        &x86Reg::DR7           => hv_x86_reg_t::HV_X86_DR7,
        &x86Reg::TPR           => hv_x86_reg_t::HV_X86_TPR,
        &x86Reg::XCR0          => hv_x86_reg_t::HV_X86_XCR0,
        &x86Reg::REGISTERS_MAX => hv_x86_reg_t::HV_X86_REGISTERS_MAX,
    }
}

impl vCPU {
    /// Creates a vCPU instance for the current thread
    pub fn new() -> Result<vCPU, Error> {
        let mut vcpuid: hv_vcpuid_t = 0;

        let error = match_error_code(unsafe {
            hv_vcpu_create(&mut vcpuid, 0)
        });

        match error {
            Error::Success => Ok(vCPU {
                id: vcpuid as u32
            }),
            _ => Err(error)
        }
    }

    /// Destroys the vCPU instance associated with the current thread
    pub fn destory(&self) -> Error {
        match_error_code(unsafe {
            hv_vcpu_destroy(self.id as hv_vcpuid_t)
        })
    }

    /// Executes the vCPU
    pub fn run(&self) -> Error {
        match_error_code(unsafe {
            hv_vcpu_run(self.id as hv_vcpuid_t)
        })
    }

    /// Returns the cumulative execution time of the vCPU in nanoseconds
    pub fn exec_time(&self) -> Result<u64, Error> {
        let mut exec_time: uint64_t = 0;

        let error = match_error_code(unsafe {
            hv_vcpu_get_exec_time(self.id, &mut exec_time)
        });

        match error {
            Error::Success => Ok(exec_time as u64),
            _ => Err(error)
        }
    }

    /// Forces flushing of cached vCPU state
    pub fn flush(&self) -> Error {
        match_error_code(unsafe {
            hv_vcpu_flush(self.id as hv_vcpuid_t)
        })
    }

    /// Invalidates the translation lookaside buffer (TLB) of a vCPU
    pub fn invalidate_tlb(&self) -> Error {
        match_error_code(unsafe {
            hv_vcpu_invalidate_tlb(self.id as hv_vcpuid_t)
        })
    }

    /// Enables an MSR to be used natively by the VM
    pub fn enable_native_msr(&self, msr: u32, enable: bool) -> Error {
        match_error_code(unsafe {
            hv_vcpu_enable_native_msr(self.id as hv_vcpuid_t, msr as uint32_t, enable)
        })
    }

    /// Returns the current value of an MSR of the vCPU
    pub fn read_msr(&self, msr: u32) -> Result<u64, Error> {
        let mut value: uint64_t = 0;

            let error = match_error_code(unsafe {
                hv_vcpu_read_msr(self.id as hv_vcpuid_t, msr as uint32_t, &mut value)
            });

        match error {
            Error::Success => Ok(value as u64),
            _ => Err(error)
        }
    }

    /// Set the value of an MSR of the vCPU
    pub fn write_msr(&self, msr: u32, value: u64) -> Error {
        match_error_code(unsafe {
            hv_vcpu_write_msr(self.id as hv_vcpuid_t, msr as uint32_t, &(value as uint64_t))
        })
    }

    /// Returns the current value of an architectural x86 register
    /// of the vCPU
    pub fn read_register(&self, reg: &x86Reg) -> Result<u64, Error> {
        let mut value: uint64_t = 0;

        let error = match_error_code(unsafe {
            hv_vcpu_read_register(self.id as hv_vcpuid_t, match_x86Reg(&reg), &mut value)
        });

        match error {
            Error::Success => Ok(value as u64),
            _ => Err(error)
        }
    }

    /// Sets the value of an architectural x86 register of the vCPU
    pub fn write_register(&self, reg: &x86Reg, value: u64) -> Error {
        match_error_code(unsafe {
            hv_vcpu_write_register(self.id as hv_vcpuid_t, match_x86Reg(&reg), value as uint64_t)
        })
    }
}

impl fmt::Debug for vCPU {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "vCPU ID: {}", (*self).id)
    }
}
<|endoftext|>


<commit_before>//! This module is strictly internal.
//!
//! These functions are used by `date()`, `time()` and `datetime()`.
//! They are currently not private, because the need to be accessible,
//! but are not useful by themselves.
//!
//! Please refer to the top-level functions instead, as they offer a better abstraction.
//!
//! **These functions may be made private later.**

use helper::*;
use nom::{self, is_digit};
use super::{Time, DateTime, Date};

macro_rules! empty_or(
    ($i:expr, $submac:ident!( $($args:tt)* )) => (
        if $i.len() == 0 {
            nom::IResult::Done($i, None)
        } else {
            match $submac!($i, $($args)*) {
                nom::IResult::Done(i,o)     => nom::IResult::Done(i, Some(o)),
                nom::IResult::Error(_)      => nom::IResult::Done($i, None),
                nom::IResult::Incomplete(i) => nom::IResult::Incomplete(i)

            }
        }
    );
);

macro_rules! check(
  ($input:expr, $submac:ident!( $($args:tt)* )) => (

    {
      let mut failed = false;
      for &idx in $input {
        if !$submac!(idx, $($args)*) {
            failed = true;
            break;
        }
      }
      if failed {
        nom::IResult::Error(nom::ErrorKind::Custom(20))
      } else {
        nom::IResult::Done(&b""[..], $input)
      }
    }
  );
  ($input:expr, $f:expr) => (
    check!($input, call!($f));
  );
);

macro_rules! char_between(
    ($input:expr, $min:expr, $max:expr) => (
        {
        fn f(c: u8) -> bool { c >= ($min as u8) && c <= ($max as u8)}
        flat_map!($input, take!(1), check!(f))
        }
    );
);

named!(take_4_digits, flat_map!(take!(4), check!(is_digit)));

// year
named!(year_prefix, alt!(tag!("+") | tag!("-")));
named!(year <i32>, do_parse!(
        pref: opt!(complete!(year_prefix)) >>
        year: call!(take_4_digits) >>
        (
            match pref {
                Some(b"-") => -buf_to_i32(year),
                _ => buf_to_i32(year)
            }
        )));

// MM
named!(lower_month <u32>, do_parse!(tag!("0") >> s:char_between!('1', '9') >> (buf_to_u32(s))));
named!(upper_month <u32>, do_parse!(tag!("1") >> s:char_between!('0', '2') >> (10+buf_to_u32(s))));
named!(month <u32>, alt!(lower_month | upper_month));

// DD
named!(day_zero  <u32>, do_parse!(tag!("0") >> s:char_between!('1', '9') >> (buf_to_u32(s))));
named!(day_one   <u32>, do_parse!(tag!("1") >> s:char_between!('0', '9') >> (10+buf_to_u32(s))));
named!(day_two   <u32>, do_parse!(tag!("2") >> s:char_between!('0', '9') >> (20+buf_to_u32(s))));
named!(day_three <u32>, do_parse!(tag!("3") >> s:char_between!('0', '1') >> (30+buf_to_u32(s))));
named!(day <u32>, alt!(day_zero | day_one | day_two | day_three));

// WW
// reusing day_N parsers, sorry
named!(week_three <u32>, do_parse!(tag!("3") >> s:char_between!('0', '9') >> (30+buf_to_u32(s))));
named!(week_four  <u32>, do_parse!(tag!("4") >> s:char_between!('0', '9') >> (40+buf_to_u32(s))));
named!(week_five  <u32>, do_parse!(tag!("5") >> s:char_between!('0', '3') >> (50+buf_to_u32(s))));

named!(week <u32>, alt!(day_zero | day_one | day_two | week_three| week_four | week_five ));
named!(week_day <u32>, map!(char_between!('1', '7') , |s| buf_to_u32(s)));

// ordinal DDD
named!(ord_day <u32>, do_parse!(
        a:char_between!('0','3') >>
        b:char_between!('0','9') >>
        c:char_between!('0','9') >>
        ( buf_to_u32(a)*100 + buf_to_u32(b)*10 + buf_to_u32(c) )
        ));

// YYYY-MM-DD
named!(pub ymd_date <Date>, do_parse!(
        y: year >>
        opt!(complete!(tag!("-"))) >>
        m: month >>
        opt!(complete!(tag!("-"))) >>
        d: day >>
        ( Date::YMD{ year: y, month: m, day: d } )
        ));

// YYYY-MM-DD
named!(pub ordinal_date <Date>, do_parse!(
        y: year >>
        opt!(complete!(tag!("-"))) >>
        d: ord_day >>
        ( Date::Ordinal{ year: y, ddd: d } )
        ));

// YYYY-"W"WW-D
named!(pub iso_week_date <Date>, do_parse!(
        y: year >>
        opt!(complete!(tag!("-"))) >>
        tag!("W") >>
        w: week >>
        opt!(complete!(tag!("-"))) >>
        d: week_day >>
        ( Date::Week{ year: y, ww: w, d: d } )
        ));

named!(pub parse_date <Date>, alt!( ymd_date | iso_week_date | ordinal_date ) );

// TIME

// HH
named!(lower_hour <u32>, do_parse!(f:char_between!('0','1') >>
                                   s:char_between!('0','9') >>
                                   ( buf_to_u32(f)*10 + buf_to_u32(s) )));
named!(upper_hour <u32>, do_parse!(tag!("2") >>
                                   s:char_between!('0','4') >>
                                   (20+buf_to_u32(s))));
named!(hour <u32>, alt!(lower_hour | upper_hour));

// MM
named!(below_sixty <u32>, do_parse!(f:char_between!('0','5') >>
                                    s:char_between!('0','9') >>
                                    ( buf_to_u32(f)*10 + buf_to_u32(s) ) ));
named!(upto_sixty <u32>, alt!(below_sixty | map!(tag!("60"), |_| 60)));

named!(minute <u32>, call!(below_sixty));
named!(second <u32>, call!(upto_sixty));
named!(millisecond <u32>, map!( is_a!("0123456789"), |ms| buf_to_u32(ms) ) );

// HH:MM:[SS][.(m*)][(Z|+...|-...)]
named!(pub parse_time <Time>, do_parse!(
        h: hour >>
        opt!(complete!(tag!(":"))) >>
        m: minute >>
        s:  opt!(complete!( do_parse!( opt!(tag!(":")) >> s:second >> (s)))) >>
        ms: opt!(complete!( do_parse!( tag!(".") >> ms:millisecond >> (ms)))) >>
        z:  opt!(complete!( alt!( timezone_hour | timezone_utc) )) >>
        (
            Time {
                hour: h,
                minute: m,
                second: s.unwrap_or(0),
                millisecond: ms.unwrap_or(0),
                tz_offset_hours: z.unwrap_or((0,0)).0,
                tz_offset_minutes: z.unwrap_or((0,0)).1
            }
        )
        ));

named!(sign <i32>, alt!(
        tag!("-") => { |_| -1 } |
        tag!("+") => { |_| 1 }
        )
    );

named!(timezone_hour <(i32,i32)>, do_parse!(
        s: sign >>
        h: hour >>
        m: empty_or!(
            do_parse!(opt!(tag!(":")) >> m: minute >> ( m ))
           ) >>
        ( (s * (h as i32) , s * (m.unwrap_or(0) as i32)) )
        ));

named!(timezone_utc <(i32,i32)>, map!(tag!("Z"), |_| (0,0)));

// Full ISO8601
named!(pub parse_datetime <DateTime>, do_parse!(
        d: parse_date >>
        tag!("T") >>
        t: parse_time >>
        (
            DateTime{
                date: d,
                time: t,
            }
        )
        ));

#[cfg(test)]
mod tests{

    use super::{year, month, day};
    use super::{hour, minute, second};
    use nom::IResult::*;

    #[test]
    fn test_year() {
        assert_eq!(Done(&[][..],   2015), year(b"2015"));
        assert_eq!(Done(&[][..],  -0333), year(b"-0333"));
        assert_eq!(Done(&b"-"[..], 2015), year(b"2015-"));
        assert!(year(b"abcd").is_err());
        assert!(year(b"2a03").is_err());
    }

    #[test]
    fn test_month() {
        assert_eq!(Done(&[][..], 1),    month(b"01"));
        assert_eq!(Done(&[][..], 6),    month(b"06"));
        assert_eq!(Done(&[][..], 12),   month(b"12"));
        assert_eq!(Done(&b"-"[..], 12), month(b"12-"));

        assert!(month(b"13").is_err());
        assert!(month(b"00").is_err());
    }

    #[test]
    fn test_day() {
        assert_eq!(Done(&[][..], 1),    day(b"01"));
        assert_eq!(Done(&[][..], 12),   day(b"12"));
        assert_eq!(Done(&[][..], 20),   day(b"20"));
        assert_eq!(Done(&[][..], 28),   day(b"28"));
        assert_eq!(Done(&[][..], 30),   day(b"30"));
        assert_eq!(Done(&[][..], 31),   day(b"31"));
        assert_eq!(Done(&b"-"[..], 31), day(b"31-"));

        assert!(day(b"00").is_err());
        assert!(day(b"32").is_err());
    }

    #[test]
    fn test_hour() {
        assert_eq!(Done(&[][..], 0),  hour(b"00"));
        assert_eq!(Done(&[][..], 1),  hour(b"01"));
        assert_eq!(Done(&[][..], 6),  hour(b"06"));
        assert_eq!(Done(&[][..], 12), hour(b"12"));
        assert_eq!(Done(&[][..], 13), hour(b"13"));
        assert_eq!(Done(&[][..], 20), hour(b"20"));
        assert_eq!(Done(&[][..], 24), hour(b"24"));

        assert!(hour(b"25").is_err());
        assert!(hour(b"30").is_err());
        assert!(hour(b"ab").is_err());
    }

    #[test]
    fn test_minute() {
        assert_eq!(Done(&[][..], 0),  minute(b"00"));
        assert_eq!(Done(&[][..], 1),  minute(b"01"));
        assert_eq!(Done(&[][..], 30), minute(b"30"));
        assert_eq!(Done(&[][..], 59), minute(b"59"));

        assert!(minute(b"60").is_err());
        assert!(minute(b"61").is_err());
        assert!(minute(b"ab").is_err());
    }

    #[test]
    fn test_second() {
        assert_eq!(Done(&[][..], 0),  second(b"00"));
        assert_eq!(Done(&[][..], 1),  second(b"01"));
        assert_eq!(Done(&[][..], 30), second(b"30"));
        assert_eq!(Done(&[][..], 59), second(b"59"));
        assert_eq!(Done(&[][..], 60), second(b"60"));

        assert!(second(b"61").is_err());
        assert!(second(b"ab").is_err());
    }

}
<commit_msg>refactor: Use preceded where it makes sense<commit_after>//! This module is strictly internal.
//!
//! These functions are used by `date()`, `time()` and `datetime()`.
//! They are currently not private, because the need to be accessible,
//! but are not useful by themselves.
//!
//! Please refer to the top-level functions instead, as they offer a better abstraction.
//!
//! **These functions may be made private later.**

use helper::*;
use nom::{self, is_digit};
use super::{Time, DateTime, Date};

macro_rules! empty_or(
    ($i:expr, $submac:ident!( $($args:tt)* )) => (
        if $i.len() == 0 {
            nom::IResult::Done($i, None)
        } else {
            match $submac!($i, $($args)*) {
                nom::IResult::Done(i,o)     => nom::IResult::Done(i, Some(o)),
                nom::IResult::Error(_)      => nom::IResult::Done($i, None),
                nom::IResult::Incomplete(i) => nom::IResult::Incomplete(i)

            }
        }
    );
);

macro_rules! check(
  ($input:expr, $submac:ident!( $($args:tt)* )) => (

    {
      let mut failed = false;
      for &idx in $input {
        if !$submac!(idx, $($args)*) {
            failed = true;
            break;
        }
      }
      if failed {
        nom::IResult::Error(nom::ErrorKind::Custom(20))
      } else {
        nom::IResult::Done(&b""[..], $input)
      }
    }
  );
  ($input:expr, $f:expr) => (
    check!($input, call!($f));
  );
);

macro_rules! char_between(
    ($input:expr, $min:expr, $max:expr) => (
        {
        fn f(c: u8) -> bool { c >= ($min as u8) && c <= ($max as u8)}
        flat_map!($input, take!(1), check!(f))
        }
    );
);

named!(take_4_digits, flat_map!(take!(4), check!(is_digit)));

// year
named!(year_prefix, alt!(tag!("+") | tag!("-")));
named!(year <i32>, do_parse!(
        pref: opt!(complete!(year_prefix)) >>
        year: call!(take_4_digits) >>
        (
            match pref {
                Some(b"-") => -buf_to_i32(year),
                _ => buf_to_i32(year)
            }
        )));

// MM
named!(lower_month <u32>, do_parse!(tag!("0") >> s:char_between!('1', '9') >> (buf_to_u32(s))));
named!(upper_month <u32>, do_parse!(tag!("1") >> s:char_between!('0', '2') >> (10+buf_to_u32(s))));
named!(month <u32>, alt!(lower_month | upper_month));

// DD
named!(day_zero  <u32>, do_parse!(tag!("0") >> s:char_between!('1', '9') >> (buf_to_u32(s))));
named!(day_one   <u32>, do_parse!(tag!("1") >> s:char_between!('0', '9') >> (10+buf_to_u32(s))));
named!(day_two   <u32>, do_parse!(tag!("2") >> s:char_between!('0', '9') >> (20+buf_to_u32(s))));
named!(day_three <u32>, do_parse!(tag!("3") >> s:char_between!('0', '1') >> (30+buf_to_u32(s))));
named!(day <u32>, alt!(day_zero | day_one | day_two | day_three));

// WW
// reusing day_N parsers, sorry
named!(week_three <u32>, do_parse!(tag!("3") >> s:char_between!('0', '9') >> (30+buf_to_u32(s))));
named!(week_four  <u32>, do_parse!(tag!("4") >> s:char_between!('0', '9') >> (40+buf_to_u32(s))));
named!(week_five  <u32>, do_parse!(tag!("5") >> s:char_between!('0', '3') >> (50+buf_to_u32(s))));

named!(week <u32>, alt!(day_zero | day_one | day_two | week_three| week_four | week_five ));
named!(week_day <u32>, map!(char_between!('1', '7') , |s| buf_to_u32(s)));

// ordinal DDD
named!(ord_day <u32>, do_parse!(
        a:char_between!('0','3') >>
        b:char_between!('0','9') >>
        c:char_between!('0','9') >>
        ( buf_to_u32(a)*100 + buf_to_u32(b)*10 + buf_to_u32(c) )
        ));

// YYYY-MM-DD
named!(pub ymd_date <Date>, do_parse!(
        y: year >>
        opt!(complete!(tag!("-"))) >>
        m: month >>
        opt!(complete!(tag!("-"))) >>
        d: day >>
        ( Date::YMD{ year: y, month: m, day: d } )
        ));

// YYYY-MM-DD
named!(pub ordinal_date <Date>, do_parse!(
        y: year >>
        opt!(complete!(tag!("-"))) >>
        d: ord_day >>
        ( Date::Ordinal{ year: y, ddd: d } )
        ));

// YYYY-"W"WW-D
named!(pub iso_week_date <Date>, do_parse!(
        y: year >>
        opt!(complete!(tag!("-"))) >>
        tag!("W") >>
        w: week >>
        opt!(complete!(tag!("-"))) >>
        d: week_day >>
        ( Date::Week{ year: y, ww: w, d: d } )
        ));

named!(pub parse_date <Date>, alt!( ymd_date | iso_week_date | ordinal_date ) );

// TIME

// HH
named!(lower_hour <u32>, do_parse!(f:char_between!('0','1') >>
                                   s:char_between!('0','9') >>
                                   ( buf_to_u32(f)*10 + buf_to_u32(s) )));
named!(upper_hour <u32>, do_parse!(tag!("2") >>
                                   s:char_between!('0','4') >>
                                   (20+buf_to_u32(s))));
named!(hour <u32>, alt!(lower_hour | upper_hour));

// MM
named!(below_sixty <u32>, do_parse!(f:char_between!('0','5') >>
                                    s:char_between!('0','9') >>
                                    ( buf_to_u32(f)*10 + buf_to_u32(s) ) ));
named!(upto_sixty <u32>, alt!(below_sixty | map!(tag!("60"), |_| 60)));

named!(minute <u32>, call!(below_sixty));
named!(second <u32>, call!(upto_sixty));
named!(millisecond <u32>, map!( is_a!("0123456789"), |ms| buf_to_u32(ms) ) );

// HH:MM:[SS][.(m*)][(Z|+...|-...)]
named!(pub parse_time <Time>, do_parse!(
        h: hour >>
        opt!(complete!(tag!(":"))) >>
        m: minute >>
        s:  opt!(complete!( preceded!(opt!(tag!(":")), second))) >>
        ms: opt!(complete!( preceded!(tag!("."), millisecond))) >>
        z:  opt!(complete!( alt!( timezone_hour | timezone_utc) )) >>
        (
            Time {
                hour: h,
                minute: m,
                second: s.unwrap_or(0),
                millisecond: ms.unwrap_or(0),
                tz_offset_hours: z.unwrap_or((0,0)).0,
                tz_offset_minutes: z.unwrap_or((0,0)).1
            }
        )
        ));

named!(sign <i32>, alt!(
        tag!("-") => { |_| -1 } |
        tag!("+") => { |_| 1 }
        )
    );

named!(timezone_hour <(i32,i32)>, do_parse!(
        s: sign >>
        h: hour >>
        m: empty_or!(
            preceded!(opt!(tag!(":")), minute)
           ) >>
        ( (s * (h as i32) , s * (m.unwrap_or(0) as i32)) )
        ));

named!(timezone_utc <(i32,i32)>, map!(tag!("Z"), |_| (0,0)));

// Full ISO8601
named!(pub parse_datetime <DateTime>, do_parse!(
        d: parse_date >>
        tag!("T") >>
        t: parse_time >>
        (
            DateTime{
                date: d,
                time: t,
            }
        )
        ));

#[cfg(test)]
mod tests{

    use super::{year, month, day};
    use super::{hour, minute, second};
    use nom::IResult::*;

    #[test]
    fn test_year() {
        assert_eq!(Done(&[][..],   2015), year(b"2015"));
        assert_eq!(Done(&[][..],  -0333), year(b"-0333"));
        assert_eq!(Done(&b"-"[..], 2015), year(b"2015-"));
        assert!(year(b"abcd").is_err());
        assert!(year(b"2a03").is_err());
    }

    #[test]
    fn test_month() {
        assert_eq!(Done(&[][..], 1),    month(b"01"));
        assert_eq!(Done(&[][..], 6),    month(b"06"));
        assert_eq!(Done(&[][..], 12),   month(b"12"));
        assert_eq!(Done(&b"-"[..], 12), month(b"12-"));

        assert!(month(b"13").is_err());
        assert!(month(b"00").is_err());
    }

    #[test]
    fn test_day() {
        assert_eq!(Done(&[][..], 1),    day(b"01"));
        assert_eq!(Done(&[][..], 12),   day(b"12"));
        assert_eq!(Done(&[][..], 20),   day(b"20"));
        assert_eq!(Done(&[][..], 28),   day(b"28"));
        assert_eq!(Done(&[][..], 30),   day(b"30"));
        assert_eq!(Done(&[][..], 31),   day(b"31"));
        assert_eq!(Done(&b"-"[..], 31), day(b"31-"));

        assert!(day(b"00").is_err());
        assert!(day(b"32").is_err());
    }

    #[test]
    fn test_hour() {
        assert_eq!(Done(&[][..], 0),  hour(b"00"));
        assert_eq!(Done(&[][..], 1),  hour(b"01"));
        assert_eq!(Done(&[][..], 6),  hour(b"06"));
        assert_eq!(Done(&[][..], 12), hour(b"12"));
        assert_eq!(Done(&[][..], 13), hour(b"13"));
        assert_eq!(Done(&[][..], 20), hour(b"20"));
        assert_eq!(Done(&[][..], 24), hour(b"24"));

        assert!(hour(b"25").is_err());
        assert!(hour(b"30").is_err());
        assert!(hour(b"ab").is_err());
    }

    #[test]
    fn test_minute() {
        assert_eq!(Done(&[][..], 0),  minute(b"00"));
        assert_eq!(Done(&[][..], 1),  minute(b"01"));
        assert_eq!(Done(&[][..], 30), minute(b"30"));
        assert_eq!(Done(&[][..], 59), minute(b"59"));

        assert!(minute(b"60").is_err());
        assert!(minute(b"61").is_err());
        assert!(minute(b"ab").is_err());
    }

    #[test]
    fn test_second() {
        assert_eq!(Done(&[][..], 0),  second(b"00"));
        assert_eq!(Done(&[][..], 1),  second(b"01"));
        assert_eq!(Done(&[][..], 30), second(b"30"));
        assert_eq!(Done(&[][..], 59), second(b"59"));
        assert_eq!(Done(&[][..], 60), second(b"60"));

        assert!(second(b"61").is_err());
        assert!(second(b"ab").is_err());
    }

}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use rustc_serialize::json::{Json, ToJson};

pub struct Payload {
    pub aps: APS,
}

pub struct APS {
    pub alert: Option<APSAlert>,

    // The number to display as the badge of the app icon.
    pub badge: Option<u32>,

    // The name of a sound file in the app bundle or in the Library/Sounds folder of
    // the app’s data container.
    pub sound: Option<String>,

    // Provide this key with a value of 1 to indicate that new content is available.
    pub content_available: Option<u32>,

    // Provide this key with a string value that represents the identifier property.
    pub category: Option<String>,
}

pub enum APSAlert {
    Plain(String),
    Localized(APSLocalizedAlert),
}

pub struct APSLocalizedAlert {
    pub title: String,
    pub body: String,
    pub title_loc_key: Option<String>,
    pub title_loc_args: Option<Vec<String>>,
    pub action_loc_key: Option<String>,
    pub loc_key: String,
    pub loc_args: Vec<String>,
    pub launch_image: Option<String>,
}

impl Payload {
    pub fn new<S>(alert: APSAlert, badge: Option<u32>, sound: S) -> Payload
        where S: Into<String>
    {
        Payload {
            aps: APS {
                alert: Some(alert),
                badge: badge,
                sound: Some(sound.into()),
                content_available: None,
                category: None,
            },
        }
    }

    pub fn new_action_notification<S>(alert: APSAlert, badge: Option<u32>, sound: S, category: S) -> Payload
        where S: Into<String>
    {
        Payload {
            aps: APS {
                alert: Some(alert),
                badge: badge,
                sound: Some(sound.into()),
                content_available: None,
                category: Some(category.into()),
            },
        }
    }

    pub fn new_silent_notification() -> Payload {
        Payload {
            aps: APS {
                alert: None,
                badge: None,
                sound: None,
                content_available: Some(1),
                category: None,
            },
        }
    }

    pub fn to_string(&self) -> String {
        self.to_json().to_string()
    }

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

impl ToJson for Payload {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("aps".to_string(), self.aps.to_json());
        Json::Object(d)
    }
}

impl ToJson for APS {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        match self.alert {
            Some(APSAlert::Plain(ref s)) => {
                d.insert("alert".to_string(), s.to_json());
            }
            Some(APSAlert::Localized(ref l)) => {
                d.insert("alert".to_string(), l.to_json());
            }
            None => {}
        };
        if let Some(ref badge) = self.badge {
            d.insert("badge".to_string(), badge.to_json());
        }
        if let Some(ref sound) = self.sound {
            d.insert("sound".to_string(), sound.to_json());
        }
        if let Some(ref content_available) = self.content_available {
            d.insert("content-available".to_string(), content_available.to_json());
        }
        if let Some(ref category) = self.category {
            d.insert("category".to_string(), category.to_json());
        }
        Json::Object(d)
    }
}

impl ToJson for APSLocalizedAlert {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("title".to_string(), self.title.to_json());
        d.insert("body".to_string(), self.body.to_json());
        d.insert("title-loc-key".to_string(), match self.title_loc_key {
            Some(ref k) => k.to_json(),
            None => Json::Null,
        });
        d.insert("title-loc-args".to_string(), match self.title_loc_args {
            Some(ref a) => a.to_json(),
            None => Json::Null,
        });
        d.insert("action-loc-key".to_string(), match self.action_loc_key {
            Some(ref k) => k.to_json(),
            None => Json::Null,
        });
        d.insert("loc-key".to_string(), self.loc_key.to_json());
        d.insert("loc-args".to_string(), self.loc_args.to_json());
        if let Some(ref i) = self.launch_image {
            d.insert("launch-image".to_string(), i.to_json());
        }
        Json::Object(d)
    }
}
<commit_msg>Changes in payload<commit_after>use std::borrow::Cow;
use std::collections::BTreeMap;
use rustc_serialize::json::{Json, ToJson};

/// The Remote Notification Payload. Each remote notification includes a payload.
/// The payload contains information about how the system should alert the user as well
/// as any custom data you provide.
pub struct Payload<'a> {
    pub aps: APS<'a>,
}

impl<'a> Payload<'a> {
    pub fn new<S>(alert: APSAlert, badge: Option<u32>, sound: S) -> Payload<'a>
        where S: Into<Cow<'a, str>>
    {
        Payload {
            aps: APS {
                alert: Some(alert),
                badge: badge,
                sound: Some(sound.into()),
                content_available: None,
                category: None,
            },
        }
    }

    pub fn new_action_notification<S>(alert: APSAlert, badge: Option<u32>, sound: S, category: S) -> Payload<'a>
        where S: Into<Cow<'a, str>>
    {
        Payload {
            aps: APS {
                alert: Some(alert),
                badge: badge,
                sound: Some(sound.into()),
                content_available: None,
                category: Some(category.into()),
            },
        }
    }

    pub fn new_silent_notification() -> Payload<'a> {
        Payload {
            aps: APS {
                alert: None,
                badge: None,
                sound: None,
                content_available: Some(1),
                category: None,
            },
        }
    }

    pub fn to_string(&self) -> String {
        self.to_json().to_string()
    }

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

impl<'a> ToJson for Payload<'a> {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("aps".to_string(), self.aps.to_json());
        Json::Object(d)
    }
}

/// The APS can contain one or more properties that specify the following user notification types:
/// - an alert message to display to the user
/// - a number to badge the app icon with
/// - a sound to play
pub struct APS<'a> {
    /// If this property is included, the system displays a standard alert or a banner,
    /// based on the user’s setting.
    pub alert: Option<APSAlert>,

    /// The number to display as the badge of the app icon.
    pub badge: Option<u32>,

    /// The name of a sound file in the app bundle or in the Library/Sounds folder of
    /// the app’s data container.
    pub sound: Option<Cow<'a, str>>,

    /// Provide this key with a value of 1 to indicate that new content is available.
    pub content_available: Option<u32>,

    /// Provide this key with a string value that represents the identifier property.
    pub category: Option<Cow<'a, str>>,
}

impl<'a> ToJson for APS<'a> {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        match self.alert {
            Some(APSAlert::Plain(ref s)) => {
                d.insert("alert".to_string(), s.to_json());
            }
            Some(APSAlert::Localized(ref l)) => {
                d.insert("alert".to_string(), l.to_json());
            }
            None => {}
        };
        if let Some(ref badge) = self.badge {
            d.insert("badge".to_string(), badge.to_json());
        }
        if let Some(ref sound) = self.sound {
            d.insert("sound".to_string(), sound.to_json());
        }
        if let Some(ref content_available) = self.content_available {
            d.insert("content-available".to_string(), content_available.to_json());
        }
        if let Some(ref category) = self.category {
            d.insert("category".to_string(), category.to_json());
        }
        Json::Object(d)
    }
}

/// Can specify a string or a dictionary as the value of alert.
pub enum APSAlert {
    Plain(String),
    Localized(APSLocalizedAlert),
}

/// Child properties of the alert property.
pub struct APSLocalizedAlert {
    /// A short string describing the purpose of the notification
    pub title: String,

    /// The text of the alert message.
    pub body: String,

    /// The key to a title string in the Localizable.strings file for the current localization.
    pub title_loc_key: Option<String>,

    /// Variable string values to appear in place of the format specifiers in title-loc-key.
    pub title_loc_args: Option<Vec<String>>,

    /// If a string is specified, the system displays an alert that includes the Close and View buttons.
    pub action_loc_key: Option<String>,

    /// A key to an alert-message string in a Localizable.strings file for the current localization.
    pub loc_key: String,

    /// Variable string values to appear in place of the format specifiers in loc-key.
    pub loc_args: Vec<String>,

    /// The filename of an image file in the app bundle.
    /// The image is used as the launch image when users tap the action button or move the action slider.
    pub launch_image: Option<String>,
}

impl ToJson for APSLocalizedAlert {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("title".to_string(), self.title.to_json());
        d.insert("body".to_string(), self.body.to_json());
        d.insert("title-loc-key".to_string(), match self.title_loc_key {
            Some(ref k) => k.to_json(),
            None => Json::Null,
        });
        d.insert("title-loc-args".to_string(), match self.title_loc_args {
            Some(ref a) => a.to_json(),
            None => Json::Null,
        });
        d.insert("action-loc-key".to_string(), match self.action_loc_key {
            Some(ref k) => k.to_json(),
            None => Json::Null,
        });
        d.insert("loc-key".to_string(), self.loc_key.to_json());
        d.insert("loc-args".to_string(), self.loc_args.to_json());
        if let Some(ref i) = self.launch_image {
            d.insert("launch-image".to_string(), i.to_json());
        }
        Json::Object(d)
    }
}
<|endoftext|>


<commit_before>use command::Command;
use vm::VM;

pub struct Program {
    instructions : Vec<Command>,
    instruction_pointer: Option<usize>,
    pub is_seeking: bool,
    current_depth: u64,
    goal_depth: Option<u64>,
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            is_seeking: false,
            current_depth: 0,
            goal_depth: None,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() { self.instruction_pointer = Some(0); }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match self.instruction_pointer {
            None => {},
            Some(mut index) => {
                if self.is_seeking {
                    let (new_index, still_seeking) = self.seek_forward(index);
                    self.is_seeking = still_seeking;
                    index = new_index;
                }
                while index < self.instructions.len() {
                    let command = self.instructions[index];
                    if command == Command::JumpForward {
                        index = self.start_jump_forward(vm, index);
                    } else if command == Command::JumpBackward {
                        index = self.jump_backward(&vm, index);
                    } else {
                        vm.apply(command);
                        index = index + 1;
                    }
                }
                self.instruction_pointer = Some(index);
            }
        }
    }

    fn jump_backward (&mut self, vm: &VM, starting_index: usize) -> usize {
        match vm.cells[vm.data_pointer] {
            0 => {
                self.current_depth = self.current_depth - 1;
                starting_index + 1
            },
            _ => {
                let goal_depth = self.current_depth;
                for index in (0..starting_index).rev() {
                    match self.instructions[index] {
                        Command::JumpBackward => {
                            self.current_depth = self.current_depth + 1;
                        },
                        Command::JumpForward => {
                            if self.current_depth == goal_depth { return index + 1 }
                            self.current_depth = self.current_depth - 1;
                        },
                        _ => {},
                    }
                }
                panic!("No starting brace found!");
            },
        }
    }

    fn seek_forward(&mut self, starting_index: usize) -> (usize, bool) {
        let goal_depth = self.goal_depth.unwrap();
        for index in starting_index..self.instructions.len() {
            match self.instructions[index] {
                Command::JumpForward => self.current_depth = self.current_depth + 1,
                Command::JumpBackward => self.current_depth = self.current_depth - 1,
                _ => {},
            }
            if self.current_depth == goal_depth { return (index + 1, false) }
        }
        (self.instructions.len(), true)
    }

    fn start_jump_forward(&mut self, vm: &VM, index: usize) -> usize {
        if vm.cells[vm.data_pointer] == 0 {
            self.goal_depth = Some(self.current_depth);
            let (index, still_seeking) = self.seek_forward(index);
            self.is_seeking = still_seeking;
            return index;
        } else {
            self.current_depth = self.current_depth + 1;
            return index + 1;
        }
    }
}
<commit_msg>Add ProgramStatus enum<commit_after>use command::Command;
use vm::VM;

pub struct Program {
    instructions : Vec<Command>,
    instruction_pointer: Option<usize>,
    pub is_seeking: bool,
    current_depth: u64,
    goal_depth: Option<u64>,
}

enum ProgramStatus {
    Normal,
    Seeking(u64),
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            is_seeking: false,
            current_depth: 0,
            goal_depth: None,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() { self.instruction_pointer = Some(0); }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match self.instruction_pointer {
            None => {},
            Some(mut index) => {
                if self.is_seeking {
                    let (new_index, still_seeking) = self.seek_forward(index);
                    self.is_seeking = still_seeking;
                    index = new_index;
                }
                while index < self.instructions.len() {
                    let command = self.instructions[index];
                    if command == Command::JumpForward {
                        index = self.start_jump_forward(vm, index);
                    } else if command == Command::JumpBackward {
                        index = self.jump_backward(&vm, index);
                    } else {
                        vm.apply(command);
                        index = index + 1;
                    }
                }
                self.instruction_pointer = Some(index);
            }
        }
    }

    fn jump_backward (&mut self, vm: &VM, starting_index: usize) -> usize {
        match vm.cells[vm.data_pointer] {
            0 => {
                self.current_depth = self.current_depth - 1;
                starting_index + 1
            },
            _ => {
                let goal_depth = self.current_depth;
                for index in (0..starting_index).rev() {
                    match self.instructions[index] {
                        Command::JumpBackward => {
                            self.current_depth = self.current_depth + 1;
                        },
                        Command::JumpForward => {
                            if self.current_depth == goal_depth { return index + 1 }
                            self.current_depth = self.current_depth - 1;
                        },
                        _ => {},
                    }
                }
                panic!("No starting brace found!");
            },
        }
    }

    fn seek_forward(&mut self, starting_index: usize) -> (usize, bool) {
        let goal_depth = self.goal_depth.unwrap();
        for index in starting_index..self.instructions.len() {
            match self.instructions[index] {
                Command::JumpForward => self.current_depth = self.current_depth + 1,
                Command::JumpBackward => self.current_depth = self.current_depth - 1,
                _ => {},
            }
            if self.current_depth == goal_depth { return (index + 1, false) }
        }
        (self.instructions.len(), true)
    }

    fn start_jump_forward(&mut self, vm: &VM, index: usize) -> usize {
        if vm.cells[vm.data_pointer] == 0 {
            self.goal_depth = Some(self.current_depth);
            let (index, still_seeking) = self.seek_forward(index);
            self.is_seeking = still_seeking;
            return index;
        } else {
            self.current_depth = self.current_depth + 1;
            return index + 1;
        }
    }
}
<|endoftext|>