rama_core/username/
compose.rs1use core::fmt::{self, Write};
2
3use crate::std::{string::String, sync::Arc, vec::Vec};
4
5use super::DEFAULT_USERNAME_LABEL_SEPARATOR;
6
7use rama_utils::macros::all_the_tuples_no_last_special_case;
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 core::error::Error for ComposeError {
38 fn source(&self) -> Option<&(dyn core::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 #[inline(always)]
106 fn write_labels(&self, composer: &mut Composer<SEPARATOR>) -> Result<(), ComposeError> {
107 composer.write_label(self)
108 }
109}
110
111impl<const SEPARATOR: char, const N: usize, W> UsernameLabelWriter<SEPARATOR> for [W; N]
112where
113 W: UsernameLabelWriter<SEPARATOR>,
114{
115 fn write_labels(&self, composer: &mut Composer<SEPARATOR>) -> Result<(), ComposeError> {
116 for writer in self {
117 writer.write_labels(composer)?;
118 }
119 Ok(())
120 }
121}
122
123impl<const SEPARATOR: char, W> UsernameLabelWriter<SEPARATOR> for Option<W>
124where
125 W: UsernameLabelWriter<SEPARATOR>,
126{
127 fn write_labels(&self, composer: &mut Composer<SEPARATOR>) -> Result<(), ComposeError> {
128 match self {
129 Some(writer) => writer.write_labels(composer),
130 None => Ok(()),
131 }
132 }
133}
134
135impl<const SEPARATOR: char, W> UsernameLabelWriter<SEPARATOR> for &W
136where
137 W: UsernameLabelWriter<SEPARATOR>,
138{
139 #[inline(always)]
140 fn write_labels(&self, composer: &mut Composer<SEPARATOR>) -> Result<(), ComposeError> {
141 (*self).write_labels(composer)
142 }
143}
144
145impl<const SEPARATOR: char, W> UsernameLabelWriter<SEPARATOR> for Arc<W>
146where
147 W: UsernameLabelWriter<SEPARATOR>,
148{
149 fn write_labels(&self, composer: &mut Composer<SEPARATOR>) -> Result<(), ComposeError> {
150 (**self).write_labels(composer)
151 }
152}
153
154impl<const SEPARATOR: char, W> UsernameLabelWriter<SEPARATOR> for Vec<W>
155where
156 W: UsernameLabelWriter<SEPARATOR>,
157{
158 fn write_labels(&self, composer: &mut Composer<SEPARATOR>) -> Result<(), ComposeError> {
159 for writer in self {
160 writer.write_labels(composer)?;
161 }
162 Ok(())
163 }
164}
165
166macro_rules! impl_username_label_writer_either {
167 ($id:ident, $($param:ident),+ $(,)?) => {
168 impl<const SEPARATOR: char, $($param),+> UsernameLabelWriter<SEPARATOR> for crate::combinators::$id<$($param),+>
169 where
170 $(
171 $param: UsernameLabelWriter<SEPARATOR>,
172 )+
173 {
174 fn write_labels(&self, composer: &mut Composer<SEPARATOR>) -> Result<(), ComposeError> {
175 match self {
176 $(
177 crate::combinators::$id::$param(writer) => {
178 writer.write_labels(composer)
179 }
180 )+
181 }
182 }
183 }
184 };
185}
186
187crate::combinators::impl_either!(impl_username_label_writer_either);
188
189macro_rules! impl_username_label_writer_for_tuple {
190 ( $($ty:ident),* $(,)? ) => {
191 impl<const SEPARATOR: char, $($ty),*> UsernameLabelWriter<SEPARATOR> for ($($ty,)*)
192 where
193 $( $ty: UsernameLabelWriter<SEPARATOR>, )*
194 {
195 fn write_labels(&self, composer: &mut Composer<SEPARATOR>) -> Result<(), ComposeError> {
196 let ($($ty),*,) = self;
197 $(
198 $ty.write_labels(composer)?;
199 )*
200 Ok(())
201 }
202 }
203 };
204}
205all_the_tuples_no_last_special_case!(impl_username_label_writer_for_tuple);