1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
//! This crate provides safe but low-level for the Wasm imports available in the OC-Wasm
//! environment.
//!
//! # Features
//! The `panic` feature controls how certain system call errors which should be impossible are
//! handled. When the feature is enabled, a panic is generated in those situations. When the
//! feature is disabled, a Wasm `unreachable` (trap) instruction is executed instead; this produces
//! smaller code but less useful error messages.
//!
//! The `std` feature controls whether [`error::Error`](error::Error) implements
//! `std::error::Error`, which it cannot do in a `no_std` environment.
#![cfg_attr(not(feature = "std"), no_std)]
#![warn(
// Turn on extra language lints.
future_incompatible,
missing_abi,
nonstandard_style,
rust_2018_idioms,
// Disabled due to <https://github.com/rust-lang/rust/issues/69952>.
// single_use_lifetimes,
trivial_casts,
trivial_numeric_casts,
unused,
unused_crate_dependencies,
unused_import_braces,
unused_lifetimes,
unused_qualifications,
// Turn on extra Rustdoc lints.
rustdoc::all,
// Turn on extra Clippy lints.
clippy::cargo,
clippy::pedantic,
)]
pub mod component;
pub mod computer;
pub mod descriptor;
pub mod error;
pub mod execute;
pub mod extref;
use core::fmt::{Display, Formatter};
use core::str::FromStr;
use minicbor::{
data::{Tag, Type},
decode, encode,
};
use uuid::Uuid;
/// A component address.
///
/// This is just a UUID. It supports `minicbor`. When encoding, it encodes as a byte string tagged
/// with the Binary UUID tag. When decoding, it decodes from an optional Binary UUID (or
/// Identifier, for backwards compatibility) tag followed by either a byte string or a UTF-8
/// string.
#[derive(Clone, Copy, Debug, Default, Hash, Eq, Ord, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct Address(Uuid);
impl Address {
const TAG: Tag = Tag::Unassigned(37);
#[must_use = "This function is only useful for its return value"]
pub const fn as_bytes(&self) -> &[u8; 16] {
self.0.as_bytes()
}
#[must_use = "This function is only useful for its return value"]
pub const fn from_bytes(b: [u8; 16]) -> Self {
Self(Uuid::from_bytes(b))
}
}
impl Display for Address {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
self.0.fmt(f)
}
}
impl FromStr for Address {
type Err = <Uuid as FromStr>::Err;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(<Uuid as FromStr>::from_str(s)?))
}
}
impl<Context> decode::Decode<'_, Context> for Address {
fn decode(d: &mut decode::Decoder<'_>, _: &mut Context) -> Result<Self, decode::Error> {
// Check the datatype of the next item.
let mut datatype = d.datatype()?;
// If it’s a tag, it must have value Identifier (39) or Binary UUID, and the tagged value
// is the UUID.
if datatype == Type::Tag {
let tag = d.tag()?;
if tag != Self::TAG && tag != Tag::Unassigned(39) {
return Err(decode::Error::message("expected tag Binary UUID"));
}
datatype = d.datatype()?;
}
// Now the value must appear as either byte string holding a binary UUID or a UTF-8 string
// holding a text UUID. Indefinite forms do not need to be supported as OC-Wasm never
// generates them in data passed to the Wasm module instance.
match datatype {
Type::Bytes => {
let b = d.bytes()?;
Ok(Self::from_bytes(b.try_into().map_err(|_| {
decode::Error::message("expected 16 bytes")
})?))
}
Type::String => {
let s = d.str()?;
Ok(
Self::from_str(s)
.map_err(|_| decode::Error::message("expected UUID string"))?,
)
}
_ => Err(decode::Error::message("expected byte or UTF-8 string")),
}
}
}
impl<Context> encode::Encode<Context> for Address {
fn encode<W: encode::Write>(
&self,
e: &mut encode::Encoder<W>,
_: &mut Context,
) -> Result<(), encode::Error<W::Error>> {
e.tag(Self::TAG)?.bytes(self.as_bytes())?;
Ok(())
}
}
/// Panics or traps depending on the state of the `panic` feature.
///
/// If the `panic` feature is enabled, this macro panics with the given message. If it is disabled,
/// this macro invokes Wasm `UNREACHABLE` (trap) instruction, instantly terminating execution; the
/// message is ignored.
#[cfg(feature = "panic")]
#[macro_export]
macro_rules! panic_or_trap {
($message: literal) => {
core::panic!($message)
};
}
/// Panics or traps depending on the state of the `panic` feature.
///
/// If the `panic` feature is enabled, this macro panics with the given message. If it is disabled,
/// this macro invokes Wasm `UNREACHABLE` (trap) instruction, instantly terminating execution; the
/// message is ignored.
#[cfg(not(feature = "panic"))]
#[macro_export]
macro_rules! panic_or_trap {
($message: literal) => {
core::arch::wasm32::unreachable()
};
}
mod helpers;