<commit_before>use std::ops::Fn;
use std::error::FromError;
use std::sync::mpsc;

use std::path::Path as StdPath;

// @todo, change to std::io once stable.
use std::old_io as io;

//================================================================================
// Error:
//================================================================================

/**
 * `Error` contains all the possible errors for `fsnotify`.
 */
pub enum Error {
	Io( io::IoError ),
	NotifyError( String ),
	PathNotFound,
	NotImplemented,
}

impl FromError<io::IoError> for Error {
	fn from_error( from: io::IoError ) -> Error {
		Error::Io( from )
	}
}

//================================================================================
// Misc typedefs:
//================================================================================

pub type Path = StdPath;

/**
 * The `Result` of an operation, with either `T` (success), `Error` (failure).
 */
pub type NotifyResult<T> = Result<T, Error>;

/**
 * `R = NotifyResult<()`
 * Indicates either success or failure of an operation.
 */
pub type R = NotifyResult<()>;

//================================================================================
// Configuration:
//================================================================================

/**
 * `RecursionFilter`, a predicate function that, when recursion is enabled,
 * tells the `FsNotifier` if it should subscribe to a sub-directory.
 *
 * If the value returned is true, it will subscribe, otherwise, it will not.
 */
pub type RecursionFilter<'a> = Option<&'a (Fn( &Path ) -> bool + 'a)>;

/**
 * `RecursionLimit` denoted what the maximum recursion depth is starting
 * from a tree point that was explicitly added to the watch list.
 *
 * `None` means that there is no limit, it will do recursion forever.
 * `Some(0)` means that no recursion will happen at all.
 */
pub type RecursionLimit = Option<usize>;

/**
 * `Configuration` provides configuration for a `FsNotifier`.
 *
 * It configures what operations to subcribe to if applicable for the platform.
 * This lets you avoid tracking events of no interest.
 *
 * It also configures if symlinks should be followed or not (`follow_symlinks`).
 *
 * Lastly, it configures the `RecursionLimit`, and `RecursionFilter`.
 */
pub struct Configuration<'a> {
	subscribe: Operations,
	follow_symlinks: bool,
	recursion_limit: RecursionLimit,
	recursion_filter: RecursionFilter<'a>,
}

//================================================================================
// Events:
//================================================================================

mod operations;
use self::operations::Operations;

/**
 * Event:s are passed to the `EventSender`.
 * It has information about the path that the operations that happened on it.
 */
pub struct Event<'a> {
	pub path: Option<&'a Path>,
	pub op: NotifyResult<Operations>,
}

/**
 * `EventSender`, a `Sender` for an `Event`.
 */
pub type EventSender<'a> = mpsc::Sender<Event<'a>>;

//================================================================================
// Notifier trait:
//================================================================================

/**
 * FsNotifier, a trait, is the generic interface for
 * subscribing to file system change events.
 *
 * It provides 4 basic operations:
 * 	+ `.add( &Path )`
 * 	+ `.remove( &Path )`
 * 	+ `.start()`
 * 	+ `.stop()`
 *
 * As this trait deals with I/O interaction with the operating system, things can fail.
 * Thus, all methods return a `NotifyResult<T> = Result<T, Error>`.
 * All methods but the first, `.new(...)` return `R = NotifyResult<()>`,
 * indicating either success or failure of the operation.
 */
pub trait FsNotifier<'a> : Drop {
	/**
	 * Constructs a `FsNotifier`.
	 *
	 * The sender is an `EventSender` which the notifier will send events through.
	 * The config: `Configuration` contains information about how to handle recursion,
	 * symlinks and what file system operations that should be tracked.
	 *
	 * The returned value is a the notifier, wrapped in a `NotifyResult`.
	 * This is done because there might be I/O failures depending on the system.
	 */
	fn new( sender: EventSender, config: Configuration<'a> ) -> NotifyResult<Self>;

	/**
	 * Adds a path to track to the notifier.
	 *
	 * Returned is a Result<()>, that indicates either failure or success.
	 */
	fn add( &self, path: &Path ) -> R;

	/**
	 * Tells the notifier to stop tracking a path.
	 *
	 * Returned is a Result<()>, that indicates either failure or success.
	 */
	fn remove( &self, path: &Path ) -> R;

	/**
	 * Tells the notifier to start the tracking.
	 * This operation is blocking, therefore it should be wrapped in a thread.
	 *
	 * Returned is a Result<()>, that indicates either failure or success.
	 */
	fn start( &self ) -> R;

	/**
	 * Tells the notifier to stop the tracking.
	 *
	 * Returned is a Result<()>, that indicates either failure or success.
	 */
	fn stop( &self ) -> R;
}<commit_msg>PathNotFound -> PathInvalid, lifetime added to EventSender.<commit_after>use std::ops::Fn;
use std::error::FromError;
use std::sync::mpsc;

use std::path::Path as StdPath;

// @todo, change to std::io once stable.
use std::old_io as io;

//================================================================================
// Error:
//================================================================================

/**
 * `Error` contains all the possible errors for `fsnotify`.
 */
pub enum Error {
	Io( io::IoError ),
	NotifyError( String ),
	PathInvalid,
	NotImplemented,
}

impl FromError<io::IoError> for Error {
	fn from_error( from: io::IoError ) -> Error {
		Error::Io( from )
	}
}

//================================================================================
// Misc typedefs:
//================================================================================

pub type Path = StdPath;

/**
 * The `Result` of an operation, with either `T` (success), `Error` (failure).
 */
pub type NotifyResult<T> = Result<T, Error>;

/**
 * `R = NotifyResult<()`
 * Indicates either success or failure of an operation.
 */
pub type R = NotifyResult<()>;

//================================================================================
// Configuration:
//================================================================================

/**
 * `RecursionFilter`, a predicate function that, when recursion is enabled,
 * tells the `FsNotifier` if it should subscribe to a sub-directory.
 *
 * If the value returned is true, it will subscribe, otherwise, it will not.
 */
pub type RecursionFilter<'a> = Option<&'a (Fn( &Path ) -> bool + 'a)>;

/**
 * `RecursionLimit` denoted what the maximum recursion depth is starting
 * from a tree point that was explicitly added to the watch list.
 *
 * `None` means that there is no limit, it will do recursion forever.
 * `Some(0)` means that no recursion will happen at all.
 */
pub type RecursionLimit = Option<usize>;

/**
 * `Configuration` provides configuration for a `FsNotifier`.
 *
 * It configures what operations to subcribe to if applicable for the platform.
 * This lets you avoid tracking events of no interest.
 *
 * It also configures if symlinks should be followed or not (`follow_symlinks`).
 *
 * Lastly, it configures the `RecursionLimit`, and `RecursionFilter`.
 */
pub struct Configuration<'a> {
	subscribe: Operations,
	follow_symlinks: bool,
	recursion_limit: RecursionLimit,
	recursion_filter: RecursionFilter<'a>,
}

//================================================================================
// Events:
//================================================================================

mod operations;
use self::operations::Operations;

/**
 * Event:s are passed to the `EventSender`.
 * It has information about the path that the operations that happened on it.
 */
pub struct Event<'a> {
	pub path: Option<&'a Path>,
	pub op: NotifyResult<Operations>,
}

/**
 * `EventSender`, a `Sender` for an `Event`.
 */
pub type EventSender<'a> = mpsc::Sender<Event<'a>>;

//================================================================================
// Notifier trait:
//================================================================================

/**
 * FsNotifier, a trait, is the generic interface for
 * subscribing to file system change events.
 *
 * It provides 4 basic operations:
 * 	+ `.add( &Path )`
 * 	+ `.remove( &Path )`
 * 	+ `.start()`
 * 	+ `.stop()`
 *
 * As this trait deals with I/O interaction with the operating system, things can fail.
 * Thus, all methods return a `NotifyResult<T> = Result<T, Error>`.
 * All methods but the first, `.new(...)` return `R = NotifyResult<()>`,
 * indicating either success or failure of the operation.
 */
pub trait FsNotifier<'a> : Drop {
	/**
	 * Constructs a `FsNotifier`.
	 *
	 * The sender is an `EventSender` which the notifier will send events through.
	 * The config: `Configuration` contains information about how to handle recursion,
	 * symlinks and what file system operations that should be tracked.
	 *
	 * The returned value is a the notifier, wrapped in a `NotifyResult`.
	 * This is done because there might be I/O failures depending on the system.
	 */
	fn new( sender: EventSender<'a>, config: Configuration<'a> ) -> NotifyResult<Self>;

	/**
	 * Adds a path to track to the notifier.
	 *
	 * Returned is a Result<()>, that indicates either failure or success.
	 */
	fn add( &self, path: &Path ) -> R;

	/**
	 * Tells the notifier to stop tracking a path.
	 *
	 * Returned is a Result<()>, that indicates either failure or success.
	 */
	fn remove( &self, path: &Path ) -> R;

	/**
	 * Tells the notifier to start the tracking.
	 * This operation is blocking, therefore it should be wrapped in a thread.
	 *
	 * Returned is a Result<()>, that indicates either failure or success.
	 */
	fn start( &self ) -> R;

	/**
	 * Tells the notifier to stop the tracking.
	 *
	 * Returned is a Result<()>, that indicates either failure or success.
	 */
	fn stop( &self ) -> R;
}<|endoftext|>


<commit_before>// TODO: COPYRIGHT, USE & AUTHORS
// TODO: RUST DOCS!

/// GA Random Numbers Util
///
/// Wrapper around the rand crate
///
use rand::{random, Rng, thread_rng};
use rand::distributions::range::SampleRange;

pub fn ga_random_float() -> f32
{
    random()
}

// Return a random number from range [low, high).
pub fn ga_random_range<T: PartialOrd + SampleRange>(low: T, high: T) -> T
{
    thread_rng().gen_range(low, high)
}

pub fn ga_random_float_test(v: f32) -> bool
{
    ga_random_float() < v
}
<commit_msg>random wip<commit_after>// TODO: COPYRIGHT, USE & AUTHORS
// TODO: RUST DOCS!

/// GA Random Numbers Util
///
/// Wrapper around the rand crate
///
use rand::{random, XorShiftRng, Rng, SeedableRng, thread_rng};
use rand::distributions::range::SampleRange;

const kGASeedSize : usize = 4;

/// GARandomCtx
///
/// Seeded and Stateful Random Number Generator.
/// Uses rand::XorShiftRng for speed purposes.
///
struct GARandomCtx
{
    seed: [u32; kGASeedSize],
    rng:  XorShiftRng,
    name: String,
    seeded: bool,
    values_genarated: u32
}

impl GARandomCtx
{
// Constructors
    pub fn new_unseeded(name: String) -> GARandomCtx
    {
        let std_rng = XorShiftRng::new_unseeded();
        GARandomCtx
        {
            seed: [0 ; kGASeedSize],
            rng: std_rng,
            name: name,
            seeded: false
        }
    }

