From db818ad4c66122790537cfa1c48de0e8542ed6f0 Mon Sep 17 00:00:00 2001 From: Matt Keeter Date: Thu, 23 Apr 2026 16:15:55 -0400 Subject: [PATCH 1/2] Make some dopple types generic --- humility-doppel/src/lib.rs | 41 +++++++----------------- load_derive/src/lib.rs | 64 +++++++++++++++++++++++++++++++++++--- 2 files changed, 71 insertions(+), 34 deletions(-) diff --git a/humility-doppel/src/lib.rs b/humility-doppel/src/lib.rs index f5e32e080..dad4ecc10 100644 --- a/humility-doppel/src/lib.rs +++ b/humility-doppel/src/lib.rs @@ -387,38 +387,23 @@ pub enum CounterVariant { } #[derive(Clone, Debug, Load)] -pub struct ClaimOnceCell { - pub cell: UnsafeCell, +pub struct ClaimOnceCell { + pub cell: UnsafeCell, } #[derive(Clone, Debug, Load)] -pub struct StaticCell { - pub cell: UnsafeCell, +pub struct StaticCell { + pub cell: UnsafeCell, } #[derive(Clone, Debug, Load)] -pub struct UnsafeCell { - pub value: Value, -} - -#[derive(Clone, Debug)] -pub struct MaybeUninit { +pub struct UnsafeCell { pub value: T, } -impl humility::reflect::Load for MaybeUninit { - fn from_value(v: &Value) -> Result { - let v_struct = v.as_struct()?; - anyhow::ensure!( - v_struct.name().starts_with("MaybeUninit"), - "expected MaybeUninit, got {:?}", - v_struct.name() - ); - let value = v_struct - .get("value") - .ok_or_else(|| anyhow!("missing `value` member"))?; - T::from_value(value).map(|value| Self { value }) - } +#[derive(Clone, Debug, Load)] +pub struct MaybeUninit { + pub value: T, } /// Double of the struct from `udprpc` @@ -571,13 +556,9 @@ impl humility::reflect::Load for CounterVariant { let counter = value.as_struct()?; if counter.name().starts_with("AtomicU32") { - let cell = UnsafeCell::from_value(&counter["v"])?; - return cell - .value - .as_base()? - .as_u32() - .map(Self::Single) - .ok_or_else(|| anyhow::anyhow!("ringbuf count must be a u32")); + let cell = UnsafeCell::::from_value(&counter["v"]) + .context("ringbuf count must be a u32")?; + return Ok(Self::Single(cell.value)); } Ok(Self::Nested(Counters::from_value(value)?)) diff --git a/load_derive/src/lib.rs b/load_derive/src/lib.rs index 5353da204..383b75dcc 100644 --- a/load_derive/src/lib.rs +++ b/load_derive/src/lib.rs @@ -12,10 +12,10 @@ pub fn load_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ts = match &input.data { syn::Data::Struct(data) => match &data.fields { syn::Fields::Named(fields) => { - gen_named_struct(&input.ident, fields) + gen_named_struct(&input.ident, &input.generics, fields) } syn::Fields::Unnamed(fields) => { - gen_unnamed_struct(&input.ident, fields) + gen_unnamed_struct(&input.ident, &input.generics, fields) } syn::Fields::Unit => { unimplemented!( @@ -31,6 +31,56 @@ pub fn load_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { proc_macro::TokenStream::from(ts) } +/// Returns generics to go by the `impl` keyword (e.g. ``) +fn impl_generics(g: &syn::Generics) -> Option { + if g.lt_token.is_some() { + let iter = g + .params + .iter() + .flat_map(|p| { + if let syn::GenericParam::Type(t) = p { + let mut t = t.clone(); + t.attrs.clear(); + t.eq_token = None; + t.default = None; + Some(quote_spanned!(p.span()=>#t)) + } else { + None + } + }) + .collect::>(); + Some(quote_spanned!(g.span()=><#(#iter),*>)) + } else { + None + } +} + +/// Returns generics to go by the `struct` keyword (e.g. ``) +fn struct_generics(g: &syn::Generics) -> Option { + if g.lt_token.is_some() { + let iter = g + .params + .iter() + .flat_map(|p| { + if let syn::GenericParam::Type(t) = p { + let mut t = t.clone(); + t.attrs.clear(); + t.colon_token = None; + t.bounds.clear(); + t.eq_token = None; + t.default = None; + Some(quote_spanned!(p.span()=>#t)) + } else { + None + } + }) + .collect::>(); + Some(quote_spanned!(g.span()=><#(#iter),*>)) + } else { + None + } +} + fn gen_enum( ident: &syn::Ident, data: &syn::DataEnum, @@ -128,6 +178,7 @@ fn gen_enum( fn gen_named_struct( ident: &syn::Ident, + generics: &syn::Generics, fields: &syn::FieldsNamed, ) -> proc_macro2::TokenStream { let field_name_strs = fields.named.iter().map(|fld| { @@ -144,8 +195,10 @@ fn gen_named_struct( }); let field_defs = field_defs.collect::(); + let impl_generics = impl_generics(generics); + let struct_generics = struct_generics(generics); quote_spanned!(ident.span()=> - impl humility::reflect::Load for #ident { + impl #impl_generics humility::reflect::Load for #ident #struct_generics { fn from_value(v: &humility::reflect::Value) -> anyhow::Result { let v = v.as_struct()?; v.check_members(&[#field_name_strs])?; @@ -159,6 +212,7 @@ fn gen_named_struct( fn gen_unnamed_struct( ident: &syn::Ident, + generics: &syn::Generics, fields: &syn::FieldsUnnamed, ) -> proc_macro2::TokenStream { let len = fields.unnamed.len(); @@ -177,8 +231,10 @@ fn gen_unnamed_struct( }); let field_uses = field_uses.collect::(); + let impl_generics = impl_generics(generics); + let struct_generics = struct_generics(generics); quote_spanned!(ident.span()=> - impl humility::reflect::Load for #ident { + impl #impl_generics humility::reflect::Load for #ident #struct_generics { fn from_value(v: &humility::reflect::Value) -> anyhow::Result { let v = v.as_tuple()?; if v.len() != #len { From 356f0190c57f76b556cf735c0694a04f6285f69c Mon Sep 17 00:00:00 2001 From: Matt Keeter Date: Thu, 23 Apr 2026 16:43:57 -0400 Subject: [PATCH 2/2] Use generic ClaimOnceCell where possible --- cmd/host/src/lib.rs | 4 ++-- cmd/ringbuf/src/lib.rs | 6 +++--- humility-spd/src/lib.rs | 19 ++++++------------- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/cmd/host/src/lib.rs b/cmd/host/src/lib.rs index 1b6e0da84..3bd6d2963 100644 --- a/cmd/host/src/lib.rs +++ b/cmd/host/src/lib.rs @@ -184,9 +184,9 @@ fn read_qualified_state_buf( return Ok(None); }; - let as_static_cell: doppel::ClaimOnceCell = + let as_static_cell: doppel::ClaimOnceCell = reflect::read_variable(hubris, core, var)?; - Ok(Some(HostStateBuf::from_value(&as_static_cell.cell.value)?)) + Ok(Some(as_static_cell.cell.value)) } fn print_escaped_ascii(mut bytes: &[u8]) { diff --git a/cmd/ringbuf/src/lib.rs b/cmd/ringbuf/src/lib.rs index 01dbf1dff..212056762 100644 --- a/cmd/ringbuf/src/lib.rs +++ b/cmd/ringbuf/src/lib.rs @@ -145,9 +145,9 @@ fn ringbuf_dump( Ringbuf::from_value(&ringbuf_val).map(|r| (Some(r), None)) }) .or_else(|_e| { - let cell: StaticCell = StaticCell::from_value(&ringbuf_val)?; - let ringbuf = Ringbuf::from_value(&cell.cell.value)?; - Ok::<_, anyhow::Error>((Some(ringbuf), None)) + let cell: StaticCell = + StaticCell::from_value(&ringbuf_val)?; + Ok::<_, anyhow::Error>((Some(cell.cell.value), None)) })?; if let (Some(mut counters), false) = (counters, no_totals) { diff --git a/humility-spd/src/lib.rs b/humility-spd/src/lib.rs index 111864b3c..28b46709e 100644 --- a/humility-spd/src/lib.rs +++ b/humility-spd/src/lib.rs @@ -5,7 +5,7 @@ use humility::hubris::*; use humility::{ reflect, - reflect::{Base, Load, Value}, + reflect::{Base, Value}, }; use humility_doppel as doppel; @@ -66,18 +66,11 @@ pub fn spd_lookup( .collect(), )) } else if let Ok(var) = hubris.lookup_qualified_variable(PACKRAT_BUF_NAME) { - let var_ty = hubris.lookup_type(var.goff)?; - let mut buf: Vec = vec![0u8; var.size]; - - core.halt()?; - core.read_8(var.addr, &mut buf)?; - core.run()?; - - let v = reflect::load_value(hubris, &buf, var_ty, 0)?; - let as_static_cell = doppel::ClaimOnceCell::from_value(&v)?; - let Value::Struct(packrat_bufs) = &as_static_cell.cell.value else { - bail!("expected {PACKRAT_BUF_NAME} to be a struct"); - }; + let packrat_bufs = reflect::read_variable::< + doppel::ClaimOnceCell, + >(hubris, core, var)? + .cell + .value; let Some(Value::Struct(compute_sled_bufs)) = packrat_bufs .get("gimlet_bufs") .or_else(|| packrat_bufs.get("cosmo_bufs"))