Merge "Add current control loop python"
diff --git a/aos/events/event_loop_runtime.rs b/aos/events/event_loop_runtime.rs
index 7f58dbb..76c1e2e 100644
--- a/aos/events/event_loop_runtime.rs
+++ b/aos/events/event_loop_runtime.rs
@@ -34,11 +34,9 @@
 //!     https://github.com/google/autocxx/issues/1146 for details.
 //!   * For various reasons autocxx can't directly wrap APIs using types ergonomic for C++. This and
 //!     the previous point mean we wrap all of the C++ objects specifically for this class.
-//!   * Keeping track of all the lifetimes and creating appropriate references for the callbacks is
-//!     really hard in Rust. Even doing it for the library implementation turned out to be hard
-//!     enough to look for alternatives. I think you'd have to make extensive use of pointers, but
-//!     Rust makes that hard, and it's easy to create references in ways that violate Rust's
-//!     aliasing rules.
+//!   * Rust's lifetimes are only flexible enough to track everything with a single big lifetime.
+//!     All the callbacks can store references to things tied to the event loop's lifetime, but no
+//!     other lifetimes.
 //!   * We can't use [`futures::stream::Stream`] and all of its nice [`futures::stream::StreamExt`]
 //!     helpers for watchers because we need lifetime-generic `Item` types. Effectively we're making
 //!     a lending stream. This is very close to lending iterators, which is one of the motivating
@@ -48,6 +46,7 @@
     fmt,
     future::Future,
     marker::PhantomData,
+    mem::ManuallyDrop,
     panic::{catch_unwind, AssertUnwindSafe},
     pin::Pin,
     slice,
@@ -56,7 +55,7 @@
 };
 
 use autocxx::{
-    subclass::{is_subclass, CppSubclass},
+    subclass::{subclass, CppSubclass},
     WithinBox,
 };
 use cxx::UniquePtr;
@@ -69,6 +68,7 @@
 use aos_configuration::{ChannelLookupError, ConfigurationExt};
 
 pub use aos_uuid::UUID;
+pub use ffi::aos::EventLoopRuntime as CppEventLoopRuntime;
 pub use ffi::aos::ExitHandle as CppExitHandle;
 
 autocxx::include_cpp! (
@@ -95,6 +95,13 @@
 
 pub type EventLoop = ffi::aos::EventLoop;
 
+/// A marker type which is invariant with respect to the given lifetime.
+///
+/// When interacting with functions that take and return things with a given lifetime, the lifetime
+/// becomes invariant. Because we don't store these functions as Rust types, we need a type like
+/// this to tell the Rust compiler that it can't substitute a shorter _or_ longer lifetime.
+pub type InvariantLifetime<'a> = PhantomData<fn(&'a ()) -> &'a ()>;
+
 /// # Safety
 ///
 /// This should have a `'event_loop` lifetime and `future` should include that in its type, but
@@ -102,7 +109,7 @@
 /// enforcing the lifetime: it destroys this object along with the C++ `EventLoopRuntime`, which
 /// must be outlived by the EventLoop.
 #[doc(hidden)]
-#[is_subclass(superclass("aos::ApplicationFuture"))]
+#[subclass]
 pub struct RustApplicationFuture {
     /// This logically has a `'event_loop` bound, see the class comment for details.
     future: Pin<Box<dyn Future<Output = Never>>>,
@@ -145,17 +152,138 @@
     }
 }
 
