|
1 | | -use super::convert::{component_val_to_rb, rb_to_component_val}; |
2 | | -use crate::ruby_api::{errors::ExceptionMessage, store::StoreContextValue}; |
3 | | -use magnus::{exception::arg_error, prelude::*, value, Error, IntoValue, RArray, Value}; |
| 1 | +use crate::ruby_api::{ |
| 2 | + component::{ |
| 3 | + convert::{component_val_to_rb, rb_to_component_val}, |
| 4 | + Instance, |
| 5 | + }, |
| 6 | + errors::ExceptionMessage, |
| 7 | + store::{Store, StoreContextValue}, |
| 8 | +}; |
| 9 | +use magnus::{ |
| 10 | + class, exception::arg_error, gc::Marker, method, prelude::*, typed_data::Obj, value, |
| 11 | + DataTypeFunctions, Error, IntoValue, RArray, RModule, Ruby, TypedData, Value, |
| 12 | +}; |
4 | 13 | use wasmtime::component::{Func as FuncImpl, Type, Val}; |
5 | 14 |
|
6 | | -pub struct Func; |
| 15 | +/// @yard |
| 16 | +/// @rename Wasmtime::Component::Func |
| 17 | +/// Represents a WebAssembly component Function |
| 18 | +/// @see https://docs.wasmtime.dev/api/wasmtime/component/struct.Func.html Wasmtime's Rust doc |
| 19 | +/// |
| 20 | +/// == Component model types conversion |
| 21 | +/// |
| 22 | +/// Here's how component model types map to Ruby objects: |
| 23 | +/// |
| 24 | +/// bool:: |
| 25 | +/// Ruby +true+ or +false+, no automatic conversion happens. |
| 26 | +/// s8, u8, s16, u16, etc.:: |
| 27 | +/// Ruby +Integer+. Overflows raise. |
| 28 | +/// f32, f64:: |
| 29 | +/// Ruby +Float+. |
| 30 | +/// string:: |
| 31 | +/// Ruby +String+. Exception will be raised if the string is not valid UTF-8. |
| 32 | +/// list<T>:: |
| 33 | +/// Ruby +Array+. |
| 34 | +/// tuple:: |
| 35 | +/// Ruby +Array+ of the same size of tuple. Example: +tuple<T, U>+ would be converted to +[T, U]+. |
| 36 | +/// record:: |
| 37 | +/// Ruby +Hash+ where field names are +String+s. |
| 38 | +/// result<O, E>:: |
| 39 | +/// {Result} instance. When converting a result branch of the none |
| 40 | +/// type, the {Result}’s value MUST be +nil+. |
| 41 | +/// |
| 42 | +/// Examples of none type in a result: unparametrized +result+, +result<O>+, +result<_, E>+. |
| 43 | +/// option<T>:: |
| 44 | +/// +nil+ is mapped to +None+, anything else is mapped to +Some(T)+. |
| 45 | +/// flags:: |
| 46 | +/// Ruby +Array+ of +String+s. |
| 47 | +/// enum:: |
| 48 | +/// Ruby +String+. Exception will be raised of the +String+ is not a valid enum value. |
| 49 | +/// variant:: |
| 50 | +/// {Variant} instance wrapping the variant's name and optionally its value. |
| 51 | +/// Exception will be raised for: |
| 52 | +/// - invalid {Variant#name}, |
| 53 | +/// - unparametrized variant and not nil {Variant#value}. |
| 54 | +/// resource (own<T> or borrow<T>):: |
| 55 | +/// Not yet supported. |
| 56 | +#[derive(TypedData)] |
| 57 | +#[magnus(class = "Wasmtime::Component::Func", size, mark, free_immediately)] |
| 58 | +pub struct Func { |
| 59 | + store: Obj<Store>, |
| 60 | + instance: Obj<Instance>, |
| 61 | + inner: FuncImpl, |
| 62 | +} |
| 63 | +unsafe impl Send for Func {} |
| 64 | + |
| 65 | +impl DataTypeFunctions for Func { |
| 66 | + fn mark(&self, marker: &Marker) { |
| 67 | + marker.mark(self.store); |
| 68 | + marker.mark(self.instance); |
| 69 | + } |
| 70 | +} |
7 | 71 |
|
8 | 72 | impl Func { |
9 | | - pub fn invoke( |
10 | | - store: &StoreContextValue, |
11 | | - func: &FuncImpl, |
12 | | - args: &[Value], |
13 | | - ) -> Result<Value, Error> { |
14 | | - let results_ty = func.results(store.context()?); |
| 73 | + /// @yard |
| 74 | + /// Calls a Wasm component model function. |
| 75 | + /// @def call(*args) |
| 76 | + /// @param args [Array<Object>] the function's arguments as per its Wasm definition |
| 77 | + /// @return [Object] the function's return value as per its Wasm definition |
| 78 | + /// @see Func Func class-level documentation for type conversion logic |
| 79 | + pub fn call(&self, args: &[Value]) -> Result<Value, Error> { |
| 80 | + Func::invoke(self.store, &self.inner, args) |
| 81 | + } |
| 82 | + |
| 83 | + pub fn from_inner(inner: FuncImpl, instance: Obj<Instance>, store: Obj<Store>) -> Self { |
| 84 | + Self { |
| 85 | + store, |
| 86 | + instance, |
| 87 | + inner, |
| 88 | + } |
| 89 | + } |
| 90 | + |
| 91 | + pub fn invoke(store: Obj<Store>, func: &FuncImpl, args: &[Value]) -> Result<Value, Error> { |
| 92 | + let store_context_value = StoreContextValue::from(store); |
| 93 | + let results_ty = func.results(store.context_mut()); |
15 | 94 | let mut results = vec![wasmtime::component::Val::Bool(false); results_ty.len()]; |
16 | | - let params = convert_params(store, &func.params(store.context()?), args)?; |
| 95 | + let params = convert_params( |
| 96 | + &store_context_value, |
| 97 | + &func.params(store.context_mut()), |
| 98 | + args, |
| 99 | + )?; |
17 | 100 |
|
18 | | - func.call(store.context_mut()?, ¶ms, &mut results) |
19 | | - .map_err(|e| store.handle_wasm_error(e))?; |
| 101 | + func.call(store.context_mut(), ¶ms, &mut results) |
| 102 | + .map_err(|e| store_context_value.handle_wasm_error(e))?; |
20 | 103 |
|
21 | 104 | let result = match results_ty.len() { |
22 | 105 | 0 => Ok(value::qnil().as_value()), |
23 | | - 1 => component_val_to_rb(results.into_iter().next().unwrap(), store), |
| 106 | + 1 => component_val_to_rb(results.into_iter().next().unwrap(), &store_context_value), |
24 | 107 | _ => results |
25 | 108 | .into_iter() |
26 | | - .map(|val| component_val_to_rb(val, store)) |
| 109 | + .map(|val| component_val_to_rb(val, &store_context_value)) |
27 | 110 | .collect::<Result<RArray, Error>>() |
28 | 111 | .map(IntoValue::into_value), |
29 | 112 | }; |
30 | 113 |
|
31 | | - func.post_return(store.context_mut()?) |
32 | | - .map_err(|e| store.handle_wasm_error(e))?; |
| 114 | + func.post_return(store.context_mut()) |
| 115 | + .map_err(|e| store_context_value.handle_wasm_error(e))?; |
33 | 116 |
|
34 | 117 | result |
35 | 118 | } |
@@ -65,3 +148,10 @@ fn convert_params( |
65 | 148 |
|
66 | 149 | Ok(params) |
67 | 150 | } |
| 151 | + |
| 152 | +pub fn init(_ruby: &Ruby, namespace: &RModule) -> Result<(), Error> { |
| 153 | + let func = namespace.define_class("Func", class::object())?; |
| 154 | + func.define_method("call", method!(Func::call, -1))?; |
| 155 | + |
| 156 | + Ok(()) |
| 157 | +} |
0 commit comments