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

use appkit::NSRect;

use libc::{c_double, c_long};
use libc;

pub type Class = libc::intptr_t;
pub type IMP = extern "C" fn(id, SEL) -> id;
pub type Ivar = libc::intptr_t;
pub type SEL = libc::intptr_t;
#[allow(non_camel_case_types)]
pub type id = libc::intptr_t;

pub static nil: id = 0 as id;

extern {
    pub fn class_addMethod(cls: Class, name: SEL, imp: IMP, types: *const libc::c_char) -> bool;
    pub fn class_addIvar(cls: Class,
                         name: *const libc::c_char,
                         size: libc::size_t,
                         alignment: u8,
                         types: *const libc::c_char)
                         -> bool;
    pub fn object_setInstanceVariable(obj: id, name: *const libc::c_char, value: *mut libc::c_void);
    pub fn object_getInstanceVariable(obj: id, name: *const libc::c_char, outValue: *mut *mut libc::c_void);
    pub fn objc_allocateClassPair(superclass: Class, name: *const libc::c_char, extraBytes: libc::size_t)
                                  -> Class;
    pub fn objc_getClass(name: *const libc::c_char) -> id;
    pub fn objc_msgSend(theReceiver: id, theSelector: SEL) -> id;
    pub fn objc_registerClassPair(cls: Class);
    pub fn sel_registerName(name: *const libc::c_char) -> SEL;
}

/// A convenience method to convert the name of a class to the class object itself.
#[inline]
pub fn class(name: &str) -> id {
    unsafe {
        objc_getClass(name.to_c_str().as_ptr())
    }
}

/// A convenience method to convert the name of a selector to the selector object.
#[inline]
pub fn selector(name: &str) -> SEL {
    unsafe {
        sel_registerName(name.to_c_str().as_ptr())
    }
}

/// A trait that allows syntax like:
///
///     let string = "NSString".send("alloc").send("initWithCString:", "Hello world!");
pub trait ObjCMethodCall {
    unsafe fn send<S:ObjCSelector,A:ObjCMethodArgs>(self, selector: S, args: A) -> id;
    unsafe fn send_double<S:ObjCSelector,A:ObjCMethodDoubleArgs>(self, selector: S, args: A)
                          -> c_double;
    unsafe fn send_long<S:ObjCSelector,A:ObjCMethodLongArgs>(self, selector: S, args: A) -> c_long;
    unsafe fn send_void<S:ObjCSelector,A:ObjCMethodVoidArgs>(self, selector: S, args: A);
}

impl ObjCMethodCall for id {
    unsafe fn send<S:ObjCSelector,A:ObjCMethodArgs>(self, selector: S, args: A) -> id {
        args.send_args(self, selector.as_selector())
    }
    unsafe fn send_double<S:ObjCSelector,A:ObjCMethodDoubleArgs>(self, selector: S, args: A)
                          -> c_double {
        args.send_double_args(self, selector.as_selector())
    }
    unsafe fn send_long<S:ObjCSelector,A:ObjCMethodLongArgs>(self, selector: S, args: A)
                        -> c_long {
        args.send_long_args(self, selector.as_selector())
    }
    unsafe fn send_void<S:ObjCSelector,A:ObjCMethodVoidArgs>(self, selector: S, args: A) {
        args.send_void_args(self, selector.as_selector())
    }
}

/// A convenience implementation that allows methods on class names to be called directly, as in:
///
///     "NSString".send("alloc")
impl<'a> ObjCMethodCall for &'a str {
    unsafe fn send<S:ObjCSelector,A:ObjCMethodArgs>(self, selector: S, args: A) -> id {
        args.send_args(class(self), selector.as_selector())
    }
    unsafe fn send_double<S:ObjCSelector,A:ObjCMethodDoubleArgs>(self, selector: S, args: A)
                          -> c_double {
        args.send_double_args(class(self), selector.as_selector())
    }
    unsafe fn send_long<S:ObjCSelector,A:ObjCMethodLongArgs>(self, selector: S, args: A)
                        -> c_long {
        args.send_long_args(class(self), selector.as_selector())
    }
    unsafe fn send_void<S:ObjCSelector,A:ObjCMethodVoidArgs>(self, selector: S, args: A) {
        args.send_void_args(class(self), selector.as_selector())
    }
}

/// A trait that allows C strings to be used as selectors without having to convert them first.
pub trait ObjCSelector {
    fn as_selector(self) -> SEL;
}

impl<'a> ObjCSelector for &'a str {
    #[inline]
    fn as_selector(self) -> SEL {
        // TODO(pcwalton): Cache somehow.
        unsafe {
            sel_registerName(self.to_c_str().as_ptr())
        }
    }
}

impl ObjCSelector for SEL {
    #[inline]
    fn as_selector(self) -> SEL {
        self
    }
}

/// Traits that simulate variadic parameters for convenience when sending messages.
trait ObjCMethodArgs {
    unsafe fn send_args(self, receiver: id, selector: SEL) -> id;
}
trait ObjCMethodDoubleArgs {
    unsafe fn send_double_args(self, receiver: id, selector: SEL) -> c_double;
}
trait ObjCMethodLongArgs {
    unsafe fn send_long_args(self, receiver: id, selector: SEL) -> c_long;
}
trait ObjCMethodVoidArgs {
    unsafe fn send_void_args(self, receiver: id, selector: SEL);
}

impl ObjCMethodArgs for () {
    #[inline]
    unsafe fn send_args(self, receiver: id, selector: SEL) -> id {
        invoke_msg_id(receiver, selector)
    }
}

impl ObjCMethodArgs for (id, id, id, id, id) {
    #[inline]
    unsafe fn send_args(self, receiver: id, selector: SEL) -> id {
        let (first, second, third, fourth, fifth) = self;
        invoke_msg_id_id_id_id_id_id(receiver, selector, first, second, third, fourth, fifth)
    }
}

impl ObjCMethodArgs for NSRect {
    #[inline]
    unsafe fn send_args(self, receiver: id, selector: SEL) -> id {
        invoke_msg_id_NSRect(receiver, selector, &self)
    }
}

impl ObjCMethodDoubleArgs for () {
    #[inline]
    unsafe fn send_double_args(self, receiver: id, selector: SEL) -> f64 {
        invoke_msg_double(receiver, selector)
    }
}

impl ObjCMethodLongArgs for () {
    #[inline]
    unsafe fn send_long_args(self, receiver: id, selector: SEL) -> c_long {
        invoke_msg_long(receiver, selector)
    }
}

impl ObjCMethodVoidArgs for () {
    #[inline]
    unsafe fn send_void_args(self, receiver: id, selector: SEL) {
        invoke_msg_void(receiver, selector)
    }
}

impl ObjCMethodVoidArgs for bool {
    #[inline]
    unsafe fn send_void_args(self, receiver: id, selector: SEL) {
        invoke_msg_void_bool(receiver, selector, self)
    }
}

impl ObjCMethodVoidArgs for id {
    #[inline]
    unsafe fn send_void_args(self, receiver: id, selector: SEL) {
        invoke_msg_void_id(receiver, selector, self)
    }
}

/// A trait that simulates variadic parameters for method calls.

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

    #[test]
    pub fn test_nsapp() {
        unsafe {
            let _nsApp = "NSApplication".send("sharedApplication", ());
        }
    }

    #[test]
    pub fn test_custom_obj() {
        extern fn MyObject_doSomething(this: id, _: SEL) -> id {
            println!("doSomething");
            return this;
        }

        let ns_object = class("NSObject");
        let my_object = unsafe {
            objc_allocateClassPair(ns_object, "MyObject".to_c_str().as_ptr(), 0 as libc::size_t)
        };
        unsafe {
            let doSomething = selector("doSomething");
            let _ = class_addMethod(my_object, doSomething, MyObject_doSomething, "@@:".to_c_str().as_ptr());

            objc_registerClassPair(my_object);

            let mut obj: id = my_object.send("alloc", ());
            obj = obj.send("init", ());
            obj.send_void("doSomething", ());
        }
    }
}

#[link(name = "msgsend", kind = "static")]
extern {
    fn invoke_msg_double(theReceiver: id, theSelector: SEL) -> f64;
    fn invoke_msg_id(theReceiver: id, theSelector: SEL) -> id;
    fn invoke_msg_id_id_id_id_id_id(theReceiver: id,
                                    theSelector: SEL,
                                    a: id,
                                    b: id,
                                    c: id,
                                    d: id,
                                    e: id)
                                    -> id;
    fn invoke_msg_id_NSRect(theReceiver: id, theSelector: SEL, a: &NSRect) -> id;
    fn invoke_msg_long(theReceiver: id, theSelector: SEL) -> c_long;
    fn invoke_msg_void(theReceiver: id, theSelector: SEL);
    fn invoke_msg_void_bool(theReceiver: id, theSelector: SEL, a: bool);
    fn invoke_msg_void_id(theReceiver: id, theSelector: SEL, a: id);
}

<commit_msg>Make invoke_msg bindings public for rust-alert<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use appkit::NSRect;

use libc::{c_double, c_long};
use libc;

pub type Class = libc::intptr_t;
pub type IMP = extern "C" fn(id, SEL) -> id;
pub type Ivar = libc::intptr_t;
pub type SEL = libc::intptr_t;
#[allow(non_camel_case_types)]
pub type id = libc::intptr_t;

pub static nil: id = 0 as id;

