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

use dom::bindings::callback::ExceptionHandling::Report;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::FunctionBinding::Function;
use dom::bindings::global::global_object_for_js_object;
use dom::bindings::utils::Reflectable;
use dom::window::ScriptHelpers;
use euclid::length::Length;
use js::jsapi::{HandleValue, Heap, RootedValue};
use js::jsval::{JSVal, UndefinedValue};
use num::traits::Saturating;
use script_traits::{MsDuration, precise_time_ms};
use script_traits::{TimerEventChan, TimerEventId, TimerEventRequest, TimerSource};
use std::cell::Cell;
use std::cmp::{self, Ord, Ordering};
use std::default::Default;
use std::rc::Rc;
use std::sync::mpsc::Sender;
use util::mem::HeapSizeOf;
use util::str::DOMString;

#[derive(JSTraceable, PartialEq, Eq, Copy, Clone, HeapSizeOf, Hash, PartialOrd, Ord)]
pub struct TimerHandle(i32);

#[derive(JSTraceable, HeapSizeOf)]
#[privatize]
pub struct ActiveTimers {
    #[ignore_heap_size_of = "Defined in std"]
    timer_event_chan: Box<TimerEventChan + Send>,
    #[ignore_heap_size_of = "Defined in std"]
    scheduler_chan: Sender<TimerEventRequest>,
    next_timer_handle: Cell<TimerHandle>,
    timers: DOMRefCell<Vec<Timer>>,
    suspended_since: Cell<Option<MsDuration>>,
    /// Initially 0, increased whenever the associated document is reactivated
    /// by the amount of ms the document was inactive. The current time can be
    /// offset back by this amount for a coherent time across document
    /// activations.
    suspension_offset: Cell<MsDuration>,
    /// Calls to `fire_timer` with a different argument than this get ignored.
    /// They were previously scheduled and got invalidated when
    ///  - timers were suspended,
    ///  - the timer it was scheduled for got canceled or
    ///  - a timer was added with an earlier callback time. In this case the
    ///    original timer is rescheduled when it is the next one to get called.
    expected_event_id: Cell<TimerEventId>,
    /// The nesting level of the currently executing timer task or 0.
    nesting_level: Cell<u32>,
}

// Holder for the various JS values associated with setTimeout
// (ie. function value to invoke and all arguments to pass
//      to the function when calling it)
// TODO: Handle rooting during fire_timer when movable GC is turned on
#[derive(JSTraceable, HeapSizeOf)]
#[privatize]
struct Timer {
    handle: TimerHandle,
    source: TimerSource,
    callback: InternalTimerCallback,
    is_interval: IsInterval,
    nesting_level: u32,
    duration: MsDuration,
    next_call: MsDuration,
}

// Enum allowing more descriptive values for the is_interval field
#[derive(JSTraceable, PartialEq, Copy, Clone, HeapSizeOf)]
pub enum IsInterval {
    Interval,
    NonInterval,
}

impl Ord for Timer {
    fn cmp(&self, other: &Timer) -> Ordering {
        match self.next_call.cmp(&other.next_call).reverse() {
            Ordering::Equal => self.handle.cmp(&other.handle).reverse(),
            res @ _ => res
        }
    }
}

impl PartialOrd for Timer {
    fn partial_cmp(&self, other: &Timer) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Eq for Timer {}
impl PartialEq for Timer {
    fn eq(&self, other: &Timer) -> bool {
        self as *const Timer == other as *const Timer
    }
}

#[derive(Clone)]
pub enum TimerCallback {
    StringTimerCallback(DOMString),
    FunctionTimerCallback(Rc<Function>),
}

#[derive(JSTraceable, Clone)]
enum InternalTimerCallback {
    StringTimerCallback(DOMString),
    FunctionTimerCallback(Rc<Function>, Rc<Vec<Heap<JSVal>>>),
}

impl HeapSizeOf for InternalTimerCallback {
    fn heap_size_of_children(&self) -> usize {
        // FIXME: Rc<T> isn't HeapSizeOf and we can't ignore it due to #6870 and #6871
        0
    }
}

impl ActiveTimers {
    pub fn new(timer_event_chan: Box<TimerEventChan + Send>,
               scheduler_chan: Sender<TimerEventRequest>)
               -> ActiveTimers {
        ActiveTimers {
            timer_event_chan: timer_event_chan,
            scheduler_chan: scheduler_chan,
            next_timer_handle: Cell::new(TimerHandle(1)),
            timers: DOMRefCell::new(Vec::new()),
            suspended_since: Cell::new(None),
            suspension_offset: Cell::new(Length::new(0)),
            expected_event_id: Cell::new(TimerEventId(0)),
            nesting_level: Cell::new(0),
        }
    }

    // see https://html.spec.whatwg.org/multipage/#timer-initialisation-steps
    pub fn set_timeout_or_interval(&self,
                               callback: TimerCallback,
                               arguments: Vec<HandleValue>,
                               timeout: i32,
                               is_interval: IsInterval,
                               source: TimerSource)
                               -> i32 {
        assert!(self.suspended_since.get().is_none());

        // step 3
        let TimerHandle(new_handle) = self.next_timer_handle.get();
        self.next_timer_handle.set(TimerHandle(new_handle + 1));

        let timeout = cmp::max(0, timeout);
        // step 7
        let duration = self.clamp_duration(Length::new(timeout as u64));
        let next_call = self.base_time() + duration;

        let callback = match callback {
            TimerCallback::StringTimerCallback(code_str) =>
                InternalTimerCallback::StringTimerCallback(code_str),
            TimerCallback::FunctionTimerCallback(function) => {
                // This is a bit complicated, but this ensures that the vector's
                // buffer isn't reallocated (and moved) after setting the Heap values
                let mut args = Vec::with_capacity(arguments.len());
                for _ in 0..arguments.len() {
                    args.push(Heap::default());
                }
                for (i, item) in arguments.iter().enumerate() {
                    args.get_mut(i).unwrap().set(item.get());
                }
                InternalTimerCallback::FunctionTimerCallback(function, Rc::new(args))
            }
        };

        let timer = Timer {
            handle: TimerHandle(new_handle),
            source: source,
            callback: callback,
            is_interval: is_interval,
            duration: duration,
            // step 6
            nesting_level: self.nesting_level.get() + 1,
            next_call: next_call,
        };

        self.insert_timer(timer);

        let TimerHandle(max_handle) = self.timers.borrow().last().unwrap().handle;
        if max_handle == new_handle {
            self.schedule_timer_call();
        }

        // step 10
        new_handle
    }

    pub fn clear_timeout_or_interval(&self, handle: i32) {
        let handle = TimerHandle(handle);
        let was_next = self.is_next_timer(handle);

        self.timers.borrow_mut().retain(|t| t.handle != handle);

        if was_next {
            self.invalidate_expected_event_id();
            self.schedule_timer_call();
        }
    }

    // see https://html.spec.whatwg.org/multipage/#timer-initialisation-steps
    #[allow(unsafe_code)]
    pub fn fire_timer<T: Reflectable>(&self, id: TimerEventId, this: &T) {
        let expected_id = self.expected_event_id.get();
        if expected_id != id {
            debug!("ignoring timer fire event {:?} (expected {:?}", id, expected_id);
            return;
        }

        assert!(self.suspended_since.get().is_none());

        let base_time = self.base_time();

        // Since the event id was the expected one, at least one timer should be due.
        assert!(base_time >= self.timers.borrow().last().unwrap().next_call);

        loop {
            let timer = {
                let mut timers = self.timers.borrow_mut();

                if timers.is_empty() || timers.last().unwrap().next_call > base_time {
                    break;
                }

                timers.pop().unwrap()
            };
            let callback = timer.callback.clone();

            // prep for step 6 in nested set_timeout_or_interval calls
            self.nesting_level.set(timer.nesting_level);

            // step 4.3
            if timer.is_interval == IsInterval::Interval {
                let mut timer = timer;

                // step 7
                timer.duration = self.clamp_duration(timer.duration);
                // step 8, 9
                timer.nesting_level += 1;
                timer.next_call = base_time + timer.duration;
                self.insert_timer(timer);
            }

            // step 14
            match callback {
                InternalTimerCallback::StringTimerCallback(code_str) => {
                    let proxy = this.reflector().get_jsobject();
                    let cx = global_object_for_js_object(proxy.get()).r().get_cx();
                    let mut rval = RootedValue::new(cx, UndefinedValue());

                    this.evaluate_js_on_global_with_result(&code_str, rval.handle_mut());
                },
                InternalTimerCallback::FunctionTimerCallback(function, arguments) => {
                    let arguments: Vec<JSVal> = arguments.iter().map(|arg| arg.get()).collect();
                    let arguments = arguments.iter().by_ref().map(|arg| unsafe {
                        HandleValue::from_marked_location(arg)
                    }).collect();

                    let _ = function.Call_(this, arguments, Report);
                }
            };

            self.nesting_level.set(0);
        }

        self.schedule_timer_call();
    }

    fn insert_timer(&self, timer: Timer) {
        let mut timers = self.timers.borrow_mut();
        let insertion_index = timers.binary_search(&timer).err().unwrap();
        timers.insert(insertion_index, timer);
    }

