<commit_before>#![allow(non_camel_case_types)]
#![allow(dead_code)]

use std::fmt::Debug;
use std::fmt::Formatter;
use std::fmt;
use std::str;
use std::ffi::CStr;

use libc::types::os::arch::c95::c_char;
use cql_bindgen::cass_error_desc;
use cql_bindgen::CASS_ERROR_LIB_BAD_PARAMS;
use cql_bindgen::CASS_ERROR_LIB_NO_STREAMS;
use cql_bindgen::CASS_ERROR_LAST_ENTRY;
use cql_bindgen::CASS_ERROR_SSL_IDENTITY_MISMATCH;
use cql_bindgen::CASS_ERROR_SSL_INVALID_PEER_CERT;
use cql_bindgen::CASS_ERROR_SSL_NO_PEER_CERT;
use cql_bindgen::CASS_ERROR_SSL_INVALID_PRIVATE_KEY;
use cql_bindgen::CASS_ERROR_SSL_INVALID_CERT;
use cql_bindgen::CASS_ERROR_SERVER_UNPREPARED;
use cql_bindgen::CASS_ERROR_SERVER_ALREADY_EXISTS;
use cql_bindgen::CASS_ERROR_SERVER_CONFIG_ERROR;
use cql_bindgen::CASS_ERROR_SERVER_INVALID_QUERY;
use cql_bindgen::CASS_ERROR_SERVER_UNAUTHORIZED;
use cql_bindgen::CASS_ERROR_SERVER_SYNTAX_ERROR;
use cql_bindgen::CASS_ERROR_SERVER_READ_TIMEOUT;
use cql_bindgen::CASS_ERROR_SERVER_WRITE_TIMEOUT;
use cql_bindgen::CASS_ERROR_SERVER_TRUNCATE_ERROR;
use cql_bindgen::CASS_ERROR_SERVER_IS_BOOTSTRAPPING;
use cql_bindgen::CASS_ERROR_SERVER_OVERLOADED;
use cql_bindgen::CASS_ERROR_SERVER_UNAVAILABLE;
use cql_bindgen::CASS_ERROR_SERVER_BAD_CREDENTIALS;
use cql_bindgen::CASS_ERROR_SERVER_PROTOCOL_ERROR;
use cql_bindgen::CASS_ERROR_SERVER_SERVER_ERROR;
use cql_bindgen::CASS_ERROR_LIB_UNABLE_TO_CLOSE;
use cql_bindgen::CASS_ERROR_LIB_UNABLE_TO_CONNECT;
use cql_bindgen::CASS_ERROR_LIB_NOT_IMPLEMENTED;
use cql_bindgen::CASS_ERROR_LIB_NULL_VALUE;
use cql_bindgen::CASS_ERROR_LIB_UNABLE_TO_DETERMINE_PROTOCOL;
use cql_bindgen::CASS_ERROR_LIB_NAME_DOES_NOT_EXIST;
use cql_bindgen::CASS_ERROR_LIB_INVALID_STATEMENT_TYPE;
use cql_bindgen::CASS_ERROR_LIB_CALLBACK_ALREADY_SET;
use cql_bindgen::CASS_ERROR_LIB_UNABLE_TO_SET_KEYSPACE;
use cql_bindgen::CASS_ERROR_LIB_REQUEST_TIMED_OUT;
use cql_bindgen::CASS_ERROR_LIB_INVALID_VALUE_TYPE;
use cql_bindgen::CASS_ERROR_LIB_INVALID_ITEM_COUNT;
use cql_bindgen::CASS_ERROR_LIB_INDEX_OUT_OF_BOUNDS;
use cql_bindgen::CASS_ERROR_LIB_NO_HOSTS_AVAILABLE;
use cql_bindgen::CASS_ERROR_LIB_WRITE_ERROR;
use cql_bindgen::CASS_ERROR_LIB_NO_AVAILABLE_IO_THREAD;
use cql_bindgen::CASS_ERROR_LIB_REQUEST_QUEUE_FULL;
use cql_bindgen::CASS_ERROR_LIB_UNEXPECTED_RESPONSE;
use cql_bindgen::CASS_ERROR_LIB_HOST_RESOLUTION;
use cql_bindgen::CASS_ERROR_LIB_MESSAGE_ENCODE;
use cql_bindgen::CASS_ERROR_LIB_UNABLE_TO_INIT;
use cql_bindgen::CASS_OK;

use cql_bindgen::CassError as _CassError;

#[derive(Debug,Eq,PartialEq,Copy,Clone)]
#[repr(C)]
pub enum CassErrorSource {
    NONE = 0isize,
    LIB = 1,
    SERVER = 2,
    SSL = 3,
    COMPRESSION = 4
}

pub struct CassError(_CassError);

impl Debug for CassError {
    fn fmt(&self, f:&mut Formatter) -> fmt::Result {
        let c_buf: *const c_char = unsafe { self.desc() };
        let buf: &[u8] = unsafe { CStr::from_ptr(c_buf).to_bytes() };
        match str::from_utf8(buf) {
            Ok(str_slice) => {
                write!(f, "{:?}", str_slice)
            },
            Err(err) => panic!("unreachable? {:?}", err)
        }
    }
}

#[derive(Debug,Eq,PartialEq,Copy,Clone)]
#[repr(C)]
pub enum CassErrorTypes {
    CASS_OK = 0,
    LIB_BAD_PARAMS = 16777217,
    LIB_NO_STREAMS = 16777218,
    LIB_UNABLE_TO_INIT = 16777219,
    LIB_MESSAGE_ENCODE = 16777220,
    LIB_HOST_RESOLUTION = 16777221,
    LIB_UNEXPECTED_RESPONSE = 16777222,
    LIB_REQUEST_QUEUE_FULL = 16777223,
    LIB_NO_AVAILABLE_IO_THREAD = 16777224,
    LIB_WRITE_ERROR = 16777225,
    LIB_NO_HOSTS_AVAILABLE = 16777226,
    LIB_INDEX_OUT_OF_BOUNDS = 16777227,
    LIB_INVALID_ITEM_COUNT = 16777228,
    LIB_INVALID_VALUE_TYPE = 16777229,
    LIB_REQUEST_TIMED_OUT = 16777230,
    LIB_UNABLE_TO_SET_KEYSPACE = 16777231,
    LIB_CALLBACK_ALREADY_SET = 16777232,
    LIB_INVALID_STATEMENT_TYPE = 16777233,
    LIB_NAME_DOES_NOT_EXIST = 16777234,
    LIB_UNABLE_TO_DETERMINE_PROTOCOL = 16777235,
    LIB_NULL_VALUE = 16777236,
    LIB_NOT_IMPLEMENTED = 16777237,
    LIB_UNABLE_TO_CONNECT = 16777238,
    LIB_UNABLE_TO_CLOSE = 16777239,
    SERVER_SERVER_ERROR = 33554432,
    SERVER_PROTOCOL_ERROR = 33554442,
    SERVER_BAD_CREDENTIALS = 33554688,
    SERVER_UNAVAILABLE = 33558528,
    SERVER_OVERLOADED = 33558529,
    SERVER_IS_BOOTSTRAPPING = 33558530,
    SERVER_TRUNCATE_ERROR = 33558531,
    SERVER_WRITE_TIMEOUT = 33558784,
    SERVER_READ_TIMEOUT = 33559040,
    SERVER_SYNTAX_ERROR = 33562624,
    SERVER_UNAUTHORIZED = 33562880,
    SERVER_INVALID_QUERY = 33563136,
    SERVER_CONFIG_ERROR = 33563392,
    SERVER_ALREADY_EXISTS = 33563648,
    SERVER_UNPREPARED = 33563904,
    SSL_INVALID_CERT = 50331649,
    SSL_INVALID_PRIVATE_KEY = 50331650,
    SSL_NO_PEER_CERT = 50331651,
    SSL_INVALID_PEER_CERT = 50331652,
    SSL_IDENTITY_MISMATCH = 50331653,
    LAST_ENTRY = 50331654
}

impl CassError {
    pub fn wrap<'a,T>(&'a self, wrappee:T) -> Result<T,CassError> {
        match self.0 {
            CASS_OK => Ok(wrappee),
            err => Err(CassError::build(err))
        }
    }

    pub fn build(val:u32) -> CassError {
        match val {
            0        => CassError(CASS_OK),
            16777217 => CassError(CASS_ERROR_LIB_BAD_PARAMS),
            16777218 => CassError(CASS_ERROR_LIB_NO_STREAMS),
            16777219 => CassError(CASS_ERROR_LIB_UNABLE_TO_INIT),
            16777220 => CassError(CASS_ERROR_LIB_MESSAGE_ENCODE),
            16777221 => CassError(CASS_ERROR_LIB_HOST_RESOLUTION),
            16777222 => CassError(CASS_ERROR_LIB_UNEXPECTED_RESPONSE),
            16777223 => CassError(CASS_ERROR_LIB_REQUEST_QUEUE_FULL),
            16777224 => CassError(CASS_ERROR_LIB_NO_AVAILABLE_IO_THREAD),
            16777225 => CassError(CASS_ERROR_LIB_WRITE_ERROR),
            16777226 => CassError(CASS_ERROR_LIB_NO_HOSTS_AVAILABLE),
            16777227 => CassError(CASS_ERROR_LIB_INDEX_OUT_OF_BOUNDS),
            16777228 => CassError(CASS_ERROR_LIB_INVALID_ITEM_COUNT),
            16777229 => CassError(CASS_ERROR_LIB_INVALID_VALUE_TYPE),
            16777230 => CassError(CASS_ERROR_LIB_REQUEST_TIMED_OUT),
            16777231 => CassError(CASS_ERROR_LIB_UNABLE_TO_SET_KEYSPACE),
            16777232 => CassError(CASS_ERROR_LIB_CALLBACK_ALREADY_SET),
            16777233 => CassError(CASS_ERROR_LIB_INVALID_STATEMENT_TYPE),
            16777234 => CassError(CASS_ERROR_LIB_NAME_DOES_NOT_EXIST),
            16777235 => CassError(CASS_ERROR_LIB_UNABLE_TO_DETERMINE_PROTOCOL),
            16777236 => CassError(CASS_ERROR_LIB_NULL_VALUE),
            16777237 => CassError(CASS_ERROR_LIB_NOT_IMPLEMENTED),
            16777238 => CassError(CASS_ERROR_LIB_UNABLE_TO_CONNECT),
            16777239 => CassError(CASS_ERROR_LIB_UNABLE_TO_CLOSE),
            33554432 => CassError(CASS_ERROR_SERVER_SERVER_ERROR),
            33554442 => CassError(CASS_ERROR_SERVER_PROTOCOL_ERROR),
            33554688 => CassError(CASS_ERROR_SERVER_BAD_CREDENTIALS),
            33558528 => CassError(CASS_ERROR_SERVER_UNAVAILABLE),
            33558529 => CassError(CASS_ERROR_SERVER_OVERLOADED),
            33558530 => CassError(CASS_ERROR_SERVER_IS_BOOTSTRAPPING),
            33558531 => CassError(CASS_ERROR_SERVER_TRUNCATE_ERROR),
            33558784 => CassError(CASS_ERROR_SERVER_WRITE_TIMEOUT),
            33559040 => CassError(CASS_ERROR_SERVER_READ_TIMEOUT),
            33562624 => CassError(CASS_ERROR_SERVER_SYNTAX_ERROR),
            33562880 => CassError(CASS_ERROR_SERVER_UNAUTHORIZED),
            33563136 => CassError(CASS_ERROR_SERVER_INVALID_QUERY),
            33563392 => CassError(CASS_ERROR_SERVER_CONFIG_ERROR),
            33563648 => CassError(CASS_ERROR_SERVER_ALREADY_EXISTS),
            33563904 => CassError(CASS_ERROR_SERVER_UNPREPARED),
            50331649 => CassError(CASS_ERROR_SSL_INVALID_CERT),
            50331650 => CassError(CASS_ERROR_SSL_INVALID_PRIVATE_KEY),
            50331651 => CassError(CASS_ERROR_SSL_NO_PEER_CERT),
            50331652 => CassError(CASS_ERROR_SSL_INVALID_PEER_CERT),
            50331653 => CassError(CASS_ERROR_SSL_IDENTITY_MISMATCH),
            50331654 => CassError(CASS_ERROR_LAST_ENTRY),
            _ => panic!(val)
        }
    }
}

