hugr_core/std_extensions/collections/
value_array.rs

1//! A version of the standard fixed-length array extension where arrays of copyable types
2//! are copyable themselves.
3//!
4//! Supports all regular array operations apart from `clone` and `discard`.
5
6use std::sync::Arc;
7
8use delegate::delegate;
9use lazy_static::lazy_static;
10
11use crate::builder::{BuildError, Dataflow};
12use crate::extension::resolution::{ExtensionResolutionError, WeakExtensionRegistry};
13use crate::extension::simple_op::{HasConcrete, MakeOpDef};
14use crate::extension::{ExtensionId, SignatureError, TypeDef, TypeDefBound};
15use crate::ops::constant::{CustomConst, ValueName};
16use crate::types::type_param::{TypeArg, TypeParam};
17use crate::types::{CustomCheckFailure, Type, TypeBound, TypeName};
18use crate::{Extension, Wire};
19
20use super::array::op_builder::GenericArrayOpBuilder;
21use super::array::{
22    Array, ArrayKind, FROM, GenericArrayConvert, GenericArrayConvertDef, GenericArrayOp,
23    GenericArrayOpDef, GenericArrayRepeat, GenericArrayRepeatDef, GenericArrayScan,
24    GenericArrayScanDef, GenericArrayValue, INTO,
25};
26
27/// Reported unique name of the value array type.
28pub const VALUE_ARRAY_TYPENAME: TypeName = TypeName::new_inline("value_array");
29/// Reported unique name of the value array value.
30pub const VALUE_ARRAY_VALUENAME: TypeName = TypeName::new_inline("value_array");
31/// Reported unique name of the extension
32pub const EXTENSION_ID: ExtensionId = ExtensionId::new_static_unchecked("collections.value_array");
33/// Extension version.
34pub const VERSION: semver::Version = semver::Version::new(0, 1, 1);
35
36/// A fixed-length collection of values.
37///
38/// A value array inherits its linearity from its elements.
39#[derive(Clone, Copy, Debug, derive_more::Display, Eq, PartialEq, Default)]
40pub struct ValueArray;
41
42impl ArrayKind for ValueArray {
43    const EXTENSION_ID: ExtensionId = EXTENSION_ID;
44    const TYPE_NAME: TypeName = VALUE_ARRAY_TYPENAME;
45    const VALUE_NAME: ValueName = VALUE_ARRAY_VALUENAME;
46
47    fn extension() -> &'static Arc<Extension> {
48        &EXTENSION
49    }
50
51    fn type_def() -> &'static TypeDef {
52        EXTENSION.get_type(&VALUE_ARRAY_TYPENAME).unwrap()
53    }
54
55    fn build_clone<D: Dataflow>(
56        _builder: &mut D,
57        _elem_ty: Type,
58        _size: u64,
59        arr: Wire,
60    ) -> Result<(Wire, Wire), BuildError> {
61        Ok((arr, arr))
62    }
63
64    fn build_discard<D: Dataflow>(
65        _builder: &mut D,
66        _elem_ty: Type,
67        _size: u64,
68        _arr: Wire,
69    ) -> Result<(), BuildError> {
70        Ok(())
71    }
72}
73
74/// Value array operation definitions.
75pub type VArrayOpDef = GenericArrayOpDef<ValueArray>;
76/// Value array repeat operation definition.
77pub type VArrayRepeatDef = GenericArrayRepeatDef<ValueArray>;
78/// Value array scan operation definition.
79pub type VArrayScanDef = GenericArrayScanDef<ValueArray>;
80/// Value array to default array conversion operation definition.
81pub type VArrayToArrayDef = GenericArrayConvertDef<ValueArray, INTO, Array>;
82/// Value array from default array conversion operation definition.
83pub type VArrayFromArrayDef = GenericArrayConvertDef<ValueArray, FROM, Array>;
84
85/// Value array operations.
86pub type VArrayOp = GenericArrayOp<ValueArray>;
87/// The value array repeat operation.
88pub type VArrayRepeat = GenericArrayRepeat<ValueArray>;
89/// The value array scan operation.
90pub type VArrayScan = GenericArrayScan<ValueArray>;
91/// The value array to default array conversion operation.
92pub type VArrayToArray = GenericArrayConvert<ValueArray, INTO, Array>;
93/// The value array from default array conversion operation.
94pub type VArrayFromArray = GenericArrayConvert<ValueArray, FROM, Array>;
95
96/// A value array extension value.
97pub type VArrayValue = GenericArrayValue<ValueArray>;
98
99lazy_static! {
100    /// Extension for value array operations.
101    pub static ref EXTENSION: Arc<Extension> = {
102        Extension::new_arc(EXTENSION_ID, VERSION, |extension, extension_ref| {
103            extension.add_type(
104                    VALUE_ARRAY_TYPENAME,
105                    vec![ TypeParam::max_nat_type(), TypeBound::Linear.into()],
106                    "Fixed-length value array".into(),
107                    // Value arrays are copyable iff their elements are
108                    TypeDefBound::from_params(vec![1]),
109                    extension_ref,
110                )
111                .unwrap();
112
113            VArrayOpDef::load_all_ops(extension, extension_ref).unwrap();
114            VArrayRepeatDef::new().add_to_extension(extension, extension_ref).unwrap();
115            VArrayScanDef::new().add_to_extension(extension, extension_ref).unwrap();
116            VArrayToArrayDef::new().add_to_extension(extension, extension_ref).unwrap();
117            VArrayFromArrayDef::new().add_to_extension(extension, extension_ref).unwrap();
118        })
119    };
120}
121
122#[typetag::serde(name = "VArrayValue")]
123impl CustomConst for VArrayValue {
124    delegate! {
125        to self {
126            fn name(&self) -> ValueName;
127            fn validate(&self) -> Result<(), CustomCheckFailure>;
128            fn update_extensions(
129                &mut self,
130                extensions: &WeakExtensionRegistry,
131            ) -> Result<(), ExtensionResolutionError>;
132            fn get_type(&self) -> Type;
133        }
134    }
135
136    fn equal_consts(&self, other: &dyn CustomConst) -> bool {
137        crate::ops::constant::downcast_equal_consts(self, other)
138    }
139}
140
141/// Gets the [`TypeDef`] for value arrays. Note that instantiations are more easily
142/// created via [`value_array_type`] and [`value_array_type_parametric`]
143#[must_use]
144pub fn value_array_type_def() -> &'static TypeDef {
145    ValueArray::type_def()
146}
147
148/// Instantiate a new value array type given a size argument and element type.
149///
150/// This method is equivalent to [`value_array_type_parametric`], but uses concrete
151/// arguments types to ensure no errors are possible.
152#[must_use]
153pub fn value_array_type(size: u64, element_ty: Type) -> Type {
154    ValueArray::ty(size, element_ty)
155}
156
157/// Instantiate a new value array type given the size and element type parameters.
158///
159/// This is a generic version of [`value_array_type`].
160pub fn value_array_type_parametric(
161    size: impl Into<TypeArg>,
162    element_ty: impl Into<TypeArg>,
163) -> Result<Type, SignatureError> {
164    ValueArray::ty_parametric(size, element_ty)
165}
166
167/// Trait for building value array operations in a dataflow graph.
168pub trait VArrayOpBuilder: GenericArrayOpBuilder {
169    /// Adds a new array operation to the dataflow graph and return the wire
170    /// representing the new array.
171    ///
172    /// # Arguments
173    ///
174    /// * `elem_ty` - The type of the elements in the array.
175    /// * `values` - An iterator over the values to initialize the array with.
176    ///
177    /// # Errors
178    ///
179    /// If building the operation fails.
180    ///
181    /// # Returns
182    ///
183    /// The wire representing the new array.
184    fn add_new_value_array(
185        &mut self,
186        elem_ty: Type,
187        values: impl IntoIterator<Item = Wire>,
188    ) -> Result<Wire, BuildError> {
189        self.add_new_generic_array::<ValueArray>(elem_ty, values)
190    }
191
192    /// Adds an array get operation to the dataflow graph.
193    ///
194    /// # Arguments
195    ///
196    /// * `elem_ty` - The type of the elements in the array.
197    /// * `size` - The size of the array.
198    /// * `input` - The wire representing the array.
199    /// * `index` - The wire representing the index to get.
200    ///
201    /// # Errors
202    ///
203    /// If building the operation fails.
204    ///
205    /// # Returns
206    ///
207    /// * The wire representing the value at the specified index in the array
208    /// * The wire representing the array
209    fn add_value_array_get(
210        &mut self,
211        elem_ty: Type,
212        size: u64,
213        input: Wire,
214        index: Wire,
215    ) -> Result<(Wire, Wire), BuildError> {
216        self.add_generic_array_get::<ValueArray>(elem_ty, size, input, index)
217    }
218
219    /// Adds an array set operation to the dataflow graph.
220    ///
221    /// This operation sets the value at a specified index in the array.
222    ///
223    /// # Arguments
224    ///
225    /// * `elem_ty` - The type of the elements in the array.
226    /// * `size` - The size of the array.
227    /// * `input` - The wire representing the array.
228    /// * `index` - The wire representing the index to set.
229    /// * `value` - The wire representing the value to set at the specified index.
230    ///
231    /// # Errors
232    ///
233    /// Returns an error if building the operation fails.
234    ///
235    /// # Returns
236    ///
237    /// The wire representing the updated array after the set operation.
238    fn add_value_array_set(
239        &mut self,
240        elem_ty: Type,
241        size: u64,
242        input: Wire,
243        index: Wire,
244        value: Wire,
245    ) -> Result<Wire, BuildError> {
246        self.add_generic_array_set::<ValueArray>(elem_ty, size, input, index, value)
247    }
248
249    /// Adds an array swap operation to the dataflow graph.
250    ///
251    /// This operation swaps the values at two specified indices in the array.
252    ///
253    /// # Arguments
254    ///
255    /// * `elem_ty` - The type of the elements in the array.
256    /// * `size` - The size of the array.
257    /// * `input` - The wire representing the array.
258    /// * `index1` - The wire representing the first index to swap.
259    /// * `index2` - The wire representing the second index to swap.
260    ///
261    /// # Errors
262    ///
263    /// Returns an error if building the operation fails.
264    ///
265    /// # Returns
266    ///
267    /// The wire representing the updated array after the swap operation.
268    fn add_value_array_swap(
269        &mut self,
270        elem_ty: Type,
271        size: u64,
272        input: Wire,
273        index1: Wire,
274        index2: Wire,
275    ) -> Result<Wire, BuildError> {
276        let op =
277            GenericArrayOpDef::<ValueArray>::swap.instantiate(&[size.into(), elem_ty.into()])?;
278        let [out] = self
279            .add_dataflow_op(op, vec![input, index1, index2])?
280            .outputs_arr();
281        Ok(out)
282    }
283
284    /// Adds an array pop-left operation to the dataflow graph.
285    ///
286    /// This operation removes the leftmost element from the array.
287    ///
288    /// # Arguments
289    ///
290    /// * `elem_ty` - The type of the elements in the array.
291    /// * `size` - The size of the array.
292    /// * `input` - The wire representing the array.
293    ///
294    /// # Errors
295    ///
296    /// Returns an error if building the operation fails.
297    ///
298    /// # Returns
299    ///
300    /// The wire representing the Option<elemty, array<SIZE-1, elemty>>
301    fn add_array_pop_left(
302        &mut self,
303        elem_ty: Type,
304        size: u64,
305        input: Wire,
306    ) -> Result<Wire, BuildError> {
307        self.add_generic_array_pop_left::<ValueArray>(elem_ty, size, input)
308    }
309
310    /// Adds an array pop-right operation to the dataflow graph.
311    ///
312    /// This operation removes the rightmost element from the array.
313    ///
314    /// # Arguments
315    ///
316    /// * `elem_ty` - The type of the elements in the array.
317    /// * `size` - The size of the array.
318    /// * `input` - The wire representing the array.
319    ///
320    /// # Errors
321    ///
322    /// Returns an error if building the operation fails.
323    ///
324    /// # Returns
325    ///
326    /// The wire representing the Option<elemty, array<SIZE-1, elemty>>
327    fn add_array_pop_right(
328        &mut self,
329        elem_ty: Type,
330        size: u64,
331        input: Wire,
332    ) -> Result<Wire, BuildError> {
333        self.add_generic_array_pop_right::<ValueArray>(elem_ty, size, input)
334    }
335
336    /// Adds an operation to discard an empty array from the dataflow graph.
337    ///
338    /// # Arguments
339    ///
340    /// * `elem_ty` - The type of the elements in the array.
341    /// * `input` - The wire representing the array.
342    ///
343    /// # Errors
344    ///
345    /// Returns an error if building the operation fails.
346    fn add_array_discard_empty(&mut self, elem_ty: Type, input: Wire) -> Result<(), BuildError> {
347        self.add_generic_array_discard_empty::<ValueArray>(elem_ty, input)
348    }
349}
350
351impl<D: Dataflow> VArrayOpBuilder for D {}