<div align="center">
<h1>CrossBus</h1>
<p>
<strong>A Platform-Less, Runtime-Less Actor Computing Model</strong>
</p>
<p>
[![API Document](https://img.shields.io/docsrs/crossbus/latest)](https://docs.rs/crossbus)
[![crates.io](https://img.shields.io/crates/v/crossbus.svg)](https://crates.io/crates/crossbus)
</p>
</div>
## Overview
[CrossBus](https://github.com/hominee/crossbus) is an implementation of
[Actor Computing Model](https://en.wikipedia.org/wiki/Actor_model),
with the concept that
- **Runtime-less**
crossbus neither provide runtime for app execution
nor access the system interface abstraction.
no built-in runtime, but any runtime is allowed,
the system-provided / third-party's / that from
`FFI`-binding all work.
Last but not least, even a bare-bone [noop-waker executor](https://docs.rs/futures-task/latest/futures_task/fn.noop_waker.html)
can do.
runtime-located features like `concurrency`, `network` and `I/O`
are up to implementor.
- **Bare-Metal Compatible**
crossbus links to no system libraries, no libc,
and a few upstream libraries
enbale you run rust code on bare metal.
the [examples](https://github.com/hominee/crossbus/tree/master/examples)
folder contains some demos to use crossbus.
- **Platform-less by Runtime-less**
take the advantage of runtime-less, crossbus is able to
bypass the limitation of runtime implementor and system
interface abstraction and go right straight to manipulate
task directly. Only a simple and dummy future executor(look at
the [no-std example](https://github.com/hominee/crossbus/tree/master/examples/no-std)) is sufficed to run crossbus. This is the primary
concept of crossbus to run across many platforms or
without platforms.
- **Future-oriented Routine and Events**
the futures way to execute task is retained even
without runtime thanks to rust. crossbus defines a set of types
and traits to allow asynchronous tasks manipulation.
- **Real-time Execution Control**
taking the advantage of the design of future routine,
each poll and events alongside can be intercepted for
each spawned task during execution, with which more
execution control is possible.
**Currently crossbus is in its alpha version, all APIs and architecture
is not stable yet, and evolves very quickly.**
## Documentation
- [API Document](https://docs.rs/crossbus)
- [Dev Blog](https://hominee.github.io/crossbus/dev/post/content.html)
- [Manual Book Coming Soon]()
## Feature Flags
To reduce code redundancy and speed up compilation, crossbus use feature flag to mark the necessary modules/functions, Currently here are some supported Features:
- `core`/`no-std`: the default feature, bare-metal compatible
- `std`: rust std library dependent
- `derive`: enable `#[derive(Message)]` and `#[crossbus::main(...)]`
- `log`: enable logging out states and infos during runtime
- `time`: enable Actor to known time when blocking/delaying some duration
- `rt`: enable use some common convenient runtime
- `tokio`: convenience to use bare tokio-based runtime
- `async-std`: convenience to use async-std-based runtime
- `wasm32`: convenience to use wasm-bindgen-futures-based runtime
- `unstable`: marker for unstable feature
- `time-metric`: enabled with `unstable` and `time`, numerical timing feature
- `force-poll`: enabled with `unstable`, `time`-dependent to periodically wakeup future polling
## How to Use
First of all, add `crossbus` to `Cargo.toml` of project
```toml
[dependencies]
crossbus = "0.0.6-a"
```
#### Types and Imports
define Some types and methods according to your business logic.
let's say a actor to add some number up,
Okay, then the message should be numbers
the actor should know the result after adding.
```rust
use crossbus::prelude::*;
struct Num(uisze);
impl Message for Num {}
struct CrossBus {
sum: isize
}
```
#### Actor Implementation
the actor should be created before using it
we tell crossbus how to create it
```rust
impl Actor for CrossBus {
type Message = Num;
...
fn create(ctx: &mut Context<Self>) -> Self {
Self { sum: 0, }
}
...
}
```
#### Message Action & Reaction
Okay, How the actor respond when the message comes?
we should tell crossbus.
```rust
...
fn action(&mut self, msg: Self::Message, ctx: &mut Context<Self>) {
self.sum += msg.0;
}
...
```
So far so good, but how to obtain the final result
it can be available when the actor process all messages
and stopped, right?
```rust
...
fn stopped(&mut self, _: &mut Context<Self>) {
println!("final sum: {}", self.sum);
}
...
```
Done. Congratulation! You just knew the basic routine to use crossbus.
the Full code see below.
## Example
Here presents a simple demo to sum numbers.
For more examples, you can go to the [examples](https://github.com/hominee/crossbus/tree/master/examples) folder
and clone the repo and run them locally.
```rust
use crossbus::prelude::*;
struct Num(uisze);
impl Message for Num {}
struct CrossBus {
sum: isize
}
impl Actor for CrossBus {
type Message = Num;
fn create(ctx: &mut Context<Self>) -> Self {
Self { sum: 0, }
}
fn action(&mut self, msg: Self::Message, ctx: &mut Context<Self>) {
self.sum += msg.0;
}
fn stopped(&mut self, _: &mut Context<Self>) {
println!("final sum: {}", self.sum);
assert_eq!(self.sum, 7);
}
}
#[main(runtime = tokio)]
async fn main() {
let (addr, id) = CrossBus::start();
println!("actor {} started", id);
let sender = addr.sender();
sender.send(Num(1)).unwrap();
sender.send(Num(2)).unwrap();
sender.send(Num(4)).unwrap();
}
```
## Contributing
Feel Free to Contribute! All issues / bugs-report / feature-request / etc
are welcome!
## References
- [Actix](https://actix.rs)
- [Yew](https://yew.rs)
- [Actor Model](https://en.wikipedia.org/wiki/Actor_model)