<commit_before>use bifrost::rpc;
use bifrost::conshash::ConsistentHashing;
use bifrost::raft;
use bifrost::raft::client::RaftClient;
use bifrost::raft::state_machine::{master as sm_master};
use bifrost::membership::server::Membership;
use bifrost::membership::member::MemberService;
use bifrost::conshash::weights::Weights;
use bifrost::tcp::{STANDALONE_ADDRESS_STRING};
use ram::chunk::Chunks;
use ram::schema::SchemasServer;
use ram::schema::{sm as schema_sm};
use ram::types::Id;
use std::sync::Arc;
use std::io;

pub mod cell_rpc;
pub mod transactions;

#[derive(Debug)]
pub enum ServerError {
    CannotJoinCluster,
    CannotJoinClusterGroup(sm_master::ExecError),
    CannotInitMemberTable,
    CannotSetServerWeight,
    CannotInitConsistentHashTable,
    CannotLoadMetaClient,
    CannotInitializeSchemaServer(sm_master::ExecError),
    StandaloneMustAlsoBeMetaServer,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerOptions {
    pub chunk_count: usize,
    pub memory_size: usize,
    pub standalone: bool,
    pub is_meta: bool,
    pub meta_members: Vec<String>,
    pub address: String,
    pub backup_storage: Option<String>,
    pub meta_storage: Option<String>,
    pub group_name: String,
}

pub struct ServerMeta {
    pub schemas: SchemasServer
}

pub struct NebServer {
    pub chunks: Arc<Chunks>,
    pub meta: Arc<ServerMeta>,
    pub rpc: Arc<rpc::Server>,
    pub consh: Arc<ConsistentHashing>,
    pub member_pool: rpc::ClientPool,
    pub txn_peer: transactions::Peer,
    pub raft_service: Option<Arc<raft::RaftService>>,
    pub server_id: u64
}

impl NebServer {
    fn load_meta_server(opt: &ServerOptions, rpc_server: &Arc<rpc::Server>) -> Result<Arc<raft::RaftService>, ServerError> {
        let server_addr = &opt.address;
        let raft_service = raft::RaftService::new(raft::Options {
            storage: match opt.meta_storage {
                Some(ref path) => raft::Storage::DISK(path.clone()),
                None => raft::Storage::MEMORY,
            },
            address: server_addr.clone(),
            service_id: raft::DEFAULT_SERVICE_ID,
        });
        rpc_server.register_service(
            raft::DEFAULT_SERVICE_ID,
            &raft_service
        );
        raft_service.register_state_machine(Box::new(schema_sm::SchemasSM::new(&opt.group_name, &raft_service)));
        raft::RaftService::start(&raft_service);
        match raft_service.join(&opt.meta_members) {
            Err(sm_master::ExecError::CannotConstructClient) => {
                info!("Cannot join meta cluster, will bootstrap one.");
                raft_service.bootstrap();
            },
            Ok(Ok(())) => {
                info!("Joined meta cluster, number of members: {}", raft_service.num_members());
            },
            e => {
                error!("Cannot join into cluster: {:?}", e);
                return Err(ServerError::CannotJoinCluster)
            }
        }
        Membership::new(rpc_server, &raft_service);
        Weights::new(&raft_service);
        return Ok(raft_service);
    }
    fn join_group(opt: &ServerOptions, raft_client: &Arc<RaftClient>) -> Result<(), ServerError> {
        let member_service = MemberService::new(&opt.address, raft_client);
        match member_service.join_group(&opt.group_name) {
            Ok(_) => {Ok(())},
            Err(e) => {
                error!("Cannot join cluster group");
                Err(ServerError::CannotJoinClusterGroup(e))
            }
        }
    }
    fn init_conshash(opt: &ServerOptions, raft_client: &Arc<RaftClient>)
        -> Result<Arc<ConsistentHashing>, ServerError> {
        match ConsistentHashing::new(&opt.group_name, raft_client) {
            Ok(ch) => {
                ch.set_weight(&opt.address, opt.memory_size as u64);
                if !ch.init_table().is_ok() {
                    error!("Cannot initialize member table");
                    return Err(ServerError::CannotInitMemberTable);
                }
                return Ok(ch);
            },
            _ => {
                error!("Cannot initialize consistent hash table");
                return Err(ServerError::CannotInitConsistentHashTable);
            }
        }
    }
    fn load_cluster_clients
    (opt: &ServerOptions, schemas: &mut SchemasServer, rpc_server: &Arc<rpc::Server>)
     -> Result<Arc<ConsistentHashing>, ServerError>{
        let raft_client = RaftClient::new(&opt.meta_members, raft::DEFAULT_SERVICE_ID);
        match raft_client {
            Ok(raft_client) => {
                RaftClient::prepare_subscription(rpc_server);
                NebServer::join_group(opt, &raft_client)?;
                let conshash = NebServer::init_conshash(opt, &raft_client)?;
                let schema_server = match SchemasServer::new(&opt.group_name, Some(&raft_client)) {
                    Ok(schema) => schema,
                    Err(e) => return Err(ServerError::CannotInitializeSchemaServer(e))
                };
                *schemas = schema_server;
                Ok(conshash)
            },
            Err(e) => {
                error!("Cannot load meta client: {:?}", e);
                Err(ServerError::CannotLoadMetaClient)
            }
        }
    }
    pub fn new_from_opts(opts: &ServerOptions) -> Result<Arc<NebServer>, ServerError> {
        let server_addr = if opts.standalone {&STANDALONE_ADDRESS_STRING} else {&opts.address};
        let rpc_server = rpc::Server::new(server_addr);
        rpc::Server::listen_and_resume(&rpc_server);
        return NebServer::new(opts, server_addr, &rpc_server)
    }
    pub fn new(
        opts: &ServerOptions,
        server_addr: &String,
        rpc_server: &Arc<rpc::Server>,
    ) -> Result<Arc<NebServer>, ServerError> {
        let mut raft_service = None;
        if opts.is_meta {
            raft_service = Some(NebServer::load_meta_server(&opts, &rpc_server)?);
        }
        if !opts.is_meta && opts.standalone {
            return Err(ServerError::StandaloneMustAlsoBeMetaServer)
        }
        let mut schemas = SchemasServer::new(&opts.group_name, None).unwrap();
        let conshasing =
            NebServer::load_cluster_clients(&opts, &mut schemas, &rpc_server)?;
        let meta_rc = Arc::new(ServerMeta {
            schemas
        });
        let chunks = Chunks::new(
            opts.chunk_count,
            opts.memory_size,
            meta_rc.clone(),
            opts.backup_storage.clone(),
        );
        let server = Arc::new(NebServer {
            chunks,
            meta: meta_rc,
            rpc: rpc_server.clone(),
            consh: conshasing,
            member_pool: rpc::ClientPool::new(),
            txn_peer: transactions::Peer::new(server_addr),
            raft_service,
            server_id: rpc_server.server_id
        });
        rpc_server.register_service(
            cell_rpc::DEFAULT_SERVICE_ID,
            &cell_rpc::NebRPCService::new(&server)
        );
        rpc_server.register_service(
            transactions::manager::DEFAULT_SERVICE_ID,
            &transactions::manager::TransactionManager::new(&server)
        );
        rpc_server.register_service(
            transactions::data_site::DEFAULT_SERVICE_ID,
            &transactions::data_site::DataManager::new(&server)
        );
        Ok(server)
    }
    pub fn get_server_id_by_id(&self, id: &Id) -> Option<u64> {
        if let Some(server_id) = self.consh.get_by_server_id(id.higher) {
            Some(server_id)
        } else {
            None
        }
    }
    pub fn get_member_by_server_id(&self, server_id: u64) -> io::Result<Arc<rpc::RPCClient>> {
        if let Some(ref server_name) = self.consh.to_server_name(Some(server_id)) {
            self.member_pool.get(server_name)
        } else {
            Err(io::Error::new(io::ErrorKind::Other, "Cannot find server id in consistent hash table"))
        }
    }
}<commit_msg>attach prefix to group name<commit_after>use bifrost::rpc;
use bifrost::conshash::ConsistentHashing;
use bifrost::raft;
use bifrost::raft::client::RaftClient;
use bifrost::raft::state_machine::{master as sm_master};
use bifrost::membership::server::Membership;
use bifrost::membership::member::MemberService;
use bifrost::conshash::weights::Weights;
use bifrost::tcp::{STANDALONE_ADDRESS_STRING};
use ram::chunk::Chunks;
use ram::schema::SchemasServer;
use ram::schema::{sm as schema_sm};
use ram::types::Id;
use std::sync::Arc;
use std::io;

pub mod cell_rpc;
pub mod transactions;

#[derive(Debug)]
pub enum ServerError {
    CannotJoinCluster,
    CannotJoinClusterGroup(sm_master::ExecError),
    CannotInitMemberTable,
    CannotSetServerWeight,
    CannotInitConsistentHashTable,
    CannotLoadMetaClient,
    CannotInitializeSchemaServer(sm_master::ExecError),
    StandaloneMustAlsoBeMetaServer,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerOptions {
    pub chunk_count: usize,
    pub memory_size: usize,
    pub standalone: bool,
    pub is_meta: bool,
    pub meta_members: Vec<String>,
    pub address: String,
    pub backup_storage: Option<String>,
    pub meta_storage: Option<String>,
    pub group_name: String,
}

pub struct ServerMeta {
    pub schemas: SchemasServer
}

pub struct NebServer {
    pub chunks: Arc<Chunks>,
    pub meta: Arc<ServerMeta>,
    pub rpc: Arc<rpc::Server>,
    pub consh: Arc<ConsistentHashing>,
    pub member_pool: rpc::ClientPool,
    pub txn_peer: transactions::Peer,
    pub raft_service: Option<Arc<raft::RaftService>>,
    pub server_id: u64
}

impl NebServer {
    fn load_meta_server(opt: &ServerOptions, rpc_server: &Arc<rpc::Server>) -> Result<Arc<raft::RaftService>, ServerError> {
        let server_addr = &opt.address;
        let raft_service = raft::RaftService::new(raft::Options {
            storage: match opt.meta_storage {
                Some(ref path) => raft::Storage::DISK(path.clone()),
                None => raft::Storage::MEMORY,
            },
            address: server_addr.clone(),
            service_id: raft::DEFAULT_SERVICE_ID,
        });
        rpc_server.register_service(
            raft::DEFAULT_SERVICE_ID,
            &raft_service
        );
        raft_service.register_state_machine(Box::new(schema_sm::SchemasSM::new(&opt.group_name, &raft_service)));
        raft::RaftService::start(&raft_service);
        match raft_service.join(&opt.meta_members) {
            Err(sm_master::ExecError::CannotConstructClient) => {
                info!("Cannot join meta cluster, will bootstrap one.");
                raft_service.bootstrap();
            },
            Ok(Ok(())) => {
                info!("Joined meta cluster, number of members: {}", raft_service.num_members());
            },
            e => {
                error!("Cannot join into cluster: {:?}", e);
                return Err(ServerError::CannotJoinCluster)
            }
        }
        Membership::new(rpc_server, &raft_service);
        Weights::new(&raft_service);
        return Ok(raft_service);
    }
    fn join_group(opt: &ServerOptions, raft_client: &Arc<RaftClient>) -> Result<(), ServerError> {
        let member_service = MemberService::new(&opt.address, raft_client);
        match member_service.join_group(&opt.group_name) {
            Ok(_) => {Ok(())},
            Err(e) => {
                error!("Cannot join cluster group");
                Err(ServerError::CannotJoinClusterGroup(e))
            }
        }
    }
    fn init_conshash(opt: &ServerOptions, raft_client: &Arc<RaftClient>)
        -> Result<Arc<ConsistentHashing>, ServerError> {
        match ConsistentHashing::new(&opt.group_name, raft_client) {
            Ok(ch) => {
                ch.set_weight(&opt.address, opt.memory_size as u64);
                if !ch.init_table().is_ok() {
                    error!("Cannot initialize member table");
                    return Err(ServerError::CannotInitMemberTable);
                }
                return Ok(ch);
            },
            _ => {
                error!("Cannot initialize consistent hash table");
                return Err(ServerError::CannotInitConsistentHashTable);
            }
        }
    }
    fn load_cluster_clients
    (opt: &ServerOptions, schemas: &mut SchemasServer, rpc_server: &Arc<rpc::Server>)
     -> Result<Arc<ConsistentHashing>, ServerError>{
        let raft_client = RaftClient::new(&opt.meta_members, raft::DEFAULT_SERVICE_ID);
        match raft_client {
            Ok(raft_client) => {
                RaftClient::prepare_subscription(rpc_server);
                NebServer::join_group(opt, &raft_client)?;
                let conshash = NebServer::init_conshash(opt, &raft_client)?;
                let schema_server = match SchemasServer::new(&opt.group_name, Some(&raft_client)) {
                    Ok(schema) => schema,
                    Err(e) => return Err(ServerError::CannotInitializeSchemaServer(e))
                };
                *schemas = schema_server;
                Ok(conshash)
            },
            Err(e) => {
                error!("Cannot load meta client: {:?}", e);
                Err(ServerError::CannotLoadMetaClient)
            }
        }
    }
    pub fn new_from_opts(opts: &ServerOptions) -> Result<Arc<NebServer>, ServerError> {
        let server_addr = if opts.standalone {&STANDALONE_ADDRESS_STRING} else {&opts.address};
        let rpc_server = rpc::Server::new(server_addr);
        rpc::Server::listen_and_resume(&rpc_server);
        return NebServer::new(opts, server_addr, &rpc_server)
    }
    pub fn new(
        opts: &ServerOptions,
        server_addr: &String,
        rpc_server: &Arc<rpc::Server>,
    ) -> Result<Arc<NebServer>, ServerError> {
        let mut opts = opts.clone();
        opts.group_name = format!("neb_{}", opts.group_name);
        let mut raft_service = None;
        if opts.is_meta {
            raft_service = Some(NebServer::load_meta_server(&opts, &rpc_server)?);
        }
        if !opts.is_meta && opts.standalone {
            return Err(ServerError::StandaloneMustAlsoBeMetaServer)
        }
        let mut schemas = SchemasServer::new(&opts.group_name, None).unwrap();
        let conshasing =
            NebServer::load_cluster_clients(&opts, &mut schemas, &rpc_server)?;
        let meta_rc = Arc::new(ServerMeta {
            schemas
        });
        let chunks = Chunks::new(
            opts.chunk_count,
            opts.memory_size,
            meta_rc.clone(),
            opts.backup_storage.clone(),
        );
        let server = Arc::new(NebServer {
            chunks,
            meta: meta_rc,
            rpc: rpc_server.clone(),
            consh: conshasing,
            member_pool: rpc::ClientPool::new(),
            txn_peer: transactions::Peer::new(server_addr),
            raft_service,
            server_id: rpc_server.server_id
        });
        rpc_server.register_service(
            cell_rpc::DEFAULT_SERVICE_ID,
            &cell_rpc::NebRPCService::new(&server)
        );
        rpc_server.register_service(
            transactions::manager::DEFAULT_SERVICE_ID,
            &transactions::manager::TransactionManager::new(&server)
        );
        rpc_server.register_service(
            transactions::data_site::DEFAULT_SERVICE_ID,
            &transactions::data_site::DataManager::new(&server)
        );
        Ok(server)
    }
    pub fn get_server_id_by_id(&self, id: &Id) -> Option<u64> {
        if let Some(server_id) = self.consh.get_by_server_id(id.higher) {
            Some(server_id)
        } else {
            None
        }
    }
    pub fn get_member_by_server_id(&self, server_id: u64) -> io::Result<Arc<rpc::RPCClient>> {
        if let Some(ref server_name) = self.consh.to_server_name(Some(server_id)) {
            self.member_pool.get(server_name)
        } else {
            Err(io::Error::new(io::ErrorKind::Other, "Cannot find server id in consistent hash table"))
        }
    }
}<|endoftext|>


<commit_before>//! Unwinding for *emscripten* target.
//!
//! Whereas Rust's usual unwinding implementation for Unix platforms
//! calls into the libunwind APIs directly, on Emscripten we instead
//! call into the C++ unwinding APIs. This is just an expedience since
//! Emscripten's runtime always implements those APIs and does not
//! implement libunwind.

#![allow(private_no_mangle_fns)]

use alloc::boxed::Box;
use core::any::Any;
use core::mem;
use core::ptr;
use libc::{self, c_int};
use unwind as uw;

// This matches the layout of std::type_info in C++
#[repr(C)]
struct TypeInfo {
    vtable: *const usize,
    name: *const u8,
}
unsafe impl Sync for TypeInfo {}

extern "C" {
    // The leading `\x01` byte here is actually a magical signal to LLVM to
    // *not* apply any other mangling like prefixing with a `_` character.
    //
    // This symbol is the vtable used by C++'s `std::type_info`. Objects of type
    // `std::type_info`, type descriptors, have a pointer to this table. Type
    // descriptors are referenced by the C++ EH structures defined above and
    // that we construct below.
    //
    // Note that the real size is larger than 3 usize, but we only need our
    // vtable to point to the third element.
    #[link_name = "\x01_ZTVN10__cxxabiv117__class_type_infoE"]
    static CLASS_TYPE_INFO_VTABLE: [usize; 3];
}

// std::type_info for a rust_panic class
#[lang = "eh_catch_typeinfo"]
static EXCEPTION_TYPE_INFO: TypeInfo = TypeInfo {
    // Normally we would use .as_ptr().add(2) but this doesn't work in a const context.
    vtable: unsafe { &CLASS_TYPE_INFO_VTABLE[2] },
    // This intentionally doesn't use the normal name mangling scheme because
    // we don't want C++ to be able to produce or catch Rust panics.
    name: b"rust_panic\0".as_ptr(),
};

pub fn payload() -> *mut u8 {
    ptr::null_mut()
}

struct Exception {
    // This needs to be an Option because the object's lifetime follows C++
    // semantics: when catch_unwind moves the Box out of the exception it must
    // still leave the exception object in a valid state because its destructor
    // is still going to be called by __cxa_end_catch..
    data: Option<Box<dyn Any + Send>>,
}

pub unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> {
    assert!(!ptr.is_null());
    let adjusted_ptr = __cxa_begin_catch(ptr as *mut libc::c_void) as *mut Exception;
    let ex = (*adjusted_ptr).data.take();
    __cxa_end_catch();
    ex.unwrap()
}

pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
    let sz = mem::size_of_val(&data);
    let exception = __cxa_allocate_exception(sz) as *mut Exception;
    if exception.is_null() {
        return uw::_URC_FATAL_PHASE1_ERROR as u32;
    }
    ptr::write(exception, Exception { data: Some(data) });
    __cxa_throw(exception as *mut _, &EXCEPTION_TYPE_INFO, exception_cleanup);

