Skip to content
Open
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
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@ memmap2 = "0.5.7"
once_cell = "1.16.0"
procmaps = "0.4.1"
rustc-demangle = "0.1.21"
serde = "1.0"
thiserror = "1.0.37"
itertools = "0.10.5"

[dev-dependencies]
quickcheck = "1.0"
quickcheck_macros = "1.0"
serde_derive = "1.0.151"
serde_json = "1.0.11"
48 changes: 41 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
//!
//! // initialize the debuginfo provider
//! let context = deflect::default_provider()?;
//!
//!
//! // create some type-erased data
//! let erased: Box<dyn Any> = Box::new(Foo { a: 42 });
//!
Expand All @@ -30,27 +30,27 @@
//!
//! // pretty-print the reflected value
//! assert_eq!(value.to_string(), "box Foo { a: 42 }");
//!
//!
//! // downcast into a `BoxedDyn` value
//! let value: deflect::value::BoxedDyn = value.try_into()?;
//!
//! // dereference the boxed value
//! let value: deflect::Value = value.deref()?;
//!
//!
//! // downcast into a `Struct` value
//! let value: deflect::value::Struct = value.try_into()?;
//!
//!
//! // get the field `a` by name
//! let Some(field) = value.field("a")? else {
//! panic!("no field named `a`!")
//! };
//!
//!
//! // get the value of the field
//! let value = field.value()?;
//!
//!
//! // downcast into a `u8`
//! let value: u8 = value.try_into()?;
//!
//!
//! // check that it's equal to `42`!
//! assert_eq!(value, 42);
//! # Ok::<_, Box<dyn std::error::Error>>(())
Expand Down Expand Up @@ -256,6 +256,7 @@ pub trait Reflect {
}
}

// Implement `Reflect` for ALL types.
impl<T: ?Sized> Reflect for T {}

impl dyn Reflect + '_ {
Expand Down Expand Up @@ -325,6 +326,18 @@ impl fmt::Debug for dyn Reflect {
}
}

impl serde::Serialize for dyn Reflect + '_
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let context = default_provider().map_err(crate::ser_err)?;
let value = self.reflect(&context).map_err(crate::ser_err)?;
value.serialize(serializer)
}
}

macro_rules! generate_type_and_value {
($($(#[$attr:meta])* $t:ident,)*) => {
/// A reflected type.
Expand Down Expand Up @@ -460,6 +473,20 @@ macro_rules! generate_type_and_value {
}
}

impl<'value, 'dwarf, P> serde::Serialize for Value<'value, 'dwarf, P>
where
P: crate::DebugInfoProvider,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
$(Self::$t(v) => v.serialize(serializer),)*
}
}
}

$(
#[doc = concat!(
"Upcast a [`",
Expand Down Expand Up @@ -795,3 +822,10 @@ fn fmt_err<E: fmt::Display>(err: E) -> fmt::Error {
eprintln!("ERROR: {err}");
fmt::Error
}

fn ser_err<E>(e: impl ToString) -> E
where
E: serde::ser::Error,
{
E::custom(e.to_string())
}
20 changes: 20 additions & 0 deletions src/schema/name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,26 @@ where
pub fn to_slice(&self) -> Result<Cow<'_, [u8]>, crate::Error> {
Ok(self.name.to_slice()?)
}

pub(crate) fn to_static_str(
&self,
key: crate::gimli::UnitOffset,
) -> Result<&'static str, crate::Error> {
use dashmap::DashMap;
use once_cell::sync::Lazy;

static NAME_CACHE: Lazy<DashMap<crate::gimli::UnitOffset, &'static str>> =
Lazy::new(DashMap::new);

let name = NAME_CACHE.entry(key).or_try_insert_with(|| {
let name = self.to_string_lossy()?;
let name = name.to_string();
let name = Box::leak(name.into_boxed_str());
Ok::<_, crate::Error>(name)
})?;

Ok(*name)
}
}

impl<R> fmt::Debug for Name<R>
Expand Down
8 changes: 8 additions & 0 deletions src/schema/variant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ where
unit: &'dwarf crate::gimli::Unit<R, usize>,
entry: crate::gimli::DebuggingInformationEntry<'dwarf, 'dwarf, R>,
discriminant_val: Option<super::Data>,
index: usize,
}

impl<'dwarf, R> Variant<'dwarf, R>
Expand All @@ -22,12 +23,14 @@ where
unit: &'dwarf crate::gimli::Unit<R, usize>,
entry: crate::gimli::DebuggingInformationEntry<'dwarf, 'dwarf, R>,
discriminant_val: Option<super::Data>,
index: usize,
) -> Self {
Self {
dwarf,
unit,
entry,
discriminant_val,
index,
}
}

Expand Down Expand Up @@ -83,6 +86,11 @@ where
let tree = self.unit.entries_tree(Some(self.entry.offset()))?;
Ok(super::Fields::from_tree(self.dwarf, self.unit, tree))
}

/// The index of the variant.
pub fn index(&self) -> usize {
self.index
}
}

impl<'dwarf, R> fmt::Display for Variant<'dwarf, R>
Expand Down
11 changes: 11 additions & 0 deletions src/schema/variants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ where
unit: self.unit,
iter: self.tree.root()?.children(),
discriminant_type: &self.discriminant_type,
count: 0,
})
}
}
Expand All @@ -49,6 +50,7 @@ where
unit: &'dwarf crate::gimli::Unit<R, usize>,
iter: crate::gimli::EntriesTreeIter<'dwarf, 'dwarf, 'tree, R>,
discriminant_type: &'tree super::Type<'dwarf, R>,
count: usize,
}

impl<'dwarf, 'tree, R: crate::gimli::Reader<Offset = usize>> VariantsIter<'dwarf, 'tree, R>
Expand All @@ -75,11 +77,16 @@ where
.ok_or_else(|| crate::error::missing_child(crate::gimli::DW_TAG_member))?;
let entry = crate::get_type(entry.entry())?;
let entry = self.unit.entry(entry)?;

let index = self.count;
self.count = self.count.wrapping_add(1);

return Ok(Some(super::Variant::new(
self.dwarf,
self.unit,
entry,
discriminant_value,
index,
)));
}
crate::gimli::DW_TAG_enumerator => {
Expand All @@ -90,11 +97,15 @@ where
discriminant_value(self.discriminant_type, dw_at_discr_value)
});

let index = self.count;
self.count = self.count.wrapping_add(1);

return Ok(Some(super::Variant::new(
self.dwarf,
self.unit,
entry.clone(),
discriminant_value,
index,
)));
}
crate::gimli::DW_TAG_member => continue,
Expand Down
20 changes: 20 additions & 0 deletions src/value/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,23 @@ where
debug_list.finish()
}
}

impl<'value, 'dwarf, P> serde::Serialize for Array<'value, 'dwarf, P>
where
P: crate::DebugInfoProvider,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeSeq;
let len = self.schema.len().map_err(crate::ser_err)?;
let len = Some(usize::try_from(len).map_err(crate::ser_err)?);
let mut ser_seq = serializer.serialize_seq(len).map_err(crate::ser_err)?;
for maybe_elt in self.iter().map_err(crate::ser_err)? {
let elt = maybe_elt.map_err(crate::ser_err)?;
ser_seq.serialize_element(&elt)?;
}
ser_seq.end()
}
}
15 changes: 14 additions & 1 deletion src/value/box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,17 @@ where
f.write_str("box ")?;
self.deref().map_err(crate::fmt_err)?.fmt(f)
}
}
}

impl<'value, 'dwarf, P> serde::Serialize for Box<'value, 'dwarf, P>
where
P: crate::DebugInfoProvider,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let value = self.deref().map_err(crate::ser_err)?;
value.serialize(serializer)
}
}
15 changes: 14 additions & 1 deletion src/value/boxed_dyn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ where
pub fn schema(&self) -> &crate::schema::BoxedDyn<'dwarf, P::Reader> {
&self.schema
}

fn data(&self, size: usize) -> Result<crate::Bytes<'value>, crate::Error> {
let field =
unsafe { super::Field::new(self.schema.pointer().clone(), self.value, self.provider) };
Expand Down Expand Up @@ -108,3 +108,16 @@ where
value.fmt(f)
}
}

impl<'value, 'dwarf, P> serde::Serialize for BoxedDyn<'value, 'dwarf, P>
where
P: crate::DebugInfoProvider,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let value = self.deref().map_err(crate::ser_err)?;
value.serialize(serializer)
}
}
19 changes: 19 additions & 0 deletions src/value/boxed_slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,22 @@ where
f.write_str("[..]")
}
}

impl<'value, 'dwarf, P> serde::Serialize for BoxedSlice<'value, 'dwarf, P>
where
P: crate::DebugInfoProvider,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeSeq;
let len = Some(self.length().map_err(crate::ser_err)?);
let mut ser_seq = serializer.serialize_seq(len).map_err(crate::ser_err)?;
for maybe_elt in self.iter().map_err(crate::ser_err)? {
let elt = maybe_elt.map_err(crate::ser_err)?;
ser_seq.serialize_element(&elt)?
}
ser_seq.end()
}
}
55 changes: 55 additions & 0 deletions src/value/enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,58 @@ where
self.variant().map_err(crate::fmt_err)?.fmt(f)
}
}

impl<'value, 'dwarf, P> serde::Serialize for Enum<'value, 'dwarf, P>
where
P: crate::DebugInfoProvider,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeStructVariant;

let schema = self.schema();
let offset = schema.entry().offset();
let type_name = schema.name();
let type_name = type_name
.to_static_str(offset)
.map_err(crate::ser_err)?
.clone();

let variant = self.variant().map_err(crate::ser_err)?;
let variant_schema = variant.schema();
let offset = variant_schema.entry().offset();
let variant_name = variant_schema.name().map_err(crate::ser_err)?;
let variant_name = variant_name
.to_static_str(offset)
.map_err(crate::ser_err)?
.clone();
let variant_index = variant_schema.index();

let mut fields = variant.fields().map_err(crate::ser_err)?;
let mut fields_iter = fields.iter().map_err(crate::ser_err)?;
let mut fields = vec![];
while let Some(f) = fields_iter.try_next().map_err(crate::ser_err)? {
fields.push(f);
}

let mut s = serializer.serialize_struct_variant(
&type_name,
variant_index.try_into().map_err(crate::ser_err)?,
&variant_name,
fields.len(),
)?;

fields.into_iter().try_for_each(|field| {
let schema = field.schema();
let offset = schema.entry().offset();
let field_name = schema.name().map_err(crate::ser_err)?;
let field_name = field_name.to_static_str(offset).map_err(crate::ser_err)?;
let field_value = field.value().map_err(crate::ser_err)?;
s.serialize_field(&field_name, &field_value)
})?;

s.end()
}
}
11 changes: 11 additions & 0 deletions src/value/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,14 @@ where
}
}

impl<'value, 'dwarf, P> serde::Serialize for Function<'value, 'dwarf, P>
where
P: crate::DebugInfoProvider,
{
fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
Err(crate::ser_err("cannot serialize function"))
}
}
Loading