<commit_before>use std::process::exit;
use std::path::Path;

use clap;
use cargo_shim::{
    Profile,
    CargoPackage,
    CargoProject,
    CargoTarget,
    BuildType,
    BuildConfig,
    TargetKind,
    CargoResult,
    MessageFormat,
    target_to_build_target
};

use config::Config;
use emscripten::initialize_emscripten;
use error::Error;
use wasm;

pub struct BuildArgsMatcher< 'a > {
    pub matches: &'a clap::ArgMatches< 'a >,
    pub project: &'a CargoProject
}

impl< 'a > BuildArgsMatcher< 'a > {
    fn requested_build_type( &self ) -> BuildType {
        if self.matches.is_present( "release" ) {
            BuildType::Release
        } else {
            BuildType::Debug
        }
    }

    pub fn targeting_emscripten_asmjs( &self ) -> bool {
        !self.targeting_emscripten_wasm() && !self.targeting_native_wasm()
    }

    pub fn targeting_emscripten_wasm( &self ) -> bool {
        self.matches.is_present( "target-webasm-emscripten" )
    }

    pub fn targeting_native_wasm( &self ) -> bool {
        self.matches.is_present( "target-webasm" )
    }

    pub fn targeting_wasm( &self ) -> bool {
        self.targeting_emscripten_wasm() || self.targeting_native_wasm()
    }

    pub fn targeting_emscripten( &self ) -> bool {
        self.targeting_emscripten_wasm() || self.targeting_emscripten_asmjs()
    }

    fn use_system_emscripten( &self ) -> bool {
        self.matches.is_present( "use-system-emscripten" )
    }

    fn message_format( &self ) -> MessageFormat {
        if let Some( name ) = self.matches.value_of( "message-format" ) {
            match name {
                "human" => MessageFormat::Human,
                "json" => MessageFormat::Json,
                _ => unreachable!()
            }
        } else {
            MessageFormat::Human
        }
    }

    fn is_verbose( &self ) -> bool {
        self.matches.is_present( "verbose" )
    }

    fn build_type( &self ) -> BuildType {
        let build_type = self.requested_build_type();
        if self.targeting_native_wasm() && build_type == BuildType::Debug {
            // TODO: Remove this in the future.
            println_err!( "warning: debug builds on the wasm-unknown-unknown are currently totally broken" );
            println_err!( "         forcing a release build" );
            return BuildType::Release;
        }

        build_type
    }

    fn package( &self ) -> Result< Option< &CargoPackage >, Error > {
        if let Some( name ) = self.matches.value_of( "package" ) {
            match self.project.packages.iter().find( |package| package.name == name ) {
                None => Err( Error::ConfigurationError( format!( "package `{}` not found", name ) ) ),
                package => Ok( package )
            }
        } else {
            Ok( None )
        }
    }

    pub fn package_or_default( &self ) -> Result< &CargoPackage, Error > {
        Ok( self.package()?.unwrap_or_else( || self.project.default_package() ) )
    }

    fn target( &'a self, package: &'a CargoPackage ) -> Result< Option< &'a CargoTarget >, Error > {
        let targets = &package.targets;
        if self.matches.is_present( "lib" ) {
            match targets.iter().find( |target| target.kind == TargetKind::Lib ) {
                None => return Err( Error::ConfigurationError( format!( "no library targets found" ) ) ),
                target => Ok( target )
            }
        } else if let Some( name ) = self.matches.value_of( "bin" ) {
            match targets.iter().find( |target| target.kind == TargetKind::Bin && target.name == name ) {
                None => return Err( Error::ConfigurationError( format!( "no bin target named `{}`", name ) ) ),
                target => Ok( target )
            }
        } else if let Some( name ) = self.matches.value_of( "example" ) {
            match targets.iter().find( |target| target.kind == TargetKind::Example && target.name == name ) {
                None => return Err( Error::ConfigurationError( format!( "no example target named `{}`", name ) ) ),
                target => Ok( target )
            }
        } else if let Some( name ) = self.matches.value_of( "bench" ) {
            match targets.iter().find( |target| target.kind == TargetKind::Bench && target.name == name ) {
                None => return Err( Error::ConfigurationError( format!( "no bench target named `{}`", name ) ) ),
                target => Ok( target )
            }
        } else {
            Ok( None )
        }
    }

    pub fn target_or_select< F >( &'a self, package: &'a CargoPackage, filter: F ) -> Result< Vec< &'a CargoTarget >, Error >
        where for< 'r > F: Fn( &'r CargoTarget ) -> bool
    {
        Ok( self.target( package )?.map( |target| vec![ target ] ).unwrap_or_else( || {
            package.targets.iter().filter( |target| filter( target ) ).collect()
        }))
    }

    fn triplet_or_default( &self ) -> &str {
        if self.matches.is_present( "target-webasm") {
            "wasm32-unknown-unknown"
        } else if self.matches.is_present( "target-webasm-emscripten" ) {
            "wasm32-unknown-emscripten"
        } else {
            "asmjs-unknown-emscripten"
        }
    }

    fn features( &self ) -> Vec< &str > {
        if let Some( features ) = self.matches.value_of( "features" ) {
            features.split_whitespace().collect()
        } else {
            Vec::new()
        }
    }

    pub fn prepare_builder( &self, config: &Config, package: &CargoPackage, target: &CargoTarget, profile: Profile ) -> Builder {
        let mut extra_paths = Vec::new();
        let mut extra_rustflags = Vec::new();
        let mut extra_environment = Vec::new();

        if self.targeting_emscripten() {
            if let Some( emscripten ) = initialize_emscripten( self.use_system_emscripten(), self.targeting_wasm() ) {
                extra_paths.push( emscripten.emscripten_path.clone() );

                let emscripten_path = emscripten.emscripten_path.to_string_lossy().into_owned();
                let emscripten_llvm_path = emscripten.emscripten_llvm_path.to_string_lossy().into_owned();

                extra_environment.push( ("EMSCRIPTEN".to_owned(), emscripten_path) );
                extra_environment.push( ("EMSCRIPTEN_FASTCOMP".to_owned(), emscripten_llvm_path.clone()) );
                extra_environment.push( ("LLVM".to_owned(), emscripten_llvm_path) );
                if let Some( binaryen_path ) = emscripten.binaryen_path {
                    let binaryen_path = binaryen_path.to_string_lossy().into_owned();
                    extra_environment.push( ("BINARYEN".to_owned(), binaryen_path) );
                }
            }

            // When compiling tests we want the exit runtime,
            // when compiling for the Web we don't want it
            // since that's more efficient.
            let exit_runtime = profile == Profile::Main;

            extra_rustflags.push( "-C".to_owned() );
            extra_rustflags.push( "link-arg=-s".to_owned() );
            extra_rustflags.push( "-C".to_owned() );
            extra_rustflags.push( format!( "link-arg=NO_EXIT_RUNTIME={}", exit_runtime as u32 ) );
        }

        if let Some( ref link_args ) = config.link_args {
            for arg in link_args {
                if arg.contains( " " ) {
                    // Not sure how to handle spaces, as `-C link-arg="{}"` doesn't work.
                    println_err!( "error: you have a space in one of the entries in `link-args` in your `Web.toml`;" );
                    println_err!( "       this is currently unsupported - aborting!" );
                    exit( 101 );
                }

                extra_rustflags.push( "-C".to_owned() );
                extra_rustflags.push( format!( "link-arg={}", arg ) );
            }
        }

        if self.targeting_native_wasm() && self.requested_build_type() == BuildType::Debug {
            extra_rustflags.push( "-C".to_owned() );
            extra_rustflags.push( "debuginfo=2".to_owned() );
        }

        Builder::new( BuildConfig {
            build_target: target_to_build_target( target, profile ),
            build_type: self.build_type(),
            triplet: Some( self.triplet_or_default().into() ),
            package: Some( package.name.clone() ),
            features: self.features().into_iter().map( |feature| feature.to_owned() ).collect(),
            no_default_features: self.matches.is_present( "no-default-features" ),
            enable_all_features: self.matches.is_present( "all-features" ),
            extra_paths,
            extra_rustflags,
            extra_environment,
            message_format: self.message_format(),
            is_verbose: self.is_verbose()
        })
    }
}

pub struct Builder( BuildConfig );

impl Builder {
    pub fn new( build_config: BuildConfig ) -> Self {
        Builder( build_config )
    }

    pub fn run( &self ) -> Result< CargoResult, Error > {
        let result = self.0.build( Some( |path: &Path| {
            if let Some( artifact ) = wasm::process_wasm_file( &self.0, path ) {
                vec![ artifact ]
            } else {
                Vec::new()
            }
        }));

        if result.is_ok() == false {
            return Err( Error::BuildError );
        }

        Ok( result )
    }
}
<commit_msg>Disable incremental compilation on wasm32-unknown-unknown<commit_after>use std::process::exit;
use std::path::Path;
use std::env;

use clap;
use cargo_shim::{
    Profile,
    CargoPackage,
    CargoProject,
    CargoTarget,
    BuildType,
    BuildConfig,
    TargetKind,
    CargoResult,
    MessageFormat,
    target_to_build_target
};

use config::Config;
use emscripten::initialize_emscripten;
use error::Error;
use wasm;

pub struct BuildArgsMatcher< 'a > {
    pub matches: &'a clap::ArgMatches< 'a >,
    pub project: &'a CargoProject
}

impl< 'a > BuildArgsMatcher< 'a > {
    fn requested_build_type( &self ) -> BuildType {
        if self.matches.is_present( "release" ) {
            BuildType::Release
        } else {
            BuildType::Debug
        }
    }

    pub fn targeting_emscripten_asmjs( &self ) -> bool {
        !self.targeting_emscripten_wasm() && !self.targeting_native_wasm()
    }

    pub fn targeting_emscripten_wasm( &self ) -> bool {
        self.matches.is_present( "target-webasm-emscripten" )
    }

    pub fn targeting_native_wasm( &self ) -> bool {
        self.matches.is_present( "target-webasm" )
    }

    pub fn targeting_wasm( &self ) -> bool {
        self.targeting_emscripten_wasm() || self.targeting_native_wasm()
    }

    pub fn targeting_emscripten( &self ) -> bool {
        self.targeting_emscripten_wasm() || self.targeting_emscripten_asmjs()
    }

    fn use_system_emscripten( &self ) -> bool {
        self.matches.is_present( "use-system-emscripten" )
    }

    fn message_format( &self ) -> MessageFormat {
        if let Some( name ) = self.matches.value_of( "message-format" ) {
            match name {
                "human" => MessageFormat::Human,
                "json" => MessageFormat::Json,
                _ => unreachable!()
            }
        } else {
            MessageFormat::Human
        }
    }

    fn is_verbose( &self ) -> bool {
        self.matches.is_present( "verbose" )
    }

    fn build_type( &self ) -> BuildType {
        let build_type = self.requested_build_type();
        if self.targeting_native_wasm() && build_type == BuildType::Debug {
            // TODO: Remove this in the future.
            println_err!( "warning: debug builds on the wasm-unknown-unknown are currently totally broken" );
            println_err!( "         forcing a release build" );
            return BuildType::Release;
        }

        build_type
    }

    fn package( &self ) -> Result< Option< &CargoPackage >, Error > {
        if let Some( name ) = self.matches.value_of( "package" ) {
            match self.project.packages.iter().find( |package| package.name == name ) {
                None => Err( Error::ConfigurationError( format!( "package `{}` not found", name ) ) ),
                package => Ok( package )
            }
        } else {
            Ok( None )
        }
    }

    pub fn package_or_default( &self ) -> Result< &CargoPackage, Error > {
        Ok( self.package()?.unwrap_or_else( || self.project.default_package() ) )
    }

    fn target( &'a self, package: &'a CargoPackage ) -> Result< Option< &'a CargoTarget >, Error > {
        let targets = &package.targets;
        if self.matches.is_present( "lib" ) {
            match targets.iter().find( |target| target.kind == TargetKind::Lib ) {
                None => return Err( Error::ConfigurationError( format!( "no library targets found" ) ) ),
                target => Ok( target )
            }
        } else if let Some( name ) = self.matches.value_of( "bin" ) {
            match targets.iter().find( |target| target.kind == TargetKind::Bin && target.name == name ) {
                None => return Err( Error::ConfigurationError( format!( "no bin target named `{}`", name ) ) ),
                target => Ok( target )
            }
        } else if let Some( name ) = self.matches.value_of( "example" ) {
            match targets.iter().find( |target| target.kind == TargetKind::Example && target.name == name ) {
                None => return Err( Error::ConfigurationError( format!( "no example target named `{}`", name ) ) ),
                target => Ok( target )
            }
        } else if let Some( name ) = self.matches.value_of( "bench" ) {
            match targets.iter().find( |target| target.kind == TargetKind::Bench && target.name == name ) {
                None => return Err( Error::ConfigurationError( format!( "no bench target named `{}`", name ) ) ),
                target => Ok( target )
            }
        } else {
            Ok( None )
        }
    }

    pub fn target_or_select< F >( &'a self, package: &'a CargoPackage, filter: F ) -> Result< Vec< &'a CargoTarget >, Error >
        where for< 'r > F: Fn( &'r CargoTarget ) -> bool
    {
        Ok( self.target( package )?.map( |target| vec![ target ] ).unwrap_or_else( || {
            package.targets.iter().filter( |target| filter( target ) ).collect()
        }))
    }

    fn triplet_or_default( &self ) -> &str {
        if self.matches.is_present( "target-webasm") {
            "wasm32-unknown-unknown"
        } else if self.matches.is_present( "target-webasm-emscripten" ) {
            "wasm32-unknown-emscripten"
        } else {
            "asmjs-unknown-emscripten"
        }
    }

    fn features( &self ) -> Vec< &str > {
        if let Some( features ) = self.matches.value_of( "features" ) {
            features.split_whitespace().collect()
        } else {
            Vec::new()
        }
    }

    pub fn prepare_builder( &self, config: &Config, package: &CargoPackage, target: &CargoTarget, profile: Profile ) -> Builder {
        let mut extra_paths = Vec::new();
        let mut extra_rustflags = Vec::new();
        let mut extra_environment = Vec::new();

        if self.targeting_emscripten() {
            if let Some( emscripten ) = initialize_emscripten( self.use_system_emscripten(), self.targeting_wasm() ) {
                extra_paths.push( emscripten.emscripten_path.clone() );

                let emscripten_path = emscripten.emscripten_path.to_string_lossy().into_owned();
                let emscripten_llvm_path = emscripten.emscripten_llvm_path.to_string_lossy().into_owned();

                extra_environment.push( ("EMSCRIPTEN".to_owned(), emscripten_path) );
                extra_environment.push( ("EMSCRIPTEN_FASTCOMP".to_owned(), emscripten_llvm_path.clone()) );
                extra_environment.push( ("LLVM".to_owned(), emscripten_llvm_path) );
                if let Some( binaryen_path ) = emscripten.binaryen_path {
                    let binaryen_path = binaryen_path.to_string_lossy().into_owned();
                    extra_environment.push( ("BINARYEN".to_owned(), binaryen_path) );
                }
            }

            // When compiling tests we want the exit runtime,
            // when compiling for the Web we don't want it
            // since that's more efficient.
            let exit_runtime = profile == Profile::Main;

            extra_rustflags.push( "-C".to_owned() );
            extra_rustflags.push( "link-arg=-s".to_owned() );
            extra_rustflags.push( "-C".to_owned() );
            extra_rustflags.push( format!( "link-arg=NO_EXIT_RUNTIME={}", exit_runtime as u32 ) );
        }

        if let Some( ref link_args ) = config.link_args {
            for arg in link_args {
                if arg.contains( " " ) {
                    // Not sure how to handle spaces, as `-C link-arg="{}"` doesn't work.
                    println_err!( "error: you have a space in one of the entries in `link-args` in your `Web.toml`;" );
                    println_err!( "       this is currently unsupported - aborting!" );
                    exit( 101 );
                }

                extra_rustflags.push( "-C".to_owned() );
                extra_rustflags.push( format!( "link-arg={}", arg ) );
            }
        }

        if self.targeting_native_wasm() && self.requested_build_type() == BuildType::Debug {
            extra_rustflags.push( "-C".to_owned() );
            extra_rustflags.push( "debuginfo=2".to_owned() );
        }

        if self.targeting_native_wasm() {
            // Incremental compilation currently doesn't work very well with
            // this target, so disable it.
            if env::var_os( "CARGO_INCREMENTAL" ).is_some() {
                extra_environment.push( ("CARGO_INCREMENTAL".to_owned(), "0".to_owned()) );
            }
        }

        Builder::new( BuildConfig {
            build_target: target_to_build_target( target, profile ),
            build_type: self.build_type(),
            triplet: Some( self.triplet_or_default().into() ),
            package: Some( package.name.clone() ),
            features: self.features().into_iter().map( |feature| feature.to_owned() ).collect(),
            no_default_features: self.matches.is_present( "no-default-features" ),
            enable_all_features: self.matches.is_present( "all-features" ),
            extra_paths,
            extra_rustflags,
            extra_environment,
            message_format: self.message_format(),
            is_verbose: self.is_verbose()
        })
    }
}

pub struct Builder( BuildConfig );

impl Builder {
    pub fn new( build_config: BuildConfig ) -> Self {
        Builder( build_config )
    }

    pub fn run( &self ) -> Result< CargoResult, Error > {
        let result = self.0.build( Some( |path: &Path| {
            if let Some( artifact ) = wasm::process_wasm_file( &self.0, path ) {
                vec![ artifact ]
            } else {
                Vec::new()
            }
        }));

        if result.is_ok() == false {
            return Err( Error::BuildError );
        }

        Ok( result )
    }
}
<|endoftext|>


<commit_before>//! Prepared statements cache for faster execution.

use std::cell::RefCell;
use std::collections::VecDeque;
use std::ops::{Deref, DerefMut};
use {Result, Connection, Statement};

/// Prepared statements cache.
#[derive(Debug)]
pub struct StatementCache<'conn> {
    conn: &'conn Connection,
    cache: RefCell<VecDeque<Statement<'conn>>>, // back = LRU
}

pub struct CachedStatement<'c: 's, 's> {
    stmt: Option<Statement<'c>>,
    cache: &'s StatementCache<'c>,
    pub cacheable: bool,
}

impl<'c, 's> Deref for CachedStatement<'c, 's> {
    type Target = Statement<'c>;

    fn deref(&self) -> &Statement<'c> {
        self.stmt.as_ref().unwrap()
    }
}

impl<'c, 's> DerefMut for CachedStatement<'c, 's> {
    fn deref_mut(&mut self) -> &mut Statement<'c> {
        self.stmt.as_mut().unwrap()
    }
}

impl<'c, 's> Drop for CachedStatement<'c, 's> {
    #[allow(unused_must_use)]
    fn drop(&mut self) {
        if self.cacheable {
            self.cache.release(self.stmt.take().unwrap());
        } else {
            self.stmt.take().unwrap().finalize();
        }
    }
}

impl<'c, 's> CachedStatement<'c, 's> {
    fn new(stmt: Statement<'c>, cache: &'s StatementCache<'c>) -> CachedStatement<'c, 's> {
        CachedStatement {
            stmt: Some(stmt),
            cache: cache,
            cacheable: true,
        }
    }
}

impl<'conn> StatementCache<'conn> {
    /// Create a statement cache.
    pub fn new(conn: &'conn Connection, capacity: usize) -> StatementCache<'conn> {
        StatementCache {
            conn: conn,
            cache: RefCell::new(VecDeque::with_capacity(capacity)),
        }
    }

    /// Search the cache for a prepared-statement object that implements `sql`.
    // If no such prepared-statement can be found, allocate and prepare a new one.
    ///
    /// # Failure
    ///
    /// Will return `Err` if no cached statement can be found and the underlying SQLite prepare call fails.
    pub fn get<'s>(&'s self, sql: &str) -> Result<CachedStatement<'conn, 's>> {
        let mut cache = self.cache.borrow_mut();
        let stmt = match cache.iter().rposition(|entry| entry.eq(sql)) {
            Some(index) => Ok(cache.swap_remove_front(index).unwrap()), // FIXME Not LRU compliant
            _ => self.conn.prepare(sql),
        };
        stmt.map(|stmt| CachedStatement::new(stmt, self))
    }

    /// If `discard` is true, then the statement is deleted immediately.
    /// Otherwise it is added to the LRU list and may be returned
    /// by a subsequent call to `get()`.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `stmt` (or the already cached statement implementing the same SQL) statement is `discard`ed
    /// and the underlying SQLite finalize call fails.
    fn release(&self, mut stmt: Statement<'conn>) {
        let mut cache = self.cache.borrow_mut();
        if cache.capacity() == cache.len() {
            // is full
            cache.pop_back(); // LRU dropped
        }
        stmt.reset_if_needed();
        stmt.clear_bindings();
        cache.push_front(stmt)
    }

    /// Flush the prepared statement cache
    pub fn clear(&self) {
        self.cache.borrow_mut().clear();
    }

