1use std::sync::{Arc, Weak};
4
5use strum::IntoEnumIterator;
6
7use crate::ops::{ExtensionOp, OpName, OpNameRef};
8use crate::types::type_param::TermKindError;
9use crate::{Extension, ops::OpType, types::TypeArg};
10
11use super::{ExtensionBuildError, ExtensionId, OpDef, SignatureError, op_def::SignatureFunc};
12use crate::ops::custom::qualify_name;
13use delegate::delegate;
14use thiserror::Error;
15
16#[derive(Debug, Error, PartialEq, Clone)]
18#[error("{0}")]
19#[allow(missing_docs)]
20#[non_exhaustive]
21pub enum OpLoadError {
22 #[error("Op with name {0} is not a member of this set.")]
23 NotMember(String),
24 #[error("Type args invalid: {0}.")]
25 InvalidArgs(#[from] SignatureError),
26 #[error("OpDef belongs to extension {0}, expected {1}.")]
27 WrongExtension(ExtensionId, ExtensionId),
28}
29
30impl From<TermKindError> for OpLoadError {
31 fn from(value: TermKindError) -> Self {
32 SignatureError::from(value).into()
33 }
34}
35
36pub trait MakeOpDef {
44 fn opdef_id(&self) -> OpName;
53
54 fn from_def(op_def: &OpDef) -> Result<Self, OpLoadError>
56 where
57 Self: Sized;
58
59 fn extension(&self) -> ExtensionId;
61
62 fn qualified_opdef_id(&self) -> OpName {
65 qualify_name(&self.extension(), &self.opdef_id())
66 }
67
68 fn extension_ref(&self) -> Weak<Extension>;
70
71 fn init_signature(&self, extension_ref: &Weak<Extension>) -> SignatureFunc;
77
78 fn signature(&self) -> SignatureFunc {
80 self.init_signature(&self.extension_ref())
81 }
82
83 fn description(&self) -> String {
85 self.opdef_id().to_string()
86 }
87
88 fn post_opdef(&self, _def: &mut OpDef) {}
90
91 fn add_to_extension(
97 &self,
98 extension: &mut Extension,
99 extension_ref: &Weak<Extension>,
100 ) -> Result<(), ExtensionBuildError> {
101 let def = extension.add_op(
102 self.opdef_id(),
103 self.description(),
104 self.init_signature(extension_ref),
105 extension_ref,
106 )?;
107
108 self.post_opdef(def);
109
110 Ok(())
111 }
112
113 fn load_all_ops(
119 extension: &mut Extension,
120 extension_ref: &Weak<Extension>,
121 ) -> Result<(), ExtensionBuildError>
122 where
123 Self: IntoEnumIterator,
124 {
125 for op in Self::iter() {
126 op.add_to_extension(extension, extension_ref)?;
127 }
128 Ok(())
129 }
130
131 fn from_op(ext_op: &ExtensionOp) -> Result<Self, OpLoadError>
133 where
134 Self: Sized + std::str::FromStr,
135 {
136 Self::from_extension_op(ext_op)
137 }
138}
139
140pub trait HasConcrete: MakeOpDef {
142 type Concrete: MakeExtensionOp;
144
145 fn instantiate(&self, type_args: &[TypeArg]) -> Result<Self::Concrete, OpLoadError>;
147}
148
149pub trait HasDef: MakeExtensionOp {
151 type Def: HasConcrete<Concrete = Self> + std::str::FromStr;
153
154 fn from_op(ext_op: &ExtensionOp) -> Result<Self, OpLoadError>
156 where
157 Self: Sized,
158 {
159 Self::from_extension_op(ext_op)
160 }
161}
162
163pub trait MakeExtensionOp {
166 fn op_id(&self) -> OpName;
172
173 fn from_extension_op(ext_op: &ExtensionOp) -> Result<Self, OpLoadError>
175 where
176 Self: Sized;
177 #[must_use]
180 fn from_optype(op: &OpType) -> Option<Self>
181 where
182 Self: Sized,
183 {
184 let ext: &ExtensionOp = op.as_extension_op()?;
185 Self::from_extension_op(ext).ok()
186 }
187
188 fn type_args(&self) -> Vec<TypeArg>;
190
191 fn to_registered(
194 self,
195 extension_id: ExtensionId,
196 extension: Arc<Extension>,
197 ) -> RegisteredOp<Self>
198 where
199 Self: Sized,
200 {
201 RegisteredOp {
202 extension_id,
203 extension,
204 op: self,
205 }
206 }
207}
208
209impl<T: MakeOpDef> MakeExtensionOp for T {
211 fn op_id(&self) -> OpName {
212 self.opdef_id()
213 }
214
215 #[inline]
216 fn from_extension_op(ext_op: &ExtensionOp) -> Result<Self, OpLoadError>
217 where
218 Self: Sized,
219 {
220 Self::from_def(ext_op.def())
221 }
222
223 #[inline]
224 fn type_args(&self) -> Vec<TypeArg> {
225 vec![]
226 }
227}
228
229pub fn try_from_name<T>(name: &OpNameRef, def_extension: &ExtensionId) -> Result<T, OpLoadError>
232where
233 T: std::str::FromStr + MakeOpDef,
234{
235 let op = T::from_str(name).map_err(|_| OpLoadError::NotMember(name.to_string()))?;
236 let expected_extension = op.extension();
237 if def_extension != &expected_extension {
238 return Err(OpLoadError::WrongExtension(
239 def_extension.clone(),
240 expected_extension,
241 ));
242 }
243
244 Ok(op)
245}
246
247#[derive(Clone, Debug)]
250pub struct RegisteredOp<T> {
251 pub extension_id: ExtensionId,
253 extension: Arc<Extension>,
255 op: T,
257}
258
259impl<T> RegisteredOp<T> {
260 pub fn to_inner(self) -> T {
262 self.op
263 }
264}
265
266impl<T: MakeExtensionOp> RegisteredOp<T> {
267 pub fn to_extension_op(&self) -> Result<ExtensionOp, SignatureError> {
269 let op_def = self.extension.get_op(&self.op_id()).unwrap_or_else(|| {
270 panic!(
271 "Extension::get_op() called with an invalid name ({}).",
272 self.op_id()
273 )
274 });
275 ExtensionOp::new(op_def.clone(), self.type_args())
276 }
277
278 delegate! {
279 to self.op {
280 pub fn op_id(&self) -> OpName;
282 pub fn type_args(&self) -> Vec<TypeArg>;
284 }
285 }
286}
287
288pub trait MakeRegisteredOp: MakeExtensionOp {
292 fn extension_id(&self) -> ExtensionId;
294 fn extension_ref(&self) -> Arc<Extension>;
296
297 fn to_extension_op(self) -> Result<ExtensionOp, SignatureError>
300 where
301 Self: Sized,
302 {
303 let registered: RegisteredOp<_> = self.into();
304 registered.to_extension_op()
305 }
306}
307
308impl<T: MakeRegisteredOp> From<T> for RegisteredOp<T> {
309 fn from(ext_op: T) -> Self {
310 let extension_id = ext_op.extension_id();
311 let extension = ext_op.extension_ref();
312 ext_op.to_registered(extension_id, extension)
313 }
314}
315
316impl<T: MakeRegisteredOp> From<T> for OpType {
317 fn from(ext_op: T) -> Self {
319 ext_op.to_extension_op().unwrap().into()
320 }
321}
322
323#[cfg(test)]
324mod test {
325 use std::sync::{Arc, LazyLock};
326
327 use crate::{
328 const_extension_ids, type_row,
329 types::{Signature, Term},
330 };
331
332 use super::*;
333 use strum::{EnumIter, EnumString, IntoStaticStr};
334
335 #[derive(Clone, Debug, Hash, PartialEq, Eq, EnumIter, IntoStaticStr, EnumString)]
336 enum DummyEnum {
337 Dumb,
338 }
339
340 impl MakeOpDef for DummyEnum {
341 fn opdef_id(&self) -> OpName {
342 <&'static str>::from(self).into()
343 }
344
345 fn init_signature(&self, _extension_ref: &Weak<Extension>) -> SignatureFunc {
346 Signature::new_endo(type_row![]).into()
347 }
348
349 fn extension_ref(&self) -> Weak<Extension> {
350 Arc::downgrade(&EXT)
351 }
352
353 fn from_def(_op_def: &OpDef) -> Result<Self, OpLoadError> {
354 Ok(Self::Dumb)
355 }
356
357 fn extension(&self) -> ExtensionId {
358 EXT_ID.clone()
359 }
360 }
361
362 impl HasConcrete for DummyEnum {
363 type Concrete = Self;
364
365 fn instantiate(&self, _type_args: &[TypeArg]) -> Result<Self::Concrete, OpLoadError> {
366 if _type_args.is_empty() {
367 Ok(self.clone())
368 } else {
369 Err(OpLoadError::InvalidArgs(SignatureError::InvalidTypeArgs))
370 }
371 }
372 }
373 const_extension_ids! {
374 const EXT_ID: ExtensionId = "DummyExt";
375 }
376
377 static EXT: LazyLock<Arc<Extension>> = LazyLock::new(|| {
378 Extension::new_test_arc(EXT_ID.clone(), |ext, extension_ref| {
379 DummyEnum::Dumb
380 .add_to_extension(ext, extension_ref)
381 .unwrap();
382 })
383 });
384
385 impl MakeRegisteredOp for DummyEnum {
386 fn extension_id(&self) -> ExtensionId {
387 EXT_ID.clone()
388 }
389
390 fn extension_ref(&self) -> Arc<Extension> {
391 EXT.clone()
392 }
393 }
394
395 #[test]
396 fn test_dummy_enum() {
397 let o = DummyEnum::Dumb;
398
399 assert_eq!(
400 DummyEnum::from_def(EXT.get_op(&o.opdef_id()).unwrap()).unwrap(),
401 o
402 );
403
404 assert_eq!(
405 DummyEnum::from_optype(&o.clone().to_extension_op().unwrap().into()).unwrap(),
406 o
407 );
408 assert_eq!(format!("{EXT_ID}.Dumb"), o.qualified_opdef_id());
409 let registered: RegisteredOp<_> = o.clone().into();
410 assert_eq!(registered.to_inner(), o);
411
412 assert_eq!(o.instantiate(&[]), Ok(o.clone()));
413 assert_eq!(
414 o.instantiate(&[Term::from(1u64)]),
415 Err(OpLoadError::InvalidArgs(SignatureError::InvalidTypeArgs))
416 );
417 }
418}