Skip to main content

hugr_core/
extension.rs

1//! Extension framework for user-defined operations and types.
2//!
3// TODO: YAML declaration and parsing. This should be similar to a plugin
4// system (outside the `types` module), which also parses nested [`OpDef`]s.
5//!
6//!
7//! # Example
8//!
9//! By default HUGR does not include any quantum operations, but it is possible to define
10//! them in an extension and then use them in a HUGR.
11//! Here we show how to define a custom quantum extension, and how to use it to build a HUGR for a simple quantum circuit.
12//! ```
13//! use hugr::builder::{BuildError, DFGBuilder, Dataflow, DataflowHugr, inout_sig};
14//! // The prelude includes basic types like `bool`, `usize_t` and a `qubit` type.
15//! use hugr::extension::prelude::{bool_t, qb_t};
16//! use hugr::envelope::EnvelopeConfig;
17//! use hugr::hugr::Hugr;
18//!
19//! // By default, no gateset is defined. This module provides Hadamard and CX gates.
20//! mod mini_quantum_extension {
21//!     use hugr::{
22//!         extension::{
23//!             prelude::{bool_t, qb_t},
24//!             ExtensionId, Version,
25//!         },
26//!         ops::{ExtensionOp, OpName},
27//!         types::{FuncValueType, PolyFuncTypeRV},
28//!         Extension,
29//!     };
30//!
31//!     use std::sync::{Arc, LazyLock};
32//!
33//!     fn one_qb_func() -> PolyFuncTypeRV {
34//!         FuncValueType::new_endo(vec![qb_t()]).into()
35//!     }
36//!
37//!     fn two_qb_func() -> PolyFuncTypeRV {
38//!         FuncValueType::new_endo(vec![qb_t(), qb_t()]).into()
39//!     }
40//!     /// The extension identifier.
41//!     pub const EXTENSION_ID: ExtensionId = ExtensionId::new_unchecked("mini.quantum");
42//!     pub const VERSION: Version = Version::new(0, 1, 0);
43//!     fn extension() -> Arc<Extension> {
44//!         Extension::new_arc(EXTENSION_ID, VERSION, |ext, extension_ref| {
45//!             ext.add_op(OpName::new_inline("H"), "Hadamard".into(), one_qb_func(), extension_ref)
46//!                 .unwrap();
47//!
48//!             ext.add_op(OpName::new_inline("CX"), "CX".into(), two_qb_func(), extension_ref)
49//!                 .unwrap();
50//!
51//!             ext.add_op(
52//!                 OpName::new_inline("Measure"),
53//!                 "Measure a qubit, returning the qubit and the measurement result.".into(),
54//!                 FuncValueType::new(vec![qb_t()], vec![qb_t(), bool_t()]),
55//!                 extension_ref,
56//!             )
57//!             .unwrap();
58//!         })
59//!     }
60//!
61//!     /// Quantum extension definition.
62//!     pub static EXTENSION: LazyLock<Arc<Extension>> = LazyLock::new(extension);
63//!
64//!     fn get_gate(gate_name: impl Into<OpName>) -> ExtensionOp {
65//!         EXTENSION
66//!             .instantiate_extension_op(&gate_name.into(), [])
67//!             .unwrap()
68//!             .into()
69//!     }
70//!     pub fn h_gate() -> ExtensionOp {
71//!         get_gate("H")
72//!     }
73//!
74//!     pub fn cx_gate() -> ExtensionOp {
75//!         get_gate("CX")
76//!     }
77//!
78//!     pub fn measure() -> ExtensionOp {
79//!         get_gate("Measure")
80//!     }
81//! }
82//!
83//! use mini_quantum_extension::{cx_gate, h_gate, measure};
84//!
85//! //      ┌───┐
86//! // q_0: ┤ H ├──■─────
87//! //      ├───┤┌─┴─┐┌─┐
88//! // q_1: ┤ H ├┤ X ├┤M├
89//! //      └───┘└───┘└╥┘
90//! // c:              ╚═
91//! fn make_dfg_hugr() -> Result<Hugr, BuildError> {
92//!     let mut dfg_builder = DFGBuilder::new(inout_sig(
93//!         vec![qb_t(), qb_t()],
94//!         vec![qb_t(), qb_t(), bool_t()],
95//!     ))?;
96//!     let [wire0, wire1] = dfg_builder.input_wires_arr();
97//!     let h0 = dfg_builder.add_dataflow_op(h_gate(), vec![wire0])?;
98//!     let h1 = dfg_builder.add_dataflow_op(h_gate(), vec![wire1])?;
99//!     let cx = dfg_builder.add_dataflow_op(cx_gate(), h0.outputs().chain(h1.outputs()))?;
100//!     let measure = dfg_builder.add_dataflow_op(measure(), cx.outputs().last())?;
101//!     dfg_builder.finish_hugr_with_outputs(cx.outputs().take(1).chain(measure.outputs()))
102//! }
103//!
104//! let h: Hugr = make_dfg_hugr().unwrap();
105//! // Serialize the hugr to obtain a printable representation
106//! let serialized = h.store_str(EnvelopeConfig::text()).unwrap();
107//! println!("{}", serialized);
108//! ```
109
110use itertools::Itertools;
111use resolution::{ExtensionResolutionError, WeakExtensionRegistry};
112pub use semver::Version;
113use serde::{Deserialize, Deserializer, Serialize};
114use std::cell::UnsafeCell;
115use std::collections::btree_map;
116use std::collections::{BTreeMap, BTreeSet};
117use std::fmt::Debug;
118use std::sync::atomic::{AtomicBool, Ordering};
119use std::sync::{Arc, Weak};
120use std::{io, mem};
121
122use derive_more::Display;
123use thiserror::Error;
124
125use crate::hugr::IdentList;
126use crate::ops::custom::{ExtensionOp, OpaqueOp};
127use crate::ops::{OpName, OpNameRef};
128use crate::types::RowVariable;
129use crate::types::type_param::{TermTypeError, TypeArg, TypeParam};
130use crate::types::{CustomType, TypeBound, TypeName};
131use crate::types::{Signature, TypeNameRef};
132
133mod const_fold;
134mod op_def;
135pub mod prelude;
136pub mod resolution;
137pub mod simple_op;
138mod type_def;
139
140pub use const_fold::{ConstFold, ConstFoldResult, Folder, fold_out_row};
141pub use op_def::{
142    CustomSignatureFunc, CustomValidator, LowerFunc, OpDef, SignatureFromArgs, SignatureFunc,
143    ValidateJustArgs, ValidateTypeArgs, deserialize_lower_funcs,
144};
145pub use prelude::{PRELUDE, PRELUDE_REGISTRY};
146pub use type_def::{TypeDef, TypeDefBound};
147
148#[cfg(feature = "declarative")]
149pub mod declarative;
150
151/// Extension Registries store extensions to be looked up e.g. during validation.
152#[derive(Debug, Display, Default)]
153#[display("ExtensionRegistry[{}]", exts.keys().join(", "))]
154pub struct ExtensionRegistry {
155    /// The extensions in the registry.
156    exts: BTreeMap<ExtensionId, Arc<Extension>>,
157    /// A flag indicating whether the current set of extensions has been
158    /// validated.
159    ///
160    /// This is used to avoid re-validating the extensions every time the
161    /// registry is validated, and is set to `false` whenever a new extension is
162    /// added.
163    valid: AtomicBool,
164}
165
166impl PartialEq for ExtensionRegistry {
167    fn eq(&self, other: &Self) -> bool {
168        self.exts == other.exts
169    }
170}
171
172impl Clone for ExtensionRegistry {
173    fn clone(&self) -> Self {
174        Self {
175            exts: self.exts.clone(),
176            valid: self.valid.load(Ordering::Relaxed).into(),
177        }
178    }
179}
180
181impl ExtensionRegistry {
182    /// Create a new empty extension registry.
183    pub fn new(extensions: impl IntoIterator<Item = Arc<Extension>>) -> Self {
184        let mut res = Self::default();
185        for ext in extensions {
186            res.register_updated(ext);
187        }
188        res
189    }
190
191    /// Load an `ExtensionRegistry` serialized as json.
192    ///
193    /// After deserialization, updates all the internal `Weak<Extension>`
194    /// references to point to the newly created [`Arc`]s in the registry,
195    /// or extensions in the `additional_extensions` parameter.
196    pub fn load_json(
197        reader: impl io::Read,
198        other_extensions: &ExtensionRegistry,
199    ) -> Result<Self, ExtensionRegistryLoadError> {
200        let extensions: Vec<Extension> = serde_json::from_reader(reader)?;
201        // After deserialization, we need to update all the internal
202        // `Weak<Extension>` references.
203        Ok(ExtensionRegistry::new_with_extension_resolution(
204            extensions,
205            &other_extensions.into(),
206        )?)
207    }
208
209    /// Gets the Extension with the given name
210    pub fn get(&self, name: &str) -> Option<&Arc<Extension>> {
211        self.exts.get(name)
212    }
213
214    /// Returns `true` if the registry contains an extension with the given name.
215    pub fn contains(&self, name: &str) -> bool {
216        self.exts.contains_key(name)
217    }
218
219    /// Validate the set of extensions.
220    pub fn validate(&self) -> Result<(), ExtensionRegistryError> {
221        if self.valid.load(Ordering::Relaxed) {
222            return Ok(());
223        }
224        for ext in self.exts.values() {
225            ext.validate()
226                .map_err(|e| ExtensionRegistryError::InvalidSignature(ext.name().clone(), e))?;
227        }
228        self.valid.store(true, Ordering::Relaxed);
229        Ok(())
230    }
231
232    /// Registers a new extension to the registry.
233    ///
234    /// Returns a reference to the registered extension if successful.
235    pub fn register(
236        &mut self,
237        extension: impl Into<Arc<Extension>>,
238    ) -> Result<(), ExtensionRegistryError> {
239        let extension = extension.into();
240        match self.exts.entry(extension.name().clone()) {
241            btree_map::Entry::Occupied(prev) => Err(ExtensionRegistryError::AlreadyRegistered(
242                extension.name().clone(),
243                Box::new(prev.get().version().clone()),
244                Box::new(extension.version().clone()),
245            )),
246            btree_map::Entry::Vacant(ve) => {
247                ve.insert(extension);
248                // Clear the valid flag so that the registry is re-validated.
249                self.valid.store(false, Ordering::Relaxed);
250
251                Ok(())
252            }
253        }
254    }
255
256    /// Registers a new extension to the registry, keeping the one most up to
257    /// date if the extension already exists.
258    ///
259    /// If extension IDs match, the extension with the higher version is kept.
260    /// If versions match, the original extension is kept. Returns a reference
261    /// to the registered extension if successful.
262    ///
263    /// Takes an Arc to the extension. To avoid cloning Arcs unless necessary,
264    /// see [`ExtensionRegistry::register_updated_ref`].
265    pub fn register_updated(&mut self, extension: impl Into<Arc<Extension>>) {
266        let extension = extension.into();
267        match self.exts.entry(extension.name().clone()) {
268            btree_map::Entry::Occupied(mut prev) => {
269                if prev.get().version() < extension.version() {
270                    *prev.get_mut() = extension;
271                }
272            }
273            btree_map::Entry::Vacant(ve) => {
274                ve.insert(extension);
275            }
276        }
277        // Clear the valid flag so that the registry is re-validated.
278        self.valid.store(false, Ordering::Relaxed);
279    }
280
281    /// Registers a new extension to the registry, keeping the one most up to
282    /// date if the extension already exists.
283    ///
284    /// If extension IDs match, the extension with the higher version is kept.
285    /// If versions match, the original extension is kept. Returns a reference
286    /// to the registered extension if successful.
287    ///
288    /// Clones the Arc only when required. For no-cloning version see
289    /// [`ExtensionRegistry::register_updated`].
290    pub fn register_updated_ref(&mut self, extension: &Arc<Extension>) {
291        match self.exts.entry(extension.name().clone()) {
292            btree_map::Entry::Occupied(mut prev) => {
293                if prev.get().version() < extension.version() {
294                    *prev.get_mut() = extension.clone();
295                }
296            }
297            btree_map::Entry::Vacant(ve) => {
298                ve.insert(extension.clone());
299            }
300        }
301        // Clear the valid flag so that the registry is re-validated.
302        self.valid.store(false, Ordering::Relaxed);
303    }
304
305    /// Returns the number of extensions in the registry.
306    pub fn len(&self) -> usize {
307        self.exts.len()
308    }
309
310    /// Returns `true` if the registry contains no extensions.
311    pub fn is_empty(&self) -> bool {
312        self.exts.is_empty()
313    }
314
315    /// Returns an iterator over the extensions in the registry.
316    pub fn iter(&self) -> <&Self as IntoIterator>::IntoIter {
317        self.exts.values()
318    }
319
320    /// Returns an iterator over the extensions ids in the registry.
321    pub fn ids(&self) -> impl Iterator<Item = &ExtensionId> {
322        self.exts.keys()
323    }
324
325    /// Delete an extension from the registry and return it if it was present.
326    pub fn remove_extension(&mut self, name: &ExtensionId) -> Option<Arc<Extension>> {
327        // Clear the valid flag so that the registry is re-validated.
328        self.valid.store(false, Ordering::Relaxed);
329
330        self.exts.remove(name)
331    }
332
333    /// Constructs a new `ExtensionRegistry` from a list of [`Extension`]s while
334    /// giving you a [`WeakExtensionRegistry`] to the allocation. This allows
335    /// you to add [`Weak`] self-references to the [`Extension`]s while
336    /// constructing them, before wrapping them in [`Arc`]s.
337    ///
338    /// This is similar to [`Arc::new_cyclic`], but for `ExtensionRegistries`.
339    ///
340    /// Calling [`Weak::upgrade`] on a weak reference in the
341    /// [`WeakExtensionRegistry`] inside your closure will return an extension
342    /// with no internal (op / type / value) definitions.
343    //
344    // It may be possible to implement this safely using `Arc::new_cyclic`
345    // directly, but the callback type does not allow for returning extra
346    // data so it seems unlikely.
347    pub fn new_cyclic<F, E>(
348        extensions: impl IntoIterator<Item = Extension>,
349        init: F,
350    ) -> Result<Self, E>
351    where
352        F: FnOnce(Vec<Extension>, &WeakExtensionRegistry) -> Result<Vec<Extension>, E>,
353    {
354        let extensions = extensions.into_iter().collect_vec();
355
356        // Unsafe internally-mutable wrapper around an extension. Important:
357        // `repr(transparent)` ensures the layout is identical to `Extension`,
358        // so it can be safely transmuted.
359        #[repr(transparent)]
360        struct ExtensionCell {
361            ext: UnsafeCell<Extension>,
362        }
363
364        // Create the arcs with internal mutability, and collect weak references
365        // over immutable references.
366        //
367        // This is safe as long as the cell mutation happens when we can guarantee
368        // that the weak references are not used.
369        let (arcs, weaks): (Vec<Arc<ExtensionCell>>, Vec<Weak<Extension>>) = extensions
370            .iter()
371            .map(|ext| {
372                // Create a new arc with an empty extension sharing the name and version of the original,
373                // but with no internal definitions.
374                //
375                // `UnsafeCell` is not sync, but we are not writing to it while the weak references are
376                // being used.
377                #[allow(clippy::arc_with_non_send_sync)]
378                let arc = Arc::new(ExtensionCell {
379                    ext: UnsafeCell::new(Extension::new(ext.name().clone(), ext.version().clone())),
380                });
381
382                // SAFETY: `ExtensionCell` is `repr(transparent)`, so it has the same layout as `Extension`.
383                let weak_arc: Weak<Extension> = unsafe { mem::transmute(Arc::downgrade(&arc)) };
384                (arc, weak_arc)
385            })
386            .unzip();
387
388        let mut weak_registry = WeakExtensionRegistry::default();
389        for (ext, weak) in extensions.iter().zip(weaks) {
390            weak_registry.register(ext.name().clone(), weak);
391        }
392
393        // Actual initialization here
394        // Upgrading the weak references at any point here will access the empty extensions in the arcs.
395        let extensions = init(extensions, &weak_registry)?;
396
397        // We're done.
398        let arcs: Vec<Arc<Extension>> = arcs
399            .into_iter()
400            .zip(extensions)
401            .map(|(arc, ext)| {
402                // Replace the dummy extensions with the updated ones.
403                // SAFETY: The cell is only mutated when the weak references are not used.
404                unsafe { *arc.ext.get() = ext };
405                // Pretend the UnsafeCells never existed.
406                // SAFETY: `ExtensionCell` is `repr(transparent)`, so it has the same layout as `Extension`.
407                unsafe { mem::transmute::<Arc<ExtensionCell>, Arc<Extension>>(arc) }
408            })
409            .collect();
410        Ok(ExtensionRegistry::new(arcs))
411    }
412}
413
414impl IntoIterator for ExtensionRegistry {
415    type Item = Arc<Extension>;
416
417    type IntoIter = std::collections::btree_map::IntoValues<ExtensionId, Arc<Extension>>;
418
419    fn into_iter(self) -> Self::IntoIter {
420        self.exts.into_values()
421    }
422}
423
424impl<'a> IntoIterator for &'a ExtensionRegistry {
425    type Item = &'a Arc<Extension>;
426
427    type IntoIter = std::collections::btree_map::Values<'a, ExtensionId, Arc<Extension>>;
428
429    fn into_iter(self) -> Self::IntoIter {
430        self.exts.values()
431    }
432}
433
434impl<'a> Extend<&'a Arc<Extension>> for ExtensionRegistry {
435    fn extend<T: IntoIterator<Item = &'a Arc<Extension>>>(&mut self, iter: T) {
436        for ext in iter {
437            self.register_updated_ref(ext);
438        }
439    }
440}
441
442impl Extend<Arc<Extension>> for ExtensionRegistry {
443    fn extend<T: IntoIterator<Item = Arc<Extension>>>(&mut self, iter: T) {
444        for ext in iter {
445            self.register_updated(ext);
446        }
447    }
448}
449
450/// Encode/decode `ExtensionRegistry` as a list of extensions.
451///
452/// Any `Weak<Extension>` references inside the registry will be left unresolved.
453/// Prefer using [`ExtensionRegistry::load_json`] when deserializing.
454impl<'de> Deserialize<'de> for ExtensionRegistry {
455    fn deserialize<D>(deserializer: D) -> Result<ExtensionRegistry, D::Error>
456    where
457        D: Deserializer<'de>,
458    {
459        let extensions: Vec<Arc<Extension>> = Vec::deserialize(deserializer)?;
460        Ok(ExtensionRegistry::new(extensions))
461    }
462}
463
464impl Serialize for ExtensionRegistry {
465    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
466    where
467        S: serde::Serializer,
468    {
469        let extensions: Vec<Arc<Extension>> = self.exts.values().cloned().collect();
470        extensions.serialize(serializer)
471    }
472}
473
474/// An Extension Registry containing no extensions.
475pub static EMPTY_REG: ExtensionRegistry = ExtensionRegistry {
476    exts: BTreeMap::new(),
477    valid: AtomicBool::new(true),
478};
479
480/// An error that can occur in computing the signature of a node.
481/// TODO: decide on failure modes
482#[derive(Debug, Clone, Error, PartialEq, Eq)]
483#[allow(missing_docs)]
484#[non_exhaustive]
485pub enum SignatureError {
486    /// Name mismatch
487    #[error("Definition name ({0}) and instantiation name ({1}) do not match.")]
488    NameMismatch(TypeName, TypeName),
489    /// Extension mismatch
490    #[error("Definition extension ({0}) and instantiation extension ({1}) do not match.")]
491    ExtensionMismatch(ExtensionId, ExtensionId),
492    /// When the type arguments of the node did not match the params declared by the `OpDef`
493    #[error("Type arguments of node did not match params declared by definition: {0}")]
494    TypeArgMismatch(#[from] TermTypeError),
495    /// Invalid type arguments
496    #[error("Invalid type arguments for operation")]
497    InvalidTypeArgs,
498    /// The weak [`Extension`] reference for a custom type has been dropped.
499    #[error(
500        "Type '{typ}' is defined in extension '{missing}', but the extension reference has been dropped."
501    )]
502    MissingTypeExtension { typ: TypeName, missing: ExtensionId },
503    /// The Extension was found in the registry, but did not contain the Type(Def) referenced in the Signature
504    #[error("Extension '{exn}' did not contain expected TypeDef '{typ}'")]
505    ExtensionTypeNotFound { exn: ExtensionId, typ: TypeName },
506    /// The bound recorded for a `CustomType` doesn't match what the `TypeDef` would compute
507    #[error("Bound on CustomType ({actual}) did not match TypeDef ({expected})")]
508    WrongBound {
509        actual: TypeBound,
510        expected: TypeBound,
511    },
512    /// A Type Variable's cache of its declared kind is incorrect
513    #[error("Type Variable claims to be {cached} but actual declaration {actual}")]
514    TypeVarDoesNotMatchDeclaration {
515        actual: Box<TypeParam>,
516        cached: Box<TypeParam>,
517    },
518    /// A type variable that was used has not been declared
519    #[error("Type variable {idx} was not declared ({num_decls} in scope)")]
520    FreeTypeVar { idx: usize, num_decls: usize },
521    /// A row variable was found outside of a variable-length row
522    #[error("Expected a single type, but found row variable {var}")]
523    RowVarWhereTypeExpected { var: RowVariable },
524    /// The result of the type application stored in a [Call]
525    /// is not what we get by applying the type-args to the polymorphic function
526    ///
527    /// [Call]: crate::ops::dataflow::Call
528    #[error(
529        "Incorrect result of type application in Call - cached {cached} but expected {expected}"
530    )]
531    CallIncorrectlyAppliesType {
532        cached: Box<Signature>,
533        expected: Box<Signature>,
534    },
535    /// The result of the type application stored in a [`LoadFunction`]
536    /// is not what we get by applying the type-args to the polymorphic function
537    ///
538    /// [`LoadFunction`]: crate::ops::dataflow::LoadFunction
539    #[error(
540        "Incorrect result of type application in LoadFunction - cached {cached} but expected {expected}"
541    )]
542    LoadFunctionIncorrectlyAppliesType {
543        cached: Box<Signature>,
544        expected: Box<Signature>,
545    },
546
547    /// Extension declaration specifies a binary compute signature function, but none
548    /// was loaded.
549    #[error("Binary compute signature function not loaded.")]
550    MissingComputeFunc,
551
552    /// Extension declaration specifies a binary compute signature function, but none
553    /// was loaded.
554    #[error("Binary validate signature function not loaded.")]
555    MissingValidateFunc,
556}
557
558/// Concrete instantiations of types and operations defined in extensions.
559trait CustomConcrete {
560    /// The identifier type for the concrete object.
561    type Identifier;
562    /// A generic identifier to the element.
563    ///
564    /// This may either refer to a [`TypeName`] or an [`OpName`].
565    fn def_name(&self) -> &Self::Identifier;
566    /// The concrete type arguments for the instantiation.
567    fn type_args(&self) -> &[TypeArg];
568    /// Extension required by the instantiation.
569    fn parent_extension(&self) -> &ExtensionId;
570}
571
572impl CustomConcrete for OpaqueOp {
573    type Identifier = OpName;
574
575    fn def_name(&self) -> &Self::Identifier {
576        self.unqualified_id()
577    }
578
579    fn type_args(&self) -> &[TypeArg] {
580        self.args()
581    }
582
583    fn parent_extension(&self) -> &ExtensionId {
584        self.extension()
585    }
586}
587
588impl CustomConcrete for CustomType {
589    type Identifier = TypeName;
590
591    fn def_name(&self) -> &TypeName {
592        // Casts the `TypeName` to a generic string.
593        self.name()
594    }
595
596    fn type_args(&self) -> &[TypeArg] {
597        self.args()
598    }
599
600    fn parent_extension(&self) -> &ExtensionId {
601        self.extension()
602    }
603}
604
605/// A unique identifier for a extension.
606///
607/// The actual [`Extension`] is stored externally.
608pub type ExtensionId = IdentList;
609
610/// A extension is a set of capabilities required to execute a graph.
611///
612/// These are normally defined once and shared across multiple graphs and
613/// operations wrapped in [`Arc`]s inside [`ExtensionRegistry`].
614///
615/// # Example
616///
617/// The following example demonstrates how to define a new extension with a
618/// custom operation and a custom type.
619///
620/// When using `arc`s, the extension can only be modified at creation time. The
621/// defined operations and types keep a [`Weak`] reference to their extension. We provide a
622/// helper method [`Extension::new_arc`] to aid their definition.
623///
624/// ```
625/// # use hugr_core::types::Signature;
626/// # use hugr_core::extension::{Extension, ExtensionId, Version};
627/// # use hugr_core::extension::{TypeDefBound};
628/// Extension::new_arc(
629///     ExtensionId::new_unchecked("my.extension"),
630///     Version::new(0, 1, 0),
631///     |ext, extension_ref| {
632///         // Add a custom type definition
633///         ext.add_type(
634///             "MyType".into(),
635///             vec![], // No type parameters
636///             "Some type".into(),
637///             TypeDefBound::any(),
638///             extension_ref,
639///         );
640///         // Add a custom operation
641///         ext.add_op(
642///             "MyOp".into(),
643///             "Some operation".into(),
644///             Signature::new_endo([]),
645///             extension_ref,
646///         );
647///     },
648/// );
649/// ```
650#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
651pub struct Extension {
652    /// Extension version, follows semver.
653    pub version: Version,
654    /// Unique identifier for the extension.
655    pub name: ExtensionId,
656    /// Types defined by this extension.
657    types: BTreeMap<TypeName, TypeDef>,
658    /// Operation declarations with serializable definitions.
659    // Note: serde will serialize this because we configure with `features=["rc"]`.
660    // That will clone anything that has multiple references, but each
661    // OpDef should appear exactly once in this map (keyed by its name),
662    // and the other references to the OpDef are from ExternalOp's in the Hugr
663    // (which are serialized as OpaqueOp's i.e. Strings).
664    operations: BTreeMap<OpName, Arc<op_def::OpDef>>,
665}
666
667impl Extension {
668    /// Creates a new extension with the given name.
669    ///
670    /// In most cases extensions are contained inside an [`Arc`] so that they
671    /// can be shared across hugr instances and operation definitions.
672    ///
673    /// See [`Extension::new_arc`] for a more ergonomic way to create boxed
674    /// extensions.
675    #[must_use]
676    pub fn new(name: ExtensionId, version: Version) -> Self {
677        Self {
678            name,
679            version,
680            types: Default::default(),
681            operations: Default::default(),
682        }
683    }
684
685    /// Creates a new extension wrapped in an [`Arc`].
686    ///
687    /// The closure lets us use a weak reference to the arc while the extension
688    /// is being built. This is necessary for calling [`Extension::add_op`] and
689    /// [`Extension::add_type`].
690    pub fn new_arc(
691        name: ExtensionId,
692        version: Version,
693        init: impl FnOnce(&mut Extension, &Weak<Extension>),
694    ) -> Arc<Self> {
695        Arc::new_cyclic(|extension_ref| {
696            let mut ext = Self::new(name, version);
697            init(&mut ext, extension_ref);
698            ext
699        })
700    }
701
702    /// Creates a new extension wrapped in an [`Arc`], using a fallible
703    /// initialization function.
704    ///
705    /// The closure lets us use a weak reference to the arc while the extension
706    /// is being built. This is necessary for calling [`Extension::add_op`] and
707    /// [`Extension::add_type`].
708    pub fn try_new_arc<E>(
709        name: ExtensionId,
710        version: Version,
711        init: impl FnOnce(&mut Extension, &Weak<Extension>) -> Result<(), E>,
712    ) -> Result<Arc<Self>, E> {
713        // Annoying hack around not having `Arc::try_new_cyclic` that can return
714        // a Result.
715        // https://github.com/rust-lang/rust/issues/75861#issuecomment-980455381
716        //
717        // When there is an error, we store it in `error` and return it at the
718        // end instead of the partially-initialized extension.
719        let mut error = None;
720        let ext = Arc::new_cyclic(|extension_ref| {
721            let mut ext = Self::new(name, version);
722            match init(&mut ext, extension_ref) {
723                Ok(()) => ext,
724                Err(e) => {
725                    error = Some(e);
726                    ext
727                }
728            }
729        });
730        match error {
731            Some(e) => Err(e),
732            None => Ok(ext),
733        }
734    }
735
736    /// Allows read-only access to the operations in this Extension
737    #[must_use]
738    pub fn get_op(&self, name: &OpNameRef) -> Option<&Arc<op_def::OpDef>> {
739        self.operations.get(name)
740    }
741
742    /// Allows read-only access to the types in this Extension
743    #[must_use]
744    pub fn get_type(&self, type_name: &TypeNameRef) -> Option<&type_def::TypeDef> {
745        self.types.get(type_name)
746    }
747
748    /// Returns the name of the extension.
749    #[must_use]
750    pub fn name(&self) -> &ExtensionId {
751        &self.name
752    }
753
754    /// Returns the version of the extension.
755    #[must_use]
756    pub fn version(&self) -> &Version {
757        &self.version
758    }
759
760    /// Iterator over the operations of this [`Extension`].
761    pub fn operations(&self) -> impl Iterator<Item = (&OpName, &Arc<OpDef>)> {
762        self.operations.iter()
763    }
764
765    /// Iterator over the types of this [`Extension`].
766    pub fn types(&self) -> impl Iterator<Item = (&TypeName, &TypeDef)> {
767        self.types.iter()
768    }
769
770    /// Instantiate an [`ExtensionOp`] which references an [`OpDef`] in this extension.
771    pub fn instantiate_extension_op(
772        &self,
773        name: &OpNameRef,
774        args: impl Into<Vec<TypeArg>>,
775    ) -> Result<ExtensionOp, SignatureError> {
776        let op_def = self.get_op(name).expect("Op not found.");
777        ExtensionOp::new(op_def.clone(), args)
778    }
779
780    /// Validates the operation definitions in the register.
781    fn validate(&self) -> Result<(), SignatureError> {
782        // We should validate TypeParams of TypeDefs too - https://github.com/CQCL/hugr/issues/624
783        for op_def in self.operations.values() {
784            op_def.validate()?;
785        }
786        Ok(())
787    }
788}
789
790impl PartialEq for Extension {
791    fn eq(&self, other: &Self) -> bool {
792        self.name == other.name && self.version == other.version
793    }
794}
795
796/// An error that can occur in defining an extension registry.
797#[derive(Debug, Clone, Error, PartialEq, Eq)]
798#[non_exhaustive]
799pub enum ExtensionRegistryError {
800    /// Extension already defined.
801    #[error(
802        "The registry already contains an extension with id {0} and version {1}. New extension has version {2}."
803    )]
804    AlreadyRegistered(ExtensionId, Box<Version>, Box<Version>),
805    /// A registered extension has invalid signatures.
806    #[error("The extension {0} contains an invalid signature, {1}.")]
807    InvalidSignature(ExtensionId, #[source] SignatureError),
808}
809
810/// An error that can occur while loading an extension registry.
811#[derive(Debug, Error)]
812#[non_exhaustive]
813#[error("Extension registry load error")]
814pub enum ExtensionRegistryLoadError {
815    /// Deserialization error.
816    #[error(transparent)]
817    SerdeError(#[from] serde_json::Error),
818    /// Error when resolving internal extension references.
819    #[error(transparent)]
820    ExtensionResolutionError(Box<ExtensionResolutionError>),
821}
822
823impl From<ExtensionResolutionError> for ExtensionRegistryLoadError {
824    fn from(error: ExtensionResolutionError) -> Self {
825        Self::ExtensionResolutionError(Box::new(error))
826    }
827}
828
829/// An error that can occur in building a new extension.
830#[derive(Debug, Clone, Error, PartialEq, Eq)]
831#[non_exhaustive]
832pub enum ExtensionBuildError {
833    /// Existing [`OpDef`]
834    #[error("Extension already has an op called {0}.")]
835    OpDefExists(OpName),
836    /// Existing [`TypeDef`]
837    #[error("Extension already has an type called {0}.")]
838    TypeDefExists(TypeName),
839}
840
841/// A set of extensions identified by their unique [`ExtensionId`].
842#[derive(
843    Clone, Debug, Display, Default, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize,
844)]
845#[display("[{}]", _0.iter().join(", "))]
846pub struct ExtensionSet(BTreeSet<ExtensionId>);
847
848impl ExtensionSet {
849    /// Creates a new empty extension set.
850    #[must_use]
851    pub const fn new() -> Self {
852        Self(BTreeSet::new())
853    }
854
855    /// Adds a extension to the set.
856    pub fn insert(&mut self, extension: ExtensionId) {
857        self.0.insert(extension.clone());
858    }
859
860    /// Returns `true` if the set contains the given extension.
861    #[must_use]
862    pub fn contains(&self, extension: &ExtensionId) -> bool {
863        self.0.contains(extension)
864    }
865
866    /// Returns `true` if the set is a subset of `other`.
867    #[must_use]
868    pub fn is_subset(&self, other: &Self) -> bool {
869        self.0.is_subset(&other.0)
870    }
871
872    /// Returns `true` if the set is a superset of `other`.
873    #[must_use]
874    pub fn is_superset(&self, other: &Self) -> bool {
875        self.0.is_superset(&other.0)
876    }
877
878    /// Create a extension set with a single element.
879    #[must_use]
880    pub fn singleton(extension: ExtensionId) -> Self {
881        let mut set = Self::new();
882        set.insert(extension);
883        set
884    }
885
886    /// Returns the union of two extension sets.
887    #[must_use]
888    pub fn union(mut self, other: Self) -> Self {
889        self.0.extend(other.0);
890        self
891    }
892
893    /// Returns the union of an arbitrary collection of [`ExtensionSet`]s
894    pub fn union_over(sets: impl IntoIterator<Item = Self>) -> Self {
895        // `union` clones the receiver, which we do not need to do here
896        let mut res = ExtensionSet::new();
897        for s in sets {
898            res.0.extend(s.0);
899        }
900        res
901    }
902
903    /// The things in other which are in not in self
904    #[must_use]
905    pub fn missing_from(&self, other: &Self) -> Self {
906        ExtensionSet::from_iter(other.0.difference(&self.0).cloned())
907    }
908
909    /// Iterate over the contained `ExtensionIds`
910    pub fn iter(&self) -> impl Iterator<Item = &ExtensionId> {
911        self.0.iter()
912    }
913
914    /// True if this set contains no [`ExtensionId`]s
915    #[must_use]
916    pub fn is_empty(&self) -> bool {
917        self.0.is_empty()
918    }
919}
920
921impl From<ExtensionId> for ExtensionSet {
922    fn from(id: ExtensionId) -> Self {
923        Self::singleton(id)
924    }
925}
926
927impl IntoIterator for ExtensionSet {
928    type Item = ExtensionId;
929    type IntoIter = std::collections::btree_set::IntoIter<ExtensionId>;
930
931    fn into_iter(self) -> Self::IntoIter {
932        self.0.into_iter()
933    }
934}
935
936impl<'a> IntoIterator for &'a ExtensionSet {
937    type Item = &'a ExtensionId;
938    type IntoIter = std::collections::btree_set::Iter<'a, ExtensionId>;
939
940    fn into_iter(self) -> Self::IntoIter {
941        self.0.iter()
942    }
943}
944
945impl FromIterator<ExtensionId> for ExtensionSet {
946    fn from_iter<I: IntoIterator<Item = ExtensionId>>(iter: I) -> Self {
947        Self(BTreeSet::from_iter(iter))
948    }
949}
950
951/// Extension tests.
952#[cfg(test)]
953pub mod test {
954    // We re-export this here because mod op_def is private.
955    pub use super::op_def::test::SimpleOpDef;
956
957    use super::*;
958
959    impl Extension {
960        /// Create a new extension for testing, with a 0 version.
961        pub(crate) fn new_test_arc(
962            name: ExtensionId,
963            init: impl FnOnce(&mut Extension, &Weak<Extension>),
964        ) -> Arc<Self> {
965            Self::new_arc(name, Version::new(0, 0, 0), init)
966        }
967        /// Create a new extension for testing, with a 0 version.
968        pub(crate) fn try_new_test_arc(
969            name: ExtensionId,
970            init: impl FnOnce(
971                &mut Extension,
972                &Weak<Extension>,
973            ) -> Result<(), Box<dyn std::error::Error>>,
974        ) -> Result<Arc<Self>, Box<dyn std::error::Error>> {
975            Self::try_new_arc(name, Version::new(0, 0, 0), init)
976        }
977    }
978
979    #[test]
980    fn test_register_update() {
981        // Two registers that should remain the same.
982        // We use them to test both `register_updated` and `register_updated_ref`.
983        let mut reg = ExtensionRegistry::default();
984        let mut reg_ref = ExtensionRegistry::default();
985
986        let ext_1_id = ExtensionId::new("ext1").unwrap();
987        let ext_2_id = ExtensionId::new("ext2").unwrap();
988        let ext1 = Arc::new(Extension::new(ext_1_id.clone(), Version::new(1, 0, 0)));
989        let ext1_1 = Arc::new(Extension::new(ext_1_id.clone(), Version::new(1, 1, 0)));
990        let ext1_2 = Arc::new(Extension::new(ext_1_id.clone(), Version::new(0, 2, 0)));
991        let ext2 = Arc::new(Extension::new(ext_2_id, Version::new(1, 0, 0)));
992
993        reg.register(ext1.clone()).unwrap();
994        reg_ref.register(ext1.clone()).unwrap();
995        assert_eq!(&reg, &reg_ref);
996
997        // normal registration fails
998        assert_eq!(
999            reg.register(ext1_1.clone()),
1000            Err(ExtensionRegistryError::AlreadyRegistered(
1001                ext_1_id.clone(),
1002                Box::new(Version::new(1, 0, 0)),
1003                Box::new(Version::new(1, 1, 0))
1004            ))
1005        );
1006
1007        // register with update works
1008        reg_ref.register_updated_ref(&ext1_1);
1009        reg.register_updated(ext1_1.clone());
1010        assert_eq!(reg.get("ext1").unwrap().version(), &Version::new(1, 1, 0));
1011        assert_eq!(&reg, &reg_ref);
1012
1013        // register with lower version does not change version
1014        reg_ref.register_updated_ref(&ext1_2);
1015        reg.register_updated(ext1_2.clone());
1016        assert_eq!(reg.get("ext1").unwrap().version(), &Version::new(1, 1, 0));
1017        assert_eq!(&reg, &reg_ref);
1018
1019        reg.register(ext2.clone()).unwrap();
1020        assert_eq!(reg.get("ext2").unwrap().version(), &Version::new(1, 0, 0));
1021        assert_eq!(reg.len(), 2);
1022
1023        assert!(reg.remove_extension(&ext_1_id).unwrap().version() == &Version::new(1, 1, 0));
1024        assert_eq!(reg.len(), 1);
1025    }
1026
1027    mod proptest {
1028
1029        use ::proptest::{collection::hash_set, prelude::*};
1030
1031        use super::super::{ExtensionId, ExtensionSet};
1032
1033        impl Arbitrary for ExtensionSet {
1034            type Parameters = ();
1035            type Strategy = BoxedStrategy<Self>;
1036
1037            fn arbitrary_with((): Self::Parameters) -> Self::Strategy {
1038                hash_set(any::<ExtensionId>(), 0..3)
1039                    .prop_map(|extensions| extensions.into_iter().collect::<ExtensionSet>())
1040                    .boxed()
1041            }
1042        }
1043    }
1044}