diff --git a/examples/wasm/greet.pl b/examples/wasm/greet.pl new file mode 100644 index 0000000..44d5c2f --- /dev/null +++ b/examples/wasm/greet.pl @@ -0,0 +1,7 @@ +use strict; +use warnings; +use Path::Tiny qw( path ); +use lib path(__FILE__)->parent->child('lib')->stringify; +use Greet; + +print greet("Perl!"), "\n"; diff --git a/examples/wasm/lib/Greet.pm b/examples/wasm/lib/Greet.pm new file mode 100644 index 0000000..9571738 --- /dev/null +++ b/examples/wasm/lib/Greet.pm @@ -0,0 +1,33 @@ +package Greet; + +use strict; +use warnings; +use FFI::Platypus; +use FFI::Platypus::Memory qw( strcpy ); +use base qw( Exporter ); +use Wasm + -api => 0, + -self +; + +our @EXPORT = qw( greet ); + +sub greet +{ + my($subject) = @_; + + my $input_size = do { use bytes; length($subject)+1 }; + my $input_offset = _allocate($input_size); + strcpy( $memory->address + $input_offset, $subject ); + + my $output_offset = _greet($input_offset); + my $greeting = FFI::Platypus->new->cast('opaque', 'string', $memory->address + $output_offset); + my $output_size = do { use bytes; length($greeting)+1 }; + + _deallocate($input_offset, $input_size); + _deallocate($output_offset, $output_size); + + return $greeting; +} + +1; diff --git a/examples/wasm/lib/Greet.rs b/examples/wasm/lib/Greet.rs new file mode 100644 index 0000000..4442963 --- /dev/null +++ b/examples/wasm/lib/Greet.rs @@ -0,0 +1,34 @@ +/* + * rustc --target wasm32-unknown-unknown -O --crate-type=cdylib Greet.rs -o Greet.wasm + * chmod -x Greet.wasm + */ + +use std::ffi::{CStr, CString}; +use std::mem; +use std::os::raw::{c_char, c_void}; + +#[no_mangle] +pub extern fn _allocate(size: usize) -> *mut c_void { + let mut buffer = Vec::with_capacity(size); + let pointer = buffer.as_mut_ptr(); + mem::forget(buffer); + + pointer as *mut c_void +} + +#[no_mangle] +pub extern fn _deallocate(pointer: *mut c_void, capacity: usize) { + unsafe { + let _ = Vec::from_raw_parts(pointer, 0, capacity); + } +} + +#[no_mangle] +pub extern fn _greet(subject: *mut c_char) -> *mut c_char { + let subject = unsafe { CStr::from_ptr(subject).to_bytes().to_vec() }; + let mut output = b"Hello, ".to_vec(); + output.extend(&subject); + output.extend(&[b'!']); + + unsafe { CString::from_vec_unchecked(output) }.into_raw() +}