mod storable;
mod typeid_map;
use crate::config_bag::typeid_map::TypeIdMap;
use crate::type_erasure::TypeErasedBox;
use std::any::{type_name, TypeId};
use std::borrow::Cow;
use std::fmt::{Debug, Formatter};
use std::iter::Rev;
use std::marker::PhantomData;
use std::ops::Deref;
use std::slice::Iter;
use std::sync::Arc;
pub use storable::{AppendItemIter, Storable, Store, StoreAppend, StoreReplace};
#[derive(Clone, Debug)]
#[must_use]
pub struct FrozenLayer(Arc<Layer>);
impl FrozenLayer {
pub fn try_modify(self) -> Option<Layer> {
Arc::try_unwrap(self.0).ok()
}
}
impl Deref for FrozenLayer {
type Target = Layer;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<Layer> for FrozenLayer {
fn from(layer: Layer) -> Self {
FrozenLayer(Arc::new(layer))
}
}
pub(crate) mod value {
#[derive(Clone, Debug)]
pub enum Value<T> {
Set(T),
ExplicitlyUnset(&'static str),
}
impl<T: Default> Default for Value<T> {
fn default() -> Self {
Self::Set(Default::default())
}
}
}
use value::Value;
#[derive(Debug, Default)]
pub struct CloneableLayer(Layer);
impl Deref for CloneableLayer {
type Target = Layer;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Clone for CloneableLayer {
fn clone(&self) -> Self {
Self(
self.try_clone()
.expect("only cloneable types can be inserted"),
)
}
}
impl From<CloneableLayer> for Layer {
fn from(cloneable_layer: CloneableLayer) -> Layer {
cloneable_layer.0
}
}
impl CloneableLayer {
pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
Self(Layer::new(name))
}
pub fn freeze(self) -> FrozenLayer {
self.0.into()
}
pub fn unset<T: Send + Sync + Clone + Debug + 'static>(&mut self) -> &mut Self {
self.put_directly_cloneable::<StoreReplace<T>>(Value::ExplicitlyUnset(type_name::<T>()));
self
}
fn put_directly_cloneable<T: Store>(&mut self, value: T::StoredType) -> &mut Self
where
T::StoredType: Clone,
{
self.0.props.insert(
TypeId::of::<T::StoredType>(),
TypeErasedBox::new_with_clone(value),
);
self
}
pub fn store_put<T>(&mut self, item: T) -> &mut Self
where
T: Storable<Storer = StoreReplace<T>> + Clone,
{
self.put_directly_cloneable::<StoreReplace<T>>(Value::Set(item));
self
}
pub fn store_or_unset<T>(&mut self, item: Option<T>) -> &mut Self
where
T: Storable<Storer = StoreReplace<T>> + Clone,
{
let item = match item {
Some(item) => Value::Set(item),
None => Value::ExplicitlyUnset(type_name::<T>()),
};
self.put_directly_cloneable::<StoreReplace<T>>(item);
self
}
pub fn store_append<T>(&mut self, item: T) -> &mut Self
where
T: Storable<Storer = StoreAppend<T>> + Clone,
{
match self.get_mut_or_default::<StoreAppend<T>>() {
Value::Set(list) => list.push(item),
v @ Value::ExplicitlyUnset(_) => *v = Value::Set(vec![item]),
}
self
}
pub fn clear<T>(&mut self)
where
T: Storable<Storer = StoreAppend<T>> + Clone,
{
self.put_directly_cloneable::<StoreAppend<T>>(Value::ExplicitlyUnset(type_name::<T>()));
}
fn get_mut_or_default<T: Send + Sync + Store + 'static>(&mut self) -> &mut T::StoredType
where
T::StoredType: Default + Clone,
{
self.0
.props
.entry(TypeId::of::<T::StoredType>())
.or_insert_with(|| TypeErasedBox::new_with_clone(T::StoredType::default()))
.downcast_mut()
.expect("typechecked")
}
}
#[derive(Default)]
pub struct Layer {
name: Cow<'static, str>,
props: TypeIdMap<TypeErasedBox>,
}
impl Debug for Layer {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
struct Items<'a>(&'a Layer);
impl Debug for Items<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_list().entries(self.0.props.values()).finish()
}
}
f.debug_struct("Layer")
.field("name", &self.name)
.field("items", &Items(self))
.finish()
}
}
impl Layer {
fn try_clone(&self) -> Option<Self> {
let new_props = self
.props
.iter()
.flat_map(|(tyid, erased)| erased.try_clone().map(|e| (*tyid, e)))
.collect::<TypeIdMap<_>>();
if new_props.len() == self.props.len() {
Some(Layer {
name: self.name.clone(),
props: new_props,
})
} else {
None
}
}
fn put_directly<T: Store>(&mut self, value: T::StoredType) -> &mut Self {
self.props
.insert(TypeId::of::<T::StoredType>(), TypeErasedBox::new(value));
self
}
pub fn is_empty(&self) -> bool {
self.props.is_empty()
}
pub fn freeze(self) -> FrozenLayer {
self.into()
}
pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
let name = name.into();
Self {
name,
props: Default::default(),
}
}
pub fn with_name(self, name: impl Into<Cow<'static, str>>) -> Self {
Self {
name: name.into(),
props: self.props,
}
}
pub fn load<T: Storable>(&self) -> <T::Storer as Store>::ReturnedType<'_> {
T::Storer::merge_iter(ItemIter {
inner: BagIter {
head: Some(self),
tail: [].iter().rev(),
},
t: Default::default(),
})
}
pub fn unset<T: Send + Sync + Debug + 'static>(&mut self) -> &mut Self {
self.put_directly::<StoreReplace<T>>(Value::ExplicitlyUnset(type_name::<T>()));
self
}
pub fn store_put<T>(&mut self, item: T) -> &mut Self
where
T: Storable<Storer = StoreReplace<T>>,
{
self.put_directly::<StoreReplace<T>>(Value::Set(item));
self
}
pub fn store_or_unset<T>(&mut self, item: Option<T>) -> &mut Self
where
T: Storable<Storer = StoreReplace<T>>,
{
let item = match item {
Some(item) => Value::Set(item),
None => Value::ExplicitlyUnset(type_name::<T>()),
};
self.put_directly::<StoreReplace<T>>(item);
self
}
pub fn store_append<T>(&mut self, item: T) -> &mut Self
where
T: Storable<Storer = StoreAppend<T>>,
{
match self.get_mut_or_default::<StoreAppend<T>>() {
Value::Set(list) => list.push(item),
v @ Value::ExplicitlyUnset(_) => *v = Value::Set(vec![item]),
}
self
}
pub fn clear<T>(&mut self)
where
T: Storable<Storer = StoreAppend<T>>,
{
self.put_directly::<StoreAppend<T>>(Value::ExplicitlyUnset(type_name::<T>()));
}
fn get<T: Send + Sync + Store + 'static>(&self) -> Option<&T::StoredType> {
self.props
.get(&TypeId::of::<T::StoredType>())
.map(|t| t.downcast_ref().expect("typechecked"))
}
fn get_mut<T: Send + Sync + Store + 'static>(&mut self) -> Option<&mut T::StoredType> {
self.props
.get_mut(&TypeId::of::<T::StoredType>())
.map(|t| t.downcast_mut().expect("typechecked"))
}
fn get_mut_or_default<T: Send + Sync + Store + 'static>(&mut self) -> &mut T::StoredType
where
T::StoredType: Default,
{
self.props
.entry(TypeId::of::<T::StoredType>())
.or_insert_with(|| TypeErasedBox::new(T::StoredType::default()))
.downcast_mut()
.expect("typechecked")
}
}
#[must_use]
pub struct ConfigBag {
interceptor_state: Layer,
tail: Vec<FrozenLayer>,
}
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 {
f.debug_list().entries(self.0.layers()).finish()
}
}
f.debug_struct("ConfigBag")
.field("layers", &Layers(self))
.finish()
}
}
impl ConfigBag {
pub fn base() -> Self {
ConfigBag {
interceptor_state: Layer {
name: Cow::Borrowed("interceptor_state"),
props: Default::default(),
},
tail: vec![],
}
}
pub fn of_layers(layers: impl IntoIterator<Item = Layer>) -> Self {
let mut bag = ConfigBag::base();
for layer in layers {
bag.push_layer(layer);
}
bag
}
pub fn push_layer(&mut self, layer: Layer) -> &mut Self {
self.tail.push(layer.freeze());
self
}
pub fn push_shared_layer(&mut self, layer: FrozenLayer) -> &mut Self {
self.tail.push(layer);
self
}
pub fn interceptor_state(&mut self) -> &mut Layer {
&mut self.interceptor_state
}
pub fn load<T: Storable>(&self) -> <T::Storer as Store>::ReturnedType<'_> {
self.sourced_get::<T::Storer>()
}
pub fn get_mut_from_interceptor_state<T>(&mut self) -> Option<&mut T>
where
T: Storable<Storer = StoreReplace<T>> + Send + Sync + Debug + 'static,
{
match self.interceptor_state.get_mut::<StoreReplace<T>>() {
Some(Value::ExplicitlyUnset(_)) => None,
Some(Value::Set(t)) => Some(t),
None => None,
}
}
pub fn get_mut<T>(&mut self) -> Option<&mut T>
where
T: Storable<Storer = StoreReplace<T>> + Send + Sync + Debug + Clone + 'static,
{
if self
.interceptor_state
.get_mut::<StoreReplace<T>>()
.is_none()
{
let new_item = match self.tail.iter().find_map(|b| b.load::<T>()) {
Some(item) => item.clone(),
None => return None,
};
self.interceptor_state.store_put(new_item);
}
self.get_mut_from_interceptor_state()
}
pub fn get_mut_or_default<T>(&mut self) -> &mut T
where
T: Storable<Storer = StoreReplace<T>> + Send + Sync + Debug + Clone + Default + 'static,
{
self.get_mut_or_else(|| T::default())
}
pub fn get_mut_or_else<T>(&mut self, default: impl Fn() -> T) -> &mut T
where
T: Storable<Storer = StoreReplace<T>> + Send + Sync + Debug + Clone + 'static,
{
if self.get_mut::<T>().is_none() {
self.interceptor_state.store_put((default)());
return self
.get_mut()
.expect("item was just stored in the top layer");
}
self.get_mut().unwrap()
}
pub fn with_fn(
self,
name: impl Into<Cow<'static, str>>,
next: impl Fn(&mut Layer),
) -> ConfigBag {
let mut new_layer = Layer::new(name);
next(&mut new_layer);
let ConfigBag {
interceptor_state: head,
mut tail,
} = self;
tail.push(head.freeze());
ConfigBag {
interceptor_state: new_layer,
tail,
}
}
pub fn add_layer(self, name: impl Into<Cow<'static, str>>) -> ConfigBag {
self.with_fn(name, |_| {})
}
pub fn sourced_get<T: Store>(&self) -> T::ReturnedType<'_> {
let stored_type_iter = ItemIter {
inner: self.layers(),
t: PhantomData,
};
T::merge_iter(stored_type_iter)
}
fn layers(&self) -> BagIter<'_> {
BagIter {
head: Some(&self.interceptor_state),
tail: self.tail.iter().rev(),
}
}
}
pub struct ItemIter<'a, T> {
inner: BagIter<'a>,
t: PhantomData<T>,
}
impl<T> Debug for ItemIter<'_, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "ItemIter")
}
}
impl<'a, T: 'a> Iterator for ItemIter<'a, T>
where
T: Store,
{
type Item = &'a T::StoredType;
fn next(&mut self) -> Option<Self::Item> {
match self.inner.next() {
Some(layer) => layer.get::<T>().or_else(|| self.next()),
None => None,
}
}
}
struct BagIter<'a> {
head: Option<&'a Layer>,
tail: Rev<Iter<'a, FrozenLayer>>,
}
impl<'a> Iterator for BagIter<'a> {
type Item = &'a Layer;
fn next(&mut self) -> Option<Self::Item> {
if let Some(head) = self.head.take() {
Some(head)
} else {
self.tail.next().map(|t| t.deref())
}
}
}
#[cfg(test)]
mod test {
use super::ConfigBag;
use crate::config_bag::{CloneableLayer, Layer, Storable, StoreAppend, StoreReplace};
#[test]
fn layered_property_bag() {
#[derive(Debug)]
struct Prop1;
impl Storable for Prop1 {
type Storer = StoreReplace<Self>;
}
#[derive(Debug)]
struct Prop2;
impl Storable for Prop2 {
type Storer = StoreReplace<Self>;
}
let layer_a = |bag: &mut Layer| {
bag.store_put(Prop1);
};
let layer_b = |bag: &mut Layer| {
bag.store_put(Prop2);
};
#[derive(Debug)]
struct Prop3;
impl Storable for Prop3 {
type Storer = StoreReplace<Self>;
}
let mut base_bag = ConfigBag::base()
.with_fn("a", layer_a)
.with_fn("b", layer_b);
base_bag.interceptor_state().store_put(Prop3);
assert!(base_bag.load::<Prop1>().is_some());
#[derive(Debug)]
struct Prop4;
impl Storable for Prop4 {
type Storer = StoreReplace<Self>;
}
let layer_c = |bag: &mut Layer| {
bag.store_put(Prop4);
bag.unset::<Prop3>();
};
let final_bag = base_bag.with_fn("c", layer_c);
assert!(final_bag.load::<Prop4>().is_some());
assert!(final_bag.load::<Prop1>().is_some());
assert!(final_bag.load::<Prop2>().is_some());
assert!(final_bag.load::<Prop3>().is_none());
println!("{final_bag:#?}");
}
#[test]
fn config_bag() {
let bag = ConfigBag::base();
#[derive(Debug)]
struct Region(&'static str);
impl Storable for Region {
type Storer = StoreReplace<Self>;
}
let bag = bag.with_fn("service config", |layer: &mut Layer| {
layer.store_put(Region("asdf"));
});
assert_eq!(bag.load::<Region>().unwrap().0, "asdf");
#[derive(Debug)]
struct SigningName(&'static str);
impl Storable for SigningName {
type Storer = StoreReplace<Self>;
}
let operation_config = bag.with_fn("operation", |layer: &mut Layer| {
layer.store_put(SigningName("s3"));
});
assert_eq!(operation_config.load::<SigningName>().unwrap().0, "s3");
#[derive(Debug)]
struct Prop;
impl Storable for Prop {
type Storer = StoreReplace<Self>;
}
let mut open_bag = operation_config.with_fn("my_custom_info", |_bag: &mut Layer| {});
open_bag.interceptor_state().store_put(Prop);
assert_eq!(open_bag.layers().count(), 4);
}
#[test]
fn store_append() {
let mut layer = Layer::new("test");
#[derive(Debug, PartialEq, Eq)]
struct Interceptor(&'static str);
impl Storable for Interceptor {
type Storer = StoreAppend<Interceptor>;
}
layer.clear::<Interceptor>();
layer.store_append(Interceptor("123"));
layer.store_append(Interceptor("456"));
let mut second_layer = Layer::new("next");
second_layer.store_append(Interceptor("789"));
let mut bag = ConfigBag::of_layers(vec![layer, second_layer]);
assert_eq!(
bag.load::<Interceptor>().collect::<Vec<_>>(),
vec![
&Interceptor("789"),
&Interceptor("456"),
&Interceptor("123")
]
);
let mut final_layer = Layer::new("final");
final_layer.clear::<Interceptor>();
bag.push_layer(final_layer);
assert_eq!(bag.load::<Interceptor>().count(), 0);
}
#[test]
fn store_append_many_layers() {
#[derive(Debug, PartialEq, Eq, Clone)]
struct TestItem(i32, i32);
impl Storable for TestItem {
type Storer = StoreAppend<TestItem>;
}
let mut expected = vec![];
let mut bag = ConfigBag::base();
for layer_idx in 0..100 {
let mut layer = Layer::new(format!("{layer_idx}"));
for item in 0..100 {
expected.push(TestItem(layer_idx, item));
layer.store_append(TestItem(layer_idx, item));
}
bag.push_layer(layer);
}
expected.reverse();
assert_eq!(
bag.load::<TestItem>().cloned().collect::<Vec<_>>(),
expected
);
}
#[test]
fn adding_layers() {
let mut layer_1 = Layer::new("layer1");
let mut layer_2 = Layer::new("layer2");
#[derive(Clone, Debug, PartialEq, Eq, Default)]
struct Foo(usize);
impl Storable for Foo {
type Storer = StoreReplace<Foo>;
}
layer_1.store_put(Foo(0));
layer_2.store_put(Foo(1));
let layer_1 = layer_1.freeze();
let layer_2 = layer_2.freeze();
let mut bag_1 = ConfigBag::base();
let mut bag_2 = ConfigBag::base();
bag_1
.push_shared_layer(layer_1.clone())
.push_shared_layer(layer_2.clone());
bag_2.push_shared_layer(layer_2).push_shared_layer(layer_1);
assert_eq!(bag_1.load::<Foo>(), Some(&Foo(1)));
assert_eq!(bag_2.load::<Foo>(), Some(&Foo(0)));
bag_1.interceptor_state().store_put(Foo(3));
assert_eq!(bag_1.load::<Foo>(), Some(&Foo(3)));
}
#[test]
fn get_mut_or_else() {
#[derive(Clone, Debug, PartialEq, Eq, Default)]
struct Foo(usize);
impl Storable for Foo {
type Storer = StoreReplace<Foo>;
}
let mut bag = ConfigBag::base();
assert_eq!(bag.get_mut::<Foo>(), None);
assert_eq!(bag.get_mut_or_default::<Foo>(), &Foo(0));
bag.get_mut_or_default::<Foo>().0 += 1;
assert_eq!(bag.load::<Foo>(), Some(&Foo(1)));
let old_ref = bag.load::<Foo>().unwrap();
assert_eq!(old_ref, &Foo(1));
bag.get_mut::<Foo>().unwrap().0 += 1;
let new_ref = bag.load::<Foo>().unwrap();
assert_eq!(new_ref, &Foo(2));
bag.interceptor_state().unset::<Foo>();
assert_eq!(bag.get_mut::<Foo>(), None);
assert_eq!(bag.get_mut_or_default::<Foo>(), &Foo(0));
}
#[test]
fn get_mut_from_interceptor_state() {
#[derive(Debug, PartialEq, Eq, Default)]
struct Foo(usize);
impl Storable for Foo {
type Storer = StoreReplace<Self>;
}
#[derive(Clone, Debug, PartialEq, Eq, Default)]
struct Bar(usize);
impl Storable for Bar {
type Storer = StoreReplace<Self>;
}
let mut bag = ConfigBag::base();
assert!(bag.get_mut_from_interceptor_state::<Foo>().is_none());
bag.interceptor_state().store_put(Foo(1));
assert_eq!(
bag.get_mut_from_interceptor_state::<Foo>(),
Some(&mut Foo(1))
);
let mut layer = Layer::new("test");
layer.store_put(Bar(1));
bag.push_layer(layer);
assert!(bag.get_mut_from_interceptor_state::<Bar>().is_none());
}
#[test]
fn cloning_layers() {
#[derive(Clone, Debug)]
struct TestStr(String);
impl Storable for TestStr {
type Storer = StoreReplace<TestStr>;
}
let mut layer_1 = CloneableLayer::new("layer_1");
let expected_str = "I can be cloned";
layer_1.store_put(TestStr(expected_str.to_owned()));
let layer_1_cloned = layer_1.clone();
assert_eq!(expected_str, &layer_1_cloned.load::<TestStr>().unwrap().0);
layer_1.unset::<TestStr>();
assert!(layer_1.try_clone().unwrap().load::<TestStr>().is_none());
let _ = layer_1
.try_clone()
.expect("clone 1")
.try_clone()
.expect("clone 2");
#[derive(Clone, Debug)]
struct Rope(String);
impl Storable for Rope {
type Storer = StoreAppend<Rope>;
}
let mut layer_2 = CloneableLayer::new("layer_2");
layer_2.store_append(Rope("A".to_owned()));
layer_2.store_append(Rope("big".to_owned()));
layer_2.store_append(Rope("rope".to_owned()));
let layer_2_cloned = layer_2.clone();
let rope = layer_2_cloned.load::<Rope>().cloned().collect::<Vec<_>>();
assert_eq!(
"A big rope",
rope.iter()
.rev()
.map(|r| r.0.clone())
.collect::<Vec<_>>()
.join(" ")
);
}
}