radicle_git_metadata/commit/
trailers.rs1use std::{borrow::Cow, fmt, ops::Deref};
2
3pub trait Separator<'a> {
4 fn sep_for(&self, token: &Token) -> &'a str;
5}
6
7impl<'a> Separator<'a> for &'a str {
8 fn sep_for(&self, _: &Token) -> &'a str {
9 self
10 }
11}
12
13impl<'a, F> Separator<'a> for F
14where
15 F: Fn(&Token) -> &'a str,
16{
17 fn sep_for(&self, token: &Token) -> &'a str {
18 self(token)
19 }
20}
21
22#[derive(Debug, Clone, Eq, PartialEq)]
23pub struct Token<'a>(&'a str);
24
25impl Deref for Token<'_> {
26 type Target = str;
27
28 fn deref(&self) -> &Self::Target {
29 self.0
30 }
31}
32
33impl<'a> TryFrom<&'a str> for Token<'a> {
34 type Error = &'static str;
35
36 fn try_from(s: &'a str) -> Result<Self, Self::Error> {
37 let is_token = s.chars().all(|c| c.is_alphanumeric() || c == '-');
38 if is_token {
39 Ok(Token(s))
40 } else {
41 Err("token contains invalid characters")
42 }
43 }
44}
45
46pub struct Display<'a> {
47 trailer: &'a Trailer<'a>,
48 separator: &'a str,
49}
50
51impl fmt::Display for Display<'_> {
52 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
53 write!(
54 f,
55 "{}{}{}",
56 self.trailer.token.deref(),
57 self.separator,
58 self.trailer.value,
59 )
60 }
61}
62
63#[derive(Debug, Clone, Eq, PartialEq)]
67pub struct Trailer<'a> {
68 pub token: Token<'a>,
69 pub value: Cow<'a, str>,
70}
71
72impl<'a> Trailer<'a> {
73 pub fn display(&'a self, separator: &'a str) -> Display<'a> {
74 Display {
75 trailer: self,
76 separator,
77 }
78 }
79
80 pub fn to_owned(&self) -> OwnedTrailer {
81 OwnedTrailer::from(self)
82 }
83}
84
85#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
89pub struct OwnedTrailer {
90 pub token: OwnedToken,
91 pub value: String,
92}
93
94#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
95pub struct OwnedToken(String);
96
97impl Deref for OwnedToken {
98 type Target = str;
99
100 fn deref(&self) -> &Self::Target {
101 &self.0
102 }
103}
104
105impl<'a> From<&Trailer<'a>> for OwnedTrailer {
106 fn from(t: &Trailer<'a>) -> Self {
107 OwnedTrailer {
108 token: OwnedToken(t.token.0.to_string()),
109 value: t.value.to_string(),
110 }
111 }
112}
113
114impl<'a> From<Trailer<'a>> for OwnedTrailer {
115 fn from(t: Trailer<'a>) -> Self {
116 (&t).into()
117 }
118}
119
120impl<'a> From<&'a OwnedTrailer> for Trailer<'a> {
121 fn from(t: &'a OwnedTrailer) -> Self {
122 Trailer {
123 token: Token(t.token.0.as_str()),
124 value: Cow::from(&t.value),
125 }
126 }
127}