<commit_before>#![feature(macro_rules)]

#![crate_id="sdl2_image#sdl2_image:0.1"]
#![crate_type = "lib"]
#![desc = "SDL2_image bindings and wrappers"]
#![comment = "SDL2_image bindings and wrappers"]
#![license = "MIT"]

extern crate sdl2;
extern crate libc;

use libc::{c_int, c_char};
use std::ptr;
use sdl2::surface::Surface;
use sdl2::render::Texture;
use sdl2::render::Renderer;
use sdl2::rwops::RWops;
use sdl2::version::Version;
use sdl2::get_error;

// Setup linking for all targets.
#[cfg(target_os="macos")]
mod mac {
    #[cfg(mac_framework)]
    #[link(kind="framework", name="SDL2_image")]
    extern {}

    #[cfg(not(mac_framework))]
    #[link(name="SDL2_image")]
    extern {}
}

#[cfg(target_os="win32")]
#[cfg(target_os="linux")]
#[cfg(target_os="freebsd")]
mod others {
    #[link(name="SDL2_image")]
    extern {}
}

#[allow(non_camel_case_types, dead_code)]
mod ffi;

/// InitFlags are passed to init() to control which subsystem
/// functionality to load.
bitflags!(flags InitFlag : u32 {
    static InitJpg = ffi::IMG_INIT_JPG as u32,
    static InitPng = ffi::IMG_INIT_PNG as u32,
    static InitTif = ffi::IMG_INIT_TIF as u32,
    static InitWebp = ffi::IMG_INIT_WEBP as u32
})

/// Static method extensions for creating Surfaces
pub trait LoadSurface {
    // Self is only returned here to type hint to the compiler.
    // The syntax for type hinting in this case is not yet defined.
    // The intended return value is Result<~Surface, ~str>.
    fn from_file(filename: &Path) -> Result<Self, ~str>;
    fn from_xpm_array(xpm: **i8) -> Result<Self, ~str>;
}

/// Method extensions to Surface for saving to disk
pub trait SaveSurface {
    fn save(&self, filename: &Path) -> Result<(), ~str>;
    fn save_rw(&self, dst: &mut RWops) -> Result<(), ~str>;
}

impl LoadSurface for Surface {
    fn from_file(filename: &Path) -> Result<Surface, ~str> {
        //! Loads an SDL Surface from a file
        unsafe {
            let raw = ffi::IMG_Load(filename.to_c_str().unwrap());
            if raw == ptr::null() {
                Err(get_error())
            } else {
                Ok(Surface { raw: raw, owned: true })
            }
        }
    }

    fn from_xpm_array(xpm: **i8) -> Result<Surface, ~str> {
        //! Loads an SDL Surface from XPM data
        unsafe {
            let raw = ffi::IMG_ReadXPMFromArray(xpm as **c_char);
            if raw == ptr::null() {
                Err(get_error())
            } else {
                Ok(Surface { raw: raw, owned: true })
            }
        }
    }
}

impl SaveSurface for Surface {
    fn save(&self, filename: &Path) -> Result<(), ~str> {
        //! Saves an SDL Surface to a file
        unsafe {
            let status = ffi::IMG_SavePNG(self.raw,
                                          filename.to_c_str().unwrap());
            if status != 0 {
                Err(get_error())
            } else {
                Ok(())
            }
        }
    }

    fn save_rw(&self, dst: &mut RWops) -> Result<(), ~str> {
        //! Saves an SDL Surface to an RWops
        unsafe {
            let status = ffi::IMG_SavePNG_RW(self.raw, dst.raw, 0);

            if status != 0 {
                Err(get_error())
            } else {
                Ok(())
            }
        }
    }
}

/// Method extensions for creating Textures from a Renderer
pub trait LoadTexture {
    fn load_texture(&self, filename: &Path) -> Result<Texture, ~str>;
}

impl LoadTexture for Renderer {
    fn load_texture(&self, filename: &Path) -> Result<Texture, ~str> {
        //! Loads an SDL Texture from a file
        unsafe {
            let raw = ffi::IMG_LoadTexture(self.raw,
                                           filename.to_c_str().unwrap());
            if raw == ptr::null() {
                Err(get_error())
            } else {
                Ok(Texture{ raw: raw, owned: true })
            }
        }
    }
}

pub fn init(flags: InitFlag) -> InitFlag {
    //! Initializes SDL2_image with InitFlags and returns which
    //! InitFlags were actually used.
    unsafe {
        let used = ffi::IMG_Init(flags.bits() as c_int);
        InitFlag::from_bits(used as u32)
    }
}

pub fn quit() {
    //! Teardown the SDL2_Image subsystem
    unsafe { ffi::IMG_Quit(); }
}

pub fn get_linked_version() -> Version {
    //! Returns the version of the dynamically linked SDL_image library
    unsafe {
        Version::from_ll(ffi::IMG_Linked_Version())
    }
}

#[inline]
fn to_surface_result(raw: *sdl2::surface::ll::SDL_Surface) -> Result<Surface, ~str> {
    if raw == ptr::null() {
        Err(get_error())
    } else {
        Ok(Surface { raw: raw, owned: true })
    }
}

pub trait ImageRWops {
    /// load as a surface. except TGA
    fn load(&self) -> Result<Surface, ~str>;
    /// load as a surface. This can load all supported image formats.
    fn load_typed(&self, _type: &str) -> Result<Surface, ~str>;

    fn load_cur(&self) -> Result<Surface, ~str>;
    fn load_ico(&self) -> Result<Surface, ~str>;
    fn load_bmp(&self) -> Result<Surface, ~str>;
    fn load_pnm(&self) -> Result<Surface, ~str>;
    fn load_xpm(&self) -> Result<Surface, ~str>;
    fn load_xcf(&self) -> Result<Surface, ~str>;
    fn load_pcx(&self) -> Result<Surface, ~str>;
    fn load_gif(&self) -> Result<Surface, ~str>;
    fn load_jpg(&self) -> Result<Surface, ~str>;
    fn load_tif(&self) -> Result<Surface, ~str>;
    fn load_png(&self) -> Result<Surface, ~str>;
    fn load_tga(&self) -> Result<Surface, ~str>;
    fn load_lbm(&self) -> Result<Surface, ~str>;
    fn load_xv(&self)  -> Result<Surface, ~str>;
    fn load_webp(&self) -> Result<Surface, ~str>;

    fn is_cur(&self) -> bool;
    fn is_ico(&self) -> bool;
    fn is_bmp(&self) -> bool;
    fn is_pnm(&self) -> bool;
    fn is_xpm(&self) -> bool;
    fn is_xcf(&self) -> bool;
    fn is_pcx(&self) -> bool;
    fn is_gif(&self) -> bool;
    fn is_jpg(&self) -> bool;
    fn is_tif(&self) -> bool;
    fn is_png(&self) -> bool;
    fn is_lbm(&self) -> bool;
    fn is_xv(&self)  -> bool;
    fn is_webp(&self) -> bool;
}

impl ImageRWops for RWops {
    fn load(&self) -> Result<Surface, ~str> {
        let raw = unsafe {
            ffi::IMG_Load_RW(self.raw, 0)
        };
        to_surface_result(raw)
    }
    fn load_typed(&self, _type: &str) -> Result<Surface, ~str> {
        let raw = unsafe {
            ffi::IMG_LoadTyped_RW(self.raw, 0, _type.to_c_str().unwrap())
        };
        to_surface_result(raw)
    }

