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 {}