<commit_before>use ::std;
use ::for_other_imageflow_crates::preludes::external_without_std::*;
use ::ffi;
use ::job::Job;
use ::{FlowErr,FlowError, Result, JsonResponse};
use io::IoProxy;
use std::any::Any;
use ::imageflow_types::collections::AddRemoveSet;
use ::ffi::ImageflowJsonResponse;

pub struct Context {
    //version: u64, (so different context types can be differentiated)
    c_ctx: *mut ffi::ImageflowContext,
    jobs: AddRemoveSet<Job>,
    io_proxies: AddRemoveSet<IoProxy>,
    error: RefCell<ErrorBuffer>,
}

#[derive(Copy,Clone,Debug)]
pub struct ErrorBuffer{
    c_ctx: *mut ffi::ImageflowContext,
}
impl Context {

    pub fn create() -> Result<Box<Context>>{
        Context::abi_create_boxed()
    }

    /// Used by abi; should not panic
    pub fn abi_create_boxed() -> Result<Box<Context>> {
        std::panic::catch_unwind(|| {
            // Upgrade backtraces
            // Disable backtraces for debugging across the FFI boundary
            //imageflow_helpers::debug::upgrade_panic_hook_once_if_backtraces_wanted();

            let inner = unsafe { ffi::flow_context_create() };
            if inner.is_null() {
                Err(FlowError::Oom)
            } else {
                Ok(Box::new(Context {
                    c_ctx: inner,
                    error: RefCell::new(ErrorBuffer {c_ctx: inner}),
                    jobs: AddRemoveSet::with_capacity(2),
                    io_proxies: AddRemoveSet::with_capacity(2)
                }))
            }
        }).unwrap_or(Err(FlowError::Oom))
    }

    /// Used by abi; should not panic
    pub fn abi_begin_terminate(&mut self) -> bool {
        self.jobs.mut_clear();
        self.io_proxies.mut_clear();
        unsafe {
            ffi::flow_context_begin_terminate(self.c_ctx)
        }
    }

    pub fn error_mut(&self) -> RefMut<ErrorBuffer>{
        self.error.borrow_mut()
    }
    pub fn error(&self) -> Ref<ErrorBuffer>{
        self.error.try_borrow().expect("Another scope has mutably borrowed the ErrorBuffer; readonly access failed.")
    }

    pub unsafe fn unsafe_c_context_pointer(&self) -> *mut ffi::ImageflowContext{
        self.c_ctx
    }

    pub fn message(&mut self, method: &str, json: &[u8]) -> Result<JsonResponse> {
        ::context_methods::CONTEXT_ROUTER.invoke(self, method, json)
    }

    pub fn create_job(&self) -> RefMut<Job>{
        self.jobs.add_mut(Job::internal_use_only_create(self))
    }

    pub fn create_io_proxy(&self) -> RefMut<IoProxy>{
        self.io_proxies.add_mut(IoProxy::internal_use_only_create(self))
    }

    pub fn abi_try_remove_job(&self, job: *const Job) -> bool{
        self.jobs.try_remove(job).unwrap_or(false)
    }

    pub fn flow_c(&self) -> *mut ffi::ImageflowContext{
        self.c_ctx
    }

    pub fn c_error(&self) -> Option<FlowError>{
        self.error().get_error_copy()
    }

    pub fn get_proxy_mut_by_pointer(&self, proxy: *const IoProxy) -> Result<RefMut<IoProxy>> {
        // TODO: fix the many issues in this method. Runtime borrowing errors, etc.
        self.io_proxies.try_get_reference_mut(proxy).map_err(|e| FlowError::ErrNotImpl).and_then(|v| v.ok_or(FlowError::ErrNotImpl))
    }

    pub fn get_proxy_mut(&self, uuid: ::uuid::Uuid) -> Result<RefMut<IoProxy>> {
        // TODO: fix the many issues in this method. Runtime borrowing errors, etc.
        Ok(self.io_proxies.iter_mut().filter(|r| r.is_ok()).map(|r| r.unwrap()).find(|c| c.uuid == uuid).ok_or(FlowError::ErrNotImpl).unwrap())
    }

    pub fn create_io_from_copy_of_slice<'a, 'b>(&'a self, bytes: &'b [u8]) -> Result<RefMut<'a, IoProxy>> {
        IoProxy::copy_slice(self, bytes)
    }
    pub fn create_io_from_slice<'a>(&'a self, bytes: &'a [u8]) -> Result<RefMut<IoProxy>> {
        IoProxy::read_slice(self, bytes)
    }

    pub fn create_io_from_filename(&self, path: &str, dir: ::IoDirection) -> Result<RefMut<IoProxy>> {
        IoProxy::file(self, path, dir)
    }
    pub fn create_io_from_filename_with_mode(&self, path: &str, mode: ::IoMode) -> Result<RefMut<IoProxy>> {
        IoProxy::file_with_mode(self, path, mode)
    }

    pub fn create_io_output_buffer(&self) -> Result<RefMut<IoProxy>> {
        IoProxy::create_output_buffer(self)
    }

    pub fn create_abi_json_response(&mut self,
                                    json_bytes: std::borrow::Cow<[u8]>,
                                    status_code: i64)
                                    -> *const ImageflowJsonResponse {
        unsafe {
            let sizeof_struct = std::mem::size_of::<ImageflowJsonResponse>();

            let pointer = ::ffi::flow_context_calloc(self.flow_c(),
                                                     1,
                                                     sizeof_struct + json_bytes.len(),
                                                     ptr::null(),
                                                     self.flow_c() as *mut libc::c_void,
                                                     ptr::null(),
                                                     0) as *mut u8;
            // Return null on OOM
            if pointer.is_null() {
                return ::std::ptr::null();
            }
            let pointer_to_final_buffer =
            pointer.offset(sizeof_struct as isize) as *mut libc::uint8_t;
            let imageflow_response = &mut (*(pointer as *mut ImageflowJsonResponse));
            imageflow_response.buffer_utf8_no_nulls = pointer_to_final_buffer;
            imageflow_response.buffer_size = json_bytes.len();
            imageflow_response.status_code = status_code;

            let mut out_json_bytes = std::slice::from_raw_parts_mut(pointer_to_final_buffer,
                                                                    json_bytes.len());

            out_json_bytes.clone_from_slice(&json_bytes);

            imageflow_response as *const ImageflowJsonResponse
        }
    }

    pub fn destroy_allowing_panics(mut self) {
        if !self.abi_begin_terminate(){
            self.c_error().unwrap().panic_with("Error during context shutdown");
        }
    }

    pub fn abi_destroy(mut self) -> bool{
        self.jobs.mut_clear();
        true
    }

}

type ErrorCode = i32;
impl ErrorBuffer{

    /// Prints the error messages and stacktrace to the given buffer in UTF-8 form; writes a null
    /// character to terminate the string, and *ALSO* returns the number of bytes written.
    ///
    ///
    /// Happy(ish) path: Returns the length of the error message written to the buffer.
    /// Sad path: Returns -1 if slice was too small or buffer was nullptr.
    /// full_file_path, if true, will display the directory associated with the files in each stack frame.
//    pub fn write_to_slice_as_c_str(&self, slice: &mut [u8], prefer_full_paths: bool) -> i64{
//        // ffi::flow_context_error_and_stacktrace(context, buffer as *mut u8, buffer_length, full_file_path)
//    }
//
//
    /// Used by abi; should not panic
    pub fn abi_has_error(&self) -> bool{
        unsafe{
            ffi::flow_context_has_error(self.c_ctx)
        }
    }
    /// Used by abi; should not panic
    pub fn abi_clear_error(&mut self){
        unsafe {
            ffi::flow_context_clear_error(self.c_ctx)
        }
    }
    /// Used by abi; should not panic
    pub fn abi_error_code(&self) -> ErrorCode{
        unsafe {
            ffi::flow_context_error_reason(self.c_ctx)
        }
    }

    /// Used by abi; should not panic
    pub fn abi_abort_and_print_on_error(&self) -> bool{
        unsafe {
            ffi::flow_context_print_and_exit_if_err(self.c_ctx)
        }
    }

