Skip to content

Instantly share code, notes, and snippets.

@skinkade
Last active November 4, 2016 01:45
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 skinkade/0a1a83adfbf26ac84527cc47b2224ed2 to your computer and use it in GitHub Desktop.
Save skinkade/0a1a83adfbf26ac84527cc47b2224ed2 to your computer and use it in GitHub Desktop.

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);
@Xliff
Copy link

Xliff commented Nov 4, 2016

I make no promises, but try this:

class CCRNG {
   class pCCRNG is repr('CPointer') { };

    has $!initialized;
    has pCCRNG $!rng;

    # Here are the actual NativeCall functions.
    sub chacha_handle() returns pCCRNG is native(DEMO) { * }
    sub chacha_free(pCCRNG) is native(DEMO) { * }
    sub chacha_fill(pCCRNG, Buf[uint8]) is native(DEMO) { * }

    # Here are the methods we use to expose it to the outside world.
    method new() {
        $!rng = chacha_handle();
        $!initialized = True;
    }

    method free() {
        if $!initialized {
            chacha_free($rng);
            $!initialized = False; # prevent double frees
        }
    }

    method buffer(size_t $len) {
        my $temp = Buf.allocate($len);
        chacha_fill($!rng, $temp);
        Buf.new($temp[^$len]);
    }

    # Free data when the object is garbage collected.
    method DESTROY() {
        $!rng.free;
    }
} 


my CCRNG $rng .= new;
say $rng.buffer(16);

@Xliff
Copy link

Xliff commented Nov 4, 2016

Of course, we can simplify that even further...

class CCRNG {
   class pCCRNG is repr('CPointer') { };

    has pCCRNG $!rng;

    # Here are the actual NativeCall functions.
    sub chacha_handle() returns pCCRNG is native(DEMO) { * }
    sub chacha_free(pCCRNG) is native(DEMO) { * }
    sub chacha_fill(pCCRNG, Buf[uint8]) is native(DEMO) { * }

    # Here are the methods we use to expose it to the outside world.
    method new() {
        $!rng = chacha_handle();
    }

    method free() {
        if $!rng.defined {
            chacha_free($rng);
            $!rng = Nil;
        }
    }

    method buffer(size_t $len) {
        my $temp = Buf.allocate($len);
        chacha_fill($!rng, $temp);
        Buf.new($temp[^$len]);
    }

    # Free data when the object is garbage collected.
    method DESTROY() {
        $!rng.free;
    }
} 

my CCRNG $rng .= new;
say $rng.buffer(16);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment