Skip to main content

lenso_native_adapter/
managed_tasks.rs

1use std::{cell::RefCell, future::Future, rc::Rc};
2
3use lenso_kernel::{
4    CancellationToken, ManagedTask, ManagedTaskError, ManagedTaskScope, RuntimeFailure,
5};
6
7/// A Module field connected to its generation-owned task scope during activation.
8///
9/// Declare this as `#[tasks] tasks: ManagedTasks` on a struct-level Module. The authoring
10/// macro connects it before the Module's optional `Lifecycle::activate` hook runs.
11#[derive(Clone, Default)]
12pub struct ManagedTasks {
13    scope: Rc<RefCell<Option<ManagedTaskScope>>>,
14}
15
16impl std::fmt::Debug for ManagedTasks {
17    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18        formatter
19            .debug_struct("ManagedTasks")
20            .field("active", &self.is_active())
21            .finish()
22    }
23}
24
25impl ManagedTasks {
26    /// Returns whether the Module has entered activation and received its task scope.
27    pub fn is_active(&self) -> bool {
28        self.scope.borrow().is_some()
29    }
30
31    /// Returns the cooperative cancellation token for the active Module generation.
32    pub fn cancellation(&self) -> Result<CancellationToken, ManagedTasksError> {
33        self.scope
34            .borrow()
35            .as_ref()
36            .map(ManagedTaskScope::cancellation)
37            .ok_or(ManagedTasksError::Inactive)
38    }
39
40    /// Spawns work owned by this Module Instance generation.
41    pub fn spawn_local(
42        &self,
43        task: impl Future<Output = ()> + 'static,
44    ) -> Result<ManagedTask, ManagedTasksError> {
45        let scope = self
46            .scope
47            .borrow()
48            .clone()
49            .ok_or(ManagedTasksError::Inactive)?;
50        scope
51            .spawn_local(Box::pin(task))
52            .map_err(ManagedTasksError::Scope)
53    }
54
55    #[doc(hidden)]
56    pub fn __lenso_connect(&self, scope: ManagedTaskScope) -> Result<(), RuntimeFailure> {
57        let mut active = self.scope.borrow_mut();
58        if active.is_some() {
59            return Err(RuntimeFailure::ModuleFailure {
60                detail: "managed task field was connected more than once".to_owned(),
61            });
62        }
63        *active = Some(scope);
64        Ok(())
65    }
66
67    #[doc(hidden)]
68    pub fn __lenso_disconnect(&self) {
69        self.scope.borrow_mut().take();
70    }
71}
72
73/// Failure returned when a Module cannot spawn generation-owned work.
74#[derive(Debug)]
75pub enum ManagedTasksError {
76    /// The Module has not entered activation.
77    Inactive,
78    /// The connected Kernel task scope rejected the task.
79    Scope(ManagedTaskError),
80}