Rust用AWS SDKのRusotoでdefault以外の名前付きプロファイルを使用する

# はじめに
RusotoはRustのためのAWK SDKです。
↓はDynamoDBの全てのテーブルを表示するサンプルコードです。

```rust
use rusoto_core::Region;
use rusoto_dynamodb::{DynamoDb, DynamoDbClient, ListTablesInput};

#[tokio::main]
async fn main() {
    let client = DynamoDbClient::new(Region::UsEast1);
    let list_tables_input: ListTablesInput = Default::default();

    match client.list_tables(list_tables_input).await {
        Ok(output) => match output.table_names {
            Some(table_name_list) => {
                println!("Tables in database:");

                for table_name in table_name_list {
                    println!("{}", table_name);
                }
            }
            None => println!("No tables in database!"),
        },
        Err(error) => {
            println!("Error: {:?}", error);
        }
    }
}
```
出典: [rusoto/rusoto: AWS SDK for Rust](https://github.com/rusoto/rusoto)

サポートしているAWSサービスの一覧は[こちら](https://www.rusoto.org/supported-aws-services.html)でみれます。
一部のサービスにはサンプルコードが用意されていないので、その場合はCrateのドキュメントを読みましょう。

# default以外の名前付きプロファイルを使用する
上のサンプルコードではDynamoDBのクライアントを作成するのに`new`を使いました。

```rust
pub fn new(region: Region) -> DynamoDbClient
```

名前付きプロファイルを使ってクライアントを作成するときは`new_with`を使います。

```rust
pub fn new_with<P, D>(
    request_dispatcher: D,
    credentials_provider: P,
    region: region::Region,
) -> DynamoDbClient
where
    P: ProvideAwsCredentials + Send + Sync + 'static,
    D: DispatchSignedRequest + Send + Sync + 'static,
```

例えば、`~/.aws/credentials`の`staging`という名前のプロファイルを使うときは、
上のサンプルコードはこのように書けます。

```rust
use rusoto_core::{HttpClient, Region};
use rusoto_core::credential::ProfileProvider;
use rusoto_dynamodb::{DynamoDb, DynamoDbClient, ListTablesInput};

#[tokio::main]
async fn main() {
    let mut provider = ProfileProvider::new().unwrap();
    provider.set_profile("staging");

    let client = DynamoDbClient::new_with(
        HttpClient::new().unwrap(),
        provider,
        Region::ApNortheast1
    );
    let list_tables_input: ListTablesInput = Default::default();

    match client.list_tables(list_tables_input).await {
        Ok(output) => match output.table_names {
            Some(table_name_list) => {
                println!("Tables in database:");

                for table_name in table_name_list {
                    println!("{}", table_name);
                }
            }
            None => println!("No tables in databases!"),
        },
        Err(error) => {
            println!("Error: {:?}", error);
        }
    }
}
```
# AWS CLIみたいに--profileオプションでプロファイルを切り替える
コマンドライン引数を扱いたいときは`clap`[^1]が便利です。
お洒落なヘルプドキュメントも自動生成してくれます。


```rust:sample.rs
use clap::{App, Arg};
use rusoto_core::{HttpClient, Region};
use rusoto_core::credential::ProfileProvider;
use rusoto_dynamodb::{DynamoDb, DynamoDbClient, ListTablesInput};

#[tokio::main]
async fn main() {
    let matches = App::new("DynamoDB ListTables")
        .version("1.0")
        .about("Sample CLI Tool")
        .arg(
            Arg::with_name("profile")
                .short("p")
                .long("profile")
                .value_name("PROFILE")
                .help("Use a specific profile from your credential file.")
                .takes_value(true),
        )
        .get_matches();

    let client = match matches.value_of("profile") {
        Some(p) => {
            let mut provider = ProfileProvider::new().unwrap();
            provider.set_profile(p);
            DynamoDbClient::new_with(
                HttpClient::new().unwrap(),
                provider,
                Region::ApNortheast1
            )
        },
        None => DynamoDbClient::new(Region::ApNortheast1)
    };

    let list_tables_input: ListTablesInput = Default::default();
    match client.list_tables(list_tables_input).await {
        Ok(output) => match output.table_names {
            Some(table_name_list) => {
                println!("Tables in database:");

                for table_name in table_name_list {
                    println!("{}", table_name);
                }
            }
            None => println!("No tables in databases!"),
        },
        Err(error) => {
            println!("Error: {:?}", error);
        }
    }
}
```

コンパイルして実行してみます。
実行ファイル名は`sample`としました。

```shell
$ ./sample
Tables in database:
default_table_a
default_table_b
$ ./sample --profile staging
Tables in database:
staging_table_a
staging_table_b
```

`-h`を渡してあげれば、ヘルプドキュメントが表示されます。

```shell
$ ./sample -h              
DynamoDB ListTables 1.0
Sample CLI Tool

USAGE:
    sample [OPTIONS]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -p, --profile <PROFILE>    Use a specific profile from your credential file.
```

# 参考資料
[rusoto/rusoto: AWS SDK for Rust](https://github.com/rusoto/rusoto)
[rusoto_dynamodb::DynamoDbClient - Rust](https://docs.rs/rusoto_dynamodb/0.45.0/rusoto_dynamodb/struct.DynamoDbClient.html)
[clap-rs/clap: A full featured, fast Command Line Argument Parser for Rust](https://github.com/clap-rs/clap)

[^1]: clapのバージョンに気をつけてください。`sample.rs`は`2.33.1`でビルドしました。この記事を執筆している時点で`3.0`のベータ版がプレリリースされています。