<commit_before>use std::borrow::Cow;
use std::str::FromStr;

use combine::stream::position::Stream;

use crate::encode::{to_string_repr, StringStyle};
use crate::parser;
use crate::parser::is_unquoted_char;
use crate::repr::{Decor, Repr};
use crate::InternalString;

/// Key as part of a Key/Value Pair or a table header.
///
/// # Examples
///
/// ```notrust
/// [dependencies."nom"]
/// version = "5.0"
/// 'literal key' = "nonsense"
/// "basic string key" = 42
/// ```
///
/// There are 3 types of keys:
///
/// 1. Bare keys (`version` and `dependencies`)
///
/// 2. Basic quoted keys (`"basic string key"` and `"nom"`)
///
/// 3. Literal quoted keys (`'literal key'`)
///
/// For details see [toml spec](https://github.com/toml-lang/toml/#keyvalue-pair).
///
/// To parse a key use `FromStr` trait implementation: `"string".parse::<Key>()`.
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Clone)]
pub struct Key {
    key: InternalString,
    pub(crate) repr: Option<Repr>,
    pub(crate) decor: Decor,
}

impl Key {
    /// Create a new table key
    pub fn new(key: impl Into<InternalString>) -> Self {
        Self {
            key: key.into(),
            repr: None,
            decor: Default::default(),
        }
    }

    pub(crate) fn with_repr_unchecked(mut self, repr: Repr) -> Self {
        self.repr = Some(repr);
        self
    }

    /// While creating the `Key`, add `Decor` to it
    pub fn with_decor(mut self, decor: Decor) -> Self {
        self.decor = decor;
        self
    }

    /// Returns the parsed key value.
    pub fn get(&self) -> &str {
        &self.key
    }

    pub(crate) fn get_internal(&self) -> &InternalString {
        &self.key
    }

    /// Returns the key raw representation.
    pub fn to_repr(&self) -> Cow<Repr> {
        self.repr
            .as_ref()
            .map(Cow::Borrowed)
            .unwrap_or_else(|| Cow::Owned(to_key_repr(&self.key)))
    }

    /// Returns the surrounding whitespace
    pub fn decor_mut(&mut self) -> &mut Decor {
        &mut self.decor
    }

    /// Returns the surrounding whitespace
    pub fn decor(&self) -> &Decor {
        &self.decor
    }

    /// Auto formats the key.
    pub fn fmt(&mut self) {
        self.repr = Some(to_key_repr(&self.key));
    }

    fn try_parse(s: &str) -> Result<Key, parser::TomlError> {
        use combine::stream::position::{IndexPositioner, Positioner};
        use combine::EasyParser;

        let b = s.as_bytes();
        let result = parser::key_parser().easy_parse(Stream::new(b));
        match result {
            Ok((_, ref rest)) if !rest.input.is_empty() => Err(parser::TomlError::from_unparsed(
                (&rest.positioner
                    as &dyn Positioner<usize, Position = usize, Checkpoint = IndexPositioner>)
                    .position(),
                b,
            )),
            Ok(((raw, key), _)) => Ok(Key::new(key).with_repr_unchecked(Repr::new_unchecked(raw))),
            Err(e) => Err(parser::TomlError::new(e, b)),
        }
    }
}

impl std::fmt::Display for Key {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        crate::encode::Encode::encode(self, f, ("", ""))
    }
}

impl FromStr for Key {
    type Err = parser::TomlError;

    /// Tries to parse a key from a &str,
    /// if fails, tries as basic quoted key (surrounds with "")
    /// and then literal quoted key (surrounds with '')
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let basic = format!("\"{}\"", s);
        let literal = format!("'{}'", s);
        Key::try_parse(s)
            .or_else(|_| Key::try_parse(&basic))
            .or_else(|_| Key::try_parse(&literal))
    }
}

fn to_key_repr(key: &str) -> Repr {
    if key.as_bytes().iter().copied().all(is_unquoted_char) && !key.is_empty() {
        Repr::new_unchecked(key)
    } else {
        to_string_repr(key, Some(StringStyle::OnelineSingle), Some(false))
    }
}

impl<'b> From<&'b str> for Key {
    fn from(s: &'b str) -> Self {
        Key::new(s)
    }
}

impl<'b> From<&'b String> for Key {
    fn from(s: &'b String) -> Self {
        Key::new(s)
    }
}

impl From<String> for Key {
    fn from(s: String) -> Self {
        Key::new(s)
    }
}

impl From<InternalString> for Key {
    fn from(s: InternalString) -> Self {
        Key::new(s)
    }
}

#[doc(hidden)]
impl From<Key> for InternalString {
    fn from(key: Key) -> InternalString {
        key.key
    }
}
<commit_msg>fix: Key::fmt also resets decor<commit_after>use std::borrow::Cow;
use std::str::FromStr;

use combine::stream::position::Stream;

use crate::encode::{to_string_repr, StringStyle};
use crate::parser;
use crate::parser::is_unquoted_char;
use crate::repr::{Decor, Repr};
use crate::InternalString;

/// Key as part of a Key/Value Pair or a table header.
///
/// # Examples
///
/// ```notrust
/// [dependencies."nom"]
/// version = "5.0"
/// 'literal key' = "nonsense"
/// "basic string key" = 42
/// ```
///
/// There are 3 types of keys:
///
/// 1. Bare keys (`version` and `dependencies`)
///
/// 2. Basic quoted keys (`"basic string key"` and `"nom"`)
///
/// 3. Literal quoted keys (`'literal key'`)
///
/// For details see [toml spec](https://github.com/toml-lang/toml/#keyvalue-pair).
///
/// To parse a key use `FromStr` trait implementation: `"string".parse::<Key>()`.
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Clone)]
pub struct Key {
    key: InternalString,
    pub(crate) repr: Option<Repr>,
    pub(crate) decor: Decor,
}

impl Key {
    /// Create a new table key
    pub fn new(key: impl Into<InternalString>) -> Self {
        Self {
            key: key.into(),
            repr: None,
            decor: Default::default(),
        }
    }

    pub(crate) fn with_repr_unchecked(mut self, repr: Repr) -> Self {
        self.repr = Some(repr);
        self
    }

    /// While creating the `Key`, add `Decor` to it
    pub fn with_decor(mut self, decor: Decor) -> Self {
        self.decor = decor;
        self
    }

    /// Returns the parsed key value.
    pub fn get(&self) -> &str {
        &self.key
    }

    pub(crate) fn get_internal(&self) -> &InternalString {
        &self.key
    }

    /// Returns the key raw representation.
    pub fn to_repr(&self) -> Cow<Repr> {
        self.repr
            .as_ref()
            .map(Cow::Borrowed)
            .unwrap_or_else(|| Cow::Owned(to_key_repr(&self.key)))
    }

    /// Returns the surrounding whitespace
    pub fn decor_mut(&mut self) -> &mut Decor {
        &mut self.decor
    }

    /// Returns the surrounding whitespace
    pub fn decor(&self) -> &Decor {
        &self.decor
    }

    /// Auto formats the key.
    pub fn fmt(&mut self) {
        self.repr = Some(to_key_repr(&self.key));
        self.decor.clear();
    }

    fn try_parse(s: &str) -> Result<Key, parser::TomlError> {
        use combine::stream::position::{IndexPositioner, Positioner};
        use combine::EasyParser;

        let b = s.as_bytes();
        let result = parser::key_parser().easy_parse(Stream::new(b));
        match result {
            Ok((_, ref rest)) if !rest.input.is_empty() => Err(parser::TomlError::from_unparsed(
                (&rest.positioner
                    as &dyn Positioner<usize, Position = usize, Checkpoint = IndexPositioner>)
                    .position(),
                b,
            )),
            Ok(((raw, key), _)) => Ok(Key::new(key).with_repr_unchecked(Repr::new_unchecked(raw))),
            Err(e) => Err(parser::TomlError::new(e, b)),
        }
    }
}

impl std::fmt::Display for Key {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        crate::encode::Encode::encode(self, f, ("", ""))
    }
}

impl FromStr for Key {
    type Err = parser::TomlError;

    /// Tries to parse a key from a &str,
    /// if fails, tries as basic quoted key (surrounds with "")
    /// and then literal quoted key (surrounds with '')
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let basic = format!("\"{}\"", s);
        let literal = format!("'{}'", s);
        Key::try_parse(s)
            .or_else(|_| Key::try_parse(&basic))
            .or_else(|_| Key::try_parse(&literal))
    }
}

fn to_key_repr(key: &str) -> Repr {
    if key.as_bytes().iter().copied().all(is_unquoted_char) && !key.is_empty() {
        Repr::new_unchecked(key)
    } else {
        to_string_repr(key, Some(StringStyle::OnelineSingle), Some(false))
    }
}

impl<'b> From<&'b str> for Key {
    fn from(s: &'b str) -> Self {
        Key::new(s)
    }
}

impl<'b> From<&'b String> for Key {
    fn from(s: &'b String) -> Self {
        Key::new(s)
    }
}

impl From<String> for Key {
    fn from(s: String) -> Self {
        Key::new(s)
    }
}

impl From<InternalString> for Key {
    fn from(s: InternalString) -> Self {
        Key::new(s)
    }
}

#[doc(hidden)]
impl From<Key> for InternalString {
    fn from(key: Key) -> InternalString {
        key.key
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]
#![feature(unsafe_destructor)]
#![unstable]
#![allow(unstable)]

//! A library for setting current values for stack scope,
//! such as application structure.

use std::cell::RefCell;
use std::intrinsics::TypeId;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{ Occupied, Vacant };
use std::ops::{ Deref, DerefMut };

// Stores the current pointers for concrete types.
thread_local!(static KEY_CURRENT: RefCell<HashMap<TypeId, usize>>
    = RefCell::new(HashMap::new()));

/// Puts back the previous current pointer.
#[unstable]
pub struct CurrentGuard<'a, T: 'a> {
    _val: &'a mut T,
    old_ptr: Option<usize>
}

#[unstable]
impl<'a, T: 'static> CurrentGuard<'a, T> {
    /// Creates a new current guard.
    #[unstable]
    pub fn new(val: &mut T) -> CurrentGuard<T> {
        let id = TypeId::of::<T>();
        let ptr = val as *mut T as usize;
        let old_ptr = KEY_CURRENT.with(|current| {
            match current.borrow_mut().entry(id) {
                Occupied(mut entry) => Some(entry.insert(ptr)),
                Vacant(entry) => {
                    entry.insert(ptr);
                    None
                }
            }
        });
        CurrentGuard { old_ptr: old_ptr, _val: val }
    }
}

#[unsafe_destructor]
impl<'a, T: 'static> Drop for CurrentGuard<'a, T> {
    fn drop(&mut self) {
        let id = TypeId::of::<T>();
        match self.old_ptr {
            None => {
                KEY_CURRENT.with(|current| {
                    current.borrow_mut().remove(&id);
                });
                return;
            }
            Some(old_ptr) => {
                KEY_CURRENT.with(|current| {
                    match current.borrow_mut().entry(id) {
                        Occupied(mut entry) => { entry.insert(old_ptr); }
                        Vacant(entry) => { entry.insert(old_ptr); }
                    };
                });
            }
        };
    }
}

/// The current value of a type.
#[unstable]
pub struct Current<T>(());

#[unstable]
impl<T: 'static> Current<T> {
    /// Creates a new current object
    #[unstable]
    pub unsafe fn new() -> Current<T> { Current(()) }

    /// Gets mutable reference to current object.
    /// Requires mutable reference to prevent access to globals in safe code,
    /// and to prevent mutable borrows of same value in scope.
    /// Is unsafe because returned reference inherits lifetime from argument.
    #[unstable]
    pub unsafe fn current(&mut self) -> Option<&mut T> {
        use std::mem::transmute;
        let id = TypeId::of::<T>();
        let ptr: Option<usize> = KEY_CURRENT.with(|current| {
                current.borrow().get(&id).map(|id| *id)
            });
        let ptr = match ptr { None => { return None; } Some(x) => x };
        Some(transmute(ptr as *mut T))
    }

    /// Unwraps mutable reference to current object,
    /// but with nicer error message.
    #[unstable]
    pub unsafe fn current_unwrap(&mut self) -> &mut T {
        match self.current() {
            None => {
                use std::intrinsics::get_tydesc;
                let name = (*get_tydesc::<T>()).name;
                panic!("No current `{}` is set", name);
            }
            Some(x) => x
        }
    }
}

