crux_core 0.19.0

Cross-platform app development in Rust
Documentation
use std::{
    future::{self, Future},
    pin::Pin,
    task::Poll,
};

use serde::{Deserialize, Serialize};

use crate::{Command, Request, capability::Operation, command::CommandContext};

struct ImmediateWake {
    wake_count: usize,
}

impl Future for ImmediateWake {
    type Output = usize;

    fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
        if self.wake_count < 1 {
            Poll::Ready(self.wake_count)
        } else {
            self.wake_count -= 1;

            cx.waker().wake_by_ref();

            Poll::Pending
        }
    }
}

#[derive(PartialEq, Debug)]
enum Event {
    Count(usize),
}

#[derive(PartialEq, Clone, Serialize, Deserialize)]
struct Op;

impl Operation for Op {
    type Output = usize;
}

enum Effect {
    Effect(Request<Op>),
}

impl From<Request<Op>> for Effect {
    fn from(value: Request<Op>) -> Self {
        Self::Effect(value)
    }
}

#[test]
fn tasks_with_no_more_wakers_are_evicted() {
    let mut cmd = Command::request_from_shell(Op).then_send(Event::Count);

    let effect = cmd.effects().next().expect("should see effect");

    let Effect::Effect(request) = effect;

    assert!(!cmd.is_done());

    drop(request);

    assert!(cmd.is_done());
}

#[test]
fn tasks_which_wake_themselves_and_drop_wakers_are_not_evicted() {
    let mut cmd = Command::<Effect, Event>::new(|ctx| async move {
        let count = ImmediateWake { wake_count: 2 }.await;
        ctx.send_event(Event::Count(count));
    });

    assert_eq!(cmd.events().next(), Some(Event::Count(0)));

    assert!(cmd.is_done());
}

#[test]
fn is_not_done_until_all_contexts_are_dropped() {
    let mut ctx = None;
    let mut cmd = Command::new(|cmd_ctx: CommandContext<(), ()>| {
        ctx = Some(cmd_ctx);
        future::ready(())
    });

    assert!(!cmd.is_done());

    drop(ctx);

    assert!(cmd.is_done());
}