    pub fn from_seed(seed: [u32; kGASeedSize], name : String) -> GARandomCtx
    {
        let std_rng = SeedableRng::from_seed(seed);
        GARandomCtx
        {
            seed: seed,
            rng:  std_rng,
            name: name,
            seeded: true
        }
    }

// Random Values
    pub fn random_float(&mut self) -> f32
    {
        self.rng.gen::<f32>()
    }

    pub fn random_float_test(&mut self, v: f32) -> bool
    {
        self.random_float() < v
    }

    pub fn random_range<T: PartialOrd + SampleRange>(&mut self, low: T, high: T) -> T
    {
        self.rng.gen_range(low, high)
    }

// Reset State
    pub fn reseed(&mut self, seed: [u32; kGASeedSize])
    {
        self.seed = seed;
        self.rng.reseed(self.seed);
    }

    pub fn reset(&mut self)
    {
        if self.seeded
        {
            self.rng = SeedableRng::from_seed(self.seed);
        }
        else
        {
            self.rng = XorShiftRng::new_unseeded();
        }
    }
}

impl fmt::Debug for GARandomCtx
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        write!(f, "GARandomCtx {{ x: {}, y: {} }}", self.x, self.y)
    }
}

pub fn ga_random_float() -> f32
{
    random()
}

// Return a random number from range [low, high).
pub fn ga_random_range<T: PartialOrd + SampleRange>(low: T, high: T) -> T
{
    thread_rng().gen_range(low, high)
}

pub fn ga_random_float_test(v: f32) -> bool
{
    ga_random_float() < v
}
<|endoftext|>


<commit_before>mod js_obj;
mod js_type;
mod js_primitive;
<commit_msg>Fix mod.rs mods<commit_after>mod js_obj;
mod js_type;
mod js_str;
<|endoftext|>


<commit_before>extern crate semver;
extern crate uuid;
extern crate toml;

extern crate task_hookrs;
#[macro_use] extern crate libimagstore;

module_entry_path_mod!("todo", "0.1.0");

pub mod error;
pub mod task;
pub mod delete;
pub mod read;
pub mod set;
pub mod add;

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>clean up of lib.rs<commit_after>extern crate semver;
extern crate uuid;
extern crate toml;

extern crate task_hookrs;
#[macro_use] extern crate libimagstore;

module_entry_path_mod!("todo", "0.1.0");

pub mod delete;
pub mod error;
pub mod read;
pub mod result;
pub mod task;

<|endoftext|>


<commit_before>/**
 * Struct that holds agent configuration
 */
#[derive(Debug, Copy, Clone)]
pub struct AgentParameters {
    pub time_threshold: usize,
    pub count_threshold: usize,
    pub print_heap_histogram: bool,
    pub heap_histogram_max_entries: usize,
    pub print_memory_usage: bool
}

impl AgentParameters {
    pub fn parseParameters(options: *mut ::std::os::raw::c_char) -> AgentParameters {
        use std::ffi::CStr;

        let mut time_threshold: usize = 1;
        let mut count_threshold: usize = 0;
        let mut print_heap_histogram: usize = 0;
        let mut heap_histogram_max_entries: usize = 100;
        let mut print_memory_usage: usize = 1;

        let cslice;
        unsafe {
            cslice = CStr::from_ptr(options);
        }
        let s: &str = cslice.to_str().unwrap();
        let options = s.split(',').collect::<Vec<_>>();
        for option in &options {
            let tokens = option.splitn(2, '=').collect::<Vec<_>>();
            assert_eq!(tokens.len(), 2);
            let key = tokens[0];
            let value = tokens[1];
            match key {
                "time" => time_threshold = value.parse().expect("not a number"),
                "count" => count_threshold = value.parse().expect("not a number"),
                "printHeapHistogram" => print_heap_histogram = value.parse().expect("not a number"),
                "heapHistogramMaxEntries" => heap_histogram_max_entries = value.parse().expect("not a number"),
                "printMemoryUsage" => print_memory_usage = value.parse().expect("not a number"),
                _ => assert!(false),
            }
        }

        let ap = AgentParameters {
            time_threshold: time_threshold,
            count_threshold: count_threshold,
            print_heap_histogram: print_heap_histogram != 0,
            heap_histogram_max_entries: heap_histogram_max_entries,
            print_memory_usage: print_memory_usage != 0,
        };

        println!("AgentParameters={:?}", ap);
        ap
    }
}
<commit_msg>Unit test parms<commit_after>/**
 * Struct that holds agent configuration
 */
#[derive(Debug, Copy, Clone)]
pub struct AgentParameters {
    pub time_threshold: usize,
    pub count_threshold: usize,
    pub print_heap_histogram: bool,
    pub heap_histogram_max_entries: usize,
    pub print_memory_usage: bool
}