    /// # Expectations
    ///
    /// * Strings `message` and `function_name`, and `filename` should be null-terminated UTF-8 strings.
    /// * The lifetime of `message` is expected to exceed the duration of this function call.
    /// * The lifetime of `filename` and `function_name` (if provided), is expected to match or exceed the lifetime of `context`.
    /// * You may provide a null value for `filename` or `function_name`, but for the love of puppies,
    /// don't provide a dangling or invalid pointer, that will segfault... a long time later.
    ///
    /// # Caveats
    ///
    /// * You cannot raise a second error until the first has been cleared with
    ///  `imageflow_context_clear_error`. You'll be ignored, as will future
    ///   `imageflow_add_to_callstack` invocations.
    /// * If you provide an error code of zero (why?!), a different error code will be provided.
    pub fn abi_raise_error_c_style(&mut self,
                                   error_code: ErrorCode,
                                   message: Option<&CStr>,
                                   filename: Option<&'static CStr>,
                                   line: Option<i32>,
                                   function_name: Option<&'static CStr>)
                                   -> bool {
        unsafe {
            ffi::flow_context_raise_error(self.c_ctx, error_code,
                                          message.map(|cstr| cstr.as_ptr()).unwrap_or(ptr::null()),
                                          filename.map(|cstr| cstr.as_ptr()).unwrap_or(ptr::null()),
                                          line.unwrap_or(-1),
                                          function_name.map(|cstr| cstr.as_ptr()).unwrap_or(ptr::null()))
        }
    }

    pub fn abi_raise_panic(&mut self,
                                   e: &Any)-> bool{
        //TODO: this does not handle if CString fails to allocate

        let mut message = None;
        let null_byte_message = || {CString::new("panic string contained a null byte").ok()};
        if let Some(str) = e.downcast_ref::<String>(){
            message = Some(CString::new(str.as_bytes()))
        }
        if let Some(str) = e.downcast_ref::<&str>(){
            message = Some(CString::new(str.as_bytes()))
        }

        let unwrapped_message = message.and_then(|r| r.or_else(|_| CString::new("panic string contained a null byte")).ok());

        eprintln!("{:?}", unwrapped_message);

        self.abi_raise_error_c_style(31, unwrapped_message.as_ref().map(CString::as_c_str), None, None, None )
    }

    ///
    /// Adds the given UTF-8 filename, line number, and function name to the call stack.
    ///
    /// Returns `true` if add was successful.
    ///
    /// # Will fail and return false if...
    ///
    /// * You haven't raised an error
    /// * You tried to raise a second error without clearing the first one. Call will be ignored.
    /// * You've exceeded the capacity of the call stack (which, at one point, was 14). But this
    ///   category of failure is acceptable.
    pub fn abi_add_to_callstack_c_style(&mut self, filename: Option<&'static CStr>,
                                        line: Option<i32>,
                                        function_name: Option<&'static CStr>)
                                        -> bool {

        unsafe {
            ffi::flow_context_add_to_callstack(self.c_ctx,
                                               filename.map(|cstr| cstr.as_ptr()).unwrap_or(ptr::null()),
                                               line.unwrap_or(-1),
                                               function_name.map(|cstr| cstr.as_ptr()).unwrap_or(ptr::null()))
        }
    }

    pub fn assert_ok(&self) {
        if let Some(e) = self.get_error_copy() {
            e.panic_time();
        }
    }

    pub fn get_error_copy(&self) -> Option<FlowError> {
        if self.abi_has_error(){
            match self.abi_error_code(){
                0 => panic!("Inconsistent errors"),
                10 => Some(FlowError::Oom),
                _ => Some(FlowError::Err(unsafe { ErrorBuffer::get_flow_err(self.c_ctx) })),
            }
        }else{
            None
        }
    }
    unsafe fn get_flow_err(c: *mut ::ffi::ImageflowContext) -> FlowErr {

        let code = ::ffi::flow_context_error_reason(c);
        let mut buf = vec![0u8; 2048];

        let chars_written =
        ::ffi::flow_context_error_and_stacktrace(c, buf.as_mut_ptr(), buf.len(), false);

        if chars_written < 0 {
            panic!("Error msg doesn't fit in 2kb");
        } else {
            buf.resize(chars_written as usize, 0u8);
        }

        FlowErr {
            code: code,
            message_and_stack: String::from_utf8(buf).unwrap(),
        }

    }

}
impl Drop for Context {
    /// Used by abi; should not panic
    fn drop(&mut self) {
        if !self.c_ctx.is_null() {
            unsafe {
                ffi::flow_context_destroy(self.c_ctx);
            }
        }
        self.c_ctx = ptr::null_mut();
        self.error.borrow_mut().c_ctx = ptr::null_mut();
    }
}
<commit_msg>Add Context.error().c_error() -> FlowErr<commit_after>use ::std;
use ::for_other_imageflow_crates::preludes::external_without_std::*;
use ::ffi;
use ::job::Job;
use ::{FlowErr,FlowError, Result, JsonResponse};
use io::IoProxy;
use std::any::Any;
use ::imageflow_types::collections::AddRemoveSet;
use ::ffi::ImageflowJsonResponse;

pub struct Context {
    //version: u64, (so different context types can be differentiated)
    c_ctx: *mut ffi::ImageflowContext,
    jobs: AddRemoveSet<Job>,
    io_proxies: AddRemoveSet<IoProxy>,
    error: RefCell<ErrorBuffer>,
}

#[derive(Copy,Clone,Debug)]
pub struct ErrorBuffer{
    c_ctx: *mut ffi::ImageflowContext,
}
impl Context {

    pub fn create() -> Result<Box<Context>>{
        Context::abi_create_boxed()
    }

    /// Used by abi; should not panic
    pub fn abi_create_boxed() -> Result<Box<Context>> {
        std::panic::catch_unwind(|| {
            // Upgrade backtraces
            // Disable backtraces for debugging across the FFI boundary
            //imageflow_helpers::debug::upgrade_panic_hook_once_if_backtraces_wanted();

            let inner = unsafe { ffi::flow_context_create() };
            if inner.is_null() {
                Err(FlowError::Oom)
            } else {
                Ok(Box::new(Context {
                    c_ctx: inner,
                    error: RefCell::new(ErrorBuffer {c_ctx: inner}),
                    jobs: AddRemoveSet::with_capacity(2),
                    io_proxies: AddRemoveSet::with_capacity(2)
                }))
            }
        }).unwrap_or(Err(FlowError::Oom))
    }

    /// Used by abi; should not panic
    pub fn abi_begin_terminate(&mut self) -> bool {
        self.jobs.mut_clear();
        self.io_proxies.mut_clear();
        unsafe {
            ffi::flow_context_begin_terminate(self.c_ctx)
        }
    }

    pub fn error_mut(&self) -> RefMut<ErrorBuffer>{
        self.error.borrow_mut()
    }
    pub fn error(&self) -> Ref<ErrorBuffer>{
        self.error.try_borrow().expect("Another scope has mutably borrowed the ErrorBuffer; readonly access failed.")
    }

    pub unsafe fn unsafe_c_context_pointer(&self) -> *mut ffi::ImageflowContext{
        self.c_ctx
    }

    pub fn message(&mut self, method: &str, json: &[u8]) -> Result<JsonResponse> {
        ::context_methods::CONTEXT_ROUTER.invoke(self, method, json)
    }

    pub fn create_job(&self) -> RefMut<Job>{
        self.jobs.add_mut(Job::internal_use_only_create(self))
    }

    pub fn create_io_proxy(&self) -> RefMut<IoProxy>{
        self.io_proxies.add_mut(IoProxy::internal_use_only_create(self))
    }

    pub fn abi_try_remove_job(&self, job: *const Job) -> bool{
        self.jobs.try_remove(job).unwrap_or(false)
    }

    pub fn flow_c(&self) -> *mut ffi::ImageflowContext{
        self.c_ctx
    }

    pub fn c_error(&self) -> Option<FlowError>{
        self.error().get_error_copy()
    }

    pub fn get_proxy_mut_by_pointer(&self, proxy: *const IoProxy) -> Result<RefMut<IoProxy>> {
        // TODO: fix the many issues in this method. Runtime borrowing errors, etc.
        self.io_proxies.try_get_reference_mut(proxy).map_err(|e| FlowError::ErrNotImpl).and_then(|v| v.ok_or(FlowError::ErrNotImpl))
    }

    pub fn get_proxy_mut(&self, uuid: ::uuid::Uuid) -> Result<RefMut<IoProxy>> {
        // TODO: fix the many issues in this method. Runtime borrowing errors, etc.
        Ok(self.io_proxies.iter_mut().filter(|r| r.is_ok()).map(|r| r.unwrap()).find(|c| c.uuid == uuid).ok_or(FlowError::ErrNotImpl).unwrap())
    }

    pub fn create_io_from_copy_of_slice<'a, 'b>(&'a self, bytes: &'b [u8]) -> Result<RefMut<'a, IoProxy>> {
        IoProxy::copy_slice(self, bytes)
    }
    pub fn create_io_from_slice<'a>(&'a self, bytes: &'a [u8]) -> Result<RefMut<IoProxy>> {
        IoProxy::read_slice(self, bytes)
    }

    pub fn create_io_from_filename(&self, path: &str, dir: ::IoDirection) -> Result<RefMut<IoProxy>> {
        IoProxy::file(self, path, dir)
    }
    pub fn create_io_from_filename_with_mode(&self, path: &str, mode: ::IoMode) -> Result<RefMut<IoProxy>> {
        IoProxy::file_with_mode(self, path, mode)
    }

    pub fn create_io_output_buffer(&self) -> Result<RefMut<IoProxy>> {
        IoProxy::create_output_buffer(self)
    }

    pub fn create_abi_json_response(&mut self,
                                    json_bytes: std::borrow::Cow<[u8]>,
                                    status_code: i64)
                                    -> *const ImageflowJsonResponse {
        unsafe {
            let sizeof_struct = std::mem::size_of::<ImageflowJsonResponse>();

            let pointer = ::ffi::flow_context_calloc(self.flow_c(),
                                                     1,
                                                     sizeof_struct + json_bytes.len(),
                                                     ptr::null(),
                                                     self.flow_c() as *mut libc::c_void,
                                                     ptr::null(),
                                                     0) as *mut u8;
            // Return null on OOM
            if pointer.is_null() {
                return ::std::ptr::null();
            }
            let pointer_to_final_buffer =
            pointer.offset(sizeof_struct as isize) as *mut libc::uint8_t;
            let imageflow_response = &mut (*(pointer as *mut ImageflowJsonResponse));
            imageflow_response.buffer_utf8_no_nulls = pointer_to_final_buffer;
            imageflow_response.buffer_size = json_bytes.len();
            imageflow_response.status_code = status_code;

            let mut out_json_bytes = std::slice::from_raw_parts_mut(pointer_to_final_buffer,
                                                                    json_bytes.len());

            out_json_bytes.clone_from_slice(&json_bytes);

            imageflow_response as *const ImageflowJsonResponse
        }
    }

    pub fn destroy_allowing_panics(mut self) {
        if !self.abi_begin_terminate(){
            self.c_error().unwrap().panic_with("Error during context shutdown");
        }
    }

    pub fn abi_destroy(mut self) -> bool{
        self.jobs.mut_clear();
        true
    }

}

type ErrorCode = i32;
impl ErrorBuffer{

    /// Prints the error messages and stacktrace to the given buffer in UTF-8 form; writes a null
    /// character to terminate the string, and *ALSO* returns the number of bytes written.
    ///
    ///
    /// Happy(ish) path: Returns the length of the error message written to the buffer.
    /// Sad path: Returns -1 if slice was too small or buffer was nullptr.
    /// full_file_path, if true, will display the directory associated with the files in each stack frame.
//    pub fn write_to_slice_as_c_str(&self, slice: &mut [u8], prefer_full_paths: bool) -> i64{
//        // ffi::flow_context_error_and_stacktrace(context, buffer as *mut u8, buffer_length, full_file_path)
//    }
//
//
    /// Used by abi; should not panic
    pub fn abi_has_error(&self) -> bool{
        unsafe{
            ffi::flow_context_has_error(self.c_ctx)
        }
    }
    /// Used by abi; should not panic
    pub fn abi_clear_error(&mut self){
        unsafe {
            ffi::flow_context_clear_error(self.c_ctx)
        }
    }
    /// Used by abi; should not panic
    pub fn abi_error_code(&self) -> ErrorCode{
        unsafe {
            ffi::flow_context_error_reason(self.c_ctx)
        }
    }

    /// Used by abi; should not panic
    pub fn abi_abort_and_print_on_error(&self) -> bool{
        unsafe {
            ffi::flow_context_print_and_exit_if_err(self.c_ctx)
        }
    }

    /// # Expectations
    ///
    /// * Strings `message` and `function_name`, and `filename` should be null-terminated UTF-8 strings.
    /// * The lifetime of `message` is expected to exceed the duration of this function call.
    /// * The lifetime of `filename` and `function_name` (if provided), is expected to match or exceed the lifetime of `context`.
    /// * You may provide a null value for `filename` or `function_name`, but for the love of puppies,
    /// don't provide a dangling or invalid pointer, that will segfault... a long time later.
    ///
    /// # Caveats
    ///
    /// * You cannot raise a second error until the first has been cleared with
    ///  `imageflow_context_clear_error`. You'll be ignored, as will future
    ///   `imageflow_add_to_callstack` invocations.
    /// * If you provide an error code of zero (why?!), a different error code will be provided.
    pub fn abi_raise_error_c_style(&mut self,
                                   error_code: ErrorCode,
                                   message: Option<&CStr>,
                                   filename: Option<&'static CStr>,
                                   line: Option<i32>,
                                   function_name: Option<&'static CStr>)
                                   -> bool {
        unsafe {
            ffi::flow_context_raise_error(self.c_ctx, error_code,
                                          message.map(|cstr| cstr.as_ptr()).unwrap_or(ptr::null()),
                                          filename.map(|cstr| cstr.as_ptr()).unwrap_or(ptr::null()),
                                          line.unwrap_or(-1),
                                          function_name.map(|cstr| cstr.as_ptr()).unwrap_or(ptr::null()))
        }
    }

    pub fn abi_raise_panic(&mut self,
                                   e: &Any)-> bool{
        //TODO: this does not handle if CString fails to allocate

        let mut message = None;
        let null_byte_message = || {CString::new("panic string contained a null byte").ok()};
        if let Some(str) = e.downcast_ref::<String>(){
            message = Some(CString::new(str.as_bytes()))
        }
        if let Some(str) = e.downcast_ref::<&str>(){
            message = Some(CString::new(str.as_bytes()))
        }

        let unwrapped_message = message.and_then(|r| r.or_else(|_| CString::new("panic string contained a null byte")).ok());

        eprintln!("{:?}", unwrapped_message);

        self.abi_raise_error_c_style(31, unwrapped_message.as_ref().map(CString::as_c_str), None, None, None )
    }

    ///
    /// Adds the given UTF-8 filename, line number, and function name to the call stack.
    ///
    /// Returns `true` if add was successful.
    ///
    /// # Will fail and return false if...
    ///
    /// * You haven't raised an error
    /// * You tried to raise a second error without clearing the first one. Call will be ignored.
    /// * You've exceeded the capacity of the call stack (which, at one point, was 14). But this
    ///   category of failure is acceptable.
    pub fn abi_add_to_callstack_c_style(&mut self, filename: Option<&'static CStr>,
                                        line: Option<i32>,
                                        function_name: Option<&'static CStr>)
                                        -> bool {

        unsafe {
            ffi::flow_context_add_to_callstack(self.c_ctx,
                                               filename.map(|cstr| cstr.as_ptr()).unwrap_or(ptr::null()),
                                               line.unwrap_or(-1),
                                               function_name.map(|cstr| cstr.as_ptr()).unwrap_or(ptr::null()))
        }
    }

    pub fn assert_ok(&self) {
        if let Some(e) = self.get_error_copy() {
            e.panic_time();
        }
    }

    pub fn get_error_copy(&self) -> Option<FlowError> {
        if self.abi_has_error(){
            match self.abi_error_code(){
                0 => panic!("Inconsistent errors"),
                10 => Some(FlowError::Oom),
                _ => Some(FlowError::Err(unsafe { ErrorBuffer::get_flow_err(self.c_ctx) })),
            }
        }else{
            None
        }
    }

    // Returns error code 90 if there is no error or there is an inconsistency between error APIs
    pub fn c_error(&self) -> FlowErr {
        if self.abi_has_error(){
            match self.abi_error_code(){
                0 => FlowErr{ message_and_stack: String::new(), code: 90 },
                10 => FlowErr{ message_and_stack: String::new(), code: 10 },
                _ => unsafe { ErrorBuffer::get_flow_err(self.c_ctx) },
            }
        }else{
            FlowErr{ message_and_stack: String::new(), code: 90 }
        }
    }
    unsafe fn get_flow_err(c: *mut ::ffi::ImageflowContext) -> FlowErr {

        let code = ::ffi::flow_context_error_reason(c);
        let mut buf = vec![0u8; 2048];

        let chars_written =
        ::ffi::flow_context_error_and_stacktrace(c, buf.as_mut_ptr(), buf.len(), false);

        if chars_written < 0 {
            //TODO: Retry until it fits
            panic!("Error msg doesn't fit in 2kb");
        } else {
            buf.resize(chars_written as usize, 0u8);
        }

        FlowErr {
            code: code,
            message_and_stack: String::from_utf8(buf).unwrap(),
        }

    }

}
impl Drop for Context {
    /// Used by abi; should not panic
    fn drop(&mut self) {
        if !self.c_ctx.is_null() {
            unsafe {
                ffi::flow_context_destroy(self.c_ctx);
            }
        }
        self.c_ctx = ptr::null_mut();
        self.error.borrow_mut().c_ctx = ptr::null_mut();
    }
}
<|endoftext|>


<commit_before>use std::cmp::max;

// This struct is used to store our items that we want in our knap-sack.
//
// Show is for displaying the fields.
// allow(dead_code) removes a dead code warning when the name of the struct is not
// used (as in this case happens in the tests)
struct Want<'a> {
    #[allow(dead_code)]
    name: &'a str,
    weight: uint,
    value: uint
}

// Global, immutable allocation of our items. This is so we can reference
// this in multiple functions.
static items : &'static [Want<'static>] = &[
    Want {name: "map",                    weight: 9,   value: 150},
    Want {name: "compass",                weight: 13,  value: 35},
    Want {name: "water",                  weight: 153, value: 200},
    Want {name: "sandwich",               weight: 50,  value: 160},
    Want {name: "glucose",                weight: 15,  value: 60},
    Want {name: "tin",                    weight: 68,  value: 45},
    Want {name: "banana",                 weight: 27,  value: 60},
    Want {name: "apple",                  weight: 39,  value: 40},
    Want {name: "cheese",                 weight: 23,  value: 30},
    Want {name: "beer",                   weight: 52,  value: 10},
    Want {name: "suntancream",            weight: 11,  value: 70},
    Want {name: "camera",                 weight: 32,  value: 30},
    Want {name: "T-shirt",                weight: 24,  value: 15},
    Want {name: "trousers",               weight: 48,  value: 10},
    Want {name: "umbrella",               weight: 73,  value: 40},
    Want {name: "waterproof trousers",    weight: 42,  value: 70},
    Want {name: "waterproof overclothes", weight: 43,  value: 75},
    Want {name: "note-case",              weight: 22,  value: 80},
    Want {name: "sunglasses",             weight: 7,   value: 20},
    Want {name: "towel",                  weight: 18,  value: 12},
    Want {name: "socks",                  weight: 4,   value: 50},
    Want {name: "book",                   weight: 30,  value: 10}
];

// This is a bottom-up dynamic programming solution to the 0-1 knap-sack problem.
//      maximize value
//      subject to weights <= max_weight
fn knap_01_dp<'a>(xs: &[Want<'a>], max_weight: uint) -> Vec<Want<'a>> {

    // Save this value, so we don't have to make repeated calls.
    let xs_len = xs.len();

    // Imagine we wrote a recursive function(item, max_weight) that returns a
    // uint corresponding to the maximum cumulative value by considering a
    // subset of items such that the combined weight <= max_weight.
    //
    // fn best_value(item: uint, max_weight: uint) -> uint{
    //     if item == 0 {
    //         return 0;
    //     }
    //     if xs[item - 1].weight > max_weight {
    //         return best_value(item - 1, max_weight, xs);
    //     }
    //     return max(best_value(item - 1, max_weight, xs),
    //                best_value(item - 1, max_weight - xs[item - 1].weight, xs)
    //                + xs[item - 1].value);
    //     }
    //
    // best_value(xs_len, max_weight) is equal to the maximum value that we
    // can add to the bag.
    //
    // The problem with using this function is that it performs redudant
    // calculations.
    //
    // The dynamic programming solution is to precompute all of the values we
    // need and put them into a 2D array.
    //
    // In a similar vein, the top-down solution would be to memoize the
    // function then compute the results on demand.

    let zero_vec = Vec::from_elem(max_weight + 1, 0 as uint);
    let mut best_value = Vec::from_elem(xs_len + 1, zero_vec);

    // loop over the items
    for i in range(0, xs_len) {
        // loop over the weights
        for w in range(1, max_weight + 1) {
            // do we have room in our knapsack?
            if xs[i].weight > w {
                // if we don't, then we'll say that the value doesn't change
                // when considering this item
                *best_value.get_mut(i + 1).get_mut(w) = best_value[i][w].clone();
            } else {
                // if we do, then we have to see if the value we gain by adding
                // the item, given the weight, is better than not adding the item
                *best_value.get_mut(i + 1).get_mut(w) =
                    max(best_value[i][w].clone(),
                        best_value[i][w - xs[i].weight] + xs[i].value);
            }
        }
    }

    // a variable representing the weight left in the bag
    let mut left_weight = max_weight.clone();

    // a possibly over-allocated dynamically sized vector to push results to
    let mut result = Vec::with_capacity(xs_len);

    // we built up the solution space through a forward pass over the data,
    // now we have to traverse backwards to get the solution
    for i in range(1, xs_len+1).rev() {
        // We can check if an item should be added to the knap-sack by comparing
        // best_value with and without this item. If best_value added this
        // item then so should we.
        if best_value[i][left_weight] != best_value[i - 1][left_weight] {
            result.push(xs[i - 1]);
            // we remove the weight of the object from the remaining weight
            // we can add to the bag
            left_weight -= xs[i - 1].weight;
        }
    }

    return result;
}

#[cfg(not(test))]
fn main () {
    let xs = knap_01_dp(items, 400);

    // Print the items. We have to reverse the order because we solved the
    // problem backward.
    for i in xs.iter().rev() {
        println!("Item: {}, Weight: {}, Value: {}", i.name, i.weight, i.value);
    }

    // Print the sum of weights.
    let weights = xs.iter().fold(0, |a, &b| a + b.weight);
    println!("Total Weight: {}", weights);

    // Print the sum of the values.
    let values = xs.iter().fold(0, |a, &b| a + b.value);
    println!("Total Value: {}", values);

}

#[test]
fn test_dp_results() {
    let dp_results = knap_01_dp(items, 400);
    let dp_weights= dp_results.iter().fold(0, |a, &b| a + b.weight);
    let dp_values = dp_results.iter().fold(0, |a, &b| a + b.value);
    assert_eq!(dp_weights, 396);
    assert_eq!(dp_values, 1030);
}
<commit_msg>add url to knapsack 0-1<commit_after>// http://rosettacode.org/wiki/Knapsack_problem/0-1

use std::cmp::max;

// This struct is used to store our items that we want in our knap-sack.
//
// Show is for displaying the fields.
// allow(dead_code) removes a dead code warning when the name of the struct is not
// used (as in this case happens in the tests)
struct Want<'a> {
    #[allow(dead_code)]
    name: &'a str,
    weight: uint,
    value: uint
}

// Global, immutable allocation of our items. This is so we can reference
// this in multiple functions.
static items : &'static [Want<'static>] = &[
    Want {name: "map",                    weight: 9,   value: 150},
    Want {name: "compass",                weight: 13,  value: 35},
    Want {name: "water",                  weight: 153, value: 200},
    Want {name: "sandwich",               weight: 50,  value: 160},
    Want {name: "glucose",                weight: 15,  value: 60},
    Want {name: "tin",                    weight: 68,  value: 45},
    Want {name: "banana",                 weight: 27,  value: 60},
    Want {name: "apple",                  weight: 39,  value: 40},
    Want {name: "cheese",                 weight: 23,  value: 30},
    Want {name: "beer",                   weight: 52,  value: 10},
    Want {name: "suntancream",            weight: 11,  value: 70},
    Want {name: "camera",                 weight: 32,  value: 30},
    Want {name: "T-shirt",                weight: 24,  value: 15},
    Want {name: "trousers",               weight: 48,  value: 10},
    Want {name: "umbrella",               weight: 73,  value: 40},
    Want {name: "waterproof trousers",    weight: 42,  value: 70},
    Want {name: "waterproof overclothes", weight: 43,  value: 75},
    Want {name: "note-case",              weight: 22,  value: 80},
    Want {name: "sunglasses",             weight: 7,   value: 20},
    Want {name: "towel",                  weight: 18,  value: 12},
    Want {name: "socks",                  weight: 4,   value: 50},
    Want {name: "book",                   weight: 30,  value: 10}
];

// This is a bottom-up dynamic programming solution to the 0-1 knap-sack problem.
//      maximize value
//      subject to weights <= max_weight
fn knap_01_dp<'a>(xs: &[Want<'a>], max_weight: uint) -> Vec<Want<'a>> {

    // Save this value, so we don't have to make repeated calls.
    let xs_len = xs.len();

    // Imagine we wrote a recursive function(item, max_weight) that returns a
    // uint corresponding to the maximum cumulative value by considering a
    // subset of items such that the combined weight <= max_weight.
    //
    // fn best_value(item: uint, max_weight: uint) -> uint{
    //     if item == 0 {
    //         return 0;
    //     }
    //     if xs[item - 1].weight > max_weight {
    //         return best_value(item - 1, max_weight, xs);
    //     }
    //     return max(best_value(item - 1, max_weight, xs),
    //                best_value(item - 1, max_weight - xs[item - 1].weight, xs)
    //                + xs[item - 1].value);
    //     }
    //
    // best_value(xs_len, max_weight) is equal to the maximum value that we
    // can add to the bag.
    //
    // The problem with using this function is that it performs redudant
    // calculations.
    //
    // The dynamic programming solution is to precompute all of the values we
    // need and put them into a 2D array.
    //
    // In a similar vein, the top-down solution would be to memoize the
    // function then compute the results on demand.

    let zero_vec = Vec::from_elem(max_weight + 1, 0 as uint);
    let mut best_value = Vec::from_elem(xs_len + 1, zero_vec);

    // loop over the items
    for i in range(0, xs_len) {
        // loop over the weights
        for w in range(1, max_weight + 1) {
            // do we have room in our knapsack?
            if xs[i].weight > w {
                // if we don't, then we'll say that the value doesn't change
                // when considering this item
                *best_value.get_mut(i + 1).get_mut(w) = best_value[i][w].clone();
            } else {
                // if we do, then we have to see if the value we gain by adding
                // the item, given the weight, is better than not adding the item
                *best_value.get_mut(i + 1).get_mut(w) =
                    max(best_value[i][w].clone(),
                        best_value[i][w - xs[i].weight] + xs[i].value);
            }
        }
    }

    // a variable representing the weight left in the bag
    let mut left_weight = max_weight.clone();

    // a possibly over-allocated dynamically sized vector to push results to
    let mut result = Vec::with_capacity(xs_len);

    // we built up the solution space through a forward pass over the data,
    // now we have to traverse backwards to get the solution
    for i in range(1, xs_len+1).rev() {
        // We can check if an item should be added to the knap-sack by comparing
        // best_value with and without this item. If best_value added this
        // item then so should we.
        if best_value[i][left_weight] != best_value[i - 1][left_weight] {
            result.push(xs[i - 1]);
            // we remove the weight of the object from the remaining weight
            // we can add to the bag
            left_weight -= xs[i - 1].weight;
        }
    }

    return result;
}

#[cfg(not(test))]
fn main () {
    let xs = knap_01_dp(items, 400);

    // Print the items. We have to reverse the order because we solved the
    // problem backward.
    for i in xs.iter().rev() {
        println!("Item: {}, Weight: {}, Value: {}", i.name, i.weight, i.value);
    }

    // Print the sum of weights.
    let weights = xs.iter().fold(0, |a, &b| a + b.weight);
    println!("Total Weight: {}", weights);

    // Print the sum of the values.
    let values = xs.iter().fold(0, |a, &b| a + b.value);
    println!("Total Value: {}", values);

}

#[test]
fn test_dp_results() {
    let dp_results = knap_01_dp(items, 400);
    let dp_weights= dp_results.iter().fold(0, |a, &b| a + b.weight);
    let dp_values = dp_results.iter().fold(0, |a, &b| a + b.value);
    assert_eq!(dp_weights, 396);
    assert_eq!(dp_values, 1030);
}
<|endoftext|>


<commit_before>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2013, 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use gobject as ffi;
use gtype;
use gtype::GType;
use refcount::Refcount;
use types::gpointer;
use wrap::Wrapper;

use std::marker::MarkerTrait;
use std::mem::transmute;

pub unsafe trait ObjectType : MarkerTrait {
    fn get_type() -> GType;
}

impl<T> Refcount for T where T: ObjectType + Wrapper {

    unsafe fn inc_ref(&self) {
        ffi::g_object_ref(self.as_mut_ptr() as gpointer);
    }

    unsafe fn dec_ref(&self) {
        ffi::g_object_unref(self.as_mut_ptr() as gpointer);
    }
}

pub trait Upcast<T> {
    fn upcast(&self) -> &T;
}

impl<T> Upcast<T> for T {

    #[inline]
    fn upcast(&self) -> &T { self }
}

pub fn type_of<T>() -> GType where T: ObjectType {
    <T as ObjectType>::get_type()
}

pub fn is_instance_of<T, U>(object: &T) -> bool
    where T: ObjectType, U: ObjectType
{
    gtype::check_instance_is_a(object, type_of::<U>())
}

fn assert_instance_of<T, U>(object: &T)
    where T: ObjectType, U: ObjectType
{
    let dest_type = type_of::<U>();
    assert!(gtype::check_instance_is_a(object, dest_type),
            "invalid cast to type {}", dest_type.name())
}

pub fn cast<T, U>(source: &T) -> &U
    where T: ObjectType, U: ObjectType
{
    assert_instance_of::<T, U>(source);
    unsafe { transmute(source) }
}
<commit_msg>Remove the usage of MarkerTrait<commit_after>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2013, 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use gobject as ffi;
use gtype;
use gtype::GType;
use refcount::Refcount;
use types::gpointer;
use wrap::Wrapper;

use std::mem::transmute;

pub unsafe trait ObjectType {
    fn get_type() -> GType;
}

impl<T> Refcount for T where T: ObjectType + Wrapper {

    unsafe fn inc_ref(&self) {
        ffi::g_object_ref(self.as_mut_ptr() as gpointer);
    }

    unsafe fn dec_ref(&self) {
        ffi::g_object_unref(self.as_mut_ptr() as gpointer);
    }
}

pub trait Upcast<T> {
    fn upcast(&self) -> &T;
}

impl<T> Upcast<T> for T {

    #[inline]
    fn upcast(&self) -> &T { self }
}

pub fn type_of<T>() -> GType where T: ObjectType {
    <T as ObjectType>::get_type()
}

pub fn is_instance_of<T, U>(object: &T) -> bool
    where T: ObjectType, U: ObjectType
{
    gtype::check_instance_is_a(object, type_of::<U>())
}

fn assert_instance_of<T, U>(object: &T)
    where T: ObjectType, U: ObjectType
{
    let dest_type = type_of::<U>();
    assert!(gtype::check_instance_is_a(object, dest_type),
            "invalid cast to type {}", dest_type.name())
}

pub fn cast<T, U>(source: &T) -> &U
    where T: ObjectType, U: ObjectType
{
    assert_instance_of::<T, U>(source);
    unsafe { transmute(source) }
}
<|endoftext|>


<commit_before>use nom::{
    self,
    bytes::streaming::{tag, take},
    character::streaming::digit1,
    sequence::tuple,
    IResult,
};

use std::str;

// ----- number -----

// number          = 1*DIGIT
//                    ; Unsigned 32-bit integer
//                    ; (0 <= n < 4,294,967,296)
named!(pub number<u32>, flat_map!(digit1, parse_to!(u32)));

// same as `number` but 64-bit
named!(pub number_64<u64>, flat_map!(digit1, parse_to!(u64)));

// ----- string -----

// string = quoted / literal
named!(pub string<&[u8]>, alt!(quoted | literal));

// string bytes as as utf8
named!(pub string_utf8<&str>, map_res!(string, str::from_utf8));

// quoted = DQUOTE *QUOTED-CHAR DQUOTE
named!(pub quoted<&[u8]>, delimited!(
    char!('"'),
    quoted_data,
    char!('"')
));

// quoted bytes as as utf8
named!(pub quoted_utf8<&str>, map_res!(quoted, str::from_utf8));

// QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / "\" quoted-specials
pub fn quoted_data(i: &[u8]) -> IResult<&[u8], &[u8]> {
    // Ideally this should use nom's `escaped` macro, but it suffers from broken
    // type inference unless compiled with the verbose-errors feature enabled.
    let mut escape = false;
    let mut len = 0;
    for c in i {
        if *c == b'"' && !escape {
            break;
        }
        len += 1;
        if *c == b'\\' && !escape {
            escape = true
        } else if escape {
            escape = false;
        }
    }
    Ok((&i[len..], &i[..len]))
}

// quoted-specials = DQUOTE / "\"
pub fn is_quoted_specials(c: u8) -> bool {
    c == b'"' || c == b'\\'
}

/// literal = "{" number "}" CRLF *CHAR8
///            ; Number represents the number of CHAR8s
pub fn literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
    let parser = tuple((tag(b"{"), number, tag(b"}"), tag("\r\n")));

    let (remaining, (_, count, _, _)) = parser(input)?;

    let (remaining, data) = take(count)(remaining)?;

    if !data.iter().all(|byte| is_char8(*byte)) {
        // FIXME: what ErrorKind should this have?
        return Err(nom::Err::Error((remaining, nom::error::ErrorKind::Verify)));
    }

    Ok((remaining, data))
}

/// CHAR8 = %x01-ff ; any OCTET except NUL, %x00
pub fn is_char8(i: u8) -> bool {
    i != 0
}

// ----- astring ----- atom (roughly) or string

// astring = 1*ASTRING-CHAR / string
named!(pub astring<&[u8]>, alt!(
    take_while1!(is_astring_char) |
    string
));

// astring bytes as as utf8
named!(pub astring_utf8<&str>, map_res!(astring, str::from_utf8));

// ASTRING-CHAR = ATOM-CHAR / resp-specials
pub fn is_astring_char(c: u8) -> bool {
    is_atom_char(c) || is_resp_specials(c)
}

// ATOM-CHAR = <any CHAR except atom-specials>
pub fn is_atom_char(c: u8) -> bool {
    is_char(c) && !is_atom_specials(c)
}

// atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards / quoted-specials / resp-specials
pub fn is_atom_specials(c: u8) -> bool {
    c == b'('
        || c == b')'
        || c == b'{'
        || c == b' '
        || c < 32
        || is_list_wildcards(c)
        || is_quoted_specials(c)
        || is_resp_specials(c)
}

// resp-specials = "]"
pub fn is_resp_specials(c: u8) -> bool {
    c == b']'
}

// atom = 1*ATOM-CHAR
named!(pub atom<&str>, map_res!(take_while1!(is_atom_char),
    str::from_utf8
));

// ----- nstring ----- nil or string

// nstring = string / nil
named!(pub nstring<Option<&[u8]>>, alt!(
    map!(nil, |_| None) |
    map!(string, |s| Some(s))
));

// nstring bytes as utf8
named!(pub nstring_utf8<Option<&str>>, alt!(
    map!(nil, |_| None) |
    map!(string_utf8, |s| Some(s))
));

// nil = "NIL"
named!(pub nil, tag_no_case!("NIL"));

// ----- text -----

// text = 1*TEXT-CHAR
named!(pub text<&str>, map_res!(take_while!(is_text_char),
    str::from_utf8
));

// TEXT-CHAR = <any CHAR except CR and LF>
pub fn is_text_char(c: u8) -> bool {
    is_char(c) && c != b'\r' && c != b'\n'
}

// CHAR = %x01-7F
//          ; any 7-bit US-ASCII character,
//          ;  excluding NUL
// From RFC5234
pub fn is_char(c: u8) -> bool {
    match c {
        0x01..=0x7F => true,
        _ => false,
    }
}

// ----- others -----