extern {
    pub fn class_addMethod(cls: Class, name: SEL, imp: IMP, types: *const libc::c_char) -> bool;
    pub fn class_addIvar(cls: Class,
                         name: *const libc::c_char,
                         size: libc::size_t,
                         alignment: u8,
                         types: *const libc::c_char)
                         -> bool;
    pub fn object_setInstanceVariable(obj: id, name: *const libc::c_char, value: *mut libc::c_void);
    pub fn object_getInstanceVariable(obj: id, name: *const libc::c_char, outValue: *mut *mut libc::c_void);
    pub fn objc_allocateClassPair(superclass: Class, name: *const libc::c_char, extraBytes: libc::size_t)
                                  -> Class;
    pub fn objc_getClass(name: *const libc::c_char) -> id;
    pub fn objc_msgSend(theReceiver: id, theSelector: SEL) -> id;
    pub fn objc_registerClassPair(cls: Class);
    pub fn sel_registerName(name: *const libc::c_char) -> SEL;
}

/// A convenience method to convert the name of a class to the class object itself.
#[inline]
pub fn class(name: &str) -> id {
    unsafe {
        objc_getClass(name.to_c_str().as_ptr())
    }
}

/// A convenience method to convert the name of a selector to the selector object.
#[inline]
pub fn selector(name: &str) -> SEL {
    unsafe {
        sel_registerName(name.to_c_str().as_ptr())
    }
}

/// A trait that allows syntax like:
///
///     let string = "NSString".send("alloc").send("initWithCString:", "Hello world!");
pub trait ObjCMethodCall {
    unsafe fn send<S:ObjCSelector,A:ObjCMethodArgs>(self, selector: S, args: A) -> id;
    unsafe fn send_double<S:ObjCSelector,A:ObjCMethodDoubleArgs>(self, selector: S, args: A)
                          -> c_double;
    unsafe fn send_long<S:ObjCSelector,A:ObjCMethodLongArgs>(self, selector: S, args: A) -> c_long;
    unsafe fn send_void<S:ObjCSelector,A:ObjCMethodVoidArgs>(self, selector: S, args: A);
}

impl ObjCMethodCall for id {
    unsafe fn send<S:ObjCSelector,A:ObjCMethodArgs>(self, selector: S, args: A) -> id {
        args.send_args(self, selector.as_selector())
    }
    unsafe fn send_double<S:ObjCSelector,A:ObjCMethodDoubleArgs>(self, selector: S, args: A)
                          -> c_double {
        args.send_double_args(self, selector.as_selector())
    }
    unsafe fn send_long<S:ObjCSelector,A:ObjCMethodLongArgs>(self, selector: S, args: A)
                        -> c_long {
        args.send_long_args(self, selector.as_selector())
    }
    unsafe fn send_void<S:ObjCSelector,A:ObjCMethodVoidArgs>(self, selector: S, args: A) {
        args.send_void_args(self, selector.as_selector())
    }
}

/// A convenience implementation that allows methods on class names to be called directly, as in:
///
///     "NSString".send("alloc")
impl<'a> ObjCMethodCall for &'a str {
    unsafe fn send<S:ObjCSelector,A:ObjCMethodArgs>(self, selector: S, args: A) -> id {
        args.send_args(class(self), selector.as_selector())
    }
    unsafe fn send_double<S:ObjCSelector,A:ObjCMethodDoubleArgs>(self, selector: S, args: A)
                          -> c_double {
        args.send_double_args(class(self), selector.as_selector())
    }
    unsafe fn send_long<S:ObjCSelector,A:ObjCMethodLongArgs>(self, selector: S, args: A)
                        -> c_long {
        args.send_long_args(class(self), selector.as_selector())
    }
    unsafe fn send_void<S:ObjCSelector,A:ObjCMethodVoidArgs>(self, selector: S, args: A) {
        args.send_void_args(class(self), selector.as_selector())
    }
}

/// A trait that allows C strings to be used as selectors without having to convert them first.
pub trait ObjCSelector {
    fn as_selector(self) -> SEL;
}

impl<'a> ObjCSelector for &'a str {
    #[inline]
    fn as_selector(self) -> SEL {
        // TODO(pcwalton): Cache somehow.
        unsafe {
            sel_registerName(self.to_c_str().as_ptr())
        }
    }
}

impl ObjCSelector for SEL {
    #[inline]
    fn as_selector(self) -> SEL {
        self
    }
}

/// Traits that simulate variadic parameters for convenience when sending messages.
trait ObjCMethodArgs {
    unsafe fn send_args(self, receiver: id, selector: SEL) -> id;
}
trait ObjCMethodDoubleArgs {
    unsafe fn send_double_args(self, receiver: id, selector: SEL) -> c_double;
}
trait ObjCMethodLongArgs {
    unsafe fn send_long_args(self, receiver: id, selector: SEL) -> c_long;
}
trait ObjCMethodVoidArgs {
    unsafe fn send_void_args(self, receiver: id, selector: SEL);
}

impl ObjCMethodArgs for () {
    #[inline]
    unsafe fn send_args(self, receiver: id, selector: SEL) -> id {
        invoke_msg_id(receiver, selector)
    }
}

impl ObjCMethodArgs for (id, id, id, id, id) {
    #[inline]
    unsafe fn send_args(self, receiver: id, selector: SEL) -> id {
        let (first, second, third, fourth, fifth) = self;
        invoke_msg_id_id_id_id_id_id(receiver, selector, first, second, third, fourth, fifth)
    }
}

impl ObjCMethodArgs for NSRect {
    #[inline]
    unsafe fn send_args(self, receiver: id, selector: SEL) -> id {
        invoke_msg_id_NSRect(receiver, selector, &self)
    }
}

impl ObjCMethodDoubleArgs for () {
    #[inline]
    unsafe fn send_double_args(self, receiver: id, selector: SEL) -> f64 {
        invoke_msg_double(receiver, selector)
    }
}

impl ObjCMethodLongArgs for () {
    #[inline]
    unsafe fn send_long_args(self, receiver: id, selector: SEL) -> c_long {
        invoke_msg_long(receiver, selector)
    }
}

impl ObjCMethodVoidArgs for () {
    #[inline]
    unsafe fn send_void_args(self, receiver: id, selector: SEL) {
        invoke_msg_void(receiver, selector)
    }
}

impl ObjCMethodVoidArgs for bool {
    #[inline]
    unsafe fn send_void_args(self, receiver: id, selector: SEL) {
        invoke_msg_void_bool(receiver, selector, self)
    }
}

impl ObjCMethodVoidArgs for id {
    #[inline]
    unsafe fn send_void_args(self, receiver: id, selector: SEL) {
        invoke_msg_void_id(receiver, selector, self)
    }
}

/// A trait that simulates variadic parameters for method calls.

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

    #[test]
    pub fn test_nsapp() {
        unsafe {
            let _nsApp = "NSApplication".send("sharedApplication", ());
        }
    }

    #[test]
    pub fn test_custom_obj() {
        extern fn MyObject_doSomething(this: id, _: SEL) -> id {
            println!("doSomething");
            return this;
        }

        let ns_object = class("NSObject");
        let my_object = unsafe {
            objc_allocateClassPair(ns_object, "MyObject".to_c_str().as_ptr(), 0 as libc::size_t)
        };
        unsafe {
            let doSomething = selector("doSomething");
            let _ = class_addMethod(my_object, doSomething, MyObject_doSomething, "@@:".to_c_str().as_ptr());

            objc_registerClassPair(my_object);

            let mut obj: id = my_object.send("alloc", ());
            obj = obj.send("init", ());
            obj.send_void("doSomething", ());
        }
    }
}

#[link(name = "msgsend", kind = "static")]
extern {
    pub fn invoke_msg_double(theReceiver: id, theSelector: SEL) -> f64;
    pub fn invoke_msg_id(theReceiver: id, theSelector: SEL) -> id;
    pub fn invoke_msg_id_id_id_id_id_id(theReceiver: id,
                                        theSelector: SEL,
                                        a: id,
                                        b: id,
                                        c: id,
                                        d: id,
                                        e: id)
                                        -> id;
    pub fn invoke_msg_id_NSRect(theReceiver: id, theSelector: SEL, a: &NSRect) -> id;
    pub fn invoke_msg_long(theReceiver: id, theSelector: SEL) -> c_long;
    pub fn invoke_msg_void(theReceiver: id, theSelector: SEL);
    pub fn invoke_msg_void_bool(theReceiver: id, theSelector: SEL, a: bool);
    pub fn invoke_msg_void_id(theReceiver: id, theSelector: SEL, a: id);
}

<|endoftext|>


<commit_before>#![feature(phase)]

extern crate serialize;
#[phase(plugin, link)]
extern crate hammer;

use std::io::File;
use memory::Memory;
use interpret::interpret;

use hammer::{decode_args, usage};
use std::os;
use std::io;

mod memory;
mod interpret;

#[deriving(Decodable, Show)]
struct BearOpts {
	file: Option<String>,
	help: bool,
	interactive: bool
}

hammer_config!(BearOpts "BEAR - Another BF",
	|c| {
		c.short("file", 'f').short("help", 'h').short("interactive", 'i')
    }
)

fn interactive_console() {
	let mut mem = Memory::new();

    print!("> ");
   	for line in io::stdin().lines() {
   		match line {
   			Ok(val) => { interpret(val, &mut mem); print!("\n> "); },
   			Err(err) => fail!(err.desc)
   		};
    }
}

