Skip to main content

payrail_core/
idempotency.rs

1use crate::PaymentError;
2
3/// Idempotency key used to make provider write operations retry-safe.
4#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5pub struct IdempotencyKey(String);
6
7impl IdempotencyKey {
8    /// Creates a validated idempotency key.
9    ///
10    /// # Errors
11    ///
12    /// Returns an error when the key is empty or longer than 255 bytes.
13    pub fn new(value: impl AsRef<str>) -> Result<Self, PaymentError> {
14        let value = value.as_ref().trim();
15        if value.is_empty() || value.len() > 255 {
16            return Err(PaymentError::InvalidIdempotencyKey(value.to_owned()));
17        }
18
19        Ok(Self(value.to_owned()))
20    }
21
22    /// Returns the idempotency key.
23    #[inline]
24    #[must_use]
25    pub fn as_str(&self) -> &str {
26        &self.0
27    }
28}
29
30impl AsRef<str> for IdempotencyKey {
31    #[inline]
32    fn as_ref(&self) -> &str {
33        self.as_str()
34    }
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40
41    #[test]
42    fn new_accepts_key() {
43        let key = IdempotencyKey::new("ORDER-123:create").expect("key should be valid");
44
45        assert_eq!(key.as_str(), "ORDER-123:create");
46    }
47
48    #[test]
49    fn new_rejects_empty_key() {
50        assert!(matches!(
51            IdempotencyKey::new(""),
52            Err(PaymentError::InvalidIdempotencyKey(_))
53        ));
54    }
55}