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