stringmap 0.1.0

An immutable string map with pointers into frozen memory that can be shared between C, Ruby, Python and Rust.
use std::ffi::CStr;
use std::ptr;

use libc;

use ::StringMap;


#[allow(non_camel_case_types)]
#[repr(C)]
pub struct stringmap_t(StringMap);


#[no_mangle]
pub unsafe extern "C" fn stringmap_new(count: libc::size_t,
                                       keys: *const *const libc::c_char,
                                       values: *const *const libc::c_char)
                                       -> *mut stringmap_t {
    let n = count as isize;
    let mut data = Vec::default();

    if keys.is_null() || values.is_null() {
        return ptr::null_mut();
    }

    for (k, v) in (0..n).map(|i| (*keys.offset(i), *values.offset(i))) {
        if k.is_null() || v.is_null() {
            return ptr::null_mut();
        }
        data.push((CStr::from_ptr(k).to_string_lossy(),
                   CStr::from_ptr(v).to_string_lossy()));
    }

    Box::into_raw(Box::new(stringmap_t(StringMap::new(&data))))
}


#[no_mangle]
pub unsafe extern "C" fn stringmap_keys(m: *const stringmap_t)
                                        -> *const *const libc::c_char {
    m.as_ref().map(|this| this.0.keys.as_ptr()).unwrap_or(ptr::null())
}


#[no_mangle]
pub unsafe extern "C" fn stringmap_get(m: *const stringmap_t,
                                       key: *const libc::c_char)
                                       -> *const libc::c_char {
    if let Some(this) = m.as_ref() {
        let k = CStr::from_ptr(key).to_string_lossy();
        this.0
            .get(&k)
            .map(|s| s.as_ptr() as *const libc::c_char)
            .unwrap_or(ptr::null())
    } else {
        ptr::null()
    }
}


#[no_mangle]
pub unsafe extern "C" fn stringmap_len(m: *const stringmap_t) -> libc::size_t {
    m.as_ref().map(|this| this.0.len()).unwrap_or(0)
}


#[no_mangle]
pub unsafe extern "C" fn stringmap_free(m: *mut stringmap_t) { drop(m); }


unsafe fn drop<T>(ptr: *mut T) {
    // Obtain ownership, then go out of scope to drop.
    if !ptr.is_null() {
        Box::from_raw(ptr);
    }
}