    /// Return current cache size.
    pub fn len(&self) -> usize {
        self.cache.borrow().len()
    }

    /// Return maximum cache size.
    pub fn capacity(&self) -> usize {
        self.cache.borrow().capacity()
    }
}

#[cfg(test)]
mod test {
    use Connection;
    use super::StatementCache;

    #[test]
    fn test_cache() {
        let db = Connection::open_in_memory().unwrap();
        let cache = StatementCache::new(&db, 15);
        assert_eq!(0, cache.len());
        assert_eq!(15, cache.capacity());

        let sql = "PRAGMA schema_version";
        {
            let mut stmt = cache.get(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i64>(0));
        }
        assert_eq!(1, cache.len());

        {
            let mut stmt = cache.get(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i64>(0));
        }
        assert_eq!(1, cache.len());

        cache.clear();
        assert_eq!(0, cache.len());
        assert_eq!(15, cache.capacity());
    }
}
<commit_msg>Add test with cacheable set to false<commit_after>//! Prepared statements cache for faster execution.

use std::cell::RefCell;
use std::collections::VecDeque;
use std::ops::{Deref, DerefMut};
use {Result, Connection, Statement};

/// Prepared statements cache.
#[derive(Debug)]
pub struct StatementCache<'conn> {
    conn: &'conn Connection,
    cache: RefCell<VecDeque<Statement<'conn>>>, // back = LRU
}

pub struct CachedStatement<'c: 's, 's> {
    stmt: Option<Statement<'c>>,
    cache: &'s StatementCache<'c>,
    pub cacheable: bool,
}

impl<'c, 's> Deref for CachedStatement<'c, 's> {
    type Target = Statement<'c>;

    fn deref(&self) -> &Statement<'c> {
        self.stmt.as_ref().unwrap()
    }
}

impl<'c, 's> DerefMut for CachedStatement<'c, 's> {
    fn deref_mut(&mut self) -> &mut Statement<'c> {
        self.stmt.as_mut().unwrap()
    }
}

impl<'c, 's> Drop for CachedStatement<'c, 's> {
    #[allow(unused_must_use)]
    fn drop(&mut self) {
        if self.cacheable {
            self.cache.release(self.stmt.take().unwrap());
        } else {
            self.stmt.take().unwrap().finalize();
        }
    }
}

impl<'c, 's> CachedStatement<'c, 's> {
    fn new(stmt: Statement<'c>, cache: &'s StatementCache<'c>) -> CachedStatement<'c, 's> {
        CachedStatement {
            stmt: Some(stmt),
            cache: cache,
            cacheable: true,
        }
    }
}

impl<'conn> StatementCache<'conn> {
    /// Create a statement cache.
    pub fn new(conn: &'conn Connection, capacity: usize) -> StatementCache<'conn> {
        StatementCache {
            conn: conn,
            cache: RefCell::new(VecDeque::with_capacity(capacity)),
        }
    }

    /// Search the cache for a prepared-statement object that implements `sql`.
    // If no such prepared-statement can be found, allocate and prepare a new one.
    ///
    /// # Failure
    ///
    /// Will return `Err` if no cached statement can be found and the underlying SQLite prepare call fails.
    pub fn get<'s>(&'s self, sql: &str) -> Result<CachedStatement<'conn, 's>> {
        let mut cache = self.cache.borrow_mut();
        let stmt = match cache.iter().rposition(|entry| entry.eq(sql)) {
            Some(index) => Ok(cache.swap_remove_front(index).unwrap()), // FIXME Not LRU compliant
            _ => self.conn.prepare(sql),
        };
        stmt.map(|stmt| CachedStatement::new(stmt, self))
    }

    /// If `discard` is true, then the statement is deleted immediately.
    /// Otherwise it is added to the LRU list and may be returned
    /// by a subsequent call to `get()`.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `stmt` (or the already cached statement implementing the same SQL) statement is `discard`ed
    /// and the underlying SQLite finalize call fails.
    fn release(&self, mut stmt: Statement<'conn>) {
        let mut cache = self.cache.borrow_mut();
        if cache.capacity() == cache.len() {
            // is full
            cache.pop_back(); // LRU dropped
        }
        stmt.reset_if_needed();
        stmt.clear_bindings();
        cache.push_front(stmt)
    }

    /// Flush the prepared statement cache
    pub fn clear(&self) {
        self.cache.borrow_mut().clear();
    }

    /// Return current cache size.
    pub fn len(&self) -> usize {
        self.cache.borrow().len()
    }

    /// Return maximum cache size.
    pub fn capacity(&self) -> usize {
        self.cache.borrow().capacity()
    }
}

#[cfg(test)]
mod test {
    use Connection;
    use super::StatementCache;

    #[test]
    fn test_cache() {
        let db = Connection::open_in_memory().unwrap();
        let cache = StatementCache::new(&db, 15);
        assert_eq!(0, cache.len());
        assert_eq!(15, cache.capacity());

        let sql = "PRAGMA schema_version";
        {
            let mut stmt = cache.get(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i64>(0));
        }
        assert_eq!(1, cache.len());

        {
            let mut stmt = cache.get(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i64>(0));
        }
        assert_eq!(1, cache.len());

        cache.clear();
        assert_eq!(0, cache.len());
        assert_eq!(15, cache.capacity());
    }

    #[test]
    fn test_cacheable() {
        let db = Connection::open_in_memory().unwrap();
        let cache = StatementCache::new(&db, 15);

        let sql = "PRAGMA schema_version";
        {
            let mut stmt = cache.get(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i64>(0));
            stmt.cacheable = false;
        }
        assert_eq!(0, cache.len());
    }
}
<|endoftext|>


<commit_before>//! Audio IO from WAV files.

use byteorder::{self, ReadBytesExt, WriteBytesExt, LittleEndian};
use std::fs::File;
use std::io::{self, Seek, SeekFrom};

use error::{Error, Result};
use types::{SAMPLE_RATE, AudioDevice, Time, Sample};

/// Reads audio from a wav file.
///
/// The reader will continue until it runs out of samples. When it does, the
/// reader will return silence until it is reset to the beginning of the file.
pub struct WavReader {
    num_channels: usize,
    num_samples: Time,
    samples_read: Time,
    file: File
}

impl WavReader {
    /// Returns a `WavReader` reading the provided file.
    pub fn open(filename: &str) -> Result<Self> {
        let mut file = try!(File::open(filename));
        let header = try!(WavHeader::read_from_file(&mut file));
        Ok(WavReader {
            num_channels: header.num_channels as usize,
            num_samples: (header.data_size / ((header.bit_depth/8) as u32) /
                (header.num_channels as u32)) as Time,
            samples_read: 0,
            file: file
        })
    }

    /// Returns the number of audio samples in the wav file.
    pub fn get_num_samples(&self) -> Time {
        self.num_samples
    }

    /// Returns true if we have read the entire wav file.
    pub fn is_done(&self) -> bool {
        self.samples_read >= self.num_samples
    }

    /// Resets the reader to begin reading from the start of the file.
    pub fn restart(&mut self) -> io::Result<u64> {
        self.samples_read = 0;
        self.file.seek(SeekFrom::Start(44))
    }
}

impl AudioDevice for WavReader {
    fn num_inputs(&self) -> usize {
        0
    }

    fn num_outputs(&self) -> usize {
        self.num_channels
    }

    fn tick(&mut self, _: Time, _: &[Sample], outputs: &mut[Sample]) {
        for i in 0..self.num_channels {
            let s = if self.samples_read < self.num_samples {
                let n = self.file.read_i16::<LittleEndian>()
                    .expect("Failed to read next sample from wav file.");
                (n as Sample) / 32768.0
            } else {
                0.0
            };
            outputs[i] = s;
        }
        self.samples_read += 1;
    }
}

/// Writes audio to a wav file.
///
/// The writer initializes the data_size to be 0. This will not be overwritten
/// with the proper size until `update_data_size` is called.
pub struct WavWriter {
    num_channels: usize,
    file: File,
    samples_written: usize,
}

impl WavWriter {
    /// Returns a `WavWriting` writing to the provided file
    pub fn create(filename: &str, num_channels: usize)
            -> Result<Self> {
        let mut file = try!(File::create(filename));
        let header = WavHeader::new(num_channels as u16, SAMPLE_RATE as u32,
                                    0u32);
        try!(header.write_to_file(&mut file));
        Ok(WavWriter {
            num_channels: num_channels,
            file: file,
            samples_written: 0
        })
    }
}

impl Drop for WavWriter {
    fn drop(&mut self) {
        // Updates the wav header to have the correct amount of data written
        let data_size = self.samples_written * self.num_channels * 16/8;
        let file_size = 36+data_size;
        self.file.seek(SeekFrom::Start(4))
            .expect("Failed to seek wav file size.");
        self.file.write_u32::<LittleEndian>(file_size as u32)
            .expect("Failed to write wav file size.");
        self.file.seek(SeekFrom::Start(40))
            .expect("Failed to seek wav data size.");
        self.file.write_u32::<LittleEndian>(data_size as u32)
            .expect("Failed to write wav data size.");
    }
}

impl AudioDevice for WavWriter {
    fn num_inputs(&self) -> usize {
        self.num_channels
    }

    fn num_outputs(&self) -> usize {
        0
    }

    fn tick(&mut self, _: Time, inputs: &[Sample], _: &mut[Sample]) {
        for s in inputs.iter() {
            let mut clipped = *s;
            if clipped > 0.999f32 { clipped = 0.999f32; }
            if clipped < -0.999f32 { clipped = -0.999f32; }
            self.file.write_i16::<LittleEndian>((clipped*32768.0) as i16)
                .expect("Failed to write next sample to wav file.");
        }
        self.samples_written += 1;
    }
}

/// Constants for the strings used in a wav header
static RIFF: u32 = 0x46464952;
static WAVE: u32 = 0x45564157;
static FMT_: u32 = 0x20746d66;
static DATA: u32 = 0x61746164;

/// A struct container for the wav header
#[derive(Clone, Debug)]
struct WavHeader {
    riff_hdr: u32,
    file_size: u32,
    wave_lbl: u32,
    fmt_hdr: u32,
    section_size: u32,
    format: u16,
    num_channels: u16,
    sample_rate: u32,
    byte_rate: u32,
    block_align: u16,
    bit_depth: u16,
    data_hdr: u32,
    data_size: u32,
}

