1use std::str::FromStr;
4
5use nom::{
6 character::complete::{char, digit1},
7 combinator::all_consuming,
8 sequence::preceded,
9 IResult,
10};
11use serde::{Deserialize, Serialize};
12
13use crate::error::{map_add_intent, Error};
14
15#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
19pub struct SessionId(String);
20
21impl FromStr for SessionId {
22 type Err = Error;
23
24 fn from_str(input: &str) -> std::result::Result<Self, Self::Err> {
27 let desc = "SessionId";
28 let intent = "#{session_id}";
29
30 let (_, sess_id) =
31 all_consuming(parse::session_id)(input).map_err(|e| map_add_intent(desc, intent, e))?;
32
33 Ok(sess_id)
34 }
35}
36
37pub(crate) mod parse {
44 use super::*;
45
46 pub fn session_id(input: &str) -> IResult<&str, SessionId> {
47 let (input, digit) = preceded(char('$'), digit1)(input)?;
48 let id = format!("${digit}");
49 Ok((input, SessionId(id)))
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 #[test]
58 fn test_parse_session_id_fn() {
59 let actual = parse::session_id("$43");
60 let expected = Ok(("", SessionId("$43".into())));
61 assert_eq!(actual, expected);
62
63 let actual = parse::session_id("$4");
64 let expected = Ok(("", SessionId("$4".into())));
65 assert_eq!(actual, expected);
66 }
67
68 #[test]
69 fn test_parse_session_id_struct() {
70 let actual = SessionId::from_str("$43");
71 assert!(actual.is_ok());
72 assert_eq!(actual.unwrap(), SessionId("$43".into()));
73
74 let actual = SessionId::from_str("4:38");
75 assert!(matches!(
76 actual,
77 Err(Error::ParseError {
78 desc: "SessionId",
79 intent: "#{session_id}",
80 err: _
81 })
82 ));
83 }
84}