Expand description

A typemap for storing configuration. Layers and layered bags of configuration data.

The ConfigBag structure is used to store and pass around configuration for client operations. Interacting with it may be required in order to write an Interceptor or RuntimePlugin to customize a client.

A ConfigBag is essentially a stack of several immutable and sharable layers, with a single mutable layer at the top of the stack that is called “interceptor state”. The intent of this last mutable layer is to allow for more performant mutation of config within the execution of an operation.

There are three separate layer types to be aware of when using a ConfigBag:

  1. Layer - A mutable layer. This is usually only used for adding config to the ConfigBag, but is also used for the interceptor state.
  2. CloneableLayer - Identical to Layer, except that it requires Clone bounds on the items added to it so that it can be deep cloned. Can be converted to a Layer while retaining the cloneability of its items such that the resulting layer could be cloned as long as nothing else is added to it later. A Layer cannot be converted back into a CloneableLayer.
  3. FrozenLayer - Basically an Arc wrapper around a Layer. This wrapper is used to make the layer immutable, and to make it shareable between multiple ConfigBag instances. The frozen layer can be converted back to a Layer if there is only a single reference to it.

All of Layer, CloneableLayer, FrozenLayer, and ConfigBag are considered to be “bag” types. That is, they store arbitrary types so long as they implement the Storable trait.

A Storable requires a Storer to be configured, and the storer allows for storables to be stored in two different modes:

  1. StoreReplace - Only one value of this type is allowed in a bag, and calling store_put() multiple times will replace the existing value in the bag. Calling load::<T>() returns exactly one value, if present.
  2. StoreAppend - Multiple values of this type are allowed in a bag, and calling store_append() will add an additional value of this type to the bag. Calling load::<T>() returns an iterator over multiple values.

§Examples

Creating a storable data type with StoreReplace:

use aws_smithy_types::config_bag::{Storable, StoreReplace};

#[derive(Debug)]
struct SomeDataType {
    some_data: String,
}
impl Storable for SomeDataType {
    type Storer = StoreReplace<Self>;
}

Creating a storable data type with StoreAppend:

use aws_smithy_types::config_bag::{Storable, StoreAppend};

#[derive(Debug)]
struct SomeDataType {
    some_data: String,
}
impl Storable for SomeDataType {
    type Storer = StoreAppend<Self>;
}

Storing a storable in a bag when it is configured for StoreReplace:

use aws_smithy_types::config_bag::{CloneableLayer, Layer};

let mut layer = Layer::new("example");
layer.store_put(SomeDataType { some_data: "some data".to_string() });

// `store_put` can be called again to replace the original value:
layer.store_put(SomeDataType { some_data: "replacement".to_string() });

// Note: `SomeDataType` below must implement `Clone` to work with `CloneableLayer`
let mut cloneable = CloneableLayer::new("example");
cloneable.store_put(SomeDataType { some_data: "some data".to_string() });

Storing a storable in a bag when it is configured for StoreAppend:

use aws_smithy_types::config_bag::{CloneableLayer, Layer};

let mut layer = Layer::new("example");
layer.store_append(SomeDataType { some_data: "1".to_string() });
layer.store_append(SomeDataType { some_data: "2".to_string() });

Loading a StoreReplace value from a bag:

let maybe_value: Option<&SomeDataType> = layer.load::<SomeDataType>();

Loading a StoreAppend value from a bag:

let values: Vec<SomeDataType> = layer.load::<SomeDataType>().cloned().collect();

// or iterate over them directly:
for value in layer.load::<SomeDataType>() {
    // ...
}

Structs§

Traits§

  • Trait that marks the implementing types as able to be stored in the config bag
  • Trait defining how types can be stored and loaded from the config bag