Skip to content

Instantly share code, notes, and snippets.

@nwellnhof
Created June 6, 2015 11:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nwellnhof/0c83c64a8f15c253e73e to your computer and use it in GitHub Desktop.
Save nwellnhof/0c83c64a8f15c253e73e to your computer and use it in GitHub Desktop.
Proof of concept for Clownfish Rust bindings
extern crate libc;
use libc::types::common::c99::*;
use libc::types::os::arch::c95::*;
#[repr(C)]
pub struct ObjInternal {
refcount: size_t,
class: *mut ObjInternal,
}
#[link(name = "cfish")]
extern {
static CFISH_OBJ: *mut ObjInternal;
static CFISH_CLASS: *mut ObjInternal;
static CFISH_STRING: *mut ObjInternal;
fn cfish_bootstrap_parcel();
fn cfish_inc_refcount(obj: *mut ObjInternal);
fn cfish_dec_refcount(obj: *mut ObjInternal) -> uint32_t;
// The libc crate doesn't support the C99 _Bool type.
// See https://github.com/rust-lang/rust/issues/14608
fn cfish_Obj_is_a(obj: *mut ObjInternal, class: *mut ObjInternal)
-> c_char;
fn cfish_Str_new_from_trusted_utf8(utf8: *const u8, size: size_t)
-> *mut ObjInternal;
static CFISH_Str_Get_Size_OFFSET: size_t;
}
//fn cfish_class<T: ObjTrait>() -> Class { T::CLASS() }
// Obj
pub struct Obj {
ptr: *mut ObjInternal,
}
#[allow(non_snake_case)]
pub trait ObjTrait {
fn CLASS() -> Class;
fn NEW_FROM_PTR(ptr: *mut ObjInternal) -> Self;
fn PTR(&self) -> *mut ObjInternal;
fn is_a<T: ObjTrait>(&self) -> bool {
unsafe { return cfish_Obj_is_a(self.PTR(), T::CLASS().ptr) != 0; }
}
fn CAST<T: ObjTrait>(&self) -> Option<T> {
if self.is_a::<T>() {
return Some(T::NEW_FROM_PTR(self.PTR()));
}
else {
return None;
}
}
}
impl ObjTrait for Obj {
fn CLASS() -> Class { Class { ptr: CFISH_OBJ } }
fn NEW_FROM_PTR(ptr: *mut ObjInternal) -> Self {
unsafe { cfish_inc_refcount(ptr); }
Obj { ptr: ptr }
}
fn PTR(&self) -> *mut ObjInternal { self.ptr }
}
impl Drop for Obj {
fn drop(&mut self) {
unsafe { cfish_dec_refcount(self.ptr); }
}
}
impl Clone for Obj {
fn clone(&self) -> Obj {
// Should invoke Obj_Clone.
unsafe { cfish_inc_refcount(self.ptr); }
Obj { ptr: self.ptr }
}
}
// Class (no need for refcount handling)
pub struct Class {
ptr: *mut ObjInternal,
}
impl ObjTrait for Class {
fn CLASS() -> Class { Class { ptr: CFISH_CLASS } }
fn NEW_FROM_PTR(ptr: *mut ObjInternal) -> Self { Class { ptr: ptr } }
fn PTR(&self) -> *mut ObjInternal { self.ptr }
}
// String
pub struct String {
ptr: *mut ObjInternal,
}
impl ObjTrait for String {
fn CLASS() -> Class { Class { ptr: CFISH_STRING } }
fn NEW_FROM_PTR(ptr: *mut ObjInternal) -> Self {
unsafe { cfish_inc_refcount(ptr); }
String { ptr: ptr }
}
fn PTR(&self) -> *mut ObjInternal { self.ptr }
}
pub trait StringTrait : ObjTrait {
fn get_size(&self) -> usize {
let ptr = self.PTR();
unsafe {
let class = (*ptr).class as *const c_char;
let method_ptr = class.offset(CFISH_Str_Get_Size_OFFSET as isize)
as *const extern fn (*mut ObjInternal) -> size_t;
return (*method_ptr)(ptr) as usize;
}
}
}
impl StringTrait for String {}
impl Drop for String {
fn drop(&mut self) {
unsafe { cfish_dec_refcount(self.ptr); }
}
}
impl Clone for String {
fn clone(&self) -> String {
unsafe { cfish_inc_refcount(self.ptr); }
String { ptr: self.ptr }
}
}
impl String {
fn new(s: &str) -> String {
unsafe {
return String {
ptr: cfish_Str_new_from_trusted_utf8(s.as_ptr(),
s.len() as size_t),
}
}
}
}
// main
fn main() {
unsafe { cfish_bootstrap_parcel(); }
let s1 = String::new("Hello, world!");
let s2 = &s1;
assert!(s1.is_a::<String>());
assert!(!s2.is_a::<Class>());
assert_eq!(s1.get_size(), 13);
let obj = s1.CAST::<Obj>().expect("Invalid cast");
assert_eq!(s1.ptr, obj.ptr);
let class = s1.CAST::<Class>();
assert!(class.is_none());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment