blob: fbce7c9064105423ea823da3916883383f79cd88 [file] [log] [blame]
Brian Silverman9809c5f2022-07-23 16:12:23 -07001#![warn(unsafe_op_in_unsafe_fn)]
2
3//! This module provides a Rust async runtime on top of the C++ `aos::EventLoop` interface.
4//!
5//! # Rust async with `aos::EventLoop`
6//!
7//! The async runtimes we create are not general-purpose. They may only await the objects provided
8//! by this module. Awaiting anything else will hang, until it is woken which will panic. Also,
9//! doing any long-running task (besides await) will block the C++ EventLoop thread, which is
10//! usually bad.
11//!
12//! ## Multiple tasks
13//!
14//! This runtime only supports a single task (aka a single [`Future`]) at a time. For many use
15//! cases, this is sufficient. If you want more than that, one of these may be appropriate:
16//!
17//! 1. If you have a small number of tasks determined at compile time, [`futures::join`] can await
18//! them all simultaneously.
19//! 2. [`futures::stream::FuturesUnordered`] can wait on a variable number of futures. It also
20//! supports adding them at runtime. Consider something like
21//! `FuturesUnordered<Pin<Box<dyn Future<Output = ()>>>` if you want a generic "container of any
22//! future".
23//! 3. Multiple applications are better suited to multiple `EventLoopRuntime`s, on separate
24//! `aos::EventLoop`s. Otherwise they can't send messages to each other, among other
25//! restrictions. https://github.com/frc971/971-Robot-Code/issues/12 covers creating an adapter
26//! that provides multiple `EventLoop`s on top of a single underlying implementation.
27//!
28//! ## Design
29//!
30//! The design of this is tricky. This is a complicated API interface between C++ and Rust. The big
31//! considerations in arriving at this design include:
32//! * `EventLoop` implementations alias the objects they're returning from C++, which means
33//! creating Rust unique references to them is unsound. See
34//! https://github.com/google/autocxx/issues/1146 for details.
35//! * For various reasons autocxx can't directly wrap APIs using types ergonomic for C++. This and
36//! the previous point mean we wrap all of the C++ objects specifically for this class.
Brian Silverman2ee175e2023-07-11 16:32:08 -070037//! * Rust's lifetimes are only flexible enough to track everything with a single big lifetime.
38//! All the callbacks can store references to things tied to the event loop's lifetime, but no
39//! other lifetimes.
Brian Silverman9809c5f2022-07-23 16:12:23 -070040//! * We can't use [`futures::stream::Stream`] and all of its nice [`futures::stream::StreamExt`]
41//! helpers for watchers because we need lifetime-generic `Item` types. Effectively we're making
42//! a lending stream. This is very close to lending iterators, which is one of the motivating
43//! examples for generic associated types (https://github.com/rust-lang/rust/issues/44265).
44
Brian Silverman1431a772022-08-31 20:44:36 -070045use std::{
46 fmt,
47 future::Future,
48 marker::PhantomData,
Brian Silverman2ee175e2023-07-11 16:32:08 -070049 mem::ManuallyDrop,
Adam Snaider34072e12023-10-03 10:04:25 -070050 ops::{Add, Deref, DerefMut},
Brian Silverman1431a772022-08-31 20:44:36 -070051 panic::{catch_unwind, AssertUnwindSafe},
52 pin::Pin,
53 slice,
54 task::Poll,
55 time::Duration,
56};
Brian Silverman9809c5f2022-07-23 16:12:23 -070057
58use autocxx::{
Austin Schuhdad7a812023-07-26 21:11:22 -070059 subclass::{subclass, CppSubclass},
Brian Silverman9809c5f2022-07-23 16:12:23 -070060 WithinBox,
61};
62use cxx::UniquePtr;
Adam Snaider34072e12023-10-03 10:04:25 -070063use flatbuffers::{
64 root_unchecked, Allocator, FlatBufferBuilder, Follow, FollowWith, FullyQualifiedName,
65};
Adam Snaider163800b2023-07-12 00:21:17 -040066use futures::{future::pending, future::FusedFuture, never::Never};
Brian Silverman9809c5f2022-07-23 16:12:23 -070067use thiserror::Error;
68use uuid::Uuid;
69
Brian Silverman90221f82022-08-22 23:46:09 -070070pub use aos_configuration::{Channel, Configuration, Node};
71use aos_configuration::{ChannelLookupError, ConfigurationExt};
72
Brian Silverman9809c5f2022-07-23 16:12:23 -070073pub use aos_uuid::UUID;
Brian Silverman2ee175e2023-07-11 16:32:08 -070074pub use ffi::aos::EventLoopRuntime as CppEventLoopRuntime;
Adam Snaider163800b2023-07-12 00:21:17 -040075pub use ffi::aos::ExitHandle as CppExitHandle;
Brian Silverman9809c5f2022-07-23 16:12:23 -070076
77autocxx::include_cpp! (
78#include "aos/events/event_loop_runtime.h"
79
80safety!(unsafe)
81
82generate_pod!("aos::Context")
83generate!("aos::WatcherForRust")
84generate!("aos::RawSender_Error")
85generate!("aos::SenderForRust")
86generate!("aos::FetcherForRust")
Brian Silverman76f48362022-08-24 21:09:08 -070087generate!("aos::OnRunForRust")
Brian Silverman9809c5f2022-07-23 16:12:23 -070088generate!("aos::EventLoopRuntime")
Adam Snaider163800b2023-07-12 00:21:17 -040089generate!("aos::ExitHandle")
Adam Snaidercc8c2f72023-06-25 20:56:13 -070090generate!("aos::TimerForRust")
Brian Silverman9809c5f2022-07-23 16:12:23 -070091
92subclass!("aos::ApplicationFuture", RustApplicationFuture)
93
94extern_cpp_type!("aos::Configuration", crate::Configuration)
95extern_cpp_type!("aos::Channel", crate::Channel)
96extern_cpp_type!("aos::Node", crate::Node)
97extern_cpp_type!("aos::UUID", crate::UUID)
98);
99
100pub type EventLoop = ffi::aos::EventLoop;
101
Brian Silverman2ee175e2023-07-11 16:32:08 -0700102/// A marker type which is invariant with respect to the given lifetime.
103///
104/// When interacting with functions that take and return things with a given lifetime, the lifetime
105/// becomes invariant. Because we don't store these functions as Rust types, we need a type like
106/// this to tell the Rust compiler that it can't substitute a shorter _or_ longer lifetime.
107pub type InvariantLifetime<'a> = PhantomData<fn(&'a ()) -> &'a ()>;
108
Brian Silverman9809c5f2022-07-23 16:12:23 -0700109/// # Safety
110///
111/// This should have a `'event_loop` lifetime and `future` should include that in its type, but
112/// autocxx's subclass doesn't support that. Even if it did, it wouldn't be enforced. C++ is
113/// enforcing the lifetime: it destroys this object along with the C++ `EventLoopRuntime`, which
114/// must be outlived by the EventLoop.
115#[doc(hidden)]
Austin Schuhdad7a812023-07-26 21:11:22 -0700116#[subclass]
Brian Silverman9809c5f2022-07-23 16:12:23 -0700117pub struct RustApplicationFuture {
118 /// This logically has a `'event_loop` bound, see the class comment for details.
119 future: Pin<Box<dyn Future<Output = Never>>>,
120}
121
122impl ffi::aos::ApplicationFuture_methods for RustApplicationFuture {
Brian Silverman1431a772022-08-31 20:44:36 -0700123 fn Poll(&mut self) -> bool {
124 catch_unwind(AssertUnwindSafe(|| {
125 // This is always allowed because it can never create a value of type `Ready<Never>` to
126 // return, so it must always return `Pending`. That also means the value it returns doesn't
127 // mean anything, so we ignore it.
128 let _ = Pin::new(&mut self.future)
129 .poll(&mut std::task::Context::from_waker(&panic_waker()));
130 }))
131 .is_ok()
Brian Silverman9809c5f2022-07-23 16:12:23 -0700132 }
133}
134
135impl RustApplicationFuture {
136 pub fn new<'event_loop>(
137 future: impl Future<Output = Never> + 'event_loop,
138 ) -> UniquePtr<ffi::aos::ApplicationFuture> {
139 /// # Safety
140 ///
141 /// This completely removes the `'event_loop` lifetime, the caller must ensure that is
142 /// sound.
143 unsafe fn remove_lifetime<'event_loop>(
144 future: Pin<Box<dyn Future<Output = Never> + 'event_loop>>,
145 ) -> Pin<Box<dyn Future<Output = Never>>> {
146 // SAFETY: Caller is responsible.
147 unsafe { std::mem::transmute(future) }
148 }
149
150 Self::as_ApplicationFuture_unique_ptr(Self::new_cpp_owned(Self {
151 // SAFETY: C++ manages observing the lifetime, see [`RustApplicationFuture`] for
152 // details.
153 future: unsafe { remove_lifetime(Box::pin(future)) },
154 cpp_peer: Default::default(),
155 }))
156 }
157}
158
Brian Silverman2ee175e2023-07-11 16:32:08 -0700159/// An abstraction for objects which hold an `aos::EventLoop` from Rust code.
160///
161/// If you have an `aos::EventLoop` provided from C++ code, don't use this, just call
162/// [`EventLoopRuntime.new`] directly.
163///
164/// # Safety
165///
166/// Objects implementing this trait *must* have mostly-exclusive (except for running it) ownership
167/// of the `aos::EventLoop` *for its entire lifetime*, which *must* be dropped when this object is.
168/// See [`EventLoopRuntime.new`]'s safety requirements for why this can be important and details of
169/// mostly-exclusive. In other words, nothing else may mutate it in any way except processing events
170/// (including dropping, because this object has to be the one to drop it).
171///
172/// This also implies semantics similar to `Pin<&mut ffi::aos::EventLoop>` for the underlying object.
173/// Implementations of this trait must have exclusive ownership of it, and the underlying object
174/// must not be moved.
175pub unsafe trait EventLoopHolder {
176 /// Converts this holder into a raw C++ pointer. This may be fed through other Rust and C++
177 /// code, and eventually passed back to [`from_raw`].
178 fn into_raw(self) -> *mut ffi::aos::EventLoop;
179
180 /// Converts a raw C++ pointer back to a holder object.
181 ///
182 /// # Safety
183 ///
184 /// `raw` must be the result of [`into_raw`] on an instance of this same type. These raw
185 /// pointers *are not* interchangeable between implementations of this trait.
186 unsafe fn from_raw(raw: *mut ffi::aos::EventLoop) -> Self;
187}
188
189/// Owns an [`EventLoopRuntime`] and its underlying `aos::EventLoop`, with safe management of the
190/// associated Rust lifetimes.
191pub struct EventLoopRuntimeHolder<T: EventLoopHolder>(
192 ManuallyDrop<Pin<Box<CppEventLoopRuntime>>>,
193 PhantomData<T>,
194);
195
196impl<T: EventLoopHolder> EventLoopRuntimeHolder<T> {
197 /// Creates a new [`EventLoopRuntime`] and runs an initialization function on it. This is a
198 /// safe wrapper around [`EventLoopRuntime.new`] (although see [`EventLoopHolder`]'s safety
199 /// requirements, part of them are just delegated there).
200 ///
201 /// If you have an `aos::EventLoop` provided from C++ code, don't use this, just call
202 /// [`EventLoopRuntime.new`] directly.
203 ///
204 /// All setup of the runtime must be performed with `fun`, which is called before this function
205 /// returns. `fun` may create further objects to use in async functions via [`EventLoop.spawn`]
206 /// etc, but it is the only place to set things up before the EventLoop is run.
207 ///
208 /// `fun` cannot capture things outside of the event loop, because the event loop might outlive
209 /// them:
210 /// ```compile_fail
211 /// # use aos_events_event_loop_runtime::*;
212 /// # fn bad(event_loop: impl EventLoopHolder) {
213 /// let mut x = 0;
214 /// EventLoopRuntimeHolder::new(event_loop, |runtime| {
215 /// runtime.spawn(async {
216 /// x = 1;
217 /// loop {}
218 /// });
219 /// });
220 /// # }
221 /// ```
222 ///
223 /// But it can capture `'event_loop` references:
224 /// ```
225 /// # use aos_events_event_loop_runtime::*;
226 /// # use aos_configuration::ChannelExt;
227 /// # fn good(event_loop: impl EventLoopHolder) {
228 /// EventLoopRuntimeHolder::new(event_loop, |runtime| {
229 /// let channel = runtime.get_raw_channel("/test", "aos.examples.Ping").unwrap();
230 /// runtime.spawn(async {
231 /// loop {
232 /// eprintln!("{:?}", channel.type_());
233 /// }
234 /// });
235 /// });
236 /// # }
237 /// ```
238 pub fn new<F>(event_loop: T, fun: F) -> Self
239 where
240 F: for<'event_loop> FnOnce(&mut EventLoopRuntime<'event_loop>),
241 {
242 // SAFETY: The EventLoopRuntime never escapes this function, which means the only code that
243 // observes its lifetime is `fun`. `fun` must be generic across any value of its
244 // `'event_loop` lifetime parameter, which means we can choose any lifetime here, which
245 // satisfies the safety requirements.
246 //
247 // This is a similar pattern as `std::thread::scope`, `ghost-cell`, etc. Note that unlike
248 // `std::thread::scope`, our inner functions (the async ones) are definitely not allowed to
249 // capture things from the calling scope of this function, so there's no `'env` equivalent.
250 // `ghost-cell` ends up looking very similar despite doing different things with the
251 // pattern, while `std::thread::scope` has a lot of additional complexity to achieve a
252 // similar result.
253 //
254 // `EventLoopHolder`s safety requirements prevent anybody else from touching the underlying
255 // `aos::EventLoop`.
256 let mut runtime = unsafe { EventLoopRuntime::new(event_loop.into_raw()) };
257 fun(&mut runtime);
258 Self(ManuallyDrop::new(runtime.into_cpp()), PhantomData)
259 }
260}
261
262impl<T: EventLoopHolder> Drop for EventLoopRuntimeHolder<T> {
263 fn drop(&mut self) {
Adam Snaider48a54682023-09-28 21:50:42 -0700264 let event_loop = self.0.event_loop();
Brian Silverman2ee175e2023-07-11 16:32:08 -0700265 // SAFETY: We're not going to touch this field again. The underlying EventLoop will not be
266 // run again because we're going to drop it next.
267 unsafe { ManuallyDrop::drop(&mut self.0) };
268 // SAFETY: We took this from `into_raw`, and we just dropped the runtime which may contain
269 // Rust references to it.
270 unsafe { drop(T::from_raw(event_loop)) };
271 }
272}
273
Brian Silverman9809c5f2022-07-23 16:12:23 -0700274pub struct EventLoopRuntime<'event_loop>(
275 Pin<Box<ffi::aos::EventLoopRuntime>>,
Brian Silverman2ee175e2023-07-11 16:32:08 -0700276 // See documentation of [`new`] for details.
277 InvariantLifetime<'event_loop>,
Brian Silverman9809c5f2022-07-23 16:12:23 -0700278);
279
280/// Manages the Rust interface to a *single* `aos::EventLoop`. This is intended to be used by a
281/// single application.
282impl<'event_loop> EventLoopRuntime<'event_loop> {
Brian Silverman2ee175e2023-07-11 16:32:08 -0700283 /// Creates a new runtime. This must be the only user of the underlying `aos::EventLoop`.
284 ///
285 /// Consider using [`EventLoopRuntimeHolder.new`] instead, if you're working with an
286 /// `aos::EventLoop` owned (indirectly) by Rust code.
287 ///
288 /// One common pattern is calling this in the constructor of an object whose lifetime is managed
289 /// by C++; C++ doesn't inherit the Rust lifetime but we do have a lot of C++ code that obeys
290 /// these rules implicitly.
Brian Silverman9809c5f2022-07-23 16:12:23 -0700291 ///
292 /// Call [`spawn`] to respond to events. The non-event-driven APIs may be used without calling
293 /// this.
294 ///
295 /// This is an async runtime, but it's a somewhat unusual one. See the module-level
296 /// documentation for details.
297 ///
298 /// # Safety
299 ///
Brian Silverman2ee175e2023-07-11 16:32:08 -0700300 /// This function is where all the tricky lifetime guarantees to ensure soundness come
301 /// together. It all boils down to choosing `'event_loop` correctly, which is very complicated.
302 /// Here are the rules:
Brian Silverman9809c5f2022-07-23 16:12:23 -0700303 ///
Brian Silverman2ee175e2023-07-11 16:32:08 -0700304 /// 1. The `aos::EventLoop` APIs, and any other consumer-facing APIs, of the underlying
305 /// `aos::EventLoop` *must* be exclusively used by this object, and things it calls, for
306 /// `'event_loop`.
307 /// 2. `'event_loop` extends until after the last time the underlying `aos::EventLoop` is run.
308 /// This is often beyond the lifetime of this Rust `EventLoopRuntime` object.
309 /// 3. `'event_loop` must outlive this object, because this object stores references to the
310 /// underlying `aos::EventLoop`.
311 /// 4. Any other references stored in the underlying `aos::EventLoop` must be valid for
312 /// `'event_loop`. The easiest way to ensure this is by not using the `aos::EventLoop` before
313 /// passing it to this object.
Brian Silverman9809c5f2022-07-23 16:12:23 -0700314 ///
Brian Silverman2ee175e2023-07-11 16:32:08 -0700315 /// Here are some corollaries:
316 ///
317 /// 1. The underlying `aos::EventLoop` must be dropped after this object.
318 /// 2. This object will store various references valid for `'event_loop` with a duration of
319 /// `'event_loop`, which is safe as long as they're both the same `'event_loop`. Note that
320 /// this requires this type to be invariant with respect to `'event_loop`.
321 /// 3. `event_loop` (the pointer being passed in) is effectively `Pin`, which is also implied
322 /// by the underlying `aos::EventLoop` C++ type.
323 /// 4. You cannot create multiple `EventLoopRuntime`s from the same underlying `aos::EventLoop`
324 /// or otherwise use it from a different application. The first one may create
325 /// mutable Rust references while the second one expects exclusive ownership, for example.
326 ///
327 /// `aos::EventLoop`'s public API is exclusively for consumers of the event loop. Some
328 /// subclasses extend this API. Additionally, all useful implementations of `aos::EventLoop`
329 /// must have some way to process events. Sometimes this is additional API surface (such as
330 /// `aos::ShmEventLoop`), in other cases comes via other objects holding references to the
331 /// `aos::EventLoop` (such as `aos::SimulatedEventLoopFactory`). This access to run the event
332 /// loop functions independently of the consuming functions in every way except lifetime of the
333 /// `aos::EventLoop`, and may be used independently of `'event_loop`.
334 ///
335 /// ## Discussion of the rules
336 ///
337 /// Rule 1 is similar to rule 3 (they're both similar to mutable borrowing), but rule 1 extends
338 /// for the entire lifetime of the object instead of being limited to the lifetime of an
339 /// individual borrow by an instance of this type. This is similar to the way [`Pin`]'s
340 /// estrictions extend for the entire lifetime of the object, until it is dropped.
341 ///
342 /// Rule 2 and corollaries 2 and 3 go together, and are essential for making [`spawn`]ed tasks
343 /// useful. The `aos::EventLoop` is full of indirect circular references, both within itself
344 /// and via all of the callbacks. This is sound if all of these references have the *exact
345 /// same* Rust lifetime, which is `'event_loop`.
346 ///
347 /// ## Alternatives and why they don't work
348 ///
349 /// Making the argument `Pin<&'event_loop mut EventLoop>` would express some (but not all) of
350 /// these restrictions within the Rust type system. However, having an actual Rust mutable
351 /// reference like that prevents anything else from creating one via other pointers to the
352 /// same object from C++, which is a common operation. See the module-level documentation for
353 /// details.
354 ///
355 /// [`spawn`]ed tasks need to hold `&'event_loop` references to things like channels. Using a
356 /// separate `'config` lifetime wouldn't change much; the tasks still need to do things which
357 /// require them to not outlive something they don't control. This is fundamental to
358 /// self-referential objects, which `aos::EventLoop` is based around, but Rust requires unsafe
359 /// code to manage manually.
360 ///
361 /// ## Final cautions
362 ///
363 /// Following these rules is very tricky. Be very cautious calling this function. It exposes an
364 /// unbound lifetime, which means you should wrap it directly in a function that attaches a
365 /// correct lifetime.
Brian Silverman9809c5f2022-07-23 16:12:23 -0700366 pub unsafe fn new(event_loop: *mut ffi::aos::EventLoop) -> Self {
367 Self(
368 // SAFETY: We push all the validity requirements for this up to our caller.
369 unsafe { ffi::aos::EventLoopRuntime::new(event_loop) }.within_box(),
Brian Silverman2ee175e2023-07-11 16:32:08 -0700370 InvariantLifetime::default(),
Brian Silverman9809c5f2022-07-23 16:12:23 -0700371 )
372 }
373
Brian Silverman2ee175e2023-07-11 16:32:08 -0700374 /// Creates a Rust wrapper from the underlying C++ object, with an unbound lifetime.
375 ///
376 /// This may never be useful, but it's here for this big scary comment to explain why it's not
377 /// useful.
378 ///
379 /// # Safety
380 ///
381 /// See [`new`] for safety restrictions on `'event_loop` when calling this. In particular, see
382 /// the note about how tricky doing this correctly is, and remember that for this function the
383 /// event loop in question isn't even an argument to this function so it's even trickier. Also
384 /// note that you cannot call this on the result of [`into_cpp`] without violating those
385 /// restrictions.
386 pub unsafe fn from_cpp(cpp: Pin<Box<ffi::aos::EventLoopRuntime>>) -> Self {
387 Self(cpp, InvariantLifetime::default())
388 }
389
390 /// Extracts the underlying C++ object, without the corresponding Rust lifetime. This is useful
391 /// to stop the propagation of Rust lifetimes without destroying the underlying object which
392 /// contains all the state.
393 ///
394 /// Note that you *cannot* call [`from_cpp`] on the result of this, because that will violate
395 /// [`from_cpp`]'s safety requirements.
396 pub fn into_cpp(self) -> Pin<Box<ffi::aos::EventLoopRuntime>> {
397 self.0
398 }
399
Brian Silverman9809c5f2022-07-23 16:12:23 -0700400 /// Returns the pointer passed into the constructor.
401 ///
402 /// The returned value should only be used for destroying it (_after_ `self` is dropped) or
403 /// calling other C++ APIs.
Adam Snaider48a54682023-09-28 21:50:42 -0700404 pub fn raw_event_loop(&self) -> *mut ffi::aos::EventLoop {
405 self.0.event_loop()
Brian Silverman9809c5f2022-07-23 16:12:23 -0700406 }
407
Brian Silverman90221f82022-08-22 23:46:09 -0700408 /// Returns a reference to the name of this EventLoop.
409 ///
410 /// TODO(Brian): Come up with a nice way to expose this safely, without memory allocations, for
411 /// logging etc.
412 ///
413 /// # Safety
414 ///
415 /// The result must not be used after C++ could change it. Unfortunately C++ can change this
416 /// name from most places, so you should be really careful what you do with the result.
417 pub unsafe fn raw_name(&self) -> &str {
418 self.0.name()
419 }
Brian Silverman9809c5f2022-07-23 16:12:23 -0700420
421 pub fn get_raw_channel(
422 &self,
423 name: &str,
424 typename: &str,
Brian Silverman9809c5f2022-07-23 16:12:23 -0700425 ) -> Result<&'event_loop Channel, ChannelLookupError> {
Brian Silverman90221f82022-08-22 23:46:09 -0700426 self.configuration().get_channel(
427 name,
428 typename,
429 // SAFETY: We're not calling any EventLoop methods while C++ is using this for the
430 // channel lookup.
431 unsafe { self.raw_name() },
432 self.node(),
433 )
Brian Silverman9809c5f2022-07-23 16:12:23 -0700434 }
435
Brian Silverman90221f82022-08-22 23:46:09 -0700436 pub fn get_channel<T: FullyQualifiedName>(
437 &self,
438 name: &str,
439 ) -> Result<&'event_loop Channel, ChannelLookupError> {
440 self.get_raw_channel(name, T::get_fully_qualified_name())
441 }
Brian Silverman9809c5f2022-07-23 16:12:23 -0700442
443 /// Starts running the given `task`, which may not return (as specified by its type). If you
444 /// want your task to stop, return the result of awaiting [`futures::future::pending`], which
445 /// will never complete. `task` will not be polled after the underlying `aos::EventLoop` exits.
446 ///
Brian Silverman76f48362022-08-24 21:09:08 -0700447 /// Note that task will be polled immediately, to give it a chance to initialize. If you want to
448 /// defer work until the event loop starts running, await [`on_run`] in the task.
Brian Silverman9809c5f2022-07-23 16:12:23 -0700449 ///
450 /// # Panics
451 ///
452 /// Panics if called more than once. See the module-level documentation for alternatives if you
453 /// want to do this.
454 ///
455 /// # Examples with interesting return types
456 ///
457 /// These are all valid futures which never return:
458 /// ```
459 /// # fn compile_check(mut runtime: aos_events_event_loop_runtime::EventLoopRuntime) {
460 /// # use futures::{never::Never, future::pending};
461 /// async fn pending_wrapper() -> Never {
462 /// pending().await
463 /// }
464 /// async fn loop_forever() -> Never {
465 /// loop {}
466 /// }
467 ///
468 /// runtime.spawn(pending());
469 /// runtime.spawn(async { pending().await });
470 /// runtime.spawn(pending_wrapper());
471 /// runtime.spawn(async { loop {} });
472 /// runtime.spawn(loop_forever());
473 /// runtime.spawn(async { println!("all done"); pending().await });
474 /// # }
475 /// ```
476 /// but this is not:
477 /// ```compile_fail
478 /// # fn compile_check(mut runtime: aos_events_event_loop_runtime::EventLoopRuntime) {
479 /// # use futures::ready;
480 /// runtime.spawn(ready());
481 /// # }
482 /// ```
483 /// and neither is this:
484 /// ```compile_fail
485 /// # fn compile_check(mut runtime: aos_events_event_loop_runtime::EventLoopRuntime) {
486 /// # use futures::ready;
487 /// runtime.spawn(async { println!("all done") });
488 /// # }
489 /// ```
490 ///
491 /// # Examples with capturing
492 ///
493 /// The future can capture things. This is important to access other objects created from the
494 /// runtime, either before calling this function:
495 /// ```
496 /// # fn compile_check<'event_loop>(
497 /// # mut runtime: aos_events_event_loop_runtime::EventLoopRuntime<'event_loop>,
498 /// # channel1: &'event_loop aos_events_event_loop_runtime::Channel,
499 /// # channel2: &'event_loop aos_events_event_loop_runtime::Channel,
500 /// # ) {
501 /// let mut watcher1 = runtime.make_raw_watcher(channel1);
502 /// let mut watcher2 = runtime.make_raw_watcher(channel2);
503 /// runtime.spawn(async move { loop {
504 /// watcher1.next().await;
505 /// watcher2.next().await;
506 /// }});
507 /// # }
508 /// ```
509 /// or after:
510 /// ```
511 /// # fn compile_check<'event_loop>(
512 /// # mut runtime: aos_events_event_loop_runtime::EventLoopRuntime<'event_loop>,
513 /// # channel1: &'event_loop aos_events_event_loop_runtime::Channel,
514 /// # channel2: &'event_loop aos_events_event_loop_runtime::Channel,
515 /// # ) {
516 /// # use std::{cell::RefCell, rc::Rc};
517 /// let runtime = Rc::new(RefCell::new(runtime));
518 /// runtime.borrow_mut().spawn({
519 /// let mut runtime = runtime.clone();
520 /// async move {
521 /// let mut runtime = runtime.borrow_mut();
522 /// let mut watcher1 = runtime.make_raw_watcher(channel1);
523 /// let mut watcher2 = runtime.make_raw_watcher(channel2);
524 /// loop {
525 /// watcher1.next().await;
526 /// watcher2.next().await;
527 /// }
528 /// }
529 /// });
530 /// # }
531 /// ```
532 /// or both:
533 /// ```
534 /// # fn compile_check<'event_loop>(
535 /// # mut runtime: aos_events_event_loop_runtime::EventLoopRuntime<'event_loop>,
536 /// # channel1: &'event_loop aos_events_event_loop_runtime::Channel,
537 /// # channel2: &'event_loop aos_events_event_loop_runtime::Channel,
538 /// # ) {
539 /// # use std::{cell::RefCell, rc::Rc};
540 /// let mut watcher1 = runtime.make_raw_watcher(channel1);
541 /// let runtime = Rc::new(RefCell::new(runtime));
542 /// runtime.borrow_mut().spawn({
543 /// let mut runtime = runtime.clone();
544 /// async move {
545 /// let mut runtime = runtime.borrow_mut();
546 /// let mut watcher2 = runtime.make_raw_watcher(channel2);
547 /// loop {
548 /// watcher1.next().await;
549 /// watcher2.next().await;
550 /// }
551 /// }
552 /// });
553 /// # }
554 /// ```
555 ///
556 /// But you cannot capture local variables:
557 /// ```compile_fail
558 /// # fn compile_check<'event_loop>(
559 /// # mut runtime: aos_events_event_loop_runtime::EventLoopRuntime<'event_loop>,
560 /// # ) {
561 /// let mut local: i32 = 971;
562 /// let local = &mut local;
563 /// runtime.spawn(async move { loop {
564 /// println!("have: {}", local);
565 /// }});
566 /// # }
567 /// ```
Adam Snaider48a54682023-09-28 21:50:42 -0700568 pub fn spawn(&self, task: impl Future<Output = Never> + 'event_loop) {
569 self.0.Spawn(RustApplicationFuture::new(task));
Brian Silverman9809c5f2022-07-23 16:12:23 -0700570 }
571
572 pub fn configuration(&self) -> &'event_loop Configuration {
573 // SAFETY: It's always a pointer valid for longer than the underlying EventLoop.
574 unsafe { &*self.0.configuration() }
575 }
576
577 pub fn node(&self) -> Option<&'event_loop Node> {
578 // SAFETY: It's always a pointer valid for longer than the underlying EventLoop, or null.
579 unsafe { self.0.node().as_ref() }
580 }
581
582 pub fn monotonic_now(&self) -> MonotonicInstant {
583 MonotonicInstant(self.0.monotonic_now())
584 }
585
Ryan Yin683a8672022-11-09 20:44:20 -0800586 pub fn realtime_now(&self) -> RealtimeInstant {
587 RealtimeInstant(self.0.realtime_now())
588 }
Brian Silverman9809c5f2022-07-23 16:12:23 -0700589 /// Note that the `'event_loop` input lifetime is intentional. The C++ API requires that it is
590 /// part of `self.configuration()`, which will always have this lifetime.
591 ///
592 /// # Panics
593 ///
594 /// Dropping `self` before the returned object is dropped will panic.
Adam Snaider48a54682023-09-28 21:50:42 -0700595 pub fn make_raw_watcher(&self, channel: &'event_loop Channel) -> RawWatcher {
Brian Silverman9809c5f2022-07-23 16:12:23 -0700596 // SAFETY: `channel` is valid for the necessary lifetime, all other requirements fall under
597 // the usual autocxx heuristics.
Adam Snaider48a54682023-09-28 21:50:42 -0700598 RawWatcher(unsafe { self.0.MakeWatcher(channel) }.within_box())
Brian Silverman9809c5f2022-07-23 16:12:23 -0700599 }
600
Brian Silverman90221f82022-08-22 23:46:09 -0700601 /// Provides type-safe async blocking access to messages on a channel. `T` should be a
602 /// generated flatbuffers table type, the lifetime parameter does not matter, using `'static`
603 /// is easiest.
604 ///
605 /// # Panics
606 ///
607 /// Dropping `self` before the returned object is dropped will panic.
Adam Snaider48a54682023-09-28 21:50:42 -0700608 pub fn make_watcher<T>(&self, channel_name: &str) -> Result<Watcher<T>, ChannelLookupError>
Brian Silverman90221f82022-08-22 23:46:09 -0700609 where
610 for<'a> T: FollowWith<'a>,
611 for<'a> <T as FollowWith<'a>>::Inner: Follow<'a>,
612 T: FullyQualifiedName,
613 {
614 let channel = self.get_channel::<T>(channel_name)?;
615 Ok(Watcher(self.make_raw_watcher(channel), PhantomData))
616 }
617
Brian Silverman9809c5f2022-07-23 16:12:23 -0700618 /// Note that the `'event_loop` input lifetime is intentional. The C++ API requires that it is
619 /// part of `self.configuration()`, which will always have this lifetime.
620 ///
621 /// # Panics
622 ///
623 /// Dropping `self` before the returned object is dropped will panic.
Adam Snaider48a54682023-09-28 21:50:42 -0700624 pub fn make_raw_sender(&self, channel: &'event_loop Channel) -> RawSender {
Brian Silverman9809c5f2022-07-23 16:12:23 -0700625 // SAFETY: `channel` is valid for the necessary lifetime, all other requirements fall under
626 // the usual autocxx heuristics.
Adam Snaider48a54682023-09-28 21:50:42 -0700627 RawSender(unsafe { self.0.MakeSender(channel) }.within_box())
Brian Silverman9809c5f2022-07-23 16:12:23 -0700628 }
629
Brian Silverman90221f82022-08-22 23:46:09 -0700630 /// Allows sending messages on a channel with a type-safe API.
631 ///
632 /// # Panics
633 ///
634 /// Dropping `self` before the returned object is dropped will panic.
Adam Snaider48a54682023-09-28 21:50:42 -0700635 pub fn make_sender<T>(&self, channel_name: &str) -> Result<Sender<T>, ChannelLookupError>
Brian Silverman90221f82022-08-22 23:46:09 -0700636 where
637 for<'a> T: FollowWith<'a>,
638 for<'a> <T as FollowWith<'a>>::Inner: Follow<'a>,
639 T: FullyQualifiedName,
640 {
641 let channel = self.get_channel::<T>(channel_name)?;
642 Ok(Sender(self.make_raw_sender(channel), PhantomData))
643 }
644
Brian Silverman9809c5f2022-07-23 16:12:23 -0700645 /// Note that the `'event_loop` input lifetime is intentional. The C++ API requires that it is
646 /// part of `self.configuration()`, which will always have this lifetime.
647 ///
648 /// # Panics
649 ///
650 /// Dropping `self` before the returned object is dropped will panic.
Adam Snaider48a54682023-09-28 21:50:42 -0700651 pub fn make_raw_fetcher(&self, channel: &'event_loop Channel) -> RawFetcher {
Brian Silverman9809c5f2022-07-23 16:12:23 -0700652 // SAFETY: `channel` is valid for the necessary lifetime, all other requirements fall under
653 // the usual autocxx heuristics.
Adam Snaider48a54682023-09-28 21:50:42 -0700654 RawFetcher(unsafe { self.0.MakeFetcher(channel) }.within_box())
Brian Silverman9809c5f2022-07-23 16:12:23 -0700655 }
656
Brian Silverman90221f82022-08-22 23:46:09 -0700657 /// Provides type-safe access to messages on a channel, without the ability to wait for a new
658 /// one. This provides APIs to get the latest message, and to follow along and retrieve each
659 /// message in order.
660 ///
661 /// # Panics
662 ///
663 /// Dropping `self` before the returned object is dropped will panic.
Adam Snaider48a54682023-09-28 21:50:42 -0700664 pub fn make_fetcher<T>(&self, channel_name: &str) -> Result<Fetcher<T>, ChannelLookupError>
Brian Silverman90221f82022-08-22 23:46:09 -0700665 where
666 for<'a> T: FollowWith<'a>,
667 for<'a> <T as FollowWith<'a>>::Inner: Follow<'a>,
668 T: FullyQualifiedName,
669 {
670 let channel = self.get_channel::<T>(channel_name)?;
671 Ok(Fetcher(self.make_raw_fetcher(channel), PhantomData))
672 }
673
Brian Silverman9809c5f2022-07-23 16:12:23 -0700674 // TODO(Brian): Expose timers and phased loops. Should we have `sleep`-style methods for those,
675 // instead of / in addition to mirroring C++ with separate setup and wait?
676
Brian Silverman76f48362022-08-24 21:09:08 -0700677 /// Returns a Future to wait until the underlying EventLoop is running. Once this resolves, all
678 /// subsequent code will have any realtime scheduling applied. This means it can rely on
679 /// consistent timing, but it can no longer create any EventLoop child objects or do anything
680 /// else non-realtime.
Adam Snaider48a54682023-09-28 21:50:42 -0700681 pub fn on_run(&self) -> OnRun {
682 OnRun(self.0.MakeOnRun().within_box())
Brian Silverman76f48362022-08-24 21:09:08 -0700683 }
684
685 pub fn is_running(&self) -> bool {
686 self.0.is_running()
687 }
Adam Snaidercc8c2f72023-06-25 20:56:13 -0700688
689 /// Returns an unarmed timer.
Adam Snaider48a54682023-09-28 21:50:42 -0700690 pub fn add_timer(&self) -> Timer {
691 Timer(self.0.AddTimer())
Adam Snaidercc8c2f72023-06-25 20:56:13 -0700692 }
693
694 /// Returns a timer that goes off every `duration`-long ticks.
Adam Snaider48a54682023-09-28 21:50:42 -0700695 pub fn add_interval(&self, duration: Duration) -> Timer {
Adam Snaidercc8c2f72023-06-25 20:56:13 -0700696 let mut timer = self.add_timer();
697 timer.setup(self.monotonic_now(), Some(duration));
698 timer
699 }
Adam Snaidercf0dac72023-10-02 14:41:58 -0700700
701 /// Sets the scheduler priority to run the event loop at.
702 pub fn set_realtime_priority(&self, priority: i32) {
703 self.0.SetRuntimeRealtimePriority(priority.into());
704 }
Adam Snaidercc8c2f72023-06-25 20:56:13 -0700705}
706
707/// An event loop primitive that allows sleeping asynchronously.
708///
709/// # Examples
710///
711/// ```no_run
712/// # use aos_events_event_loop_runtime::EventLoopRuntime;
713/// # use std::time::Duration;
714/// # fn compile_check(runtime: &mut EventLoopRuntime<'_>) {
715/// # let mut timer = runtime.add_timer();
716/// // Goes as soon as awaited.
717/// timer.setup(runtime.monotonic_now(), None);
718/// // Goes off once in 2 seconds.
719/// timer.setup(runtime.monotonic_now() + Duration::from_secs(2), None);
720/// // Goes off as soon as awaited and every 2 seconds afterwards.
721/// timer.setup(runtime.monotonic_now(), Some(Duration::from_secs(1)));
722/// async {
723/// for i in 0..10 {
724/// timer.tick().await;
725/// }
726/// // Timer won't off anymore. Next `tick` will never return.
727/// timer.disable();
728/// timer.tick().await;
729/// };
730/// # }
731/// ```
732pub struct Timer(UniquePtr<ffi::aos::TimerForRust>);
733
734/// A "tick" for a [`Timer`].
735///
736/// This is the raw future generated by the [`Timer::tick`] function.
737pub struct TimerTick<'a>(&'a mut Timer);
738
739impl Timer {
740 /// Arms the timer.
741 ///
742 /// The timer should sleep until `base`, `base + repeat`, `base + repeat * 2`, ...
743 /// If `repeat` is `None`, then the timer only expires once at `base`.
744 pub fn setup(&mut self, base: MonotonicInstant, repeat: Option<Duration>) {
745 self.0.pin_mut().Schedule(
746 base.0,
747 repeat
748 .unwrap_or(Duration::from_nanos(0))
749 .as_nanos()
750 .try_into()
751 .expect("Out of range: Internal clock uses 64 bits"),
752 );
753 }
754
755 /// Disarms the timer.
756 ///
757 /// Can be re-enabled by calling `setup` again.
758 pub fn disable(&mut self) {
759 self.0.pin_mut().Disable();
760 }
761
762 /// Returns `true` if the timer is enabled.
763 pub fn is_enabled(&self) -> bool {
764 !self.0.IsDisabled()
765 }
766
767 /// Sets the name of the timer.
768 ///
769 /// This can be useful to get a descriptive name in the timing reports.
770 pub fn set_name(&mut self, name: &str) {
771 self.0.pin_mut().set_name(name);
772 }
773
774 /// Gets the name of the timer.
775 pub fn name(&self) -> &str {
776 self.0.name()
777 }
778
779 /// Returns a tick which can be `.await`ed.
780 ///
781 /// This tick will resolve on the next timer expired.
782 pub fn tick(&mut self) -> TimerTick {
783 TimerTick(self)
784 }
785
786 /// Polls the timer, returning `[Poll::Ready]` only once the timer expired.
787 fn poll(&mut self) -> Poll<()> {
788 if self.0.pin_mut().Poll() {
789 Poll::Ready(())
790 } else {
791 Poll::Pending
792 }
793 }
794}
795
796impl Future for TimerTick<'_> {
797 type Output = ();
798
799 fn poll(mut self: Pin<&mut Self>, _: &mut std::task::Context) -> Poll<()> {
800 self.0.poll()
801 }
Brian Silverman9809c5f2022-07-23 16:12:23 -0700802}
803
Brian Silverman9809c5f2022-07-23 16:12:23 -0700804/// Provides async blocking access to messages on a channel. This will return every message on the
805/// channel, in order.
806///
807/// Use [`EventLoopRuntime::make_raw_watcher`] to create one of these.
808///
809/// This is the non-typed API, which is mainly useful for reflection and does not provide safe APIs
810/// for actually interpreting messages. You probably want a [`Watcher`] instead.
811///
812/// This is the same concept as [`futures::stream::Stream`], but can't follow that API for technical
813/// reasons.
814///
815/// # Design
816///
817/// We can't use [`futures::stream::Stream`] because our `Item` type is `Context<'_>`, which means
818/// it's different for each `self` lifetime so we can't write a single type alias for it. We could
819/// write an intermediate type with a generic lifetime that implements `Stream` and is returned
820/// from a `make_stream` method, but that's what `Stream` is doing in the first place so adding
821/// another level doesn't help anything.
822///
823/// We also drop the extraneous `cx` argument that isn't used by this implementation anyways.
824///
825/// We also run into some limitations in the borrow checker trying to implement `poll`, I think it's
826/// the same one mentioned here:
827/// https://blog.rust-lang.org/2022/08/05/nll-by-default.html#looking-forward-what-can-we-expect-for-the-borrow-checker-of-the-future
828/// We get around that one by moving the unbounded lifetime from the pointer dereference into the
829/// function with the if statement.
Brian Silverman90221f82022-08-22 23:46:09 -0700830// SAFETY: If this outlives the parent EventLoop, the C++ code will LOG(FATAL).
831#[repr(transparent)]
832pub struct RawWatcher(Pin<Box<ffi::aos::WatcherForRust>>);
833
Brian Silverman9809c5f2022-07-23 16:12:23 -0700834impl RawWatcher {
835 /// Returns a Future to await the next value. This can be canceled (ie dropped) at will,
836 /// without skipping any messages.
837 ///
838 /// Remember not to call `poll` after it returns `Poll::Ready`, just like any other future. You
839 /// will need to call this function again to get the succeeding message.
840 ///
841 /// # Examples
842 ///
843 /// The common use case is immediately awaiting the next message:
844 /// ```
845 /// # async fn await_message(mut watcher: aos_events_event_loop_runtime::RawWatcher) {
846 /// println!("received: {:?}", watcher.next().await);
847 /// # }
848 /// ```
849 ///
850 /// You can also await the first message from any of a set of channels:
851 /// ```
852 /// # async fn select(
853 /// # mut watcher1: aos_events_event_loop_runtime::RawWatcher,
854 /// # mut watcher2: aos_events_event_loop_runtime::RawWatcher,
855 /// # ) {
856 /// futures::select! {
857 /// message1 = watcher1.next() => println!("channel 1: {:?}", message1),
858 /// message2 = watcher2.next() => println!("channel 2: {:?}", message2),
859 /// }
860 /// # }
861 /// ```
862 ///
863 /// Note that due to the returned object borrowing the `self` reference, the borrow checker will
864 /// enforce only having a single of these returned objects at a time. Drop the previous message
865 /// before asking for the next one. That means this will not compile:
866 /// ```compile_fail
867 /// # async fn compile_check(mut watcher: aos_events_event_loop_runtime::RawWatcher) {
868 /// let first = watcher.next();
869 /// let second = watcher.next();
870 /// first.await;
871 /// # }
872 /// ```
873 /// and nor will this:
874 /// ```compile_fail
875 /// # async fn compile_check(mut watcher: aos_events_event_loop_runtime::RawWatcher) {
876 /// let first = watcher.next().await;
877 /// watcher.next();
878 /// println!("still have: {:?}", first);
879 /// # }
880 /// ```
881 /// but this is fine:
882 /// ```
883 /// # async fn compile_check(mut watcher: aos_events_event_loop_runtime::RawWatcher) {
884 /// let first = watcher.next().await;
885 /// println!("have: {:?}", first);
886 /// watcher.next();
887 /// # }
888 /// ```
889 pub fn next(&mut self) -> RawWatcherNext {
890 RawWatcherNext(Some(self))
891 }
892}
893
894/// The type returned from [`RawWatcher::next`], see there for details.
895pub struct RawWatcherNext<'a>(Option<&'a mut RawWatcher>);
896
897impl<'a> Future for RawWatcherNext<'a> {
898 type Output = Context<'a>;
899 fn poll(mut self: Pin<&mut Self>, _: &mut std::task::Context) -> Poll<Context<'a>> {
900 let inner = self
901 .0
902 .take()
903 .expect("May not call poll after it returns Ready");
904 let maybe_context = inner.0.as_mut().PollNext();
905 if maybe_context.is_null() {
906 // We're not returning a reference into it, so we can safely replace the reference to
907 // use again in the future.
908 self.0.replace(inner);
909 Poll::Pending
910 } else {
911 // SAFETY: We just checked if it's null. If not, it will be a valid pointer. It will
912 // remain a valid pointer for the borrow of the underlying `RawWatcher` (ie `'a`)
913 // because we're dropping `inner` (which is that reference), so it will need to be
914 // borrowed again which cannot happen before the end of `'a`.
915 Poll::Ready(Context(unsafe { &*maybe_context }))
916 }
917 }
918}
919
920impl FusedFuture for RawWatcherNext<'_> {
921 fn is_terminated(&self) -> bool {
922 self.0.is_none()
923 }
924}
925
Brian Silverman90221f82022-08-22 23:46:09 -0700926/// Provides async blocking access to messages on a channel. This will return every message on the
927/// channel, in order.
928///
929/// Use [`EventLoopRuntime::make_watcher`] to create one of these.
930///
931/// This is the same concept as [`futures::stream::Stream`], but can't follow that API for technical
932/// reasons. See [`RawWatcher`]'s documentation for details.
933pub struct Watcher<T>(RawWatcher, PhantomData<*mut T>)
934where
935 for<'a> T: FollowWith<'a>,
936 for<'a> <T as FollowWith<'a>>::Inner: Follow<'a>;
937
938impl<T> Watcher<T>
939where
940 for<'a> T: FollowWith<'a>,
941 for<'a> <T as FollowWith<'a>>::Inner: Follow<'a>,
942{
943 /// Returns a Future to await the next value. This can be canceled (ie dropped) at will,
944 /// without skipping any messages.
945 ///
946 /// Remember not to call `poll` after it returns `Poll::Ready`, just like any other future. You
947 /// will need to call this function again to get the succeeding message.
948 ///
949 /// # Examples
950 ///
951 /// The common use case is immediately awaiting the next message:
952 /// ```
953 /// # use pong_rust_fbs::aos::examples::Pong;
954 /// # async fn await_message(mut watcher: aos_events_event_loop_runtime::Watcher<Pong<'static>>) {
955 /// println!("received: {:?}", watcher.next().await);
956 /// # }
957 /// ```
958 ///
959 /// You can also await the first message from any of a set of channels:
960 /// ```
961 /// # use pong_rust_fbs::aos::examples::Pong;
962 /// # async fn select(
963 /// # mut watcher1: aos_events_event_loop_runtime::Watcher<Pong<'static>>,
964 /// # mut watcher2: aos_events_event_loop_runtime::Watcher<Pong<'static>>,
965 /// # ) {
966 /// futures::select! {
967 /// message1 = watcher1.next() => println!("channel 1: {:?}", message1),
968 /// message2 = watcher2.next() => println!("channel 2: {:?}", message2),
969 /// }
970 /// # }
971 /// ```
972 ///
973 /// Note that due to the returned object borrowing the `self` reference, the borrow checker will
974 /// enforce only having a single of these returned objects at a time. Drop the previous message
975 /// before asking for the next one. That means this will not compile:
976 /// ```compile_fail
977 /// # use pong_rust_fbs::aos::examples::Pong;
978 /// # async fn compile_check(mut watcher: aos_events_event_loop_runtime::Watcher<Pong<'static>>) {
979 /// let first = watcher.next();
980 /// let second = watcher.next();
981 /// first.await;
982 /// # }
983 /// ```
984 /// and nor will this:
985 /// ```compile_fail
986 /// # use pong_rust_fbs::aos::examples::Pong;
987 /// # async fn compile_check(mut watcher: aos_events_event_loop_runtime::Watcher<Pong<'static>>) {
988 /// let first = watcher.next().await;
989 /// watcher.next();
990 /// println!("still have: {:?}", first);
991 /// # }
992 /// ```
993 /// but this is fine:
994 /// ```
995 /// # use pong_rust_fbs::aos::examples::Pong;
996 /// # async fn compile_check(mut watcher: aos_events_event_loop_runtime::Watcher<Pong<'static>>) {
997 /// let first = watcher.next().await;
998 /// println!("have: {:?}", first);
999 /// watcher.next();
1000 /// # }
1001 /// ```
1002 pub fn next(&mut self) -> WatcherNext<'_, <T as FollowWith<'_>>::Inner> {
1003 WatcherNext(self.0.next(), PhantomData)
1004 }
1005}
1006
1007/// The type returned from [`Watcher::next`], see there for details.
1008pub struct WatcherNext<'watcher, T>(RawWatcherNext<'watcher>, PhantomData<*mut T>)
1009where
1010 T: Follow<'watcher> + 'watcher;
1011
1012impl<'watcher, T> Future for WatcherNext<'watcher, T>
1013where
1014 T: Follow<'watcher> + 'watcher,
1015{
1016 type Output = TypedContext<'watcher, T>;
1017
1018 fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context) -> Poll<Self::Output> {
1019 Pin::new(&mut self.get_mut().0).poll(cx).map(|context|
1020 // SAFETY: The Watcher this was created from verified that the channel is the
1021 // right type, and the C++ guarantees that the buffer's type matches.
1022 TypedContext(context, PhantomData))
1023 }
1024}
1025
1026impl<'watcher, T> FusedFuture for WatcherNext<'watcher, T>
1027where
1028 T: Follow<'watcher> + 'watcher,
1029{
1030 fn is_terminated(&self) -> bool {
1031 self.0.is_terminated()
1032 }
1033}
1034
1035/// A wrapper around [`Context`] which exposes the flatbuffer message with the appropriate type.
1036pub struct TypedContext<'a, T>(
1037 // SAFETY: This must have a message, and it must be a valid `T` flatbuffer.
1038 Context<'a>,
1039 PhantomData<*mut T>,
1040)
1041where
1042 T: Follow<'a> + 'a;
1043
Brian Silverman90221f82022-08-22 23:46:09 -07001044impl<'a, T> TypedContext<'a, T>
1045where
1046 T: Follow<'a> + 'a,
1047{
1048 pub fn message(&self) -> Option<T::Inner> {
1049 self.0.data().map(|data| {
1050 // SAFETY: C++ guarantees that this is a valid flatbuffer. We guarantee it's the right
1051 // type based on invariants for our type.
1052 unsafe { root_unchecked::<T>(data) }
1053 })
1054 }
1055
1056 pub fn monotonic_event_time(&self) -> MonotonicInstant {
1057 self.0.monotonic_event_time()
1058 }
1059 pub fn monotonic_remote_time(&self) -> MonotonicInstant {
1060 self.0.monotonic_remote_time()
1061 }
Ryan Yin683a8672022-11-09 20:44:20 -08001062 pub fn realtime_event_time(&self) -> RealtimeInstant {
1063 self.0.realtime_event_time()
1064 }
1065 pub fn realtime_remote_time(&self) -> RealtimeInstant {
1066 self.0.realtime_remote_time()
1067 }
Brian Silverman90221f82022-08-22 23:46:09 -07001068 pub fn queue_index(&self) -> u32 {
1069 self.0.queue_index()
1070 }
1071 pub fn remote_queue_index(&self) -> u32 {
1072 self.0.remote_queue_index()
1073 }
1074 pub fn buffer_index(&self) -> i32 {
1075 self.0.buffer_index()
1076 }
1077 pub fn source_boot_uuid(&self) -> &Uuid {
1078 self.0.source_boot_uuid()
1079 }
1080}
1081
1082impl<'a, T> fmt::Debug for TypedContext<'a, T>
1083where
1084 T: Follow<'a> + 'a,
1085 T::Inner: fmt::Debug,
1086{
1087 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Brian Silverman90221f82022-08-22 23:46:09 -07001088 f.debug_struct("TypedContext")
1089 .field("monotonic_event_time", &self.monotonic_event_time())
1090 .field("monotonic_remote_time", &self.monotonic_remote_time())
Ryan Yin683a8672022-11-09 20:44:20 -08001091 .field("realtime_event_time", &self.realtime_event_time())
1092 .field("realtime_remote_time", &self.realtime_remote_time())
Brian Silverman90221f82022-08-22 23:46:09 -07001093 .field("queue_index", &self.queue_index())
1094 .field("remote_queue_index", &self.remote_queue_index())
1095 .field("message", &self.message())
1096 .field("buffer_index", &self.buffer_index())
1097 .field("source_boot_uuid", &self.source_boot_uuid())
1098 .finish()
1099 }
1100}
Brian Silverman9809c5f2022-07-23 16:12:23 -07001101
1102/// Provides access to messages on a channel, without the ability to wait for a new one. This
Brian Silverman90221f82022-08-22 23:46:09 -07001103/// provides APIs to get the latest message, and to follow along and retrieve each message in order.
Brian Silverman9809c5f2022-07-23 16:12:23 -07001104///
1105/// Use [`EventLoopRuntime::make_raw_fetcher`] to create one of these.
1106///
1107/// This is the non-typed API, which is mainly useful for reflection and does not provide safe APIs
1108/// for actually interpreting messages. You probably want a [`Fetcher`] instead.
Brian Silverman90221f82022-08-22 23:46:09 -07001109// SAFETY: If this outlives the parent EventLoop, the C++ code will LOG(FATAL).
1110#[repr(transparent)]
1111pub struct RawFetcher(Pin<Box<ffi::aos::FetcherForRust>>);
1112
Brian Silverman9809c5f2022-07-23 16:12:23 -07001113impl RawFetcher {
1114 pub fn fetch_next(&mut self) -> bool {
1115 self.0.as_mut().FetchNext()
1116 }
1117
1118 pub fn fetch(&mut self) -> bool {
1119 self.0.as_mut().Fetch()
1120 }
1121
1122 pub fn context(&self) -> Context {
1123 Context(self.0.context())
1124 }
1125}
1126
Brian Silverman90221f82022-08-22 23:46:09 -07001127/// Provides access to messages on a channel, without the ability to wait for a new one. This
1128/// provides APIs to get the latest message, and to follow along and retrieve each message in order.
1129///
1130/// Use [`EventLoopRuntime::make_fetcher`] to create one of these.
1131pub struct Fetcher<T>(
1132 // SAFETY: This must produce messages of type `T`.
1133 RawFetcher,
1134 PhantomData<*mut T>,
1135)
1136where
1137 for<'a> T: FollowWith<'a>,
1138 for<'a> <T as FollowWith<'a>>::Inner: Follow<'a>;
1139
1140impl<T> Fetcher<T>
1141where
1142 for<'a> T: FollowWith<'a>,
1143 for<'a> <T as FollowWith<'a>>::Inner: Follow<'a>,
1144{
1145 pub fn fetch_next(&mut self) -> bool {
1146 self.0.fetch_next()
1147 }
1148 pub fn fetch(&mut self) -> bool {
1149 self.0.fetch()
1150 }
1151
1152 pub fn context(&self) -> TypedContext<'_, <T as FollowWith<'_>>::Inner> {
1153 // SAFETY: We verified that this is the correct type, and C++ guarantees that the buffer's
1154 // type matches.
1155 TypedContext(self.0.context(), PhantomData)
1156 }
1157}
Brian Silverman9809c5f2022-07-23 16:12:23 -07001158
1159/// Allows sending messages on a channel.
1160///
1161/// This is the non-typed API, which is mainly useful for reflection and does not provide safe APIs
1162/// for actually creating messages to send. You probably want a [`Sender`] instead.
1163///
1164/// Use [`EventLoopRuntime::make_raw_sender`] to create one of these.
Brian Silverman90221f82022-08-22 23:46:09 -07001165// SAFETY: If this outlives the parent EventLoop, the C++ code will LOG(FATAL).
1166#[repr(transparent)]
1167pub struct RawSender(Pin<Box<ffi::aos::SenderForRust>>);
1168
Brian Silverman9809c5f2022-07-23 16:12:23 -07001169impl RawSender {
Brian Silverman9809c5f2022-07-23 16:12:23 -07001170 /// Returns an object which can be used to build a message.
1171 ///
1172 /// # Examples
1173 ///
1174 /// ```
1175 /// # use pong_rust_fbs::aos::examples::PongBuilder;
1176 /// # fn compile_check(mut sender: aos_events_event_loop_runtime::RawSender) {
1177 /// # unsafe {
1178 /// let mut builder = sender.make_builder();
1179 /// let pong = PongBuilder::new(builder.fbb()).finish();
1180 /// builder.send(pong);
1181 /// # }
1182 /// # }
1183 /// ```
1184 ///
1185 /// You can bail out of building a message and build another one:
1186 /// ```
1187 /// # use pong_rust_fbs::aos::examples::PongBuilder;
1188 /// # fn compile_check(mut sender: aos_events_event_loop_runtime::RawSender) {
1189 /// # unsafe {
1190 /// let mut builder1 = sender.make_builder();
1191 /// builder1.fbb();
Adam Snaider0126d832023-10-03 09:59:34 -07001192 /// drop(builder1);
Brian Silverman9809c5f2022-07-23 16:12:23 -07001193 /// let mut builder2 = sender.make_builder();
1194 /// let pong = PongBuilder::new(builder2.fbb()).finish();
1195 /// builder2.send(pong);
1196 /// # }
1197 /// # }
1198 /// ```
1199 /// but you cannot build two messages at the same time with a single builder:
1200 /// ```compile_fail
1201 /// # use pong_rust_fbs::aos::examples::PongBuilder;
1202 /// # fn compile_check(mut sender: aos_events_event_loop_runtime::RawSender) {
1203 /// # unsafe {
1204 /// let mut builder1 = sender.make_builder();
1205 /// let mut builder2 = sender.make_builder();
1206 /// PongBuilder::new(builder2.fbb()).finish();
1207 /// PongBuilder::new(builder1.fbb()).finish();
1208 /// # }
1209 /// # }
1210 /// ```
1211 pub fn make_builder(&mut self) -> RawBuilder {
Adam Snaider34072e12023-10-03 10:04:25 -07001212 // SAFETY: This is a valid slice, and `u8` doesn't have any alignment
1213 // requirements. Additionally, the lifetime of the builder is tied to
1214 // the lifetime of self so the buffer won't be accessible again until
1215 // the builder is destroyed.
1216 let allocator = ChannelPreallocatedAllocator::new(unsafe {
1217 slice::from_raw_parts_mut(self.0.as_mut().data(), self.0.as_mut().size())
1218 });
1219 let fbb = FlatBufferBuilder::new_in(allocator);
Brian Silverman9809c5f2022-07-23 16:12:23 -07001220 RawBuilder {
1221 raw_sender: self,
1222 fbb,
1223 }
1224 }
1225}
1226
Brian Silverman9809c5f2022-07-23 16:12:23 -07001227/// Used for building a message. See [`RawSender::make_builder`] for details.
1228pub struct RawBuilder<'sender> {
1229 raw_sender: &'sender mut RawSender,
Adam Snaider34072e12023-10-03 10:04:25 -07001230 fbb: FlatBufferBuilder<'sender, ChannelPreallocatedAllocator<'sender>>,
Brian Silverman9809c5f2022-07-23 16:12:23 -07001231}
1232
1233impl<'sender> RawBuilder<'sender> {
Adam Snaider34072e12023-10-03 10:04:25 -07001234 pub fn fbb(
1235 &mut self,
1236 ) -> &mut FlatBufferBuilder<'sender, ChannelPreallocatedAllocator<'sender>> {
Brian Silverman9809c5f2022-07-23 16:12:23 -07001237 &mut self.fbb
1238 }
1239
1240 /// # Safety
1241 ///
1242 /// `T` must match the type of the channel of the sender this builder was created from.
1243 pub unsafe fn send<T>(mut self, root: flatbuffers::WIPOffset<T>) -> Result<(), SendError> {
1244 self.fbb.finish_minimal(root);
1245 let data = self.fbb.finished_data();
1246
1247 use ffi::aos::RawSender_Error as FfiError;
1248 // SAFETY: This is a valid buffer we're passing.
1249 match unsafe {
1250 self.raw_sender
1251 .0
1252 .as_mut()
1253 .CopyAndSend(data.as_ptr(), data.len())
1254 } {
1255 FfiError::kOk => Ok(()),
1256 FfiError::kMessagesSentTooFast => Err(SendError::MessagesSentTooFast),
1257 FfiError::kInvalidRedzone => Err(SendError::InvalidRedzone),
1258 }
1259 }
1260}
1261
Brian Silverman90221f82022-08-22 23:46:09 -07001262/// Allows sending messages on a channel with a type-safe API.
1263///
1264/// Use [`EventLoopRuntime::make_raw_sender`] to create one of these.
1265pub struct Sender<T>(
1266 // SAFETY: This must accept messages of type `T`.
1267 RawSender,
1268 PhantomData<*mut T>,
1269)
1270where
1271 for<'a> T: FollowWith<'a>,
1272 for<'a> <T as FollowWith<'a>>::Inner: Follow<'a>;
1273
1274impl<T> Sender<T>
1275where
1276 for<'a> T: FollowWith<'a>,
1277 for<'a> <T as FollowWith<'a>>::Inner: Follow<'a>,
1278{
1279 /// Returns an object which can be used to build a message.
1280 ///
1281 /// # Examples
1282 ///
1283 /// ```
1284 /// # use pong_rust_fbs::aos::examples::{Pong, PongBuilder};
1285 /// # fn compile_check(mut sender: aos_events_event_loop_runtime::Sender<Pong<'static>>) {
1286 /// let mut builder = sender.make_builder();
1287 /// let pong = PongBuilder::new(builder.fbb()).finish();
1288 /// builder.send(pong);
1289 /// # }
1290 /// ```
1291 ///
1292 /// You can bail out of building a message and build another one:
1293 /// ```
1294 /// # use pong_rust_fbs::aos::examples::{Pong, PongBuilder};
1295 /// # fn compile_check(mut sender: aos_events_event_loop_runtime::Sender<Pong<'static>>) {
1296 /// let mut builder1 = sender.make_builder();
1297 /// builder1.fbb();
Adam Snaider0126d832023-10-03 09:59:34 -07001298 /// drop(builder1);
Brian Silverman90221f82022-08-22 23:46:09 -07001299 /// let mut builder2 = sender.make_builder();
1300 /// let pong = PongBuilder::new(builder2.fbb()).finish();
1301 /// builder2.send(pong);
1302 /// # }
1303 /// ```
1304 /// but you cannot build two messages at the same time with a single builder:
1305 /// ```compile_fail
1306 /// # use pong_rust_fbs::aos::examples::{Pong, PongBuilder};
1307 /// # fn compile_check(mut sender: aos_events_event_loop_runtime::Sender<Pong<'static>>) {
1308 /// let mut builder1 = sender.make_builder();
1309 /// let mut builder2 = sender.make_builder();
1310 /// PongBuilder::new(builder2.fbb()).finish();
1311 /// PongBuilder::new(builder1.fbb()).finish();
1312 /// # }
1313 /// ```
1314 pub fn make_builder(&mut self) -> Builder<T> {
1315 Builder(self.0.make_builder(), PhantomData)
1316 }
1317}
1318
1319/// Used for building a message. See [`Sender::make_builder`] for details.
1320pub struct Builder<'sender, T>(
1321 // SAFETY: This must accept messages of type `T`.
1322 RawBuilder<'sender>,
1323 PhantomData<*mut T>,
1324)
1325where
1326 for<'a> T: FollowWith<'a>,
1327 for<'a> <T as FollowWith<'a>>::Inner: Follow<'a>;
1328
1329impl<'sender, T> Builder<'sender, T>
1330where
1331 for<'a> T: FollowWith<'a>,
1332 for<'a> <T as FollowWith<'a>>::Inner: Follow<'a>,
1333{
Adam Snaider34072e12023-10-03 10:04:25 -07001334 pub fn fbb(
1335 &mut self,
1336 ) -> &mut FlatBufferBuilder<'sender, ChannelPreallocatedAllocator<'sender>> {
Brian Silverman90221f82022-08-22 23:46:09 -07001337 self.0.fbb()
1338 }
1339
1340 pub fn send<'a>(
1341 self,
1342 root: flatbuffers::WIPOffset<<T as FollowWith<'a>>::Inner>,
1343 ) -> Result<(), SendError> {
1344 // SAFETY: We guarantee this is the right type based on invariants for our type.
1345 unsafe { self.0.send(root) }
1346 }
1347}
1348
1349#[derive(Clone, Copy, Eq, PartialEq, Debug, Error)]
1350pub enum SendError {
1351 #[error("messages have been sent too fast on this channel")]
1352 MessagesSentTooFast,
1353 #[error("invalid redzone data, shared memory corruption detected")]
1354 InvalidRedzone,
1355}
1356
Brian Silverman9809c5f2022-07-23 16:12:23 -07001357#[repr(transparent)]
1358#[derive(Clone, Copy)]
1359pub struct Context<'context>(&'context ffi::aos::Context);
1360
1361impl fmt::Debug for Context<'_> {
1362 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Brian Silverman9809c5f2022-07-23 16:12:23 -07001363 f.debug_struct("Context")
1364 .field("monotonic_event_time", &self.monotonic_event_time())
1365 .field("monotonic_remote_time", &self.monotonic_remote_time())
Ryan Yin683a8672022-11-09 20:44:20 -08001366 .field("realtime_event_time", &self.realtime_event_time())
1367 .field("realtime_remote_time", &self.realtime_remote_time())
Brian Silverman9809c5f2022-07-23 16:12:23 -07001368 .field("queue_index", &self.queue_index())
1369 .field("remote_queue_index", &self.remote_queue_index())
1370 .field("size", &self.data().map(|data| data.len()))
1371 .field("buffer_index", &self.buffer_index())
1372 .field("source_boot_uuid", &self.source_boot_uuid())
1373 .finish()
1374 }
1375}
1376
Brian Silverman9809c5f2022-07-23 16:12:23 -07001377impl<'context> Context<'context> {
1378 pub fn monotonic_event_time(self) -> MonotonicInstant {
1379 MonotonicInstant(self.0.monotonic_event_time)
1380 }
1381
1382 pub fn monotonic_remote_time(self) -> MonotonicInstant {
1383 MonotonicInstant(self.0.monotonic_remote_time)
1384 }
1385
Ryan Yin683a8672022-11-09 20:44:20 -08001386 pub fn realtime_event_time(self) -> RealtimeInstant {
1387 RealtimeInstant(self.0.realtime_event_time)
1388 }
1389
1390 pub fn realtime_remote_time(self) -> RealtimeInstant {
1391 RealtimeInstant(self.0.realtime_remote_time)
1392 }
1393
Brian Silverman9809c5f2022-07-23 16:12:23 -07001394 pub fn queue_index(self) -> u32 {
1395 self.0.queue_index
1396 }
1397 pub fn remote_queue_index(self) -> u32 {
1398 self.0.remote_queue_index
1399 }
1400
1401 pub fn data(self) -> Option<&'context [u8]> {
1402 if self.0.data.is_null() {
1403 None
1404 } else {
1405 // SAFETY:
1406 // * `u8` has no alignment requirements
1407 // * It must be a single initialized flatbuffers buffer
1408 // * The borrow in `self.0` guarantees it won't be modified for `'context`
1409 Some(unsafe { slice::from_raw_parts(self.0.data as *const u8, self.0.size) })
1410 }
1411 }
1412
1413 pub fn buffer_index(self) -> i32 {
1414 self.0.buffer_index
1415 }
1416
1417 pub fn source_boot_uuid(self) -> &'context Uuid {
1418 // SAFETY: `self` has a valid C++ object. C++ guarantees that the return value will be
1419 // valid until something changes the context, which is `'context`.
1420 Uuid::from_bytes_ref(&self.0.source_boot_uuid)
1421 }
1422}
1423
Brian Silverman76f48362022-08-24 21:09:08 -07001424/// The type returned from [`EventLoopRuntime::on_run`], see there for details.
1425// SAFETY: If this outlives the parent EventLoop, the C++ code will LOG(FATAL).
1426#[repr(transparent)]
1427pub struct OnRun(Pin<Box<ffi::aos::OnRunForRust>>);
1428
1429impl Future for OnRun {
1430 type Output = ();
1431
1432 fn poll(self: Pin<&mut Self>, _: &mut std::task::Context) -> Poll<()> {
1433 if self.0.is_running() {
1434 Poll::Ready(())
1435 } else {
1436 Poll::Pending
1437 }
1438 }
1439}
1440
Brian Silverman9809c5f2022-07-23 16:12:23 -07001441/// Represents a `aos::monotonic_clock::time_point` in a natural Rust way. This
1442/// is intended to have the same API as [`std::time::Instant`], any missing
1443/// functionality can be added if useful.
Brian Silverman9809c5f2022-07-23 16:12:23 -07001444#[repr(transparent)]
1445#[derive(Clone, Copy, Eq, PartialEq)]
1446pub struct MonotonicInstant(i64);
1447
1448impl MonotonicInstant {
1449 /// `aos::monotonic_clock::min_time`, commonly used as a sentinel value.
1450 pub const MIN_TIME: Self = Self(i64::MIN);
1451
1452 pub fn is_min_time(self) -> bool {
1453 self == Self::MIN_TIME
1454 }
1455
1456 pub fn duration_since_epoch(self) -> Option<Duration> {
1457 if self.is_min_time() {
1458 None
1459 } else {
1460 Some(Duration::from_nanos(self.0.try_into().expect(
1461 "monotonic_clock::time_point should always be after the epoch",
1462 )))
1463 }
1464 }
1465}
1466
Adam Snaidercc8c2f72023-06-25 20:56:13 -07001467impl Add<Duration> for MonotonicInstant {
1468 type Output = MonotonicInstant;
1469
1470 fn add(self, rhs: Duration) -> Self::Output {
1471 Self(self.0 + i64::try_from(rhs.as_nanos()).unwrap())
1472 }
1473}
1474
Adam Snaiderde51c672023-09-28 21:55:43 -07001475impl From<MonotonicInstant> for i64 {
1476 fn from(value: MonotonicInstant) -> Self {
1477 value.0
1478 }
1479}
1480
Brian Silverman9809c5f2022-07-23 16:12:23 -07001481impl fmt::Debug for MonotonicInstant {
1482 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1483 self.duration_since_epoch().fmt(f)
1484 }
1485}
1486
Ryan Yin683a8672022-11-09 20:44:20 -08001487#[repr(transparent)]
1488#[derive(Clone, Copy, Eq, PartialEq)]
1489pub struct RealtimeInstant(i64);
1490
1491impl RealtimeInstant {
1492 pub const MIN_TIME: Self = Self(i64::MIN);
1493
1494 pub fn is_min_time(self) -> bool {
1495 self == Self::MIN_TIME
1496 }
1497
1498 pub fn duration_since_epoch(self) -> Option<Duration> {
1499 if self.is_min_time() {
1500 None
1501 } else {
1502 Some(Duration::from_nanos(self.0.try_into().expect(
1503 "monotonic_clock::time_point should always be after the epoch",
1504 )))
1505 }
1506 }
1507}
1508
Adam Snaiderde51c672023-09-28 21:55:43 -07001509impl From<RealtimeInstant> for i64 {
1510 fn from(value: RealtimeInstant) -> Self {
1511 value.0
1512 }
1513}
1514
Ryan Yin683a8672022-11-09 20:44:20 -08001515impl fmt::Debug for RealtimeInstant {
1516 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1517 self.duration_since_epoch().fmt(f)
1518 }
1519}
1520
Brian Silverman9809c5f2022-07-23 16:12:23 -07001521mod panic_waker {
1522 use std::task::{RawWaker, RawWakerVTable, Waker};
1523
1524 unsafe fn clone_panic_waker(_data: *const ()) -> RawWaker {
1525 raw_panic_waker()
1526 }
1527
1528 unsafe fn noop(_data: *const ()) {}
1529
1530 unsafe fn wake_panic(_data: *const ()) {
1531 panic!("Nothing should wake EventLoopRuntime's waker");
1532 }
1533
1534 const PANIC_WAKER_VTABLE: RawWakerVTable =
1535 RawWakerVTable::new(clone_panic_waker, wake_panic, wake_panic, noop);
1536
1537 fn raw_panic_waker() -> RawWaker {
1538 RawWaker::new(std::ptr::null(), &PANIC_WAKER_VTABLE)
1539 }
1540
1541 pub fn panic_waker() -> Waker {
1542 // SAFETY: The implementations of the RawWakerVTable functions do what is required of them.
1543 unsafe { Waker::from_raw(raw_panic_waker()) }
1544 }
1545}
1546
1547use panic_waker::panic_waker;
Adam Snaider163800b2023-07-12 00:21:17 -04001548
1549pub struct ExitHandle(UniquePtr<CppExitHandle>);
1550
1551impl ExitHandle {
1552 /// Exits the EventLoops represented by this handle. You probably want to immediately return
1553 /// from the context this is called in. Awaiting [`exit`] instead of using this function is an
1554 /// easy way to do that.
1555 pub fn exit_sync(mut self) {
1556 self.0.as_mut().unwrap().Exit();
1557 }
1558
1559 /// Exits the EventLoops represented by this handle, and never returns. Immediately awaiting
1560 /// this from a [`EventLoopRuntime::spawn`]ed task is usually what you want, it will ensure
1561 /// that no more code from that task runs.
1562 pub async fn exit(self) -> Never {
1563 self.exit_sync();
1564 pending().await
1565 }
1566}
1567
1568impl From<UniquePtr<CppExitHandle>> for ExitHandle {
1569 fn from(inner: UniquePtr<ffi::aos::ExitHandle>) -> Self {
1570 Self(inner)
1571 }
1572}
Adam Snaider34072e12023-10-03 10:04:25 -07001573
1574pub struct ChannelPreallocatedAllocator<'a> {
1575 buffer: &'a mut [u8],
1576}
1577
1578impl<'a> ChannelPreallocatedAllocator<'a> {
1579 pub fn new(buffer: &'a mut [u8]) -> Self {
1580 Self { buffer }
1581 }
1582}
1583
1584#[derive(Debug, Error)]
1585#[error("Can't allocate more memory with a fixed size allocator")]
1586pub struct OutOfMemory;
1587
1588// SAFETY: Allocator follows the required behavior.
1589unsafe impl Allocator for ChannelPreallocatedAllocator<'_> {
1590 type Error = OutOfMemory;
1591 fn grow_downwards(&mut self) -> Result<(), Self::Error> {
1592 // Fixed size allocator can't grow.
1593 Err(OutOfMemory)
1594 }
1595
1596 fn len(&self) -> usize {
1597 self.buffer.len()
1598 }
1599}
1600
1601impl Deref for ChannelPreallocatedAllocator<'_> {
1602 type Target = [u8];
1603
1604 fn deref(&self) -> &Self::Target {
1605 self.buffer
1606 }
1607}
1608
1609impl DerefMut for ChannelPreallocatedAllocator<'_> {
1610 fn deref_mut(&mut self) -> &mut Self::Target {
1611 self.buffer
1612 }
1613}