    fn is_next_timer(&self, handle: TimerHandle) -> bool {
        match self.timers.borrow().last() {
            None => false,
            Some(ref max_timer) => max_timer.handle == handle
        }
    }

    fn schedule_timer_call(&self) {
        assert!(self.suspended_since.get().is_none());

        let timers = self.timers.borrow();

        if let Some(timer) = timers.last() {
            let expected_event_id = self.invalidate_expected_event_id();

            let delay = Length::new(timer.next_call.get().saturating_sub(precise_time_ms().get()));
            let request = TimerEventRequest(self.timer_event_chan.clone(), timer.source,
                                            expected_event_id, delay);
            self.scheduler_chan.send(request).unwrap();
        }
    }

    pub fn suspend(&self) {
        assert!(self.suspended_since.get().is_none());

        self.suspended_since.set(Some(precise_time_ms()));
        self.invalidate_expected_event_id();
    }

    pub fn resume(&self) {
        assert!(self.suspended_since.get().is_some());

        let additional_offset = match self.suspended_since.get() {
            Some(suspended_since) => precise_time_ms() - suspended_since,
            None => panic!("Timers are not suspended.")
        };

        self.suspension_offset.set(self.suspension_offset.get() + additional_offset);

        self.schedule_timer_call();
    }

    fn base_time(&self) -> MsDuration {
        precise_time_ms() - self.suspension_offset.get()
    }

    // see step 7 of https://html.spec.whatwg.org/multipage/#timer-initialisation-steps
    fn clamp_duration(&self, unclamped: MsDuration) -> MsDuration {
        let ms = if self.nesting_level.get() > 5 {
            4
        } else {
            0
        };

        cmp::max(Length::new(ms), unclamped)
    }

    fn invalidate_expected_event_id(&self) -> TimerEventId {
        let TimerEventId(currently_expected) = self.expected_event_id.get();
        let next_id = TimerEventId(currently_expected + 1);
        debug!("invalidating expected timer (was {:?}, now {:?}", currently_expected, next_id);
        self.expected_event_id.set(next_id);
        next_id
    }
}
<commit_msg>Fixed panic in ActiveTimers.set_timeout_or_interval.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::callback::ExceptionHandling::Report;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::FunctionBinding::Function;
use dom::bindings::global::global_object_for_js_object;
use dom::bindings::utils::Reflectable;
use dom::window::ScriptHelpers;
use euclid::length::Length;
use js::jsapi::{HandleValue, Heap, RootedValue};
use js::jsval::{JSVal, UndefinedValue};
use num::traits::Saturating;
use script_traits::{MsDuration, precise_time_ms};
use script_traits::{TimerEventChan, TimerEventId, TimerEventRequest, TimerSource};
use std::cell::Cell;
use std::cmp::{self, Ord, Ordering};
use std::default::Default;
use std::rc::Rc;
use std::sync::mpsc::Sender;
use util::mem::HeapSizeOf;
use util::str::DOMString;

#[derive(JSTraceable, PartialEq, Eq, Copy, Clone, HeapSizeOf, Hash, PartialOrd, Ord)]
pub struct TimerHandle(i32);

#[derive(JSTraceable, HeapSizeOf)]
#[privatize]
pub struct ActiveTimers {
    #[ignore_heap_size_of = "Defined in std"]
    timer_event_chan: Box<TimerEventChan + Send>,
    #[ignore_heap_size_of = "Defined in std"]
    scheduler_chan: Sender<TimerEventRequest>,
    next_timer_handle: Cell<TimerHandle>,
    timers: DOMRefCell<Vec<Timer>>,
    suspended_since: Cell<Option<MsDuration>>,
    /// Initially 0, increased whenever the associated document is reactivated
    /// by the amount of ms the document was inactive. The current time can be
    /// offset back by this amount for a coherent time across document
    /// activations.
    suspension_offset: Cell<MsDuration>,
    /// Calls to `fire_timer` with a different argument than this get ignored.
    /// They were previously scheduled and got invalidated when
    ///  - timers were suspended,
    ///  - the timer it was scheduled for got canceled or
    ///  - a timer was added with an earlier callback time. In this case the
    ///    original timer is rescheduled when it is the next one to get called.
    expected_event_id: Cell<TimerEventId>,
    /// The nesting level of the currently executing timer task or 0.
    nesting_level: Cell<u32>,
}

// Holder for the various JS values associated with setTimeout
// (ie. function value to invoke and all arguments to pass
//      to the function when calling it)
// TODO: Handle rooting during fire_timer when movable GC is turned on
#[derive(JSTraceable, HeapSizeOf)]
#[privatize]
struct Timer {
    handle: TimerHandle,
    source: TimerSource,
    callback: InternalTimerCallback,
    is_interval: IsInterval,
    nesting_level: u32,
    duration: MsDuration,
    next_call: MsDuration,
}

// Enum allowing more descriptive values for the is_interval field
#[derive(JSTraceable, PartialEq, Copy, Clone, HeapSizeOf)]
pub enum IsInterval {
    Interval,
    NonInterval,
}

impl Ord for Timer {
    fn cmp(&self, other: &Timer) -> Ordering {
        match self.next_call.cmp(&other.next_call).reverse() {
            Ordering::Equal => self.handle.cmp(&other.handle).reverse(),
            res @ _ => res
        }
    }
}

impl PartialOrd for Timer {
    fn partial_cmp(&self, other: &Timer) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Eq for Timer {}
impl PartialEq for Timer {
    fn eq(&self, other: &Timer) -> bool {
        self as *const Timer == other as *const Timer
    }
}

#[derive(Clone)]
pub enum TimerCallback {
    StringTimerCallback(DOMString),
    FunctionTimerCallback(Rc<Function>),
}

#[derive(JSTraceable, Clone)]
enum InternalTimerCallback {
    StringTimerCallback(DOMString),
    FunctionTimerCallback(Rc<Function>, Rc<Vec<Heap<JSVal>>>),
}

impl HeapSizeOf for InternalTimerCallback {
    fn heap_size_of_children(&self) -> usize {
        // FIXME: Rc<T> isn't HeapSizeOf and we can't ignore it due to #6870 and #6871
        0
    }
}

impl ActiveTimers {
    pub fn new(timer_event_chan: Box<TimerEventChan + Send>,
               scheduler_chan: Sender<TimerEventRequest>)
               -> ActiveTimers {
        ActiveTimers {
            timer_event_chan: timer_event_chan,
            scheduler_chan: scheduler_chan,
            next_timer_handle: Cell::new(TimerHandle(1)),
            timers: DOMRefCell::new(Vec::new()),
            suspended_since: Cell::new(None),
            suspension_offset: Cell::new(Length::new(0)),
            expected_event_id: Cell::new(TimerEventId(0)),
            nesting_level: Cell::new(0),
        }
    }

    // see https://html.spec.whatwg.org/multipage/#timer-initialisation-steps
    pub fn set_timeout_or_interval(&self,
                               callback: TimerCallback,
                               arguments: Vec<HandleValue>,
                               timeout: i32,
                               is_interval: IsInterval,
                               source: TimerSource)
                               -> i32 {
        // step 3
        let TimerHandle(new_handle) = self.next_timer_handle.get();
        self.next_timer_handle.set(TimerHandle(new_handle + 1));

        let timeout = cmp::max(0, timeout);
        // step 7
        let duration = self.clamp_duration(Length::new(timeout as u64));
        let next_call = self.base_time() + duration;

        let callback = match callback {
            TimerCallback::StringTimerCallback(code_str) =>
                InternalTimerCallback::StringTimerCallback(code_str),
            TimerCallback::FunctionTimerCallback(function) => {
                // This is a bit complicated, but this ensures that the vector's
                // buffer isn't reallocated (and moved) after setting the Heap values
                let mut args = Vec::with_capacity(arguments.len());
                for _ in 0..arguments.len() {
                    args.push(Heap::default());
                }
                for (i, item) in arguments.iter().enumerate() {
                    args.get_mut(i).unwrap().set(item.get());
                }
                InternalTimerCallback::FunctionTimerCallback(function, Rc::new(args))
            }
        };

        let timer = Timer {
            handle: TimerHandle(new_handle),
            source: source,
            callback: callback,
            is_interval: is_interval,
            duration: duration,
            // step 6
            nesting_level: self.nesting_level.get() + 1,
            next_call: next_call,
        };

        self.insert_timer(timer);

        let TimerHandle(max_handle) = self.timers.borrow().last().unwrap().handle;
        if max_handle == new_handle {
            self.schedule_timer_call();
        }

        // step 10
        new_handle
    }

    pub fn clear_timeout_or_interval(&self, handle: i32) {
        let handle = TimerHandle(handle);
        let was_next = self.is_next_timer(handle);

        self.timers.borrow_mut().retain(|t| t.handle != handle);

        if was_next {
            self.invalidate_expected_event_id();
            self.schedule_timer_call();
        }
    }