impl AgentParameters {
    pub fn parseParameters(options: *const ::std::os::raw::c_char) -> AgentParameters {
        use std::ffi::CStr;

        let mut time_threshold: usize = 1;
        let mut count_threshold: usize = 0;
        let mut print_heap_histogram: usize = 0;
        let mut heap_histogram_max_entries: usize = 100;
        let mut print_memory_usage: usize = 1;

        let cslice;
        unsafe {
            cslice = CStr::from_ptr(options);
        }
        let s: &str = cslice.to_str().unwrap();
        let options = s.split(',').collect::<Vec<_>>();
        for option in &options {
            if option.is_empty() {
                continue
            }
            let tokens = option.splitn(2, '=').collect::<Vec<_>>();
            assert_eq!(tokens.len(), 2, "invalid option: {}", option);
            let key = tokens[0];
            let value = tokens[1];
            match key {
                "time" => if !value.is_empty() { time_threshold = value.parse().expect("not a number") },
                "count" => if !value.is_empty() { count_threshold = value.parse().expect("not a number") },
                "printHeapHistogram" => if !value.is_empty() { print_heap_histogram = value.parse().expect("not a number") },
                "heapHistogramMaxEntries" => if !value.is_empty() { heap_histogram_max_entries = value.parse().expect("not a number") },
                "printMemoryUsage" => if !value.is_empty() { print_memory_usage = value.parse().expect("not a number") },
                _ => assert!(false, "unknown option: {}", key),
            }
        }

        AgentParameters {
            time_threshold: time_threshold,
            count_threshold: count_threshold,
            print_heap_histogram: print_heap_histogram != 0,
            heap_histogram_max_entries: heap_histogram_max_entries,
            print_memory_usage: print_memory_usage != 0,
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn defaults() {
        let ap = parse("");
        assert_eq!(ap.time_threshold, 1);
        assert_eq!(ap.count_threshold, 0);
        assert!(!ap.print_heap_histogram);
        assert_eq!(ap.heap_histogram_max_entries, 100);
        assert!(ap.print_memory_usage);
    }

    #[test]
    fn parses_time_threshold() {
        let ap = parse("time=99");
        assert_eq!(ap.time_threshold, 99);
    }

    #[test]
    fn parses_time_threshold_default() {
        let ap = parse("time=");
        assert_eq!(ap.time_threshold, 1);
    }

    #[test]
    #[should_panic(expected = "not a number")]
    fn parses_time_threshold_invalid() {
        let ap = parse("time=forever");
        assert_eq!(ap.time_threshold, 1);
    }

    #[test]
    fn parses_count_threshold() {
        let ap = parse("count=88");
        assert_eq!(ap.count_threshold, 88);
    }

    #[test]
    fn parses_count_threshold_default() {
        let ap = parse("count=");
        assert_eq!(ap.count_threshold, 0);
    }

    #[test]
    #[should_panic(expected = "not a number")]
    fn parses_count_threshold_invalid() {
        let ap = parse("count=zero");
        assert_eq!(ap.count_threshold, 0);
    }

    #[test]
    fn parses_print_heap_histogram_on() {
        let ap = parse("printHeapHistogram=1");
        assert!(ap.print_heap_histogram);
    }

    #[test]
    fn parses_print_heap_histogram_off() {
        let ap = parse("printHeapHistogram=0");
        assert!(!ap.print_heap_histogram);
    }

    #[test]
    fn parses_print_heap_histogram_default() {
        let ap = parse("printHeapHistogram=");
        assert!(!ap.print_heap_histogram);
    }

    #[test]
    #[should_panic(expected = "not a number")]
    fn parses_print_heap_histogram_invalid() {
        let ap = parse("printHeapHistogram=true");
        assert!(!ap.print_heap_histogram);
    }

    #[test]
    fn parses_heap_histogram_max_entries() {
        let ap = parse("heapHistogramMaxEntries=200");
        assert_eq!(ap.heap_histogram_max_entries, 200);
    }

    #[test]
    fn parses_heap_histogram_max_entries_unlimited() {
        let ap = parse("heapHistogramMaxEntries=0");
        assert_eq!(ap.heap_histogram_max_entries, 0);
    }

    #[test]
    fn parses_heap_histogram_max_entries_default() {
        let ap = parse("heapHistogramMaxEntries=");
        assert_eq!(ap.heap_histogram_max_entries, 100);
    }

    #[test]
    #[should_panic(expected = "not a number")]
    fn parses_heap_histogram_max_entries_invalid() {
        let ap = parse("heapHistogramMaxEntries=unlimited");
        assert_eq!(ap.heap_histogram_max_entries, 100);
    }

    #[test]
    fn parses_print_memory_usage_on() {
        let ap = parse("printMemoryUsage=1");
        assert!(ap.print_memory_usage);
    }

    #[test]
    fn parses_print_memory_usage_off() {
        let ap = parse("printMemoryUsage=0");
        assert!(!ap.print_memory_usage);
    }

    #[test]
    fn parses_print_memory_usage_default() {
        let ap = parse("printMemoryUsage=");
        assert!(ap.print_memory_usage);
    }

    #[test]
    #[should_panic(expected = "not a number")]
    fn parses_print_memory_usage_invalid() {
        let ap = parse("printMemoryUsage=false");
        assert!(ap.print_memory_usage);
    }

    #[test]
    #[should_panic(expected = "unknown option: noSuch")]
    fn unknown_option() {
        parse("noSuch=0");
    }

    #[test]
    #[should_panic(expected = "invalid option: noequals")]
    fn invalid_option() {
        parse("noequals");
    }

    fn parse(o: &str) -> super::AgentParameters {
        use std::ffi::CString;

        let cstr = CString::new(o).unwrap();
        super::AgentParameters::parseParameters(cstr.as_ptr())
    }
}
<|endoftext|>


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

use WindowWrapper;
use image::ColorType;
use image::png::PNGEncoder;
use std::fs::File;
use std::path::Path;
use std::sync::mpsc::{channel, Sender};
use webrender_traits::*;
use wrench::{Wrench, WrenchThing};
use yaml_frame_reader::YamlFrameReader;

pub fn save_flipped<P: AsRef<Path>>(path: P, orig_pixels: &[u8], size: DeviceUintSize) {
    // flip image vertically (texture is upside down)
    let mut data = orig_pixels.to_owned();
    let stride = size.width as usize * 4;
    for y in 0..size.height as usize {
        let dst_start = y * stride;
        let src_start = (size.height as usize - y - 1) * stride;
        let src_slice = &orig_pixels[src_start .. src_start + stride];
        (&mut data[dst_start .. dst_start + stride]).clone_from_slice(&src_slice[..stride]);
    }

    let encoder = PNGEncoder::new(File::create(path).unwrap());
    encoder.encode(&data,
                   size.width,
                   size.height,
                   ColorType::RGBA(8))
           .expect("Unable to encode PNG!");
}

pub fn png(wrench: &mut Wrench,
           window: &mut WindowWrapper,
           mut reader: YamlFrameReader)
{
    // setup a notifier so we can wait for frames to be finished
    struct Notifier {
        tx: Sender<()>,
    };
    impl RenderNotifier for Notifier {
        fn new_frame_ready(&mut self) {
            self.tx.send(()).unwrap();
        }
        fn new_scroll_frame_ready(&mut self, _composite_needed: bool) {}
    }
    let (tx, rx) = channel();
    wrench.renderer.set_render_notifier(Box::new(Notifier { tx: tx }));
    reader.do_frame(wrench);

    // wait for the frame
    rx.recv().unwrap();
    wrench.render();

    let size = window.get_inner_size_pixels();
    let data = wrench.renderer.read_pixels_rgba8(DeviceUintRect::new(DeviceUintPoint::zero(),
                                                                     DeviceUintSize::new(size.0, size.1)));

    let mut out_path = reader.yaml_path().clone();
    out_path.set_extension("png");

    let device_size = DeviceUintSize::new(size.0, size.1);
    save_flipped(out_path, &data, device_size);
}
<commit_msg>Auto merge of #1388 - jrmuizel:device-size, r=glennw<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 WindowWrapper;
use image::ColorType;
use image::png::PNGEncoder;
use std::fs::File;
use std::path::Path;
use std::sync::mpsc::{channel, Sender};
use webrender_traits::*;
use wrench::{Wrench, WrenchThing};
use yaml_frame_reader::YamlFrameReader;

pub fn save_flipped<P: AsRef<Path>>(path: P, orig_pixels: &[u8], size: DeviceUintSize) {
    // flip image vertically (texture is upside down)
    let mut data = orig_pixels.to_owned();
    let stride = size.width as usize * 4;
    for y in 0..size.height as usize {
        let dst_start = y * stride;
        let src_start = (size.height as usize - y - 1) * stride;
        let src_slice = &orig_pixels[src_start .. src_start + stride];
        (&mut data[dst_start .. dst_start + stride]).clone_from_slice(&src_slice[..stride]);
    }

    let encoder = PNGEncoder::new(File::create(path).unwrap());
    encoder.encode(&data,
                   size.width,
                   size.height,
                   ColorType::RGBA(8))
           .expect("Unable to encode PNG!");
}

pub fn png(wrench: &mut Wrench,
           window: &mut WindowWrapper,
           mut reader: YamlFrameReader)
{
    // setup a notifier so we can wait for frames to be finished
    struct Notifier {
        tx: Sender<()>,
    };
    impl RenderNotifier for Notifier {
        fn new_frame_ready(&mut self) {
            self.tx.send(()).unwrap();
        }
        fn new_scroll_frame_ready(&mut self, _composite_needed: bool) {}
    }
    let (tx, rx) = channel();
    wrench.renderer.set_render_notifier(Box::new(Notifier { tx: tx }));
    reader.do_frame(wrench);

    // wait for the frame
    rx.recv().unwrap();
    wrench.render();

    let size = window.get_inner_size_pixels();
    let device_size = DeviceUintSize::new(size.0, size.1);
    let data = wrench.renderer.read_pixels_rgba8(DeviceUintRect::new(DeviceUintPoint::zero(),
                                                                     device_size));

    let mut out_path = reader.yaml_path().clone();
    out_path.set_extension("png");

    save_flipped(out_path, &data, device_size);
}
<|endoftext|>


<commit_before>use crate::core::compiler::{CompileKind, CompileMode, Layout, RustcTargetData};
use crate::core::profiles::Profiles;
use crate::core::{InternedString, PackageIdSpec, Workspace};
use crate::ops;
use crate::util::errors::{CargoResult, CargoResultExt};
use crate::util::paths;
use crate::util::Config;
use std::fs;
use std::path::Path;

pub struct CleanOptions<'a> {
    pub config: &'a Config,
    /// A list of packages to clean. If empty, everything is cleaned.
    pub spec: Vec<String>,
    /// The target arch triple to clean, or None for the host arch
    pub targets: Vec<String>,
    /// Whether to clean the release directory
    pub profile_specified: bool,
    /// Whether to clean the directory of a certain build profile
    pub requested_profile: InternedString,
    /// Whether to just clean the doc directory
    pub doc: bool,
}

/// Cleans the package's build artifacts.
pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> {
    let mut target_dir = ws.target_dir();
    let config = ws.config();

    // If the doc option is set, we just want to delete the doc directory.
    if opts.doc {
        target_dir = target_dir.join("doc");
        return rm_rf(&target_dir.into_path_unlocked(), config);
    }

    let profiles = Profiles::new(ws.profiles(), config, opts.requested_profile, ws.features())?;

    if opts.profile_specified {
        // After parsing profiles we know the dir-name of the profile, if a profile
        // was passed from the command line. If so, delete only the directory of
        // that profile.
        let dir_name = profiles.get_dir_name();
        target_dir = target_dir.join(dir_name);
    }

    // If we have a spec, then we need to delete some packages, otherwise, just
    // remove the whole target directory and be done with it!
    //
    // Note that we don't bother grabbing a lock here as we're just going to
    // blow it all away anyway.
    if opts.spec.is_empty() {
        return rm_rf(&target_dir.into_path_unlocked(), config);
    }

    // Clean specific packages.
    let requested_kinds = CompileKind::from_requested_targets(config, &opts.targets)?;
    let target_data = RustcTargetData::new(ws, &requested_kinds)?;
    let (pkg_set, resolve) = ops::resolve_ws(ws)?;
    let prof_dir_name = profiles.get_dir_name();
    let host_layout = Layout::new(ws, None, &prof_dir_name)?;
    // Convert requested kinds to a Vec of layouts.
    let target_layouts: Vec<(CompileKind, Layout)> = requested_kinds
        .into_iter()
        .filter_map(|kind| match kind {
            CompileKind::Target(target) => match Layout::new(ws, Some(target), &prof_dir_name) {
                Ok(layout) => Some(Ok((kind, layout))),
                Err(e) => Some(Err(e)),
            },
            CompileKind::Host => None,
        })
        .collect::<CargoResult<_>>()?;
    // A Vec of layouts. This is a little convoluted because there can only be
    // one host_layout.
    let layouts = if opts.targets.is_empty() {
        vec![(CompileKind::Host, &host_layout)]
    } else {
        target_layouts
            .iter()
            .map(|(kind, layout)| (*kind, layout))
            .collect()
    };
    // Create a Vec that also includes the host for things that need to clean both.
    let layouts_with_host: Vec<(CompileKind, &Layout)> =
        std::iter::once((CompileKind::Host, &host_layout))
            .chain(layouts.iter().map(|(k, l)| (*k, *l)))
            .collect();

    // Cleaning individual rustdoc crates is currently not supported.
    // For example, the search index would need to be rebuilt to fully
    // remove it (otherwise you're left with lots of broken links).
    // Doc tests produce no output.

    // Get Packages for the specified specs.
    let mut pkg_ids = Vec::new();
    for spec_str in opts.spec.iter() {
        // Translate the spec to a Package.
        let spec = PackageIdSpec::parse(spec_str)?;
        if spec.version().is_some() {
            config.shell().warn(&format!(
                "version qualifier in `-p {}` is ignored, \
                cleaning all versions of `{}` found",
                spec_str,
                spec.name()
            ))?;
        }
        if spec.url().is_some() {
            config.shell().warn(&format!(
                "url qualifier in `-p {}` ignored, \
                cleaning all versions of `{}` found",
                spec_str,
                spec.name()
            ))?;
        }
        let matches: Vec<_> = resolve.iter().filter(|id| spec.matches(*id)).collect();
        if matches.is_empty() {
            anyhow::bail!("package ID specification `{}` matched no packages", spec);
        }
        pkg_ids.extend(matches);
    }
    let packages = pkg_set.get_many(pkg_ids)?;

    for pkg in packages {
        let pkg_dir = format!("{}-*", pkg.name());

        // Clean fingerprints.
        for (_, layout) in &layouts_with_host {
            rm_rf_glob(&layout.fingerprint().join(&pkg_dir), config)?;
        }

        for target in pkg.targets() {
            if target.is_custom_build() {
                // Get both the build_script_build and the output directory.
                for (_, layout) in &layouts_with_host {
                    rm_rf_glob(&layout.build().join(&pkg_dir), config)?;
                }
                continue;
            }
            let crate_name = target.crate_name();
            for &mode in &[
                CompileMode::Build,
                CompileMode::Test,
                CompileMode::Check { test: false },
            ] {
                for (compile_kind, layout) in &layouts {
                    let triple = target_data.short_name(compile_kind);

                    let (file_types, _unsupported) = target_data
                        .info(*compile_kind)
                        .rustc_outputs(mode, target.kind(), triple)?;
                    let (dir, uplift_dir) = if target.is_example() {
                        (layout.examples(), layout.examples())
                    } else {
                        (layout.deps(), layout.dest())
                    };
                    for file_type in file_types {
                        // Some files include a hash in the filename, some don't.
                        let hashed_name = file_type.output_filename(target, Some("*"));
                        let unhashed_name = file_type.output_filename(target, None);
                        rm_rf_glob(&dir.join(&hashed_name), config)?;
                        rm_rf(&dir.join(&unhashed_name), config)?;
                        // Remove dep-info file generated by rustc. It is not tracked in
                        // file_types. It does not have a prefix.
                        let hashed_dep_info = dir.join(format!("{}-*.d", crate_name));
                        let unhashed_dep_info = dir.join(format!("{}.d", crate_name));
                        rm_rf_glob(&hashed_dep_info, config)?;
                        rm_rf(&unhashed_dep_info, config)?;

                        // Remove the uplifted copy.
                        let uplifted_path = uplift_dir.join(file_type.uplift_filename(target));
                        rm_rf(&uplifted_path, config)?;
                        // Dep-info generated by Cargo itself.
                        let dep_info = uplifted_path.with_extension("d");
                        rm_rf(&dep_info, config)?;
                    }
                    // TODO: what to do about build_script_build?
                    let incremental = layout.incremental().join(format!("{}-*", crate_name));
                    rm_rf_glob(&incremental, config)?;
                }
            }
        }
    }

    Ok(())
}

fn rm_rf_glob(pattern: &Path, config: &Config) -> CargoResult<()> {
    // TODO: Display utf8 warning to user?  Or switch to globset?
    let pattern = pattern
        .to_str()
        .ok_or_else(|| anyhow::anyhow!("expected utf-8 path"))?;
    for path in glob::glob(pattern)? {
        rm_rf(&path?, config)?;
    }
    Ok(())
}

fn rm_rf(path: &Path, config: &Config) -> CargoResult<()> {
    let m = fs::symlink_metadata(path);
    if m.as_ref().map(|s| s.is_dir()).unwrap_or(false) {
        config
            .shell()
            .verbose(|shell| shell.status("Removing", path.display()))?;
        paths::remove_dir_all(path)
            .chain_err(|| anyhow::format_err!("could not remove build directory"))?;
    } else if m.is_ok() {
        config
            .shell()
            .verbose(|shell| shell.status("Removing", path.display()))?;
        paths::remove_file(path)
            .chain_err(|| anyhow::format_err!("failed to remove build artifact"))?;
    }
    Ok(())
}
<commit_msg>Remove CACHEDIR.TAG as part of cargo clean<commit_after>use crate::core::compiler::{CompileKind, CompileMode, Layout, RustcTargetData};
use crate::core::profiles::Profiles;
use crate::core::{InternedString, PackageIdSpec, Workspace};
use crate::ops;
use crate::util::errors::{CargoResult, CargoResultExt};
use crate::util::paths;
use crate::util::Config;
use std::fs;
use std::path::Path;

pub struct CleanOptions<'a> {
    pub config: &'a Config,
    /// A list of packages to clean. If empty, everything is cleaned.
    pub spec: Vec<String>,
    /// The target arch triple to clean, or None for the host arch
    pub targets: Vec<String>,
    /// Whether to clean the release directory
    pub profile_specified: bool,
    /// Whether to clean the directory of a certain build profile
    pub requested_profile: InternedString,
    /// Whether to just clean the doc directory
    pub doc: bool,
}