    extern "C" fn exception_cleanup(ptr: *mut libc::c_void) {
        unsafe {
            ptr::drop_in_place(ptr as *mut Exception);
            super::__rust_drop_panic();
        }
    }
}

#[lang = "eh_personality"]
#[no_mangle]
unsafe extern "C" fn rust_eh_personality(
    version: c_int,
    actions: uw::_Unwind_Action,
    exception_class: uw::_Unwind_Exception_Class,
    exception_object: *mut uw::_Unwind_Exception,
    context: *mut uw::_Unwind_Context,
) -> uw::_Unwind_Reason_Code {
    __gxx_personality_v0(version, actions, exception_class, exception_object, context)
}

extern "C" {
    fn __cxa_allocate_exception(thrown_size: libc::size_t) -> *mut libc::c_void;
    fn __cxa_begin_catch(thrown_exception: *mut libc::c_void) -> *mut libc::c_void;
    fn __cxa_end_catch();
    fn __cxa_throw(
        thrown_exception: *mut libc::c_void,
        tinfo: *const TypeInfo,
        dest: extern "C" fn(*mut libc::c_void),
    ) -> !;
    fn __gxx_personality_v0(
        version: c_int,
        actions: uw::_Unwind_Action,
        exception_class: uw::_Unwind_Exception_Class,
        exception_object: *mut uw::_Unwind_Exception,
        context: *mut uw::_Unwind_Context,
    ) -> uw::_Unwind_Reason_Code;
}
<commit_msg>Fix destructor return value in emcc.rs<commit_after>//! Unwinding for *emscripten* target.
//!
//! Whereas Rust's usual unwinding implementation for Unix platforms
//! calls into the libunwind APIs directly, on Emscripten we instead
//! call into the C++ unwinding APIs. This is just an expedience since
//! Emscripten's runtime always implements those APIs and does not
//! implement libunwind.

#![allow(private_no_mangle_fns)]

use alloc::boxed::Box;
use core::any::Any;
use core::mem;
use core::ptr;
use libc::{self, c_int};
use unwind as uw;

// This matches the layout of std::type_info in C++
#[repr(C)]
struct TypeInfo {
    vtable: *const usize,
    name: *const u8,
}
unsafe impl Sync for TypeInfo {}

extern "C" {
    // The leading `\x01` byte here is actually a magical signal to LLVM to
    // *not* apply any other mangling like prefixing with a `_` character.
    //
    // This symbol is the vtable used by C++'s `std::type_info`. Objects of type
    // `std::type_info`, type descriptors, have a pointer to this table. Type
    // descriptors are referenced by the C++ EH structures defined above and
    // that we construct below.
    //
    // Note that the real size is larger than 3 usize, but we only need our
    // vtable to point to the third element.
    #[link_name = "\x01_ZTVN10__cxxabiv117__class_type_infoE"]
    static CLASS_TYPE_INFO_VTABLE: [usize; 3];
}

// std::type_info for a rust_panic class
#[lang = "eh_catch_typeinfo"]
static EXCEPTION_TYPE_INFO: TypeInfo = TypeInfo {
    // Normally we would use .as_ptr().add(2) but this doesn't work in a const context.
    vtable: unsafe { &CLASS_TYPE_INFO_VTABLE[2] },
    // This intentionally doesn't use the normal name mangling scheme because
    // we don't want C++ to be able to produce or catch Rust panics.
    name: b"rust_panic\0".as_ptr(),
};

pub fn payload() -> *mut u8 {
    ptr::null_mut()
}

struct Exception {
    // This needs to be an Option because the object's lifetime follows C++
    // semantics: when catch_unwind moves the Box out of the exception it must
    // still leave the exception object in a valid state because its destructor
    // is still going to be called by __cxa_end_catch..
    data: Option<Box<dyn Any + Send>>,
}

pub unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> {
    assert!(!ptr.is_null());
    let adjusted_ptr = __cxa_begin_catch(ptr as *mut libc::c_void) as *mut Exception;
    let ex = (*adjusted_ptr).data.take();
    __cxa_end_catch();
    ex.unwrap()
}

pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
    let sz = mem::size_of_val(&data);
    let exception = __cxa_allocate_exception(sz) as *mut Exception;
    if exception.is_null() {
        return uw::_URC_FATAL_PHASE1_ERROR as u32;
    }
    ptr::write(exception, Exception { data: Some(data) });
    __cxa_throw(exception as *mut _, &EXCEPTION_TYPE_INFO, exception_cleanup);
}