impl CassError {
    pub unsafe fn desc(&self) -> *const c_char {cass_error_desc(self.0)}
    pub fn debug(&self) {println!("{:?}",self)}

}
<commit_msg>made CassError finally implement Error<commit_after>#![allow(non_camel_case_types)]
#![allow(dead_code)]

use std::fmt::{Debug,Display,Formatter};
use std::fmt;
use std::str;
use std::ffi::CStr;
use std::error::Error;
use std::str::from_utf8;

use libc::types::os::arch::c95::c_char;
use cql_bindgen::cass_error_desc;
use cql_bindgen::CASS_ERROR_LIB_BAD_PARAMS;
use cql_bindgen::CASS_ERROR_LIB_NO_STREAMS;
use cql_bindgen::CASS_ERROR_LAST_ENTRY;
use cql_bindgen::CASS_ERROR_SSL_IDENTITY_MISMATCH;
use cql_bindgen::CASS_ERROR_SSL_INVALID_PEER_CERT;
use cql_bindgen::CASS_ERROR_SSL_NO_PEER_CERT;
use cql_bindgen::CASS_ERROR_SSL_INVALID_PRIVATE_KEY;
use cql_bindgen::CASS_ERROR_SSL_INVALID_CERT;
use cql_bindgen::CASS_ERROR_SERVER_UNPREPARED;
use cql_bindgen::CASS_ERROR_SERVER_ALREADY_EXISTS;
use cql_bindgen::CASS_ERROR_SERVER_CONFIG_ERROR;
use cql_bindgen::CASS_ERROR_SERVER_INVALID_QUERY;
use cql_bindgen::CASS_ERROR_SERVER_UNAUTHORIZED;
use cql_bindgen::CASS_ERROR_SERVER_SYNTAX_ERROR;
use cql_bindgen::CASS_ERROR_SERVER_READ_TIMEOUT;
use cql_bindgen::CASS_ERROR_SERVER_WRITE_TIMEOUT;
use cql_bindgen::CASS_ERROR_SERVER_TRUNCATE_ERROR;
use cql_bindgen::CASS_ERROR_SERVER_IS_BOOTSTRAPPING;
use cql_bindgen::CASS_ERROR_SERVER_OVERLOADED;
use cql_bindgen::CASS_ERROR_SERVER_UNAVAILABLE;
use cql_bindgen::CASS_ERROR_SERVER_BAD_CREDENTIALS;
use cql_bindgen::CASS_ERROR_SERVER_PROTOCOL_ERROR;
use cql_bindgen::CASS_ERROR_SERVER_SERVER_ERROR;
use cql_bindgen::CASS_ERROR_LIB_UNABLE_TO_CLOSE;
use cql_bindgen::CASS_ERROR_LIB_UNABLE_TO_CONNECT;
use cql_bindgen::CASS_ERROR_LIB_NOT_IMPLEMENTED;
use cql_bindgen::CASS_ERROR_LIB_NULL_VALUE;
use cql_bindgen::CASS_ERROR_LIB_UNABLE_TO_DETERMINE_PROTOCOL;
use cql_bindgen::CASS_ERROR_LIB_NAME_DOES_NOT_EXIST;
use cql_bindgen::CASS_ERROR_LIB_INVALID_STATEMENT_TYPE;
use cql_bindgen::CASS_ERROR_LIB_CALLBACK_ALREADY_SET;
use cql_bindgen::CASS_ERROR_LIB_UNABLE_TO_SET_KEYSPACE;
use cql_bindgen::CASS_ERROR_LIB_REQUEST_TIMED_OUT;
use cql_bindgen::CASS_ERROR_LIB_INVALID_VALUE_TYPE;
use cql_bindgen::CASS_ERROR_LIB_INVALID_ITEM_COUNT;
use cql_bindgen::CASS_ERROR_LIB_INDEX_OUT_OF_BOUNDS;
use cql_bindgen::CASS_ERROR_LIB_NO_HOSTS_AVAILABLE;
use cql_bindgen::CASS_ERROR_LIB_WRITE_ERROR;
use cql_bindgen::CASS_ERROR_LIB_NO_AVAILABLE_IO_THREAD;
use cql_bindgen::CASS_ERROR_LIB_REQUEST_QUEUE_FULL;
use cql_bindgen::CASS_ERROR_LIB_UNEXPECTED_RESPONSE;
use cql_bindgen::CASS_ERROR_LIB_HOST_RESOLUTION;
use cql_bindgen::CASS_ERROR_LIB_MESSAGE_ENCODE;
use cql_bindgen::CASS_ERROR_LIB_UNABLE_TO_INIT;
use cql_bindgen::CASS_OK;

use cql_bindgen::CassError as _CassError;

#[derive(Debug,Eq,PartialEq,Copy,Clone)]
#[repr(C)]
pub enum CassErrorSource {
    NONE = 0isize,
    LIB = 1,
    SERVER = 2,
    SSL = 3,
    COMPRESSION = 4
}

pub struct CassError(_CassError);

impl Error for CassError {
	fn description(&self) -> &str {
		let c_buf: *const c_char = unsafe { self.desc() };
        let buf: &[u8] = unsafe { CStr::from_ptr(c_buf).to_bytes() };
        from_utf8(buf).unwrap()
    }
}

impl Display for CassError {
    fn fmt(&self, f:&mut Formatter) -> fmt::Result {
        let c_buf: *const c_char = unsafe { self.desc() };
        let buf: &[u8] = unsafe { CStr::from_ptr(c_buf).to_bytes() };
        match str::from_utf8(buf) {
            Ok(str_slice) => {
                write!(f, "{:?}", str_slice)
            },
            Err(err) => panic!("unreachable? {:?}", err)
        }
    }

}

impl Debug for CassError {
    fn fmt(&self, f:&mut Formatter) -> fmt::Result {
        let c_buf: *const c_char = unsafe { self.desc() };
        let buf: &[u8] = unsafe { CStr::from_ptr(c_buf).to_bytes() };
        match str::from_utf8(buf) {
            Ok(str_slice) => {
                write!(f, "{:?}", str_slice)
            },
            Err(err) => panic!("unreachable? {:?}", err)
        }
    }
}

#[derive(Debug,Eq,PartialEq,Copy,Clone)]
#[repr(C)]
pub enum CassErrorTypes {
    CASS_OK = 0,
    LIB_BAD_PARAMS = 16777217,
    LIB_NO_STREAMS = 16777218,
    LIB_UNABLE_TO_INIT = 16777219,
    LIB_MESSAGE_ENCODE = 16777220,
    LIB_HOST_RESOLUTION = 16777221,
    LIB_UNEXPECTED_RESPONSE = 16777222,
    LIB_REQUEST_QUEUE_FULL = 16777223,
    LIB_NO_AVAILABLE_IO_THREAD = 16777224,
    LIB_WRITE_ERROR = 16777225,
    LIB_NO_HOSTS_AVAILABLE = 16777226,
    LIB_INDEX_OUT_OF_BOUNDS = 16777227,
    LIB_INVALID_ITEM_COUNT = 16777228,
    LIB_INVALID_VALUE_TYPE = 16777229,
    LIB_REQUEST_TIMED_OUT = 16777230,
    LIB_UNABLE_TO_SET_KEYSPACE = 16777231,
    LIB_CALLBACK_ALREADY_SET = 16777232,
    LIB_INVALID_STATEMENT_TYPE = 16777233,
    LIB_NAME_DOES_NOT_EXIST = 16777234,
    LIB_UNABLE_TO_DETERMINE_PROTOCOL = 16777235,
    LIB_NULL_VALUE = 16777236,
    LIB_NOT_IMPLEMENTED = 16777237,
    LIB_UNABLE_TO_CONNECT = 16777238,
    LIB_UNABLE_TO_CLOSE = 16777239,
    SERVER_SERVER_ERROR = 33554432,
    SERVER_PROTOCOL_ERROR = 33554442,
    SERVER_BAD_CREDENTIALS = 33554688,
    SERVER_UNAVAILABLE = 33558528,
    SERVER_OVERLOADED = 33558529,
    SERVER_IS_BOOTSTRAPPING = 33558530,
    SERVER_TRUNCATE_ERROR = 33558531,
    SERVER_WRITE_TIMEOUT = 33558784,
    SERVER_READ_TIMEOUT = 33559040,
    SERVER_SYNTAX_ERROR = 33562624,
    SERVER_UNAUTHORIZED = 33562880,
    SERVER_INVALID_QUERY = 33563136,
    SERVER_CONFIG_ERROR = 33563392,
    SERVER_ALREADY_EXISTS = 33563648,
    SERVER_UNPREPARED = 33563904,
    SSL_INVALID_CERT = 50331649,
    SSL_INVALID_PRIVATE_KEY = 50331650,
    SSL_NO_PEER_CERT = 50331651,
    SSL_INVALID_PEER_CERT = 50331652,
    SSL_IDENTITY_MISMATCH = 50331653,
    LAST_ENTRY = 50331654
}

impl CassError {
    pub fn wrap<'a,T>(&'a self, wrappee:T) -> Result<T,CassError> {
        match self.0 {
            CASS_OK => Ok(wrappee),
            err => Err(CassError::build(err))
        }
    }

    pub fn build(val:u32) -> CassError {
        match val {
            0        => CassError(CASS_OK),
            16777217 => CassError(CASS_ERROR_LIB_BAD_PARAMS),
            16777218 => CassError(CASS_ERROR_LIB_NO_STREAMS),
            16777219 => CassError(CASS_ERROR_LIB_UNABLE_TO_INIT),
            16777220 => CassError(CASS_ERROR_LIB_MESSAGE_ENCODE),
            16777221 => CassError(CASS_ERROR_LIB_HOST_RESOLUTION),
            16777222 => CassError(CASS_ERROR_LIB_UNEXPECTED_RESPONSE),
            16777223 => CassError(CASS_ERROR_LIB_REQUEST_QUEUE_FULL),
            16777224 => CassError(CASS_ERROR_LIB_NO_AVAILABLE_IO_THREAD),
            16777225 => CassError(CASS_ERROR_LIB_WRITE_ERROR),
            16777226 => CassError(CASS_ERROR_LIB_NO_HOSTS_AVAILABLE),
            16777227 => CassError(CASS_ERROR_LIB_INDEX_OUT_OF_BOUNDS),
            16777228 => CassError(CASS_ERROR_LIB_INVALID_ITEM_COUNT),
            16777229 => CassError(CASS_ERROR_LIB_INVALID_VALUE_TYPE),
            16777230 => CassError(CASS_ERROR_LIB_REQUEST_TIMED_OUT),
            16777231 => CassError(CASS_ERROR_LIB_UNABLE_TO_SET_KEYSPACE),
            16777232 => CassError(CASS_ERROR_LIB_CALLBACK_ALREADY_SET),
            16777233 => CassError(CASS_ERROR_LIB_INVALID_STATEMENT_TYPE),
            16777234 => CassError(CASS_ERROR_LIB_NAME_DOES_NOT_EXIST),
            16777235 => CassError(CASS_ERROR_LIB_UNABLE_TO_DETERMINE_PROTOCOL),
            16777236 => CassError(CASS_ERROR_LIB_NULL_VALUE),
            16777237 => CassError(CASS_ERROR_LIB_NOT_IMPLEMENTED),
            16777238 => CassError(CASS_ERROR_LIB_UNABLE_TO_CONNECT),
            16777239 => CassError(CASS_ERROR_LIB_UNABLE_TO_CLOSE),
            33554432 => CassError(CASS_ERROR_SERVER_SERVER_ERROR),
            33554442 => CassError(CASS_ERROR_SERVER_PROTOCOL_ERROR),
            33554688 => CassError(CASS_ERROR_SERVER_BAD_CREDENTIALS),
            33558528 => CassError(CASS_ERROR_SERVER_UNAVAILABLE),
            33558529 => CassError(CASS_ERROR_SERVER_OVERLOADED),
            33558530 => CassError(CASS_ERROR_SERVER_IS_BOOTSTRAPPING),
            33558531 => CassError(CASS_ERROR_SERVER_TRUNCATE_ERROR),
            33558784 => CassError(CASS_ERROR_SERVER_WRITE_TIMEOUT),
            33559040 => CassError(CASS_ERROR_SERVER_READ_TIMEOUT),
            33562624 => CassError(CASS_ERROR_SERVER_SYNTAX_ERROR),
            33562880 => CassError(CASS_ERROR_SERVER_UNAUTHORIZED),
            33563136 => CassError(CASS_ERROR_SERVER_INVALID_QUERY),
            33563392 => CassError(CASS_ERROR_SERVER_CONFIG_ERROR),
            33563648 => CassError(CASS_ERROR_SERVER_ALREADY_EXISTS),
            33563904 => CassError(CASS_ERROR_SERVER_UNPREPARED),
            50331649 => CassError(CASS_ERROR_SSL_INVALID_CERT),
            50331650 => CassError(CASS_ERROR_SSL_INVALID_PRIVATE_KEY),
            50331651 => CassError(CASS_ERROR_SSL_NO_PEER_CERT),
            50331652 => CassError(CASS_ERROR_SSL_INVALID_PEER_CERT),
            50331653 => CassError(CASS_ERROR_SSL_IDENTITY_MISMATCH),
            50331654 => CassError(CASS_ERROR_LAST_ENTRY),
            _ => panic!(val)
        }
    }
}