/// Cleans the package's build artifacts.
pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> {
    let mut target_dir = ws.target_dir();
    let config = ws.config();

    // If the doc option is set, we just want to delete the doc directory.
    if opts.doc {
        target_dir = target_dir.join("doc");
        return rm_rf(&target_dir.into_path_unlocked(), config);
    }

    let profiles = Profiles::new(ws.profiles(), config, opts.requested_profile, ws.features())?;

    if opts.profile_specified {
        // After parsing profiles we know the dir-name of the profile, if a profile
        // was passed from the command line. If so, delete only the directory of
        // that profile.
        let dir_name = profiles.get_dir_name();
        target_dir = target_dir.join(dir_name);
    }

    // If we have a spec, then we need to delete some packages, otherwise, just
    // remove the whole target directory and be done with it!
    //
    // Note that we don't bother grabbing a lock here as we're just going to
    // blow it all away anyway.
    if opts.spec.is_empty() {
        return rm_rf(&target_dir.into_path_unlocked(), config);
    }

    // Clean specific packages.
    let requested_kinds = CompileKind::from_requested_targets(config, &opts.targets)?;
    let target_data = RustcTargetData::new(ws, &requested_kinds)?;
    let (pkg_set, resolve) = ops::resolve_ws(ws)?;
    let prof_dir_name = profiles.get_dir_name();
    let host_layout = Layout::new(ws, None, &prof_dir_name)?;
    // Convert requested kinds to a Vec of layouts.
    let target_layouts: Vec<(CompileKind, Layout)> = requested_kinds
        .into_iter()
        .filter_map(|kind| match kind {
            CompileKind::Target(target) => match Layout::new(ws, Some(target), &prof_dir_name) {
                Ok(layout) => Some(Ok((kind, layout))),
                Err(e) => Some(Err(e)),
            },
            CompileKind::Host => None,
        })
        .collect::<CargoResult<_>>()?;
    // A Vec of layouts. This is a little convoluted because there can only be
    // one host_layout.
    let layouts = if opts.targets.is_empty() {
        vec![(CompileKind::Host, &host_layout)]
    } else {
        target_layouts
            .iter()
            .map(|(kind, layout)| (*kind, layout))
            .collect()
    };
    // Create a Vec that also includes the host for things that need to clean both.
    let layouts_with_host: Vec<(CompileKind, &Layout)> =
        std::iter::once((CompileKind::Host, &host_layout))
            .chain(layouts.iter().map(|(k, l)| (*k, *l)))
            .collect();

    // Cleaning individual rustdoc crates is currently not supported.
    // For example, the search index would need to be rebuilt to fully
    // remove it (otherwise you're left with lots of broken links).
    // Doc tests produce no output.

    // Get Packages for the specified specs.
    let mut pkg_ids = Vec::new();
    for spec_str in opts.spec.iter() {
        // Translate the spec to a Package.
        let spec = PackageIdSpec::parse(spec_str)?;
        if spec.version().is_some() {
            config.shell().warn(&format!(
                "version qualifier in `-p {}` is ignored, \
                cleaning all versions of `{}` found",
                spec_str,
                spec.name()
            ))?;
        }
        if spec.url().is_some() {
            config.shell().warn(&format!(
                "url qualifier in `-p {}` ignored, \
                cleaning all versions of `{}` found",
                spec_str,
                spec.name()
            ))?;
        }
        let matches: Vec<_> = resolve.iter().filter(|id| spec.matches(*id)).collect();
        if matches.is_empty() {
            anyhow::bail!("package ID specification `{}` matched no packages", spec);
        }
        pkg_ids.extend(matches);
    }
    let packages = pkg_set.get_many(pkg_ids)?;

    for pkg in packages {
        let pkg_dir = format!("{}-*", pkg.name());

        // Clean fingerprints.
        for (_, layout) in &layouts_with_host {
            rm_rf_glob(&layout.fingerprint().join(&pkg_dir), config)?;
        }

        for target in pkg.targets() {
            if target.is_custom_build() {
                // Get both the build_script_build and the output directory.
                for (_, layout) in &layouts_with_host {
                    rm_rf_glob(&layout.build().join(&pkg_dir), config)?;
                }
                continue;
            }
            let crate_name = target.crate_name();
            for &mode in &[
                CompileMode::Build,
                CompileMode::Test,
                CompileMode::Check { test: false },
            ] {
                for (compile_kind, layout) in &layouts {
                    let triple = target_data.short_name(compile_kind);

                    let (file_types, _unsupported) = target_data
                        .info(*compile_kind)
                        .rustc_outputs(mode, target.kind(), triple)?;
                    let (dir, uplift_dir) = if target.is_example() {
                        (layout.examples(), layout.examples())
                    } else {
                        (layout.deps(), layout.dest())
                    };
                    for file_type in file_types {
                        // Some files include a hash in the filename, some don't.
                        let hashed_name = file_type.output_filename(target, Some("*"));
                        let unhashed_name = file_type.output_filename(target, None);
                        rm_rf_glob(&dir.join(&hashed_name), config)?;
                        rm_rf(&dir.join(&unhashed_name), config)?;
                        // Remove dep-info file generated by rustc. It is not tracked in
                        // file_types. It does not have a prefix.
                        let hashed_dep_info = dir.join(format!("{}-*.d", crate_name));
                        let unhashed_dep_info = dir.join(format!("{}.d", crate_name));
                        rm_rf_glob(&hashed_dep_info, config)?;
                        rm_rf(&unhashed_dep_info, config)?;

                        // Remove the uplifted copy.
                        let uplifted_path = uplift_dir.join(file_type.uplift_filename(target));
                        rm_rf(&uplifted_path, config)?;
                        // Dep-info generated by Cargo itself.
                        let dep_info = uplifted_path.with_extension("d");
                        rm_rf(&dep_info, config)?;
                    }
                    // TODO: what to do about build_script_build?
                    let incremental = layout.incremental().join(format!("{}-*", crate_name));
                    rm_rf_glob(&incremental, config)?;
                    rm_rf(&uplift_dir.join("CACHEDIR.TAG"), config)?;
                }
            }
        }
    }

    Ok(())
}

fn rm_rf_glob(pattern: &Path, config: &Config) -> CargoResult<()> {
    // TODO: Display utf8 warning to user?  Or switch to globset?
    let pattern = pattern
        .to_str()
        .ok_or_else(|| anyhow::anyhow!("expected utf-8 path"))?;
    for path in glob::glob(pattern)? {
        rm_rf(&path?, config)?;
    }
    Ok(())
}

fn rm_rf(path: &Path, config: &Config) -> CargoResult<()> {
    let m = fs::symlink_metadata(path);
    if m.as_ref().map(|s| s.is_dir()).unwrap_or(false) {
        config
            .shell()
            .verbose(|shell| shell.status("Removing", path.display()))?;
        paths::remove_dir_all(path)
            .chain_err(|| anyhow::format_err!("could not remove build directory"))?;
    } else if m.is_ok() {
        config
            .shell()
            .verbose(|shell| shell.status("Removing", path.display()))?;
        paths::remove_file(path)
            .chain_err(|| anyhow::format_err!("failed to remove build artifact"))?;
    }
    Ok(())
}
<|endoftext|>


<commit_before>#![deny(bare_trait_objects)]

#[macro_use]
extern crate clap;

use anyhow::{format_err, Error};
use clap::Arg;
use lucet_runtime::{self, DlModule, Limits, MmapRegion, Module, PublicKey, Region, RunResult};
use lucet_wasi::{self, types::Exitcode, WasiCtxBuilder};
use std::fs::File;
use std::path::PathBuf;
use std::sync::Arc;
use std::thread;
use std::time::Duration;

struct Config<'a> {
    lucet_module: &'a str,
    guest_args: Vec<&'a str>,
    entrypoint: &'a str,
    preopen_dirs: Vec<(File, &'a str)>,
    limits: Limits,
    timeout: Option<Duration>,
    verify: bool,
    pk_path: Option<PathBuf>,
}

fn parse_humansized(desc: &str) -> Result<u64, Error> {
    use human_size::{Byte, ParsingError, Size, SpecificSize};
    match desc.parse::<Size>() {
        Ok(s) => {
            let bytes: SpecificSize<Byte> = s.into();
            Ok(bytes.value() as u64)
        }
        Err(ParsingError::MissingMultiple) => Ok(desc.parse::<u64>()?),
        Err(e) => Err(e.into()),
    }
}

