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 mutable reference to the 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 found within the interceptor state.
586 ///
587 /// This method does not search the tail of the config bag (i.e., the collection of frozen layers).
588 ///
589 /// If the caller is unsure whether `T` exists in the interceptor state,
590 /// consider using [`Self::get_mut`] instead, which requires `T` to implement `Clone`, however.
591 pub fn get_mut_from_interceptor_state<T>(&mut self) -> Option<&mut T>
592 where
593 T: Storable<Storer = StoreReplace<T>> + Send + Sync + Debug + 'static,
594 {
595 match self.interceptor_state.get_mut::<StoreReplace<T>>() {
596 Some(Value::ExplicitlyUnset(_)) => None,
597 Some(Value::Set(t)) => Some(t),
598 None => None,
599 }
600 }
601
602 /// Return a mutable reference to `T` if found within the config bag
603 ///
604 /// This method requires `T` to implement `Clone` because, if the requested item is found in the tail of the config bag,
605 /// it will be cloned and moved to the head (i.e., the interceptor state).
606 ///
607 /// If the caller is certain that `T` already exists in the interceptor state,
608 /// consider using [`Self::get_mut_from_interceptor_state`] instead, which does not require `T` to be `Clone`.
609 pub fn get_mut<T>(&mut self) -> Option<&mut T>
610 where
611 T: Storable<Storer = StoreReplace<T>> + Send + Sync + Debug + Clone + 'static,
612 {
613 if self
614 .interceptor_state
615 .get_mut::<StoreReplace<T>>()
616 .is_none()
617 {
618 let new_item = match self.tail.iter().find_map(|b| b.load::<T>()) {
619 Some(item) => item.clone(),
620 None => return None,
621 };
622 self.interceptor_state.store_put(new_item);
623 }
624 self.get_mut_from_interceptor_state()
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, the [`Default`] implementation will be used.
631 pub fn get_mut_or_default<T>(&mut self) -> &mut T
632 where
633 T: Storable<Storer = StoreReplace<T>> + Send + Sync + Debug + Clone + Default + 'static,
634 {
635 self.get_mut_or_else(|| T::default())
636 }
637
638 /// Returns a mutable reference to `T` if it is stored in the top layer of the bag
639 ///
640 /// - If `T` is in a deeper layer of the bag, that value will be cloned and inserted into the top layer
641 /// - If `T` is not present in the bag, `default` will be used to construct a new value
642 pub fn get_mut_or_else<T>(&mut self, default: impl Fn() -> T) -> &mut T
643 where
644 T: Storable<Storer = StoreReplace<T>> + Send + Sync + Debug + Clone + 'static,
645 {
646 // this code looks weird to satisfy the borrow checker—we can't keep the result of `get_mut`
647 // alive (even in a returned branch) and then call `store_put`. So: drop the borrow immediately
648 // store, the value, then pull it right back
649 if self.get_mut::<T>().is_none() {
650 self.interceptor_state.store_put((default)());
651 return self
652 .get_mut()
653 .expect("item was just stored in the top layer");
654 }
655 // above it was None
656 self.get_mut().unwrap()
657 }
658
659 /// Add another layer to this configuration bag
660 ///
661 /// Hint: If you want to re-use this layer, call `freeze` first.
662 ///
663 /// # Examples
664 /// ```
665 /// use aws_smithy_types::config_bag::{ConfigBag, Layer, Storable, StoreReplace};
666 ///
667 /// #[derive(Debug, Eq, PartialEq)]
668 /// struct ExampleStr(&'static str);
669 /// impl Storable for ExampleStr {
670 /// type Storer = StoreReplace<Self>;
671 /// }
672 ///
673 /// #[derive(Debug, Eq, PartialEq)]
674 /// struct ExampleInt(i32);
675 /// impl Storable for ExampleInt {
676 /// type Storer = StoreReplace<Self>;
677 /// }
678 ///
679 /// let mut bag = ConfigBag::base();
680 /// bag = bag.with_fn("first", |layer: &mut Layer| { layer.store_put(ExampleStr("a")); });
681 ///
682 /// // We can now load the example string out
683 /// assert_eq!(bag.load::<ExampleStr>(), Some(&ExampleStr("a")));
684 ///
685 /// // But there isn't a number stored in the bag yet
686 /// assert_eq!(bag.load::<ExampleInt>(), None);
687 ///
688 /// // Add a layer with an example int
689 /// bag = bag.with_fn("second", |layer: &mut Layer| { layer.store_put(ExampleInt(1)); });
690 ///
691 /// // Now the example int can be retrieved
692 /// assert_eq!(bag.load::<ExampleInt>(), Some(&ExampleInt(1)));
693 /// ```
694 pub fn with_fn(
695 self,
696 name: impl Into<Cow<'static, str>>,
697 next: impl Fn(&mut Layer),
698 ) -> ConfigBag {
699 let mut new_layer = Layer::new(name);
700 next(&mut new_layer);
701 let ConfigBag {
702 interceptor_state: head,
703 mut tail,
704 } = self;
705 tail.push(head.freeze());
706 ConfigBag {
707 interceptor_state: new_layer,
708 tail,
709 }
710 }
711
712 /// Add a new layer with `name` after freezing the top layer so far
713 pub fn add_layer(self, name: impl Into<Cow<'static, str>>) -> ConfigBag {
714 self.with_fn(name, |_| {})
715 }
716
717 /// Return a value (or values) of type `T` depending on how it has been stored in a `ConfigBag`
718 ///
719 /// It flexibly chooses to return a single value vs. an iterator of values depending on how
720 /// `T` implements a [`Store`] trait.
721 pub fn sourced_get<T: Store>(&self) -> T::ReturnedType<'_> {
722 let stored_type_iter = ItemIter {
723 inner: self.layers(),
724 t: PhantomData,
725 };
726 T::merge_iter(stored_type_iter)
727 }
728
729 fn layers(&self) -> BagIter<'_> {
730 BagIter {
731 head: Some(&self.interceptor_state),
732 tail: self.tail.iter().rev(),
733 }
734 }
735}
736
737/// Iterator of items returned from [`ConfigBag`].
738pub struct ItemIter<'a, T> {
739 inner: BagIter<'a>,
740 t: PhantomData<T>,
741}
742
743impl<'a, T> Debug for ItemIter<'a, T> {
744 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
745 write!(f, "ItemIter")
746 }
747}
748
749impl<'a, T: 'a> Iterator for ItemIter<'a, T>
750where
751 T: Store,
752{
753 type Item = &'a T::StoredType;
754
755 fn next(&mut self) -> Option<Self::Item> {
756 match self.inner.next() {
757 Some(layer) => layer.get::<T>().or_else(|| self.next()),
758 None => None,
759 }
760 }
761}
762
763/// Iterator over the layers of a config bag
764struct BagIter<'a> {
765 head: Option<&'a Layer>,
766 tail: Rev<Iter<'a, FrozenLayer>>,
767}
768
769impl<'a> Iterator for BagIter<'a> {
770 type Item = &'a Layer;
771
772 fn next(&mut self) -> Option<Self::Item> {
773 if let Some(head) = self.head.take() {
774 Some(head)
775 } else {
776 self.tail.next().map(|t| t.deref())
777 }
778 }
779}
780
781#[cfg(test)]
782mod test {
783 use super::ConfigBag;
784 use crate::config_bag::{CloneableLayer, Layer, Storable, StoreAppend, StoreReplace};
785
786 #[test]
787 fn layered_property_bag() {
788 #[derive(Debug)]
789 struct Prop1;
790 impl Storable for Prop1 {
791 type Storer = StoreReplace<Self>;
792 }
793 #[derive(Debug)]
794 struct Prop2;
795 impl Storable for Prop2 {
796 type Storer = StoreReplace<Self>;
797 }
798 let layer_a = |bag: &mut Layer| {
799 bag.store_put(Prop1);
800 };
801
802 let layer_b = |bag: &mut Layer| {
803 bag.store_put(Prop2);
804 };
805
806 #[derive(Debug)]
807 struct Prop3;
808 impl Storable for Prop3 {
809 type Storer = StoreReplace<Self>;
810 }
811
812 let mut base_bag = ConfigBag::base()
813 .with_fn("a", layer_a)
814 .with_fn("b", layer_b);
815 base_bag.interceptor_state().store_put(Prop3);
816 assert!(base_bag.load::<Prop1>().is_some());
817
818 #[derive(Debug)]
819 struct Prop4;
820 impl Storable for Prop4 {
821 type Storer = StoreReplace<Self>;
822 }
823
824 let layer_c = |bag: &mut Layer| {
825 bag.store_put(Prop4);
826 bag.unset::<Prop3>();
827 };
828
829 let final_bag = base_bag.with_fn("c", layer_c);
830
831 assert!(final_bag.load::<Prop4>().is_some());
832 assert!(final_bag.load::<Prop1>().is_some());
833 assert!(final_bag.load::<Prop2>().is_some());
834 // we unset prop3
835 assert!(final_bag.load::<Prop3>().is_none());
836 println!("{:#?}", final_bag);
837 }
838
839 #[test]
840 fn config_bag() {
841 let bag = ConfigBag::base();
842 #[derive(Debug)]
843 struct Region(&'static str);
844 impl Storable for Region {
845 type Storer = StoreReplace<Self>;
846 }
847 let bag = bag.with_fn("service config", |layer: &mut Layer| {
848 layer.store_put(Region("asdf"));
849 });
850
851 assert_eq!(bag.load::<Region>().unwrap().0, "asdf");
852
853 #[derive(Debug)]
854 struct SigningName(&'static str);
855 impl Storable for SigningName {
856 type Storer = StoreReplace<Self>;
857 }
858 let operation_config = bag.with_fn("operation", |layer: &mut Layer| {
859 layer.store_put(SigningName("s3"));
860 });
861
862 assert_eq!(operation_config.load::<SigningName>().unwrap().0, "s3");
863
864 #[derive(Debug)]
865 struct Prop;
866 impl Storable for Prop {
867 type Storer = StoreReplace<Self>;
868 }
869 let mut open_bag = operation_config.with_fn("my_custom_info", |_bag: &mut Layer| {});
870 open_bag.interceptor_state().store_put(Prop);
871
872 assert_eq!(open_bag.layers().count(), 4);
873 }
874
875 #[test]
876 fn store_append() {
877 let mut layer = Layer::new("test");
878 #[derive(Debug, PartialEq, Eq)]
879 struct Interceptor(&'static str);
880 impl Storable for Interceptor {
881 type Storer = StoreAppend<Interceptor>;
882 }
883
884 layer.clear::<Interceptor>();
885 // you can only call store_append because interceptor is marked with a vec
886 layer.store_append(Interceptor("123"));
887 layer.store_append(Interceptor("456"));
888
889 let mut second_layer = Layer::new("next");
890 second_layer.store_append(Interceptor("789"));
891
892 let mut bag = ConfigBag::of_layers(vec![layer, second_layer]);
893
894 assert_eq!(
895 bag.load::<Interceptor>().collect::<Vec<_>>(),
896 vec![
897 &Interceptor("789"),
898 &Interceptor("456"),
899 &Interceptor("123")
900 ]
901 );
902
903 let mut final_layer = Layer::new("final");
904 final_layer.clear::<Interceptor>();
905 bag.push_layer(final_layer);
906 assert_eq!(bag.load::<Interceptor>().count(), 0);
907 }
908
909 #[test]
910 fn store_append_many_layers() {
911 #[derive(Debug, PartialEq, Eq, Clone)]
912 struct TestItem(i32, i32);
913 impl Storable for TestItem {
914 type Storer = StoreAppend<TestItem>;
915 }
916 let mut expected = vec![];
917 let mut bag = ConfigBag::base();
918 for layer_idx in 0..100 {
919 let mut layer = Layer::new(format!("{}", layer_idx));
920 for item in 0..100 {
921 expected.push(TestItem(layer_idx, item));
922 layer.store_append(TestItem(layer_idx, item));
923 }
924 bag.push_layer(layer);
925 }
926 expected.reverse();
927 assert_eq!(
928 bag.load::<TestItem>().cloned().collect::<Vec<_>>(),
929 expected
930 );
931 }
932
933 #[test]
934 fn adding_layers() {
935 let mut layer_1 = Layer::new("layer1");
936
937 let mut layer_2 = Layer::new("layer2");
938
939 #[derive(Clone, Debug, PartialEq, Eq, Default)]
940 struct Foo(usize);
941 impl Storable for Foo {
942 type Storer = StoreReplace<Foo>;
943 }
944
945 layer_1.store_put(Foo(0));
946 layer_2.store_put(Foo(1));
947
948 let layer_1 = layer_1.freeze();
949 let layer_2 = layer_2.freeze();
950
951 let mut bag_1 = ConfigBag::base();
952 let mut bag_2 = ConfigBag::base();
953 bag_1
954 .push_shared_layer(layer_1.clone())
955 .push_shared_layer(layer_2.clone());
956 bag_2.push_shared_layer(layer_2).push_shared_layer(layer_1);
957
958 // bags have same layers but in different orders
959 assert_eq!(bag_1.load::<Foo>(), Some(&Foo(1)));
960 assert_eq!(bag_2.load::<Foo>(), Some(&Foo(0)));
961
962 bag_1.interceptor_state().store_put(Foo(3));
963 assert_eq!(bag_1.load::<Foo>(), Some(&Foo(3)));
964 }
965
966 #[test]
967 fn get_mut_or_else() {
968 #[derive(Clone, Debug, PartialEq, Eq, Default)]
969 struct Foo(usize);
970 impl Storable for Foo {
971 type Storer = StoreReplace<Foo>;
972 }
973
974 let mut bag = ConfigBag::base();
975 assert_eq!(bag.get_mut::<Foo>(), None);
976 assert_eq!(bag.get_mut_or_default::<Foo>(), &Foo(0));
977 bag.get_mut_or_default::<Foo>().0 += 1;
978 assert_eq!(bag.load::<Foo>(), Some(&Foo(1)));
979
980 let old_ref = bag.load::<Foo>().unwrap();
981 assert_eq!(old_ref, &Foo(1));
982
983 // there is one in the bag, so it can be returned
984 //let mut next = bag.add_layer("next");
985 bag.get_mut::<Foo>().unwrap().0 += 1;
986 let new_ref = bag.load::<Foo>().unwrap();
987 assert_eq!(new_ref, &Foo(2));
988
989 bag.interceptor_state().unset::<Foo>();
990 // if it was unset, we can't clone the current one, that would be wrong
991 assert_eq!(bag.get_mut::<Foo>(), None);
992 assert_eq!(bag.get_mut_or_default::<Foo>(), &Foo(0));
993 }
994
995 #[test]
996 fn get_mut_from_interceptor_state() {
997 // excludes `Clone` to verify `get_mut_from_interceptor_state` works with types without the `Clone` trait
998 #[derive(Debug, PartialEq, Eq, Default)]
999 struct Foo(usize);
1000 impl Storable for Foo {
1001 type Storer = StoreReplace<Self>;
1002 }
1003
1004 #[derive(Clone, Debug, PartialEq, Eq, Default)]
1005 struct Bar(usize);
1006 impl Storable for Bar {
1007 type Storer = StoreReplace<Self>;
1008 }
1009
1010 let mut bag = ConfigBag::base();
1011 assert!(bag.get_mut_from_interceptor_state::<Foo>().is_none());
1012
1013 bag.interceptor_state().store_put(Foo(1));
1014 assert_eq!(
1015 bag.get_mut_from_interceptor_state::<Foo>(),
1016 Some(&mut Foo(1))
1017 );
1018
1019 // `Bar` is stored in the tail of the config bag.
1020 let mut layer = Layer::new("test");
1021 layer.store_put(Bar(1));
1022 bag.push_layer(layer);
1023
1024 // the method under test should not find `Bar`, as it does not reside in the interceptor state.
1025 assert!(bag.get_mut_from_interceptor_state::<Bar>().is_none());
1026 }
1027
1028 #[test]
1029 fn cloning_layers() {
1030 #[derive(Clone, Debug)]
1031 struct TestStr(String);
1032 impl Storable for TestStr {
1033 type Storer = StoreReplace<TestStr>;
1034 }
1035 let mut layer_1 = CloneableLayer::new("layer_1");
1036 let expected_str = "I can be cloned";
1037 layer_1.store_put(TestStr(expected_str.to_owned()));
1038 let layer_1_cloned = layer_1.clone();
1039 assert_eq!(expected_str, &layer_1_cloned.load::<TestStr>().unwrap().0);
1040
1041 // Should still be cloneable after unsetting a field
1042 layer_1.unset::<TestStr>();
1043 assert!(layer_1.try_clone().unwrap().load::<TestStr>().is_none());
1044
1045 // It is cloneable multiple times in succession
1046 let _ = layer_1
1047 .try_clone()
1048 .expect("clone 1")
1049 .try_clone()
1050 .expect("clone 2");
1051
1052 #[derive(Clone, Debug)]
1053 struct Rope(String);
1054 impl Storable for Rope {
1055 type Storer = StoreAppend<Rope>;
1056 }
1057 let mut layer_2 = CloneableLayer::new("layer_2");
1058 layer_2.store_append(Rope("A".to_owned()));
1059 layer_2.store_append(Rope("big".to_owned()));
1060 layer_2.store_append(Rope("rope".to_owned()));
1061 let layer_2_cloned = layer_2.clone();
1062 let rope = layer_2_cloned.load::<Rope>().cloned().collect::<Vec<_>>();
1063 assert_eq!(
1064 "A big rope",
1065 rope.iter()
1066 .rev()
1067 .map(|r| r.0.clone())
1068 .collect::<Vec<_>>()
1069 .join(" ")
1070 );
1071 }
1072}