impl CassError {
    pub unsafe fn desc(&self) -> *const c_char {cass_error_desc(self.0)}
    pub fn debug(&self) {println!("{:?}",self)}

}
<|endoftext|>


<commit_before>use std::any::Any;
use std::mem;
use runtime::{Class, Object, Sel, Super, self};

/// Types that may be sent Objective-C messages.
/// For example: objects, classes, and blocks.
pub unsafe trait Message { }

unsafe impl Message for Object { }

unsafe impl Message for Class { }

#[cfg(target_arch = "x86")]
fn msg_send_fn<R: Any>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    // Structures 1 or 2 bytes in size are placed in EAX.
    // Structures 4 or 8 bytes in size are placed in: EAX and EDX.
    // Structures of other sizes are placed at the address supplied by the caller.
    // https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/LowLevelABI/130-IA-32_Function_Calling_Conventions/IA32.html

    use std::any::TypeId;

    let type_id = TypeId::of::<R>();
    let size = mem::size_of::<R>();
    if type_id == TypeId::of::<f32>() || type_id == TypeId::of::<f64>() {
        unsafe { mem::transmute(runtime::objc_msgSend_fpret) }
    } else if size == 0 || size == 1 || size == 2 || size == 4 || size == 8 {
        unsafe { mem::transmute(runtime::objc_msgSend) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSend_stret) }
    }
}

#[cfg(all(target_arch = "x86", not(feature = "gnustep_runtime")))]
fn msg_send_super_fn<R: Any>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    let size = mem::size_of::<R>();
    if size == 0 || size == 1 || size == 2 || size == 4 || size == 8 {
        unsafe { mem::transmute(runtime::objc_msgSendSuper) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSendSuper_stret) }
    }
}

#[cfg(target_arch = "x86_64")]
fn msg_send_fn<R>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    // If the size of an object is larger than two eightbytes, it has class MEMORY.
    // If the type has class MEMORY, then the caller provides space for the return
    // value and passes the address of this storage.
    // http://people.freebsd.org/~obrien/amd64-elf-abi.pdf

    if mem::size_of::<R>() <= 16 {
        unsafe { mem::transmute(runtime::objc_msgSend) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSend_stret) }
    }
}

#[cfg(all(target_arch = "x86_64", not(feature = "gnustep_runtime")))]
fn msg_send_super_fn<R>() -> unsafe extern fn(*const Super, Sel, ...) -> R {
    if mem::size_of::<R>() <= 16 {
        unsafe { mem::transmute(runtime::objc_msgSendSuper) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSendSuper_stret) }
    }
}

#[cfg(target_arch = "arm")]
fn msg_send_fn<R: Any>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    // Double-word sized fundamental data types don't use stret,
    // but any composite type larger than 4 bytes does.
    // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042e/IHI0042E_aapcs.pdf

    use std::any::TypeId;

    let type_id = TypeId::of::<R>();
    if mem::size_of::<R>() <= 4 ||
            type_id == TypeId::of::<i64>() ||
            type_id == TypeId::of::<u64>() ||
            type_id == TypeId::of::<f64>() {
        unsafe { mem::transmute(runtime::objc_msgSend) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSend_stret) }
    }
}

#[cfg(all(target_arch = "arm", not(feature = "gnustep_runtime")))]
fn msg_send_super_fn<R: Any>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    use std::any::TypeId;

    let type_id = TypeId::of::<R>();
    if mem::size_of::<R>() <= 4 ||
            type_id == TypeId::of::<i64>() ||
            type_id == TypeId::of::<u64>() ||
            type_id == TypeId::of::<f64>() {
        unsafe { mem::transmute(runtime::objc_msgSendSuper) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSendSuper_stret) }
    }
}

#[cfg(all(target_arch = "aarch64", not(feature = "gnustep_runtime")))]
fn msg_send_fn<R>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    // stret is not even available in arm64.
    // https://twitter.com/gparker/status/378079715824660480

    unsafe { mem::transmute(runtime::objc_msgSend) }
}

#[cfg(all(target_arch = "arm", not(feature ="gnustep_runtime")))]
fn msg_send_super_fn<R>() -> unsafe extern fn(*const Super, Sel, ...) -> R {
    unsafe { mem::transmute(runtime::objc_msgSendSuper) }
}

/// Types that may be used as the arguments of an Objective-C message.
pub trait MessageArguments {
    /// Sends a message to the given obj with the given selector and self as
    /// the arguments.
    ///
    /// The correct version of `objc_msgSend` will be chosen based on the
    /// return type. For more information, see Apple's documenation:
    /// https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html#//apple_ref/doc/uid/TP40001418-CH1g-88778
    ///
    /// It is recommended to use the `msg_send!` macro rather than calling this
    /// method directly.
    unsafe fn send<T, R>(self, obj: *mut T, sel: Sel) -> R
            where T: Message, R: Any;

    /// Sends a message to the superclass of an instance of a class with self
    /// as the arguments.
    unsafe fn send_super<T, R>(self, obj: *mut T, superclass: &Class, sel: Sel) -> R
            where T: Message, R: Any;
}

macro_rules! message_args_impl {
    ($($a:ident : $t:ident),*) => (
        impl<$($t),*> MessageArguments for ($($t,)*) {
            #[cfg(any(not(feature="gnustep_runtime"),
                      any(target_arch = "arm",
                          target_arch = "x86",
                          target_arch = "x86_64")))]
            unsafe fn send<T, R>(self, obj: *mut T, sel: Sel) -> R
                    where T: Message, R: Any {
                let msg_send_fn = msg_send_fn::<R>();
                let msg_send_fn: unsafe extern fn(*mut Object, Sel $(, $t)*) -> R =
                    mem::transmute(msg_send_fn);
                let ($($a,)*) = self;
                objc_try!({
                    msg_send_fn(obj as *mut Object, sel $(, $a)*)
                })
            }

            #[cfg(all(feature="gnustep_runtime",
                      not(any(target_arch = "arm",
                              target_arch = "x86",
                              target_arch = "x86_64"))))]
            unsafe fn send<T, R>(self, obj: *mut T, sel: Sel) -> R
                   where T: Message, R: Any {
                    let mut receiver = obj as *mut Object;
                    let nil: *mut Object = ::std::ptr::null_mut();
                    let ref slot = *runtime::objc_msg_lookup_sender(&mut receiver as *mut *mut Object, sel, nil);
                    let imp_fn = slot.method;
                    let imp_fn: unsafe extern fn(*mut Object, Sel $(, $t)*) -> R =
                        mem::transmute(imp_fn);
                    let ($($a,)*) = self;
                    objc_try!({
                      imp_fn(receiver as *mut Object, sel $(, $a)*)
                    })
            }

            #[cfg(not(feature="gnustep_runtime"))]
            unsafe fn send_super<T, R>(self, obj: *mut T, superclass: &Class, sel: Sel) -> R
                    where T: Message, R: Any {
                let msg_send_fn = msg_send_super_fn::<R>();
                let msg_send_fn: unsafe extern fn(*const Super, Sel $(, $t)*) -> R =
                    mem::transmute(msg_send_fn);
                let sup = Super { receiver: obj as *mut Object, superclass: superclass };
                let ($($a,)*) = self;
                objc_try!({
                    msg_send_fn(&sup, sel $(, $a)*)
                })
            }

            #[cfg(feature="gnustep_runtime")]
            unsafe fn send_super<T, R>(self, obj: *mut T, superclass: &Class, sel: Sel) -> R
                    where T: Message, R: Any {
                let sup = Super { receiver: obj as *mut Object, superclass: superclass };
                let ref slot = *runtime::objc_slot_lookup_super(&sup, sel);
                let imp_fn = slot.method;
                let imp_fn: unsafe extern fn(*mut Object, Sel $(, $t)*) -> R =
                    mem::transmute(imp_fn);
                let ($($a,)*) = self;
                objc_try!({
                    imp_fn(obj as *mut Object, sel $(, $a)*)
                })
            }
        }
    );
}

message_args_impl!();
message_args_impl!(a: A);
message_args_impl!(a: A, b: B);
message_args_impl!(a: A, b: B, c: C);
message_args_impl!(a: A, b: B, c: C, d: D);
message_args_impl!(a: A, b: B, c: C, d: D, e: E);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);

#[cfg(test)]
mod tests {
    use runtime::Object;
    use test_utils;

    #[test]
    fn test_send_message() {
        let obj = test_utils::sample_object();
        let result: *const Object = unsafe {
            msg_send![obj, self]
        };
        assert!(result == &*obj);
    }

    #[test]
    fn test_send_message_stret() {
        let obj = test_utils::custom_object();
        let result: test_utils::CustomStruct = unsafe {
            msg_send![obj, customStruct]
        };
        let expected = test_utils::CustomStruct { a: 1, b:2, c: 3, d: 4 };
        assert!(result == expected);
    }

    #[test]
    fn test_send_message_nil() {
        let nil: *mut Object = ::std::ptr::null_mut();
        let result: usize = unsafe {
            msg_send![nil, hash]
        };
        assert!(result == 0);

        let result: *mut Object = unsafe {
            msg_send![nil, description]
        };
        assert!(result.is_null());

        let result: f64 = unsafe {
            msg_send![nil, doubleValue]
        };
        assert!(result == 0.0);
    }

    #[test]
    fn test_send_message_super() {
        let obj = test_utils::custom_subclass_object();
        let superclass = test_utils::custom_class();
        unsafe {
            let _: () = msg_send![obj, setFoo:4u32];
            let foo: u32 = msg_send![super(obj, superclass), foo];
            assert!(foo == 4);

            // The subclass is overriden to return foo + 2
            let foo: u32 = msg_send![obj, foo];
            assert!(foo == 6);
        }
    }
}
<commit_msg>Restore original arch (aarch64 was incorrectly replaced with arm)<commit_after>use std::any::Any;
use std::mem;
use runtime::{Class, Object, Sel, Super, self};

/// Types that may be sent Objective-C messages.
/// For example: objects, classes, and blocks.
pub unsafe trait Message { }

unsafe impl Message for Object { }

unsafe impl Message for Class { }

#[cfg(target_arch = "x86")]
fn msg_send_fn<R: Any>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    // Structures 1 or 2 bytes in size are placed in EAX.
    // Structures 4 or 8 bytes in size are placed in: EAX and EDX.
    // Structures of other sizes are placed at the address supplied by the caller.
    // https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/LowLevelABI/130-IA-32_Function_Calling_Conventions/IA32.html

    use std::any::TypeId;

    let type_id = TypeId::of::<R>();
    let size = mem::size_of::<R>();
    if type_id == TypeId::of::<f32>() || type_id == TypeId::of::<f64>() {
        unsafe { mem::transmute(runtime::objc_msgSend_fpret) }
    } else if size == 0 || size == 1 || size == 2 || size == 4 || size == 8 {
        unsafe { mem::transmute(runtime::objc_msgSend) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSend_stret) }
    }
}