fn main() {
    // No-ops, but makes sure the linker doesn't throw away parts
    // of the runtime:
    lucet_runtime::lucet_internal_ensure_linked();
    lucet_wasi::export_wasi_funcs();

    let matches = app_from_crate!()
        .arg(
            Arg::with_name("entrypoint")
                .long("entrypoint")
                .takes_value(true)
                .default_value("_start")
                .help("Entrypoint to run within the WASI module"),
        )
        .arg(
            Arg::with_name("preopen_dirs")
                .required(false)
                .long("dir")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1)
                .help("A directory to provide to the WASI guest")
                .long_help(
                    "Directories on the host can be provided to the WASI guest as part of a \
                     virtual filesystem. Each directory is specified as \
                     --dir `host_path:guest_path`, where `guest_path` specifies the path that will \
                     correspond to `host_path` for calls like `fopen` in the guest.\
                     \n\n\
                     For example, `--dir /home/host_user/wasi_sandbox:/sandbox` will make \
                     `/home/host_user/wasi_sandbox` available within the guest as `/sandbox`.\
                     \n\n\
                     Guests will be able to access any files and directories under the \
                     `host_path`, but will be unable to access other parts of the host \
                     filesystem through relative paths (e.g., `/sandbox/../some_other_file`) \
                     or through symlinks.",
                ),
        )
        .arg(
            Arg::with_name("lucet_module")
                .required(true)
                .help("Path to the `lucetc`-compiled WASI module"),
        )
        .arg(
            Arg::with_name("heap_memory_size")
                .long("max-heap-size")
                .takes_value(true)
                .default_value("4 GiB")
                .help("Maximum heap size (must be a multiple of 4 KiB)"),
        )
        .arg(
            Arg::with_name("heap_address_space_size")
                .long("heap-address-space")
                .takes_value(true)
                .default_value("8 GiB")
                .help("Maximum heap address space size (must be a multiple of 4 KiB, and >= `max-heap-size`)"),
        )
        .arg(
            Arg::with_name("stack_size")
                .long("stack-size")
                .takes_value(true)
                .default_value("8 MiB")
                .help("Maximum stack size (must be a multiple of 4 KiB)"),
        )
        .arg(
            Arg::with_name("timeout").long("timeout").takes_value(true).help("Number of milliseconds the instance will be allowed to run")
            )
        .arg(
            Arg::with_name("guest_args")
                .required(false)
                .multiple(true)
                .help("Arguments to the WASI `main` function"),
        )
        .arg(
            Arg::with_name("verify")
                .long("--signature-verify")
                .takes_value(false)
                .help("Verify the signature of the source file")
        )
        .arg(
            Arg::with_name("pk_path")
                .long("--signature-pk")
                .takes_value(true)
                .help("Path to the public key to verify the source code signature")
        )
        .get_matches();

    let entrypoint = matches.value_of("entrypoint").unwrap();

    let lucet_module = matches.value_of("lucet_module").unwrap();

    let preopen_dirs = matches
        .values_of("preopen_dirs")
        .map(|vals| {
            vals.map(|preopen_dir| {
                if let [host_path, guest_path] =
                    preopen_dir.split(':').collect::<Vec<&str>>().as_slice()
                {
                    let host_dir = File::open(host_path).unwrap();
                    (host_dir, *guest_path)
                } else {
                    println!("Invalid directory specification: {}", preopen_dir);
                    println!("{}", matches.usage());
                    std::process::exit(1);
                }
            })
            .collect()
        })
        .unwrap_or(vec![]);

    let heap_memory_size = matches
        .value_of("heap_memory_size")
        .ok_or_else(|| format_err!("missing heap memory size"))
        .and_then(|v| parse_humansized(v))
        .unwrap() as usize;

    let heap_address_space_size = matches
        .value_of("heap_address_space_size")
        .ok_or_else(|| format_err!("missing heap address space size"))
        .and_then(|v| parse_humansized(v))
        .unwrap() as usize;

    if heap_memory_size > heap_address_space_size {
        println!("`heap-address-space` must be at least as large as `max-heap-size`");
        println!("{}", matches.usage());
        std::process::exit(1);
    }

    let stack_size = matches
        .value_of("stack_size")
        .ok_or_else(|| format_err!("missing stack size"))
        .and_then(|v| parse_humansized(v))
        .unwrap() as usize;

    let timeout = matches
        .value_of("timeout")
        .map(|t| Duration::from_millis(t.parse::<u64>().unwrap()));

    let limits = Limits {
        heap_memory_size,
        heap_address_space_size,
        stack_size,
        globals_size: 0, // calculated from module
        ..Limits::default()
    };

    let guest_args = matches
        .values_of("guest_args")
        .map(|vals| vals.collect())
        .unwrap_or(vec![]);

    let verify = matches.is_present("verify");
    let pk_path = matches.value_of("pk_path").map(PathBuf::from);

    let config = Config {
        lucet_module,
        guest_args,
        entrypoint,
        preopen_dirs,
        limits,
        timeout,
        verify,
        pk_path,
    };

    run(config)
}

fn run(config: Config<'_>) {
    let exitcode = {
        // doing all of this in a block makes sure everything gets dropped before exiting
        let pk = match (config.verify, config.pk_path) {
            (false, _) => None,
            (true, Some(pk_path)) => {
                Some(PublicKey::from_file(pk_path).expect("public key can be loaded"))
            }
            (true, None) => panic!("signature verification requires a public key"),
        };
        let module = if let Some(pk) = pk {
            DlModule::load_and_verify(&config.lucet_module, pk)
                .expect("signed module can be loaded")
        } else {
            DlModule::load(&config.lucet_module).expect("module can be loaded")
        };
        let min_globals_size = module.initial_globals_size();
        let globals_size = ((min_globals_size + 4096 - 1) / 4096) * 4096;

        let region = MmapRegion::create(
            1,
            &Limits {
                globals_size,
                ..config.limits
            },
        )
        .expect("region can be created");

        // put the path to the module on the front for argv[0]
        let args = std::iter::once(config.lucet_module)
            .chain(config.guest_args.into_iter())
            .collect::<Vec<&str>>();
        let mut ctx = WasiCtxBuilder::new();
        ctx.args(args.iter());
        ctx.inherit_stdio();
        ctx.inherit_env();
        for (dir, guest_path) in config.preopen_dirs {
            ctx.preopened_dir(dir, guest_path);
        }
        let mut inst = region
            .new_instance_builder(module as Arc<dyn Module>)
            .with_embed_ctx(ctx.build().expect("WASI ctx can be created"))
            .build()
            .expect("instance can be created");

        if let Some(timeout) = config.timeout {
            let kill_switch = inst.kill_switch();
            thread::spawn(move || {
                thread::sleep(timeout);
                // We may hit this line exactly when the guest exits, so sometimes `terminate` can
                // fail. That's still acceptable, so just ignore the result.
                kill_switch.terminate().ok();
            });
        }

        match inst.run(config.entrypoint, &[]) {
            // normal termination implies 0 exit code
            Ok(RunResult::Returned(_)) => 0,
            // none of the WASI hostcalls use yield yet, so this shouldn't happen
            Ok(RunResult::Yielded(_)) => panic!("lucet-wasi unexpectedly yielded"),
            Err(lucet_runtime::Error::RuntimeTerminated(
                lucet_runtime::TerminationDetails::Provided(any),
            )) => *any
                .downcast_ref::<Exitcode>()
                .expect("termination yields an exitcode"),
            Err(lucet_runtime::Error::RuntimeTerminated(
                lucet_runtime::TerminationDetails::Remote,
            )) => {
                println!("Terminated via remote kill switch (likely a timeout)");
                std::u32::MAX
            }
            Err(e) => panic!("lucet-wasi runtime error: {}", e),
        }
    };
    std::process::exit(exitcode as i32);
}
<commit_msg>explicitly run the start section in `lucet-wasi`<commit_after>#![deny(bare_trait_objects)]

#[macro_use]
extern crate clap;

use anyhow::{format_err, Error};
use clap::Arg;
use lucet_runtime::{self, DlModule, Limits, MmapRegion, Module, PublicKey, Region, RunResult};
use lucet_wasi::{self, types::Exitcode, WasiCtxBuilder};
use std::fs::File;
use std::path::PathBuf;
use std::sync::Arc;
use std::thread;
use std::time::Duration;

struct Config<'a> {
    lucet_module: &'a str,
    guest_args: Vec<&'a str>,
    entrypoint: &'a str,
    preopen_dirs: Vec<(File, &'a str)>,
    limits: Limits,
    timeout: Option<Duration>,
    verify: bool,
    pk_path: Option<PathBuf>,
}

fn parse_humansized(desc: &str) -> Result<u64, Error> {
    use human_size::{Byte, ParsingError, Size, SpecificSize};
    match desc.parse::<Size>() {
        Ok(s) => {
            let bytes: SpecificSize<Byte> = s.into();
            Ok(bytes.value() as u64)
        }
        Err(ParsingError::MissingMultiple) => Ok(desc.parse::<u64>()?),
        Err(e) => Err(e.into()),
    }
}

fn main() {
    // No-ops, but makes sure the linker doesn't throw away parts
    // of the runtime:
    lucet_runtime::lucet_internal_ensure_linked();
    lucet_wasi::export_wasi_funcs();

    let matches = app_from_crate!()
        .arg(
            Arg::with_name("entrypoint")
                .long("entrypoint")
                .takes_value(true)
                .default_value("_start")
                .help("Entrypoint to run within the WASI module"),
        )
        .arg(
            Arg::with_name("preopen_dirs")
                .required(false)
                .long("dir")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1)
                .help("A directory to provide to the WASI guest")
                .long_help(
                    "Directories on the host can be provided to the WASI guest as part of a \
                     virtual filesystem. Each directory is specified as \
                     --dir `host_path:guest_path`, where `guest_path` specifies the path that will \
                     correspond to `host_path` for calls like `fopen` in the guest.\
                     \n\n\
                     For example, `--dir /home/host_user/wasi_sandbox:/sandbox` will make \
                     `/home/host_user/wasi_sandbox` available within the guest as `/sandbox`.\
                     \n\n\
                     Guests will be able to access any files and directories under the \
                     `host_path`, but will be unable to access other parts of the host \
                     filesystem through relative paths (e.g., `/sandbox/../some_other_file`) \
                     or through symlinks.",
                ),
        )
        .arg(
            Arg::with_name("lucet_module")
                .required(true)
                .help("Path to the `lucetc`-compiled WASI module"),
        )
        .arg(
            Arg::with_name("heap_memory_size")
                .long("max-heap-size")
                .takes_value(true)
                .default_value("4 GiB")
                .help("Maximum heap size (must be a multiple of 4 KiB)"),
        )
        .arg(
            Arg::with_name("heap_address_space_size")
                .long("heap-address-space")
                .takes_value(true)
                .default_value("8 GiB")
                .help("Maximum heap address space size (must be a multiple of 4 KiB, and >= `max-heap-size`)"),
        )
        .arg(
            Arg::with_name("stack_size")
                .long("stack-size")
                .takes_value(true)
                .default_value("8 MiB")
                .help("Maximum stack size (must be a multiple of 4 KiB)"),
        )
        .arg(
            Arg::with_name("timeout").long("timeout").takes_value(true).help("Number of milliseconds the instance will be allowed to run")
            )
        .arg(
            Arg::with_name("guest_args")
                .required(false)
                .multiple(true)
                .help("Arguments to the WASI `main` function"),
        )
        .arg(
            Arg::with_name("verify")
                .long("--signature-verify")
                .takes_value(false)
                .help("Verify the signature of the source file")
        )
        .arg(
            Arg::with_name("pk_path")
                .long("--signature-pk")
                .takes_value(true)
                .help("Path to the public key to verify the source code signature")
        )
        .get_matches();

    let entrypoint = matches.value_of("entrypoint").unwrap();

    let lucet_module = matches.value_of("lucet_module").unwrap();

    let preopen_dirs = matches
        .values_of("preopen_dirs")
        .map(|vals| {
            vals.map(|preopen_dir| {
                if let [host_path, guest_path] =
                    preopen_dir.split(':').collect::<Vec<&str>>().as_slice()
                {
                    let host_dir = File::open(host_path).unwrap();
                    (host_dir, *guest_path)
                } else {
                    println!("Invalid directory specification: {}", preopen_dir);
                    println!("{}", matches.usage());
                    std::process::exit(1);
                }
            })
            .collect()
        })
        .unwrap_or(vec![]);

    let heap_memory_size = matches
        .value_of("heap_memory_size")
        .ok_or_else(|| format_err!("missing heap memory size"))
        .and_then(|v| parse_humansized(v))
        .unwrap() as usize;

    let heap_address_space_size = matches
        .value_of("heap_address_space_size")
        .ok_or_else(|| format_err!("missing heap address space size"))
        .and_then(|v| parse_humansized(v))
        .unwrap() as usize;

    if heap_memory_size > heap_address_space_size {
        println!("`heap-address-space` must be at least as large as `max-heap-size`");
        println!("{}", matches.usage());
        std::process::exit(1);
    }

    let stack_size = matches
        .value_of("stack_size")
        .ok_or_else(|| format_err!("missing stack size"))
        .and_then(|v| parse_humansized(v))
        .unwrap() as usize;

    let timeout = matches
        .value_of("timeout")
        .map(|t| Duration::from_millis(t.parse::<u64>().unwrap()));

    let limits = Limits {
        heap_memory_size,
        heap_address_space_size,
        stack_size,
        globals_size: 0, // calculated from module
        ..Limits::default()
    };

    let guest_args = matches
        .values_of("guest_args")
        .map(|vals| vals.collect())
        .unwrap_or(vec![]);

    let verify = matches.is_present("verify");
    let pk_path = matches.value_of("pk_path").map(PathBuf::from);

    let config = Config {
        lucet_module,
        guest_args,
        entrypoint,
        preopen_dirs,
        limits,
        timeout,
        verify,
        pk_path,
    };

    run(config)
}

