use std::fmt;
use serde::{Deserialize, Serialize, de};
use super::error::ClientIdValidationError;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ClientId(String);
impl ClientId {
pub const MIN_LEN: usize = 1;
pub const MAX_LEN: usize = 64;
pub fn as_str(&self) -> &str {
&self.0
}
pub fn into_inner(self) -> String {
self.0
}
}
impl TryFrom<String> for ClientId {
type Error = ClientIdValidationError;
fn try_from(value: String) -> Result<Self, Self::Error> {
if value.len() < Self::MIN_LEN {
return Err(ClientIdValidationError::TooShort { len: value.len() });
}
if value.len() > Self::MAX_LEN {
return Err(ClientIdValidationError::TooLong { len: value.len() });
}
Ok(ClientId(value))
}
}
impl TryFrom<&str> for ClientId {
type Error = ClientIdValidationError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
Self::try_from(value.to_string())
}
}
impl From<ClientId> for String {
fn from(value: ClientId) -> Self {
value.0
}
}
impl AsRef<str> for ClientId {
fn as_ref(&self) -> &str {
&self.0
}
}
impl fmt::Display for ClientId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl Serialize for ClientId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.0)
}
}
impl<'de> Deserialize<'de> for ClientId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
ClientId::try_from(s).map_err(|e| de::Error::custom(e.to_string()))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_valid_client_id() {
let client_id = ClientId::try_from("my-order-123").unwrap();
assert_eq!(client_id.as_str(), "my-order-123");
}
#[test]
fn test_min_length_client_id() {
let client_id = ClientId::try_from("a").unwrap();
assert_eq!(client_id.as_str(), "a");
}
#[test]
fn test_max_length_client_id() {
let long_string = "a".repeat(64);
let client_id = ClientId::try_from(long_string.as_str()).unwrap();
assert_eq!(client_id.as_str(), long_string);
}
#[test]
fn test_empty_client_id_fails() {
let result = ClientId::try_from("");
assert!(matches!(
result,
Err(ClientIdValidationError::TooShort { len: 0 })
));
}
#[test]
fn test_too_long_client_id_fails() {
let long_string = "a".repeat(65);
let result = ClientId::try_from(long_string.as_str());
assert!(matches!(
result,
Err(ClientIdValidationError::TooLong { len: 65 })
));
}
#[test]
fn test_into_inner() {
let client_id = ClientId::try_from("test-id").unwrap();
let inner: String = client_id.into_inner();
assert_eq!(inner, "test-id");
}
#[test]
fn test_from_string() {
let client_id = ClientId::try_from(String::from("my-order")).unwrap();
assert_eq!(client_id.as_str(), "my-order");
}
#[test]
fn test_display() {
let client_id = ClientId::try_from("display-test").unwrap();
assert_eq!(format!("{}", client_id), "display-test");
}
#[test]
fn test_serialize() {
let client_id = ClientId::try_from("serialize-test").unwrap();
let json = serde_json::to_string(&client_id).unwrap();
assert_eq!(json, "\"serialize-test\"");
}
#[test]
fn test_deserialize() {
let json = "\"deserialize-test\"";
let client_id: ClientId = serde_json::from_str(json).unwrap();
assert_eq!(client_id.as_str(), "deserialize-test");
}
#[test]
fn test_deserialize_empty_fails() {
let json = "\"\"";
let result: Result<ClientId, _> = serde_json::from_str(json);
assert!(result.is_err());
}
#[test]
fn test_deserialize_too_long_fails() {
let long_string = "a".repeat(65);
let json = format!("\"{}\"", long_string);
let result: Result<ClientId, _> = serde_json::from_str(&json);
assert!(result.is_err());
}
}