#[cfg(all(target_arch = "x86", not(feature = "gnustep_runtime")))]
fn msg_send_super_fn<R: Any>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    let size = mem::size_of::<R>();
    if size == 0 || size == 1 || size == 2 || size == 4 || size == 8 {
        unsafe { mem::transmute(runtime::objc_msgSendSuper) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSendSuper_stret) }
    }
}

#[cfg(target_arch = "x86_64")]
fn msg_send_fn<R>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    // If the size of an object is larger than two eightbytes, it has class MEMORY.
    // If the type has class MEMORY, then the caller provides space for the return
    // value and passes the address of this storage.
    // http://people.freebsd.org/~obrien/amd64-elf-abi.pdf

    if mem::size_of::<R>() <= 16 {
        unsafe { mem::transmute(runtime::objc_msgSend) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSend_stret) }
    }
}

#[cfg(all(target_arch = "x86_64", not(feature = "gnustep_runtime")))]
fn msg_send_super_fn<R>() -> unsafe extern fn(*const Super, Sel, ...) -> R {
    if mem::size_of::<R>() <= 16 {
        unsafe { mem::transmute(runtime::objc_msgSendSuper) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSendSuper_stret) }
    }
}

#[cfg(target_arch = "arm")]
fn msg_send_fn<R: Any>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    // Double-word sized fundamental data types don't use stret,
    // but any composite type larger than 4 bytes does.
    // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042e/IHI0042E_aapcs.pdf

    use std::any::TypeId;

    let type_id = TypeId::of::<R>();
    if mem::size_of::<R>() <= 4 ||
            type_id == TypeId::of::<i64>() ||
            type_id == TypeId::of::<u64>() ||
            type_id == TypeId::of::<f64>() {
        unsafe { mem::transmute(runtime::objc_msgSend) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSend_stret) }
    }
}

#[cfg(all(target_arch = "arm", not(feature = "gnustep_runtime")))]
fn msg_send_super_fn<R: Any>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    use std::any::TypeId;

    let type_id = TypeId::of::<R>();
    if mem::size_of::<R>() <= 4 ||
            type_id == TypeId::of::<i64>() ||
            type_id == TypeId::of::<u64>() ||
            type_id == TypeId::of::<f64>() {
        unsafe { mem::transmute(runtime::objc_msgSendSuper) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSendSuper_stret) }
    }
}

#[cfg(all(target_arch = "aarch64", not(feature = "gnustep_runtime")))]
fn msg_send_fn<R>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    // stret is not even available in arm64.
    // https://twitter.com/gparker/status/378079715824660480

    unsafe { mem::transmute(runtime::objc_msgSend) }
}

#[cfg(all(target_arch = "aarch64", not(feature ="gnustep_runtime")))]
fn msg_send_super_fn<R>() -> unsafe extern fn(*const Super, Sel, ...) -> R {
    unsafe { mem::transmute(runtime::objc_msgSendSuper) }
}

/// Types that may be used as the arguments of an Objective-C message.
pub trait MessageArguments {
    /// Sends a message to the given obj with the given selector and self as
    /// the arguments.
    ///
    /// The correct version of `objc_msgSend` will be chosen based on the
    /// return type. For more information, see Apple's documenation:
    /// https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html#//apple_ref/doc/uid/TP40001418-CH1g-88778
    ///
    /// It is recommended to use the `msg_send!` macro rather than calling this
    /// method directly.
    unsafe fn send<T, R>(self, obj: *mut T, sel: Sel) -> R
            where T: Message, R: Any;

    /// Sends a message to the superclass of an instance of a class with self
    /// as the arguments.
    unsafe fn send_super<T, R>(self, obj: *mut T, superclass: &Class, sel: Sel) -> R
            where T: Message, R: Any;
}

macro_rules! message_args_impl {
    ($($a:ident : $t:ident),*) => (
        impl<$($t),*> MessageArguments for ($($t,)*) {
            #[cfg(any(not(feature="gnustep_runtime"),
                      any(target_arch = "arm",
                          target_arch = "x86",
                          target_arch = "x86_64")))]
            unsafe fn send<T, R>(self, obj: *mut T, sel: Sel) -> R
                    where T: Message, R: Any {
                let msg_send_fn = msg_send_fn::<R>();
                let msg_send_fn: unsafe extern fn(*mut Object, Sel $(, $t)*) -> R =
                    mem::transmute(msg_send_fn);
                let ($($a,)*) = self;
                objc_try!({
                    msg_send_fn(obj as *mut Object, sel $(, $a)*)
                })
            }

            #[cfg(all(feature="gnustep_runtime",
                      not(any(target_arch = "arm",
                              target_arch = "x86",
                              target_arch = "x86_64"))))]
            unsafe fn send<T, R>(self, obj: *mut T, sel: Sel) -> R
                   where T: Message, R: Any {
                    let mut receiver = obj as *mut Object;
                    let nil: *mut Object = ::std::ptr::null_mut();
                    let ref slot = *runtime::objc_msg_lookup_sender(&mut receiver as *mut *mut Object, sel, nil);
                    let imp_fn = slot.method;
                    let imp_fn: unsafe extern fn(*mut Object, Sel $(, $t)*) -> R =
                        mem::transmute(imp_fn);
                    let ($($a,)*) = self;
                    objc_try!({
                      imp_fn(receiver as *mut Object, sel $(, $a)*)
                    })
            }

            #[cfg(not(feature="gnustep_runtime"))]
            unsafe fn send_super<T, R>(self, obj: *mut T, superclass: &Class, sel: Sel) -> R
                    where T: Message, R: Any {
                let msg_send_fn = msg_send_super_fn::<R>();
                let msg_send_fn: unsafe extern fn(*const Super, Sel $(, $t)*) -> R =
                    mem::transmute(msg_send_fn);
                let sup = Super { receiver: obj as *mut Object, superclass: superclass };
                let ($($a,)*) = self;
                objc_try!({
                    msg_send_fn(&sup, sel $(, $a)*)
                })
            }

            #[cfg(feature="gnustep_runtime")]
            unsafe fn send_super<T, R>(self, obj: *mut T, superclass: &Class, sel: Sel) -> R
                    where T: Message, R: Any {
                let sup = Super { receiver: obj as *mut Object, superclass: superclass };
                let ref slot = *runtime::objc_slot_lookup_super(&sup, sel);
                let imp_fn = slot.method;
                let imp_fn: unsafe extern fn(*mut Object, Sel $(, $t)*) -> R =
                    mem::transmute(imp_fn);
                let ($($a,)*) = self;
                objc_try!({
                    imp_fn(obj as *mut Object, sel $(, $a)*)
                })
            }
        }
    );
}

message_args_impl!();
message_args_impl!(a: A);
message_args_impl!(a: A, b: B);
message_args_impl!(a: A, b: B, c: C);
message_args_impl!(a: A, b: B, c: C, d: D);
message_args_impl!(a: A, b: B, c: C, d: D, e: E);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);

#[cfg(test)]
mod tests {
    use runtime::Object;
    use test_utils;

    #[test]
    fn test_send_message() {
        let obj = test_utils::sample_object();
        let result: *const Object = unsafe {
            msg_send![obj, self]
        };
        assert!(result == &*obj);
    }

    #[test]
    fn test_send_message_stret() {
        let obj = test_utils::custom_object();
        let result: test_utils::CustomStruct = unsafe {
            msg_send![obj, customStruct]
        };
        let expected = test_utils::CustomStruct { a: 1, b:2, c: 3, d: 4 };
        assert!(result == expected);
    }

    #[test]
    fn test_send_message_nil() {
        let nil: *mut Object = ::std::ptr::null_mut();
        let result: usize = unsafe {
            msg_send![nil, hash]
        };
        assert!(result == 0);

        let result: *mut Object = unsafe {
            msg_send![nil, description]
        };
        assert!(result.is_null());

        let result: f64 = unsafe {
            msg_send![nil, doubleValue]
        };
        assert!(result == 0.0);
    }

    #[test]
    fn test_send_message_super() {
        let obj = test_utils::custom_subclass_object();
        let superclass = test_utils::custom_class();
        unsafe {
            let _: () = msg_send![obj, setFoo:4u32];
            let foo: u32 = msg_send![super(obj, superclass), foo];
            assert!(foo == 4);

            // The subclass is overriden to return foo + 2
            let foo: u32 = msg_send![obj, foo];
            assert!(foo == 6);
        }
    }
}
<|endoftext|>


<commit_before>//! Store and manipulate Kafka messages.
use rdsys;
use rdsys::types::*;

use std::ffi::CStr;
use std::slice;
use std::str;

/// Timestamp of a message
#[derive(Debug,PartialEq,Eq)]
pub enum Timestamp {
    NotAvailable,
    CreateTime(i64),
    LogAppendTime(i64)
}

/// A native librdkafka message.
#[derive(Debug)]
pub struct Message {
    ptr: *mut RDKafkaMessage,
}

unsafe impl Send for Message {}

impl Message {
    /// Creates a new Message that wraps the native Kafka message pointer.
    pub fn new(ptr: *mut RDKafkaMessage) -> Message {
        Message { ptr: ptr }
    }

    /// Returns a pointer to the RDKafkaMessage.
    pub fn ptr(&self) -> *mut RDKafkaMessage {
        self.ptr
    }

    /// Returns a pointer to the message's RDKafkaTopic
    pub fn topic_ptr(&self) -> *mut RDKafkaTopic {
        unsafe { (*self.ptr).rkt }
    }

    /// Returns the length of the key field of the message.
    pub fn key_len(&self) -> usize {
        unsafe { (*self.ptr).key_len }
    }

    /// Returns the length of the payload field of the message.
    pub fn payload_len(&self) -> usize {
        unsafe { (*self.ptr).len }
    }

    /// Returns the key of the message, or None if there is no key.
    pub fn key(&self) -> Option<&[u8]> {
        unsafe {
            if (*self.ptr).key.is_null() {
                None
            } else {
                Some(slice::from_raw_parts::<u8>((*self.ptr).key as *const u8, (*self.ptr).key_len))
            }
        }
    }

    /// Returns the payload of the message, or None if there is no payload.
    pub fn payload(&self) -> Option<&[u8]> {
        unsafe {
            if (*self.ptr).payload.is_null() {
                None
            } else {
                Some(slice::from_raw_parts::<u8>((*self.ptr).payload as *const u8, (*self.ptr).len))
            }
        }
    }

    /// Returns the source topic of the message.
    pub fn topic_name(&self) -> &str {
         unsafe {
             CStr::from_ptr(rdsys::rd_kafka_topic_name((*self.ptr).rkt))
                 .to_str()
                 .expect("Topic name is not valid UTF-8")
         }
     }

    /// Converts the raw bytes of the payload to a reference of type &P, pointing to the same data inside
    /// the message. The returned reference cannot outlive the message.
    pub fn payload_view<P: ?Sized + FromBytes>(&self) -> Option<Result<&P, P::Error>> {
        self.payload().map(P::from_bytes)
    }

    /// Converts the raw bytes of the key to a reference of type &K, pointing to the same data inside
    /// the message. The returned reference cannot outlive the message.
    pub fn key_view<K: ?Sized + FromBytes>(&self) -> Option<Result<&K, K::Error>> {
        self.key().map(K::from_bytes)
    }

    /// Returns the partition number where the message is stored.
    pub fn partition(&self) -> i32 {
        unsafe { (*self.ptr).partition }
    }

    /// Returns the offset of the message.
    pub fn offset(&self) -> i64 {
        unsafe { (*self.ptr).offset }
    }

    /// Returns the message timestamp for a consumed message if available.
    pub fn timestamp(&self) -> Timestamp {
        let mut timestamp_type = rdsys::rd_kafka_timestamp_type_t::RD_KAFKA_TIMESTAMP_NOT_AVAILABLE;
        let timestamp = unsafe {
            rdsys::rd_kafka_message_timestamp(
                self.ptr,
                &mut timestamp_type
            )

        };
        match timestamp_type {
            rdsys::rd_kafka_timestamp_type_t::RD_KAFKA_TIMESTAMP_NOT_AVAILABLE => Timestamp::NotAvailable,
            rdsys::rd_kafka_timestamp_type_t::RD_KAFKA_TIMESTAMP_CREATE_TIME => Timestamp::CreateTime(timestamp),
            rdsys::rd_kafka_timestamp_type_t::RD_KAFKA_TIMESTAMP_LOG_APPEND_TIME => Timestamp::LogAppendTime(timestamp)
        }
    }
}

