Skip to main content

workshop_rs/core/
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` leaves an ambiguous bare member unresolved.
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 remain
28/// structured with their catalog candidates. Used by callers that intentionally
29/// need context-free parsing.
30#[derive(Debug, Clone, Copy, Default)]
31pub struct NoExpectedDomain;
32
33impl ExpectedDomain for NoExpectedDomain {
34    fn expected_domain(&self, _catalog_id: &str, _arg_index: usize) -> Option<&str> {
35        None
36    }
37}
38
39/// A context chain: consult `first`, then fall back to `second`.
40///
41/// Callers that combine signature sources (e.g. a provider manifest followed
42/// by the canonical catalog) chain them; neither is authoritative alone.
43#[derive(Clone, Copy)]
44pub struct ChainedExpectedDomain<'a, 'b> {
45    first: &'a dyn ExpectedDomain,
46    second: &'b dyn ExpectedDomain,
47}
48
49impl<'a, 'b> ChainedExpectedDomain<'a, 'b> {
50    /// Chain two contexts, consulting `first` before `second`.
51    pub fn new(first: &'a dyn ExpectedDomain, second: &'b dyn ExpectedDomain) -> Self {
52        ChainedExpectedDomain { first, second }
53    }
54}
55
56impl ExpectedDomain for ChainedExpectedDomain<'_, '_> {
57    fn expected_domain(&self, catalog_id: &str, arg_index: usize) -> Option<&str> {
58        self.first
59            .expected_domain(catalog_id, arg_index)
60            .or_else(|| self.second.expected_domain(catalog_id, arg_index))
61    }
62}