Unverified Commit bab8e230 authored by Russell Cohen's avatar Russell Cohen Committed by GitHub
Browse files

Add a minimal implementation of shared config (#673)

* Add a minimal implementation of shared config

* update changelog
parent 5b8fc1ef
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ vNext (Month Day, Year)
- (When complete) Add profile file provider for region (#594, #xyz)
- Improve documentation on collection-aware builders (#664)
- Add support for Transcribe `StartStreamTranscription` and S3 `SelectObjectContent` operations (#667)
- Add support for shared configuration between multiple services (#673)

**Internal Changes**
- Add NowOrLater future to smithy-async (#672)
+78 −0
Original line number Diff line number Diff line
/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0.
 */

#![deny(missing_docs)]

//! AWS Shared Config
//!
//! This module contains an shared configuration representation that is agnostic from a specific service.

use crate::region::Region;

/// AWS Shared Configuration
pub struct Config {
    region: Option<Region>,
}

/// Builder for AWS Shared Configuration
#[derive(Default)]
pub struct Builder {
    region: Option<Region>,
}

impl Builder {
    /// Set the region for the builder
    ///
    /// # Example
    /// ```rust
    /// use aws_types::config::Config;
    /// use aws_types::region::Region;
    /// let config = Config::builder().region(Region::new("us-east-1")).build();
    /// ```
    pub fn region(mut self, region: impl Into<Option<Region>>) -> Self {
        self.set_region(region);
        self
    }

    /// Set the region for the builder
    ///
    /// # Example
    /// ```rust
    /// fn region_override() -> Option<Region> {
    ///     // ...
    ///     # None
    /// }
    /// use aws_types::config::Config;
    /// use aws_types::region::Region;
    /// let mut builder = Config::builder();
    /// if let Some(region) = region_override() {
    ///     builder.set_region(region);
    /// }
    /// let config = builder.build();
    /// ```
    pub fn set_region(&mut self, region: impl Into<Option<Region>>) -> &mut Self {
        self.region = region.into();
        self
    }

    /// Build a [`Config`](Config) from this builder
    pub fn build(self) -> Config {
        Config {
            region: self.region,
        }
    }
}

impl Config {
    /// Configured region
    pub fn region(&self) -> Option<&Region> {
        self.region.as_ref()
    }

    /// Config builder
    pub fn builder() -> Builder {
        Builder::default()
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@

pub mod build_metadata;
// internal APIs, may be unstable
pub mod config;
#[doc(hidden)]
pub mod os_shim_internal;
pub mod profile;
+1 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ val DECORATORS = listOf(
    IntegrationTestDecorator(),
    AwsFluentClientDecorator(),
    CrateLicenseDecorator(),
    SharedConfigDecorator(),

    // Service specific decorators
    DisabledAuthDecorator(),
+78 −0
Original line number Diff line number Diff line
/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0.
 */

package software.amazon.smithy.rustsdk

import software.amazon.smithy.rust.codegen.rustlang.RustModule
import software.amazon.smithy.rust.codegen.rustlang.Writable
import software.amazon.smithy.rust.codegen.rustlang.asType
import software.amazon.smithy.rust.codegen.rustlang.rustTemplate
import software.amazon.smithy.rust.codegen.rustlang.writable
import software.amazon.smithy.rust.codegen.smithy.RuntimeConfig
import software.amazon.smithy.rust.codegen.smithy.RustCrate
import software.amazon.smithy.rust.codegen.smithy.customize.RustCodegenDecorator
import software.amazon.smithy.rust.codegen.smithy.generators.ProtocolConfig
import software.amazon.smithy.rust.codegen.smithy.generators.config.ConfigCustomization
import software.amazon.smithy.rust.codegen.smithy.generators.config.ServiceConfig

/**
 * Adds functionality for constructing <service>::Config objects from aws_types::Config (SharedConfig)
 *
 * - `From<&aws_types::Config> for <service>::config::Builder`: Enabling customization
 * - `pub fn new(&aws_types::Config) -> <service>::Config`: Direct construction without customization
 */
class SharedConfigDecorator : RustCodegenDecorator {
    override val name: String = "SharedConfig"
    override val order: Byte = 0

    override fun configCustomizations(
        protocolConfig: ProtocolConfig,
        baseCustomizations: List<ConfigCustomization>
    ): List<ConfigCustomization> {
        return baseCustomizations + NewFromShared(protocolConfig.runtimeConfig)
    }

    override fun extras(protocolConfig: ProtocolConfig, rustCrate: RustCrate) {
        val codegenScope = arrayOf(
            "Config" to awsTypes(runtimeConfig = protocolConfig.runtimeConfig).asType().member("config::Config")
        )
        rustCrate.withModule(RustModule.Config) {
            // TODO(sharedconfig): As more items are added to aws_types::Config, use them here to configure the config builder
            it.rustTemplate(
                """
                impl From<&#{Config}> for Builder {
                    fn from(input: &#{Config}) -> Self {
                        let mut builder = Builder::default();
                        builder = builder.region(input.region().cloned());
                        builder
                    }
                }
            """,
                *codegenScope
            )
        }
    }
}

class NewFromShared(runtimeConfig: RuntimeConfig) : ConfigCustomization() {
    private val codegenScope = arrayOf(
        "Config" to awsTypes(runtimeConfig = runtimeConfig).asType().member("config::Config")
    )
    override fun section(section: ServiceConfig): Writable {
        return when (section) {
            ServiceConfig.ConfigImpl -> writable {
                rustTemplate(
                    """
                    pub fn new(config: &#{Config}) -> Self {
                        Builder::from(config).build()
                    }
                """,
                    *codegenScope
                )
            }
            else -> emptySection
        }
    }
}
Loading