//! Resident event/effect fixture covering every current Host-driven I/O family. //! //! The callback echoes stream chunks and datagrams, rearms fired timers, //! acknowledges messages, and reflects extension commands. It owns no socket, //! timer, or subscription handles; those resources remain in the Host driver. use std::sync::atomic::{AtomicU64, Ordering}; mod bindings { // One generated module contains both the base service export and resident // actor export because this component world composes both WIT packages. wit_bindgen::generate!({ path: "wit", world: "resident-probe-component", generate_all, }); } use bindings::exports::wasmeld::resident::actor::{ DatagramSend, Effect, Event, Guest as ResidentGuest, MessageAck, SourceCommand, StreamWrite, TimerArm, }; static EVENTS_HANDLED: AtomicU64 = AtomicU64::new(0); struct ResidentProbe; impl bindings::Guest for ResidentProbe { fn init(_config: Vec) -> Result<(), bindings::ServiceError> { EVENTS_HANDLED.store(0, Ordering::Relaxed); Ok(()) } fn invoke(_input: Vec) -> Result, bindings::ServiceError> { Ok(EVENTS_HANDLED .load(Ordering::Relaxed) .to_le_bytes() .to_vec()) } } impl ResidentGuest for ResidentProbe { fn handle_event( input: Event, ) -> Result, bindings::exports::wasmeld::resident::actor::ResidentError> { // Event callbacks are serialized with normal invocations by the same // Actor mailbox, so this in-memory count is deterministic per Actor. EVENTS_HANDLED.fetch_add(1, Ordering::Relaxed); Ok(match input { Event::StreamData(chunk) => vec![Effect::WriteStream(StreamWrite { stream_id: chunk.stream_id, bytes: chunk.bytes, })], Event::Datagram(datagram) => vec![Effect::SendDatagram(DatagramSend { endpoint_id: datagram.endpoint_id, peer: datagram.peer, bytes: datagram.bytes, })], Event::Timer(timer) => vec![Effect::ArmTimer(TimerArm { timer_id: timer.timer_id, delay_ms: 10, interval_ms: None, })], Event::Message(message) => vec![Effect::AcknowledgeMessage(MessageAck { subscription_id: message.subscription_id, message_id: message.message_id, })], Event::Source(source) => vec![Effect::SourceCommand(SourceCommand { source_id: source.source_id, command: source.kind, payload: source.payload, })], Event::StreamOpened(_) | Event::StreamWritable(_) | Event::StreamHalfClosed(_) | Event::StreamClosed(_) | Event::Shutdown => Vec::new(), }) } } bindings::export!(ResidentProbe with_types_in bindings);