// On WASM and ARM, the destructor returns the pointer to the object.
cfg_if::cfg_if! {
    if #[cfg(any(target_arch = "arm", target_arch = "wasm32"))] {
        type DestructorRet = *mut libc::c_void;
    } else {
        type DestructorRet = ();
    }
}
extern "C" fn exception_cleanup(ptr: *mut libc::c_void) -> DestructorRet {
    unsafe {
        ptr::drop_in_place(ptr as *mut Exception);
        super::__rust_drop_panic();
    }
}

#[lang = "eh_personality"]
#[no_mangle]
unsafe extern "C" fn rust_eh_personality(
    version: c_int,
    actions: uw::_Unwind_Action,
    exception_class: uw::_Unwind_Exception_Class,
    exception_object: *mut uw::_Unwind_Exception,
    context: *mut uw::_Unwind_Context,
) -> uw::_Unwind_Reason_Code {
    __gxx_personality_v0(version, actions, exception_class, exception_object, context)
}

extern "C" {
    fn __cxa_allocate_exception(thrown_size: libc::size_t) -> *mut libc::c_void;
    fn __cxa_begin_catch(thrown_exception: *mut libc::c_void) -> *mut libc::c_void;
    fn __cxa_end_catch();
    fn __cxa_throw(
        thrown_exception: *mut libc::c_void,
        tinfo: *const TypeInfo,
        dest: extern "C" fn(*mut libc::c_void) -> DestructorRet,
    ) -> !;
    fn __gxx_personality_v0(
        version: c_int,
        actions: uw::_Unwind_Action,
        exception_class: uw::_Unwind_Exception_Class,
        exception_object: *mut uw::_Unwind_Exception,
        context: *mut uw::_Unwind_Context,
    ) -> uw::_Unwind_Reason_Code;
}
<|endoftext|>


<commit_before>use crate::libra_channel;
use crate::libra_channel::MessageQueue;
use futures::{executor::block_on, FutureExt, StreamExt};
use std::collections::VecDeque;
use std::thread;
use std::time::Duration;

struct TestMessageQueue {
    queue: VecDeque<u8>,
}

impl MessageQueue for TestMessageQueue {
    type Key = u8;
    type Message = u8;

    fn push(&mut self, _key: Self::Key, message: Self::Message) {
        self.queue.push_back(message);
    }

    fn pop(&mut self) -> Option<Self::Message> {
        self.queue.pop_front()
    }
}

#[test]
fn test_send_recv_order() {
    let mq = TestMessageQueue {
        queue: VecDeque::new(),
    };
    let (mut sender, mut receiver) = libra_channel::new(mq);
    sender.put(0, 0);
    sender.put(0, 1);
    sender.put(0, 2);
    sender.put(0, 3);
    let task = async move {
        // Ensure that messages are received in order
        assert_eq!(receiver.select_next_some().await, 0);
        assert_eq!(receiver.select_next_some().await, 1);
        assert_eq!(receiver.select_next_some().await, 2);
        assert_eq!(receiver.select_next_some().await, 3);
        // Ensures that there is no other value which is ready
        assert_eq!(receiver.select_next_some().now_or_never(), None);
    };
    block_on(task);
}

#[test]
fn test_empty() {
    let mq = TestMessageQueue {
        queue: VecDeque::new(),
    };
    let (_, mut receiver) = libra_channel::new(mq);
    // Ensures that there is no other value which is ready
    assert_eq!(receiver.select_next_some().now_or_never(), None);
}

#[test]
fn test_waker() {
    let mq = TestMessageQueue {
        queue: VecDeque::new(),
    };
    let (mut sender, mut receiver) = libra_channel::new(mq);
    // Ensures that there is no other value which is ready
    assert_eq!(receiver.select_next_some().now_or_never(), None);
    let join_handle = thread::spawn(move || {
        block_on(async {
            assert_eq!(receiver.select_next_some().await, 0);
        });
        block_on(async {
            assert_eq!(receiver.select_next_some().await, 1);
        });
        block_on(async {
            assert_eq!(receiver.select_next_some().await, 2);
        });
    });
    thread::sleep(Duration::from_millis(100));
    sender.put(0, 0);
    thread::sleep(Duration::from_millis(100));
    sender.put(0, 1);
    thread::sleep(Duration::from_millis(100));
    sender.put(0, 2);
    join_handle.join().unwrap();
}
<commit_msg>[testing] Add more tests for libra_channel<commit_after>use crate::{
    libra_channel::{self, MessageQueue},
    message_queues::{PerValidatorQueue, QueueStyle},
};
use futures::{executor::block_on, FutureExt, StreamExt};
use libra_types::account_address::AccountAddress;
use libra_types::account_address::ADDRESS_LENGTH;
use std::collections::VecDeque;
use std::thread;
use std::time::Duration;

struct TestMessageQueue {
    queue: VecDeque<u8>,
}

impl MessageQueue for TestMessageQueue {
    type Key = u8;
    type Message = u8;

    fn push(&mut self, _key: Self::Key, message: Self::Message) {
        self.queue.push_back(message);
    }

    fn pop(&mut self) -> Option<Self::Message> {
        self.queue.pop_front()
    }
}

#[test]
fn test_send_recv_order() {
    let mq = TestMessageQueue {
        queue: VecDeque::new(),
    };
    let (mut sender, mut receiver) = libra_channel::new(mq);
    sender.put(0, 0);
    sender.put(0, 1);
    sender.put(0, 2);
    sender.put(0, 3);
    let task = async move {
        // Ensure that messages are received in order
        assert_eq!(receiver.select_next_some().await, 0);
        assert_eq!(receiver.select_next_some().await, 1);
        assert_eq!(receiver.select_next_some().await, 2);
        assert_eq!(receiver.select_next_some().await, 3);
        // Ensures that there is no other value which is ready
        assert_eq!(receiver.select_next_some().now_or_never(), None);
    };
    block_on(task);
}

#[test]
fn test_empty() {
    let mq = TestMessageQueue {
        queue: VecDeque::new(),
    };
    let (_, mut receiver) = libra_channel::new(mq);
    // Ensures that there is no other value which is ready
    assert_eq!(receiver.select_next_some().now_or_never(), None);
}

#[test]
fn test_waker() {
    let mq = TestMessageQueue {
        queue: VecDeque::new(),
    };
    let (mut sender, mut receiver) = libra_channel::new(mq);
    // Ensures that there is no other value which is ready
    assert_eq!(receiver.select_next_some().now_or_never(), None);
    let join_handle = thread::spawn(move || {
        block_on(async {
            assert_eq!(receiver.select_next_some().await, 0);
        });
        block_on(async {
            assert_eq!(receiver.select_next_some().await, 1);
        });
        block_on(async {
            assert_eq!(receiver.select_next_some().await, 2);
        });
    });
    thread::sleep(Duration::from_millis(100));
    sender.put(0, 0);
    thread::sleep(Duration::from_millis(100));
    sender.put(0, 1);
    thread::sleep(Duration::from_millis(100));
    sender.put(0, 2);
    join_handle.join().unwrap();
}

fn test_multiple_validators_helper(
    queue_style: QueueStyle,
    num_messages_per_validator: usize,
    expected_last_message: usize,
) {
    let (mut sender, mut receiver) = libra_channel::new(PerValidatorQueue::new(queue_style, 1));
    let num_validators = 128;
    for message in 0..num_messages_per_validator {
        for validator in 0..num_validators {
            sender.put(
                AccountAddress::new([validator as u8; ADDRESS_LENGTH]),
                (validator, message),
            );
        }
    }
    block_on(async {
        for i in 0..num_validators {
            assert_eq!(
                receiver.select_next_some().await,
                (i, expected_last_message)
            );
        }
    });
    assert_eq!(receiver.select_next_some().now_or_never(), None);
}

#[test]
fn test_multiple_validators_fifo() {
    test_multiple_validators_helper(QueueStyle::FIFO, 1024, 0);
}

#[test]
fn test_multiple_validators_lifo() {
    test_multiple_validators_helper(QueueStyle::LIFO, 1024, 1023);
}
<|endoftext|>


<commit_before>//! darwin-rs: evolutionary algorithms with Rust
//!
//! Written by Willi Kappler, Version 0.2 (2016.07.xx)
//!
//! Repository: https://github.com/willi-kappler/darwin-rs
//!
//! License: MIT
//!
//! This library allows you to write evolutionary algorithms (EA) in Rust.
//! Examples provided: TSP, Sudoku, Queens Problem
//!
//!

use std::time::Instant;
use std::sync::{Arc, Mutex};

use jobsteal::{make_pool, IntoSplitIterator, SplitIterator};

use individual::{Individual, IndividualWrapper};
use population::Population;

/// The `SimulationType` type. Speficies the criteria on how a simulation should stop.
#[derive(Debug,Clone)]
pub enum SimulationType {
    /// Finish the simulation when a number of iteration has been reached.
    EndIteration(u32),
    /// Finish the simulation when a specific fitness is rached.
    /// That means if at least one of the individuals has this fitness.
    /// The fitness is calculated using the implemented `calculate_fitness` functions
    /// of the `Individual` trait
    EndFitness(f64),
    /// Finish the simulation when a specific improvement factor is reached.
    /// That means the relation between the very first fitness and the current fitness of the
    /// fittest individual
    EndFactor(f64),
}

/// The `Simulation` type. Contains all the information / configuration for the simulation to run.
pub struct Simulation<T: Individual + Send + Sync> {
    /// How should the simulation stop ?
    pub type_of_simulation: SimulationType,
    /// The number of threads to use to speed up calculation.
    pub num_of_threads: usize,
    /// All the populations for the simulation. Contains all individuals for the simulation.
    pub habitat: Vec<Population<T>>,
    /// The total run time for the simulation. This will be calculated once the stimulation has
    /// finished.
    pub total_time_in_ms: f64,
    /// The result of the simulation: improvement_factor, original_fitness and a vector of
    /// fittest individuals
    pub simulation_result: SimulationResult<T>
}

/// The SimulationResult Type. TODO
#[derive(Clone)]
pub struct SimulationResult<T: Individual + Send + Sync> {
    /// The current improvement factor, that means the ration between the very first and the
    /// current fitness.
    pub improvement_factor: f64,
    /// The very first calculated fitness, when the simulation just started.
    pub original_fitness: f64,
    /// Vector of fittest individuals. This will change during the simulation as soon as a new
    /// more fittest individual is found and pushed into the first position (index 0).
    pub fittest: Vec<IndividualWrapper<T>>
}

/// This implements the two functions `run` and `print_fitness` for the struct `Simulation`.
impl<T: Individual + Send + Sync + Clone> Simulation<T> {
    /// This actually runs the simulation.
    /// Depending on the type of simulation (EndIteration, EndFactor or Endfitness) the iteration
    /// loop will check for the stop condition accordingly.
    pub fn run(&mut self) {
        // Initialize timer
        let start_time = Instant::now();

        // Calculate the fitness for all individuals in all populations at the beginning.
        for population in self.habitat.iter_mut() {
            population.calculate_fitness();
        }

        let mut iteration_counter = 0;
        let mut pool = make_pool(self.num_of_threads).unwrap();

        // Initialize:
        // - The fittest individual.
        // - The fitness at the beginning of the simulation. This is uesed to calculate the
        //   overall improvement later on.
        let simulation_result = SimulationResult {
            improvement_factor: 0.0,
            original_fitness: self.habitat[0].population[0].fitness,
            fittest: vec![self.habitat[0].population[0].clone()]
        };

        println!("original_fitness: {}", simulation_result.original_fitness);

        let simulation_result = Arc::new(Mutex::new(Box::new(simulation_result)));

        // Check which type of simulation to run.
        match self.type_of_simulation {
            SimulationType::EndIteration(end_iteration) => {
                for iteration_counter in 0..end_iteration {
                    (&mut self.habitat).into_split_iter().for_each(
                        &pool.spawner(), |population| {
                            population.run_body(&simulation_result, iteration_counter);
                        });
                };
            }
            SimulationType::EndFactor(end_factor) => {
                loop {
                    match simulation_result.lock() {
                        Ok(simulation_result) => {
                            if simulation_result.improvement_factor <= end_factor {
                                break;
                            }
                        },
                        Err(e) => println!("Mutex (poison) error (simulation_result): {}", e)
                    }

                    iteration_counter += 1;
                    (&mut self.habitat).into_split_iter().for_each(
                        &pool.spawner(), |population| {
                            population.run_body(&simulation_result, iteration_counter);
                        });
                }
            }
            SimulationType::EndFitness(end_fitness) => {
                loop {
                    match simulation_result.lock() {
                        Ok(simulation_result) => {
                            if simulation_result.fittest[0].fitness <= end_fitness {
                                break;
                            }
                        },
                        Err(e) => println!("Mutex (poison) error (simulation_result): {}", e)
                    }

                    iteration_counter += 1;
                    (&mut self.habitat).into_split_iter().for_each(
                        &pool.spawner(), |population| {
                            population.run_body(&simulation_result, iteration_counter);
                        });
                }
            }
        }

        let elapsed = start_time.elapsed();

        self.total_time_in_ms = elapsed.as_secs() as f64 * 1000.0 + elapsed.subsec_nanos() as f64 / 1000_000.0;

        // TODO
        // match simulation_result.lock() {
        //     Ok(simulation_result) => {
        //         self.simulation_result = (*(*simulation_result)).clone();
        //     },
        //     Err(e) => println!("Mutex (poison) error (simulation_result): {}", e)
        // }

    }

    /// This is a helper function that the user can call after the simulation stops in order to
    /// see all the fitness values for all the individuals that participated to the overall
    /// improvement.
    pub fn print_fitness(&self) {
        for wrapper in self.simulation_result.fittest.iter() {
            println!("fitness: {}, num_of_mutations: {}",
                     wrapper.fitness,
                     wrapper.num_of_mutations);
        }
    }
}
<commit_msg>make abstractions explicit in order to find lifetime error<commit_after>//! darwin-rs: evolutionary algorithms with Rust
//!
//! Written by Willi Kappler, Version 0.2 (2016.07.xx)
//!
//! Repository: https://github.com/willi-kappler/darwin-rs
//!
//! License: MIT
//!
//! This library allows you to write evolutionary algorithms (EA) in Rust.
//! Examples provided: TSP, Sudoku, Queens Problem
//!
//!

use std::time::Instant;
use std::sync::{Arc, Mutex};

use jobsteal::{make_pool, IntoSplitIterator, SplitIterator};

use individual::{Individual, IndividualWrapper};
use population::Population;

/// The `SimulationType` type. Speficies the criteria on how a simulation should stop.
#[derive(Debug,Clone)]
pub enum SimulationType {
    /// Finish the simulation when a number of iteration has been reached.
    EndIteration(u32),
    /// Finish the simulation when a specific fitness is rached.
    /// That means if at least one of the individuals has this fitness.
    /// The fitness is calculated using the implemented `calculate_fitness` functions
    /// of the `Individual` trait
    EndFitness(f64),
    /// Finish the simulation when a specific improvement factor is reached.
    /// That means the relation between the very first fitness and the current fitness of the
    /// fittest individual
    EndFactor(f64),
}

/// The `Simulation` type. Contains all the information / configuration for the simulation to run.
pub struct Simulation<T: Individual + Send + Sync> {
    /// How should the simulation stop ?
    pub type_of_simulation: SimulationType,
    /// The number of threads to use to speed up calculation.
    pub num_of_threads: usize,
    /// All the populations for the simulation. Contains all individuals for the simulation.
    pub habitat: Vec<Population<T>>,
    /// The total run time for the simulation. This will be calculated once the stimulation has
    /// finished.
    pub total_time_in_ms: f64,
    /// The result of the simulation: improvement_factor, original_fitness and a vector of
    /// fittest individuals
    pub simulation_result: SimulationResult<T>
}

/// The SimulationResult Type. TODO
#[derive(Clone)]
pub struct SimulationResult<T: Individual + Send + Sync> {
    /// The current improvement factor, that means the ration between the very first and the
    /// current fitness.
    pub improvement_factor: f64,
    /// The very first calculated fitness, when the simulation just started.
    pub original_fitness: f64,
    /// Vector of fittest individuals. This will change during the simulation as soon as a new
    /// more fittest individual is found and pushed into the first position (index 0).
    pub fittest: Vec<IndividualWrapper<T>>
}

/// This implements the two functions `run` and `print_fitness` for the struct `Simulation`.
impl<T: Individual + Send + Sync + Clone> Simulation<T> {
    /// This actually runs the simulation.
    /// Depending on the type of simulation (EndIteration, EndFactor or Endfitness) the iteration
    /// loop will check for the stop condition accordingly.
    pub fn run(&mut self) {
        // Initialize timer
        let start_time = Instant::now();

        // Calculate the fitness for all individuals in all populations at the beginning.
        for population in self.habitat.iter_mut() {
            population.calculate_fitness();
        }

        let mut iteration_counter = 0;
        let mut pool = make_pool(self.num_of_threads).unwrap();

        // Initialize:
        // - The fittest individual.
        // - The fitness at the beginning of the simulation. This is uesed to calculate the
        //   overall improvement later on.
        let simulation_result = SimulationResult {
            improvement_factor: 0.0,
            original_fitness: self.habitat[0].population[0].fitness,
            fittest: vec![self.habitat[0].population[0].clone()]
        };

        println!("original_fitness: {}", simulation_result.original_fitness);

        // Make it explicit to resolve (debug) problem
        // (Will be removed later...)
        let simulation_result_box = Box::new(simulation_result);
        let simulation_result_mutex = Mutex::new(simulation_result_box);
        let simulation_result_arc = Arc::new(simulation_result_mutex);
        let simulation_result_cloned = simulation_result_arc.clone();

        // Check which type of simulation to run.
        match self.type_of_simulation {
            SimulationType::EndIteration(end_iteration) => {
                for iteration_counter in 0..end_iteration {
                    (&mut self.habitat).into_split_iter().for_each(
                        &pool.spawner(), |population| {
                            population.run_body(&simulation_result_cloned, iteration_counter);
                        });
                };
            }
            SimulationType::EndFactor(end_factor) => {
                loop {
                    match simulation_result_cloned.lock() {
                        Ok(simulation_result) => {
                            if simulation_result.improvement_factor <= end_factor {
                                break;
                            }
                        },
                        Err(e) => println!("Mutex (poison) error (simulation_result): {}", e)
                    }

                    iteration_counter += 1;
                    (&mut self.habitat).into_split_iter().for_each(
                        &pool.spawner(), |population| {
                            population.run_body(&simulation_result_cloned, iteration_counter);
                        });
                }
            }
            SimulationType::EndFitness(end_fitness) => {
                loop {
                    match simulation_result_cloned.lock() {
                        Ok(simulation_result) => {
                            if simulation_result.fittest[0].fitness <= end_fitness {
                                break;
                            }
                        },
                        Err(e) => println!("Mutex (poison) error (simulation_result): {}", e)
                    }

                    iteration_counter += 1;
                    (&mut self.habitat).into_split_iter().for_each(
                        &pool.spawner(), |population| {
                            population.run_body(&simulation_result_cloned, iteration_counter);
                        });
                }
            }
        }

        let elapsed = start_time.elapsed();

        self.total_time_in_ms = elapsed.as_secs() as f64 * 1000.0 + elapsed.subsec_nanos() as f64 / 1000_000.0;

        // TODO
        // This does not work, why ?
        // reference must be valid for the destruction scope surrounding block at 72:26...
        // ...but borrowed value is only valid for the block suffix following statement 8 at 100:70
        // match simulation_result_arc.lock() {
        //     Ok(simulation_result) => {
        //         self.simulation_result = (*(*simulation_result)).clone();
        //     },
        //     Err(e) => println!("Mutex (poison) error (simulation_result): {}", e)
        // }

    }

