From 980a169b12125de50cf84a861946896048f35276 Mon Sep 17 00:00:00 2001 From: Graham Ollis Date: Sun, 10 May 2020 15:54:21 -0600 Subject: [PATCH] add greet exmaple: passing strings back and forth --- examples/wasm/greet.pl | 7 +++++++ examples/wasm/lib/Greet.pm | 33 +++++++++++++++++++++++++++++++++ examples/wasm/lib/Greet.rs | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 examples/wasm/greet.pl create mode 100644 examples/wasm/lib/Greet.pm create mode 100644 examples/wasm/lib/Greet.rs 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() +}