+/// An abstraction for objects which hold an `aos::EventLoop` from Rust code.
+///
+/// If you have an `aos::EventLoop` provided from C++ code, don't use this, just call
+/// [`EventLoopRuntime.new`] directly.
+///
+/// # Safety
+///
+/// Objects implementing this trait *must* have mostly-exclusive (except for running it) ownership
+/// of the `aos::EventLoop` *for its entire lifetime*, which *must* be dropped when this object is.
+/// See [`EventLoopRuntime.new`]'s safety requirements for why this can be important and details of
+/// mostly-exclusive. In other words, nothing else may mutate it in any way except processing events
+/// (including dropping, because this object has to be the one to drop it).
+///
+/// This also implies semantics similar to `Pin<&mut ffi::aos::EventLoop>` for the underlying object.
+/// Implementations of this trait must have exclusive ownership of it, and the underlying object
+/// must not be moved.
+pub unsafe trait EventLoopHolder {
+    /// Converts this holder into a raw C++ pointer. This may be fed through other Rust and C++
+    /// code, and eventually passed back to [`from_raw`].
+    fn into_raw(self) -> *mut ffi::aos::EventLoop;
+
+    /// Converts a raw C++ pointer back to a holder object.
+    ///
+    /// # Safety
+    ///
+    /// `raw` must be the result of [`into_raw`] on an instance of this same type. These raw
+    /// pointers *are not* interchangeable between implementations of this trait.
+    unsafe fn from_raw(raw: *mut ffi::aos::EventLoop) -> Self;
+}
+
+/// Owns an [`EventLoopRuntime`] and its underlying `aos::EventLoop`, with safe management of the
+/// associated Rust lifetimes.
+pub struct EventLoopRuntimeHolder<T: EventLoopHolder>(
+    ManuallyDrop<Pin<Box<CppEventLoopRuntime>>>,
+    PhantomData<T>,
+);
+
+impl<T: EventLoopHolder> EventLoopRuntimeHolder<T> {
+    /// Creates a new [`EventLoopRuntime`] and runs an initialization function on it. This is a
+    /// safe wrapper around [`EventLoopRuntime.new`] (although see [`EventLoopHolder`]'s safety
+    /// requirements, part of them are just delegated there).
+    ///
+    /// If you have an `aos::EventLoop` provided from C++ code, don't use this, just call
+    /// [`EventLoopRuntime.new`] directly.
+    ///
+    /// All setup of the runtime must be performed with `fun`, which is called before this function
+    /// returns. `fun` may create further objects to use in async functions via [`EventLoop.spawn`]
+    /// etc, but it is the only place to set things up before the EventLoop is run.
+    ///
+    /// `fun` cannot capture things outside of the event loop, because the event loop might outlive
+    /// them:
+    /// ```compile_fail
+    /// # use aos_events_event_loop_runtime::*;
+    /// # fn bad(event_loop: impl EventLoopHolder) {
+    /// let mut x = 0;
+    /// EventLoopRuntimeHolder::new(event_loop, |runtime| {
+    ///     runtime.spawn(async {
+    ///         x = 1;
+    ///         loop {}
+    ///     });
+    /// });
+    /// # }
+    /// ```
+    ///
+    /// But it can capture `'event_loop` references:
+    /// ```
+    /// # use aos_events_event_loop_runtime::*;
+    /// # use aos_configuration::ChannelExt;
+    /// # fn good(event_loop: impl EventLoopHolder) {
+    /// EventLoopRuntimeHolder::new(event_loop, |runtime| {
+    ///     let channel = runtime.get_raw_channel("/test", "aos.examples.Ping").unwrap();
+    ///     runtime.spawn(async {
+    ///         loop {
+    ///             eprintln!("{:?}", channel.type_());
+    ///         }
+    ///     });
+    /// });
+    /// # }
+    /// ```
+    pub fn new<F>(event_loop: T, fun: F) -> Self
+    where
+        F: for<'event_loop> FnOnce(&mut EventLoopRuntime<'event_loop>),
+    {
+        // SAFETY: The EventLoopRuntime never escapes this function, which means the only code that
+        // observes its lifetime is `fun`. `fun` must be generic across any value of its
+        // `'event_loop` lifetime parameter, which means we can choose any lifetime here, which
+        // satisfies the safety requirements.
+        //
+        // This is a similar pattern as `std::thread::scope`, `ghost-cell`, etc. Note that unlike
+        // `std::thread::scope`, our inner functions (the async ones) are definitely not allowed to
+        // capture things from the calling scope of this function, so there's no `'env` equivalent.
+        // `ghost-cell` ends up looking very similar despite doing different things with the
+        // pattern, while `std::thread::scope` has a lot of additional complexity to achieve a
+        // similar result.
+        //
+        // `EventLoopHolder`s safety requirements prevent anybody else from touching the underlying
+        // `aos::EventLoop`.
+        let mut runtime = unsafe { EventLoopRuntime::new(event_loop.into_raw()) };
+        fun(&mut runtime);
+        Self(ManuallyDrop::new(runtime.into_cpp()), PhantomData)
+    }
+}
+
+impl<T: EventLoopHolder> Drop for EventLoopRuntimeHolder<T> {
+    fn drop(&mut self) {
+        let event_loop = self.0.as_mut().event_loop();
+        // SAFETY: We're not going to touch this field again. The underlying EventLoop will not be
+        // run again because we're going to drop it next.
+        unsafe { ManuallyDrop::drop(&mut self.0) };
+        // SAFETY: We took this from `into_raw`, and we just dropped the runtime which may contain
+        // Rust references to it.
+        unsafe { drop(T::from_raw(event_loop)) };
+    }
+}
+
 pub struct EventLoopRuntime<'event_loop>(
     Pin<Box<ffi::aos::EventLoopRuntime>>,
-    // This is the lifetime of the underlying EventLoop, which is held in C++ via `.0`.
-    PhantomData<&'event_loop mut ()>,
+    // See documentation of [`new`] for details.
+    InvariantLifetime<'event_loop>,
 );
 
 /// Manages the Rust interface to a *single* `aos::EventLoop`. This is intended to be used by a
 /// single application.
 impl<'event_loop> EventLoopRuntime<'event_loop> {
-    /// Creates a new runtime. This must be the only user of the underlying `aos::EventLoop`, or
-    /// things may panic unexpectedly.
+    /// Creates a new runtime. This must be the only user of the underlying `aos::EventLoop`.
+    ///
+    /// Consider using [`EventLoopRuntimeHolder.new`] instead, if you're working with an
+    /// `aos::EventLoop` owned (indirectly) by Rust code.
+    ///
+    /// One common pattern is calling this in the constructor of an object whose lifetime is managed
+    /// by C++; C++ doesn't inherit the Rust lifetime but we do have a lot of C++ code that obeys
+    /// these rules implicitly.
     ///
     /// Call [`spawn`] to respond to events. The non-event-driven APIs may be used without calling
     /// this.
@@ -165,27 +293,106 @@
     ///
     /// # Safety
     ///
-    /// `event_loop` must be valid for `'event_loop`. Effectively we want the argument to be
-    /// `&'event_loop mut EventLoop`, but we can't do that (see the module-level documentation for
-    /// details).
+    /// This function is where all the tricky lifetime guarantees to ensure soundness come
+    /// together. It all boils down to choosing `'event_loop` correctly, which is very complicated.
+    /// Here are the rules:
     ///
-    /// This is a tricky thing to guarantee, be very cautious calling this function. It's an unbound
-    /// lifetime so you should probably wrap it in a function that directly attaches a known
-    /// lifetime. One common pattern is calling this in the constructor of an object whose lifetime
-    /// is managed by C++; C++ doesn't inherit the Rust lifetime but we do have a lot of C++ code
-    /// that obeys the rule of destroying the object before the EventLoop, which is equivalent to
-    /// this restriction.
+    /// 1. The `aos::EventLoop` APIs, and any other consumer-facing APIs, of the underlying
+    ///    `aos::EventLoop` *must* be exclusively used by this object, and things it calls, for
+    ///    `'event_loop`.
+    /// 2. `'event_loop` extends until after the last time the underlying `aos::EventLoop` is run.
+    ///    This is often beyond the lifetime of this Rust `EventLoopRuntime` object.
+    /// 3. `'event_loop` must outlive this object, because this object stores references to the
+    ///    underlying `aos::EventLoop`.
+    /// 4. Any other references stored in the underlying `aos::EventLoop` must be valid for
+    ///    `'event_loop`. The easiest way to ensure this is by not using the `aos::EventLoop` before
+    ///    passing it to this object.
     ///
-    /// In Rust terms, this is equivalent to storing `event_loop` in the returned object, which
-    /// will dereference it throughout its lifetime, and the caller must guarantee this is sound.
+    /// Here are some corollaries:
+    ///
+    /// 1. The underlying `aos::EventLoop` must be dropped after this object.
+    /// 2. This object will store various references valid for `'event_loop` with a duration of
+    ///   `'event_loop`, which is safe as long as they're both the same `'event_loop`. Note that
+    ///   this requires this type to be invariant with respect to `'event_loop`.
+    /// 3. `event_loop` (the pointer being passed in) is effectively `Pin`, which is also implied
+    ///    by the underlying `aos::EventLoop` C++ type.
+    /// 4. You cannot create multiple `EventLoopRuntime`s from the same underlying `aos::EventLoop`
+    ///    or otherwise use it from a different application. The first one may create
+    ///    mutable Rust references while the second one expects exclusive ownership, for example.
+    ///
+    /// `aos::EventLoop`'s public API is exclusively for consumers of the event loop. Some
+    /// subclasses extend this API. Additionally, all useful implementations of `aos::EventLoop`
+    /// must have some way to process events. Sometimes this is additional API surface (such as
+    /// `aos::ShmEventLoop`), in other cases comes via other objects holding references to the
+    /// `aos::EventLoop` (such as `aos::SimulatedEventLoopFactory`). This access to run the event
+    /// loop functions independently of the consuming functions in every way except lifetime of the
+    /// `aos::EventLoop`, and may be used independently of `'event_loop`.
+    ///
+    /// ## Discussion of the rules
+    ///
+    /// Rule 1 is similar to rule 3 (they're both similar to mutable borrowing), but rule 1 extends
+    /// for the entire lifetime of the object instead of being limited to the lifetime of an
+    /// individual borrow by an instance of this type. This is similar to the way [`Pin`]'s
+    /// estrictions extend for the entire lifetime of the object, until it is dropped.
+    ///
+    /// Rule 2 and corollaries 2 and 3 go together, and are essential for making [`spawn`]ed tasks
+    /// useful. The `aos::EventLoop` is full of indirect circular references, both within itself
+    /// and via all of the callbacks. This is sound if all of these references have the *exact
+    /// same* Rust lifetime, which is `'event_loop`.
+    ///
+    /// ## Alternatives and why they don't work
+    ///
+    /// Making the argument `Pin<&'event_loop mut EventLoop>` would express some (but not all) of
+    /// these restrictions within the Rust type system. However, having an actual Rust mutable
+    /// reference like that prevents anything else from creating one via other pointers to the
+    /// same object from C++, which is a common operation. See the module-level documentation for
+    /// details.
+    ///
+    /// [`spawn`]ed tasks need to hold `&'event_loop` references to things like channels. Using a
+    /// separate `'config` lifetime wouldn't change much; the tasks still need to do things which
+    /// require them to not outlive something they don't control. This is fundamental to
+    /// self-referential objects, which `aos::EventLoop` is based around, but Rust requires unsafe
+    /// code to manage manually.
+    ///
+    /// ## Final cautions
+    ///
+    /// Following these rules is very tricky. Be very cautious calling this function. It exposes an
+    /// unbound lifetime, which means you should wrap it directly in a function that attaches a
+    /// correct lifetime.
     pub unsafe fn new(event_loop: *mut ffi::aos::EventLoop) -> Self {
         Self(
             // SAFETY: We push all the validity requirements for this up to our caller.
             unsafe { ffi::aos::EventLoopRuntime::new(event_loop) }.within_box(),
-            PhantomData,
+            InvariantLifetime::default(),
         )
     }
 
+    /// Creates a Rust wrapper from the underlying C++ object, with an unbound lifetime.
+    ///
+    /// This may never be useful, but it's here for this big scary comment to explain why it's not
+    /// useful.
+    ///
+    /// # Safety
+    ///
+    /// See [`new`] for safety restrictions on `'event_loop` when calling this. In particular, see
+    /// the note about how tricky doing this correctly is, and remember that for this function the
+    /// event loop in question isn't even an argument to this function so it's even trickier. Also
+    /// note that you cannot call this on the result of [`into_cpp`] without violating those
+    /// restrictions.
+    pub unsafe fn from_cpp(cpp: Pin<Box<ffi::aos::EventLoopRuntime>>) -> Self {
+        Self(cpp, InvariantLifetime::default())
+    }
+
+    /// Extracts the underlying C++ object, without the corresponding Rust lifetime. This is useful
+    /// to stop the propagation of Rust lifetimes without destroying the underlying object which
+    /// contains all the state.
+    ///
+    /// Note that you *cannot* call [`from_cpp`] on the result of this, because that will violate
+    /// [`from_cpp`]'s safety requirements.
+    pub fn into_cpp(self) -> Pin<Box<ffi::aos::EventLoopRuntime>> {
+        self.0
+    }
+
     /// Returns the pointer passed into the constructor.
     ///
     /// The returned value should only be used for destroying it (_after_ `self` is dropped) or
diff --git a/aos/events/simulated_event_loop.rs b/aos/events/simulated_event_loop.rs
index e0be773..ea3a154 100644
--- a/aos/events/simulated_event_loop.rs
+++ b/aos/events/simulated_event_loop.rs
@@ -1,18 +1,12 @@
-use std::{
-    marker::PhantomData,
-    mem::ManuallyDrop,
-    ops::{Deref, DerefMut},
-    pin::Pin,
-    ptr,
-};
+use std::{marker::PhantomData, pin::Pin, ptr};
 
 use autocxx::WithinBox;
 use cxx::UniquePtr;
 
 pub use aos_configuration::{Channel, Configuration, ConfigurationExt, Node};
 use aos_configuration_fbs::aos::Configuration as RustConfiguration;
-use aos_events_event_loop_runtime::EventLoopRuntime;
 pub use aos_events_event_loop_runtime::{CppExitHandle, EventLoop, ExitHandle};
+use aos_events_event_loop_runtime::{EventLoopHolder, EventLoopRuntime, EventLoopRuntimeHolder};
 use aos_flatbuffers::{transmute_table_to, Flatbuffer};
 
 autocxx::include_cpp! (
@@ -44,9 +38,7 @@
 }
 
 impl<'config> SimulatedEventLoopFactory<'config> {
-    pub fn new<'new_config: 'config>(
-        config: &'new_config impl Flatbuffer<RustConfiguration<'static>>,
-    ) -> Self {
+    pub fn new(config: &'config impl Flatbuffer<RustConfiguration<'static>>) -> Self {
         // SAFETY: `_marker` represents the lifetime of this pointer we're handing off to C++ to
         // store.
         let event_loop_factory = unsafe {
@@ -75,7 +67,7 @@
         // * `self` has a valid C++ object.
         // * C++ doesn't need the lifetimes of `name` or `node` to last any longer than this method
         //   call.
-        // * The return value is `'static` because it's wrapped in `unique_ptr`.
+        // * The return value manages its lifetime via `unique_ptr`.
         //
         // Note that dropping `self` before the return value will abort from C++, but this is still
         // sound.
@@ -85,9 +77,26 @@
         }
     }
 
-    /// Creates an [`EventLoopRuntime`] wrapper which also owns its underlying EventLoop.
-    pub fn make_runtime(&mut self, name: &str, node: Option<&Node>) -> SimulatedEventLoopRuntime {
-        SimulatedEventLoopRuntime::new(self.make_event_loop(name, node))
+    /// Creates an [`EventLoopRuntime`] wrapper which also owns its underlying [`EventLoop`].
+    ///
+    /// All setup must be performed with `fun`, which is called before this function returns. `fun`
+    /// may create further objects to use in async functions via [`EventLoop.spawn`] etc, but it is
+    /// the only place to set things up before the EventLoop is run.
+    ///
+    /// Note that dropping the return value will drop this EventLoop.
+    pub fn make_runtime<F>(
+        &mut self,
+        name: &str,
+        node: Option<&Node>,
+        fun: F,
+    ) -> EventLoopRuntimeHolder<SimulatedEventLoopHolder>
+    where
+        F: for<'event_loop> FnOnce(&mut EventLoopRuntime<'event_loop>),
+    {
+        let event_loop = self.make_event_loop(name, node);
+        // SAFETY: We just created this EventLoop, so we are the exclusive owner of it.
+        let holder = unsafe { SimulatedEventLoopHolder::new(event_loop) };
+        EventLoopRuntimeHolder::new(holder, fun)
     }
 
     pub fn make_exit_handle(&mut self) -> ExitHandle {
@@ -103,39 +112,24 @@
     // pub fn spawn_on_startup(&mut self, spawner: impl FnMut());
 }
 
-pub struct SimulatedEventLoopRuntime(ManuallyDrop<EventLoopRuntime<'static>>);
+pub struct SimulatedEventLoopHolder(UniquePtr<EventLoop>);
 
-impl SimulatedEventLoopRuntime {
-    pub fn new(event_loop: UniquePtr<EventLoop>) -> Self {
-        // SAFETY: We own the underlying EventLoop, so `'static` is the correct lifetime. Anything
-        // using this `EventLoopRuntime` will need to borrow the object we're returning, which will
-        // ensure it stays alive.
-        let runtime = unsafe { EventLoopRuntime::<'static>::new(event_loop.into_raw()) };
-        Self(ManuallyDrop::new(runtime))
+impl SimulatedEventLoopHolder {
+    /// SAFETY: `event_loop` must be the exclusive owner of the underlying EventLoop.
+    pub unsafe fn new(event_loop: UniquePtr<EventLoop>) -> Self {
+        Self(event_loop)
     }
 }
 
-impl Drop for SimulatedEventLoopRuntime {
-    fn drop(&mut self) {
-        let event_loop = self.raw_event_loop();
-        // SAFETY: We're not going to touch this field again.
-        unsafe { ManuallyDrop::drop(&mut self.0) };
-        // SAFETY: `new` created this from `into_raw`. We just dropped the only Rust reference to
-        // it.
-        unsafe { UniquePtr::from_raw(event_loop) };
+// SAFETY: The UniquePtr functions we're using here mirror most of the EventLoopHolder requirements
+// exactly. Safety requirements on [`SimulatedEventLoopHolder.new`] take care of the rest.
+unsafe impl EventLoopHolder for SimulatedEventLoopHolder {
+    fn into_raw(self) -> *mut ffi::aos::EventLoop {
+        self.0.into_raw()
     }
-}
 
-impl Deref for SimulatedEventLoopRuntime {
-    type Target = EventLoopRuntime<'static>;
-    fn deref(&self) -> &Self::Target {
-        &self.0
-    }
-}
-
-impl DerefMut for SimulatedEventLoopRuntime {
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        &mut self.0
+    unsafe fn from_raw(raw: *mut ffi::aos::EventLoop) -> Self {
+        Self(UniquePtr::from_raw(raw))
     }
 }
 
@@ -172,41 +166,49 @@
         let mut event_loop_factory = SimulatedEventLoopFactory::new(&config);
         {
             let pi1 = Some(config.message().get_node("pi1").unwrap());
-            let mut runtime1 = event_loop_factory.make_runtime("runtime1", pi1);
-            let channel = runtime1
-                .configuration()
-                .get_channel("/test", "aos.examples.Ping", "test", pi1)
-                .unwrap();
-            let mut runtime2 = event_loop_factory.make_runtime("runtime2", pi1);
 
-            {
-                let mut watcher = runtime1.make_raw_watcher(channel);
-                let exit_handle = event_loop_factory.make_exit_handle();
-                runtime1.spawn(async move {
-                    watcher.next().await;
-                    GLOBAL_STATE.with(|g| {
-                        let g = &mut *g.borrow_mut();
-                        g.watcher_count = g.watcher_count + 1;
+            let exit_handle = event_loop_factory.make_exit_handle();
+            let _runtime1 = {
+                let pi1_ref = &pi1;
+                event_loop_factory.make_runtime("runtime1", pi1, move |runtime1| {
+                    assert!(pi1_ref.unwrap().has_name());
+                    let channel = runtime1
+                        .get_raw_channel("/test", "aos.examples.Ping")
+                        .unwrap();
+                    let mut watcher = runtime1.make_raw_watcher(channel);
+                    runtime1.spawn(async move {
+                        watcher.next().await;
+                        GLOBAL_STATE.with(|g| {
+                            let g = &mut *g.borrow_mut();
+                            g.watcher_count = g.watcher_count + 1;
+                        });
+                        exit_handle.exit().await
                     });
-                    exit_handle.exit().await
-                });
-            }
+                })
+            };
 
-            {
-                let mut sender = runtime2.make_raw_sender(channel);
-                runtime2.spawn(async move {
-                    GLOBAL_STATE.with(|g| {
-                        let g = &mut *g.borrow_mut();
-                        g.startup_count = g.startup_count + 1;
+            let _runtime2 = {
+                let pi1_ref = &pi1;
+                event_loop_factory.make_runtime("runtime2", pi1, |runtime2| {
+                    assert!(pi1_ref.unwrap().has_name());
+                    let channel = runtime2
+                        .get_raw_channel("/test", "aos.examples.Ping")
+                        .unwrap();
+                    let mut sender = runtime2.make_raw_sender(channel);
+                    runtime2.spawn(async move {
+                        GLOBAL_STATE.with(|g| {
+                            let g = &mut *g.borrow_mut();
+                            g.startup_count = g.startup_count + 1;
+                        });
+
+                        let mut builder = sender.make_builder();
+                        let ping = PingBuilder::new(builder.fbb()).finish();
+                        // SAFETY: We're using the correct message type.
+                        unsafe { builder.send(ping) }.expect("send should succeed");
+                        pending().await
                     });
-
-                    let mut builder = sender.make_builder();
-                    let ping = PingBuilder::new(builder.fbb()).finish();
-                    // SAFETY: We're using the correct message type.
-                    unsafe { builder.send(ping) }.expect("send should succeed");
-                    pending().await
-                });
-            }
+                })
+            };
 
             GLOBAL_STATE.with(|g| {
                 let g = g.borrow();
diff --git a/frc971/control_loops/BUILD b/frc971/control_loops/BUILD
index a62b45f..3cdb6ab 100644
--- a/frc971/control_loops/BUILD
+++ b/frc971/control_loops/BUILD
@@ -199,6 +199,13 @@
     ],
 )
 
+flatbuffer_cc_library(
+    name = "can_falcon_fbs",
+    srcs = [
+        "can_falcon.fbs",
+    ],
+)
+
 cc_test(
     name = "position_sensor_sim_test",
     srcs = [
diff --git a/frc971/control_loops/can_falcon.fbs b/frc971/control_loops/can_falcon.fbs
new file mode 100644
index 0000000..2adbae0
--- /dev/null
+++ b/frc971/control_loops/can_falcon.fbs
@@ -0,0 +1,26 @@
+namespace frc971.control_loops;
+
+table CANFalcon {
+  // The CAN id of the falcon
+  id:int (id: 0);
+
+  // In Amps
+  supply_current:float (id: 1);
+
+  // In Amps
+  // Stator current where positive current means torque is applied in
+  // the motor's forward direction as determined by its Inverted setting.
+  torque_current:float (id: 2);
+
+  // In Volts
+  supply_voltage:float (id: 3);
+
+  // In degrees Celsius
+  device_temp:float (id: 4);
+
+  // In meters traveled on the drivetrain
+  position:float (id: 5);
+
+  // Nominal range is -1 to 1, but can be -2 to +2
+  duty_cycle: float (id: 6);
+}
diff --git a/frc971/control_loops/drivetrain/BUILD b/frc971/control_loops/drivetrain/BUILD
index 86c1ec0..29a0e1d 100644
--- a/frc971/control_loops/drivetrain/BUILD
+++ b/frc971/control_loops/drivetrain/BUILD
@@ -8,6 +8,13 @@
 package(default_visibility = ["//visibility:public"])
 
 flatbuffer_cc_library(
+    name = "drivetrain_can_position_fbs",
+    srcs = ["drivetrain_can_position.fbs"],
+    gen_reflections = 1,
+    deps = ["//frc971/control_loops:can_falcon_fbs"],
+)
+
+flatbuffer_cc_library(
     name = "spline_goal_fbs",
     srcs = ["spline_goal.fbs"],
     gen_reflections = 1,
@@ -352,11 +359,11 @@
         ":drivetrain_config",
         ":drivetrain_states",
         ":gear",
+        ":spline_goal_fbs",
         "//aos:math",
-        "//frc971/control_loops:polytope",
         "//frc971/control_loops:coerce_goal",
         "//frc971/control_loops:control_loops_fbs",
-        ":spline_goal_fbs",
+        "//frc971/control_loops:polytope",
         "//frc971/control_loops:state_feedback_loop",
     ] + select({
         "@platforms//os:linux": [
@@ -364,8 +371,8 @@
             ":drivetrain_output_fbs",
             ":drivetrain_position_fbs",
             ":drivetrain_status_fbs",
-            "//frc971/input:robot_state_fbs",
             "//aos/util:log_interval",
+            "//frc971/input:robot_state_fbs",
         ],
         "@platforms//os:none": [
             ":drivetrain_goal_float_fbs",
@@ -469,8 +476,8 @@
         "//frc971/control_loops:control_loops_fbs",
         "//frc971/control_loops:state_feedback_loop",
         "//frc971/queues:gyro_fbs",
-        "//frc971/wpilib:imu_fbs",
         "//frc971/wpilib:imu_batch_fbs",
+        "//frc971/wpilib:imu_fbs",
         "//y2016:constants",
         "//y2016/control_loops/drivetrain:polydrivetrain_plants",
     ] + cpu_select({
@@ -498,17 +505,17 @@
     target_compatible_with = ["@platforms//os:linux"],
     deps = [
         ":drivetrain_config",
-        ":trajectory_generator",
-        ":drivetrain_lib",
-        ":localizer_fbs",
         ":drivetrain_goal_fbs",
-        ":drivetrain_status_fbs",
-        ":drivetrain_position_fbs",
+        ":drivetrain_lib",
         ":drivetrain_output_fbs",
+        ":drivetrain_position_fbs",
+        ":drivetrain_status_fbs",
         ":drivetrain_test_lib",
-        "//frc971/control_loops:control_loop_test",
+        ":localizer_fbs",
+        ":trajectory_generator",
         "//aos/events/logging:log_writer",
         "//aos/testing:googletest",
+        "//frc971/control_loops:control_loop_test",
         "//frc971/queues:gyro_fbs",
         "//frc971/wpilib:imu_fbs",
     ] + cpu_select({
@@ -633,8 +640,8 @@
     target_compatible_with = ["@platforms//os:linux"],
     deps = [
         ":distance_spline",
-        "//aos/testing:googletest",
         "//aos:flatbuffers",
+        "//aos/testing:googletest",
         "//aos/testing:test_shm",
         "@com_github_gflags_gflags//:gflags",
     ] + cpu_select({
@@ -712,8 +719,8 @@
     linkstatic = True,
     target_compatible_with = ["@platforms//os:linux"],
     deps = [
-        ":trajectory",
         ":drivetrain_test_lib",
+        ":trajectory",
         "//aos/testing:googletest",
         "//aos/testing:test_shm",
         "//y2016:constants",
diff --git a/frc971/control_loops/drivetrain/drivetrain_can_position.fbs b/frc971/control_loops/drivetrain/drivetrain_can_position.fbs
new file mode 100644
index 0000000..192f23d
--- /dev/null
+++ b/frc971/control_loops/drivetrain/drivetrain_can_position.fbs
@@ -0,0 +1,18 @@
+include "frc971/control_loops/can_falcon.fbs";
+namespace frc971.control_loops.drivetrain;
+
+// CAN readings from the CAN sensor reader loop
+table CANPosition {
+  falcons: [CANFalcon] (id: 0);
+
+  // The timestamp of the measurement on the canivore clock in nanoseconds
+  // This will have less jitter than the
+  // timestamp of the message being sent out.
+  timestamp:int64 (id: 1);
+
+  // The ctre::phoenix::StatusCode of the measurement
+  // Should be OK = 0
+  status:int (id: 2);
+}
+
+root_type CANPosition;
diff --git a/frc971/control_loops/drivetrain/swerve/BUILD b/frc971/control_loops/drivetrain/swerve/BUILD
new file mode 100644
index 0000000..06ba36a
--- /dev/null
+++ b/frc971/control_loops/drivetrain/swerve/BUILD
@@ -0,0 +1,15 @@
+load("@com_github_google_flatbuffers//:build_defs.bzl", "flatbuffer_cc_library")
+
+package(default_visibility = ["//visibility:public"])
+
+flatbuffer_cc_library(
+    name = "swerve_drivetrain_output_fbs",
+    srcs = ["swerve_drivetrain_output.fbs"],
+    gen_reflections = 1,
+)
+
+flatbuffer_cc_library(
+    name = "swerve_drivetrain_position_fbs",
+    srcs = ["swerve_drivetrain_position.fbs"],
+    gen_reflections = 1,
+)
diff --git a/frc971/control_loops/drivetrain/swerve/swerve_drivetrain_output.fbs b/frc971/control_loops/drivetrain/swerve/swerve_drivetrain_output.fbs
new file mode 100644
index 0000000..43ba0ed
--- /dev/null
+++ b/frc971/control_loops/drivetrain/swerve/swerve_drivetrain_output.fbs
@@ -0,0 +1,16 @@
+namespace frc971.control_loops.drivetrain.swerve;
+
+table SwerveModuleOutput {
+  // Current in Amps.
+  rotation_current:double (id: 0);
+  translation_current:double (id: 1);
+}
+
+table Output {
+  front_left_output:SwerveModuleOutput (id: 0);
+  front_right_output:SwerveModuleOutput (id: 1);
+  back_left_output:SwerveModuleOutput (id: 2);
+  back_right_output:SwerveModuleOutput (id: 3);
+}
+
+root_type Output;
diff --git a/frc971/control_loops/drivetrain/swerve/swerve_drivetrain_position.fbs b/frc971/control_loops/drivetrain/swerve/swerve_drivetrain_position.fbs
new file mode 100644
index 0000000..e0f5571
--- /dev/null
+++ b/frc971/control_loops/drivetrain/swerve/swerve_drivetrain_position.fbs
@@ -0,0 +1,22 @@
+namespace frc971.control_loops.drivetrain.swerve;
+
+table SwerveModulePosition {
+  // Rotation in radians
+  rotation_encoder:double (id: 0);
+  // Translation in meters
+  translation_encoder:double (id: 1);
+
+  // Speed in radians/s
+  rotation_speed:double (id: 2);
+  // Speed in m/s
+  translation_speed:double (id: 3);
+}
+
+table Position {
+  front_left_position:SwerveModulePosition (id: 0);
+  front_right_position:SwerveModulePosition (id: 1);
+  back_left_position:SwerveModulePosition (id: 2);
+  back_right_position:SwerveModulePosition (id: 3);
+}
+
+root_type Position;
diff --git a/y2023/BUILD b/y2023/BUILD
index fa39d3c..ed8f347 100644
--- a/y2023/BUILD
+++ b/y2023/BUILD
@@ -213,7 +213,7 @@
         "//y2023/control_loops/superstructure:superstructure_goal_fbs",
         "//y2023/control_loops/drivetrain:target_selector_hint_fbs",
         "//y2023/control_loops/drivetrain:target_selector_status_fbs",
-        "//y2023/control_loops/drivetrain:drivetrain_can_position_fbs",
+        "//frc971/control_loops/drivetrain:drivetrain_can_position_fbs",
         "//y2023/control_loops/superstructure:superstructure_output_fbs",
         "//y2023/control_loops/superstructure:superstructure_position_fbs",
         "//y2023/control_loops/superstructure:superstructure_status_fbs",
@@ -286,6 +286,7 @@
         "//frc971/autonomous:auto_mode_fbs",
         "//frc971/control_loops:control_loop",
         "//frc971/control_loops:control_loops_fbs",
+        "//frc971/control_loops/drivetrain:drivetrain_can_position_fbs",
         "//frc971/control_loops/drivetrain:drivetrain_position_fbs",
         "//frc971/input:robot_state_fbs",
         "//frc971/queues:gyro_fbs",
@@ -304,7 +305,6 @@
         "//third_party:phoenix",
         "//third_party:phoenixpro",
         "//third_party:wpilib",
-        "//y2023/control_loops/drivetrain:drivetrain_can_position_fbs",
         "//y2023/control_loops/superstructure:led_indicator_lib",
         "//y2023/control_loops/superstructure:superstructure_output_fbs",
         "//y2023/control_loops/superstructure:superstructure_position_fbs",
diff --git a/y2023/control_loops/drivetrain/BUILD b/y2023/control_loops/drivetrain/BUILD
index 063e972..f6b5655 100644
--- a/y2023/control_loops/drivetrain/BUILD
+++ b/y2023/control_loops/drivetrain/BUILD
@@ -116,15 +116,6 @@
 )
 
 flatbuffer_cc_library(
-    name = "drivetrain_can_position_fbs",
-    srcs = [
-        "drivetrain_can_position.fbs",
-    ],
-    gen_reflections = 1,
-    visibility = ["//visibility:public"],
-)
-
-flatbuffer_cc_library(
     name = "target_selector_status_fbs",
     srcs = [
         ":target_selector_status.fbs",
diff --git a/y2023/control_loops/drivetrain/drivetrain_can_position.fbs b/y2023/control_loops/drivetrain/drivetrain_can_position.fbs
deleted file mode 100644
index 34fbf12..0000000
--- a/y2023/control_loops/drivetrain/drivetrain_can_position.fbs
+++ /dev/null
@@ -1,42 +0,0 @@
-namespace y2023.control_loops.drivetrain;
-
-table CANFalcon {
-  // The CAN id of the falcon
-  id:int (id: 0);
-
-  // In Amps
-  supply_current:float (id: 1);
-
-  // In Amps
-  // Stator current where positive current means torque is applied in
-  // the motor's forward direction as determined by its Inverted setting.
-  torque_current:float (id: 2);
-
-  // In Volts
-  supply_voltage:float (id: 3);
-
-  // In degrees Celsius
-  device_temp:float (id: 4);
-
-  // In meters traveled on the drivetrain
-  position:float (id: 5);
-
-  // Nominal range is -1 to 1, but can be -2 to +2
-  duty_cycle: float (id: 6);
-}
-
-// CAN readings from the CAN sensor reader loop
-table CANPosition {
-  falcons: [CANFalcon] (id: 0);
-
-  // The timestamp of the measurement on the canivore clock in nanoseconds
-  // This will have less jitter than the
-  // timestamp of the message being sent out.
-  timestamp:int64 (id: 1);
-
-  // The ctre::phoenix::StatusCode of the measurement
-  // Should be OK = 0
-  status:int (id: 2);
-}
-
-root_type CANPosition;
diff --git a/y2023/control_loops/superstructure/BUILD b/y2023/control_loops/superstructure/BUILD
index afca18b..861bbf8 100644
--- a/y2023/control_loops/superstructure/BUILD
+++ b/y2023/control_loops/superstructure/BUILD
@@ -58,8 +58,8 @@
     deps = [
         "//frc971/control_loops:control_loops_fbs",
         "//frc971/control_loops:profiled_subsystem_fbs",
+        "//frc971/control_loops/drivetrain:drivetrain_can_position_fbs",
         "//frc971/vision:calibration_fbs",
-        "//y2023/control_loops/drivetrain:drivetrain_can_position_fbs",
     ],
 )
 
@@ -103,12 +103,12 @@
         "//aos/events:event_loop",
         "//frc971/constants:constants_sender_lib",
         "//frc971/control_loops:control_loop",
+        "//frc971/control_loops/drivetrain:drivetrain_can_position_fbs",
         "//frc971/control_loops/drivetrain:drivetrain_status_fbs",
         "//frc971/shooter_interpolation:interpolation",
         "//y2023:constants",
         "//y2023/constants:constants_fbs",
         "//y2023/constants:simulated_constants_sender",
-        "//y2023/control_loops/drivetrain:drivetrain_can_position_fbs",
         "//y2023/control_loops/superstructure/arm",
         "//y2023/control_loops/superstructure/arm:arm_trajectories_fbs",
     ],
diff --git a/y2023/control_loops/superstructure/arm/BUILD b/y2023/control_loops/superstructure/arm/BUILD
index 39e549b..a742c50 100644
--- a/y2023/control_loops/superstructure/arm/BUILD
+++ b/y2023/control_loops/superstructure/arm/BUILD
@@ -14,9 +14,9 @@
         ":generated_graph",
         "//frc971/control_loops/double_jointed_arm:ekf",
         "//frc971/control_loops/double_jointed_arm:graph",
+        "//frc971/control_loops/drivetrain:drivetrain_can_position_fbs",
         "//frc971/zeroing",
         "//y2023:constants",
-        "//y2023/control_loops/drivetrain:drivetrain_can_position_fbs",
         "//y2023/control_loops/superstructure:superstructure_position_fbs",
         "//y2023/control_loops/superstructure:superstructure_status_fbs",
         "//y2023/control_loops/superstructure/arm:arm_constants",
diff --git a/y2023/control_loops/superstructure/superstructure.h b/y2023/control_loops/superstructure/superstructure.h
index 1100b86..fdfef4e 100644
--- a/y2023/control_loops/superstructure/superstructure.h
+++ b/y2023/control_loops/superstructure/superstructure.h
@@ -5,10 +5,10 @@
 #include "aos/json_to_flatbuffer.h"
 #include "frc971/constants/constants_sender_lib.h"
 #include "frc971/control_loops/control_loop.h"
+#include "frc971/control_loops/drivetrain/drivetrain_can_position_generated.h"
 #include "frc971/control_loops/drivetrain/drivetrain_status_generated.h"
 #include "y2023/constants.h"
 #include "y2023/constants/constants_generated.h"
-#include "y2023/control_loops/drivetrain/drivetrain_can_position_generated.h"
 #include "y2023/control_loops/superstructure/arm/arm.h"
 #include "y2023/control_loops/superstructure/arm/arm_trajectories_generated.h"
 #include "y2023/control_loops/superstructure/end_effector.h"
diff --git a/y2023/wpilib_interface.cc b/y2023/wpilib_interface.cc
index 978d6e5..d043e6f 100644
--- a/y2023/wpilib_interface.cc
+++ b/y2023/wpilib_interface.cc
@@ -40,6 +40,7 @@
 #include "aos/util/phased_loop.h"
 #include "aos/util/wrapping_counter.h"
 #include "frc971/autonomous/auto_mode_generated.h"
+#include "frc971/control_loops/drivetrain/drivetrain_can_position_generated.h"
 #include "frc971/control_loops/drivetrain/drivetrain_position_generated.h"
 #include "frc971/input/robot_state_generated.h"
 #include "frc971/queues/gyro_generated.h"
@@ -57,7 +58,6 @@
 #include "frc971/wpilib/wpilib_robot_base.h"
 #include "y2023/can_configuration_generated.h"
 #include "y2023/constants.h"
-#include "y2023/control_loops/drivetrain/drivetrain_can_position_generated.h"
 #include "y2023/control_loops/superstructure/led_indicator.h"
 #include "y2023/control_loops/superstructure/superstructure_output_generated.h"
 #include "y2023/control_loops/superstructure/superstructure_position_generated.h"
@@ -224,9 +224,9 @@
 
   ctre::phoenixpro::hardware::TalonFX *talon() { return &talon_; }
 
-  flatbuffers::Offset<drivetrain::CANFalcon> WritePosition(
+  flatbuffers::Offset<frc971::control_loops::CANFalcon> WritePosition(
       flatbuffers::FlatBufferBuilder *fbb) {
-    drivetrain::CANFalcon::Builder builder(*fbb);
+    frc971::control_loops::CANFalcon::Builder builder(*fbb);
     builder.add_id(device_id_);
     builder.add_device_temp(device_temp());
     builder.add_supply_voltage(supply_voltage());
@@ -289,7 +289,9 @@
       : event_loop_(event_loop),
         signals_(signals_registry.begin(), signals_registry.end()),
         can_position_sender_(
-            event_loop->MakeSender<drivetrain::CANPosition>("/drivetrain")),
+            event_loop
+                ->MakeSender<frc971::control_loops::drivetrain::CANPosition>(
+                    "/drivetrain")),
         roller_falcon_data_(std::nullopt) {
     event_loop->SetRuntimeRealtimePriority(40);
     event_loop->SetRuntimeAffinity(aos::MakeCpusetFromCpus({1}));
@@ -340,7 +342,8 @@
       falcon->RefreshNontimesyncedSignals();
     }
 
-    aos::SizedArray<flatbuffers::Offset<drivetrain::CANFalcon>, kCANFalconCount>
+    aos::SizedArray<flatbuffers::Offset<frc971::control_loops::CANFalcon>,
+                    kCANFalconCount>
         falcons;
 
     for (auto falcon : {right_front_, right_back_, right_under_, left_front_,
@@ -349,11 +352,14 @@
     }
 
     auto falcons_list =
-        builder.fbb()->CreateVector<flatbuffers::Offset<drivetrain::CANFalcon>>(
-            falcons);
+        builder.fbb()
+            ->CreateVector<
+                flatbuffers::Offset<frc971::control_loops::CANFalcon>>(falcons);
 
-    drivetrain::CANPosition::Builder can_position_builder =
-        builder.MakeBuilder<drivetrain::CANPosition>();
+    frc971::control_loops::drivetrain::CANPosition::Builder
+        can_position_builder =
+            builder
+                .MakeBuilder<frc971::control_loops::drivetrain::CANPosition>();
 
     can_position_builder.add_falcons(falcons_list);
     can_position_builder.add_timestamp(right_front_->GetTimestamp());
@@ -379,7 +385,8 @@
   aos::EventLoop *event_loop_;
 
   const std::vector<ctre::phoenixpro::BaseStatusSignalValue *> signals_;
-  aos::Sender<drivetrain::CANPosition> can_position_sender_;
+  aos::Sender<frc971::control_loops::drivetrain::CANPosition>
+      can_position_sender_;
 
   std::shared_ptr<Falcon> right_front_, right_back_, right_under_, left_front_,
       left_back_, left_under_, roller_falcon_;
diff --git a/y2023/y2023_roborio.json b/y2023/y2023_roborio.json
index 4af3d34..33d9904 100644
--- a/y2023/y2023_roborio.json
+++ b/y2023/y2023_roborio.json
@@ -154,7 +154,7 @@
     },
     {
       "name": "/drivetrain",
-      "type": "y2023.control_loops.drivetrain.CANPosition",
+      "type": "frc971.control_loops.drivetrain.CANPosition",
       "source_node": "roborio",
       "frequency": 220,
       "num_senders": 2,