    fn load_cur(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadCUR_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_ico(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadICO_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_bmp(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadBMP_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_pnm(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadPNM_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_xpm(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadXPM_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_xcf(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadXCF_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_pcx(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadPCX_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_gif(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadGIF_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_jpg(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadJPG_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_tif(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadTIF_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_png(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadPNG_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_tga(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadTGA_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_lbm(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadLBM_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_xv(&self)  -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadXV_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_webp(&self)  -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadWEBP_RW(self.raw) };
        to_surface_result(raw)
    }

    fn is_cur(&self) -> bool {
        unsafe { ffi::IMG_isCUR(self.raw) == 1 }
    }
    fn is_ico(&self) -> bool {
        unsafe { ffi::IMG_isICO(self.raw) == 1 }
    }
    fn is_bmp(&self) -> bool {
        unsafe { ffi::IMG_isBMP(self.raw) == 1 }
    }
    fn is_pnm(&self) -> bool {
        unsafe { ffi::IMG_isPNM(self.raw) == 1 }
    }
    fn is_xpm(&self) -> bool {
        unsafe { ffi::IMG_isXPM(self.raw) == 1 }
    }
    fn is_xcf(&self) -> bool {
        unsafe { ffi::IMG_isXCF(self.raw) == 1 }
    }
    fn is_pcx(&self) -> bool {
        unsafe { ffi::IMG_isPCX(self.raw) == 1 }
    }
    fn is_gif(&self) -> bool {
        unsafe { ffi::IMG_isGIF(self.raw) == 1 }
    }
    fn is_jpg(&self) -> bool {
        unsafe { ffi::IMG_isJPG(self.raw) == 1 }
    }
    fn is_tif(&self) -> bool {
        unsafe { ffi::IMG_isTIF(self.raw) == 1 }
    }
    fn is_png(&self) -> bool {
        unsafe { ffi::IMG_isPNG(self.raw) == 1 }
    }
    fn is_lbm(&self) -> bool {
        unsafe { ffi::IMG_isLBM(self.raw) == 1 }
    }
    fn is_xv(&self)  -> bool {
        unsafe { ffi::IMG_isXV(self.raw)  == 1 }
    }
    fn is_webp(&self) -> bool {
        unsafe { ffi::IMG_isWEBP(self.raw)  == 1 }
    }
}
<commit_msg>fix build error: change from_bits to from_bits_truncate, avoid Option<> wrapper<commit_after>#![feature(macro_rules)]

#![crate_id="sdl2_image#sdl2_image:0.1"]
#![crate_type = "lib"]
#![desc = "SDL2_image bindings and wrappers"]
#![comment = "SDL2_image bindings and wrappers"]
#![license = "MIT"]

extern crate sdl2;
extern crate libc;

use libc::{c_int, c_char};
use std::ptr;
use sdl2::surface::Surface;
use sdl2::render::Texture;
use sdl2::render::Renderer;
use sdl2::rwops::RWops;
use sdl2::version::Version;
use sdl2::get_error;

// Setup linking for all targets.
#[cfg(target_os="macos")]
mod mac {
    #[cfg(mac_framework)]
    #[link(kind="framework", name="SDL2_image")]
    extern {}

    #[cfg(not(mac_framework))]
    #[link(name="SDL2_image")]
    extern {}
}

#[cfg(target_os="win32")]
#[cfg(target_os="linux")]
#[cfg(target_os="freebsd")]
mod others {
    #[link(name="SDL2_image")]
    extern {}
}

#[allow(non_camel_case_types, dead_code)]
mod ffi;

/// InitFlags are passed to init() to control which subsystem
/// functionality to load.
bitflags!(flags InitFlag : u32 {
    static InitJpg = ffi::IMG_INIT_JPG as u32,
    static InitPng = ffi::IMG_INIT_PNG as u32,
    static InitTif = ffi::IMG_INIT_TIF as u32,
    static InitWebp = ffi::IMG_INIT_WEBP as u32
})

/// Static method extensions for creating Surfaces
pub trait LoadSurface {
    // Self is only returned here to type hint to the compiler.
    // The syntax for type hinting in this case is not yet defined.
    // The intended return value is Result<~Surface, ~str>.
    fn from_file(filename: &Path) -> Result<Self, ~str>;
    fn from_xpm_array(xpm: **i8) -> Result<Self, ~str>;
}

/// Method extensions to Surface for saving to disk
pub trait SaveSurface {
    fn save(&self, filename: &Path) -> Result<(), ~str>;
    fn save_rw(&self, dst: &mut RWops) -> Result<(), ~str>;
}

impl LoadSurface for Surface {
    fn from_file(filename: &Path) -> Result<Surface, ~str> {
        //! Loads an SDL Surface from a file
        unsafe {
            let raw = ffi::IMG_Load(filename.to_c_str().unwrap());
            if raw == ptr::null() {
                Err(get_error())
            } else {
                Ok(Surface { raw: raw, owned: true })
            }
        }
    }

    fn from_xpm_array(xpm: **i8) -> Result<Surface, ~str> {
        //! Loads an SDL Surface from XPM data
        unsafe {
            let raw = ffi::IMG_ReadXPMFromArray(xpm as **c_char);
            if raw == ptr::null() {
                Err(get_error())
            } else {
                Ok(Surface { raw: raw, owned: true })
            }
        }
    }
}

impl SaveSurface for Surface {
    fn save(&self, filename: &Path) -> Result<(), ~str> {
        //! Saves an SDL Surface to a file
        unsafe {
            let status = ffi::IMG_SavePNG(self.raw,
                                          filename.to_c_str().unwrap());
            if status != 0 {
                Err(get_error())
            } else {
                Ok(())
            }
        }
    }

    fn save_rw(&self, dst: &mut RWops) -> Result<(), ~str> {
        //! Saves an SDL Surface to an RWops
        unsafe {
            let status = ffi::IMG_SavePNG_RW(self.raw, dst.raw, 0);

            if status != 0 {
                Err(get_error())
            } else {
                Ok(())
            }
        }
    }
}

/// Method extensions for creating Textures from a Renderer
pub trait LoadTexture {
    fn load_texture(&self, filename: &Path) -> Result<Texture, ~str>;
}

impl LoadTexture for Renderer {
    fn load_texture(&self, filename: &Path) -> Result<Texture, ~str> {
        //! Loads an SDL Texture from a file
        unsafe {
            let raw = ffi::IMG_LoadTexture(self.raw,
                                           filename.to_c_str().unwrap());
            if raw == ptr::null() {
                Err(get_error())
            } else {
                Ok(Texture{ raw: raw, owned: true })
            }
        }
    }
}

pub fn init(flags: InitFlag) -> InitFlag {
    //! Initializes SDL2_image with InitFlags and returns which
    //! InitFlags were actually used.
    unsafe {
        let used = ffi::IMG_Init(flags.bits() as c_int);
        InitFlag::from_bits_truncate(used as u32)
    }
}

pub fn quit() {
    //! Teardown the SDL2_Image subsystem
    unsafe { ffi::IMG_Quit(); }
}

pub fn get_linked_version() -> Version {
    //! Returns the version of the dynamically linked SDL_image library
    unsafe {
        Version::from_ll(ffi::IMG_Linked_Version())
    }
}

#[inline]
fn to_surface_result(raw: *sdl2::surface::ll::SDL_Surface) -> Result<Surface, ~str> {
    if raw == ptr::null() {
        Err(get_error())
    } else {
        Ok(Surface { raw: raw, owned: true })
    }
}

pub trait ImageRWops {
    /// load as a surface. except TGA
    fn load(&self) -> Result<Surface, ~str>;
    /// load as a surface. This can load all supported image formats.
    fn load_typed(&self, _type: &str) -> Result<Surface, ~str>;

    fn load_cur(&self) -> Result<Surface, ~str>;
    fn load_ico(&self) -> Result<Surface, ~str>;
    fn load_bmp(&self) -> Result<Surface, ~str>;
    fn load_pnm(&self) -> Result<Surface, ~str>;
    fn load_xpm(&self) -> Result<Surface, ~str>;
    fn load_xcf(&self) -> Result<Surface, ~str>;
    fn load_pcx(&self) -> Result<Surface, ~str>;
    fn load_gif(&self) -> Result<Surface, ~str>;
    fn load_jpg(&self) -> Result<Surface, ~str>;
    fn load_tif(&self) -> Result<Surface, ~str>;
    fn load_png(&self) -> Result<Surface, ~str>;
    fn load_tga(&self) -> Result<Surface, ~str>;
    fn load_lbm(&self) -> Result<Surface, ~str>;
    fn load_xv(&self)  -> Result<Surface, ~str>;
    fn load_webp(&self) -> Result<Surface, ~str>;

    fn is_cur(&self) -> bool;
    fn is_ico(&self) -> bool;
    fn is_bmp(&self) -> bool;
    fn is_pnm(&self) -> bool;
    fn is_xpm(&self) -> bool;
    fn is_xcf(&self) -> bool;
    fn is_pcx(&self) -> bool;
    fn is_gif(&self) -> bool;
    fn is_jpg(&self) -> bool;
    fn is_tif(&self) -> bool;
    fn is_png(&self) -> bool;
    fn is_lbm(&self) -> bool;
    fn is_xv(&self)  -> bool;
    fn is_webp(&self) -> bool;
}

impl ImageRWops for RWops {
    fn load(&self) -> Result<Surface, ~str> {
        let raw = unsafe {
            ffi::IMG_Load_RW(self.raw, 0)
        };
        to_surface_result(raw)
    }
    fn load_typed(&self, _type: &str) -> Result<Surface, ~str> {
        let raw = unsafe {
            ffi::IMG_LoadTyped_RW(self.raw, 0, _type.to_c_str().unwrap())
        };
        to_surface_result(raw)
    }

    fn load_cur(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadCUR_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_ico(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadICO_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_bmp(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadBMP_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_pnm(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadPNM_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_xpm(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadXPM_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_xcf(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadXCF_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_pcx(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadPCX_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_gif(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadGIF_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_jpg(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadJPG_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_tif(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadTIF_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_png(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadPNG_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_tga(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadTGA_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_lbm(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadLBM_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_xv(&self)  -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadXV_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_webp(&self)  -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadWEBP_RW(self.raw) };
        to_surface_result(raw)
    }

    fn is_cur(&self) -> bool {
        unsafe { ffi::IMG_isCUR(self.raw) == 1 }
    }
    fn is_ico(&self) -> bool {
        unsafe { ffi::IMG_isICO(self.raw) == 1 }
    }
    fn is_bmp(&self) -> bool {
        unsafe { ffi::IMG_isBMP(self.raw) == 1 }
    }
    fn is_pnm(&self) -> bool {
        unsafe { ffi::IMG_isPNM(self.raw) == 1 }
    }
    fn is_xpm(&self) -> bool {
        unsafe { ffi::IMG_isXPM(self.raw) == 1 }
    }
    fn is_xcf(&self) -> bool {
        unsafe { ffi::IMG_isXCF(self.raw) == 1 }
    }
    fn is_pcx(&self) -> bool {
        unsafe { ffi::IMG_isPCX(self.raw) == 1 }
    }
    fn is_gif(&self) -> bool {
        unsafe { ffi::IMG_isGIF(self.raw) == 1 }
    }
    fn is_jpg(&self) -> bool {
        unsafe { ffi::IMG_isJPG(self.raw) == 1 }
    }
    fn is_tif(&self) -> bool {
        unsafe { ffi::IMG_isTIF(self.raw) == 1 }
    }
    fn is_png(&self) -> bool {
        unsafe { ffi::IMG_isPNG(self.raw) == 1 }
    }
    fn is_lbm(&self) -> bool {
        unsafe { ffi::IMG_isLBM(self.raw) == 1 }
    }
    fn is_xv(&self)  -> bool {
        unsafe { ffi::IMG_isXV(self.raw)  == 1 }
    }
    fn is_webp(&self) -> bool {
        unsafe { ffi::IMG_isWEBP(self.raw)  == 1 }
    }
}
<|endoftext|>


<commit_before>
use hybrid_clocks::{Timestamp, WallT};
use serde_json;
use uuid::Uuid;

#[macro_export]
macro_rules! enum_str {
    ($name:ident { $($variant:ident($str:expr), )* }) => {
        #[derive(Clone, Copy, Debug, Eq, PartialEq)]
        pub enum $name {
            $($variant,)*
        }

        impl ::serde::Serialize for $name {
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
                where S: ::serde::Serializer,
            {
                // Serialize the enum as a string.
                serializer.serialize_str(match *self {
                    $( $name::$variant => $str, )*
                })
            }
        }

        impl ::serde::Deserialize for $name {
            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
                where D: ::serde::Deserializer,
            {
                struct Visitor;

                impl ::serde::de::Visitor for Visitor {
                    type Value = $name;

                    fn visit_str<E>(self, value: &str) -> Result<$name, E>
                        where E: ::serde::de::Error,
                    {
                        match value {
                            $( $str => Ok($name::$variant), )*
                            _ => Err(E::invalid_value(::serde::de::Unexpected::Str(&value), &self))
                        }
                    }

                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                        formatter.write_str(&format!("{} enumeration", stringify!($name)))
                    }
                }

                // Deserialize the enum from a string.
                deserializer.deserialize_str(Visitor)
            }
        }
    }
}

#[derive(Debug, Serialize, Deserialize, Copy, Clone)]
pub enum CRDT {
    LWW,
    GSET,
    ORSET,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Log {
    pub id: Uuid,
    pub owner: Uuid,
    pub prev: Option<Uuid>,
    pub next: Option<Uuid>,
    pub when: Timestamp<WallT>,
    pub data: serde_json::Value,
}
<commit_msg>Apparently "cargo fmt" doesn't get everything in one go...<commit_after>use hybrid_clocks::{Timestamp, WallT};
use serde_json;
use uuid::Uuid;

#[macro_export]
macro_rules! enum_str {
    ($name:ident { $($variant:ident($str:expr), )* }) => {
        #[derive(Clone, Copy, Debug, Eq, PartialEq)]
        pub enum $name {
            $($variant,)*
        }

        impl ::serde::Serialize for $name {
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
                where S: ::serde::Serializer,
            {
                // Serialize the enum as a string.
                serializer.serialize_str(match *self {
                    $( $name::$variant => $str, )*
                })
            }
        }

        impl ::serde::Deserialize for $name {
            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
                where D: ::serde::Deserializer,
            {
                struct Visitor;

                impl ::serde::de::Visitor for Visitor {
                    type Value = $name;

                    fn visit_str<E>(self, value: &str) -> Result<$name, E>
                        where E: ::serde::de::Error,
                    {
                        match value {
                            $( $str => Ok($name::$variant), )*
                            _ => Err(E::invalid_value(::serde::de::Unexpected::Str(&value), &self))
                        }
                    }

                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                        formatter.write_str(&format!("{} enumeration", stringify!($name)))
                    }
                }

                // Deserialize the enum from a string.
                deserializer.deserialize_str(Visitor)
            }
        }
    }
}

#[derive(Debug, Serialize, Deserialize, Copy, Clone)]
pub enum CRDT {
    LWW,
    GSET,
    ORSET,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Log {
    pub id: Uuid,
    pub owner: Uuid,
    pub prev: Option<Uuid>,
    pub next: Option<Uuid>,
    pub when: Timestamp<WallT>,
    pub data: serde_json::Value,
}
<|endoftext|>


<commit_before>//! Register pressure tracking.
//!
//! SSA-based register allocation depends on a spilling phase that "lowers register pressure
//! sufficiently". This module defines the data structures needed to measure register pressure
//! accurately enough to guarantee that the coloring phase will not run out of registers.
//!
//! Ideally, measuring register pressure amounts to simply counting the number of live registers at
//! any given program point. This simplistic method has two problems:
//!
//! 1. Registers are not interchangeable. Most ISAs have separate integer and floating-point
//!    register banks, so we need to at least count the number of live registers in each register
//!    bank separately.
//!
//! 2. Some ISAs have complicated register aliasing properties. In particular, the 32-bit ARM
//!    ISA has a floating-point register bank where two 32-bit registers alias one 64-bit register.
//!    This makes it difficult to accurately measure register pressure.
//!
//! This module deals with the problems via *register banks* and *top-level register classes*.
//! Register classes in different register banks are completely independent, so we can count
//! registers in one bank without worrying about the other bank at all.
//!
//! All register classes have a unique top-level register class, and we will count registers for
//! each top-level register class individually. However, a register bank can have multiple
//! top-level register classes that interfere with each other, so all top-level counts need to
//! be considered when determining how many more registers can be allocated.
//!
//! Currently, the only register bank with multiple top-level registers is the `arm32`
//! floating-point register bank which has `S`, `D`, and `Q` top-level classes.
//!
//! # Base and transient counts
//!
//! We maintain two separate register counts per top-level register class: base counts and
//! transient counts. The base counts are adjusted with the `take` and `free` functions. The
//! transient counts are adjusted with `take_transient` and `free_transient`.

// Remove once we're using the pressure tracker.
#![allow(dead_code)]

use isa::registers::{RegInfo, MAX_TOPRCS, RegClass, RegClassMask};
use regalloc::AllocatableSet;
use std::cmp::min;
use std::fmt;
use std::iter::ExactSizeIterator;

/// Information per top-level register class.
///
/// Everything but the counts is static information computed from the constructor arguments.
#[derive(Default)]
struct TopRC {
    // Number of registers currently used from this register class.
    base_count: u32,
    transient_count: u32,

    // Max number of registers that can be allocated.
    limit: u32,

    // Register units per register.
    width: u8,

    // The first aliasing top-level RC.
    first_toprc: u8,

    // The number of aliasing top-level RCs.
    num_toprcs: u8,
}

impl TopRC {
    fn total_count(&self) -> u32 {
        self.base_count + self.transient_count
    }
}

pub struct Pressure {
    // Bit mask of top-level register classes that are aliased by other top-level register classes.
    // Unaliased register classes can use a simpler interference algorithm.
    aliased: RegClassMask,

    // Current register counts per top-level register class.
    toprc: [TopRC; MAX_TOPRCS],
}

impl Pressure {
    /// Create a new register pressure tracker.
    pub fn new(reginfo: &RegInfo, usable: &AllocatableSet) -> Pressure {
        let mut p = Pressure {
            aliased: 0,
            toprc: Default::default(),
        };

        // Get the layout of aliasing top-level register classes from the register banks.
        for bank in reginfo.banks {
            let first = bank.first_toprc;
            let num = bank.num_toprcs;
            for rc in &mut p.toprc[first..first + num] {
                rc.first_toprc = first as u8;
                rc.num_toprcs = num as u8;
            }

            // Flag the top-level register classes with aliases.
            if num > 1 {
                p.aliased |= ((1 << num) - 1) << first;
            }
        }

        // Compute per-class limits from `usable`.
        for (toprc, rc) in p.toprc
                .iter_mut()
                .take_while(|t| t.num_toprcs > 0)
                .zip(reginfo.classes) {
            toprc.limit = usable.iter(rc).len() as u32;
            toprc.width = rc.width;
        }

        p
    }

    /// Check for an available register in the register class `rc`.
    ///
    /// If it is possible to allocate one more register from `rc`'s top-level register class,
    /// returns 0.
    ///
    /// If not, returns a bit-mask of top-level register classes that are interfering. Register
    /// pressure should be eased in one of the returned top-level register classes before calling
    /// `can_take()` to check again.
    fn check_avail(&self, rc: RegClass) -> RegClassMask {
        let entry = &self.toprc[rc.toprc as usize];
        let mask = 1 << rc.toprc;
        if self.aliased & mask == 0 {
            // This is a simple unaliased top-level register class.
            if entry.total_count() < entry.limit {
                0
            } else {
                mask
            }
        } else {
            // This is the more complicated case. The top-level register class has aliases.
            self.check_avail_aliased(entry)
        }
    }

    /// Check for an available register in a top-level register class that may have aliases.
    ///
    /// This is the out-of-line slow path for `check_avail()`.
    fn check_avail_aliased(&self, entry: &TopRC) -> RegClassMask {
        let first = entry.first_toprc as usize;
        let num = entry.num_toprcs as usize;
        let width = entry.width as u32;
        let ulimit = entry.limit * width;

        // Count up the number of available register units.
        let mut units = 0;
        for (rc, rci) in self.toprc[first..first + num].iter().zip(first..) {
            let rcw = rc.width as u32;
            // If `rc.width` is smaller than `width`, each register in `rc` could potentially block
            // one of ours. This is assuming that none of the smaller registers are straddling the
            // bigger ones.
            //
            // If `rc.width` is larger than `width`, we are also assuming that the registers are
            // aligned and `rc.width` is a multiple of `width`.
            let u = if rcw < width {
                // We can't take more than the total number of register units in the class.
                // This matters for arm32 S-registers which can only ever lock out 16 D-registers.
                min(rc.total_count() * width, rc.limit * rcw)
            } else {
                rc.total_count() * rcw
            };

            // If this top-level RC on its own is responsible for exceeding our limit, return it
            // early to guarantee that registers here are spilled before spilling other registers
            // unnecessarily.
            if u >= ulimit {
                return 1 << rci;
            }

            units += u;
        }

        // We've counted up the worst-case number of register units claimed by all aliasing
        // classes. Compare to the unit limit in this class.
        if units < ulimit {
            0
        } else {
            // Registers need to be spilled from any one of the aliasing classes.
            ((1 << num) - 1) << first
        }
    }

    /// Take a register from `rc`.
    ///
    /// This does not check if there are enough registers available.
    pub fn take(&mut self, rc: RegClass) {
        self.toprc[rc.toprc as usize].base_count += 1
    }

    /// Free a register in `rc`.
    pub fn free(&mut self, rc: RegClass) {
        self.toprc[rc.toprc as usize].base_count -= 1
    }

    /// Reset all counts to 0, both base and transient.
    pub fn reset(&mut self) {
        for e in &mut self.toprc {
            e.base_count = 0;
            e.transient_count = 0;
        }
    }

    /// Try to increment a transient counter.
    ///
    /// This will fail if there are not enough registers available.
    pub fn take_transient(&mut self, rc: RegClass) -> Result<(), RegClassMask> {
        let mask = self.check_avail(rc);
        if mask == 0 {
            self.toprc[rc.toprc as usize].transient_count += 1;
            Ok(())
        } else {
            Err(mask)
        }
    }

    /// Reset all transient counts to 0.
    pub fn reset_transient(&mut self) {
        for e in &mut self.toprc {
            e.transient_count = 0;
        }
    }

    /// Preserve the transient counts by transferring them to the base counts.
    pub fn preserve_transient(&mut self) {
        for e in &mut self.toprc {
            e.base_count += e.transient_count;
            e.transient_count = 0;
        }
    }
}

impl fmt::Display for Pressure {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Pressure[")?;
        for rc in &self.toprc {
            write!(f, " {}+{}/{}", rc.base_count, rc.transient_count, rc.limit)?;
        }
        write!(f, " ]")
    }
}

#[cfg(test)]
mod tests {
    use isa::{TargetIsa, RegClass};
    use regalloc::AllocatableSet;
    use std::borrow::Borrow;
    use super::Pressure;

    // Make an arm32 `TargetIsa`, if possible.
    fn arm32() -> Option<Box<TargetIsa>> {
        use settings;
        use isa;

        let shared_builder = settings::builder();
        let shared_flags = settings::Flags::new(&shared_builder);

        isa::lookup("arm32").map(|b| b.finish(shared_flags))
    }

    // Get a register class by name.
    fn rc_by_name(isa: &TargetIsa, name: &str) -> RegClass {
        isa.register_info()
            .classes
            .iter()
            .find(|rc| rc.name == name)
            .expect("Can't find named register class.")
    }

    #[test]
    fn basic_counting() {
        let isa = arm32().expect("This test requires arm32 support");
        let isa = isa.borrow();
        let gpr = rc_by_name(isa, "GPR");
        let s = rc_by_name(isa, "S");
        let reginfo = isa.register_info();
        let regs = AllocatableSet::new();

        let mut pressure = Pressure::new(&reginfo, &regs);
        let mut count = 0;
        while pressure.check_avail(gpr) == 0 {
            pressure.take(gpr);
            count += 1;
        }
        assert_eq!(count, 16);
        assert_eq!(pressure.check_avail(gpr), 1 << gpr.toprc);
        assert_eq!(pressure.check_avail(s), 0);
        pressure.free(gpr);
        assert_eq!(pressure.check_avail(gpr), 0);
        pressure.take(gpr);
        assert_eq!(pressure.check_avail(gpr), 1 << gpr.toprc);
        assert_eq!(pressure.check_avail(s), 0);
        pressure.reset();
        assert_eq!(pressure.check_avail(gpr), 0);
        assert_eq!(pressure.check_avail(s), 0);
    }

    #[test]
    fn arm_float_bank() {
        let isa = arm32().expect("This test requires arm32 support");
        let isa = isa.borrow();
        let s = rc_by_name(isa, "S");
        let d = rc_by_name(isa, "D");
        let q = rc_by_name(isa, "Q");
        let reginfo = isa.register_info();
        let regs = AllocatableSet::new();

        let mut pressure = Pressure::new(&reginfo, &regs);
        assert_eq!(pressure.check_avail(s), 0);
        assert_eq!(pressure.check_avail(d), 0);
        assert_eq!(pressure.check_avail(q), 0);

        // Allocating a single S-register should not affect availability.
        pressure.take(s);
        assert_eq!(pressure.check_avail(s), 0);
        assert_eq!(pressure.check_avail(d), 0);
        assert_eq!(pressure.check_avail(q), 0);

        pressure.take(d);
        assert_eq!(pressure.check_avail(s), 0);
        assert_eq!(pressure.check_avail(d), 0);
        assert_eq!(pressure.check_avail(q), 0);

        pressure.take(q);
        assert_eq!(pressure.check_avail(s), 0);
        assert_eq!(pressure.check_avail(d), 0);
        assert_eq!(pressure.check_avail(q), 0);

        // Take a total of 16 S-regs.
        for _ in 1..16 {
            pressure.take(s);
        }
        assert_eq!(pressure.check_avail(s), 0);
        assert_eq!(pressure.check_avail(d), 0);
        assert_eq!(pressure.check_avail(q), 0);

        // We've taken 16 S, 1 D, and 1 Q. There should be 6 more Qs.
        for _ in 0..6 {
            assert_eq!(pressure.check_avail(d), 0);
            assert_eq!(pressure.check_avail(q), 0);
            pressure.take(q);
        }

        // We've taken 16 S, 1 D, and 7 Qs.
        assert!(pressure.check_avail(s) != 0);
        assert_eq!(pressure.check_avail(d), 0);
        assert!(pressure.check_avail(q) != 0);
    }
}
<commit_msg>Only print pressure for toprcs containing registers.<commit_after>//! Register pressure tracking.
//!
//! SSA-based register allocation depends on a spilling phase that "lowers register pressure
//! sufficiently". This module defines the data structures needed to measure register pressure
//! accurately enough to guarantee that the coloring phase will not run out of registers.
//!
//! Ideally, measuring register pressure amounts to simply counting the number of live registers at
//! any given program point. This simplistic method has two problems:
//!
//! 1. Registers are not interchangeable. Most ISAs have separate integer and floating-point
//!    register banks, so we need to at least count the number of live registers in each register
//!    bank separately.
//!
//! 2. Some ISAs have complicated register aliasing properties. In particular, the 32-bit ARM
//!    ISA has a floating-point register bank where two 32-bit registers alias one 64-bit register.
//!    This makes it difficult to accurately measure register pressure.
//!
//! This module deals with the problems via *register banks* and *top-level register classes*.
//! Register classes in different register banks are completely independent, so we can count
//! registers in one bank without worrying about the other bank at all.
//!
//! All register classes have a unique top-level register class, and we will count registers for
//! each top-level register class individually. However, a register bank can have multiple
//! top-level register classes that interfere with each other, so all top-level counts need to
//! be considered when determining how many more registers can be allocated.
//!
//! Currently, the only register bank with multiple top-level registers is the `arm32`
//! floating-point register bank which has `S`, `D`, and `Q` top-level classes.
//!
//! # Base and transient counts
//!
//! We maintain two separate register counts per top-level register class: base counts and
//! transient counts. The base counts are adjusted with the `take` and `free` functions. The
//! transient counts are adjusted with `take_transient` and `free_transient`.

// Remove once we're using the pressure tracker.
#![allow(dead_code)]

use isa::registers::{RegInfo, MAX_TOPRCS, RegClass, RegClassMask};
use regalloc::AllocatableSet;
use std::cmp::min;
use std::fmt;
use std::iter::ExactSizeIterator;

/// Information per top-level register class.
///
/// Everything but the counts is static information computed from the constructor arguments.
#[derive(Default)]
struct TopRC {
    // Number of registers currently used from this register class.
    base_count: u32,
    transient_count: u32,

    // Max number of registers that can be allocated.
    limit: u32,

    // Register units per register.
    width: u8,

    // The first aliasing top-level RC.
    first_toprc: u8,

    // The number of aliasing top-level RCs.
    num_toprcs: u8,
}

impl TopRC {
    fn total_count(&self) -> u32 {
        self.base_count + self.transient_count
    }
}

pub struct Pressure {
    // Bit mask of top-level register classes that are aliased by other top-level register classes.
    // Unaliased register classes can use a simpler interference algorithm.
    aliased: RegClassMask,

    // Current register counts per top-level register class.
    toprc: [TopRC; MAX_TOPRCS],
}

impl Pressure {
    /// Create a new register pressure tracker.
    pub fn new(reginfo: &RegInfo, usable: &AllocatableSet) -> Pressure {
        let mut p = Pressure {
            aliased: 0,
            toprc: Default::default(),
        };

        // Get the layout of aliasing top-level register classes from the register banks.
        for bank in reginfo.banks {
            let first = bank.first_toprc;
            let num = bank.num_toprcs;
            for rc in &mut p.toprc[first..first + num] {
                rc.first_toprc = first as u8;
                rc.num_toprcs = num as u8;
            }

            // Flag the top-level register classes with aliases.
            if num > 1 {
                p.aliased |= ((1 << num) - 1) << first;
            }
        }

        // Compute per-class limits from `usable`.
        for (toprc, rc) in p.toprc
                .iter_mut()
                .take_while(|t| t.num_toprcs > 0)
                .zip(reginfo.classes) {
            toprc.limit = usable.iter(rc).len() as u32;
            toprc.width = rc.width;
        }

        p
    }

    /// Check for an available register in the register class `rc`.
    ///
    /// If it is possible to allocate one more register from `rc`'s top-level register class,
    /// returns 0.
    ///
    /// If not, returns a bit-mask of top-level register classes that are interfering. Register
    /// pressure should be eased in one of the returned top-level register classes before calling
    /// `can_take()` to check again.
    fn check_avail(&self, rc: RegClass) -> RegClassMask {
        let entry = &self.toprc[rc.toprc as usize];
        let mask = 1 << rc.toprc;
        if self.aliased & mask == 0 {
            // This is a simple unaliased top-level register class.
            if entry.total_count() < entry.limit {
                0
            } else {
                mask
            }
        } else {
            // This is the more complicated case. The top-level register class has aliases.
            self.check_avail_aliased(entry)
        }
    }

    /// Check for an available register in a top-level register class that may have aliases.
    ///
    /// This is the out-of-line slow path for `check_avail()`.
    fn check_avail_aliased(&self, entry: &TopRC) -> RegClassMask {
        let first = entry.first_toprc as usize;
        let num = entry.num_toprcs as usize;
        let width = entry.width as u32;
        let ulimit = entry.limit * width;

        // Count up the number of available register units.
        let mut units = 0;
        for (rc, rci) in self.toprc[first..first + num].iter().zip(first..) {
            let rcw = rc.width as u32;
            // If `rc.width` is smaller than `width`, each register in `rc` could potentially block
            // one of ours. This is assuming that none of the smaller registers are straddling the
            // bigger ones.
            //
            // If `rc.width` is larger than `width`, we are also assuming that the registers are
            // aligned and `rc.width` is a multiple of `width`.
            let u = if rcw < width {
                // We can't take more than the total number of register units in the class.
                // This matters for arm32 S-registers which can only ever lock out 16 D-registers.
                min(rc.total_count() * width, rc.limit * rcw)
            } else {
                rc.total_count() * rcw
            };

            // If this top-level RC on its own is responsible for exceeding our limit, return it
            // early to guarantee that registers here are spilled before spilling other registers
            // unnecessarily.
            if u >= ulimit {
                return 1 << rci;
            }

            units += u;
        }

        // We've counted up the worst-case number of register units claimed by all aliasing
        // classes. Compare to the unit limit in this class.
        if units < ulimit {
            0
        } else {
            // Registers need to be spilled from any one of the aliasing classes.
            ((1 << num) - 1) << first
        }
    }

    /// Take a register from `rc`.
    ///
    /// This does not check if there are enough registers available.
    pub fn take(&mut self, rc: RegClass) {
        self.toprc[rc.toprc as usize].base_count += 1
    }

    /// Free a register in `rc`.
    pub fn free(&mut self, rc: RegClass) {
        self.toprc[rc.toprc as usize].base_count -= 1
    }

    /// Reset all counts to 0, both base and transient.
    pub fn reset(&mut self) {
        for e in &mut self.toprc {
            e.base_count = 0;
            e.transient_count = 0;
        }
    }

    /// Try to increment a transient counter.
    ///
    /// This will fail if there are not enough registers available.
    pub fn take_transient(&mut self, rc: RegClass) -> Result<(), RegClassMask> {
        let mask = self.check_avail(rc);
        if mask == 0 {
            self.toprc[rc.toprc as usize].transient_count += 1;
            Ok(())
        } else {
            Err(mask)
        }
    }

    /// Reset all transient counts to 0.
    pub fn reset_transient(&mut self) {
        for e in &mut self.toprc {
            e.transient_count = 0;
        }
    }

    /// Preserve the transient counts by transferring them to the base counts.
    pub fn preserve_transient(&mut self) {
        for e in &mut self.toprc {
            e.base_count += e.transient_count;
            e.transient_count = 0;
        }
    }
}

impl fmt::Display for Pressure {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Pressure[")?;
        for rc in &self.toprc {
            if rc.limit > 0 {
                write!(f, " {}+{}/{}", rc.base_count, rc.transient_count, rc.limit)?;
            }
        }
        write!(f, " ]")
    }
}

#[cfg(test)]
mod tests {
    use isa::{TargetIsa, RegClass};
    use regalloc::AllocatableSet;
    use std::borrow::Borrow;
    use super::Pressure;

    // Make an arm32 `TargetIsa`, if possible.
    fn arm32() -> Option<Box<TargetIsa>> {
        use settings;
        use isa;

        let shared_builder = settings::builder();
        let shared_flags = settings::Flags::new(&shared_builder);

        isa::lookup("arm32").map(|b| b.finish(shared_flags))
    }

    // Get a register class by name.
    fn rc_by_name(isa: &TargetIsa, name: &str) -> RegClass {
        isa.register_info()
            .classes
            .iter()
            .find(|rc| rc.name == name)
            .expect("Can't find named register class.")
    }

    #[test]
    fn basic_counting() {
        let isa = arm32().expect("This test requires arm32 support");
        let isa = isa.borrow();
        let gpr = rc_by_name(isa, "GPR");
        let s = rc_by_name(isa, "S");
        let reginfo = isa.register_info();
        let regs = AllocatableSet::new();

        let mut pressure = Pressure::new(&reginfo, &regs);
        let mut count = 0;
        while pressure.check_avail(gpr) == 0 {
            pressure.take(gpr);
            count += 1;
        }
        assert_eq!(count, 16);
        assert_eq!(pressure.check_avail(gpr), 1 << gpr.toprc);
        assert_eq!(pressure.check_avail(s), 0);
        pressure.free(gpr);
        assert_eq!(pressure.check_avail(gpr), 0);
        pressure.take(gpr);
        assert_eq!(pressure.check_avail(gpr), 1 << gpr.toprc);
        assert_eq!(pressure.check_avail(s), 0);
        pressure.reset();
        assert_eq!(pressure.check_avail(gpr), 0);
        assert_eq!(pressure.check_avail(s), 0);
    }

    #[test]
    fn arm_float_bank() {
        let isa = arm32().expect("This test requires arm32 support");
        let isa = isa.borrow();
        let s = rc_by_name(isa, "S");
        let d = rc_by_name(isa, "D");
        let q = rc_by_name(isa, "Q");
        let reginfo = isa.register_info();
        let regs = AllocatableSet::new();

        let mut pressure = Pressure::new(&reginfo, &regs);
        assert_eq!(pressure.check_avail(s), 0);
        assert_eq!(pressure.check_avail(d), 0);
        assert_eq!(pressure.check_avail(q), 0);

        // Allocating a single S-register should not affect availability.
        pressure.take(s);
        assert_eq!(pressure.check_avail(s), 0);
        assert_eq!(pressure.check_avail(d), 0);
        assert_eq!(pressure.check_avail(q), 0);

        pressure.take(d);
        assert_eq!(pressure.check_avail(s), 0);
        assert_eq!(pressure.check_avail(d), 0);
        assert_eq!(pressure.check_avail(q), 0);

        pressure.take(q);
        assert_eq!(pressure.check_avail(s), 0);
        assert_eq!(pressure.check_avail(d), 0);
        assert_eq!(pressure.check_avail(q), 0);

        // Take a total of 16 S-regs.
        for _ in 1..16 {
            pressure.take(s);
        }
        assert_eq!(pressure.check_avail(s), 0);
        assert_eq!(pressure.check_avail(d), 0);
        assert_eq!(pressure.check_avail(q), 0);

        // We've taken 16 S, 1 D, and 1 Q. There should be 6 more Qs.
        for _ in 0..6 {
            assert_eq!(pressure.check_avail(d), 0);
            assert_eq!(pressure.check_avail(q), 0);
            pressure.take(q);
        }

        // We've taken 16 S, 1 D, and 7 Qs.
        assert!(pressure.check_avail(s) != 0);
        assert_eq!(pressure.check_avail(d), 0);
        assert!(pressure.check_avail(q) != 0);
    }
}
<|endoftext|>


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

use gfx_traits::Epoch;
use ipc_channel::ipc;
use layout::display_list::items::{BaseDisplayItem, DisplayItem, DisplayList, ImageDisplayItem};
use metrics::{PaintTimeMetrics, ProfilerMetadataFactory, ProgressiveWebMetric};
use msg::constellation_msg::TEST_PIPELINE_ID;
use profile_traits::time::{ProfilerChan, TimerMetadata};
use servo_url::ServoUrl;
use time;
use webrender_api::{ImageKey, ImageRendering, LayoutSize};

struct DummyProfilerMetadataFactory {}
impl ProfilerMetadataFactory for DummyProfilerMetadataFactory {
    fn new_metadata(&self) -> Option<TimerMetadata> {
        None
    }
}

#[test]
fn test_paint_metrics_construction() {
    let (sender, _) = ipc::channel().unwrap();
    let profiler_chan = ProfilerChan(sender);
    let (layout_sender, _) = ipc::channel().unwrap();
    let (script_sender, _) = ipc::channel().unwrap();
    let paint_time_metrics = PaintTimeMetrics::new(
        TEST_PIPELINE_ID,
        profiler_chan,
        layout_sender,
        script_sender,
        ServoUrl::parse("about:blank").unwrap(),
    );
    assert_eq!(
        (&paint_time_metrics).get_navigation_start(),
        None,
        "navigation start is None"
    );
    assert_eq!(
        paint_time_metrics.get_first_paint(),
        None,
        "first paint is None"
    );
    assert_eq!(
        paint_time_metrics.get_first_contentful_paint(),
        None,
        "first contentful paint is None"
    );
}

fn test_common(display_list: &DisplayList, epoch: Epoch) -> PaintTimeMetrics {
    let (sender, _) = ipc::channel().unwrap();
    let profiler_chan = ProfilerChan(sender);
    let (layout_sender, _) = ipc::channel().unwrap();
    let (script_sender, _) = ipc::channel().unwrap();
    let mut paint_time_metrics = PaintTimeMetrics::new(
        TEST_PIPELINE_ID,
        profiler_chan,
        layout_sender,
        script_sender,
        ServoUrl::parse("about:blank").unwrap(),
    );
    let dummy_profiler_metadata_factory = DummyProfilerMetadataFactory {};

    paint_time_metrics.maybe_observe_paint_time(
        &dummy_profiler_metadata_factory,
        epoch,
        &*display_list,
    );

    // Should not set any metric until navigation start is set.
    paint_time_metrics.maybe_set_metric(epoch, 0);
    assert_eq!(
        paint_time_metrics.get_first_paint(),
        None,
        "first paint is None"
    );
    assert_eq!(
        paint_time_metrics.get_first_contentful_paint(),
        None,
        "first contentful paint is None"
    );

    let navigation_start = time::precise_time_ns();
    paint_time_metrics.set_navigation_start(navigation_start);
    assert_eq!(
        (&paint_time_metrics).get_navigation_start().unwrap(),
        navigation_start,
        "navigation start is set"
    );

    paint_time_metrics
}

#[test]
fn test_first_paint_setter() {
    let empty_display_list = DisplayList {
        list: Vec::new(),
        clip_scroll_nodes: Vec::new(),
    };
    let epoch = Epoch(0);
    let paint_time_metrics = test_common(&empty_display_list, epoch);
    let now = time::precise_time_ns();
    paint_time_metrics.maybe_set_metric(epoch, now);
    assert!(
        paint_time_metrics.get_first_paint().is_some(),
        "first paint is set"
    );
    assert_eq!(
        paint_time_metrics.get_first_contentful_paint(),
        None,
        "first contentful paint is None"
    );
}

#[test]
fn test_first_contentful_paint_setter() {
    let image = DisplayItem::Image(Box::new(ImageDisplayItem {
        base: BaseDisplayItem::empty(),
        id: ImageKey::DUMMY,
        stretch_size: LayoutSize::zero(),
        tile_spacing: LayoutSize::zero(),
        image_rendering: ImageRendering::Auto,
    }));
    let display_list = DisplayList {
        list: vec![image],
        clip_scroll_nodes: Vec::new(),
    };
    let epoch = Epoch(0);
    let paint_time_metrics = test_common(&display_list, epoch);
    let now = time::precise_time_ns();
    paint_time_metrics.maybe_set_metric(epoch, now);
    assert!(
        paint_time_metrics.get_first_contentful_paint().is_some(),
        "first contentful paint is set"
    );
    assert!(
        paint_time_metrics.get_first_paint().is_some(),
        "first paint is set"
    );
}
<commit_msg>Fix unit tests<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use gfx_traits::Epoch;
use ipc_channel::ipc;
use layout::display_list::items::{BaseDisplayItem, CommonDisplayItem, DisplayItem, DisplayList};
use metrics::{PaintTimeMetrics, ProfilerMetadataFactory, ProgressiveWebMetric};
use msg::constellation_msg::TEST_PIPELINE_ID;
use profile_traits::time::{ProfilerChan, TimerMetadata};
use servo_url::ServoUrl;
use time;
use webrender_api::{AlphaType, ImageDisplayItem, ImageKey, ImageRendering, LayoutSize};

struct DummyProfilerMetadataFactory {}
impl ProfilerMetadataFactory for DummyProfilerMetadataFactory {
    fn new_metadata(&self) -> Option<TimerMetadata> {
        None
    }
}

#[test]
fn test_paint_metrics_construction() {
    let (sender, _) = ipc::channel().unwrap();
    let profiler_chan = ProfilerChan(sender);
    let (layout_sender, _) = ipc::channel().unwrap();
    let (script_sender, _) = ipc::channel().unwrap();
    let paint_time_metrics = PaintTimeMetrics::new(
        TEST_PIPELINE_ID,
        profiler_chan,
        layout_sender,
        script_sender,
        ServoUrl::parse("about:blank").unwrap(),
    );
    assert_eq!(
        (&paint_time_metrics).get_navigation_start(),
        None,
        "navigation start is None"
    );
    assert_eq!(
        paint_time_metrics.get_first_paint(),
        None,
        "first paint is None"
    );
    assert_eq!(
        paint_time_metrics.get_first_contentful_paint(),
        None,
        "first contentful paint is None"
    );
}

fn test_common(display_list: &DisplayList, epoch: Epoch) -> PaintTimeMetrics {
    let (sender, _) = ipc::channel().unwrap();
    let profiler_chan = ProfilerChan(sender);
    let (layout_sender, _) = ipc::channel().unwrap();
    let (script_sender, _) = ipc::channel().unwrap();
    let mut paint_time_metrics = PaintTimeMetrics::new(
        TEST_PIPELINE_ID,
        profiler_chan,
        layout_sender,
        script_sender,
        ServoUrl::parse("about:blank").unwrap(),
    );
    let dummy_profiler_metadata_factory = DummyProfilerMetadataFactory {};

    paint_time_metrics.maybe_observe_paint_time(
        &dummy_profiler_metadata_factory,
        epoch,
        &*display_list,
    );

    // Should not set any metric until navigation start is set.
    paint_time_metrics.maybe_set_metric(epoch, 0);
    assert_eq!(
        paint_time_metrics.get_first_paint(),
        None,
        "first paint is None"
    );
    assert_eq!(
        paint_time_metrics.get_first_contentful_paint(),
        None,
        "first contentful paint is None"
    );

    let navigation_start = time::precise_time_ns();
    paint_time_metrics.set_navigation_start(navigation_start);
    assert_eq!(
        (&paint_time_metrics).get_navigation_start().unwrap(),
        navigation_start,
        "navigation start is set"
    );

    paint_time_metrics
}

#[test]
fn test_first_paint_setter() {
    let empty_display_list = DisplayList {
        list: Vec::new(),
        clip_scroll_nodes: Vec::new(),
    };
    let epoch = Epoch(0);
    let paint_time_metrics = test_common(&empty_display_list, epoch);
    let now = time::precise_time_ns();
    paint_time_metrics.maybe_set_metric(epoch, now);
    assert!(
        paint_time_metrics.get_first_paint().is_some(),
        "first paint is set"
    );
    assert_eq!(
        paint_time_metrics.get_first_contentful_paint(),
        None,
        "first contentful paint is None"
    );
}

#[test]
fn test_first_contentful_paint_setter() {
    let image = DisplayItem::Image(CommonDisplayItem::new(
        BaseDisplayItem::empty(),
        ImageDisplayItem {
            image_key: ImageKey::DUMMY,
            stretch_size: LayoutSize::zero(),
            tile_spacing: LayoutSize::zero(),
            image_rendering: ImageRendering::Auto,
            alpha_type: AlphaType::PremultipliedAlpha,
        }
    ));
    let display_list = DisplayList {
        list: vec![image],
        clip_scroll_nodes: Vec::new(),
    };
    let epoch = Epoch(0);
    let paint_time_metrics = test_common(&display_list, epoch);
    let now = time::precise_time_ns();
    paint_time_metrics.maybe_set_metric(epoch, now);
    assert!(
        paint_time_metrics.get_first_contentful_paint().is_some(),
        "first contentful paint is set"
    );
    assert!(
        paint_time_metrics.get_first_paint().is_some(),
        "first paint is set"
    );
}
<|endoftext|>


<commit_before>// Kevin Cantu
// Boyer-Moore string searching

use std;

// Function: findn
//
// Boyer-Moore string search, which returns
// up to `nn` byte positions of matched substrings
fn findn (needle: str, haystack: str, nn: uint) -> [uint] {

   let results = [];

   // empty haystack
   if str::len(haystack) == 0u {
      ret results;
   }

   // empty needle
   if str::len(needle) == 0u {
      vec::push(results, 0u);
      ret results;
   }

   // needle too large
   if str::len(haystack) < str::len(needle) {
      ret results;
   }

   // generate the tables
   let ct = char_table(needle);
   let pt = prefix_table(needle);

   // simplify the table referencing
   let getShift = fn@(pos: uint) -> uint {
      let charShift, prefShift; // also: ct, pt, needle

      assert needle != "";
      assert pos >= 0u;
      assert pos < str::len(needle);

      alt ct.find(needle[pos] as uint) {
         option::none    { charShift = str::len(needle);}
         option::some(x) { charShift = x;}
      }

      let offset = str::len(needle) - pos;

      assert offset >= 0u;
      assert offset < str::len(needle);

      alt pt.find(offset) {
         option::none { fail "something is out of range" }
         option::some(x) { prefShift = x;}
      }

      std::io::println(#fmt("<charShift: %u, prefShift: %u>", charShift, prefShift));
      ret greaterOf(charShift, prefShift);
   };

   let outerLim  = str::len(haystack);
   let windowLim = str::len(needle);

   // step up through the haystack
   let outerii = 0u;
   while outerii < outerLim - windowLim + 1u {

      // step back through needle
      let windowii = windowLim;
      while 0u < windowii
            && (outerii + (windowii - 1u)) < outerLim  // don't exceed haystack
      {
         windowii -= 1u;

         std::io::println(#fmt("%c@%u =? %c@%u",
                          needle[windowii] as char,
                          windowii,
                          haystack[outerii+windowii] as char,
                          outerii + windowii));

         // if still matching
         if needle[windowii] == haystack[outerii+windowii] {

            // if full match
            if windowii == 0u {
               std::io::println(#fmt("[pushing %u]", outerii));
               vec::push(results, outerii);

               if vec::len(results) >= nn {
                  ret results;
               } else {
                  outerii += windowLim;
               }
            }

         // if partial match
         } else {
            let shift = getShift(windowii);

            outerii += shift;
            break;
         }
      }
   }

   ret results;
}

fn char_table (needle: str) -> std::map::map<uint, uint> {
   let mm: std::map::map<uint, uint> = std::map::new_uint_hash();
   let len = str::len(needle);

   let jj = len - 1u; // drop the last byte

   assert jj >= 0u;
   assert jj < str::len(needle);

   // from last-1 to first
   while jj > 0u {
      jj -= 1u;
      if ! mm.contains_key(needle[jj] as uint) {
         // store reverse indexes
         mm.insert(needle[jj] as uint, len - 1u - jj);
      }
   }

   ret mm;
}

#[test]
fn test_char_table () {
   let ct = char_table("ANPANMAN");
   assert 1u == ct.get('A' as uint); assert 2u == ct.get('M' as uint);
   assert 3u == ct.get('N' as uint);
   assert 5u == ct.get('P' as uint);
   assert option::none == ct.find('z' as uint);
}

fn prefix_table (needle: str) -> std::map::map<uint, uint> {
   let mm: std::map::map<uint, uint> = std::map::new_uint_hash();

   // WAIT, HOW IS THIS ALLOWED TO MUTATE mm?
   let fill = fn@(kk: uint, vv: uint) {
      if ! mm.contains_key(kk) {
         mm.insert(kk, vv);
         //std::io::println(#fmt("%u => %u", kk, vv));
      }
   };

   let lim   = str::len(needle);
   assert 0u < lim;

   // step to larger suffixes
   let sii = 0u;
   while sii < lim {

      // tail of the needle we seek
      let suffix      = str::slice(needle, lim - sii,      lim);
      let suffix_plus = str::slice(needle, lim - sii - 1u, lim);
      let slen = str::len(suffix);

      // step to smaller prefixes
      let pii = lim - 1u;
      while pii > 0u {

         // a prefix of the needle that might be matched by
         // a partial match of a suffix
         // (which we might want to jump to)
         let prefix = str::slice(needle, 0u, pii);

         //let msg  = "<"+suffix+"("+#fmt("%u",sii)+")";
         //let msg2 = prefix+"("+#fmt("%u",pii)+")>";
         //std::io::println(msg + " × " + msg2);

         // suffix might be fully matched
         let is_suffix_matched =
            str::ends_with(prefix, suffix)
            && !str::ends_with(prefix, suffix_plus)
            &&  slen < str::len(prefix);

         // prefix is bigger than suffix, only tail can match
         let is_suffix_partially_matched =
            str::len(prefix) <= str::len(suffix)
            && str::ends_with(suffix, prefix);

         if is_suffix_matched || is_suffix_partially_matched {
            fill(sii, lim-pii);
         }

         pii -= 1u;
      }

      // no matching prefix
      fill(sii, lim-pii);

      sii += 1u;
   }

   ret mm;
}

#[test]
fn test_prefix_table() {
   let pt = prefix_table("ANPANMAN");
                            //      ... 8

   assert 1u == pt.get(0u); //        (n)
   assert 8u == pt.get(1u); //       (a)n
   assert 3u == pt.get(2u); //      (m)an
   assert 6u == pt.get(3u); //     (n)man
   assert 6u == pt.get(4u); //    (a)nman
   assert 6u == pt.get(5u); //   (p)anman
   assert 6u == pt.get(6u); //  (n)panman
   assert 6u == pt.get(7u); // (a)npanman
   //assert 0u == pt.get(8u); // fail
}

////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////

// prefixes, smallest first
fn prefixes(ss: str) -> [str] unsafe {
   let vv = [];

   vec::push(vv, "");
   str::chars_iteri(ss) {|ii, _bb|
      vec::push(vv, str::slice(ss, 0u, ii+1u));
   }

   ret vv;
}

#[test]
fn test_prefs() {
   assert ["", "a", "ab", "abc", "abcd"] == prefixes("abcd");
   assert [""] == prefixes("");
}

// suffixes, largest first
fn suffixes(ss: str) -> [str] unsafe {
   let vv = [];
   let lim = str::len(ss);

   str::chars_iteri(ss) {|ii, _bb|
      vec::push(vv, str::slice(ss, ii, lim));
   }
   vec::push(vv, "");

   ret vv;
}

#[test]
fn test_sufs() {
   assert ["abcd", "bcd", "cd", "d", ""] == suffixes("abcd");
   assert [""] == suffixes("");
}

fn greaterOf(a: uint, b: uint) -> uint {
   if a > b { ret a; } else { ret b; }
}

#[test]
fn test_greaterOf() {
   assert greaterOf(15u, 17u) == 17u;
   assert greaterOf(17u, 15u) == 17u;
}

fn find_(needle: str, haystack: str) -> option<uint> {
   let found = findn(needle, haystack, 1u);

   alt vec::len(found) {
      0u { option::none }
      xx { option::some(found[0u]) }
   }
}

#[test]
fn test_findn() {
   assert [] == findn("banana", "apple pie", 1u);
  assert (findn("abc", "abcxxxxxx", 1u) == [0u]);
  assert (findn("abc", "xxxabcxxx", 1u) == [3u]);
  assert (findn("abc", "xxxxxxabc", 1u) == [6u]);
  assert (findn("abc", "xxxabcabc", 5u) == [3u, 6u]);
}

#[test]
fn test_find_ascii() {
  assert (find_("banana", "apple pie") == option::none);
  assert (find_("", "") == option::none);
  assert (find_("abc", "abcxxxxxx") == option::some(0u));
  assert (find_("abc", "xxxabcxxx") == option::some(3u));
  assert (find_("abc", "xxxxxxabc") == option::some(6u));
}

#[test]
fn test_find_A() {
  let data = "ประเทศไทย中华Việt Nam";
  assert (find_("", data)     == option::some( 0u));
}

#[test]
fn test_find_B() {
  let data = "ประเทศไทย中华Việt Nam";
  assert (find_("ประเ", data) == option::some( 0u));
  assert (find_("ะเ", data)   == option::some( 6u));
  assert (find_("中华", data) == option::some(27u));
  assert (find_("ไท华", data) == option::none);
}

<commit_msg>findn works on ascii tests...<commit_after>// Kevin Cantu
// Boyer-Moore string searching

use std;

// Function: findn
//
// Boyer-Moore string search, which returns
// up to `nn` byte positions of matched substrings
fn findn (needle: str, haystack: str, nn: uint) -> [uint] {

   let results = [];

   // empty haystack
   if str::len(haystack) == 0u {
      ret results;
   }

   // empty needle
   if str::len(needle) == 0u {
      vec::push(results, 0u);
      ret results;
   }

   // needle too large
   if str::len(haystack) < str::len(needle) {
      ret results;
   }

   // generate the tables
   let ct = char_table(needle);
   let pt = prefix_table(needle);

   // simplify the table referencing
   let getShift = fn@(pos: uint) -> uint {
      let charShift, prefShift; // also: ct, pt, needle

      assert needle != "";
      assert pos >= 0u;
      assert pos < str::len(needle);

      alt ct.find(needle[pos] as uint) {
         option::none    { charShift = str::len(needle);}
         option::some(x) { charShift = x;}
      }

      let offset = str::len(needle) - pos;

      assert offset >= 0u;
      assert offset < str::len(needle);

      alt pt.find(offset) {
         option::none { fail "something is out of range" }
         option::some(x) { prefShift = x;}
      }

      std::io::println(#fmt("<charShift: %u, prefShift: %u>", charShift, prefShift));
      ret greaterOf(charShift, prefShift);
   };

   let outerLim  = str::len(haystack);
   let windowLim = str::len(needle);

   // step up through the haystack
   let outerii = 0u;
   while outerii < outerLim - windowLim + 1u {

      // step back through needle
      let windowii = windowLim;
      while 0u < windowii
            && (outerii + (windowii - 1u)) < outerLim  // don't exceed haystack
      {
         windowii -= 1u;

         std::io::println(#fmt("%c@%u =? %c@%u",
                          needle[windowii] as char,
                          windowii,
                          haystack[outerii+windowii] as char,
                          outerii + windowii));

         // if still matching
         if needle[windowii] == haystack[outerii+windowii] {

            // if full match
            if windowii == 0u {
               std::io::println(#fmt("[pushing %u]", outerii));
               vec::push(results, outerii);

               if vec::len(results) >= nn {
                  ret results;
               } else {
                  outerii += windowLim;
               }
            }

         // if partial match
         } else {
            let shift = getShift(windowii);

            outerii += shift;
            break;
         }
      }
   }

   ret results;
}

fn char_table (needle: str) -> std::map::map<uint, uint> {
   let mm: std::map::map<uint, uint> = std::map::new_uint_hash();
   let len = str::len(needle);

   let jj = len - 1u; // drop the last byte

   assert jj >= 0u;
   assert jj < str::len(needle);

   // from last-1 to first
   while jj > 0u {
      jj -= 1u;
      if ! mm.contains_key(needle[jj] as uint) {
         // store reverse indexes
         mm.insert(needle[jj] as uint, len - 1u - jj);
      }
   }

   ret mm;
}

//#[test]
fn test_char_table () {
   let ct = char_table("ANPANMAN");
   assert 1u == ct.get('A' as uint); assert 2u == ct.get('M' as uint);
   assert 3u == ct.get('N' as uint);
   assert 5u == ct.get('P' as uint);
   assert option::none == ct.find('z' as uint);
}

fn prefix_table (needle: str) -> std::map::map<uint, uint> unsafe {
   let mm: std::map::map<uint, uint> = std::map::new_uint_hash();

   // WAIT, HOW IS THIS ALLOWED TO MUTATE mm?
   let fill = fn@(kk: uint, vv: uint) {
      if ! mm.contains_key(kk) {
         mm.insert(kk, vv);
         std::io::println(#fmt("%u => %u", kk, vv));
      }
   };

   let lim   = str::len(needle);
   assert 0u < lim;

   // step to larger suffixes
   let sii = 0u;
   while sii < lim {

      // tail of the needle we seek
      let suffix      = str::unsafe::slice_bytes(needle, lim - sii,      lim);
      let suffix_plus = str::unsafe::slice_bytes(needle, lim - sii - 1u, lim);
      let slen = str::len(suffix);

      // step to smaller prefixes
      let pii = lim - 1u;
      while pii > 0u {

         // a prefix of the needle that might be matched by
         // a partial match of a suffix
         // (which we might want to jump to)
         let prefix = str::unsafe::slice_bytes(needle, 0u, pii);

         //let msg  = "<"+suffix+"("+#fmt("%u",sii)+")";
         //let msg2 = prefix+"("+#fmt("%u",pii)+")>";
         let msg  = "<suf("+#fmt("%u",sii)+")";
         let msg2 = "pref("+#fmt("%u",pii)+")>";
         std::io::println(msg + " × " + msg2);

         // suffix might be fully matched
         let is_suffix_matched =
            str::ends_with(prefix, suffix)
            && !str::ends_with(prefix, suffix_plus)
            &&  slen < str::len(prefix);

         // prefix is bigger than suffix, only tail can match
         let is_suffix_partially_matched =
            str::len(prefix) <= str::len(suffix)
            && str::ends_with(suffix, prefix);

         if is_suffix_matched || is_suffix_partially_matched {
            fill(sii, lim-pii);
         }

         pii -= 1u;
      }

      // no matching prefix
      fill(sii, lim-pii);

      sii += 1u;
   }

   ret mm;
}

//#[test]
fn test_prefix_table_ascii() {
   let pt = prefix_table("ANPANMAN");
                            //      ... 8

   assert 1u == pt.get(0u); //        (n)
   assert 8u == pt.get(1u); //       (a)n
   assert 3u == pt.get(2u); //      (m)an
   assert 6u == pt.get(3u); //     (n)man
   assert 6u == pt.get(4u); //    (a)nman
   assert 6u == pt.get(5u); //   (p)anman
   assert 6u == pt.get(6u); //  (n)panman
   assert 6u == pt.get(7u); // (a)npanman
   //assert 0u == pt.get(8u); // fail
}

//#[test]
fn test_prefix_table_utf8() {
   let pt = prefix_table("ประเ");

   assert  1u == pt.get(0u);
   assert 12u == pt.get(3u);
   assert 12u == pt.get(6u);
   assert 12u == pt.get(9u);
}

////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////

// prefixes, smallest first
fn prefixes(ss: str) -> [str] unsafe {
   let vv = [];

   vec::push(vv, "");
   str::chars_iteri(ss) {|ii, _bb|
      vec::push(vv, str::slice(ss, 0u, ii+1u));
   }

   ret vv;
}

//#[test]
fn test_prefs() {
   assert ["", "a", "ab", "abc", "abcd"] == prefixes("abcd");
   assert [""] == prefixes("");
}

// suffixes, largest first
fn suffixes(ss: str) -> [str] unsafe {
   let vv = [];
   let lim = str::len(ss);

   str::chars_iteri(ss) {|ii, _bb|
      vec::push(vv, str::slice(ss, ii, lim));
   }
   vec::push(vv, "");

   ret vv;
}

//#[test]
fn test_sufs() {
   assert ["abcd", "bcd", "cd", "d", ""] == suffixes("abcd");
   assert [""] == suffixes("");
}

fn greaterOf(a: uint, b: uint) -> uint {
   if a > b { ret a; } else { ret b; }
}

//#[test]
fn test_greaterOf() {
   assert greaterOf(15u, 17u) == 17u;
   assert greaterOf(17u, 15u) == 17u;
}

fn find_(needle: str, haystack: str) -> option<uint> {
   let found = findn(needle, haystack, 1u);

   alt vec::len(found) {
      0u { option::none }
      xx { option::some(found[0u]) }
   }
}

//#[test]
fn test_findn() {
   assert [] == findn("banana", "apple pie", 1u);
  assert (findn("abc", "abcxxxxxx", 1u) == [0u]);
  assert (findn("abc", "xxxabcxxx", 1u) == [3u]);
  assert (findn("abc", "xxxxxxabc", 1u) == [6u]);
  assert (findn("abc", "xxxabcabc", 1u) == [3u]);
  assert (findn("abc", "xxxabcabc", 5u) == [3u, 6u]);
  assert (findn("abc", "xxxabcxxabc", 5u) == [3u, 8u]);
}

//#[test]
fn test_find_ascii() {
  assert (find_("banana", "apple pie") == option::none);
  assert (find_("", "") == option::none);
  assert (find_("abc", "abcxxxxxx") == option::some(0u));
  assert (find_("abc", "xxxabcxxx") == option::some(3u));
  assert (find_("abc", "xxxxxxabc") == option::some(6u));
}

//#[test]
fn test_find_utf8() {
  let data = "ประเทศไทย中华Việt Nam";
  assert (find_("", data)     == option::some( 0u));
  assert (find_("ประเ", data) == option::some( 0u));
  assert (find_("ะเ", data)   == option::some( 6u));
  assert (find_("ไท华", data) == option::none);
}

#[test]
fn test_find_B() {
  let data = "ประเทศไทย中华Việt Nam";
  assert (find_("中华", data) == option::some(30u));
}

<|endoftext|>


<commit_before>// Kevin Cantu
// Boyer-Moore string searching

use std;

// Function: findn_bytes
//
// Boyer-Moore string search, which returns
// up to `nn` byte positions of matched substrings
fn findn_bytes (needle: str, haystack: str, nn: uint) -> [uint] {
   let results = [];
   let ct = char_table(needle);
   let pt = prefix_table(needle);

   log(error, ct);
   log(error, pt);

   let ii = 0u;
   let jj = 0u;

   while ii < str::len_bytes(haystack) {

      jj = str::len_bytes(needle) - 1u;

      // reverse through needle
      while 0u <= jj {

         // if still matching
         if needle[jj] == haystack[ii] {
            // if full match
            if jj == 0u {
               vec::push(results, jj);
               if vec::len(results) >= nn { ret results; }
            }

         // if partial match
         } else {
            let sufn = str::len_bytes(needle) - jj;

            let ctx;
            let ptx;

            alt ct.find(needle[sufn] as uint) {
               option::none { ctx = str::len_bytes(needle);}
               option::some(x) { ctx = x;}
            }

            alt pt.find(sufn) {
               option::none { fail "something is out of range" }
               option::some(x) { ptx = x;}
            }

            ii += greaterOf(ctx, ptx) - jj;
            jj = 0u;
         }

         jj -= 1u;
      }

      ii += 1u;
   }

   ret results;
}

fn char_table (needle: str) -> std::map::map<uint, uint> {
   let mm: std::map::map<uint, uint> = std::map::new_uint_hash();
   let len = str::len_bytes(needle);

   let jj = len - 1u; // drop the last byte

   // from last-1 to first
   while jj > 0u {
      jj -= 1u;
      if ! mm.contains_key(needle[jj] as uint) {
         // store reverse indexes
         mm.insert(needle[jj] as uint, len - 1u - jj);
      }
   }

   ret mm;
}

#[test]
fn test_char_table () {
   let ct = char_table("ANPANMAN");
   assert 1u == ct.get('A' as uint);
   assert 2u == ct.get('M' as uint);
   assert 3u == ct.get('N' as uint);
   assert 5u == ct.get('P' as uint);
   assert option::none == ct.find('z' as uint);
}

fn prefix_table (needle: str) -> std::map::map<uint, uint> {
   let mm: std::map::map<uint, uint> = std::map::new_uint_hash();

   let prefs = vec::reversed(prefixes(needle)); // largest first
   let sufs  = vec::reversed(suffixes(needle)); // smallest first
   let jj    = 0u;
   let kk    = 0u;
   let lim   = str::len(needle);

   while jj < lim {    // sufixes
      kk = 0u;

      while kk < lim { // prefixes
         let suf = sufs[jj];
         let pref = prefs[kk];

         if str::len_bytes(pref) > str::len_bytes(suf) {
            std::io::println("[" + pref + ", " + suf + "]");
            std::io::println(">");
            if str::ends_with(pref, suf) {
               std::io::println("(suf)");
               if !str::ends_with(pref, sufs[jj+1u]) {
                  std::io::println("(suf+1)");
               }
            }
         }

         if str::len_bytes(pref) > str::len_bytes(suf) &&
            str::ends_with(pref, suf) &&
           !str::ends_with(pref, sufs[jj+1u])
         {
            std::io::print("-");

            if ! mm.contains_key(jj)
            {
               std::io::println("*");
               mm.insert(jj, kk);
            }
         }

         kk += 1u;
      }

      // for this suffix jj, if no matching prefix, where did we fall out?
      // i.e., what is the last prefix that was still partially matching,
      // e.g., for suffix "man", the prefix "an" works, and is +6...
      //       but will not be added above...
      //
      // TODO: add that to table

      jj += 1u;
   }

   ret mm
}

#[test]
fn test_prefix_table() {
   let pt = prefix_table("ANPANMAN");
   std::io::print("+");
   log(error, pt);
   assert 8u == pt.get(2u);
}

////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////

// prefixes, smallest first
fn prefixes(ss: str) -> [str] unsafe {
   let vv = [];
   let sz = 0u;
   str::bytes_iter(ss) {|_bb|
      sz += 1u;
      vec::push(vv, str::unsafe::slice_bytes(ss, 0u, sz));
   }
   ret vv;
}

#[test]
fn test_prefs() {
   assert ["a", "ab", "abc", "abcd"] == prefixes("abcd");
}

// suffixes, largest first
fn suffixes(ss: str) -> [str] unsafe {
   let vv = [];
   let sz = 0u;
   let lim = str::len_bytes(ss);
   str::bytes_iter(ss) {|_bb|
      vec::push(vv, str::unsafe::slice_bytes(ss, sz, lim));
      sz += 1u;
   }
   ret vv;
}

#[test]
fn test_sufs() {
   assert ["abcd", "bcd", "cd", "d"] == suffixes("abcd");
}

fn greaterOf(a: uint, b: uint) -> uint {
   if a > b { ret a; } else { ret b; }
}

#[test]
fn test_greaterOf() {
   assert greaterOf(15u, 17u) == 17u;
   assert greaterOf(17u, 15u) == 17u;
}

fn find_bytes_(needle: str, haystack: str) -> option<uint> {
   ret option::some(findn_bytes(needle, haystack, 1u)[0u]);
}

//#[test]
fn test_find_bytes() {
  // byte positions
  assert (find_bytes_("banana", "apple pie") == option::none);
  assert (find_bytes_("", "") == option::some(0u));

  let data = "ประเทศไทย中华Việt Nam";
  assert (find_bytes_(data, "")     == option::some(0u));
  assert (find_bytes_(data, "ประเ") == option::some( 0u));
  assert (find_bytes_(data, "ะเ")   == option::some( 6u));
  assert (find_bytes_(data, "中华") == option::some(27u));
  assert (find_bytes_(data, "ไท华") == option::none);
}

<commit_msg>(boyer-moore) prefixes broken for now...<commit_after>// Kevin Cantu
// Boyer-Moore string searching

use std;

// Function: findn_bytes
//
// Boyer-Moore string search, which returns
// up to `nn` byte positions of matched substrings
fn findn_bytes (needle: str, haystack: str, nn: uint) -> [uint] {
   let results = [];
   let ct = char_table(needle);
   let pt = prefix_table(needle);

   log(error, ct);
   log(error, pt);

   let ii = 0u;
   let jj = 0u;

   while ii < str::len_bytes(haystack) {

      jj = str::len_bytes(needle) - 1u;

      // reverse through needle
      while 0u <= jj {

         // if still matching
         if needle[jj] == haystack[ii] {
            // if full match
            if jj == 0u {
               vec::push(results, jj);
               if vec::len(results) >= nn { ret results; }
            }

         // if partial match
         } else {
            let sufn = str::len_bytes(needle) - jj;

            let ctx;
            let ptx;

            alt ct.find(needle[sufn] as uint) {
               option::none { ctx = str::len_bytes(needle);}
               option::some(x) { ctx = x;}
            }

            alt pt.find(sufn) {
               option::none { fail "something is out of range" }
               option::some(x) { ptx = x;}
            }

            ii += greaterOf(ctx, ptx) - jj;
            jj = 0u;
         }

         jj -= 1u;
      }

      ii += 1u;
   }

   ret results;
}

fn char_table (needle: str) -> std::map::map<uint, uint> {
   let mm: std::map::map<uint, uint> = std::map::new_uint_hash();
   let len = str::len_bytes(needle);

   let jj = len - 1u; // drop the last byte

   // from last-1 to first
   while jj > 0u {
      jj -= 1u;
      if ! mm.contains_key(needle[jj] as uint) {
         // store reverse indexes
         mm.insert(needle[jj] as uint, len - 1u - jj);
      }
   }

   ret mm;
}

#[test]
fn test_char_table () {
   let ct = char_table("ANPANMAN");
   assert 1u == ct.get('A' as uint);
   assert 2u == ct.get('M' as uint);
   assert 3u == ct.get('N' as uint);
   assert 5u == ct.get('P' as uint);
   assert option::none == ct.find('z' as uint);
}

fn prefix_table (needle: str) -> std::map::map<uint, uint> {
   let mm: std::map::map<uint, uint> = std::map::new_uint_hash();

   let prefs = vec::reversed(prefixes(needle)); // largest first
   let sufs  = vec::reversed(suffixes(needle)); // smallest first
   let jj    = 0u;
   let kk    = 0u;
   let lim   = str::len(needle);

   while jj < lim {    // sufixes
      std::io::println("\n<newsuff: " + sufs[jj] + ">");

      kk = 0u;

      while kk < lim { // prefixes
         std::io::print("<prefixes: " + prefs[kk] + "> ");

         let suf = sufs[jj];
         let pref = prefs[kk];

         if str::len_bytes(pref) > str::len_bytes(suf) {
            //std::io::println("[" + pref + ", " + suf + "]");
            std::io::print("(pref > suf)");
            if str::ends_with(pref, suf) {
               std::io::print("(ew)");
               if !str::ends_with(pref, sufs[jj+1u]) {
                  std::io::print("(ew+1)");

                  if ! mm.contains_key(jj)
                  {
                     std::io::print(#fmt("(+%u)", kk));
                     mm.insert(jj, kk);
                  }
               }
            }
         }

         if str::len_bytes(pref) <= str::len_bytes(suf) {
            std::io::print("(pref <= suf)");

            if str::ends_with(suf, pref) // partial
            {
               std::io::print("(^ew)");

               if ! mm.contains_key(jj)
               {
                  std::io::print(#fmt("(*%u)", kk));
                  mm.insert(jj, kk);
               }
            }
         }

         std::io::println("");

         kk += 1u;
      }

      // for this suffix jj, if no matching prefix, where did we fall out?
      // i.e., what is the last prefix that was still partially matching,
      // e.g., for suffix "man", the prefix "an" works, and is +6...
      //       but will not be added above...
      //
      // TODO: add that to table
      if ! mm.contains_key(jj)
      {
         std::io::print(#fmt("(=%u)", kk));
         mm.insert(jj, kk);
      }

      jj += 1u;
   }

   ret mm
}

#[test]
fn test_prefix_table() {
   let pt = prefix_table("ANPANMAN");
                        //     ... 8
   std::io::print("+");
   log(error, pt);
   assert 1u == pt.get(0u); //  (a)n
   assert 8u == pt.get(1u); // (m)an
   assert 3u == pt.get(2u); //(n)man
   assert 6u == pt.get(3u);
   assert 6u == pt.get(4u);
   assert 6u == pt.get(5u);
   assert 6u == pt.get(6u);
   assert 6u == pt.get(7u); // MATCH
   assert 0u == pt.get(8u); // fail
   //assert 0u == pt.get(9u); // fail
}

////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////

// prefixes, smallest first
fn prefixes(ss: str) -> [str] unsafe {
   let vv = [];
   let sz = 0u;
   str::bytes_iter(ss) {|_bb|
      sz += 1u;
      vec::push(vv, str::unsafe::slice_bytes(ss, 0u, sz));
   }
   ret vv;
}

#[test]
fn test_prefs() {
   assert ["", "a", "ab", "abc", "abcd"] == prefixes("abcd");
}

// suffixes, largest first
fn suffixes(ss: str) -> [str] unsafe {
   let vv = [];
   let sz = 0u;
   let lim = str::len_bytes(ss);
   str::bytes_iter(ss) {|_bb|
      vec::push(vv, str::unsafe::slice_bytes(ss, sz, lim));
      sz += 1u;
   }
   ret vv;
}

#[test]
fn test_sufs() {
   assert ["abcd", "bcd", "cd", "d", ""] == suffixes("abcd");
}

fn greaterOf(a: uint, b: uint) -> uint {
   if a > b { ret a; } else { ret b; }
}

#[test]
fn test_greaterOf() {
   assert greaterOf(15u, 17u) == 17u;
   assert greaterOf(17u, 15u) == 17u;
}

fn find_bytes_(needle: str, haystack: str) -> option<uint> {
   ret option::some(findn_bytes(needle, haystack, 1u)[0u]);
}

//#[test]
fn test_find_bytes() {
  // byte positions
  assert (find_bytes_("banana", "apple pie") == option::none);
  assert (find_bytes_("", "") == option::some(0u));

  let data = "ประเทศไทย中华Việt Nam";
  assert (find_bytes_(data, "")     == option::some(0u));
  assert (find_bytes_(data, "ประเ") == option::some( 0u));
  assert (find_bytes_(data, "ะเ")   == option::some( 6u));
  assert (find_bytes_(data, "中华") == option::some(27u));
  assert (find_bytes_(data, "ไท华") == option::none);
}

<|endoftext|>


<commit_before>//! Temporal feature extraction module.
//!
//! Contains functions to extract & summarize the temporal aspects
//! of a given Song.
#[cfg(feature = "aubio-lib")]
extern crate aubio_lib;

use aubio_rs::{OnsetMode, Tempo};
use crate::utils::Normalize;

/**
 * Beats per minutes ([BPM](https://en.wikipedia.org/wiki/Tempo#Measurement))
 * detection object.
 *
 * It indicates the (subjective) "speed" of a music piece. The higher the BPM,
 * the "quicker" the song will feel.
 *
 * It uses `WPhase`, a phase-deviation onset detection function to perform
 * onset detection; it proved to be the best for finding out the BPM of a panel
 * of songs I had, but it could very well be replaced by something better in the
 * future.
 *
 * Ranges from 0 (theoretically...) to 206 BPM. (Even though aubio apparently
 * has trouble to identify tempo > 190 BPM - did not investigate too much)
 *
 */
pub struct BPMDesc {
    aubio_obj: Tempo,
}

// TODO use the confidence value to discard this descriptor if confidence
// is too low.
impl BPMDesc {
    pub const WINDOW_SIZE: usize = 512;
    pub const HOP_SIZE: usize = BPMDesc::WINDOW_SIZE / 4;

    pub fn new(sample_rate: u32) -> Self {
        BPMDesc {
            aubio_obj: Tempo::new(
                OnsetMode::WPhase,
                BPMDesc::WINDOW_SIZE,
                BPMDesc::HOP_SIZE,
                sample_rate,
            )
            .unwrap(),
        }
    }

    pub fn do_(&mut self, chunk: &[f32]) {
        self.aubio_obj.do_result(chunk).unwrap();
    }

    /**
     * Compute score related to tempo.
     * Right now, basically returns the song's BPM.
     *
     * - `song` Song to compute score from
     */
    // TODO analyze a whole library and check that this is not > 1.
    pub fn get_value(&mut self) -> f32 {
        self.normalize(self.aubio_obj.get_bpm())
    }
}

impl Normalize for BPMDesc {
    // See aubio/src/tempo/beattracking.c:387
    // Should really be 413, needs testing
    const MAX_VALUE: f32 = 206.;
    const MIN_VALUE: f32 = 0.;
}

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

    #[test]
    fn test_tempo_real() {
        let song = decode_song("data/s16_mono_22_5kHz.flac").unwrap();
        let mut tempo_desc = BPMDesc::new(song.sample_rate);
        for chunk in song.sample_array.chunks_exact(BPMDesc::HOP_SIZE) {
            tempo_desc.do_(&chunk);
        }
        assert!(0.01 > (0.378605 - tempo_desc.get_value()).abs());
    }

    #[test]
    fn test_tempo_artificial() {
        let mut tempo_desc = BPMDesc::new(22050);
        // This gives one beat every second, so 60 BPM
        let mut one_chunk = vec![0.; 22000];
        one_chunk.append(&mut vec![1.; 100]);
        let chunks = std::iter::repeat(one_chunk.iter()).take(100).flatten().cloned().collect::<Vec<f32>>();
        for chunk in chunks.chunks_exact(BPMDesc::HOP_SIZE) {
            tempo_desc.do_(&chunk);
        }

        // -0.41 is 60 BPM normalized
        assert!(0.01 > (-0.416853 - tempo_desc.get_value()).abs());
    }

    #[test]
    fn test_tempo_boundaries() {
        let mut tempo_desc = BPMDesc::new(10);
        let silence_chunk = vec![0.; 1024];
        tempo_desc.do_(&silence_chunk);
        assert_eq!(-1., tempo_desc.get_value());

        let mut tempo_desc = BPMDesc::new(22050);
        // The highest value I could obtain was with these params, even though
        // apparently the higher bound is 206 BPM, but here I found ~189 BPM.
        let mut one_chunk = vec![0.; 6989];
        one_chunk.append(&mut vec![1.; 100]);
        let chunks = std::iter::repeat(one_chunk.iter()).take(500).flatten().cloned().collect::<Vec<f32>>();
        for chunk in chunks.chunks_exact(BPMDesc::HOP_SIZE) {
            tempo_desc.do_(&chunk);
        }
        // 0.83 is 189 BPM normalized
        assert!(0.01 > (0.83015 - tempo_desc.get_value()).abs());
    }
}
<commit_msg>Change default onset mode for tempo<commit_after>//! Temporal feature extraction module.
//!
//! Contains functions to extract & summarize the temporal aspects
//! of a given Song.
#[cfg(feature = "aubio-lib")]
extern crate aubio_lib;

use aubio_rs::{OnsetMode, Tempo};
use crate::utils::Normalize;

/**
 * Beats per minutes ([BPM](https://en.wikipedia.org/wiki/Tempo#Measurement))
 * detection object.
 *
 * It indicates the (subjective) "speed" of a music piece. The higher the BPM,
 * the "quicker" the song will feel.
 *
 * It uses `WPhase`, a phase-deviation onset detection function to perform
 * onset detection; it proved to be the best for finding out the BPM of a panel
 * of songs I had, but it could very well be replaced by something better in the
 * future.
 *
 * Ranges from 0 (theoretically...) to 206 BPM. (Even though aubio apparently
 * has trouble to identify tempo > 190 BPM - did not investigate too much)
 *
 */
pub struct BPMDesc {
    aubio_obj: Tempo,
}

// TODO use the confidence value to discard this descriptor if confidence
// is too low.
impl BPMDesc {
    pub const WINDOW_SIZE: usize = 512;
    pub const HOP_SIZE: usize = BPMDesc::WINDOW_SIZE / 4;

    pub fn new(sample_rate: u32) -> Self {
        BPMDesc {
            aubio_obj: Tempo::new(
                OnsetMode::SpecFlux,
                BPMDesc::WINDOW_SIZE,
                BPMDesc::HOP_SIZE,
                sample_rate,
            )
            .unwrap(),
        }
    }

    pub fn do_(&mut self, chunk: &[f32]) {
        self.aubio_obj.do_result(chunk).unwrap();
    }

    /**
     * Compute score related to tempo.
     * Right now, basically returns the song's BPM.
     *
     * - `song` Song to compute score from
     */
    // TODO analyze a whole library and check that this is not > 1.
    pub fn get_value(&mut self) -> f32 {
        self.normalize(self.aubio_obj.get_bpm())
    }
}

impl Normalize for BPMDesc {
    // See aubio/src/tempo/beattracking.c:387
    // Should really be 413, needs testing
    const MAX_VALUE: f32 = 206.;
    const MIN_VALUE: f32 = 0.;
}

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

    #[test]
    fn test_tempo_real() {
        let song = decode_song("data/s16_mono_22_5kHz.flac").unwrap();
        let mut tempo_desc = BPMDesc::new(song.sample_rate);
        for chunk in song.sample_array.chunks_exact(BPMDesc::HOP_SIZE) {
            tempo_desc.do_(&chunk);
        }
        assert!(0.01 > (0.378605 - tempo_desc.get_value()).abs());
    }

    #[test]
    fn test_tempo_artificial() {
        let mut tempo_desc = BPMDesc::new(22050);
        // This gives one beat every second, so 60 BPM
        let mut one_chunk = vec![0.; 22000];
        one_chunk.append(&mut vec![1.; 100]);
        let chunks = std::iter::repeat(one_chunk.iter()).take(100).flatten().cloned().collect::<Vec<f32>>();
        for chunk in chunks.chunks_exact(BPMDesc::HOP_SIZE) {
            tempo_desc.do_(&chunk);
        }

        // -0.41 is 60 BPM normalized
        assert!(0.01 > (-0.416853 - tempo_desc.get_value()).abs());
    }

    #[test]
    fn test_tempo_boundaries() {
        let mut tempo_desc = BPMDesc::new(10);
        let silence_chunk = vec![0.; 1024];
        tempo_desc.do_(&silence_chunk);
        assert_eq!(-1., tempo_desc.get_value());

        let mut tempo_desc = BPMDesc::new(22050);
        // The highest value I could obtain was with these params, even though
        // apparently the higher bound is 206 BPM, but here I found ~189 BPM.
        let mut one_chunk = vec![0.; 6989];
        one_chunk.append(&mut vec![1.; 100]);
        let chunks = std::iter::repeat(one_chunk.iter()).take(500).flatten().cloned().collect::<Vec<f32>>();
        for chunk in chunks.chunks_exact(BPMDesc::HOP_SIZE) {
            tempo_desc.do_(&chunk);
        }
        // 0.83 is 189 BPM normalized
        assert!(0.01 > (0.83015 - tempo_desc.get_value()).abs());
    }
}
<|endoftext|>