Skip to main content

workshop_rs/
signatures.rs

1//! Canonical signature context for ambiguous enum member resolution.
2//!
3//! The canonical catalog pins the expected enum domain of selected call
4//! argument positions (e.g. `createHudText` argument 9 is `HudReeval`). The
5//! Workshop parse path uses those expected domains to resolve a bare enum
6//! member spelling that is ambiguous across domains (e.g. the shared `None`
7//! member of `ChaseTimeReeval` / `ChaseRateReeval` / `Invis`).
8//!
9//! This module defines the minimal parse-context contract between the
10//! catalog owner and the Workshop frontend. It deliberately carries no
11//! signature data: the catalog data file remains the only domain table.
12//! (Extracted from the Wright-authored `wright_core::signatures` module;
13//! see [`docs/provenance.md`](https://github.com/wrightkit/workshop-rs/blob/main/docs/provenance.md).)
14
15/// Supplies the expected enum domain for a call argument during parsing.
16///
17/// The parser asks for the expected domain of argument `arg_index` (0-based)
18/// of the call whose Workshop catalog id is `catalog_id`. Implementations
19/// must return the domain only when the canonical signature pins exactly one;
20/// returning `None` keeps an ambiguous bare member rejected.
21pub trait ExpectedDomain {
22    /// The expected enum domain for `arg_index` of the call with catalog id
23    /// `catalog_id`, or `None` when the signature does not pin one.
24    fn expected_domain(&self, catalog_id: &str, arg_index: usize) -> Option<&str>;
25}
26
27/// A context with no signature metadata. Ambiguous bare enum members stay
28/// rejected. Used by callers that intentionally need context-free parsing.
29#[derive(Debug, Clone, Copy, Default)]
30pub struct NoExpectedDomain;
31
32impl ExpectedDomain for NoExpectedDomain {
33    fn expected_domain(&self, _catalog_id: &str, _arg_index: usize) -> Option<&str> {
34        None
35    }
36}
37
38/// A context chain: consult `first`, then fall back to `second`.
39///
40/// Callers that combine signature sources (e.g. a provider manifest followed
41/// by the canonical catalog) chain them; neither is authoritative alone.
42#[derive(Clone, Copy)]
43pub struct ChainedExpectedDomain<'a, 'b> {
44    first: &'a dyn ExpectedDomain,
45    second: &'b dyn ExpectedDomain,
46}
47
48impl<'a, 'b> ChainedExpectedDomain<'a, 'b> {
49    /// Chain two contexts, consulting `first` before `second`.
50    pub fn new(first: &'a dyn ExpectedDomain, second: &'b dyn ExpectedDomain) -> Self {
51        ChainedExpectedDomain { first, second }
52    }
53}
54
55impl ExpectedDomain for ChainedExpectedDomain<'_, '_> {
56    fn expected_domain(&self, catalog_id: &str, arg_index: usize) -> Option<&str> {
57        self.first
58            .expected_domain(catalog_id, arg_index)
59            .or_else(|| self.second.expected_domain(catalog_id, arg_index))
60    }
61}