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

Remove idempotency token trait (#571)

* remove idempotency token trait

There is no compelling reason to provide your own implementation of the `IdempotencyToken` trait. Exposing this trait left us open to unecessary backwards compatibility risks. Instead,
this commit refactors idempotency token to be a simple struct/enum.

* fix clippy
parent c10899da
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -18,17 +18,17 @@ class IdempotencyTokenProviderCustomization : NamedSectionGenerator<ServiceConfi
    override fun section(section: ServiceConfig): Writable {
        return when (section) {
            is ServiceConfig.ConfigStruct -> writable {
                rust("pub (crate) make_token: Box<dyn #T::MakeIdempotencyToken>,", RuntimeType.IdempotencyToken)
                rust("pub (crate) make_token: #T::IdempotencyTokenProvider,", RuntimeType.IdempotencyToken)
            }
            ServiceConfig.ConfigImpl -> emptySection
            ServiceConfig.BuilderStruct -> writable {
                rust("make_token: Option<Box<dyn #T::MakeIdempotencyToken>>,", RuntimeType.IdempotencyToken)
                rust("make_token: Option<#T::IdempotencyTokenProvider>,", RuntimeType.IdempotencyToken)
            }
            ServiceConfig.BuilderImpl -> writable {
                rust(
                    """
            pub fn make_token(mut self, make_token: impl #T::MakeIdempotencyToken + 'static) -> Self {
                self.make_token = Some(Box::new(make_token));
            pub fn make_token(mut self, make_token: impl Into<#T::IdempotencyTokenProvider>) -> Self {
                self.make_token = Some(make_token.into());
                self
            }
            """,
@@ -36,7 +36,7 @@ class IdempotencyTokenProviderCustomization : NamedSectionGenerator<ServiceConfi
                )
            }
            ServiceConfig.BuilderBuild -> writable {
                rust("make_token: self.make_token.unwrap_or_else(|| Box::new(#T::default_provider())),", RuntimeType.IdempotencyToken)
                rust("make_token: self.make_token.unwrap_or_else(#T::default_provider),", RuntimeType.IdempotencyToken)
            }
        }
    }
+46 −11
Original line number Diff line number Diff line
@@ -30,23 +30,58 @@ pub(crate) fn uuid_v4(input: u128) -> String {
    out
}

pub trait MakeIdempotencyToken: Send + Sync {
    fn make_idempotency_token(&self) -> String;
/// IdempotencyTokenProvider generates idempotency tokens for idempotency API requests
///
/// Generally, customers will not need to interact with this at all. A sensible default will be
/// provided automatically during config construction. However, if you need deterministic behavior
/// for testing, two options are available:
/// 1. Utilize the From<&'static str>` implementation to hard code an idempotency token
/// 2. Seed the token provider with [`IdempotencyTokenProvider::with_seed`](IdempotencyTokenProvider::with_seed)
pub struct IdempotencyTokenProvider {
    inner: Inner,
}

pub fn default_provider() -> impl MakeIdempotencyToken {
    Mutex::new(fastrand::Rng::new())
enum Inner {
    Static(&'static str),
    Random(Mutex<fastrand::Rng>),
}

impl MakeIdempotencyToken for Mutex<fastrand::Rng> {
    fn make_idempotency_token(&self) -> String {
        let input: u128 = self.lock().unwrap().u128(..);
pub fn default_provider() -> IdempotencyTokenProvider {
    IdempotencyTokenProvider::random()
}

impl From<&'static str> for IdempotencyTokenProvider {
    fn from(token: &'static str) -> Self {
        Self::fixed(token)
    }
}

impl IdempotencyTokenProvider {
    pub fn make_idempotency_token(&self) -> String {
        match &self.inner {
            Inner::Static(token) => token.to_string(),
            Inner::Random(rng) => {
                let input: u128 = rng.lock().unwrap().u128(..);
                uuid_v4(input)
            }
        }
    }

impl MakeIdempotencyToken for &'static str {
    fn make_idempotency_token(&self) -> String {
        self.to_string()
    pub fn with_seed(seed: u64) -> Self {
        Self {
            inner: Inner::Random(Mutex::new(fastrand::Rng::with_seed(seed))),
        }
    }

    pub fn random() -> Self {
        Self {
            inner: Inner::Random(Mutex::new(fastrand::Rng::new())),
        }
    }

    pub fn fixed(token: &'static str) -> Self {
        Self {
            inner: Inner::Static(token),
        }
    }
}
+2 −5
Original line number Diff line number Diff line
@@ -19,9 +19,8 @@ mod rest_xml_wrapped_errors;
#[cfg(test)]
mod test {
    use crate::idempotency_token;
    use crate::idempotency_token::uuid_v4;
    use crate::idempotency_token::{uuid_v4, IdempotencyTokenProvider};
    use proptest::prelude::*;
    use std::sync::Mutex;

    #[test]
    fn test_uuid() {
@@ -36,7 +35,6 @@ mod test {
    #[test]
    fn default_token_generator_smoke_test() {
        // smoke test to make sure the default token generator produces a token-like object
        use crate::idempotency_token::MakeIdempotencyToken;
        assert_eq!(
            idempotency_token::default_provider()
                .make_idempotency_token()
@@ -47,8 +45,7 @@ mod test {

    #[test]
    fn token_generator() {
        let provider = Mutex::new(fastrand::Rng::with_seed(123));
        use crate::idempotency_token::MakeIdempotencyToken;
        let provider = IdempotencyTokenProvider::with_seed(123);
        assert_eq!(
            provider.make_idempotency_token(),
            "b4021a03-ae07-4db5-fc1b-38bf919691f8"