Skip to main content

vyre_spec/
intrinsic_descriptor.rs

1//! Descriptor for a Category C hardware intrinsic.
2//!
3//! `IntrinsicDescriptor` binds a stable name, a required hardware unit, and a
4//! CPU reference function. Backends that claim support for the intrinsic must
5//! produce output that matches the CPU reference exactly on every witnessed
6//! input. Conform proofs carry this descriptor so that any reader can audit
7//! the hardware contract that the backend claims to satisfy.
8
9use std::sync::Arc;
10
11/// Flat byte-ABI CPU reference function used by Category C descriptors.
12///
13/// The function reads raw bytes from `input`, computes the operation's
14/// semantics, and appends the result bytes to `output`. This type lives in
15/// `vyre-spec` so that conform certificates can embed the function pointer
16/// without dragging the rest of the compiler into the data contract.
17pub type CpuFn = fn(input: &[u8], output: &mut Vec<u8>);
18
19/// Stable string identity for a backend.
20///
21/// Concrete driver crates own the spelling of their ids. The spec layer stores
22/// ids as opaque strings so adding a backend never requires editing this crate.
23#[derive(Debug, Clone)]
24pub struct BackendId(Arc<str>);
25
26impl BackendId {
27    /// Construct a backend id from any string-like value.
28    #[must_use]
29    pub fn new(name: impl Into<Arc<str>>) -> Self {
30        Self(name.into())
31    }
32
33    /// Return the backend id as a string slice.
34    #[must_use]
35    pub fn as_str(&self) -> &str {
36        &self.0
37    }
38}
39
40impl From<&str> for BackendId {
41    fn from(name: &str) -> Self {
42        Self(Arc::from(name))
43    }
44}
45
46impl From<String> for BackendId {
47    fn from(name: String) -> Self {
48        Self(Arc::from(name))
49    }
50}
51
52impl core::fmt::Display for BackendId {
53    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
54        f.write_str(&self.0)
55    }
56}
57
58impl PartialEq for BackendId {
59    fn eq(&self, other: &Self) -> bool {
60        self.0.as_ref() == other.0.as_ref()
61    }
62}
63
64impl Eq for BackendId {}
65
66impl core::hash::Hash for BackendId {
67    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
68        self.0.as_ref().hash(state);
69    }
70}
71
72/// Backend identity used when checking Category C intrinsic availability.
73///
74/// This is intentionally a data wrapper, not an enum. Concrete backend names
75/// belong in the driver crates that implement them.
76#[derive(Debug, Clone, PartialEq, Eq, Hash)]
77pub struct Backend {
78    id: BackendId,
79    name: Option<Arc<str>>,
80}
81
82impl Backend {
83    /// Construct a backend identity from an opaque backend id.
84    #[must_use]
85    pub fn new(id: impl Into<BackendId>) -> Self {
86        Self {
87            id: id.into(),
88            name: None,
89        }
90    }
91
92    /// Construct a backend identity with a friendly display name.
93    #[must_use]
94    pub fn named(id: impl Into<BackendId>, name: impl Into<Arc<str>>) -> Self {
95        Self {
96            id: id.into(),
97            name: Some(name.into()),
98        }
99    }
100
101    /// Stable string identifier for this backend.
102    #[must_use]
103    pub fn id(&self) -> &str {
104        self.id.as_str()
105    }
106
107    /// Friendly backend name, falling back to [`Backend::id`].
108    #[must_use]
109    pub fn name(&self) -> &str {
110        self.name.as_deref().unwrap_or_else(|| self.id())
111    }
112}
113
114impl From<BackendId> for Backend {
115    fn from(id: BackendId) -> Self {
116        Self::new(id)
117    }
118}
119
120impl From<&str> for Backend {
121    fn from(id: &str) -> Self {
122        Self::new(BackendId::from(id))
123    }
124}
125
126impl From<&Backend> for BackendId {
127    fn from(backend: &Backend) -> Self {
128        backend.id.clone()
129    }
130}
131
132use crate::op_contract::OperationContract;
133
134/// Descriptor for a Category C hardware intrinsic.
135#[non_exhaustive]
136#[derive(Debug, Clone)]
137pub struct IntrinsicDescriptor {
138    name: &'static str,
139    hardware: &'static str,
140    cpu_fn: CpuFn,
141    contract: Option<OperationContract>,
142}
143
144impl IntrinsicDescriptor {
145    /// Create an intrinsic descriptor with an explicit CPU reference function.
146    #[must_use]
147    pub const fn new(name: &'static str, hardware: &'static str, cpu_fn: CpuFn) -> Self {
148        Self {
149            name,
150            hardware,
151            cpu_fn,
152            contract: None,
153        }
154    }
155
156    /// Create an intrinsic descriptor with optional execution contract metadata.
157    #[must_use]
158    pub const fn with_contract(
159        name: &'static str,
160        hardware: &'static str,
161        cpu_fn: CpuFn,
162        contract: OperationContract,
163    ) -> Self {
164        Self {
165            name,
166            hardware,
167            cpu_fn,
168            contract: Some(contract),
169        }
170    }
171
172    /// Stable intrinsic name.
173    #[must_use]
174    pub const fn name(&self) -> &'static str {
175        self.name
176    }
177
178    /// Required hardware unit or backend feature.
179    #[must_use]
180    pub const fn hardware(&self) -> &'static str {
181        self.hardware
182    }
183
184    /// CPU reference implementation for this intrinsic.
185    #[must_use]
186    pub const fn cpu_fn(&self) -> CpuFn {
187        self.cpu_fn
188    }
189
190    /// Optional capability and execution contract annotations.
191    #[must_use]
192    pub const fn contract(&self) -> Option<&OperationContract> {
193        self.contract.as_ref()
194    }
195}