Based on: http://jakegoulding.com/rust-ffi-omnibus/objects/
Not working yet.
The Rust library:
extern crate rand;
use rand::Rng;
use rand::SeedableRng;
use rand::os::OsRng;
use rand::chacha::ChaChaRng;
#[no_mangle]
pub extern "C" fn chacha_handle() -> *mut ChaChaRng {
let mut os_csprng = match OsRng::new() {
Ok(g) => g,
Err(e) => panic!("{}", e),
};
let mut seed = [0u32; 4];
seed[0] = os_csprng.next_u32();
seed[1] = os_csprng.next_u32();
seed[2] = os_csprng.next_u32();
seed[3] = os_csprng.next_u32();
Box::into_raw(Box::new(ChaChaRng::from_seed(&seed)))
}
#[no_mangle]
pub extern "C" fn chacha_free(ptr: *mut ChaChaRng) {
if ptr.is_null() { return }
unsafe { Box::from_raw(ptr); }
}
#[no_mangle]
pub extern "C" fn chacha_fill(ptr: *mut ChaChaRng, buffer: &mut [u8]) {
let rng = unsafe {
assert!(!ptr.is_null());
&mut *ptr
};
rng.fill_bytes(buffer);
}
The Perl6 script:
use NativeCall;
constant DEMO = './target/debug/rust_p6_demo';
class CCRNG is repr('CPointer') {
has $!initialized;
# Here are the actual NativeCall functions.
sub chacha_handle() returns CCRNG is native(DEMO) { * }
sub chacha_free(CCRNG) is native(DEMO) { * }
sub chacha_fill(CCRNG, Buf[uint8]) is native(DEMO) { * }
# Here are the methods we use to expose it to the outside world.
method new() {
chacha_handle();
$!initialized = True;
}
method free() {
if $!initialized {
chacha_free(self);
$!initialized = False; # prevent double frees
}
}
method buffer(size_t $len) {
my $temp = Buf.allocate($len);
chacha_fill(self, $temp);
Buf.new($temp[^$len]);
}
# Free data when the object is garbage collected.
method DESTROY() {
self.free;
}
}
my CCRNG $rng .= new;
say $rng.buffer(16);
I make no promises, but try this: