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}