impl<T: 'static> Deref for Current<T> {
    type Target = T;

    #[inline(always)]
    fn deref<'a>(&'a self) -> &'a T {
        use std::mem::transmute;
        unsafe {
            // Current does not contain anything,
            // so it is safe to transmute to mutable.
            transmute::<_, &'a mut Current<T>>(self).current_unwrap()
        }
    }
}

impl<T: 'static> DerefMut for Current<T> {
    #[inline(always)]
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        unsafe { self.current_unwrap() }
    }
}
<commit_msg>Update to latest Rust.<commit_after>#![deny(missing_docs)]
#![feature(unsafe_destructor)]
#![unstable]
#![allow(unstable)]

//! A library for setting current values for stack scope,
//! such as application structure.

use std::cell::RefCell;
use std::any::TypeId;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{ Occupied, Vacant };
use std::ops::{ Deref, DerefMut };

// Stores the current pointers for concrete types.
thread_local!(static KEY_CURRENT: RefCell<HashMap<TypeId, usize>>
    = RefCell::new(HashMap::new()));

/// Puts back the previous current pointer.
#[unstable]
pub struct CurrentGuard<'a, T: 'a> {
    _val: &'a mut T,
    old_ptr: Option<usize>
}

#[unstable]
impl<'a, T: 'static> CurrentGuard<'a, T> {
    /// Creates a new current guard.
    #[unstable]
    pub fn new(val: &mut T) -> CurrentGuard<T> {
        let id = TypeId::of::<T>();
        let ptr = val as *mut T as usize;
        let old_ptr = KEY_CURRENT.with(|current| {
            match current.borrow_mut().entry(id) {
                Occupied(mut entry) => Some(entry.insert(ptr)),
                Vacant(entry) => {
                    entry.insert(ptr);
                    None
                }
            }
        });
        CurrentGuard { old_ptr: old_ptr, _val: val }
    }
}

#[unsafe_destructor]
impl<'a, T: 'static> Drop for CurrentGuard<'a, T> {
    fn drop(&mut self) {
        let id = TypeId::of::<T>();
        match self.old_ptr {
            None => {
                KEY_CURRENT.with(|current| {
                    current.borrow_mut().remove(&id);
                });
                return;
            }
            Some(old_ptr) => {
                KEY_CURRENT.with(|current| {
                    match current.borrow_mut().entry(id) {
                        Occupied(mut entry) => { entry.insert(old_ptr); }
                        Vacant(entry) => { entry.insert(old_ptr); }
                    };
                });
            }
        };
    }
}

/// The current value of a type.
#[unstable]
pub struct Current<T>(());

#[unstable]
impl<T: 'static> Current<T> {
    /// Creates a new current object
    #[unstable]
    pub unsafe fn new() -> Current<T> { Current(()) }

    /// Gets mutable reference to current object.
    /// Requires mutable reference to prevent access to globals in safe code,
    /// and to prevent mutable borrows of same value in scope.
    /// Is unsafe because returned reference inherits lifetime from argument.
    #[unstable]
    pub unsafe fn current(&mut self) -> Option<&mut T> {
        use std::mem::transmute;
        let id = TypeId::of::<T>();
        let ptr: Option<usize> = KEY_CURRENT.with(|current| {
                current.borrow().get(&id).map(|id| *id)
            });
        let ptr = match ptr { None => { return None; } Some(x) => x };
        Some(transmute(ptr as *mut T))
    }

    /// Unwraps mutable reference to current object,
    /// but with nicer error message.
    #[unstable]
    pub unsafe fn current_unwrap(&mut self) -> &mut T {
        match self.current() {
            None => {
                use std::intrinsics::get_tydesc;
                let name = (*get_tydesc::<T>()).name;
                panic!("No current `{}` is set", name);
            }
            Some(x) => x
        }
    }
}

impl<T: 'static> Deref for Current<T> {
    type Target = T;

    #[inline(always)]
    fn deref<'a>(&'a self) -> &'a T {
        use std::mem::transmute;
        unsafe {
            // Current does not contain anything,
            // so it is safe to transmute to mutable.
            transmute::<_, &'a mut Current<T>>(self).current_unwrap()
        }
    }
}

impl<T: 'static> DerefMut for Current<T> {
    #[inline(always)]
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        unsafe { self.current_unwrap() }
    }
}
<|endoftext|>


<commit_before>//! Openapi provides structures and support for serializing and deserializing [openapi](https://github.com/OAI/OpenAPI-Specification) specifications
//!
//! # Examples
//!
//! Typical use deserialing an existing to a persisted spec to rust form or
//! visa versa
//!
//! The hyper client should be configured with tls.
//!
//! ```no_run
//! extern crate openapi;
//!
//! fn main() {
//!   match openapi::from_path("path/to/openapi.yaml") {
//!     Ok(spec) => println!("spec: {:?}", spec),
//!     Err(err) => println!("error: {}", err)
//!   }
//! }
//! ```
//!
//! # Errors
//!
//! Operations typically result in a `openapi::Result` Type which is an alias
//! for Rust's
//! built-in Result with the Err Type fixed to the
//! [openapi::errors::Error](errors/struct.Error.html) enum type. These are
//! provided
//! using [error_chain](https://github.com/brson/error-chain) crate so their
//! shape and behavior should be consistent and familiar to existing
//! error_chain users.
//!
use serde::{Deserialize, Serialize};
use std::{fs::File, io::Read, path::Path, result::Result as StdResult};

pub mod error;
pub mod v2;
pub mod v3_0;

pub use error::Error;

const MINIMUM_OPENAPI30_VERSION: &str = ">= 3.0";

pub type Result<T> = StdResult<T, Error>;

/// Supported versions of the OpenApi.
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[serde(untagged)]
pub enum OpenApi {
    /// Version 2.0 of the OpenApi specification.
    ///
    /// Refer to the official
    /// [specification](https://github.com/OAI/OpenAPI-Specification/blob/0dd79f6/versions/2.0.md)
    /// for more information.
    V2(v2::Spec),

    /// Version 3.0.1 of the OpenApi specification.
    ///
    /// Refer to the official
    /// [specification](https://github.com/OAI/OpenAPI-Specification/blob/0dd79f6/versions/3.0.1.md)
    /// for more information.
    #[allow(non_camel_case_types)]
    V3_0(v3_0::Spec),
}

/// deserialize an open api spec from a path
pub fn from_path<P>(path: P) -> Result<OpenApi>
where
    P: AsRef<Path>,
{
    from_reader(File::open(path)?)
}

/// deserialize an open api spec from type which implements Read
pub fn from_reader<R>(read: R) -> Result<OpenApi>
where
    R: Read,
{
    Ok(serde_yaml::from_reader::<R, OpenApi>(read)?)
}

/// serialize to a yaml string
pub fn to_yaml(spec: &OpenApi) -> Result<String> {
    Ok(serde_yaml::to_string(spec)?)
}

/// serialize to a json string
pub fn to_json(spec: &OpenApi) -> Result<String> {
    Ok(serde_json::to_string_pretty(spec)?)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::{
        fs::{self, File},
        io::Write,
    };

    /// Helper function for reading a file to string.
    fn read_file<P>(path: P) -> String
    where
        P: AsRef<Path>,
    {
        let mut f = File::open(path).unwrap();
        let mut content = String::new();
        f.read_to_string(&mut content).unwrap();
        content
    }

    /// Helper function to write string to file.
    fn write_to_file<P>(
        path: P,
        filename: &str,
        data: &str,
    ) where
        P: AsRef<Path> + std::fmt::Debug,
    {
        println!("    Saving string to {:?}...", path);
        std::fs::create_dir_all(&path).unwrap();
        let full_filename = path.as_ref().to_path_buf().join(filename);
        let mut f = File::create(&full_filename).unwrap();
        f.write_all(data.as_bytes()).unwrap();
    }

    /// Convert a YAML `&str` to a JSON `String`.
    fn convert_yaml_str_to_json(yaml_str: &str) -> String {
        let yaml: serde_yaml::Value = serde_yaml::from_str(yaml_str).unwrap();
        let json: serde_json::Value = serde_yaml::from_value(yaml).unwrap();
        serde_json::to_string_pretty(&json).unwrap()
    }

    /// Deserialize and re-serialize the input file to a JSON string through two different
    /// paths, comparing the result.
    /// 1. File -> `String` -> `serde_yaml::Value` -> `serde_json::Value` -> `String`
    /// 2. File -> `Spec` -> `serde_json::Value` -> `String`
    /// Both conversion of `serde_json::Value` -> `String` are done
    /// using `serde_json::to_string_pretty`.
    /// Since the first conversion is independant of the current crate (and only
    /// uses serde's json and yaml support), no information should be lost in the final
    /// JSON string. The second conversion goes through our `OpenApi`, so the final JSON
    /// string is a representation of _our_ implementation.
    /// By comparing those two JSON conversions, we can validate our implementation.
    fn compare_spec_through_json(
        input_file: &Path,
        save_path_base: &Path,
    ) -> (String, String, String) {
        // First conversion:
        //     File -> `String` -> `serde_yaml::Value` -> `serde_json::Value` -> `String`

        // Read the original file to string
        let spec_yaml_str = read_file(&input_file);
        // Convert YAML string to JSON string
        let spec_json_str = convert_yaml_str_to_json(&spec_yaml_str);

        // Second conversion:
        //     File -> `Spec` -> `serde_json::Value` -> `String`

        // Parse the input file
        let parsed_spec = from_path(&input_file).unwrap();
        // Convert to serde_json::Value
        let parsed_spec_json: serde_json::Value = serde_json::to_value(parsed_spec).unwrap();
        // Convert to a JSON string
        let parsed_spec_json_str: String = serde_json::to_string_pretty(&parsed_spec_json).unwrap();

        // Save JSON strings to file
        let api_filename = input_file
            .file_name()
            .unwrap()
            .to_str()
            .unwrap()
            .replace(".yaml", ".json");

        let mut save_path = save_path_base.to_path_buf();
        save_path.push("yaml_to_json");
        write_to_file(&save_path, &api_filename, &spec_json_str);

        let mut save_path = save_path_base.to_path_buf();
        save_path.push("yaml_to_spec_to_json");
        write_to_file(&save_path, &api_filename, &parsed_spec_json_str);

        // Return the JSON filename and the two JSON strings
        (api_filename, parsed_spec_json_str, spec_json_str)
    }

    // Just tests if the deserialization does not blow up. But does not test correctness
    #[test]
    fn can_deserialize() {
        for entry in fs::read_dir("data/v2").unwrap() {
            let entry = entry.unwrap();
            let path = entry.path();
            // cargo test -- --nocapture to see this message
            println!("Testing if {:?} is deserializable", path);
            from_path(path).unwrap();
        }
    }

    #[test]
    fn can_deserialize_and_reserialize_v2() {
        let save_path_base: std::path::PathBuf =
            ["target", "tests", "can_deserialize_and_reserialize_v2"]
                .iter()
                .collect();
        let mut invalid_diffs = Vec::new();

        for entry in fs::read_dir("data/v2").unwrap() {
            let entry = entry.unwrap();
            let path = entry.path();

            println!("Testing if {:?} is deserializable", path);

            let (api_filename, parsed_spec_json_str, spec_json_str) =
                compare_spec_through_json(&path, &save_path_base);

            if parsed_spec_json_str != spec_json_str {
                invalid_diffs.push((api_filename, parsed_spec_json_str, spec_json_str));
            }
        }

        for invalid_diff in &invalid_diffs {
            println!("File {} failed JSON comparison!", invalid_diff.0);
        }
        assert!(invalid_diffs.len() == 0);
    }

    #[test]
    fn can_deserialize_and_reserialize_v3() {
        let save_path_base: std::path::PathBuf =
            ["target", "tests", "can_deserialize_and_reserialize_v3"]
                .iter()
                .collect();
        let mut invalid_diffs = Vec::new();

        for entry in fs::read_dir("data/v3.0").unwrap() {
            let entry = entry.unwrap();
            let path = entry.path();

            println!("Testing if {:?} is deserializable", path);

            let (api_filename, parsed_spec_json_str, spec_json_str) =
                compare_spec_through_json(&path, &save_path_base);

            if parsed_spec_json_str != spec_json_str {
                invalid_diffs.push((api_filename, parsed_spec_json_str, spec_json_str));
            }
        }

        for invalid_diff in &invalid_diffs {
            println!("File {} failed JSON comparison!", invalid_diff.0);
        }
        assert!(invalid_diffs.len() == 0);
    }
}
<commit_msg>remove helper method with stdlib method<commit_after>//! Openapi provides structures and support for serializing and deserializing [openapi](https://github.com/OAI/OpenAPI-Specification) specifications
//!
//! # Examples
//!
//! Typical use deserialing an existing to a persisted spec to rust form or
//! visa versa
//!
//! The hyper client should be configured with tls.
//!
//! ```no_run
//! extern crate openapi;
//!
//! fn main() {
//!   match openapi::from_path("path/to/openapi.yaml") {
//!     Ok(spec) => println!("spec: {:?}", spec),
//!     Err(err) => println!("error: {}", err)
//!   }
//! }
//! ```
//!
//! # Errors
//!
//! Operations typically result in a `openapi::Result` Type which is an alias
//! for Rust's
//! built-in Result with the Err Type fixed to the
//! [openapi::errors::Error](errors/struct.Error.html) enum type. These are
//! provided
//! using [error_chain](https://github.com/brson/error-chain) crate so their
//! shape and behavior should be consistent and familiar to existing
//! error_chain users.
//!
use serde::{Deserialize, Serialize};
use std::{fs::File, io::Read, path::Path, result::Result as StdResult};

