<commit_before>//! # C API for rav1e
//!
//! [rav1e](https://github.com/xiph/rav1e/) is an [AV1](https://aomediacodec.github.io/av1-spec/)
//! encoder written in [Rust](https://rust-lang.org)
//!
//! This is the C-compatible API

extern crate rav1e;
extern crate libc;

use std::slice;
use std::sync::Arc;

use std::ffi::CStr;
use std::os::raw::c_char;
use std::os::raw::c_int;

use libc::size_t;
use libc::ptrdiff_t;

/// Raw video Frame
///
/// It can be allocated throught rav1e_frame_new(), populated using rav1e_frame_fill_plane()
/// and freed using rav1e_frame_unref().
pub struct Frame(Arc<rav1e::Frame<u16>>);

type EncoderStatus=rav1e::EncoderStatus;

/// Encoder configuration
///
/// Instantiate it using rav1e_config_default() and fine-tune it using
/// rav1e_config_parse().
///
/// Use rav1e_config_unref() to free its memory.
pub struct Config {
    cfg: rav1e::Config,
    last_err: Option<EncoderStatus>,
}

/// Encoder context
///
/// Contains the encoding state, it is created by rav1e_context_new() using an
/// Encoder configuration.
///
/// Use rav1e_context_unref() to free its memory.
pub struct Context {
    ctx: rav1e::Context<u16>,
    last_err: Option<EncoderStatus>,
}

type FrameType = rav1e::FrameType;

/// Encoded Packet
///
/// The encoded packets are retrieved using rav1e_receive_packet().
///
/// Use rav1e_packet_unref() to free its memory.
#[repr(C)]
pub struct Packet {
    /// Encoded data buffer
    pub data: *const u8,
    /// Encoded data buffer size
    pub len: size_t,
    /// Frame sequence number
    pub number: u64,
    /// Frame type
    pub frame_type: FrameType,
}

