1#[doc(hidden)]
2pub use tokenizer::Tokenizer;
3
4pub mod branch;
5pub mod expires;
6pub mod maddr;
7pub mod q;
8pub mod received;
9pub mod tag;
10pub mod ttl;
11pub mod user;
12
13pub use branch::Branch;
14pub use expires::Expires;
15pub use maddr::Maddr;
16pub use q::Q;
17pub use received::Received;
18pub use tag::Tag;
19pub use ttl::Ttl;
20pub use user::User;
21
22use crate::{Error, Method, Transport};
23use rsip_derives::NewType;
24use std::convert::TryInto;
25
26#[derive(Debug, PartialEq, Eq, Clone)]
33pub enum Param {
34 Transport(Transport),
35 User(User),
36 Method(Method),
37 Ttl(Ttl),
38 Maddr(Maddr),
39 Lr,
40 Branch(Branch), Received(Received), Tag(Tag), Expires(Expires), Q(Q), Other(OtherParam, Option<OtherParamValue>),
46}
47
48#[derive(NewType, Debug, PartialEq, Eq, Clone)]
49pub struct OtherParam(String);
50#[derive(NewType, Debug, PartialEq, Eq, Clone)]
51pub struct OtherParamValue(String);
52
53impl std::fmt::Display for Param {
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 match &self {
56 Self::Transport(transport) => write!(f, ";transport={}", transport),
57 Self::User(user) => write!(f, ";user={}", user),
58 Self::Method(method) => write!(f, ";method={}", method),
59 Self::Ttl(ttl) => write!(f, ";ttl={}", ttl),
60 Self::Maddr(maddr) => write!(f, ";maddr={}", maddr),
61 Self::Lr => write!(f, ";lr"),
62 Self::Branch(branch) => write!(f, ";branch={}", branch),
63 Self::Received(received) => write!(f, ";received={}", received),
64 Self::Tag(tag) => write!(f, ";tag={}", tag),
65 Self::Expires(expires) => write!(f, ";expires={}", expires),
66 Self::Q(q) => write!(f, ";q={}", q),
67 Self::Other(name, Some(value)) => write!(f, ";{}={}", name, value),
68 Self::Other(name, None) => write!(f, ";{}", name),
69 }
70 }
71}
72
73impl<'a> std::convert::TryFrom<tokenizer::Tokenizer<'a, &'a str, char>> for Param {
74 type Error = Error;
75
76 fn try_from(tokenizer: tokenizer::Tokenizer<'a, &'a str, char>) -> Result<Self, Self::Error> {
77 (tokenizer.name, tokenizer.value).try_into()
78 }
79}
80
81impl<'a> std::convert::TryFrom<tokenizer::Tokenizer<'a, &'a [u8], u8>> for Param {
82 type Error = Error;
83
84 fn try_from(tokenizer: tokenizer::Tokenizer<'a, &'a [u8], u8>) -> Result<Self, Self::Error> {
85 use std::str::from_utf8;
86
87 Self::try_from(Tokenizer::from((
88 from_utf8(tokenizer.name)?,
89 tokenizer.value.map(from_utf8).transpose()?,
90 )))
91 }
92}
93
94impl<'a> std::convert::TryFrom<(&'a str, Option<&'a str>)> for Param {
95 type Error = Error;
96
97 fn try_from(from: (&'a str, Option<&'a str>)) -> Result<Self, Self::Error> {
98 use std::str::FromStr;
99
100 match (from.0, from.1) {
101 (s, Some(v)) if s.eq_ignore_ascii_case("transport") => {
102 Ok(Param::Transport(Transport::from_str(v)?))
103 }
104 (s, Some(v)) if s.eq_ignore_ascii_case("user") => Ok(Param::User(User::new(v))),
105 (s, Some(v)) if s.eq_ignore_ascii_case("method") => {
106 Ok(Param::Method(Method::from_str(v)?))
107 }
108 (s, Some(v)) if s.eq_ignore_ascii_case("ttl") => Ok(Param::Ttl(Ttl::new(v))),
109 (s, Some(v)) if s.eq_ignore_ascii_case("maddr") => Ok(Param::Maddr(Maddr::new(v))),
110 (s, Some(v)) if s.eq_ignore_ascii_case("branch") => Ok(Param::Branch(Branch::new(v))),
111 (s, Some(v)) if s.eq_ignore_ascii_case("received") => {
112 Ok(Param::Received(Received::new(v)))
113 }
114 (s, Some(v)) if s.eq_ignore_ascii_case("tag") => Ok(Param::Tag(Tag::new(v))),
115 (s, Some(v)) if s.eq_ignore_ascii_case("expires") => {
116 Ok(Param::Expires(Expires::new(v)))
117 }
118 (s, Some(v)) if s.eq_ignore_ascii_case("q") => Ok(Param::Q(Q::new(v))),
119 (s, None) if s.eq_ignore_ascii_case("lr") => Ok(Param::Lr),
120 (s, v) => Ok(Param::Other(s.into(), v.map(Into::into))),
121 }
122 }
123}
124
125#[doc(hidden)]
126pub mod tokenizer {
127 use crate::{AbstractInput, AbstractInputItem, GResult, GenericNomError, TokenizerError};
128 use std::marker::PhantomData;
129
130 #[derive(Debug, PartialEq, Eq, Clone)]
131 pub struct Tokenizer<'a, T, I>
132 where
133 T: AbstractInput<'a, I>,
134 I: AbstractInputItem<I>,
135 {
136 pub name: T,
137 pub value: Option<T>,
138 phantom1: PhantomData<&'a T>,
139 phantom2: PhantomData<I>,
140 }
141
142 impl<'a, T, I> From<(T, Option<T>)> for Tokenizer<'a, T, I>
143 where
144 T: AbstractInput<'a, I>,
145 I: AbstractInputItem<I>,
146 {
147 fn from(from: (T, Option<T>)) -> Self {
148 Self {
149 name: from.0,
150 value: from.1,
151 phantom1: PhantomData,
152 phantom2: PhantomData,
153 }
154 }
155 }
156
157 impl<'a, T, I> Tokenizer<'a, T, I>
158 where
159 T: AbstractInput<'a, I>,
160 I: AbstractInputItem<I>,
161 {
162 pub fn tokenize(part: T) -> GResult<T, Self> {
163 use nom::{
164 bytes::complete::{tag, take_while},
165 combinator::{map, opt},
166 sequence::tuple,
167 };
168
169 let (rem, (_, name, value)) = tuple((
170 tag(";"),
171 take_while(I::is_token), opt(map(tuple((tag("="), take_while(I::is_token))), |t| t.1)),
173 ))(part)
174 .map_err(|_: GenericNomError<'a, T>| {
175 TokenizerError::from(("uri param", part)).into()
176 })?;
177
178 Ok((rem, (name, value).into()))
179 }
180 }
181}
182
183#[cfg(feature = "test-utils")]
184impl testing_utils::Randomize for Param {
185 fn random() -> Self {
186 use testing_utils::{rand_str_of, sample, Randomize};
187 sample(&[
188 Param::Transport(Randomize::random()),
189 Param::Method(Randomize::random()),
190 Param::User(Randomize::random()),
191 Param::Ttl(Randomize::random()),
192 Param::Maddr(Randomize::random()),
193 Param::Lr,
194 Param::Branch(Randomize::random()),
195 Param::Received(Randomize::random()),
196 Param::Tag(Randomize::random()),
197 Param::Expires(Randomize::random()),
198 Param::Q(Randomize::random()),
199 Param::Other(
200 rand_str_of(3).into(),
201 sample(&[None, Some(rand_str_of(5).into())]),
202 ),
203 ])
204 }
205}