pub mod error;
pub mod v2;
pub mod v3_0;

pub use error::Error;

const MINIMUM_OPENAPI30_VERSION: &str = ">= 3.0";

pub type Result<T> = StdResult<T, Error>;

/// Supported versions of the OpenApi.
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[serde(untagged)]
pub enum OpenApi {
    /// Version 2.0 of the OpenApi specification.
    ///
    /// Refer to the official
    /// [specification](https://github.com/OAI/OpenAPI-Specification/blob/0dd79f6/versions/2.0.md)
    /// for more information.
    V2(v2::Spec),

    /// Version 3.0.1 of the OpenApi specification.
    ///
    /// Refer to the official
    /// [specification](https://github.com/OAI/OpenAPI-Specification/blob/0dd79f6/versions/3.0.1.md)
    /// for more information.
    #[allow(non_camel_case_types)]
    V3_0(v3_0::Spec),
}

/// deserialize an open api spec from a path
pub fn from_path<P>(path: P) -> Result<OpenApi>
where
    P: AsRef<Path>,
{
    from_reader(File::open(path)?)
}

/// deserialize an open api spec from type which implements Read
pub fn from_reader<R>(read: R) -> Result<OpenApi>
where
    R: Read,
{
    Ok(serde_yaml::from_reader::<R, OpenApi>(read)?)
}

/// serialize to a yaml string
pub fn to_yaml(spec: &OpenApi) -> Result<String> {
    Ok(serde_yaml::to_string(spec)?)
}

/// serialize to a json string
pub fn to_json(spec: &OpenApi) -> Result<String> {
    Ok(serde_json::to_string_pretty(spec)?)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::{
        fs::{self, read_to_string, File},
        io::Write,
    };

    /// Helper function to write string to file.
    fn write_to_file<P>(
        path: P,
        filename: &str,
        data: &str,
    ) where
        P: AsRef<Path> + std::fmt::Debug,
    {
        println!("    Saving string to {:?}...", path);
        std::fs::create_dir_all(&path).unwrap();
        let full_filename = path.as_ref().to_path_buf().join(filename);
        let mut f = File::create(&full_filename).unwrap();
        f.write_all(data.as_bytes()).unwrap();
    }

    /// Convert a YAML `&str` to a JSON `String`.
    fn convert_yaml_str_to_json(yaml_str: &str) -> String {
        let yaml: serde_yaml::Value = serde_yaml::from_str(yaml_str).unwrap();
        let json: serde_json::Value = serde_yaml::from_value(yaml).unwrap();
        serde_json::to_string_pretty(&json).unwrap()
    }

    /// Deserialize and re-serialize the input file to a JSON string through two different
    /// paths, comparing the result.
    /// 1. File -> `String` -> `serde_yaml::Value` -> `serde_json::Value` -> `String`
    /// 2. File -> `Spec` -> `serde_json::Value` -> `String`
    /// Both conversion of `serde_json::Value` -> `String` are done
    /// using `serde_json::to_string_pretty`.
    /// Since the first conversion is independant of the current crate (and only
    /// uses serde's json and yaml support), no information should be lost in the final
    /// JSON string. The second conversion goes through our `OpenApi`, so the final JSON
    /// string is a representation of _our_ implementation.
    /// By comparing those two JSON conversions, we can validate our implementation.
    fn compare_spec_through_json(
        input_file: &Path,
        save_path_base: &Path,
    ) -> (String, String, String) {
        // First conversion:
        //     File -> `String` -> `serde_yaml::Value` -> `serde_json::Value` -> `String`

        // Read the original file to string
        let spec_yaml_str = read_to_string(&input_file).expect(&format!("failed to read contents of {:?}", input_file));
        // Convert YAML string to JSON string
        let spec_json_str = convert_yaml_str_to_json(&spec_yaml_str);

        // Second conversion:
        //     File -> `Spec` -> `serde_json::Value` -> `String`

        // Parse the input file
        let parsed_spec = from_path(&input_file).unwrap();
        // Convert to serde_json::Value
        let parsed_spec_json: serde_json::Value = serde_json::to_value(parsed_spec).unwrap();
        // Convert to a JSON string
        let parsed_spec_json_str: String = serde_json::to_string_pretty(&parsed_spec_json).unwrap();

        // Save JSON strings to file
        let api_filename = input_file
            .file_name()
            .unwrap()
            .to_str()
            .unwrap()
            .replace(".yaml", ".json");

        let mut save_path = save_path_base.to_path_buf();
        save_path.push("yaml_to_json");
        write_to_file(&save_path, &api_filename, &spec_json_str);

        let mut save_path = save_path_base.to_path_buf();
        save_path.push("yaml_to_spec_to_json");
        write_to_file(&save_path, &api_filename, &parsed_spec_json_str);

        // Return the JSON filename and the two JSON strings
        (api_filename, parsed_spec_json_str, spec_json_str)
    }

    // Just tests if the deserialization does not blow up. But does not test correctness
    #[test]
    fn can_deserialize() {
        for entry in fs::read_dir("data/v2").unwrap() {
            let entry = entry.unwrap();
            let path = entry.path();
            // cargo test -- --nocapture to see this message
            println!("Testing if {:?} is deserializable", path);
            from_path(path).unwrap();
        }
    }

    #[test]
    fn can_deserialize_and_reserialize_v2() {
        let save_path_base: std::path::PathBuf =
            ["target", "tests", "can_deserialize_and_reserialize_v2"]
                .iter()
                .collect();
        let mut invalid_diffs = Vec::new();

        for entry in fs::read_dir("data/v2").unwrap() {
            let entry = entry.unwrap();
            let path = entry.path();

            println!("Testing if {:?} is deserializable", path);

            let (api_filename, parsed_spec_json_str, spec_json_str) =
                compare_spec_through_json(&path, &save_path_base);

            if parsed_spec_json_str != spec_json_str {
                invalid_diffs.push((api_filename, parsed_spec_json_str, spec_json_str));
            }
        }

        for invalid_diff in &invalid_diffs {
            println!("File {} failed JSON comparison!", invalid_diff.0);
        }
        assert!(invalid_diffs.len() == 0);
    }

    #[test]
    fn can_deserialize_and_reserialize_v3() {
        let save_path_base: std::path::PathBuf =
            ["target", "tests", "can_deserialize_and_reserialize_v3"]
                .iter()
                .collect();
        let mut invalid_diffs = Vec::new();

        for entry in fs::read_dir("data/v3.0").unwrap() {
            let entry = entry.unwrap();
            let path = entry.path();

            println!("Testing if {:?} is deserializable", path);

            let (api_filename, parsed_spec_json_str, spec_json_str) =
                compare_spec_through_json(&path, &save_path_base);

            if parsed_spec_json_str != spec_json_str {
                invalid_diffs.push((api_filename, parsed_spec_json_str, spec_json_str));
            }
        }

        for invalid_diff in &invalid_diffs {
            println!("File {} failed JSON comparison!", invalid_diff.0);
        }
        assert!(invalid_diffs.len() == 0);
    }
}
<|endoftext|>


<commit_before>#![feature(try_trait)]

extern crate pgn_reader;
extern crate memmap;
extern crate madvise;
extern crate btoi;
extern crate rand;
extern crate reqwest;

use std::env;
use std::mem;
use std::str;
use std::cmp::min;
use std::fs::File;
use std::option::NoneError;
use std::io::Read;

use memmap::Mmap;
use madvise::{AccessPattern, AdviseMemory};
use pgn_reader::{Visitor, Skip, Reader, San};
use btoi::ParseIntegerError;
use rand::{thread_rng, Rng};
use rand::distributions::OpenClosed01;

const BATCH_SIZE: usize = 50;

const MAX_PLIES: usize = 50;

#[derive(Debug)]
enum TimeControl {
    UltraBullet,
    Bullet,
    Blitz,
    Rapid,
    Classical,
    Correspondence,
}

#[derive(Debug)]
struct TimeControlError;

impl From<NoneError> for TimeControlError {
    fn from(_: NoneError) -> TimeControlError {
        TimeControlError { }
    }
}

impl From<ParseIntegerError> for TimeControlError {
    fn from(_: ParseIntegerError) -> TimeControlError {
        TimeControlError { }
    }
}

impl TimeControl {
    fn from_seconds_and_increment(seconds: u64, increment: u64) -> TimeControl {
        let total = seconds + 40 * increment;

        if total < 30 {
            TimeControl::UltraBullet
        } else if total < 180 {
            TimeControl::Bullet
        } else if total < 480 {
            TimeControl::Blitz
        } else if total < 1500 {
            TimeControl::Rapid
        } else if total < 21_600 {
            TimeControl::Classical
        } else {
            TimeControl::Correspondence
        }
    }

    fn from_bytes(bytes: &[u8]) -> Result<TimeControl, TimeControlError> {
        if bytes == b"-" {
            return Ok(TimeControl::Correspondence);
        }

        let mut parts = bytes.splitn(2, |ch| *ch == b'+');
        let seconds = btoi::btou(parts.next()?)?;
        let increment = btoi::btou(parts.next()?)?;
        Ok(TimeControl::from_seconds_and_increment(seconds, increment))
    }
}

struct Indexer<'pgn> {
    filename: String,
    date: &'pgn [u8],

    white_elo: i16,
    black_elo: i16,
    time_control: TimeControl,
    skip: bool,

    current_game: Vec<u8>,
    plies: usize,
    standard: bool,

    batch: Vec<u8>,
    batch_size: usize,
}

impl<'pgn> Indexer<'pgn> {
    fn new(filename: &str) -> Indexer {
        Indexer {
            filename: filename.into(),
            date: b"0000.00.00",

            white_elo: 0,
            black_elo: 0,
            time_control: TimeControl::Correspondence,
            skip: true,

            current_game: Vec::new(),
            plies: 0,
            standard: true,

            batch: Vec::new(),
            batch_size: 0,
        }
    }

    fn send(&mut self) {
        if self.batch_size > 0 {
            self.batch_size = 0;

            let mut res = reqwest::blocking::Client::new()
                .put("http://localhost:9000/import/lichess")
                .body(mem::replace(&mut self.batch, Vec::new()))
                .send().expect("send batch");

            let mut answer = String::new();
            res.read_to_string(&mut answer).expect("decode response");
            println!("{} d: {} t: {}", self.filename, str::from_utf8(self.date).expect("date is valid utf8"), answer);
            assert!(res.status().is_success());
        }
    }
}

impl<'pgn> Visitor<'pgn> for Indexer<'pgn> {
    type Result = ();

    fn begin_game(&mut self) {
        self.current_game.clear();
        self.plies = 0;
    }

    fn begin_headers(&mut self) {
        self.white_elo = 0;
        self.black_elo = 0;
        self.time_control = TimeControl::Correspondence;
        self.standard = true;
    }

    fn header(&mut self, key: &'pgn [u8], value: &'pgn [u8]) {
        if key == b"WhiteElo" {
            self.white_elo = if value == b"?" { 0 } else { btoi::btoi(value).expect("WhiteElo") };
        } else if key == b"BlackElo" {
            self.black_elo = if value == b"?" { 0 } else { btoi::btoi(value).expect("BlackElo") };
        } else if key == b"TimeControl" {
            self.time_control = TimeControl::from_bytes(value).expect("TimeControl");
        } else if key == b"Variant" {
            self.standard = value == b"Standard";
            if self.standard {
                return; // we add this unconditionally later
            }
        } else if key == b"Date" || key == b"UTCDate" {
            self.date = value;
        }

        let (key, value) = if key == b"Site" {
            (&b"LichessID"[..], value.rsplitn(2, |ch| *ch == b'/').next().expect("Site"))
        } else {
            (key, value)
        };

        self.current_game.push(b'[');
        self.current_game.extend(key);
        self.current_game.extend(b" \"");
        self.current_game.extend(value);
        self.current_game.extend(b"\"]\n");
    }

    fn end_headers(&mut self) -> Skip {
        let rating = (self.white_elo + self.black_elo) / 2;

        let probability = if self.standard {
            self.current_game.extend(b"[Variant \"Standard\"]\n");

            match self.time_control {
                TimeControl::Correspondence | TimeControl::Classical => 1.0,
                TimeControl::Rapid if rating >= 2000 => 1.0,
                TimeControl::Rapid if rating >= 1800 => 2.0 / 5.0,
                TimeControl::Rapid => 1.0 / 8.0,
                TimeControl::Blitz if rating >= 2000 => 1.0,
                TimeControl::Blitz if rating >= 1800 => 1.0 / 4.0,
                TimeControl::Blitz => 1.0 / 15.0,
                TimeControl::Bullet if rating >= 2300 => 1.0,
                TimeControl::Bullet if rating >= 2200 => 4.0 / 5.0,
                TimeControl::Bullet if rating >= 2000 => 1.0 / 4.0,
                TimeControl::Bullet if rating >= 1800 => 1.0 / 7.0,
                _ => 1.0 / 20.0,
            }
        } else {
            if rating >= 1600 { 1.0 } else { 0.5 } // variant games
        };

        self.current_game.push(b'\n');

        let rnd = thread_rng().sample(OpenClosed01);
        let accept = min(self.white_elo, self.black_elo) >= 1500 && probability >= rnd;

        self.skip = !accept;
        Skip(self.skip)
    }

    fn san(&mut self, san: San) {
        if self.plies < MAX_PLIES {
            if self.plies > 0 {
                self.current_game.push(b' ');
            }

            self.current_game.extend(san.to_string().as_bytes());
            self.plies += 1;
        }
    }

    fn begin_variation(&mut self) -> Skip {
        Skip(true) // stay in the mainline
    }

    fn end_game(&mut self, _game: &'pgn [u8]) {
        if !self.skip && self.plies > 8 {
            if self.batch_size >= BATCH_SIZE {
                self.send();
            }

            if self.batch_size > 0 {
                self.batch.extend(b"\n\n\n");
            }

            self.batch.extend(&self.current_game);
            self.batch_size += 1;
        }
    }
}

fn main() {
    for arg in env::args().skip(1) {
        eprintln!("% indexing lichess games from {} ...", arg);
        let file = File::open(&arg).expect("fopen");
        let pgn = unsafe { Mmap::map(&file).expect("mmap") };
        pgn.advise_memory_access(AccessPattern::Sequential).expect("madvise");

        let mut indexer = Indexer::new(&arg);
        Reader::new(&mut indexer, &pgn[..]).read_all();
        indexer.send(); // send last
    }
}
<commit_msg>build index-lichess on stable rust<commit_after>extern crate pgn_reader;
extern crate memmap;
extern crate madvise;
extern crate btoi;
extern crate rand;
extern crate reqwest;

use std::env;
use std::mem;
use std::str;
use std::cmp::min;
use std::fs::File;
use std::io::Read;

use memmap::Mmap;
use madvise::{AccessPattern, AdviseMemory};
use pgn_reader::{Visitor, Skip, Reader, San};
use btoi::ParseIntegerError;
use rand::{thread_rng, Rng};
use rand::distributions::OpenClosed01;

const BATCH_SIZE: usize = 50;

const MAX_PLIES: usize = 50;

#[derive(Debug)]
enum TimeControl {
    UltraBullet,
    Bullet,
    Blitz,
    Rapid,
    Classical,
    Correspondence,
}

#[derive(Debug)]
struct TimeControlError;

impl From<ParseIntegerError> for TimeControlError {
    fn from(_: ParseIntegerError) -> TimeControlError {
        TimeControlError { }
    }
}

impl TimeControl {
    fn from_seconds_and_increment(seconds: u64, increment: u64) -> TimeControl {
        let total = seconds + 40 * increment;

        if total < 30 {
            TimeControl::UltraBullet
        } else if total < 180 {
            TimeControl::Bullet
        } else if total < 480 {
            TimeControl::Blitz
        } else if total < 1500 {
            TimeControl::Rapid
        } else if total < 21_600 {
            TimeControl::Classical
        } else {
            TimeControl::Correspondence
        }
    }

    fn from_bytes(bytes: &[u8]) -> Result<TimeControl, TimeControlError> {
        if bytes == b"-" {
            return Ok(TimeControl::Correspondence);
        }

        let mut parts = bytes.splitn(2, |ch| *ch == b'+');
        let seconds = btoi::btou(parts.next().ok_or(TimeControlError)?)?;
        let increment = btoi::btou(parts.next().ok_or(TimeControlError)?)?;
        Ok(TimeControl::from_seconds_and_increment(seconds, increment))
    }
}

struct Indexer<'pgn> {
    filename: String,
    date: &'pgn [u8],

    white_elo: i16,
    black_elo: i16,
    time_control: TimeControl,
    skip: bool,

    current_game: Vec<u8>,
    plies: usize,
    standard: bool,

    batch: Vec<u8>,
    batch_size: usize,
}

impl<'pgn> Indexer<'pgn> {
    fn new(filename: &str) -> Indexer {
        Indexer {
            filename: filename.into(),
            date: b"0000.00.00",

            white_elo: 0,
            black_elo: 0,
            time_control: TimeControl::Correspondence,
            skip: true,

            current_game: Vec::new(),
            plies: 0,
            standard: true,

            batch: Vec::new(),
            batch_size: 0,
        }
    }

    fn send(&mut self) {
        if self.batch_size > 0 {
            self.batch_size = 0;

            let mut res = reqwest::blocking::Client::new()
                .put("http://localhost:9000/import/lichess")
                .body(mem::replace(&mut self.batch, Vec::new()))
                .send().expect("send batch");

            let mut answer = String::new();
            res.read_to_string(&mut answer).expect("decode response");
            println!("{} d: {} t: {}", self.filename, str::from_utf8(self.date).expect("date is valid utf8"), answer);
            assert!(res.status().is_success());
        }
    }
}

impl<'pgn> Visitor<'pgn> for Indexer<'pgn> {
    type Result = ();

    fn begin_game(&mut self) {
        self.current_game.clear();
        self.plies = 0;
    }

    fn begin_headers(&mut self) {
        self.white_elo = 0;
        self.black_elo = 0;
        self.time_control = TimeControl::Correspondence;
        self.standard = true;
    }

    fn header(&mut self, key: &'pgn [u8], value: &'pgn [u8]) {
        if key == b"WhiteElo" {
            self.white_elo = if value == b"?" { 0 } else { btoi::btoi(value).expect("WhiteElo") };
        } else if key == b"BlackElo" {
            self.black_elo = if value == b"?" { 0 } else { btoi::btoi(value).expect("BlackElo") };
        } else if key == b"TimeControl" {
            self.time_control = TimeControl::from_bytes(value).expect("TimeControl");
        } else if key == b"Variant" {
            self.standard = value == b"Standard";
            if self.standard {
                return; // we add this unconditionally later
            }
        } else if key == b"Date" || key == b"UTCDate" {
            self.date = value;
        }

        let (key, value) = if key == b"Site" {
            (&b"LichessID"[..], value.rsplitn(2, |ch| *ch == b'/').next().expect("Site"))
        } else {
            (key, value)
        };

        self.current_game.push(b'[');
        self.current_game.extend(key);
        self.current_game.extend(b" \"");
        self.current_game.extend(value);
        self.current_game.extend(b"\"]\n");
    }

    fn end_headers(&mut self) -> Skip {
        let rating = (self.white_elo + self.black_elo) / 2;

        let probability = if self.standard {
            self.current_game.extend(b"[Variant \"Standard\"]\n");

            match self.time_control {
                TimeControl::Correspondence | TimeControl::Classical => 1.0,
                TimeControl::Rapid if rating >= 2000 => 1.0,
                TimeControl::Rapid if rating >= 1800 => 2.0 / 5.0,
                TimeControl::Rapid => 1.0 / 8.0,
                TimeControl::Blitz if rating >= 2000 => 1.0,
                TimeControl::Blitz if rating >= 1800 => 1.0 / 4.0,
                TimeControl::Blitz => 1.0 / 15.0,
                TimeControl::Bullet if rating >= 2300 => 1.0,
                TimeControl::Bullet if rating >= 2200 => 4.0 / 5.0,
                TimeControl::Bullet if rating >= 2000 => 1.0 / 4.0,
                TimeControl::Bullet if rating >= 1800 => 1.0 / 7.0,
                _ => 1.0 / 20.0,
            }
        } else {
            if rating >= 1600 { 1.0 } else { 0.5 } // variant games
        };

        self.current_game.push(b'\n');

        let rnd = thread_rng().sample(OpenClosed01);
        let accept = min(self.white_elo, self.black_elo) >= 1500 && probability >= rnd;

        self.skip = !accept;
        Skip(self.skip)
    }

    fn san(&mut self, san: San) {
        if self.plies < MAX_PLIES {
            if self.plies > 0 {
                self.current_game.push(b' ');
            }

            self.current_game.extend(san.to_string().as_bytes());
            self.plies += 1;
        }
    }

    fn begin_variation(&mut self) -> Skip {
        Skip(true) // stay in the mainline
    }

    fn end_game(&mut self, _game: &'pgn [u8]) {
        if !self.skip && self.plies > 8 {
            if self.batch_size >= BATCH_SIZE {
                self.send();
            }

            if self.batch_size > 0 {
                self.batch.extend(b"\n\n\n");
            }

            self.batch.extend(&self.current_game);
            self.batch_size += 1;
        }
    }
}

fn main() {
    for arg in env::args().skip(1) {
        eprintln!("% indexing lichess games from {} ...", arg);
        let file = File::open(&arg).expect("fopen");
        let pgn = unsafe { Mmap::map(&file).expect("mmap") };
        pgn.advise_memory_access(AccessPattern::Sequential).expect("madvise");

        let mut indexer = Indexer::new(&arg);
        Reader::new(&mut indexer, &pgn[..]).read_all();
        indexer.send(); // send last
    }
}
<|endoftext|>


<commit_before>//! Heatmap provides a time-series of Histograms, which is useful for
//! recording distributions over time and reporting percentiles over time
//!
//!
//! # Goals
//! * pre-allocated datastructure
//! * report time-series percentiles
//! * auto-slicing by record time
//!
//! # Future work
//! * make it work
//! * make it awesome
//! * add roll-up
//!
//! # Usage
//! Create a heatmap. Insert values over time. Profit.
//!
//! ```
//!
//! use heatmap::*;

#![crate_type = "lib"]

#![crate_name = "heatmap"]

extern crate histogram;
extern crate time;

use histogram::*;
use time::*;

#[derive(Clone, Copy)]
pub struct HeatmapConfig {
    precision: u32,
    max_memory: u32,
    max_value: u64,
    slice_duration: u64,
    num_slices: usize,
}

