Add a .gitattributes file to specify eol=LF (#1370)
* Add a .gitattributes file specifying LF-style line endings. This is similar to [Rust's .gitattributes file] though simplified. Most of our source and documentation files already used LF-style line endings, including *.cs files, so this makes things more consistent. [Rust's .gitattributes file]: https://github.com/rust-lang/rust/blob/master/.gitattributes * Remove UTF-8 BOMs in *.cs files. Most of our *.cs files don't have UTF-8 BOMs, so this makes things more consistent.
This commit is contained in:
7
.gitattributes
vendored
Normal file
7
.gitattributes
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Use LF-style line endings for all text files.
|
||||||
|
* text=auto eol=lf
|
||||||
|
|
||||||
|
# Older git versions try to fix line endings on images, this prevents it.
|
||||||
|
*.png binary
|
||||||
|
*.ico binary
|
||||||
|
*.wasm binary
|
||||||
18
crates/misc/dotnet/docs/.gitignore
vendored
18
crates/misc/dotnet/docs/.gitignore
vendored
@@ -1,9 +1,9 @@
|
|||||||
###############
|
###############
|
||||||
# folder #
|
# folder #
|
||||||
###############
|
###############
|
||||||
/**/DROP/
|
/**/DROP/
|
||||||
/**/TEMP/
|
/**/TEMP/
|
||||||
/**/packages/
|
/**/packages/
|
||||||
/**/bin/
|
/**/bin/
|
||||||
/**/obj/
|
/**/obj/
|
||||||
_site
|
_site
|
||||||
|
|||||||
10
crates/misc/dotnet/docs/api/.gitignore
vendored
10
crates/misc/dotnet/docs/api/.gitignore
vendored
@@ -1,5 +1,5 @@
|
|||||||
###############
|
###############
|
||||||
# temp file #
|
# temp file #
|
||||||
###############
|
###############
|
||||||
*.yml
|
*.yml
|
||||||
.manifest
|
.manifest
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Wasmtime for NET
|
# Wasmtime for NET
|
||||||
|
|
||||||
This is the .NET API for [Wasmtime](https://github.com/bytecodealliance/wasmtime).
|
This is the .NET API for [Wasmtime](https://github.com/bytecodealliance/wasmtime).
|
||||||
|
|
||||||
See the [documentation](Wasmtime.html#classes) for the various .NET classes.
|
See the [documentation](Wasmtime.html#classes) for the various .NET classes.
|
||||||
@@ -1,211 +1,211 @@
|
|||||||
# Introduction to Wasmtime for .NET
|
# Introduction to Wasmtime for .NET
|
||||||
|
|
||||||
[Wasmtime](https://github.com/bytecodealliance/wasmtime) is a standalone runtime capable of executing [WebAssembly](https://webassembly.org/) outside of a web browser.
|
[Wasmtime](https://github.com/bytecodealliance/wasmtime) is a standalone runtime capable of executing [WebAssembly](https://webassembly.org/) outside of a web browser.
|
||||||
|
|
||||||
Wasmtime for .NET is a .NET API for Wasmtime. It enables .NET developers to easily instantiate and execute WebAssembly modules.
|
Wasmtime for .NET is a .NET API for Wasmtime. It enables .NET developers to easily instantiate and execute WebAssembly modules.
|
||||||
|
|
||||||
For this tutorial, we will create a WebAssembly module from a program written in Rust and use that WebAssembly module from a .NET Core 3.0 application.
|
For this tutorial, we will create a WebAssembly module from a program written in Rust and use that WebAssembly module from a .NET Core 3.0 application.
|
||||||
|
|
||||||
# Creating a simple WebAssembly module
|
# Creating a simple WebAssembly module
|
||||||
|
|
||||||
One of the reasons why WebAssembly is so exciting is that [many languages are able to target WebAssembly](https://github.com/appcypher/awesome-wasm-langs). This means, for example, a plugin model based on WebAssembly could enable developers to write sandboxed, cross-platform plugins in any number of languages.
|
One of the reasons why WebAssembly is so exciting is that [many languages are able to target WebAssembly](https://github.com/appcypher/awesome-wasm-langs). This means, for example, a plugin model based on WebAssembly could enable developers to write sandboxed, cross-platform plugins in any number of languages.
|
||||||
|
|
||||||
Here I've decided to use [Rust](https://www.rust-lang.org/) for the implementation of the WebAssembly module. Rust is a modern systems programming language that can easily target WebAssembly.
|
Here I've decided to use [Rust](https://www.rust-lang.org/) for the implementation of the WebAssembly module. Rust is a modern systems programming language that can easily target WebAssembly.
|
||||||
|
|
||||||
If you wish to skip creating the WebAssembly module, download the [prebuilt WebAssembly module](https://raw.githubusercontent.com/bytecodealliance/wasmtime/master/crates/misc/dotnet/docs/wasm/intro/hello.wasm) from this tutorial, copy it to your .NET project directory, and continue from the _[Using the WebAssembly module from .NET](#using-the-webassembly-module-from-net)_ section.
|
If you wish to skip creating the WebAssembly module, download the [prebuilt WebAssembly module](https://raw.githubusercontent.com/bytecodealliance/wasmtime/master/crates/misc/dotnet/docs/wasm/intro/hello.wasm) from this tutorial, copy it to your .NET project directory, and continue from the _[Using the WebAssembly module from .NET](#using-the-webassembly-module-from-net)_ section.
|
||||||
|
|
||||||
## Installing a Rust toolchain
|
## Installing a Rust toolchain
|
||||||
|
|
||||||
To get started with Rust, install [rustup](https://rustup.rs/), the manager for Rust toolchains.
|
To get started with Rust, install [rustup](https://rustup.rs/), the manager for Rust toolchains.
|
||||||
|
|
||||||
This will install both a `rustup` command and a `cargo` command (for the active Rust toolchain) to your PATH.
|
This will install both a `rustup` command and a `cargo` command (for the active Rust toolchain) to your PATH.
|
||||||
|
|
||||||
## Installing the WebAssembly target
|
## Installing the WebAssembly target
|
||||||
|
|
||||||
To target WebAssembly with the active Rust toolchain, install the WebAssembly [target triple](https://forge.rust-lang.org/release/platform-support.html):
|
To target WebAssembly with the active Rust toolchain, install the WebAssembly [target triple](https://forge.rust-lang.org/release/platform-support.html):
|
||||||
|
|
||||||
```text
|
```text
|
||||||
rustup target add wasm32-unknown-unknown
|
rustup target add wasm32-unknown-unknown
|
||||||
```
|
```
|
||||||
|
|
||||||
## Creating the Rust project
|
## Creating the Rust project
|
||||||
|
|
||||||
Create a new Rust library project named `hello`:
|
Create a new Rust library project named `hello`:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
cargo new --lib hello
|
cargo new --lib hello
|
||||||
cd hello
|
cd hello
|
||||||
```
|
```
|
||||||
|
|
||||||
To target WebAssembly, the library needs to be built as a `cdylib` (dynamic library) rather than the default of a static Rust library. Add the following to the `Cargo.toml` file in the project root:
|
To target WebAssembly, the library needs to be built as a `cdylib` (dynamic library) rather than the default of a static Rust library. Add the following to the `Cargo.toml` file in the project root:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Implementing the WebAssembly code
|
## Implementing the WebAssembly code
|
||||||
|
|
||||||
The WebAssembly implementation will import a `print` function from the host environment and pass it a string to print. It will export a `run` function that will invoke the imported `print` function.
|
The WebAssembly implementation will import a `print` function from the host environment and pass it a string to print. It will export a `run` function that will invoke the imported `print` function.
|
||||||
|
|
||||||
Replace the code in `src/lib.rs` with the following Rust code:
|
Replace the code in `src/lib.rs` with the following Rust code:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn print(address: i32, length: i32);
|
fn print(address: i32, length: i32);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern fn run() {
|
pub unsafe extern fn run() {
|
||||||
let message = "Hello world!";
|
let message = "Hello world!";
|
||||||
print(message.as_ptr() as i32, message.len() as i32);
|
print(message.as_ptr() as i32, message.len() as i32);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that this example passes the string as a pair of _address and length_. This is because WebAssembly only supports a few core types (such as integers and floats) and a "string" has no native representation in WebAssembly.
|
Note that this example passes the string as a pair of _address and length_. This is because WebAssembly only supports a few core types (such as integers and floats) and a "string" has no native representation in WebAssembly.
|
||||||
|
|
||||||
In the future, WebAssembly will support [interface types](https://hacks.mozilla.org/2019/08/webassembly-interface-types/) that will enable higher-level abstractions of types like strings so they can be represented in a natural way.
|
In the future, WebAssembly will support [interface types](https://hacks.mozilla.org/2019/08/webassembly-interface-types/) that will enable higher-level abstractions of types like strings so they can be represented in a natural way.
|
||||||
|
|
||||||
Also note that the _address_ is not actually a physical memory address within the address space of a process but an address within the _[WebAssembly memory](https://hacks.mozilla.org/2017/07/memory-in-webassembly-and-why-its-safer-than-you-think/)_ of the module. Thus the WebAssembly module has no direct access to the memory of the host environment.
|
Also note that the _address_ is not actually a physical memory address within the address space of a process but an address within the _[WebAssembly memory](https://hacks.mozilla.org/2017/07/memory-in-webassembly-and-why-its-safer-than-you-think/)_ of the module. Thus the WebAssembly module has no direct access to the memory of the host environment.
|
||||||
|
|
||||||
## Building the WebAssembly module
|
## Building the WebAssembly module
|
||||||
|
|
||||||
Use `cargo build` to build the WebAssembly module:
|
Use `cargo build` to build the WebAssembly module:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
cargo build --target wasm32-unknown-unknown --release
|
cargo build --target wasm32-unknown-unknown --release
|
||||||
```
|
```
|
||||||
|
|
||||||
This should create a `hello.wasm` file in the `target/wasm32-unknown-unknown/release` directory. We will use `hello.wasm` in the next section of the tutorial.
|
This should create a `hello.wasm` file in the `target/wasm32-unknown-unknown/release` directory. We will use `hello.wasm` in the next section of the tutorial.
|
||||||
|
|
||||||
As this example is very simple and does not require any of the data from the custom sections of the WebAssembly module, you may use `wasm-strip` if you have the [WebAssembly Binary Toolkit](https://github.com/WebAssembly/wabt) installed:
|
As this example is very simple and does not require any of the data from the custom sections of the WebAssembly module, you may use `wasm-strip` if you have the [WebAssembly Binary Toolkit](https://github.com/WebAssembly/wabt) installed:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
wasm-strip target/wasm32-unknown-unknown/release/hello.wasm
|
wasm-strip target/wasm32-unknown-unknown/release/hello.wasm
|
||||||
```
|
```
|
||||||
|
|
||||||
The resulting file should be less than 200 bytes.
|
The resulting file should be less than 200 bytes.
|
||||||
|
|
||||||
# Using the WebAssembly module from .NET
|
# Using the WebAssembly module from .NET
|
||||||
|
|
||||||
## Installing a .NET Core 3.0 SDK
|
## Installing a .NET Core 3.0 SDK
|
||||||
|
|
||||||
Install a [.NET Core 3.0 SDK](https://dotnet.microsoft.com/download/dotnet-core/3.0) for your platform if you haven't already.
|
Install a [.NET Core 3.0 SDK](https://dotnet.microsoft.com/download/dotnet-core/3.0) for your platform if you haven't already.
|
||||||
|
|
||||||
This will add a `dotnet` command to your PATH.
|
This will add a `dotnet` command to your PATH.
|
||||||
|
|
||||||
## Creating the .NET Core project
|
## Creating the .NET Core project
|
||||||
|
|
||||||
The .NET program will be a simple console application, so create a new console project with `dotnet new`:
|
The .NET program will be a simple console application, so create a new console project with `dotnet new`:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
mkdir tutorial
|
mkdir tutorial
|
||||||
cd tutorial
|
cd tutorial
|
||||||
dotnet new console
|
dotnet new console
|
||||||
```
|
```
|
||||||
|
|
||||||
## Referencing the Wasmtime for .NET package
|
## Referencing the Wasmtime for .NET package
|
||||||
|
|
||||||
To use Wasmtime for .NET from the project, we need to add a reference to the [Wasmtime NuGet package](https://www.nuget.org/packages/Wasmtime):
|
To use Wasmtime for .NET from the project, we need to add a reference to the [Wasmtime NuGet package](https://www.nuget.org/packages/Wasmtime):
|
||||||
|
|
||||||
```text
|
```text
|
||||||
dotnet add package --version 0.0.1-alpha1 wasmtime
|
dotnet add package --version 0.0.1-alpha1 wasmtime
|
||||||
```
|
```
|
||||||
|
|
||||||
_Note that the `--version` option is required because the package is currently prerelease._
|
_Note that the `--version` option is required because the package is currently prerelease._
|
||||||
|
|
||||||
This will add a `PackageReference` to the project file so that Wasmtime for .NET can be used.
|
This will add a `PackageReference` to the project file so that Wasmtime for .NET can be used.
|
||||||
|
|
||||||
## Implementing the .NET code
|
## Implementing the .NET code
|
||||||
|
|
||||||
Replace the contents of `Program.cs` with the following:
|
Replace the contents of `Program.cs` with the following:
|
||||||
|
|
||||||
```c#
|
```c#
|
||||||
using System;
|
using System;
|
||||||
using Wasmtime;
|
using Wasmtime;
|
||||||
|
|
||||||
namespace Tutorial
|
namespace Tutorial
|
||||||
{
|
{
|
||||||
class Host : IHost
|
class Host : IHost
|
||||||
{
|
{
|
||||||
public Instance Instance { get; set; }
|
public Instance Instance { get; set; }
|
||||||
|
|
||||||
[Import("print", Module="env")]
|
[Import("print", Module="env")]
|
||||||
public void Print(int address, int length)
|
public void Print(int address, int length)
|
||||||
{
|
{
|
||||||
var message = Instance.Externs.Memories[0].ReadString(address, length);
|
var message = Instance.Externs.Memories[0].ReadString(address, length);
|
||||||
Console.WriteLine(message);
|
Console.WriteLine(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Program
|
class Program
|
||||||
{
|
{
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
using var engine = new Engine();
|
using var engine = new Engine();
|
||||||
using var store = engine.CreateStore();
|
using var store = engine.CreateStore();
|
||||||
using var module = store.CreateModule("hello.wasm");
|
using var module = store.CreateModule("hello.wasm");
|
||||||
using dynamic instance = module.Instantiate(new Host());
|
using dynamic instance = module.Instantiate(new Host());
|
||||||
|
|
||||||
instance.run();
|
instance.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Host` class is responsible for implementing the imported [functions](https://webassembly.github.io/spec/core/syntax/modules.html#functions), [globals](https://webassembly.github.io/spec/core/syntax/modules.html#globals), [memories](https://webassembly.github.io/spec/core/syntax/modules.html#memories), and [tables](https://webassembly.github.io/spec/core/syntax/modules.html#syntax-table) for the WebAssembly module. For Wasmtime for .NET, this is done via the [`Import`](https://peterhuene.github.io/wasmtime.net/api/Wasmtime.ImportAttribute.html) attribute applied to functions and fields of type [`Global<T>`](https://peterhuene.github.io/wasmtime.net/api/Wasmtime.Global-1.html), [`MutableGlobal<T>`](https://peterhuene.github.io/wasmtime.net/api/Wasmtime.MutableGlobal-1.html), and [`Memory`](https://peterhuene.github.io/wasmtime.net/api/Wasmtime.Memory.html) (support for WebAssembly tables is not yet implemented). The [`Instance`](https://peterhuene.github.io/wasmtime.net/api/Wasmtime.IHost.html#Wasmtime_IHost_Instance) property of the host is set during instantiation of the WebAssembly module.
|
The `Host` class is responsible for implementing the imported [functions](https://webassembly.github.io/spec/core/syntax/modules.html#functions), [globals](https://webassembly.github.io/spec/core/syntax/modules.html#globals), [memories](https://webassembly.github.io/spec/core/syntax/modules.html#memories), and [tables](https://webassembly.github.io/spec/core/syntax/modules.html#syntax-table) for the WebAssembly module. For Wasmtime for .NET, this is done via the [`Import`](https://peterhuene.github.io/wasmtime.net/api/Wasmtime.ImportAttribute.html) attribute applied to functions and fields of type [`Global<T>`](https://peterhuene.github.io/wasmtime.net/api/Wasmtime.Global-1.html), [`MutableGlobal<T>`](https://peterhuene.github.io/wasmtime.net/api/Wasmtime.MutableGlobal-1.html), and [`Memory`](https://peterhuene.github.io/wasmtime.net/api/Wasmtime.Memory.html) (support for WebAssembly tables is not yet implemented). The [`Instance`](https://peterhuene.github.io/wasmtime.net/api/Wasmtime.IHost.html#Wasmtime_IHost_Instance) property of the host is set during instantiation of the WebAssembly module.
|
||||||
|
|
||||||
Here the host is implementing an import of `print` in the `env` module, which is the default import module name for WebAssembly modules compiled using the Rust toolchain.
|
Here the host is implementing an import of `print` in the `env` module, which is the default import module name for WebAssembly modules compiled using the Rust toolchain.
|
||||||
|
|
||||||
The [`Engine`](https://peterhuene.github.io/wasmtime.net/api/Wasmtime.Engine.html) is used to create a [`Store`](https://peterhuene.github.io/wasmtime.net/api/Wasmtime.Store.html) that will store all Wasmtime runtime objects, such as WebAssembly modules and their instantiations.
|
The [`Engine`](https://peterhuene.github.io/wasmtime.net/api/Wasmtime.Engine.html) is used to create a [`Store`](https://peterhuene.github.io/wasmtime.net/api/Wasmtime.Store.html) that will store all Wasmtime runtime objects, such as WebAssembly modules and their instantiations.
|
||||||
|
|
||||||
A WebAssembly module _instantiation_ is the stateful representation of a module that can be executed. Here, the code is casting the [`Instance`](https://peterhuene.github.io/wasmtime.net/api/Wasmtime.Instance.html) to [`dynamic`](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/using-type-dynamic) which allows us to easily invoke the `run` function that was exported by the WebAssembly module.
|
A WebAssembly module _instantiation_ is the stateful representation of a module that can be executed. Here, the code is casting the [`Instance`](https://peterhuene.github.io/wasmtime.net/api/Wasmtime.Instance.html) to [`dynamic`](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/using-type-dynamic) which allows us to easily invoke the `run` function that was exported by the WebAssembly module.
|
||||||
|
|
||||||
Alternatively, the `run` function could be invoked without using the runtime binding of the `dynamic` feature like this:
|
Alternatively, the `run` function could be invoked without using the runtime binding of the `dynamic` feature like this:
|
||||||
|
|
||||||
```c#
|
```c#
|
||||||
...
|
...
|
||||||
using var instance = module.Instantiate(new Host());
|
using var instance = module.Instantiate(new Host());
|
||||||
instance.Externs.Functions[0].Invoke();
|
instance.Externs.Functions[0].Invoke();
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
## Building the .NET application
|
## Building the .NET application
|
||||||
|
|
||||||
Use `dotnet build` to build the .NET application:
|
Use `dotnet build` to build the .NET application:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
dotnet build
|
dotnet build
|
||||||
```
|
```
|
||||||
|
|
||||||
This will create a `tutorial.dll` in the `bin/Debug/netcoreapp3.0` directory that implements the .NET Core application. An executable `tutorial` (or `tutorial.exe` on Windows) should also be present in the same directory to run the application.
|
This will create a `tutorial.dll` in the `bin/Debug/netcoreapp3.0` directory that implements the .NET Core application. An executable `tutorial` (or `tutorial.exe` on Windows) should also be present in the same directory to run the application.
|
||||||
|
|
||||||
## Running the .NET application
|
## Running the .NET application
|
||||||
|
|
||||||
Before running the application, we need to copy the `hello.wasm` file to the project directory.
|
Before running the application, we need to copy the `hello.wasm` file to the project directory.
|
||||||
|
|
||||||
Once the WebAssembly module is present in project directory, we can run the application:
|
Once the WebAssembly module is present in project directory, we can run the application:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
dotnet run
|
dotnet run
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternatively, we can execute the program directly without building the application again:
|
Alternatively, we can execute the program directly without building the application again:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
bin/Debug/netcoreapp3.0/tutorial
|
bin/Debug/netcoreapp3.0/tutorial
|
||||||
```
|
```
|
||||||
|
|
||||||
This should result in the following output:
|
This should result in the following output:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Hello world!
|
Hello world!
|
||||||
```
|
```
|
||||||
|
|
||||||
# Wrapping up
|
# Wrapping up
|
||||||
|
|
||||||
We did it! We executed a function written in Rust from .NET and a function implemented in .NET from Rust without much trouble at all. And, thanks to the design of WebAssembly, the Rust code was effectively sandboxed from accessing the memory of the .NET application.
|
We did it! We executed a function written in Rust from .NET and a function implemented in .NET from Rust without much trouble at all. And, thanks to the design of WebAssembly, the Rust code was effectively sandboxed from accessing the memory of the .NET application.
|
||||||
|
|
||||||
Hopefully this introduction to Wasmtime for .NET has offered a small glipse of the potential of using WebAssembly from .NET.
|
Hopefully this introduction to Wasmtime for .NET has offered a small glipse of the potential of using WebAssembly from .NET.
|
||||||
|
|
||||||
One last note: _Wasmtime for .NET is currently in a very early stage of development and the API might change dramatically in the future_.
|
One last note: _Wasmtime for .NET is currently in a very early stage of development and the API might change dramatically in the future_.
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
- name: Introduction to Wasmtime for .NET
|
- name: Introduction to Wasmtime for .NET
|
||||||
href: intro.md
|
href: intro.md
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Wasmtime for .NET
|
# Wasmtime for .NET
|
||||||
|
|
||||||
A .NET API for [Wasmtime](https://github.com/bytecodealliance/wasmtime).
|
A .NET API for [Wasmtime](https://github.com/bytecodealliance/wasmtime).
|
||||||
|
|
||||||
Wasmtime is a standalone runtime for [WebAssembly](https://webassembly.org/), using the Cranelift JIT compiler.
|
Wasmtime is a standalone runtime for [WebAssembly](https://webassembly.org/), using the Cranelift JIT compiler.
|
||||||
|
|
||||||
Wasmtime for .NET enables .NET code to instantiate WebAssembly modules and to interact with them in-process.
|
Wasmtime for .NET enables .NET code to instantiate WebAssembly modules and to interact with them in-process.
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
{{!Copyright (c) Oscar Vasquez. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
|
{{!Copyright (c) Oscar Vasquez. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<title>{{#title}}{{title}}{{/title}}{{^title}}{{>partials/title}}{{/title}} {{#_appTitle}}| {{_appTitle}} {{/_appTitle}}</title>
|
<title>{{#title}}{{title}}{{/title}}{{^title}}{{>partials/title}}{{/title}} {{#_appTitle}}| {{_appTitle}} {{/_appTitle}}</title>
|
||||||
<meta name="viewport" content="width=device-width">
|
<meta name="viewport" content="width=device-width">
|
||||||
<meta name="title" content="{{#title}}{{title}}{{/title}}{{^title}}{{>partials/title}}{{/title}} {{#_appTitle}}| {{_appTitle}} {{/_appTitle}}">
|
<meta name="title" content="{{#title}}{{title}}{{/title}}{{^title}}{{>partials/title}}{{/title}} {{#_appTitle}}| {{_appTitle}} {{/_appTitle}}">
|
||||||
<meta name="generator" content="docfx {{_docfxVersion}}">
|
<meta name="generator" content="docfx {{_docfxVersion}}">
|
||||||
{{#_description}}<meta name="description" content="{{_description}}">{{/_description}}
|
{{#_description}}<meta name="description" content="{{_description}}">{{/_description}}
|
||||||
<link rel="shortcut icon" href="{{_rel}}{{{_appFaviconPath}}}{{^_appFaviconPath}}favicon.ico{{/_appFaviconPath}}">
|
<link rel="shortcut icon" href="{{_rel}}{{{_appFaviconPath}}}{{^_appFaviconPath}}favicon.ico{{/_appFaviconPath}}">
|
||||||
<link rel="stylesheet" href="{{_rel}}styles/docfx.vendor.css">
|
<link rel="stylesheet" href="{{_rel}}styles/docfx.vendor.css">
|
||||||
<link rel="stylesheet" href="{{_rel}}styles/docfx.css">
|
<link rel="stylesheet" href="{{_rel}}styles/docfx.css">
|
||||||
<link rel="stylesheet" href="{{_rel}}styles/main.css">
|
<link rel="stylesheet" href="{{_rel}}styles/main.css">
|
||||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">
|
||||||
<meta property="docfx:navrel" content="{{_navRel}}">
|
<meta property="docfx:navrel" content="{{_navRel}}">
|
||||||
<meta property="docfx:tocrel" content="{{_tocRel}}">
|
<meta property="docfx:tocrel" content="{{_tocRel}}">
|
||||||
{{#_noindex}}<meta name="searchOption" content="noindex">{{/_noindex}}
|
{{#_noindex}}<meta name="searchOption" content="noindex">{{/_noindex}}
|
||||||
{{#_enableSearch}}<meta property="docfx:rel" content="{{_rel}}">{{/_enableSearch}}
|
{{#_enableSearch}}<meta property="docfx:rel" content="{{_rel}}">{{/_enableSearch}}
|
||||||
{{#_enableNewTab}}<meta property="docfx:newtab" content="true">{{/_enableNewTab}}
|
{{#_enableNewTab}}<meta property="docfx:newtab" content="true">{{/_enableNewTab}}
|
||||||
</head>
|
</head>
|
||||||
@@ -1,394 +1,394 @@
|
|||||||
body {
|
body {
|
||||||
color: #ccd5dc;
|
color: #ccd5dc;
|
||||||
font-family: "Open Sans",sans-serif;
|
font-family: "Open Sans",sans-serif;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
-ms-text-size-adjust: 100%;
|
-ms-text-size-adjust: 100%;
|
||||||
-webkit-text-size-adjust: 100%;
|
-webkit-text-size-adjust: 100%;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
background-color: #2d2d30;
|
background-color: #2d2d30;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 32px;
|
font-size: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
line-height: 1.8;
|
line-height: 1.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
line-height: 1.8;
|
line-height: 1.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
h5 {
|
h5 {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding: 10px 0px;
|
padding: 10px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
article h1,
|
article h1,
|
||||||
article h2,
|
article h2,
|
||||||
article h3,
|
article h3,
|
||||||
article h4 {
|
article h4 {
|
||||||
margin-top: 35px;
|
margin-top: 35px;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
article h4 {
|
article h4 {
|
||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
border-bottom: 2px solid #ddd;
|
border-bottom: 2px solid #ddd;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-brand>img {
|
.navbar-brand>img {
|
||||||
color: #2d2d30;
|
color: #2d2d30;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar {
|
.navbar {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.subnav {
|
.subnav {
|
||||||
border-top: 1px solid #ddd;
|
border-top: 1px solid #ddd;
|
||||||
background-color: #333337;
|
background-color: #333337;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-inverse {
|
.navbar-inverse {
|
||||||
background-color: #1e1e1e;
|
background-color: #1e1e1e;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-inverse .navbar-nav>li>a,
|
.navbar-inverse .navbar-nav>li>a,
|
||||||
.navbar-inverse .navbar-text {
|
.navbar-inverse .navbar-text {
|
||||||
color: #66666d;
|
color: #66666d;
|
||||||
background-color: #1e1e1e;
|
background-color: #1e1e1e;
|
||||||
border-bottom: 3px solid transparent;
|
border-bottom: 3px solid transparent;
|
||||||
padding-bottom: 12px;
|
padding-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-inverse .navbar-nav>li>a:focus,
|
.navbar-inverse .navbar-nav>li>a:focus,
|
||||||
.navbar-inverse .navbar-nav>li>a:hover {
|
.navbar-inverse .navbar-nav>li>a:hover {
|
||||||
color: #c5c5de;
|
color: #c5c5de;
|
||||||
background-color: #1e1e1e;
|
background-color: #1e1e1e;
|
||||||
border-bottom: 3px solid #333337;
|
border-bottom: 3px solid #333337;
|
||||||
transition: all ease 0.25s;
|
transition: all ease 0.25s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-inverse .navbar-nav>.active>a,
|
.navbar-inverse .navbar-nav>.active>a,
|
||||||
.navbar-inverse .navbar-nav>.active>a:focus,
|
.navbar-inverse .navbar-nav>.active>a:focus,
|
||||||
.navbar-inverse .navbar-nav>.active>a:hover {
|
.navbar-inverse .navbar-nav>.active>a:hover {
|
||||||
color: #c5c5de;
|
color: #c5c5de;
|
||||||
background-color: #1e1e1e;
|
background-color: #1e1e1e;
|
||||||
border-bottom: 3px solid #333337;
|
border-bottom: 3px solid #333337;
|
||||||
transition: all ease 0.25s;
|
transition: all ease 0.25s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-form .form-control {
|
.navbar-form .form-control {
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toc .level1>li {
|
.toc .level1>li {
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toc .nav>li>a {
|
.toc .nav>li>a {
|
||||||
color: #ccd5dc;
|
color: #ccd5dc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidefilter {
|
.sidefilter {
|
||||||
background-color: #2d2d30;
|
background-color: #2d2d30;
|
||||||
border-left: none;
|
border-left: none;
|
||||||
border-right: none;
|
border-right: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidefilter {
|
.sidefilter {
|
||||||
background-color: #2d2d30;
|
background-color: #2d2d30;
|
||||||
border-left: none;
|
border-left: none;
|
||||||
border-right: none;
|
border-right: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toc-filter {
|
.toc-filter {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
background-color: #2d2d30;
|
background-color: #2d2d30;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toc-filter>input {
|
.toc-filter>input {
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: unset;
|
border-radius: unset;
|
||||||
background-color: #333337;
|
background-color: #333337;
|
||||||
padding: 5px 0 5px 20px;
|
padding: 5px 0 5px 20px;
|
||||||
font-size: 90%
|
font-size: 90%
|
||||||
}
|
}
|
||||||
|
|
||||||
.toc-filter>input:focus {
|
.toc-filter>input:focus {
|
||||||
color: #ccd5dc;
|
color: #ccd5dc;
|
||||||
transition: all ease 0.25s;
|
transition: all ease 0.25s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toc-filter>.filter-icon {
|
.toc-filter>.filter-icon {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidetoc>.toc {
|
.sidetoc>.toc {
|
||||||
background-color: #2d2d30;
|
background-color: #2d2d30;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidetoc {
|
.sidetoc {
|
||||||
background-color: #2d2d30;
|
background-color: #2d2d30;
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.alert {
|
.alert {
|
||||||
background-color: inherit;
|
background-color: inherit;
|
||||||
border: none;
|
border: none;
|
||||||
padding: 10px 0;
|
padding: 10px 0;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.alert>p {
|
.alert>p {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
border-bottom: 1px solid;
|
border-bottom: 1px solid;
|
||||||
background-color: #212123;
|
background-color: #212123;
|
||||||
}
|
}
|
||||||
|
|
||||||
.alert>h5 {
|
.alert>h5 {
|
||||||
padding: 10px 15px;
|
padding: 10px 15px;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
border-top: 2px solid;
|
border-top: 2px solid;
|
||||||
background-color: #212123;
|
background-color: #212123;
|
||||||
border-radius: none;
|
border-radius: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.alert>ul {
|
.alert>ul {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
padding: 5px 40px;
|
padding: 5px 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.alert-info{
|
.alert-info{
|
||||||
color: #1976d2;
|
color: #1976d2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.alert-warning{
|
.alert-warning{
|
||||||
color: #f57f17;
|
color: #f57f17;
|
||||||
}
|
}
|
||||||
|
|
||||||
.alert-danger{
|
.alert-danger{
|
||||||
color: #d32f2f;
|
color: #d32f2f;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
padding: 9.5px;
|
padding: 9.5px;
|
||||||
margin: 0 0 10px;
|
margin: 0 0 10px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
background-color: #1e1e1e;;
|
background-color: #1e1e1e;;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
code{
|
code{
|
||||||
background: #1e1e1e !important;
|
background: #1e1e1e !important;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hljs{
|
.hljs{
|
||||||
color: #bbb;
|
color: #bbb;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toc .nav > li.active > .expand-stub::before, .toc .nav > li.in > .expand-stub::before, .toc .nav > li.in.active > .expand-stub::before, .toc .nav > li.filtered > .expand-stub::before {
|
.toc .nav > li.active > .expand-stub::before, .toc .nav > li.in > .expand-stub::before, .toc .nav > li.in.active > .expand-stub::before, .toc .nav > li.filtered > .expand-stub::before {
|
||||||
content: "▾";
|
content: "▾";
|
||||||
}
|
}
|
||||||
|
|
||||||
.toc .nav > li > .expand-stub::before, .toc .nav > li.active > .expand-stub::before {
|
.toc .nav > li > .expand-stub::before, .toc .nav > li.active > .expand-stub::before {
|
||||||
content: "▸";
|
content: "▸";
|
||||||
}
|
}
|
||||||
|
|
||||||
.affix ul ul > li > a:before {
|
.affix ul ul > li > a:before {
|
||||||
content: "|";
|
content: "|";
|
||||||
}
|
}
|
||||||
|
|
||||||
.breadcrumb .label.label-primary {
|
.breadcrumb .label.label-primary {
|
||||||
background: #444;
|
background: #444;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#breadcrumb .breadcrumb>li a {
|
#breadcrumb .breadcrumb>li a {
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-size: 85%;
|
font-size: 85%;
|
||||||
display: inline;
|
display: inline;
|
||||||
padding: 0 .6em 0;
|
padding: 0 .6em 0;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
vertical-align: baseline;
|
vertical-align: baseline;
|
||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
#breadcrumb .breadcrumb>li a:hover{
|
#breadcrumb .breadcrumb>li a:hover{
|
||||||
color: #c5c5de;
|
color: #c5c5de;
|
||||||
transition: all ease 0.25s;
|
transition: all ease 0.25s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.breadcrumb > li + li:before {
|
.breadcrumb > li + li:before {
|
||||||
content: "⯈";
|
content: "⯈";
|
||||||
font-size: 75%;
|
font-size: 75%;
|
||||||
color: #1e1e1e;
|
color: #1e1e1e;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toc .level1>li {
|
.toc .level1>li {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 130%;
|
font-size: 130%;
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
border-top: none;
|
border-top: none;
|
||||||
background-color: #1e1e1e;
|
background-color: #1e1e1e;
|
||||||
padding: 15px 0;
|
padding: 15px 0;
|
||||||
font-size: 90%;
|
font-size: 90%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toc .nav > li > a:hover, .toc .nav > li > a:focus {
|
.toc .nav > li > a:hover, .toc .nav > li > a:focus {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
transition: all ease 0.1s;
|
transition: all ease 0.1s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-control {
|
.form-control {
|
||||||
background-color: #333337;
|
background-color: #333337;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
-webkit-box-shadow: none;
|
-webkit-box-shadow: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-control:focus {
|
.form-control:focus {
|
||||||
border-color: #66afe9;
|
border-color: #66afe9;
|
||||||
outline: 0;
|
outline: 0;
|
||||||
-webkit-box-shadow: none;
|
-webkit-box-shadow: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
input#search-query:focus {
|
input#search-query:focus {
|
||||||
color: #c5c5de;
|
color: #c5c5de;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-bordered, .table-bordered>tbody>tr>td, .table-bordered>tbody>tr>th, .table-bordered>tfoot>tr>td, .table-bordered>tfoot>tr>th, .table-bordered>thead>tr>td, .table-bordered>thead>tr>th {
|
.table-bordered, .table-bordered>tbody>tr>td, .table-bordered>tbody>tr>th, .table-bordered>tfoot>tr>td, .table-bordered>tfoot>tr>th, .table-bordered>thead>tr>td, .table-bordered>thead>tr>th {
|
||||||
border: 1px solid #1E1E1E;
|
border: 1px solid #1E1E1E;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-striped>tbody>tr:nth-of-type(odd) {
|
.table-striped>tbody>tr:nth-of-type(odd) {
|
||||||
background-color: #212123;
|
background-color: #212123;
|
||||||
}
|
}
|
||||||
|
|
||||||
blockquote {
|
blockquote {
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
margin: 0 0 10px;
|
margin: 0 0 10px;
|
||||||
font-size: 110%;
|
font-size: 110%;
|
||||||
border-left: 5px solid #69696e;
|
border-left: 5px solid #69696e;
|
||||||
color: #69696e;
|
color: #69696e;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pagination>.disabled>a, .pagination>.disabled>a:focus, .pagination>.disabled>a:hover, .pagination>.disabled>span, .pagination>.disabled>span:focus, .pagination>.disabled>span:hover {
|
.pagination>.disabled>a, .pagination>.disabled>a:focus, .pagination>.disabled>a:hover, .pagination>.disabled>span, .pagination>.disabled>span:focus, .pagination>.disabled>span:hover {
|
||||||
background-color: #333337;
|
background-color: #333337;
|
||||||
border-color: #333337;
|
border-color: #333337;
|
||||||
}
|
}
|
||||||
|
|
||||||
.breadcrumb>li, .pagination {
|
.breadcrumb>li, .pagination {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 1600px){
|
@media (min-width: 1600px){
|
||||||
.container {
|
.container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.sidefilter {
|
.sidefilter {
|
||||||
width: 20%;
|
width: 20%;
|
||||||
}
|
}
|
||||||
.sidetoc{
|
.sidetoc{
|
||||||
width: 20%;
|
width: 20%;
|
||||||
}
|
}
|
||||||
.article.grid-right {
|
.article.grid-right {
|
||||||
margin-left: 21%;
|
margin-left: 21%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
color:#8ec4f5;
|
color:#8ec4f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lang-text {
|
.lang-text {
|
||||||
color:#ccd5dc;
|
color:#ccd5dc;
|
||||||
}
|
}
|
||||||
|
|
||||||
button, a {
|
button, a {
|
||||||
color: #8ec4f5;
|
color: #8ec4f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.affix > ul > li.active > a, .affix > ul > li.active > a:before {
|
.affix > ul > li.active > a, .affix > ul > li.active > a:before {
|
||||||
color: #8ec4f5;
|
color: #8ec4f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.affix ul > li.active > a, .affix ul > li.active > a:before {
|
.affix ul > li.active > a, .affix ul > li.active > a:before {
|
||||||
color: #8ec4f5;
|
color: #8ec4f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.affix ul > li > a {
|
.affix ul > li > a {
|
||||||
color: #d3cfcf;
|
color: #d3cfcf;
|
||||||
}
|
}
|
||||||
|
|
||||||
button:hover, button:focus, a:hover, a:focus {
|
button:hover, button:focus, a:hover, a:focus {
|
||||||
color: #339eff;
|
color: #339eff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toc .nav > li.active > a {
|
.toc .nav > li.active > a {
|
||||||
color: #8ec4f5;
|
color: #8ec4f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toc .nav > li.active > a:hover, .toc .nav > li.active > a:focus {
|
.toc .nav > li.active > a:hover, .toc .nav > li.active > a:focus {
|
||||||
color: #339eff;
|
color: #339eff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-inverse .navbar-nav > li > a, .navbar-inverse .navbar-text {
|
.navbar-inverse .navbar-nav > li > a, .navbar-inverse .navbar-text {
|
||||||
color: #9898a6;
|
color: #9898a6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-inverse .navbar-nav>.active>a,
|
.navbar-inverse .navbar-nav>.active>a,
|
||||||
.navbar-inverse .navbar-nav>.active>a:focus,
|
.navbar-inverse .navbar-nav>.active>a:focus,
|
||||||
.navbar-inverse .navbar-nav>.active>a:hover {
|
.navbar-inverse .navbar-nav>.active>a:hover {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hljs-attr,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo,.hljs-title {
|
.hljs-attr,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo,.hljs-title {
|
||||||
color:#b685ff;
|
color:#b685ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hljs-keyword,.hljs-selector-tag,.hljs-type {
|
.hljs-keyword,.hljs-selector-tag,.hljs-type {
|
||||||
color:#cc74a6;
|
color:#cc74a6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hljs-emphasis,.hljs-quote,.hljs-string,.hljs-strong,.hljs-template-variable,.hljs-variable {
|
.hljs-emphasis,.hljs-quote,.hljs-string,.hljs-strong,.hljs-template-variable,.hljs-variable {
|
||||||
color:#cc74a6
|
color:#cc74a6
|
||||||
}
|
}
|
||||||
|
|
||||||
#breadcrumb .breadcrumb >li a {
|
#breadcrumb .breadcrumb >li a {
|
||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toc-filter > input {
|
.toc-filter > input {
|
||||||
color: #d3cfcf;
|
color: #d3cfcf;
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
- name: Articles
|
- name: Articles
|
||||||
href: articles/
|
href: articles/
|
||||||
- name: API Documentation
|
- name: API Documentation
|
||||||
href: api/
|
href: api/
|
||||||
homepage: api/index.md
|
homepage: api/index.md
|
||||||
- name: GitHub Repo
|
- name: GitHub Repo
|
||||||
href: https://github.com/bytecodealliance/wasmtime
|
href: https://github.com/bytecodealliance/wasmtime
|
||||||
|
|||||||
@@ -1,32 +1,32 @@
|
|||||||
using System;
|
using System;
|
||||||
using Wasmtime;
|
using Wasmtime;
|
||||||
|
|
||||||
namespace HelloExample
|
namespace HelloExample
|
||||||
{
|
{
|
||||||
class Host : IHost
|
class Host : IHost
|
||||||
{
|
{
|
||||||
public Instance Instance { get; set; }
|
public Instance Instance { get; set; }
|
||||||
|
|
||||||
[Import("print_global")]
|
[Import("print_global")]
|
||||||
public void PrintGlobal()
|
public void PrintGlobal()
|
||||||
{
|
{
|
||||||
Console.WriteLine($"The value of the global is: {Global.Value}.");
|
Console.WriteLine($"The value of the global is: {Global.Value}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Import("global")]
|
[Import("global")]
|
||||||
public readonly MutableGlobal<int> Global = new MutableGlobal<int>(1);
|
public readonly MutableGlobal<int> Global = new MutableGlobal<int>(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
class Program
|
class Program
|
||||||
{
|
{
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
using var engine = new Engine();
|
using var engine = new Engine();
|
||||||
using var store = engine.CreateStore();
|
using var store = engine.CreateStore();
|
||||||
using var module = store.CreateModule("global.wasm");
|
using var module = store.CreateModule("global.wasm");
|
||||||
using dynamic instance = module.Instantiate(new Host());
|
using dynamic instance = module.Instantiate(new Host());
|
||||||
|
|
||||||
instance.run(20);
|
instance.run(20);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\src\Wasmtime.csproj" />
|
<ProjectReference Include="..\..\src\Wasmtime.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!-- This is needed as we're not referencing Wasmtime as a package. -->
|
<!-- This is needed as we're not referencing Wasmtime as a package. -->
|
||||||
<Target Name="BuildWasmtime" BeforeTargets="AssignTargetPaths">
|
<Target Name="BuildWasmtime" BeforeTargets="AssignTargetPaths">
|
||||||
<Message Text="Building Wasmtime from source." Importance="High" />
|
<Message Text="Building Wasmtime from source." Importance="High" />
|
||||||
<Exec Command="$(BuildWasmtimeCommand)" StandardOutputImportance="Low" StandardErrorImportance="Low" />
|
<Exec Command="$(BuildWasmtimeCommand)" StandardOutputImportance="Low" StandardErrorImportance="Low" />
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="$(WasmtimeOutputPath)/$(WasmtimeLibraryFilename)" Link="$(WasmtimeLibraryFilename)" CopyToOutputDirectory="PreserveNewest" />
|
<None Include="$(WasmtimeOutputPath)/$(WasmtimeLibraryFilename)" Link="$(WasmtimeLibraryFilename)" CopyToOutputDirectory="PreserveNewest" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
using System;
|
using System;
|
||||||
using Wasmtime;
|
using Wasmtime;
|
||||||
|
|
||||||
namespace HelloExample
|
namespace HelloExample
|
||||||
{
|
{
|
||||||
class Host : IHost
|
class Host : IHost
|
||||||
{
|
{
|
||||||
public Instance Instance { get; set; }
|
public Instance Instance { get; set; }
|
||||||
|
|
||||||
[Import("hello")]
|
[Import("hello")]
|
||||||
public void SayHello()
|
public void SayHello()
|
||||||
{
|
{
|
||||||
Console.WriteLine("Hello from C#, WebAssembly!");
|
Console.WriteLine("Hello from C#, WebAssembly!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Program
|
class Program
|
||||||
{
|
{
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
using var engine = new Engine();
|
using var engine = new Engine();
|
||||||
using var store = engine.CreateStore();
|
using var store = engine.CreateStore();
|
||||||
using var module = store.CreateModule("hello.wasm");
|
using var module = store.CreateModule("hello.wasm");
|
||||||
using dynamic instance = module.Instantiate(new Host());
|
using dynamic instance = module.Instantiate(new Host());
|
||||||
|
|
||||||
instance.run();
|
instance.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\src\Wasmtime.csproj" />
|
<ProjectReference Include="..\..\src\Wasmtime.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!-- This is needed as we're not referencing Wasmtime as a package. -->
|
<!-- This is needed as we're not referencing Wasmtime as a package. -->
|
||||||
<Target Name="BuildWasmtime" BeforeTargets="AssignTargetPaths">
|
<Target Name="BuildWasmtime" BeforeTargets="AssignTargetPaths">
|
||||||
<Message Text="Building Wasmtime from source." Importance="High" />
|
<Message Text="Building Wasmtime from source." Importance="High" />
|
||||||
<Exec Command="$(BuildWasmtimeCommand)" StandardOutputImportance="Low" StandardErrorImportance="Low" />
|
<Exec Command="$(BuildWasmtimeCommand)" StandardOutputImportance="Low" StandardErrorImportance="Low" />
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="$(WasmtimeOutputPath)/$(WasmtimeLibraryFilename)" Link="$(WasmtimeLibraryFilename)" CopyToOutputDirectory="PreserveNewest" />
|
<None Include="$(WasmtimeOutputPath)/$(WasmtimeLibraryFilename)" Link="$(WasmtimeLibraryFilename)" CopyToOutputDirectory="PreserveNewest" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,30 +1,30 @@
|
|||||||
using System;
|
using System;
|
||||||
using Wasmtime;
|
using Wasmtime;
|
||||||
|
|
||||||
namespace HelloExample
|
namespace HelloExample
|
||||||
{
|
{
|
||||||
class Host : IHost
|
class Host : IHost
|
||||||
{
|
{
|
||||||
public Instance Instance { get; set; }
|
public Instance Instance { get; set; }
|
||||||
|
|
||||||
[Import("log")]
|
[Import("log")]
|
||||||
public void Log(int address, int length)
|
public void Log(int address, int length)
|
||||||
{
|
{
|
||||||
var message = Instance.Externs.Memories[0].ReadString(address, length);
|
var message = Instance.Externs.Memories[0].ReadString(address, length);
|
||||||
Console.WriteLine($"Message from WebAssembly: {message}");
|
Console.WriteLine($"Message from WebAssembly: {message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Program
|
class Program
|
||||||
{
|
{
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
using var engine = new Engine();
|
using var engine = new Engine();
|
||||||
using var store = engine.CreateStore();
|
using var store = engine.CreateStore();
|
||||||
using var module = store.CreateModule("memory.wasm");
|
using var module = store.CreateModule("memory.wasm");
|
||||||
using dynamic instance = module.Instantiate(new Host());
|
using dynamic instance = module.Instantiate(new Host());
|
||||||
|
|
||||||
instance.run();
|
instance.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\src\Wasmtime.csproj" />
|
<ProjectReference Include="..\..\src\Wasmtime.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!-- This is needed as we're not referencing Wasmtime as a package. -->
|
<!-- This is needed as we're not referencing Wasmtime as a package. -->
|
||||||
<Target Name="BuildWasmtime" BeforeTargets="AssignTargetPaths">
|
<Target Name="BuildWasmtime" BeforeTargets="AssignTargetPaths">
|
||||||
<Message Text="Building Wasmtime from source." Importance="High" />
|
<Message Text="Building Wasmtime from source." Importance="High" />
|
||||||
<Exec Command="$(BuildWasmtimeCommand)" StandardOutputImportance="Low" StandardErrorImportance="Low" />
|
<Exec Command="$(BuildWasmtimeCommand)" StandardOutputImportance="Low" StandardErrorImportance="Low" />
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="$(WasmtimeOutputPath)/$(WasmtimeLibraryFilename)" Link="$(WasmtimeLibraryFilename)" CopyToOutputDirectory="PreserveNewest" />
|
<None Include="$(WasmtimeOutputPath)/$(WasmtimeLibraryFilename)" Link="$(WasmtimeLibraryFilename)" CopyToOutputDirectory="PreserveNewest" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,85 +1,85 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Wasmtime
|
namespace Wasmtime
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the Wasmtime engine.
|
/// Represents the Wasmtime engine.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Engine : IDisposable
|
public class Engine : IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a new <see cref="Engine" />.
|
/// Constructs a new <see cref="Engine" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Engine()
|
public Engine()
|
||||||
{
|
{
|
||||||
Handle = Interop.wasm_engine_new();
|
Handle = Interop.wasm_engine_new();
|
||||||
|
|
||||||
if (Handle.IsInvalid)
|
if (Handle.IsInvalid)
|
||||||
{
|
{
|
||||||
throw new WasmtimeException("Failed to create Wasmtime engine.");
|
throw new WasmtimeException("Failed to create Wasmtime engine.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Engine(Interop.WasmConfigHandle config)
|
internal Engine(Interop.WasmConfigHandle config)
|
||||||
{
|
{
|
||||||
Handle = Interop.wasm_engine_new_with_config(config);
|
Handle = Interop.wasm_engine_new_with_config(config);
|
||||||
config.SetHandleAsInvalid();
|
config.SetHandleAsInvalid();
|
||||||
|
|
||||||
if (Handle.IsInvalid)
|
if (Handle.IsInvalid)
|
||||||
{
|
{
|
||||||
throw new WasmtimeException("Failed to create Wasmtime engine.");
|
throw new WasmtimeException("Failed to create Wasmtime engine.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new Wasmtime <see cref="Store" />.
|
/// Creates a new Wasmtime <see cref="Store" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Returns the new <see cref="Store" />.</returns>
|
/// <returns>Returns the new <see cref="Store" />.</returns>
|
||||||
public Store CreateStore()
|
public Store CreateStore()
|
||||||
{
|
{
|
||||||
return new Store(this);
|
return new Store(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts the WebAssembly text format to the binary format
|
/// Converts the WebAssembly text format to the binary format
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Returns the binary-encoded wasm module.</returns>
|
/// <returns>Returns the binary-encoded wasm module.</returns>
|
||||||
public byte[] WatToWasm(string wat)
|
public byte[] WatToWasm(string wat)
|
||||||
{
|
{
|
||||||
var watBytes = Encoding.UTF8.GetBytes(wat);
|
var watBytes = Encoding.UTF8.GetBytes(wat);
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
fixed (byte *ptr = watBytes)
|
fixed (byte *ptr = watBytes)
|
||||||
{
|
{
|
||||||
Interop.wasm_byte_vec_t watByteVec;
|
Interop.wasm_byte_vec_t watByteVec;
|
||||||
watByteVec.size = (UIntPtr)watBytes.Length;
|
watByteVec.size = (UIntPtr)watBytes.Length;
|
||||||
watByteVec.data = ptr;
|
watByteVec.data = ptr;
|
||||||
if (!Interop.wasmtime_wat2wasm(Handle, ref watByteVec, out var bytes, out var error)) {
|
if (!Interop.wasmtime_wat2wasm(Handle, ref watByteVec, out var bytes, out var error)) {
|
||||||
var errorSpan = new ReadOnlySpan<byte>(error.data, checked((int)error.size));
|
var errorSpan = new ReadOnlySpan<byte>(error.data, checked((int)error.size));
|
||||||
var message = Encoding.UTF8.GetString(errorSpan);
|
var message = Encoding.UTF8.GetString(errorSpan);
|
||||||
Interop.wasm_byte_vec_delete(ref error);
|
Interop.wasm_byte_vec_delete(ref error);
|
||||||
throw new WasmtimeException("failed to parse input wat: " + message);
|
throw new WasmtimeException("failed to parse input wat: " + message);
|
||||||
}
|
}
|
||||||
var byteSpan = new ReadOnlySpan<byte>(bytes.data, checked((int)bytes.size));
|
var byteSpan = new ReadOnlySpan<byte>(bytes.data, checked((int)bytes.size));
|
||||||
var ret = byteSpan.ToArray();
|
var ret = byteSpan.ToArray();
|
||||||
Interop.wasm_byte_vec_delete(ref bytes);
|
Interop.wasm_byte_vec_delete(ref bytes);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (!Handle.IsInvalid)
|
if (!Handle.IsInvalid)
|
||||||
{
|
{
|
||||||
Handle.Dispose();
|
Handle.Dispose();
|
||||||
Handle.SetHandleAsInvalid();
|
Handle.SetHandleAsInvalid();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Interop.EngineHandle Handle { get; private set; }
|
internal Interop.EngineHandle Handle { get; private set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,77 +1,77 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.1</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.CSharp" Version="4.6.0" />
|
<PackageReference Include="Microsoft.CSharp" Version="4.6.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AssemblyName>Wasmtime.Dotnet</AssemblyName>
|
<AssemblyName>Wasmtime.Dotnet</AssemblyName>
|
||||||
<PackageId>Wasmtime</PackageId>
|
<PackageId>Wasmtime</PackageId>
|
||||||
<Version>$(WasmtimeVersion)-preview1</Version>
|
<Version>$(WasmtimeVersion)-preview1</Version>
|
||||||
<Authors>Peter Huene</Authors>
|
<Authors>Peter Huene</Authors>
|
||||||
<Owners>Peter Huene</Owners>
|
<Owners>Peter Huene</Owners>
|
||||||
<IncludeSymbols>true</IncludeSymbols>
|
<IncludeSymbols>true</IncludeSymbols>
|
||||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||||
<RepositoryUrl>https://github.com/bytecodealliance/wasmtime</RepositoryUrl>
|
<RepositoryUrl>https://github.com/bytecodealliance/wasmtime</RepositoryUrl>
|
||||||
<PackageReleaseNotes>Initial release of Wasmtime for .NET.</PackageReleaseNotes>
|
<PackageReleaseNotes>Initial release of Wasmtime for .NET.</PackageReleaseNotes>
|
||||||
<Summary>A .NET API for Wasmtime, a standalone WebAssembly runtime</Summary>
|
<Summary>A .NET API for Wasmtime, a standalone WebAssembly runtime</Summary>
|
||||||
<PackageTags>webassembly, .net, wasm, wasmtime</PackageTags>
|
<PackageTags>webassembly, .net, wasm, wasmtime</PackageTags>
|
||||||
<Title>Wasmtime</Title>
|
<Title>Wasmtime</Title>
|
||||||
<PackageDescription>
|
<PackageDescription>
|
||||||
A .NET API for Wasmtime.
|
A .NET API for Wasmtime.
|
||||||
|
|
||||||
Wasmtime is a standalone runtime for WebAssembly, using the Cranelift JIT compiler.
|
Wasmtime is a standalone runtime for WebAssembly, using the Cranelift JIT compiler.
|
||||||
|
|
||||||
Wasmtime for .NET enables .NET code to instantiate WebAssembly modules and to interact with them in-process.
|
Wasmtime for .NET enables .NET code to instantiate WebAssembly modules and to interact with them in-process.
|
||||||
</PackageDescription>
|
</PackageDescription>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<Target Name="PackWasmtime" BeforeTargets="_GetPackageFiles">
|
<Target Name="PackWasmtime" BeforeTargets="_GetPackageFiles">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<WasmtimeArchitecture>x86_64</WasmtimeArchitecture>
|
<WasmtimeArchitecture>x86_64</WasmtimeArchitecture>
|
||||||
<ReleaseURLBase>https://github.com/bytecodealliance/wasmtime/releases/download/v$(WasmtimeVersion)/wasmtime-v$(WasmtimeVersion)-$(WasmtimeArchitecture)</ReleaseURLBase>
|
<ReleaseURLBase>https://github.com/bytecodealliance/wasmtime/releases/download/v$(WasmtimeVersion)/wasmtime-v$(WasmtimeVersion)-$(WasmtimeArchitecture)</ReleaseURLBase>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<WasmtimeDownload Include="Linux">
|
<WasmtimeDownload Include="Linux">
|
||||||
<URL>$(ReleaseURLBase)-linux-c-api.tar.xz</URL>
|
<URL>$(ReleaseURLBase)-linux-c-api.tar.xz</URL>
|
||||||
<DownloadFolder>$(IntermediateOutputPath)wasmtime-linux</DownloadFolder>
|
<DownloadFolder>$(IntermediateOutputPath)wasmtime-linux</DownloadFolder>
|
||||||
<DownloadFilename>linux.tar.xz</DownloadFilename>
|
<DownloadFilename>linux.tar.xz</DownloadFilename>
|
||||||
<WasmtimeLibraryFilename>libwasmtime.so</WasmtimeLibraryFilename>
|
<WasmtimeLibraryFilename>libwasmtime.so</WasmtimeLibraryFilename>
|
||||||
<PackagePath>runtimes/linux-x64/native</PackagePath>
|
<PackagePath>runtimes/linux-x64/native</PackagePath>
|
||||||
</WasmtimeDownload>
|
</WasmtimeDownload>
|
||||||
<WasmtimeDownload Include="macOS">
|
<WasmtimeDownload Include="macOS">
|
||||||
<URL>$(ReleaseURLBase)-macos-c-api.tar.xz</URL>
|
<URL>$(ReleaseURLBase)-macos-c-api.tar.xz</URL>
|
||||||
<DownloadFolder>$(IntermediateOutputPath)wasmtime-macos</DownloadFolder>
|
<DownloadFolder>$(IntermediateOutputPath)wasmtime-macos</DownloadFolder>
|
||||||
<DownloadFilename>macos.tar.xz</DownloadFilename>
|
<DownloadFilename>macos.tar.xz</DownloadFilename>
|
||||||
<WasmtimeLibraryFilename>libwasmtime.dylib</WasmtimeLibraryFilename>
|
<WasmtimeLibraryFilename>libwasmtime.dylib</WasmtimeLibraryFilename>
|
||||||
<PackagePath>runtimes/osx-x64/native</PackagePath>
|
<PackagePath>runtimes/osx-x64/native</PackagePath>
|
||||||
</WasmtimeDownload>
|
</WasmtimeDownload>
|
||||||
<WasmtimeDownload Include="Windows">
|
<WasmtimeDownload Include="Windows">
|
||||||
<URL>$(ReleaseURLBase)-windows-c-api.zip</URL>
|
<URL>$(ReleaseURLBase)-windows-c-api.zip</URL>
|
||||||
<DownloadFolder>$(IntermediateOutputPath)wasmtime-windows</DownloadFolder>
|
<DownloadFolder>$(IntermediateOutputPath)wasmtime-windows</DownloadFolder>
|
||||||
<DownloadFilename>windows.zip</DownloadFilename>
|
<DownloadFilename>windows.zip</DownloadFilename>
|
||||||
<WasmtimeLibraryFilename>wasmtime.dll</WasmtimeLibraryFilename>
|
<WasmtimeLibraryFilename>wasmtime.dll</WasmtimeLibraryFilename>
|
||||||
<PackagePath>runtimes/win-x64/native</PackagePath>
|
<PackagePath>runtimes/win-x64/native</PackagePath>
|
||||||
</WasmtimeDownload>
|
</WasmtimeDownload>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Message Text="Downloading Wasmtime release." Importance="High" />
|
<Message Text="Downloading Wasmtime release." Importance="High" />
|
||||||
<DownloadFile SourceUrl="%(WasmtimeDownload.URL)" DestinationFolder="%(WasmtimeDownload.DownloadFolder)" DestinationFileName="%(WasmtimeDownload.DownloadFilename)" SkipUnchangedFiles="true" />
|
<DownloadFile SourceUrl="%(WasmtimeDownload.URL)" DestinationFolder="%(WasmtimeDownload.DownloadFolder)" DestinationFileName="%(WasmtimeDownload.DownloadFilename)" SkipUnchangedFiles="true" />
|
||||||
|
|
||||||
<Message Text="Decompressing Wasmtime release." Importance="High" />
|
<Message Text="Decompressing Wasmtime release." Importance="High" />
|
||||||
<Exec Command="tar --strip-components 1 -xvzf %(WasmtimeDownload.DownloadFilename)" WorkingDirectory="%(WasmtimeDownload.DownloadFolder)" StandardOutputImportance="Low" StandardErrorImportance="Low" />
|
<Exec Command="tar --strip-components 1 -xvzf %(WasmtimeDownload.DownloadFilename)" WorkingDirectory="%(WasmtimeDownload.DownloadFolder)" StandardOutputImportance="Low" StandardErrorImportance="Low" />
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="%(WasmtimeDownload.DownloadFolder)/lib/%(WasmtimeDownload.WasmtimeLibraryFilename)" Link="%(WasmtimeDownload.PackagePath)/%(WasmtimeDownload.WasmtimeLibraryFilename)">
|
<Content Include="%(WasmtimeDownload.DownloadFolder)/lib/%(WasmtimeDownload.WasmtimeLibraryFilename)" Link="%(WasmtimeDownload.PackagePath)/%(WasmtimeDownload.WasmtimeLibraryFilename)">
|
||||||
<PackagePath>%(WasmtimeDownload.PackagePath)</PackagePath>
|
<PackagePath>%(WasmtimeDownload.PackagePath)</PackagePath>
|
||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,150 +1,150 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Wasmtime.Tests
|
namespace Wasmtime.Tests
|
||||||
{
|
{
|
||||||
public class FunctionExportsFixture : ModuleFixture
|
public class FunctionExportsFixture : ModuleFixture
|
||||||
{
|
{
|
||||||
protected override string ModuleFileName => "FunctionExports.wat";
|
protected override string ModuleFileName => "FunctionExports.wat";
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FunctionExportsTests : IClassFixture<FunctionExportsFixture>
|
public class FunctionExportsTests : IClassFixture<FunctionExportsFixture>
|
||||||
{
|
{
|
||||||
public FunctionExportsTests(FunctionExportsFixture fixture)
|
public FunctionExportsTests(FunctionExportsFixture fixture)
|
||||||
{
|
{
|
||||||
Fixture = fixture;
|
Fixture = fixture;
|
||||||
}
|
}
|
||||||
|
|
||||||
private FunctionExportsFixture Fixture { get; set; }
|
private FunctionExportsFixture Fixture { get; set; }
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(GetFunctionExports))]
|
[MemberData(nameof(GetFunctionExports))]
|
||||||
public void ItHasTheExpectedFunctionExports(string exportName, ValueKind[] expectedParameters, ValueKind[] expectedResults)
|
public void ItHasTheExpectedFunctionExports(string exportName, ValueKind[] expectedParameters, ValueKind[] expectedResults)
|
||||||
{
|
{
|
||||||
var export = Fixture.Module.Exports.Functions.Where(f => f.Name == exportName).FirstOrDefault();
|
var export = Fixture.Module.Exports.Functions.Where(f => f.Name == exportName).FirstOrDefault();
|
||||||
export.Should().NotBeNull();
|
export.Should().NotBeNull();
|
||||||
export.Parameters.Should().Equal(expectedParameters);
|
export.Parameters.Should().Equal(expectedParameters);
|
||||||
export.Results.Should().Equal(expectedResults);
|
export.Results.Should().Equal(expectedResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ItHasTheExpectedNumberOfExportedFunctions()
|
public void ItHasTheExpectedNumberOfExportedFunctions()
|
||||||
{
|
{
|
||||||
GetFunctionExports().Count().Should().Be(Fixture.Module.Exports.Functions.Count);
|
GetFunctionExports().Count().Should().Be(Fixture.Module.Exports.Functions.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<object[]> GetFunctionExports()
|
public static IEnumerable<object[]> GetFunctionExports()
|
||||||
{
|
{
|
||||||
yield return new object[] {
|
yield return new object[] {
|
||||||
"no_params_no_results",
|
"no_params_no_results",
|
||||||
Array.Empty<ValueKind>(),
|
Array.Empty<ValueKind>(),
|
||||||
Array.Empty<ValueKind>()
|
Array.Empty<ValueKind>()
|
||||||
};
|
};
|
||||||
|
|
||||||
yield return new object[] {
|
yield return new object[] {
|
||||||
"one_i32_param_no_results",
|
"one_i32_param_no_results",
|
||||||
new ValueKind[] {
|
new ValueKind[] {
|
||||||
ValueKind.Int32
|
ValueKind.Int32
|
||||||
},
|
},
|
||||||
Array.Empty<ValueKind>()
|
Array.Empty<ValueKind>()
|
||||||
};
|
};
|
||||||
|
|
||||||
yield return new object[] {
|
yield return new object[] {
|
||||||
"one_i64_param_no_results",
|
"one_i64_param_no_results",
|
||||||
new ValueKind[] {
|
new ValueKind[] {
|
||||||
ValueKind.Int64
|
ValueKind.Int64
|
||||||
},
|
},
|
||||||
Array.Empty<ValueKind>()
|
Array.Empty<ValueKind>()
|
||||||
};
|
};
|
||||||
|
|
||||||
yield return new object[] {
|
yield return new object[] {
|
||||||
"one_f32_param_no_results",
|
"one_f32_param_no_results",
|
||||||
new ValueKind[] {
|
new ValueKind[] {
|
||||||
ValueKind.Float32
|
ValueKind.Float32
|
||||||
},
|
},
|
||||||
Array.Empty<ValueKind>()
|
Array.Empty<ValueKind>()
|
||||||
};
|
};
|
||||||
|
|
||||||
yield return new object[] {
|
yield return new object[] {
|
||||||
"one_f64_param_no_results",
|
"one_f64_param_no_results",
|
||||||
new ValueKind[] {
|
new ValueKind[] {
|
||||||
ValueKind.Float64
|
ValueKind.Float64
|
||||||
},
|
},
|
||||||
Array.Empty<ValueKind>()
|
Array.Empty<ValueKind>()
|
||||||
};
|
};
|
||||||
|
|
||||||
yield return new object[] {
|
yield return new object[] {
|
||||||
"one_param_of_each_type",
|
"one_param_of_each_type",
|
||||||
new ValueKind[] {
|
new ValueKind[] {
|
||||||
ValueKind.Int32,
|
ValueKind.Int32,
|
||||||
ValueKind.Int64,
|
ValueKind.Int64,
|
||||||
ValueKind.Float32,
|
ValueKind.Float32,
|
||||||
ValueKind.Float64
|
ValueKind.Float64
|
||||||
},
|
},
|
||||||
Array.Empty<ValueKind>()
|
Array.Empty<ValueKind>()
|
||||||
};
|
};
|
||||||
|
|
||||||
yield return new object[] {
|
yield return new object[] {
|
||||||
"no_params_one_i32_result",
|
"no_params_one_i32_result",
|
||||||
Array.Empty<ValueKind>(),
|
Array.Empty<ValueKind>(),
|
||||||
new ValueKind[] {
|
new ValueKind[] {
|
||||||
ValueKind.Int32,
|
ValueKind.Int32,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
yield return new object[] {
|
yield return new object[] {
|
||||||
"no_params_one_i64_result",
|
"no_params_one_i64_result",
|
||||||
Array.Empty<ValueKind>(),
|
Array.Empty<ValueKind>(),
|
||||||
new ValueKind[] {
|
new ValueKind[] {
|
||||||
ValueKind.Int64,
|
ValueKind.Int64,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
yield return new object[] {
|
yield return new object[] {
|
||||||
"no_params_one_f32_result",
|
"no_params_one_f32_result",
|
||||||
Array.Empty<ValueKind>(),
|
Array.Empty<ValueKind>(),
|
||||||
new ValueKind[] {
|
new ValueKind[] {
|
||||||
ValueKind.Float32,
|
ValueKind.Float32,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
yield return new object[] {
|
yield return new object[] {
|
||||||
"no_params_one_f64_result",
|
"no_params_one_f64_result",
|
||||||
Array.Empty<ValueKind>(),
|
Array.Empty<ValueKind>(),
|
||||||
new ValueKind[] {
|
new ValueKind[] {
|
||||||
ValueKind.Float64,
|
ValueKind.Float64,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
yield return new object[] {
|
yield return new object[] {
|
||||||
"one_result_of_each_type",
|
"one_result_of_each_type",
|
||||||
Array.Empty<ValueKind>(),
|
Array.Empty<ValueKind>(),
|
||||||
new ValueKind[] {
|
new ValueKind[] {
|
||||||
ValueKind.Int32,
|
ValueKind.Int32,
|
||||||
ValueKind.Int64,
|
ValueKind.Int64,
|
||||||
ValueKind.Float32,
|
ValueKind.Float32,
|
||||||
ValueKind.Float64,
|
ValueKind.Float64,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
yield return new object[] {
|
yield return new object[] {
|
||||||
"one_param_and_result_of_each_type",
|
"one_param_and_result_of_each_type",
|
||||||
new ValueKind[] {
|
new ValueKind[] {
|
||||||
ValueKind.Int32,
|
ValueKind.Int32,
|
||||||
ValueKind.Int64,
|
ValueKind.Int64,
|
||||||
ValueKind.Float32,
|
ValueKind.Float32,
|
||||||
ValueKind.Float64,
|
ValueKind.Float64,
|
||||||
},
|
},
|
||||||
new ValueKind[] {
|
new ValueKind[] {
|
||||||
ValueKind.Int32,
|
ValueKind.Int32,
|
||||||
ValueKind.Int64,
|
ValueKind.Int64,
|
||||||
ValueKind.Float32,
|
ValueKind.Float32,
|
||||||
ValueKind.Float64,
|
ValueKind.Float64,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FluentAssertions" Version="5.9.0" />
|
<PackageReference Include="FluentAssertions" Version="5.9.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||||
<PackageReference Include="xunit" Version="2.4.0" />
|
<PackageReference Include="xunit" Version="2.4.0" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
|
||||||
<PackageReference Include="coverlet.collector" Version="1.0.1" />
|
<PackageReference Include="coverlet.collector" Version="1.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\src\Wasmtime.csproj" />
|
<ProjectReference Include="..\src\Wasmtime.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!-- This is needed as we're not referencing Wasmtime as a package. -->
|
<!-- This is needed as we're not referencing Wasmtime as a package. -->
|
||||||
<Target Name="BuildWasmtime" BeforeTargets="AssignTargetPaths">
|
<Target Name="BuildWasmtime" BeforeTargets="AssignTargetPaths">
|
||||||
<Message Text="Building Wasmtime from source." Importance="High" />
|
<Message Text="Building Wasmtime from source." Importance="High" />
|
||||||
<Exec Command="$(BuildWasmtimeCommand)" StandardOutputImportance="Low" StandardErrorImportance="Low" />
|
<Exec Command="$(BuildWasmtimeCommand)" StandardOutputImportance="Low" StandardErrorImportance="Low" />
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="$(WasmtimeOutputPath)/$(WasmtimeLibraryFilename)" Link="$(WasmtimeLibraryFilename)" CopyToOutputDirectory="PreserveNewest" />
|
<None Include="$(WasmtimeOutputPath)/$(WasmtimeLibraryFilename)" Link="$(WasmtimeLibraryFilename)" CopyToOutputDirectory="PreserveNewest" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="Modules/*.wat" CopyToOutputDirectory="PreserveNewest" />
|
<None Update="Modules/*.wat" CopyToOutputDirectory="PreserveNewest" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
Reference in New Issue
Block a user