    // see https://html.spec.whatwg.org/multipage/#timer-initialisation-steps
    #[allow(unsafe_code)]
    pub fn fire_timer<T: Reflectable>(&self, id: TimerEventId, this: &T) {
        let expected_id = self.expected_event_id.get();
        if expected_id != id {
            debug!("ignoring timer fire event {:?} (expected {:?}", id, expected_id);
            return;
        }

        assert!(self.suspended_since.get().is_none());

        let base_time = self.base_time();

        // Since the event id was the expected one, at least one timer should be due.
        assert!(base_time >= self.timers.borrow().last().unwrap().next_call);

        loop {
            let timer = {
                let mut timers = self.timers.borrow_mut();

                if timers.is_empty() || timers.last().unwrap().next_call > base_time {
                    break;
                }

                timers.pop().unwrap()
            };
            let callback = timer.callback.clone();

            // prep for step 6 in nested set_timeout_or_interval calls
            self.nesting_level.set(timer.nesting_level);

            // step 4.3
            if timer.is_interval == IsInterval::Interval {
                let mut timer = timer;

                // step 7
                timer.duration = self.clamp_duration(timer.duration);
                // step 8, 9
                timer.nesting_level += 1;
                timer.next_call = base_time + timer.duration;
                self.insert_timer(timer);
            }

            // step 14
            match callback {
                InternalTimerCallback::StringTimerCallback(code_str) => {
                    let proxy = this.reflector().get_jsobject();
                    let cx = global_object_for_js_object(proxy.get()).r().get_cx();
                    let mut rval = RootedValue::new(cx, UndefinedValue());

                    this.evaluate_js_on_global_with_result(&code_str, rval.handle_mut());
                },
                InternalTimerCallback::FunctionTimerCallback(function, arguments) => {
                    let arguments: Vec<JSVal> = arguments.iter().map(|arg| arg.get()).collect();
                    let arguments = arguments.iter().by_ref().map(|arg| unsafe {
                        HandleValue::from_marked_location(arg)
                    }).collect();

                    let _ = function.Call_(this, arguments, Report);
                }
            };

            self.nesting_level.set(0);
        }

        self.schedule_timer_call();
    }

    fn insert_timer(&self, timer: Timer) {
        let mut timers = self.timers.borrow_mut();
        let insertion_index = timers.binary_search(&timer).err().unwrap();
        timers.insert(insertion_index, timer);
    }

    fn is_next_timer(&self, handle: TimerHandle) -> bool {
        match self.timers.borrow().last() {
            None => false,
            Some(ref max_timer) => max_timer.handle == handle
        }
    }

    fn schedule_timer_call(&self) {
        if self.suspended_since.get().is_some() {
            // The timer will be scheduled when the pipeline is thawed.
            return;
        }

        let timers = self.timers.borrow();

        if let Some(timer) = timers.last() {
            let expected_event_id = self.invalidate_expected_event_id();

            let delay = Length::new(timer.next_call.get().saturating_sub(precise_time_ms().get()));
            let request = TimerEventRequest(self.timer_event_chan.clone(), timer.source,
                                            expected_event_id, delay);
            self.scheduler_chan.send(request).unwrap();
        }
    }

    pub fn suspend(&self) {
        assert!(self.suspended_since.get().is_none());

        self.suspended_since.set(Some(precise_time_ms()));
        self.invalidate_expected_event_id();
    }

    pub fn resume(&self) {
        assert!(self.suspended_since.get().is_some());

        let additional_offset = match self.suspended_since.get() {
            Some(suspended_since) => precise_time_ms() - suspended_since,
            None => panic!("Timers are not suspended.")
        };

        self.suspension_offset.set(self.suspension_offset.get() + additional_offset);

        self.schedule_timer_call();
    }

    fn base_time(&self) -> MsDuration {
        let offset = self.suspension_offset.get();

        match self.suspended_since.get() {
            Some(time) => time - offset,
            None => precise_time_ms() - offset,
        }
    }

    // see step 7 of https://html.spec.whatwg.org/multipage/#timer-initialisation-steps
    fn clamp_duration(&self, unclamped: MsDuration) -> MsDuration {
        let ms = if self.nesting_level.get() > 5 {
            4
        } else {
            0
        };

        cmp::max(Length::new(ms), unclamped)
    }

    fn invalidate_expected_event_id(&self) -> TimerEventId {
        let TimerEventId(currently_expected) = self.expected_event_id.get();
        let next_id = TimerEventId(currently_expected + 1);
        debug!("invalidating expected timer (was {:?}, now {:?}", currently_expected, next_id);
        self.expected_event_id.set(next_id);
        next_id
    }
}
<|endoftext|>


<commit_before>fn main() {
	println!("hello, world!");
}
<commit_msg>rust: tutorial through chapter 4<commit_after>// main defines the program entry point
fn main() {
	// println!() is a macro which functions similar to C printf()
	println!("hello, {}!\n", "world");

	let item = "apple";
	let price: f32 =
		if item == "apple" {
			1.00
		} else if item == "banana" {
			1.50
		} else {
			2.00
		};

	println!("The price of {} is {}", item, price);
}
<|endoftext|>


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

use super::constants::*;
use super::evdev::{grab_evdev, ungrab_evdev};
use super::virtio_input_event;
use super::InputError;
use super::Result;
use data_model::DataInit;
use std::collections::VecDeque;
use std::io::Read;
use std::io::Write;
use std::mem::size_of;
use std::os::unix::io::{AsRawFd, RawFd};

#[derive(Copy, Clone, Debug, Default)]
#[repr(C)]
pub struct input_event {
    timestamp_fields: [u64; 2],
    pub type_: u16,
    pub code: u16,
    pub value: u32,
}
// Safe because it only has data and has no implicit padding.
unsafe impl DataInit for input_event {}

impl input_event {
    const EVENT_SIZE: usize = size_of::<input_event>();

    fn from_virtio_input_event(other: &virtio_input_event) -> input_event {
        input_event {
            timestamp_fields: [0, 0],
            type_: other.type_.into(),
            code: other.code.into(),
            value: other.value.into(),
        }
    }
}

/// Encapsulates a socket or device node into an abstract event source, providing a common
/// interface.
/// It supports read and write operations to provide and accept events just like an event device
/// node would, except that it handles virtio_input_event instead of input_event structures.
/// It's necessary to call receive_events() before events are available for read.
pub trait EventSource: Read + Write + AsRawFd {
    /// Perform any necessary initialization before receiving and sending events from/to the source.
    fn init(&mut self) -> Result<()> {
        Ok(())
    }
    /// Perform any necessary cleanup when the device will no longer be used.
    fn finalize(&mut self) -> Result<()> {
        Ok(())
    }

    /// Receive events from the source, filters them and stores them in a queue for future
    /// consumption by reading from this object. Returns the number of new non filtered events
    /// received. This function may block waiting for events to be available.
    fn receive_events(&mut self) -> Result<usize>;
    /// Returns the number of received events that have not been filtered or consumed yet.
    fn available_events_count(&self) -> usize;
}

// Try to read 16 events at a time to match what the linux guest driver does.
const READ_BUFFER_SIZE: usize = 16 * size_of::<input_event>();

// The read buffer needs to be aligned to the alignment of input_event, which is aligned as u64
#[repr(align(8))]
pub struct ReadBuffer {
    buffer: [u8; READ_BUFFER_SIZE],
}

/// Encapsulates implementation details common to all kinds of event sources.
pub struct EventSourceImpl<T> {
    source: T,
    queue: VecDeque<virtio_input_event>,
    read_buffer: ReadBuffer,
    // The read index accounts for incomplete events read previously.
    read_idx: usize,
}

// Reads input events from the source.
// Events are originally read as input_event structs and converted to virtio_input_event internally.
impl<T: Read> EventSourceImpl<T> {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        let mut bytes = 0usize;
        for evt_slice in buf.chunks_exact_mut(virtio_input_event::EVENT_SIZE) {
            match self.queue.pop_front() {
                None => {
                    break;
                }
                Some(evt) => {
                    evt_slice.copy_from_slice(evt.as_slice());
                    bytes += evt_slice.len();
                }
            }
        }
        Ok(bytes)
    }
}

// Writes input events to the source.
// Events come as virtio_input_event structs and are converted to input_event internally.
impl<T: Write> EventSourceImpl<T> {
    fn write<F: Fn(&virtio_input_event) -> bool>(
        &mut self,
        buf: &[u8],
        event_filter: F,
    ) -> std::io::Result<usize> {
        for evt_slice in buf.chunks_exact(virtio_input_event::EVENT_SIZE) {
            // Don't use from_slice() here, the buffer is not guaranteed to be properly aligned.
            let mut vio_evt = virtio_input_event::new(0, 0, 0);
            vio_evt.as_mut_slice().copy_from_slice(evt_slice);
            if !event_filter(&vio_evt) {
                continue;
            }
            let evt = input_event::from_virtio_input_event(&vio_evt);
            self.source.write_all(evt.as_slice())?;
        }

        let len = buf.len() - buf.len() % virtio_input_event::EVENT_SIZE;
        Ok(len)
    }

