pub mod dynclib_abi;
pub mod vtable;
#[cfg(all(target_arch = "wasm32", not(feature = "web")))]
pub mod wasm;
#[cfg(feature = "cdylib")]
pub mod dynclib;
#[cfg(all(target_arch = "wasm32", not(feature = "web")))]
#[doc(hidden)]
pub mod __wasm_macro_support {
pub use super::wasm::adapter::{
WorkloadCell, run_dispatch, run_on_credential_expiring, run_on_credential_renewed,
run_on_data_stream, run_on_error, run_on_mailbox_backpressure, run_on_ready,
run_on_signaling_connected, run_on_signaling_connecting, run_on_signaling_disconnected,
run_on_start, run_on_stop, run_on_webrtc_connected, run_on_webrtc_connecting,
run_on_webrtc_disconnected, run_on_websocket_connected, run_on_websocket_connecting,
run_on_websocket_disconnected,
};
pub use super::wasm::generated::actr::workload::types::{
ActrError as WitActrError, ActrId as WitActrId, BackpressureEvent as WitBackpressureEvent,
CredentialEvent as WitCredentialEvent, DataStream as WitDataStream,
ErrorEvent as WitErrorEvent, PeerEvent as WitPeerEvent, RpcEnvelope as WitRpcEnvelope,
};
pub use super::wasm::generated::exports::actr::workload::workload::Guest;
}
#[macro_export]
macro_rules! entry {
($workload_type:ty) => {
$crate::entry!($workload_type, <$workload_type as ::core::default::Default>::default());
};
($workload_type:ty, $init_expr:expr) => {
#[cfg(all(target_arch = "wasm32", not(feature = "web")))]
const _: () = {
static __ACTR_WORKLOAD: $crate::guest::__wasm_macro_support::WorkloadCell<$workload_type> =
$crate::guest::__wasm_macro_support::WorkloadCell::new();
fn __actr_workload() -> &'static $workload_type {
__ACTR_WORKLOAD.get_or_init(|| -> $workload_type { $init_expr })
}
struct __ActrEntryAdapter;
impl $crate::guest::__wasm_macro_support::Guest for __ActrEntryAdapter {
async fn dispatch(
envelope: $crate::guest::__wasm_macro_support::WitRpcEnvelope,
) -> ::core::result::Result<
::std::vec::Vec<u8>,
$crate::guest::__wasm_macro_support::WitActrError,
> {
$crate::guest::__wasm_macro_support::run_dispatch(
__actr_workload(),
envelope,
)
.await
}
async fn on_start() -> ::core::result::Result<
(),
$crate::guest::__wasm_macro_support::WitActrError,
> {
$crate::guest::__wasm_macro_support::run_on_start(__actr_workload()).await
}
async fn on_ready() -> ::core::result::Result<
(),
$crate::guest::__wasm_macro_support::WitActrError,
> {
$crate::guest::__wasm_macro_support::run_on_ready(__actr_workload()).await
}
async fn on_stop() -> ::core::result::Result<
(),
$crate::guest::__wasm_macro_support::WitActrError,
> {
$crate::guest::__wasm_macro_support::run_on_stop(__actr_workload()).await
}
async fn on_error(
event: $crate::guest::__wasm_macro_support::WitErrorEvent,
) -> ::core::result::Result<
(),
$crate::guest::__wasm_macro_support::WitActrError,
> {
$crate::guest::__wasm_macro_support::run_on_error(__actr_workload(), event)
.await
}
async fn on_signaling_connecting() {
$crate::guest::__wasm_macro_support::run_on_signaling_connecting(
__actr_workload(),
)
.await
}
async fn on_signaling_connected() {
$crate::guest::__wasm_macro_support::run_on_signaling_connected(
__actr_workload(),
)
.await
}
async fn on_signaling_disconnected() {
$crate::guest::__wasm_macro_support::run_on_signaling_disconnected(
__actr_workload(),
)
.await
}
async fn on_websocket_connecting(
event: $crate::guest::__wasm_macro_support::WitPeerEvent,
) {
$crate::guest::__wasm_macro_support::run_on_websocket_connecting(
__actr_workload(),
event,
)
.await
}
async fn on_websocket_connected(
event: $crate::guest::__wasm_macro_support::WitPeerEvent,
) {
$crate::guest::__wasm_macro_support::run_on_websocket_connected(
__actr_workload(),
event,
)
.await
}
async fn on_websocket_disconnected(
event: $crate::guest::__wasm_macro_support::WitPeerEvent,
) {
$crate::guest::__wasm_macro_support::run_on_websocket_disconnected(
__actr_workload(),
event,
)
.await
}
async fn on_webrtc_connecting(
event: $crate::guest::__wasm_macro_support::WitPeerEvent,
) {
$crate::guest::__wasm_macro_support::run_on_webrtc_connecting(
__actr_workload(),
event,
)
.await
}
async fn on_webrtc_connected(
event: $crate::guest::__wasm_macro_support::WitPeerEvent,
) {
$crate::guest::__wasm_macro_support::run_on_webrtc_connected(
__actr_workload(),
event,
)
.await
}
async fn on_webrtc_disconnected(
event: $crate::guest::__wasm_macro_support::WitPeerEvent,
) {
$crate::guest::__wasm_macro_support::run_on_webrtc_disconnected(
__actr_workload(),
event,
)
.await
}
async fn on_credential_renewed(
event: $crate::guest::__wasm_macro_support::WitCredentialEvent,
) {
$crate::guest::__wasm_macro_support::run_on_credential_renewed(
__actr_workload(),
event,
)
.await
}
async fn on_credential_expiring(
event: $crate::guest::__wasm_macro_support::WitCredentialEvent,
) {
$crate::guest::__wasm_macro_support::run_on_credential_expiring(
__actr_workload(),
event,
)
.await
}
async fn on_mailbox_backpressure(
event: $crate::guest::__wasm_macro_support::WitBackpressureEvent,
) {
$crate::guest::__wasm_macro_support::run_on_mailbox_backpressure(
__actr_workload(),
event,
)
.await
}
async fn on_data_stream(
chunk: $crate::guest::__wasm_macro_support::WitDataStream,
sender: $crate::guest::__wasm_macro_support::WitActrId,
) -> ::core::result::Result<
(),
$crate::guest::__wasm_macro_support::WitActrError,
> {
$crate::guest::__wasm_macro_support::run_on_data_stream(chunk, sender).await
}
}
$crate::guest::wasm::generated::export!(__ActrEntryAdapter with_types_in $crate::guest::wasm::generated);
};
#[cfg(all(target_arch = "wasm32", feature = "web"))]
const _: () = {
#[$crate::web::__web_macro_support::wasm_bindgen(start)]
fn __actr_web_bootstrap() {
let workload: $workload_type = $init_expr;
let adapter =
$crate::web::__web_macro_support::WebWorkloadAdapter::new(workload);
$crate::web::__web_macro_support::register_workload(adapter);
}
};
#[cfg(feature = "cdylib")]
const _: () = {
static mut __ACTR_WORKLOAD: Option<$workload_type> = None;
static mut __ACTR_VTABLE: Option<*const $crate::guest::vtable::HostVTable> = None;
#[unsafe(no_mangle)]
pub unsafe extern "C" fn actr_init(
vtable: *const $crate::guest::vtable::HostVTable,
init_ptr: *const u8,
init_len: usize,
) -> i32 {
if vtable.is_null() {
return $crate::guest::dynclib_abi::code::INIT_FAILED;
}
let init_bytes = if init_ptr.is_null() || init_len == 0 {
&[][..]
} else {
unsafe { std::slice::from_raw_parts(init_ptr, init_len) }
};
if $crate::guest::dynclib_abi::decode_message::<$crate::guest::dynclib_abi::InitPayloadV1>(
init_bytes,
)
.is_err()
{
return $crate::guest::dynclib_abi::code::PROTOCOL_ERROR;
}
let workload: $workload_type = $init_expr;
unsafe {
if __ACTR_WORKLOAD.is_some() {
return $crate::guest::dynclib_abi::code::INIT_FAILED;
}
__ACTR_VTABLE = Some(vtable);
__ACTR_WORKLOAD = Some(workload);
}
$crate::guest::dynclib_abi::code::SUCCESS
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn actr_handle(
req_ptr: *const u8,
req_len: usize,
resp_out: *mut *mut u8,
resp_len_out: *mut usize,
) -> i32 {
use actr_protocol::prost::Message as ProstMessage;
use $crate::{MessageDispatcher, Workload};
let vtable = match unsafe { __ACTR_VTABLE } {
Some(vt) => vt,
None => return $crate::guest::dynclib_abi::code::INIT_FAILED,
};
if req_ptr.is_null() {
return $crate::guest::dynclib_abi::code::PROTOCOL_ERROR;
}
let req_bytes = unsafe { std::slice::from_raw_parts(req_ptr, req_len) };
let frame = match $crate::guest::dynclib_abi::decode_message::<
$crate::guest::dynclib_abi::AbiFrame,
>(req_bytes) {
Ok(f) => f,
Err(_) => return $crate::guest::dynclib_abi::code::PROTOCOL_ERROR,
};
if frame.op == $crate::guest::dynclib_abi::op::GUEST_LIFECYCLE {
let payload = match <$crate::guest::dynclib_abi::GuestLifecycleV1 as $crate::guest::dynclib_abi::AbiPayload>::decode_payload(&frame.payload) {
Ok(payload) => payload,
Err(_) => return $crate::guest::dynclib_abi::code::PROTOCOL_ERROR,
};
let ctx = match unsafe {
$crate::guest::dynclib::context::DynclibContext::from_invocation(vtable, payload.ctx)
} {
Ok(c) => c,
Err(_) => return $crate::guest::dynclib_abi::code::HANDLE_FAILED,
};
let workload = unsafe {
match __ACTR_WORKLOAD.as_ref() {
Some(w) => w,
None => return $crate::guest::dynclib_abi::code::INIT_FAILED,
}
};
let lifecycle_result = match payload.hook {
$crate::guest::dynclib_abi::lifecycle_hook::ON_START => {
let fut = workload.on_start(&ctx);
let waker = std::task::Waker::noop();
let mut cx = std::task::Context::from_waker(waker);
let mut pinned = std::pin::pin!(fut);
match pinned.as_mut().poll(&mut cx) {
std::task::Poll::Ready(v) => v,
std::task::Poll::Pending => {
return $crate::guest::dynclib_abi::code::HANDLE_FAILED;
}
}
}
$crate::guest::dynclib_abi::lifecycle_hook::ON_READY => {
let fut = workload.on_ready(&ctx);
let waker = std::task::Waker::noop();
let mut cx = std::task::Context::from_waker(waker);
let mut pinned = std::pin::pin!(fut);
match pinned.as_mut().poll(&mut cx) {
std::task::Poll::Ready(v) => v,
std::task::Poll::Pending => {
return $crate::guest::dynclib_abi::code::HANDLE_FAILED;
}
}
}
$crate::guest::dynclib_abi::lifecycle_hook::ON_STOP => {
let fut = workload.on_stop(&ctx);
let waker = std::task::Waker::noop();
let mut cx = std::task::Context::from_waker(waker);
let mut pinned = std::pin::pin!(fut);
match pinned.as_mut().poll(&mut cx) {
std::task::Poll::Ready(v) => v,
std::task::Poll::Pending => {
return $crate::guest::dynclib_abi::code::HANDLE_FAILED;
}
}
}
_ => return $crate::guest::dynclib_abi::code::UNSUPPORTED_OP,
};
let resp_bytes = match lifecycle_result {
Ok(()) => match $crate::guest::dynclib_abi::success_reply(::std::vec::Vec::new()) {
Ok(bytes) => bytes,
Err(code) => return code,
},
Err(err) => match $crate::guest::dynclib_abi::error_reply(
$crate::guest::dynclib_abi::code::HANDLE_FAILED,
err.to_string().into_bytes(),
) {
Ok(bytes) => bytes,
Err(code) => return code,
},
};
let resp_len = resp_bytes.len();
let layout = match std::alloc::Layout::from_size_align(resp_len.max(1), 1) {
Ok(l) => l,
Err(_) => return $crate::guest::dynclib_abi::code::GENERIC_ERROR,
};
let ptr = unsafe { std::alloc::alloc(layout) };
if ptr.is_null() {
return $crate::guest::dynclib_abi::code::GENERIC_ERROR;
}
unsafe {
std::ptr::copy_nonoverlapping(resp_bytes.as_ptr(), ptr, resp_len);
*resp_out = ptr;
*resp_len_out = resp_len;
}
return $crate::guest::dynclib_abi::code::SUCCESS;
}
if frame.op == $crate::guest::dynclib_abi::op::GUEST_HOOK {
let payload = match <$crate::guest::dynclib_abi::GuestHookV1 as $crate::guest::dynclib_abi::AbiPayload>::decode_payload(&frame.payload) {
Ok(payload) => payload,
Err(_) => return $crate::guest::dynclib_abi::code::PROTOCOL_ERROR,
};
let ctx = match unsafe {
$crate::guest::dynclib::context::DynclibContext::from_invocation(vtable, payload.ctx)
} {
Ok(c) => c,
Err(_) => return $crate::guest::dynclib_abi::code::HANDLE_FAILED,
};
let workload = unsafe {
match __ACTR_WORKLOAD.as_ref() {
Some(w) => w,
None => return $crate::guest::dynclib_abi::code::INIT_FAILED,
}
};
macro_rules! __actr_poll_unit {
($future:expr) => {{
let fut = $future;
let waker = std::task::Waker::noop();
let mut cx = std::task::Context::from_waker(waker);
let mut pinned = std::pin::pin!(fut);
match pinned.as_mut().poll(&mut cx) {
std::task::Poll::Ready(()) => {}
std::task::Poll::Pending => {
return $crate::guest::dynclib_abi::code::HANDLE_FAILED;
}
}
}};
}
let peer_event = |peer: $crate::guest::dynclib_abi::PeerEventV1| {
$crate::PeerEvent {
peer: peer.peer,
relayed: peer.relayed,
}
};
let timestamp = |ts: $crate::guest::dynclib_abi::TimestampV1| {
std::time::UNIX_EPOCH
+ std::time::Duration::new(ts.seconds, ts.nanoseconds)
};
match payload.hook {
$crate::guest::dynclib_abi::runtime_hook::ON_SIGNALING_CONNECTING => {
__actr_poll_unit!(workload.on_signaling_connecting(Some(&ctx)));
}
$crate::guest::dynclib_abi::runtime_hook::ON_SIGNALING_CONNECTED => {
__actr_poll_unit!(workload.on_signaling_connected(Some(&ctx)));
}
$crate::guest::dynclib_abi::runtime_hook::ON_SIGNALING_DISCONNECTED => {
__actr_poll_unit!(workload.on_signaling_disconnected(&ctx));
}
$crate::guest::dynclib_abi::runtime_hook::ON_WEBSOCKET_CONNECTING => {
let event = match payload.peer {
Some(peer) => peer_event(peer),
None => return $crate::guest::dynclib_abi::code::PROTOCOL_ERROR,
};
__actr_poll_unit!(workload.on_websocket_connecting(&ctx, &event));
}
$crate::guest::dynclib_abi::runtime_hook::ON_WEBSOCKET_CONNECTED => {
let event = match payload.peer {
Some(peer) => peer_event(peer),
None => return $crate::guest::dynclib_abi::code::PROTOCOL_ERROR,
};
__actr_poll_unit!(workload.on_websocket_connected(&ctx, &event));
}
$crate::guest::dynclib_abi::runtime_hook::ON_WEBSOCKET_DISCONNECTED => {
let event = match payload.peer {
Some(peer) => peer_event(peer),
None => return $crate::guest::dynclib_abi::code::PROTOCOL_ERROR,
};
__actr_poll_unit!(workload.on_websocket_disconnected(&ctx, &event));
}
$crate::guest::dynclib_abi::runtime_hook::ON_WEBRTC_CONNECTING => {
let event = match payload.peer {
Some(peer) => peer_event(peer),
None => return $crate::guest::dynclib_abi::code::PROTOCOL_ERROR,
};
__actr_poll_unit!(workload.on_webrtc_connecting(&ctx, &event));
}
$crate::guest::dynclib_abi::runtime_hook::ON_WEBRTC_CONNECTED => {
let event = match payload.peer {
Some(peer) => peer_event(peer),
None => return $crate::guest::dynclib_abi::code::PROTOCOL_ERROR,
};
__actr_poll_unit!(workload.on_webrtc_connected(&ctx, &event));
}
$crate::guest::dynclib_abi::runtime_hook::ON_WEBRTC_DISCONNECTED => {
let event = match payload.peer {
Some(peer) => peer_event(peer),
None => return $crate::guest::dynclib_abi::code::PROTOCOL_ERROR,
};
__actr_poll_unit!(workload.on_webrtc_disconnected(&ctx, &event));
}
$crate::guest::dynclib_abi::runtime_hook::ON_CREDENTIAL_RENEWED => {
let event = match payload.credential {
Some(credential) => $crate::CredentialEvent {
new_expiry: timestamp(credential.new_expiry),
},
None => return $crate::guest::dynclib_abi::code::PROTOCOL_ERROR,
};
__actr_poll_unit!(workload.on_credential_renewed(&ctx, &event));
}
$crate::guest::dynclib_abi::runtime_hook::ON_CREDENTIAL_EXPIRING => {
let event = match payload.credential {
Some(credential) => $crate::CredentialEvent {
new_expiry: timestamp(credential.new_expiry),
},
None => return $crate::guest::dynclib_abi::code::PROTOCOL_ERROR,
};
__actr_poll_unit!(workload.on_credential_expiring(&ctx, &event));
}
$crate::guest::dynclib_abi::runtime_hook::ON_MAILBOX_BACKPRESSURE => {
let event = match payload.backpressure {
Some(backpressure) => $crate::BackpressureEvent {
queue_len: backpressure.queue_len as usize,
threshold: backpressure.threshold as usize,
},
None => return $crate::guest::dynclib_abi::code::PROTOCOL_ERROR,
};
__actr_poll_unit!(workload.on_mailbox_backpressure(&ctx, &event));
}
_ => return $crate::guest::dynclib_abi::code::UNSUPPORTED_OP,
}
let resp_bytes = match $crate::guest::dynclib_abi::success_reply(::std::vec::Vec::new()) {
Ok(bytes) => bytes,
Err(code) => return code,
};
let resp_len = resp_bytes.len();
let layout = match std::alloc::Layout::from_size_align(resp_len.max(1), 1) {
Ok(l) => l,
Err(_) => return $crate::guest::dynclib_abi::code::GENERIC_ERROR,
};
let ptr = unsafe { std::alloc::alloc(layout) };
if ptr.is_null() {
return $crate::guest::dynclib_abi::code::GENERIC_ERROR;
}
unsafe {
std::ptr::copy_nonoverlapping(resp_bytes.as_ptr(), ptr, resp_len);
*resp_out = ptr;
*resp_len_out = resp_len;
}
return $crate::guest::dynclib_abi::code::SUCCESS;
}
if frame.op == $crate::guest::dynclib_abi::op::GUEST_DATA_STREAM {
let payload = match <$crate::guest::dynclib_abi::GuestDataStreamV1 as $crate::guest::dynclib_abi::AbiPayload>::decode_payload(&frame.payload) {
Ok(payload) => payload,
Err(_) => return $crate::guest::dynclib_abi::code::PROTOCOL_ERROR,
};
let resp_bytes = match $crate::guest::dynclib::context::dispatch_registered_stream(payload) {
Ok(()) => match $crate::guest::dynclib_abi::success_reply(::std::vec::Vec::new()) {
Ok(bytes) => bytes,
Err(code) => return code,
},
Err(err) => match $crate::guest::dynclib_abi::error_reply(
$crate::guest::dynclib_abi::code::HANDLE_FAILED,
err.to_string().into_bytes(),
) {
Ok(bytes) => bytes,
Err(code) => return code,
},
};
let resp_len = resp_bytes.len();
let layout = match std::alloc::Layout::from_size_align(resp_len.max(1), 1) {
Ok(l) => l,
Err(_) => return $crate::guest::dynclib_abi::code::GENERIC_ERROR,
};
let ptr = unsafe { std::alloc::alloc(layout) };
if ptr.is_null() {
return $crate::guest::dynclib_abi::code::GENERIC_ERROR;
}
unsafe {
std::ptr::copy_nonoverlapping(resp_bytes.as_ptr(), ptr, resp_len);
*resp_out = ptr;
*resp_len_out = resp_len;
}
return $crate::guest::dynclib_abi::code::SUCCESS;
}
if frame.op != $crate::guest::dynclib_abi::op::GUEST_HANDLE {
return $crate::guest::dynclib_abi::code::UNSUPPORTED_OP;
}
let handle = match <$crate::guest::dynclib_abi::GuestHandleV1 as $crate::guest::dynclib_abi::AbiPayload>::decode_payload(&frame.payload) {
Ok(handle) => handle,
Err(_) => return $crate::guest::dynclib_abi::code::PROTOCOL_ERROR,
};
let envelope = match actr_protocol::RpcEnvelope::decode(handle.rpc_envelope.as_slice()) {
Ok(e) => e,
Err(_) => return $crate::guest::dynclib_abi::code::PROTOCOL_ERROR,
};
let ctx = match unsafe {
$crate::guest::dynclib::context::DynclibContext::from_invocation(vtable, handle.ctx)
} {
Ok(c) => c,
Err(_) => return $crate::guest::dynclib_abi::code::HANDLE_FAILED,
};
let workload = unsafe {
match __ACTR_WORKLOAD.as_ref() {
Some(w) => w,
None => return $crate::guest::dynclib_abi::code::INIT_FAILED,
}
};
type Dispatcher = <$workload_type as Workload>::Dispatcher;
let resp_result = {
let fut = Dispatcher::dispatch(workload, envelope, &ctx);
let waker = std::task::Waker::noop();
let mut cx = std::task::Context::from_waker(waker);
let mut pinned = std::pin::pin!(fut);
match pinned.as_mut().poll(&mut cx) {
std::task::Poll::Ready(v) => v,
std::task::Poll::Pending => {
return $crate::guest::dynclib_abi::code::HANDLE_FAILED;
}
}
};
let resp_bytes = match resp_result {
Ok(b) => match $crate::guest::dynclib_abi::success_reply(b.to_vec()) {
Ok(bytes) => bytes,
Err(code) => return code,
},
Err(err) => match $crate::guest::dynclib_abi::error_reply(
$crate::guest::dynclib_abi::code::HANDLE_FAILED,
err.to_string().into_bytes(),
) {
Ok(bytes) => bytes,
Err(code) => return code,
},
};
let resp_len = resp_bytes.len();
let layout = match std::alloc::Layout::from_size_align(resp_len.max(1), 1) {
Ok(l) => l,
Err(_) => return $crate::guest::dynclib_abi::code::GENERIC_ERROR,
};
let ptr = unsafe { std::alloc::alloc(layout) };
if ptr.is_null() {
return $crate::guest::dynclib_abi::code::GENERIC_ERROR;
}
unsafe {
std::ptr::copy_nonoverlapping(resp_bytes.as_ptr(), ptr, resp_len);
*resp_out = ptr;
*resp_len_out = resp_len;
}
$crate::guest::dynclib_abi::code::SUCCESS
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn actr_free_response(ptr: *mut u8, len: usize) {
if ptr.is_null() || len == 0 {
return;
}
let layout = match std::alloc::Layout::from_size_align(len, 1) {
Ok(l) => l,
Err(_) => return,
};
unsafe { std::alloc::dealloc(ptr, layout) };
}
};
};
}