Skip to content

Commit

Permalink
pulled out universal_ffi from wasm_ffi
Browse files Browse the repository at this point in the history
  • Loading branch information
vm75 committed Dec 11, 2024
1 parent 4c1a940 commit 270dea6
Show file tree
Hide file tree
Showing 231 changed files with 1,207 additions and 6,618 deletions.
4 changes: 4 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
# We'll use defaults from the LLVM style, but with 2 columns indentation.
BasedOnStyle: WebKit
IndentWidth: 2
48 changes: 48 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Publish Dart Packages

on:
push:
branches:
- main
paths:
- 'wasm_ffi/CHANGELOG.md'
- 'universal_ffi/CHANGELOG.md'

jobs:
analyze-and-publish:
name: Analyze and Publish Dart Packages
runs-on: ubuntu-latest

strategy:
matrix:
package:
- wasm_ffi
- universal_ffi

steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Set up Dart
uses: dart-lang/setup-dart@v2
with:
channel: stable

- name: Analyze ${matrix.package}
run: |
cd ${matrix.package}
dart pub get
dart analyze
dart test
- name: Publish ${matrix.package} (if valid)
env:
PUB_TOKEN: ${{ secrets.PUB_TOKEN }}
run: |
cd ${matrix.package}
# Validate the package
dart pub publish --dry-run
# Publish the package if validation succeeds
echo "Publishing ${matrix.package} to pub.dev..."
# dart pub publish --force
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

# Avoid committing pubspec.lock for library packages; see
# https://dart.dev/guides/libraries/private-files#pubspeclock.
./pubspec.lock
pubspec.lock