    fn flush(&mut self) -> std::io::Result<()> {
        self.source.flush()
    }
}

impl<T: AsRawFd> EventSourceImpl<T> {
    fn as_raw_fd(&self) -> RawFd {
        self.source.as_raw_fd()
    }
}

impl<T> EventSourceImpl<T>
where
    T: Read + Write + AsRawFd,
{
    // Receive events from the source and store them in a queue, unless they should be filtered out.
    fn receive_events<F: Fn(&input_event) -> bool>(&mut self, event_filter: F) -> Result<usize> {
        let read = self
            .source
            .read(&mut self.read_buffer.buffer[self.read_idx..])
            .map_err(|e| InputError::EventsReadError(e))?;
        let buff_size = read + self.read_idx;

        for evt_slice in self
            .read_buffer
            .buffer
            .chunks_exact(input_event::EVENT_SIZE)
        {
            let input_evt = match input_event::from_slice(evt_slice) {
                Some(x) => x,
                None => {
                    // This shouldn't happen because all slices (even the last one) are guaranteed
                    // to have the correct size and be properly aligned.
                    error!(
                        "Failed converting a slice of sice {} to input_event",
                        evt_slice.len()
                    );
                    // Skipping the event here effectively means no events will be received, because
                    // if from_slice fails once it will fail always.
                    continue;
                }
            };
            if !event_filter(&input_evt) {
                continue;
            }
            let vio_evt = virtio_input_event::from_input_event(input_evt);
            self.queue.push_back(vio_evt);
        }

        let remainder = buff_size % input_event::EVENT_SIZE;
        // If there is an incomplete event at the end of the buffer, it needs to be moved to the
        // beginning and the next read operation must write right after it.
        if remainder != 0 {
            warn!("read incomplete event from source");
            // The copy should only happen if there is at least one complete event in the buffer,
            // otherwise source and destination would be the same.
            if buff_size != remainder {
                let (des, src) = self.read_buffer.buffer.split_at_mut(buff_size - remainder);
                des[..remainder].copy_from_slice(src);
            }
        }
        self.read_idx = remainder;

        let received_events = buff_size / input_event::EVENT_SIZE;

        Ok(received_events)
    }

    fn available_events(&self) -> usize {
        self.queue.len()
    }

    fn new(source: T) -> EventSourceImpl<T> {
        EventSourceImpl {
            source,
            queue: VecDeque::new(),
            read_buffer: ReadBuffer {
                buffer: [0u8; READ_BUFFER_SIZE],
            },
            read_idx: 0,
        }
    }
}

/// Encapsulates a (unix) socket as an event source.
pub struct SocketEventSource<T> {
    evt_source_impl: EventSourceImpl<T>,
}

impl<T> SocketEventSource<T>
where
    T: Read + Write + AsRawFd,
{
    pub fn new(source: T) -> SocketEventSource<T> {
        SocketEventSource {
            evt_source_impl: EventSourceImpl::new(source),
        }
    }
}

impl<T: Read> Read for SocketEventSource<T> {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        self.evt_source_impl.read(buf)
    }
}

impl<T> Write for SocketEventSource<T>
where
    T: Read + Write + AsRawFd,
{
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        self.evt_source_impl.write(buf, |_evt| true)
    }

    fn flush(&mut self) -> std::io::Result<()> {
        self.evt_source_impl.flush()
    }
}

impl<T: AsRawFd> AsRawFd for SocketEventSource<T> {
    fn as_raw_fd(&self) -> RawFd {
        self.evt_source_impl.as_raw_fd()
    }
}

impl<T> EventSource for SocketEventSource<T>
where
    T: Read + Write + AsRawFd,
{
    fn init(&mut self) -> Result<()> {
        Ok(())
    }

    fn finalize(&mut self) -> Result<()> {
        ungrab_evdev(self)
    }

    fn receive_events(&mut self) -> Result<usize> {
        self.evt_source_impl.receive_events(|_evt| true)
    }

    fn available_events_count(&self) -> usize {
        self.evt_source_impl.available_events()
    }
}

/// Encapsulates an event device node as an event source
pub struct EvdevEventSource<T> {
    evt_source_impl: EventSourceImpl<T>,
}

impl<T> EvdevEventSource<T>
where
    T: Read + Write + AsRawFd,
{
    pub fn new(source: T) -> EvdevEventSource<T> {
        EvdevEventSource {
            evt_source_impl: EventSourceImpl::new(source),
        }
    }
}

impl<T: Read> Read for EvdevEventSource<T> {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        self.evt_source_impl.read(buf)
    }
}

impl<T> Write for EvdevEventSource<T>
where
    T: Read + Write + AsRawFd,
{
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        self.evt_source_impl.write(buf, |evt| {
            // Miscellaneous events produced by the device are sent back to it by the kernel input
            // subsystem, but because these events are handled by the host kernel as well as the
            // guest the device would get them twice. Which would prompt the device to send the
            // event to the guest again entering an infinite loop.
            evt.type_ != EV_MSC
        })
    }

    fn flush(&mut self) -> std::io::Result<()> {
        self.evt_source_impl.flush()
    }
}

impl<T: AsRawFd> AsRawFd for EvdevEventSource<T> {
    fn as_raw_fd(&self) -> RawFd {
        self.evt_source_impl.as_raw_fd()
    }
}

impl<T> EventSource for EvdevEventSource<T>
where
    T: Read + Write + AsRawFd,
{
    fn init(&mut self) -> Result<()> {
        grab_evdev(self)
    }

    fn finalize(&mut self) -> Result<()> {
        ungrab_evdev(self)
    }

    fn receive_events(&mut self) -> Result<usize> {
        self.evt_source_impl.receive_events(|_evt| true)
    }

    fn available_events_count(&self) -> usize {
        self.evt_source_impl.available_events()
    }
}
<commit_msg>Input device: Don't send more events than received from the source<commit_after>// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use super::constants::*;
use super::evdev::{grab_evdev, ungrab_evdev};
use super::virtio_input_event;
use super::InputError;
use super::Result;
use data_model::DataInit;
use std::collections::VecDeque;
use std::io::Read;
use std::io::Write;
use std::mem::size_of;
use std::os::unix::io::{AsRawFd, RawFd};

#[derive(Copy, Clone, Debug, Default)]
#[repr(C)]
pub struct input_event {
    timestamp_fields: [u64; 2],
    pub type_: u16,
    pub code: u16,
    pub value: u32,
}
// Safe because it only has data and has no implicit padding.
unsafe impl DataInit for input_event {}

impl input_event {
    const EVENT_SIZE: usize = size_of::<input_event>();

    fn from_virtio_input_event(other: &virtio_input_event) -> input_event {
        input_event {
            timestamp_fields: [0, 0],
            type_: other.type_.into(),
            code: other.code.into(),
            value: other.value.into(),
        }
    }
}

/// Encapsulates a socket or device node into an abstract event source, providing a common
/// interface.
/// It supports read and write operations to provide and accept events just like an event device
/// node would, except that it handles virtio_input_event instead of input_event structures.
/// It's necessary to call receive_events() before events are available for read.
pub trait EventSource: Read + Write + AsRawFd {
    /// Perform any necessary initialization before receiving and sending events from/to the source.
    fn init(&mut self) -> Result<()> {
        Ok(())
    }
    /// Perform any necessary cleanup when the device will no longer be used.
    fn finalize(&mut self) -> Result<()> {
        Ok(())
    }

    /// Receive events from the source, filters them and stores them in a queue for future
    /// consumption by reading from this object. Returns the number of new non filtered events
    /// received. This function may block waiting for events to be available.
    fn receive_events(&mut self) -> Result<usize>;
    /// Returns the number of received events that have not been filtered or consumed yet.
    fn available_events_count(&self) -> usize;
}

// Try to read 16 events at a time to match what the linux guest driver does.
const READ_BUFFER_SIZE: usize = 16 * size_of::<input_event>();

// The read buffer needs to be aligned to the alignment of input_event, which is aligned as u64
#[repr(align(8))]
pub struct ReadBuffer {
    buffer: [u8; READ_BUFFER_SIZE],
}

/// Encapsulates implementation details common to all kinds of event sources.
pub struct EventSourceImpl<T> {
    source: T,
    queue: VecDeque<virtio_input_event>,
    read_buffer: ReadBuffer,
    // The read index accounts for incomplete events read previously.
    read_idx: usize,
}

// Reads input events from the source.
// Events are originally read as input_event structs and converted to virtio_input_event internally.
impl<T: Read> EventSourceImpl<T> {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        let mut bytes = 0usize;
        for evt_slice in buf.chunks_exact_mut(virtio_input_event::EVENT_SIZE) {
            match self.queue.pop_front() {
                None => {
                    break;
                }
                Some(evt) => {
                    evt_slice.copy_from_slice(evt.as_slice());
                    bytes += evt_slice.len();
                }
            }
        }
        Ok(bytes)
    }
}

// Writes input events to the source.
// Events come as virtio_input_event structs and are converted to input_event internally.
impl<T: Write> EventSourceImpl<T> {
    fn write<F: Fn(&virtio_input_event) -> bool>(
        &mut self,
        buf: &[u8],
        event_filter: F,
    ) -> std::io::Result<usize> {
        for evt_slice in buf.chunks_exact(virtio_input_event::EVENT_SIZE) {
            // Don't use from_slice() here, the buffer is not guaranteed to be properly aligned.
            let mut vio_evt = virtio_input_event::new(0, 0, 0);
            vio_evt.as_mut_slice().copy_from_slice(evt_slice);
            if !event_filter(&vio_evt) {
                continue;
            }
            let evt = input_event::from_virtio_input_event(&vio_evt);
            self.source.write_all(evt.as_slice())?;
        }

        let len = buf.len() - buf.len() % virtio_input_event::EVENT_SIZE;
        Ok(len)
    }

    fn flush(&mut self) -> std::io::Result<()> {
        self.source.flush()
    }
}

impl<T: AsRawFd> EventSourceImpl<T> {
    fn as_raw_fd(&self) -> RawFd {
        self.source.as_raw_fd()
    }
}

impl<T> EventSourceImpl<T>
where
    T: Read + Write + AsRawFd,
{
    // Receive events from the source and store them in a queue, unless they should be filtered out.
    fn receive_events<F: Fn(&input_event) -> bool>(&mut self, event_filter: F) -> Result<usize> {
        let read = self
            .source
            .read(&mut self.read_buffer.buffer[self.read_idx..])
            .map_err(|e| InputError::EventsReadError(e))?;
        let buff_size = read + self.read_idx;

        for evt_slice in self.read_buffer.buffer[..buff_size].chunks_exact(input_event::EVENT_SIZE)
        {
            let input_evt = match input_event::from_slice(evt_slice) {
                Some(x) => x,
                None => {
                    // This shouldn't happen because all slices (even the last one) are guaranteed
                    // to have the correct size and be properly aligned.
                    error!(
                        "Failed converting a slice of sice {} to input_event",
                        evt_slice.len()
                    );
                    // Skipping the event here effectively means no events will be received, because
                    // if from_slice fails once it will fail always.
                    continue;
                }
            };
            if !event_filter(&input_evt) {
                continue;
            }
            let vio_evt = virtio_input_event::from_input_event(input_evt);
            self.queue.push_back(vio_evt);
        }

        let remainder = buff_size % input_event::EVENT_SIZE;
        // If there is an incomplete event at the end of the buffer, it needs to be moved to the
        // beginning and the next read operation must write right after it.
        if remainder != 0 {
            warn!("read incomplete event from source");
            // The copy should only happen if there is at least one complete event in the buffer,
            // otherwise source and destination would be the same.
            if buff_size != remainder {
                let (des, src) = self.read_buffer.buffer.split_at_mut(buff_size - remainder);
                des[..remainder].copy_from_slice(src);
            }
        }
        self.read_idx = remainder;

        let received_events = buff_size / input_event::EVENT_SIZE;

        Ok(received_events)
    }

    fn available_events(&self) -> usize {
        self.queue.len()
    }

    fn new(source: T) -> EventSourceImpl<T> {
        EventSourceImpl {
            source,
            queue: VecDeque::new(),
            read_buffer: ReadBuffer {
                buffer: [0u8; READ_BUFFER_SIZE],
            },
            read_idx: 0,
        }
    }
}

/// Encapsulates a (unix) socket as an event source.
pub struct SocketEventSource<T> {
    evt_source_impl: EventSourceImpl<T>,
}

impl<T> SocketEventSource<T>
where
    T: Read + Write + AsRawFd,
{
    pub fn new(source: T) -> SocketEventSource<T> {
        SocketEventSource {
            evt_source_impl: EventSourceImpl::new(source),
        }
    }
}

impl<T: Read> Read for SocketEventSource<T> {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        self.evt_source_impl.read(buf)
    }
}

impl<T> Write for SocketEventSource<T>
where
    T: Read + Write + AsRawFd,
{
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        self.evt_source_impl.write(buf, |_evt| true)
    }

    fn flush(&mut self) -> std::io::Result<()> {
        self.evt_source_impl.flush()
    }
}

impl<T: AsRawFd> AsRawFd for SocketEventSource<T> {
    fn as_raw_fd(&self) -> RawFd {
        self.evt_source_impl.as_raw_fd()
    }
}

impl<T> EventSource for SocketEventSource<T>
where
    T: Read + Write + AsRawFd,
{
    fn init(&mut self) -> Result<()> {
        Ok(())
    }

    fn finalize(&mut self) -> Result<()> {
        ungrab_evdev(self)
    }

    fn receive_events(&mut self) -> Result<usize> {
        self.evt_source_impl.receive_events(|_evt| true)
    }

    fn available_events_count(&self) -> usize {
        self.evt_source_impl.available_events()
    }
}

/// Encapsulates an event device node as an event source
pub struct EvdevEventSource<T> {
    evt_source_impl: EventSourceImpl<T>,
}

impl<T> EvdevEventSource<T>
where
    T: Read + Write + AsRawFd,
{
    pub fn new(source: T) -> EvdevEventSource<T> {
        EvdevEventSource {
            evt_source_impl: EventSourceImpl::new(source),
        }
    }
}

impl<T: Read> Read for EvdevEventSource<T> {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        self.evt_source_impl.read(buf)
    }
}

impl<T> Write for EvdevEventSource<T>
where
    T: Read + Write + AsRawFd,
{
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        self.evt_source_impl.write(buf, |evt| {
            // Miscellaneous events produced by the device are sent back to it by the kernel input
            // subsystem, but because these events are handled by the host kernel as well as the
            // guest the device would get them twice. Which would prompt the device to send the
            // event to the guest again entering an infinite loop.
            evt.type_ != EV_MSC
        })
    }

    fn flush(&mut self) -> std::io::Result<()> {
        self.evt_source_impl.flush()
    }
}

impl<T: AsRawFd> AsRawFd for EvdevEventSource<T> {
    fn as_raw_fd(&self) -> RawFd {
        self.evt_source_impl.as_raw_fd()
    }
}

impl<T> EventSource for EvdevEventSource<T>
where
    T: Read + Write + AsRawFd,
{
    fn init(&mut self) -> Result<()> {
        grab_evdev(self)
    }

    fn finalize(&mut self) -> Result<()> {
        ungrab_evdev(self)
    }

    fn receive_events(&mut self) -> Result<usize> {
        self.evt_source_impl.receive_events(|_evt| true)
    }

    fn available_events_count(&self) -> usize {
        self.evt_source_impl.available_events()
    }
}
<|endoftext|>


<commit_before>/**
 * A structure shared across REPL instances for storing history
 * such as statements and view items. I wish the AST was sendable.
 */
struct Repl {
    prompt: ~str,
    binary: ~str,
    running: bool,
    view_items: ~str,
    stmts: ~str
}

/// A utility function that hands off a pretty printer to a callback.
fn with_pp(intr: @token::ident_interner,
           cb: fn(pprust::ps, io::Writer)) -> ~str {
    do io::with_str_writer |writer| {
        let pp = pprust::rust_printer(writer, intr);

        cb(pp, writer);
        pp::eof(pp.s);
    }
}

/**
 * The AST (or the rest of rustc) are not sendable yet,
 * so recorded things are printed to strings. A terrible hack that
 * needs changes to rustc in order to be outed. This is unfortunately
 * going to cause the REPL to regress in parser performance,
 * because it has to parse the statements and view_items on each
 * input.
 */
fn record(repl: Repl, blk: @ast::blk, intr: @token::ident_interner) -> Repl {
    let view_items = if blk.node.view_items.len() > 0 {
        let new_view_items = do with_pp(intr) |pp, writer| {
            for blk.node.view_items.each |view_item| {
                pprust::print_view_item(pp, *view_item);
                writer.write_line(~"");
            }
        };

        debug!("new view items %s", new_view_items);

        repl.view_items + "\n" + new_view_items
    } else { repl.view_items };
    let stmts = if blk.node.stmts.len() > 0 {
        let new_stmts = do with_pp(intr) |pp, writer| {
            for blk.node.stmts.each |stmt| {
                match stmt.node {
                    ast::stmt_decl(*) => {
                        pprust::print_stmt(pp, **stmt);
                        writer.write_line(~"");
                    }
                    ast::stmt_expr(expr, _) | ast::stmt_semi(expr, _) => {
                        match expr.node {
                            ast::expr_assign(*) |
                            ast::expr_assign_op(*) |
                            ast::expr_swap(*) => {
                                pprust::print_stmt(pp, **stmt);
                                writer.write_line(~"");
                            }
                            _ => {}
                        }
                    }
                }
            }
        };

        debug!("new stmts %s", new_stmts);

        repl.stmts + "\n" + new_stmts
    } else { repl.stmts };

    Repl{
        view_items: view_items,
        stmts: stmts,
        .. repl
    }
}

/// Run an input string in a Repl, returning the new Repl.
fn run(repl: Repl, input: ~str) -> Repl {
    let options: @session::options = @{
        crate_type: session::unknown_crate,
        binary: repl.binary,
        addl_lib_search_paths: ~[os::getcwd()],
        .. *session::basic_options()
    };

    debug!("building driver input");
    let head = include_str!("wrapper.rs");
    let foot = fmt!("%s\nfn main() {\n%s\n\nprint({\n%s\n})\n}",
                    repl.view_items, repl.stmts, input);
    let wrapped = driver::str_input(head + foot);

    debug!("inputting %s", head + foot);

    debug!("building a driver session");
    let sess = driver::build_session(options, diagnostic::emit);

    debug!("building driver configuration");
    let cfg = driver::build_configuration(sess,
                                          repl.binary,
                                          wrapped);

    debug!("parsing");
    let mut crate = driver::parse_input(sess, cfg, wrapped);
    let mut opt = None;

    for crate.node.module.items.each |item| {
        match item.node {
            ast::item_fn(_, _, _, blk) => {
                if item.ident == sess.ident_of(~"main") {
                    opt = blk.node.expr;
                }
            }
            _ => {}
        }
    }

    let blk = match opt.get().node {
        ast::expr_call(_, exprs, _) => {
            match exprs[0].node {
                ast::expr_block(blk) => @blk,
                _ => fail
            }
        }
        _ => fail
    };

    debug!("configuration");
    crate = front::config::strip_unconfigured_items(crate);

    debug!("maybe building test harness");
    crate = front::test::modify_for_testing(sess, crate);

    debug!("expansion");
    crate = syntax::ext::expand::expand_crate(sess.parse_sess,
                                              sess.opts.cfg,
                                              crate);

    debug!("intrinsic injection");
    crate = front::intrinsic_inject::inject_intrinsic(sess, crate);

    debug!("core injection");
    crate = front::core_inject::maybe_inject_libcore_ref(sess, crate);

    debug!("building lint settings table");
    lint::build_settings_crate(sess, crate);

    debug!("ast indexing");
    let ast_map = syntax::ast_map::map_crate(sess.diagnostic(), *crate);

    debug!("external crate/lib resolution");
    creader::read_crates(sess.diagnostic(), *crate, sess.cstore,
                         sess.filesearch,
                         session::sess_os_to_meta_os(sess.targ_cfg.os),
                         sess.opts.static, sess.parse_sess.interner);

    debug!("language item collection");
    let lang_items = middle::lang_items::collect_language_items(crate, sess);

    debug!("resolution");
    let {def_map: def_map,
         exp_map2: exp_map2,
         trait_map: trait_map} = middle::resolve::resolve_crate(sess,
                                                                lang_items,
                                                                crate);

    debug!("freevar finding");
    let freevars = freevars::annotate_freevars(def_map, crate);

    debug!("region_resolution");
    let region_map = middle::region::resolve_crate(sess, def_map, crate);

    debug!("region paramaterization inference");
    let rp_set = middle::region::determine_rp_in_crate(sess, ast_map,
                                                       def_map, crate);

    debug!("typechecking");
    let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars,
                            region_map, rp_set, move lang_items, crate);
    let (method_map, vtable_map) = typeck::check_crate(ty_cx, trait_map,
                                                       crate);

    debug!("const marking");
    middle::const_eval::process_crate(crate, def_map, ty_cx);

    debug!("const checking");
    middle::check_const::check_crate(sess, crate, ast_map, def_map,
                                     method_map, ty_cx);

    debug!("privacy checking");
    middle::privacy::check_crate(ty_cx, &method_map, crate);

    debug!("loop checking");
    middle::check_loop::check_crate(ty_cx, crate);

    debug!("alt checking");
    middle::check_alt::check_crate(ty_cx, crate);

    debug!("liveness checking");
    let last_use_map = middle::liveness::check_crate(ty_cx,
                                                     method_map, crate);

    debug!("borrow checking");
    let (root_map, mutbl_map) = middle::borrowck::check_crate(ty_cx,
                                                              method_map,
                                                              last_use_map,
                                                              crate);

    debug!("kind checking");
    kind::check_crate(ty_cx, method_map, last_use_map, crate);

    debug!("lint checking");
    lint::check_crate(ty_cx, crate);

    let maps = {mutbl_map: mutbl_map,
                root_map: root_map,
                last_use_map: last_use_map,
                method_map: method_map,
                vtable_map: vtable_map};

    debug!("translation");
    let (llmod, _) = trans::base::trans_crate(sess, crate, ty_cx,
                                              ~path::from_str("<repl>"),
                                              exp_map2, maps);
    let pm = llvm::LLVMCreatePassManager();

    debug!("executing jit");
    back::link::jit::exec(sess, pm, llmod, 0, false);
    llvm::LLVMDisposePassManager(pm);

    debug!("recording input into repl history");
    record(repl, blk, sess.parse_sess.interner)
}

/// Run a command, e.g. :clear, :exit, etc.
fn run_cmd(repl: &mut Repl, _in: io::Reader, _out: io::Writer,
           cmd: ~str, _args: ~[~str]) {
    match cmd {
        ~"exit" => repl.running = false,
        ~"clear" => {
            repl.view_items = ~"";
            repl.stmts = ~"";

            // XXX: Win32 version of linenoise can't do this
            //rl::clear();
        }
        ~"help" => {
            io::println(~":clear - clear the screen\n" +
                        ~":exit - exit from the repl\n" +
                        ~":help - show this message");
        }
        _ => io::println(~"unknown cmd: " + cmd)
    }
}

pub fn main() {
    let args = os::args();
    let in = io::stdin();
    let out = io::stdout();
    let mut repl = Repl {
        prompt: ~"rusti> ",
        binary: args[0],
        running: true,
        view_items: ~"",
        stmts: ~""
    };

    unsafe {
        do rl::complete |line, suggest| {
            if line.starts_with(":") {
                suggest(~":clear");
                suggest(~":exit");
                suggest(~":help");
            }
        }
    }

    while repl.running {
        let result = unsafe { rl::read(repl.prompt) };

        if result.is_none() {
            break;
        }

        let line = result.get();

        if line.is_empty() {
            io::println(~"()");

            loop;
        }

        unsafe { rl::add_history(line) };

        if line.starts_with(~":") {
            let full = line.substr(1, line.len() - 1);
            let split = full.split_char(' ');
            let len = split.len();

            if len > 0 {
                let cmd = split[0];

                if !cmd.is_empty() {
                    let args = if len > 1 {
                        do vec::view(split, 1, len - 1).map |arg| {
                            *arg
                        }
                    } else { ~[] };

                    run_cmd(&mut repl, in, out, cmd, args);

                    loop;
                }
            }
        }

        let result = do task::try |copy repl| {
            run(copy repl, line)
        };

        if result.is_ok() {
            repl = result.get();
        }
    }
}
<commit_msg>Added support for multiline commands in the REPL with :{ .. :}<commit_after>/**
 * A structure shared across REPL instances for storing history
 * such as statements and view items. I wish the AST was sendable.
 */
struct Repl {
    prompt: ~str,
    binary: ~str,
    running: bool,
    view_items: ~str,
    stmts: ~str
}

// Action to do after reading a :command
enum CmdAction {
    action_none,
    action_run_line(~str),
}

/// A utility function that hands off a pretty printer to a callback.
fn with_pp(intr: @token::ident_interner,
           cb: fn(pprust::ps, io::Writer)) -> ~str {
    do io::with_str_writer |writer| {
        let pp = pprust::rust_printer(writer, intr);

        cb(pp, writer);
        pp::eof(pp.s);
    }
}

/**
 * The AST (or the rest of rustc) are not sendable yet,
 * so recorded things are printed to strings. A terrible hack that
 * needs changes to rustc in order to be outed. This is unfortunately
 * going to cause the REPL to regress in parser performance,
 * because it has to parse the statements and view_items on each
 * input.
 */
fn record(repl: Repl, blk: @ast::blk, intr: @token::ident_interner) -> Repl {
    let view_items = if blk.node.view_items.len() > 0 {
        let new_view_items = do with_pp(intr) |pp, writer| {
            for blk.node.view_items.each |view_item| {
                pprust::print_view_item(pp, *view_item);
                writer.write_line(~"");
            }
        };

        debug!("new view items %s", new_view_items);

        repl.view_items + "\n" + new_view_items
    } else { repl.view_items };
    let stmts = if blk.node.stmts.len() > 0 {
        let new_stmts = do with_pp(intr) |pp, writer| {
            for blk.node.stmts.each |stmt| {
                match stmt.node {
                    ast::stmt_decl(*) => {
                        pprust::print_stmt(pp, **stmt);
                        writer.write_line(~"");
                    }
                    ast::stmt_expr(expr, _) | ast::stmt_semi(expr, _) => {
                        match expr.node {
                            ast::expr_assign(*) |
                            ast::expr_assign_op(*) |
                            ast::expr_swap(*) => {
                                pprust::print_stmt(pp, **stmt);
                                writer.write_line(~"");
                            }
                            _ => {}
                        }
                    }
                }
            }
        };

        debug!("new stmts %s", new_stmts);

        repl.stmts + "\n" + new_stmts
    } else { repl.stmts };

    Repl{
        view_items: view_items,
        stmts: stmts,
        .. repl
    }
}