// list-wildcards = "%" / "*"
pub fn is_list_wildcards(c: u8) -> bool {
    c == b'%' || c == b'*'
}

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

    #[test]
    fn test_string_literal() {
        match string(b"{3}\r\nXYZ") {
            Ok((_, value)) => {
                assert_eq!(value, b"XYZ");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }

    #[test]
    fn test_astring() {
        match astring(b"text ") {
            Ok((_, value)) => {
                assert_eq!(value, b"text");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }
}
<commit_msg>fixed typos<commit_after>use nom::{
    self,
    bytes::streaming::{tag, take},
    character::streaming::digit1,
    sequence::tuple,
    IResult,
};

use std::str;

// ----- number -----

// number          = 1*DIGIT
//                    ; Unsigned 32-bit integer
//                    ; (0 <= n < 4,294,967,296)
named!(pub number<u32>, flat_map!(digit1, parse_to!(u32)));

// same as `number` but 64-bit
named!(pub number_64<u64>, flat_map!(digit1, parse_to!(u64)));

// ----- string -----

// string = quoted / literal
named!(pub string<&[u8]>, alt!(quoted | literal));

// string bytes as utf8
named!(pub string_utf8<&str>, map_res!(string, str::from_utf8));

// quoted = DQUOTE *QUOTED-CHAR DQUOTE
named!(pub quoted<&[u8]>, delimited!(
    char!('"'),
    quoted_data,
    char!('"')
));

// quoted bytes as utf8
named!(pub quoted_utf8<&str>, map_res!(quoted, str::from_utf8));

// QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / "\" quoted-specials
pub fn quoted_data(i: &[u8]) -> IResult<&[u8], &[u8]> {
    // Ideally this should use nom's `escaped` macro, but it suffers from broken
    // type inference unless compiled with the verbose-errors feature enabled.
    let mut escape = false;
    let mut len = 0;
    for c in i {
        if *c == b'"' && !escape {
            break;
        }
        len += 1;
        if *c == b'\\' && !escape {
            escape = true
        } else if escape {
            escape = false;
        }
    }
    Ok((&i[len..], &i[..len]))
}

// quoted-specials = DQUOTE / "\"
pub fn is_quoted_specials(c: u8) -> bool {
    c == b'"' || c == b'\\'
}

/// literal = "{" number "}" CRLF *CHAR8
///            ; Number represents the number of CHAR8s
pub fn literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
    let parser = tuple((tag(b"{"), number, tag(b"}"), tag("\r\n")));

    let (remaining, (_, count, _, _)) = parser(input)?;

    let (remaining, data) = take(count)(remaining)?;

    if !data.iter().all(|byte| is_char8(*byte)) {
        // FIXME: what ErrorKind should this have?
        return Err(nom::Err::Error((remaining, nom::error::ErrorKind::Verify)));
    }

    Ok((remaining, data))
}

/// CHAR8 = %x01-ff ; any OCTET except NUL, %x00
pub fn is_char8(i: u8) -> bool {
    i != 0
}

// ----- astring ----- atom (roughly) or string

// astring = 1*ASTRING-CHAR / string
named!(pub astring<&[u8]>, alt!(
    take_while1!(is_astring_char) |
    string
));

// astring bytes as utf8
named!(pub astring_utf8<&str>, map_res!(astring, str::from_utf8));

// ASTRING-CHAR = ATOM-CHAR / resp-specials
pub fn is_astring_char(c: u8) -> bool {
    is_atom_char(c) || is_resp_specials(c)
}

// ATOM-CHAR = <any CHAR except atom-specials>
pub fn is_atom_char(c: u8) -> bool {
    is_char(c) && !is_atom_specials(c)
}

// atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards / quoted-specials / resp-specials
pub fn is_atom_specials(c: u8) -> bool {
    c == b'('
        || c == b')'
        || c == b'{'
        || c == b' '
        || c < 32
        || is_list_wildcards(c)
        || is_quoted_specials(c)
        || is_resp_specials(c)
}

// resp-specials = "]"
pub fn is_resp_specials(c: u8) -> bool {
    c == b']'
}

// atom = 1*ATOM-CHAR
named!(pub atom<&str>, map_res!(take_while1!(is_atom_char),
    str::from_utf8
));

// ----- nstring ----- nil or string

// nstring = string / nil
named!(pub nstring<Option<&[u8]>>, alt!(
    map!(nil, |_| None) |
    map!(string, |s| Some(s))
));

// nstring bytes as utf8
named!(pub nstring_utf8<Option<&str>>, alt!(
    map!(nil, |_| None) |
    map!(string_utf8, |s| Some(s))
));

// nil = "NIL"
named!(pub nil, tag_no_case!("NIL"));

// ----- text -----

// text = 1*TEXT-CHAR
named!(pub text<&str>, map_res!(take_while!(is_text_char),
    str::from_utf8
));

// TEXT-CHAR = <any CHAR except CR and LF>
pub fn is_text_char(c: u8) -> bool {
    is_char(c) && c != b'\r' && c != b'\n'
}

// CHAR = %x01-7F
//          ; any 7-bit US-ASCII character,
//          ;  excluding NUL
// From RFC5234
pub fn is_char(c: u8) -> bool {
    match c {
        0x01..=0x7F => true,
        _ => false,
    }
}

// ----- others -----

// list-wildcards = "%" / "*"
pub fn is_list_wildcards(c: u8) -> bool {
    c == b'%' || c == b'*'
}

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

    #[test]
    fn test_string_literal() {
        match string(b"{3}\r\nXYZ") {
            Ok((_, value)) => {
                assert_eq!(value, b"XYZ");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }

    #[test]
    fn test_astring() {
        match astring(b"text ") {
            Ok((_, value)) => {
                assert_eq!(value, b"text");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }
}
<|endoftext|>


<commit_before>use rss::ChannelBuilder;
use rss::Item;
use std::fs;

mod decoration;
mod markdown;
mod paths;
mod printing;

fn main() {
    printing::heading("Creating website build directory.");

    printing::subheading("Cleaning the build directory.");
    paths::remove_dir(&paths::build());

    printing::subheading("Generating the build directory.");
    paths::create_dir(&paths::build());
    generate_pages();
}

fn generate_pages() {
    let mut markdown_links_to_routes = Vec::new();
    let mut rss_items = Vec::new();

    match fs::read_dir(&paths::pages()) {
        Ok(markdown_files) => {
            for markdown_file in markdown_files {
                let markdown_file = match &markdown_file {
                    Ok(markdown_file) => markdown_file.path(),
                    Err(error) => panic!("There was a problem: {:?}", error),
                };

                let markdown_file_contents = match fs::read_to_string(&markdown_file) {
                    Ok(contents) => contents,
                    Err(error) => panic!("There was a problem: {:?}", error),
                };

                let route = &paths::file_stem(markdown_file);

                let mut lines = markdown_file_contents.lines();

                let title = match lines.next() {
                    Some(title) => title.replace("# ", ""),
                    None => panic!("Cannot find a title in {}.", &route),
                };

                match lines.next() {
                    Some(_) => (),
                    None => panic!(
                        "Cannot find a break between title and description in {}.",
                        &route
                    ),
                };

                let description = match lines.next() {
                    Some(description) => description.replace("_", "").replace(".", ""),
                    None => panic!("Cannot find a description in {}.", &route),
                };

                paths::create_dir(&paths::build().join(route));
                paths::create_file(
                    &paths::build().join(route).join("index.html"),
                    &markdown::to_html(&markdown_file_contents, &title, &description),
                );

                let is_post = route != "about" && route != "resume" && route != "projects";

                if is_post {
                    markdown_links_to_routes.push(
                        format!("- [{}: {}](/{}/).", &title, &description, &route).to_string(),
                    );

                    let mut rss_item = Item::default();
                    rss_item.set_link(format!("https://trevordmiller.com/{}/", &route));
                    rss_item.set_title(title);
                    rss_item.set_description(format!("{}.", description));
                    rss_item.set_author("Trevor D. Miller".to_string());
                    rss_items.push(rss_item);
                }
            }
        }
        Err(error) => panic!("There was a problem: {:?}", error),
    };

    let markdown_index_contents = format!(
        "# Posts\n_My posts about software development._\n{}",
        markdown_links_to_routes.join("\n")
    );

    paths::create_file(
        &paths::build().join("index.html"),
        &markdown::to_html(
            &markdown_index_contents,
            "Posts",
            "My posts about software development.",
        ),
    );

    let channel = match ChannelBuilder::default()
        .language("en-us".to_string())
        .link("https://trevordmiller.com")
        .title("trevordmiller")
        .description("trevordmiller RSS feed.")
        .items(rss_items)
        .build()
    {
        Ok(channel) => channel.to_string(),
        Err(error) => panic!("There was a problem: {:?}", error),
    };

    paths::create_file(&paths::build().join("rss.xml"), &channel);
}
<commit_msg>Keep period punctuation consistent<commit_after>use rss::ChannelBuilder;
use rss::Item;
use std::fs;

mod decoration;
mod markdown;
mod paths;
mod printing;

fn main() {
    printing::heading("Creating website build directory.");

    printing::subheading("Cleaning the build directory.");
    paths::remove_dir(&paths::build());

    printing::subheading("Generating the build directory.");
    paths::create_dir(&paths::build());
    generate_pages();
}

fn generate_pages() {
    let mut markdown_links_to_routes = Vec::new();
    let mut rss_items = Vec::new();

    match fs::read_dir(&paths::pages()) {
        Ok(markdown_files) => {
            for markdown_file in markdown_files {
                let markdown_file = match &markdown_file {
                    Ok(markdown_file) => markdown_file.path(),
                    Err(error) => panic!("There was a problem: {:?}", error),
                };

                let markdown_file_contents = match fs::read_to_string(&markdown_file) {
                    Ok(contents) => contents,
                    Err(error) => panic!("There was a problem: {:?}", error),
                };

                let route = &paths::file_stem(markdown_file);

                let mut lines = markdown_file_contents.lines();

                let title = match lines.next() {
                    Some(title) => title.replace("# ", ""),
                    None => panic!("Cannot find a title in {}.", &route),
                };

                match lines.next() {
                    Some(_) => (),
                    None => panic!(
                        "Cannot find a break between title and description in {}.",
                        &route
                    ),
                };

                let description = match lines.next() {
                    Some(description) => description.replace("_", "").replace(".", ""),
                    None => panic!("Cannot find a description in {}.", &route),
                };

                paths::create_dir(&paths::build().join(route));
                paths::create_file(
                    &paths::build().join(route).join("index.html"),
                    &markdown::to_html(&markdown_file_contents, &title, &format!("{}.", &description).to_string()),
                );

                let is_post = route != "about" && route != "resume" && route != "projects";

                if is_post {
                    markdown_links_to_routes.push(
                        format!("- [{}: {}](/{}/).", &title, &description, &route).to_string(),
                    );

                    let mut rss_item = Item::default();
                    rss_item.set_link(format!("https://trevordmiller.com/{}/", &route));
                    rss_item.set_title(title);
                    rss_item.set_description(format!("{}.", description));
                    rss_item.set_author("Trevor D. Miller".to_string());
                    rss_items.push(rss_item);
                }
            }
        }
        Err(error) => panic!("There was a problem: {:?}", error),
    };

    let markdown_index_contents = format!(
        "# Posts\n_My posts about software development._\n{}",
        markdown_links_to_routes.join("\n")
    );

    paths::create_file(
        &paths::build().join("index.html"),
        &markdown::to_html(
            &markdown_index_contents,
            "Posts",
            "My posts about software development.",
        ),
    );

    let channel = match ChannelBuilder::default()
        .language("en-us".to_string())
        .link("https://trevordmiller.com")
        .title("trevordmiller")
        .description("trevordmiller RSS feed.")
        .items(rss_items)
        .build()
    {
        Ok(channel) => channel.to_string(),
        Err(error) => panic!("There was a problem: {:?}", error),
    };

    paths::create_file(&paths::build().join("rss.xml"), &channel);
}
<|endoftext|>


<commit_before>use super::{bindings, constants, error, SSLAlertLevel};
use super::ssl_config::SSLConfig;

use std::marker::PhantomData;
use std::ffi::CStr;
use std::io;
use std::mem::transmute;
use std::slice;

use mbed::error::CError;

pub struct SSLContext<'a> {
    inner: bindings::mbedtls_ssl_context,
    phantom: PhantomData<&'a ()>,

}

impl <'a> SSLContext<'a> {
    pub fn new() -> Self {
        let mut ctx = SSLContext {
            inner: bindings::mbedtls_ssl_context::default(),
            phantom: PhantomData,
        };
        unsafe {
            bindings::mbedtls_ssl_init(&mut ctx.inner);
        }

        ctx
    }

    pub fn setup(&mut self, config: &'a SSLConfig) -> Result<(), error::SSLAllocError> {
        let r = unsafe {
            bindings::mbedtls_ssl_setup(
                &mut self.inner,
                config.inner(),
            )
        };

        error::SSLAllocError::from_code(r).map(|_| ())
    }

    /// Set hostname for ServerName TLS extension (client-side only)
    pub fn set_hostname(&mut self, hostname: &CStr) -> Result<(), error::SSLAllocError> {
        let r = unsafe {
            bindings::mbedtls_ssl_set_hostname(
                &mut self.inner,
                hostname.as_ptr(),
            )
        };

        error::SSLAllocError::from_code(r).map(|_| ())
    }

    /// Set the underlying BIO callbacks for write and read.
    pub fn set_bio_async<E : CError, IO : Read<E> + Write<E>>(&mut self, io: &'a mut IO) {
        unsafe {
            bindings::mbedtls_ssl_set_bio(
                &mut self.inner,
                io as *mut _ as *mut ::libc::c_void,
                Some(wrap_bio_send_callback::<E, IO>),
                Some(wrap_bio_read_callback::<E, IO>),
                None,
            );
        };
    }

    /// Perform the SSL handshake.
    ///
    /// Note:
    /// If this function returns non-zero, then the ssl context becomes unusable, and you should
    /// either free it or call mbedtls_ssl_session_reset() on it before re-using it. If DTLS is in
    /// use, then you may choose to handle MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED specially for
    /// logging purposes, but you still need to reset/free the context.
    pub fn handshake(&mut self) -> Result<(), error::SSLError> {
        let r = unsafe {
            bindings::mbedtls_ssl_handshake(
                &mut self.inner,
            )
        };

        error::SSLError::from_code(r).map(|_| ())
    }

    /// Try to write exactly 'len' application data bytes.
    ///
    /// Warning: This function will do partial writes in some cases. If the return value is
    /// non-negative but less than length, the function must be called again with updated
    /// arguments: buf + ret, len - ret (if ret is the return value) until it returns a value
    /// equal to the last 'len' argument.
    ///
    /// Note:
    /// When this function returns MBEDTLS_ERR_SSL_WANT_WRITE/READ, it must be called later with
    /// the same arguments, until it returns a positive value.
    pub fn write(&mut self, buf: &[u8]) -> Result<usize, error::SSLError> {
        let r = unsafe {
            bindings::mbedtls_ssl_write(
                &mut self.inner,
                buf.as_ptr(), buf.len() as u64
            )
        };

        error::SSLError::from_code(r).map(|i| i as usize)
    }

    /// Read at most 'len' application data bytes.
    ///
    /// Returns: the number of bytes read, or 0 for EOF, or a negative error code.
    pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, error::SSLError> {
        let r = unsafe {
            bindings::mbedtls_ssl_read(
                &mut self.inner,
                buf.as_mut_ptr(), buf.len() as u64
            )
        };

        error::SSLError::from_code(r).map(|i| i as usize)
    }

    /// Notify the peer that the connection is being closed.
    pub fn close_notify(&mut self) -> Result<(), error::SSLError> {
        let r = unsafe {
            bindings::mbedtls_ssl_close_notify(&mut self.inner)
        };

        error::SSLError::from_code(r).map(|_| ())
    }

    /// Reset an already initialized SSL context for re-use while retaining application-set
    /// variables, function pointers and data.
    pub fn session_reset(&mut self) -> Result<(), error::SSLError> {
        let r = unsafe {
            bindings::mbedtls_ssl_session_reset(&mut self.inner)
        };

        error::SSLError::from_code(r).map(|_| ())
    }

    /// Initiate an SSL renegotiation on the running connection.
    ///
    /// Client: perform the renegotiation right now.
    /// Server: request renegotiation, which will be performed during the next call to
    /// read() if honored by client.
    pub fn renegotiate(&mut self) -> Result<(), error::SSLError> {
        let r = unsafe {
            bindings::mbedtls_ssl_renegotiate(&mut self.inner)
        };

        error::SSLError::from_code(r).map(|_| ())
    }

    /// Send an alert message
    pub fn send_alert_message(&mut self, level: SSLAlertLevel, message: u8)
    -> Result<(), error::SSLError> {
        let level_char = match level {
            SSLAlertLevel::Warning => constants::MBEDTLS_SSL_ALERT_LEVEL_WARNING,
            SSLAlertLevel::Fatal => constants::MBEDTLS_SSL_ALERT_LEVEL_FATAL,
        };
        let r = unsafe {
            bindings::mbedtls_ssl_send_alert_message(
                &mut self.inner, level_char, message
            )
        };

        error::SSLError::from_code(r).map(|_| ())
    }

    /// Set client's transport-level identification info.
    ///
    /// (Server only. DTLS only.)
    ///
    /// This is usually the IP address (and port), but could be anything identify the client
    /// depending on the underlying network stack. Used for HelloVerifyRequest with DTLS. This is
    /// not used to route the actual packets.
    ///
    /// Returns: SSLError::BadInputData if used on client, SSLError::AllocFailed if out of memory.
    pub fn set_client_transport_id(&mut self, info: &[u8]) -> Result<(), error::SSLError> {
        let r = unsafe {
            bindings::mbedtls_ssl_set_client_transport_id(
                &mut self.inner,
                info.as_ptr(), info.len() as u64
            )
        };

        error::SSLError::from_code(r).map(|_| ())
    }

    /// Get the name of the negotiated Application Layer Protocol.
    ///
    /// This function should be called after the handshake is completed.
    pub fn get_alpn_protocol(&self) -> Option<&'a CStr> {
        unsafe {
            let ret = bindings::mbedtls_ssl_get_alpn_protocol(&self.inner);

            if !ret.is_null() {
                Some(CStr::from_ptr(ret))
            } else {
                None
            }
        }
    }
}

impl <'a> Drop for SSLContext<'a> {
    fn drop(&mut self) {
        unsafe {
            bindings::mbedtls_ssl_free(&mut self.inner);
        }
    }
}

pub trait Write<E: CError> {
    fn write(&mut self, buf: &[u8]) -> Result<usize, E>;
}

pub trait Read<E: CError> {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, E>;
}

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

impl <T: io::Read> Read<io::Error> for T {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
        self.read(buf)
    }
}

impl CError for io::Error {
    fn to_int(&self) -> i32 {
        match self.kind() {
            io::ErrorKind::WouldBlock => -1,
            _ => -1,
        }
    }
}

extern "C" fn wrap_bio_send_callback<E: CError, IO : Read<E> + Write<E>>(
    target: *mut ::libc::c_void,
    output: *const ::libc::c_uchar, len: ::libc::size_t
) -> ::libc::c_int {
    unsafe {
        let f : *mut IO = transmute(target);
        let r = (*f).write(slice::from_raw_parts(output, len as usize));
        match r {
            Ok(i) => i as i32,
            Err(e) => e.to_int(),
        }
    }
}

extern "C" fn wrap_bio_read_callback<E : CError, IO : Read<E> + Write<E>>(
    target: *mut ::libc::c_void,
    output: *mut ::libc::c_uchar, len: ::libc::size_t
) -> ::libc::c_int {
    unsafe {
        let f : *mut IO = transmute(target);
        let r = (*f).read(slice::from_raw_parts_mut(output, len as usize));
        match r {
            Ok(i) => i as i32,
            Err(e) => e.to_int(),
        }
    }
}
<commit_msg>Add more things<commit_after>use super::{bindings, constants, error, SSLAlertLevel};
use super::ssl_config::SSLConfig;

use std::marker::PhantomData;
use std::ffi::CStr;
use std::io;
use std::mem::transmute;
use std::slice;

use mbed::error::CError;

pub struct SSLContext<'a> {
    inner: bindings::mbedtls_ssl_context,
    phantom: PhantomData<&'a ()>,

}

impl <'a> SSLContext<'a> {
    pub fn new() -> Self {
        let mut ctx = SSLContext {
            inner: bindings::mbedtls_ssl_context::default(),
            phantom: PhantomData,
        };
        unsafe {
            bindings::mbedtls_ssl_init(&mut ctx.inner);
        }

        ctx
    }

    pub fn setup(&mut self, config: &'a SSLConfig) -> Result<(), error::SSLAllocError> {
        let r = unsafe {
            bindings::mbedtls_ssl_setup(
                &mut self.inner,
                config.inner(),
            )
        };

        error::SSLAllocError::from_code(r).map(|_| ())
    }

    /// Set hostname for ServerName TLS extension (client-side only)
    pub fn set_hostname(&mut self, hostname: &CStr) -> Result<(), error::SSLAllocError> {
        let r = unsafe {
            bindings::mbedtls_ssl_set_hostname(
                &mut self.inner,
                hostname.as_ptr(),
            )
        };

        error::SSLAllocError::from_code(r).map(|_| ())
    }

    /// Set the underlying BIO callbacks for write and read.
    pub fn set_bio_async<E : CError, IO : Read<E> + Write<E>>(&mut self, io: &'a mut IO) {
        unsafe {
            bindings::mbedtls_ssl_set_bio(
                &mut self.inner,
                io as *mut _ as *mut ::libc::c_void,
                Some(wrap_bio_send_callback::<E, IO>),
                Some(wrap_bio_read_callback::<E, IO>),
                None,
            );
        };
    }

    /// Perform the SSL handshake.
    ///
    /// Note:
    /// If this function returns non-zero, then the ssl context becomes unusable, and you should
    /// either free it or call mbedtls_ssl_session_reset() on it before re-using it. If DTLS is in
    /// use, then you may choose to handle MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED specially for
    /// logging purposes, but you still need to reset/free the context.
    pub fn handshake(&mut self) -> Result<(), error::SSLError> {
        let r = unsafe {
            bindings::mbedtls_ssl_handshake(
                &mut self.inner,
            )
        };

        error::SSLError::from_code(r).map(|_| ())
    }

    /// Try to write exactly 'len' application data bytes.
    ///
    /// Warning: This function will do partial writes in some cases. If the return value is
    /// non-negative but less than length, the function must be called again with updated
    /// arguments: buf + ret, len - ret (if ret is the return value) until it returns a value
    /// equal to the last 'len' argument.
    ///
    /// Note:
    /// When this function returns MBEDTLS_ERR_SSL_WANT_WRITE/READ, it must be called later with
    /// the same arguments, until it returns a positive value.
    pub fn write(&mut self, buf: &[u8]) -> Result<usize, error::SSLError> {
        let r = unsafe {
            bindings::mbedtls_ssl_write(
                &mut self.inner,
                buf.as_ptr(), buf.len() as u64
            )
        };

        error::SSLError::from_code(r).map(|i| i as usize)
    }

    /// Read at most 'len' application data bytes.
    ///
    /// Returns: the number of bytes read, or 0 for EOF, or a negative error code.
    pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, error::SSLError> {
        let r = unsafe {
            bindings::mbedtls_ssl_read(
                &mut self.inner,
                buf.as_mut_ptr(), buf.len() as u64
            )
        };

        error::SSLError::from_code(r).map(|i| i as usize)
    }

    /// Notify the peer that the connection is being closed.
    pub fn close_notify(&mut self) -> Result<(), error::SSLError> {
        let r = unsafe {
            bindings::mbedtls_ssl_close_notify(&mut self.inner)
        };

        error::SSLError::from_code(r).map(|_| ())
    }

    /// Reset an already initialized SSL context for re-use while retaining application-set
    /// variables, function pointers and data.
    pub fn session_reset(&mut self) -> Result<(), error::SSLError> {
        let r = unsafe {
            bindings::mbedtls_ssl_session_reset(&mut self.inner)
        };

        error::SSLError::from_code(r).map(|_| ())
    }

    /// Initiate an SSL renegotiation on the running connection.
    ///
    /// Client: perform the renegotiation right now.
    /// Server: request renegotiation, which will be performed during the next call to
    /// read() if honored by client.
    pub fn renegotiate(&mut self) -> Result<(), error::SSLError> {
        let r = unsafe {
            bindings::mbedtls_ssl_renegotiate(&mut self.inner)
        };

        error::SSLError::from_code(r).map(|_| ())
    }

    /// Send an alert message
    pub fn send_alert_message(&mut self, level: SSLAlertLevel, message: u8)
    -> Result<(), error::SSLError> {
        let level_char = match level {
            SSLAlertLevel::Warning => constants::MBEDTLS_SSL_ALERT_LEVEL_WARNING,
            SSLAlertLevel::Fatal => constants::MBEDTLS_SSL_ALERT_LEVEL_FATAL,
        };
        let r = unsafe {
            bindings::mbedtls_ssl_send_alert_message(
                &mut self.inner, level_char, message
            )
        };

        error::SSLError::from_code(r).map(|_| ())
    }

    /// Set client's transport-level identification info.
    ///
    /// (Server only. DTLS only.)
    ///
    /// This is usually the IP address (and port), but could be anything identify the client
    /// depending on the underlying network stack. Used for HelloVerifyRequest with DTLS. This is
    /// not used to route the actual packets.
    ///
    /// Returns: SSLError::BadInputData if used on client, SSLError::AllocFailed if out of memory.
    pub fn set_client_transport_id(&mut self, info: &[u8]) -> Result<(), error::SSLError> {
        let r = unsafe {
            bindings::mbedtls_ssl_set_client_transport_id(
                &mut self.inner,
                info.as_ptr(), info.len() as u64
            )
        };

        error::SSLError::from_code(r).map(|_| ())
    }

    /// Get the name of the negotiated Application Layer Protocol.
    ///
    /// This function should be called after the handshake is completed.
    pub fn get_alpn_protocol(&self) -> Option<&'a CStr> {
        unsafe {
            let ret = bindings::mbedtls_ssl_get_alpn_protocol(&self.inner);

            if !ret.is_null() {
                Some(CStr::from_ptr(ret))
            } else {
                None
            }
        }
    }

    /// Return the number of data bytes available to read.
    pub fn get_bytes_avail(&self) -> usize {
        unsafe {
            bindings::mbedtls_ssl_get_bytes_avail(&self.inner) as usize
        }
    }

    /// Return the current SSL version (SSLv3/TLSv1/etc)
    pub fn get_version(&self) -> &'static CStr {
        unsafe {
            let r = bindings::mbedtls_ssl_get_version(&self.inner);
            CStr::from_ptr(r)
        }
    }

    /// Return the name of the current ciphersuite.
    pub fn get_ciphersuite(&self) -> &'static CStr {
        unsafe {
            let r = bindings::mbedtls_ssl_get_ciphersuite(&self.inner);
            CStr::from_ptr(r)
        }
    }
}