fn main() {
	let opts: BearOpts = match decode_args(os::args().tail()) {
		Ok(val) => val,
		Err(err) => fail!(err.message)
	};
	if opts.help {
		let (desc, usage_text) = usage::<BearOpts>(true);
	    println!("Usage: {}", os::args().get(0));
	    println!("{}", usage_text);
	    println!("{}", desc.unwrap());
	}
	else if opts.interactive {
        interactive_console();
	}
	else {
		let filename = match opts.file {
			Some(val) => val,
			None => fail!("--file required")
		};
		let test = match File::open(&Path::new(filename)).read_to_end() {
			Ok(val) => {
				match String::from_utf8(val) {
					Ok(val) => val,
					Err(err) => fail!(err)
				}
			},
			Err(err) => fail!(err.desc)
		};

		let mut mem = Memory::new();

		interpret(test, &mut mem);
	}
}<commit_msg>Tabs get sooooo annoying sometimes...<commit_after>#![feature(phase)]

extern crate serialize;
#[phase(plugin, link)]
extern crate hammer;

use std::io::File;
use memory::Memory;
use interpret::interpret;

use hammer::{decode_args, usage};
use std::os;
use std::io;

mod memory;
mod interpret;

#[deriving(Decodable, Show)]
struct BearOpts {
    file: Option<String>,
    help: bool,
    interactive: bool
}

hammer_config!(BearOpts "BEAR - Another BF",
    |c| {
        c.short("file", 'f').short("help", 'h').short("interactive", 'i')
    }
)

fn interactive_console() {
    let mut mem = Memory::new();

    print!("> ");
    for line in io::stdin().lines() {
        match line {
            Ok(val) => { interpret(val, &mut mem); print!("\n> "); },
            Err(err) => fail!(err.desc)
        };
    }
}

fn main() {
    let opts: BearOpts = match decode_args(os::args().tail()) {
        Ok(val) => val,
        Err(err) => fail!(err.message)
    };
    if opts.help {
        let (desc, usage_text) = usage::<BearOpts>(true);
        println!("Usage: {}", os::args().get(0));
        println!("{}", usage_text);
        println!("{}", desc.unwrap());
    }
    else if opts.interactive {
        interactive_console();
    }
    else {
        let filename = match opts.file {
            Some(val) => val,
            None => fail!("--file required")
        };
        let test = match File::open(&Path::new(filename)).read_to_end() {
            Ok(val) => {
                match String::from_utf8(val) {
                    Ok(val) => val,
                    Err(err) => fail!(err)
                }
            },
            Err(err) => fail!(err.desc)
        };

        let mut mem = Memory::new();

        interpret(test, &mut mem);
    }
}<|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)]
#[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);
    }
}
<commit_msg>capi: Update doctest for error enum changes.<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!(rv, mp4parse::mp4parse_error::MP4PARSE_OK);
//!     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>//! This module contains definition of table/row cells stuff

use super::format::Alignment;
use super::utils::display_width;
use super::utils::print_align;
use super::{color, Attr, Terminal};
use std::io::{Error, Write};
use std::string::ToString;
use std::str::FromStr;

/// Represent a table cell containing a string.
///
/// Once created, a cell's content cannot be modified.
/// The cell would have to be replaced by another one
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct Cell {
    content: Vec<String>,
    width: usize,
    align: Alignment,
    style: Vec<Attr>,
    hspan: usize,
}

impl Cell {
    /// Create a new `Cell` initialized with content from `string`.
    /// Text alignment in cell is configurable with the `align` argument
    pub fn new_align(string: &str, align: Alignment) -> Cell {
        let content: Vec<String> = string.lines().map(|x| x.to_string()).collect();
        let mut width = 0;
        for cont in &content {
            let l = display_width(&cont[..]);
            if l > width {
                width = l;
            }
        }
        Cell {
            content: content,
            width: width,
            align: align,
            style: Vec::new(),
            hspan: 1,
        }
    }

    /// Create a new `Cell` initialized with content from `string`.
    /// By default, content is align to `LEFT`
    pub fn new(string: &str) -> Cell {
        Cell::new_align(string, Alignment::LEFT)
    }

    /// Set text alignment in the cell
    pub fn align(&mut self, align: Alignment) {
        self.align = align;
    }

    /// Add a style attribute to the cell
    pub fn style(&mut self, attr: Attr) {
        self.style.push(attr);
    }

    /// Add a style attribute to the cell. Can be chained
    pub fn with_style(mut self, attr: Attr) -> Cell {
        self.style(attr);
        self
    }

    /// Add horizontal spanning to the cell
    pub fn with_hspan(mut self, hspan: usize) -> Cell {
        self.set_hspan(hspan);
        self
    }

    /// Remove all style attributes and reset alignment to default (LEFT)
    pub fn reset_style(&mut self) {
        self.style.clear();
        self.align(Alignment::LEFT);
    }

    /// Set the cell's style by applying the given specifier string
    ///
    /// # Style spec syntax
    ///
    /// The syntax for the style specifier looks like this :
    /// **FrBybl** which means **F**oreground **r**ed **B**ackground **y**ellow **b**old **l**eft
    ///
    /// ### List of supported specifiers :
    ///
    /// * **F** : **F**oreground (must be followed by a color specifier)
    /// * **B** : **B**ackground (must be followed by a color specifier)
    /// * **b** : **b**old
    /// * **i** : **i**talic
    /// * **u** : **u**nderline
    /// * **c** : Align **c**enter
    /// * **l** : Align **l**eft
    /// * **r** : Align **r**ight
    /// * **d** : **d**efault style
    ///
    /// ### List of color specifiers :
    ///
    /// * **r** : Red
    /// * **b** : Blue
    /// * **g** : Green
    /// * **y** : Yellow
    /// * **c** : Cyan
    /// * **m** : Magenta
    /// * **w** : White
    /// * **d** : Black
    ///
    /// And capital letters are for **bright** colors.
    /// Eg :
    ///
    /// * **R** : Bright Red
    /// * **B** : Bright Blue
    /// * ... and so on ...
    pub fn style_spec(mut self, spec: &str) -> Cell {
        self.reset_style();
        let mut foreground = false;
        let mut background = false;
        let mut it = spec.chars().peekable();
        while let Some(c) = it.next() {
            if foreground || background {
                let color = match c {
                    'r' => color::RED,
                    'R' => color::BRIGHT_RED,
                    'b' => color::BLUE,
                    'B' => color::BRIGHT_BLUE,
                    'g' => color::GREEN,
                    'G' => color::BRIGHT_GREEN,
                    'y' => color::YELLOW,
                    'Y' => color::BRIGHT_YELLOW,
                    'c' => color::CYAN,
                    'C' => color::BRIGHT_CYAN,
                    'm' => color::MAGENTA,
                    'M' => color::BRIGHT_MAGENTA,
                    'w' => color::WHITE,
                    'W' => color::BRIGHT_WHITE,
                    'd' => color::BLACK,
                    'D' => color::BRIGHT_BLACK,
                    _ => {
                        // Silently ignore unknown tags
                        foreground = false;
                        background = false;
                        continue;
                    }
                };
                if foreground {
                    self.style(Attr::ForegroundColor(color));
                } else if background {
                    self.style(Attr::BackgroundColor(color));
                }
                foreground = false;
                background = false;
            } else {
                match c {
                    'F' => foreground = true,
                    'B' => background = true,
                    'b' => self.style(Attr::Bold),
                    'i' => self.style(Attr::Italic(true)),
                    'u' => self.style(Attr::Underline(true)),
                    'c' => self.align(Alignment::CENTER),
                    'l' => self.align(Alignment::LEFT),
                    'r' => self.align(Alignment::RIGHT),
                    'H' => {
                        let mut span_s = String::new();
                        while let Some('0'..='9') = it.peek() {
                            span_s.push(it.next().unwrap());
                        }
                        let span = usize::from_str(&span_s).unwrap();
                        self.set_hspan(span);
                    }
                    _ => { /* Silently ignore unknown tags */ }
                }
            }
        }
        self
    }

    /// Return the height of the cell
    #[deprecated(since="0.8.0", note="Will become private in future release. See [issue #87](https://github.com/phsym/prettytable-rs/issues/87)")]
    pub fn get_height(&self) -> usize {
        self.content.len()
    }

    /// Return the width of the cell
    #[deprecated(since="0.8.0", note="Will become private in future release. See [issue #87](https://github.com/phsym/prettytable-rs/issues/87)")]
    pub fn get_width(&self) -> usize {
        self.width
    }

    /// Set horizontal span for this cell (must be > 0)
    pub fn set_hspan(&mut self, hspan: usize) {
        self.hspan = if hspan <= 0 {1} else {hspan};
    }

    /// Get horizontal span of this cell (> 0)
    pub fn get_hspan(&self) -> usize {
        self.hspan
    }

    /// Return a copy of the full string contained in the cell
    pub fn get_content(&self) -> String {
        self.content.join("\n")
    }

    /// Print a partial cell to `out`. Since the cell may be multi-lined,
    /// `idx` is the line index to print. `col_width` is the column width used to
    /// fill the cells with blanks so it fits in the table.
    /// If `ìdx` is higher than this cell's height, it will print empty content
    #[deprecated(since="0.8.0", note="Will become private in future release. See [issue #87](https://github.com/phsym/prettytable-rs/issues/87)")]
    pub fn print<T: Write + ?Sized>(
        &self,
        out: &mut T,
        idx: usize,
        col_width: usize,
        skip_right_fill: bool,
    ) -> Result<(), Error> {
        let c = self.content.get(idx).map(|s| s.as_ref()).unwrap_or("");
        print_align(out, self.align, c, ' ', col_width, skip_right_fill)
    }

    /// Apply style then call `print` to print the cell into a terminal
    #[deprecated(since="0.8.0", note="Will become private in future release. See [issue #87](https://github.com/phsym/prettytable-rs/issues/87)")]
    pub fn print_term<T: Terminal + ?Sized>(
        &self,
        out: &mut T,
        idx: usize,
        col_width: usize,
        skip_right_fill: bool,
    ) -> Result<(), Error> {
        for a in &self.style {
            match out.attr(*a) {
                Ok(..) | Err(::term::Error::NotSupported) | Err(::term::Error::ColorOutOfRange) => {
                    ()
                } // Ignore unsupported atrributes
                Err(e) => return Err(term_error_to_io_error(e)),
            };
        }
        self.print(out, idx, col_width, skip_right_fill)?;
        match out.reset() {
            Ok(..) | Err(::term::Error::NotSupported) | Err(::term::Error::ColorOutOfRange) => {
                Ok(())
            }
            Err(e) => Err(term_error_to_io_error(e)),
        }
    }
}

fn term_error_to_io_error(te: ::term::Error) -> Error {
    match te {
        ::term::Error::Io(why) => why,
        _ => Error::new(::std::io::ErrorKind::Other, te),
    }
}

impl<'a, T: ToString> From<&'a T> for Cell {
    fn from(f: &T) -> Cell {
        Cell::new(&f.to_string())
    }
}

impl ToString for Cell {
    fn to_string(&self) -> String {
        self.get_content()
    }
}

impl Default for Cell {
    /// Return a cell initialized with a single empty `String`, with LEFT alignment
    fn default() -> Cell {
        Cell {
            content: vec!["".to_string(); 1],
            width: 0,
            align: Alignment::LEFT,
            style: Vec::new(),
            hspan: 1,
        }
    }
}

/// This macro simplifies `Cell` creation
///
/// Support 2 syntax : With and without style specification.
/// # Syntax
/// ```text
/// cell!(value);
/// ```
/// or
///
/// ```text
/// cell!(spec:value);
/// ```
/// Value must implement the `std::string::ToString` trait
///
/// For details about style specifier syntax, check doc for [`Cell::style_spec`](cell/struct.Cell.html#method.style_spec) method
/// # Example
/// ```
/// # #[macro_use] extern crate prettytable;
/// # fn main() {
/// let cell = cell!("value");
/// // Do something with the cell
/// # drop(cell);
/// // Create a cell with style (Red foreground, Bold, aligned to left);
/// let styled = cell!(Frbl->"value");
/// # drop(styled);
/// # }
/// ```
#[macro_export]
macro_rules! cell {
    () => {
        $crate::cell::Cell::default()
    };
    ($value:expr) => {
        $crate::cell::Cell::new(&$value.to_string())
    };
    ($style:ident -> $value:expr) => {
        cell!($value).style_spec(stringify!($style))
    };
}

#[cfg(test)]
mod tests {
    use cell::Cell;
    use format::Alignment;
    use term::{color, Attr};
    use utils::StringWriter;

    #[test]
    fn get_content() {
        let cell = Cell::new("test");
        assert_eq!(cell.get_content(), "test");
    }

    #[test]
    fn print_ascii() {
        let ascii_cell = Cell::new("hello");
        assert_eq!(ascii_cell.get_width(), 5);

        let mut out = StringWriter::new();
        let _ = ascii_cell.print(&mut out, 0, 10, false);
        assert_eq!(out.as_string(), "hello     ");
    }

    #[test]
    fn print_unicode() {
        let unicode_cell = Cell::new("привет");
        assert_eq!(unicode_cell.get_width(), 6);

        let mut out = StringWriter::new();
        let _ = unicode_cell.print(&mut out, 0, 10, false);
        assert_eq!(out.as_string(), "привет    ");
    }

    #[test]
    fn print_cjk() {
        let unicode_cell = Cell::new("由系统自动更新");
        assert_eq!(unicode_cell.get_width(), 14);
        let mut out = StringWriter::new();
        let _ = unicode_cell.print(&mut out, 0, 20, false);
        assert_eq!(out.as_string(), "由系统自动更新      ");
    }

    #[test]
    fn align_left() {
        let cell = Cell::new_align("test", Alignment::LEFT);
        let mut out = StringWriter::new();
        let _ = cell.print(&mut out, 0, 10, false);
        assert_eq!(out.as_string(), "test      ");
    }

    #[test]
    fn align_center() {
        let cell = Cell::new_align("test", Alignment::CENTER);
        let mut out = StringWriter::new();
        let _ = cell.print(&mut out, 0, 10, false);
        assert_eq!(out.as_string(), "   test   ");
    }

    #[test]
    fn align_right() {
        let cell = Cell::new_align("test", Alignment::RIGHT);
        let mut out = StringWriter::new();
        let _ = cell.print(&mut out, 0, 10, false);
        assert_eq!(out.as_string(), "      test");
    }

    #[test]
    fn style_spec() {
        let mut cell = Cell::new("test").style_spec("FrBBbuic");
        assert_eq!(cell.style.len(), 5);
        assert!(cell.style.contains(&Attr::Underline(true)));
        assert!(cell.style.contains(&Attr::Italic(true)));
        assert!(cell.style.contains(&Attr::Bold));
        assert!(cell.style.contains(&Attr::ForegroundColor(color::RED)));
        assert!(
            cell.style
                .contains(&Attr::BackgroundColor(color::BRIGHT_BLUE))
        );
        assert_eq!(cell.align, Alignment::CENTER);

        cell = cell.style_spec("FDBwr");
        assert_eq!(cell.style.len(), 2);
        assert!(
            cell.style
                .contains(&Attr::ForegroundColor(color::BRIGHT_BLACK))
        );
        assert!(cell.style.contains(&Attr::BackgroundColor(color::WHITE)));
        assert_eq!(cell.align, Alignment::RIGHT);

        // Test with invalid sepcifier chars
        cell = cell.clone();
        cell = cell.style_spec("FzBr");
        assert!(cell.style.contains(&Attr::BackgroundColor(color::RED)));
        assert_eq!(cell.style.len(), 1);
        cell = cell.style_spec("zzz");
        assert!(cell.style.is_empty());
        assert_eq!(cell.get_hspan(), 1);
        cell = cell.style_spec("FDBwH03r");
        assert_eq!(cell.get_hspan(), 3);
    }

    #[test]
    fn reset_style() {
        let mut cell = Cell::new("test")
            .with_style(Attr::ForegroundColor(color::BRIGHT_BLACK))
            .with_style(Attr::BackgroundColor(color::WHITE));
        cell.align(Alignment::RIGHT);

        //style_spec("FDBwr");
        assert_eq!(cell.style.len(), 2);
        assert_eq!(cell.align, Alignment::RIGHT);
        cell.reset_style();
        assert_eq!(cell.style.len(), 0);
        assert_eq!(cell.align, Alignment::LEFT);
    }

    #[test]
    fn default_empty_cell() {
        let cell = Cell::default();
        assert_eq!(cell.align, Alignment::LEFT);
        assert!(cell.style.is_empty());
        assert_eq!(cell.get_content(), "");
        assert_eq!(cell.to_string(), "");
        assert_eq!(cell.get_height(), 1);
        assert_eq!(cell.get_width(), 0);
    }
}
<commit_msg>Added missing inlined doc about span style string<commit_after>//! This module contains definition of table/row cells stuff

use super::format::Alignment;
use super::utils::display_width;
use super::utils::print_align;
use super::{color, Attr, Terminal};
use std::io::{Error, Write};
use std::string::ToString;
use std::str::FromStr;

/// Represent a table cell containing a string.
///
/// Once created, a cell's content cannot be modified.
/// The cell would have to be replaced by another one
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct Cell {
    content: Vec<String>,
    width: usize,
    align: Alignment,
    style: Vec<Attr>,
    hspan: usize,
}

impl Cell {
    /// Create a new `Cell` initialized with content from `string`.
    /// Text alignment in cell is configurable with the `align` argument
    pub fn new_align(string: &str, align: Alignment) -> Cell {
        let content: Vec<String> = string.lines().map(|x| x.to_string()).collect();
        let mut width = 0;
        for cont in &content {
            let l = display_width(&cont[..]);
            if l > width {
                width = l;
            }
        }
        Cell {
            content: content,
            width: width,
            align: align,
            style: Vec::new(),
            hspan: 1,
        }
    }

    /// Create a new `Cell` initialized with content from `string`.
    /// By default, content is align to `LEFT`
    pub fn new(string: &str) -> Cell {
        Cell::new_align(string, Alignment::LEFT)
    }

    /// Set text alignment in the cell
    pub fn align(&mut self, align: Alignment) {
        self.align = align;
    }

    /// Add a style attribute to the cell
    pub fn style(&mut self, attr: Attr) {
        self.style.push(attr);
    }

    /// Add a style attribute to the cell. Can be chained
    pub fn with_style(mut self, attr: Attr) -> Cell {
        self.style(attr);
        self
    }

    /// Add horizontal spanning to the cell
    pub fn with_hspan(mut self, hspan: usize) -> Cell {
        self.set_hspan(hspan);
        self
    }

    /// Remove all style attributes and reset alignment to default (LEFT)
    pub fn reset_style(&mut self) {
        self.style.clear();
        self.align(Alignment::LEFT);
    }

    /// Set the cell's style by applying the given specifier string
    ///
    /// # Style spec syntax
    ///
    /// The syntax for the style specifier looks like this :
    /// **FrBybl** which means **F**oreground **r**ed **B**ackground **y**ellow **b**old **l**eft
    ///
    /// ### List of supported specifiers :
    ///
    /// * **F** : **F**oreground (must be followed by a color specifier)
    /// * **B** : **B**ackground (must be followed by a color specifier)
    /// * **H** : **H**orizontal span (must be followed by a number)
    /// * **b** : **b**old
    /// * **i** : **i**talic
    /// * **u** : **u**nderline
    /// * **c** : Align **c**enter
    /// * **l** : Align **l**eft
    /// * **r** : Align **r**ight
    /// * **d** : **d**efault style
    ///
    /// ### List of color specifiers :
    ///
    /// * **r** : Red
    /// * **b** : Blue
    /// * **g** : Green
    /// * **y** : Yellow
    /// * **c** : Cyan
    /// * **m** : Magenta
    /// * **w** : White
    /// * **d** : Black
    ///
    /// And capital letters are for **bright** colors.
    /// Eg :
    ///
    /// * **R** : Bright Red
    /// * **B** : Bright Blue
    /// * ... and so on ...
    pub fn style_spec(mut self, spec: &str) -> Cell {
        self.reset_style();
        let mut foreground = false;
        let mut background = false;
        let mut it = spec.chars().peekable();
        while let Some(c) = it.next() {
            if foreground || background {
                let color = match c {
                    'r' => color::RED,
                    'R' => color::BRIGHT_RED,
                    'b' => color::BLUE,
                    'B' => color::BRIGHT_BLUE,
                    'g' => color::GREEN,
                    'G' => color::BRIGHT_GREEN,
                    'y' => color::YELLOW,
                    'Y' => color::BRIGHT_YELLOW,
                    'c' => color::CYAN,
                    'C' => color::BRIGHT_CYAN,
                    'm' => color::MAGENTA,
                    'M' => color::BRIGHT_MAGENTA,
                    'w' => color::WHITE,
                    'W' => color::BRIGHT_WHITE,
                    'd' => color::BLACK,
                    'D' => color::BRIGHT_BLACK,
                    _ => {
                        // Silently ignore unknown tags
                        foreground = false;
                        background = false;
                        continue;
                    }
                };
                if foreground {
                    self.style(Attr::ForegroundColor(color));
                } else if background {
                    self.style(Attr::BackgroundColor(color));
                }
                foreground = false;
                background = false;
            } else {
                match c {
                    'F' => foreground = true,
                    'B' => background = true,
                    'b' => self.style(Attr::Bold),
                    'i' => self.style(Attr::Italic(true)),
                    'u' => self.style(Attr::Underline(true)),
                    'c' => self.align(Alignment::CENTER),
                    'l' => self.align(Alignment::LEFT),
                    'r' => self.align(Alignment::RIGHT),
                    'H' => {
                        let mut span_s = String::new();
                        while let Some('0'..='9') = it.peek() {
                            span_s.push(it.next().unwrap());
                        }
                        let span = usize::from_str(&span_s).unwrap();
                        self.set_hspan(span);
                    }
                    _ => { /* Silently ignore unknown tags */ }
                }
            }
        }
        self
    }

    /// Return the height of the cell
    #[deprecated(since="0.8.0", note="Will become private in future release. See [issue #87](https://github.com/phsym/prettytable-rs/issues/87)")]
    pub fn get_height(&self) -> usize {
        self.content.len()
    }

    /// Return the width of the cell
    #[deprecated(since="0.8.0", note="Will become private in future release. See [issue #87](https://github.com/phsym/prettytable-rs/issues/87)")]
    pub fn get_width(&self) -> usize {
        self.width
    }

    /// Set horizontal span for this cell (must be > 0)
    pub fn set_hspan(&mut self, hspan: usize) {
        self.hspan = if hspan <= 0 {1} else {hspan};
    }

    /// Get horizontal span of this cell (> 0)
    pub fn get_hspan(&self) -> usize {
        self.hspan
    }

    /// Return a copy of the full string contained in the cell
    pub fn get_content(&self) -> String {
        self.content.join("\n")
    }

    /// Print a partial cell to `out`. Since the cell may be multi-lined,
    /// `idx` is the line index to print. `col_width` is the column width used to
    /// fill the cells with blanks so it fits in the table.
    /// If `ìdx` is higher than this cell's height, it will print empty content
    #[deprecated(since="0.8.0", note="Will become private in future release. See [issue #87](https://github.com/phsym/prettytable-rs/issues/87)")]
    pub fn print<T: Write + ?Sized>(
        &self,
        out: &mut T,
        idx: usize,
        col_width: usize,
        skip_right_fill: bool,
    ) -> Result<(), Error> {
        let c = self.content.get(idx).map(|s| s.as_ref()).unwrap_or("");
        print_align(out, self.align, c, ' ', col_width, skip_right_fill)
    }

    /// Apply style then call `print` to print the cell into a terminal
    #[deprecated(since="0.8.0", note="Will become private in future release. See [issue #87](https://github.com/phsym/prettytable-rs/issues/87)")]
    pub fn print_term<T: Terminal + ?Sized>(
        &self,
        out: &mut T,
        idx: usize,
        col_width: usize,
        skip_right_fill: bool,
    ) -> Result<(), Error> {
        for a in &self.style {
            match out.attr(*a) {
                Ok(..) | Err(::term::Error::NotSupported) | Err(::term::Error::ColorOutOfRange) => {
                    ()
                } // Ignore unsupported atrributes
                Err(e) => return Err(term_error_to_io_error(e)),
            };
        }
        self.print(out, idx, col_width, skip_right_fill)?;
        match out.reset() {
            Ok(..) | Err(::term::Error::NotSupported) | Err(::term::Error::ColorOutOfRange) => {
                Ok(())
            }
            Err(e) => Err(term_error_to_io_error(e)),
        }
    }
}

fn term_error_to_io_error(te: ::term::Error) -> Error {
    match te {
        ::term::Error::Io(why) => why,
        _ => Error::new(::std::io::ErrorKind::Other, te),
    }
}

impl<'a, T: ToString> From<&'a T> for Cell {
    fn from(f: &T) -> Cell {
        Cell::new(&f.to_string())
    }
}

impl ToString for Cell {
    fn to_string(&self) -> String {
        self.get_content()
    }
}

impl Default for Cell {
    /// Return a cell initialized with a single empty `String`, with LEFT alignment
    fn default() -> Cell {
        Cell {
            content: vec!["".to_string(); 1],
            width: 0,
            align: Alignment::LEFT,
            style: Vec::new(),
            hspan: 1,
        }
    }
}

/// This macro simplifies `Cell` creation
///
/// Support 2 syntax : With and without style specification.
/// # Syntax
/// ```text
/// cell!(value);
/// ```
/// or
///
/// ```text
/// cell!(spec:value);
/// ```
/// Value must implement the `std::string::ToString` trait
///
/// For details about style specifier syntax, check doc for [`Cell::style_spec`](cell/struct.Cell.html#method.style_spec) method
/// # Example
/// ```
/// # #[macro_use] extern crate prettytable;
/// # fn main() {
/// let cell = cell!("value");
/// // Do something with the cell
/// # drop(cell);
/// // Create a cell with style (Red foreground, Bold, aligned to left);
/// let styled = cell!(Frbl->"value");
/// # drop(styled);
/// # }
/// ```
#[macro_export]
macro_rules! cell {
    () => {
        $crate::cell::Cell::default()
    };
    ($value:expr) => {
        $crate::cell::Cell::new(&$value.to_string())
    };
    ($style:ident -> $value:expr) => {
        cell!($value).style_spec(stringify!($style))
    };
}

#[cfg(test)]
mod tests {
    use cell::Cell;
    use format::Alignment;
    use term::{color, Attr};
    use utils::StringWriter;

    #[test]
    fn get_content() {
        let cell = Cell::new("test");
        assert_eq!(cell.get_content(), "test");
    }

    #[test]
    fn print_ascii() {
        let ascii_cell = Cell::new("hello");
        assert_eq!(ascii_cell.get_width(), 5);

        let mut out = StringWriter::new();
        let _ = ascii_cell.print(&mut out, 0, 10, false);
        assert_eq!(out.as_string(), "hello     ");
    }

    #[test]
    fn print_unicode() {
        let unicode_cell = Cell::new("привет");
        assert_eq!(unicode_cell.get_width(), 6);

        let mut out = StringWriter::new();
        let _ = unicode_cell.print(&mut out, 0, 10, false);
        assert_eq!(out.as_string(), "привет    ");
    }

    #[test]
    fn print_cjk() {
        let unicode_cell = Cell::new("由系统自动更新");
        assert_eq!(unicode_cell.get_width(), 14);
        let mut out = StringWriter::new();
        let _ = unicode_cell.print(&mut out, 0, 20, false);
        assert_eq!(out.as_string(), "由系统自动更新      ");
    }

    #[test]
    fn align_left() {
        let cell = Cell::new_align("test", Alignment::LEFT);
        let mut out = StringWriter::new();
        let _ = cell.print(&mut out, 0, 10, false);
        assert_eq!(out.as_string(), "test      ");
    }

    #[test]
    fn align_center() {
        let cell = Cell::new_align("test", Alignment::CENTER);
        let mut out = StringWriter::new();
        let _ = cell.print(&mut out, 0, 10, false);
        assert_eq!(out.as_string(), "   test   ");
    }

    #[test]
    fn align_right() {
        let cell = Cell::new_align("test", Alignment::RIGHT);
        let mut out = StringWriter::new();
        let _ = cell.print(&mut out, 0, 10, false);
        assert_eq!(out.as_string(), "      test");
    }

    #[test]
    fn style_spec() {
        let mut cell = Cell::new("test").style_spec("FrBBbuic");
        assert_eq!(cell.style.len(), 5);
        assert!(cell.style.contains(&Attr::Underline(true)));
        assert!(cell.style.contains(&Attr::Italic(true)));
        assert!(cell.style.contains(&Attr::Bold));
        assert!(cell.style.contains(&Attr::ForegroundColor(color::RED)));
        assert!(
            cell.style
                .contains(&Attr::BackgroundColor(color::BRIGHT_BLUE))
        );
        assert_eq!(cell.align, Alignment::CENTER);

        cell = cell.style_spec("FDBwr");
        assert_eq!(cell.style.len(), 2);
        assert!(
            cell.style
                .contains(&Attr::ForegroundColor(color::BRIGHT_BLACK))
        );
        assert!(cell.style.contains(&Attr::BackgroundColor(color::WHITE)));
        assert_eq!(cell.align, Alignment::RIGHT);

        // Test with invalid sepcifier chars
        cell = cell.clone();
        cell = cell.style_spec("FzBr");
        assert!(cell.style.contains(&Attr::BackgroundColor(color::RED)));
        assert_eq!(cell.style.len(), 1);
        cell = cell.style_spec("zzz");
        assert!(cell.style.is_empty());
        assert_eq!(cell.get_hspan(), 1);
        cell = cell.style_spec("FDBwH03r");
        assert_eq!(cell.get_hspan(), 3);
    }

    #[test]
    fn reset_style() {
        let mut cell = Cell::new("test")
            .with_style(Attr::ForegroundColor(color::BRIGHT_BLACK))
            .with_style(Attr::BackgroundColor(color::WHITE));
        cell.align(Alignment::RIGHT);

        //style_spec("FDBwr");
        assert_eq!(cell.style.len(), 2);
        assert_eq!(cell.align, Alignment::RIGHT);
        cell.reset_style();
        assert_eq!(cell.style.len(), 0);
        assert_eq!(cell.align, Alignment::LEFT);
    }

    #[test]
    fn default_empty_cell() {
        let cell = Cell::default();
        assert_eq!(cell.align, Alignment::LEFT);
        assert!(cell.style.is_empty());
        assert_eq!(cell.get_content(), "");
        assert_eq!(cell.to_string(), "");
        assert_eq!(cell.get_height(), 1);
        assert_eq!(cell.get_width(), 0);
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use fnv::FnvHashSet;
use graphql_ir::Program;
use graphql_transforms::{
    flatten, generate_id_field, generate_typename, inline_fragments, remove_base_fragments,
    skip_client_extensions, sort_selections,
};
use interner::StringKey;

pub struct Programs<'schema> {
    pub reader: Program<'schema>,
    pub normalization: Program<'schema>,
    pub operation_text: Program<'schema>,
}

pub fn apply_transforms<'schema>(
    program: &Program<'schema>,
    base_fragment_names: &FnvHashSet<StringKey>,
) -> Programs<'schema> {
    // common
    //  |- reader
    //  |- operation
    //     |- normalization
    //     |- operation_text
    let common_program = apply_common_transforms(&program);
    let reader_program = apply_reader_transforms(&common_program, base_fragment_names);
    let operation_program = apply_operation_transforms(&common_program);
    let normalization_program = apply_normalization_transforms(&operation_program);
    let operation_text_program = apply_operation_text_transforms(&operation_program);

    Programs {
        reader: reader_program,
        normalization: normalization_program,
        operation_text: operation_text_program,
    }
}

/// Applies transforms that apply to every output.
fn apply_common_transforms<'schema>(program: &Program<'schema>) -> Program<'schema> {
    // JS compiler
    // - DisallowIdAsAlias
    // - ConnectionTransform
    // - RelayDirectiveTransform
    // - MaskTransform
    // - MatchTransform
    // - RefetchableFragmentTransform
    // - DeferStreamTransform

    // TODO remove this clone once some transform is applied
    program.clone()
}

/// Applies transforms only for generated reader code.
/// Corresponds to the "fragment transforms" in the JS compiler.
fn apply_reader_transforms<'schema>(
    program: &Program<'schema>,
    base_fragment_names: &FnvHashSet<StringKey>,
) -> Program<'schema> {
    // JS compiler
    // - ClientExtensionsTransform
    // - FieldHandleTransform
    // - InlineDataFragmentTransform
    // - FlattenTransform, flattenAbstractTypes: true
    // - SkipRedundantNodesTransform

    let program = remove_base_fragments(&program, base_fragment_names);
    let program = flatten(&program, true);

    sort_selections(&program)
}

/// Applies transforms that apply to all operation artifacts.
/// Corresponds to the "query transforms" in the JS compiler.
fn apply_operation_transforms<'schema>(program: &Program<'schema>) -> Program<'schema> {
    // JS compiler
    // - ValidateUnusedVariablesTransform
    // - ApplyFragmentArgumentTransform
    // - ValidateGlobalVariablesTransform
    // - GenerateIDFieldTransform
    // - TestOperationTransform

    generate_id_field(&program)
}

/// After the operation transforms, this applies further transforms that only
/// apply to the generated normalization code.
///
/// Corresponds to the "codegen transforms" in the JS compiler
fn apply_normalization_transforms<'schema>(program: &Program<'schema>) -> Program<'schema> {
    // JS compiler
    // - SkipUnreachableNodeTransform
    // - SplitModuleImportTransform
    // - InlineFragmentsTransform
    // - ClientExtensionsTransform
    // - FlattenTransform, flattenAbstractTypes: true
    // - SkipRedundantNodesTransform
    // - GenerateTypeNameTransform
    // - ValidateServerOnlyDirectivesTransform

    let program = inline_fragments(&program);
    let program = flatten(&program, true);
    let program = generate_typename(&program);
    sort_selections(&program)
}

/// After the operation transforms, this applies further transforms that only
/// apply to the printed operation text.
///
/// Corresponds to the "print transforms" in the JS compiler
fn apply_operation_text_transforms<'schema>(program: &Program<'schema>) -> Program<'schema> {
    // JS compiler
    // - ClientExtensionsTransform
    // - SkipClientExtensionsTransform
    // - SkipUnreachableNodeTransform
    // - FlattenTransform, flattenAbstractTypes: false
    // - GenerateTypeNameTransform
    // - SkipHandleFieldTransform
    // - FilterDirectivesTransform
    // - SkipUnusedVariablesTransform
    // - ValidateRequiredArgumentsTransform

    let program = skip_client_extensions(&program);
    let program = flatten(&program, false);
    let program = generate_typename(&program);
    sort_selections(&program)
}
<commit_msg>Apply @connection transform to compiler pipeline<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use fnv::FnvHashSet;
use graphql_ir::Program;
use graphql_transforms::{
    flatten, generate_id_field, generate_typename, inline_fragments, remove_base_fragments,
    skip_client_extensions, sort_selections, transform_connections, FBConnectionInterface,
};
use interner::StringKey;

pub struct Programs<'schema> {
    pub reader: Program<'schema>,
    pub normalization: Program<'schema>,
    pub operation_text: Program<'schema>,
}

pub fn apply_transforms<'schema>(
    program: &Program<'schema>,
    base_fragment_names: &FnvHashSet<StringKey>,
) -> Programs<'schema> {
    // common
    //  |- reader
    //  |- operation
    //     |- normalization
    //     |- operation_text
    let common_program = apply_common_transforms(&program);
    let reader_program = apply_reader_transforms(&common_program, base_fragment_names);
    let operation_program = apply_operation_transforms(&common_program);
    let normalization_program = apply_normalization_transforms(&operation_program);
    let operation_text_program = apply_operation_text_transforms(&operation_program);

    Programs {
        reader: reader_program,
        normalization: normalization_program,
        operation_text: operation_text_program,
    }
}

/// Applies transforms that apply to every output.
fn apply_common_transforms<'schema>(program: &Program<'schema>) -> Program<'schema> {
    // JS compiler
    // - DisallowIdAsAlias
    // - ConnectionTransform
    // - RelayDirectiveTransform
    // - MaskTransform
    // - MatchTransform
    // - RefetchableFragmentTransform
    // - DeferStreamTransform

    transform_connections(program, &FBConnectionInterface::default())
}

/// Applies transforms only for generated reader code.
/// Corresponds to the "fragment transforms" in the JS compiler.
fn apply_reader_transforms<'schema>(
    program: &Program<'schema>,
    base_fragment_names: &FnvHashSet<StringKey>,
) -> Program<'schema> {
    // JS compiler
    // - ClientExtensionsTransform
    // - FieldHandleTransform
    // - InlineDataFragmentTransform
    // - FlattenTransform, flattenAbstractTypes: true
    // - SkipRedundantNodesTransform

    let program = remove_base_fragments(&program, base_fragment_names);
    let program = flatten(&program, true);

    sort_selections(&program)
}

