-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add binding crate integrations (#89)
* feat(io): implement `Read` and `Write` for streams Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * feat(rand): add `rand` crate integration Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * chore: split examples into `std` and `no_std` Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * ci: build all std and no_std examples Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * refactor(rand): use `writeln` to write to stdout Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * feat(wasi-ext): add workspace crate Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * ci: build in `--workspace` mode Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> --------- Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
- Loading branch information
1 parent
13e01d5
commit 4c9ff82
Showing
15 changed files
with
290 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
[package] | ||
name = "wasi-ext" | ||
version = "0.1.0" | ||
authors = ["Roman Volosatovs <rvolosatovs@riseup.net>"] | ||
description = "Third-party crate integrations for WASI" | ||
|
||
license.workspace = true | ||
edition.workspace = true | ||
repository.workspace = true | ||
|
||
[features] | ||
default = ["std"] | ||
std = ["wasi/std"] | ||
|
||
[dependencies] | ||
rand = { workspace = true, optional = true } | ||
wasi = { workspace = true } | ||
|
||
[[example]] | ||
name = "rand" | ||
required-features = ["rand", "std"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
use std::io::Write as _; | ||
|
||
use wasi_ext::rand::rand::Rng as _; | ||
use wasi_ext::rand::{HostInsecureRng, HostRng}; | ||
|
||
fn main() { | ||
let mut stdout = wasi::cli::stdout::get_stdout(); | ||
|
||
let r: u64 = HostRng.gen(); | ||
writeln!(stdout, "Cryptographically-secure random u64 is {r}").unwrap(); | ||
|
||
let r: u64 = HostInsecureRng.gen(); | ||
writeln!(stdout, "Pseudo-random u64 is {r}").unwrap(); | ||
|
||
stdout.flush().unwrap(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
#[cfg(feature = "rand")] | ||
pub mod rand; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
pub use rand; | ||
|
||
use rand::{CryptoRng, RngCore}; | ||
|
||
/// The secure interface for cryptographically-secure random numbers | ||
pub struct HostRng; | ||
|
||
impl CryptoRng for HostRng {} | ||
|
||
impl RngCore for HostRng { | ||
#[inline] | ||
fn next_u32(&mut self) -> u32 { | ||
wasi::random::random::get_random_u64() as _ | ||
} | ||
|
||
#[inline] | ||
fn next_u64(&mut self) -> u64 { | ||
wasi::random::random::get_random_u64() | ||
} | ||
|
||
fn fill_bytes(&mut self, dest: &mut [u8]) { | ||
let n = dest.len(); | ||
if usize::BITS <= u64::BITS || n <= u64::MAX as _ { | ||
dest.copy_from_slice(&wasi::random::random::get_random_bytes(n as _)); | ||
} else { | ||
let (head, tail) = dest.split_at_mut(u64::MAX as _); | ||
head.copy_from_slice(&wasi::random::random::get_random_bytes(u64::MAX)); | ||
self.fill_bytes(tail); | ||
} | ||
} | ||
|
||
#[inline] | ||
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> { | ||
self.fill_bytes(dest); | ||
Ok(()) | ||
} | ||
} | ||
|
||
/// The insecure interface for insecure pseudo-random numbers | ||
pub struct HostInsecureRng; | ||
|
||
impl RngCore for HostInsecureRng { | ||
#[inline] | ||
fn next_u32(&mut self) -> u32 { | ||
wasi::random::insecure::get_insecure_random_u64() as _ | ||
} | ||
|
||
#[inline] | ||
fn next_u64(&mut self) -> u64 { | ||
wasi::random::insecure::get_insecure_random_u64() | ||
} | ||
|
||
fn fill_bytes(&mut self, dest: &mut [u8]) { | ||
let n = dest.len(); | ||
if usize::BITS <= u64::BITS || n <= u64::MAX as _ { | ||
dest.copy_from_slice(&wasi::random::insecure::get_insecure_random_bytes(n as _)); | ||
} else { | ||
let (head, tail) = dest.split_at_mut(u64::MAX as _); | ||
head.copy_from_slice(&wasi::random::insecure::get_insecure_random_bytes(u64::MAX)); | ||
self.fill_bytes(tail); | ||
} | ||
} | ||
|
||
#[inline] | ||
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> { | ||
self.fill_bytes(dest); | ||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
wasi::cli::command::export!(Example); | ||
|
||
struct Example; | ||
|
||
impl wasi::exports::cli::run::Guest for Example { | ||
fn run() -> Result<(), ()> { | ||
let stdout = wasi::cli::stdout::get_stdout(); | ||
stdout.blocking_write_and_flush(b"Hello, WASI!").unwrap(); | ||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,14 @@ | ||
use std::io::Write as _; | ||
|
||
wasi::cli::command::export!(Example); | ||
|
||
struct Example; | ||
|
||
impl wasi::exports::cli::run::Guest for Example { | ||
fn run() -> Result<(), ()> { | ||
let stdout = wasi::cli::stdout::get_stdout(); | ||
stdout.blocking_write_and_flush(b"Hello, WASI!").unwrap(); | ||
let mut stdout = wasi::cli::stdout::get_stdout(); | ||
stdout.write_all(b"Hello, WASI!").unwrap(); | ||
stdout.flush().unwrap(); | ||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
fn main() { | ||
let stdout = wasi::cli::stdout::get_stdout(); | ||
stdout.blocking_write_and_flush(b"Hello, world!\n").unwrap(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,7 @@ | ||
use std::io::Write as _; | ||
|
||
fn main() { | ||
let stdout = wasi::cli::stdout::get_stdout(); | ||
stdout.blocking_write_and_flush(b"Hello, world!\n").unwrap(); | ||
let mut stdout = wasi::cli::stdout::get_stdout(); | ||
stdout.write_all(b"Hello, world!\n").unwrap(); | ||
stdout.flush().unwrap(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
use wasi::http::types::{ | ||
Fields, IncomingRequest, OutgoingBody, OutgoingResponse, ResponseOutparam, | ||
}; | ||
|
||
wasi::http::proxy::export!(Example); | ||
|
||
struct Example; | ||
|
||
impl wasi::exports::http::incoming_handler::Guest for Example { | ||
fn handle(_request: IncomingRequest, response_out: ResponseOutparam) { | ||
let resp = OutgoingResponse::new(Fields::new()); | ||
let body = resp.body().unwrap(); | ||
|
||
ResponseOutparam::set(response_out, Ok(resp)); | ||
|
||
let out = body.write().unwrap(); | ||
out.blocking_write_and_flush(b"Hello, WASI!").unwrap(); | ||
drop(out); | ||
|
||
OutgoingBody::finish(body, None).unwrap(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,8 @@ | ||
#[cfg(feature = "std")] | ||
mod std; | ||
|
||
impl core::fmt::Display for crate::io::error::Error { | ||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { | ||
f.write_str(&self.to_debug_string()) | ||
} | ||
} | ||
|
||
#[cfg(feature = "std")] | ||
impl std::error::Error for crate::io::error::Error {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
use std::error::Error; | ||
use std::io; | ||
use std::num::NonZeroU64; | ||
|
||
use crate::io::streams::StreamError; | ||
|
||
impl Error for crate::io::error::Error {} | ||
|
||
impl io::Read for crate::io::streams::InputStream { | ||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | ||
let n = buf | ||
.len() | ||
.try_into() | ||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; | ||
match self.blocking_read(n) { | ||
Ok(chunk) => { | ||
let n = chunk.len(); | ||
if n > buf.len() { | ||
return Err(io::Error::new( | ||
io::ErrorKind::Other, | ||
"more bytes read than requested", | ||
)); | ||
} | ||
buf[..n].copy_from_slice(&chunk); | ||
Ok(n) | ||
} | ||
Err(StreamError::Closed) => Ok(0), | ||
Err(StreamError::LastOperationFailed(e)) => { | ||
Err(io::Error::new(io::ErrorKind::Other, e.to_debug_string())) | ||
} | ||
} | ||
} | ||
} | ||
|
||
impl io::Write for crate::io::streams::OutputStream { | ||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | ||
let n = loop { | ||
match self.check_write().map(NonZeroU64::new) { | ||
Ok(Some(n)) => { | ||
break n; | ||
} | ||
Ok(None) => { | ||
self.subscribe().block(); | ||
} | ||
Err(StreamError::Closed) => return Ok(0), | ||
Err(StreamError::LastOperationFailed(e)) => { | ||
return Err(io::Error::new(io::ErrorKind::Other, e.to_debug_string())) | ||
} | ||
}; | ||
}; | ||
let n = n | ||
.get() | ||
.try_into() | ||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; | ||
let n = buf.len().min(n); | ||
crate::io::streams::OutputStream::write(self, &buf[..n]).map_err(|e| match e { | ||
StreamError::Closed => io::ErrorKind::UnexpectedEof.into(), | ||
StreamError::LastOperationFailed(e) => { | ||
io::Error::new(io::ErrorKind::Other, e.to_debug_string()) | ||
} | ||
})?; | ||
Ok(n) | ||
} | ||
|
||
fn flush(&mut self) -> io::Result<()> { | ||
self.blocking_flush() | ||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters