Skip to content

Commit

Permalink
Add useful Debug impl to PropertyBag and ConfigBag
Browse files Browse the repository at this point in the history
  • Loading branch information
rcoh committed Apr 20, 2023
1 parent 437ae5b commit 60ec896
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 24 deletions.
68 changes: 47 additions & 21 deletions rust-runtime/aws-smithy-http/src/property_bag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@
use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::fmt;
use std::fmt::Debug;
use std::fmt::{Debug, Formatter};
use std::hash::{BuildHasherDefault, Hasher};
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex};

type AnyMap = HashMap<TypeId, Box<dyn Any + Send + Sync>, BuildHasherDefault<IdHasher>>;
type AnyMap =
HashMap<TypeId, (&'static str, Box<dyn Any + Send + Sync>), BuildHasherDefault<IdHasher>>;

// With TypeIds as keys, there's no need to hash them. They are already hashes
// themselves, coming from the compiler. The IdHasher just holds the u64 of
Expand Down Expand Up @@ -82,8 +83,11 @@ impl PropertyBag {
/// ```
pub fn insert<T: Send + Sync + 'static>(&mut self, val: T) -> Option<T> {
self.map
.insert(TypeId::of::<T>(), Box::new(val))
.and_then(|boxed| {
.insert(
TypeId::of::<T>(),
(std::any::type_name::<T>(), Box::new(val)),
)
.and_then(|(_, boxed)| {
(boxed as Box<dyn Any + 'static>)
.downcast()
.ok()
Expand All @@ -106,7 +110,12 @@ impl PropertyBag {
pub fn get<T: Send + Sync + 'static>(&self) -> Option<&T> {
self.map
.get(&TypeId::of::<T>())
.and_then(|boxed| (&**boxed as &(dyn Any + 'static)).downcast_ref())
.and_then(|(_, boxed)| (&**boxed as &(dyn Any + 'static)).downcast_ref())
}

/// Returns an iterator of the types contained in this PropertyBag
pub fn contents(&self) -> impl Iterator<Item = &'static str> + '_ {
self.map.values().map(|(name, _)| *name)
}

/// Get a mutable reference to a type previously inserted on this `PropertyBag`.
Expand All @@ -124,7 +133,7 @@ impl PropertyBag {
pub fn get_mut<T: Send + Sync + 'static>(&mut self) -> Option<&mut T> {
self.map
.get_mut(&TypeId::of::<T>())
.and_then(|boxed| (&mut **boxed as &mut (dyn Any + 'static)).downcast_mut())
.and_then(|(_, boxed)| (&mut **boxed as &mut (dyn Any + 'static)).downcast_mut())
}

/// Remove a type from this `PropertyBag`.
Expand All @@ -141,7 +150,7 @@ impl PropertyBag {
/// assert!(props.get::<i32>().is_none());
/// ```
pub fn remove<T: Send + Sync + 'static>(&mut self) -> Option<T> {
self.map.remove(&TypeId::of::<T>()).and_then(|boxed| {
self.map.remove(&TypeId::of::<T>()).and_then(|(_, boxed)| {
(boxed as Box<dyn Any + 'static>)
.downcast()
.ok()
Expand All @@ -168,7 +177,16 @@ impl PropertyBag {

impl fmt::Debug for PropertyBag {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PropertyBag").finish()
let mut fmt = f.debug_struct("PropertyBag");

struct Contents<'a>(&'a PropertyBag);
impl<'a> Debug for Contents<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.0.contents()).finish()
}
}
fmt.field("contents", &Contents(&self));
fmt.finish()
}
}

Expand Down Expand Up @@ -225,22 +243,30 @@ impl From<PropertyBag> for SharedPropertyBag {
}

#[cfg(test)]
#[test]
fn test_extensions() {
#[derive(Debug, PartialEq)]
struct MyType(i32);
mod test {
use crate::property_bag::PropertyBag;

#[test]
fn test_extensions() {
#[derive(Debug, PartialEq)]
struct MyType(i32);

let mut extensions = PropertyBag::new();
let mut property_bag = PropertyBag::new();

extensions.insert(5i32);
extensions.insert(MyType(10));
property_bag.insert(5i32);
property_bag.insert(MyType(10));

assert_eq!(extensions.get(), Some(&5i32));
assert_eq!(extensions.get_mut(), Some(&mut 5i32));
assert_eq!(property_bag.get(), Some(&5i32));
assert_eq!(property_bag.get_mut(), Some(&mut 5i32));

assert_eq!(extensions.remove::<i32>(), Some(5i32));
assert!(extensions.get::<i32>().is_none());
assert_eq!(property_bag.remove::<i32>(), Some(5i32));
assert!(property_bag.get::<i32>().is_none());

assert_eq!(extensions.get::<bool>(), None);
assert_eq!(extensions.get(), Some(&MyType(10)));
assert_eq!(property_bag.get::<bool>(), None);
assert_eq!(property_bag.get(), Some(&MyType(10)));
assert_eq!(
format!("{:?}", property_bag),
r#"PropertyBag { contents: ["aws_smithy_http::property_bag::test::test_extensions::MyType"] }"#
);
}
}
41 changes: 38 additions & 3 deletions rust-runtime/aws-smithy-runtime-api/src/config_bag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,40 @@
//! 1. A new layer of configuration may be applied onto an existing configuration structure without modifying it or taking ownership.
//! 2. No lifetime shenanigans to deal with
use aws_smithy_http::property_bag::PropertyBag;
use std::fmt::Debug;
use std::fmt::{Debug, Formatter};
use std::ops::Deref;
use std::sync::Arc;

/// Layered Configuration Structure
///
/// [`ConfigBag`] is the "unlocked" form of the bag. Only the top layer of the bag may be unlocked.
#[must_use]
#[derive(Debug)]
pub struct ConfigBag {
head: Layer,
tail: Option<FrozenConfigBag>,
}

impl Debug for ConfigBag {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
struct Layers<'a>(&'a ConfigBag);
impl Debug for Layers<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut list = f.debug_list();
list.entry(&self.0.head);
let mut us = self.0.tail.as_ref();
while let Some(bag) = us {
list.entry(&bag.head);
us = bag.tail.as_ref()
}
list.finish()
}
}
f.debug_struct("ConfigBag")
.field("layers", &Layers(&self))
.finish()
}
}

/// Layered Configuration Structure
///
/// [`FrozenConfigBag`] is the "locked" form of the bag.
Expand Down Expand Up @@ -55,12 +75,26 @@ enum Value<T> {
ExplicitlyUnset,
}

#[derive(Debug)]
struct Layer {
name: &'static str,
props: PropertyBag,
}

impl Debug for Layer {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
struct Contents<'a>(&'a Layer);
impl Debug for Contents<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_list().entries(self.0.props.contents()).finish()
}
}
f.debug_struct("Layer")
.field("name", &self.name)
.field("properties", &Contents(&self))
.finish()
}
}

fn no_op(_: &mut ConfigBag) {}

impl FrozenConfigBag {
Expand Down Expand Up @@ -258,6 +292,7 @@ mod test {
assert!(final_bag.get::<Prop2>().is_some());
// we unset prop3
assert!(final_bag.get::<Prop3>().is_none());
println!("{:#?}", final_bag);
}

#[test]
Expand Down

0 comments on commit 60ec896

Please sign in to comment.