/// Run an input string in a Repl, returning the new Repl.
fn run(repl: Repl, input: ~str) -> Repl {
    let options: @session::options = @{
        crate_type: session::unknown_crate,
        binary: repl.binary,
        addl_lib_search_paths: ~[os::getcwd()],
        .. *session::basic_options()
    };

    debug!("building driver input");
    let head = include_str!("wrapper.rs");
    let foot = fmt!("%s\nfn main() {\n%s\n\nprint({\n%s\n})\n}",
                    repl.view_items, repl.stmts, input);
    let wrapped = driver::str_input(head + foot);

    debug!("inputting %s", head + foot);

    debug!("building a driver session");
    let sess = driver::build_session(options, diagnostic::emit);

    debug!("building driver configuration");
    let cfg = driver::build_configuration(sess,
                                          repl.binary,
                                          wrapped);

    debug!("parsing");
    let mut crate = driver::parse_input(sess, cfg, wrapped);
    let mut opt = None;

    for crate.node.module.items.each |item| {
        match item.node {
            ast::item_fn(_, _, _, blk) => {
                if item.ident == sess.ident_of(~"main") {
                    opt = blk.node.expr;
                }
            }
            _ => {}
        }
    }

    let blk = match opt.get().node {
        ast::expr_call(_, exprs, _) => {
            match exprs[0].node {
                ast::expr_block(blk) => @blk,
                _ => fail
            }
        }
        _ => fail
    };

    debug!("configuration");
    crate = front::config::strip_unconfigured_items(crate);

    debug!("maybe building test harness");
    crate = front::test::modify_for_testing(sess, crate);

    debug!("expansion");
    crate = syntax::ext::expand::expand_crate(sess.parse_sess,
                                              sess.opts.cfg,
                                              crate);

    debug!("intrinsic injection");
    crate = front::intrinsic_inject::inject_intrinsic(sess, crate);

    debug!("core injection");
    crate = front::core_inject::maybe_inject_libcore_ref(sess, crate);

    debug!("building lint settings table");
    lint::build_settings_crate(sess, crate);

    debug!("ast indexing");
    let ast_map = syntax::ast_map::map_crate(sess.diagnostic(), *crate);

    debug!("external crate/lib resolution");
    creader::read_crates(sess.diagnostic(), *crate, sess.cstore,
                         sess.filesearch,
                         session::sess_os_to_meta_os(sess.targ_cfg.os),
                         sess.opts.static, sess.parse_sess.interner);

    debug!("language item collection");
    let lang_items = middle::lang_items::collect_language_items(crate, sess);

    debug!("resolution");
    let {def_map: def_map,
         exp_map2: exp_map2,
         trait_map: trait_map} = middle::resolve::resolve_crate(sess,
                                                                lang_items,
                                                                crate);

    debug!("freevar finding");
    let freevars = freevars::annotate_freevars(def_map, crate);

    debug!("region_resolution");
    let region_map = middle::region::resolve_crate(sess, def_map, crate);

    debug!("region paramaterization inference");
    let rp_set = middle::region::determine_rp_in_crate(sess, ast_map,
                                                       def_map, crate);

    debug!("typechecking");
    let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars,
                            region_map, rp_set, move lang_items, crate);
    let (method_map, vtable_map) = typeck::check_crate(ty_cx, trait_map,
                                                       crate);

    debug!("const marking");
    middle::const_eval::process_crate(crate, def_map, ty_cx);

    debug!("const checking");
    middle::check_const::check_crate(sess, crate, ast_map, def_map,
                                     method_map, ty_cx);

    debug!("privacy checking");
    middle::privacy::check_crate(ty_cx, &method_map, crate);

    debug!("loop checking");
    middle::check_loop::check_crate(ty_cx, crate);

    debug!("alt checking");
    middle::check_alt::check_crate(ty_cx, crate);

    debug!("liveness checking");
    let last_use_map = middle::liveness::check_crate(ty_cx,
                                                     method_map, crate);

    debug!("borrow checking");
    let (root_map, mutbl_map) = middle::borrowck::check_crate(ty_cx,
                                                              method_map,
                                                              last_use_map,
                                                              crate);

    debug!("kind checking");
    kind::check_crate(ty_cx, method_map, last_use_map, crate);

    debug!("lint checking");
    lint::check_crate(ty_cx, crate);

    let maps = {mutbl_map: mutbl_map,
                root_map: root_map,
                last_use_map: last_use_map,
                method_map: method_map,
                vtable_map: vtable_map};

    debug!("translation");
    let (llmod, _) = trans::base::trans_crate(sess, crate, ty_cx,
                                              ~path::from_str("<repl>"),
                                              exp_map2, maps);
    let pm = llvm::LLVMCreatePassManager();

    debug!("executing jit");
    back::link::jit::exec(sess, pm, llmod, 0, false);
    llvm::LLVMDisposePassManager(pm);

    debug!("recording input into repl history");
    record(repl, blk, sess.parse_sess.interner)
}

/// Tries to get a line from rl after outputting a prompt. Returns
/// None if no input was read (e.g. EOF was reached).
fn get_line(prompt: ~str) -> Option<~str> {
    let result = unsafe { rl::read(prompt) };

    if result.is_none() {
        return None;
    }

    let line = result.get();

    unsafe { rl::add_history(line) };

    return Some(line);
}

/// Run a command, e.g. :clear, :exit, etc.
fn run_cmd(repl: &mut Repl, _in: io::Reader, _out: io::Writer,
           cmd: ~str, _args: ~[~str]) -> CmdAction {
    let mut action = action_none;
    match cmd {
        ~"exit" => repl.running = false,
        ~"clear" => {
            repl.view_items = ~"";
            repl.stmts = ~"";

            // XXX: Win32 version of linenoise can't do this
            //rl::clear();
        }
        ~"help" => {
            io::println(~":{\\n ..lines.. \\n:}\\n - execute multiline command\n" +
                        ~":clear - clear the screen\n" +
                        ~":exit - exit from the repl\n" +
                        ~":help - show this message");
        }
        ~"{" => {
            let mut multiline_cmd = ~"";
            let mut end_multiline = false;
            while (!end_multiline) {
                match get_line(~"rusti| ") {
                    None => fail ~"unterminated multiline command :{ .. :}",
                    Some(line) => {
                        if str::trim(line) == ~":}" {
                            end_multiline = true;
                        } else {
                            multiline_cmd += line + ~"\n";
                        }
                    }
                }
            }
            action = action_run_line(multiline_cmd);
        }
        _ => io::println(~"unknown cmd: " + cmd)
    }
    return action;
}

/// Executes a line of input, which may either be rust code or a
/// :command. Returns a new Repl if it has changed.
fn run_line(repl: &mut Repl, in: io::Reader, out: io::Writer, line: ~str)
    -> Option<Repl> {
    if line.starts_with(~":") {
        let full = line.substr(1, line.len() - 1);
        let split = str::words(full);
        let len = split.len();

        if len > 0 {
            let cmd = split[0];

            if !cmd.is_empty() {
                let args = if len > 1 {
                    do vec::view(split, 1, len - 1).map |arg| {
                        *arg
                    }
                } else { ~[] };

                match run_cmd(repl, in, out, cmd, args) {
                    action_none => { }
                    action_run_line(multiline_cmd) => {
                        if !multiline_cmd.is_empty() {
                            return run_line(repl, in, out, multiline_cmd);
                        }
                    }
                }
                return None;
            }
        }
    }

    let r = *repl;
    let result = do task::try |copy r| {
        run(r, line)
    };

    if result.is_ok() {
        return Some(result.get());
    }
    return None;
}