    /// This is a helper function that the user can call after the simulation stops in order to
    /// see all the fitness values for all the individuals that participated to the overall
    /// improvement.
    pub fn print_fitness(&self) {
        for wrapper in self.simulation_result.fittest.iter() {
            println!("fitness: {}, num_of_mutations: {}",
                     wrapper.fitness,
                     wrapper.num_of_mutations);
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>flexbox 2020: Store align_items on FlexContext<commit_after><|endoftext|>


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

//! Terminfo database interface.

use std::collections::HashMap;
use std::env;
use std::error;
use std::fmt;
use std::fs::File;
use std::io::prelude::*;
use std::io;
use std::io::BufReader;
use std::path::Path;

use Attr;
use color;
use Terminal;
use self::searcher::get_dbpath_for_term;
use self::parser::compiled::{parse, msys_terminfo};
use self::parm::{expand, Variables, Param};

/// A parsed terminfo database entry.
#[derive(Debug)]
pub struct TermInfo {
    /// Names for the terminal
    pub names: Vec<String>,
    /// Map of capability name to boolean value
    pub bools: HashMap<String, bool>,
    /// Map of capability name to numeric value
    pub numbers: HashMap<String, u16>,
    /// Map of capability name to raw (unexpanded) string
    pub strings: HashMap<String, Vec<u8>>,
}

/// A terminfo creation error.
#[derive(Debug)]
pub enum Error {
    /// TermUnset Indicates that the environment doesn't include enough information to find
    /// the terminfo entry.
    TermUnset,
    /// MalformedTerminfo indicates that parsing the terminfo entry failed.
    MalformedTerminfo(String),
    /// io::Error forwards any io::Errors encountered when finding or reading the terminfo entry.
    IoError(io::Error),
}

impl error::Error for Error {
    fn description(&self) -> &str {
        "failed to create TermInfo"
    }

    fn cause(&self) -> Option<&error::Error> {
        use self::Error::*;
        match self {
            &IoError(ref e) => Some(e),
            _ => None,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;
        match self {
            &TermUnset => Ok(()),
            &MalformedTerminfo(ref e) => e.fmt(f),
            &IoError(ref e) => e.fmt(f),
        }
    }
}

impl TermInfo {
    /// Create a TermInfo based on current environment.
    pub fn from_env() -> Result<TermInfo, Error> {
        let term = match env::var("TERM") {
            Ok(name) => TermInfo::from_name(&name),
            Err(..) => return Err(Error::TermUnset),
        };

        if term.is_err() && env::var("MSYSCON").ok().map_or(false, |s| "mintty.exe" == s) {
            // msys terminal
            Ok(msys_terminfo())
        } else {
            term
        }
    }

    /// Create a TermInfo for the named terminal.
    pub fn from_name(name: &str) -> Result<TermInfo, Error> {
        get_dbpath_for_term(name)
            .ok_or_else(|| {
                Error::IoError(io::Error::new(io::ErrorKind::NotFound, "terminfo file not found"))
            })
            .and_then(|p| TermInfo::from_path(&(*p)))
    }

    /// Parse the given TermInfo.
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<TermInfo, Error> {
        Self::_from_path(path.as_ref())
    }
    // Keep the metadata small
    fn _from_path(path: &Path) -> Result<TermInfo, Error> {
        let file = File::open(path).map_err(|e| Error::IoError(e))?;
        let mut reader = BufReader::new(file);
        parse(&mut reader, false).map_err(|e| Error::MalformedTerminfo(e))
    }
}

pub mod searcher;

/// TermInfo format parsing.
pub mod parser {
    //! ncurses-compatible compiled terminfo format parsing (term(5))
    pub mod compiled;
}
pub mod parm;

fn cap_for_attr(attr: Attr) -> &'static str {
    match attr {
        Attr::Bold => "bold",
        Attr::Dim => "dim",
        Attr::Italic(true) => "sitm",
        Attr::Italic(false) => "ritm",
        Attr::Underline(true) => "smul",
        Attr::Underline(false) => "rmul",
        Attr::Blink => "blink",
        Attr::Standout(true) => "smso",
        Attr::Standout(false) => "rmso",
        Attr::Reverse => "rev",
        Attr::Secure => "invis",
        Attr::ForegroundColor(_) => "setaf",
        Attr::BackgroundColor(_) => "setab",
    }
}

/// A Terminal that knows how many colors it supports, with a reference to its
/// parsed Terminfo database record.
pub struct TerminfoTerminal<T> {
    num_colors: u16,
    out: T,
    ti: TermInfo,
}

impl<T: Write + Send> Terminal for TerminfoTerminal<T> {
    type Output = T;
    fn fg(&mut self, color: color::Color) -> io::Result<bool> {
        let color = self.dim_if_necessary(color);
        if self.num_colors > color {
            return self.apply_cap("setaf", &[Param::Number(color as i32)]);
        }
        Ok(false)
    }

    fn bg(&mut self, color: color::Color) -> io::Result<bool> {
        let color = self.dim_if_necessary(color);
        if self.num_colors > color {
            return self.apply_cap("setab", &[Param::Number(color as i32)]);
        }
        Ok(false)
    }

    fn attr(&mut self, attr: Attr) -> io::Result<bool> {
        match attr {
            Attr::ForegroundColor(c) => self.fg(c),
            Attr::BackgroundColor(c) => self.bg(c),
            _ => self.apply_cap(cap_for_attr(attr), &[]),
        }
    }

    fn supports_attr(&self, attr: Attr) -> bool {
        match attr {
            Attr::ForegroundColor(_) | Attr::BackgroundColor(_) => self.num_colors > 0,
            _ => {
                let cap = cap_for_attr(attr);
                self.ti.strings.get(cap).is_some()
            }
        }
    }

    fn reset(&mut self) -> io::Result<bool> {
        // are there any terminals that have color/attrs and not sgr0?
        // Try falling back to sgr, then op
        let cmd = match ["sg0", "sgr", "op"]
                            .iter()
                            .filter_map(|cap| self.ti.strings.get(*cap))
                            .next() {
            Some(op) => {
                match expand(&op, &[], &mut Variables::new()) {
                    Ok(cmd) => cmd,
                    Err(e) => return Err(io::Error::new(io::ErrorKind::InvalidData, e)),
                }
            }
            None => return Ok(false),
        };
        self.out.write_all(&cmd).and(Ok(true))
    }

    fn get_ref(&self) -> &T {
        &self.out
    }

    fn get_mut(&mut self) -> &mut T {
        &mut self.out
    }

    fn into_inner(self) -> T
        where Self: Sized
    {
        self.out
    }
}

impl<T: Write + Send> TerminfoTerminal<T> {
    /// Create a new TerminfoTerminal with the given TermInfo and Write.
    pub fn new_with_terminfo(out: T, terminfo: TermInfo) -> TerminfoTerminal<T> {
        let nc = if terminfo.strings.contains_key("setaf") &&
                    terminfo.strings.contains_key("setab") {
            terminfo.numbers.get("colors").map_or(0, |&n| n)
        } else {
            0
        };

        TerminfoTerminal {
            out: out,
            ti: terminfo,
            num_colors: nc,
        }
    }

    /// Create a new TerminfoTerminal for the current environment with the given Write.
    ///
    /// Returns `None` when the terminfo cannot be found or parsed.
    pub fn new(out: T) -> Option<TerminfoTerminal<T>> {
        TermInfo::from_env().map(move |ti| TerminfoTerminal::new_with_terminfo(out, ti)).ok()
    }

    fn dim_if_necessary(&self, color: color::Color) -> color::Color {
        if color >= self.num_colors && color >= 8 && color < 16 {
            color - 8
        } else {
            color
        }
    }

    fn apply_cap(&mut self, cmd: &str, params: &[Param]) -> io::Result<bool> {
        match self.ti.strings.get(cmd) {
            Some(cmd) => {
                match expand(&cmd, params, &mut Variables::new()) {
                    Ok(s) => self.out.write_all(&s).and(Ok(true)),
                    Err(e) => Err(io::Error::new(io::ErrorKind::InvalidData, e)),
                }
            }
            None => Ok(false),
        }
    }
}

impl<T: Write> Write for TerminfoTerminal<T> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.out.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.out.flush()
    }
}
<commit_msg>Fix default terminfo code for reset (sg0 -> sgr0)<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Terminfo database interface.

use std::collections::HashMap;
use std::env;
use std::error;
use std::fmt;
use std::fs::File;
use std::io::prelude::*;
use std::io;
use std::io::BufReader;
use std::path::Path;

use Attr;
use color;
use Terminal;
use self::searcher::get_dbpath_for_term;
use self::parser::compiled::{parse, msys_terminfo};
use self::parm::{expand, Variables, Param};

/// A parsed terminfo database entry.
#[derive(Debug)]
pub struct TermInfo {
    /// Names for the terminal
    pub names: Vec<String>,
    /// Map of capability name to boolean value
    pub bools: HashMap<String, bool>,
    /// Map of capability name to numeric value
    pub numbers: HashMap<String, u16>,
    /// Map of capability name to raw (unexpanded) string
    pub strings: HashMap<String, Vec<u8>>,
}

/// A terminfo creation error.
#[derive(Debug)]
pub enum Error {
    /// TermUnset Indicates that the environment doesn't include enough information to find
    /// the terminfo entry.
    TermUnset,
    /// MalformedTerminfo indicates that parsing the terminfo entry failed.
    MalformedTerminfo(String),
    /// io::Error forwards any io::Errors encountered when finding or reading the terminfo entry.
    IoError(io::Error),
}

impl error::Error for Error {
    fn description(&self) -> &str {
        "failed to create TermInfo"
    }

    fn cause(&self) -> Option<&error::Error> {
        use self::Error::*;
        match self {
            &IoError(ref e) => Some(e),
            _ => None,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;
        match self {
            &TermUnset => Ok(()),
            &MalformedTerminfo(ref e) => e.fmt(f),
            &IoError(ref e) => e.fmt(f),
        }
    }
}

impl TermInfo {
    /// Create a TermInfo based on current environment.
    pub fn from_env() -> Result<TermInfo, Error> {
        let term = match env::var("TERM") {
            Ok(name) => TermInfo::from_name(&name),
            Err(..) => return Err(Error::TermUnset),
        };

        if term.is_err() && env::var("MSYSCON").ok().map_or(false, |s| "mintty.exe" == s) {
            // msys terminal
            Ok(msys_terminfo())
        } else {
            term
        }
    }

    /// Create a TermInfo for the named terminal.
    pub fn from_name(name: &str) -> Result<TermInfo, Error> {
        get_dbpath_for_term(name)
            .ok_or_else(|| {
                Error::IoError(io::Error::new(io::ErrorKind::NotFound, "terminfo file not found"))
            })
            .and_then(|p| TermInfo::from_path(&(*p)))
    }

