ftth_rsip/common/
version.rs1use crate::Error;
2#[doc(hidden)]
3pub use tokenizer::Tokenizer;
4
5use std::convert::{TryFrom, TryInto};
6
7#[derive(Debug, PartialEq, Eq, Clone)]
9pub enum Version {
10 V1,
11 V2,
12 }
14
15impl Default for Version {
16 fn default() -> Self {
17 Self::V2
18 }
19}
20
21impl<'a> TryFrom<&'a [u8]> for Version {
22 type Error = crate::Error;
23
24 fn try_from(from: &'a [u8]) -> Result<Self, Self::Error> {
25 Tokenizer::tokenize(from)?.1.try_into()
26 }
27}
28
29impl std::fmt::Display for Version {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 match self {
32 Self::V1 => write!(f, "SIP/1.0"),
33 Self::V2 => write!(f, "SIP/2.0"),
34 }
35 }
36}
37
38impl<'a> std::convert::TryFrom<tokenizer::Tokenizer<'a, &'a str, char>> for Version {
39 type Error = Error;
40
41 fn try_from(tokenizer: tokenizer::Tokenizer<'a, &'a str, char>) -> Result<Self, Self::Error> {
42 match tokenizer.major {
43 "1" => Ok(Version::V1),
44 "2" => Ok(Version::V2),
45 _ => Err(Self::Error::ParseError("Unrecognized SIP version".into())),
46 }
47 }
48}
49
50impl<'a> std::convert::TryFrom<tokenizer::Tokenizer<'a, &'a [u8], u8>> for Version {
51 type Error = Error;
52
53 fn try_from(tokenizer: tokenizer::Tokenizer<'a, &'a [u8], u8>) -> Result<Self, Self::Error> {
54 match tokenizer.major {
55 b"1" => Ok(Version::V1),
56 b"2" => Ok(Version::V2),
57 _ => Err(Self::Error::ParseError("Unrecognized SIP version".into())),
58 }
59 }
60}
61
62#[doc(hidden)]
63mod tokenizer {
64 use crate::{AbstractInput, AbstractInputItem, GResult, GenericNomError, TokenizerError};
65 use std::marker::PhantomData;
66
67 #[derive(Debug, PartialEq, Eq, Clone)]
68 pub struct Tokenizer<'a, T, I>
69 where
70 T: AbstractInput<'a, I>,
71 I: AbstractInputItem<I>,
72 {
73 pub major: T,
74 pub minor: T,
75 phantom1: PhantomData<&'a T>,
76 phantom2: PhantomData<I>,
77 }
78
79 impl<'a, T, I> From<(T, T)> for Tokenizer<'a, T, I>
80 where
81 T: AbstractInput<'a, I>,
82 I: AbstractInputItem<I>,
83 {
84 fn from(from: (T, T)) -> Self {
85 Self {
86 major: from.0,
87 minor: from.1,
88 phantom1: PhantomData,
89 phantom2: PhantomData,
90 }
91 }
92 }
93
94 impl<'a, T, I> Tokenizer<'a, T, I>
95 where
96 T: AbstractInput<'a, I>,
97 I: AbstractInputItem<I>,
98 {
99 pub fn tokenize(part: T) -> GResult<T, Self> {
100 use nom::{bytes::complete::tag, character::complete::digit1, sequence::tuple};
101
102 let (rem, (_, major, _, minor)) = tuple((tag("SIP/"), digit1, tag("."), digit1))(part)
103 .map_err(|_: GenericNomError<'a, T>| {
104 TokenizerError::from(("version", part)).into()
105 })?;
106
107 Ok((rem, (major, minor).into()))
108 }
109 }
110}
111
112#[cfg(feature = "test-utils")]
113impl testing_utils::Randomize for Version {
114 fn random() -> Self {
115 Self::V2
117 }
118}