impl HeatmapConfig {
    pub fn new() -> HeatmapConfig {
        HeatmapConfig {
            precision: 3,
            max_memory: 0,
            max_value: 1_000_000_000,
            slice_duration: 60_000_000_000,
            num_slices: 60,
        }
    }

    pub fn precision(&mut self, precision: u32) -> &mut Self {
        self.precision = precision;
        self
    }

    pub fn max_memory(&mut self, bytes: u32) -> &mut Self {
        self.max_memory = bytes;
        self
    }

    pub fn max_value(&mut self, value: u64) -> &mut Self {
        self.max_value = value;
        self
    }

    pub fn slice_duration(&mut self, duration: u64) -> &mut Self {
        self.slice_duration = duration;
        self
    }

    pub fn num_slices(&mut self, count: usize) -> &mut Self {
        self.num_slices = count;
        self
    }
}

#[derive(Clone, Copy)]
pub struct HeatmapCounters {
    entries_total: u64,
}

impl HeatmapCounters {
    pub fn new() -> HeatmapCounters {
        HeatmapCounters {
            entries_total: 0,
        }
    }

    pub fn clear(&mut self) {
        self.entries_total = 0;
    }
}

#[derive(Clone)]
pub struct HeatmapData {
    data: Vec<Histogram>,
    counters: HeatmapCounters,
    iterator: usize,
    start: u64,
    stop: u64,
}

#[derive(Clone, Copy)]
pub struct HeatmapProperties;

#[derive(Clone)]
pub struct Heatmap {
    config: HeatmapConfig,
    data: HeatmapData,
    properties: HeatmapProperties,
}

#[derive(Clone)]
pub struct HeatmapSlice {
    pub start: u64,
    pub stop: u64,
    pub histogram: Histogram,
}

impl HeatmapSlice {
    pub fn start(self) -> u64 {
        self.start
    }

    pub fn stop(self) -> u64 {
        self.stop
    }

    pub fn histogram(self) -> Histogram {
        self.histogram
    }
}

impl Iterator for Heatmap {
    type Item = HeatmapSlice;

    fn next(&mut self) -> Option<HeatmapSlice> {
        let current = self.data.iterator;
        self.data.iterator += 1;

        if current == (self.config.num_slices as usize) {
            self.data.iterator = 0;
            None
        } else {
            let start = (self.data.iterator as u64 * self.config.slice_duration) + self.data.start;
            Some(HeatmapSlice {
                start: start,
                stop: start + self.config.slice_duration,
                histogram: self.data.data[current].clone(),
            })
        }
    }
}

impl Heatmap {

    /// create a new Heatmap with defaults
    ///
    /// # Example
    /// ```
    /// # use heatmap::Heatmap;
    ///
    /// let mut h = Heatmap::new().unwrap();
    pub fn new() -> Option<Heatmap> {
        Heatmap::configured(HeatmapConfig::new())
    }

    /// create a new Heatmap
    ///
    /// # Example
    /// ```
    /// # use heatmap::{Heatmap,HeatmapConfig};
    ///
    /// let mut c = HeatmapConfig::new();
    /// c.precision(4); // set precision to 4 digits
    /// c.max_value(1_000_000_000); // store values up to 1 Million
    /// c.slice_duration(1_000_000_000); // 1 second slices
    /// c.num_slices(300); // 300 slices => 5 minutes of records
    ///
    /// let mut h = Heatmap::configured(c).unwrap();
    pub fn configured(config: HeatmapConfig) -> Option<Heatmap> {

        let mut data = Vec::with_capacity(config.num_slices);

        unsafe {
            data.set_len(config.num_slices);
        }

        for i in 0..config.num_slices {
            let mut c = HistogramConfig::new();
            c.max_value(config.max_value);
            c.precision(config.precision);
            c.max_memory(config.max_memory / config.num_slices as u32);

            data[i] = Histogram::configured(c).unwrap();
        }

        let start = time::precise_time_ns();

        Some(Heatmap {
            config: config,
            data: HeatmapData {
                data: data,
                counters: HeatmapCounters::new(),
                iterator: 0,
                start: start,
                stop: start + config.slice_duration * config.num_slices as u64,
            },
            properties: HeatmapProperties,
        })
    }

    /// clear the heatmap data
    ///
    /// # Example
    /// ```
    /// # use heatmap::{Heatmap,HeatmapConfig};
    ///
    /// let mut h = Heatmap::new(
    ///     HeatmapConfig{
    ///         max_value: 1000000,
    ///         precision: 3,
    ///         max_memory: 0,
    ///			slice_duration: 1000000000,
    ///			num_slices: 300,
    /// }).unwrap();
    ///
    /// h.increment(1);
    /// assert_eq!(h.entries(), 1);
    /// h.clear();
    /// assert_eq!(h.entries(), 0);
    pub fn clear(&mut self) -> Result<(), &'static str> {
        for i in 0..self.config.num_slices {
            match self.data.data[i].clear() {
                Ok(_) => {},
                Err(e) => { return Err(e); },
            }
        }

        self.data.counters.clear();
        self.data.start = time::precise_time_ns();
        self.data.stop =
            self.data.start + self.config.slice_duration * self.config.num_slices as u64;
        Ok(())
    }

    /// increment the count for a value at a time
    ///
    /// # Example
    /// ```
    /// extern crate heatmap;
    /// extern crate time;
    ///
    /// let mut h = heatmap::Heatmap::new().unwrap();
    ///
    /// h.increment(time::precise_time_ns(), 1);
    /// assert_eq!(h.entries(), 1);
    pub fn increment(&mut self, time: u64, value: u64) -> Result<(), &'static str> {
        self.record(time, value, 1_u64)
    }

    /// record additional counts for value at a time
    ///
    /// # Example
    /// ```
    /// extern crate heatmap;
    /// extern crate time;
    ///
    /// let mut h = heatmap::Heatmap::new().unwrap();
    ///
    /// h.record(time::precise_time_ns(), 1, 1);
    /// assert_eq!(h.entries(), 1);
    ///
    /// h.record(time::precise_time_ns(), 2, 2);
    /// assert_eq!(h.entries(), 3);
    ///
    /// h.record(time::precise_time_ns(), 10, 10);
    /// assert_eq!(h.entries(), 13);
    pub fn record(&mut self, time: u64, value: u64, count: u64) -> Result<(), &'static str> {
        self.data.counters.entries_total = self.data.counters.entries_total.saturating_add(count);

        match self.histogram_index(time) {
            Ok(histogram_index) => {
                self.data.data[histogram_index].record(value, count)
            }
            Err(e) => {
                Err(e)
            }
        }
    }

    pub fn get(&mut self, time: u64, value: u64) -> Result<u64, &'static str> {
        match self.histogram_index(time) {
            Ok(histogram_index) => {
                match self.data.data[histogram_index].get(value) {
                    Some(count) => {
                        Ok(count)
                    }
                    None => {
                        Err("histogram didn't have")
                    }
                }
            }
            Err(e) => {
                Err(e)
            }
        }
    }

    /// internal function to find the index of the histogram in the heatmap
    fn histogram_index(&mut self, time: u64) -> Result<usize, &'static str> {
        if time < self.data.start {
            return Err("sample too early");
        } else if time > self.data.stop {
            return Err("sample too late");
        }
        Ok(((time - self.data.start) as f64 / self.config.slice_duration as f64).floor() as usize)
    }

    /// return the number of entries in the Histogram
    ///
    /// # Example
    /// ```
    /// extern crate heatmap;
    /// extern crate time;
    ///
    /// let mut h = heatmap::Heatmap::new().unwrap();
    ///
    /// assert_eq!(h.entries(), 0);
    /// h.record(time::precise_time_ns(), 1, 1);
    /// assert_eq!(h.entries(), 1);
    pub fn entries(&mut self) -> u64 {
        self.data.counters.entries_total
    }

    /// merge one Heatmap into another Heatmap
    ///
    /// # Example
    /// ```
    /// extern crate heatmap;
    /// extern crate time;
    ///
    /// let mut a = heatmap::Heatmap::new().unwrap();
    ///
    /// let mut b = heatmap::Heatmap::new().unwrap();
    ///
    /// assert_eq!(a.entries(), 0);
    /// assert_eq!(b.entries(), 0);
    ///
    /// let _ = a.increment(1, 1);
    /// let _ = b.increment(2, 1);
    ///
    /// assert_eq!(a.entries(), 1);
    /// assert_eq!(b.entries(), 1);
    ///
    /// a.merge(&mut b);
    ///
    /// assert_eq!(a.entries(), 2);
    /// assert_eq!(a.get(1, 1).unwrap(), 1);
    /// assert_eq!(a.get(2, 1).unwrap(), 1);
    pub fn merge(&mut self, other: &mut Heatmap) {
        loop {
            match other.next() {
                Some(slice) => {
                    match self.histogram_index(slice.start) {
                        Ok(i) => {
                            self.data.data[i].merge(&mut slice.histogram.clone());
                            self.data.counters.entries_total += slice.histogram.clone().entries();
                        }
                        Err(_) => {}
                    }

                }
                None => { break }
            }
        }
    }
}
<commit_msg>make tests pass<commit_after>//! Heatmap provides a time-series of Histograms, which is useful for
//! recording distributions over time and reporting percentiles over time
//!
//!
//! # Goals
//! * pre-allocated datastructure
//! * report time-series percentiles
//! * auto-slicing by record time
//!
//! # Future work
//! * make it work
//! * make it awesome
//! * add roll-up
//!
//! # Usage
//! Create a heatmap. Insert values over time. Profit.
//!
//! ```
//!
//! use heatmap::*;

#![crate_type = "lib"]

#![crate_name = "heatmap"]

extern crate histogram;
extern crate time;

use histogram::*;
use time::*;

#[derive(Clone, Copy)]
pub struct HeatmapConfig {
    precision: u32,
    max_memory: u32,
    max_value: u64,
    slice_duration: u64,
    num_slices: usize,
    start: u64,
}

impl HeatmapConfig {
    pub fn new() -> HeatmapConfig {
        HeatmapConfig {
            precision: 3,
            max_memory: 0,
            max_value: 1_000_000_000,
            slice_duration: 60_000_000_000,
            num_slices: 60,
            start: 0,
        }
    }

    pub fn precision(&mut self, precision: u32) -> &mut Self {
        self.precision = precision;
        self
    }

    pub fn max_memory(&mut self, bytes: u32) -> &mut Self {
        self.max_memory = bytes;
        self
    }

    pub fn max_value(&mut self, value: u64) -> &mut Self {
        self.max_value = value;
        self
    }

    pub fn slice_duration(&mut self, duration: u64) -> &mut Self {
        self.slice_duration = duration;
        self
    }

    pub fn num_slices(&mut self, count: usize) -> &mut Self {
        self.num_slices = count;
        self
    }

    pub fn start(&mut self, time: u64) -> &mut Self {
        self.start = time;
        self
    }
}

#[derive(Clone, Copy)]
pub struct HeatmapCounters {
    entries_total: u64,
}

impl HeatmapCounters {
    pub fn new() -> HeatmapCounters {
        HeatmapCounters { entries_total: 0 }
    }

    pub fn clear(&mut self) {
        self.entries_total = 0;
    }
}

#[derive(Clone)]
pub struct HeatmapData {
    data: Vec<Histogram>,
    counters: HeatmapCounters,
    iterator: usize,
    start: u64,
    stop: u64,
}

#[derive(Clone, Copy)]
pub struct HeatmapProperties;

#[derive(Clone)]
pub struct Heatmap {
    config: HeatmapConfig,
    data: HeatmapData,
    properties: HeatmapProperties,
}

#[derive(Clone)]
pub struct HeatmapSlice {
    pub start: u64,
    pub stop: u64,
    pub histogram: Histogram,
}

impl HeatmapSlice {
    pub fn start(self) -> u64 {
        self.start
    }

    pub fn stop(self) -> u64 {
        self.stop
    }

    pub fn histogram(self) -> Histogram {
        self.histogram
    }
}

impl Iterator for Heatmap {
    type Item = HeatmapSlice;

