Skip to main content

vyre_spec/
category.rs

1//! Frozen operation-category records used to separate composition from intrinsics.
2
3/// Backend support predicate for a Category C operation.
4pub trait BackendAvailability: Send + Sync {
5    /// Return true when the backend identified by `op` supports the operation.
6    fn available(&self, op: &str) -> bool;
7}
8
9impl<F> BackendAvailability for F
10where
11    F: Fn(&str) -> bool + Send + Sync,
12{
13    fn available(&self, op: &str) -> bool {
14        self(op)
15    }
16}
17
18/// Function-pointer wrapper for static backend-availability predicates.
19#[derive(Clone, Copy)]
20pub struct BackendAvailabilityPredicate {
21    predicate: fn(&str) -> bool,
22}
23
24impl BackendAvailabilityPredicate {
25    /// Create a backend-availability predicate from a total function.
26    #[must_use]
27    pub const fn new(predicate: fn(&str) -> bool) -> Self {
28        Self { predicate }
29    }
30
31    /// Return true when the named backend supports the operation.
32    #[must_use]
33    pub fn available(&self, op: &str) -> bool {
34        <Self as BackendAvailability>::available(self, op)
35    }
36}
37
38impl core::fmt::Debug for BackendAvailabilityPredicate {
39    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
40        f.write_str("BackendAvailabilityPredicate(..)")
41    }
42}
43
44impl BackendAvailability for BackendAvailabilityPredicate {
45    fn available(&self, op: &str) -> bool {
46        (self.predicate)(op)
47    }
48}
49
50/// vyre operation category in the frozen data contract.
51///
52/// Category B — runtime opcode dispatch, stack-machine VMs, and eval engines
53/// — is intentionally absent from this enum. vyre has no opcode interpreter
54/// and no execution path that is not a lowered IR program on a backend, so
55/// Category B is forbidden by the conformance model rather than specified
56/// as a valid operation category. Example: `Category::Intrinsic` records that an op is
57/// backed by a named hardware capability such as a subgroup intrinsic.
58#[derive(Debug, Clone)]
59#[non_exhaustive]
60pub enum Category {
61    /// Compositional operation that must disappear after lowering.
62    A {
63        /// Operation IDs that define the zero-overhead composition.
64        composition_of: Vec<&'static str>,
65    },
66    /// Hardware intrinsic with declared per-backend availability.
67    C {
68        /// Hardware unit or backend feature required by the intrinsic.
69        hardware: &'static str,
70        /// Predicate that returns true when the backend supports this op.
71        backend_availability: BackendAvailabilityPredicate,
72    },
73}
74
75impl Category {
76    /// Temporary marker used until every operation receives a real category.
77    #[must_use]
78    pub fn unclassified() -> Self {
79        Self::A {
80            composition_of: Vec::new(),
81        }
82    }
83
84    /// True when the category is the compile-only empty Category A marker.
85    #[must_use]
86    pub fn is_unclassified(&self) -> bool {
87        matches!(self, Self::A { composition_of } if composition_of.is_empty())
88    }
89}
90
91impl PartialEq for Category {
92    fn eq(&self, other: &Self) -> bool {
93        match (self, other) {
94            (
95                Self::A {
96                    composition_of: left,
97                },
98                Self::A {
99                    composition_of: right,
100                },
101            ) => left == right,
102            (
103                Self::C { hardware: left, .. },
104                Self::C {
105                    hardware: right, ..
106                },
107            ) => left == right,
108            _ => false,
109        }
110    }
111}
112
113impl Eq for Category {}