From 14e95131b0a244a7ffded578a4a3f55c012fe457 Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Wed, 12 Aug 2026 09:46:00 -0400 Subject: [PATCH] Add example of humility as a library with `async-trait` This was annoying to debug. Mabe we can make it better. --- Cargo.lock | 82 +++++++++++++++++++++++++++++++++-- Cargo.toml | 1 + examples/async/Cargo.toml | 16 +++++++ examples/async/src/main.rs | 88 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 184 insertions(+), 3 deletions(-) create mode 100644 examples/async/Cargo.toml create mode 100644 examples/async/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index ed6c57a9c..dcd623c89 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -172,6 +172,17 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "async-trait" +version = "0.1.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + [[package]] name = "atomic" version = "0.6.1" @@ -639,7 +650,7 @@ version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] @@ -1870,6 +1881,22 @@ dependencies = [ "num-traits", ] +[[package]] +name = "humility-async" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "humility-core", + "humility-hiffy", + "humility-idol", + "humility-probes-core", + "idol", + "slog", + "thiserror 2.0.18", + "tokio", +] + [[package]] name = "humility-auxflash" version = "0.1.0" @@ -4117,7 +4144,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] @@ -5335,6 +5362,16 @@ dependencies = [ "anstream 0.6.21", ] +[[package]] +name = "socket2" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + [[package]] name = "spd" version = "0.1.0" @@ -5459,6 +5496,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "synstructure" version = "0.13.2" @@ -5730,6 +5778,34 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "tokio" +version = "1.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" +dependencies = [ + "bytes", + "libc", + "mio 1.2.0", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + [[package]] name = "toml" version = "1.1.2+spec-1.1.0" @@ -6302,7 +6378,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e500974a2..d27da037b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ [workspace] default-members = ["humility-bin"] members = [ + "examples/*", "humility-arch-arm", "humility-arch-cortex", "humility-auxflash", diff --git a/examples/async/Cargo.toml b/examples/async/Cargo.toml new file mode 100644 index 000000000..4a2700d9c --- /dev/null +++ b/examples/async/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "humility-async" +version = "0.1.0" +edition.workspace = true + +[dependencies] +async-trait = "0.1.89" +tokio = { version = "1", features = ["full"] } +humility.workspace = true +humility-probes-core.workspace = true +humility-hiffy.workspace = true +humility-idol.workspace = true +anyhow.workspace = true +idol.workspace = true +thiserror.workspace = true +slog.workspace = true diff --git a/examples/async/src/main.rs b/examples/async/src/main.rs new file mode 100644 index 000000000..66b0fb96b --- /dev/null +++ b/examples/async/src/main.rs @@ -0,0 +1,88 @@ +/// Demonstrating using humiltiy as a library with async traits +/// +/// This ended up being non-obvious when this was used in another project. +/// This is designed to be a straightfoward example to play around with. +use humility::hubris::HubrisArchive; +use humility_idol::HubrisIdol; +use humility_probes_core::HubrisAttach; +use slog::Logger; +use std::sync::{Arc, Mutex}; + +#[derive(Debug, thiserror::Error)] +enum WrappedError { + #[error("HUMILITY_ARCHIVE unset")] + HumilityArchiveUnset(#[source] std::env::VarError), + #[error("HUMILTIY_PROBE unset")] + HumilityProbeUnset(#[source] std::env::VarError), + #[error("Hubris archive load failed")] + HubrisArchive(#[source] anyhow::Error), + #[error("probe attach failed")] + ProbeAttach(#[source] anyhow::Error), +} + +struct MyWrapper { + // This does not work! `HubrisArchive` cannot be `Sync` because + // other struct members like addr2line/gimli are not `Sync`. + // You can experiment to see the full error. + //hubris: HubrisArchive, + hubris: Arc>, + log: Logger, +} + +impl MyWrapper { + fn new(log: &Logger) -> Result { + let hubris = std::env::var("HUMILITY_ARCHIVE") + .map_err(WrappedError::HumilityArchiveUnset)?; + + let hubris = HubrisArchive::load_from_path(&hubris, &log) + .map_err(WrappedError::HubrisArchive)?; + + let log = log.new(slog::o!()); + + Ok(Self { hubris: Arc::new(Mutex::new(hubris)), log }) + } +} + +#[async_trait::async_trait] +trait MyTrait { + async fn do_something(&self) -> Result<(), WrappedError>; +} + +#[async_trait::async_trait] +impl MyTrait for MyWrapper { + async fn do_something(&self) -> Result<(), WrappedError> { + let probe = std::env::var("HUMILITY_PROBE") + .map_err(WrappedError::HumilityProbeUnset)?; + + let hubris = self.hubris.lock().unwrap(); + let mut core = hubris + .attach_probe(&probe, 8000, &self.log) + .map_err(WrappedError::ProbeAttach)?; + + let get_op = hubris.get_idol_command("Sequencer.get_state").unwrap(); + + let mut context = humility_hiffy::HiffyContext::new( + &hubris, + &mut core, + std::time::Duration::from_millis(10000), + &self.log, + ) + .unwrap(); + + let _state = + context.call::(&mut core, &get_op, &[], None, None).unwrap(); + + Ok(()) + } +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let log = humility::log::init(false); + + let wrapper = MyWrapper::new(&log).unwrap(); + + wrapper.do_something().await.unwrap(); + + Ok(()) +}