Skip to content

Commit

Permalink
Large refactor, make actor traits more first-class
Browse files Browse the repository at this point in the history
  • Loading branch information
aeplay committed Oct 10, 2018
1 parent f175a62 commit a1ed12a
Show file tree
Hide file tree
Showing 12 changed files with 267 additions and 176 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "kay"
description = "Experimental high-performance actor system framework for Rust"
version = "0.2.24"
version = "0.3.0"
authors = ["Anselm Eickhoff <[email protected]>"]
repository = "https://github.com/aeickhoff/kay"
license = "MIT"
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ It offers...
- [X] Actor `ID`s identifying
- [X] Instances of an Actor Type
- [X] Broadcasts to all instances of an Actor Type
- [X] Specific-type-erased Actor Trait IDs
- [X] Generic (type-erased) Actor Trait IDs
- [X] Actor instances across networked computers
- [X] A `Recipient<Message>` trait in which a user implements message handling for each message type that an Actor can receive
- [X] `Swarm`s - collections of large numbers of instances of identical behaviour
- [X] `InstanceStore`s - collections of large numbers of instances of one actor type
- [X] Compact and efficiently managed memory storage for dynamically-sized instance state, supplied by `chunky`
- [X] Dispatch of messages to individual instances
- [X] Very efficient broadcasting of a message to all instances
- [ ] Serialisation-free persistence, snapshotting and loading of actor and system state using memory-mapped files, implemented by `chunky`
- [ ] Future-like abstractions for awaiting and aggregating asynchronous responses from other actors
- [ ] Abstractions like futures and map-reduce for awaiting and aggregating asynchronous responses from other actors
- [X] *"Essential"* message types that are handled even after a panic occurs in an Actor, allowing interactive inspection of the whole panicked system

It internally uses...
Expand All @@ -35,6 +35,6 @@ It internally uses...
- [ ] multi-writer, single-reader
- [ ] lock-free
- [X] The experimental `TypeId` feature, to tag message blobs with their type id for runtime message handling function dispatch
- [X] A [Slot Map](http://seanmiddleditch.com/data-structures-for-game-developers-the-slot-map/) in `Swarm`s to assign unique `ID`s to instances, while always keeping them in continous memory chunks. This makes iterating over them for broadcast messages very fast.
- [X] A [Slot Map](http://seanmiddleditch.com/data-structures-for-game-developers-the-slot-map/) in `InstanceStore`s to assign unique `ID`s to instances, while always keeping them in continous memory chunks. This makes iterating over them for broadcast messages very fast.

kay is inspired by Data-Oriented Game Development, Erlang and the original ideas behind Object-Orientedness. It is thus named after [Alan Kay](https://en.wikipedia.org/wiki/Alan_Kay).
12 changes: 6 additions & 6 deletions examples/simple_common/src/counter/kay_auto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ impl CounterID {
}
pub fn spawn(initial_count: u32, world: &mut World) -> Self {
let id = unsafe { CounterID::from_raw(world.allocate_instance_id::<Counter>()) };
let swarm = world.local_broadcast::<Counter>();
world.send(swarm, MSG_Counter_spawn(id, initial_count));
let instance_store = world.local_broadcast::<Counter>();
world.send(instance_store, MSG_Counter_spawn(id, initial_count));
id
}
}
Expand All @@ -126,8 +126,8 @@ struct MSG_Counter_spawn(pub CounterID, pub u32);
impl ServerLoggerID {
pub fn spawn(counter_id: CounterID, world: &mut World) -> Self {
let id = unsafe { ServerLoggerID::from_raw(world.allocate_instance_id::<ServerLogger>()) };
let swarm = world.local_broadcast::<ServerLogger>();
world.send(swarm, MSG_ServerLogger_spawn(id, counter_id));
let instance_store = world.local_broadcast::<ServerLogger>();
world.send(instance_store, MSG_ServerLogger_spawn(id, counter_id));
id
}
}
Expand All @@ -138,8 +138,8 @@ impl BrowserLoggerID {
pub fn spawn(counter_id: CounterID, world: &mut World) -> Self {
let id =
unsafe { BrowserLoggerID::from_raw(world.allocate_instance_id::<BrowserLogger>()) };
let swarm = world.local_broadcast::<BrowserLogger>();
world.send(swarm, MSG_BrowserLogger_spawn(id, counter_id));
let instance_store = world.local_broadcast::<BrowserLogger>();
world.send(instance_store, MSG_BrowserLogger_spawn(id, counter_id));
id
}
}
Expand Down
46 changes: 46 additions & 0 deletions src/actor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use compact::Compact;
use id::{RawID, TypedID};
use storage_aware::StorageAware;

/// Represents both Actors and ActorTraits, used everywhere both are admissible
pub trait ActorOrActorTrait: 'static {
/// The unique `TypedID` of this actor or actor trait
type ID: TypedID;
}

impl<A: Actor> ActorOrActorTrait for A {
type ID = <Self as Actor>::ID;
}

/// Trait that Actors instance have to implement for a [`InstanceStore`](struct.InstanceStore.html)
/// so their internally stored instance `RawID` can be gotten and set.
///
/// Furthermore, an `Actor` has to implement [`Compact`](../../compact), so a `InstanceStore`
/// can compactly store each `Actor`'s potentially dynamically-sized state.
///
/// This trait can is auto-derived when using the
/// [`kay_codegen`](../../kay_codegen/index.html) build script.
pub trait Actor: Compact + StorageAware + 'static {
/// The unique `TypedID` of this actor
type ID: TypedID;
/// Get `TypedID` of this actor
fn id(&self) -> Self::ID;
/// Set the full RawID (Actor type id + instance id)
/// of this actor (only used internally by `InstanceStore`)
unsafe fn set_id(&mut self, id: RawID);

/// Get the id of this actor as an actor trait `TypedID`
/// (available if the actor implements the corresponding trait)
fn id_as<TargetID: TraitIDFrom<Self>>(&self) -> TargetID {
TargetID::from(self.id())
}
}

/// Helper trait that signifies that an actor's `TypedID` can be converted
/// to an actor trait `TypedID` if that actor implements the corresponding trait.
pub trait TraitIDFrom<A: Actor>: TypedID {
/// Construct the actor trait `TypedID` from an actor's `TypedID`
fn from(id: <A as Actor>::ID) -> Self {
Self::from_raw(id.as_raw())
}
}
Loading

0 comments on commit a1ed12a

Please sign in to comment.