impl WavHeader {
    /// Returns a new wav header with all values initalized for our supported
    /// audio formats
    fn new(num_channels: u16, sample_rate: u32, data_size: u32) -> Self {
        WavHeader {
            riff_hdr: RIFF,
            file_size: data_size+36,
            wave_lbl: WAVE,
            fmt_hdr: FMT_,
            section_size: 16,
            format: 1,
            num_channels: num_channels,
            sample_rate: sample_rate,
            byte_rate: sample_rate*(num_channels as u32)*16/8,
            block_align: num_channels*16/8,
            bit_depth: 16,
            data_hdr: DATA,
            data_size: data_size,
        }
    }

    /// Attempts to read a wav header from the provided file
    fn read_from_file(f: &mut File) -> Result<Self> {
        let riff_hdr = try!(f.read_u32::<LittleEndian>());
        let file_size = try!(f.read_u32::<LittleEndian>());
        let wave_lbl = try!(f.read_u32::<LittleEndian>());
        let fmt_hdr = try!(f.read_u32::<LittleEndian>());
        let section_size = try!(f.read_u32::<LittleEndian>());
        let format = try!(f.read_u16::<LittleEndian>());
        let num_channels = try!(f.read_u16::<LittleEndian>());
        let sample_rate = try!(f.read_u32::<LittleEndian>());
        let byte_rate = try!(f.read_u32::<LittleEndian>());
        let block_align = try!(f.read_u16::<LittleEndian>());
        let bit_depth = try!(f.read_u16::<LittleEndian>());
        let data_hdr = try!(f.read_u32::<LittleEndian>());
        let data_size = try!(f.read_u32::<LittleEndian>());
        let header = WavHeader {
            riff_hdr: riff_hdr,
            file_size: file_size,
            wave_lbl: wave_lbl,
            fmt_hdr: fmt_hdr,
            section_size: section_size,
            format: format,
            num_channels: num_channels,
            sample_rate: sample_rate,
            byte_rate: byte_rate,
            block_align: block_align,
            bit_depth: bit_depth,
            data_hdr: data_hdr,
            data_size: data_size
        };
        header.check()
    }

    /// Returns the header if the wav header has valid fields and uses the
    /// supported formats, otherwise return a descriptive error
    fn check(self) -> Result<Self> {
        // Check the headers are correct
        if self.riff_hdr != RIFF { return Err(Error::InvalidFile); }
        if self.wave_lbl != WAVE { return Err(Error::InvalidFile); }
        if self.fmt_hdr  != FMT_ { return Err(Error::InvalidFile); }
        if self.data_hdr != DATA { return Err(Error::InvalidFile); }

        // Check sizes are correct
        if self.file_size != self.data_size + 36 {
            return Err(Error::InvalidFile);
        }
        if self.section_size != 16 {
            return Err(Error::InvalidFile);
        }
        if self.byte_rate != self.sample_rate*(self.num_channels as u32)*
            (self.bit_depth as u32)/8 {
            return Err(Error::InvalidFile);
        }
        if self.block_align != self.num_channels*self.bit_depth/8 {
            return Err(Error::InvalidFile);
        }

        // Check for formats we can read
        if self.format != 1 {
            return Err(Error::Unsupported("Only PCM is supported"));
        }
        if self.sample_rate != (SAMPLE_RATE as u32) {
            return Err(Error::Unsupported(
                    "Sample rate conversion not supported"));
        }
        if self.bit_depth != 16 {
            return Err(Error::Unsupported("Only 16-bit supported"));
        }

        // If this header is valid, then return it instead
        Ok(self)
    }

    /// Attempts to write this wav header to the provided file
    fn write_to_file(&self, f: &mut File) -> byteorder::Result<()> {
        f.write_u32::<LittleEndian>(self.riff_hdr)
            .and_then(|()| f.write_u32::<LittleEndian>(self.file_size))
            .and_then(|()| f.write_u32::<LittleEndian>(self.wave_lbl))
            .and_then(|()| f.write_u32::<LittleEndian>(self.fmt_hdr))
            .and_then(|()| f.write_u32::<LittleEndian>(self.section_size))
            .and_then(|()| f.write_u16::<LittleEndian>(self.format))
            .and_then(|()| f.write_u16::<LittleEndian>(self.num_channels))
            .and_then(|()| f.write_u32::<LittleEndian>(self.sample_rate))
            .and_then(|()| f.write_u32::<LittleEndian>(self.byte_rate))
            .and_then(|()| f.write_u16::<LittleEndian>(self.block_align))
            .and_then(|()| f.write_u16::<LittleEndian>(self.bit_depth))
            .and_then(|()| f.write_u32::<LittleEndian>(self.data_hdr))
            .and_then(|()| f.write_u32::<LittleEndian>(self.data_size))
    }
}
<commit_msg>Modify wav IO to use arbitrary Read/Write types<commit_after>//! Audio IO from WAV files.

use byteorder::{self, ReadBytesExt, WriteBytesExt, LittleEndian};
use std::fs::File;
use std::io::{self, Read, Seek, SeekFrom, Write};

use error::{Error, Result};
use types::{SAMPLE_RATE, AudioDevice, Time, Sample};

/// Reads audio from a wav file.
///
/// The reader will continue until it runs out of samples. When it does, the
/// reader will return silence until it is reset to the beginning of the file.
pub struct WavReader<R: Read> {
    num_channels: usize,
    num_samples: Time,
    samples_read: Time,
    reader: R
}

impl WavReader<File> {
    /// Returns a `WavReader` reading the provided file.
    pub fn open(filename: &str) -> Result<Self> {
        let file = try!(File::open(filename));
        WavReader::new(file)
    }
}

impl<R: Read> WavReader<R> {
    /// Retuns a `WavReader` reading anything implementing `Read`.
    pub fn new(mut reader: R) -> Result<Self> {
        let header = try!(WavHeader::read_from_file(&mut reader));
        Ok(WavReader {
            num_channels: header.num_channels as usize,
            num_samples: (header.data_size / ((header.bit_depth/8) as u32) /
                (header.num_channels as u32)) as Time,
            samples_read: 0,
            reader: reader
        })
    }

    /// Returns the number of audio samples in the wav file.
    pub fn get_num_samples(&self) -> Time {
        self.num_samples
    }

    /// Returns true if we have read the entire wav file.
    pub fn is_done(&self) -> bool {
        self.samples_read >= self.num_samples
    }
}

impl<R: Read+Seek> WavReader<R> {
    /// Resets the reader to begin reading from the start of the file.
    pub fn restart(&mut self) -> io::Result<u64> {
        self.samples_read = 0;
        self.reader.seek(SeekFrom::Start(44))
    }
}

impl<R: Read> AudioDevice for WavReader<R> {
    fn num_inputs(&self) -> usize {
        0
    }

    fn num_outputs(&self) -> usize {
        self.num_channels
    }

    fn tick(&mut self, _: Time, _: &[Sample], outputs: &mut[Sample]) {
        for i in 0..self.num_channels {
            let s = if self.samples_read < self.num_samples {
                let n = self.reader.read_i16::<LittleEndian>()
                    .expect("Failed to read next sample from wav.");
                (n as Sample) / 32768.0
            } else {
                0.0
            };
            outputs[i] = s;
        }
        self.samples_read += 1;
    }
}

/// Writes audio to a wav file.
///
/// The writer initializes the data_size to be 0. This will not be overwritten
/// with the proper size until `update_data_size` is called.
///
/// While `WavReader` only requires its type be `Seek` to use the `restart`
/// method, the `WavWriter` reqiures `Seek` for all types, because the final
/// data size must be written to the header when the writer leaves scope.
pub struct WavWriter<W: Write+Seek> {
    num_channels: usize,
    samples_written: usize,
    writer: W,
}

impl WavWriter<File> {
    /// Returns a `WavWriter` writing to the provided file.
    pub fn create(filename: &str, num_channels: usize)
            -> Result<Self> {
        let file = try!(File::create(filename));
        WavWriter::new(file, num_channels)
    }
}

impl<W: Write+Seek> WavWriter<W> {
    /// Returns a `WavWriter` writing to anything implementing `Write`.
    pub fn new(mut writer: W, num_channels: usize) -> Result<Self> {
        let header = WavHeader::new(num_channels as u16, SAMPLE_RATE as u32,
                                    0u32);
        try!(header.write_to_file(&mut writer));
        Ok(WavWriter {
            num_channels: num_channels,
            samples_written: 0,
            writer: writer,
        })
    }
}

impl<W: Write+Seek> Drop for WavWriter<W> {
    fn drop(&mut self) {
        // Updates the wav header to have the correct amount of data written
        let data_size = self.samples_written * self.num_channels * 16/8;
        let file_size = 36+data_size;
        self.writer.seek(SeekFrom::Start(4))
            .expect("Failed to seek wav file size.");
        self.writer.write_u32::<LittleEndian>(file_size as u32)
            .expect("Failed to write wav file size.");
        self.writer.seek(SeekFrom::Start(40))
            .expect("Failed to seek wav data size.");
        self.writer.write_u32::<LittleEndian>(data_size as u32)
            .expect("Failed to write wav data size.");
    }
}

impl<W: Write+Seek> AudioDevice for WavWriter<W> {
    fn num_inputs(&self) -> usize {
        self.num_channels
    }

    fn num_outputs(&self) -> usize {
        0
    }

    fn tick(&mut self, _: Time, inputs: &[Sample], _: &mut[Sample]) {
        for s in inputs.iter() {
            let mut clipped = *s;
            if clipped > 0.999f32 { clipped = 0.999f32; }
            if clipped < -0.999f32 { clipped = -0.999f32; }
            self.writer.write_i16::<LittleEndian>((clipped*32768.0) as i16)
                .expect("Failed to write next sample to wav file.");
        }
        self.samples_written += 1;
    }
}

/// Constants for the strings used in a wav header
static RIFF: u32 = 0x46464952;
static WAVE: u32 = 0x45564157;
static FMT_: u32 = 0x20746d66;
static DATA: u32 = 0x61746164;

/// A struct container for the wav header
#[derive(Clone, Debug)]
struct WavHeader {
    riff_hdr: u32,
    file_size: u32,
    wave_lbl: u32,
    fmt_hdr: u32,
    section_size: u32,
    format: u16,
    num_channels: u16,
    sample_rate: u32,
    byte_rate: u32,
    block_align: u16,
    bit_depth: u16,
    data_hdr: u32,
    data_size: u32,
}

impl WavHeader {
    /// Returns a new wav header with all values initalized for our supported
    /// audio formats
    fn new(num_channels: u16, sample_rate: u32, data_size: u32) -> Self {
        WavHeader {
            riff_hdr: RIFF,
            file_size: data_size+36,
            wave_lbl: WAVE,
            fmt_hdr: FMT_,
            section_size: 16,
            format: 1,
            num_channels: num_channels,
            sample_rate: sample_rate,
            byte_rate: sample_rate*(num_channels as u32)*16/8,
            block_align: num_channels*16/8,
            bit_depth: 16,
            data_hdr: DATA,
            data_size: data_size,
        }
    }

    /// Attempts to read a wav header from the provided file
    fn read_from_file<R: Read>(f: &mut R) -> Result<Self> {
        let riff_hdr = try!(f.read_u32::<LittleEndian>());
        let file_size = try!(f.read_u32::<LittleEndian>());
        let wave_lbl = try!(f.read_u32::<LittleEndian>());
        let fmt_hdr = try!(f.read_u32::<LittleEndian>());
        let section_size = try!(f.read_u32::<LittleEndian>());
        let format = try!(f.read_u16::<LittleEndian>());
        let num_channels = try!(f.read_u16::<LittleEndian>());
        let sample_rate = try!(f.read_u32::<LittleEndian>());
        let byte_rate = try!(f.read_u32::<LittleEndian>());
        let block_align = try!(f.read_u16::<LittleEndian>());
        let bit_depth = try!(f.read_u16::<LittleEndian>());
        let data_hdr = try!(f.read_u32::<LittleEndian>());
        let data_size = try!(f.read_u32::<LittleEndian>());
        let header = WavHeader {
            riff_hdr: riff_hdr,
            file_size: file_size,
            wave_lbl: wave_lbl,
            fmt_hdr: fmt_hdr,
            section_size: section_size,
            format: format,
            num_channels: num_channels,
            sample_rate: sample_rate,
            byte_rate: byte_rate,
            block_align: block_align,
            bit_depth: bit_depth,
            data_hdr: data_hdr,
            data_size: data_size
        };
        header.check()
    }

    /// Returns the header if the wav header has valid fields and uses the
    /// supported formats, otherwise return a descriptive error
    fn check(self) -> Result<Self> {
        // Check the headers are correct
        if self.riff_hdr != RIFF { return Err(Error::InvalidFile); }
        if self.wave_lbl != WAVE { return Err(Error::InvalidFile); }
        if self.fmt_hdr  != FMT_ { return Err(Error::InvalidFile); }
        if self.data_hdr != DATA { return Err(Error::InvalidFile); }

        // Check sizes are correct
        if self.file_size != self.data_size + 36 {
            return Err(Error::InvalidFile);
        }
        if self.section_size != 16 {
            return Err(Error::InvalidFile);
        }
        if self.byte_rate != self.sample_rate*(self.num_channels as u32)*
            (self.bit_depth as u32)/8 {
            return Err(Error::InvalidFile);
        }
        if self.block_align != self.num_channels*self.bit_depth/8 {
            return Err(Error::InvalidFile);
        }

        // Check for formats we can read
        if self.format != 1 {
            return Err(Error::Unsupported("Only PCM is supported"));
        }
        if self.sample_rate != (SAMPLE_RATE as u32) {
            return Err(Error::Unsupported(
                    "Sample rate conversion not supported"));
        }
        if self.bit_depth != 16 {
            return Err(Error::Unsupported("Only 16-bit supported"));
        }

        // If this header is valid, then return it instead
        Ok(self)
    }

    /// Attempts to write this wav header to the provided file
    fn write_to_file<W: Write>(&self, w: &mut W) -> byteorder::Result<()> {
        w.write_u32::<LittleEndian>(self.riff_hdr)
            .and_then(|()| w.write_u32::<LittleEndian>(self.file_size))
            .and_then(|()| w.write_u32::<LittleEndian>(self.wave_lbl))
            .and_then(|()| w.write_u32::<LittleEndian>(self.fmt_hdr))
            .and_then(|()| w.write_u32::<LittleEndian>(self.section_size))
            .and_then(|()| w.write_u16::<LittleEndian>(self.format))
            .and_then(|()| w.write_u16::<LittleEndian>(self.num_channels))
            .and_then(|()| w.write_u32::<LittleEndian>(self.sample_rate))
            .and_then(|()| w.write_u32::<LittleEndian>(self.byte_rate))
            .and_then(|()| w.write_u16::<LittleEndian>(self.block_align))
            .and_then(|()| w.write_u16::<LittleEndian>(self.bit_depth))
            .and_then(|()| w.write_u32::<LittleEndian>(self.data_hdr))
            .and_then(|()| w.write_u32::<LittleEndian>(self.data_size))
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017, 2018 Erik Nordstrøm <erik@nordstroem.no>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

use strum::IntoEnumIterator;
use arrayvec::ArrayVec;
use rand::Rng;

#[derive(EnumIter, Display, Copy, Clone)]
pub enum Color
{
    #[strum(serialize="?")]
    Unknown,
    #[strum(serialize="♠")]
    Spades,
    #[strum(serialize="♥")]
    Hearts,
    #[strum(serialize="♦")]
    Diamonds,
    #[strum(serialize="♣")]
    Clubs
}

#[derive(EnumIter, Display, Copy, Clone)]
pub enum Rank
{
    #[strum(serialize="?")]
    Unknown,
    A,
    #[strum(serialize="2")]
    Two,
    #[strum(serialize="3")]
    Three,
    #[strum(serialize="4")]
    Four,
    #[strum(serialize="5")]
    Five,
    #[strum(serialize="6")]
    Six,
    #[strum(serialize="7")]
    Seven,
    #[strum(serialize="8")]
    Eight,
    #[strum(serialize="9")]
    Nine,
    #[strum(serialize="10")]
    Ten,
    J,
    Q,
    K
}

pub struct Card
{
    pub color:     Color,
    pub rank:      Rank,
    pub id:        i8,
    pub facing_up: bool
}

// TODO: Change to ArrayVec<[Card; 52]> after PR for that size has been merged.
pub fn cards_by_id_shuffled_deck () -> ArrayVec<[Card; 56]>
{
    /*
     * The cards in the shuffled deck appear in order of their IDs,
     * such that the card with ID n is at array position n.
     */

    let mut all_cards = ArrayVec::<[_; 56]>::new();

    let mut card_ids: Vec<i8> = (0..52).collect();
    rand::thread_rng().shuffle(&mut card_ids);

    let mut card_ids_iter = card_ids.iter_mut();

    for color in Color::iter().skip(1)
    {
        for rank in Rank::iter().skip(1)
        {
            let curr_id = *(card_ids_iter.next().unwrap());

            let card = Card
            {
                color:     color,
                rank:      rank,
                id:        curr_id,
                facing_up: false
            };

            all_cards.push(card);
        }
    }

    all_cards.sort_unstable_by_key(|k| k.id);

    all_cards
}
<commit_msg>Remove a couple of intermediate variables.<commit_after>/*
 * Copyright (c) 2017, 2018 Erik Nordstrøm <erik@nordstroem.no>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

use strum::IntoEnumIterator;
use arrayvec::ArrayVec;
use rand::Rng;

#[derive(EnumIter, Display, Copy, Clone)]
pub enum Color
{
    #[strum(serialize="?")]
    Unknown,
    #[strum(serialize="♠")]
    Spades,
    #[strum(serialize="♥")]
    Hearts,
    #[strum(serialize="♦")]
    Diamonds,
    #[strum(serialize="♣")]
    Clubs
}

#[derive(EnumIter, Display, Copy, Clone)]
pub enum Rank
{
    #[strum(serialize="?")]
    Unknown,
    A,
    #[strum(serialize="2")]
    Two,
    #[strum(serialize="3")]
    Three,
    #[strum(serialize="4")]
    Four,
    #[strum(serialize="5")]
    Five,
    #[strum(serialize="6")]
    Six,
    #[strum(serialize="7")]
    Seven,
    #[strum(serialize="8")]
    Eight,
    #[strum(serialize="9")]
    Nine,
    #[strum(serialize="10")]
    Ten,
    J,
    Q,
    K
}

pub struct Card
{
    pub color:     Color,
    pub rank:      Rank,
    pub id:        i8,
    pub facing_up: bool
}

// TODO: Change to ArrayVec<[Card; 52]> after PR for that size has been merged.
pub fn cards_by_id_shuffled_deck () -> ArrayVec<[Card; 56]>
{
    /*
     * The cards in the shuffled deck appear in order of their IDs,
     * such that the card with ID n is at array position n.
     */

    let mut all_cards = ArrayVec::<[_; 56]>::new();

    let mut card_ids: Vec<i8> = (0..52).collect();
    rand::thread_rng().shuffle(&mut card_ids);

    let mut card_ids_iter = card_ids.iter_mut();

    for color in Color::iter().skip(1)
    {
        for rank in Rank::iter().skip(1)
        {
            all_cards.push(Card
            {
                color:     color,
                rank:      rank,
                id:        *(card_ids_iter.next().unwrap()),
                facing_up: false
            });
        }
    }

    all_cards.sort_unstable_by_key(|k| k.id);

    all_cards
}
<|endoftext|>


<commit_before>macro_rules! expand_align {
    () => {
        s! {
            #[allow(missing_debug_implementations)]
            #[repr(align(4))]
            pub struct pthread_mutex_t {
                size: [u8; ::__SIZEOF_PTHREAD_MUTEX_T],
            }

            #[repr(align(4))]
            pub struct pthread_rwlock_t {
                size: [u8; ::__SIZEOF_PTHREAD_RWLOCK_T],
            }

            #[repr(align(4))]
            pub struct pthread_mutexattr_t {
                size: [u8; ::__SIZEOF_PTHREAD_MUTEXATTR_T],
            }

            #[repr(align(4))]
            pub struct pthread_rwlockattr_t {
                size: [u8; ::__SIZEOF_PTHREAD_RWLOCKATTR_T],
            }

            #[repr(align(4))]
            pub struct pthread_condattr_t {
                size: [u8; ::__SIZEOF_PTHREAD_CONDATTR_T],
            }
        }

        s_no_extra_traits! {
            #[cfg_attr(target_pointer_width = "32",
                       repr(align(4)))]
            #[cfg_attr(target_pointer_width = "64",
                       repr(align(8)))]
            pub struct pthread_cond_t {
                size: [u8; ::__SIZEOF_PTHREAD_COND_T],
            }

            #[repr(align(8))]
            pub struct max_align_t {
                priv_: [f64; 2]
            }

        }

        cfg_if! {
            if #[cfg(feature = "extra_traits")] {
                impl PartialEq for pthread_cond_t {
                    fn eq(&self, other: &pthread_cond_t) -> bool {
                        self.size
                            .iter()
                            .zip(other.size.iter())
                            .all(|(a,b)| a == b)
                    }
                }
                impl Eq for pthread_cond_t {}
                impl ::fmt::Debug for pthread_cond_t {
                    fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                        f.debug_struct("pthread_cond_t")
                            // FIXME: .field("size", &self.size)
                            .finish()
                    }
                }
                impl ::hash::Hash for pthread_cond_t {
                    fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                        self.size.hash(state);
                    }
                }
            }
        }
    };
}
<commit_msg>Allow missing debug impls in emscripten<commit_after>macro_rules! expand_align {
    () => {
        s! {
            #[allow(missing_debug_implementations)]
            #[repr(align(4))]
            pub struct pthread_mutex_t {
                size: [u8; ::__SIZEOF_PTHREAD_MUTEX_T],
            }

            #[repr(align(4))]
            pub struct pthread_rwlock_t {
                size: [u8; ::__SIZEOF_PTHREAD_RWLOCK_T],
            }

            #[repr(align(4))]
            pub struct pthread_mutexattr_t {
                size: [u8; ::__SIZEOF_PTHREAD_MUTEXATTR_T],
            }

            #[repr(align(4))]
            pub struct pthread_rwlockattr_t {
                size: [u8; ::__SIZEOF_PTHREAD_RWLOCKATTR_T],
            }

            #[repr(align(4))]
            pub struct pthread_condattr_t {
                size: [u8; ::__SIZEOF_PTHREAD_CONDATTR_T],
            }
        }

        s_no_extra_traits! {
            #[cfg_attr(target_pointer_width = "32",
                       repr(align(4)))]
            #[cfg_attr(target_pointer_width = "64",
                       repr(align(8)))]
            pub struct pthread_cond_t {
                size: [u8; ::__SIZEOF_PTHREAD_COND_T],
            }

            #[allow(missing_debug_implementations)]
            #[repr(align(8))]
            pub struct max_align_t {
                priv_: [f64; 2]
            }

        }

        cfg_if! {
            if #[cfg(feature = "extra_traits")] {
                impl PartialEq for pthread_cond_t {
                    fn eq(&self, other: &pthread_cond_t) -> bool {
                        self.size
                            .iter()
                            .zip(other.size.iter())
                            .all(|(a,b)| a == b)
                    }
                }
                impl Eq for pthread_cond_t {}
                impl ::fmt::Debug for pthread_cond_t {
                    fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                        f.debug_struct("pthread_cond_t")
                            // FIXME: .field("size", &self.size)
                            .finish()
                    }
                }
                impl ::hash::Hash for pthread_cond_t {
                    fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                        self.size.hash(state);
                    }
                }
            }
        }
    };
}
<|endoftext|>


<commit_before>
//! A color type, with utility methods for modifying colors and parsing colors from hex strings.

use gl;
use gl::types::*;
use std;
use shader::UniformValue;
use buffer::VertexComponent;

/// A color with red, green, blue and alpha components. All components are expected to be
/// between 0 and 1, both inclusinve.
#[derive(Clone, Copy, Debug)]
pub struct Color {
    pub r: f32,
    pub g: f32,
    pub b: f32,
    pub a: f32,
}

impl Color {
    /// Creates a new, completly opaque (alpha = 1), color.
    ///
    /// All parameters should be between 0 and 1, both inclusive.
    pub fn rgb(r: f32, g: f32, b: f32) -> Color {
        Color {
            r: clamp(r, 0.0, 1.0),
            g: clamp(g, 0.0, 1.0),
            b: clamp(b, 0.0, 1.0),
            a: 1.0
        }
    }

    /// Creates a new color.
    ///
    /// All parameters should be between 0 and 1, both inclusive.
    pub fn rgba(r: f32, g: f32, b: f32, a: f32) -> Color {
        Color {
            r: clamp(r, 0.0, 1.0),
            g: clamp(g, 0.0, 1.0),
            b: clamp(b, 0.0, 1.0),
            a: clamp(a, 0.0, 1.0)
        }
    }

    /// Creates a color from a hex string. The string should be
    /// of the format "#rrggbb" or "rrggbb", where each of r, g
    /// and b is a hexadecimal digit.
    pub fn hex(string: &str) -> Color {
        let value = {
            if string.len() == 6 {
                i32::from_str_radix(string, 16)
            } else if string.len() == 7 {
                i32::from_str_radix(&string[1..], 16)
            } else {
                Ok(0xffffff) // White
            }
        }.unwrap_or(0xffffff);

        let r = value >> 16 & 0xff;
        let g = value >> 8 & 0xff;
        let b = value & 0xff;

        let r = r as f32 / 255.0;
        let g = g as f32 / 255.0;
        let b = b as f32 / 255.0;

        Color { r: r, g: g, b: b, a: 1.0 }
    }

    /// Creates a new color based on this color, with the red,
    /// green and blue components multiplied by the given factor.
    pub fn with_lightness(&self, factor: f32) -> Color {
        Color {
            r: clamp(self.r*factor, 0.0, 1.0),
            g: clamp(self.g*factor, 0.0, 1.0),
            b: clamp(self.b*factor, 0.0, 1.0),
            a: self.a
        }
    }
}

// Does not properly handle NaN, which should not really matter
fn clamp(value: f32, min: f32, max: f32) -> f32 {
    if value < min {
        return min;
    }
    if value > max {
        return max;
    }
    value
}

impl VertexComponent for Color {
    fn bytes() -> usize { std::mem::size_of::<f32>() * 4 }
    fn primitives() -> usize { 4 }
    fn data_type() -> GLenum { gl::FLOAT }
}
impl UniformValue for Color {
    unsafe fn set_uniform(&self, location: GLint) {
        gl::Uniform4f(location, self.r, self.g, self.b, self.a);
    }
}

<commit_msg>Added `Color::hex_int`<commit_after>
//! A color type, with utility methods for modifying colors and parsing colors from hex strings.

use gl;
use gl::types::*;
use std;
use shader::UniformValue;
use buffer::VertexComponent;

/// A color with red, green, blue and alpha components. All components are expected to be
/// between 0 and 1, both inclusinve.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Color {
    pub r: f32,
    pub g: f32,
    pub b: f32,
    pub a: f32,
}

impl Color {
    /// Creates a new, completly opaque (alpha = 1), color.
    ///
    /// All parameters should be between 0 and 1, both inclusive.
    pub fn rgb(r: f32, g: f32, b: f32) -> Color {
        Color {
            r: clamp(r, 0.0, 1.0),
            g: clamp(g, 0.0, 1.0),
            b: clamp(b, 0.0, 1.0),
            a: 1.0
        }
    }

    /// Creates a new color.
    ///
    /// All parameters should be between 0 and 1, both inclusive.
    pub fn rgba(r: f32, g: f32, b: f32, a: f32) -> Color {
        Color {
            r: clamp(r, 0.0, 1.0),
            g: clamp(g, 0.0, 1.0),
            b: clamp(b, 0.0, 1.0),
            a: clamp(a, 0.0, 1.0)
        }
    }

    /// Creates a color from a hex string. The string should be
    /// of the format "#rrggbb" or "rrggbb", where each of r, g
    /// and b is a hexadecimal digit.
    ///
    /// If the string is not valid, this returns solid white.
    pub fn hex(string: &str) -> Color {
        let value = {
            if string.len() == 6 {
                u32::from_str_radix(string, 16)
            } else if string.len() == 7 {
                u32::from_str_radix(&string[1..], 16)
            } else {
                Ok(0xffffff) // White
            }
        }.unwrap_or(0xffffff);

        Color::hex_int(value)
    }

    /// Creates a color from a hex int. Bit `0..8` (The eight least significant bits) are the
    /// red channel. Bit `8..16` are the green channel. Bit `16..24` are the blue channel. Note
    /// that this function currently ignores the alpha channel.
    ///
    /// # Example
    /// ```rust
    /// # use gondola::color::Color;
    /// let color = Color::hex_int(0xff00ff);
    ///
    /// assert_eq!(color, Color::rgb(1.0, 0.0, 1.0));
    /// ```
    pub fn hex_int(value: u32) -> Color {
        let r = value >> 16 & 0xff;
        let g = value >> 8 & 0xff;
        let b = value & 0xff;

        let r = r as f32 / 255.0;
        let g = g as f32 / 255.0;
        let b = b as f32 / 255.0;

        Color { r: r, g: g, b: b, a: 1.0 }
    }

    /// Creates a new color based on this color, with the red,
    /// green and blue components multiplied by the given factor.
    pub fn with_lightness(&self, factor: f32) -> Color {
        Color {
            r: clamp(self.r*factor, 0.0, 1.0),
            g: clamp(self.g*factor, 0.0, 1.0),
            b: clamp(self.b*factor, 0.0, 1.0),
            a: self.a
        }
    }
}

// Does not properly handle NaN, which should not really matter
fn clamp(value: f32, min: f32, max: f32) -> f32 {
    if value < min {
        return min;
    }
    if value > max {
        return max;
    }
    value
}

impl VertexComponent for Color {
    fn bytes() -> usize { std::mem::size_of::<f32>() * 4 }
    fn primitives() -> usize { 4 }
    fn data_type() -> GLenum { gl::FLOAT }
}
impl UniformValue for Color {
    unsafe fn set_uniform(&self, location: GLint) {
        gl::Uniform4f(location, self.r, self.g, self.b, self.a);
    }
}

<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use aptos_config::config::StoragePrunerConfig;
use aptos_secure_push_metrics::MetricsPusher;
use aptos_vm::AptosVM;
use std::path::PathBuf;
use structopt::StructOpt;

#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

#[derive(Debug, StructOpt)]
struct PrunerOpt {
    #[structopt(long)]
    enable_state_store_pruner: bool,

    #[structopt(long)]
    enable_ledger_pruner: bool,

    #[structopt(long, default_value = "100000", requires = "enable_state_store_pruner")]
    state_prune_window: u64,

    #[structopt(long, default_value = "100000", requires = "enable_ledger_pruner")]
    ledger_prune_window: u64,

    #[structopt(long, default_value = "500")]
    ledger_pruning_batch_size: usize,

    #[structopt(long, default_value = "500")]
    state_store_pruning_batch_size: usize,
}

impl PrunerOpt {
    fn pruner_config(&self) -> StoragePrunerConfig {
        StoragePrunerConfig {
            enable_state_store_pruner: self.enable_state_store_pruner,
            enable_ledger_pruner: self.enable_ledger_pruner,
            state_store_prune_window: self.state_prune_window,
            ledger_prune_window: self.ledger_prune_window,
            ledger_pruning_batch_size: self.ledger_pruning_batch_size,
            state_store_pruning_batch_size: self.state_store_pruning_batch_size,
        }
    }
}

