add split-crate example

This commit is contained in:
Jorge Aparicio 2021-09-27 15:18:37 +02:00
parent a58be575cb
commit 11694e134f
11 changed files with 368 additions and 0 deletions

View file

@ -0,0 +1,10 @@
[package]
name = "actors"
version = "0.1.0"
edition = "2018"
[dependencies.rtic-actor-traits]
path = "../../actor-traits"
[dev-dependencies.rtic-post-spy]
path = "../../post-spy"

View file

@ -0,0 +1,84 @@
use rtic_actor_traits::Post;
use crate::TemperatureReadingCelsius;
pub struct FakeTemperatureSensor<P>
where
P: Post<TemperatureReadingCelsius>,
{
delta: i32,
outbox: P,
temperature: i32,
}
// a real temperature sensor would use the embedded-hal traits (e.g. I2C) or some higher level trait
impl<P> FakeTemperatureSensor<P>
where
P: Post<TemperatureReadingCelsius>,
{
pub fn new(outbox: P, initial_temperature: i32, delta: i32) -> Self {
Self {
delta,
outbox,
temperature: initial_temperature,
}
}
pub fn read(&mut self) {
self.outbox
.post(TemperatureReadingCelsius(self.temperature))
.expect("OOM");
self.temperature += self.delta;
}
}
#[cfg(test)]
mod tests {
use rtic_post_spy::PostSpy;
use super::*;
#[test]
fn on_read_it_posts_reading() {
let mut sensor = FakeTemperatureSensor::new(PostSpy::default(), 0, 0);
sensor.read();
let spy = sensor.outbox;
let posted_messages = spy.posted_messages::<TemperatureReadingCelsius>();
assert_eq!(1, posted_messages.count());
}
#[test]
fn reading_starts_at_initial_temperature() {
let initial_temperature = 1;
let mut sensor = FakeTemperatureSensor::new(PostSpy::default(), initial_temperature, 0);
sensor.read();
let spy = sensor.outbox;
let mut posted_messages = spy.posted_messages::<TemperatureReadingCelsius>();
assert_eq!(
Some(&TemperatureReadingCelsius(initial_temperature)),
posted_messages.next()
);
}
#[test]
fn reading_changes_by_delta() {
let initial_temperature = 42;
let delta = 1;
let mut sensor = FakeTemperatureSensor::new(PostSpy::default(), initial_temperature, delta);
sensor.read();
sensor.read();
let spy = sensor.outbox;
let mut posted_messages = spy.posted_messages::<TemperatureReadingCelsius>();
assert_eq!(
Some(&TemperatureReadingCelsius(initial_temperature)),
posted_messages.next()
);
assert_eq!(
Some(&TemperatureReadingCelsius(initial_temperature + delta)),
posted_messages.next()
);
}
}

View file

@ -0,0 +1,14 @@
#![no_std]
mod fake_temperature_sensor;
mod temperature_monitor;
// Actors
pub use fake_temperature_sensor::FakeTemperatureSensor;
pub use temperature_monitor::TemperatureMonitor;
// Messages
pub struct TemperatureAlert;
#[derive(Clone, Debug, PartialEq)]
pub struct TemperatureReadingCelsius(pub i32);

View file

@ -0,0 +1,63 @@
use rtic_actor_traits::{Post, Receive};
use crate::{TemperatureAlert, TemperatureReadingCelsius};
pub struct TemperatureMonitor<P>
where
P: Post<TemperatureAlert>,
{
outbox: P,
threshold: i32,
}
impl<P> TemperatureMonitor<P>
where
P: Post<TemperatureAlert>,
{
pub fn new(outbox: P, threshold: i32) -> Self {
Self { outbox, threshold }
}
}
impl<P> Receive<TemperatureReadingCelsius> for TemperatureMonitor<P>
where
P: Post<TemperatureAlert>,
{
fn receive(&mut self, temperature: TemperatureReadingCelsius) {
if temperature.0 >= self.threshold {
self.outbox.post(TemperatureAlert).ok().expect("OOM");
}
}
}
#[cfg(test)]
mod tests {
use rtic_post_spy::PostSpy;
use super::*;
#[test]
fn when_temperature_is_above_threshold_it_posts_alert_once() {
let mut monitor = TemperatureMonitor::new(PostSpy::default(), 0);
// manually send a message
let message = TemperatureReadingCelsius(1);
monitor.receive(message);
let spy = monitor.outbox;
let posted_messages = spy.posted_messages::<TemperatureAlert>();
assert_eq!(1, posted_messages.count());
}
#[test]
fn when_temperature_is_below_threshold_it_does_not_post_alert() {
let mut monitor = TemperatureMonitor::new(PostSpy::default(), 0);
let message = TemperatureReadingCelsius(-1);
monitor.receive(message);
let spy = monitor.outbox;
let posted_messages = spy.posted_messages::<TemperatureAlert>();
assert_eq!(0, posted_messages.count());
}
}