impl <'a> Drop for SSLContext<'a> {
    fn drop(&mut self) {
        unsafe {
            bindings::mbedtls_ssl_free(&mut self.inner);
        }
    }
}

pub trait Write<E: CError> {
    fn write(&mut self, buf: &[u8]) -> Result<usize, E>;
}

pub trait Read<E: CError> {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, E>;
}

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

impl <T: io::Read> Read<io::Error> for T {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
        self.read(buf)
    }
}

impl CError for io::Error {
    fn to_int(&self) -> i32 {
        match self.kind() {
            io::ErrorKind::WouldBlock => -1,
            _ => -1,
        }
    }
}

extern "C" fn wrap_bio_send_callback<E: CError, IO : Read<E> + Write<E>>(
    target: *mut ::libc::c_void,
    output: *const ::libc::c_uchar, len: ::libc::size_t
) -> ::libc::c_int {
    unsafe {
        let f : *mut IO = transmute(target);
        let r = (*f).write(slice::from_raw_parts(output, len as usize));
        match r {
            Ok(i) => i as i32,
            Err(e) => e.to_int(),
        }
    }
}

extern "C" fn wrap_bio_read_callback<E : CError, IO : Read<E> + Write<E>>(
    target: *mut ::libc::c_void,
    output: *mut ::libc::c_uchar, len: ::libc::size_t
) -> ::libc::c_int {
    unsafe {
        let f : *mut IO = transmute(target);
        let r = (*f).read(slice::from_raw_parts_mut(output, len as usize));
        match r {
            Ok(i) => i as i32,
            Err(e) => e.to_int(),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2014-2016 bluss and ndarray developers.
//
// 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.

use std::ops::Add;
use libnum::{self, Zero, Float};

use imp_prelude::*;
use numeric_util;

use {
    LinalgScalar,
    aview0,
};

/// Numerical methods for arrays.
impl<A, S, D> ArrayBase<S, D>
    where S: Data<Elem=A>,
          D: Dimension,
{
    /// Return the sum of all elements in the array.
    ///
    /// ```
    /// use ndarray::arr2;
    ///
    /// let a = arr2(&[[1., 2.],
    ///                [3., 4.]]);
    /// assert_eq!(a.scalar_sum(), 10.);
    /// ```
    pub fn scalar_sum(&self) -> A
        where A: Clone + Add<Output=A> + libnum::Zero,
    {
        if let Some(slc) = self.as_slice_memory_order() {
            return numeric_util::unrolled_sum(slc);
        }
        let mut sum = A::zero();
        for row in self.inner_iter() {
            if let Some(slc) = row.as_slice() {
                sum = sum + numeric_util::unrolled_sum(slc);
            } else {
                sum = sum + row.iter().fold(A::zero(), |acc, elt| acc + elt.clone());
            }
        }
        sum
    }

    /// Return sum along `axis`.
    ///
    /// ```
    /// use ndarray::{aview0, aview1, arr2, Axis};
    ///
    /// let a = arr2(&[[1., 2.],
    ///                [3., 4.]]);
    /// assert!(
    ///     a.sum(Axis(0)) == aview1(&[4., 6.]) &&
    ///     a.sum(Axis(1)) == aview1(&[3., 7.]) &&
    ///
    ///     a.sum(Axis(0)).sum(Axis(0)) == aview0(&10.)
    /// );
    /// ```
    ///
    /// **Panics** if `axis` is out of bounds.
    pub fn sum(&self, axis: Axis) -> OwnedArray<A, <D as RemoveAxis>::Smaller>
        where A: Clone + Zero + Add<Output=A>,
              D: RemoveAxis,
    {
        let n = self.shape().axis(axis);
        let mut res = self.subview(axis, 0).to_owned();
        for i in 1..n {
            let view = self.subview(axis, i);
            res = res + &view;
        }
        res
    }

    /// Return mean along `axis`.
    ///
    /// **Panics** if `axis` is out of bounds.
    ///
    /// ```
    /// use ndarray::{aview1, arr2, Axis};
    ///
    /// let a = arr2(&[[1., 2.],
    ///                [3., 4.]]);
    /// assert!(
    ///     a.mean(Axis(0)) == aview1(&[2.0, 3.0]) &&
    ///     a.mean(Axis(1)) == aview1(&[1.5, 3.5])
    /// );
    /// ```
    pub fn mean(&self, axis: Axis) -> OwnedArray<A, <D as RemoveAxis>::Smaller>
        where A: LinalgScalar,
              D: RemoveAxis,
    {
        let n = self.shape().axis(axis);
        let sum = self.sum(axis);
        let mut cnt = A::one();
        for _ in 1..n {
            cnt = cnt + A::one();
        }
        sum / &aview0(&cnt)
    }

    /// Return `true` if the arrays' elementwise differences are all within
    /// the given absolute tolerance, `false` otherwise.
    ///
    /// If their shapes disagree, `rhs` is broadcast to the shape of `self`.
    ///
    /// **Panics** if broadcasting to the same shape isn’t possible.
    pub fn all_close<S2, E>(&self, rhs: &ArrayBase<S2, E>, tol: A) -> bool
        where A: Float,
              S2: Data<Elem=A>,
              E: Dimension,
    {
        let rhs_broadcast = rhs.broadcast_unwrap(self.dim());
        self.iter().zip(rhs_broadcast.iter()).all(|(x, y)| (*x - *y).abs() <= tol)
    }
}

<commit_msg>Use .scalar_sum() in .sum() when possible<commit_after>// Copyright 2014-2016 bluss and ndarray developers.
//
// 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.

use std::ops::Add;
use libnum::{self, Zero, Float};
use itertools::free::enumerate;

use imp_prelude::*;
use numeric_util;

use {
    LinalgScalar,
    aview0,
};

/// Numerical methods for arrays.
impl<A, S, D> ArrayBase<S, D>
    where S: Data<Elem=A>,
          D: Dimension,
{
    /// Return the sum of all elements in the array.
    ///
    /// ```
    /// use ndarray::arr2;
    ///
    /// let a = arr2(&[[1., 2.],
    ///                [3., 4.]]);
    /// assert_eq!(a.scalar_sum(), 10.);
    /// ```
    pub fn scalar_sum(&self) -> A
        where A: Clone + Add<Output=A> + libnum::Zero,
    {
        if let Some(slc) = self.as_slice_memory_order() {
            return numeric_util::unrolled_sum(slc);
        }
        let mut sum = A::zero();
        for row in self.inner_iter() {
            if let Some(slc) = row.as_slice() {
                sum = sum + numeric_util::unrolled_sum(slc);
            } else {
                sum = sum + row.iter().fold(A::zero(), |acc, elt| acc + elt.clone());
            }
        }
        sum
    }

    /// Return sum along `axis`.
    ///
    /// ```
    /// use ndarray::{aview0, aview1, arr2, Axis};
    ///
    /// let a = arr2(&[[1., 2.],
    ///                [3., 4.]]);
    /// assert!(
    ///     a.sum(Axis(0)) == aview1(&[4., 6.]) &&
    ///     a.sum(Axis(1)) == aview1(&[3., 7.]) &&
    ///
    ///     a.sum(Axis(0)).sum(Axis(0)) == aview0(&10.)
    /// );
    /// ```
    ///
    /// **Panics** if `axis` is out of bounds.
    pub fn sum(&self, axis: Axis) -> OwnedArray<A, <D as RemoveAxis>::Smaller>
        where A: Clone + Zero + Add<Output=A>,
              D: RemoveAxis,
    {
        let n = self.shape().axis(axis);
        let mut res = self.subview(axis, 0).to_owned();
        let stride = self.strides()[axis.axis()];
        if self.ndim() == 2 && stride == 1 {
            // contiguous along the axis we are summing
            let ax = axis.axis();
            for (i, elt) in enumerate(&mut res) {
                *elt = self.subview(Axis(1 - ax), i).scalar_sum();
            }
        } else {
            for i in 1..n {
                let view = self.subview(axis, i);
                res = res + &view;
            }
        }
        res
    }

    /// Return mean along `axis`.
    ///
    /// **Panics** if `axis` is out of bounds.
    ///
    /// ```
    /// use ndarray::{aview1, arr2, Axis};
    ///
    /// let a = arr2(&[[1., 2.],
    ///                [3., 4.]]);
    /// assert!(
    ///     a.mean(Axis(0)) == aview1(&[2.0, 3.0]) &&
    ///     a.mean(Axis(1)) == aview1(&[1.5, 3.5])
    /// );
    /// ```
    pub fn mean(&self, axis: Axis) -> OwnedArray<A, <D as RemoveAxis>::Smaller>
        where A: LinalgScalar,
              D: RemoveAxis,
    {
        let n = self.shape().axis(axis);
        let sum = self.sum(axis);
        let mut cnt = A::one();
        for _ in 1..n {
            cnt = cnt + A::one();
        }
        sum / &aview0(&cnt)
    }

    /// Return `true` if the arrays' elementwise differences are all within
    /// the given absolute tolerance, `false` otherwise.
    ///
    /// If their shapes disagree, `rhs` is broadcast to the shape of `self`.
    ///
    /// **Panics** if broadcasting to the same shape isn’t possible.
    pub fn all_close<S2, E>(&self, rhs: &ArrayBase<S2, E>, tol: A) -> bool
        where A: Float,
              S2: Data<Elem=A>,
              E: Dimension,
    {
        let rhs_broadcast = rhs.broadcast_unwrap(self.dim());
        self.iter().zip(rhs_broadcast.iter()).all(|(x, y)| (*x - *y).abs() <= tol)
    }
}

<|endoftext|>


<commit_before><commit_msg>Remove redundant mask<commit_after><|endoftext|>