pub fn main() {
    let args = os::args();
    let in = io::stdin();
    let out = io::stdout();
    let mut repl = Repl {
        prompt: ~"rusti> ",
        binary: args[0],
        running: true,
        view_items: ~"",
        stmts: ~""
    };

    unsafe {
        do rl::complete |line, suggest| {
            if line.starts_with(":") {
                suggest(~":clear");
                suggest(~":exit");
                suggest(~":help");
            }
        }
    }

    while repl.running {
        match get_line(repl.prompt) {
            None => break,
            Some(line) => {
                if line.is_empty() {
                    io::println(~"()");
                    loop;
                }
                match run_line(&mut repl, in, out, line) {
                    Some(new_repl) => repl = new_repl,
                    None => { }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(unix, not(target_os = "ios"))]
mod imp {
    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::{Ok, Err};

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    #[cfg(unix)]
    pub struct OsRng {
        inner: ReaderRng<File>
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: reader_rng })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            self.inner.next_u32()
        }
        fn next_u64(&mut self) -> u64 {
            self.inner.next_u64()
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            self.inner.fill_bytes(v)
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    extern crate libc;

    use collections::Collection;
    use io::{IoResult};
    use kinds::marker;
    use mem;
    use os;
    use rand::Rng;
    use result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::MutableSlice;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    pub struct OsRng {
        marker: marker::NoCopy
    }

    #[repr(C)]
    struct SecRandom;

    static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            Ok(OsRng {marker: marker::NoCopy} )
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                fail!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use core_collections::Collection;
    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::{Ok, Err};
    use rt::stack;
    use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
    use self::libc::types::os::arch::extra::{LONG_PTR};
    use slice::MutableSlice;

    type HCRYPTPROV = LONG_PTR;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;
    static NTE_BAD_SIGNATURE: DWORD = 0x80090006;

    #[allow(non_snake_case)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let mut ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            // FIXME #13259:
            // It turns out that if we can't acquire a context with the
            // NTE_BAD_SIGNATURE error code, the documentation states:
            //
            //     The provider DLL signature could not be verified. Either the
            //     DLL or the digital signature has been tampered with.
            //
            // Sounds fishy, no? As it turns out, our signature can be bad
            // because our Thread Information Block (TIB) isn't exactly what it
            // expects. As to why, I have no idea. The only data we store in the
            // TIB is the stack limit for each thread, but apparently that's
            // enough to make the signature valid.
            //
            // Furthermore, this error only happens the *first* time we call
            // CryptAcquireContext, so we don't have to worry about future
            // calls.
            //
            // Anyway, the fix employed here is that if we see this error, we
            // pray that we're not close to the end of the stack, temporarily
            // set the stack limit to 0 (what the TIB originally was), acquire a
            // context, and then reset the stack limit.
            //
            // Again, I'm not sure why this is the fix, nor why we're getting
            // this error. All I can say is that this seems to allow libnative
            // to progress where it otherwise would be hindered. Who knew?
            if ret == 0 && os::errno() as DWORD == NTE_BAD_SIGNATURE {
                unsafe {
                    let limit = stack::get_sp_limit();
                    stack::record_sp_limit(0);
                    ret = CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                               PROV_RSA_FULL,
                                               CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
                    stack::record_sp_limit(limit);
                }
            }

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                fail!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                fail!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

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

    use super::OsRng;
    use rand::Rng;
    use task;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8, .. 1000];
        r.fill_bytes(v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in range(0u, 20) {
            let (tx, rx) = channel();
            txs.push(tx);
            task::spawn(proc() {
                // wait until all the tasks are ready to go.
                rx.recv();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                task::deschedule();
                let mut v = [0u8, .. 1000];

                for _ in range(0u, 100) {
                    r.next_u32();
                    task::deschedule();
                    r.next_u64();
                    task::deschedule();
                    r.fill_bytes(v);
                    task::deschedule();
                }
            })
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(())
        }
    }
}
<commit_msg>Disable runtime split stack support on Windows<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(unix, not(target_os = "ios"))]
mod imp {
    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::{Ok, Err};

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    #[cfg(unix)]
    pub struct OsRng {
        inner: ReaderRng<File>
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: reader_rng })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            self.inner.next_u32()
        }
        fn next_u64(&mut self) -> u64 {
            self.inner.next_u64()
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            self.inner.fill_bytes(v)
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    extern crate libc;

    use collections::Collection;
    use io::{IoResult};
    use kinds::marker;
    use mem;
    use os;
    use rand::Rng;
    use result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::MutableSlice;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    pub struct OsRng {
        marker: marker::NoCopy
    }

    #[repr(C)]
    struct SecRandom;

    static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            Ok(OsRng {marker: marker::NoCopy} )
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                fail!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use core_collections::Collection;
    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::{Ok, Err};
    use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
    use self::libc::types::os::arch::extra::{LONG_PTR};
    use slice::MutableSlice;

    type HCRYPTPROV = LONG_PTR;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;

    #[allow(non_snake_case)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                fail!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                fail!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

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

    use super::OsRng;
    use rand::Rng;
    use task;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8, .. 1000];
        r.fill_bytes(v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in range(0u, 20) {
            let (tx, rx) = channel();
            txs.push(tx);
            task::spawn(proc() {
                // wait until all the tasks are ready to go.
                rx.recv();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                task::deschedule();
                let mut v = [0u8, .. 1000];

                for _ in range(0u, 100) {
                    r.next_u32();
                    task::deschedule();
                    r.next_u64();
                    task::deschedule();
                    r.fill_bytes(v);
                    task::deschedule();
                }
            })
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(())
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::ops::{Range, RangeFull, RangeFrom, RangeTo, RangeInclusive};

// Test the Range structs without the syntactic sugar.

#[test]
fn test_range() {
    let r = Range { start: 2, end: 10 };
    let mut count = 0;
    for (i, ri) in r.enumerate() {
        assert!(ri == i + 2);
        assert!(ri >= 2 && ri < 10);
        count += 1;
    }
    assert!(count == 8);
}

#[test]
fn test_range_from() {
    let r = RangeFrom { start: 2 };
    let mut count = 0;
    for (i, ri) in r.take(10).enumerate() {
        assert!(ri == i + 2);
        assert!(ri >= 2 && ri < 12);
        count += 1;
    }
    assert!(count == 10);
}

#[test]
fn test_range_to() {
    // Not much to test.
    let _ = RangeTo { end: 42 };
}

#[test]
fn test_full_range() {
    // Not much to test.
    let _ = RangeFull;
}

#[test]
fn test_range_inclusive() {
    let mut r = RangeInclusive { start: 1i8, end: 2 };
    assert_eq!(r.next(), Some(1));
    assert_eq!(r.next(), Some(2));
    assert_eq!(r.next(), None);

    r = RangeInclusive { start: 127i8, end: 127 };
    assert_eq!(r.next(), Some(127));
    assert_eq!(r.next(), None);

    r = RangeInclusive { start: -128i8, end: -128 };
    assert_eq!(r.next_back(), Some(-128));
    assert_eq!(r.next_back(), None);

    // degenerate
    r = RangeInclusive { start: 1, end: -1 };
    assert_eq!(r.size_hint(), (0, Some(0)));
    assert_eq!(r.next(), None);
}

#[test]
fn test_range_is_empty() {
    use core::f32::*;

    assert!(!(0.0 .. 10.0).is_empty());
    assert!( (-0.0 .. 0.0).is_empty());
    assert!( (10.0 .. 0.0).is_empty());

    assert!(!(NEG_INFINITY .. INFINITY).is_empty());
    assert!( (EPSILON .. NAN).is_empty());
    assert!( (NAN .. EPSILON).is_empty());
    assert!( (NAN .. NAN).is_empty());

    assert!(!(0.0 ..= 10.0).is_empty());
    assert!(!(-0.0 ..= 0.0).is_empty());
    assert!( (10.0 ..= 0.0).is_empty());

    assert!(!(NEG_INFINITY ..= INFINITY).is_empty());
    assert!( (EPSILON ..= NAN).is_empty());
    assert!( (NAN ..= EPSILON).is_empty());
    assert!( (NAN ..= NAN).is_empty());
}<commit_msg>Fix tidy<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::ops::{Range, RangeFull, RangeFrom, RangeTo, RangeInclusive};

// Test the Range structs without the syntactic sugar.

#[test]
fn test_range() {
    let r = Range { start: 2, end: 10 };
    let mut count = 0;
    for (i, ri) in r.enumerate() {
        assert!(ri == i + 2);
        assert!(ri >= 2 && ri < 10);
        count += 1;
    }
    assert!(count == 8);
}

#[test]
fn test_range_from() {
    let r = RangeFrom { start: 2 };
    let mut count = 0;
    for (i, ri) in r.take(10).enumerate() {
        assert!(ri == i + 2);
        assert!(ri >= 2 && ri < 12);
        count += 1;
    }
    assert!(count == 10);
}

#[test]
fn test_range_to() {
    // Not much to test.
    let _ = RangeTo { end: 42 };
}

#[test]
fn test_full_range() {
    // Not much to test.
    let _ = RangeFull;
}

#[test]
fn test_range_inclusive() {
    let mut r = RangeInclusive { start: 1i8, end: 2 };
    assert_eq!(r.next(), Some(1));
    assert_eq!(r.next(), Some(2));
    assert_eq!(r.next(), None);

    r = RangeInclusive { start: 127i8, end: 127 };
    assert_eq!(r.next(), Some(127));
    assert_eq!(r.next(), None);

    r = RangeInclusive { start: -128i8, end: -128 };
    assert_eq!(r.next_back(), Some(-128));
    assert_eq!(r.next_back(), None);

    // degenerate
    r = RangeInclusive { start: 1, end: -1 };
    assert_eq!(r.size_hint(), (0, Some(0)));
    assert_eq!(r.next(), None);
}

#[test]
fn test_range_is_empty() {
    use core::f32::*;

    assert!(!(0.0 .. 10.0).is_empty());
    assert!( (-0.0 .. 0.0).is_empty());
    assert!( (10.0 .. 0.0).is_empty());

    assert!(!(NEG_INFINITY .. INFINITY).is_empty());
    assert!( (EPSILON .. NAN).is_empty());
    assert!( (NAN .. EPSILON).is_empty());
    assert!( (NAN .. NAN).is_empty());

    assert!(!(0.0 ..= 10.0).is_empty());
    assert!(!(-0.0 ..= 0.0).is_empty());
    assert!( (10.0 ..= 0.0).is_empty());

    assert!(!(NEG_INFINITY ..= INFINITY).is_empty());
    assert!( (EPSILON ..= NAN).is_empty());
    assert!( (NAN ..= EPSILON).is_empty());
    assert!( (NAN ..= NAN).is_empty());
}
<|endoftext|>