Make Extern / ExternType conversion generic

main
copygirl 1 year ago
parent 48db307793
commit 81559ab326
  1. 4
      README.md
  2. 2
      src/engine.zig
  3. 56
      src/extern.zig
  4. 43
      src/func.zig
  5. 72
      src/instance.zig
  6. 13
      src/linker.zig
  7. 2
      src/memory.zig

@ -20,7 +20,7 @@ fn print_hello() void {
pub fn main() !void { pub fn main() !void {
const wasm = @import("wasmslime"); const wasm = @import("wasmslime");
// Should deinit Wasm objects. Omitted for brevity. // Should deinit Wasm objects, but this is omitted for brevity.
var engine = try wasm.Engine.initDefault(); var engine = try wasm.Engine.initDefault();
var module = try wasm.Module.initFromWat(engine, wat_bytes, null); var module = try wasm.Module.initFromWat(engine, wat_bytes, null);
var linker = wasm.Linker.init(engine); var linker = wasm.Linker.init(engine);
@ -28,7 +28,7 @@ pub fn main() !void {
var store = wasm.Store.init(engine); var store = wasm.Store.init(engine);
var context = store.getContext(); var context = store.getContext();
var instance = try linker.instantiate(context, module, null); var instance = try linker.instantiate(context, module, null);
const run_func = try instance.getFunc(context, "main"); const run_func = try instance.get(context, "main", wasm.Func);
try run_func.call(context, .{}, void, null); try run_func.call(context, .{}, void, null);
} }
``` ```

@ -48,7 +48,7 @@ pub const Engine = opaque {
/// async-signal-safe. /// async-signal-safe.
/// ///
/// See also `Config.epoch_interruption_set`. /// See also `Config.epoch_interruption_set`.
pub fn increment_epoch(self: *Engine) void { pub fn incrementEpoch(self: *Engine) void {
wasmtime_engine_increment_epoch(self); wasmtime_engine_increment_epoch(self);
} }

@ -46,20 +46,26 @@ pub const Extern = extern struct {
return wasmtime_extern_type(context, self); return wasmtime_extern_type(context, self);
} }
pub fn fromFunc(func: Func) Extern { pub fn from(value: anytype) Extern {
return .{ .kind = .func, .of = .{ .func = func } }; return switch (@TypeOf(value)) {
Extern => value, // Convenience no-op for use with generic functions.
Func => .{ .kind = .func, .of = .{ .func = value } },
Global => .{ .kind = .global, .of = .{ .global = value } },
Table => .{ .kind = .table, .of = .{ .table = value } },
Memory => .{ .kind = .memory, .of = .{ .memory = value } },
else => @compileError("Expected one of 'Extern', 'Func', 'Global', 'Table' or 'Memory', but found '" ++ @typeName(@TypeOf(value)) ++ "'"),
};
} }
pub fn asFunc(self: Extern) ?Func { pub fn as(self: Extern, comptime T: type) !T {
return if (self.kind == .func) self.of.func else null; return switch (T) {
} Extern => self, // Convenience no-op for use with generic functions.
Func => if (self.kind == .func) self.of.func else error.IncorrectType,
pub fn fromMemory(memory: Memory) Extern { Global => if (self.kind == .global) self.of.global else error.IncorrectType,
return .{ .kind = .memory, .of = .{ .memory = memory } }; Table => if (self.kind == .table) self.of.table else error.IncorrectType,
} Memory => if (self.kind == .memory) self.of.memory else error.IncorrectType,
else => @compileError("Expected one of 'Extern', 'Func', 'Global', 'Table' or 'Memory', but found '" ++ @typeName(T) ++ "'"),
pub fn asMemory(self: Extern) ?Memory { };
return if (self.kind == .memory) self.of.memory else null;
} }
extern "c" fn wasmtime_extern_delete(*Extern) void; extern "c" fn wasmtime_extern_delete(*Extern) void;
@ -86,20 +92,22 @@ pub const ExternType = opaque {
return wasm_externtype_kind(self); return wasm_externtype_kind(self);
} }
pub fn fromFuncType(func: *FuncType) *ExternType { pub fn from(value: anytype) @TypeOf(value) {
return wasm_functype_as_externtype(func); return switch (@TypeOf(value)) {
} *ExternType => value, // Convenience no-op for use with generic functions.
*FuncType => wasm_functype_as_externtype(value),
pub fn asFuncType(self: *ExternType) ?*FuncType { *MemoryType => wasm_memorytype_as_externtype(value),
return wasm_externtype_as_functype(self); else => @compileError("Expected one of '*ExternType', '*FuncType' or '*MemoryType', but found '" ++ @typeName(@TypeOf(value)) ++ "'"),
} };
pub fn fromMemoryType(func: *MemoryType) *ExternType {
return wasm_memorytype_as_externtype(func);
} }
pub fn asMemoryType(self: *ExternType) ?*MemoryType { pub fn as(self: *ExternType, comptime T: type) !T {
return wasm_externtype_as_memorytype(self); return switch (T) {
*ExternType => self, // Convenience no-op for use with generic functions.
*FuncType => wasm_externtype_as_functype(self) orelse error.IncorrectType,
*MemoryType => wasm_externtype_as_memorytype(self) orelse error.IncorrectType,
else => @compileError("Expected one of '*ExternType', '*FuncType' or '*MemoryType', but found '" ++ @typeName(T) ++ "'"),
};
} }
extern "c" fn wasm_externtype_copy(*const ExternType) *ExternType; extern "c" fn wasm_externtype_copy(*const ExternType) *ExternType;

@ -26,32 +26,29 @@ pub const Caller = opaque {
return wasmtime_caller_context(self); return wasmtime_caller_context(self);
} }
/// Get an exported `Extern` from the caller's context. /// Gets an exported `Extern` by name from the caller's context, converted
/// Returns `error.ExportNotFound` if export is not found. /// to the specified type. If `T` is `Extern` no conversion is done.
pub fn getExport(self: *Caller, name: []const u8) !Extern { ///
/// Returns `error.ExportNotFound` if export with that name is not found.
/// Returns `error.IncorrectType` if the export isn't the right type.
pub fn get(
self: *Caller,
name: []const u8,
comptime T: type,
) !T {
var result: Extern = undefined; var result: Extern = undefined;
return if (wasmtime_caller_export_get(self, name.ptr, name.len, &result)) result else error.ExportNotFound; return if (wasmtime_caller_export_get(self, name.ptr, name.len, &result)) result.as(T) else error.ExportNotFound;
}
/// Get an exported `Func` from the caller's context.
/// Returns `error.ExportNotFound` if export is not found.
/// Returns `error.ExportIncorrectType` if the export isn't a `Func`.
pub fn getFunc(self: *Caller, name: []const u8) !Func {
return (try self.getExport(name)).asFunc() orelse error.ExportIncorrectType;
}
/// Get an exported `Memory` from the caller's context.
/// Returns `error.ExportNotFound` if export is not found.
/// Returns `error.ExportIncorrectType` if the export isn't a `Memory`.
pub fn getMemory(self: *Caller, name: []const u8) !Memory {
return (try self.getExport(name)).asMemory() orelse error.ExportIncorrectType;
} }
/// Get an exported `Memory`'s data slice from the caller's context. /// Get an exported `Memory`'s data slice from the caller's context.
/// Returns `error.ExportNotFound` if export is not found. ///
/// Returns `error.ExportIncorrectType` if the export isn't a `Memory`. /// Returns `error.ExportNotFound` if export with that name is not found.
pub fn getMemoryData(self: *Caller, name: []const u8) ![]u8 { /// Returns `error.IncorrectType` if the export isn't the a `Memory`.
return (try self.getMemory(name)).getData(self.getContext()); pub fn getData(
self: *Caller,
name: []const u8,
) ![]u8 {
return (try self.get(name, Memory)).getData(self.getContext());
} }
extern "c" fn wasmtime_caller_context(*Caller) *Store.Context; extern "c" fn wasmtime_caller_context(*Caller) *Store.Context;
@ -191,7 +188,7 @@ pub const Func = extern struct {
} }
pub fn toExtern(self: Func) Extern { pub fn toExtern(self: Func) Extern {
return Extern.fromFunc(self); return Extern.from(self, Func);
} }
fn isTupleOrEmpty(comptime T: type) bool { fn isTupleOrEmpty(comptime T: type) bool {

@ -1,7 +1,6 @@
const Engine = @import("./engine.zig").Engine; const Engine = @import("./engine.zig").Engine;
const Module = @import("./module.zig").Module; const Module = @import("./module.zig").Module;
const Store = @import("./store.zig").Store; const Store = @import("./store.zig").Store;
const Func = @import("./func.zig").Func;
const Memory = @import("./memory.zig").Memory; const Memory = @import("./memory.zig").Memory;
const Diagnostics = @import("./diagnostics.zig").Diagnostics; const Diagnostics = @import("./diagnostics.zig").Diagnostics;
const Error = @import("./error.zig").Error; const Error = @import("./error.zig").Error;
@ -40,50 +39,63 @@ pub const Instance = extern struct {
/// ///
/// This function does not take ownership of any of its arguments, but all /// This function does not take ownership of any of its arguments, but all
/// return values (Error or Trap) are owned by the caller. /// return values (Error or Trap) are owned by the caller.
pub fn init(context: *Store.Context, module: *const Module, imports: []const Extern, diag: ?*Diagnostics) !Instance { pub fn init(
context: *Store.Context,
module: *const Module,
imports: []const Extern,
diag: ?*Diagnostics,
) !Instance {
var result: Instance = undefined; var result: Instance = undefined;
var trap: ?*Trap = null; var trap: ?*Trap = null;
const err = wasmtime_instance_new(context, module, imports.ptr, imports.len, &result, &trap); const err = wasmtime_instance_new(context, module, imports.ptr, imports.len, &result, &trap);
return try Diagnostics.handleErrorOrTrap(err, error.InstanceInit, trap, result, diag); return try Diagnostics.handleErrorOrTrap(err, error.InstanceInit, trap, result, diag);
} }
/// Get an exported `Extern` by name from this instance. /// Gets an exported `Extern` by name from this instance, converted to the
/// Returns `error.ExportNotFound` if export is not found. /// specified type. If `T` is `Extern` no conversion is done.
pub fn getExport(self: *const Instance, context: *Store.Context, name: []const u8) !Extern { ///
/// Returns `error.ExportNotFound` if export with that name is not found.
/// Returns `error.IncorrectType` if the export isn't the right type.
pub fn get(
self: *const Instance,
context: *Store.Context,
name: []const u8,
comptime T: type,
) !T {
var result: Extern = undefined; var result: Extern = undefined;
return if (wasmtime_instance_export_get(context, self, name.ptr, name.len, &result)) result else error.ExportNotFound; return if (wasmtime_instance_export_get(context, self, name.ptr, name.len, &result)) result.as(T) else error.ExportNotFound;
}
/// Get an exported `Func` by name from this instance.
/// Returns `error.ExportNotFound` if export is not found.
/// Returns `error.ExportIncorrectType` if the export isn't a `Func`.
pub fn getFunc(self: *const Instance, context: *Store.Context, name: []const u8) !Func {
return (try self.getExport(context, name)).asFunc() orelse error.ExportIncorrectType;
}
/// Get an exported `Memory` by name from this instance.
/// Returns `error.ExportNotFound` if export is not found.
/// Returns `error.ExportIncorrectType` if the export isn't a `Memory`.
pub fn getMemory(self: *const Instance, context: *Store.Context, name: []const u8) !Memory {
return (try self.getExport(context, name)).asMemory() orelse error.ExportIncorrectType;
} }
/// Get an exported `Memory`'s data slice from this instance. /// Get an exported `Memory`'s data slice from this instance.
/// Returns `error.ExportNotFound` if export is not found. ///
/// Returns `error.ExportIncorrectType` if the export isn't a `Memory`. /// Returns `error.ExportNotFound` if export with that name is not found.
pub fn getMemoryData(self: *const Instance, context: *Store.Context, name: []const u8) ![]u8 { /// Returns `error.IncorrectType` if the export isn't the a `Memory`.
return (try self.getMemory(context, name)).getData(context); pub fn getData(
self: *const Instance,
context: *Store.Context,
name: []const u8,
) ![]u8 {
return (try self.get(context, name, Memory)).getData(context);
} }
/// Get an export by index from an instance, or /// Gets an exported `Extern` by index from this instance, converted to
/// `error.ExportNotFound` if not found. /// the specified type. If `T` is `Extern` no conversion is done.
pub fn getExportByIndex(self: *const Instance, context: *Store.Context, index: usize) !Extern { ///
/// Returns `error.ExportNotFound` if export with that name is not found.
/// Returns `error.IncorrectType` if the export isn't the right type.
pub fn getByIndex(
self: *const Instance,
context: *Store.Context,
index: usize,
comptime T: type,
) !struct { result: T, name: []const u8 } {
var result: Extern = undefined; var result: Extern = undefined;
// TODO: Add a way to also return `name`?
// NOTE: Apparently `name` is owned by the store and must be used immediately.
var name: [*]const u8 = null; var name: [*]const u8 = null;
var name_len: usize = undefined; var name_len: usize = undefined;
return if (wasmtime_instance_export_nth(context, self, index, &name, &name_len, &result)) result else error.ExportNotFound; return if (wasmtime_instance_export_nth(context, self, index, &name, &name_len, &result))
.{ .result = result.as(T), .name = name[0..name_len] }
else
error.ExportNotFound;
} }
extern "c" fn wasmtime_instance_new(*Store.Context, *const Module, [*]const Extern, usize, *Instance, *?*Trap) ?*Error; extern "c" fn wasmtime_instance_new(*Store.Context, *const Module, [*]const Extern, usize, *Instance, *?*Trap) ?*Error;

@ -124,6 +124,8 @@ pub const Linker = opaque {
} }
/// Acquires the "default export" of the named module in this linker. /// Acquires the "default export" of the named module in this linker.
///
/// Returns an error if the default export is not a function.
pub fn getDefault( pub fn getDefault(
linker: *const Linker, linker: *const Linker,
context: *Store.Context, context: *Store.Context,
@ -135,15 +137,20 @@ pub const Linker = opaque {
return Diagnostics.handleError(err, error.LinkerGetDefault, result, diag); return Diagnostics.handleError(err, error.LinkerGetDefault, result, diag);
} }
/// Loads an item by name from this linker. /// Loads an item by name from this linker, converted to the
/// specified type. If `T` is `Extern` no conversion is done.
///
/// Returns `error.ExportNotFound` if export with that name is not found.
/// Returns `error.IncorrectType` if the export isn't the right type.
pub fn get( pub fn get(
linker: *const Linker, linker: *const Linker,
context: *Store.Context, context: *Store.Context,
module: []const u8, module: []const u8,
name: []const u8, name: []const u8,
) ?Extern { comptime T: type,
) !Extern {
var result: Extern = undefined; var result: Extern = undefined;
return if (wasmtime_linker_get(linker, context, module.ptr, module.len, name.ptr, name.len, &result)) result else null; return if (wasmtime_linker_get(linker, context, module.ptr, module.len, name.ptr, name.len, &result)) result.as(T) else error.ExportNotFound;
} }
extern "c" fn wasmtime_linker_new(*Engine) *Linker; extern "c" fn wasmtime_linker_new(*Engine) *Linker;

@ -35,7 +35,7 @@ pub const Memory = extern struct {
} }
pub fn toExtern(self: Memory) Extern { pub fn toExtern(self: Memory) Extern {
return Extern.fromMemory(self); return Extern.from(self, Memory);
} }
extern "c" fn wasmtime_memory_new(*Store.Context, *const MemoryType, *Memory) ?*Error; extern "c" fn wasmtime_memory_new(*Store.Context, *const MemoryType, *Memory) ?*Error;

Loading…
Cancel
Save