#[derive(Debug, StructOpt)]
struct Opt {
    #[structopt(long, default_value = "500")]
    block_size: usize,

    #[structopt(long)]
    concurrency_level: Option<usize>,

    #[structopt(flatten)]
    pruner_opt: PrunerOpt,

    #[structopt(subcommand)]
    cmd: Command,

    #[structopt(
        long,
        about = "Verify sequence number of all the accounts after execution finishes"
    )]
    verify_sequence_numbers: bool,
}

impl Opt {
    fn concurrency_level(&self) -> usize {
        match self.concurrency_level {
            None => {
                let level = num_cpus::get();
                println!(
                    "\nVM concurrency level defaults to num of cpus: {}\n",
                    level
                );
                level
            }
            Some(level) => level,
        }
    }
}

#[derive(Debug, StructOpt)]
enum Command {
    CreateDb {
        #[structopt(long, parse(from_os_str))]
        data_dir: PathBuf,

        #[structopt(long, default_value = "1000000")]
        num_accounts: usize,

        #[structopt(long, default_value = "1000000")]
        init_account_balance: u64,
    },
    RunExecutor {
        #[structopt(
            long,
            default_value = "1000",
            about = "number of transfer blocks to run"
        )]
        blocks: usize,

        #[structopt(long, parse(from_os_str))]
        data_dir: PathBuf,

        #[structopt(long, parse(from_os_str))]
        checkpoint_dir: PathBuf,
    },
    AddAccounts {
        #[structopt(long, parse(from_os_str))]
        data_dir: PathBuf,

        #[structopt(long, parse(from_os_str))]
        checkpoint_dir: PathBuf,

        #[structopt(long, default_value = "1000000")]
        num_new_accounts: usize,

        #[structopt(long, default_value = "1000000")]
        init_account_balance: u64,
    },
}

fn main() {
    let _mp = MetricsPusher::start();
    let opt = Opt::from_args();

    aptos_logger::Logger::new().init();

    rayon::ThreadPoolBuilder::new()
        .thread_name(|index| format!("rayon-global-{}", index))
        .build_global()
        .expect("Failed to build rayon global thread pool.");
    AptosVM::set_concurrency_level_once(opt.concurrency_level());

    match opt.cmd {
        Command::CreateDb {
            data_dir,
            num_accounts,
            init_account_balance,
        } => {
            executor_benchmark::db_generator::run(
                num_accounts,
                init_account_balance,
                opt.block_size,
                data_dir,
                opt.pruner_opt.pruner_config(),
                opt.verify_sequence_numbers,
            );
        }
        Command::RunExecutor {
            blocks,
            data_dir,
            checkpoint_dir,
        } => {
            executor_benchmark::run_benchmark(
                opt.block_size,
                blocks,
                data_dir,
                checkpoint_dir,
                opt.verify_sequence_numbers,
                opt.pruner_opt.pruner_config(),
            );
        }
        Command::AddAccounts {
            data_dir,
            checkpoint_dir,
            num_new_accounts,
            init_account_balance,
        } => {
            executor_benchmark::add_accounts(
                num_new_accounts,
                init_account_balance,
                opt.block_size,
                data_dir,
                checkpoint_dir,
                opt.pruner_opt.pruner_config(),
                opt.verify_sequence_numbers,
            );
        }
    }
}
<commit_msg>[Fix] Remove "requires" in pruner flags for executor-benchmark. (#2731)<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use aptos_config::config::StoragePrunerConfig;
use aptos_secure_push_metrics::MetricsPusher;
use aptos_vm::AptosVM;
use std::path::PathBuf;
use structopt::StructOpt;

#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

#[derive(Debug, StructOpt)]
struct PrunerOpt {
    #[structopt(long)]
    enable_state_store_pruner: bool,

    #[structopt(long)]
    enable_ledger_pruner: bool,

    #[structopt(long, default_value = "100000")]
    state_prune_window: u64,

    #[structopt(long, default_value = "100000")]
    ledger_prune_window: u64,

    #[structopt(long, default_value = "500")]
    ledger_pruning_batch_size: usize,

    #[structopt(long, default_value = "500")]
    state_store_pruning_batch_size: usize,
}

impl PrunerOpt {
    fn pruner_config(&self) -> StoragePrunerConfig {
        StoragePrunerConfig {
            enable_state_store_pruner: self.enable_state_store_pruner,
            enable_ledger_pruner: self.enable_ledger_pruner,
            state_store_prune_window: self.state_prune_window,
            ledger_prune_window: self.ledger_prune_window,
            ledger_pruning_batch_size: self.ledger_pruning_batch_size,
            state_store_pruning_batch_size: self.state_store_pruning_batch_size,
        }
    }
}

#[derive(Debug, StructOpt)]
struct Opt {
    #[structopt(long, default_value = "500")]
    block_size: usize,

    #[structopt(long)]
    concurrency_level: Option<usize>,

    #[structopt(flatten)]
    pruner_opt: PrunerOpt,

    #[structopt(subcommand)]
    cmd: Command,

    #[structopt(
        long,
        about = "Verify sequence number of all the accounts after execution finishes"
    )]
    verify_sequence_numbers: bool,
}

impl Opt {
    fn concurrency_level(&self) -> usize {
        match self.concurrency_level {
            None => {
                let level = num_cpus::get();
                println!(
                    "\nVM concurrency level defaults to num of cpus: {}\n",
                    level
                );
                level
            }
            Some(level) => level,
        }
    }
}

#[derive(Debug, StructOpt)]
enum Command {
    CreateDb {
        #[structopt(long, parse(from_os_str))]
        data_dir: PathBuf,

        #[structopt(long, default_value = "1000000")]
        num_accounts: usize,

        #[structopt(long, default_value = "1000000")]
        init_account_balance: u64,
    },
    RunExecutor {
        #[structopt(
            long,
            default_value = "1000",
            about = "number of transfer blocks to run"
        )]
        blocks: usize,

        #[structopt(long, parse(from_os_str))]
        data_dir: PathBuf,

        #[structopt(long, parse(from_os_str))]
        checkpoint_dir: PathBuf,
    },
    AddAccounts {
        #[structopt(long, parse(from_os_str))]
        data_dir: PathBuf,

        #[structopt(long, parse(from_os_str))]
        checkpoint_dir: PathBuf,

        #[structopt(long, default_value = "1000000")]
        num_new_accounts: usize,

        #[structopt(long, default_value = "1000000")]
        init_account_balance: u64,
    },
}

fn main() {
    let _mp = MetricsPusher::start();
    let opt = Opt::from_args();

    aptos_logger::Logger::new().init();

    rayon::ThreadPoolBuilder::new()
        .thread_name(|index| format!("rayon-global-{}", index))
        .build_global()
        .expect("Failed to build rayon global thread pool.");
    AptosVM::set_concurrency_level_once(opt.concurrency_level());

    match opt.cmd {
        Command::CreateDb {
            data_dir,
            num_accounts,
            init_account_balance,
        } => {
            executor_benchmark::db_generator::run(
                num_accounts,
                init_account_balance,
                opt.block_size,
                data_dir,
                opt.pruner_opt.pruner_config(),
                opt.verify_sequence_numbers,
            );
        }
        Command::RunExecutor {
            blocks,
            data_dir,
            checkpoint_dir,
        } => {
            executor_benchmark::run_benchmark(
                opt.block_size,
                blocks,
                data_dir,
                checkpoint_dir,
                opt.verify_sequence_numbers,
                opt.pruner_opt.pruner_config(),
            );
        }
        Command::AddAccounts {
            data_dir,
            checkpoint_dir,
            num_new_accounts,
            init_account_balance,
        } => {
            executor_benchmark::add_accounts(
                num_new_accounts,
                init_account_balance,
                opt.block_size,
                data_dir,
                checkpoint_dir,
                opt.pruner_opt.pruner_config(),
                opt.verify_sequence_numbers,
            );
        }
    }
}
<|endoftext|>


<commit_before>extern crate sha1;

use std::cmp::{Ordering, Ord, Eq, PartialEq, PartialOrd};

struct Node {
    node: String,
    hash: i32
}

impl Eq for Node {
}

#[allow(unused_variables)]
impl PartialOrd for Node {
    fn partial_cmp(&self, other: &Node) -> Option<Ordering> {
        None
    }
}

#[allow(unused_variables)]
impl PartialEq for Node {
    fn eq(&self, other: &Node) -> bool {
        false
    }
}

impl Ord for Node {
    fn cmp(&self, other: &Node) -> Ordering {
        if self.hash == other.hash {
            Ordering::Greater
        }else if self.hash > other.hash {
            Ordering::Greater
        } else {
            Ordering::Less
        }
    }
}

impl Node {
    fn self_cmp(&self, other: &Node) -> Ordering {
        if self.hash >= other.hash {
            Ordering::Equal
        } else {
            Ordering::Less
        }
    }
}

type TickArray = Vec<Node>;

pub struct HashRing {
    default_spots: i32,
    ticks: TickArray,
    length: usize
}

#[allow(exceeding_bitshifts)]
impl HashRing {
    pub fn new(n: i32) -> HashRing {
        let tk = Vec::new();
        let h = HashRing{default_spots: n, ticks: tk, length: 0};
        h
    }

    pub fn add(&mut self, n: String, s: i32) {
        let spots = self.default_spots * s;
        let mut hash = sha1::Sha1::new();

        for i in 0..spots {
            hash.reset();
            let ts: String = i.to_string();

            let b = format!("{}:{}", n, ts);
            hash.update(b.as_bytes());
            let hash_bytes = hash.digest().bytes();
            let _node = Node{node: n.clone(), hash: ((hash_bytes[19] as u32) | (hash_bytes[18] as u32) << 8 | (hash_bytes[17] as u32) << 16 | (hash_bytes[16] as u32) << 24) as i32};
            self.ticks.push(_node);
        }
    }

    pub fn bake(&mut self) {
        self.ticks.sort_by(|a, b| a.cmp(&b));
        self.length = self.ticks.len();
    }

    pub fn hash(&self, s: String) -> String {
        let mut h = sha1::Sha1::new();
        h.reset();
        h.update(s.as_bytes());
        let hash_bytes = h.digest().bytes();
        let v = ((hash_bytes[19] as u32) | (hash_bytes[18] as u32) << 8 | (hash_bytes[17] as u32) << 16 | (hash_bytes[16] as u32) << 24) as i32;

        let _node = Node{hash: v, node: "".to_string()};
        match self.ticks.binary_search_by(|v| v.self_cmp(&_node)) {
            Ok(i) => {
                let nd = &self.ticks[i];
                nd.node.clone()
            },
            Err(_) => {
                // idx == self.length occur, reset the idx to 0
                let nd = &self.ticks[0];
                nd.node.clone()
            }
        }
    }
}