    /// Parse the given TermInfo.
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<TermInfo, Error> {
        Self::_from_path(path.as_ref())
    }
    // Keep the metadata small
    fn _from_path(path: &Path) -> Result<TermInfo, Error> {
        let file = File::open(path).map_err(|e| Error::IoError(e))?;
        let mut reader = BufReader::new(file);
        parse(&mut reader, false).map_err(|e| Error::MalformedTerminfo(e))
    }
}

pub mod searcher;

/// TermInfo format parsing.
pub mod parser {
    //! ncurses-compatible compiled terminfo format parsing (term(5))
    pub mod compiled;
}
pub mod parm;

fn cap_for_attr(attr: Attr) -> &'static str {
    match attr {
        Attr::Bold => "bold",
        Attr::Dim => "dim",
        Attr::Italic(true) => "sitm",
        Attr::Italic(false) => "ritm",
        Attr::Underline(true) => "smul",
        Attr::Underline(false) => "rmul",
        Attr::Blink => "blink",
        Attr::Standout(true) => "smso",
        Attr::Standout(false) => "rmso",
        Attr::Reverse => "rev",
        Attr::Secure => "invis",
        Attr::ForegroundColor(_) => "setaf",
        Attr::BackgroundColor(_) => "setab",
    }
}

/// A Terminal that knows how many colors it supports, with a reference to its
/// parsed Terminfo database record.
pub struct TerminfoTerminal<T> {
    num_colors: u16,
    out: T,
    ti: TermInfo,
}

impl<T: Write + Send> Terminal for TerminfoTerminal<T> {
    type Output = T;
    fn fg(&mut self, color: color::Color) -> io::Result<bool> {
        let color = self.dim_if_necessary(color);
        if self.num_colors > color {
            return self.apply_cap("setaf", &[Param::Number(color as i32)]);
        }
        Ok(false)
    }

    fn bg(&mut self, color: color::Color) -> io::Result<bool> {
        let color = self.dim_if_necessary(color);
        if self.num_colors > color {
            return self.apply_cap("setab", &[Param::Number(color as i32)]);
        }
        Ok(false)
    }

    fn attr(&mut self, attr: Attr) -> io::Result<bool> {
        match attr {
            Attr::ForegroundColor(c) => self.fg(c),
            Attr::BackgroundColor(c) => self.bg(c),
            _ => self.apply_cap(cap_for_attr(attr), &[]),
        }
    }

    fn supports_attr(&self, attr: Attr) -> bool {
        match attr {
            Attr::ForegroundColor(_) | Attr::BackgroundColor(_) => self.num_colors > 0,
            _ => {
                let cap = cap_for_attr(attr);
                self.ti.strings.get(cap).is_some()
            }
        }
    }

    fn reset(&mut self) -> io::Result<bool> {
        // are there any terminals that have color/attrs and not sgr0?
        // Try falling back to sgr, then op
        let cmd = match ["sgr0", "sgr", "op"]
                            .iter()
                            .filter_map(|cap| self.ti.strings.get(*cap))
                            .next() {
            Some(op) => {
                match expand(&op, &[], &mut Variables::new()) {
                    Ok(cmd) => cmd,
                    Err(e) => return Err(io::Error::new(io::ErrorKind::InvalidData, e)),
                }
            }
            None => return Ok(false),
        };
        self.out.write_all(&cmd).and(Ok(true))
    }

    fn get_ref(&self) -> &T {
        &self.out
    }

    fn get_mut(&mut self) -> &mut T {
        &mut self.out
    }

    fn into_inner(self) -> T
        where Self: Sized
    {
        self.out
    }
}

impl<T: Write + Send> TerminfoTerminal<T> {
    /// Create a new TerminfoTerminal with the given TermInfo and Write.
    pub fn new_with_terminfo(out: T, terminfo: TermInfo) -> TerminfoTerminal<T> {
        let nc = if terminfo.strings.contains_key("setaf") &&
                    terminfo.strings.contains_key("setab") {
            terminfo.numbers.get("colors").map_or(0, |&n| n)
        } else {
            0
        };

        TerminfoTerminal {
            out: out,
            ti: terminfo,
            num_colors: nc,
        }
    }

    /// Create a new TerminfoTerminal for the current environment with the given Write.
    ///
    /// Returns `None` when the terminfo cannot be found or parsed.
    pub fn new(out: T) -> Option<TerminfoTerminal<T>> {
        TermInfo::from_env().map(move |ti| TerminfoTerminal::new_with_terminfo(out, ti)).ok()
    }

    fn dim_if_necessary(&self, color: color::Color) -> color::Color {
        if color >= self.num_colors && color >= 8 && color < 16 {
            color - 8
        } else {
            color
        }
    }

    fn apply_cap(&mut self, cmd: &str, params: &[Param]) -> io::Result<bool> {
        match self.ti.strings.get(cmd) {
            Some(cmd) => {
                match expand(&cmd, params, &mut Variables::new()) {
                    Ok(s) => self.out.write_all(&s).and(Ok(true)),
                    Err(e) => Err(io::Error::new(io::ErrorKind::InvalidData, e)),
                }
            }
            None => Ok(false),
        }
    }
}

impl<T: Write> Write for TerminfoTerminal<T> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.out.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.out.flush()
    }
}
<|endoftext|>


<commit_before>use clap::ArgMatches;
use std::collections::HashSet;

pub fn actions_get(matches: &ArgMatches) -> HashSet<String> {
    let mut hs_actions = HashSet::<String>::new();

    if let Some(_) = matches.values_of("list-provides") {
        let bill = String::from("load-jobs");
        hs_actions.insert(bill);
        let list_provides = String::from("list-provides");
        hs_actions.insert(list_provides);
    }
    if let Some(_) = matches.values_of("list-target") {
        let bill = String::from("load-jobs");
        hs_actions.insert(bill);
        let list_provides = String::from("list-target");
        hs_actions.insert(list_provides);
    }
    if let Some(_) = matches.values_of("session") {
        let bill = String::from("load-jobs");
        hs_actions.insert(bill);
        let str_load_scripts = String::from("load-scripts");
        hs_actions.insert(str_load_scripts);
        let session = String::from("session");
        hs_actions.insert(session);
    }
    return hs_actions;
}
<commit_msg>Add central configuration structure<commit_after>use cfg;
use clap::ArgMatches;
use std::collections::HashSet;

pub fn actions_get(matches: &ArgMatches) -> HashSet<String> {
    let mut hs_actions = HashSet::<String>::new();

    if let Some(_) = matches.values_of("list-provides") {
        let bill = String::from("load-jobs");
        hs_actions.insert(bill);
        let list_provides = String::from("list-provides");
        hs_actions.insert(list_provides);
    }
    if let Some(_) = matches.values_of("list-target") {
        let bill = String::from("load-jobs");
        hs_actions.insert(bill);
        let list_provides = String::from("list-target");
        hs_actions.insert(list_provides);
    }
    if let Some(_) = matches.values_of("session") {
        let bill = String::from("load-jobs");
        hs_actions.insert(bill);
        let str_load_scripts = String::from("load-scripts");
        hs_actions.insert(str_load_scripts);
        let session = String::from("session");
        hs_actions.insert(session);
    }
    return hs_actions;
}

pub fn cfg_actions_update_clap(fred: &mut cfg::Config, matches: &ArgMatches) {
    if let Some(_) = matches.values_of("list-provides") {
        fred.actions.insert(cfg::Action::DbConnect);
        fred.actions.insert(cfg::Action::LoadJobs);
        fred.actions.insert(cfg::Action::ListProvides);
    }
    if let Some(_) = matches.values_of("list-target") {
        fred.actions.insert(cfg::Action::DbConnect);
        fred.actions.insert(cfg::Action::LoadJobs);
        fred.actions.insert(cfg::Action::ListTarget);
    }
    if let Some(_) = matches.values_of("session") {
        fred.actions.insert(cfg::Action::DbConnect);
        fred.actions.insert(cfg::Action::LoadJobs);
        fred.actions.insert(cfg::Action::LoadScripts);
        fred.actions.insert(cfg::Action::SessionStart);
    }
    if let Some(jobs_dir_it) = matches.values_of("dir-jobs") {
        for jobs_dir in jobs_dir_it {
            fred.path_jobs.push(jobs_dir.to_string());
        }
    }
    if let Some(jobs_dir_it) = matches.values_of("dir-sh") {
        for jobs_dir in jobs_dir_it {
            fred.path_shell.push(jobs_dir.to_string());
        }
    }

    if let Some(jobs_dir_it) = matches.values_of("dir-py") {
        for jobs_dir in jobs_dir_it {
            fred.path_python.push(jobs_dir.to_string());
        }
    }
    if fred.actions.contains(&cfg::Action::LoadScripts) {}

    if let Some(in_v) = matches.values_of("rdbms") {
        for enviroment_variable in in_v {
            fred.rdbms_connection_uri = Some(enviroment_variable.to_string());
        }
    } else {
        fred.rdbms_connection_uri = None;
    }
}
<|endoftext|>


<commit_before>//! Argument passing

use crate::prelude::*;

use rustc_target::abi::call::{ArgAbi, ArgAttributes, PassMode as RustcPassMode};
pub(super) use EmptySinglePair::*;

#[derive(Copy, Clone, Debug)]
pub(super) enum PassMode {
    NoPass,
    ByVal(Type),
    ByValPair(Type, Type),
    ByRef { size: Option<Size> },
}

#[derive(Copy, Clone, Debug)]
pub(super) enum EmptySinglePair<T> {
    Empty,
    Single(T),
    Pair(T, T),
}

impl<T> EmptySinglePair<T> {
    pub(super) fn into_iter(self) -> EmptySinglePairIter<T> {
        EmptySinglePairIter(self)
    }

    pub(super) fn map<U>(self, mut f: impl FnMut(T) -> U) -> EmptySinglePair<U> {
        match self {
            Empty => Empty,
            Single(v) => Single(f(v)),
            Pair(a, b) => Pair(f(a), f(b)),
        }
    }
}

pub(super) struct EmptySinglePairIter<T>(EmptySinglePair<T>);

impl<T> Iterator for EmptySinglePairIter<T> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        match std::mem::replace(&mut self.0, Empty) {
            Empty => None,
            Single(v) => Some(v),
            Pair(a, b) => {
                self.0 = Single(b);
                Some(a)
            }
        }
    }
}

impl<T: std::fmt::Debug> EmptySinglePair<T> {
    pub(super) fn assert_single(self) -> T {
        match self {
            Single(v) => v,
            _ => panic!("Called assert_single on {:?}", self),
        }
    }

    pub(super) fn assert_pair(self) -> (T, T) {
        match self {
            Pair(a, b) => (a, b),
            _ => panic!("Called assert_pair on {:?}", self),
        }
    }
}

impl PassMode {
    pub(super) fn get_param_ty(self, tcx: TyCtxt<'_>) -> EmptySinglePair<Type> {
        match self {
            PassMode::NoPass => Empty,
            PassMode::ByVal(clif_type) => Single(clif_type),
            PassMode::ByValPair(a, b) => Pair(a, b),
            PassMode::ByRef { size: Some(_) } => Single(pointer_ty(tcx)),
            PassMode::ByRef { size: None } => Pair(pointer_ty(tcx), pointer_ty(tcx)),
        }
    }
}