fn run(config: Config<'_>) {
    let exitcode = {
        // doing all of this in a block makes sure everything gets dropped before exiting
        let pk = match (config.verify, config.pk_path) {
            (false, _) => None,
            (true, Some(pk_path)) => {
                Some(PublicKey::from_file(pk_path).expect("public key can be loaded"))
            }
            (true, None) => panic!("signature verification requires a public key"),
        };
        let module = if let Some(pk) = pk {
            DlModule::load_and_verify(&config.lucet_module, pk)
                .expect("signed module can be loaded")
        } else {
            DlModule::load(&config.lucet_module).expect("module can be loaded")
        };
        let min_globals_size = module.initial_globals_size();
        let globals_size = ((min_globals_size + 4096 - 1) / 4096) * 4096;

        let region = MmapRegion::create(
            1,
            &Limits {
                globals_size,
                ..config.limits
            },
        )
        .expect("region can be created");

        // put the path to the module on the front for argv[0]
        let args = std::iter::once(config.lucet_module)
            .chain(config.guest_args.into_iter())
            .collect::<Vec<&str>>();
        let mut ctx = WasiCtxBuilder::new();
        ctx.args(args.iter());
        ctx.inherit_stdio();
        ctx.inherit_env();
        for (dir, guest_path) in config.preopen_dirs {
            ctx.preopened_dir(dir, guest_path);
        }
        let mut inst = region
            .new_instance_builder(module as Arc<dyn Module>)
            .with_embed_ctx(ctx.build().expect("WASI ctx can be created"))
            .build()
            .expect("instance can be created");

        if let Some(timeout) = config.timeout {
            let kill_switch = inst.kill_switch();
            thread::spawn(move || {
                thread::sleep(timeout);
                // We may hit this line exactly when the guest exits, so sometimes `terminate` can
                // fail. That's still acceptable, so just ignore the result.
                kill_switch.terminate().ok();
            });
        }

        inst.run_start().expect("Wasm start function runs");

        match inst.run(config.entrypoint, &[]) {
            // normal termination implies 0 exit code
            Ok(RunResult::Returned(_)) => 0,
            // none of the WASI hostcalls use yield yet, so this shouldn't happen
            Ok(RunResult::Yielded(_)) => panic!("lucet-wasi unexpectedly yielded"),
            Err(lucet_runtime::Error::RuntimeTerminated(
                lucet_runtime::TerminationDetails::Provided(any),
            )) => *any
                .downcast_ref::<Exitcode>()
                .expect("termination yields an exitcode"),
            Err(lucet_runtime::Error::RuntimeTerminated(
                lucet_runtime::TerminationDetails::Remote,
            )) => {
                println!("Terminated via remote kill switch (likely a timeout)");
                std::u32::MAX
            }
            Err(e) => panic!("lucet-wasi runtime error: {}", e),
        }
    };
    std::process::exit(exitcode as i32);
}
<|endoftext|>


<commit_before>#![cfg_attr(not(feature = "tweetust"), allow(unused_imports))]

extern crate futures;
extern crate serde_json as json;
extern crate tokio_core;
extern crate twitter_stream;

use futures::{Future, Stream};
use std::fs::File;
use tokio_core::reactor::Core;
use twitter_stream::{Error, StreamMessage, Token, TwitterStream};

#[cfg(feature = "tweetust")]
fn main() {
    extern crate tweetust;

    // `credential.json` must have the following form:
    // {"consumer_key": "...", "consumer_secret": "...", "access_key": "...", "access_secret": "..."}

    let credential = File::open("examples/credential.json").unwrap();
    let token: Token = json::from_reader(credential).unwrap();

    let mut core = Core::new().unwrap();

    let future_stream = TwitterStream::user(&token, &core.handle());
    let rest = tweetust::TwitterClient::new(token, tweetust::DefaultHttpHandler::with_https_connector().unwrap());

    // Information of the authenticated user:
    let user = rest.account().verify_credentials().execute().unwrap().object;

    let bot = future_stream.flatten_stream().for_each(|message| {
        if let StreamMessage::Tweet(tweet) = message {
            if tweet.user.id != user.id as u64
                && tweet.entities.user_mentions.iter().any(|mention| mention.id == user.id as u64)
            {
                println!("On {}, @{} tweeted: {:?}", tweet.created_at, tweet.user.screen_name, tweet.text);

                let response = format!("@{} {}", tweet.user.screen_name, tweet.text);
                rest.statuses()
                    .update(response)
                    .in_reply_to_status_id(tweet.id as _)
                    .execute()
                    .map_err(Error::custom)?;
            }
        }

        Ok(())
    });

    core.run(bot).unwrap();
}

#[cfg(not(feature = "tweetust"))]
fn main() {
    println!("This example needs `tweetust` feature");
}
<commit_msg>Make echo_bot examples work on Windows<commit_after>#![cfg_attr(not(feature = "tweetust"), allow(unused_imports))]

extern crate futures;
extern crate serde_json as json;
extern crate tokio_core;
extern crate twitter_stream;

use futures::{Future, Stream};
use std::fs::File;
use std::path::PathBuf;
use tokio_core::reactor::Core;
use twitter_stream::{Error, StreamMessage, Token, TwitterStream};

#[cfg(feature = "tweetust")]
fn main() {
    extern crate tweetust;

    // `credential.json` must have the following form:
    // {"consumer_key": "...", "consumer_secret": "...", "access_key": "...", "access_secret": "..."}

    let mut credential_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    credential_path.push("examples");
    credential_path.push("credential.json");

    let credential = File::open(credential_path).unwrap();
    let token: Token = json::from_reader(credential).unwrap();

    let mut core = Core::new().unwrap();

    let future_stream = TwitterStream::user(&token, &core.handle());
    let rest = tweetust::TwitterClient::new(token, tweetust::DefaultHttpHandler::with_https_connector().unwrap());

    // Information of the authenticated user:
    let user = rest.account().verify_credentials().execute().unwrap().object;

    let bot = future_stream.flatten_stream().for_each(|message| {
        if let StreamMessage::Tweet(tweet) = message {
            if tweet.user.id != user.id as u64
                && tweet.entities.user_mentions.iter().any(|mention| mention.id == user.id as u64)
            {
                println!("On {}, @{} tweeted: {:?}", tweet.created_at, tweet.user.screen_name, tweet.text);

                let response = format!("@{} {}", tweet.user.screen_name, tweet.text);
                rest.statuses()
                    .update(response)
                    .in_reply_to_status_id(tweet.id as _)
                    .execute()
                    .map_err(Error::custom)?;
            }
        }

        Ok(())
    });

    core.run(bot).unwrap();
}

#[cfg(not(feature = "tweetust"))]
fn main() {
    println!("This example needs `tweetust` feature");
}
<|endoftext|>


<commit_before>#[doc = "Random number generation"];

export rng, seed, seeded_rng, weighted, extensions;

enum rctx {}

#[abi = "cdecl"]
native mod rustrt {
    fn rand_seed() -> [u8];
    fn rand_new() -> *rctx;
    fn rand_new_seeded(seed: [u8]) -> *rctx;
    fn rand_next(c: *rctx) -> u32;
    fn rand_free(c: *rctx);
}

#[doc = "A random number generator"]
iface rng {
    #[doc = "Return the next random integer"]
    fn next() -> u32;
}

#[doc = "A value with a particular weight compared to other values"]
type weighted<T> = { weight: uint, item: T };

#[doc = "Extension methods for random number generators"]
impl extensions for rng {

    #[doc = "Return a random int"]
    fn gen_int() -> int {
        self.gen_i64() as int
    }

    #[doc = "Return an int randomly chosen from the range [start, end], \
             failing if start > end"]
    fn gen_int_from(start: int, end: int) -> int {
        assert start <= end;
        start + int::abs(self.gen_int() % (end - start + 1))
    }

    #[doc = "Return a random i8"]
    fn gen_i8() -> i8 {
        self.next() as i8
    }

    #[doc = "Return a random i16"]
    fn gen_i16() -> i16 {
        self.next() as i16
    }

    #[doc = "Return a random i32"]
    fn gen_i32() -> i32 {
        self.next() as i32
    }

    #[doc = "Return a random i64"]
    fn gen_i64() -> i64 {
        (self.next() as i64 << 32) | self.next() as i64
    }

    #[doc = "Return a random uint"]
    fn gen_uint() -> uint {
        self.gen_u64() as uint
    }

    #[doc = "Return a uint randomly chosen from the range [start, end], \
             failing if start > end"]
    fn gen_uint_from(start: uint, end: uint) -> uint {
        assert start <= end;
        start + (self.gen_uint() % (end - start + 1u))
    }

    #[doc = "Return a random u8"]
    fn gen_u8() -> u8 {
        self.next() as u8
    }

    #[doc = "Return a random u16"]
    fn gen_u16() -> u16 {
        self.next() as u16
    }

    #[doc = "Return a random u32"]
    fn gen_u32() -> u32 {
        self.next()
    }

    #[doc = "Return a random u64"]
    fn gen_u64() -> u64 {
        (self.next() as u64 << 32) | self.next() as u64
    }

    #[doc = "Return a random float"]
    fn gen_float() -> float {
        self.gen_f64() as float
    }