# other build files
**/build/
Expand Down
20 changes: 10 additions & 10 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,28 @@
"version": "0.2.0",
"configurations": [
{
"name": "Flutter Example",
"name": "wasm_ffi: example",
"type": "dart",
"request": "launch",
"program": "lib/main.dart",
"cwd": "example",
"program": "web",
"cwd": "wasm_ffi/example",
},
{
"name": "Dart Native example",
"name": "universal_ffi: web example",
"type": "dart",
"request": "launch",
"program": "bin/example.dart",
"cwd": "example_dart",
"program": "web",
"cwd": "universal_ffi/example",
},
{
"name": "Dart Web example",
"name": "universal_ffi: ffi example",
"type": "dart",
"request": "launch",
"program": "web",
"cwd": "example_dart",
"program": "bin/example.dart",
"cwd": "universal_ffi/example",
},
{
"name": "Bump Version",
"name": "bump version",
"type": "dart",
"request": "launch",
"program": "tool/bump_version.dart",
Expand Down
27 changes: 0 additions & 27 deletions Dockerfile

This file was deleted.

24 changes: 24 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.PHONY: update-version build run

update-version:
./tools/update-version.sh

test:
cd wasm_ffi && make test

sync:
rsync -auv wasm_ffi/example/src/ universal_ffi/example/src/
rsync -auv universal_ffi/example/src/ wasm_ffi/example/src/

build:
cd wasm_ffi/example && make build
cd universal_ffi/example && make build

run:
cd wasm_ffi/example && make run

run-wasm:
cd universal_ffi/example && make run-wasm

run-ffi:
cd universal_ffi/example && make run-ffi
88 changes: 29 additions & 59 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,74 +1,44 @@
# wasm_ffi
`wasm_ffi` intends to be a drop-in replacement for `dart:ffi` on the web platform using wasm. wasm_ffi is built on top of [web_ffi](https://pub.dev/packages/web_ffi).
For ease of use cross-platform, the following are provided:
* ffi_bridge: selects `wasm_ffi/ffi.dart` for web and `dart:ffi` for other platforms
* ffi_utils_bridge: selects `wasm_ffi/ffi_utils.dart` for web and `package:ffi` for other platforms
* FfiWrapper: a simple wrapper utility which loads `DynamicLibrary` asynchronously. Also provides a `safeUsing` method which uses the current library's memory.
<div align="center">
<h1>Native Ffi</h1>
</div>
<div align="center">

The general idea is to expose an API that is compatible with `dart:ffi` but translates all calls through `dart:js` to a browser running `WebAssembly`.
[![License]](LICENSE)
[![Build]][build_url]

Webassembly (wasm) compiled with [emscripten](https://emscripten.org/) as well as standalone wasm is supported.
</div>

The provided example shows how to use wasm_ffi both in web and in dart.
# Native Ffi

## Installation
Native Ffi contains Dart utilities to easily incorporate native(C/C++) code into your Dart/Flutter project.
It has the two Dart modules.

* Dart
```
dart pub add wasm_ffi
```
# Wasm Ffi

* Flutter
```
flutter pub add wasm_ffi
```
[![Repo]](https://github.com/vm75/wasm_ffi/wasm_ffi)
![Pub Version](https://img.shields.io/pub/v/wasm_ffi)
![Pub Points](https://img.shields.io/pub/points/wasm_ffi)
![Pub Popularity](https://img.shields.io/pub/popularity/wasm_ffi)
![Pub Likes](https://img.shields.io/pub/likes/wasm_ffi)

## Usage examples

### FfiWrapper and ffigen (all platforms)
* Generate bindings using `ffigen`
* Replace `import 'dart:ffi' as ffi;` with `import 'package:wasm_ffi/ffi_bridge.dart' as ffi;` in the generated binding files
* Instantiate FfiWrapper: `ffiWrapper = await FfiWrapper.load('path to wasm or js');`
* Create binding instance: `BindingClass bindings = BindingClass(ffiWrapper.library);`
* Call method: `ffiWrapper.safeUsing((Arena arena) { ... });`


### Direct load example (only for web)
```dart
import 'package:wasm_ffi/ffi.dart' as ffi;
# Universal Ffi

Future<void> main() async {
final library = await DynamicLibrary.open('path to wasm or js'); // NOTE: It is async
final func = library.lookupFunction<int Function(), int Function()>('functionName');
print(func());
}
```
[![Repo]](https://github.com/vm75/wasm_ffi/universal_ffi)
![Pub Version](https://img.shields.io/pub/v/wasm_ffi)
![Pub Points](https://img.shields.io/pub/points/universal_ffi)
![Pub Popularity](https://img.shields.io/pub/popularity/universal_ffi)
![Pub Likes](https://img.shields.io/pub/likes/universal_ffi)

## Differences to dart:ffi
While `wasm_ffi` tries to mimic the `dart:ffi` API as close as possible, there are some differences. The list below documents the most importent ones, make sure to read it. For more insight, take a look at the API documentation.
---

* The [`DynamicLibrary`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi/DynamicLibrary-class.html) class constructor is different. One key difference is that the 'load' method is asynchronous.
* If more than one library is loaded, it is recommended to use `FfiWrapper:safeUsing` instead of `using`, as it ensure that the correct memory is used.
* Each library has its own memory, so objects cannot be shared between libraries.
* Some advanced types are still unsupported.
* There are some classes and functions that are present in `wasm_ffi` but not in `dart:ffi`; such things are annotated with [`@extra`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi_meta/extra-constant.html).
* There is a new class [`Memory`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi_modules/Memory-class.html) which is **IMPORTANT** and explained in deepth below.
* If you extend the [`Opaque`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi/Opaque-class.html) class, you must register the extended class using [`@extra registerOpaqueType<T>()`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi_modules/registerOpaqueType.html) before using it! Also, your class MUST NOT have type arguments (what should not be a problem).
* There are some rules concerning interacting with native functions, as listed below.
**Native Ffi** provides a simple way to use the same native(C/C++) code across multiple platforms. Contributions are welcome! 🚀

## Rules for functions (TODO: needs update)
There are some rules and things to notice when working with functions:
* When looking up a function using [`DynamicLibrary.lookup<NativeFunction<NF>>()`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi/DynamicLibrary/lookup.html) (or [`DynamicLibraryExtension.lookupFunction<T extends Function, F extends Function>()`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi/DynamicLibraryExtension/lookupFunction.html)) the actuall type argument `NF` (or `T` respectively) of is not used: There is no type checking, if the function exported from `WebAssembly` has the same signature or amount of parameters, only the name is looked up.
* There are special constraints on the return type (not on parameter types) of functions `DF` (or `F` ) if you call [`NativeFunctionPointer.asFunction<DF>()`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi/NativeFunctionPointer/asFunction.html) (or [`DynamicLibraryExtension.lookupFunction<T extends Function, F extends Function>()`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi/DynamicLibraryExtension/lookupFunction.html) what uses the former internally):
* You may nest the pointer type up to two times but not more:
* e.g. `Pointer<Int32>` and `Pointer<Pointer<Int32>>` are allowed but `Pointer<Pointer<Pointer<Int32>>>` is not.
* If the return type is `Pointer<NativeFunction>` you MUST use `Pointer<NativeFunction<dynamic>>`, everything else will fail. You can restore the type arguments afterwards yourself using casting. On the other hand, as stated above, type arguments for `NativeFunction`s are just ignored anyway.
* To concretize the things above, [return_types.md](https://github.com/vm75/wasm_ffi/tree/main/return_types.md) lists what may be used as return type, everyhing else will cause a runtime error.
* WORKAROUND: If you need something else (e.g. `Pointer<Pointer<Pointer<Double>>>`), use `Pointer<IntPtr>` and cast it yourselfe afterwards using [`Pointer.cast()`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi/Pointer/cast.html).
[license_url]: https://github.com/vm75/wasm_ffi/blob/main/LICENSE
[build_url]: https://github.com/vm75/wasm_ffi/actions

## Memory (TODO: needs update)
NOTE: While most of this section is still correct, some of it is now automated.
The first call you sould do when you want to use `wasm_ffi` is [`Memory.init()`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi_modules/Memory/init.html). It has an optional parameter where you can adjust your pointer size. The argument defaults to 4 to represent 32bit pointers, if you use wasm64, call `Memory.init(8)`.
Contraty to `dart:ffi` where the dart process shares all the memory, on `WebAssembly`, each instance is bound to a `WebAssembly.Memory` object. For now, we assume that every `WebAssembly` module you use has it's own memory. If you think we should change that, open a issue on [GitHub](https://github.com/vm75/wasm_ffi/) and report your usecase.
Every pointer you use is bound to a memory object. This memory object is accessible using the [`@extra Pointer.boundMemory`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi/Pointer/boundMemory.html) field. If you want to create a Pointer using the [`Pointer.fromAddress()`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi/Pointer/Pointer.fromAddress.html) constructor, you may notice the optional `bindTo` parameter. Since each pointer must be bound to a memory object, you can explicitly speficy a memory object here. To match the `dart:ffi` API, the `bindTo` parameter is optional. Because it is optional, there has to be a fallback mechanism if no `bindTo` is specified: The static [`Memory.global`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi_modules/Memory/global.html) field. If that field is also not set, an exception is thrown when invoking the `Pointer.fromAddress()` constructor.
Also, each [`DynamicLibrary`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi/DynamicLibrary-class.html) is bound to a memory object, which is again accessible with [`@extra DynamicLibrary.boundMemory`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi/DynamicLibrary/boundMemory.html). This might come in handy, since `Memory` implements the [`Allocator`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi/Allocator-class.html) class.
[License]: https://img.shields.io/badge/license-MIT-blue.svg
[Build]: https://img.shields.io/github/actions/workflow/status/vm75/wasm_ffi/.github/workflows/publish.yml?branch=main
[Repo]: https://img.shields.io/badge/Repo-gray?style=flat&logo=Github
43 changes: 0 additions & 43 deletions example/.gitignore

This file was deleted.

45 changes: 0 additions & 45 deletions example/.metadata

This file was deleted.

Loading

0 comments on commit 270dea6

Please sign in to comment.