/// Applies transforms that apply to all operation artifacts.
/// Corresponds to the "query transforms" in the JS compiler.
fn apply_operation_transforms<'schema>(program: &Program<'schema>) -> Program<'schema> {
    // JS compiler
    // - ValidateUnusedVariablesTransform
    // - ApplyFragmentArgumentTransform
    // - ValidateGlobalVariablesTransform
    // - GenerateIDFieldTransform
    // - TestOperationTransform

    generate_id_field(&program)
}

/// After the operation transforms, this applies further transforms that only
/// apply to the generated normalization code.
///
/// Corresponds to the "codegen transforms" in the JS compiler
fn apply_normalization_transforms<'schema>(program: &Program<'schema>) -> Program<'schema> {
    // JS compiler
    // - SkipUnreachableNodeTransform
    // - SplitModuleImportTransform
    // - InlineFragmentsTransform
    // - ClientExtensionsTransform
    // - FlattenTransform, flattenAbstractTypes: true
    // - SkipRedundantNodesTransform
    // - GenerateTypeNameTransform
    // - ValidateServerOnlyDirectivesTransform

    let program = inline_fragments(&program);
    let program = flatten(&program, true);
    let program = generate_typename(&program);
    sort_selections(&program)
}

/// After the operation transforms, this applies further transforms that only
/// apply to the printed operation text.
///
/// Corresponds to the "print transforms" in the JS compiler
fn apply_operation_text_transforms<'schema>(program: &Program<'schema>) -> Program<'schema> {
    // JS compiler
    // - ClientExtensionsTransform
    // - SkipClientExtensionsTransform
    // - SkipUnreachableNodeTransform
    // - FlattenTransform, flattenAbstractTypes: false
    // - GenerateTypeNameTransform
    // - SkipHandleFieldTransform
    // - FilterDirectivesTransform
    // - SkipUnusedVariablesTransform
    // - ValidateRequiredArgumentsTransform

    let program = skip_client_extensions(&program);
    let program = flatten(&program, false);
    let program = generate_typename(&program);
    sort_selections(&program)
}
<|endoftext|>


<commit_before>use std;
use std::str;
use std::sync::{Arc, Mutex};
use std::time::Duration;

use curl::easy::Easy;
use futures::Future;
use tokio_curl::Session;
use quick_xml::events::BytesStart;
use quick_xml::events::Event as XmlEvent;
use quick_xml::events::attributes::Attributes;
use quick_xml::reader::Reader as XmlReader;

use errors::*;

pub trait FromXml: Sized {
    fn from_xml<B: std::io::BufRead>(reader: &mut XmlReader<B>, start: &BytesStart) -> Result<Self>;
}

fn parse_atom_link<B: std::io::BufRead>(reader: &mut XmlReader<B>, attributes: Attributes) -> Option<String> {
    let mut link_tmp = None;
    let mut is_alternate = true;
    for attribute in attributes {
        match attribute {
            Ok(attribute) => {
                match attribute.key {
                    b"href" => {
                        match attribute.unescape_and_decode_value(reader) {
                            Ok(link) => link_tmp = Some(link),
                            Err(_) => continue,
                        }
                    }
                    b"rel" => {
                        is_alternate = attribute.value == b"alternate";
                    }
                    _ => (),
                }
            }
            Err(_) => continue,
        }
    }
    if is_alternate { link_tmp } else { None }
}

fn skip_element<B: std::io::BufRead>(reader: &mut XmlReader<B>) -> Result<()> {
    let mut buf = Vec::new();
    loop {
        match reader.read_event(&mut buf) {
            Ok(XmlEvent::Start(_)) => {
                skip_element(reader)?;
            }
            Ok(XmlEvent::End(_)) => break,
            Ok(XmlEvent::Eof) => break,
            Err(err) => return Err(err.into()),
            _ => (),
        }
        buf.clear();
    }
    Ok(())
}

impl FromXml for Option<String> {
    fn from_xml<B: std::io::BufRead>(reader: &mut XmlReader<B>, _start: &BytesStart) -> Result<Self> {
        let mut buf = Vec::new();
        let mut content: Option<String> = None;
        loop {
            match reader.read_event(&mut buf) {
                Ok(XmlEvent::Start(_)) => {
                    skip_element(reader)?;
                }
                Ok(XmlEvent::Text(ref e)) => {
                    let text = e.unescape_and_decode(&reader)?;
                    content = Some(text);
                }
                Ok(XmlEvent::CData(ref e)) => {
                    let text = e.unescape_and_decode(&reader)?;
                    content = Some(text);
                }
                Ok(XmlEvent::End(_)) => break,
                Ok(XmlEvent::Eof) => break,
                Err(err) => return Err(err.into()),
                _ => (),
            }
            buf.clear();
        }
        Ok(content)
    }
}

#[derive(Debug, Clone, Default)]
pub struct RSS {
    pub title: String,
    pub link: String,
    pub items: Vec<Item>,
}

impl FromXml for RSS {
    fn from_xml<B: std::io::BufRead>(reader: &mut XmlReader<B>, _start: &BytesStart) -> Result<Self> {
        let mut buf = Vec::new();
        let mut rss = RSS::default();
        loop {
            match reader.read_event(&mut buf) {
                Ok(XmlEvent::Empty(ref e)) => {
                    match e.name() {
                        b"link" => {
                            if let Some(link) = parse_atom_link(reader, e.attributes()) {
                                rss.link = link;
                            }
                        }
                        _ => (),
                    }
                }
                Ok(XmlEvent::Start(ref e)) => {
                    match e.name() {
                        b"title" => {
                            if let Some(title) = Option::from_xml(reader, e)? {
                                rss.title = title;
                            }
                        }
                        b"link" => {
                            if let Some(link) = Option::from_xml(reader, e)? {
                                // RSS
                                rss.link = link;
                            } else {
                                // ATOM
                                if let Some(link) = parse_atom_link(reader, e.attributes()) {
                                    rss.link = link;
                                }
                            }
                        }
                        b"item" | b"entry" => {
                            rss.items.push(Item::from_xml(reader, e)?);
                        }
                        _ => skip_element(reader)?,
                    }
                }
                Ok(XmlEvent::End(_)) => break,
                Ok(XmlEvent::Eof) => break,
                Err(err) => return Err(err.into()),
                _ => (),
            }
            buf.clear();
        }
        Ok(rss)
    }
}

#[derive(Debug, Clone, Default)]
pub struct Item {
    pub title: Option<String>,
    pub link: Option<String>,
    pub id: Option<String>,
}

impl FromXml for Item {
    fn from_xml<B: std::io::BufRead>(reader: &mut XmlReader<B>, _start: &BytesStart) -> Result<Self> {
        let mut buf = Vec::new();
        let mut item = Item::default();
        loop {
            match reader.read_event(&mut buf) {
                Ok(XmlEvent::Empty(ref e)) => {
                    match e.name() {
                        b"link" => {
                            if let Some(link) = parse_atom_link(reader, e.attributes()) {
                                item.link = Some(link);
                            }
                        }
                        _ => (),
                    }
                }
                Ok(XmlEvent::Start(ref e)) => {
                    match e.name() {
                        b"title" => {
                            item.title = Option::from_xml(reader, e)?;
                        }
                        b"link" => {
                            if let Some(link) = Option::from_xml(reader, e)? {
                                // RSS
                                item.link = Some(link);
                            } else {
                                // ATOM
                                if let Some(link) = parse_atom_link(reader, e.attributes()) {
                                    item.link = Some(link);
                                }
                            }
                        }
                        b"id" | b"guid" => {
                            item.id = Option::from_xml(reader, e)?;
                        }
                        _ => skip_element(reader)?,
                    }
                }
                Ok(XmlEvent::End(_)) => break,
                Ok(XmlEvent::Eof) => break,
                Err(err) => return Err(err.into()),
                _ => (),
            }
            buf.clear();
        }
        Ok(item)
    }
}

pub fn parse<B: std::io::BufRead>(reader: B) -> Result<RSS> {
    let mut reader = XmlReader::from_reader(reader);
    reader.trim_text(true);
    let mut buf = Vec::new();
    loop {
        match reader.read_event(&mut buf) {
            Ok(XmlEvent::Start(ref e)) => {
                match e.name() {
                    b"rss" => continue,
                    b"channel" | b"feed" => {
                        return RSS::from_xml(&mut reader, e);
                    }
                    _ => skip_element(&mut reader)?,
                }
            }
            Ok(XmlEvent::Eof) => return Err(ErrorKind::EOF.into()),
            Err(err) => return Err(err.into()),
            _ => (),
        }
        buf.clear();
    }
}

pub fn fetch_feed<'a>(session: &Session, link: &str) -> impl Future<Item = RSS, Error = Error> + 'a {
    let mut req = Easy::new();
    let buf = Arc::new(Mutex::new(Vec::new()));
    {
        let buf = buf.clone();
        req.get(true).unwrap();
        req.url(link).unwrap();
        req.accept_encoding("").unwrap(); // accept all encoding
        req.useragent("RSSBot/1.0 (https://github.com/iovxw/rssbot)").unwrap();
        req.follow_location(true).unwrap();
        req.timeout(Duration::from_secs(10)).unwrap();
        req.write_function(move |data| {
                buf.lock().unwrap().extend_from_slice(data);
                Ok(data.len())
            })
            .unwrap();
    }
    session.perform(req).map_err(|e| e.into()).and_then(move |mut resp| {
        let response_code = resp.response_code().unwrap();
        if response_code != 200 {
            return Err(ErrorKind::Http(response_code).into());
        }
        let buf = buf.lock().unwrap();
        parse(buf.as_slice())
    })
}
<commit_msg>add encodings support<commit_after>use std;
use std::str;
use std::sync::{Arc, Mutex};
use std::time::Duration;

