aws_smithy_types/
config_bag.rs

1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6//! Layers and layered bags of configuration data.
7//!
8//! The [`ConfigBag`](crate::config_bag::ConfigBag) structure is used to store and pass around configuration for client operations.
9//! Interacting with it may be required in order to write an `Interceptor` or `RuntimePlugin` to
10//! customize a client.
11//!
12//! A `ConfigBag` is essentially a stack of several immutable and sharable layers, with a single _mutable_ layer at
13//! the top of the stack that is called "interceptor state". The intent of this last mutable layer is to allow for
14//! more performant mutation of config within the execution of an operation.
15//!
16//! There are three separate layer types to be aware of when using a `ConfigBag`:
17//! 1. [`Layer`](crate::config_bag::Layer) - A mutable layer. This is usually only used for adding config
18//!    to the `ConfigBag`, but is also used for the interceptor state.
19//! 2. [`CloneableLayer`](crate::config_bag::CloneableLayer) - Identical to `Layer`, except that it requires
20//!    `Clone` bounds on the items added to it so that it can be deep cloned. Can be converted to a `Layer`
21//!    while retaining the cloneability of its items such that the resulting layer could be cloned as long as
22//!    nothing else is added to it later. A `Layer` cannot be converted back into a `CloneableLayer`.
23//! 3. [`FrozenLayer`](crate::config_bag::FrozenLayer) - Basically an [`Arc`](std::sync::Arc) wrapper around
24//!    a `Layer`. This wrapper is used to make the layer immutable, and to make it shareable between multiple
25//!    `ConfigBag` instances. The frozen layer can be converted back to a `Layer` if there is only a single reference to it.
26//!
27//! All of `Layer`, `CloneableLayer`, `FrozenLayer`, and `ConfigBag` are considered to be "bag" types.
28//! That is, they store arbitrary types so long as they implement the [`Storable`](crate::config_bag::Storable) trait.
29//!
30//! A `Storable` requires a `Storer` to be configured, and the storer allows for storables to be stored
31//! in two different modes:
32//! 1. [`StoreReplace`](crate::config_bag::StoreReplace) - Only one value of this type is allowed in a bag, and
33//!    calling [`store_put()`](crate::config_bag::Layer::store_put) multiple times will replace the existing value
34//!    in the bag. Calling [`load::<T>()`](crate::config_bag::Layer::load) returns exactly one value, if present.
35//! 2. [`StoreAppend`](crate::config_bag::StoreAppend) - Multiple values of this type are allowed in a bag, and
36//!    calling [`store_append()`](crate::config_bag::Layer::store_append) will add an additional value of this type
37//!    to the bag. Calling [`load::<T>()`](crate::config_bag::Layer::load) returns an iterator over multiple values.
38//!
39//! # Examples
40//!
41//! Creating a storable data type with `StoreReplace`:
42//!
43//! ```no_run
44//! use aws_smithy_types::config_bag::{Storable, StoreReplace};
45//!
46//! #[derive(Debug)]
47//! struct SomeDataType {
48//!     some_data: String,
49//! }
50//! impl Storable for SomeDataType {
51//!     type Storer = StoreReplace<Self>;
52//! }
53//! ```
54//!
55//! Creating a storable data type with `StoreAppend`:
56//!
57//! ```no_run
58//! use aws_smithy_types::config_bag::{Storable, StoreAppend};
59//!
60//! #[derive(Debug)]
61//! struct SomeDataType {
62//!     some_data: String,
63//! }
64//! impl Storable for SomeDataType {
65//!     type Storer = StoreAppend<Self>;
66//! }
67//! ```
68//!
69//! Storing a storable in a bag when it is configured for `StoreReplace`:
70//!
71//! ```no_run
72//! # use aws_smithy_types::config_bag::{Storable, StoreReplace};
73//! # #[derive(Clone, Debug)]
74//! # struct SomeDataType { some_data: String }
75//! # impl Storable for SomeDataType { type Storer = StoreReplace<Self>; }
76//! use aws_smithy_types::config_bag::{CloneableLayer, Layer};
77//!
78//! let mut layer = Layer::new("example");
79//! layer.store_put(SomeDataType { some_data: "some data".to_string() });
80//!
81//! // `store_put` can be called again to replace the original value:
82//! layer.store_put(SomeDataType { some_data: "replacement".to_string() });
83//!
84//! // Note: `SomeDataType` below must implement `Clone` to work with `CloneableLayer`
85//! let mut cloneable = CloneableLayer::new("example");
86//! cloneable.store_put(SomeDataType { some_data: "some data".to_string() });
87//! ```
88//!
89//! Storing a storable in a bag when it is configured for `StoreAppend`:
90//!
91//! ```no_run
92//! # use aws_smithy_types::config_bag::{Storable, StoreAppend};
93//! # #[derive(Clone, Debug)]
94//! # struct SomeDataType { some_data: String }
95//! # impl Storable for SomeDataType { type Storer = StoreAppend<Self>; }
96//! use aws_smithy_types::config_bag::{CloneableLayer, Layer};
97//!
98//! let mut layer = Layer::new("example");
99//! layer.store_append(SomeDataType { some_data: "1".to_string() });
100//! layer.store_append(SomeDataType { some_data: "2".to_string() });
101//! ```
102//!
103//! Loading a `StoreReplace` value from a bag:
104//!
105//! ```no_run
106//! # use aws_smithy_types::config_bag::{Storable, StoreReplace};
107//! # #[derive(Clone, Debug)]
108//! # struct SomeDataType { some_data: String }
109//! # impl Storable for SomeDataType { type Storer = StoreReplace<Self>; }
110//! # use aws_smithy_types::config_bag::Layer;
111//! # let layer = Layer::new("example");
112//! let maybe_value: Option<&SomeDataType> = layer.load::<SomeDataType>();
113//! ```
114//!
115//! Loading a `StoreAppend` value from a bag:
116//!
117//! ```no_run
118//! # use aws_smithy_types::config_bag::{Storable, StoreAppend};
119//! # #[derive(Clone, Debug)]
120//! # struct SomeDataType { some_data: String }
121//! # impl Storable for SomeDataType { type Storer = StoreAppend<Self>; }
122//! # use aws_smithy_types::config_bag::Layer;
123//! # let layer = Layer::new("example");
124//! let values: Vec<SomeDataType> = layer.load::<SomeDataType>().cloned().collect();
125//!
126//! // or iterate over them directly:
127//! for value in layer.load::<SomeDataType>() {
128//!     # let _ = value;
129//!     // ...
130//! }
131//! ```
132//!
133mod storable;
134mod typeid_map;
135
136use crate::config_bag::typeid_map::TypeIdMap;
137use crate::type_erasure::TypeErasedBox;
138use std::any::{type_name, TypeId};
139use std::borrow::Cow;
140use std::fmt::{Debug, Formatter};
141use std::iter::Rev;
142use std::marker::PhantomData;
143use std::ops::Deref;
144use std::slice::Iter;
145use std::sync::Arc;
146
147pub use storable::{AppendItemIter, Storable, Store, StoreAppend, StoreReplace};
148
149/// [`FrozenLayer`] is the immutable and shareable form of [`Layer`].
150///
151/// See the [module docs](crate::config_bag) for more documentation.
152#[derive(Clone, Debug)]
153#[must_use]
154pub struct FrozenLayer(Arc<Layer>);
155
156impl FrozenLayer {
157    /// Attempts to convert this bag directly into a [`Layer`] if no other references exist.
158    pub fn try_modify(self) -> Option<Layer> {
159        Arc::try_unwrap(self.0).ok()
160    }
161}
162
163impl Deref for FrozenLayer {
164    type Target = Layer;
165
166    fn deref(&self) -> &Self::Target {
167        &self.0
168    }
169}
170
171impl From<Layer> for FrozenLayer {
172    fn from(layer: Layer) -> Self {
173        FrozenLayer(Arc::new(layer))
174    }
175}
176
177/// Private module to keep Value type while avoiding "private type in public latest"
178pub(crate) mod value {
179    #[derive(Clone, Debug)]
180    pub enum Value<T> {
181        Set(T),
182        ExplicitlyUnset(&'static str),
183    }
184
185    impl<T: Default> Default for Value<T> {
186        fn default() -> Self {
187            Self::Set(Default::default())
188        }
189    }
190}
191use value::Value;
192
193/// [`CloneableLayer`] allows itself to be cloned. This is useful when a type that implements
194/// `Clone` wishes to store a config layer.
195///
196/// It ensures that all the items in `CloneableLayer` are `Clone` upon entry, e.g. when they are
197/// first stored, the mutable methods require that they have a `Clone` bound on them.
198///
199/// While [`FrozenLayer`] is also cloneable, which is a shallow clone via `Arc`, `CloneableLayer`
200/// performs a deep clone that newly allocates all the items stored in it.
201///
202/// Cloneable enforces that non clone items cannot be added
203/// ```rust,compile_fail
204/// use aws_smithy_types::config_bag::Storable;
205/// use aws_smithy_types::config_bag::StoreReplace;
206/// use aws_smithy_types::config_bag::CloneableLayer;
207/// #[derive(Debug)]
208/// struct MyNotCloneStruct;
209///
210/// impl Storable for MyNotCloneStruct {
211///     type Storer = StoreReplace<MyNotCloneStruct>;
212/// }
213/// let mut layer = CloneableLayer::new("layer");
214/// layer.store_put(MyNotCloneStruct);
215/// ```
216///
217/// See the [module docs](crate::config_bag) for more documentation.
218#[derive(Debug, Default)]
219pub struct CloneableLayer(Layer);
220
221impl Deref for CloneableLayer {
222    type Target = Layer;
223
224    fn deref(&self) -> &Self::Target {
225        &self.0
226    }
227}
228
229impl Clone for CloneableLayer {
230    fn clone(&self) -> Self {
231        Self(
232            self.try_clone()
233                .expect("only cloneable types can be inserted"),
234        )
235    }
236}
237
238impl From<CloneableLayer> for Layer {
239    fn from(cloneable_layer: CloneableLayer) -> Layer {
240        cloneable_layer.0
241    }
242}
243
244// We need to "override" the mutable methods to encode the information that an item being stored
245// implements `Clone`. For the immutable methods, they can just be delegated via the `Deref` trait.
246impl CloneableLayer {
247    /// Creates a new `CloneableLayer` with a given name
248    pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
249        Self(Layer::new(name))
250    }
251
252    /// Converts this layer into a frozen layer that can no longer be mutated.
253    pub fn freeze(self) -> FrozenLayer {
254        self.0.into()
255    }
256
257    /// Removes `T` from this bag
258    pub fn unset<T: Send + Sync + Clone + Debug + 'static>(&mut self) -> &mut Self {
259        self.put_directly_cloneable::<StoreReplace<T>>(Value::ExplicitlyUnset(type_name::<T>()));
260        self
261    }
262
263    fn put_directly_cloneable<T: Store>(&mut self, value: T::StoredType) -> &mut Self
264    where
265        T::StoredType: Clone,
266    {
267        self.0.props.insert(
268            TypeId::of::<T::StoredType>(),
269            TypeErasedBox::new_with_clone(value),
270        );
271        self
272    }
273
274    /// Stores `item` of type `T` into the config bag, overriding a previous value of the same type
275    pub fn store_put<T>(&mut self, item: T) -> &mut Self
276    where
277        T: Storable<Storer = StoreReplace<T>> + Clone,
278    {
279        self.put_directly_cloneable::<StoreReplace<T>>(Value::Set(item));
280        self
281    }
282
283    /// Stores `item` of type `T` into the config bag, overriding a previous value of the same type,
284    /// or unsets it by passing a `None`
285    pub fn store_or_unset<T>(&mut self, item: Option<T>) -> &mut Self
286    where
287        T: Storable<Storer = StoreReplace<T>> + Clone,
288    {
289        let item = match item {
290            Some(item) => Value::Set(item),
291            None => Value::ExplicitlyUnset(type_name::<T>()),
292        };
293        self.put_directly_cloneable::<StoreReplace<T>>(item);
294        self
295    }
296
297    /// Stores `item` of type `T` into the config bag, appending it to the existing list of the same
298    /// type
299    pub fn store_append<T>(&mut self, item: T) -> &mut Self
300    where
301        T: Storable<Storer = StoreAppend<T>> + Clone,
302    {
303        match self.get_mut_or_default::<StoreAppend<T>>() {
304            Value::Set(list) => list.push(item),
305            v @ Value::ExplicitlyUnset(_) => *v = Value::Set(vec![item]),
306        }
307        self
308    }
309
310    /// Clears the value of type `T` from the config bag
311    pub fn clear<T>(&mut self)
312    where
313        T: Storable<Storer = StoreAppend<T>> + Clone,
314    {
315        self.put_directly_cloneable::<StoreAppend<T>>(Value::ExplicitlyUnset(type_name::<T>()));
316    }
317
318    fn get_mut_or_default<T: Send + Sync + Store + 'static>(&mut self) -> &mut T::StoredType
319    where
320        T::StoredType: Default + Clone,
321    {
322        self.0
323            .props
324            .entry(TypeId::of::<T::StoredType>())
325            .or_insert_with(|| TypeErasedBox::new_with_clone(T::StoredType::default()))
326            .downcast_mut()
327            .expect("typechecked")
328    }
329}
330
331/// A named layer comprising a config bag
332///
333/// See the [module docs](crate::config_bag) for more documentation.
334#[derive(Default)]
335pub struct Layer {
336    name: Cow<'static, str>,
337    props: TypeIdMap<TypeErasedBox>,
338}
339
340impl Debug for Layer {
341    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
342        struct Items<'a>(&'a Layer);
343        impl Debug for Items<'_> {
344            fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
345                f.debug_list().entries(self.0.props.values()).finish()
346            }
347        }
348        f.debug_struct("Layer")
349            .field("name", &self.name)
350            .field("items", &Items(self))
351            .finish()
352    }
353}
354
355impl Layer {
356    fn try_clone(&self) -> Option<Self> {
357        let new_props = self
358            .props
359            .iter()
360            .flat_map(|(tyid, erased)| erased.try_clone().map(|e| (*tyid, e)))
361            .collect::<TypeIdMap<_>>();
362        if new_props.len() == self.props.len() {
363            Some(Layer {
364                name: self.name.clone(),
365                props: new_props,
366            })
367        } else {
368            None
369        }
370    }
371
372    /// Inserts `value` into the layer directly
373    fn put_directly<T: Store>(&mut self, value: T::StoredType) -> &mut Self {
374        self.props
375            .insert(TypeId::of::<T::StoredType>(), TypeErasedBox::new(value));
376        self
377    }
378
379    /// Returns true if this layer is empty.
380    pub fn is_empty(&self) -> bool {
381        self.props.is_empty()
382    }
383
384    /// Converts this layer into a frozen layer that can no longer be mutated.
385    pub fn freeze(self) -> FrozenLayer {
386        self.into()
387    }
388
389    /// Create a new Layer with a given name
390    pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
391        let name = name.into();
392        Self {
393            name,
394            props: Default::default(),
395        }
396    }
397
398    /// Changes the name of this layer.
399    pub fn with_name(self, name: impl Into<Cow<'static, str>>) -> Self {
400        Self {
401            name: name.into(),
402            props: self.props,
403        }
404    }
405
406    /// Load a storable item from the bag
407    pub fn load<T: Storable>(&self) -> <T::Storer as Store>::ReturnedType<'_> {
408        T::Storer::merge_iter(ItemIter {
409            inner: BagIter {
410                head: Some(self),
411                tail: [].iter().rev(),
412            },
413            t: Default::default(),
414        })
415    }
416
417    /// Remove `T` from this bag
418    pub fn unset<T: Send + Sync + Debug + 'static>(&mut self) -> &mut Self {
419        self.put_directly::<StoreReplace<T>>(Value::ExplicitlyUnset(type_name::<T>()));
420        self
421    }
422
423    /// Stores `item` of type `T` into the config bag, overriding a previous value of the same type
424    pub fn store_put<T>(&mut self, item: T) -> &mut Self
425    where
426        T: Storable<Storer = StoreReplace<T>>,
427    {
428        self.put_directly::<StoreReplace<T>>(Value::Set(item));
429        self
430    }
431
432    /// Stores `item` of type `T` into the config bag, overriding a previous value of the same type,
433    /// or unsets it by passing a `None`
434    pub fn store_or_unset<T>(&mut self, item: Option<T>) -> &mut Self
435    where
436        T: Storable<Storer = StoreReplace<T>>,
437    {
438        let item = match item {
439            Some(item) => Value::Set(item),
440            None => Value::ExplicitlyUnset(type_name::<T>()),
441        };
442        self.put_directly::<StoreReplace<T>>(item);
443        self
444    }
445
446    /// This can only be used for types that use [`StoreAppend`]
447    /// ```
448    /// use aws_smithy_types::config_bag::{ConfigBag, Layer, Storable, StoreAppend, StoreReplace};
449    /// let mut layer_1 = Layer::new("example");
450    /// #[derive(Debug, PartialEq, Eq)]
451    /// struct Interceptor(&'static str);
452    /// impl Storable for Interceptor {
453    ///     type Storer = StoreAppend<Interceptor>;
454    /// }
455    ///
456    /// layer_1.store_append(Interceptor("321"));
457    /// layer_1.store_append(Interceptor("654"));
458    ///
459    /// let mut layer_2 = Layer::new("second layer");
460    /// layer_2.store_append(Interceptor("987"));
461    ///
462    /// let bag = ConfigBag::of_layers(vec![layer_1, layer_2]);
463    ///
464    /// assert_eq!(
465    ///     bag.load::<Interceptor>().collect::<Vec<_>>(),
466    ///     vec![&Interceptor("987"), &Interceptor("654"), &Interceptor("321")]
467    /// );
468    /// ```
469    pub fn store_append<T>(&mut self, item: T) -> &mut Self
470    where
471        T: Storable<Storer = StoreAppend<T>>,
472    {
473        match self.get_mut_or_default::<StoreAppend<T>>() {
474            Value::Set(list) => list.push(item),
475            v @ Value::ExplicitlyUnset(_) => *v = Value::Set(vec![item]),
476        }
477        self
478    }
479
480    /// Clears the value of type `T` from the config bag
481    ///
482    /// This internally marks the item of type `T` as cleared as opposed to wiping it out from the
483    /// config bag.
484    pub fn clear<T>(&mut self)
485    where
486        T: Storable<Storer = StoreAppend<T>>,
487    {
488        self.put_directly::<StoreAppend<T>>(Value::ExplicitlyUnset(type_name::<T>()));
489    }
490
491    /// Retrieves the value of type `T` from this layer if exists
492    fn get<T: Send + Sync + Store + 'static>(&self) -> Option<&T::StoredType> {
493        self.props
494            .get(&TypeId::of::<T::StoredType>())
495            .map(|t| t.downcast_ref().expect("typechecked"))
496    }
497
498    /// Returns a mutable reference to `T` if it is stored in this layer
499    fn get_mut<T: Send + Sync + Store + 'static>(&mut self) -> Option<&mut T::StoredType> {
500        self.props
501            .get_mut(&TypeId::of::<T::StoredType>())
502            .map(|t| t.downcast_mut().expect("typechecked"))
503    }
504
505    /// Returns a mutable reference to `T` if it is stored in this layer, otherwise returns the
506    /// [`Default`] implementation of `T`
507    fn get_mut_or_default<T: Send + Sync + Store + 'static>(&mut self) -> &mut T::StoredType
508    where
509        T::StoredType: Default,
510    {
511        self.props
512            .entry(TypeId::of::<T::StoredType>())
513            .or_insert_with(|| TypeErasedBox::new(T::StoredType::default()))
514            .downcast_mut()
515            .expect("typechecked")
516    }
517}
518
519/// Layered configuration structure
520///
521/// See the [module docs](crate::config_bag) for more documentation.
522#[must_use]
523pub struct ConfigBag {
524    interceptor_state: Layer,
525    tail: Vec<FrozenLayer>,
526}
527
528impl Debug for ConfigBag {
529    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
530        struct Layers<'a>(&'a ConfigBag);
531        impl Debug for Layers<'_> {
532            fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
533                f.debug_list().entries(self.0.layers()).finish()
534            }
535        }
536        f.debug_struct("ConfigBag")
537            .field("layers", &Layers(self))
538            .finish()
539    }
540}
541
542impl ConfigBag {
543    /// Create a new config bag "base".
544    pub fn base() -> Self {
545        ConfigBag {
546            interceptor_state: Layer {
547                name: Cow::Borrowed("interceptor_state"),
548                props: Default::default(),
549            },
550            tail: vec![],
551        }
552    }
553
554    /// Create a [`ConfigBag`] consisting of the given layers.
555    pub fn of_layers(layers: impl IntoIterator<Item = Layer>) -> Self {
556        let mut bag = ConfigBag::base();
557        for layer in layers {
558            bag.push_layer(layer);
559        }
560        bag
561    }
562
563    /// Add the given layer to the config bag.
564    pub fn push_layer(&mut self, layer: Layer) -> &mut Self {
565        self.tail.push(layer.freeze());
566        self
567    }
568
569    /// Add a frozen/shared layer to the config bag.
570    pub fn push_shared_layer(&mut self, layer: FrozenLayer) -> &mut Self {
571        self.tail.push(layer);
572        self
573    }
574
575    /// Return a reference to the mutable interceptor state.
576    pub fn interceptor_state(&mut self) -> &mut Layer {
577        &mut self.interceptor_state
578    }
579
580    /// Load a value (or values) of type `T` depending on how `T` implements [`Storable`]
581    pub fn load<T: Storable>(&self) -> <T::Storer as Store>::ReturnedType<'_> {
582        self.sourced_get::<T::Storer>()
583    }
584
585    /// Return a mutable reference to `T` if it is stored in the top layer of the bag
586    pub fn get_mut<T>(&mut self) -> Option<&mut T>
587    where
588        T: Storable<Storer = StoreReplace<T>> + Send + Sync + Debug + Clone + 'static,
589    {
590        // this code looks weird to satisfy the borrow checker—we can't keep the result of `get_mut`
591        // alive (even in a returned branch) and then call `store_put`. So: drop the borrow immediately
592        // store, the value, then pull it right back
593        if self
594            .interceptor_state
595            .get_mut::<StoreReplace<T>>()
596            .is_none()
597        {
598            let new_item = match self.tail.iter().find_map(|b| b.load::<T>()) {
599                Some(item) => item.clone(),
600                None => return None,
601            };
602            self.interceptor_state.store_put(new_item);
603            self.get_mut()
604        } else if matches!(
605            self.interceptor_state.get::<StoreReplace<T>>(),
606            Some(Value::ExplicitlyUnset(_))
607        ) {
608            None
609        } else if let Some(Value::Set(t)) = self.interceptor_state.get_mut::<StoreReplace<T>>() {
610            Some(t)
611        } else {
612            unreachable!()
613        }
614    }
615
616    /// Returns a mutable reference to `T` if it is stored in the top layer of the bag
617    ///
618    /// - If `T` is in a deeper layer of the bag, that value will be cloned and inserted into the top layer
619    /// - If `T` is not present in the bag, the [`Default`] implementation will be used.
620    pub fn get_mut_or_default<T>(&mut self) -> &mut T
621    where
622        T: Storable<Storer = StoreReplace<T>> + Send + Sync + Debug + Clone + Default + 'static,
623    {
624        self.get_mut_or_else(|| T::default())
625    }
626
627    /// Returns a mutable reference to `T` if it is stored in the top layer of the bag
628    ///
629    /// - If `T` is in a deeper layer of the bag, that value will be cloned and inserted into the top layer
630    /// - If `T` is not present in the bag, `default` will be used to construct a new value
631    pub fn get_mut_or_else<T>(&mut self, default: impl Fn() -> T) -> &mut T
632    where
633        T: Storable<Storer = StoreReplace<T>> + Send + Sync + Debug + Clone + 'static,
634    {
635        // this code looks weird to satisfy the borrow checker—we can't keep the result of `get_mut`
636        // alive (even in a returned branch) and then call `store_put`. So: drop the borrow immediately
637        // store, the value, then pull it right back
638        if self.get_mut::<T>().is_none() {
639            self.interceptor_state.store_put((default)());
640            return self
641                .get_mut()
642                .expect("item was just stored in the top layer");
643        }
644        // above it was None
645        self.get_mut().unwrap()
646    }
647
648    /// Add another layer to this configuration bag
649    ///
650    /// Hint: If you want to re-use this layer, call `freeze` first.
651    ///
652    /// # Examples
653    /// ```
654    /// use aws_smithy_types::config_bag::{ConfigBag, Layer, Storable, StoreReplace};
655    ///
656    /// #[derive(Debug, Eq, PartialEq)]
657    /// struct ExampleStr(&'static str);
658    /// impl Storable for ExampleStr {
659    ///     type Storer = StoreReplace<Self>;
660    /// }
661    ///
662    /// #[derive(Debug, Eq, PartialEq)]
663    /// struct ExampleInt(i32);
664    /// impl Storable for ExampleInt {
665    ///     type Storer = StoreReplace<Self>;
666    /// }
667    ///
668    /// let mut bag = ConfigBag::base();
669    /// bag = bag.with_fn("first", |layer: &mut Layer| { layer.store_put(ExampleStr("a")); });
670    ///
671    /// // We can now load the example string out
672    /// assert_eq!(bag.load::<ExampleStr>(), Some(&ExampleStr("a")));
673    ///
674    /// // But there isn't a number stored in the bag yet
675    /// assert_eq!(bag.load::<ExampleInt>(), None);
676    ///
677    /// // Add a layer with an example int
678    /// bag = bag.with_fn("second", |layer: &mut Layer| { layer.store_put(ExampleInt(1)); });
679    ///
680    /// // Now the example int can be retrieved
681    /// assert_eq!(bag.load::<ExampleInt>(), Some(&ExampleInt(1)));
682    /// ```
683    pub fn with_fn(
684        self,
685        name: impl Into<Cow<'static, str>>,
686        next: impl Fn(&mut Layer),
687    ) -> ConfigBag {
688        let mut new_layer = Layer::new(name);
689        next(&mut new_layer);
690        let ConfigBag {
691            interceptor_state: head,
692            mut tail,
693        } = self;
694        tail.push(head.freeze());
695        ConfigBag {
696            interceptor_state: new_layer,
697            tail,
698        }
699    }
700
701    /// Add a new layer with `name` after freezing the top layer so far
702    pub fn add_layer(self, name: impl Into<Cow<'static, str>>) -> ConfigBag {
703        self.with_fn(name, |_| {})
704    }
705
706    /// Return a value (or values) of type `T` depending on how it has been stored in a `ConfigBag`
707    ///
708    /// It flexibly chooses to return a single value vs. an iterator of values depending on how
709    /// `T` implements a [`Store`] trait.
710    pub fn sourced_get<T: Store>(&self) -> T::ReturnedType<'_> {
711        let stored_type_iter = ItemIter {
712            inner: self.layers(),
713            t: PhantomData,
714        };
715        T::merge_iter(stored_type_iter)
716    }
717
718    fn layers(&self) -> BagIter<'_> {
719        BagIter {
720            head: Some(&self.interceptor_state),
721            tail: self.tail.iter().rev(),
722        }
723    }
724}
725
726/// Iterator of items returned from [`ConfigBag`].
727pub struct ItemIter<'a, T> {
728    inner: BagIter<'a>,
729    t: PhantomData<T>,
730}
731
732impl<'a, T> Debug for ItemIter<'a, T> {
733    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
734        write!(f, "ItemIter")
735    }
736}
737
738impl<'a, T: 'a> Iterator for ItemIter<'a, T>
739where
740    T: Store,
741{
742    type Item = &'a T::StoredType;
743
744    fn next(&mut self) -> Option<Self::Item> {
745        match self.inner.next() {
746            Some(layer) => layer.get::<T>().or_else(|| self.next()),
747            None => None,
748        }
749    }
750}
751
752/// Iterator over the layers of a config bag
753struct BagIter<'a> {
754    head: Option<&'a Layer>,
755    tail: Rev<Iter<'a, FrozenLayer>>,
756}
757
758impl<'a> Iterator for BagIter<'a> {
759    type Item = &'a Layer;
760
761    fn next(&mut self) -> Option<Self::Item> {
762        if let Some(head) = self.head.take() {
763            Some(head)
764        } else {
765            self.tail.next().map(|t| t.deref())
766        }
767    }
768}
769
770#[cfg(test)]
771mod test {
772    use super::ConfigBag;
773    use crate::config_bag::{CloneableLayer, Layer, Storable, StoreAppend, StoreReplace};
774
775    #[test]
776    fn layered_property_bag() {
777        #[derive(Debug)]
778        struct Prop1;
779        impl Storable for Prop1 {
780            type Storer = StoreReplace<Self>;
781        }
782        #[derive(Debug)]
783        struct Prop2;
784        impl Storable for Prop2 {
785            type Storer = StoreReplace<Self>;
786        }
787        let layer_a = |bag: &mut Layer| {
788            bag.store_put(Prop1);
789        };
790
791        let layer_b = |bag: &mut Layer| {
792            bag.store_put(Prop2);
793        };
794
795        #[derive(Debug)]
796        struct Prop3;
797        impl Storable for Prop3 {
798            type Storer = StoreReplace<Self>;
799        }
800
801        let mut base_bag = ConfigBag::base()
802            .with_fn("a", layer_a)
803            .with_fn("b", layer_b);
804        base_bag.interceptor_state().store_put(Prop3);
805        assert!(base_bag.load::<Prop1>().is_some());
806
807        #[derive(Debug)]
808        struct Prop4;
809        impl Storable for Prop4 {
810            type Storer = StoreReplace<Self>;
811        }
812
813        let layer_c = |bag: &mut Layer| {
814            bag.store_put(Prop4);
815            bag.unset::<Prop3>();
816        };
817
818        let final_bag = base_bag.with_fn("c", layer_c);
819
820        assert!(final_bag.load::<Prop4>().is_some());
821        assert!(final_bag.load::<Prop1>().is_some());
822        assert!(final_bag.load::<Prop2>().is_some());
823        // we unset prop3
824        assert!(final_bag.load::<Prop3>().is_none());
825        println!("{:#?}", final_bag);
826    }
827
828    #[test]
829    fn config_bag() {
830        let bag = ConfigBag::base();
831        #[derive(Debug)]
832        struct Region(&'static str);
833        impl Storable for Region {
834            type Storer = StoreReplace<Self>;
835        }
836        let bag = bag.with_fn("service config", |layer: &mut Layer| {
837            layer.store_put(Region("asdf"));
838        });
839
840        assert_eq!(bag.load::<Region>().unwrap().0, "asdf");
841
842        #[derive(Debug)]
843        struct SigningName(&'static str);
844        impl Storable for SigningName {
845            type Storer = StoreReplace<Self>;
846        }
847        let operation_config = bag.with_fn("operation", |layer: &mut Layer| {
848            layer.store_put(SigningName("s3"));
849        });
850
851        assert_eq!(operation_config.load::<SigningName>().unwrap().0, "s3");
852
853        #[derive(Debug)]
854        struct Prop;
855        impl Storable for Prop {
856            type Storer = StoreReplace<Self>;
857        }
858        let mut open_bag = operation_config.with_fn("my_custom_info", |_bag: &mut Layer| {});
859        open_bag.interceptor_state().store_put(Prop);
860
861        assert_eq!(open_bag.layers().count(), 4);
862    }
863
864    #[test]
865    fn store_append() {
866        let mut layer = Layer::new("test");
867        #[derive(Debug, PartialEq, Eq)]
868        struct Interceptor(&'static str);
869        impl Storable for Interceptor {
870            type Storer = StoreAppend<Interceptor>;
871        }
872
873        layer.clear::<Interceptor>();
874        // you can only call store_append because interceptor is marked with a vec
875        layer.store_append(Interceptor("123"));
876        layer.store_append(Interceptor("456"));
877
878        let mut second_layer = Layer::new("next");
879        second_layer.store_append(Interceptor("789"));
880
881        let mut bag = ConfigBag::of_layers(vec![layer, second_layer]);
882
883        assert_eq!(
884            bag.load::<Interceptor>().collect::<Vec<_>>(),
885            vec![
886                &Interceptor("789"),
887                &Interceptor("456"),
888                &Interceptor("123")
889            ]
890        );
891
892        let mut final_layer = Layer::new("final");
893        final_layer.clear::<Interceptor>();
894        bag.push_layer(final_layer);
895        assert_eq!(bag.load::<Interceptor>().count(), 0);
896    }
897
898    #[test]
899    fn store_append_many_layers() {
900        #[derive(Debug, PartialEq, Eq, Clone)]
901        struct TestItem(i32, i32);
902        impl Storable for TestItem {
903            type Storer = StoreAppend<TestItem>;
904        }
905        let mut expected = vec![];
906        let mut bag = ConfigBag::base();
907        for layer_idx in 0..100 {
908            let mut layer = Layer::new(format!("{}", layer_idx));
909            for item in 0..100 {
910                expected.push(TestItem(layer_idx, item));
911                layer.store_append(TestItem(layer_idx, item));
912            }
913            bag.push_layer(layer);
914        }
915        expected.reverse();
916        assert_eq!(
917            bag.load::<TestItem>().cloned().collect::<Vec<_>>(),
918            expected
919        );
920    }
921
922    #[test]
923    fn adding_layers() {
924        let mut layer_1 = Layer::new("layer1");
925
926        let mut layer_2 = Layer::new("layer2");
927
928        #[derive(Clone, Debug, PartialEq, Eq, Default)]
929        struct Foo(usize);
930        impl Storable for Foo {
931            type Storer = StoreReplace<Foo>;
932        }
933
934        layer_1.store_put(Foo(0));
935        layer_2.store_put(Foo(1));
936
937        let layer_1 = layer_1.freeze();
938        let layer_2 = layer_2.freeze();
939
940        let mut bag_1 = ConfigBag::base();
941        let mut bag_2 = ConfigBag::base();
942        bag_1
943            .push_shared_layer(layer_1.clone())
944            .push_shared_layer(layer_2.clone());
945        bag_2.push_shared_layer(layer_2).push_shared_layer(layer_1);
946
947        // bags have same layers but in different orders
948        assert_eq!(bag_1.load::<Foo>(), Some(&Foo(1)));
949        assert_eq!(bag_2.load::<Foo>(), Some(&Foo(0)));
950
951        bag_1.interceptor_state().store_put(Foo(3));
952        assert_eq!(bag_1.load::<Foo>(), Some(&Foo(3)));
953    }
954
955    #[test]
956    fn get_mut_or_else() {
957        #[derive(Clone, Debug, PartialEq, Eq, Default)]
958        struct Foo(usize);
959        impl Storable for Foo {
960            type Storer = StoreReplace<Foo>;
961        }
962
963        let mut bag = ConfigBag::base();
964        assert_eq!(bag.get_mut::<Foo>(), None);
965        assert_eq!(bag.get_mut_or_default::<Foo>(), &Foo(0));
966        bag.get_mut_or_default::<Foo>().0 += 1;
967        assert_eq!(bag.load::<Foo>(), Some(&Foo(1)));
968
969        let old_ref = bag.load::<Foo>().unwrap();
970        assert_eq!(old_ref, &Foo(1));
971
972        // there is one in the bag, so it can be returned
973        //let mut next = bag.add_layer("next");
974        bag.get_mut::<Foo>().unwrap().0 += 1;
975        let new_ref = bag.load::<Foo>().unwrap();
976        assert_eq!(new_ref, &Foo(2));
977
978        bag.interceptor_state().unset::<Foo>();
979        // if it was unset, we can't clone the current one, that would be wrong
980        assert_eq!(bag.get_mut::<Foo>(), None);
981        assert_eq!(bag.get_mut_or_default::<Foo>(), &Foo(0));
982    }
983
984    #[test]
985    fn cloning_layers() {
986        #[derive(Clone, Debug)]
987        struct TestStr(String);
988        impl Storable for TestStr {
989            type Storer = StoreReplace<TestStr>;
990        }
991        let mut layer_1 = CloneableLayer::new("layer_1");
992        let expected_str = "I can be cloned";
993        layer_1.store_put(TestStr(expected_str.to_owned()));
994        let layer_1_cloned = layer_1.clone();
995        assert_eq!(expected_str, &layer_1_cloned.load::<TestStr>().unwrap().0);
996
997        // Should still be cloneable after unsetting a field
998        layer_1.unset::<TestStr>();
999        assert!(layer_1.try_clone().unwrap().load::<TestStr>().is_none());
1000
1001        // It is cloneable multiple times in succession
1002        let _ = layer_1
1003            .try_clone()
1004            .expect("clone 1")
1005            .try_clone()
1006            .expect("clone 2");
1007
1008        #[derive(Clone, Debug)]
1009        struct Rope(String);
1010        impl Storable for Rope {
1011            type Storer = StoreAppend<Rope>;
1012        }
1013        let mut layer_2 = CloneableLayer::new("layer_2");
1014        layer_2.store_append(Rope("A".to_owned()));
1015        layer_2.store_append(Rope("big".to_owned()));
1016        layer_2.store_append(Rope("rope".to_owned()));
1017        let layer_2_cloned = layer_2.clone();
1018        let rope = layer_2_cloned.load::<Rope>().cloned().collect::<Vec<_>>();
1019        assert_eq!(
1020            "A big rope",
1021            rope.iter()
1022                .rev()
1023                .map(|r| r.0.clone())
1024                .collect::<Vec<_>>()
1025                .join(" ")
1026        );
1027    }
1028}