impl Drop for Message {
    fn drop(&mut self) {
        trace!("Destroying message {:?}", self);
        unsafe { rdsys::rd_kafka_message_destroy(self.ptr) };
    }
}

/// Given a reference to a byte array, returns a different view of the same data.
/// No copy of the data should be performed.
pub trait FromBytes {
    type Error;
    fn from_bytes(&[u8]) -> Result<&Self, Self::Error>;
}

impl FromBytes for [u8] {
    type Error = ();
    fn from_bytes(bytes: &[u8]) -> Result<&Self, Self::Error> {
        Ok(bytes)
    }
}

impl FromBytes for str {
    type Error = str::Utf8Error;
    fn from_bytes(bytes: &[u8]) -> Result<&Self, Self::Error> {
        str::from_utf8(bytes)
    }
}

/// Given some data, returns the byte representation of that data.
/// No copy of the data should be performed.
pub trait ToBytes {
    fn to_bytes(&self) -> &[u8];
}

impl ToBytes for [u8] {
    fn to_bytes(&self) -> &[u8] {
        self
    }
}

impl ToBytes for str {
    fn to_bytes(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToBytes for Vec<u8> {
    fn to_bytes(&self) -> &[u8] {
        self.as_slice()
    }
}

impl ToBytes for String {
    fn to_bytes(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl<'a, T: ToBytes> ToBytes for &'a T {
    fn to_bytes(&self) -> &[u8] {
        (*self).to_bytes()
    }
}

impl ToBytes for () {
    fn to_bytes(&self) -> &[u8] {
        &[]
    }
}
<commit_msg>Implement Clone and Copy for Timestamp<commit_after>//! Store and manipulate Kafka messages.
use rdsys;
use rdsys::types::*;

use std::ffi::CStr;
use std::slice;
use std::str;

/// Timestamp of a message
#[derive(Debug,PartialEq,Eq,Clone,Copy)]
pub enum Timestamp {
    NotAvailable,
    CreateTime(i64),
    LogAppendTime(i64)
}

/// A native librdkafka message.
#[derive(Debug)]
pub struct Message {
    ptr: *mut RDKafkaMessage,
}

unsafe impl Send for Message {}

impl Message {
    /// Creates a new Message that wraps the native Kafka message pointer.
    pub fn new(ptr: *mut RDKafkaMessage) -> Message {
        Message { ptr: ptr }
    }

    /// Returns a pointer to the RDKafkaMessage.
    pub fn ptr(&self) -> *mut RDKafkaMessage {
        self.ptr
    }

    /// Returns a pointer to the message's RDKafkaTopic
    pub fn topic_ptr(&self) -> *mut RDKafkaTopic {
        unsafe { (*self.ptr).rkt }
    }

    /// Returns the length of the key field of the message.
    pub fn key_len(&self) -> usize {
        unsafe { (*self.ptr).key_len }
    }

    /// Returns the length of the payload field of the message.
    pub fn payload_len(&self) -> usize {
        unsafe { (*self.ptr).len }
    }

    /// Returns the key of the message, or None if there is no key.
    pub fn key(&self) -> Option<&[u8]> {
        unsafe {
            if (*self.ptr).key.is_null() {
                None
            } else {
                Some(slice::from_raw_parts::<u8>((*self.ptr).key as *const u8, (*self.ptr).key_len))
            }
        }
    }

    /// Returns the payload of the message, or None if there is no payload.
    pub fn payload(&self) -> Option<&[u8]> {
        unsafe {
            if (*self.ptr).payload.is_null() {
                None
            } else {
                Some(slice::from_raw_parts::<u8>((*self.ptr).payload as *const u8, (*self.ptr).len))
            }
        }
    }

    /// Returns the source topic of the message.
    pub fn topic_name(&self) -> &str {
         unsafe {
             CStr::from_ptr(rdsys::rd_kafka_topic_name((*self.ptr).rkt))
                 .to_str()
                 .expect("Topic name is not valid UTF-8")
         }
     }

    /// Converts the raw bytes of the payload to a reference of type &P, pointing to the same data inside
    /// the message. The returned reference cannot outlive the message.
    pub fn payload_view<P: ?Sized + FromBytes>(&self) -> Option<Result<&P, P::Error>> {
        self.payload().map(P::from_bytes)
    }

    /// Converts the raw bytes of the key to a reference of type &K, pointing to the same data inside
    /// the message. The returned reference cannot outlive the message.
    pub fn key_view<K: ?Sized + FromBytes>(&self) -> Option<Result<&K, K::Error>> {
        self.key().map(K::from_bytes)
    }

    /// Returns the partition number where the message is stored.
    pub fn partition(&self) -> i32 {
        unsafe { (*self.ptr).partition }
    }

    /// Returns the offset of the message.
    pub fn offset(&self) -> i64 {
        unsafe { (*self.ptr).offset }
    }

    /// Returns the message timestamp for a consumed message if available.
    pub fn timestamp(&self) -> Timestamp {
        let mut timestamp_type = rdsys::rd_kafka_timestamp_type_t::RD_KAFKA_TIMESTAMP_NOT_AVAILABLE;
        let timestamp = unsafe {
            rdsys::rd_kafka_message_timestamp(
                self.ptr,
                &mut timestamp_type
            )

        };
        match timestamp_type {
            rdsys::rd_kafka_timestamp_type_t::RD_KAFKA_TIMESTAMP_NOT_AVAILABLE => Timestamp::NotAvailable,
            rdsys::rd_kafka_timestamp_type_t::RD_KAFKA_TIMESTAMP_CREATE_TIME => Timestamp::CreateTime(timestamp),
            rdsys::rd_kafka_timestamp_type_t::RD_KAFKA_TIMESTAMP_LOG_APPEND_TIME => Timestamp::LogAppendTime(timestamp)
        }
    }
}

impl Drop for Message {
    fn drop(&mut self) {
        trace!("Destroying message {:?}", self);
        unsafe { rdsys::rd_kafka_message_destroy(self.ptr) };
    }
}

/// Given a reference to a byte array, returns a different view of the same data.
/// No copy of the data should be performed.
pub trait FromBytes {
    type Error;
    fn from_bytes(&[u8]) -> Result<&Self, Self::Error>;
}

impl FromBytes for [u8] {
    type Error = ();
    fn from_bytes(bytes: &[u8]) -> Result<&Self, Self::Error> {
        Ok(bytes)
    }
}

impl FromBytes for str {
    type Error = str::Utf8Error;
    fn from_bytes(bytes: &[u8]) -> Result<&Self, Self::Error> {
        str::from_utf8(bytes)
    }
}

/// Given some data, returns the byte representation of that data.
/// No copy of the data should be performed.
pub trait ToBytes {
    fn to_bytes(&self) -> &[u8];
}

impl ToBytes for [u8] {
    fn to_bytes(&self) -> &[u8] {
        self
    }
}

impl ToBytes for str {
    fn to_bytes(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToBytes for Vec<u8> {
    fn to_bytes(&self) -> &[u8] {
        self.as_slice()
    }
}

impl ToBytes for String {
    fn to_bytes(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl<'a, T: ToBytes> ToBytes for &'a T {
    fn to_bytes(&self) -> &[u8] {
        (*self).to_bytes()
    }
}

impl ToBytes for () {
    fn to_bytes(&self) -> &[u8] {
        &[]
    }
}
<|endoftext|>


<commit_before>#![allow(unused_results)]
#![allow(clippy::print_stdout)]

use std::sync::atomic::AtomicUsize;

#[cfg(not(target_arch = "x86_64"))]
use std::time::{Duration, Instant};

#[cfg(feature = "no_metrics")]
use std::marker::PhantomData;

#[cfg(not(feature = "no_metrics"))]
use std::sync::atomic::Ordering::{Acquire, Relaxed};

use crate::Lazy;

use super::*;

/// A metric collector for all pagecache users running in this
/// process.
pub static M: Lazy<Metrics, fn() -> Metrics> = Lazy::new(Metrics::default);

#[allow(clippy::cast_precision_loss)]
pub(crate) fn clock() -> f64 {
    if cfg!(feature = "no_metrics") {
        0.
    } else {
        #[cfg(target_arch = "x86_64")]
        #[allow(unsafe_code)]
        unsafe {
            let mut aux = 0;
            core::arch::x86_64::__rdtscp(&mut aux) as f64
        }

        #[cfg(not(target_arch = "x86_64"))]
        {
            let u = uptime();
            (u.as_secs() * 1_000_000_000) as f64 + f64::from(u.subsec_nanos())
        }
    }
}

// not correct, since it starts counting at the first observance...
#[cfg(not(target_arch = "x86_64"))]
pub(crate) fn uptime() -> Duration {
    static START: Lazy<Instant, fn() -> Instant> = Lazy::new(Instant::now);

    if cfg!(feature = "no_metrics") {
        Duration::new(0, 0)
    } else {
        START.elapsed()
    }
}

/// Measure the duration of an event, and call `Histogram::measure()`.
pub struct Measure<'h> {
    _start: f64,
    #[cfg(not(feature = "no_metrics"))]
    histo: &'h Histogram,
    #[cfg(feature = "no_metrics")]
    _pd: PhantomData<&'h ()>,
}

impl<'h> Measure<'h> {
    /// The time delta from ctor to dtor is recorded in `histo`.
    #[inline]
    pub fn new(_histo: &'h Histogram) -> Measure<'h> {
        Measure {
            #[cfg(feature = "no_metrics")]
            _pd: PhantomData,
            #[cfg(not(feature = "no_metrics"))]
            histo: _histo,
            _start: clock(),
        }
    }
}

impl<'h> Drop for Measure<'h> {
    #[inline]
    fn drop(&mut self) {
        #[cfg(not(feature = "no_metrics"))]
        self.histo.measure(clock() - self._start);
    }
}

#[derive(Default, Debug)]
pub struct Metrics {
    pub advance_snapshot: Histogram,
    pub start_segment_accountant: Histogram,
    pub start_pagecache: Histogram,
    pub snapshot_apply: Histogram,
    pub segment_read: Histogram,
    pub segment_utilization: Histogram,
    pub read_segment_message: Histogram,
    pub tree_set: Histogram,
    pub tree_get: Histogram,
    pub tree_del: Histogram,
    pub tree_cas: Histogram,
    pub tree_scan: Histogram,
    pub tree_reverse_scan: Histogram,
    pub tree_merge: Histogram,
    pub tree_start: Histogram,
    pub tree_traverse: Histogram,
    pub tree_child_split_attempt: CachePadded<AtomicUsize>,
    pub tree_child_split_success: CachePadded<AtomicUsize>,
    pub tree_parent_split_attempt: CachePadded<AtomicUsize>,
    pub tree_parent_split_success: CachePadded<AtomicUsize>,
    pub tree_root_split_attempt: CachePadded<AtomicUsize>,
    pub tree_root_split_success: CachePadded<AtomicUsize>,
    pub get_page: Histogram,
    pub rewrite_page: Histogram,
    pub replace_page: Histogram,
    pub link_page: Histogram,
    pub page_out: Histogram,
    pub pull: Histogram,
    pub serialize: Histogram,
    pub deserialize: Histogram,
    pub compress: Histogram,
    pub decompress: Histogram,
    pub make_stable: Histogram,
    pub assign_offset: Histogram,
    pub assign_spinloop: Histogram,
    pub reserve_lat: Histogram,
    pub reserve_sz: Histogram,
    pub write_to_log: Histogram,
    pub written_bytes: Histogram,
    pub read: Histogram,
    pub tree_loops: CachePadded<AtomicUsize>,
    pub log_reservations: CachePadded<AtomicUsize>,
    pub log_reservation_attempts: CachePadded<AtomicUsize>,
    pub accountant_lock: Histogram,
    pub accountant_hold: Histogram,
    pub accountant_next: Histogram,
    pub accountant_mark_link: Histogram,
    pub accountant_mark_replace: Histogram,
    pub accountant_bump_tip: Histogram,
    #[cfg(feature = "measure_allocs")]
    pub allocations: CachePadded<AtomicUsize>,
    #[cfg(feature = "measure_allocs")]
    pub allocated_bytes: CachePadded<AtomicUsize>,
}

#[cfg(not(feature = "no_metrics"))]
impl Metrics {
    #[inline]
    pub fn tree_looped(&self) {
        self.tree_loops.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn log_reservation_attempted(&self) {
        self.log_reservation_attempts.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn log_reservation_success(&self) {
        self.log_reservations.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn tree_child_split_attempt(&self) {
        self.tree_child_split_attempt.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn tree_child_split_success(&self) {
        self.tree_child_split_success.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn tree_parent_split_attempt(&self) {
        self.tree_parent_split_attempt.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn tree_parent_split_success(&self) {
        self.tree_parent_split_success.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn tree_root_split_attempt(&self) {
        self.tree_root_split_attempt.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn tree_root_split_success(&self) {
        self.tree_root_split_success.fetch_add(1, Relaxed);
    }

    pub fn print_profile(&self) {
        println!(
            "sled profile:\n\
             {0: >17} | {1: >10} | {2: >10} | {3: >10} | {4: >10} | {5: >10} | {6: >10} | {7: >10} | {8: >10} | {9: >10}",
            "op",
            "min (us)",
            "med (us)",
            "90 (us)",
            "99 (us)",
            "99.9 (us)",
            "99.99 (us)",
            "max (us)",
            "count",
            "sum (s)"
        );
        println!("{}", std::iter::repeat("-").take(134).collect::<String>());

        let p = |mut tuples: Vec<(String, _, _, _, _, _, _, _, _, _)>| {
            tuples.sort_by_key(|t| (t.9 * -1. * 1e3) as i64);
            for v in tuples {
                println!(
                    "{0: >17} | {1: >10.1} | {2: >10.1} | {3: >10.1} \
                     | {4: >10.1} | {5: >10.1} | {6: >10.1} | {7: >10.1} \
                     | {8: >10.1} | {9: >10.3}",
                    v.0, v.1, v.2, v.3, v.4, v.5, v.6, v.7, v.8, v.9,
                );
            }
        };

        let lat = |name: &str, histo: &Histogram| {
            (
                name.to_string(),
                histo.percentile(0.) / 1e3,
                histo.percentile(50.) / 1e3,
                histo.percentile(90.) / 1e3,
                histo.percentile(99.) / 1e3,
                histo.percentile(99.9) / 1e3,
                histo.percentile(99.99) / 1e3,
                histo.percentile(100.) / 1e3,
                histo.count(),
                histo.sum() as f64 / 1e9,
            )
        };

        let sz = |name: &str, histo: &Histogram| {
            (
                name.to_string(),
                histo.percentile(0.),
                histo.percentile(50.),
                histo.percentile(90.),
                histo.percentile(99.),
                histo.percentile(99.9),
                histo.percentile(99.99),
                histo.percentile(100.),
                histo.count(),
                histo.sum() as f64,
            )
        };

        println!("tree:");
        p(vec![
            lat("traverse", &self.tree_traverse),
            lat("get", &self.tree_get),
            lat("set", &self.tree_set),
            lat("merge", &self.tree_merge),
            lat("del", &self.tree_del),
            lat("cas", &self.tree_cas),
            lat("scan", &self.tree_scan),
            lat("rev scan", &self.tree_reverse_scan),
        ]);
        let total_loops = self.tree_loops.load(Acquire);
        let total_ops = self.tree_get.count()
            + self.tree_set.count()
            + self.tree_merge.count()
            + self.tree_del.count()
            + self.tree_cas.count()
            + self.tree_scan.count()
            + self.tree_reverse_scan.count();
        let loop_pct = total_loops * 100 / total_ops;
        println!("tree contention loops: {} ({}%)", total_loops, loop_pct);
        println!(
            "tree split success rates: child({}/{}) parent({}/{}) root({}/{})",
            self.tree_child_split_success.load(Acquire),
            self.tree_child_split_attempt.load(Acquire),
            self.tree_parent_split_success.load(Acquire),
            self.tree_parent_split_attempt.load(Acquire),
            self.tree_root_split_success.load(Acquire),
            self.tree_root_split_attempt.load(Acquire),
        );

        println!("{}", std::iter::repeat("-").take(134).collect::<String>());
        println!("pagecache:");
        p(vec![
            lat("snapshot", &self.advance_snapshot),
            lat("get", &self.get_page),
            lat("rewrite", &self.rewrite_page),
            lat("replace", &self.replace_page),
            lat("link", &self.link_page),
            lat("pull", &self.pull),
            lat("page_out", &self.page_out),
        ]);

        println!("{}", std::iter::repeat("-").take(134).collect::<String>());
        println!("serialization and compression:");
        p(vec![
            lat("serialize", &self.serialize),
            lat("deserialize", &self.deserialize),
            lat("compress", &self.compress),
            lat("decompress", &self.decompress),
        ]);

        println!("{}", std::iter::repeat("-").take(134).collect::<String>());
        println!("log:");
        p(vec![
            lat("make_stable", &self.make_stable),
            lat("read", &self.read),
            lat("write", &self.write_to_log),
            sz("written bytes", &self.written_bytes),
            lat("assign offset", &self.assign_offset),
            lat("assign spinloop", &self.assign_spinloop),
            lat("reserve lat", &self.reserve_lat),
            sz("reserve sz", &self.reserve_sz),
        ]);
        println!("log reservations: {}", self.log_reservations.load(Acquire));
        println!(
            "log res attempts: {}",
            self.log_reservation_attempts.load(Acquire)
        );

        println!("{}", std::iter::repeat("-").take(134).collect::<String>());
        println!("segment accountant:");
        p(vec![
            lat("acquire", &self.accountant_lock),
            lat("hold", &self.accountant_hold),
            lat("next", &self.accountant_next),
            lat("replace", &self.accountant_mark_replace),
            lat("link", &self.accountant_mark_link),
        ]);

        println!("{}", std::iter::repeat("-").take(134).collect::<String>());
        println!("recovery:");
        p(vec![
            lat("start", &self.tree_start),
            lat("advance snapshot", &self.advance_snapshot),
            lat("load SA", &self.start_segment_accountant),
            lat("load PC", &self.start_pagecache),
            lat("snap apply", &self.snapshot_apply),
            lat("segment read", &self.segment_read),
            lat("log message read", &self.read_segment_message),
            sz("segment util", &self.segment_utilization),
        ]);

        #[cfg(feature = "measure_allocs")]
        {
            println!(
                "{}",
                std::iter::repeat("-").take(134).collect::<String>()
            );
            println!("allocation statistics:");
            println!(
                "total allocations: {}",
                measure_allocs::ALLOCATIONS.load(Acquire)
            );
            println!(
                "allocated bytes: {}",
                measure_allocs::ALLOCATED_BYTES.load(Acquire)
            );
        }
    }
}

#[cfg(feature = "no_metrics")]
impl Metrics {
    pub const fn log_reservation_attempted(&self) {}

    pub const fn log_reservation_success(&self) {}

    pub const fn tree_child_split_attempt(&self) {}

    pub const fn tree_child_split_success(&self) {}

    pub const fn tree_parent_split_attempt(&self) {}

    pub const fn tree_parent_split_success(&self) {}

    pub const fn tree_root_split_attempt(&self) {}

    pub const fn tree_root_split_success(&self) {}

    pub const fn tree_looped(&self) {}

    pub const fn print_profile(&self) {}
}
<commit_msg>Improve profile info about retries<commit_after>#![allow(unused_results)]
#![allow(clippy::print_stdout)]

use std::sync::atomic::AtomicUsize;

#[cfg(not(target_arch = "x86_64"))]
use std::time::{Duration, Instant};

#[cfg(feature = "no_metrics")]
use std::marker::PhantomData;

#[cfg(not(feature = "no_metrics"))]
use std::sync::atomic::Ordering::{Acquire, Relaxed};

use crate::Lazy;

use super::*;

/// A metric collector for all pagecache users running in this
/// process.
pub static M: Lazy<Metrics, fn() -> Metrics> = Lazy::new(Metrics::default);

#[allow(clippy::cast_precision_loss)]
pub(crate) fn clock() -> f64 {
    if cfg!(feature = "no_metrics") {
        0.
    } else {
        #[cfg(target_arch = "x86_64")]
        #[allow(unsafe_code)]
        unsafe {
            let mut aux = 0;
            core::arch::x86_64::__rdtscp(&mut aux) as f64
        }

        #[cfg(not(target_arch = "x86_64"))]
        {
            let u = uptime();
            (u.as_secs() * 1_000_000_000) as f64 + f64::from(u.subsec_nanos())
        }
    }
}

// not correct, since it starts counting at the first observance...
#[cfg(not(target_arch = "x86_64"))]
pub(crate) fn uptime() -> Duration {
    static START: Lazy<Instant, fn() -> Instant> = Lazy::new(Instant::now);

    if cfg!(feature = "no_metrics") {
        Duration::new(0, 0)
    } else {
        START.elapsed()
    }
}

/// Measure the duration of an event, and call `Histogram::measure()`.
pub struct Measure<'h> {
    _start: f64,
    #[cfg(not(feature = "no_metrics"))]
    histo: &'h Histogram,
    #[cfg(feature = "no_metrics")]
    _pd: PhantomData<&'h ()>,
}

impl<'h> Measure<'h> {
    /// The time delta from ctor to dtor is recorded in `histo`.
    #[inline]
    pub fn new(_histo: &'h Histogram) -> Measure<'h> {
        Measure {
            #[cfg(feature = "no_metrics")]
            _pd: PhantomData,
            #[cfg(not(feature = "no_metrics"))]
            histo: _histo,
            _start: clock(),
        }
    }
}

impl<'h> Drop for Measure<'h> {
    #[inline]
    fn drop(&mut self) {
        #[cfg(not(feature = "no_metrics"))]
        self.histo.measure(clock() - self._start);
    }
}

#[derive(Default, Debug)]
pub struct Metrics {
    pub advance_snapshot: Histogram,
    pub start_segment_accountant: Histogram,
    pub start_pagecache: Histogram,
    pub snapshot_apply: Histogram,
    pub segment_read: Histogram,
    pub segment_utilization: Histogram,
    pub read_segment_message: Histogram,
    pub tree_set: Histogram,
    pub tree_get: Histogram,
    pub tree_del: Histogram,
    pub tree_cas: Histogram,
    pub tree_scan: Histogram,
    pub tree_reverse_scan: Histogram,
    pub tree_merge: Histogram,
    pub tree_start: Histogram,
    pub tree_traverse: Histogram,
    pub tree_child_split_attempt: CachePadded<AtomicUsize>,
    pub tree_child_split_success: CachePadded<AtomicUsize>,
    pub tree_parent_split_attempt: CachePadded<AtomicUsize>,
    pub tree_parent_split_success: CachePadded<AtomicUsize>,
    pub tree_root_split_attempt: CachePadded<AtomicUsize>,
    pub tree_root_split_success: CachePadded<AtomicUsize>,
    pub get_page: Histogram,
    pub rewrite_page: Histogram,
    pub replace_page: Histogram,
    pub link_page: Histogram,
    pub page_out: Histogram,
    pub pull: Histogram,
    pub serialize: Histogram,
    pub deserialize: Histogram,
    pub compress: Histogram,
    pub decompress: Histogram,
    pub make_stable: Histogram,
    pub assign_offset: Histogram,
    pub assign_spinloop: Histogram,
    pub reserve_lat: Histogram,
    pub reserve_sz: Histogram,
    pub write_to_log: Histogram,
    pub written_bytes: Histogram,
    pub read: Histogram,
    pub tree_loops: CachePadded<AtomicUsize>,
    pub log_reservations: CachePadded<AtomicUsize>,
    pub log_reservation_attempts: CachePadded<AtomicUsize>,
    pub accountant_lock: Histogram,
    pub accountant_hold: Histogram,
    pub accountant_next: Histogram,
    pub accountant_mark_link: Histogram,
    pub accountant_mark_replace: Histogram,
    pub accountant_bump_tip: Histogram,
    #[cfg(feature = "measure_allocs")]
    pub allocations: CachePadded<AtomicUsize>,
    #[cfg(feature = "measure_allocs")]
    pub allocated_bytes: CachePadded<AtomicUsize>,
}

#[cfg(not(feature = "no_metrics"))]
impl Metrics {
    #[inline]
    pub fn tree_looped(&self) {
        self.tree_loops.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn log_reservation_attempted(&self) {
        self.log_reservation_attempts.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn log_reservation_success(&self) {
        self.log_reservations.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn tree_child_split_attempt(&self) {
        self.tree_child_split_attempt.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn tree_child_split_success(&self) {
        self.tree_child_split_success.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn tree_parent_split_attempt(&self) {
        self.tree_parent_split_attempt.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn tree_parent_split_success(&self) {
        self.tree_parent_split_success.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn tree_root_split_attempt(&self) {
        self.tree_root_split_attempt.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn tree_root_split_success(&self) {
        self.tree_root_split_success.fetch_add(1, Relaxed);
    }

    pub fn print_profile(&self) {
        println!(
            "sled profile:\n\
             {0: >17} | {1: >10} | {2: >10} | {3: >10} | {4: >10} | {5: >10} | {6: >10} | {7: >10} | {8: >10} | {9: >10}",
            "op",
            "min (us)",
            "med (us)",
            "90 (us)",
            "99 (us)",
            "99.9 (us)",
            "99.99 (us)",
            "max (us)",
            "count",
            "sum (s)"
        );
        println!("{}", std::iter::repeat("-").take(134).collect::<String>());

        let p = |mut tuples: Vec<(String, _, _, _, _, _, _, _, _, _)>| {
            tuples.sort_by_key(|t| (t.9 * -1. * 1e3) as i64);
            for v in tuples {
                println!(
                    "{0: >17} | {1: >10.1} | {2: >10.1} | {3: >10.1} \
                     | {4: >10.1} | {5: >10.1} | {6: >10.1} | {7: >10.1} \
                     | {8: >10.1} | {9: >10.3}",
                    v.0, v.1, v.2, v.3, v.4, v.5, v.6, v.7, v.8, v.9,
                );
            }
        };

        let lat = |name: &str, histo: &Histogram| {
            (
                name.to_string(),
                histo.percentile(0.) / 1e3,
                histo.percentile(50.) / 1e3,
                histo.percentile(90.) / 1e3,
                histo.percentile(99.) / 1e3,
                histo.percentile(99.9) / 1e3,
                histo.percentile(99.99) / 1e3,
                histo.percentile(100.) / 1e3,
                histo.count(),
                histo.sum() as f64 / 1e9,
            )
        };

        let sz = |name: &str, histo: &Histogram| {
            (
                name.to_string(),
                histo.percentile(0.),
                histo.percentile(50.),
                histo.percentile(90.),
                histo.percentile(99.),
                histo.percentile(99.9),
                histo.percentile(99.99),
                histo.percentile(100.),
                histo.count(),
                histo.sum() as f64,
            )
        };

        println!("tree:");
        p(vec![
            lat("traverse", &self.tree_traverse),
            lat("get", &self.tree_get),
            lat("set", &self.tree_set),
            lat("merge", &self.tree_merge),
            lat("del", &self.tree_del),
            lat("cas", &self.tree_cas),
            lat("scan", &self.tree_scan),
            lat("rev scan", &self.tree_reverse_scan),
        ]);
        let total_loops = self.tree_loops.load(Acquire);
        let total_ops = self.tree_get.count()
            + self.tree_set.count()
            + self.tree_merge.count()
            + self.tree_del.count()
            + self.tree_cas.count()
            + self.tree_scan.count()
            + self.tree_reverse_scan.count();
        let loop_pct = total_loops * 100 / total_ops;
        println!(
            "tree contention loops: {} ({}% retry rate)",
            total_loops, loop_pct
        );
        println!(
            "tree split success rates: child({}/{}) parent({}/{}) root({}/{})",
            self.tree_child_split_success.load(Acquire),
            self.tree_child_split_attempt.load(Acquire),
            self.tree_parent_split_success.load(Acquire),
            self.tree_parent_split_attempt.load(Acquire),
            self.tree_root_split_success.load(Acquire),
            self.tree_root_split_attempt.load(Acquire),
        );

        println!("{}", std::iter::repeat("-").take(134).collect::<String>());
        println!("pagecache:");
        p(vec![
            lat("snapshot", &self.advance_snapshot),
            lat("get", &self.get_page),
            lat("rewrite", &self.rewrite_page),
            lat("replace", &self.replace_page),
            lat("link", &self.link_page),
            lat("pull", &self.pull),
            lat("page_out", &self.page_out),
        ]);

        println!("{}", std::iter::repeat("-").take(134).collect::<String>());
        println!("serialization and compression:");
        p(vec![
            lat("serialize", &self.serialize),
            lat("deserialize", &self.deserialize),
            lat("compress", &self.compress),
            lat("decompress", &self.decompress),
        ]);

        println!("{}", std::iter::repeat("-").take(134).collect::<String>());
        println!("log:");
        p(vec![
            lat("make_stable", &self.make_stable),
            lat("read", &self.read),
            lat("write", &self.write_to_log),
            sz("written bytes", &self.written_bytes),
            lat("assign offset", &self.assign_offset),
            lat("assign spinloop", &self.assign_spinloop),
            lat("reserve lat", &self.reserve_lat),
            sz("reserve sz", &self.reserve_sz),
        ]);
        let log_reservations = self.log_reservations.load(Acquire);
        let log_reservation_attempts =
            self.log_reservation_attempts.load(Acquire);
        let log_reservation_retry_rate =
            (log_reservation_attempts - log_reservations) * 100
                / log_reservations;
        println!("log reservations: {}", log_reservations);
        println!(
            "log res attempts: {}, ({}% retry rate)",
            log_reservation_attempts, log_reservation_retry_rate,
        );

        println!("{}", std::iter::repeat("-").take(134).collect::<String>());
        println!("segment accountant:");
        p(vec![
            lat("acquire", &self.accountant_lock),
            lat("hold", &self.accountant_hold),
            lat("next", &self.accountant_next),
            lat("replace", &self.accountant_mark_replace),
            lat("link", &self.accountant_mark_link),
        ]);

        println!("{}", std::iter::repeat("-").take(134).collect::<String>());
        println!("recovery:");
        p(vec![
            lat("start", &self.tree_start),
            lat("advance snapshot", &self.advance_snapshot),
            lat("load SA", &self.start_segment_accountant),
            lat("load PC", &self.start_pagecache),
            lat("snap apply", &self.snapshot_apply),
            lat("segment read", &self.segment_read),
            lat("log message read", &self.read_segment_message),
            sz("segment util", &self.segment_utilization),
        ]);

        #[cfg(feature = "measure_allocs")]
        {
            println!(
                "{}",
                std::iter::repeat("-").take(134).collect::<String>()
            );
            println!("allocation statistics:");
            println!(
                "total allocations: {}",
                measure_allocs::ALLOCATIONS.load(Acquire)
            );
            println!(
                "allocated bytes: {}",
                measure_allocs::ALLOCATED_BYTES.load(Acquire)
            );
        }
    }
}

#[cfg(feature = "no_metrics")]
impl Metrics {
    pub const fn log_reservation_attempted(&self) {}

    pub const fn log_reservation_success(&self) {}

    pub const fn tree_child_split_attempt(&self) {}

    pub const fn tree_child_split_success(&self) {}

    pub const fn tree_parent_split_attempt(&self) {}

    pub const fn tree_parent_split_success(&self) {}

    pub const fn tree_root_split_attempt(&self) {}

    pub const fn tree_root_split_success(&self) {}

    pub const fn tree_looped(&self) {}

    pub const fn print_profile(&self) {}
}
<|endoftext|>


<commit_before>// Integration with Musashi
extern crate libc;

// Register enum copied from Musashi's m68k_register_t enum
#[repr(C)]
#[derive(Copy, Clone)]
pub enum Register {
	/* Real registers */
	D0,		/* Data registers */
	D1,
	D2,
	D3,
	D4,
	D5,
	D6,
	D7,
	A0,		/* Address registers */
	A1,
	A2,
	A3,
	A4,
	A5,
	A6,
	A7,
	PC,		/* Program Counter */
	SR,		/* Status Register */
	SP,		/* The current Stack Pointer (located in A7) */
	USP,		/* User Stack Pointer */
	ISP,		/* Interrupt Stack Pointer */
	MSP,		/* Master Stack Pointer */
	SFC,		/* Source Function Code */
	DFC,		/* Destination Function Code */
	VBR,		/* Vector Base Register */
	CACR,		/* Cache Control Register */
	CAAR,		/* Cache Address Register */

	/* Assumed registers */
	/* These are cheat registers which emulate the 1-longword prefetch
	 * present in the 68000 and 68010.
	 */
	PrefAddr,	/* Last prefetch address */
	PrefData,	/* Last prefetch data */

	/* Convenience registers */
	PPC,		/* Previous value in the program counter */
	IR,			/* Instruction register */
	CpuType	/* Type of CPU being run */
}

#[repr(C)]
#[derive(Copy, Clone)]
enum CpuType
{
	Invalid,
	M68000,
	M68010,
	M68EC020,
	M68020,
	M68030,		/* Supported by disassembler ONLY */
	M68040		/* Supported by disassembler ONLY */
}

#[link(name = "musashi", kind = "static")]
extern {
	fn m68k_init();
	fn m68k_set_cpu_type(cputype: CpuType);
	fn m68k_pulse_reset();
	fn m68k_execute(num_cycles: i32) -> i32;
	fn m68k_get_reg(context: *mut libc::c_void, regnum: Register) -> u32;
	fn m68k_set_reg(regnum: Register, value: u32);
}

// callbacks from Musashi
#[no_mangle]
pub extern fn cpu_read_byte(address: u32) -> u32 {panic!("rb")}
#[no_mangle]
pub extern fn cpu_read_word(address: u32) -> u32 {panic!("rw")}
#[no_mangle]
pub extern fn cpu_read_long(address: u32) -> u32 {panic!("rl")}
#[no_mangle]
pub extern fn cpu_write_byte(address: u32, value: u32) {panic!("wb")}
#[no_mangle]
pub extern fn cpu_write_word(address: u32, value: u32) {panic!("ww")}
#[no_mangle]
pub extern fn cpu_write_long(address: u32, value: u32) {panic!("wl")}
#[no_mangle]
pub extern fn cpu_pulse_reset() {panic!("pr")}
#[no_mangle]
pub extern fn cpu_long_branch() {panic!("lb")}
#[no_mangle]
pub extern fn cpu_set_fc(fc: u32) {panic!("sf")}
#[no_mangle]
pub extern fn cpu_irq_ack(level: i32) -> i32 {panic!("ia")}

use std::ptr;

pub fn experimental_communication() {
	unsafe {
		m68k_init();
		m68k_set_cpu_type(CpuType::M68000);
		m68k_set_reg(Register::D0, 123);
		println!("D0: {}", m68k_get_reg(ptr::null_mut(), Register::D0));
	}
}

pub fn roundtrip_register(reg: Register, value: u32) -> u32 {
	unsafe {
		m68k_init();
		m68k_set_cpu_type(CpuType::M68000);
		m68k_set_reg(reg, value);
		m68k_get_reg(ptr::null_mut(), reg)
	}
}
#[cfg(test)]
mod tests {
	use super::*;

	#[test]
	fn roundtrip_D0() {
		assert_eq!(256, roundtrip_register(Register::D0, 256));
	}
}<commit_msg>Update Musashi RAM callbacks to use 1K static RAM<commit_after>// Integration with Musashi
extern crate libc;

// Register enum copied from Musashi's m68k_register_t enum
#[repr(C)]
#[derive(Copy, Clone)]
pub enum Register {
	/* Real registers */
	D0,		/* Data registers */
	D1,
	D2,
	D3,
	D4,
	D5,
	D6,
	D7,
	A0,		/* Address registers */
	A1,
	A2,
	A3,
	A4,
	A5,
	A6,
	A7,
	PC,		/* Program Counter */
	SR,		/* Status Register */
	SP,		/* The current Stack Pointer (located in A7) */
	USP,		/* User Stack Pointer */
	ISP,		/* Interrupt Stack Pointer */
	MSP,		/* Master Stack Pointer */
	SFC,		/* Source Function Code */
	DFC,		/* Destination Function Code */
	VBR,		/* Vector Base Register */
	CACR,		/* Cache Control Register */
	CAAR,		/* Cache Address Register */

	/* Assumed registers */
	/* These are cheat registers which emulate the 1-longword prefetch
	 * present in the 68000 and 68010.
	 */
	PrefAddr,	/* Last prefetch address */
	PrefData,	/* Last prefetch data */

	/* Convenience registers */
	PPC,		/* Previous value in the program counter */
	IR,			/* Instruction register */
	CpuType	/* Type of CPU being run */
}

#[repr(C)]
#[derive(Copy, Clone)]
enum CpuType
{
	Invalid,
	M68000,
	M68010,
	M68EC020,
	M68020,
	M68030,		/* Supported by disassembler ONLY */
	M68040		/* Supported by disassembler ONLY */
}

#[link(name = "musashi", kind = "static")]
extern {
	fn m68k_init();
	fn m68k_set_cpu_type(cputype: CpuType);
	fn m68k_pulse_reset();
	fn m68k_execute(num_cycles: i32) -> i32;
	fn m68k_get_reg(context: *mut libc::c_void, regnum: Register) -> u32;
	fn m68k_set_reg(regnum: Register, value: u32);
}

static mut musashi_memory:  [u8; 1024] = [0u8; 1024];

// callbacks from Musashi
#[no_mangle]
pub extern fn cpu_read_byte(address: u32) -> u32 {
	println!("read byte {:08x}", address);
	let address = address as usize;
	unsafe {
		musashi_memory[address] as u32
	}
}
#[no_mangle]
pub extern fn cpu_read_word(address: u32) -> u32 {
	println!("read word {:08x}", address);
	let address = address as usize;
	unsafe {
		((musashi_memory[address+0] as u32) << 8
		|(musashi_memory[address+1] as u32) << 0) as u32
	}
}
#[no_mangle]
pub extern fn cpu_read_long(address: u32) -> u32 {
	println!("read long {:08x}", address);
	let address = address as usize;
	unsafe {
		((musashi_memory[address+0] as u32) << 24
		|(musashi_memory[address+1] as u32) << 16
		|(musashi_memory[address+2] as u32) <<  8
		|(musashi_memory[address+3] as u32) <<  0) as u32
	}
}

#[no_mangle]
pub extern fn cpu_write_byte(address: u32, value: u32) {
	let address = address as usize;
	unsafe {
		musashi_memory[address+0] = (value & 0xff) as u8;
	}
}
#[no_mangle]
pub extern fn cpu_write_word(address: u32, value: u32) {
	let address = address as usize;
	unsafe {
		musashi_memory[address+0] = (value & 0xff00 >> 8) as u8;
		musashi_memory[address+1] = (value & 0x00ff >> 0) as u8;
	}
}
#[no_mangle]
pub extern fn cpu_write_long(address: u32, value: u32) {
	let address = address as usize;
	unsafe {
		musashi_memory[address+0] = (value & 0xff000000 >> 24) as u8;
		musashi_memory[address+1] = (value & 0x00ff0000 >> 16) as u8;
		musashi_memory[address+2] = (value & 0x0000ff00 >>  8) as u8;
		musashi_memory[address+3] = (value & 0x000000ff >>  0) as u8;
	}
}

#[no_mangle]
pub extern fn cpu_pulse_reset() {panic!("pr")}
#[no_mangle]
pub extern fn cpu_long_branch() {println!("lb")}
#[no_mangle]
pub extern fn cpu_set_fc(fc: u32) {println!("set_fc {}", fc)}
#[no_mangle]
pub extern fn cpu_irq_ack(level: i32) -> i32 {panic!("ia")}
#[no_mangle]
pub extern fn cpu_instr_callback() {println!("ic")}

use std::ptr;

pub fn experimental_communication() {
	unsafe {
		m68k_init();
		m68k_set_cpu_type(CpuType::M68000);
		m68k_set_reg(Register::D0, 123);
		println!("D0: {}", m68k_get_reg(ptr::null_mut(), Register::D0));
	}
}

pub fn roundtrip_register(reg: Register, value: u32) -> u32 {
	unsafe {
		m68k_init();
		m68k_set_cpu_type(CpuType::M68000);
		m68k_set_reg(reg, value);
		m68k_get_reg(ptr::null_mut(), reg)
	}
}
#[cfg(test)]
mod tests {
	use super::*;

	#[test]
	fn roundtrip_D0() {
		assert_eq!(256, roundtrip_register(Register::D0, 256));
	}
}<|endoftext|>


<commit_before>use std::ops::Add;

#[derive(Debug)]
struct Year {
    num: i32,
    leap: bool,
}

impl Year {
    fn new(y: i32) -> Self {
        Year {
            num: y,
            leap: Self::judge_leap(y),
        }
    }

    fn judge_leap(y: i32) -> bool {
        if (y % 4) != 0 {
            return false;
        } else if (y % 100) != 0 {
            return true;
        } else if (y % 400) != 0 {
            return false;
        } else {
            true
        }
    }
}

#[derive(Debug)]
struct Month(u8);

impl Month {
    fn new(m: u8) -> Result<Self, String> {
        if m < 1 || m > 12 {
            return Err(String::from("Are you kidding me"));
        }

        Ok(Month(m))
    }
}

#[derive(Debug)]
struct Days(i32);

impl Days {
    fn new(d:i32) ->
}

#[derive(Debug)]
struct Date {
    Y: Year,
    M: Month,
    D: Days,
}

impl Date {
    fn new(y: i32, m: u8, d: i32) -> Result<Self, String> {
        Ok(Date {
            Y: Year::new(y),
            M: Month::new(m)?,
            D: Days::new(d),
        })
    }
}

impl Add<u32> for Date {
    type Output = Self;
    fn add(self, other: u32) -> Self {
        Date::new()
    }
}

fn date_calculation(d: Date, days: i32) -> Date {
    Date::new()
}

fn main() {}
<commit_msg>finish<commit_after>use std::ops::{Add, Sub};

#[derive(Debug, Clone, Copy)]
struct Year {
    num: i32,
    leap: bool,
}

impl Year {
    fn new(y: i32) -> Self {
        Year {
            num: y,
            leap: Self::judge_leap(y),
        }
    }

    fn judge_leap(y: i32) -> bool {
        if (y % 4) != 0 {
            return false;
        } else if (y % 100) != 0 {
            return true;
        } else if (y % 400) != 0 {
            return false;
        } else {
            true
        }
    }

    // fn leap_year_months() -> [i8; 12] {
    //     [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    // }

    // fn normal_year_months() -> [i8; 12] {
    //     [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    // }
}

impl Add<i32> for Year {
    type Output = Self;
    fn add(self, other: i32) -> Self {
        Self::new(self.num + other)
    }
}
impl Sub<i32> for Year {
    type Output = Self;
    fn sub(self, other: i32) -> Self {
        Self::new(self.num - other)
    }
}

#[derive(Debug, Clone, Copy)]
struct Month {
    num: i32,
}

impl Month {
    fn new_with_year(mut m: i32) -> (i32, Self) {
        let mut count = 0;
        while m > 12 {
            count += 1;
            m -= 12
        }
        (count, Month { num: m })
    }

    fn new(m: i32) -> Self {
        Month { num: m }
    }

    fn days_with_year(&self, year: Year) -> Result<u8, String> {
        if self.num < 1 || self.num > 12 {
            return Err("Wrong".to_string());
        }

        match self.num {
            1 | 3 | 5 | 7 | 8 | 10 | 12 => Ok(31),
            4 | 6 | 9 | 11 => Ok(30),
            2 => {
                if year.leap {
                    Ok(29)
                } else {
                    Ok(28)
                }
            }
            _ => Err("Wrong month".to_string()),
        }
    }

    // fn days(&self) -> u8 {
    //     match self.num {
    //         1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
    //         4 | 6 | 9 | 11 => 30,
    //         2 => 28,
    //         _ => 0,
    //     }
    // }
}

impl Add<i32> for Month {
    type Output = Self;
    fn add(self, other: i32) -> Self {
        let temp = (self.num + other) % 12;
        if temp != 0 {
            Self::new(temp)
        } else {
            Self::new(12)
        }
    }
}
impl Sub<i32> for Month {
    type Output = Self;
    fn sub(self, other: i32) -> Self {
        let mut temp = self.num - other;
        while temp < 1 {
            temp += 12
        }
        Self::new(temp)
    }
}

#[derive(Debug)]
struct Days(i32);

impl Days {
    fn new(d: i32) -> Self {
        Days(d)
    }
}

#[derive(Debug)]
struct Date {
    Y: Year,
    M: Month,
    D: Days,
}

impl Date {
    fn new(y: i32, m: i32, d: i32) -> Self {
        let (y_adjust, real_m) = Month::new_with_year(m);
        let mut init = Date {
            Y: Year::new(y) + y_adjust,
            M: real_m,
            D: Days::new(d),
        };

        //Self::days_adjust(&mut init); // same as below
        init.days_adjust();
        init
    }

    fn days_adjust(&mut self) {
        if self.D.0 <= 0 {
            // negative days
            while self.D.0 <= 0 {
                self.M = self.M - 1;
                // cross year
                if self.M.num == 12 {
                    self.Y = self.Y - 1;
                }
                let dd = self.M.days_with_year(self.Y).unwrap();

                self.D.0 += dd as i32;
            }
        } else {
            loop {
                let dd = self.M.days_with_year(self.Y).unwrap();
                if self.D.0 > dd as i32 {
                    self.M = self.M + 1;
                    if self.M.num == 1 {
                        self.Y = self.Y + 1;
                    }
                    self.D.0 -= dd as i32
                } else {
                    break;
                }
            }
        }
    }
}

fn date_calculation(mut d: Date, days: i32) -> Date {
    d.D.0 += days;
    d.days_adjust();
    d
}

fn tests_set_of_month() {
    let case0 = Month::new(2);
    assert!((case0 + 1).num == 3);

    let case1 = Month::new(12);
    assert!((case1 + 1).num == 1);

    assert!((case1 + 2).days_with_year(Year::new(2000)) == Ok(29));

    let case2 = Month::new_with_year(14);
    assert!(case2.0 == 1);
    assert!(case2.1.num == 2);

    let case3 = Month::new_with_year(24);
    assert!(case3.0 == 1);
    assert!(case3.1.num == 12);

    let case4 = Month::new(2);
    assert!((case4 - 14).num == 12);
}

fn tests_set_of_date() {
    let case0 = Date::new(2000, 3, 0);
    assert!(case0.M.num == 2);
    assert!(case0.D.0 == 29);

    let case1 = Date::new(2000, 1, -1);
    assert!(case1.Y.num == 1999);
    assert!(case1.M.num == 12);
    assert!(case1.D.0 == 30);

    let case2 = Date::new(2000, 1, 32);
    assert!(case2.M.num == 2);
    assert!(case2.D.0 == 1);

    let case3 = Date::new(1999, 12, 31 + 365);
    assert!(case3.M.num == 12);
    assert!(case3.D.0 == 30);
}

fn main() {
    tests_set_of_month();
    tests_set_of_date();

    let case0 = Date::new(2015, 2, 15);
    let result0 = date_calculation(case0, 7);
    assert!(result0.Y.num == 2015);
    assert!(result0.M.num == 2);
    assert!(result0.D.0 == 22);

    let case0 = Date::new(2015, 2, 15);
    let result0 = date_calculation(case0, -7);
    assert!(result0.Y.num == 2015);
    assert!(result0.M.num == 2);
    assert!(result0.D.0 == 8);

    let case0 = Date::new(2015, 2, 15);
    let result0 = date_calculation(case0, -16);
    assert!(result0.Y.num == 2015);
    assert!(result0.M.num == 1);
    assert!(result0.D.0 == 30);
}
<|endoftext|>