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!(®, ®_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!(®, ®_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!(®, ®_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}