type ChromaSamplePosition=rav1e::ChromaSamplePosition;
type ChromaSampling=rav1e::ChromaSampling;
type MatrixCoefficients=rav1e::MatrixCoefficients;
type ColorPrimaries=rav1e::ColorPrimaries;
type TransferCharacteristics=rav1e::TransferCharacteristics;
type Rational=rav1e::Rational;

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_default() -> *mut Config {
    let cfg = rav1e::Config {
        enc: rav1e::EncoderConfig::default(),
        threads: 0,
    };

    let c = Box::new(Config {
        cfg,
        last_err: None,
    });

    Box::into_raw(c)
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_color_description(cfg: *mut Config,
                                                            matrix: MatrixCoefficients,
                                                            primaries: ColorPrimaries,
                                                            transfer: TransferCharacteristics)
{
    (*cfg).cfg.enc.color_description = Some(rav1e::ColorDescription {
        matrix_coefficients: matrix,
        color_primaries: primaries,
        transfer_characteristics: transfer,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_content_light(cfg: *mut Config,
                                                        max_content_light_level: u16,
                                                        max_frame_average_light_level: u16)
{
    (*cfg).cfg.enc.content_light = Some(rav1e::ContentLight {
        max_content_light_level,
        max_frame_average_light_level,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_mastering_display(cfg: *mut Config,
                                                            primaries: [rav1e::Point; 3],
                                                            white_point: rav1e::Point,
                                                            max_luminance: u32,
                                                            min_luminance: u32)
{
    (*cfg).cfg.enc.mastering_display = Some(rav1e::MasteringDisplay {
        primaries,
        white_point,
        max_luminance,
        min_luminance,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_unref(cfg: *mut Config) {
    let _ = Box::from_raw(cfg);
}

/// Set a configuration parameter using its key and value
///
/// Available keys and values
/// - "quantizer": 0-255, default 100
/// - "speed": 0-10, default 3
/// - "tune": "psnr"-"psychovisual", default "psnr"
///
/// Returns a negative value on non-zero.
#[no_mangle]
pub unsafe extern "C" fn rav1e_config_parse(
    cfg: *mut Config,
    key: *const c_char,
    value: *const c_char,
) -> c_int {
    let key = CStr::from_ptr(key).to_string_lossy();
    let value = CStr::from_ptr(value).to_string_lossy();

    (*cfg)
        .cfg
        .parse(&key, &value)
        .map(|_v| {
            (*cfg).last_err = None;
            0
        }).map_err(|e| (*cfg).last_err = Some(e))
        .unwrap_or(-1)
}

/// Generate a new encoding context from a populated encoder configuration
///
/// Multiple contexts can be generated through it.
#[no_mangle]
pub unsafe extern "C" fn rav1e_context_new(cfg: *const Config) -> *mut Context {
    let ctx = Context {
        ctx: (*cfg).cfg.new_context(),
        last_err: None,
    };

    Box::into_raw(Box::new(ctx))
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_context_unref(ctx: *mut Context) {
    let _ = Box::from_raw(ctx);
}

/// Produce a new frame from the encoding context
///
/// It must be populated using rav1e_frame_fill_plane().
///
/// The frame is reference counted and must be released passing it to rav1e_frame_unref(),
/// see rav1e_send_frame().
#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_new(ctx: *const Context) -> *mut Frame {
    let f = (*ctx).ctx.new_frame();
    let frame = Box::new(Frame(f));

    Box::into_raw(frame)
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_unref(frame: *mut Frame) {
    let _ = Arc::from_raw(frame);
}

/// Send the frame for encoding
///
/// The function increases the frame internal reference count and it can be passed multiple
/// times to different rav1e_send_frame().
#[no_mangle]
pub unsafe extern "C" fn rav1e_send_frame(ctx: *mut Context, frame: *const Frame) -> c_int {
    let frame = if frame.is_null() {
        None
    } else {
        Some((*frame).0.clone())
    };

    (*ctx)
        .ctx
        .send_frame(frame)
        .map(|_v| {
            (*ctx).last_err = None;
            0
        }).map_err(|e| (*ctx).last_err = Some(e))
        .unwrap_or(-1)
}

/// Receive encoded data
#[no_mangle]
pub unsafe extern "C" fn rav1e_receive_packet(
    ctx: *mut Context,
    pkt: *mut *mut Packet,
) -> c_int {
    (*ctx)
        .ctx
        .receive_packet()
        .map(|p| {
            (*ctx).last_err = None;
            let packet = Packet {
                data: p.data.as_ptr(),
                len: p.data.len(),
                number: p.number,
                frame_type: p.frame_type,
            };
            *pkt = Box::into_raw(Box::new(packet));
            0
        }).map_err(|e| (*ctx).last_err = Some(e))
        .unwrap_or(-1)
}

#[no_mangle]
pub unsafe extern fn rav1e_packet_unref(pkt: *mut Packet) {
    let _ = Box::from_raw(pkt);
}

/// Produce a sequence header matching the current encoding context
///
/// Its format is compatible with the AV1 Matroska and ISOBMFF specification.
///
/// Use rav1e_container_sequence_header_unref() to free it.
#[no_mangle]
pub unsafe extern fn rav1e_container_sequence_header(ctx: *mut Context, buf_size: *mut size_t) -> *mut u8 {
    let buf = (*ctx).ctx.container_sequence_header();

    *buf_size = buf.len();
    Box::into_raw(buf.into_boxed_slice()) as *mut u8
}

#[no_mangle]
pub unsafe extern fn rav1e_container_sequence_header_unref(sequence: *mut u8) {
    let _ = Box::from_raw(sequence);
}

/// Fill a frame plane
///
/// Currently the frame contains 3 planes, the first is luminance followed by
/// chrominance.
///
/// The data is copied and this function has to be called for each plane.
///
/// frame: A frame provided by rav1e_frame_new()
/// plane: The index of the plane starting from 0
/// data: The data to be copied
/// data_len: Lenght of the buffer
/// stride: Plane line in bytes, including padding
/// bytewidth: Number of bytes per component, either 1 or 2
#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_fill_plane(
    frame: *mut Frame,
    plane: c_int,
    data: *const u8,
    data_len: size_t,
    stride: ptrdiff_t,
    bytewidth: c_int,
) {
    let input = Arc::get_mut(&mut (*frame).0).unwrap();
    let data_slice = slice::from_raw_parts(data, data_len as usize);

    input.planes[plane as usize].copy_from_raw_u8(data_slice, stride as usize, bytewidth as usize);
}
<commit_msg>crav1e: Update send_frame and receive_packet<commit_after>//! # C API for rav1e
//!
//! [rav1e](https://github.com/xiph/rav1e/) is an [AV1](https://aomediacodec.github.io/av1-spec/)
//! encoder written in [Rust](https://rust-lang.org)
//!
//! This is the C-compatible API

extern crate rav1e;
extern crate libc;

use std::slice;
use std::sync::Arc;

use std::ffi::CStr;
use std::os::raw::c_char;
use std::os::raw::c_int;

use libc::size_t;
use libc::ptrdiff_t;

/// Raw video Frame
///
/// It can be allocated throught rav1e_frame_new(), populated using rav1e_frame_fill_plane()
/// and freed using rav1e_frame_unref().
pub struct Frame(Arc<rav1e::Frame<u16>>);

type EncoderStatus=rav1e::EncoderStatus;

/// Encoder configuration
///
/// Instantiate it using rav1e_config_default() and fine-tune it using
/// rav1e_config_parse().
///
/// Use rav1e_config_unref() to free its memory.
pub struct Config {
    cfg: rav1e::Config,
    last_err: Option<EncoderStatus>,
}

/// Encoder context
///
/// Contains the encoding state, it is created by rav1e_context_new() using an
/// Encoder configuration.
///
/// Use rav1e_context_unref() to free its memory.
pub struct Context {
    ctx: rav1e::Context<u16>,
    last_err: Option<EncoderStatus>,
}

type FrameType = rav1e::FrameType;

/// Encoded Packet
///
/// The encoded packets are retrieved using rav1e_receive_packet().
///
/// Use rav1e_packet_unref() to free its memory.
#[repr(C)]
pub struct Packet {
    /// Encoded data buffer
    pub data: *const u8,
    /// Encoded data buffer size
    pub len: size_t,
    /// Frame sequence number
    pub number: u64,
    /// Frame type
    pub frame_type: FrameType,
}

type ChromaSamplePosition=rav1e::ChromaSamplePosition;
type ChromaSampling=rav1e::ChromaSampling;
type MatrixCoefficients=rav1e::MatrixCoefficients;
type ColorPrimaries=rav1e::ColorPrimaries;
type TransferCharacteristics=rav1e::TransferCharacteristics;
type Rational=rav1e::Rational;

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_default() -> *mut Config {
    let cfg = rav1e::Config {
        enc: rav1e::EncoderConfig::default(),
        threads: 0,
    };

    let c = Box::new(Config {
        cfg,
        last_err: None,
    });

    Box::into_raw(c)
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_color_description(cfg: *mut Config,
                                                            matrix: MatrixCoefficients,
                                                            primaries: ColorPrimaries,
                                                            transfer: TransferCharacteristics)
{
    (*cfg).cfg.enc.color_description = Some(rav1e::ColorDescription {
        matrix_coefficients: matrix,
        color_primaries: primaries,
        transfer_characteristics: transfer,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_content_light(cfg: *mut Config,
                                                        max_content_light_level: u16,
                                                        max_frame_average_light_level: u16)
{
    (*cfg).cfg.enc.content_light = Some(rav1e::ContentLight {
        max_content_light_level,
        max_frame_average_light_level,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_mastering_display(cfg: *mut Config,
                                                            primaries: [rav1e::Point; 3],
                                                            white_point: rav1e::Point,
                                                            max_luminance: u32,
                                                            min_luminance: u32)
{
    (*cfg).cfg.enc.mastering_display = Some(rav1e::MasteringDisplay {
        primaries,
        white_point,
        max_luminance,
        min_luminance,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_unref(cfg: *mut Config) {
    let _ = Box::from_raw(cfg);
}

/// Set a configuration parameter using its key and value
///
/// Available keys and values
/// - "quantizer": 0-255, default 100
/// - "speed": 0-10, default 3
/// - "tune": "psnr"-"psychovisual", default "psnr"
///
/// Returns a negative value on non-zero.
#[no_mangle]
pub unsafe extern "C" fn rav1e_config_parse(
    cfg: *mut Config,
    key: *const c_char,
    value: *const c_char,
) -> c_int {
    let key = CStr::from_ptr(key).to_string_lossy();
    let value = CStr::from_ptr(value).to_string_lossy();

    (*cfg)
        .cfg
        .parse(&key, &value)
        .map(|_v| {
            (*cfg).last_err = None;
            0
        }).map_err(|e| (*cfg).last_err = Some(e))
        .unwrap_or(-1)
}

/// Generate a new encoding context from a populated encoder configuration
///
/// Multiple contexts can be generated through it.
#[no_mangle]
pub unsafe extern "C" fn rav1e_context_new(cfg: *const Config) -> *mut Context {
    let ctx = Context {
        ctx: (*cfg).cfg.new_context(),
        last_err: None,
    };

    Box::into_raw(Box::new(ctx))
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_context_unref(ctx: *mut Context) {
    let _ = Box::from_raw(ctx);
}

/// Produce a new frame from the encoding context
///
/// It must be populated using rav1e_frame_fill_plane().
///
/// The frame is reference counted and must be released passing it to rav1e_frame_unref(),
/// see rav1e_send_frame().
#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_new(ctx: *const Context) -> *mut Frame {
    let f = (*ctx).ctx.new_frame();
    let frame = Box::new(Frame(f));

    Box::into_raw(frame)
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_unref(frame: *mut Frame) {
    let _ = Arc::from_raw(frame);
}

/// Send the frame for encoding
///
/// The function increases the frame internal reference count and it can be passed multiple
/// times to different rav1e_send_frame().
///
/// Returns:
/// - `0` on success,
/// - `> 0` if the input queue is full
/// - `< 0` on unrecoverable failure
#[no_mangle]
pub unsafe extern "C" fn rav1e_send_frame(ctx: *mut Context, frame: *const Frame) -> c_int {
    let frame = if frame.is_null() {
        None
    } else {
        Some((*frame).0.clone())
    };

    (*ctx)
        .ctx
        .send_frame(frame)
        .map(|_v| {
            (*ctx).last_err = None;
            0
        }).unwrap_or_else(|e| {
            use rav1e::EncoderStatus::*;
            (*ctx).last_err = Some(e);
            match e {
                EnoughData => 1,
                NeedMoreData | NeedMoreFrames => unreachable!(),
                _ => -1,
            }
        })
}

/// Receive encoded data
///
/// Returns:
/// - `0` on success
/// - `> 0` if additional frame data is required
/// - `< 0` on unrecoverable failure
#[no_mangle]
pub unsafe extern "C" fn rav1e_receive_packet(
    ctx: *mut Context,
    pkt: *mut *mut Packet,
) -> c_int {
    (*ctx)
        .ctx
        .receive_packet()
        .map(|p| {
            (*ctx).last_err = None;
            let packet = Packet {
                data: p.data.as_ptr(),
                len: p.data.len(),
                number: p.number,
                frame_type: p.frame_type,
            };
            *pkt = Box::into_raw(Box::new(packet));
            0
        }).unwrap_or_else(|e| {
            use rav1e::EncoderStatus::*;
            (*ctx).last_err = Some(e);
            match e {
                NeedMoreData |
                    NeedMoreFrames => 1,
                EnoughData => unreachable!(),
                _ => -1,
            }
        })
}

#[no_mangle]
pub unsafe extern fn rav1e_packet_unref(pkt: *mut Packet) {
    let _ = Box::from_raw(pkt);
}

/// Produce a sequence header matching the current encoding context
///
/// Its format is compatible with the AV1 Matroska and ISOBMFF specification.
///
/// Use rav1e_container_sequence_header_unref() to free it.
#[no_mangle]
pub unsafe extern fn rav1e_container_sequence_header(ctx: *mut Context, buf_size: *mut size_t) -> *mut u8 {
    let buf = (*ctx).ctx.container_sequence_header();

    *buf_size = buf.len();
    Box::into_raw(buf.into_boxed_slice()) as *mut u8
}

#[no_mangle]
pub unsafe extern fn rav1e_container_sequence_header_unref(sequence: *mut u8) {
    let _ = Box::from_raw(sequence);
}

/// Fill a frame plane
///
/// Currently the frame contains 3 planes, the first is luminance followed by
/// chrominance.
///
/// The data is copied and this function has to be called for each plane.
///
/// frame: A frame provided by rav1e_frame_new()
/// plane: The index of the plane starting from 0
/// data: The data to be copied
/// data_len: Lenght of the buffer
/// stride: Plane line in bytes, including padding
/// bytewidth: Number of bytes per component, either 1 or 2
#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_fill_plane(
    frame: *mut Frame,
    plane: c_int,
    data: *const u8,
    data_len: size_t,
    stride: ptrdiff_t,
    bytewidth: c_int,
) {
    let input = Arc::get_mut(&mut (*frame).0).unwrap();
    let data_slice = slice::from_raw_parts(data, data_len as usize);

    input.planes[plane as usize].copy_from_raw_u8(data_slice, stride as usize, bytewidth as usize);
}
<|endoftext|>


<commit_before>//! C API for mp4parse module.
//!
//! Parses ISO Base Media Format aka video/mp4 streams.
//!
//! # Examples
//!
//! ```rust
//! extern crate mp4parse;
//!
//! // Minimal valid mp4 containing no tracks.
//! let data = b"\0\0\0\x0cftypmp42";
//!
//! let context = mp4parse::mp4parse_new();
//! unsafe {
//!     let rv = mp4parse::mp4parse_read(context, data.as_ptr(), data.len());
//!     assert_eq!(0, rv);
//!     mp4parse::mp4parse_free(context);
//! }
//! ```

// 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 https://mozilla.org/MPL/2.0/.

use std;
use std::io::Cursor;

// Symbols we need from our rust api.
use MediaContext;
use TrackType;
use read_mp4;
use Error;
use media_time_to_ms;
use track_time_to_ms;
use SampleEntry;

#[repr(C)]
pub enum mp4parse_error {
    MP4PARSE_OK = 0,
    MP4PARSE_ERROR_BADARG = 1,
    MP4PARSE_ERROR_INVALID = 2,
    MP4PARSE_ERROR_UNSUPPORTED = 3,
    MP4PARSE_ERROR_EOF = 4,
    MP4PARSE_ERROR_ASSERT = 5,
    MP4PARSE_ERROR_IO = 6,
}

#[repr(C)]
pub enum mp4parse_track_type {
    MP4PARSE_TRACK_TYPE_H264 = 0,
    MP4PARSE_TRACK_TYPE_AAC = 1,
}

#[repr(C)]
pub struct mp4parse_track_info {
    track_type: mp4parse_track_type,
    track_id: u32,
    duration: u64,
    media_time: i64, // wants to be u64? understand how elst adjustment works
    // TODO(kinetik): include crypto guff
}

#[repr(C)]
pub struct mp4parse_track_audio_info {
    channels: u16,
    bit_depth: u16,
    sample_rate: u32,
    // TODO(kinetik):
    // int32_t profile;
    // int32_t extended_profile; // check types
    // extra_data
    // codec_specific_config
}

#[repr(C)]
pub struct mp4parse_track_video_info {
    display_width: u32,
    display_height: u32,
    image_width: u16,
    image_height: u16,
    // TODO(kinetik):
    // extra_data
    // codec_specific_config
}

#[repr(C)]
#[allow(non_camel_case_types)]
pub struct mp4parse_state(MediaContext);

// C API wrapper functions.

/// Allocate an opaque rust-side parser context.
#[no_mangle]
pub extern "C" fn mp4parse_new() -> *mut mp4parse_state {
    let context = Box::new(mp4parse_state(MediaContext::new()));
    Box::into_raw(context)
}

/// Free a rust-side parser context.
#[no_mangle]
pub unsafe extern "C" fn mp4parse_free(context: *mut mp4parse_state) {
    assert!(!context.is_null());
    let _ = Box::from_raw(context);
}

/// Feed a buffer through `read_mp4()` with the given rust-side
/// parser context, returning success or an error code.
///
/// This is safe to call with NULL arguments but will crash
/// if given invalid pointers, as is usual for C.
#[no_mangle]
pub unsafe extern "C" fn mp4parse_read(context: *mut mp4parse_state, buffer: *const u8, size: usize) -> mp4parse_error {
    // Validate arguments from C.
    if context.is_null() || buffer.is_null() || size < 8 {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    let mut context: &mut MediaContext = &mut (*context).0;

    // Wrap the buffer we've been give in a slice.
    let b = std::slice::from_raw_parts(buffer, size);
    let mut c = Cursor::new(b);

    // Parse in a subthread to catch any panics.
    let task = std::thread::spawn(move || read_mp4(&mut c, &mut context));
    // The task's JoinHandle will return an error result if the
    // thread panicked, and will wrap the closure's return'd
    // result in an Ok(..) otherwise, meaning we could see
    // Ok(Err(Error::..)) here. So map thread failures back
    // to an mp4parse::Error before converting to a C return value.
    match task.join().unwrap_or(Err(Error::AssertCaught)) {
        Ok(_) => mp4parse_error::MP4PARSE_OK,
        Err(Error::InvalidData) => mp4parse_error::MP4PARSE_ERROR_INVALID,
        Err(Error::Unsupported) => mp4parse_error::MP4PARSE_ERROR_UNSUPPORTED,
        Err(Error::UnexpectedEOF) => mp4parse_error::MP4PARSE_ERROR_EOF,
        Err(Error::AssertCaught) => mp4parse_error::MP4PARSE_ERROR_ASSERT,
        Err(Error::Io(_)) => mp4parse_error::MP4PARSE_ERROR_IO,
    }
}

/// Return the number of tracks parsed by previous `read_mp4()` calls.
#[no_mangle]
pub unsafe extern "C" fn mp4parse_get_track_count(context: *const mp4parse_state) -> u32 {
    // Validate argument from C.
    assert!(!context.is_null());
    let context: &MediaContext = &(*context).0;

    // Make sure the track count fits in a u32.
    assert!(context.tracks.len() < u32::max_value() as usize);
    context.tracks.len() as u32
}

#[no_mangle]
pub unsafe extern "C" fn mp4parse_get_track_info(context: *mut mp4parse_state, track: u32, info: *mut mp4parse_track_info) -> mp4parse_error {
    if context.is_null() || info.is_null() {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    let context: &mut MediaContext = &mut (*context).0;
    let track_index: usize = track as usize;
    let info: &mut mp4parse_track_info = &mut *info;

    if track_index >= context.tracks.len() {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    info.track_type = match context.tracks[track_index].track_type {
        TrackType::Video => mp4parse_track_type::MP4PARSE_TRACK_TYPE_H264,
        TrackType::Audio => mp4parse_track_type::MP4PARSE_TRACK_TYPE_AAC,
        TrackType::Unknown => return mp4parse_error::MP4PARSE_ERROR_UNSUPPORTED,
    };

    // Maybe context & track should just have a single simple is_valid() instead?
    if context.timescale.is_none() ||
       context.tracks[track_index].timescale.is_none() ||
       context.tracks[track_index].duration.is_none() ||
       context.tracks[track_index].track_id.is_none() {
        return mp4parse_error::MP4PARSE_ERROR_INVALID;
    }

    std::thread::spawn(move || {
        let track = &context.tracks[track_index];
        let empty_duration = if track.empty_duration.is_some() {
            media_time_to_ms(track.empty_duration.unwrap(), context.timescale.unwrap())
        } else {
            0
        };
        info.media_time = if track.media_time.is_some() {
            track_time_to_ms(track.media_time.unwrap(), track.timescale.unwrap()) as i64 - empty_duration as i64
        } else {
            0
        };
        info.duration = track_time_to_ms(track.duration.unwrap(), track.timescale.unwrap());
        info.track_id = track.track_id.unwrap();
        mp4parse_error::MP4PARSE_OK
    }).join().unwrap_or(mp4parse_error::MP4PARSE_ERROR_INVALID)
}

#[no_mangle]
pub unsafe extern "C" fn mp4parse_get_track_audio_info(context: *mut mp4parse_state, track: u32, info: *mut mp4parse_track_audio_info) -> mp4parse_error {
    if context.is_null() || info.is_null() {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    let context: &mut MediaContext = &mut (*context).0;

    if track as usize >= context.tracks.len() {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    let track = &context.tracks[track as usize];

    match track.track_type {
        TrackType::Audio => {}
        _ => return mp4parse_error::MP4PARSE_ERROR_INVALID,
    };

    let audio = match track.data {
        Some(ref data) => data,
        None => return mp4parse_error::MP4PARSE_ERROR_INVALID,
    };

    let audio = match *audio {
        SampleEntry::Audio(ref x) => x,
        _ => return mp4parse_error::MP4PARSE_ERROR_INVALID,
    };

    (*info).channels = audio.channelcount;
    (*info).bit_depth = audio.samplesize;
    (*info).sample_rate = audio.samplerate >> 16; // 16.16 fixed point

    mp4parse_error::MP4PARSE_OK
}

#[no_mangle]
pub unsafe extern "C" fn mp4parse_get_track_video_info(context: *mut mp4parse_state, track: u32, info: *mut mp4parse_track_video_info) -> mp4parse_error {
    if context.is_null() || info.is_null() {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    let context: &mut MediaContext = &mut (*context).0;

    if track as usize >= context.tracks.len() {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    let track = &context.tracks[track as usize];

    match track.track_type {
        TrackType::Video => {}
        _ => return mp4parse_error::MP4PARSE_ERROR_INVALID,
    };

    let video = match track.data {
        Some(ref data) => data,
        None => return mp4parse_error::MP4PARSE_ERROR_INVALID,
    };

    let video = match *video {
        SampleEntry::Video(ref x) => x,
        _ => return mp4parse_error::MP4PARSE_ERROR_INVALID,
    };

    if let Some(ref tkhd) = track.tkhd {
        (*info).display_width = tkhd.width >> 16; // 16.16 fixed point
        (*info).display_height = tkhd.height >> 16; // 16.16 fixed point
    } else {
        return mp4parse_error::MP4PARSE_ERROR_INVALID;
    }
    (*info).image_width = video.width;
    (*info).image_width = video.height;

    mp4parse_error::MP4PARSE_OK
}

#[test]
fn new_context() {
    let context = mp4parse_new();
    assert!(!context.is_null());
    unsafe {
        mp4parse_free(context);
    }
}

#[test]
#[should_panic(expected = "assertion failed")]
fn free_null_context() {
    unsafe {
        mp4parse_free(std::ptr::null_mut());
    }
}

#[test]
fn arg_validation() {
    let null_buffer = std::ptr::null();
    let null_context = std::ptr::null_mut();

    let context = mp4parse_new();
    assert!(!context.is_null());

    let buffer = vec![0u8; 8];

    unsafe {
        assert_eq!(mp4parse_error::MP4PARSE_ERROR_BADARG,
                   mp4parse_read(null_context, null_buffer, 0));
        assert_eq!(mp4parse_error::MP4PARSE_ERROR_BADARG,
                   mp4parse_read(context, null_buffer, 0));
    }

    for size in 0..buffer.len() {
        println!("testing buffer length {}", size);
        unsafe {
            assert_eq!(mp4parse_error::MP4PARSE_ERROR_BADARG,
                       mp4parse_read(context, buffer.as_ptr(), size));
        }
    }

    unsafe {
        mp4parse_free(context);
    }
}
<commit_msg>Derive PartialEq and Debug on mp4parse_error.<commit_after>//! C API for mp4parse module.
//!
//! Parses ISO Base Media Format aka video/mp4 streams.
//!
//! # Examples
//!
//! ```rust
//! extern crate mp4parse;
//!
//! // Minimal valid mp4 containing no tracks.
//! let data = b"\0\0\0\x0cftypmp42";
//!
//! let context = mp4parse::mp4parse_new();
//! unsafe {
//!     let rv = mp4parse::mp4parse_read(context, data.as_ptr(), data.len());
//!     assert_eq!(0, rv);
//!     mp4parse::mp4parse_free(context);
//! }
//! ```

// 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 https://mozilla.org/MPL/2.0/.

use std;
use std::io::Cursor;

// Symbols we need from our rust api.
use MediaContext;
use TrackType;
use read_mp4;
use Error;
use media_time_to_ms;
use track_time_to_ms;
use SampleEntry;

#[repr(C)]
#[derive(PartialEq,Debug)]
pub enum mp4parse_error {
    MP4PARSE_OK = 0,
    MP4PARSE_ERROR_BADARG = 1,
    MP4PARSE_ERROR_INVALID = 2,
    MP4PARSE_ERROR_UNSUPPORTED = 3,
    MP4PARSE_ERROR_EOF = 4,
    MP4PARSE_ERROR_ASSERT = 5,
    MP4PARSE_ERROR_IO = 6,
}

#[repr(C)]
pub enum mp4parse_track_type {
    MP4PARSE_TRACK_TYPE_H264 = 0,
    MP4PARSE_TRACK_TYPE_AAC = 1,
}

#[repr(C)]
pub struct mp4parse_track_info {
    track_type: mp4parse_track_type,
    track_id: u32,
    duration: u64,
    media_time: i64, // wants to be u64? understand how elst adjustment works
    // TODO(kinetik): include crypto guff
}

#[repr(C)]
pub struct mp4parse_track_audio_info {
    channels: u16,
    bit_depth: u16,
    sample_rate: u32,
    // TODO(kinetik):
    // int32_t profile;
    // int32_t extended_profile; // check types
    // extra_data
    // codec_specific_config
}

#[repr(C)]
pub struct mp4parse_track_video_info {
    display_width: u32,
    display_height: u32,
    image_width: u16,
    image_height: u16,
    // TODO(kinetik):
    // extra_data
    // codec_specific_config
}

#[repr(C)]
#[allow(non_camel_case_types)]
pub struct mp4parse_state(MediaContext);

// C API wrapper functions.

/// Allocate an opaque rust-side parser context.
#[no_mangle]
pub extern "C" fn mp4parse_new() -> *mut mp4parse_state {
    let context = Box::new(mp4parse_state(MediaContext::new()));
    Box::into_raw(context)
}

/// Free a rust-side parser context.
#[no_mangle]
pub unsafe extern "C" fn mp4parse_free(context: *mut mp4parse_state) {
    assert!(!context.is_null());
    let _ = Box::from_raw(context);
}

/// Feed a buffer through `read_mp4()` with the given rust-side
/// parser context, returning success or an error code.
///
/// This is safe to call with NULL arguments but will crash
/// if given invalid pointers, as is usual for C.
#[no_mangle]
pub unsafe extern "C" fn mp4parse_read(context: *mut mp4parse_state, buffer: *const u8, size: usize) -> mp4parse_error {
    // Validate arguments from C.
    if context.is_null() || buffer.is_null() || size < 8 {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    let mut context: &mut MediaContext = &mut (*context).0;

    // Wrap the buffer we've been give in a slice.
    let b = std::slice::from_raw_parts(buffer, size);
    let mut c = Cursor::new(b);

    // Parse in a subthread to catch any panics.
    let task = std::thread::spawn(move || read_mp4(&mut c, &mut context));
    // The task's JoinHandle will return an error result if the
    // thread panicked, and will wrap the closure's return'd
    // result in an Ok(..) otherwise, meaning we could see
    // Ok(Err(Error::..)) here. So map thread failures back
    // to an mp4parse::Error before converting to a C return value.
    match task.join().unwrap_or(Err(Error::AssertCaught)) {
        Ok(_) => mp4parse_error::MP4PARSE_OK,
        Err(Error::InvalidData) => mp4parse_error::MP4PARSE_ERROR_INVALID,
        Err(Error::Unsupported) => mp4parse_error::MP4PARSE_ERROR_UNSUPPORTED,
        Err(Error::UnexpectedEOF) => mp4parse_error::MP4PARSE_ERROR_EOF,
        Err(Error::AssertCaught) => mp4parse_error::MP4PARSE_ERROR_ASSERT,
        Err(Error::Io(_)) => mp4parse_error::MP4PARSE_ERROR_IO,
    }
}

/// Return the number of tracks parsed by previous `read_mp4()` calls.
#[no_mangle]
pub unsafe extern "C" fn mp4parse_get_track_count(context: *const mp4parse_state) -> u32 {
    // Validate argument from C.
    assert!(!context.is_null());
    let context: &MediaContext = &(*context).0;

    // Make sure the track count fits in a u32.
    assert!(context.tracks.len() < u32::max_value() as usize);
    context.tracks.len() as u32
}

#[no_mangle]
pub unsafe extern "C" fn mp4parse_get_track_info(context: *mut mp4parse_state, track: u32, info: *mut mp4parse_track_info) -> mp4parse_error {
    if context.is_null() || info.is_null() {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    let context: &mut MediaContext = &mut (*context).0;
    let track_index: usize = track as usize;
    let info: &mut mp4parse_track_info = &mut *info;

    if track_index >= context.tracks.len() {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    info.track_type = match context.tracks[track_index].track_type {
        TrackType::Video => mp4parse_track_type::MP4PARSE_TRACK_TYPE_H264,
        TrackType::Audio => mp4parse_track_type::MP4PARSE_TRACK_TYPE_AAC,
        TrackType::Unknown => return mp4parse_error::MP4PARSE_ERROR_UNSUPPORTED,
    };

    // Maybe context & track should just have a single simple is_valid() instead?
    if context.timescale.is_none() ||
       context.tracks[track_index].timescale.is_none() ||
       context.tracks[track_index].duration.is_none() ||
       context.tracks[track_index].track_id.is_none() {
        return mp4parse_error::MP4PARSE_ERROR_INVALID;
    }

    std::thread::spawn(move || {
        let track = &context.tracks[track_index];
        let empty_duration = if track.empty_duration.is_some() {
            media_time_to_ms(track.empty_duration.unwrap(), context.timescale.unwrap())
        } else {
            0
        };
        info.media_time = if track.media_time.is_some() {
            track_time_to_ms(track.media_time.unwrap(), track.timescale.unwrap()) as i64 - empty_duration as i64
        } else {
            0
        };
        info.duration = track_time_to_ms(track.duration.unwrap(), track.timescale.unwrap());
        info.track_id = track.track_id.unwrap();
        mp4parse_error::MP4PARSE_OK
    }).join().unwrap_or(mp4parse_error::MP4PARSE_ERROR_INVALID)
}

#[no_mangle]
pub unsafe extern "C" fn mp4parse_get_track_audio_info(context: *mut mp4parse_state, track: u32, info: *mut mp4parse_track_audio_info) -> mp4parse_error {
    if context.is_null() || info.is_null() {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    let context: &mut MediaContext = &mut (*context).0;

    if track as usize >= context.tracks.len() {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    let track = &context.tracks[track as usize];

    match track.track_type {
        TrackType::Audio => {}
        _ => return mp4parse_error::MP4PARSE_ERROR_INVALID,
    };

    let audio = match track.data {
        Some(ref data) => data,
        None => return mp4parse_error::MP4PARSE_ERROR_INVALID,
    };

    let audio = match *audio {
        SampleEntry::Audio(ref x) => x,
        _ => return mp4parse_error::MP4PARSE_ERROR_INVALID,
    };

    (*info).channels = audio.channelcount;
    (*info).bit_depth = audio.samplesize;
    (*info).sample_rate = audio.samplerate >> 16; // 16.16 fixed point

    mp4parse_error::MP4PARSE_OK
}

#[no_mangle]
pub unsafe extern "C" fn mp4parse_get_track_video_info(context: *mut mp4parse_state, track: u32, info: *mut mp4parse_track_video_info) -> mp4parse_error {
    if context.is_null() || info.is_null() {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    let context: &mut MediaContext = &mut (*context).0;

    if track as usize >= context.tracks.len() {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    let track = &context.tracks[track as usize];

    match track.track_type {
        TrackType::Video => {}
        _ => return mp4parse_error::MP4PARSE_ERROR_INVALID,
    };

    let video = match track.data {
        Some(ref data) => data,
        None => return mp4parse_error::MP4PARSE_ERROR_INVALID,
    };

    let video = match *video {
        SampleEntry::Video(ref x) => x,
        _ => return mp4parse_error::MP4PARSE_ERROR_INVALID,
    };

    if let Some(ref tkhd) = track.tkhd {
        (*info).display_width = tkhd.width >> 16; // 16.16 fixed point
        (*info).display_height = tkhd.height >> 16; // 16.16 fixed point
    } else {
        return mp4parse_error::MP4PARSE_ERROR_INVALID;
    }
    (*info).image_width = video.width;
    (*info).image_width = video.height;

    mp4parse_error::MP4PARSE_OK
}

#[test]
fn new_context() {
    let context = mp4parse_new();
    assert!(!context.is_null());
    unsafe {
        mp4parse_free(context);
    }
}

#[test]
#[should_panic(expected = "assertion failed")]
fn free_null_context() {
    unsafe {
        mp4parse_free(std::ptr::null_mut());
    }
}

#[test]
fn arg_validation() {
    let null_buffer = std::ptr::null();
    let null_context = std::ptr::null_mut();

    let context = mp4parse_new();
    assert!(!context.is_null());

    let buffer = vec![0u8; 8];

    unsafe {
        assert_eq!(mp4parse_error::MP4PARSE_ERROR_BADARG,
                   mp4parse_read(null_context, null_buffer, 0));
        assert_eq!(mp4parse_error::MP4PARSE_ERROR_BADARG,
                   mp4parse_read(context, null_buffer, 0));
    }

    for size in 0..buffer.len() {
        println!("testing buffer length {}", size);
        unsafe {
            assert_eq!(mp4parse_error::MP4PARSE_ERROR_BADARG,
                       mp4parse_read(context, buffer.as_ptr(), size));
        }
    }

    unsafe {
        mp4parse_free(context);
    }
}
<|endoftext|>


<commit_before>extern crate serialize;
extern crate docopt;

use docopt::Docopt;

static USAGE: &'static str = "
Usage: wc [options] [<file>]

Options:
    -c, --bytes  print the byte counts
    -m, --chars  print the character counts
    -l, --lines  print the newline counts
    -w, --words  print the word counts
    -L, --max-line-length  print the length of the longest line
    -h, --help  display this help and exit
    -v, --version  output version information and exit
";

#[deriving(Decodable)]
struct Args {
    arg_file: Option<String>,
    flag_bytes: bool,
    flag_chars: bool,
    flag_lines: bool,
    flag_words: bool,
    flag_max_line_length: bool,
}

fn main() {
    println!("24 days of Rust - docopt (day 4)");
    //let args: Args = Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit());
    let docopt = match Docopt::new(USAGE) {
        Ok(d) => d,
        Err(e) => e.exit(),
    };
    println!("{}", docopt);
    let args: Args = match docopt.decode() {
        Ok(args) => args,
        Err(e) => e.exit(),
    };
    println!("Counting stuff in {}", args.arg_file.unwrap_or("standard input".to_string()));
    if args.flag_bytes {
        println!("Counting bytes!");
    }
    if args.flag_chars {
        println!("Counting characters!");
    }
    if args.flag_lines {
        println!("Counting lines!");
    }
    if args.flag_words {
        println!("Counting words!");
    }
    if args.flag_max_line_length {
        println!("Measuring the longest line!");
    }
}
<commit_msg>Switched to docopt! macro.<commit_after>#![feature(phase)]
extern crate serialize;
extern crate docopt;
#[phase(plugin)]
extern crate docopt_macros;

use docopt::Docopt;

docopt!(Args, "
Usage: wc [options] [<file>]

Options:
    -c, --bytes  print the byte counts
    -m, --chars  print the character counts
    -l, --lines  print the newline counts
    -w, --words  print the word counts
    -L, --max-line-length  print the length of the longest line
    -h, --help  display this help and exit
    -v, --version  output version information and exit
", arg_file: Option<String>)

fn main() {
    println!("24 days of Rust - docopt (day 4)");
    let docopt = Args::docopt();
    println!("{}", docopt);
    let args: Args = match docopt.decode() {
        Ok(args) => args,
        Err(e) => e.exit(),
    };
    println!("Counting stuff in {}", args.arg_file.unwrap_or("standard input".to_string()));
    if args.flag_bytes {
        println!("Counting bytes!");
    }
    if args.flag_chars {
        println!("Counting characters!");
    }
    if args.flag_lines {
        println!("Counting lines!");
    }
    if args.flag_words {
        println!("Counting words!");
    }
    if args.flag_max_line_length {
        println!("Measuring the longest line!");
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::rc::Rc;
use std::io;

use ast::*;
use env::*;
use parser::*;
use test::Bencher;

pub struct Evaler<R>  {
    parser: Parser<R>,
    env:    Rc<RefCell<Env>>,
    iteractive: bool

}

#[allow(dead_code)]
impl <R: Reader> Evaler<R> {
    pub fn new(inner: R, iteractive: bool) -> Evaler<R> {
        let env = Env::new();
        Evaler {
            parser: Parser::new_from(inner, iteractive),
            env:    Rc::new(RefCell::new(env)),
            iteractive: iteractive

        }
    }

    pub fn eval(&mut self) -> Option<Expr> {
        let mut res = None;
        loop {
            if self.iteractive {
                print!("> ");
            }
            let exp = self.parser.read_exp();
            match exp {
                Some(_exp) => {
                    let r = self.eval_exp(_exp);
                    if self.iteractive {
                        r.print();
                        println!("");
                    }
                    res = Some(r);
                },
                None => break
            }
        }
        res
    }

    pub fn eval_from(&mut self, code: String) -> Option<Expr> {
        self.parser.load(code);
        let mut res = None;
        loop {
            let exp = self.parser.read_exp();
            match exp {
                Some(_exp) => {
                    let r = self.eval_exp(_exp);
                    res = Some(r);
                },
                None => break
            }
        }
        res
    }

    fn eval_exp(&mut self, exp: Expr) -> Expr {
        if exp.is_self()   { return exp; }
        if exp.is_symbol() { return self.env.borrow().lookup(exp.as_str()).unwrap(); }
        if exp.is_quote()  { return exp.cdr().car(); }
        if exp.is_assign() { return self.eval_assign(exp); }
        if exp.is_def()    { return self.eval_def(exp); }
        if exp.is_begin()  { return self.eval_begin(exp); }
        if exp.is_if()     { return self.eval_if(exp); }
        if exp.is_lambda() { return self.eval_lambda(exp); }
        if exp.is_and()    { return self.eval_and(exp); }
        if exp.is_or()     { return self.eval_or(exp); }
        if exp.is_cond()   { return self.eval_cond(exp); }
        if exp.is_let()    { return self.eval_let(exp); }
        if exp.is_pair()   { return self.eval_app(exp); }
        Expr::Symbol(SymbolNode::new("OK"))
    }

    fn eval_assign(&mut self, exp: Expr) -> Expr {
        let var = exp.c("da");
        let val = self.eval_exp(exp.c("dda"));
        self.env.clone().borrow_mut().def_var(var.as_str(), val);
        Expr::Symbol(SymbolNode::new("OK"))
    }

    fn eval_def(&mut self, exp: Expr) -> Expr {
        let var = exp.def_var();
        let val = exp.def_val();
        let val = self.eval_exp(val);
        self.env.clone().borrow_mut().def_var(var.as_str(), val);
        Expr::Symbol(SymbolNode::new("OK"))
    }

    fn eval_if(&mut self, exp: Expr) -> Expr {
        let pred = exp.c("da");
        let blk_t = exp.c("dda");
        let blk_f = exp.c("ddd");
        let res = self.eval_exp(pred);
        if res.is_true() {
            self.eval_exp(blk_t)
        } else {
            if res.is_empty() {
                Expr::Bool(BoolNode::new(false))
            } else {
                self.eval_exp(blk_f.car())
            }
        }
    }

    fn eval_and(&mut self, exp: Expr) -> Expr {
        let mut elems = exp.cdr();
        if elems.is_empty() {
            return Expr::Bool(BoolNode::new(true));
        }
        loop {
            if elems.is_last() { break; }
            let res = self.eval_exp(elems.car());
            if res.is_false() {
                return Expr::Bool(BoolNode::new(false));
            }
            elems = elems.cdr();
        }
        self.eval_exp(elems.car())
    }

    fn eval_or(&mut self, exp: Expr) -> Expr {
        let mut elems = exp.cdr();
        if elems.is_empty() {
            return Expr::Bool(BoolNode::new(true));
        }
        loop {
            if elems.is_last() { break; }
            let res = self.eval_exp(elems.car());
            if res.is_true() {
                return Expr::Bool(BoolNode::new(true));
            }
            elems = elems.cdr();
        }
        self.eval_exp(elems.car())
    }

    fn eval_cond(&mut self, exp: Expr) -> Expr {
        let mut elems = exp.cdr().car();
        loop {
            if elems.is_empty() { break; }
            let cur = elems.car();
            let val = self.eval_exp(cur.clone());
            if val.is_true() || val == Expr::Symbol(SymbolNode::new("else")) {
                return self.eval_exp(cur.clone().cdr().car());
            }
            elems = elems.cdr();
        }
        Expr::Bool(BoolNode::new(true))
    }

    fn eval_let(&mut self, exp: Expr) -> Expr {
        fn bind_params(exp: Expr) -> Expr {
            if exp.is_empty() {
                Expr::Nil
            } else {
                Expr::Pair(PairNode::new(exp.c("aa"), bind_params(exp.cdr())))
            }
        }

        fn bind_args(exp: Expr) -> Expr {
            if exp.is_empty() {
                Expr::Nil
            } else {
                Expr::Pair(PairNode::new(exp.c("ada"), bind_args(exp.cdr())))
            }
        }

        let bindings = exp.c("da");
        let obj = Expr::Pair(PairNode::new(
            bind_params(bindings.clone()).make_lambda(exp.c("dd")),
            bind_args(bindings)));
        self.eval_exp(obj)
    }

    fn eval_begin(&mut self, exp: Expr) -> Expr {
        let mut _exp = exp.cdr();
        loop {
            if _exp.is_last() { break; }
            self.eval_exp(_exp.car());
            _exp = _exp.cdr();
        }
        self.eval_exp(_exp.car())
    }

    fn eval_values(&mut self, exprs: Expr) -> Expr {
        if exprs.is_empty() {
            Expr::Nil
        } else {
            let first = self.eval_exp(exprs.car());
            Expr::Pair(PairNode::new(first, self.eval_values(exprs.cdr())))
        }
    }

    fn eval_app(&mut self, expr: Expr) -> Expr {
        let _proc = self.eval_exp(expr.car());
        let _args = self.eval_values(expr.cdr());
        if _proc.is_proc() {
            let func = _proc.as_proc().func();
            return func(_args);
        } else {
            assert!(_proc.is_cproc());
            let _vars = _proc.params();
            self.env = self.env.clone().borrow_mut().extend(_vars, _args);
            let begin = Expr::Symbol(SymbolNode::new("begin"));
            let res = self.eval_exp(Expr::Pair(PairNode::new(begin, _proc.body())));
            self.env = self.env.clone().borrow_mut().parent().unwrap();
            res
        }
    }

    fn eval_lambda(&mut self, expr: Expr) -> Expr {
        // vars + body + env
        Expr::CompProc(CompProcNode::new(expr.c("da"), expr.c("dd"), self.env.clone()))
    }
}

macro_rules! test_case {
    ($test_str:expr, $expect_type:ident, $expect_val:expr) => { {
        let mut evaler = Evaler::new(io::stdin(), false);
        let res = evaler.eval_from($test_str.to_string()).unwrap();
        if res.$expect_type() != $expect_val {
            assert!(false);
        }
    }}
}

#[test]
fn test_evaler() {
    test_case!("11", as_int, 11);
    test_case!("'a", as_str, "a");
    test_case!(r#""hello""#, as_str, "hello");
    test_case!("#t", as_bool, true);
    test_case!("(and #t #t)", as_bool, true);
    test_case!("(and #t #f)", as_bool, false);
    test_case!("(or #t #t)", as_bool, true);
    test_case!("(or #f #f)", as_bool, false);
    test_case!("(or #t #f)", as_bool, true);
    test_case!("(set! a 1)", as_str, "OK");
    test_case!("(integer? 1)", as_bool, true);
    test_case!("(boolean? #t)", as_bool, true);
    test_case!("(boolean? #f)", as_bool, true);
    test_case!("(integer? #t)", as_bool, false);
    test_case!("(+ 1 1)", as_int, 2);
    test_case!("(- 1 1)", as_int, 0);
    test_case!("(+ 1 1  1)", as_int, 3);
    test_case!("(+ 1 1 -1 -1)", as_int, 0);
    test_case!("(/ 2 1)", as_int, 2);
    test_case!("(* 2 2)", as_int, 4);
    test_case!("(> 2 1)", as_bool, true);
    test_case!("(> 1 2)", as_bool, false);
    test_case!("(> 1 1)", as_bool, false);
    test_case!("(- (+ 3 (* 8 5)) 1)", as_int, 42);
    test_case!("(eq? 1 1)", as_bool, true);
    test_case!("(eq? 1 2)", as_bool, false);
    test_case!("(eq? 1 #f)", as_bool, false);
    test_case!("(pair? '())", as_bool, true);
    test_case!("(> (+ 1 1) 0)", as_bool, true);
    test_case!("(if (> 1 0) 1 else 2)", as_int, 1);
    test_case!("(begin (set! a 1) a)", as_int, 1);
    test_case!("(let ((a 1)) (+ a 1))", as_int, 2);
    test_case!("(let ((a 1)) (> (+ a 1) 0))", as_bool, true);
    test_case!("(let ((a 1) (b 2)) (> a b))", as_bool, false);
    test_case!("(define (add a b) (+ a b))", as_str, "OK");
    test_case!("(cond ((eq? 1 1) 1) ((> 1 2) 2) ))", as_int, 1);
    test_case!("(begin (set! x 5) (set! x 4) (+ x 1))", as_int, 5);
    test_case!("(car '(1 2))", as_int, 1);
    test_case!("(car (cdr '(1 2)))", as_int, 2);
    test_case!("(car (cons 1 2))", as_int, 1);
    test_case!("(car (cons (pair? '(1)) pair? '()))", as_bool, true);
    test_case!("(car (cdr (cons 1 2)))", as_int, 2);
    test_case!("(car (car (cons (cons 2 3) (cons 1 2))))", as_int, 2);
    test_case!("((lambda (x) x) 1)", as_int, 1);
    test_case!("((lambda (x y) (+ x y )) 1 2)", as_int, 3);
    test_case!("(define add4 (let ((x 4)) (lambda (y) (+ x y))))", as_str, "OK");
    test_case!("(begin 1 2)", as_int, 2);
    test_case!("((lambda (x) x) 5)", as_int, 5);
    test_case!("(let ((fu (lambda (x) (+ x 1)))) (fu 1))", as_int, 2);
    test_case!("((lambda ( x y ) ( if ( = y 0) 1 (* y (x x (- y 1)))))
               (lambda ( x y ) ( if ( = y 0) 1 (* y (x x (- y 1))))) 5)", as_int, 5is*4*3*2);
}

#[bench]
fn eval_bench(b: &mut Bencher) {
    b.iter(|| test_evaler());
}

#[bench]
fn lambda_bench(b: &mut Bencher) {
    b.iter(||
           test_case!("((lambda ( x y ) ( if ( = y 0) 1 (* y (x x (- y 1)))))
                      (lambda ( x y ) ( if ( = y 0) 1 (* y (x x (- y 1))))) 5)", as_int, 5is*4*3*2));
}
<commit_msg>trivial fix<commit_after>use std::cell::RefCell;
use std::rc::Rc;
use std::io;

use ast::*;
use env::*;
use parser::*;
use test::Bencher;

pub struct Evaler<R>  {
    parser: Parser<R>,
    env:    Rc<RefCell<Env>>,
    iteractive: bool

}

#[allow(dead_code)]
impl <R: Reader> Evaler<R> {
    pub fn new(inner: R, iteractive: bool) -> Evaler<R> {
        let env = Env::new();
        Evaler {
            parser: Parser::new_from(inner, iteractive),
            env:    Rc::new(RefCell::new(env)),
            iteractive: iteractive

        }
    }

    pub fn eval(&mut self) -> Option<Expr> {
        let mut res = None;
        loop {
            if self.iteractive {
                print!("> ");
            }
            let exp = self.parser.read_exp();
            match exp {
                Some(_exp) => {
                    let r = self.eval_exp(_exp);
                    if self.iteractive {
                        r.print();
                        println!("");
                    }
                    res = Some(r);
                },
                None => break
            }
        }
        res
    }

    pub fn eval_from(&mut self, code: String) -> Option<Expr> {
        self.parser.load(code);
        let mut res = None;
        loop {
            let exp = self.parser.read_exp();
            match exp {
                Some(_exp) => {
                    let r = self.eval_exp(_exp);
                    res = Some(r);
                },
                None => break
            }
        }
        res
    }

    fn eval_exp(&mut self, exp: Expr) -> Expr {
        if exp.is_self()   { return exp; }
        if exp.is_symbol() { return self.env.borrow().lookup(exp.as_str()).unwrap(); }
        if exp.is_quote()  { return exp.cdr().car(); }
        if exp.is_assign() { return self.eval_assign(exp); }
        if exp.is_def()    { return self.eval_def(exp); }
        if exp.is_begin()  { return self.eval_begin(exp); }
        if exp.is_if()     { return self.eval_if(exp); }
        if exp.is_lambda() { return self.eval_lambda(exp); }
        if exp.is_and()    { return self.eval_and(exp); }
        if exp.is_or()     { return self.eval_or(exp); }
        if exp.is_cond()   { return self.eval_cond(exp); }
        if exp.is_let()    { return self.eval_let(exp); }
        if exp.is_pair()   { return self.eval_app(exp); }
        Expr::Symbol(SymbolNode::new("OK"))
    }

    fn eval_assign(&mut self, exp: Expr) -> Expr {
        let var = exp.c("da");
        let val = self.eval_exp(exp.c("dda"));
        self.env.clone().borrow_mut().def_var(var.as_str(), val);
        Expr::Symbol(SymbolNode::new("OK"))
    }

    fn eval_def(&mut self, exp: Expr) -> Expr {
        let var = exp.def_var();
        let val = exp.def_val();
        let val = self.eval_exp(val);
        self.env.clone().borrow_mut().def_var(var.as_str(), val);
        Expr::Symbol(SymbolNode::new("OK"))
    }

    fn eval_if(&mut self, exp: Expr) -> Expr {
        let pred = exp.c("da");
        let blk_t = exp.c("dda");
        let blk_f = exp.c("ddd");
        let res = self.eval_exp(pred);
        if res.is_true() {
            self.eval_exp(blk_t)
        } else {
            if res.is_empty() {
                Expr::Bool(BoolNode::new(false))
            } else {
                self.eval_exp(blk_f.car())
            }
        }
    }

    fn eval_and(&mut self, exp: Expr) -> Expr {
        let mut elems = exp.cdr();
        if elems.is_empty() {
            return Expr::Bool(BoolNode::new(true));
        }
        loop {
            if elems.is_last() { break; }
            let res = self.eval_exp(elems.car());
            if res.is_false() {
                return Expr::Bool(BoolNode::new(false));
            }
            elems = elems.cdr();
        }
        self.eval_exp(elems.car())
    }

    fn eval_or(&mut self, exp: Expr) -> Expr {
        let mut elems = exp.cdr();
        if elems.is_empty() {
            return Expr::Bool(BoolNode::new(true));
        }
        loop {
            if elems.is_last() { break; }
            let res = self.eval_exp(elems.car());
            if res.is_true() {
                return Expr::Bool(BoolNode::new(true));
            }
            elems = elems.cdr();
        }
        self.eval_exp(elems.car())
    }

    fn eval_cond(&mut self, exp: Expr) -> Expr {
        let mut elems = exp.cdr().car();
        loop {
            if elems.is_empty() { break; }
            let cur = elems.car();
            let val = self.eval_exp(cur.clone());
            if val.is_true() || val == Expr::Symbol(SymbolNode::new("else")) {
                return self.eval_exp(cur.clone().cdr().car());
            }
            elems = elems.cdr();
        }
        Expr::Bool(BoolNode::new(true))
    }

    fn eval_let(&mut self, exp: Expr) -> Expr {
        fn bind_params(exp: Expr) -> Expr {
            if exp.is_empty() {
                Expr::Nil
            } else {
                Expr::Pair(PairNode::new(exp.c("aa"), bind_params(exp.cdr())))
            }
        }

        fn bind_args(exp: Expr) -> Expr {
            if exp.is_empty() {
                Expr::Nil
            } else {
                Expr::Pair(PairNode::new(exp.c("ada"), bind_args(exp.cdr())))
            }
        }

        let bindings = exp.c("da");
        let obj = Expr::Pair(PairNode::new(
            bind_params(bindings.clone()).make_lambda(exp.c("dd")),
            bind_args(bindings)));
        self.eval_exp(obj)
    }

    fn eval_begin(&mut self, exp: Expr) -> Expr {
        let mut _exp = exp.cdr();
        loop {
            if _exp.is_last() { break; }
            self.eval_exp(_exp.car());
            _exp = _exp.cdr();
        }
        self.eval_exp(_exp.car())
    }

    fn eval_values(&mut self, exprs: Expr) -> Expr {
        if exprs.is_empty() {
            Expr::Nil
        } else {
            let first = self.eval_exp(exprs.car());
            Expr::Pair(PairNode::new(first, self.eval_values(exprs.cdr())))
        }
    }

    fn eval_app(&mut self, expr: Expr) -> Expr {
        let _proc = self.eval_exp(expr.car());
        let _args = self.eval_values(expr.cdr());
        if _proc.is_proc() {
            let func = _proc.as_proc().func();
            return func(_args);
        } else {
            assert!(_proc.is_cproc());
            let _vars = _proc.params();
            self.env = self.env.clone().borrow_mut().extend(_vars, _args);
            let begin = Expr::Symbol(SymbolNode::new("begin"));
            let res = self.eval_exp(Expr::Pair(PairNode::new(begin, _proc.body())));
            self.env = self.env.clone().borrow_mut().parent().unwrap();
            res
        }
    }

    fn eval_lambda(&mut self, expr: Expr) -> Expr {
        // vars + body + env
        Expr::CompProc(CompProcNode::new(expr.c("da"), expr.c("dd"), self.env.clone()))
    }
}

macro_rules! test_case {
    ($test_str:expr, $expect_type:ident, $expect_val:expr) => { {
        let mut evaler = Evaler::new(io::stdin(), false);
        let res = evaler.eval_from($test_str.to_string()).unwrap();
        if res.$expect_type() != $expect_val {
            assert!(false);
        }
    }}
}

#[test]
fn test_evaler() {
    test_case!("11", as_int, 11);
    test_case!("'a", as_str, "a");
    test_case!(r#""hello""#, as_str, "hello");
    test_case!("#t", as_bool, true);
    test_case!("(and #t #t)", as_bool, true);
    test_case!("(and #t #f)", as_bool, false);
    test_case!("(or #t #t)", as_bool, true);
    test_case!("(or #f #f)", as_bool, false);
    test_case!("(or #t #f)", as_bool, true);
    test_case!("(set! a 1)", as_str, "OK");
    test_case!("(integer? 1)", as_bool, true);
    test_case!("(boolean? #t)", as_bool, true);
    test_case!("(boolean? #f)", as_bool, true);
    test_case!("(integer? #t)", as_bool, false);
    test_case!("(+ 1 1)", as_int, 2);
    test_case!("(- 1 1)", as_int, 0);
    test_case!("(+ 1 1  1)", as_int, 3);
    test_case!("(+ 1 1 -1 -1)", as_int, 0);
    test_case!("(/ 2 1)", as_int, 2);
    test_case!("(* 2 2)", as_int, 4);
    test_case!("(> 2 1)", as_bool, true);
    test_case!("(> 1 2)", as_bool, false);
    test_case!("(> 1 1)", as_bool, false);
    test_case!("(- (+ 3 (* 8 5)) 1)", as_int, 42);
    test_case!("(eq? 1 1)", as_bool, true);
    test_case!("(eq? 1 2)", as_bool, false);
    test_case!("(eq? 1 #f)", as_bool, false);
    test_case!("(pair? '())", as_bool, true);
    test_case!("(> (+ 1 1) 0)", as_bool, true);
    test_case!("(if (> 1 0) 1 else 2)", as_int, 1);
    test_case!("(begin (set! a 1) a)", as_int, 1);
    test_case!("(let ((a 1)) (+ a 1))", as_int, 2);
    test_case!("(let ((a 1)) (> (+ a 1) 0))", as_bool, true);
    test_case!("(let ((a 1) (b 2)) (> a b))", as_bool, false);
    test_case!("(define (add a b) (+ a b))", as_str, "OK");
    test_case!("(cond ((eq? 1 1) 1) ((> 1 2) 2) ))", as_int, 1);
    test_case!("(begin (set! x 5) (set! x 4) (+ x 1))", as_int, 5);
    test_case!("(car '(1 2))", as_int, 1);
    test_case!("(car (cdr '(1 2)))", as_int, 2);
    test_case!("(car (cons 1 2))", as_int, 1);
    test_case!("(car (cons (pair? '(1)) pair? '()))", as_bool, true);
    test_case!("(car (cdr (cons 1 2)))", as_int, 2);
    test_case!("(car (car (cons (cons 2 3) (cons 1 2))))", as_int, 2);
    test_case!("((lambda (x) x) 1)", as_int, 1);
    test_case!("((lambda (x y) (+ x y )) 1 2)", as_int, 3);
    test_case!("(define add4 (let ((x 4)) (lambda (y) (+ x y))))", as_str, "OK");
    test_case!("(begin 1 2)", as_int, 2);
    test_case!("((lambda (x) x) 5)", as_int, 5);
    test_case!("(let ((fu (lambda (x) (+ x 1)))) (fu 1))", as_int, 2);
    test_case!("((lambda (x y ) (if ( = y 0) 1 (* y (x x (- y 1)))))
               (lambda (x y ) (if ( = y 0) 1 (* y (x x (- y 1))))) 5)", as_int, 5is*4*3*2);
}

#[bench]
fn eval_bench(b: &mut Bencher) {
    b.iter(|| test_evaler());
}

#[bench]
fn lambda_bench(b: &mut Bencher) {
    b.iter(||
           test_case!("((lambda (x y ) (if ( = y 0) 1 (* y (x x (- y 1)))))
                      (lambda (x y ) (if ( = y 0) 1 (* y (x x (- y 1))))) 5)", as_int, 5is*4*3*2));
}
<|endoftext|>


<commit_before>use std::sync::{Mutex, Arc};
use std::sync::atomics::{AtomicUint, SeqCst};

pub struct EWMA {
    pub uncounted: AtomicUint, // This tracks uncounted events
    alpha: f64,
    rate: Mutex<f64>,
    init: bool,
}

pub struct EWMASnapshot {
    value: f64
}

impl EWMASnapshot {
    pub fn rate(&self) -> f64 {
        return self.value;
    }
}

impl EWMA {
    pub fn rate(&self) -> f64 {
        let r = self.rate.lock();
        *r * (1e9 as f64)
    }

    pub fn snapshot(&self) -> EWMASnapshot {
        return EWMASnapshot{ value: self.rate() };
    }

    pub fn tick(&mut self) {
        let counter: uint = self.uncounted.load(SeqCst);

        self.uncounted.fetch_sub(counter, SeqCst); // Broken atm

        let mut rate = self.rate.lock();
        let i_rate = (counter as f64) / (5e9);

        if self.init {
            *rate += self.alpha * (i_rate - *rate);
        } else {
            self.init = true;
            *rate = i_rate;
        }

        rate.cond.signal();
    }

    pub fn update(&self, n: uint) {
        self.uncounted.fetch_add(n, SeqCst);
    }

    pub fn new(alpha: f64) -> EWMA {
        return EWMA{
            uncounted: AtomicUint::new(0u),
            alpha: alpha,
            rate: Mutex::new(0f64),
            init: false,
        }
    }

}

#[cfg(test)]
mod test {
    use ewma::EWMA;
    use std::num::Float;

    // Tick a minute
    fn elapse_minute(e: &mut EWMA) {
        for i in range(0i, 12i) {
            e.tick();
        }
    }

    // Returns whether the rate() is within 0.0001 of expected after ticking a minute
    fn within(e: &mut EWMA, expected: f64) -> bool {
        elapse_minute(e);
        let r: f64 = e.rate();
        (r - expected).abs() < 0.0001
    }

    #[test]
    fn ewma1() {
        let i = -5.0f64/60.0f64/1f64;
        let mut e = EWMA::new(1f64 - i.exp());
        e.update(3u);
        e.tick();

        let mut r: f64;

        // initial
        r = e.rate();
        assert_eq!(r, 0.6f64);

        // 1 minute
        assert_eq!(within(&mut e, 0.22072766470286553f64), true);

        // 2 minute
        assert_eq!(within(&mut e, 0.08120116994196772f64), true);

        // 3 minute
        assert_eq!(within(&mut e, 0.029872241020718428f64), true);

        // 4 minute
        assert_eq!(within(&mut e, 0.01098938333324054f64), true);

        // 5 minute
        assert_eq!(within(&mut e, 0.004042768199451294f64), true);

        // 6 minute
        assert_eq!(within(&mut e, 0.0014872513059998212f64), true);

        // 7 minute
        assert_eq!(within(&mut e, 0.0005471291793327122f64), true);

        // 8 minute
        assert_eq!(within(&mut e, 0.00020127757674150815f64), true);

        // 9 minute
        assert_eq!(within(&mut e, 7.404588245200814e-05f64), true);

        // 10 minute
        assert_eq!(within(&mut e, 2.7239957857491083e-05f64), true);

        // 11 minute
        assert_eq!(within(&mut e, 1.0021020474147462e-05f64), true);

        // 12 minute
        assert_eq!(within(&mut e, 3.6865274119969525e-06f64), true);

        // 13 minute
        assert_eq!(within(&mut e, 1.3561976441886433e-06f64), true);

        // 14 minute
        assert_eq!(within(&mut e, 4.989172314621449e-07f64), true);

        // 15 minute
        assert_eq!(within(&mut e, 1.8354139230109722e-07f64), true);
    }

    #[test]
    fn ewma5() {
        let i = -5.0f64/60.0f64/5f64;
        let mut e = EWMA::new(1f64 - i.exp());
        e.update(3u);
        e.tick();

        let r: f64 = e.rate();
        assert_eq!(r, 0.6f64);

        // 1 minute
        assert_eq!(within(&mut e, 0.49123845184678905f64), true);

                // 2 minute
        assert_eq!(within(&mut e, 0.4021920276213837f64), true);

        // 3 minute
        assert_eq!(within(&mut e, 0.32928698165641596f64), true);

        // 4 minute
        assert_eq!(within(&mut e, 0.269597378470333f64), true);

        // 5 minute
        assert_eq!(within(&mut e, 0.2207276647028654f64), true);

        // 6 minute
        assert_eq!(within(&mut e, 0.18071652714732128f64), true);

        // 7 minute
        assert_eq!(within(&mut e, 0.14795817836496392f64), true);

        // 8 minute
        assert_eq!(within(&mut e, 0.12113791079679326f64), true);

        // 9 minute
        assert_eq!(within(&mut e, 0.09917933293295193f64), true);

        // 10 minute
        assert_eq!(within(&mut e, 0.08120116994196763f64), true);

        // 11 minute
        assert_eq!(within(&mut e, 0.06648189501740036), true);

        // 12 minute
        assert_eq!(within(&mut e, 0.05443077197364752f64), true);

        // 13 minute
        assert_eq!(within(&mut e, 0.04456414692860035f64), true);

        // 14 minute
        assert_eq!(within(&mut e, 0.03648603757513079f64), true);

        // 15 minute
        assert_eq!(within(&mut e, 0.0298722410207183831020718428f64), true);
    }

        #[test]
    fn ewma15() {
        let i = -5.0f64/60.0f64/15f64;
        let mut e = EWMA::new(1f64 - i.exp());
        e.update(3u);
        e.tick();

        let r: f64 = e.rate();
        assert_eq!(r, 0.6f64);

        // 1 minute
        assert_eq!(within(&mut e, 0.5613041910189706f64), true);

        // 2 minute
        assert_eq!(within(&mut e, 0.5251039914257684f64), true);

        // 3 minute
        assert_eq!(within(&mut e, 0.4912384518467888184678905f64), true);

        // 4 minute
        assert_eq!(within(&mut e, 0.459557003018789f64), true);

        // 5 minute
        assert_eq!(within(&mut e, 0.4299187863442732f64), true);

        // 6 minute
        assert_eq!(within(&mut e, 0.4021920276213831f64), true);

        // 7 minute
        assert_eq!(within(&mut e, 0.37625345116383313f64), true);

        // 8 minute
        assert_eq!(within(&mut e, 0.3519877317060185f64), true);

        // 9 minute
        assert_eq!(within(&mut e, 0.3292869816564153165641596f64), true);

        // 10 minute
        assert_eq!(within(&mut e, 0.3080502714195546f64), true);

        // 11 minute
        assert_eq!(within(&mut e, 0.2881831806538789f64), true);

        // 12 minute
        assert_eq!(within(&mut e, 0.26959737847033216f64), true);

        // 13 minute
        assert_eq!(within(&mut e, 0.2522102307052083f64), true);

        // 14 minute
        assert_eq!(within(&mut e, 0.23594443252115815f64), true);

        // 15 minute
        assert_eq!(within(&mut e, 0.2207276647028646247028654470286553f64), true);
    }
}<commit_msg>Cleanup EWMA<commit_after>use std::sync::{Mutex, Arc};
use std::sync::atomics::{AtomicUint, SeqCst};

pub struct EWMA {
    pub uncounted: AtomicUint, // This tracks uncounted events
    alpha: f64,
    rate: Mutex<f64>,
    init: bool,
}

pub struct EWMASnapshot {
    value: f64
}

impl EWMASnapshot {
    pub fn rate(&self) -> f64 {
        return self.value;
    }
}

impl EWMA {
    pub fn rate(&self) -> f64 {
        let r = self.rate.lock();
        *r * (1e9 as f64)
    }

    pub fn snapshot(&self) -> EWMASnapshot {
        return EWMASnapshot{ value: self.rate() };
    }

    pub fn tick(&mut self) {
        let counter: uint = self.uncounted.load(SeqCst);

        self.uncounted.fetch_sub(counter, SeqCst); // Broken atm

        let mut rate = self.rate.lock();
        let i_rate = (counter as f64) / (5e9);

        if self.init {
            *rate += self.alpha * (i_rate - *rate);
        } else {
            self.init = true;
            *rate = i_rate;
        }

        rate.cond.signal();
    }

    pub fn update(&self, n: uint) {
        self.uncounted.fetch_add(n, SeqCst);
    }

    // construct new by alpha
    pub fn new(alpha: f64) -> EWMA {
        EWMA{
            uncounted: AtomicUint::new(0u),
            alpha: alpha,
            rate: Mutex::new(0f64),
            init: false,
        }
    }

    // constructs a new EWMA for a n-minute moving average.
    pub fn new_by_minute(rate: f64) -> EWMA {
        let i: f64 = -5.0f64 / 60.0f64 / rate;
        return EWMA::new(1f64 - i.exp())
    }
}

#[cfg(test)]
mod test {
    use ewma::EWMA;
    use std::num::Float;

    // Tick a minute
    fn elapse_minute(e: &mut EWMA) {
        for i in range(0i, 12i) {
            e.tick();
        }
    }

    // Returns whether the rate() is within 0.0001 of expected after ticking a minute
    fn within(e: &mut EWMA, expected: f64) -> bool {
        elapse_minute(e);
        let r: f64 = e.rate();
        (r - expected).abs() < 0.0001
    }

    #[test]
    fn ewma1() {
        let mut e = EWMA::new_by_minute(1f64);
        e.update(3u);
        e.tick();

        let mut r: f64;

        // initial
        r = e.rate();
        assert_eq!(r, 0.6f64);

        // 1 minute
        assert_eq!(within(&mut e, 0.22072766470286553f64), true);

        // 2 minute
        assert_eq!(within(&mut e, 0.08120116994196772f64), true);

        // 3 minute
        assert_eq!(within(&mut e, 0.029872241020718428f64), true);

        // 4 minute
        assert_eq!(within(&mut e, 0.01098938333324054f64), true);

        // 5 minute
        assert_eq!(within(&mut e, 0.004042768199451294f64), true);

        // 6 minute
        assert_eq!(within(&mut e, 0.0014872513059998212f64), true);

        // 7 minute
        assert_eq!(within(&mut e, 0.0005471291793327122f64), true);

        // 8 minute
        assert_eq!(within(&mut e, 0.00020127757674150815f64), true);

        // 9 minute
        assert_eq!(within(&mut e, 7.404588245200814e-05f64), true);

        // 10 minute
        assert_eq!(within(&mut e, 2.7239957857491083e-05f64), true);

        // 11 minute
        assert_eq!(within(&mut e, 1.0021020474147462e-05f64), true);

        // 12 minute
        assert_eq!(within(&mut e, 3.6865274119969525e-06f64), true);

        // 13 minute
        assert_eq!(within(&mut e, 1.3561976441886433e-06f64), true);

        // 14 minute
        assert_eq!(within(&mut e, 4.989172314621449e-07f64), true);

        // 15 minute
        assert_eq!(within(&mut e, 1.8354139230109722e-07f64), true);
    }

    #[test]
    fn ewma5() {
        let mut e = EWMA::new_by_minute(5f64);
        e.update(3u);
        e.tick();

        let r: f64 = e.rate();
        assert_eq!(r, 0.6f64);

        // 1 minute
        assert_eq!(within(&mut e, 0.49123845184678905f64), true);

                // 2 minute
        assert_eq!(within(&mut e, 0.4021920276213837f64), true);

        // 3 minute
        assert_eq!(within(&mut e, 0.32928698165641596f64), true);

        // 4 minute
        assert_eq!(within(&mut e, 0.269597378470333f64), true);

        // 5 minute
        assert_eq!(within(&mut e, 0.2207276647028654f64), true);

        // 6 minute
        assert_eq!(within(&mut e, 0.18071652714732128f64), true);

        // 7 minute
        assert_eq!(within(&mut e, 0.14795817836496392f64), true);

        // 8 minute
        assert_eq!(within(&mut e, 0.12113791079679326f64), true);

        // 9 minute
        assert_eq!(within(&mut e, 0.09917933293295193f64), true);

        // 10 minute
        assert_eq!(within(&mut e, 0.08120116994196763f64), true);

        // 11 minute
        assert_eq!(within(&mut e, 0.06648189501740036), true);

        // 12 minute
        assert_eq!(within(&mut e, 0.05443077197364752f64), true);

        // 13 minute
        assert_eq!(within(&mut e, 0.04456414692860035f64), true);

        // 14 minute
        assert_eq!(within(&mut e, 0.03648603757513079f64), true);

        // 15 minute
        assert_eq!(within(&mut e, 0.0298722410207183831020718428f64), true);
    }

        #[test]
    fn ewma15() {
        let mut e = EWMA::new_by_minute(15f64);
        e.update(3u);
        e.tick();

        let r: f64 = e.rate();
        assert_eq!(r, 0.6f64);

        // 1 minute
        assert_eq!(within(&mut e, 0.5613041910189706f64), true);

        // 2 minute
        assert_eq!(within(&mut e, 0.5251039914257684f64), true);

        // 3 minute
        assert_eq!(within(&mut e, 0.4912384518467888184678905f64), true);

        // 4 minute
        assert_eq!(within(&mut e, 0.459557003018789f64), true);

        // 5 minute
        assert_eq!(within(&mut e, 0.4299187863442732f64), true);

        // 6 minute
        assert_eq!(within(&mut e, 0.4021920276213831f64), true);

        // 7 minute
        assert_eq!(within(&mut e, 0.37625345116383313f64), true);

        // 8 minute
        assert_eq!(within(&mut e, 0.3519877317060185f64), true);

        // 9 minute
        assert_eq!(within(&mut e, 0.3292869816564153165641596f64), true);

        // 10 minute
        assert_eq!(within(&mut e, 0.3080502714195546f64), true);

        // 11 minute
        assert_eq!(within(&mut e, 0.2881831806538789f64), true);

        // 12 minute
        assert_eq!(within(&mut e, 0.26959737847033216f64), true);

        // 13 minute
        assert_eq!(within(&mut e, 0.2522102307052083f64), true);

        // 14 minute
        assert_eq!(within(&mut e, 0.23594443252115815f64), true);

        // 15 minute
        assert_eq!(within(&mut e, 0.2207276647028646247028654470286553f64), true);
    }
}<|endoftext|>


<commit_before>//! This module contains the game logic

use std::f64;
use std::env::current_exe;

use itertools_num;
use opengl_graphics::GlGraphics;
use opengl_graphics::glyph_cache::GlyphCache;
use piston_window::{clear, ControllerButton, Context, ControllerAxisArgs, Key, text, Transformed};
use rand::{self, ThreadRng};

use drawing::{color, Point, Size};
use models::{Bullet, Enemy, Particle, Vector, World};
use traits::{Advance, Collide, Position};

// Constants related to time
const BULLETS_PER_SECOND: f64 = 100.0;
const BULLET_RATE: f64 = 1.0 / BULLETS_PER_SECOND;

const ENEMY_SPAWNS_PER_SECOND: f64 = 1.0;
const ENEMY_SPAWN_RATE: f64 = 1.0 / ENEMY_SPAWNS_PER_SECOND;

const TRAIL_PARTICLES_PER_SECOND: f64 = 20.0;
const TRAIL_PARTICLE_RATE: f64 = 1.0 / TRAIL_PARTICLES_PER_SECOND;

// Constants related to movement
// Speed is measured in pixels per second
// Rotation speed is measured in radians per second
const ADVANCE_SPEED: f64 = 200.0;
const BULLET_SPEED: f64 = 500.0;
const ENEMY_SPEED: f64 = 100.0;
const ROTATE_SPEED: f64 = 2.0 * f64::consts::PI;

/// The data structure that drives the game
pub struct Game {
    /// The world contains everything that needs to be drawn
    world: World,
    /// The current score of the player
    score: u32,
    /// The active actions
    actions: Actions,
    /// Timers needed by the game
    timers: Timers,
    /// A random number generator
    rng: ThreadRng,
    /// Resources needed for drawing
    resources: Resources
}

/// Active actions (toggled by user input)
#[derive(Default)]
struct Actions {
    rotate_left: bool,
    rotate_right: bool,
    boost: bool,
    shoot: bool
}

/// Timers to handle creation of bullets, enemies and particles
#[derive(Default)]
struct Timers {
    current_time: f64,
    last_tail_particle: f64,
    last_shoot: f64,
    last_spawned_enemy: f64
}

/// Additional resources needed for the game
struct Resources {
    font: GlyphCache<'static>
}

impl Game {
    /// Returns a new `Game` containing a `World` of the given `Size`
    pub fn new(size: Size) -> Game {
        let mut rng = rand::thread_rng();
        let exe_directory = current_exe().unwrap().parent().unwrap().to_owned();
        Game {
            world: World::new(&mut rng, size),
            score: 0,
            actions: Actions::default(),
            timers: Timers::default(),
            rng: rng,
            resources: Resources {
                font: GlyphCache::new(&exe_directory.join("resources/FiraMono-Bold.ttf")).unwrap()
            }
        }
    }

    /// Processes a key press
    pub fn key_press(&mut self, key: Key) {
        self.handle_key(key, true);
    }

    /// Processes a key release
    pub fn key_release(&mut self, key: Key) {
        self.handle_key(key, false);
    }

    /// Handles a key press or release
    fn handle_key(&mut self, key: Key, pressed: bool) {
        match key {
            Key::Left => self.actions.rotate_left = pressed,
            Key::Right => self.actions.rotate_right = pressed,
            Key::Up => self.actions.boost = pressed,
            Key::Space => self.actions.shoot = pressed,
            _ => ()
        }
    }

    /// Processes a button press
    pub fn button_press(&mut self, controller: ControllerButton) {
        self.handle_button(controller, true);
    }

    /// Processes a button release
    pub fn button_release(&mut self, controller: ControllerButton) {
        self.handle_button(controller, false);
    }

    /// Handles a button press or release
    fn handle_button(&mut self, controller: ControllerButton, pressed: bool) {
        // Button 10 is A button on XInput
        match controller.button {
            10 => self.actions.shoot = pressed,
            _ => ()
        }
    }

    /// Handles a controller axis input
    pub fn handle_axis(&mut self, controller: ControllerAxisArgs) {
        // Axis 0 is left stick (XInput). -1.0 left to 1.0 right
        if controller.axis == 0 {
            match controller.position {
                -1.0 ... -0.2 => {
                    self.actions.rotate_left = true;
                    self.actions.rotate_right = false;
                },
                0.2 ... 1.0 => {
                    self.actions.rotate_left = false;
                    self.actions.rotate_right = true;
                },
                -0.199 ... 0.199 => {
                    self.actions.rotate_left = false;
                    self.actions.rotate_right = false;
                },
                _ => {}
            }
        }

        // Axis 5 is right trigger (XInput). -1.0 is not pressed, 1.0 is fully pressed
        if controller.axis == 5 {
            match controller.position {
                -0.8 ... 1.0 => {
                    self.actions.boost = true;
                },
                -1.0 ... -0.799 => {
                    self.actions.boost = false;
                },
                _ => {}
            }
        }
    }

    /// Renders the game to the screen
    pub fn render(&mut self, c: Context, g: &mut GlGraphics) {
        // Clear everything
        clear(color::BLACK, g);

        // Render the world
        self.world.render(c, g);

        // Render the score
        text(color::ORANGE,
             22,
             &format!("Score: {}", self.score),
             &mut self.resources.font,
             c.trans(10.0, 20.0).transform,
             g);
    }

    /// Updates the game
    ///
    /// `dt` is the amount of seconds that have passed since the last update
    pub fn update(&mut self, dt: f64) {
        self.timers.current_time += dt;

        // Update rocket rotation
        if self.actions.rotate_left {
            *self.world.player.direction_mut() += -ROTATE_SPEED * dt;
        }
        if self.actions.rotate_right {
            *self.world.player.direction_mut() += ROTATE_SPEED * dt;
        };

        // Set speed and advance the player with wrap around
        let speed = if self.actions.boost { 2.0 * ADVANCE_SPEED } else { ADVANCE_SPEED };
        self.world.player.advance_wrapping(dt * speed, self.world.size.clone());

        // Update particles
        for particle in &mut self.world.particles {
            particle.update(dt);
        }

        // Remove old particles
        self.world.particles.retain(|p| p.ttl > 0.0);

        // Add new particles at the player's position, to leave a trail
        if self.timers.current_time - self.timers.last_tail_particle > TRAIL_PARTICLE_RATE {
            self.timers.last_tail_particle = self.timers.current_time;
            self.world.particles.push(Particle::new(self.world.player.vector.clone().invert(),
                                                    0.5));
        }

        // Add bullets
        if self.actions.shoot && self.timers.current_time - self.timers.last_shoot > BULLET_RATE {
            self.timers.last_shoot = self.timers.current_time;
            self.world.bullets.push(Bullet::new(Vector::new(self.world.player.nose(),
                                                            self.world.player.direction())));
        }

        // Advance bullets
        for bullet in &mut self.world.bullets {
            bullet.update(dt * BULLET_SPEED);
        }

        // Remove bullets outside the viewport
        {
            // Shorten the lifetime of size
            let size = &self.world.size;
            self.world.bullets.retain(|b| size.contains(b.position()));
        }

        // Spawn enemies at random locations
        if self.timers.current_time - self.timers.last_spawned_enemy > ENEMY_SPAWN_RATE {
            self.timers.last_spawned_enemy = self.timers.current_time;
            let mut new_enemy;
            loop {
                new_enemy = Enemy::new(Vector::random(&mut self.rng, self.world.size.clone()));
                if !self.world.player.collides_with(&new_enemy) {
                    break;
                }
            }
            self.world.enemies.push(new_enemy);
        }

        // Move enemies in the player's direction
        for enemy in &mut self.world.enemies {
            enemy.update(dt * ENEMY_SPEED, self.world.player.position());
        }

        self.handle_player_collisions();
        self.handle_bullet_collisions();
    }

    /// Handles collisions between the bullets and the enemies
    ///
    /// When an enemy is reached by a bullet, both the enemy and the bullet
    /// will be removed. Additionally, the score will be increased by 10
    fn handle_bullet_collisions(&mut self) {
        let old_enemy_count = self.world.enemies.len();

        // We introduce a scope to shorten the lifetime of the borrows below
        {
            let bullets = &mut self.world.bullets;
            let enemies = &mut self.world.enemies;
            let particles = &mut self.world.particles;

            bullets.retain(|bullet| {
                // Remove the first enemy that collides with a bullet (if any)
                // Add an explosion on its place
                if let Some((index, position)) = enemies.iter().enumerate()
                    .find(|&(_, enemy)| enemy.collides_with(bullet))
                    .map(|(index, enemy)| (index, enemy.position()))
                    {
                        Game::make_explosion(particles, position, 10);
                        enemies.remove(index);
                        false
                    } else {
                    true
                }
            });
        }

        let killed_enemies = (old_enemy_count - self.world.enemies.len()) as u32;
        self.score += 10 * killed_enemies;
    }

    /// reset our game-state
    fn reset(&mut self) {
        // Reset player position
        *self.world.player.x_mut() = self.world.size.random_x(&mut self.rng);
        *self.world.player.y_mut() = self.world.size.random_y(&mut self.rng);

        // Reset score
        self.score = 0;

        // Remove all enemies and bullets
        self.world.bullets.clear();
        self.world.enemies.clear();
    }

    /// Handles collisions between the player and the enemies
    fn handle_player_collisions(&mut self) {
        if self.world.enemies.iter().any(|enemy| self.world.player.collides_with(enemy)) {
            // Make an explosion where the player was
            let ppos = self.world.player.position();
            Game::make_explosion(&mut self.world.particles, ppos, 8);

            self.reset();
        }
    }

    /// Generates a new explosion of the given intensity at the given position.
    /// This works best with values between 5 and 25
    fn make_explosion(particles: &mut Vec<Particle>, position: Point, intensity: u8) {
        for rotation in itertools_num::linspace(0.0, 2.0 * f64::consts::PI, 30) {
            for ttl in (1..intensity).map(|x| (x as f64) / 10.0) {
                particles.push(Particle::new(Vector::new(position.clone(), rotation), ttl));
            }
        }
    }
}
<commit_msg>Simplify single match statement. Detected by clippy.<commit_after>//! This module contains the game logic

use std::f64;
use std::env::current_exe;

use itertools_num;
use opengl_graphics::GlGraphics;
use opengl_graphics::glyph_cache::GlyphCache;
use piston_window::{clear, ControllerButton, Context, ControllerAxisArgs, Key, text, Transformed};
use rand::{self, ThreadRng};

use drawing::{color, Point, Size};
use models::{Bullet, Enemy, Particle, Vector, World};
use traits::{Advance, Collide, Position};

// Constants related to time
const BULLETS_PER_SECOND: f64 = 100.0;
const BULLET_RATE: f64 = 1.0 / BULLETS_PER_SECOND;

const ENEMY_SPAWNS_PER_SECOND: f64 = 1.0;
const ENEMY_SPAWN_RATE: f64 = 1.0 / ENEMY_SPAWNS_PER_SECOND;

const TRAIL_PARTICLES_PER_SECOND: f64 = 20.0;
const TRAIL_PARTICLE_RATE: f64 = 1.0 / TRAIL_PARTICLES_PER_SECOND;

// Constants related to movement
// Speed is measured in pixels per second
// Rotation speed is measured in radians per second
const ADVANCE_SPEED: f64 = 200.0;
const BULLET_SPEED: f64 = 500.0;
const ENEMY_SPEED: f64 = 100.0;
const ROTATE_SPEED: f64 = 2.0 * f64::consts::PI;

/// The data structure that drives the game
pub struct Game {
    /// The world contains everything that needs to be drawn
    world: World,
    /// The current score of the player
    score: u32,
    /// The active actions
    actions: Actions,
    /// Timers needed by the game
    timers: Timers,
    /// A random number generator
    rng: ThreadRng,
    /// Resources needed for drawing
    resources: Resources
}

/// Active actions (toggled by user input)
#[derive(Default)]
struct Actions {
    rotate_left: bool,
    rotate_right: bool,
    boost: bool,
    shoot: bool
}

/// Timers to handle creation of bullets, enemies and particles
#[derive(Default)]
struct Timers {
    current_time: f64,
    last_tail_particle: f64,
    last_shoot: f64,
    last_spawned_enemy: f64
}

/// Additional resources needed for the game
struct Resources {
    font: GlyphCache<'static>
}

impl Game {
    /// Returns a new `Game` containing a `World` of the given `Size`
    pub fn new(size: Size) -> Game {
        let mut rng = rand::thread_rng();
        let exe_directory = current_exe().unwrap().parent().unwrap().to_owned();
        Game {
            world: World::new(&mut rng, size),
            score: 0,
            actions: Actions::default(),
            timers: Timers::default(),
            rng: rng,
            resources: Resources {
                font: GlyphCache::new(&exe_directory.join("resources/FiraMono-Bold.ttf")).unwrap()
            }
        }
    }

    /// Processes a key press
    pub fn key_press(&mut self, key: Key) {
        self.handle_key(key, true);
    }

    /// Processes a key release
    pub fn key_release(&mut self, key: Key) {
        self.handle_key(key, false);
    }

    /// Handles a key press or release
    fn handle_key(&mut self, key: Key, pressed: bool) {
        match key {
            Key::Left => self.actions.rotate_left = pressed,
            Key::Right => self.actions.rotate_right = pressed,
            Key::Up => self.actions.boost = pressed,
            Key::Space => self.actions.shoot = pressed,
            _ => ()
        }
    }

    /// Processes a button press
    pub fn button_press(&mut self, controller: ControllerButton) {
        self.handle_button(controller, true);
    }

    /// Processes a button release
    pub fn button_release(&mut self, controller: ControllerButton) {
        self.handle_button(controller, false);
    }

    /// Handles a button press or release
    fn handle_button(&mut self, controller: ControllerButton, pressed: bool) {
        // Button 10 is A button on XInput
        if controller.button == 10 {
            self.actions.shoot = pressed
        }
    }

    /// Handles a controller axis input
    pub fn handle_axis(&mut self, controller: ControllerAxisArgs) {
        // Axis 0 is left stick (XInput). -1.0 left to 1.0 right
        if controller.axis == 0 {
            match controller.position {
                -1.0 ... -0.2 => {
                    self.actions.rotate_left = true;
                    self.actions.rotate_right = false;
                },
                0.2 ... 1.0 => {
                    self.actions.rotate_left = false;
                    self.actions.rotate_right = true;
                },
                -0.199 ... 0.199 => {
                    self.actions.rotate_left = false;
                    self.actions.rotate_right = false;
                },
                _ => {}
            }
        }

        // Axis 5 is right trigger (XInput). -1.0 is not pressed, 1.0 is fully pressed
        if controller.axis == 5 {
            match controller.position {
                -0.8 ... 1.0 => {
                    self.actions.boost = true;
                },
                -1.0 ... -0.799 => {
                    self.actions.boost = false;
                },
                _ => {}
            }
        }
    }

    /// Renders the game to the screen
    pub fn render(&mut self, c: Context, g: &mut GlGraphics) {
        // Clear everything
        clear(color::BLACK, g);

        // Render the world
        self.world.render(c, g);

        // Render the score
        text(color::ORANGE,
             22,
             &format!("Score: {}", self.score),
             &mut self.resources.font,
             c.trans(10.0, 20.0).transform,
             g);
    }

    /// Updates the game
    ///
    /// `dt` is the amount of seconds that have passed since the last update
    pub fn update(&mut self, dt: f64) {
        self.timers.current_time += dt;

        // Update rocket rotation
        if self.actions.rotate_left {
            *self.world.player.direction_mut() += -ROTATE_SPEED * dt;
        }
        if self.actions.rotate_right {
            *self.world.player.direction_mut() += ROTATE_SPEED * dt;
        };

        // Set speed and advance the player with wrap around
        let speed = if self.actions.boost { 2.0 * ADVANCE_SPEED } else { ADVANCE_SPEED };
        self.world.player.advance_wrapping(dt * speed, self.world.size.clone());

        // Update particles
        for particle in &mut self.world.particles {
            particle.update(dt);
        }

        // Remove old particles
        self.world.particles.retain(|p| p.ttl > 0.0);

        // Add new particles at the player's position, to leave a trail
        if self.timers.current_time - self.timers.last_tail_particle > TRAIL_PARTICLE_RATE {
            self.timers.last_tail_particle = self.timers.current_time;
            self.world.particles.push(Particle::new(self.world.player.vector.clone().invert(),
                                                    0.5));
        }

        // Add bullets
        if self.actions.shoot && self.timers.current_time - self.timers.last_shoot > BULLET_RATE {
            self.timers.last_shoot = self.timers.current_time;
            self.world.bullets.push(Bullet::new(Vector::new(self.world.player.nose(),
                                                            self.world.player.direction())));
        }

        // Advance bullets
        for bullet in &mut self.world.bullets {
            bullet.update(dt * BULLET_SPEED);
        }

        // Remove bullets outside the viewport
        {
            // Shorten the lifetime of size
            let size = &self.world.size;
            self.world.bullets.retain(|b| size.contains(b.position()));
        }

        // Spawn enemies at random locations
        if self.timers.current_time - self.timers.last_spawned_enemy > ENEMY_SPAWN_RATE {
            self.timers.last_spawned_enemy = self.timers.current_time;
            let mut new_enemy;
            loop {
                new_enemy = Enemy::new(Vector::random(&mut self.rng, self.world.size.clone()));
                if !self.world.player.collides_with(&new_enemy) {
                    break;
                }
            }
            self.world.enemies.push(new_enemy);
        }

        // Move enemies in the player's direction
        for enemy in &mut self.world.enemies {
            enemy.update(dt * ENEMY_SPEED, self.world.player.position());
        }

        self.handle_player_collisions();
        self.handle_bullet_collisions();
    }

    /// Handles collisions between the bullets and the enemies
    ///
    /// When an enemy is reached by a bullet, both the enemy and the bullet
    /// will be removed. Additionally, the score will be increased by 10
    fn handle_bullet_collisions(&mut self) {
        let old_enemy_count = self.world.enemies.len();

        // We introduce a scope to shorten the lifetime of the borrows below
        {
            let bullets = &mut self.world.bullets;
            let enemies = &mut self.world.enemies;
            let particles = &mut self.world.particles;

            bullets.retain(|bullet| {
                // Remove the first enemy that collides with a bullet (if any)
                // Add an explosion on its place
                if let Some((index, position)) = enemies.iter().enumerate()
                    .find(|&(_, enemy)| enemy.collides_with(bullet))
                    .map(|(index, enemy)| (index, enemy.position()))
                    {
                        Game::make_explosion(particles, position, 10);
                        enemies.remove(index);
                        false
                    } else {
                    true
                }
            });
        }

        let killed_enemies = (old_enemy_count - self.world.enemies.len()) as u32;
        self.score += 10 * killed_enemies;
    }

    /// reset our game-state
    fn reset(&mut self) {
        // Reset player position
        *self.world.player.x_mut() = self.world.size.random_x(&mut self.rng);
        *self.world.player.y_mut() = self.world.size.random_y(&mut self.rng);

        // Reset score
        self.score = 0;

        // Remove all enemies and bullets
        self.world.bullets.clear();
        self.world.enemies.clear();
    }

    /// Handles collisions between the player and the enemies
    fn handle_player_collisions(&mut self) {
        if self.world.enemies.iter().any(|enemy| self.world.player.collides_with(enemy)) {
            // Make an explosion where the player was
            let ppos = self.world.player.position();
            Game::make_explosion(&mut self.world.particles, ppos, 8);

            self.reset();
        }
    }

    /// Generates a new explosion of the given intensity at the given position.
    /// This works best with values between 5 and 25
    fn make_explosion(particles: &mut Vec<Particle>, position: Point, intensity: u8) {
        for rotation in itertools_num::linspace(0.0, 2.0 * f64::consts::PI, 30) {
            for ttl in (1..intensity).map(|x| (x as f64) / 10.0) {
                particles.push(Particle::new(Vector::new(position.clone(), rotation), ttl));
            }
        }
    }
}
<|endoftext|>