workshop_rs/core/signatures.rs
1/// Supplies the expected enum domain for a call argument during parsing.
2///
3/// The parser asks for the expected domain of argument `arg_index` (0-based)
4/// of the call whose Workshop catalog id is `catalog_id`. Implementations
5/// must return the domain only when the canonical signature pins exactly one;
6/// returning `None` leaves an ambiguous bare member unresolved.
7pub trait ExpectedDomain {
8 /// The expected enum domain for `arg_index` of the call with catalog id
9 /// `catalog_id`, or `None` when the signature does not pin one.
10 fn expected_domain(&self, catalog_id: &str, arg_index: usize) -> Option<&str>;
11}
12
13/// A context with no signature metadata. Ambiguous bare enum members remain
14/// structured with their catalog candidates. Used by callers that intentionally
15/// need context-free parsing.
16#[derive(Debug, Clone, Copy, Default)]
17pub struct NoExpectedDomain;
18
19impl ExpectedDomain for NoExpectedDomain {
20 fn expected_domain(&self, _catalog_id: &str, _arg_index: usize) -> Option<&str> {
21 None
22 }
23}
24
25/// A context chain: consult `first`, then fall back to `second`.
26///
27/// Callers that combine signature sources (e.g. a provider manifest followed
28/// by the canonical catalog) chain them; neither is authoritative alone.
29#[derive(Clone, Copy)]
30pub struct ChainedExpectedDomain<'a, 'b> {
31 first: &'a dyn ExpectedDomain,
32 second: &'b dyn ExpectedDomain,
33}
34
35impl<'a, 'b> ChainedExpectedDomain<'a, 'b> {
36 /// Chain two contexts, consulting `first` before `second`.
37 pub fn new(first: &'a dyn ExpectedDomain, second: &'b dyn ExpectedDomain) -> Self {
38 ChainedExpectedDomain { first, second }
39 }
40}
41
42impl ExpectedDomain for ChainedExpectedDomain<'_, '_> {
43 fn expected_domain(&self, catalog_id: &str, arg_index: usize) -> Option<&str> {
44 self.first
45 .expected_domain(catalog_id, arg_index)
46 .or_else(|| self.second.expected_domain(catalog_id, arg_index))
47 }
48}