fix: consolidate modules
Better consoliation of modules into more logical components.
This commit is contained in:
parent
06566b5e0f
commit
c80060f453
18 changed files with 206 additions and 250 deletions
|
|
@ -8,9 +8,8 @@
|
|||
use crate::harness::{black_box, Bench, BenchSuite};
|
||||
use std::thread;
|
||||
use swactor::{
|
||||
Ctx,
|
||||
actor::ActorInterface,
|
||||
runtime::{Runtime, RuntimeConfig},
|
||||
runtime::{Ctx, Runtime, RuntimeConfig},
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
|
|
|
|||
|
|
@ -8,9 +8,8 @@
|
|||
|
||||
use crate::harness::{black_box, Bench, BenchSuite};
|
||||
use swactor::{
|
||||
Ctx,
|
||||
actor::{ActorAddress, ActorInterface},
|
||||
runtime::{Runtime, RuntimeConfig},
|
||||
runtime::{Ctx, Runtime, RuntimeConfig},
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use swactor::{
|
||||
Ctx,
|
||||
actor::{ActorAddress, ActorInterface},
|
||||
runtime::{Runtime, RuntimeConfig},
|
||||
runtime::{Ctx, Runtime, RuntimeConfig},
|
||||
};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use swactor::{
|
||||
Ctx,
|
||||
actor::{ActorAddress, ActorInterface},
|
||||
runtime::{Inbox, Runtime, RuntimeConfig},
|
||||
runtime::{Ctx, Inbox, Runtime, RuntimeConfig},
|
||||
};
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use std::any::Any;
|
||||
|
||||
use crate::{get_random, worker::mailbox::Mailbox};
|
||||
use crate::context::{ContextInner, Ctx};
|
||||
use crate::{get_random, runtime::{ContextInner, Ctx}, worker::Mailbox};
|
||||
|
||||
/// The primary trait defining data that can be passed to and from actor processes
|
||||
pub trait Message: 'static + Sized + Clone + Send + Sync {}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::collections::HashMap;
|
||||
use std::sync::RwLock;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use crate::actor::ActorAddress;
|
||||
|
||||
|
|
@ -50,6 +51,26 @@ impl AddressMap {
|
|||
}
|
||||
}
|
||||
|
||||
/// Round-robin actor placement strategy.
|
||||
pub(crate) struct Placement {
|
||||
next: AtomicUsize,
|
||||
num_workers: usize,
|
||||
}
|
||||
|
||||
impl Placement {
|
||||
pub fn new(num_workers: usize) -> Self {
|
||||
Self {
|
||||
next: AtomicUsize::new(0),
|
||||
num_workers,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next_worker(&self) -> WorkerId {
|
||||
let id = self.next.fetch_add(1, Ordering::Relaxed) % self.num_workers;
|
||||
WorkerId(id)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
@ -87,4 +108,13 @@ mod tests {
|
|||
map.insert(addr1, WorkerId(0));
|
||||
assert_eq!(map.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_robin() {
|
||||
let p = Placement::new(3);
|
||||
assert_eq!(p.next_worker(), WorkerId(0));
|
||||
assert_eq!(p.next_worker(), WorkerId(1));
|
||||
assert_eq!(p.next_worker(), WorkerId(2));
|
||||
assert_eq!(p.next_worker(), WorkerId(0));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use crossbeam_queue::{ArrayQueue, SegQueue};
|
||||
|
||||
pub struct HybridChannel<T> {
|
||||
ring: ArrayQueue<T>,
|
||||
overflow: SegQueue<T>,
|
||||
overflow_len: AtomicUsize,
|
||||
}
|
||||
|
||||
impl<T> HybridChannel<T> {
|
||||
|
|
@ -15,7 +13,6 @@ impl<T> HybridChannel<T> {
|
|||
Self {
|
||||
ring: ArrayQueue::new(capacity),
|
||||
overflow: SegQueue::new(),
|
||||
overflow_len: AtomicUsize::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -24,7 +21,6 @@ impl<T> HybridChannel<T> {
|
|||
Ok(()) => Ok(()),
|
||||
Err(v) => {
|
||||
self.overflow.push(v);
|
||||
self.overflow_len.fetch_add(1, Ordering::Relaxed);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -37,16 +33,12 @@ impl<T> HybridChannel<T> {
|
|||
|
||||
match self.overflow.pop() {
|
||||
Some(value) => {
|
||||
self.overflow_len.fetch_sub(1, Ordering::Relaxed);
|
||||
Some(value)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.ring.len() + self.overflow_len.load(Ordering::Relaxed)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Receiver<T> {
|
||||
|
|
@ -59,11 +51,6 @@ impl<T> Receiver<T> {
|
|||
|
||||
Self { queue }
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.queue.len()
|
||||
}
|
||||
|
||||
pub fn try_recv(&self) -> Option<T> {
|
||||
return self.queue.pop();
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
use std::any::Any;
|
||||
|
||||
use crate::actor::{Actor, ActorAddress, ActorInterface, AnyActor, Message};
|
||||
use crate::worker::mailbox::Mailbox;
|
||||
use crate::Error;
|
||||
|
||||
/// Object-safe inner trait for sending type-erased messages.
|
||||
pub(crate) trait ContextInner {
|
||||
fn send_any(&self, addr: ActorAddress, msg: Box<dyn Any + Send>) -> Result<(), Error>;
|
||||
fn spawn_any(&self, addr: ActorAddress, actor: Box<dyn AnyActor>) -> Result<(), Error>;
|
||||
fn mailbox_waterlevel(&self) -> usize;
|
||||
}
|
||||
|
||||
/// Actor syscall interface — passed to `ActorInterface::handle()`.
|
||||
///
|
||||
/// Wraps a `&dyn ContextInner` to solve the object-safety problem while
|
||||
/// providing a typed public API.
|
||||
pub struct Ctx<'a> {
|
||||
inner: &'a dyn ContextInner,
|
||||
self_addr: ActorAddress,
|
||||
}
|
||||
|
||||
impl<'a> Ctx<'a> {
|
||||
pub(crate) fn new(inner: &'a dyn ContextInner, self_addr: ActorAddress) -> Self {
|
||||
Self { inner, self_addr }
|
||||
}
|
||||
|
||||
/// Returns the address of the actor currently being ticked.
|
||||
pub fn self_addr(&self) -> ActorAddress {
|
||||
self.self_addr
|
||||
}
|
||||
|
||||
/// Send a typed message to an actor address.
|
||||
pub fn send<M: Message>(&self, addr: ActorAddress, msg: M) -> Result<(), Error> {
|
||||
self.inner.send_any(addr, Box::new(msg))
|
||||
}
|
||||
|
||||
/// Spawn a new actor, returning its address.
|
||||
pub fn spawn<A: ActorInterface>(&self, actor: A) -> Result<ActorAddress, Error> {
|
||||
let addr = ActorAddress::new_random();
|
||||
let waterlevel = self.inner.mailbox_waterlevel();
|
||||
let actor = Actor::new(addr, Mailbox::new(waterlevel), actor);
|
||||
let boxed: Box<dyn AnyActor> = Box::new(actor);
|
||||
self.inner.spawn_any(addr, boxed)?;
|
||||
Ok(addr)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,31 +2,6 @@ use std::any::Any;
|
|||
|
||||
use crate::actor::ActorAddress;
|
||||
|
||||
/// A type-erased message envelope for cross-worker delivery.
|
||||
///
|
||||
/// Uses `Box` (no atomic refcount) and move semantics (no clone).
|
||||
pub(crate) struct Envelope {
|
||||
dest: ActorAddress,
|
||||
payload: Box<dyn Any + Send>,
|
||||
}
|
||||
|
||||
impl Envelope {
|
||||
pub fn new(dest: ActorAddress, payload: Box<dyn Any + Send>) -> Self {
|
||||
Self { dest, payload }
|
||||
}
|
||||
|
||||
pub fn dest(&self) -> ActorAddress {
|
||||
self.dest
|
||||
}
|
||||
|
||||
pub fn downcast<M: 'static>(self) -> Option<M> {
|
||||
self.payload.downcast::<M>().ok().map(|b| *b)
|
||||
}
|
||||
|
||||
pub fn into_payload(self) -> Box<dyn Any + Send> {
|
||||
self.payload
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
|
|||
|
|
@ -5,12 +5,8 @@ pub(crate) mod channel;
|
|||
pub(crate) mod error;
|
||||
pub use error::Error;
|
||||
|
||||
pub mod context;
|
||||
pub use context::Ctx;
|
||||
|
||||
pub(crate) mod envelope;
|
||||
pub(crate) mod address_map;
|
||||
pub(crate) mod placement;
|
||||
pub mod config;
|
||||
|
||||
pub mod runtime;
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use crate::address_map::WorkerId;
|
||||
|
||||
/// Round-robin actor placement strategy.
|
||||
pub(crate) struct Placement {
|
||||
next: AtomicUsize,
|
||||
num_workers: usize,
|
||||
}
|
||||
|
||||
impl Placement {
|
||||
pub fn new(num_workers: usize) -> Self {
|
||||
Self {
|
||||
next: AtomicUsize::new(0),
|
||||
num_workers,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next_worker(&self) -> WorkerId {
|
||||
let id = self.next.fetch_add(1, Ordering::Relaxed) % self.num_workers;
|
||||
WorkerId(id)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn round_robin() {
|
||||
let p = Placement::new(3);
|
||||
assert_eq!(p.next_worker(), WorkerId(0));
|
||||
assert_eq!(p.next_worker(), WorkerId(1));
|
||||
assert_eq!(p.next_worker(), WorkerId(2));
|
||||
assert_eq!(p.next_worker(), WorkerId(0));
|
||||
}
|
||||
}
|
||||
|
|
@ -6,14 +6,11 @@ use std::sync::{Arc, RwLock};
|
|||
use std::thread::{self, JoinHandle};
|
||||
|
||||
use crate::actor::{Actor, ActorAddress, ActorInterface, AnyActor, Message};
|
||||
use crate::address_map::{AddressMap, WorkerId};
|
||||
use crate::address_map::{AddressMap, Placement, WorkerId};
|
||||
use crate::channel::{Receiver, Sender};
|
||||
// Re-export config types so existing code using `runtime::RuntimeConfig` still works
|
||||
pub use crate::config::{BackoffPolicy, RuntimeConfig};
|
||||
use crate::context::ContextInner;
|
||||
use crate::envelope::Envelope;
|
||||
use crate::placement::Placement;
|
||||
use crate::worker::mailbox::Mailbox;
|
||||
use crate::worker::Mailbox;
|
||||
use crate::worker::{TickContext, Worker};
|
||||
use crate::Error;
|
||||
|
||||
|
|
@ -32,6 +29,34 @@ impl<M: Message> SenderT for Sender<M> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// A type-erased message envelope for cross-worker delivery.
|
||||
///
|
||||
/// Uses `Box` (no atomic refcount) and move semantics (no clone).
|
||||
pub(crate) struct Envelope {
|
||||
dest: ActorAddress,
|
||||
payload: Box<dyn Any + Send>,
|
||||
}
|
||||
|
||||
impl Envelope {
|
||||
pub fn new(dest: ActorAddress, payload: Box<dyn Any + Send>) -> Self {
|
||||
Self { dest, payload }
|
||||
}
|
||||
|
||||
pub fn dest(&self) -> ActorAddress {
|
||||
self.dest
|
||||
}
|
||||
|
||||
pub fn downcast<M: 'static>(self) -> Option<M> {
|
||||
self.payload.downcast::<M>().ok().map(|b| *b)
|
||||
}
|
||||
|
||||
pub fn into_payload(self) -> Box<dyn Any + Send> {
|
||||
self.payload
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ─── InboxRegistry ───────────────────────────────────────────────────────────
|
||||
|
||||
/// Registry of external inboxes — replaces the Router's role for non-actor receivers.
|
||||
|
|
@ -83,6 +108,50 @@ impl<M: Message> Inbox<M> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// Object-safe inner trait for sending type-erased messages.
|
||||
pub(crate) trait ContextInner {
|
||||
fn send_any(&self, addr: ActorAddress, msg: Box<dyn Any + Send>) -> Result<(), Error>;
|
||||
fn spawn_any(&self, addr: ActorAddress, actor: Box<dyn AnyActor>) -> Result<(), Error>;
|
||||
fn mailbox_waterlevel(&self) -> usize;
|
||||
}
|
||||
|
||||
/// Actor syscall interface — passed to `ActorInterface::handle()`.
|
||||
///
|
||||
/// Wraps a `&dyn ContextInner` to solve the object-safety problem while
|
||||
/// providing a typed public API.
|
||||
pub struct Ctx<'a> {
|
||||
inner: &'a dyn ContextInner,
|
||||
self_addr: ActorAddress,
|
||||
}
|
||||
|
||||
impl<'a> Ctx<'a> {
|
||||
pub(crate) fn new(inner: &'a dyn ContextInner, self_addr: ActorAddress) -> Self {
|
||||
Self { inner, self_addr }
|
||||
}
|
||||
|
||||
/// Returns the address of the actor currently being ticked.
|
||||
pub fn self_addr(&self) -> ActorAddress {
|
||||
self.self_addr
|
||||
}
|
||||
|
||||
/// Send a typed message to an actor address.
|
||||
pub fn send<M: Message>(&self, addr: ActorAddress, msg: M) -> Result<(), Error> {
|
||||
self.inner.send_any(addr, Box::new(msg))
|
||||
}
|
||||
|
||||
/// Spawn a new actor, returning its address.
|
||||
pub fn spawn<A: ActorInterface>(&self, actor: A) -> Result<ActorAddress, Error> {
|
||||
let addr = ActorAddress::new_random();
|
||||
let waterlevel = self.inner.mailbox_waterlevel();
|
||||
let actor = Actor::new(addr, Mailbox::new(waterlevel), actor);
|
||||
let boxed: Box<dyn AnyActor> = Box::new(actor);
|
||||
self.inner.spawn_any(addr, boxed)?;
|
||||
Ok(addr)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ─── Runtime ─────────────────────────────────────────────────────────────────
|
||||
|
||||
/// The `Runtime` struct is the primary gateway for interacting with the framework.
|
||||
|
|
|
|||
|
|
@ -1,19 +1,13 @@
|
|||
pub mod mailbox;
|
||||
pub(crate) mod pool;
|
||||
|
||||
use std::any::Any;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
|
||||
use crate::actor::{ActorAddress, AnyActor};
|
||||
use crate::address_map::{AddressMap, WorkerId};
|
||||
use crate::actor::{ActorAddress, AnyActor, Message};
|
||||
use crate::address_map::{AddressMap, Placement, WorkerId};
|
||||
use crate::channel::{Receiver, Sender};
|
||||
use crate::config::RuntimeConfig;
|
||||
use crate::context::ContextInner;
|
||||
use crate::envelope::Envelope;
|
||||
use crate::placement::Placement;
|
||||
use crate::runtime::InboxRegistry;
|
||||
use crate::runtime::{ContextInner, Envelope, InboxRegistry};
|
||||
use crate::Error;
|
||||
use pool::ActorPool;
|
||||
|
||||
/// Shared state passed to tick_once — single thin pointer avoids register spill.
|
||||
pub(crate) struct TickContext<'a> {
|
||||
|
|
@ -146,3 +140,93 @@ impl ContextInner for WorkerContext<'_> {
|
|||
self.config.mailbox_waterlevel
|
||||
}
|
||||
}
|
||||
|
||||
/// Per-worker actor storage.
|
||||
pub(crate) struct ActorPool {
|
||||
actors: HashMap<ActorAddress, Box<dyn AnyActor>>,
|
||||
}
|
||||
|
||||
impl ActorPool {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
actors: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, addr: ActorAddress, actor: Box<dyn AnyActor>) {
|
||||
self.actors.insert(addr, actor);
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, addr: &ActorAddress) -> Option<Box<dyn AnyActor>> {
|
||||
self.actors.remove(addr)
|
||||
}
|
||||
|
||||
/// Deliver a type-erased message to the actor at `addr`.
|
||||
/// Returns `true` if the actor was found and the message type matched.
|
||||
pub fn deliver(&mut self, addr: &ActorAddress, msg: Box<dyn Any + Send>) -> bool {
|
||||
if let Some(actor) = self.actors.get_mut(addr) {
|
||||
actor.deliver(msg)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Tick all actors in the pool. Returns `true` if any actor processed messages.
|
||||
pub fn tick_all(&mut self, inner: &dyn ContextInner) -> bool {
|
||||
let mut did_work = false;
|
||||
for actor in self.actors.values_mut() {
|
||||
if actor.tick(inner) {
|
||||
did_work = true;
|
||||
}
|
||||
}
|
||||
did_work
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.actors.len()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub struct Mailbox<M: Message> {
|
||||
queue: VecDeque<M>,
|
||||
waterlevel: usize,
|
||||
}
|
||||
|
||||
impl<M: Message> Mailbox<M> {
|
||||
pub fn new(waterlevel: usize) -> Self {
|
||||
Self {
|
||||
queue: VecDeque::new(),
|
||||
waterlevel,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, msg: M) {
|
||||
self.queue.push_back(msg);
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> Option<M> {
|
||||
self.queue.pop_front()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.queue.len()
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.queue.is_empty()
|
||||
}
|
||||
|
||||
/// How many messages to process this tick:
|
||||
/// - `len < waterlevel` → process all (`len`)
|
||||
/// - `len >= waterlevel` → process half (`len >> 1`)
|
||||
pub fn drain_count(&self) -> usize {
|
||||
let len = self.queue.len();
|
||||
if len < self.waterlevel {
|
||||
len
|
||||
} else {
|
||||
len >> 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
use std::collections::VecDeque;
|
||||
|
||||
use crate::actor::Message;
|
||||
|
||||
pub struct Mailbox<M: Message> {
|
||||
queue: VecDeque<M>,
|
||||
waterlevel: usize,
|
||||
}
|
||||
|
||||
impl<M: Message> Mailbox<M> {
|
||||
pub fn new(waterlevel: usize) -> Self {
|
||||
Self {
|
||||
queue: VecDeque::new(),
|
||||
waterlevel,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, msg: M) {
|
||||
self.queue.push_back(msg);
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> Option<M> {
|
||||
self.queue.pop_front()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.queue.len()
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.queue.is_empty()
|
||||
}
|
||||
|
||||
/// How many messages to process this tick:
|
||||
/// - `len < waterlevel` → process all (`len`)
|
||||
/// - `len >= waterlevel` → process half (`len >> 1`)
|
||||
pub fn drain_count(&self) -> usize {
|
||||
let len = self.queue.len();
|
||||
if len < self.waterlevel {
|
||||
len
|
||||
} else {
|
||||
len >> 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
use std::any::Any;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::actor::{ActorAddress, AnyActor};
|
||||
use crate::context::ContextInner;
|
||||
|
||||
/// Per-worker actor storage.
|
||||
pub(crate) struct ActorPool {
|
||||
actors: HashMap<ActorAddress, Box<dyn AnyActor>>,
|
||||
}
|
||||
|
||||
impl ActorPool {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
actors: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, addr: ActorAddress, actor: Box<dyn AnyActor>) {
|
||||
self.actors.insert(addr, actor);
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, addr: &ActorAddress) -> Option<Box<dyn AnyActor>> {
|
||||
self.actors.remove(addr)
|
||||
}
|
||||
|
||||
/// Deliver a type-erased message to the actor at `addr`.
|
||||
/// Returns `true` if the actor was found and the message type matched.
|
||||
pub fn deliver(&mut self, addr: &ActorAddress, msg: Box<dyn Any + Send>) -> bool {
|
||||
if let Some(actor) = self.actors.get_mut(addr) {
|
||||
actor.deliver(msg)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Tick all actors in the pool. Returns `true` if any actor processed messages.
|
||||
pub fn tick_all(&mut self, inner: &dyn ContextInner) -> bool {
|
||||
let mut did_work = false;
|
||||
for actor in self.actors.values_mut() {
|
||||
if actor.tick(inner) {
|
||||
did_work = true;
|
||||
}
|
||||
}
|
||||
did_work
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.actors.len()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use swactor::worker::mailbox::Mailbox;
|
||||
use swactor::worker::Mailbox;
|
||||
|
||||
// ── Basic operations ──
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use swactor::{Ctx, actor::{ActorAddress, ActorInterface}, runtime::{Inbox, Runtime, RuntimeConfig}};
|
||||
use swactor::{actor::{ActorAddress, ActorInterface}, runtime::{Ctx, Inbox, Runtime, RuntimeConfig}};
|
||||
|
||||
#[derive(Clone)]
|
||||
struct PingMessage {
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ impl Stress {
|
|||
}
|
||||
|
||||
// Test actors used across stress tests
|
||||
use swactor::{Ctx, actor::ActorInterface};
|
||||
use swactor::{actor::ActorInterface, runtime::Ctx};
|
||||
|
||||
/// An actor that just absorbs messages
|
||||
pub struct BlackHole;
|
||||
|
|
|
|||
Loading…
Reference in a new issue