use std::fmt::{Display, Formatter};
use std::str::FromStr;
use http::HeaderValue;
use reqsign_core::{Error, Result};
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct SigningRegionSet(String);
impl SigningRegionSet {
pub fn new(value: impl Into<String>) -> Result<Self> {
let value = value.into();
let regions = value.split(',').map(str::trim).collect::<Vec<_>>();
if regions.is_empty() || regions.iter().any(|region| region.is_empty()) {
return Err(Error::request_invalid(
"AWS signing region set must not contain empty regions",
));
}
let value = regions.join(",");
HeaderValue::from_str(&value).map_err(|e| {
Error::request_invalid("AWS signing region set is not a valid header value")
.with_source(e)
})?;
Ok(Self(value))
}
pub fn from_regions<I, S>(regions: I) -> Result<Self>
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
let regions = regions
.into_iter()
.map(|region| region.as_ref().to_string())
.collect::<Vec<_>>();
Self::new(regions.join(","))
}
pub fn all() -> Self {
Self("*".to_string())
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl AsRef<str> for SigningRegionSet {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl Display for SigningRegionSet {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
impl FromStr for SigningRegionSet {
type Err = Error;
fn from_str(value: &str) -> Result<Self> {
Self::new(value)
}
}
impl TryFrom<String> for SigningRegionSet {
type Error = Error;
fn try_from(value: String) -> Result<Self> {
Self::new(value)
}
}
impl TryFrom<&str> for SigningRegionSet {
type Error = Error;
fn try_from(value: &str) -> Result<Self> {
Self::new(value)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn normalizes_comma_separated_regions() {
let regions = SigningRegionSet::new("us-east-1, us-west-2").unwrap();
assert_eq!(regions.as_str(), "us-east-1,us-west-2");
}
#[test]
fn builds_from_regions_and_wildcard() {
let regions = SigningRegionSet::from_regions(["us-east-1", "us-west-2"]).unwrap();
assert_eq!(regions.as_str(), "us-east-1,us-west-2");
assert_eq!(SigningRegionSet::all().as_str(), "*");
}
#[test]
fn rejects_empty_members() {
assert!(SigningRegionSet::new("").is_err());
assert!(SigningRegionSet::new("us-east-1,").is_err());
assert!(SigningRegionSet::new("us-east-1,,us-west-2").is_err());
}
}