Skip to main content

payrail_core/
reference.rs

1use crate::PaymentError;
2
3macro_rules! string_newtype {
4    ($name:ident, $error:ident, $doc:literal) => {
5        #[doc = $doc]
6        #[derive(Debug, Clone, PartialEq, Eq, Hash)]
7        pub struct $name(String);
8
9        impl $name {
10            /// Creates a validated string newtype.
11            ///
12            /// # Errors
13            ///
14            /// Returns an error when the value is empty or longer than 255 bytes.
15            pub fn new(value: impl AsRef<str>) -> Result<Self, PaymentError> {
16                let value = value.as_ref().trim();
17                if value.is_empty() || value.len() > 255 {
18                    return Err(PaymentError::$error(value.to_owned()));
19                }
20
21                Ok(Self(value.to_owned()))
22            }
23
24            /// Returns the validated string.
25            #[inline]
26            #[must_use]
27            pub fn as_str(&self) -> &str {
28                &self.0
29            }
30
31            /// Converts into the owned string.
32            #[inline]
33            #[must_use]
34            pub fn into_string(self) -> String {
35                self.0
36            }
37        }
38
39        impl AsRef<str> for $name {
40            #[inline]
41            fn as_ref(&self) -> &str {
42                self.as_str()
43            }
44        }
45    };
46}
47
48string_newtype!(MerchantReference, InvalidReference, "Merchant reference.");
49string_newtype!(ProviderReference, InvalidReference, "Provider reference.");
50string_newtype!(PaymentId, InvalidReference, "PayRail payment identifier.");
51string_newtype!(
52    WebhookEventId,
53    InvalidReference,
54    "Webhook event identifier."
55);
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60
61    #[test]
62    fn new_accepts_reference() {
63        let reference = MerchantReference::new("ORDER-123").expect("reference should be valid");
64
65        assert_eq!(reference.as_str(), "ORDER-123");
66        assert_eq!(reference.into_string(), "ORDER-123");
67    }
68
69    #[test]
70    fn new_rejects_empty_reference() {
71        assert!(matches!(
72            ProviderReference::new(" "),
73            Err(PaymentError::InvalidReference(_))
74        ));
75    }
76}