Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cmd/host/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,9 @@ fn read_qualified_state_buf(
return Ok(None);
};

let as_static_cell: doppel::ClaimOnceCell =
let as_static_cell: doppel::ClaimOnceCell<HostStateBuf> =
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]) {
Expand Down
6 changes: 3 additions & 3 deletions cmd/ringbuf/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Ringbuf> =
StaticCell::from_value(&ringbuf_val)?;
Ok::<_, anyhow::Error>((Some(cell.cell.value), None))
})?;

if let (Some(mut counters), false) = (counters, no_totals) {
Expand Down
43 changes: 15 additions & 28 deletions humility-doppel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,36 +387,27 @@ pub enum CounterVariant {
}

#[derive(Clone, Debug, Load)]
pub struct ClaimOnceCell {
pub cell: UnsafeCell,
#[load(check_name)]
pub struct ClaimOnceCell<T: Load> {
pub cell: UnsafeCell<T>,
}

#[derive(Clone, Debug, Load)]
pub struct StaticCell {
pub cell: UnsafeCell,
#[load(check_name)]
pub struct StaticCell<T: Load> {
pub cell: UnsafeCell<T>,
}

#[derive(Clone, Debug, Load)]
pub struct UnsafeCell {
pub value: Value,
}

#[derive(Clone, Debug)]
pub struct MaybeUninit<T> {
#[load(check_name)]
pub struct UnsafeCell<T: Load> {
pub value: T,
}

impl<T: humility::reflect::Load> humility::reflect::Load for MaybeUninit<T> {
fn from_value(v: &Value) -> Result<Self> {
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")?;
T::from_value(value).map(|value| Self { value })
}
#[derive(Clone, Debug, Load)]
#[load(check_name)]
pub struct MaybeUninit<T: Load> {
pub value: T,
}

Comment thread
mkeeter marked this conversation as resolved.
/// Double of the struct from `udprpc`
Expand Down Expand Up @@ -570,13 +561,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::<u32>::from_value(&counter["v"])
.context("ringbuf count must be a u32")?;
return Ok(Self::Single(cell.value));
}

Ok(Self::Nested(Counters::from_value(value)?))
Expand Down
19 changes: 6 additions & 13 deletions humility-spd/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use humility::hubris::*;
use humility::{
reflect,
reflect::{Base, Load, Value},
reflect::{Base, Value},
};
use humility_doppel as doppel;

Expand Down Expand Up @@ -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<u8> = 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<reflect::Struct>,
>(hubris, core, var)?
.cell
.value;
let Ok(Value::Struct(compute_sled_bufs)) = packrat_bufs
.get("gimlet_bufs")
.or_else(|_e| packrat_bufs.get("cosmo_bufs"))
Expand Down
77 changes: 67 additions & 10 deletions load_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,83 @@
use quote::quote_spanned;
use syn::spanned::Spanned;

#[proc_macro_derive(Load)]
#[proc_macro_derive(Load, attributes(load))]
pub fn load_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = syn::parse_macro_input!(input as syn::DeriveInput);

let name_check = if has_check_name(&input.attrs) {
Some(gen_name_check(&input.ident))
} else {
None
};

let ts = match &input.data {
syn::Data::Struct(data) => match &data.fields {
syn::Fields::Named(fields) => {
gen_named_struct(&input.ident, fields)
}
syn::Fields::Unnamed(fields) => {
gen_unnamed_struct(&input.ident, fields)
}
syn::Fields::Named(fields) => gen_named_struct(
&input.ident,
&input.generics,
fields,
name_check,
),
syn::Fields::Unnamed(fields) => gen_unnamed_struct(
&input.ident,
&input.generics,
fields,
name_check,
),
syn::Fields::Unit => {
unimplemented!(
"unit struct not implemented as DWARF rep \
not clear at time of writing"
);
}
},
syn::Data::Enum(data) => gen_enum(&input.ident, data),
syn::Data::Enum(data) => gen_enum(&input.ident, data, name_check),
_ => unimplemented!("unsupported type for derive"),
};

proc_macro::TokenStream::from(ts)
}

/// Returns true if the input has a `#[load(check_name)]` attribute.
fn has_check_name(attrs: &[syn::Attribute]) -> bool {
attrs.iter().any(|a| {
if !a.path().is_ident("load") {
return false;
}
let mut found = false;
let _ = a.parse_nested_meta(|meta| {
if meta.path.is_ident("check_name") {
found = true;
}
Ok(())
});
found
})
}

/// Generates a snippet that checks that the reflected container `v`'s name
/// matches `ident` (modulo module path prefixes and generic parameters).
fn gen_name_check(ident: &syn::Ident) -> proc_macro2::TokenStream {
quote_spanned!(ident.span()=>
{
let name: &str = v.name();
let stripped = name.split('<').next().unwrap_or(name);
let stripped = stripped.rsplit("::").next().unwrap_or(stripped);
if stripped != stringify!(#ident) {
anyhow::bail!(
"expected reflected type name `{}`, got `{}`",
stringify!(#ident), name,
);
}
}
)
}

fn gen_enum(
ident: &syn::Ident,
data: &syn::DataEnum,
name_check: Option<proc_macro2::TokenStream>,
) -> proc_macro2::TokenStream {
let mut arms = vec![];
for variant in &data.variants {
Expand Down Expand Up @@ -116,6 +164,7 @@ fn gen_enum(
impl humility::reflect::Load for #ident {
fn from_value(v: &humility::reflect::Value) -> anyhow::Result<Self> {
let v = v.as_enum()?;
#name_check
match (v.disc(), v.contents()) {
#arms
_ => anyhow::bail!("unexpected shape for {}: {:?}",
Expand All @@ -128,7 +177,9 @@ fn gen_enum(

fn gen_named_struct(
ident: &syn::Ident,
generics: &syn::Generics,
fields: &syn::FieldsNamed,
name_check: Option<proc_macro2::TokenStream>,
) -> proc_macro2::TokenStream {
let field_name_strs = fields.named.iter().map(|fld| {
let name = fld.ident.as_ref().unwrap();
Expand All @@ -144,10 +195,12 @@ fn gen_named_struct(
});
let field_defs = field_defs.collect::<proc_macro2::TokenStream>();

let (impl_generics, ty_generics, _where_clause) = generics.split_for_impl();
quote_spanned!(ident.span()=>
impl humility::reflect::Load for #ident {
impl #impl_generics humility::reflect::Load for #ident #ty_generics {
fn from_value(v: &humility::reflect::Value) -> anyhow::Result<Self> {
let v = v.as_struct()?;
#name_check
v.check_members(&[#field_name_strs])?;
Ok(Self {
#field_defs
Expand All @@ -159,7 +212,9 @@ fn gen_named_struct(

fn gen_unnamed_struct(
ident: &syn::Ident,
generics: &syn::Generics,
fields: &syn::FieldsUnnamed,
name_check: Option<proc_macro2::TokenStream>,
) -> proc_macro2::TokenStream {
let len = fields.unnamed.len();
let field_lets = fields.unnamed.iter().enumerate().map(|(i, fld)| {
Expand All @@ -177,10 +232,12 @@ fn gen_unnamed_struct(
});
let field_uses = field_uses.collect::<proc_macro2::TokenStream>();

let (impl_generics, ty_generics, _where_clause) = generics.split_for_impl();
quote_spanned!(ident.span()=>
impl humility::reflect::Load for #ident {
impl #impl_generics humility::reflect::Load for #ident #ty_generics {
fn from_value(v: &humility::reflect::Value) -> anyhow::Result<Self> {
let v = v.as_tuple()?;
#name_check
if v.len() != #len {
anyhow::bail!("wrong tuple size for {}: {:?}",
stringify!(#ident), v);
Expand Down
Loading