1
//! [`KeySpecifier`] derive-adhoc macro and its support code
2
//!
3
//! # STABILITY - NOTHING IN THIS MODULE IS PART OF THE STABLE PUBLIC API
4
//!
5
//! The `pub` items in this module are accessible as `$crate::key_specifier_derive`,
6
//! but `#[doc(hidden)]` is applied at the top level.
7
//!
8
//! (Recall that the actual derive-adhoc macro
9
//! `KeySpecifier` ends up in the crate toplevel,
10
//! so that *does* form part of our public API.)
11

            
12
use std::iter;
13

            
14
use derive_deftly::define_derive_deftly;
15
use itertools::{EitherOrBoth, Itertools, izip};
16

            
17
use super::*;
18
use crate::DENOTATOR_SEP;
19

            
20
pub use crate::KeyPathInfoBuilder;
21
pub use tor_error::{Bug, internal, into_internal};
22

            
23
/// Trait for (only) formatting as a [`KeySpecifierComponent`]
24
///
25
/// Like the formatting part of `KeySpecifierComponent`
26
/// but implemented for Option and &str too.
27
pub trait RawKeySpecifierComponent {
28
    /// Append `self`s `KeySpecifierComponent` string representation to `s`
29
    //
30
    // This is not quite like `KeySpecifierComponent::to_slug`,
31
    // since that *returns* a String (effectively) and we *append*.
32
    // At some future point we may change KeySpecifierComponent,
33
    // although the current API has the nice feature that
34
    // the syntax of the appended string is checked before we receive it here.
35
    fn append_to(&self, s: &mut String) -> Result<(), Bug>;
36
}
37
impl<T: KeySpecifierComponent> RawKeySpecifierComponent for T {
38
10413
    fn append_to(&self, s: &mut String) -> Result<(), Bug> {
39
10413
        self.to_slug()?.as_str().append_to(s)
40
10413
    }
41
}
42
impl<T: KeySpecifierComponent> RawKeySpecifierComponent for Option<T> {
43
6426
    fn append_to(&self, s: &mut String) -> Result<(), Bug> {
44
6426
        let v: &dyn RawKeySpecifierComponent = match self.as_ref() {
45
32
            Some(v) => v,
46
6394
            None => &"*",
47
        };
48
6426
        v.append_to(s)
49
6426
    }
50
}
51
impl<'s> RawKeySpecifierComponent for &'s str {
52
178282
    fn append_to(&self, s: &mut String) -> Result<(), Bug> {
53
178282
        s.push_str(self);
54
178282
        Ok(())
55
178282
    }
56
}
57

            
58
/// Make a string like `pc/pc/pc/lc_lc_lc`
59
51974
fn arti_path_string_from_components(
60
51974
    path_comps: &[&dyn RawKeySpecifierComponent],
61
51974
    leaf_comps: &[&dyn RawKeySpecifierComponent],
62
51974
) -> Result<String, Bug> {
63
51974
    let mut path = String::new();
64

            
65
145382
    for comp in path_comps {
66
93408
        comp.append_to(&mut path)?;
67
93408
        path.push('/');
68
    }
69
83930
    for (delim, comp) in izip!(
70
51974
        iter::once(None).chain(iter::repeat(Some(DENOTATOR_SEP))),
71
51974
        leaf_comps,
72
    ) {
73
83930
        if let Some(delim) = delim {
74
31956
            path.push(delim);
75
51974
        }
76
83930
        comp.append_to(&mut path)?;
77
    }
78

            
79
51974
    Ok(path)
80
51974
}
81

            
82
/// Make a string like `pc/pc/pc/pd+pd+pd@cd+cd+cd+cd`
83
2136
fn cert_arti_path_string_from_components(
84
2136
    subj_comp: &str,
85
2136
    leaf_comps: &[&dyn RawKeySpecifierComponent],
86
2136
) -> Result<String, Bug> {
87
2136
    if leaf_comps.is_empty() {
88
2132
        return Ok(subj_comp.to_string());
89
4
    }
90

            
91
4
    let mut path = if subj_comp.contains('+') {
92
2
        format!("{subj_comp}@")
93
    } else {
94
2
        format!("{subj_comp}+@")
95
    };
96

            
97
6
    for (delim, comp) in izip!(
98
4
        iter::once(None).chain(iter::repeat(Some(DENOTATOR_SEP))),
99
4
        leaf_comps,
100
    ) {
101
6
        if let Some(delim) = delim {
102
2
            path.push(delim);
103
4
        }
104
6
        comp.append_to(&mut path)?;
105
    }
106

            
107
4
    Ok(path)
108
2136
}
109

            
110
/// Make an `ArtiPath` like `pc/pc/pc/lc_lc_lc`
111
///
112
/// This is the engine for the `KeySpecifier` macro's `arti_path()` impls.
113
///
114
/// The macro-generated code sets up couple of vectors.
115
/// Each vector entry is a pointer to the field in the original struct,
116
/// plus a vtable pointer saying what to do with it.
117
///
118
/// For fixed elements in the path,
119
/// the vtable entry's data pointer is a pointer to a constant &str.
120
///
121
/// In the macro, this is done by the user-defined expansion `ARTI_FROM_COMPONENTS_ARGS`.
122
///
123
/// Doing it this way minimises the amount of macro-generated machine code.
124
44838
pub fn arti_path_from_components(
125
44838
    path_comps: &[&dyn RawKeySpecifierComponent],
126
44838
    leaf_comps: &[&dyn RawKeySpecifierComponent],
127
44838
) -> Result<ArtiPath, ArtiPathUnavailableError> {
128
44838
    Ok(arti_path_string_from_components(path_comps, leaf_comps)?
129
44838
        .try_into()
130
44838
        .map_err(into_internal!("bad ArtiPath from good components"))?)
131
44838
}
132

            
133
/// Make a `KeyPathPattern::Arti` like `pc/pc/pc/lc_lc_lc`
134
7136
pub fn arti_pattern_from_components(
135
7136
    path_comps: &[&dyn RawKeySpecifierComponent],
136
7136
    leaf_comps: &[&dyn RawKeySpecifierComponent],
137
7136
) -> Result<KeyPathPattern, Bug> {
138
7136
    Ok(KeyPathPattern::Arti(arti_path_string_from_components(
139
7136
        path_comps, leaf_comps,
140
    )?))
141
7136
}
142

            
143
/// Make a `KeyPathPattern::Arti` for a certificate specifier
144
2136
pub fn cert_arti_pattern_from_components(
145
2136
    subj_path: &str,
146
2136
    leaf_comps: &[&dyn RawKeySpecifierComponent],
147
2136
) -> Result<KeyPathPattern, Bug> {
148
2136
    Ok(KeyPathPattern::Arti(cert_arti_path_string_from_components(
149
2136
        subj_path, leaf_comps,
150
    )?))
151
2136
}
152

            
153
/// Error returned from [`RawKeySpecifierComponentParser::parse`]
154
#[derive(Debug)]
155
#[allow(clippy::exhaustive_enums)] // Not part of public API
156
pub enum RawComponentParseResult {
157
    /// This was a field
158
    ///
159
    /// The `Option` has been filled with the actual value.
160
    /// It has an entry in the `keys` argument to [`parse_arti_path`].
161
    ParsedField,
162
    /// This was a literal, and it matched
163
    MatchedLiteral,
164
    /// Becomes [`ArtiPathError::PatternNotMatched`]
165
    PatternNotMatched,
166
    /// `InvalidKeyPathComponentValue`
167
    Invalid(InvalidKeyPathComponentValue),
168
}
169

            
170
use RawComponentParseResult as RCPR;
171

            
172
/// Trait for parsing a path component, used by [`parse_arti_path`]
173
///
174
/// Implemented for `Option<impl KeySpecifierComponent>`,
175
/// and guarantees to fill in the Option if it succeeds.
176
///
177
/// Also implemented for `&str`: just checks that the string is right,
178
/// (and, doesn't modify `*self`).
179
pub trait RawKeySpecifierComponentParser {
180
    /// Check that `comp` is as expected, and store any results in `self`.
181
    fn parse(&mut self, comp: &Slug) -> RawComponentParseResult;
182
}
183

            
184
impl<T: KeySpecifierComponent> RawKeySpecifierComponentParser for Option<T> {
185
4048
    fn parse(&mut self, comp: &Slug) -> RawComponentParseResult {
186
4048
        let v = match T::from_slug(comp) {
187
4048
            Ok(v) => v,
188
            Err(e) => return RCPR::Invalid(e),
189
        };
190
4048
        *self = Some(v);
191
4048
        RCPR::ParsedField
192
4048
    }
193
}
194
impl<'s> RawKeySpecifierComponentParser for &'s str {
195
23896
    fn parse(&mut self, comp: &Slug) -> RawComponentParseResult {
196
23896
        if comp.as_str() == *self {
197
16824
            RCPR::MatchedLiteral
198
        } else {
199
7072
            RCPR::PatternNotMatched
200
        }
201
23896
    }
202
}
203

            
204
/// List of parsers for fields
205
type Parsers<'p> = [&'p mut dyn RawKeySpecifierComponentParser];
206

            
207
/// Split a string into components and parse each one
208
23918
fn extract(
209
23918
    input: Option<&str>,
210
23918
    delim: char,
211
23918
    parsers: &mut Parsers,
212
23918
    keys: &mut &[&str],
213
23918
) -> Result<(), ArtiPathError> {
214
42530
    for ent in Itertools::zip_longest(
215
24427
        input.map(|input| input.split(delim)).into_iter().flatten(),
216
23918
        parsers,
217
    ) {
218
42530
        let EitherOrBoth::Both(comp, parser) = ent else {
219
            // wrong number of components
220
208
            return Err(ArtiPathError::PatternNotMatched);
221
        };
222

            
223
        // TODO would be nice to avoid allocating again here,
224
        // but I think that needs an `SlugRef`.
225
42322
        let comp = Slug::new(comp.to_owned())
226
42322
            .map_err(ArtiPathSyntaxError::Slug)
227
42322
            .map_err(ArtiPathError::InvalidArtiPath)?;
228

            
229
42322
        let missing_keys = || internal!("keys list too short, bad args to parse_arti_path");
230

            
231
42322
        match parser.parse(&comp) {
232
7072
            RCPR::PatternNotMatched => Err(ArtiPathError::PatternNotMatched),
233
            RCPR::Invalid(error) => Err(ArtiPathError::InvalidKeyPathComponentValue {
234
                error,
235
                key: keys.first().ok_or_else(missing_keys)?.to_string(),
236
                value: comp,
237
            }),
238
            RCPR::ParsedField => {
239
18426
                *keys = keys.split_first().ok_or_else(missing_keys)?.1;
240
18426
                Ok(())
241
            }
242
16824
            RCPR::MatchedLiteral => Ok(()),
243
7072
        }?;
244
    }
245
16638
    Ok(())
246
23918
}
247

            
248
/// Parse a `KeyPath` as an `ArtiPath` like pc/pc/pc/lc_lc_lc
249
///
250
/// `keys` is the field names for each of the path_parsers and leaf_parsers,
251
/// *but* only the ones which will return `RCPR::ParsedField` (or `::Invalid`).
252
///
253
/// As with `arti_path_string_components` etc., we try to minimise
254
/// the amount of macro-generated machine code.
255
///
256
/// The macro-generated impl again assembles two vectors,
257
/// one for the path components and one for the leaf components.
258
///
259
/// For a field, the vector entry is a pointer to `&mut Option<...>`
260
/// for the field, along with a `RawKeySpecifierComponentParser` vtable entry.
261
/// (The macro-generated impl must unwrap each of these Options,
262
/// to assemble the final struct.  In principle this could be avoided with
263
/// use of `MaybeUninit` and unsafe.)
264
///
265
/// For a fixed string component, the vector entry data pointer points to its `&str`.
266
/// "Parsing" consists of checking that the string is as expected.
267
///
268
/// We also need the key names for error reporting.
269
/// We pass this as a *single* array, and a double-reference to the slice,
270
/// since that resolves to one pointer to a static structure.
271
15276
pub fn parse_arti_path(
272
15276
    arti_path: &ArtiPath,
273
15276
    keys: &&[&str],
274
15276
    path_parsers: &mut Parsers,
275
15276
    leaf_parsers: &mut Parsers,
276
15276
) -> Result<(), ArtiPathError> {
277
15276
    let path = arti_path.as_str();
278

            
279
15276
    let (path, leaf) = match path.rsplit_once('/') {
280
15276
        Some((path, leaf)) => (Some(path), leaf),
281
        None => (None, path),
282
    };
283

            
284
15276
    let mut keys: &[&str] = keys;
285

            
286
15276
    extract(path, '/', path_parsers, &mut keys)?;
287
8620
    extract(Some(leaf), DENOTATOR_SEP, leaf_parsers, &mut keys)?;
288
7996
    Ok(())
289
15276
}
290

            
291
/// Parse the denotators from the `ArtiPath` of a certificate.
292
///
293
/// The specified `cert_denos` should be the substring of an `ArtiPath`
294
/// containing the certificate denotator group.
295
///
296
/// The `leaf_parses` and `keys` arguments serve the same purpose as in
297
/// [`parse_arti_path`].
298
22
pub fn parse_cert_denotators(
299
22
    cert_denos: &str,
300
22
    keys: &&[&str],
301
22
    leaf_parsers: &mut Parsers,
302
22
) -> Result<(), ArtiPathError> {
303
22
    let mut keys: &[&str] = keys;
304

            
305
22
    extract(Some(cert_denos), DENOTATOR_SEP, leaf_parsers, &mut keys)?;
306

            
307
22
    Ok(())
308
22
}
309

            
310
/// Build a `KeyPathInfo` given the information about a key specifier
311
///
312
/// Calling pattern, to minimise macro-generated machine code,
313
/// is similar `arti_path_from_components`.
314
///
315
/// The macro-generated code parses the path into its KeySpecifier impl
316
/// (as an owned value) and then feeds references to the various fields
317
/// to `describe_via_components`.
318
938
pub fn describe_via_components(
319
938
    summary: &&str,
320
938
    role: &dyn RawKeySpecifierComponent,
321
938
    extra_keys: &&[&str],
322
938
    extra_info: &[&dyn KeySpecifierComponent],
323
938
) -> Result<KeyPathInfo, Bug> {
324
938
    let mut info = KeyPathInfoBuilder::default();
325
938
    info.summary(summary.to_string());
326
938
    info.role({
327
938
        let mut s = String::new();
328
938
        role.append_to(&mut s)?;
329
938
        s
330
    });
331
1154
    for (key, value) in izip!(*extra_keys, extra_info) {
332
1154
        let value = KeySpecifierComponentPrettyHelper(*value).to_string();
333
1154
        info.extra_info(*key, value);
334
1154
    }
335
938
    info.build()
336
938
        .map_err(into_internal!("failed to build KeyPathInfo"))
337
938
}
338

            
339
define_derive_deftly! {
340
    /// A helper for implementing [`KeySpecifier`]s.
341
    ///
342
    /// Applies to a struct that has some static components (`prefix`, `role`),
343
    /// and a number of variable components represented by its fields.
344
    ///
345
    /// Implements `KeySpecifier` etc.
346
    ///
347
    /// Each field is either a path field (which becomes a component in the `ArtiPath`),
348
    /// or a denotator (which becomes *part* of the final component in the `ArtiPath`).
349
    ///
350
    /// The `prefix` is the first component of the [`ArtiPath`] of the [`KeySpecifier`].
351
    ///
352
    /// The role should be the name of the key in the Tor Specifications.
353
    /// The **lowercased** `role` is used as the _prefix of the last component_
354
    /// of the [`ArtiPath`] of the specifier.
355
    /// The `role` is followed by the denotators of the key.
356
    ///
357
    /// The denotator fields, if there are any,
358
    /// should be annotated with `#[denotator]`.
359
    ///
360
    /// The declaration order of the fields is important.
361
    /// The inner components of the [`ArtiPath`] of the specifier are built
362
    /// from the string representation of its path fields, taken in declaration order,
363
    /// followed by the encoding of its denotators, also taken in the order they were declared.
364
    /// As such, all path fields, must implement [`KeySpecifierComponent`].
365
    /// and all denotators must implement [`KeySpecifierComponent`].
366
    /// The denotators are separated from the rest of the path, and from each other,
367
    /// by `+` characters.
368
    ///
369
    /// For example, a key specifier with `prefix` `"foo"` and `role` `"bar"`
370
    /// will have an [`ArtiPath`] of the form
371
    /// `"foo/<field1_str>/<field2_str>/../bar[+<denotators>]"`.
372
    ///
373
    /// A key specifier of this form, with denotators that encode to "d1" and "d2",
374
    /// would look like this: `"foo/<field1_str>/<field2_str>/../bar+d1+d2"`.
375
    ///
376
    /// ### Results of applying this macro
377
    ///
378
    /// `#[derive(Deftly)] #[derive_deftly(KeySpecifier)] struct SomeKeySpec ...`
379
    /// generates:
380
    ///
381
    ///  * `impl `[`KeySpecifier`]` for SomeKeySpec`
382
    ///  * `struct SomeKeySpecPattern`,
383
    ///    a derived struct which contains an `Option` for each field.
384
    ///    `None` in the pattern means "any".
385
    ///  * `impl `[`KeySpecifierPattern`]` for SomeKeySpecPattern`
386
    ///  * `impl TryFrom<`[`KeyPath`]> for SomeKeySpec`
387
    ///  * Registration of an impl of [`KeyPathInfoExtractor`]
388
    ///    (on a private unit struct `SomeKeySpecInfoExtractor`)
389
    ///
390
    /// ### Custom attributes
391
    ///
392
    ///  * **`#[deftly(prefix)]`** (toplevel):
393
    ///    Specifies the fixed prefix (the first path component).
394
    ///    Must be a literal string.
395
    ///
396
    ///  * **`#[deftly(role = "...")]`** (toplevel):
397
    ///    Specifies the role - the initial portion of the leafname.
398
    ///    This should be the name of the key in the Tor Specifications.
399
    ///    Must be a literal string.
400
    ///    This or the field-level `#[deftly(role)]` must be specified.
401
    ///
402
    ///  * **`[adhoc(role)]` (field):
403
    ///    Specifies that the role is determined at runtime.
404
    ///    The field type must implement [`KeyDenotator`].
405
    ///
406
    ///  * **`#[deftly(summary = "...")]`** (summary, mandatory):
407
    ///    Specifies the summary; ends up as the `summary` field in [`KeyPathInfo`].
408
    ///    (See [`KeyPathInfoBuilder::summary()`].)
409
    ///    Must be a literal string.
410
    ///
411
    ///  * **`#[deftly(denotator)]`** (field):
412
    ///    Designates a field that should be represented
413
    ///    in the key file leafname, after the role.
414
    ///
415
    ///  * **`#[deftly(ctor_path = "<variant>")]`** (toplevel):
416
    ///    Specifies that this kind of key has a representation in C Tor keystores,
417
    ///    and provides the appropriate [`CTorPath`] variant in `<variant>`.
418
    ///
419
    ///    Used for implementing [`CTorKeySpecifier`].
420
    ///
421
    ///    If specified, the generated [`KeySpecifier::ctor_path`] implementation
422
    ///    will return [`CTorPath`]::`<variant>` populated with the fields extracted
423
    ///    from this type. Therefore, your type **must** have exactly the same fields
424
    ///    as the specified `CTorPath` variant.
425
    ///
426
    ///    If not specified, the generated [`KeySpecifier::ctor_path`]
427
    ///    implementation will always return `None`.
428
    ///
429
    ///  * **`#[deftly(fixed_path_component = "component")]`** (field):
430
    ///    Before this field insert a fixed path component `component`.
431
    ///    (Can be even used before a denotator component,
432
    ///    to add a final fixed path component.)
433
    ///
434
    ///  * **`#[deftly(key_specifier = "type")]`** (field):
435
    ///    If this is the specifier for a public key, the specifier for
436
    ///    the corresponding keypair type.
437
    ///
438
    ///    If not specified, the generated [`KeySpecifier::keypair_specifier`]
439
    ///    implementation will always return `None`.
440
    //
441
    //     NOTE: The `KeySpecifier::keypair_specifier` implementation
442
    //     of the `ArtiPath` of a public key will always return `None`,
443
    //     even if the public key specifier it represents has a keypair specifier.
444
    //
445
    ///
446
    export KeySpecifier for struct:
447

            
448
    // A condition that evaluates to `true` for path fields.
449
    ${defcond F_IS_PATH not(any(fmeta(denotator), fmeta(role)))}
450
    ${defcond F_IS_ROLE all(fmeta(role), not(tmeta(role)))}
451

            
452
    #[doc = concat!("Pattern matching some or all [`", stringify!($tname), "`]")]
453
    #[allow(dead_code)] // Not everyone will need the pattern feature
454
    #[non_exhaustive]
455
    $tvis struct $<$tname Pattern><$tdefgens>
456
    where $twheres
457
    ${vdefbody $vname $(
458
        ${fattrs doc}
459
        ///
460
        /// `None` to match keys with any value for this field.
461
        $fvis $fname: Option<$ftype>,
462
    ) }
463

            
464
    // ** MAIN KNOWLEDGE OF HOW THE PATH IS CONSTRUCTED **
465
    //
466
    // These two user-defined expansions,
467
    //   $ARTI_PATH_COMPONENTS
468
    //   $ARTI_LEAF_COMPONENTS
469
    // expand to code for handling each path and leaf component,
470
    // in the order in which they appear in the ArtiPath.
471
    //
472
    // The "code for handling", by default, is:
473
    //   - for a field, take a reference to the field in `self`
474
    //   - for a fixed component, take a reference to a &'static str
475
    // in each case with a comma appended.
476
    // So this is suitable for including in a &[&dyn ...].
477
    //
478
    // The call site can override the behaviour by locally redefining,
479
    // the two user-defined expansions DO_FIELD and DO_LITERAL.
480
    //
481
    // DO_FIELD should expand to the code necessary to handle a field.
482
    // It probably wants to refer to $fname.
483
    //
484
    // DO_LITERAL should expand to the code necessary to handle a literal value.
485
    // When DO_LITERAL is called the user-defined expansion LIT will expand to
486
    // something like `${fmeta(...) as str}`, which will in turn expand to
487
    // a string literal.
488
    //
489
    // For use sites which want to distinguish the role from other fields:
490
    // DO_ROLE_FIELD and DO_ROLE_LITERAL are used for the role.
491
    // They default to expanding $DO_FIELD and $DO_LITERAL respectively.
492
    //
493
    // This is the *only* place that knows how ArtiPaths are constructed,
494
    // when the path syntax is defined using the KeySpecifier d-a macro.
495
    //
496
    // The actual code here is necessarily rather abstract.
497
    ${define ARTI_PATH_COMPONENTS {
498
        // #[deftly(prefix = ...)]
499
        ${define LIT ${tmeta(prefix) as str}}
500
        $DO_LITERAL
501

            
502
        ${for fields {
503
            // #[deftly(fixed_path_component = ...)]
504
            ${if fmeta(fixed_path_component) {
505
                // IWVNI d-a allowed arguments to use-defined expansions, but this will do
506
                ${define LIT ${fmeta(fixed_path_component) as str}}
507
                $DO_LITERAL
508
            }}
509
            // Path fields
510
            ${if F_IS_PATH { $DO_FIELD }}
511
        }}
512
    }}
513
    ${define ARTI_LEAF_COMPONENTS {
514
        ${if tmeta(role) {
515
            // #[deftly(role = ...)] on the toplevel
516
            ${define LIT { stringify!(${snake_case ${tmeta(role)}}) }}
517
            $DO_ROLE_LITERAL
518
        }}
519
        ${for fields {
520
            // #[deftly(role)] on a field
521
            ${if F_IS_ROLE { $DO_ROLE_FIELD }}
522
        }}
523
        ${for fields {
524
            // #[deftly(denotator)]
525
            ${if fmeta(denotator) { $DO_FIELD }}
526
        }}
527
    }}
528

            
529
    ${define DO_FIELD { &self.$fname, }}
530
    ${define DO_LITERAL { &$LIT, }}
531
    ${define DO_ROLE_FIELD { $DO_FIELD }}
532
    ${define DO_ROLE_LITERAL { $DO_LITERAL }}
533

            
534
    impl<$tgens> $crate::KeySpecifier for $ttype
535
    where $twheres
536
    {
537
12517
        fn arti_path(
538
12517
            &self,
539
12517
        ) -> std::result::Result<$crate::ArtiPath, $crate::ArtiPathUnavailableError> {
540
            use $crate::key_specifier_derive::*;
541

            
542
            arti_path_from_components(
543
                &[ $ARTI_PATH_COMPONENTS ],
544
                &[ $ARTI_LEAF_COMPONENTS ],
545
            )
546
        }
547

            
548
298
        fn ctor_path(&self) -> Option<$crate::CTorPath> {
549
            <Self as $crate::CTorKeySpecifier>::ctor_path(self)
550
        }
551

            
552
3741
        fn keypair_specifier(&self) -> Option<Box<dyn KeySpecifier>> {
553
            ${if tmeta(keypair_specifier) {
554
                Some(Box::new(std::convert::Into::<
555
                    ${tmeta(keypair_specifier) as token_stream}
556
                >::into(self)))
557
            } else {
558
                None
559
            }}
560
        }
561
    }
562

            
563
    impl<$tgens> $crate::KeySpecifierPattern for $<$tname Pattern><$tdefgens>
564
    where $twheres
565
    {
566
6362
        fn arti_pattern(
567
6362
            &self,
568
6362
        ) -> std::result::Result<$crate::KeyPathPattern, $crate::key_specifier_derive::Bug> {
569
            use $crate::key_specifier_derive::*;
570

            
571
            arti_pattern_from_components(
572
                &[ $ARTI_PATH_COMPONENTS ],
573
                &[ $ARTI_LEAF_COMPONENTS ],
574
            )
575
        }
576

            
577
19249
        fn new_any() -> Self {
578
            $< $tname Pattern > {
579
                $( $fname: None, )
580
            }
581
        }
582
    }
583

            
584
    struct $< $tname InfoExtractor >;
585

            
586
    impl<$tgens> $crate::KeyPathInfoExtractor for $< $tname InfoExtractor >
587
    where $twheres
588
    {
589
9909
        fn describe(
590
9909
            &self,
591
9909
            path: &$crate::KeyPath,
592
9909
        ) -> std::result::Result<$crate::KeyPathInfo, $crate::KeyPathError> {
593
            use $crate::key_specifier_derive::*;
594

            
595
            // Parse this path
596
            #[allow(unused_variables)] // Unused if no fields
597
            let spec = $ttype::try_from(path)?;
598

            
599
            // none of this cares about non-role literals
600
            // all the others three be explicitly defined each time
601
            ${define DO_LITERAL {}}
602

            
603
            static NON_ROLE_FIELD_KEYS: &[&str] = &[
604
                ${define DO_FIELD { stringify!($fname), }}
605
                ${define DO_ROLE_FIELD {}}
606
                ${define DO_ROLE_LITERAL {}}
607
                $ARTI_PATH_COMPONENTS
608
                $ARTI_LEAF_COMPONENTS
609
            ];
610

            
611
            describe_via_components(
612
                &${tmeta(summary) as str},
613

            
614
                // role
615
                ${define DO_FIELD {}}
616
                ${define DO_ROLE_FIELD { &spec.$fname, }}
617
                ${define DO_ROLE_LITERAL { &$LIT, }}
618
                $ARTI_LEAF_COMPONENTS
619

            
620
                &NON_ROLE_FIELD_KEYS,
621

            
622
                &[
623
                    ${define DO_FIELD { &spec.$fname, }}
624
                    ${define DO_ROLE_FIELD {}}
625
                    ${define DO_ROLE_LITERAL {}}
626
                    $ARTI_PATH_COMPONENTS
627
                    $ARTI_LEAF_COMPONENTS
628
                ],
629
            ).map_err($crate::KeyPathError::Bug)
630
        }
631
    }
632

            
633
    impl<$tgens> TryFrom<&$crate::KeyPath> for $tname
634
    where $twheres
635
    {
636
        type Error = $crate::KeyPathError;
637

            
638
12385
        fn try_from(path: &$crate::KeyPath) -> std::result::Result<$tname, Self::Error> {
639
            use $crate::key_specifier_derive::*;
640

            
641
            static FIELD_KEYS: &[&str] = &[
642
                ${define DO_LITERAL {}}
643
                ${define DO_FIELD { stringify!($fname), }}
644
                $ARTI_PATH_COMPONENTS
645
                $ARTI_LEAF_COMPONENTS
646
            ];
647

            
648
            #[allow(unused_mut)] // not needed if there are no fields
649
            #[allow(unused_variables)] // not needed if there are no fields
650
            let mut builder =
651
                <$<$tname Pattern>::<$tgens> as $crate::KeySpecifierPattern>::new_any();
652

            
653
            ${define DO_FIELD { &mut builder.$fname, }}
654
            ${define DO_LITERAL { &mut $LIT, }}
655

            
656
            #[allow(unused_variables)] // CTorPath is only used with ctor_path(..)
657
            match path {
658
                $crate::KeyPath::Arti(path) => {
659
                    parse_arti_path(
660
                        path,
661
                        &FIELD_KEYS,
662
                        &mut [ $ARTI_PATH_COMPONENTS ],
663
                        &mut [ $ARTI_LEAF_COMPONENTS ],
664
                    ).map_err(|err| $crate::KeyPathError::Arti { path: path.clone(), err })?;
665
                },
666
                $crate::KeyPath::CTor(path) => {
667
                    return <Self as $crate::CTorKeySpecifier>::from_ctor_path(path.clone())
668
                        .map_err(|err| $crate::KeyPathError::CTor { path: path.clone(), err });
669
                },
670
                #[allow(unreachable_patterns)] // This is reachable if used outside of tor-keymgr
671
                &_ => {
672
                    return Err(internal!("unrecognized key path?!").into());
673
                }
674
            };
675

            
676
            #[allow(unused_variables)] // not needed if there are no fields
677
            let handle_none = || internal!("bad RawKeySpecifierComponentParser impl");
678

            
679
            Ok($tname { $(
680
                $fname: builder.$fname.ok_or_else(handle_none)?,
681
            ) })
682
        }
683
    }
684

            
685
    ${if tmeta(ctor_path) {
686

            
687
    ${define CTOR_PATH_VARIANT ${tmeta(ctor_path) as path}}
688

            
689
    impl<$tgens> $crate::CTorKeySpecifier for $ttype
690
    where $twheres
691
    {
692
298
        fn ctor_path(&self) -> Option<$crate::CTorPath> {
693
            Some($crate::CTorPath :: $CTOR_PATH_VARIANT {
694
                $( $fname: self.$fname.clone(), )
695
            })
696
        }
697

            
698
339
        fn from_ctor_path(
699
339
            path: $crate::CTorPath
700
339
        ) -> std::result::Result<Self, $crate::CTorPathError> {
701

            
702
            match path {
703
                $crate::CTorPath :: $CTOR_PATH_VARIANT { $( $fname, )} => {
704
                    Ok( Self { $( $fname, ) })
705
                },
706
                _ => Err($crate::CTorPathError::KeySpecifierMismatch(stringify!($tname).into())),
707
            }
708
        }
709
    }
710

            
711
    } else {
712
    impl<$tgens> $crate::CTorKeySpecifier for $ttype
713
    where $twheres
714
    {
715
        fn ctor_path(&self) -> Option<$crate::CTorPath> {
716
            None
717
        }
718

            
719
2588
        fn from_ctor_path(
720
2588
            _: $crate::CTorPath
721
2588
        ) -> std::result::Result<Self, $crate::CTorPathError> {
722
            Err($crate::CTorPathError::MissingCTorPath(stringify!($tname).to_string()))
723
        }
724
    }
725

            
726
    }}
727

            
728
    // Register the info extractor with `KeyMgr`.
729
    $crate::inventory::submit!(&$< $tname InfoExtractor > as &dyn $crate::KeyPathInfoExtractor);
730
}
731

            
732
#[cfg(feature = "experimental-api")]
733
define_derive_deftly! {
734
    /// A helper for implementing [`KeyCertificateSpecifier`]s.
735
    ///
736
    /// ### Results of applying this macro
737
    ///
738
    /// `#[derive(Deftly)] #[derive_deftly(CertSpecifier)] struct SomeCertSpec ...`
739
    /// generates:
740
    ///
741
    ///  * `impl `[`KeyCertificateSpecifier`]` for SomeCertSpec`
742
    ///  * `struct SomeCertSpecPattern`,
743
    ///    a derived struct which contains an `Option` for each denotator field,
744
    ///    and a non-optional field for the subject key `KeyPathPattern`.
745
    ///    `None` in the pattern means "any".
746
    ///  * `impl `[`CertSpecifierPattern`]` for SomeCertSpecPattern`
747
    ///  * `impl TryFrom<`[`KeyPath`]> for SomeCertSpec`
748
    ///
749
    ///
750
    /// ### Custom attributes
751
    ///
752
    ///  * **`#[deftly(subject)]`** (mandatory, field):
753
    ///    Designates a field that represents the subject key specifier.
754
    ///    This should only be applied to **one** field.
755
    ///
756
    ///  * **`#[deftly(denotator)]`** (field):
757
    ///    Designates a field that should be represented
758
    ///    in the key file leafname.
759
    ///    The `ArtiPath` of the certificate is derived from the `ArtiPath`
760
    ///    of the subject key,  by concatenating the `ArtiPath` of the subject
761
    ///    key with provided denotators provided.
762
    ///    If no there are no denotators, the `ArtiPath` of the certificate
763
    ///    is the same as the `ArtiPath` of the subject key.
764
    export CertSpecifier beta_deftly, for struct:
765

            
766
    // Ensure exactly one field annotated with #[deftly(subject)]
767
    ${if not(approx_equal(${for fields { ${when fmeta(subject)} 1 }}, 1))
768
        { ${error "Exactly one field must be #[deftly(subject)]"} }
769
    }
770

            
771
    // All fields must be either #[deftly(subject)] or #[deftly(denotator)]
772
    $(
773
        ${when not(any(
774
            fmeta(subject),
775
            fmeta(denotator),
776
        ))}
777

            
778
        ${error
779
            message=${concat $fname " must be #[deftly(subject)] or #[deftly(denotator)]"}
780
        }
781
    )
782

            
783
    ${define SUBJ_FNAME
784
        ${for fields {
785
            ${if fmeta(subject) {
786
                &self.$fname
787
            }}
788
        }}
789
    }
790

            
791
    ${define SUBJ_FTYPE
792
        ${for fields {
793
            ${if fmeta(subject) {
794
                $ftype
795
            }}
796
        }}
797
    }
798

            
799
    ${define SUBJ_PATTERN_FTYPE
800
        ${for fields {
801
            ${if fmeta(subject) {
802
                $<$ftype Pattern>
803
            }}
804
        }}
805
    }
806

            
807
    impl<$tgens> $crate::KeyCertificateSpecifier for $tname<$tdefgens>
808
    where $twheres
809
    {
810
642
        fn cert_denotators(&self) -> Vec<&dyn $crate::KeySpecifierComponent> {
811
            vec![
812
                ${for fields {
813
                    // #[deftly(denotator)]
814
                    ${if fmeta(denotator) { &self.$fname, }}
815
                }}
816
            ]
817
        }
818

            
819
1176
        fn subject_key_specifier(&self) -> &dyn $crate::KeySpecifier {
820
            ${SUBJ_FNAME}
821
        }
822
    }
823

            
824
    #[doc = concat!("Pattern matching some or all [`", stringify!($tname), "`]")]
825
    #[allow(dead_code)] // Not everyone will need the pattern feature
826
    #[non_exhaustive]
827
    $tvis struct $<$tname Pattern><$tdefgens>
828
    where $twheres
829
    {
830
        ${for fields {
831
            // The subject key specifier pattern is non-optional,
832
            // because we derive the fixed part of the pattern from it
833
            ${if fmeta(subject) {
834
                ${fattrs doc}
835
                $fvis $fname: $<$ftype Pattern>,
836
            }}
837
            // The denotators are optional
838
            ${if fmeta(denotator) {
839
                ${fattrs doc}
840
                $fvis $fname: Option<$ftype>,
841
            }}
842
        }}
843
    }
844

            
845
    ${define DO_FIELD { &self.$fname, }}
846

            
847
    ${define ARTI_LEAF_COMPONENTS {
848
        ${for fields {
849
            // #[deftly(denotator)]
850
            ${if fmeta(denotator) { $DO_FIELD }}
851
        }}
852
    }}
853

            
854
    impl<$tgens> $crate::CertSpecifierPattern for $<$tname Pattern><$tdefgens>
855
    where $twheres
856
    {
857
        type SubjectKeySpecifierPattern = ${SUBJ_PATTERN_FTYPE};
858

            
859
2046
        fn arti_pattern(
860
2046
            &self,
861
2046
        ) -> std::result::Result<$crate::KeyPathPattern, $crate::key_specifier_derive::Bug> {
862
            use $crate::key_specifier_derive::*;
863
            use $crate::KeyPathPattern::*;
864
            use $crate::KeySpecifierPattern as _;
865

            
866
            let subj_path_pat = ${SUBJ_FNAME}.arti_pattern()?;
867
            let subj_path = match subj_path_pat {
868
                Arti(path) => path,
869
                _ => {
870
                    return Err(
871
                        tor_error::internal!("subject key pattern is not an Arti pattern?!").into()
872
                    );
873
                }
874
            };
875

            
876
            cert_arti_pattern_from_components(
877
                &subj_path,
878
                &[ $ARTI_LEAF_COMPONENTS ],
879
            )
880
        }
881

            
882
2578
        fn new_any() -> Self {
883
            // Build the "any" pattern of the subject key.
884
            let spec =
885
                < <$<$tname Pattern>::<$tgens> as $crate::CertSpecifierPattern>::SubjectKeySpecifierPattern
886
                    as $crate::KeySpecifierPattern>::new_any();
887

            
888
            $< $tname Pattern > {
889
                $(
890
                    ${if fmeta(subject) { $fname: spec, }}
891
                )
892
                $(
893
                    ${if fmeta(denotator) { $fname: None, }}
894
                )
895
            }
896
        }
897
    }
898

            
899
    impl<$tgens> TryFrom<&$crate::KeyPath> for $tname
900
    where $twheres
901
    {
902
        type Error = $crate::KeyPathError;
903

            
904
532
        fn try_from(path: &$crate::KeyPath) -> std::result::Result<$tname, Self::Error> {
905
            use $crate::key_specifier_derive::*;
906

            
907
            let arti_path = match path {
908
                $crate::KeyPath::Arti(path) => path,
909
                &_ => {
910
                    return Err(tor_error::bad_api_usage!("Cert specifiers never have non-ArtiPaths").into());
911
                }
912
            };
913

            
914
            #[allow(unused_mut)] // not needed if there are no fields
915
            #[allow(unused_variables)] // not needed if there are no fields
916
            let mut builder =
917
                <$<$tname Pattern>::<$tgens> as $crate::CertSpecifierPattern>::new_any();
918

            
919
            let subj_key = if let Some((key_path, cert_denos)) = arti_path.split_once($crate::DENOTATOR_GROUP_SEP) {
920

            
921
                // Handle the special case where the subject key ArtiPath has no denotators,
922
                // but the cert ArtiPath *does*. This translates to paths that contain
923
                // the slightly odd +@ construction, where + designates the beginning
924
                // of the denotator section, followed by an empty denotator group.
925
                let key_path = match key_path.strip_suffix('+') {
926
                    Some(p) => p,
927
                    None => key_path,
928
                };
929

            
930
                let key_arti_path = $crate::ArtiPath::new(key_path.to_string())
931
                    .map_err(tor_error::into_internal!("cert path contains invalid key ArtiPath?!"))?;
932

            
933
                static FIELD_KEYS: &[&str] = &[
934
                    ${for fields {
935
                        // #[deftly(denotator)]
936
                        ${if fmeta(denotator) { stringify!($fname), }}
937
                    }}
938
                ];
939

            
940
                parse_cert_denotators(
941
                    cert_denos,
942
                    &FIELD_KEYS,
943
                    ${define DO_FIELD { &mut builder.$fname, }}
944
                    &mut [ $ARTI_LEAF_COMPONENTS ],
945
                ).map_err(|err| $crate::KeyPathError::Arti { path: arti_path.clone(), err })?;
946

            
947
                let key_spec = $crate::KeyPath::Arti(key_arti_path);
948

            
949
                $SUBJ_FTYPE::try_from(&key_spec)?
950
            } else {
951
                // Cert has no denotators, so the whole path is the path
952
                // of the subject key specifier
953
                $SUBJ_FTYPE::try_from(path)?
954
            };
955

            
956
            #[allow(unused_variables)] // not needed if there are no fields
957
            let handle_none = || internal!("bad RawKeySpecifierComponentParser impl");
958

            
959
            Ok($tname {
960
                ${for fields {
961
                    // The denotators are optional...
962
                    ${if fmeta(denotator) {
963
                        $fname: builder.$fname.ok_or_else(handle_none)?,
964
                    }}
965
                    // ...but subject key specifier pattern is not
966
                    ${if fmeta(subject) {
967
                        $fname: subj_key,
968
                    }}
969
                }}
970
            })
971
        }
972
    }
973

            
974
    // TODO: generate and register a KeyPathInfoExtractor impl for cert specifiers
975
    // (so that KeyMgr::describe() can describe them)
976
}
977

            
978
pub use derive_deftly_template_KeySpecifier;
979

            
980
#[cfg(feature = "experimental-api")]
981
pub use derive_deftly_template_CertSpecifier;