    #[doc = "Return a random f32"]
    fn gen_f32() -> f32 {
        self.gen_f64() as f32
    }

    #[doc = "Return a random f64"]
    fn gen_f64() -> f64 {
        let u1 = self.next() as f64;
        let u2 = self.next() as f64;
        let u3 = self.next() as f64;
        let scale = u32::max_value as f64;
        ret ((u1 / scale + u2) / scale + u3) / scale;
    }

    #[doc = "Return a random char"]
    fn gen_char() -> char {
        self.next() as char
    }

    #[doc = "Return a char randomly chosen from chars, failing if chars is \
             empty"]
    fn gen_char_from(chars: str) -> char {
        assert !chars.is_empty();
        self.choose(str::chars(chars))
    }

    #[doc = "Return a random bool"]
    fn gen_bool() -> bool {
        self.next() & 1u32 == 1u32
    }

    #[doc = "Return a bool with a 1 in n chance of true"]
    fn gen_weighted_bool(n: uint) -> bool {
        if n == 0u {
            true
        } else {
            self.gen_uint_from(1u, n) == 1u
        }
    }

    #[doc = "Return a random string of the specified length composed of A-Z, \
             a-z, 0-9"]
    fn gen_str(len: uint) -> str {
        let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
                      "abcdefghijklmnopqrstuvwxyz" +
                      "0123456789";
        let mut s = "";
        let mut i = 0u;
        while (i < len) {
            s = s + str::from_char(self.gen_char_from(charset));
            i += 1u;
        }
        s
    }

    #[doc = "Return a random byte string of the specified length"]
    fn gen_bytes(len: uint) -> [u8] {
        vec::from_fn(len) {|_i|
            self.gen_u8()
        }
    }

    #[doc = "Choose an item randomly, failing if values is empty"]
    fn choose<T:copy>(values: [T]) -> T {
        self.choose_option(values).get()
    }

    #[doc = "Choose some(item) randomly, returning none if values is empty"]
    fn choose_option<T:copy>(values: [T]) -> option<T> {
        if values.is_empty() {
            none
        } else {
            some(values[self.gen_uint_from(0u, values.len() - 1u)])
        }
    }

    #[doc = "Choose an item respecting the relative weights, failing if \
             the sum of the weights is 0"]
    fn choose_weighted<T: copy>(v : [weighted<T>]) -> T {
        self.choose_weighted_option(v).get()
    }

    #[doc = "Choose some(item) respecting the relative weights, returning \
             none if the sum of the weights is 0"]
    fn choose_weighted_option<T:copy>(v: [weighted<T>]) -> option<T> {
        let mut total = 0u;
        for v.each {|item|
            total += item.weight;
        }
        if total == 0u {
            ret none;
        }
        let chosen = self.gen_uint_from(0u, total - 1u);
        let mut so_far = 0u;
        for v.each {|item|
            so_far += item.weight;
            if so_far > chosen {
                ret some(item.item);
            }
        }
        unreachable();
    }

    #[doc = "Return a vec containing copies of the items, in order, where \
             the weight of the item determines how many copies there are"]
    fn weighted_vec<T:copy>(v: [weighted<T>]) -> [T] {
        let mut r = [];
        for v.each {|item|
            uint::range(0u, item.weight) {|_i|
                r += [item.item];
            }
        }
        r
    }

    #[doc = "Shuffle a vec"]
    fn shuffle<T:copy>(values: [T]) -> [T] {
        let mut m = vec::to_mut(values);
        self.shuffle_mut(m);
        ret vec::from_mut(m);
    }

    #[doc = "Shuffle a mutable vec in place"]
    fn shuffle_mut<T>(&values: [mut T]) {
        let mut i = values.len();
        while i >= 2u {
            // invariant: elements with index >= i have been locked in place.
            i -= 1u;
            // lock element i in place.
            vec::swap(values, i, self.gen_uint_from(0u, i));
        }
    }

}

resource rand_res(c: *rctx) { rustrt::rand_free(c); }

impl of rng for @rand_res {
    fn next() -> u32 { ret rustrt::rand_next(**self); }
}

#[doc = "Create a new random seed for seeded_rng"]
fn seed() -> [u8] {
    rustrt::rand_seed()
}

#[doc = "Create a random number generator with a system specified seed"]
fn rng() -> rng {
    @rand_res(rustrt::rand_new()) as rng
}

#[doc = "Create a random number generator using the specified seed. A \
         generator constructed with a given seed will generate the same \
         sequence of values as all other generators constructed with the \
         same seed. The seed may be any length."]
fn seeded_rng(seed: [u8]) -> rng {
    @rand_res(rustrt::rand_new_seeded(seed)) as rng
}

#[cfg(test)]
mod tests {

    #[test]
    fn rng_seeded() {
        let seed = rand::seed();
        let ra = rand::seeded_rng(seed);
        let rb = rand::seeded_rng(seed);
        assert ra.gen_str(100u) == rb.gen_str(100u);
    }

    #[test]
    fn rng_seeded_custom_seed() {
        // much shorter than generated seeds which are 1024 bytes
        let seed = [2u8, 32u8, 4u8, 32u8, 51u8];
        let ra = rand::seeded_rng(seed);
        let rb = rand::seeded_rng(seed);
        assert ra.gen_str(100u) == rb.gen_str(100u);
    }

    #[test]
    fn gen_int_from() {
        let r = rand::rng();
        let a = r.gen_int_from(-3, 42);
        assert a >= -3 && a <= 42;
        assert r.gen_int_from(0, 0) == 0;
        assert r.gen_int_from(-12, -12) == -12;
    }

    #[test]
    #[should_fail]
    fn gen_int_from_fail() {
        rand::rng().gen_int_from(5, -2);
    }

    #[test]
    fn gen_uint_from() {
        let r = rand::rng();
        let a = r.gen_uint_from(3u, 42u);
        assert a >= 3u && a <= 42u;
        assert r.gen_uint_from(0u, 0u) == 0u;
        assert r.gen_uint_from(12u, 12u) == 12u;
    }

    #[test]
    #[should_fail]
    fn gen_uint_from_fail() {
        rand::rng().gen_uint_from(5u, 2u);
    }

    #[test]
    fn gen_float() {
        let r = rand::rng();
        let a = r.gen_float();
        let b = r.gen_float();
        log(debug, (a, b));
    }

    #[test]
    fn gen_weighted_bool() {
        let r = rand::rng();
        assert r.gen_weighted_bool(0u) == true;
        assert r.gen_weighted_bool(1u) == true;
    }

    #[test]
    fn gen_str() {
        let r = rand::rng();
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        assert r.gen_str(0u).len() == 0u;
        assert r.gen_str(10u).len() == 10u;
        assert r.gen_str(16u).len() == 16u;
    }

    #[test]
    fn gen_bytes() {
        let r = rand::rng();
        assert r.gen_bytes(0u).len() == 0u;
        assert r.gen_bytes(10u).len() == 10u;
        assert r.gen_bytes(16u).len() == 16u;
    }

    #[test]
    fn choose() {
        let r = rand::rng();
        assert r.choose([1, 1, 1]) == 1;
    }

    #[test]
    fn choose_option() {
        let r = rand::rng();
        assert r.choose_option([]) == none::<int>;
        assert r.choose_option([1, 1, 1]) == some(1);
    }

    #[test]
    fn choose_weighted() {
        let r = rand::rng();
        assert r.choose_weighted([{weight: 1u, item: 42}]) == 42;
        assert r.choose_weighted([
            {weight: 0u, item: 42},
            {weight: 1u, item: 43}
        ]) == 43;
    }

    #[test]
    fn choose_weighted_option() {
        let r = rand::rng();
        assert r.choose_weighted_option([{weight: 1u, item: 42}]) == some(42);
        assert r.choose_weighted_option([
            {weight: 0u, item: 42},
            {weight: 1u, item: 43}
        ]) == some(43);
        assert r.choose_weighted_option([]) == none::<int>;
    }

    #[test]
    fn weighted_vec() {
        let r = rand::rng();
        let empty: [int] = [];
        assert r.weighted_vec([]) == empty;
        assert r.weighted_vec([
            {weight: 0u, item: 3u},
            {weight: 1u, item: 2u},
            {weight: 2u, item: 1u}
        ]) == [2u, 1u, 1u];
    }

