tor_cell/relaycell/
extlist.rs1use derive_deftly::Deftly;
7use tor_bytes::{EncodeError, EncodeResult, Readable, Reader, Result, Writeable, Writer};
8use tor_memquota::{derive_deftly_template_HasMemoryCost, HasMemoryCostStructural};
9
10#[derive(Clone, Debug, derive_more::Deref, derive_more::DerefMut, Deftly)]
28#[derive_deftly(HasMemoryCost)]
29#[deftly(has_memory_cost(bounds = "T: HasMemoryCostStructural"))]
30pub(super) struct ExtList<T> {
31 pub(super) extensions: Vec<T>,
33}
34impl<T> Default for ExtList<T> {
35 fn default() -> Self {
36 Self {
37 extensions: Vec::new(),
38 }
39 }
40}
41
42#[derive(Clone, Debug, derive_more::Deref, derive_more::DerefMut, derive_more::From)]
44pub(super) struct ExtListRef<'a, T> {
45 extensions: &'a [T],
47}
48
49pub(super) trait ExtGroup: Readable + Writeable {
55 type Id: From<u8> + Into<u8> + Eq + PartialEq + Ord + Copy;
57 fn type_id(&self) -> Self::Id;
59}
60pub(super) trait Ext: Sized {
62 type Id: From<u8> + Into<u8>;
66 fn type_id(&self) -> Self::Id;
68 fn take_body_from(b: &mut Reader<'_>) -> Result<Self>;
71 fn write_body_onto<B: Writer + ?Sized>(&self, b: &mut B) -> EncodeResult<()>;
73}
74impl<T: ExtGroup> Readable for ExtList<T> {
75 fn take_from(b: &mut Reader<'_>) -> Result<Self> {
76 let n_extensions = b.take_u8()?;
77 let extensions: Result<Vec<T>> = (0..n_extensions).map(|_| b.extract::<T>()).collect();
78 Ok(Self {
79 extensions: extensions?,
80 })
81 }
82}
83impl<'a, T: ExtGroup> Writeable for ExtListRef<'a, T> {
84 fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) -> EncodeResult<()> {
85 let n_extensions = self
86 .extensions
87 .len()
88 .try_into()
89 .map_err(|_| EncodeError::BadLengthValue)?;
90 b.write_u8(n_extensions);
91 let mut exts_sorted: Vec<&T> = self.extensions.iter().collect();
92 exts_sorted.sort_by_key(|ext| ext.type_id());
93 exts_sorted.iter().try_for_each(|ext| ext.write_onto(b))?;
94 Ok(())
95 }
96}
97impl<T: ExtGroup> Writeable for ExtList<T> {
98 fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) -> EncodeResult<()> {
99 ExtListRef::from(&self.extensions[..]).write_onto(b)
100 }
101}
102impl<T: ExtGroup> ExtList<T> {
103 #[cfg(feature = "hs")] pub(super) fn replace_by_type(&mut self, ext: T) {
107 self.retain(|e| e.type_id() != ext.type_id());
108 self.push(ext);
109 }
110 pub(super) fn into_vec(self) -> Vec<T> {
112 self.extensions
113 }
114}
115
116#[derive(Clone, Debug, Deftly, Eq, PartialEq)]
118#[derive_deftly(HasMemoryCost)]
119#[deftly(has_memory_cost(bounds = "ID: Copy + 'static"))]
122pub struct UnrecognizedExt<ID> {
123 #[deftly(has_memory_cost(copy))]
125 pub(super) type_id: ID,
126 pub(super) body: Vec<u8>,
128}
129
130impl<ID> UnrecognizedExt<ID> {
131 pub fn new(type_id: ID, body: impl Into<Vec<u8>>) -> Self {
139 Self {
140 type_id,
141 body: body.into(),
142 }
143 }
144}
145
146macro_rules! decl_extension_group {
152 {
153 $( #[$meta:meta] )*
154 $v:vis enum $id:ident [ $type_id:ty ] {
155 $(
156 $(#[$cmeta:meta])*
157 $([feature: #[$fmeta:meta]])?
158 $case:ident),*
159 $(,)?
160 }
161 } => {paste::paste!{
162 $( #[$meta] )*
163 $v enum $id {
164 $( $(#[$cmeta])*
165 $( #[$fmeta] )?
166 $case($case),
167 )*
168 Unrecognized(crate::relaycell::extlist::UnrecognizedExt<$type_id>)
171 }
172 impl tor_bytes::Readable for $id {
173 fn take_from(b: &mut Reader<'_>) -> tor_bytes::Result<Self> {
174 #[allow(unused)]
175 use crate::relaycell::extlist::Ext as _;
176 let type_id = b.take_u8()?.into();
177 Ok(match type_id {
178 $(
179 $( #[$fmeta] )?
180 $type_id::[< $case:snake:upper >] => {
181 Self::$case( b.read_nested_u8len(|r| $case::take_body_from(r))? )
182 }
183 )*
184 _ => {
185 Self::Unrecognized(crate::relaycell::extlist::UnrecognizedExt {
186 type_id,
187 body: b.read_nested_u8len(|r| Ok(r.take_rest().into()))?,
188 })
189 }
190 })
191 }
192 }
193 impl tor_bytes::Writeable for $id {
194 fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) -> tor_bytes::EncodeResult<
195()> {
196 #![allow(unused_imports)]
197 use crate::relaycell::extlist::Ext as _;
198 use tor_bytes::Writeable as _;
199 use std::ops::DerefMut;
200 match self {
201 $(
202 $( #[$fmeta] )?
203 Self::$case(val) => {
204 b.write_u8(val.type_id().into());
205 let mut nested = b.write_nested_u8len();
206 val.write_body_onto(nested.deref_mut())?;
207 nested.finish()?;
208 }
209 )*
210 Self::Unrecognized(unrecognized) => {
211 b.write_u8(unrecognized.type_id.into());
212 let mut nested = b.write_nested_u8len();
213 nested.write_all(&unrecognized.body[..]);
214 nested.finish()?;
215 }
216 }
217 Ok(())
218 }
219 }
220 impl crate::relaycell::extlist::ExtGroup for $id {
221 type Id = $type_id;
222 fn type_id(&self) -> Self::Id {
223 #![allow(unused_imports)]
224 use crate::relaycell::extlist::Ext as _;
225 match self {
226 $(
227 $( #[$fmeta] )?
228 Self::$case(val) => val.type_id(),
229 )*
230 Self::Unrecognized(unrecognized) => unrecognized.type_id,
231 }
232 }
233 }
234 $(
235 $( #[$fmeta] )?
236 impl From<$case> for $id {
237 fn from(val: $case) -> $id {
238 $id :: $case ( val )
239 }
240 }
241 )*
242 impl From<crate::relaycell::extlist::UnrecognizedExt<$type_id>> for $id {
243 fn from(val: crate::relaycell::extlist::UnrecognizedExt<$type_id>) -> $id {
244 $id :: Unrecognized(val)
245 }
246 }
247}}
248}
249pub(super) use decl_extension_group;