tor_netdoc/parse2/
traits.rs

1//! Core model for netdoc parsing
2
3use super::*;
4
5/// A document or section that can be parsed
6///
7/// Normally [derived](derive_deftly_template_NetdocParseable).
8pub trait NetdocParseable: Sized {
9    /// Document type for errors, normally its intro keyword
10    fn doctype_for_error() -> &'static str;
11
12    /// Is `Keyword` an intro Item Keyword for this kind of document?
13    ///
14    /// This is used with 1-keyword lookahead, to allow us to push or pop
15    /// the parsing state into or out of a sub-document.
16    ///
17    /// For signatures sections, this should report *every* recognised keyword.
18    fn is_intro_item_keyword(kw: KeywordRef<'_>) -> bool;
19
20    /// Parse the document from a stream of Items
21    ///
22    /// Should stop before reading any keyword matching `stop_at`.
23    /// (Except, right at the start.)
24    ///
25    /// Should also stop before reading a 2nd intro keyword,
26    /// so that successive calls to this function can parse
27    /// successive sub-documents of this kind.
28    ///
29    /// Otherwise, should continue until EOF.
30    ///
31    /// Must check whether the first item is this document's `is_intro_item_keyword`,
32    /// and error if not.
33    fn from_items(input: &mut ItemStream<'_>, stop_at: stop_at!()) -> Result<Self, ErrorProblem>;
34}
35
36/// A network document with (unverified) signatures
37///
38/// Typically implemented automatically, for `FooSigned` structs, as defined by
39/// [`#[derive_deftly(NetdocSigned)]`](derive_deftly_template_NetdocSigned).
40pub trait NetdocSigned {
41    /// The body, ie not including the signatures
42    type Body: Sized;
43    /// The signatures (the whole signature section)
44    type Signatures: Sized;
45
46    /// Inspect the document (and its signatures)
47    ///
48    /// # Security hazard
49    ///
50    /// The signature has not been verified, so the returned data must not be trusted.
51    fn inspect_unverified(&self) -> (&Self::Body, &Self::Signatures);
52
53    /// Obtain the actual document (and signatures), without verifying
54    ///
55    /// # Security hazard
56    ///
57    /// The signature has not been verified, so the returned data must not be trusted.
58    fn unwrap_unverified(self) -> (Self::Body, Self::Signatures);
59
60    /// Construct a new `NetdocSigned` from a body and signatures
61    ///
62    /// (Called by code generated by `#[derive_deftly(NetdocSigned)]`.)
63    fn from_parts(body: Self::Body, signatures: Self::Signatures) -> Self;
64}
65
66/// An item (value) that can appear in a netdoc
67///
68/// This is the type `T` of a field `item: T` in a netdoc type.
69///
70/// An implementation is provided for tuples of `ItemArgumentParseable`,
71/// which parses each argument in turn,
72/// ignores additional arguments,
73/// and rejects any Object.
74///
75/// Typically derived with
76/// [`#[derive_deftly(ItemValueParseable)]`](derive_deftly_template_ItemValueParseable).
77///
78/// Signature items are special, and implement [`SignatureItemParseable`] instead.
79pub trait ItemValueParseable: Sized {
80    /// Parse the item's value
81    fn from_unparsed(item: UnparsedItem<'_>) -> Result<Self, ErrorProblem>;
82}
83
84/// An (individual) argument that can appear in a netdoc
85///
86/// An implementations is provided for **`T: FromStr`**,
87/// which expects a single argument and passes it to `FromStr`.
88///
89/// For netdoc arguments whose specified syntax spans multiple space-separated words,
90/// use a manual implementation or a wrapper type.
91pub trait ItemArgumentParseable: Sized {
92    /// Parse the argument
93    fn from_args<'s>(
94        args: &mut ArgumentStream<'s>,
95        field: &'static str,
96    ) -> Result<Self, ErrorProblem>;
97}
98
99/// A possibly-optional Object value that can appear in netdoc
100///
101/// Implemented for `Option`, so that `field: Option<ObjectValue>`
102/// allows parsing an optional object.
103pub trait ItemObjectParseable: Sized {
104    /// Check that the Label is right
105    fn check_label(label: &str) -> Result<(), ErrorProblem>;
106
107    /// Convert the bytes of the Object (which was present) into the actual value
108    ///
109    /// `input` has been base64-decoded.
110    fn from_bytes(input: &[u8]) -> Result<Self, ErrorProblem>;
111
112    /// Convert the bytes of the Object, if any, into the actual value
113    ///
114    /// If there was an Object, `input` has been base64-decoded.
115    /// If there was no Object, `input` is `None`.
116    ///
117    /// The provided implementation considers a missing object to be an error.
118    fn from_bytes_option(input: Option<&[u8]>) -> Result<Self, ErrorProblem> {
119        Self::from_bytes(input.ok_or(EP::MissingObject)?)
120    }
121}
122
123//---------- provided blanket impls ----------
124
125impl<T: ItemObjectParseable> ItemObjectParseable for Option<T> {
126    fn check_label(label: &str) -> Result<(), EP> {
127        T::check_label(label)
128    }
129
130    fn from_bytes(input: &[u8]) -> Result<Self, EP> {
131        Ok(Some(T::from_bytes(input)?))
132    }
133    fn from_bytes_option(input: Option<&[u8]>) -> Result<Self, EP> {
134        let Some(input) = input else { return Ok(None) };
135        Self::from_bytes(input)
136    }
137}
138
139impl<T: FromStr> ItemArgumentParseable for T {
140    fn from_args<'s>(args: &mut ArgumentStream<'s>, field: &'static str) -> Result<Self, EP> {
141        let v = args
142            .next()
143            .ok_or(EP::MissingArgument { field })?
144            .parse()
145            .map_err(|_e| EP::InvalidArgument { field })?;
146        Ok(v)
147    }
148}
149
150/// implement [`ItemValueParseable`] for a particular tuple size
151macro_rules! item_value_parseable_for_tuple {
152    { $($i:literal)* } => { paste! {
153        impl< $( [<T$i>]: ItemArgumentParseable, )* >
154            ItemValueParseable for ( $( [<T$i>], )* )
155        {
156            fn from_unparsed(
157                #[allow(unused_mut)]
158                mut item: UnparsedItem<'_>,
159            ) -> Result<Self, ErrorProblem> {
160                let r = ( $(
161                    <[<T$i>] as ItemArgumentParseable>::from_args(
162                        item.args_mut(),
163                        stringify!($i),
164                    )?,
165                )* );
166                if item.object().is_some() { return Err(EP::ObjectUnexpected) }
167                Ok(r)
168            }
169        }
170    } }
171}
172
173item_value_parseable_for_tuple! {}
174item_value_parseable_for_tuple! { 0 }
175item_value_parseable_for_tuple! { 0 1 }
176item_value_parseable_for_tuple! { 0 1 2 }
177item_value_parseable_for_tuple! { 0 1 2 3 }
178item_value_parseable_for_tuple! { 0 1 2 3 4 }
179item_value_parseable_for_tuple! { 0 1 2 3 4 5 }
180item_value_parseable_for_tuple! { 0 1 2 3 4 5 6 }
181item_value_parseable_for_tuple! { 0 1 2 3 4 5 6 7 }
182item_value_parseable_for_tuple! { 0 1 2 3 4 5 6 7 8 }
183item_value_parseable_for_tuple! { 0 1 2 3 4 5 6 7 8 9 }