pub(super) fn get_pass_mode<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> PassMode {
    if layout.is_zst() {
        // WARNING zst arguments must never be passed, as that will break CastKind::ClosureFnPointer
        PassMode::NoPass
    } else {
        let arg_abi = ArgAbi::new(&tcx, layout, |_, _, _| ArgAttributes::new());
        match arg_abi.mode {
            RustcPassMode::Ignore => PassMode::NoPass,
            RustcPassMode::Direct(_) => match &arg_abi.layout.abi {
                Abi::Scalar(scalar) => PassMode::ByVal(scalar_to_clif_type(tcx, scalar.clone())),
                // FIXME implement Vector Abi in a cg_llvm compatible way
                Abi::Vector { .. } => {
                    if let Some(vector_ty) = crate::intrinsics::clif_vector_type(tcx, arg_abi.layout) {
                        PassMode::ByVal(vector_ty)
                    } else {
                        PassMode::ByRef {
                            size: Some(arg_abi.layout.size),
                        }
                    }
                }
                _ => unreachable!("{:?}", arg_abi.layout.abi)
            },
            RustcPassMode::Pair(_, _) => match &arg_abi.layout.abi {
                Abi::ScalarPair(a, b) => {
                    let a = scalar_to_clif_type(tcx, a.clone());
                    let b = scalar_to_clif_type(tcx, b.clone());
                    if a == types::I128 && b == types::I128 {
                        // Returning (i128, i128) by-val-pair would take 4 regs, while only 3 are
                        // available on x86_64. Cranelift gets confused when too many return params
                        // are used.
                        PassMode::ByRef {
                            size: Some(arg_abi.layout.size),
                        }
                    } else {
                        PassMode::ByValPair(a, b)
                    }
                }
                _ => unreachable!("{:?}", arg_abi.layout.abi)
            },
            RustcPassMode::Cast(_) | RustcPassMode::Indirect {
                attrs: _,
                extra_attrs: None,
                on_stack: false,
            } => PassMode::ByRef {
                size: Some(arg_abi.layout.size),
            },
            RustcPassMode::Indirect {
                attrs: _,
                extra_attrs,
                on_stack: true,
            } => {
                assert!(extra_attrs.is_none());
                PassMode::ByRef {
                    size: Some(arg_abi.layout.size)
                }
            }
            RustcPassMode::Indirect {
                attrs: _,
                extra_attrs: Some(_),
                on_stack: false,
            } => PassMode::ByRef {
                size: None,
            },
        }
    }
}

/// Get a set of values to be passed as function arguments.
pub(super) fn adjust_arg_for_abi<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl Module>,
    arg: CValue<'tcx>,
) -> EmptySinglePair<Value> {
    match get_pass_mode(fx.tcx, arg.layout()) {
        PassMode::NoPass => Empty,
        PassMode::ByVal(_) => Single(arg.load_scalar(fx)),
        PassMode::ByValPair(_, _) => {
            let (a, b) = arg.load_scalar_pair(fx);
            Pair(a, b)
        }
        PassMode::ByRef { size: _ } => match arg.force_stack(fx) {
            (ptr, None) => Single(ptr.get_addr(fx)),
            (ptr, Some(meta)) => Pair(ptr.get_addr(fx), meta),
        },
    }
}

/// Create a [`CValue`] containing the value of a function parameter adding clif function parameters
/// as necessary.
pub(super) fn cvalue_for_param<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl Module>,
    start_block: Block,
    #[cfg_attr(not(debug_assertions), allow(unused_variables))] local: Option<mir::Local>,
    #[cfg_attr(not(debug_assertions), allow(unused_variables))] local_field: Option<usize>,
    arg_ty: Ty<'tcx>,
) -> Option<CValue<'tcx>> {
    let layout = fx.layout_of(arg_ty);
    let pass_mode = get_pass_mode(fx.tcx, layout);

    if let PassMode::NoPass = pass_mode {
        return None;
    }

    let clif_types = pass_mode.get_param_ty(fx.tcx);
    let block_params = clif_types.map(|t| fx.bcx.append_block_param(start_block, t));

    #[cfg(debug_assertions)]
    crate::abi::comments::add_arg_comment(
        fx,
        "arg",
        local,
        local_field,
        block_params,
        pass_mode,
        arg_ty,
    );

    match pass_mode {
        PassMode::NoPass => unreachable!(),
        PassMode::ByVal(_) => Some(CValue::by_val(block_params.assert_single(), layout)),
        PassMode::ByValPair(_, _) => {
            let (a, b) = block_params.assert_pair();
            Some(CValue::by_val_pair(a, b, layout))
        }
        PassMode::ByRef { size: Some(_) } => Some(CValue::by_ref(
            Pointer::new(block_params.assert_single()),
            layout,
        )),
        PassMode::ByRef { size: None } => {
            let (ptr, meta) = block_params.assert_pair();
            Some(CValue::by_ref_unsized(Pointer::new(ptr), meta, layout))
        }
    }
}
<commit_msg>Split abi adjustments out<commit_after>//! Argument passing

use crate::prelude::*;

use rustc_target::abi::call::{ArgAbi, ArgAttributes, PassMode as RustcPassMode};
pub(super) use EmptySinglePair::*;

#[derive(Copy, Clone, Debug)]
pub(super) enum PassMode {
    NoPass,
    ByVal(Type),
    ByValPair(Type, Type),
    ByRef { size: Option<Size> },
}

#[derive(Copy, Clone, Debug)]
pub(super) enum EmptySinglePair<T> {
    Empty,
    Single(T),
    Pair(T, T),
}

impl<T> EmptySinglePair<T> {
    pub(super) fn into_iter(self) -> EmptySinglePairIter<T> {
        EmptySinglePairIter(self)
    }

    pub(super) fn map<U>(self, mut f: impl FnMut(T) -> U) -> EmptySinglePair<U> {
        match self {
            Empty => Empty,
            Single(v) => Single(f(v)),
            Pair(a, b) => Pair(f(a), f(b)),
        }
    }
}

pub(super) struct EmptySinglePairIter<T>(EmptySinglePair<T>);

impl<T> Iterator for EmptySinglePairIter<T> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        match std::mem::replace(&mut self.0, Empty) {
            Empty => None,
            Single(v) => Some(v),
            Pair(a, b) => {
                self.0 = Single(b);
                Some(a)
            }
        }
    }
}

impl<T: std::fmt::Debug> EmptySinglePair<T> {
    pub(super) fn assert_single(self) -> T {
        match self {
            Single(v) => v,
            _ => panic!("Called assert_single on {:?}", self),
        }
    }

    pub(super) fn assert_pair(self) -> (T, T) {
        match self {
            Pair(a, b) => (a, b),
            _ => panic!("Called assert_pair on {:?}", self),
        }
    }
}

impl PassMode {
    pub(super) fn get_param_ty(self, tcx: TyCtxt<'_>) -> EmptySinglePair<Type> {
        match self {
            PassMode::NoPass => Empty,
            PassMode::ByVal(clif_type) => Single(clif_type),
            PassMode::ByValPair(a, b) => Pair(a, b),
            PassMode::ByRef { size: Some(_) } => Single(pointer_ty(tcx)),
            PassMode::ByRef { size: None } => Pair(pointer_ty(tcx), pointer_ty(tcx)),
        }
    }
}

pub(super) fn get_pass_mode<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> PassMode {
    let mut arg_abi = ArgAbi::new(&tcx, layout, |_, _, _| ArgAttributes::new());
    if layout.is_zst() {
        // WARNING zst arguments must never be passed, as that will break CastKind::ClosureFnPointer
        arg_abi.mode = RustcPassMode::Ignore;
    }
    match arg_abi.mode {
        RustcPassMode::Ignore => {}
        RustcPassMode::Direct(_) => match &arg_abi.layout.abi {
            Abi::Scalar(_) => {},
            // FIXME implement Vector Abi in a cg_llvm compatible way
            Abi::Vector { .. } => {
                if crate::intrinsics::clif_vector_type(tcx, arg_abi.layout).is_none() {
                    arg_abi.mode = RustcPassMode::Indirect {
                        attrs: ArgAttributes::new(),
                        extra_attrs: None,
                        on_stack: false,
                    };
                }
            }
            _ => unreachable!("{:?}", arg_abi.layout.abi)
        },
        RustcPassMode::Pair(_, _) => match &arg_abi.layout.abi {
            Abi::ScalarPair(a, b) => {
                let a = scalar_to_clif_type(tcx, a.clone());
                let b = scalar_to_clif_type(tcx, b.clone());
                if a == types::I128 && b == types::I128 {
                    arg_abi.mode = RustcPassMode::Indirect {
                        attrs: ArgAttributes::new(),
                        extra_attrs: None,
                        on_stack: false,
                    };
                }
            }
            _ => unreachable!("{:?}", arg_abi.layout.abi)
        },
        _ => {}
    }
    match arg_abi.mode {
        RustcPassMode::Ignore => PassMode::NoPass,
        RustcPassMode::Direct(_) => match &arg_abi.layout.abi {
            Abi::Scalar(scalar) => PassMode::ByVal(scalar_to_clif_type(tcx, scalar.clone())),
            // FIXME implement Vector Abi in a cg_llvm compatible way
            Abi::Vector { .. } => {
                let vector_ty = crate::intrinsics::clif_vector_type(tcx, arg_abi.layout).unwrap();
                PassMode::ByVal(vector_ty)
            }
            _ => unreachable!("{:?}", arg_abi.layout.abi)
        },
        RustcPassMode::Pair(_, _) => match &arg_abi.layout.abi {
            Abi::ScalarPair(a, b) => {
                let a = scalar_to_clif_type(tcx, a.clone());
                let b = scalar_to_clif_type(tcx, b.clone());
                PassMode::ByValPair(a, b)
            }
            _ => unreachable!("{:?}", arg_abi.layout.abi)
        },
        RustcPassMode::Cast(_) | RustcPassMode::Indirect {
            attrs: _,
            extra_attrs: None,
            on_stack: false,
        } => PassMode::ByRef {
            size: Some(arg_abi.layout.size),
        },
        RustcPassMode::Indirect {
            attrs: _,
            extra_attrs,
            on_stack: true,
        } => {
            assert!(extra_attrs.is_none());
            PassMode::ByRef {
                size: Some(arg_abi.layout.size)
            }
        }
        RustcPassMode::Indirect {
            attrs: _,
            extra_attrs: Some(_),
            on_stack: false,
        } => PassMode::ByRef {
            size: None,
        },
    }
}

/// Get a set of values to be passed as function arguments.
pub(super) fn adjust_arg_for_abi<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl Module>,
    arg: CValue<'tcx>,
) -> EmptySinglePair<Value> {
    match get_pass_mode(fx.tcx, arg.layout()) {
        PassMode::NoPass => Empty,
        PassMode::ByVal(_) => Single(arg.load_scalar(fx)),
        PassMode::ByValPair(_, _) => {
            let (a, b) = arg.load_scalar_pair(fx);
            Pair(a, b)
        }
        PassMode::ByRef { size: _ } => match arg.force_stack(fx) {
            (ptr, None) => Single(ptr.get_addr(fx)),
            (ptr, Some(meta)) => Pair(ptr.get_addr(fx), meta),
        },
    }
}

