asteroid_mq_model/
interest.rs1use std::{convert::Infallible, fmt::Display, str::FromStr};
2
3use bytes::Bytes;
4use serde::{Deserialize, Serialize};
5use typeshare::typeshare;
6
7#[derive(Debug, Clone, PartialEq, Eq, Hash)]
8#[typeshare(serialized_as = "String")]
9pub struct Subject(pub(crate) Bytes);
10
11impl From<&'static str> for Subject {
12 fn from(value: &'static str) -> Self {
13 Subject(Bytes::from_static(value.as_bytes()))
14 }
15}
16
17impl Serialize for Subject {
18 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
19 where
20 S: serde::Serializer,
21 {
22 let string = unsafe { std::str::from_utf8_unchecked(self.0.as_ref()) };
23 serializer.serialize_str(string)
24 }
25}
26
27impl<'de> Deserialize<'de> for Subject {
28 fn deserialize<D>(deserializer: D) -> Result<Subject, D::Error>
29 where
30 D: serde::Deserializer<'de>,
31 {
32 let string = String::deserialize(deserializer)?;
33 Ok(Subject(Bytes::from(string)))
34 }
35}
36
37impl FromStr for Subject {
38 type Err = Infallible;
39 fn from_str(s: &str) -> Result<Self, Self::Err> {
40 Ok(Subject(Bytes::from(s.to_owned())))
41 }
42}
43
44impl Display for Subject {
45 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 let string = unsafe { std::str::from_utf8_unchecked(self.0.as_ref()) };
47 write!(f, "{}", string)
48 }
49}
50
51impl AsRef<str> for Subject {
52 fn as_ref(&self) -> &str {
53 self.as_str()
54 }
55}
56
57impl Subject {
58 pub fn as_str(&self) -> &str {
59 unsafe { std::str::from_utf8_unchecked(self.0.as_ref()) }
60 }
61 pub fn as_bytes(&self) -> &[u8] {
62 self.0.as_ref()
63 }
64 pub fn new<B: Into<Bytes>>(bytes: B) -> Self {
65 Self(bytes.into())
66 }
67 pub const fn const_new(bytes: &'static str) -> Self {
68 Self(Bytes::from_static(bytes.as_bytes()))
69 }
70 pub fn segments(&self) -> SubjectSegments<'_> {
71 SubjectSegments {
72 inner: self.0.as_ref(),
73 }
74 }
75}
76#[derive(Debug, Clone)]
77pub struct SubjectSegments<'a> {
78 inner: &'a [u8],
80}
81
82impl<'a> Iterator for SubjectSegments<'a> {
83 type Item = &'a [u8];
84
85 fn next(&mut self) -> Option<Self::Item> {
86 if self.inner.is_empty() {
87 return None;
88 }
89 let mut slash_index = None;
90 for index in 0..self.inner.len() {
91 if self.inner[index] == b'/' {
92 slash_index.replace(index);
93 break;
94 }
95 }
96 if let Some(slash_index) = slash_index {
97 let next = &self.inner[0..slash_index];
98 let mut next_start = None;
99 for (bias, b) in self.inner[slash_index..].iter().enumerate() {
100 if *b != b'/' {
101 next_start = Some(slash_index + bias);
102 break;
103 }
104 }
105 if let Some(next_start) = next_start {
106 self.inner = &self.inner[next_start..]
107 } else {
108 self.inner = &[];
109 }
110 Some(next)
111 } else {
112 let next = self.inner;
113 self.inner = &[];
114 Some(next)
115 }
116 }
117}
118
119#[derive(Debug, Clone, PartialEq, Eq, Hash)]
123#[typeshare(serialized_as = "String")]
124pub struct Interest(pub(crate) Bytes);
125
126impl Serialize for Interest {
127 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
128 where
129 S: serde::Serializer,
130 {
131 let string = unsafe { std::str::from_utf8_unchecked(self.0.as_ref()) };
132 serializer.serialize_str(string)
133 }
134}
135
136impl<'de> Deserialize<'de> for Interest {
137 fn deserialize<D>(deserializer: D) -> Result<Interest, D::Error>
138 where
139 D: serde::Deserializer<'de>,
140 {
141 let string = String::deserialize(deserializer)?;
142 Ok(Interest(Bytes::from(string)))
143 }
144}
145
146impl Interest {
147 pub fn new<B: Into<Bytes>>(bytes: B) -> Self {
148 Self(bytes.into())
149 }
150 pub fn as_segments(&self) -> impl Iterator<Item = InterestSegment<'_>> + Clone {
151 self.0.split(|c| *c == b'/').filter_map(|seg| {
152 if seg.is_empty() {
153 None
154 } else {
155 Some(match seg.trim_ascii() {
156 b"*" => InterestSegment::Any,
157 b"**" => InterestSegment::RecursiveAny,
158 specific => InterestSegment::Specific(specific),
159 })
160 }
161 })
162 }
163}
164
165pub enum InterestSegment<'a> {
166 Specific(&'a [u8]),
167 Any,
168 RecursiveAny,
169}
170impl InterestSegment<'_> {
171 pub fn to_owned(&self) -> OwnedInterestSegment {
172 match self {
173 InterestSegment::Specific(s) => OwnedInterestSegment::Specific(s.to_vec()),
174 InterestSegment::Any => OwnedInterestSegment::Any,
175 InterestSegment::RecursiveAny => OwnedInterestSegment::RecursiveAny,
176 }
177 }
178}
179pub enum OwnedInterestSegment {
180 Specific(Vec<u8>),
181 Any,
182 RecursiveAny,
183}