xpanse_api/app.rs
1//! Application lifecycle and resource ownership.
2//!
3//! Apps lease capabilities from a [`Registry`] when they are created and must
4//! return every lease when they are released. This makes resource availability
5//! predictable as the platform switches between apps.
6
7use alloc::boxed::Box;
8use core::future::Future;
9use core::pin::Pin;
10
11use crate::registry::Registry;
12
13/// An application that can be selected and run by the xpanse firmware.
14///
15/// `can_run` should mirror the resource set acquired by `new`, without mutating
16/// the registry. After `run` completes, the platform passes the app to
17/// `release`, which must return all of its resource leases.
18///
19/// Apps run on core 1, so any task spawned will also run core 1
20///
21/// Apps can use slint ui or direct video to show stuff on the screen
22///
23/// # Example
24///
25/// ```ignore
26/// use std::{boxed::Box, future::Future, pin::Pin};
27/// use xpanse_api::{
28/// app::App,
29/// registry::{Registry, ResourceLease},
30/// };
31///
32/// struct StatusLed;
33///
34/// struct StatusApp {
35/// led: ResourceLease<StatusLed>,
36/// }
37///
38/// impl App for StatusApp {
39/// const NAME: &'static str = "Status";
40///
41/// fn can_run(registry: &Registry) -> bool {
42/// registry.has::<StatusLed>()
43/// }
44///
45/// fn new(registry: &mut Registry) -> Option<Self> {
46/// Some(Self { led: registry.take_resource()? })
47/// }
48///
49/// fn run<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
50/// Box::pin(async move {
51/// let _led = self.led.resource_mut();
52/// // Drive the capability until the app decides to exit.
53/// })
54/// }
55///
56/// fn release(self, registry: &mut Registry) {
57/// registry.return_resource(self.led);
58/// }
59/// }
60/// ```
61pub trait App: Send {
62 /// User-facing name shown by the app picker.
63 const NAME: &'static str;
64
65 /// Runs the app until it exits.
66 ///
67 /// Resource leases held by `self` remain exclusive while this future is
68 /// alive. The returned future is not required to be [`Send`].
69 fn run<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = ()> + 'a>>;
70
71 /// Reports whether all resources required by this app are available.
72 ///
73 /// This method must not mutate `registry`. Use
74 /// [`Registry::has_resource_set`] when the app needs several distinct
75 /// physical resources.
76 fn can_run(registry: &Registry) -> bool
77 where
78 Self: Sized;
79
80 /// Leases the resources required to construct the app.
81 ///
82 /// Returns `None` if the resources are no longer available. Acquisition of
83 /// multiple resources should use [`Registry::take_resource_set`] so it is
84 /// atomic.
85 fn new(registry: &mut Registry) -> Option<Self>
86 where
87 Self: Sized;
88
89 /// Returns every resource lease held by the app to `registry`.
90 ///
91 /// Dropping a lease instead would permanently remove its complete physical
92 /// resource group from the registry.
93 fn release(self, registry: &mut Registry)
94 where
95 Self: Sized;
96}