    fn next(&mut self) -> Option<HeatmapSlice> {
        let current = self.data.iterator;
        self.data.iterator += 1;

        if current == (self.config.num_slices as usize) {
            self.data.iterator = 0;
            None
        } else {
            let start = (self.data.iterator as u64 * self.config.slice_duration) + self.data.start;
            Some(HeatmapSlice {
                start: start,
                stop: start + self.config.slice_duration,
                histogram: self.data.data[current].clone(),
            })
        }
    }
}

impl Heatmap {

    /// create a new Heatmap with defaults
    ///
    /// # Example
    /// ```
    /// # use heatmap::Heatmap;
    ///
    /// let mut h = Heatmap::new().unwrap();
    pub fn new() -> Option<Heatmap> {
        Heatmap::configured(HeatmapConfig::new())
    }

    /// create a new Heatmap
    ///
    /// # Example
    /// ```
    /// # use heatmap::{Heatmap,HeatmapConfig};
    ///
    /// let mut c = HeatmapConfig::new();
    /// c.precision(4); // set precision to 4 digits
    /// c.max_value(1_000_000_000); // store values up to 1 Million
    /// c.slice_duration(1_000_000_000); // 1 second slices
    /// c.num_slices(300); // 300 slices => 5 minutes of records
    ///
    /// let mut h = Heatmap::configured(c).unwrap();
    pub fn configured(config: HeatmapConfig) -> Option<Heatmap> {

        let mut data = Vec::with_capacity(config.num_slices);

        unsafe {
            data.set_len(config.num_slices);
        }

        for i in 0..config.num_slices {
            let mut c = HistogramConfig::new();
            c.max_value(config.max_value);
            c.precision(config.precision);
            c.max_memory(config.max_memory / config.num_slices as u32);

            data[i] = Histogram::configured(c).unwrap();
        }

        let start = config.start;

        Some(Heatmap {
            config: config,
            data: HeatmapData {
                data: data,
                counters: HeatmapCounters::new(),
                iterator: 0,
                start: start,
                stop: start + config.slice_duration * config.num_slices as u64,
            },
            properties: HeatmapProperties,
        })
    }

    /// clear the heatmap data
    ///
    /// # Example
    /// ```
    /// # use heatmap::{Heatmap,HeatmapConfig};
    ///
    /// let mut h = Heatmap::new(
    ///     HeatmapConfig{
    ///         max_value: 1000000,
    ///         precision: 3,
    ///         max_memory: 0,
    ///			slice_duration: 1000000000,
    ///			num_slices: 300,
    /// }).unwrap();
    ///
    /// h.increment(1);
    /// assert_eq!(h.entries(), 1);
    /// h.clear();
    /// assert_eq!(h.entries(), 0);
    pub fn clear(&mut self) -> Result<(), &'static str> {
        for i in 0..self.config.num_slices {
            match self.data.data[i].clear() {
                Ok(_) => {}
                Err(e) => {
                    return Err(e);
                }
            }
        }

        self.data.counters.clear();
        self.data.start = time::precise_time_ns();
        self.data.stop = self.data.start +
                         self.config.slice_duration * self.config.num_slices as u64;
        Ok(())
    }

    /// increment the count for a value at a time
    ///
    /// # Example
    /// ```
    /// extern crate heatmap;
    /// extern crate time;
    ///
    /// let mut h = heatmap::Heatmap::new().unwrap();
    ///
    /// h.increment(time::precise_time_ns(), 1);
    /// assert_eq!(h.entries(), 1);
    pub fn increment(&mut self, time: u64, value: u64) -> Result<(), &'static str> {
        self.record(time, value, 1_u64)
    }

    /// record additional counts for value at a time
    ///
    /// # Example
    /// ```
    /// extern crate heatmap;
    /// extern crate time;
    ///
    /// let mut h = heatmap::Heatmap::new().unwrap();
    ///
    /// h.record(time::precise_time_ns(), 1, 1);
    /// assert_eq!(h.entries(), 1);
    ///
    /// h.record(time::precise_time_ns(), 2, 2);
    /// assert_eq!(h.entries(), 3);
    ///
    /// h.record(time::precise_time_ns(), 10, 10);
    /// assert_eq!(h.entries(), 13);
    pub fn record(&mut self, time: u64, value: u64, count: u64) -> Result<(), &'static str> {
        self.data.counters.entries_total = self.data.counters.entries_total.saturating_add(count);

        match self.histogram_index(time) {
            Ok(histogram_index) => {
                self.data.data[histogram_index].record(value, count)
            }
            Err(e) => {
                Err(e)
            }
        }
    }

    pub fn get(&mut self, time: u64, value: u64) -> Result<u64, &'static str> {
        match self.histogram_index(time) {
            Ok(histogram_index) => {
                match self.data.data[histogram_index].get(value) {
                    Some(count) => {
                        Ok(count)
                    }
                    None => {
                        Err("histogram didn't have")
                    }
                }
            }
            Err(e) => {
                Err(e)
            }
        }
    }

    /// internal function to find the index of the histogram in the heatmap
    fn histogram_index(&mut self, time: u64) -> Result<usize, &'static str> {
        if time < self.data.start {
            return Err("sample too early");
        } else if time > self.data.stop {
            return Err("sample too late");
        }
        let index: usize = ((time - self.data.start) as f64 /
                            self.config.slice_duration as f64)
                               .floor() as usize;
        println!("index: time: {} is {}", time, index);
        Ok(index)
    }

    /// return the number of entries in the Histogram
    ///
    /// # Example
    /// ```
    /// extern crate heatmap;
    /// extern crate time;
    ///
    /// let mut h = heatmap::Heatmap::new().unwrap();
    ///
    /// assert_eq!(h.entries(), 0);
    /// h.record(time::precise_time_ns(), 1, 1);
    /// assert_eq!(h.entries(), 1);
    pub fn entries(&mut self) -> u64 {
        self.data.counters.entries_total
    }

    /// merge one Heatmap into another Heatmap
    ///
    /// # Example
    /// ```
    /// extern crate heatmap;
    /// extern crate time;
    ///
    /// let mut c = heatmap::HeatmapConfig::new();
    /// c.num_slices(61);
    ///
    /// let mut a = heatmap::Heatmap::configured(c).unwrap();
    ///
    /// let mut b = heatmap::Heatmap::new().unwrap();
    ///
    /// assert_eq!(a.entries(), 0);
    /// assert_eq!(b.entries(), 0);
    ///
    /// let _ = a.increment(1, 1);
    /// let _ = b.increment(1, 1);
    ///
    /// assert_eq!(a.entries(), 1);
    /// assert_eq!(b.entries(), 1);
    ///
    /// a.merge(&mut b);
    ///
    /// assert_eq!(a.entries(), 2);
    /// assert_eq!(a.get(1, 1).unwrap(), 1);
    /// assert_eq!(a.get(2, 1).unwrap(), 1);
    pub fn merge(&mut self, other: &mut Heatmap) {
        loop {
            match other.next() {
                Some(other_slice) => {
                    match self.histogram_index(other_slice.clone().start()) {
                        Ok(i) => {
                            self.data.data[i].merge(&mut other_slice.clone().histogram.clone());
                            self.data.counters.entries_total += other_slice.clone()
                                                                           .histogram
                                                                           .clone()
                                                                           .entries();
                        }
                        Err(e) => {}
                    }

                }
                None => {
                    break;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate protobuf;
extern crate byteorder;
use std::io::prelude::*;
use protobuf::{MessageStatic, Message, parse_from_bytes};
use byteorder::{ReadBytesExt, LittleEndian, WriteBytesExt};
use std::io::Cursor;

pub fn read_pbuf<T>(reader: &mut Box<BufRead>) -> Vec<T>
  where T: MessageStatic {
  let mut event: T;
  let mut events: Vec<T> = Vec::new();
  let mut head = vec![0; 2];

  loop {
    match reader.read_exact(&mut head) {
      Ok(n) => n,
      Err(_) => break
    };
    let h = header(&head);
    let mut proto = vec![0; h];
    match reader.read_exact(&mut proto) {
      Ok(n) => n,
      Err(e) => panic!("{:?}", e)
    };
    event = match parse_from_bytes::<T>(&mut proto) {
              Ok(n) => n,
              Err(e) => panic!("{:?}", e)
            };
    events.push(event);
  }
  events
}

fn header(sz: &Vec<u8>) -> usize {
  let mut rdr = Cursor::new(sz);
  match rdr.read_i16::<LittleEndian>() {
    Ok(x) => x as usize,
    Err(e) => panic!("Something wicked this way comes: {}", e)
  }
}

pub fn write_pbuf<T>(event: &T, writer: &mut Box<Write>)
  where T: Message {
  let bts = Message::write_to_bytes(event).unwrap();
  let l = bts.len();
  match writer.write_u16::<LittleEndian>(l as u16) {
    Ok(n) => n,
    Err(e) => panic!("{:?}", e)
  };
  match writer.write(&bts[..]) {
    Ok(n) => assert_eq!(l, n),
    Err(e) => panic!("{:?}", e)
  }
}<commit_msg>Minor namechange<commit_after>extern crate protobuf;
extern crate byteorder;
use std::io::prelude::*;
use protobuf::{MessageStatic, Message, parse_from_bytes};
use byteorder::{ReadBytesExt, LittleEndian, WriteBytesExt};
use std::io::Cursor;

pub fn read_pbuf<T>(reader: &mut Box<BufRead>) -> Vec<T>
  where T: MessageStatic {
  let mut msg: T;
  let mut msgs: Vec<T> = Vec::new();
  let mut head = vec![0; 2];

  loop {
    match reader.read_exact(&mut head) {
      Ok(n) => n,
      Err(_) => break
    };
    let h = header(&head);
    let mut proto = vec![0; h];
    match reader.read_exact(&mut proto) {
      Ok(n) => n,
      Err(e) => panic!("{:?}", e)
    };
    msg = match parse_from_bytes::<T>(&mut proto) {
              Ok(n) => n,
              Err(e) => panic!("{:?}", e)
            };
    msgs.push(msg);
  }
  msgs
}

fn header(sz: &Vec<u8>) -> usize {
  let mut rdr = Cursor::new(sz);
  match rdr.read_i16::<LittleEndian>() {
    Ok(x) => x as usize,
    Err(e) => panic!("Something wicked this way comes: {}", e)
  }
}

pub fn write_pbuf<T>(msg: &T, writer: &mut Box<Write>)
  where T: Message {
  let bts = Message::write_to_bytes(msg).unwrap();
  let l = bts.len();
  match writer.write_u16::<LittleEndian>(l as u16) {
    Ok(n) => n,
    Err(e) => panic!("{:?}", e)
  };
  match writer.write(&bts[..]) {
    Ok(n) => assert_eq!(l, n),
    Err(e) => panic!("{:?}", e)
  }
}
<|endoftext|>


<commit_before>extern crate x264_sys as ffi;

use std::mem;
use ffi::x264::*;
use std::ptr::null;
use std::os::raw::c_int;
use std::ffi::CString;

pub struct Picture {
    pic: x264_picture_t,
    plane_size: [usize; 3],
    native: bool,
}

struct ColorspaceScale {
    w: [usize; 3],
    h: [usize; 3],
}
fn scale_from_csp(csp: u32) -> ColorspaceScale {
    if csp == X264_CSP_I420 {
        ColorspaceScale {
            w: [256 * 1, 256 / 2, 256 / 2],
            h: [256 * 1, 256 / 2, 256 / 2],
        }
    } else if csp == X264_CSP_YV12 {
        ColorspaceScale {
            w: [256 * 1, 256 / 2, 256 / 2],
            h: [256 * 1, 256 / 2, 256 / 2],
        }
    } else if csp == X264_CSP_NV12 {
        ColorspaceScale {
            w: [256 * 1, 256 * 1, 0],
            h: [256 * 1, 256 / 2, 0],
        }
    } else if csp == X264_CSP_NV21 {
        ColorspaceScale {
            w: [256 * 1, 256 * 1, 0],
            h: [256 * 1, 256 / 2, 0],
        }
    } else if csp == X264_CSP_I422 {
        ColorspaceScale {
            w: [256 * 1, 256 / 2, 256 / 2],
            h: [256 * 1, 256 * 1, 256 * 1],
        }
    } else if csp == X264_CSP_YV16 {
        ColorspaceScale {
            w: [256 * 1, 256 / 2, 256 / 2],
            h: [256 * 1, 256 * 1, 256 * 1],
        }
    } else if csp == X264_CSP_NV16 {
        ColorspaceScale {
            w: [256 * 1, 256 * 1, 0],
            h: [256 * 1, 256 * 1, 0],
        }
        /*
    } else if csp == X264_CSP_YUYV {
        ColorspaceScale {
            w: [256 * 2, 0, 0],
            h: [256 * 1, 0, 0],
        }
    } else if csp == X264_CSP_UYVY {
        ColorspaceScale {
            w: [256 * 2, 0, 0],
            h: [256 * 1, 0, 0],
        }
        */
    } else if csp == X264_CSP_I444 {
        ColorspaceScale {
            w: [256 * 1, 256 * 1, 256 * 1],
            h: [256 * 1, 256 * 1, 256 * 1],
        }
    } else if csp == X264_CSP_YV24 {
        ColorspaceScale {
            w: [256 * 1, 256 * 1, 256 * 1],
            h: [256 * 1, 256 * 1, 256 * 1],
        }
    } else if csp == X264_CSP_BGR {
        ColorspaceScale {
            w: [256 * 3, 0, 0],
            h: [256 * 1, 0, 0],
        }
    } else if csp == X264_CSP_BGRA {
        ColorspaceScale {
            w: [256 * 4, 0, 0],
            h: [256 * 1, 0, 0],
        }
    } else if csp == X264_CSP_RGB {
        ColorspaceScale {
            w: [256 * 3, 0, 0],
            h: [256 * 1, 0, 0],
        }
    } else {
        unreachable!()
    }
}

impl Picture {
    /*
    pub fn new() -> Picture {
        let mut pic = unsafe { mem::uninitialized() };

        unsafe { x264_picture_init(&mut pic as *mut x264_picture_t) };

        Picture { pic: pic }
    }
*/
    pub fn from_param(param: &Param) -> Result<Picture, &'static str> {
        let mut pic: x264_picture_t = unsafe { mem::uninitialized() };

        let ret = unsafe {
            x264_picture_alloc(&mut pic as *mut x264_picture_t,
                               param.par.i_csp,
                               param.par.i_width,
                               param.par.i_height)
        };
        if ret < 0 {
            Err("Allocation Failure")
        } else {
            let scale = scale_from_csp(param.par.i_csp as u32 & X264_CSP_MASK as u32);
            let bytes = 1 + (param.par.i_csp as u32 & X264_CSP_HIGH_DEPTH as u32);
            let mut plane_size = [0; 3];

            for i in 0..pic.img.i_plane as usize {
                plane_size[i] = param.par.i_width as usize * scale.w[i] / 256 * bytes as usize *
                                param.par.i_height as usize *
                                scale.h[i] / 256;
            }

            Ok(Picture {
                   pic: pic,
                   plane_size: plane_size,
                   native: true,
               })
        }
    }

    pub fn as_slice<'a>(&'a self, plane: usize) -> Result<&'a [u8], &'static str> {
        if plane > self.pic.img.i_plane as usize {
            Err("Invalid Argument")
        } else {
            let size = self.plane_size[plane];
            Ok(unsafe { std::slice::from_raw_parts(self.pic.img.plane[plane], size) })
        }
    }

    pub fn as_mut_slice<'a>(&'a mut self, plane: usize) -> Result<&'a mut [u8], &'static str> {
        if plane > self.pic.img.i_plane as usize {
            Err("Invalid Argument")
        } else {
            let size = self.plane_size[plane];
            Ok(unsafe { std::slice::from_raw_parts_mut(self.pic.img.plane[plane], size) })
        }
    }

    pub fn set_timestamp(mut self, pts: i64) -> Picture {
        self.pic.i_pts = pts;
        self
    }
}

impl Drop for Picture {
    fn drop(&mut self) {
        if self.native {
            unsafe { x264_picture_clean(&mut self.pic as *mut x264_picture_t) };
        }
    }
}

// TODO: Provide a builder API instead?
pub struct Param {
    par: x264_param_t,
}

impl Param {
    pub fn new() -> Param {
        let mut par = unsafe { mem::uninitialized() };

        unsafe {
            x264_param_default(&mut par as *mut x264_param_t);
        }

        Param { par: par }
    }
    pub fn default_preset<'a, 'b, Oa, Ob>(tune: Oa, preset: Ob) -> Result<Param, &'static str>
        where Oa: Into<Option<&'a str>>,
              Ob: Into<Option<&'b str>>
    {
        let mut par = unsafe { mem::uninitialized() };
        let t = tune.into().map_or_else(|| None, |v| Some(CString::new(v).unwrap()));
        let p = preset.into().map_or_else(|| None, |v| Some(CString::new(v).unwrap()));

        let c_tune = t.map_or_else(|| null(), |v| v.as_ptr() as *const i8);
        let c_preset = p.map_or_else(|| null(), |v| v.as_ptr() as *const i8);
        match unsafe {
                  x264_param_default_preset(&mut par as *mut x264_param_t, c_tune, c_preset)
              } {
            -1 => Err("Invalid Argument"),
            0 => Ok(Param { par: par }),
            _ => Err("Unexpected"),
        }
    }
    pub fn apply_profile(mut self, profile: &str) -> Result<Param, &'static str> {
        let p = CString::new(profile).unwrap();
        match unsafe { x264_param_apply_profile(&mut self.par, p.as_ptr() as *const i8) } {
            -1 => Err("Invalid Argument"),
            0 => Ok(self),
            _ => Err("Unexpected"),
        }
    }
    pub fn param_parse<'a>(mut self, name: &str, value: &str) -> Result<Param, &'static str> {
        let n = CString::new(name).unwrap();
        let v = CString::new(value).unwrap();
        match unsafe {
                  x264_param_parse(&mut self.par,
                                   n.as_ptr() as *const i8,
                                   v.as_ptr() as *const i8)
              } {
            -1 => Err("Invalid Argument"),
            0 => Ok(self),
            _ => Err("Unexpected"),
        }
    }
    pub fn set_dimension(mut self, height: usize, width: usize) -> Param {
        self.par.i_height = height as c_int;
        self.par.i_width = width as c_int;

        self
    }
}

