1use crate::errors::InvalidValue;
4use crate::{
5 Encoding, Error, Ident, Result,
6 value::{Decimal, Value},
7};
8use core::{
9 fmt::{self, Debug, Write},
10 str::{self, FromStr},
11};
12
13pub type Pair<'a> = (Ident<'a>, Value<'a>);
15
16pub(crate) const PAIR_DELIMITER: char = '=';
18
19pub(crate) const PARAMS_DELIMITER: char = ',';
21
22const MAX_LENGTH: usize = 127;
24
25const INVARIANT_VIOLATED_MSG: &str = "PHC params invariant violated";
28
29#[derive(Clone, Default, Eq, PartialEq)]
43pub struct ParamsString(Buffer);
44
45impl ParamsString {
46 pub fn new() -> Self {
48 Self::default()
49 }
50
51 pub fn add_b64_bytes<'a>(&mut self, name: impl TryInto<Ident<'a>>, bytes: &[u8]) -> Result<()> {
53 if !self.is_empty() {
54 self.0
55 .write_char(PARAMS_DELIMITER)
56 .map_err(|_| Error::ParamsMaxExceeded)?
57 }
58
59 let name = name.try_into().map_err(|_| Error::ParamNameInvalid)?;
60
61 let offset = self.0.length;
63 if write!(self.0, "{name}=").is_err() {
64 self.0.length = offset;
65 return Err(Error::ParamsMaxExceeded);
66 }
67
68 let offset = self.0.length as usize;
70 let written = Encoding::B64
71 .encode(bytes, &mut self.0.bytes[offset..])?
72 .len();
73
74 self.0.length += written as u8;
75 Ok(())
76 }
77
78 pub fn add_decimal<'a>(&mut self, name: impl TryInto<Ident<'a>>, value: Decimal) -> Result<()> {
80 let name = name.try_into().map_err(|_| Error::ParamNameInvalid)?;
81 self.add(name, value)
82 }
83
84 pub fn add_str<'a>(
86 &mut self,
87 name: impl TryInto<Ident<'a>>,
88 value: impl TryInto<Value<'a>>,
89 ) -> Result<()> {
90 let name = name.try_into().map_err(|_| Error::ParamNameInvalid)?;
91
92 let value = value
93 .try_into()
94 .map_err(|_| Error::ParamValueInvalid(InvalidValue::InvalidFormat))?;
95
96 self.add(name, value)
97 }
98
99 pub fn as_bytes(&self) -> &[u8] {
101 self.as_str().as_bytes()
102 }
103
104 pub fn as_str(&self) -> &str {
106 self.0.as_ref()
107 }
108
109 pub fn len(&self) -> usize {
111 self.as_str().len()
112 }
113
114 pub fn is_empty(&self) -> bool {
116 self.len() == 0
117 }
118
119 pub fn iter(&self) -> Iter<'_> {
121 Iter::new(self.as_str())
122 }
123
124 pub fn get<'a>(&self, name: impl TryInto<Ident<'a>>) -> Option<Value<'_>> {
126 let name = name.try_into().ok()?;
127
128 for (n, v) in self.iter() {
129 if name == n {
130 return Some(v);
131 }
132 }
133
134 None
135 }
136
137 pub fn get_str<'a>(&self, name: impl TryInto<Ident<'a>>) -> Option<&str> {
139 self.get(name).map(|value| value.as_str())
140 }
141
142 pub fn get_decimal<'a>(&self, name: impl TryInto<Ident<'a>>) -> Option<Decimal> {
146 self.get(name).and_then(|value| value.decimal().ok())
147 }
148
149 fn add(&mut self, name: Ident<'_>, value: impl fmt::Display) -> Result<()> {
151 if self.get(name).is_some() {
152 return Err(Error::ParamNameDuplicated);
153 }
154
155 let orig_len = self.0.length;
156
157 if !self.is_empty() {
158 self.0
159 .write_char(PARAMS_DELIMITER)
160 .map_err(|_| Error::ParamsMaxExceeded)?
161 }
162
163 if write!(self.0, "{name}={value}").is_err() {
164 self.0.length = orig_len;
165 return Err(Error::ParamsMaxExceeded);
166 }
167
168 Ok(())
169 }
170}
171
172impl FromStr for ParamsString {
173 type Err = Error;
174
175 fn from_str(s: &str) -> Result<Self> {
176 if s.len() > MAX_LENGTH {
177 return Err(Error::ParamsMaxExceeded);
178 }
179
180 if s.is_empty() {
181 return Ok(ParamsString::new());
182 }
183
184 for mut param in s.split(PARAMS_DELIMITER).map(|p| p.split(PAIR_DELIMITER)) {
186 param
188 .next()
189 .ok_or(Error::ParamNameInvalid)
190 .and_then(Ident::try_from)?;
191
192 param
194 .next()
195 .ok_or(Error::ParamValueInvalid(InvalidValue::Malformed))
196 .and_then(Value::try_from)?;
197
198 if param.next().is_some() {
199 return Err(Error::ParamValueInvalid(InvalidValue::Malformed));
200 }
201 }
202
203 let mut bytes = [0u8; MAX_LENGTH];
204 bytes[..s.len()].copy_from_slice(s.as_bytes());
205
206 Ok(Self(Buffer {
207 bytes,
208 length: s.len() as u8,
209 }))
210 }
211}
212
213impl<'a> FromIterator<Pair<'a>> for ParamsString {
214 fn from_iter<I>(iter: I) -> Self
215 where
216 I: IntoIterator<Item = Pair<'a>>,
217 {
218 let mut params = ParamsString::new();
219
220 for pair in iter {
221 params.add_str(pair.0, pair.1).expect("PHC params error");
222 }
223
224 params
225 }
226}
227
228impl fmt::Display for ParamsString {
229 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
230 f.write_str(self.as_str())
231 }
232}
233
234impl fmt::Debug for ParamsString {
235 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
236 f.debug_map().entries(self.iter()).finish()
237 }
238}
239
240#[derive(Debug)]
242pub struct Iter<'a> {
243 inner: Option<str::Split<'a, char>>,
244}
245
246impl<'a> Iter<'a> {
247 fn new(s: &'a str) -> Self {
249 if s.is_empty() {
250 Self { inner: None }
251 } else {
252 Self {
253 inner: Some(s.split(PARAMS_DELIMITER)),
254 }
255 }
256 }
257}
258
259impl<'a> Iterator for Iter<'a> {
260 type Item = Pair<'a>;
261
262 fn next(&mut self) -> Option<Pair<'a>> {
263 let mut param = self.inner.as_mut()?.next()?.split(PAIR_DELIMITER);
264
265 let name = param
266 .next()
267 .and_then(|id| Ident::try_from(id).ok())
268 .expect(INVARIANT_VIOLATED_MSG);
269
270 let value = param
271 .next()
272 .and_then(|value| Value::try_from(value).ok())
273 .expect(INVARIANT_VIOLATED_MSG);
274
275 debug_assert_eq!(param.next(), None);
276 Some((name, value))
277 }
278}
279
280#[derive(Clone, Debug, Eq)]
282struct Buffer {
283 bytes: [u8; MAX_LENGTH],
285
286 length: u8,
288}
289
290impl AsRef<str> for Buffer {
291 fn as_ref(&self) -> &str {
292 str::from_utf8(&self.bytes[..(self.length as usize)]).expect(INVARIANT_VIOLATED_MSG)
293 }
294}
295
296impl Default for Buffer {
297 fn default() -> Buffer {
298 Buffer {
299 bytes: [0u8; MAX_LENGTH],
300 length: 0,
301 }
302 }
303}
304
305impl PartialEq for Buffer {
306 fn eq(&self, other: &Self) -> bool {
307 self.as_ref().eq(other.as_ref())
309 }
310}
311
312impl Write for Buffer {
313 fn write_str(&mut self, input: &str) -> fmt::Result {
314 let bytes = input.as_bytes();
315 let length = self.length as usize;
316
317 if length + bytes.len() > MAX_LENGTH {
318 return Err(fmt::Error);
319 }
320
321 self.bytes[length..(length + bytes.len())].copy_from_slice(bytes);
322 self.length += bytes.len() as u8;
323
324 Ok(())
325 }
326}
327
328#[cfg(test)]
329mod tests {
330 use super::{Error, Ident, ParamsString, Value};
331
332 #[cfg(feature = "alloc")]
333 use alloc::string::ToString;
334 use core::str::FromStr;
335
336 #[test]
337 fn add() {
338 let mut params = ParamsString::new();
339 params.add_str("a", "1").unwrap();
340 params.add_decimal("b", 2).unwrap();
341 params.add_str("c", "3").unwrap();
342
343 assert_eq!(params.iter().count(), 3);
344 assert_eq!(params.get_decimal("a").unwrap(), 1);
345 assert_eq!(params.get_decimal("b").unwrap(), 2);
346 assert_eq!(params.get_decimal("c").unwrap(), 3);
347 }
348
349 #[test]
350 #[cfg(feature = "alloc")]
351 fn add_b64_bytes() {
352 let mut params = ParamsString::new();
353 params.add_b64_bytes("a", &[1]).unwrap();
354 params.add_b64_bytes("b", &[2, 3]).unwrap();
355 params.add_b64_bytes("c", &[4, 5, 6]).unwrap();
356 assert_eq!(params.to_string(), "a=AQ,b=AgM,c=BAUG");
357 }
358
359 #[test]
360 fn duplicate_names() {
361 let name = Ident::new("a").unwrap();
362 let mut params = ParamsString::new();
363 params.add_decimal(name, 1).unwrap();
364
365 let err = params.add_decimal(name, 2u32).err().unwrap();
366 assert_eq!(err, Error::ParamNameDuplicated);
367 }
368
369 #[test]
370 fn from_iter() {
371 let params = ParamsString::from_iter(
372 [
373 (Ident::new("a").unwrap(), Value::try_from("1").unwrap()),
374 (Ident::new("b").unwrap(), Value::try_from("2").unwrap()),
375 (Ident::new("c").unwrap(), Value::try_from("3").unwrap()),
376 ]
377 .iter()
378 .cloned(),
379 );
380
381 assert_eq!(params.iter().count(), 3);
382 assert_eq!(params.get_decimal("a").unwrap(), 1);
383 assert_eq!(params.get_decimal("b").unwrap(), 2);
384 assert_eq!(params.get_decimal("c").unwrap(), 3);
385 }
386
387 #[test]
388 fn iter() {
389 let mut params = ParamsString::new();
390 params.add_str("a", "1").unwrap();
391 params.add_str("b", "2").unwrap();
392 params.add_str("c", "3").unwrap();
393
394 let mut i = params.iter();
395
396 for (name, value) in &[("a", "1"), ("b", "2"), ("c", "3")] {
397 let name = Ident::new(name).unwrap();
398 let value = Value::try_from(*value).unwrap();
399 assert_eq!(i.next(), Some((name, value)));
400 }
401
402 assert_eq!(i.next(), None);
403 }
404
405 #[test]
410 fn parse_empty() {
411 let params = ParamsString::from_str("").unwrap();
412 assert!(params.is_empty());
413 }
414
415 #[test]
416 fn parse_one() {
417 let params = ParamsString::from_str("a=1").unwrap();
418 assert_eq!(params.iter().count(), 1);
419 assert_eq!(params.get("a").unwrap().decimal().unwrap(), 1);
420 }
421
422 #[test]
423 fn parse_many() {
424 let params = ParamsString::from_str("a=1,b=2,c=3").unwrap();
425 assert_eq!(params.iter().count(), 3);
426 assert_eq!(params.get_decimal("a").unwrap(), 1);
427 assert_eq!(params.get_decimal("b").unwrap(), 2);
428 assert_eq!(params.get_decimal("c").unwrap(), 3);
429 }
430
431 #[test]
436 #[cfg(feature = "alloc")]
437 fn display_empty() {
438 let params = ParamsString::new();
439 assert_eq!(params.to_string(), "");
440 }
441
442 #[test]
443 #[cfg(feature = "alloc")]
444 fn display_one() {
445 let params = ParamsString::from_str("a=1").unwrap();
446 assert_eq!(params.to_string(), "a=1");
447 }
448
449 #[test]
450 #[cfg(feature = "alloc")]
451 fn display_many() {
452 let params = ParamsString::from_str("a=1,b=2,c=3").unwrap();
453 assert_eq!(params.to_string(), "a=1,b=2,c=3");
454 }
455}