    #[test]
    fn shuffle() {
        let r = rand::rng();
        let empty: [int] = [];
        assert r.shuffle([]) == empty;
        assert r.shuffle([1, 1, 1]) == [1, 1, 1];
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>core: Ignore a should_fail test on win32<commit_after>#[doc = "Random number generation"];

export rng, seed, seeded_rng, weighted, extensions;

enum rctx {}

#[abi = "cdecl"]
native mod rustrt {
    fn rand_seed() -> [u8];
    fn rand_new() -> *rctx;
    fn rand_new_seeded(seed: [u8]) -> *rctx;
    fn rand_next(c: *rctx) -> u32;
    fn rand_free(c: *rctx);
}

#[doc = "A random number generator"]
iface rng {
    #[doc = "Return the next random integer"]
    fn next() -> u32;
}

#[doc = "A value with a particular weight compared to other values"]
type weighted<T> = { weight: uint, item: T };

#[doc = "Extension methods for random number generators"]
impl extensions for rng {

    #[doc = "Return a random int"]
    fn gen_int() -> int {
        self.gen_i64() as int
    }

    #[doc = "Return an int randomly chosen from the range [start, end], \
             failing if start > end"]
    fn gen_int_from(start: int, end: int) -> int {
        assert start <= end;
        start + int::abs(self.gen_int() % (end - start + 1))
    }

    #[doc = "Return a random i8"]
    fn gen_i8() -> i8 {
        self.next() as i8
    }

    #[doc = "Return a random i16"]
    fn gen_i16() -> i16 {
        self.next() as i16
    }

    #[doc = "Return a random i32"]
    fn gen_i32() -> i32 {
        self.next() as i32
    }

    #[doc = "Return a random i64"]
    fn gen_i64() -> i64 {
        (self.next() as i64 << 32) | self.next() as i64
    }

    #[doc = "Return a random uint"]
    fn gen_uint() -> uint {
        self.gen_u64() as uint
    }

    #[doc = "Return a uint randomly chosen from the range [start, end], \
             failing if start > end"]
    fn gen_uint_from(start: uint, end: uint) -> uint {
        assert start <= end;
        start + (self.gen_uint() % (end - start + 1u))
    }

    #[doc = "Return a random u8"]
    fn gen_u8() -> u8 {
        self.next() as u8
    }

    #[doc = "Return a random u16"]
    fn gen_u16() -> u16 {
        self.next() as u16
    }

    #[doc = "Return a random u32"]
    fn gen_u32() -> u32 {
        self.next()
    }

    #[doc = "Return a random u64"]
    fn gen_u64() -> u64 {
        (self.next() as u64 << 32) | self.next() as u64
    }

    #[doc = "Return a random float"]
    fn gen_float() -> float {
        self.gen_f64() as float
    }

    #[doc = "Return a random f32"]
    fn gen_f32() -> f32 {
        self.gen_f64() as f32
    }

    #[doc = "Return a random f64"]
    fn gen_f64() -> f64 {
        let u1 = self.next() as f64;
        let u2 = self.next() as f64;
        let u3 = self.next() as f64;
        let scale = u32::max_value as f64;
        ret ((u1 / scale + u2) / scale + u3) / scale;
    }

    #[doc = "Return a random char"]
    fn gen_char() -> char {
        self.next() as char
    }

    #[doc = "Return a char randomly chosen from chars, failing if chars is \
             empty"]
    fn gen_char_from(chars: str) -> char {
        assert !chars.is_empty();
        self.choose(str::chars(chars))
    }

    #[doc = "Return a random bool"]
    fn gen_bool() -> bool {
        self.next() & 1u32 == 1u32
    }

    #[doc = "Return a bool with a 1 in n chance of true"]
    fn gen_weighted_bool(n: uint) -> bool {
        if n == 0u {
            true
        } else {
            self.gen_uint_from(1u, n) == 1u
        }
    }

    #[doc = "Return a random string of the specified length composed of A-Z, \
             a-z, 0-9"]
    fn gen_str(len: uint) -> str {
        let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
                      "abcdefghijklmnopqrstuvwxyz" +
                      "0123456789";
        let mut s = "";
        let mut i = 0u;
        while (i < len) {
            s = s + str::from_char(self.gen_char_from(charset));
            i += 1u;
        }
        s
    }

    #[doc = "Return a random byte string of the specified length"]
    fn gen_bytes(len: uint) -> [u8] {
        vec::from_fn(len) {|_i|
            self.gen_u8()
        }
    }

    #[doc = "Choose an item randomly, failing if values is empty"]
    fn choose<T:copy>(values: [T]) -> T {
        self.choose_option(values).get()
    }

    #[doc = "Choose some(item) randomly, returning none if values is empty"]
    fn choose_option<T:copy>(values: [T]) -> option<T> {
        if values.is_empty() {
            none
        } else {
            some(values[self.gen_uint_from(0u, values.len() - 1u)])
        }
    }

    #[doc = "Choose an item respecting the relative weights, failing if \
             the sum of the weights is 0"]
    fn choose_weighted<T: copy>(v : [weighted<T>]) -> T {
        self.choose_weighted_option(v).get()
    }

    #[doc = "Choose some(item) respecting the relative weights, returning \
             none if the sum of the weights is 0"]
    fn choose_weighted_option<T:copy>(v: [weighted<T>]) -> option<T> {
        let mut total = 0u;
        for v.each {|item|
            total += item.weight;
        }
        if total == 0u {
            ret none;
        }
        let chosen = self.gen_uint_from(0u, total - 1u);
        let mut so_far = 0u;
        for v.each {|item|
            so_far += item.weight;
            if so_far > chosen {
                ret some(item.item);
            }
        }
        unreachable();
    }

    #[doc = "Return a vec containing copies of the items, in order, where \
             the weight of the item determines how many copies there are"]
    fn weighted_vec<T:copy>(v: [weighted<T>]) -> [T] {
        let mut r = [];
        for v.each {|item|
            uint::range(0u, item.weight) {|_i|
                r += [item.item];
            }
        }
        r
    }

    #[doc = "Shuffle a vec"]
    fn shuffle<T:copy>(values: [T]) -> [T] {
        let mut m = vec::to_mut(values);
        self.shuffle_mut(m);
        ret vec::from_mut(m);
    }

    #[doc = "Shuffle a mutable vec in place"]
    fn shuffle_mut<T>(&values: [mut T]) {
        let mut i = values.len();
        while i >= 2u {
            // invariant: elements with index >= i have been locked in place.
            i -= 1u;
            // lock element i in place.
            vec::swap(values, i, self.gen_uint_from(0u, i));
        }
    }

}

resource rand_res(c: *rctx) { rustrt::rand_free(c); }

impl of rng for @rand_res {
    fn next() -> u32 { ret rustrt::rand_next(**self); }
}

#[doc = "Create a new random seed for seeded_rng"]
fn seed() -> [u8] {
    rustrt::rand_seed()
}

#[doc = "Create a random number generator with a system specified seed"]
fn rng() -> rng {
    @rand_res(rustrt::rand_new()) as rng
}

#[doc = "Create a random number generator using the specified seed. A \
         generator constructed with a given seed will generate the same \
         sequence of values as all other generators constructed with the \
         same seed. The seed may be any length."]
fn seeded_rng(seed: [u8]) -> rng {
    @rand_res(rustrt::rand_new_seeded(seed)) as rng
}

#[cfg(test)]
mod tests {

    #[test]
    fn rng_seeded() {
        let seed = rand::seed();
        let ra = rand::seeded_rng(seed);
        let rb = rand::seeded_rng(seed);
        assert ra.gen_str(100u) == rb.gen_str(100u);
    }

    #[test]
    fn rng_seeded_custom_seed() {
        // much shorter than generated seeds which are 1024 bytes
        let seed = [2u8, 32u8, 4u8, 32u8, 51u8];
        let ra = rand::seeded_rng(seed);
        let rb = rand::seeded_rng(seed);
        assert ra.gen_str(100u) == rb.gen_str(100u);
    }

    #[test]
    fn gen_int_from() {
        let r = rand::rng();
        let a = r.gen_int_from(-3, 42);
        assert a >= -3 && a <= 42;
        assert r.gen_int_from(0, 0) == 0;
        assert r.gen_int_from(-12, -12) == -12;
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(target_os = "win3"))]
    fn gen_int_from_fail() {
        rand::rng().gen_int_from(5, -2);
    }

    #[test]
    fn gen_uint_from() {
        let r = rand::rng();
        let a = r.gen_uint_from(3u, 42u);
        assert a >= 3u && a <= 42u;
        assert r.gen_uint_from(0u, 0u) == 0u;
        assert r.gen_uint_from(12u, 12u) == 12u;
    }

    #[test]
    #[should_fail]
    fn gen_uint_from_fail() {
        rand::rng().gen_uint_from(5u, 2u);
    }

    #[test]
    fn gen_float() {
        let r = rand::rng();
        let a = r.gen_float();
        let b = r.gen_float();
        log(debug, (a, b));
    }

    #[test]
    fn gen_weighted_bool() {
        let r = rand::rng();
        assert r.gen_weighted_bool(0u) == true;
        assert r.gen_weighted_bool(1u) == true;
    }

    #[test]
    fn gen_str() {
        let r = rand::rng();
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        assert r.gen_str(0u).len() == 0u;
        assert r.gen_str(10u).len() == 10u;
        assert r.gen_str(16u).len() == 16u;
    }

    #[test]
    fn gen_bytes() {
        let r = rand::rng();
        assert r.gen_bytes(0u).len() == 0u;
        assert r.gen_bytes(10u).len() == 10u;
        assert r.gen_bytes(16u).len() == 16u;
    }

    #[test]
    fn choose() {
        let r = rand::rng();
        assert r.choose([1, 1, 1]) == 1;
    }

    #[test]
    fn choose_option() {
        let r = rand::rng();
        assert r.choose_option([]) == none::<int>;
        assert r.choose_option([1, 1, 1]) == some(1);
    }

    #[test]
    fn choose_weighted() {
        let r = rand::rng();
        assert r.choose_weighted([{weight: 1u, item: 42}]) == 42;
        assert r.choose_weighted([
            {weight: 0u, item: 42},
            {weight: 1u, item: 43}
        ]) == 43;
    }

    #[test]
    fn choose_weighted_option() {
        let r = rand::rng();
        assert r.choose_weighted_option([{weight: 1u, item: 42}]) == some(42);
        assert r.choose_weighted_option([
            {weight: 0u, item: 42},
            {weight: 1u, item: 43}
        ]) == some(43);
        assert r.choose_weighted_option([]) == none::<int>;
    }

    #[test]
    fn weighted_vec() {
        let r = rand::rng();
        let empty: [int] = [];
        assert r.weighted_vec([]) == empty;
        assert r.weighted_vec([
            {weight: 0u, item: 3u},
            {weight: 1u, item: 2u},
            {weight: 2u, item: 1u}
        ]) == [2u, 1u, 1u];
    }

    #[test]
    fn shuffle() {
        let r = rand::rng();
        let empty: [int] = [];
        assert r.shuffle([]) == empty;
        assert r.shuffle([1, 1, 1]) == [1, 1, 1];
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>use bindings::{
	jit_value_t,
	jit_value_is_temporary,
	jit_value_get_context,
	jit_value_get_type,
	jit_value_get_function
};
use context::Context;
use function::Function;
use types::Type;
use util::NativeRef;
#[deriving(Clone)]
/// A Value that is being JIT compiled
native_ref!(Value, _value, jit_value_t)
impl Value {
	/// Get the type of the value
	pub fn get_type(&self) -> Type {
		unsafe {
			let ty = jit_value_get_type(self.as_ptr());
			NativeRef::from_ptr(ty)
		}
	}
	/// Get the function which owns this value
	pub fn get_function(&self) -> Function {
		unsafe {
			NativeRef::from_ptr(jit_value_get_function(self.as_ptr()))
		}
	}
	/// Get the context which this value belongs to
	pub fn get_context(&self) -> Context {
		unsafe {
			NativeRef::from_ptr(jit_value_get_context(self.as_ptr()))
		}
	}
	/// Return true if the value is temporary so its scope extends over a single block within its function
	pub fn is_temp(&self) -> bool {
		unsafe {
			jit_value_is_temporary(self.as_ptr()) != 0
		}
	}
}
<commit_msg>Add `is_addressable` to Value<commit_after>use bindings::{
	jit_value_t,
	jit_value_is_addressable,
	jit_value_is_temporary,
	jit_value_get_context,
	jit_value_get_type,
	jit_value_get_function
};
use context::Context;
use function::Function;
use types::Type;
use util::NativeRef;
#[deriving(Clone)]
/// A Value that is being JIT compiled
native_ref!(Value, _value, jit_value_t)
impl Value {
	/// Get the type of the value
	pub fn get_type(&self) -> Type {
		unsafe {
			let ty = jit_value_get_type(self.as_ptr());
			NativeRef::from_ptr(ty)
		}
	}
	/// Get the function which owns this value
	pub fn get_function(&self) -> Function {
		unsafe {
			NativeRef::from_ptr(jit_value_get_function(self.as_ptr()))
		}
	}
	/// Get the context which this value belongs to
	pub fn get_context(&self) -> Context {
		unsafe {
			NativeRef::from_ptr(jit_value_get_context(self.as_ptr()))
		}
	}
	/// Return true if the value is temporary so its scope extends over a single block within its function
	pub fn is_temp(&self) -> bool {
		unsafe {
			jit_value_is_temporary(self.as_ptr()) != 0
		}
	}
	/// Return true if the value can have its address taken from it
	pub fn is_addressable(&self) -> bool {
		unsafe {
			jit_value_is_addressable(self.as_ptr()) != 0
		}
	}
}
<|endoftext|>