// TODO: Expose a NAL abstraction
pub struct NalData {
    vec: Vec<u8>,
}

impl NalData {
    /*
     * x264 functions return x264_nal_t arrays that are valid only until another
     * function of that kind is called.
     *
     * Always copy the data over.
     *
     * TODO: Consider using Bytes as backing store.
     */
    fn from_nals(c_nals: *mut x264_nal_t, nb_nal: usize) -> NalData {
        let mut data = NalData { vec: Vec::new() };

        for i in 0..nb_nal {
            let nal = unsafe { Box::from_raw(c_nals.offset(i as isize)) };

            let payload =
                unsafe { std::slice::from_raw_parts(nal.p_payload, nal.i_payload as usize) };

            data.vec.extend_from_slice(payload);

            mem::forget(payload);
            mem::forget(nal);
        }

        data
    }

    pub fn as_bytes(&self) -> &[u8] {
        self.vec.as_slice()
    }
}

pub struct Encoder {
    enc: *mut x264_t,
}

impl Encoder {
    pub fn open(par: &mut Param) -> Result<Encoder, &'static str> {
        let enc = unsafe { x264_encoder_open(&mut par.par as *mut x264_param_t) };

        if enc.is_null() {
            Err("Out of Memory")
        } else {
            Ok(Encoder { enc: enc })
        }
    }

    pub fn get_headers(&mut self) -> Result<NalData, &'static str> {
        let mut nb_nal: c_int = 0;
        let mut c_nals: *mut x264_nal_t = unsafe { mem::uninitialized() };

        let bytes = unsafe {
            x264_encoder_headers(self.enc,
                                 &mut c_nals as *mut *mut x264_nal_t,
                                 &mut nb_nal as *mut c_int)
        };

        if bytes < 0 {
            Err("Encoding Headers Failed")
        } else {
            Ok(NalData::from_nals(c_nals, nb_nal as usize))
        }
    }

    pub fn encode<'a, P>(&mut self, pic: P) -> Result<Option<(NalData, i64, i64)>, &'static str>
        where P: Into<Option<&'a Picture>>
    {
        let mut pic_out: x264_picture_t = unsafe { mem::uninitialized() };
        let mut c_nals: *mut x264_nal_t = unsafe { mem::uninitialized() };
        let mut nb_nal: c_int = 0;
        let c_pic = pic.into().map_or_else(|| null(), |v| &v.pic as *const x264_picture_t);

        let ret = unsafe {
            x264_encoder_encode(self.enc,
                                &mut c_nals as *mut *mut x264_nal_t,
                                &mut nb_nal as *mut c_int,
                                c_pic as *mut x264_picture_t,
                                &mut pic_out as *mut x264_picture_t)
        };
        if ret < 0 {
            Err("Error encoding")
        } else {
            if nb_nal > 0 {
                let data = NalData::from_nals(c_nals, nb_nal as usize);
                Ok(Some((data, pic_out.i_pts, pic_out.i_dts)))
            } else {
                Ok(None)
            }
        }
    }

    pub fn delayed_frames(&self) -> bool {
        unsafe { x264_encoder_delayed_frames(self.enc) != 0 }
    }
}

impl Drop for Encoder {
    fn drop(&mut self) {
        unsafe { x264_encoder_close(self.enc) };
    }
}

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

    #[test]
    fn test_open() {
        let mut par = Param::new().set_dimension(640, 480);

        let mut enc = Encoder::open(&mut par).unwrap();

        let headers = enc.get_headers().unwrap();

        println!("Headers len {}", headers.as_bytes().len());
    }

    #[test]
    fn test_picture() {
        let par = Param::new().set_dimension(640, 480);
        {
            let mut pic = Picture::from_param(&par).unwrap();
            {
                let p = pic.as_mut_slice(0).unwrap();
                p[0] = 1;
            }
            let p = pic.as_slice(0).unwrap();

            assert_eq!(p[0], 1);
        }
    }

    #[test]
    fn test_encode() {
        let mut par = Param::new().set_dimension(640, 480);
        let mut enc = Encoder::open(&mut par).unwrap();
        let mut pic = Picture::from_param(&par).unwrap();

        let headers = enc.get_headers().unwrap();

        println!("Headers len {}", headers.as_bytes().len());

        for pts in 0..5 {
            pic = pic.set_timestamp(pts as i64);
            let ret = enc.encode(&pic).unwrap();
            match ret {
                Some((_, pts, dts)) => println!("Frame pts {}, dts {}", pts, dts),
                _ => (),
            }
        }

        while enc.delayed_frames() {
            let ret = enc.encode(None).unwrap();
            match ret {
                Some((_, pts, dts)) => println!("Frame pts {}, dts {}", pts, dts),
                _ => (),
            }
        }
    }
}
<commit_msg>Replace deprecated `mem::uninitialized`<commit_after>extern crate x264_sys as ffi;

use std::mem;
use ffi::x264::*;
use std::ptr::null;
use std::os::raw::c_int;
use std::ffi::CString;

pub struct Picture {
    pic: x264_picture_t,
    plane_size: [usize; 3],
    native: bool,
}