use curl::easy::Easy;
use futures::Future;
use tokio_curl::Session;
use quick_xml::events::BytesStart;
use quick_xml::events::Event as XmlEvent;
use quick_xml::events::attributes::Attributes;
use quick_xml::reader::Reader as XmlReader;

use errors::*;

pub trait FromXml: Sized {
    fn from_xml<B: std::io::BufRead>(reader: &mut XmlReader<B>, start: &BytesStart) -> Result<Self>;
}

fn parse_atom_link<B: std::io::BufRead>(reader: &mut XmlReader<B>, attributes: Attributes) -> Option<String> {
    let mut link_tmp = None;
    let mut is_alternate = true;
    for attribute in attributes {
        match attribute {
            Ok(attribute) => {
                match reader.decode(attribute.key).as_ref() {
                    "href" => {
                        match attribute.unescape_and_decode_value(reader) {
                            Ok(link) => link_tmp = Some(link),
                            Err(_) => continue,
                        }
                    }
                    "rel" => {
                        is_alternate = reader.decode(attribute.value).as_ref() == "alternate";
                    }
                    _ => (),
                }
            }
            Err(_) => continue,
        }
    }
    if is_alternate { link_tmp } else { None }
}

fn skip_element<B: std::io::BufRead>(reader: &mut XmlReader<B>) -> Result<()> {
    let mut buf = Vec::new();
    loop {
        match reader.read_event(&mut buf) {
            Ok(XmlEvent::Start(_)) => {
                skip_element(reader)?;
            }
            Ok(XmlEvent::End(_)) => break,
            Ok(XmlEvent::Eof) => break,
            Err(err) => return Err(err.into()),
            _ => (),
        }
        buf.clear();
    }
    Ok(())
}

impl FromXml for Option<String> {
    fn from_xml<B: std::io::BufRead>(reader: &mut XmlReader<B>, _start: &BytesStart) -> Result<Self> {
        let mut buf = Vec::new();
        let mut content: Option<String> = None;
        loop {
            match reader.read_event(&mut buf) {
                Ok(XmlEvent::Start(_)) => {
                    skip_element(reader)?;
                }
                Ok(XmlEvent::Text(ref e)) => {
                    let text = e.unescape_and_decode(&reader)?;
                    content = Some(text);
                }
                Ok(XmlEvent::CData(ref e)) => {
                    let text = reader.decode(&e).as_ref().to_owned();
                    content = Some(text);
                }
                Ok(XmlEvent::End(_)) => break,
                Ok(XmlEvent::Eof) => break,
                Err(err) => return Err(err.into()),
                _ => (),
            }
            buf.clear();
        }
        Ok(content)
    }
}

#[derive(Debug, Clone, Default)]
pub struct RSS {
    pub title: String,
    pub link: String,
    pub items: Vec<Item>,
}

impl FromXml for RSS {
    fn from_xml<B: std::io::BufRead>(reader: &mut XmlReader<B>, _start: &BytesStart) -> Result<Self> {
        let mut buf = Vec::new();
        let mut rss = RSS::default();
        loop {
            match reader.read_event(&mut buf) {
                Ok(XmlEvent::Empty(ref e)) => {
                    match reader.decode(e.name()).as_ref() {
                        "link" => {
                            if let Some(link) = parse_atom_link(reader, e.attributes()) {
                                rss.link = link;
                            }
                        }
                        _ => (),
                    }
                }
                Ok(XmlEvent::Start(ref e)) => {
                    match reader.decode(e.name()).as_ref() {
                        "title" => {
                            if let Some(title) = Option::from_xml(reader, e)? {
                                rss.title = title;
                            }
                        }
                        "link" => {
                            if let Some(link) = Option::from_xml(reader, e)? {
                                // RSS
                                rss.link = link;
                            } else {
                                // ATOM
                                if let Some(link) = parse_atom_link(reader, e.attributes()) {
                                    rss.link = link;
                                }
                            }
                        }
                        "item" | "entry" => {
                            rss.items.push(Item::from_xml(reader, e)?);
                        }
                        _ => skip_element(reader)?,
                    }
                }
                Ok(XmlEvent::End(_)) => break,
                Ok(XmlEvent::Eof) => break,
                Err(err) => return Err(err.into()),
                _ => (),
            }
            buf.clear();
        }
        Ok(rss)
    }
}

#[derive(Debug, Clone, Default)]
pub struct Item {
    pub title: Option<String>,
    pub link: Option<String>,
    pub id: Option<String>,
}

impl FromXml for Item {
    fn from_xml<B: std::io::BufRead>(reader: &mut XmlReader<B>, _start: &BytesStart) -> Result<Self> {
        let mut buf = Vec::new();
        let mut item = Item::default();
        loop {
            match reader.read_event(&mut buf) {
                Ok(XmlEvent::Empty(ref e)) => {
                    match reader.decode(e.name()).as_ref() {
                        "link" => {
                            if let Some(link) = parse_atom_link(reader, e.attributes()) {
                                item.link = Some(link);
                            }
                        }
                        _ => (),
                    }
                }
                Ok(XmlEvent::Start(ref e)) => {
                    match reader.decode(e.name()).as_ref() {
                        "title" => {
                            item.title = Option::from_xml(reader, e)?;
                        }
                        "link" => {
                            if let Some(link) = Option::from_xml(reader, e)? {
                                // RSS
                                item.link = Some(link);
                            } else {
                                // ATOM
                                if let Some(link) = parse_atom_link(reader, e.attributes()) {
                                    item.link = Some(link);
                                }
                            }
                        }
                        "id" | "guid" => {
                            item.id = Option::from_xml(reader, e)?;
                        }
                        _ => skip_element(reader)?,
                    }
                }
                Ok(XmlEvent::End(_)) => break,
                Ok(XmlEvent::Eof) => break,
                Err(err) => return Err(err.into()),
                _ => (),
            }
            buf.clear();
        }
        Ok(item)
    }
}

pub fn parse<B: std::io::BufRead>(reader: B) -> Result<RSS> {
    let mut reader = XmlReader::from_reader(reader);
    reader.trim_text(true);
    let mut buf = Vec::new();
    loop {
        match reader.read_event(&mut buf) {
            Ok(XmlEvent::Start(ref e)) => {
                match reader.decode(e.name()).as_ref() {
                    "rss" => continue,
                    "channel" | "feed" => {
                        return RSS::from_xml(&mut reader, e);
                    }
                    _ => skip_element(&mut reader)?,
                }
            }
            Ok(XmlEvent::Eof) => return Err(ErrorKind::EOF.into()),
            Err(err) => return Err(err.into()),
            _ => (),
        }
        buf.clear();
    }
}

pub fn fetch_feed<'a>(session: &Session, link: &str) -> impl Future<Item = RSS, Error = Error> + 'a {
    let mut req = Easy::new();
    let buf = Arc::new(Mutex::new(Vec::new()));
    {
        let buf = buf.clone();
        req.get(true).unwrap();
        req.url(link).unwrap();
        req.accept_encoding("").unwrap(); // accept all encoding
        req.useragent("RSSBot/1.0 (https://github.com/iovxw/rssbot)").unwrap();
        req.follow_location(true).unwrap();
        req.timeout(Duration::from_secs(10)).unwrap();
        req.write_function(move |data| {
                buf.lock().unwrap().extend_from_slice(data);
                Ok(data.len())
            })
            .unwrap();
    }
    session.perform(req).map_err(|e| e.into()).and_then(move |mut resp| {
        let response_code = resp.response_code().unwrap();
        if response_code != 200 {
            return Err(ErrorKind::Http(response_code).into());
        }
        let buf = buf.lock().unwrap();
        parse(buf.as_slice())
    })
}
<|endoftext|>


<commit_before>use actor;

static max_players: uint = 30;

pub struct Game{
    pub score: uint,
    pub highscore: uint
}

impl Game{
    pub fn new() -> Game {
        Game {
            score : 0,
            highscore: 0
        }
    }
    pub fn max_players(&self)-> uint{
        max_players + (self.score * 3)
    }

    pub fn restart(&mut self){
        self.score = 0;
    }

    pub fn process_messages(&mut self, messages: &Vec<(&str, actor::ActorView)>){
        for &(msg, ref v) in messages.iter(){
            //println!("{} : {}", msg, v);
            match msg{
                "collect"  => {
                    if v.id == 1 {
                        self.score += 1;
                        if self.highscore < self.score {
                            self.highscore = self.score;
                        }
                    }
                },
                _       => ()
            }
        }
    }
}<commit_msg>reasonable difficulty level<commit_after>use actor;

static max_players: uint = 10;

pub struct Game{
    pub score: uint,
    pub highscore: uint
}

impl Game{
    pub fn new() -> Game {
        Game {
            score : 0,
            highscore: 0
        }
    }
    pub fn max_players(&self)-> uint{
        max_players + (self.score * 3)
    }

    pub fn restart(&mut self){
        self.score = 0;
    }

    pub fn process_messages(&mut self, messages: &Vec<(&str, actor::ActorView)>){
        for &(msg, ref v) in messages.iter(){
            //println!("{} : {}", msg, v);
            match msg{
                "collect"  => {
                    if v.id == 1 {
                        self.score += 1;
                        if self.highscore < self.score {
                            self.highscore = self.score;
                        }
                    }
                },
                _       => ()
            }
        }
    }
}<|endoftext|>