/// Create a [`CValue`] containing the value of a function parameter adding clif function parameters
/// as necessary.
pub(super) fn cvalue_for_param<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl Module>,
    start_block: Block,
    #[cfg_attr(not(debug_assertions), allow(unused_variables))] local: Option<mir::Local>,
    #[cfg_attr(not(debug_assertions), allow(unused_variables))] local_field: Option<usize>,
    arg_ty: Ty<'tcx>,
) -> Option<CValue<'tcx>> {
    let layout = fx.layout_of(arg_ty);
    let pass_mode = get_pass_mode(fx.tcx, layout);

    if let PassMode::NoPass = pass_mode {
        return None;
    }

    let clif_types = pass_mode.get_param_ty(fx.tcx);
    let block_params = clif_types.map(|t| fx.bcx.append_block_param(start_block, t));

    #[cfg(debug_assertions)]
    crate::abi::comments::add_arg_comment(
        fx,
        "arg",
        local,
        local_field,
        block_params,
        pass_mode,
        arg_ty,
    );

    match pass_mode {
        PassMode::NoPass => unreachable!(),
        PassMode::ByVal(_) => Some(CValue::by_val(block_params.assert_single(), layout)),
        PassMode::ByValPair(_, _) => {
            let (a, b) = block_params.assert_pair();
            Some(CValue::by_val_pair(a, b, layout))
        }
        PassMode::ByRef { size: Some(_) } => Some(CValue::by_ref(
            Pointer::new(block_params.assert_single()),
            layout,
        )),
        PassMode::ByRef { size: None } => {
            let (ptr, meta) = block_params.assert_pair();
            Some(CValue::by_ref_unsized(Pointer::new(ptr), meta, layout))
        }
    }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

//! The datas extracted from a sound file.

use std::mem;
use std::libc::c_void;
use std::vec::Vec;

use openal::{ffi, al};
use sndfile::{SndFile, SndInfo, Read};
use internal::OpenAlData;
use audio_tags::{Tags, AudioTags, get_sound_tags};

/**
 * Samples extracted from a file.
 *
 * SoundDatas are made to be shared between several Sound and played in the same
 * time.
 *
 * # Example
 * ```
 * extern crate ears;
 * use ears::{Sound, SoundData};
 *
 * fn main() -> () {
 *   // Create a SoundData
 *   let snd_data = Rc::new(RefCell::new(SoundData::new(~"path/to/my/sound.wav")
 *                                       .unwrap()));
 *
 *   // Create two Sound with the same SoundData
 *   let snd1 = Sound::new_with_data(snd_data.clone()).unwrap();
 *   let snd2 = Sound::new_with_data(snd_data.clone()).unwrap();
 *
 *   // Play the sounds
 *   snd1.play();
 *   snd2.play();
 *
 *   // Wait until snd2 is playing
 *   while snd2.is_playing() {}
 * }
 * ```
 */
pub struct SoundData {
    /// The SoundTags who contains all the information of the sound
    priv sound_tags     : Tags,
    /// The sndfile samples information
    priv snd_info       : SndInfo,
    /// The total samples count of the Sound
    priv nb_sample      : i64,
    /// The OpenAl internal identifier for the buffer
    priv al_buffer      : u32
}

impl SoundData {
    /**
     * Create a new SoundData.
     *
     * The SoundData contains all the information extracted from the
     * file: samples and tags.
     * It's an easy way to share the same samples between man Sounds objects.
     *
     * # Arguments
     * * `path` - The path of the file to load
     *
     * # Return
     * An Option with Some(SoundData) if the SoundData is create, or None if
     * an error has occured.
     */
    pub fn new(path : &str) -> Option<SoundData> {
        check_openal_context!(None);

        let mut file;

        match SndFile::new(path, Read) {
            Ok(file_) => file = file_,
            Err(err) => { println!("{}", err); return None; }
        };

        let infos = file.get_sndinfo();

        let nb_sample = infos.channels as i64 * infos.frames;

        let mut samples = Vec::from_elem(nb_sample as uint, 0i16);
        file.read_i16(samples.as_mut_slice(), nb_sample as i64);

        let mut buffer_id = 0;
        let len = mem::size_of::<i16>() * (samples.len());

        // Retrieve format informations
        let format =  match al::get_channels_format(infos.channels) {
            Some(fmt) => fmt,
            None => {
                println!("Internal error : unrecognized format.");
                return None;
            }
        };

        al::alGenBuffers(1, &mut buffer_id);
        al::alBufferData(buffer_id,
                         format,
                         samples.as_ptr() as *c_void,
                         len as i32,
                         infos.samplerate);

        match al::openal_has_error() {
            Some(err)   => { println!("{}", err); return None; },
            None        => {}
        };

        let sound_data = SoundData {
            sound_tags  : get_sound_tags(&file),
            snd_info    : infos,
            nb_sample   : nb_sample,
            al_buffer   : buffer_id
        };
        file.close();

        Some(sound_data)
    }
}

/**
 * Get the sound file infos.
 *
 * # Return
 * The struct SndInfo.
 */
pub fn get_sndinfo<'r>(s_data: &'r SoundData) -> &'r SndInfo {
    &s_data.snd_info
}

/**
 * Get the OpenAL identifier of the samples buffer.
 *
 * # Return
 * The OpenAL internal identifier for the samples buffer of the sound.
 */
pub fn get_buffer(s_data: &SoundData) -> u32 {
    s_data.al_buffer
}

impl AudioTags for SoundData {
    /**
     * Get the tags of a Sound.
     *
     * # Return
     * A borrowed pointer to the internal struct SoundTags
     */
    fn get_tags(&self) -> Tags {
        self.sound_tags.clone()
    }
}

impl Drop for SoundData {
    /**
     * Destroy all the resources attached to the SoundData.
     */
    fn drop(&mut self) -> () {
        unsafe {
            ffi::alDeleteBuffers(1, &mut self.al_buffer);
        }
    }
}

#[cfg(test)]
mod test {
    #[allow(unused_variable)]
    use sound_data::SoundData;

    #[test]
    fn sounddata_create_OK() -> () {
        #[allow(unused_variable)];
        let snd_data = SoundData::new("shot.wav").unwrap();

    }

    #[test]
    #[should_fail]
    fn sounddata_create_FAIL() -> () {
        #[allow(unused_variable)];
        let snd_data = SoundData::new("toto.wav").unwrap();
    }
}
<commit_msg>update warning from attribute syntax<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

//! The datas extracted from a sound file.

use std::mem;
use std::libc::c_void;
use std::vec::Vec;

use openal::{ffi, al};
use sndfile::{SndFile, SndInfo, Read};
use internal::OpenAlData;
use audio_tags::{Tags, AudioTags, get_sound_tags};

/**
 * Samples extracted from a file.
 *
 * SoundDatas are made to be shared between several Sound and played in the same
 * time.
 *
 * # Example
 * ```
 * extern crate ears;
 * use ears::{Sound, SoundData};
 *
 * fn main() -> () {
 *   // Create a SoundData
 *   let snd_data = Rc::new(RefCell::new(SoundData::new(~"path/to/my/sound.wav")
 *                                       .unwrap()));
 *
 *   // Create two Sound with the same SoundData
 *   let snd1 = Sound::new_with_data(snd_data.clone()).unwrap();
 *   let snd2 = Sound::new_with_data(snd_data.clone()).unwrap();
 *
 *   // Play the sounds
 *   snd1.play();
 *   snd2.play();
 *
 *   // Wait until snd2 is playing
 *   while snd2.is_playing() {}
 * }
 * ```
 */
pub struct SoundData {
    /// The SoundTags who contains all the information of the sound
    priv sound_tags     : Tags,
    /// The sndfile samples information
    priv snd_info       : SndInfo,
    /// The total samples count of the Sound
    priv nb_sample      : i64,
    /// The OpenAl internal identifier for the buffer
    priv al_buffer      : u32
}

impl SoundData {
    /**
     * Create a new SoundData.
     *
     * The SoundData contains all the information extracted from the
     * file: samples and tags.
     * It's an easy way to share the same samples between man Sounds objects.
     *
     * # Arguments
     * * `path` - The path of the file to load
     *
     * # Return
     * An Option with Some(SoundData) if the SoundData is create, or None if
     * an error has occured.
     */
    pub fn new(path : &str) -> Option<SoundData> {
        check_openal_context!(None);

        let mut file;

        match SndFile::new(path, Read) {
            Ok(file_) => file = file_,
            Err(err) => { println!("{}", err); return None; }
        };

        let infos = file.get_sndinfo();

        let nb_sample = infos.channels as i64 * infos.frames;

        let mut samples = Vec::from_elem(nb_sample as uint, 0i16);
        file.read_i16(samples.as_mut_slice(), nb_sample as i64);

        let mut buffer_id = 0;
        let len = mem::size_of::<i16>() * (samples.len());

        // Retrieve format informations
        let format =  match al::get_channels_format(infos.channels) {
            Some(fmt) => fmt,
            None => {
                println!("Internal error : unrecognized format.");
                return None;
            }
        };

        al::alGenBuffers(1, &mut buffer_id);
        al::alBufferData(buffer_id,
                         format,
                         samples.as_ptr() as *c_void,
                         len as i32,
                         infos.samplerate);

        match al::openal_has_error() {
            Some(err)   => { println!("{}", err); return None; },
            None        => {}
        };

        let sound_data = SoundData {
            sound_tags  : get_sound_tags(&file),
            snd_info    : infos,
            nb_sample   : nb_sample,
            al_buffer   : buffer_id
        };
        file.close();

        Some(sound_data)
    }
}

/**
 * Get the sound file infos.
 *
 * # Return
 * The struct SndInfo.
 */
pub fn get_sndinfo<'r>(s_data: &'r SoundData) -> &'r SndInfo {
    &s_data.snd_info
}

/**
 * Get the OpenAL identifier of the samples buffer.
 *
 * # Return
 * The OpenAL internal identifier for the samples buffer of the sound.
 */
pub fn get_buffer(s_data: &SoundData) -> u32 {
    s_data.al_buffer
}

impl AudioTags for SoundData {
    /**
     * Get the tags of a Sound.
     *
     * # Return
     * A borrowed pointer to the internal struct SoundTags
     */
    fn get_tags(&self) -> Tags {
        self.sound_tags.clone()
    }
}

impl Drop for SoundData {
    /**
     * Destroy all the resources attached to the SoundData.
     */
    fn drop(&mut self) -> () {
        unsafe {
            ffi::alDeleteBuffers(1, &mut self.al_buffer);
        }
    }
}

#[cfg(test)]
mod test {
    #[allow(unused_variable)]
    use sound_data::SoundData;

    #[test]
    fn sounddata_create_OK() -> () {
        #![allow(unused_variable)]
        let snd_data = SoundData::new("shot.wav").unwrap();

    }

    #[test]
    #[should_fail]
    fn sounddata_create_FAIL() -> () {
        #![allow(unused_variable)]
        let snd_data = SoundData::new("toto.wav").unwrap();
    }
}
<|endoftext|>