struct ColorspaceScale {
    w: [usize; 3],
    h: [usize; 3],
}
fn scale_from_csp(csp: u32) -> ColorspaceScale {
    if csp == X264_CSP_I420 {
        ColorspaceScale {
            w: [256 * 1, 256 / 2, 256 / 2],
            h: [256 * 1, 256 / 2, 256 / 2],
        }
    } else if csp == X264_CSP_YV12 {
        ColorspaceScale {
            w: [256 * 1, 256 / 2, 256 / 2],
            h: [256 * 1, 256 / 2, 256 / 2],
        }
    } else if csp == X264_CSP_NV12 {
        ColorspaceScale {
            w: [256 * 1, 256 * 1, 0],
            h: [256 * 1, 256 / 2, 0],
        }
    } else if csp == X264_CSP_NV21 {
        ColorspaceScale {
            w: [256 * 1, 256 * 1, 0],
            h: [256 * 1, 256 / 2, 0],
        }
    } else if csp == X264_CSP_I422 {
        ColorspaceScale {
            w: [256 * 1, 256 / 2, 256 / 2],
            h: [256 * 1, 256 * 1, 256 * 1],
        }
    } else if csp == X264_CSP_YV16 {
        ColorspaceScale {
            w: [256 * 1, 256 / 2, 256 / 2],
            h: [256 * 1, 256 * 1, 256 * 1],
        }
    } else if csp == X264_CSP_NV16 {
        ColorspaceScale {
            w: [256 * 1, 256 * 1, 0],
            h: [256 * 1, 256 * 1, 0],
        }
        /*
    } else if csp == X264_CSP_YUYV {
        ColorspaceScale {
            w: [256 * 2, 0, 0],
            h: [256 * 1, 0, 0],
        }
    } else if csp == X264_CSP_UYVY {
        ColorspaceScale {
            w: [256 * 2, 0, 0],
            h: [256 * 1, 0, 0],
        }
        */
    } else if csp == X264_CSP_I444 {
        ColorspaceScale {
            w: [256 * 1, 256 * 1, 256 * 1],
            h: [256 * 1, 256 * 1, 256 * 1],
        }
    } else if csp == X264_CSP_YV24 {
        ColorspaceScale {
            w: [256 * 1, 256 * 1, 256 * 1],
            h: [256 * 1, 256 * 1, 256 * 1],
        }
    } else if csp == X264_CSP_BGR {
        ColorspaceScale {
            w: [256 * 3, 0, 0],
            h: [256 * 1, 0, 0],
        }
    } else if csp == X264_CSP_BGRA {
        ColorspaceScale {
            w: [256 * 4, 0, 0],
            h: [256 * 1, 0, 0],
        }
    } else if csp == X264_CSP_RGB {
        ColorspaceScale {
            w: [256 * 3, 0, 0],
            h: [256 * 1, 0, 0],
        }
    } else {
        unreachable!()
    }
}

impl Picture {
    /*
    pub fn new() -> Picture {
        let mut pic = unsafe { mem::uninitialized() };

        unsafe { x264_picture_init(&mut pic as *mut x264_picture_t) };

        Picture { pic: pic }
    }
*/
    pub fn from_param(param: &Param) -> Result<Picture, &'static str> {
        let mut pic: mem::MaybeUninit<x264_picture_t> = mem::MaybeUninit::uninit();

        let ret = unsafe {
            x264_picture_alloc(pic.as_mut_ptr(),
                               param.par.i_csp,
                               param.par.i_width,
                               param.par.i_height)
        };
        if ret < 0 {
            Err("Allocation Failure")
        } else {
            let pic = unsafe{ pic.assume_init() };

            let scale = scale_from_csp(param.par.i_csp as u32 & X264_CSP_MASK as u32);
            let bytes = 1 + (param.par.i_csp as u32 & X264_CSP_HIGH_DEPTH as u32);
            let mut plane_size = [0; 3];

            for i in 0..pic.img.i_plane as usize {
                plane_size[i] = param.par.i_width as usize * scale.w[i] / 256 * bytes as usize *
                                param.par.i_height as usize *
                                scale.h[i] / 256;
            }

            Ok(Picture {
                   pic: pic,
                   plane_size: plane_size,
                   native: true,
               })
        }
    }

    pub fn as_slice<'a>(&'a self, plane: usize) -> Result<&'a [u8], &'static str> {
        if plane > self.pic.img.i_plane as usize {
            Err("Invalid Argument")
        } else {
            let size = self.plane_size[plane];
            Ok(unsafe { std::slice::from_raw_parts(self.pic.img.plane[plane], size) })
        }
    }

    pub fn as_mut_slice<'a>(&'a mut self, plane: usize) -> Result<&'a mut [u8], &'static str> {
        if plane > self.pic.img.i_plane as usize {
            Err("Invalid Argument")
        } else {
            let size = self.plane_size[plane];
            Ok(unsafe { std::slice::from_raw_parts_mut(self.pic.img.plane[plane], size) })
        }
    }

    pub fn set_timestamp(mut self, pts: i64) -> Picture {
        self.pic.i_pts = pts;
        self
    }
}

impl Drop for Picture {
    fn drop(&mut self) {
        if self.native {
            unsafe { x264_picture_clean(&mut self.pic as *mut x264_picture_t) };
        }
    }
}

// TODO: Provide a builder API instead?
pub struct Param {
    par: x264_param_t,
}

impl Param {
    pub fn new() -> Param {
        let mut par: mem::MaybeUninit<x264_param_t> = mem::MaybeUninit::uninit();

        let par = unsafe {
            x264_param_default(par.as_mut_ptr());
            par.assume_init()
        };

        Param { par: par }
    }
    pub fn default_preset<'a, 'b, Oa, Ob>(tune: Oa, preset: Ob) -> Result<Param, &'static str>
        where Oa: Into<Option<&'a str>>,
              Ob: Into<Option<&'b str>>
    {
        let mut par: mem::MaybeUninit<x264_param_t> = mem::MaybeUninit::uninit();
        let t = tune.into().map_or_else(|| None, |v| Some(CString::new(v).unwrap()));
        let p = preset.into().map_or_else(|| None, |v| Some(CString::new(v).unwrap()));

        let c_tune = t.map_or_else(|| null(), |v| v.as_ptr() as *const i8);
        let c_preset = p.map_or_else(|| null(), |v| v.as_ptr() as *const i8);
        match unsafe {
                  x264_param_default_preset(par.as_mut_ptr(), c_tune, c_preset)
              } {
            -1 => Err("Invalid Argument"),
            0 => Ok(Param { par: unsafe{ par.assume_init() } }),
            _ => Err("Unexpected"),
        }
    }
    pub fn apply_profile(mut self, profile: &str) -> Result<Param, &'static str> {
        let p = CString::new(profile).unwrap();
        match unsafe { x264_param_apply_profile(&mut self.par, p.as_ptr() as *const i8) } {
            -1 => Err("Invalid Argument"),
            0 => Ok(self),
            _ => Err("Unexpected"),
        }
    }
    pub fn param_parse<'a>(mut self, name: &str, value: &str) -> Result<Param, &'static str> {
        let n = CString::new(name).unwrap();
        let v = CString::new(value).unwrap();
        match unsafe {
                  x264_param_parse(&mut self.par,
                                   n.as_ptr() as *const i8,
                                   v.as_ptr() as *const i8)
              } {
            -1 => Err("Invalid Argument"),
            0 => Ok(self),
            _ => Err("Unexpected"),
        }
    }
    pub fn set_dimension(mut self, height: usize, width: usize) -> Param {
        self.par.i_height = height as c_int;
        self.par.i_width = width as c_int;

        self
    }
}

// TODO: Expose a NAL abstraction
pub struct NalData {
    vec: Vec<u8>,
}

impl NalData {
    /*
     * x264 functions return x264_nal_t arrays that are valid only until another
     * function of that kind is called.
     *
     * Always copy the data over.
     *
     * TODO: Consider using Bytes as backing store.
     */
    fn from_nals(c_nals: *mut x264_nal_t, nb_nal: usize) -> NalData {
        let mut data = NalData { vec: Vec::new() };

        for i in 0..nb_nal {
            let nal = unsafe { Box::from_raw(c_nals.offset(i as isize)) };

            let payload =
                unsafe { std::slice::from_raw_parts(nal.p_payload, nal.i_payload as usize) };

            data.vec.extend_from_slice(payload);

            mem::forget(payload);
            mem::forget(nal);
        }

        data
    }

    pub fn as_bytes(&self) -> &[u8] {
        self.vec.as_slice()
    }
}

pub struct Encoder {
    enc: *mut x264_t,
}

impl Encoder {
    pub fn open(par: &mut Param) -> Result<Encoder, &'static str> {
        let enc = unsafe { x264_encoder_open(&mut par.par as *mut x264_param_t) };

        if enc.is_null() {
            Err("Out of Memory")
        } else {
            Ok(Encoder { enc: enc })
        }
    }

    pub fn get_headers(&mut self) -> Result<NalData, &'static str> {
        let mut nb_nal: c_int = 0;
        let mut c_nals: mem::MaybeUninit<*mut x264_nal_t> = mem::MaybeUninit::uninit();

        let bytes = unsafe {
            x264_encoder_headers(self.enc,
                                 c_nals.as_mut_ptr(),
                                 &mut nb_nal as *mut c_int)
        };

        if bytes < 0 {
            Err("Encoding Headers Failed")
        } else {
            let c_nals = unsafe{ c_nals.assume_init() };
            Ok(NalData::from_nals(c_nals, nb_nal as usize))
        }
    }

    pub fn encode<'a, P>(&mut self, pic: P) -> Result<Option<(NalData, i64, i64)>, &'static str>
        where P: Into<Option<&'a Picture>>
    {
        let mut pic_out: mem::MaybeUninit<x264_picture_t> = mem::MaybeUninit::uninit();
        let mut c_nals : mem::MaybeUninit<*mut x264_nal_t> = mem::MaybeUninit::uninit();
        let mut nb_nal: c_int = 0;
        let c_pic = pic.into().map_or_else(|| null(), |v| &v.pic as *const x264_picture_t);

        let ret = unsafe {
            x264_encoder_encode(self.enc,
                                c_nals.as_mut_ptr(),
                                &mut nb_nal as *mut c_int,
                                c_pic as *mut x264_picture_t,
                                pic_out.as_mut_ptr())
        };
        if ret < 0 {
            Err("Error encoding")
        } else {
            let pic_out = unsafe { pic_out.assume_init() };
            let c_nals = unsafe { c_nals.assume_init() };

            if nb_nal > 0 {
                let data = NalData::from_nals(c_nals, nb_nal as usize);
                Ok(Some((data, pic_out.i_pts, pic_out.i_dts)))
            } else {
                Ok(None)
            }
        }
    }

    pub fn delayed_frames(&self) -> bool {
        unsafe { x264_encoder_delayed_frames(self.enc) != 0 }
    }
}

impl Drop for Encoder {
    fn drop(&mut self) {
        unsafe { x264_encoder_close(self.enc) };
    }
}

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

    #[test]
    fn test_open() {
        let mut par = Param::new().set_dimension(640, 480);

        let mut enc = Encoder::open(&mut par).unwrap();

        let headers = enc.get_headers().unwrap();

        println!("Headers len {}", headers.as_bytes().len());
    }

    #[test]
    fn test_picture() {
        let par = Param::new().set_dimension(640, 480);
        {
            let mut pic = Picture::from_param(&par).unwrap();
            {
                let p = pic.as_mut_slice(0).unwrap();
                p[0] = 1;
            }
            let p = pic.as_slice(0).unwrap();

            assert_eq!(p[0], 1);
        }
    }

    #[test]
    fn test_encode() {
        let mut par = Param::new().set_dimension(640, 480);
        let mut enc = Encoder::open(&mut par).unwrap();
        let mut pic = Picture::from_param(&par).unwrap();

        let headers = enc.get_headers().unwrap();

        println!("Headers len {}", headers.as_bytes().len());

        for pts in 0..5 {
            pic = pic.set_timestamp(pts as i64);
            let ret = enc.encode(&pic).unwrap();
            match ret {
                Some((_, pts, dts)) => println!("Frame pts {}, dts {}", pts, dts),
                _ => (),
            }
        }

        while enc.delayed_frames() {
            let ret = enc.encode(None).unwrap();
            match ret {
                Some((_, pts, dts)) => println!("Frame pts {}, dts {}", pts, dts),
                _ => (),
            }
        }
    }
}
<|endoftext|>


<commit_before>#![feature(core, collections, io, path)]

extern crate tcod;

pub mod engine;
pub mod gui;
pub mod util;
<commit_msg>rustup: Remove collections feature<commit_after>#![feature(core, io, path)]

extern crate tcod;

pub mod engine;
pub mod gui;
pub mod util;
<|endoftext|>


<commit_before>extern crate tcod;

pub mod engine;
pub mod gui;
pub mod util;
<commit_msg>Allow glob imports<commit_after>#![feature(globs)]

extern crate tcod;

pub mod engine;
pub mod gui;
pub mod util;
<|endoftext|>