#[test]
fn test_simple() {
    let mut ring = HashRing::new(255);
    ring.add("node1".to_string(), 1);
    ring.add("node2".to_string(), 1);
    ring.add("node3".to_string(), 1);
    ring.bake();
    let i = ring.hash("liutaihua".to_string());
    println!("======= str: liutaihua, hash res:{:?} ========", i);
}

#[test]
fn bench() {
    let mut ring = HashRing::new(255);
    ring.add("node1".to_string(), 1);
    ring.add("node2".to_string(), 1);
    ring.add("node3".to_string(), 1);
    ring.add("node4".to_string(), 1);
    ring.add("node5".to_string(), 1);

    ring.bake();
    for i in 20000..30000 {
        println!("{} {}", i, ring.hash(i.to_string()));
    }
}
<commit_msg>fix shift left stack overflow<commit_after>extern crate sha1;

use std::cmp::{Ordering, Ord, Eq, PartialEq, PartialOrd};

struct Node {
    node: String,
    hash: u32
}

impl Eq for Node {
}

#[allow(unused_variables)]
impl PartialOrd for Node {
    fn partial_cmp(&self, other: &Node) -> Option<Ordering> {
        None
    }
}

#[allow(unused_variables)]
impl PartialEq for Node {
    fn eq(&self, other: &Node) -> bool {
        false
    }
}

impl Ord for Node {
    fn cmp(&self, other: &Node) -> Ordering {
        if self.hash == other.hash {
            Ordering::Greater
        }else if self.hash > other.hash {
            Ordering::Greater
        } else {
            Ordering::Less
        }
    }
}

impl Node {
    fn self_cmp(&self, other: &Node) -> Ordering {
        if self.hash >= other.hash {
            Ordering::Equal
        } else {
            Ordering::Less
        }
    }
}

type TickArray = Vec<Node>;

pub struct HashRing {
    default_spots: i32,
    ticks: TickArray,
    length: usize
}

#[allow(exceeding_bitshifts)]
impl HashRing {
    pub fn new(n: i32) -> HashRing {
        let tk = Vec::new();
        let h = HashRing{default_spots: n, ticks: tk, length: 0};
        h
    }

    pub fn add(&mut self, n: String, s: i32) {
        let spots = self.default_spots * s;
        let mut hash = sha1::Sha1::new();

        for i in 0..spots {
            hash.reset();
            let ts: String = i.to_string();

            let b = format!("{}:{}", n, ts);
            hash.update(b.as_bytes());
            let hash_bytes = hash.digest().bytes();
            let _node = Node{node: n.clone(), hash: (hash_bytes[19] as u32) | (hash_bytes[18] as u32) << 8 | (hash_bytes[17] as u32) << 16 | (hash_bytes[16] as u32) << 24};
            self.ticks.push(_node);
        }
    }

    pub fn bake(&mut self) {
        self.ticks.sort_by(|a, b| a.cmp(&b));
        self.length = self.ticks.len();
    }

    pub fn hash(&self, s: String) -> String {
        let mut h = sha1::Sha1::new();
        h.reset();
        h.update(s.as_bytes());
        let hash_bytes = h.digest().bytes();
        let v = (hash_bytes[19] as u32) | (hash_bytes[18] as u32) << 8 | (hash_bytes[17] as u32) << 16 | (hash_bytes[16] as u32) << 24;

        let _node = Node{hash: v, node: "".to_string()};
        match self.ticks.binary_search_by(|v| v.self_cmp(&_node)) {
            Ok(i) => {
                let nd = &self.ticks[i];
                nd.node.clone()
            },
            Err(_) => {
                // idx == self.length occur, reset the idx to 0
                let nd = &self.ticks[0];
                nd.node.clone()
            }
        }
    }
}

#[test]
fn test_simple() {
    let mut ring = HashRing::new(255);
    ring.add("node1".to_string(), 1);
    ring.add("node2".to_string(), 1);
    ring.add("node3".to_string(), 1);
    ring.bake();
    let i = ring.hash("liutaihua".to_string());
    println!("======= str: liutaihua, hash res:{:?} ========", i);
}

#[test]
fn bench() {
    let mut ring = HashRing::new(255);
    ring.add("node1".to_string(), 1);
    ring.add("node2".to_string(), 1);
    ring.add("node3".to_string(), 1);
    ring.add("node4".to_string(), 1);
    ring.add("node5".to_string(), 1);

    ring.bake();
    for i in 20000..30000 {
        println!("{} {}", i, ring.hash(i.to_string()));
    }
}
<|endoftext|>


<commit_before>extern crate sha1;

use std::cmp::{Ordering, Ord, Eq, PartialEq, PartialOrd};

struct node {
    node: String,
    hash: i32
}

impl Eq for node {
}

impl PartialOrd for node {
    fn partial_cmp(&self, other: &node) -> Option<Ordering> {
        None
    }
}

impl PartialEq for node {
    fn eq(&self, other: &node) -> bool {
        false
    }
}

impl Ord for node {
    fn cmp(&self, other: &node) -> Ordering {
        if self.hash >= other.hash {
            Ordering::Equal
        } else {
            Ordering::Less
        }
    }
}

//impl node {
//    fn new(n: String, hash: i32) -> node {
//
//    }
//}

type TickArray = Vec<node>;

pub struct HashRing {
    defaultSpots: i32,
    ticks: TickArray,
    length: usize
}

#[allow(exceeding_bitshifts)]
impl HashRing {
    pub fn new(n: i32) -> HashRing {
        let tk = Vec::new();
        let h = HashRing{defaultSpots: n, ticks: tk, length: 0};
        h
    }

    pub fn add(&mut self, n: String, s: i32) {
        let tSpots = self.defaultSpots * s;
        let mut hash = sha1::Sha1::new();

        for i in 0..tSpots {
            hash.reset();
            let ts: String = i.to_string();

            let b = format!("{}:{}", n, ts);
            hash.update(b.as_bytes());
            let hashBytes = hash.digest().bytes();
            let _node = node{node: n.clone(), hash: (hashBytes[19] | hashBytes[18] << 8 | hashBytes[17] << 16 | hashBytes[16] << 24) as i32};
            self.ticks.push(_node);
        }
    }

    pub fn bake(&mut self) {
        self.ticks.sort();
        self.length = self.ticks.len();
    }

    pub fn hash(&self, s: String) -> String {
        let mut h = sha1::Sha1::new();
        h.reset();
        h.update(s.as_bytes());
        let hashBytes = h.digest().bytes();
        let v = (hashBytes[19] | hashBytes[18] << 8 | hashBytes[17] << 16 | hashBytes[16] << 24) as i32;
        let _node = node{hash: v, node: "".to_string()};
        let nd: &node;
        match self.ticks.binary_search_by(|v| v.cmp(&_node)) {
            Ok(i) => {
                nd = &self.ticks[i];
            },
            _ => {
                nd = &self.ticks[0];
            }
        }
        nd.node.clone()
    }
}

#[cfg(test)]
mod tests {

}<commit_msg>add test<commit_after>extern crate sha1;

use std::cmp::{Ordering, Ord, Eq, PartialEq, PartialOrd};

struct Node {
    node: String,
    hash: i32
}

impl Eq for Node {
}

#[allow(unused_variables)]
impl PartialOrd for Node {
    fn partial_cmp(&self, other: &Node) -> Option<Ordering> {
        None
    }
}

#[allow(unused_variables)]
impl PartialEq for Node {
    fn eq(&self, other: &Node) -> bool {
        false
    }
}

impl Ord for Node {
    fn cmp(&self, other: &Node) -> Ordering {
        if self.hash >= other.hash {
            Ordering::Equal
        } else {
            Ordering::Less
        }
    }
}

type TickArray = Vec<Node>;

pub struct HashRing {
    default_spots: i32,
    ticks: TickArray,
    length: usize
}

#[allow(exceeding_bitshifts)]
impl HashRing {
    pub fn new(n: i32) -> HashRing {
        let tk = Vec::new();
        let h = HashRing{default_spots: n, ticks: tk, length: 0};
        h
    }

    pub fn add(&mut self, n: String, s: i32) {
        let spots = self.default_spots * s;
        let mut hash = sha1::Sha1::new();

        for i in 0..spots {
            hash.reset();
            let ts: String = i.to_string();

            let b = format!("{}:{}", n, ts);
            hash.update(b.as_bytes());
            let hash_bytes = hash.digest().bytes();
            let _node = Node{node: n.clone(), hash: ((hash_bytes[19] as u32) | (hash_bytes[18] as u32) << 8 | (hash_bytes[17] as u32) << 16 | (hash_bytes[16] as u32) << 24) as i32};
            self.ticks.push(_node);
        }
    }

    pub fn bake(&mut self) {
        self.ticks.sort();
        self.length = self.ticks.len();
    }

    pub fn hash(&self, s: String) -> String {
        let mut h = sha1::Sha1::new();
        h.reset();
        h.update(s.as_bytes());
        let hash_bytes = h.digest().bytes();
//        let v = (hash_bytes[19] | hash_bytes[18] << 8 | hash_bytes[17] << 16 | hash_bytes[16] << 24) as i32;
        let v = ((hash_bytes[19] as u32) | (hash_bytes[18] as u32) << 8 | (hash_bytes[17] as u32) << 16 | (hash_bytes[16] as u32) << 24) as i32;

        let _node = Node{hash: v, node: "".to_string()};
        let nd: &Node;
        match self.ticks.binary_search_by(|v| v.cmp(&_node)) {
            Ok(i) => {
                nd = &self.ticks[i];
            },
            _ => {
                nd = &self.ticks[0];
            }
        }
        nd.node.clone()
    }
}

#[test]
fn test_simple() {
    let mut ring = HashRing::new(255);
    ring.add("node1".to_string(), 1);
    ring.add("node2".to_string(), 1);
    ring.add("node3".to_string(), 1);
    ring.bake();
    let i = ring.hash("liutaihua".to_string());
    println!("======= str: liutaihua, hash res:{:?} ========", i);
}

#[test]
fn bench() {
    let mut ring = HashRing::new(255);
    ring.add("node1".to_string(), 1);
    ring.add("node2".to_string(), 1);
    ring.add("node3".to_string(), 1);
    ring.add("node4".to_string(), 1);
    ring.add("node5".to_string(), 1);

    ring.bake();
    for i in 0..1000 {
        println!("{}", ring.hash(i.to_string()));
    }
}
<|endoftext|>