rama_core/username/
compose.rs1use rama_utils::macros::all_the_tuples_no_last_special_case;
2use std::{
3 fmt::{self, Write},
4 sync::Arc,
5};
6
7use super::DEFAULT_USERNAME_LABEL_SEPARATOR;
8
9#[derive(Debug, Clone)]
10pub struct Composer<const SEPARATOR: char = DEFAULT_USERNAME_LABEL_SEPARATOR> {
14 buffer: String,
15}
16
17#[derive(Debug, Clone)]
18pub struct ComposeError(ComposeErrorKind);
21
22#[derive(Debug, Clone)]
23enum ComposeErrorKind {
24 EmptyLabel,
25 FmtError(fmt::Error),
26}
27
28impl fmt::Display for ComposeError {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 match self.0 {
31 ComposeErrorKind::EmptyLabel => f.write_str("empty label"),
32 ComposeErrorKind::FmtError(err) => write!(f, "fmt error: {err}"),
33 }
34 }
35}
36
37impl std::error::Error for ComposeError {
38 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
39 match &self.0 {
40 ComposeErrorKind::EmptyLabel => None,
41 ComposeErrorKind::FmtError(err) => err.source(),
42 }
43 }
44}
45
46impl<const SEPARATOR: char> Composer<SEPARATOR> {
47 fn new(username: String) -> Self {
48 Self { buffer: username }
49 }
50
51 pub fn write_label(&mut self, label: impl AsRef<str>) -> Result<(), ComposeError> {
53 self.buffer
54 .write_char(SEPARATOR)
55 .map_err(|err| ComposeError(ComposeErrorKind::FmtError(err)))?;
56 let label = label.as_ref();
57 if label.is_empty() {
58 return Err(ComposeError(ComposeErrorKind::EmptyLabel));
59 }
60 self.buffer
61 .write_str(label.as_ref())
62 .map_err(|err| ComposeError(ComposeErrorKind::FmtError(err)))?;
63 Ok(())
64 }
65
66 fn compose(self) -> String {
67 self.buffer
68 }
69}
70
71#[inline]
72pub fn compose_username(
74 username: String,
75 labels: impl UsernameLabelWriter<DEFAULT_USERNAME_LABEL_SEPARATOR>,
76) -> Result<String, ComposeError> {
77 compose_username_with_separator::<DEFAULT_USERNAME_LABEL_SEPARATOR>(username, labels)
78}
79
80pub fn compose_username_with_separator<const SEPARATOR: char>(
83 username: String,
84 labels: impl UsernameLabelWriter<SEPARATOR>,
85) -> Result<String, ComposeError> {
86 let mut composer = Composer::<SEPARATOR>::new(username);
87 labels.write_labels(&mut composer)?;
88 Ok(composer.compose())
89}
90
91pub trait UsernameLabelWriter<const SEPARATOR: char> {
94 fn write_labels(&self, composer: &mut Composer<SEPARATOR>) -> Result<(), ComposeError>;
96}
97
98impl<const SEPARATOR: char> UsernameLabelWriter<SEPARATOR> for String {
99 fn write_labels(&self, composer: &mut Composer<SEPARATOR>) -> Result<(), ComposeError> {
100 composer.write_label(self)
101 }
102}
103
104impl<const SEPARATOR: char> UsernameLabelWriter<SEPARATOR> for &str {
105 fn write_labels(&self, composer: &mut Composer<SEPARATOR>) -> Result<(), ComposeError> {
106 composer.write_label(self)
107 }
108}
109
110impl<const SEPARATOR: char, const N: usize, W> UsernameLabelWriter<SEPARATOR> for [W; N]
111where
112 W: UsernameLabelWriter<SEPARATOR>,
113{
114 fn write_labels(&self, composer: &mut Composer<SEPARATOR>) -> Result<(), ComposeError> {
115 for writer in self {
116 writer.write_labels(composer)?;
117 }
118 Ok(())
119 }
120}
121
122impl<const SEPARATOR: char, W> UsernameLabelWriter<SEPARATOR> for Option<W>
123where
124 W: UsernameLabelWriter<SEPARATOR>,
125{
126 fn write_labels(&self, composer: &mut Composer<SEPARATOR>) -> Result<(), ComposeError> {
127 match self {
128 Some(writer) => writer.write_labels(composer),
129 None => Ok(()),
130 }
131 }
132}
133
134impl<const SEPARATOR: char, W> UsernameLabelWriter<SEPARATOR> for &W
135where
136 W: UsernameLabelWriter<SEPARATOR>,
137{
138 fn write_labels(&self, composer: &mut Composer<SEPARATOR>) -> Result<(), ComposeError> {
139 (*self).write_labels(composer)
140 }
141}
142
143impl<const SEPARATOR: char, W> UsernameLabelWriter<SEPARATOR> for Arc<W>
144where
145 W: UsernameLabelWriter<SEPARATOR>,
146{
147 fn write_labels(&self, composer: &mut Composer<SEPARATOR>) -> Result<(), ComposeError> {
148 (**self).write_labels(composer)
149 }
150}
151
152impl<const SEPARATOR: char, W> UsernameLabelWriter<SEPARATOR> for Vec<W>
153where
154 W: UsernameLabelWriter<SEPARATOR>,
155{
156 fn write_labels(&self, composer: &mut Composer<SEPARATOR>) -> Result<(), ComposeError> {
157 for writer in self {
158 writer.write_labels(composer)?;
159 }
160 Ok(())
161 }
162}
163
164macro_rules! impl_username_label_writer_either {
165 ($id:ident, $($param:ident),+ $(,)?) => {
166 impl<const SEPARATOR: char, $($param),+> UsernameLabelWriter<SEPARATOR> for crate::combinators::$id<$($param),+>
167 where
168 $(
169 $param: UsernameLabelWriter<SEPARATOR>,
170 )+
171 {
172 fn write_labels(&self, composer: &mut Composer<SEPARATOR>) -> Result<(), ComposeError> {
173 match self {
174 $(
175 crate::combinators::$id::$param(writer) => {
176 writer.write_labels(composer)
177 }
178 )+
179 }
180 }
181 }
182 };
183}
184
185crate::combinators::impl_either!(impl_username_label_writer_either);
186
187macro_rules! impl_username_label_writer_for_tuple {
188 ( $($ty:ident),* $(,)? ) => {
189 #[allow(non_snake_case)]
190 impl<const SEPARATOR: char, $($ty),*> UsernameLabelWriter<SEPARATOR> for ($($ty,)*)
191 where
192 $( $ty: UsernameLabelWriter<SEPARATOR>, )*
193 {
194 fn write_labels(&self, composer: &mut Composer<SEPARATOR>) -> Result<(), ComposeError> {
195 let ($($ty),*,) = self;
196 $(
197 $ty.write_labels(composer)?;
198 )*
199 Ok(())
200 }
201 }
202 };
203}
204all_the_tuples_no_last_special_case!(impl_username_label_writer_for_tuple);