tor_netdoc/util.rs
1//! Misc helper functions and types for use in parsing network documents
2
3use derive_deftly::define_derive_deftly;
4
5pub(crate) mod str;
6
7pub mod batching_split_before;
8
9use std::iter::Peekable;
10
11define_derive_deftly! {
12 /// Implement `AsMut<Self>`
13 ///
14 /// For Reasons, Rust does not have a blanket:
15 ///
16 /// ```rust,ignore
17 /// impl<T> AsMut<T> for T { .. }
18 /// ```
19 ///
20 /// This derive macro expands to the obvious and trivial implementation,
21 /// for the type that it's applied to.
22 //
23 // TODO move this somewhere lower in the stack, eg tor-basic-utils
24 export AsMutSelf expect items:
25
26 impl<$tgens> ::std::convert::AsMut<Self> for $ttype where $twheres {
27 fn as_mut(&mut self) -> &mut Self {
28 self
29 }
30 }
31}
32
33/// An iterator with a `.peek()` method
34///
35/// We make this a trait to avoid entangling all the types with `Peekable`.
36/// Ideally we would do this with `Itertools::PeekingNext`
37/// but that was not implemented for `&mut PeekingNext`
38/// when we wrote this code,
39/// and we need that because we use a lot of `&mut NetdocReader`.
40/// <https://github.com/rust-itertools/itertools/issues/678>
41///
42/// TODO: As of itertools 0.11.0, `PeekingNext` _is_ implemented for
43/// `&'a mut I where I: PeekingNext`, so we can remove this type some time.
44///
45/// # **UNSTABLE**
46///
47/// This type is UNSTABLE and not part of the semver guarantees.
48/// You'll only see it if you ran rustdoc with `--document-private-items`.
49// This is needed because this is a trait bound for batching_split_before.
50#[doc(hidden)]
51pub trait PeekableIterator: Iterator {
52 /// Inspect the next item, if there is one
53 fn peek(&mut self) -> Option<&Self::Item>;
54}
55
56impl<I: Iterator> PeekableIterator for Peekable<I> {
57 fn peek(&mut self) -> Option<&Self::Item> {
58 self.peek()
59 }
60}
61
62impl<I: PeekableIterator> PeekableIterator for &mut I {
63 fn peek(&mut self) -> Option<&Self::Item> {
64 <I as PeekableIterator>::peek(*self)
65 }
66}
67
68/// A Private module for declaring a "sealed" trait.
69pub(crate) mod private {
70 /// A non-exported trait, used to prevent others from implementing a trait.
71 ///
72 /// For more information on this pattern, see [the Rust API
73 /// guidelines](https://rust-lang.github.io/api-guidelines/future-proofing.html#c-sealed).
74 #[expect(dead_code, unreachable_pub)] // TODO keep this Sealed trait in case we want it again?
75 pub trait Sealed {}
76}
77
78#[cfg(test)]
79#[allow(unused)]
80fn test_as_mut_compiles() {
81 use derive_deftly::Deftly;
82
83 #[derive(Deftly)]
84 #[derive_deftly(AsMutSelf)]
85 struct S<T: Clone>
86 where
87 Option<T>: Clone,
88 {
89 t: T,
90 }
91
92 let _: &mut S<()> = S { t: () }.as_mut();
93}
94
95/// Define `DirectorySignatureHashAlgo`, for `directory-signature` items
96///
97/// This macro exists to avoid clone-and-hack between poc and prod code.
98///
99/// It is difficult for either of those modules to use the other's definition,
100/// because they have different stability, different cfg gating,
101/// and want to derive deftly differently.
102///
103/// tl;dr: defining this type in doc/netstatus.rs would mean
104/// the poc derived structs would end up in the prod module;
105/// defining it in poc puts it behind the `incomplete` feature gate.
106//
107// TODO DIRAUTH after poc abolished, turn back into a normal struct DirectorySignatureHashAlgo
108macro_rules! define_directory_signature_hash_algo { { $( $attrs:tt )* } => {
109 /// `directory-signature` hash algorithm argument
110 #[derive(Clone, Copy, Debug, Eq, PartialEq, strum::EnumString, Deftly)]
111 $($attrs)*
112 #[non_exhaustive]
113 #[strum(serialize_all = "snake_case")]
114 pub enum DirectorySignatureHashAlgo {
115 /// SHA-1
116 #[deftly(hash_len = "20")]
117 Sha1,
118 /// SHA-256
119 #[deftly(hash_len = "32")]
120 Sha256,
121 }
122} }