Skip to main content

commit_bridge/domain/
commit_hash.rs

1//! Domain type to represent a git commit hash.
2
3use crate::error::ValidationError;
4use rovo::schemars::JsonSchema;
5use serde::{Deserialize, Serialize};
6
7/// A git commit hash.
8#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
9#[serde(try_from = "String", into = "String")]
10pub struct CommitHash(String);
11
12impl CommitHash {
13    /// Create a new `CommitHash`.
14    pub fn new(value: String) -> Result<Self, ValidationError> {
15        Self::try_from(value)
16    }
17
18    /// Get the inner string.
19    pub fn into_inner(self) -> String {
20        self.0
21    }
22
23    /// Get the string as a slice.
24    pub fn as_str(&self) -> &str {
25        &self.0
26    }
27}
28
29crate::derive_sqlx_traits!(CommitHash);
30
31impl AsRef<str> for CommitHash {
32    fn as_ref(&self) -> &str {
33        &self.0
34    }
35}
36
37impl std::fmt::Display for CommitHash {
38    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39        write!(f, "{}", self.0)
40    }
41}
42
43impl TryFrom<String> for CommitHash {
44    type Error = ValidationError;
45
46    fn try_from(value: String) -> Result<Self, Self::Error> {
47        let len = value.len();
48        if len != 40 && len != 64 {
49            tracing::warn!(
50                "Validation failed for CommitHash: {}. Invalid length: {}",
51                value,
52                len
53            );
54            return Err(ValidationError::InvalidValue(format!(
55                "Commit hash must be 40 or 64 characters long. Got: {}",
56                len
57            )));
58        }
59
60        if !value.chars().all(|c| c.is_ascii_hexdigit()) {
61            tracing::warn!(
62                "Validation failed for CommitHash: {}. Non-hex characters",
63                value
64            );
65            return Err(ValidationError::InvalidValue(format!(
66                "Commit hash must be a hexadecimal string. Got: {}",
67                value
68            )));
69        }
70
71        Ok(CommitHash(value))
72    }
73}
74
75impl From<CommitHash> for String {
76    fn from(val: CommitHash) -> Self {
77        val.0
78    }
79}
80
81impl std::ops::Deref for CommitHash {
82    type Target = str;
83
84    fn deref(&self) -> &Self::Target {
85        &self.0
86    }
87}
88
89impl PartialEq<str> for CommitHash {
90    fn eq(&self, other: &str) -> bool {
91        self.0 == other
92    }
93}
94
95impl PartialEq<CommitHash> for str {
96    fn eq(&self, other: &CommitHash) -> bool {
97        self == other.0
98    }
99}
100
101impl PartialEq<String> for CommitHash {
102    fn eq(&self, other: &String) -> bool {
103        &self.0 == other
104    }
105}
106
107impl PartialEq<CommitHash> for String {
108    fn eq(&self, other: &CommitHash) -> bool {
109        self == &other.0
110    }
111}