diff --git a/hugr-core/src/std_extensions.rs b/hugr-core/src/std_extensions.rs index 1d49ea4e1e..d57663391d 100644 --- a/hugr-core/src/std_extensions.rs +++ b/hugr-core/src/std_extensions.rs @@ -21,6 +21,7 @@ pub fn std_reg() -> ExtensionRegistry { arithmetic::float_types::EXTENSION.to_owned(), collections::array::EXTENSION.to_owned(), collections::list::EXTENSION.to_owned(), + collections::borrow_array::EXTENSION.to_owned(), collections::static_array::EXTENSION.to_owned(), collections::value_array::EXTENSION.to_owned(), logic::EXTENSION.to_owned(), diff --git a/hugr-core/src/std_extensions/collections.rs b/hugr-core/src/std_extensions/collections.rs index efd53c805e..0c52ad94d6 100644 --- a/hugr-core/src/std_extensions/collections.rs +++ b/hugr-core/src/std_extensions/collections.rs @@ -1,6 +1,7 @@ //! List type and operations. pub mod array; +pub mod borrow_array; pub mod list; pub mod static_array; pub mod value_array; diff --git a/hugr-core/src/std_extensions/collections/array.rs b/hugr-core/src/std_extensions/collections/array.rs index 01e0ca73a6..06e4ae8b3b 100644 --- a/hugr-core/src/std_extensions/collections/array.rs +++ b/hugr-core/src/std_extensions/collections/array.rs @@ -223,7 +223,7 @@ pub trait ArrayOpBuilder: GenericArrayOpBuilder { self.add_generic_array_unpack::(elem_ty, size, input) } /// Adds an array clone operation to the dataflow graph and return the wires - /// representing the originala and cloned array. + /// representing the original and cloned array. /// /// # Arguments /// diff --git a/hugr-core/src/std_extensions/collections/array/array_clone.rs b/hugr-core/src/std_extensions/collections/array/array_clone.rs index d522142a5b..2575a32c26 100644 --- a/hugr-core/src/std_extensions/collections/array/array_clone.rs +++ b/hugr-core/src/std_extensions/collections/array/array_clone.rs @@ -194,6 +194,7 @@ mod tests { use crate::extension::prelude::bool_t; use crate::std_extensions::collections::array::Array; + use crate::std_extensions::collections::borrow_array::BorrowArray; use crate::{ extension::prelude::qb_t, ops::{OpTrait, OpType}, @@ -203,6 +204,7 @@ mod tests { #[rstest] #[case(Array)] + #[case(BorrowArray)] fn test_clone_def(#[case] _kind: AK) { let op = GenericArrayClone::::new(bool_t(), 2).unwrap(); let optype: OpType = op.clone().into(); @@ -217,6 +219,7 @@ mod tests { #[rstest] #[case(Array)] + #[case(BorrowArray)] fn test_clone(#[case] _kind: AK) { let size = 2; let element_ty = bool_t(); diff --git a/hugr-core/src/std_extensions/collections/array/array_conversion.rs b/hugr-core/src/std_extensions/collections/array/array_conversion.rs index bbb79336a2..b7cbeb4ba7 100644 --- a/hugr-core/src/std_extensions/collections/array/array_conversion.rs +++ b/hugr-core/src/std_extensions/collections/array/array_conversion.rs @@ -246,12 +246,14 @@ mod tests { use crate::extension::prelude::bool_t; use crate::ops::{OpTrait, OpType}; use crate::std_extensions::collections::array::Array; + use crate::std_extensions::collections::borrow_array::BorrowArray; use crate::std_extensions::collections::value_array::ValueArray; use super::*; #[rstest] #[case(ValueArray, Array)] + #[case(BorrowArray, Array)] fn test_convert_from_def( #[case] _kind: AK, #[case] _other_kind: OtherAK, @@ -264,6 +266,7 @@ mod tests { #[rstest] #[case(ValueArray, Array)] + #[case(BorrowArray, Array)] fn test_convert_into_def( #[case] _kind: AK, #[case] _other_kind: OtherAK, @@ -276,6 +279,7 @@ mod tests { #[rstest] #[case(ValueArray, Array)] + #[case(BorrowArray, Array)] fn test_convert_from( #[case] _kind: AK, #[case] _other_kind: OtherAK, @@ -296,6 +300,7 @@ mod tests { #[rstest] #[case(ValueArray, Array)] + #[case(BorrowArray, Array)] fn test_convert_into( #[case] _kind: AK, #[case] _other_kind: OtherAK, diff --git a/hugr-core/src/std_extensions/collections/array/array_discard.rs b/hugr-core/src/std_extensions/collections/array/array_discard.rs index a97ac35eaa..7e7a6599e0 100644 --- a/hugr-core/src/std_extensions/collections/array/array_discard.rs +++ b/hugr-core/src/std_extensions/collections/array/array_discard.rs @@ -178,6 +178,7 @@ mod tests { use crate::extension::prelude::bool_t; use crate::std_extensions::collections::array::Array; + use crate::std_extensions::collections::borrow_array::BorrowArray; use crate::{ extension::prelude::qb_t, ops::{OpTrait, OpType}, @@ -187,6 +188,7 @@ mod tests { #[rstest] #[case(Array)] + #[case(BorrowArray)] fn test_discard_def(#[case] _kind: AK) { let op = GenericArrayDiscard::::new(bool_t(), 2).unwrap(); let optype: OpType = op.clone().into(); @@ -198,6 +200,7 @@ mod tests { #[rstest] #[case(Array)] + #[case(BorrowArray)] fn test_discard(#[case] _kind: AK) { let size = 2; let element_ty = bool_t(); diff --git a/hugr-core/src/std_extensions/collections/array/array_op.rs b/hugr-core/src/std_extensions/collections/array/array_op.rs index deaac6eb58..3ce2308f1a 100644 --- a/hugr-core/src/std_extensions/collections/array/array_op.rs +++ b/hugr-core/src/std_extensions/collections/array/array_op.rs @@ -339,6 +339,7 @@ mod tests { use crate::extension::prelude::usize_t; use crate::std_extensions::arithmetic::float_types::float64_type; use crate::std_extensions::collections::array::Array; + use crate::std_extensions::collections::borrow_array::BorrowArray; use crate::std_extensions::collections::value_array::ValueArray; use crate::{ builder::{DFGBuilder, Dataflow, DataflowHugr, inout_sig}, @@ -351,6 +352,7 @@ mod tests { #[rstest] #[case(Array)] #[case(ValueArray)] + #[case(BorrowArray)] fn test_array_ops(#[case] _kind: AK) { for def in GenericArrayOpDef::::iter() { let ty = if def == GenericArrayOpDef::get { @@ -373,6 +375,7 @@ mod tests { #[rstest] #[case(Array)] #[case(ValueArray)] + #[case(BorrowArray)] /// Test building a HUGR involving a new_array operation. fn test_new_array(#[case] _kind: AK) { let mut b = DFGBuilder::new(inout_sig(vec![qb_t(), qb_t()], AK::ty(2, qb_t()))).unwrap(); @@ -389,6 +392,7 @@ mod tests { #[rstest] #[case(Array)] #[case(ValueArray)] + #[case(BorrowArray)] /// Test building a HUGR involving an unpack operation. fn test_unpack(#[case] _kind: AK) { let mut b = DFGBuilder::new(inout_sig(AK::ty(2, qb_t()), vec![qb_t(), qb_t()])).unwrap(); @@ -405,6 +409,7 @@ mod tests { #[rstest] #[case(Array)] #[case(ValueArray)] + #[case(BorrowArray)] fn test_get(#[case] _kind: AK) { let size = 2; let element_ty = bool_t(); @@ -430,6 +435,7 @@ mod tests { #[rstest] #[case(Array)] #[case(ValueArray)] + #[case(BorrowArray)] fn test_set(#[case] _kind: AK) { let size = 2; let element_ty = bool_t(); @@ -452,6 +458,7 @@ mod tests { #[rstest] #[case(Array)] #[case(ValueArray)] + #[case(BorrowArray)] fn test_swap(#[case] _kind: AK) { let size = 2; let element_ty = bool_t(); @@ -473,6 +480,7 @@ mod tests { #[rstest] #[case(Array)] #[case(ValueArray)] + #[case(BorrowArray)] fn test_pops(#[case] _kind: AK) { let size = 2; let element_ty = bool_t(); @@ -505,6 +513,7 @@ mod tests { #[rstest] #[case(Array)] #[case(ValueArray)] + #[case(BorrowArray)] fn test_discard_empty(#[case] _kind: AK) { let size = 0; let element_ty = bool_t(); @@ -523,6 +532,7 @@ mod tests { #[rstest] #[case(Array)] #[case(ValueArray)] + #[case(BorrowArray)] /// Initialize an array operation where the element type is not from the prelude. fn test_non_prelude_op(#[case] _kind: AK) { let size = 2; diff --git a/hugr-core/src/std_extensions/collections/array/array_repeat.rs b/hugr-core/src/std_extensions/collections/array/array_repeat.rs index b1b84e3521..d2428ff3e0 100644 --- a/hugr-core/src/std_extensions/collections/array/array_repeat.rs +++ b/hugr-core/src/std_extensions/collections/array/array_repeat.rs @@ -183,6 +183,7 @@ mod tests { use rstest::rstest; use crate::std_extensions::collections::array::Array; + use crate::std_extensions::collections::borrow_array::BorrowArray; use crate::std_extensions::collections::value_array::ValueArray; use crate::{ extension::prelude::qb_t, @@ -195,6 +196,7 @@ mod tests { #[rstest] #[case(Array)] #[case(ValueArray)] + #[case(BorrowArray)] fn test_repeat_def(#[case] _kind: AK) { let op = GenericArrayRepeat::::new(qb_t(), 2); let optype: OpType = op.clone().into(); @@ -205,6 +207,7 @@ mod tests { #[rstest] #[case(Array)] #[case(ValueArray)] + #[case(BorrowArray)] fn test_repeat(#[case] _kind: AK) { let size = 2; let element_ty = qb_t(); diff --git a/hugr-core/src/std_extensions/collections/array/array_scan.rs b/hugr-core/src/std_extensions/collections/array/array_scan.rs index de39db3175..ce9c2369d5 100644 --- a/hugr-core/src/std_extensions/collections/array/array_scan.rs +++ b/hugr-core/src/std_extensions/collections/array/array_scan.rs @@ -243,6 +243,7 @@ mod tests { use crate::extension::prelude::usize_t; use crate::std_extensions::collections::array::Array; + use crate::std_extensions::collections::borrow_array::BorrowArray; use crate::std_extensions::collections::value_array::ValueArray; use crate::{ extension::prelude::{bool_t, qb_t}, @@ -255,6 +256,7 @@ mod tests { #[rstest] #[case(Array)] #[case(ValueArray)] + #[case(BorrowArray)] fn test_scan_def(#[case] _kind: AK) { let op = GenericArrayScan::::new(bool_t(), qb_t(), vec![usize_t()], 2); let optype: OpType = op.clone().into(); @@ -265,6 +267,7 @@ mod tests { #[rstest] #[case(Array)] #[case(ValueArray)] + #[case(BorrowArray)] fn test_scan_map(#[case] _kind: AK) { let size = 2; let src_ty = qb_t(); @@ -290,6 +293,7 @@ mod tests { #[rstest] #[case(Array)] #[case(ValueArray)] + #[case(BorrowArray)] fn test_scan_accs(#[case] _kind: AK) { let size = 2; let src_ty = qb_t(); diff --git a/hugr-core/src/std_extensions/collections/array/array_value.rs b/hugr-core/src/std_extensions/collections/array/array_value.rs index dfe0d0a9f2..916f218739 100644 --- a/hugr-core/src/std_extensions/collections/array/array_value.rs +++ b/hugr-core/src/std_extensions/collections/array/array_value.rs @@ -146,6 +146,7 @@ mod test { use crate::std_extensions::arithmetic::float_types::ConstF64; use crate::std_extensions::collections::array::Array; + use crate::std_extensions::collections::borrow_array::BorrowArray; use crate::std_extensions::collections::value_array::ValueArray; use super::*; @@ -153,6 +154,7 @@ mod test { #[rstest] #[case(Array)] #[case(ValueArray)] + #[case(BorrowArray)] fn test_array_value(#[case] _kind: AK) { let array_value = GenericArrayValue::::new(usize_t(), vec![ConstUsize::new(3).into()]); array_value.validate().unwrap(); diff --git a/hugr-core/src/std_extensions/collections/array/op_builder.rs b/hugr-core/src/std_extensions/collections/array/op_builder.rs index 2740673f80..b408e1a3de 100644 --- a/hugr-core/src/std_extensions/collections/array/op_builder.rs +++ b/hugr-core/src/std_extensions/collections/array/op_builder.rs @@ -1,6 +1,7 @@ //! Builder trait for array operations in the dataflow graph. use crate::std_extensions::collections::array::GenericArrayOpDef; +use crate::std_extensions::collections::borrow_array::BorrowArray; use crate::std_extensions::collections::value_array::ValueArray; use crate::{ Wire, @@ -390,6 +391,11 @@ pub fn build_all_value_array_ops(builder: B) -> B { build_all_array_ops_generic::(builder) } +/// Helper function to build a Hugr that contains all basic array operations. +pub fn build_all_borrow_array_ops(builder: B) -> B { + build_all_array_ops_generic::(builder) +} + /// Testing utilities to generate Hugrs that contain array operations. #[cfg(test)] mod test { @@ -411,4 +417,11 @@ mod test { let builder = DFGBuilder::new(sig).unwrap(); build_all_value_array_ops(builder).finish_hugr().unwrap(); } + + #[test] + fn all_borrow_array_ops() { + let sig = Signature::new_endo(Type::EMPTY_TYPEROW); + let builder = DFGBuilder::new(sig).unwrap(); + build_all_borrow_array_ops(builder).finish_hugr().unwrap(); + } } diff --git a/hugr-core/src/std_extensions/collections/borrow_array.rs b/hugr-core/src/std_extensions/collections/borrow_array.rs new file mode 100644 index 0000000000..da7fc47559 --- /dev/null +++ b/hugr-core/src/std_extensions/collections/borrow_array.rs @@ -0,0 +1,797 @@ +//! A version of the standard fixed-length array extension that includes unsafe +//! operations for borrowing and returning that may panic. + +use std::sync::{self, Arc}; + +use delegate::delegate; +use lazy_static::lazy_static; + +use crate::extension::{ExtensionId, SignatureError, TypeDef, TypeDefBound}; +use crate::ops::constant::{CustomConst, ValueName}; +use crate::type_row; +use crate::types::type_param::{TypeArg, TypeParam}; +use crate::types::{CustomCheckFailure, Term, Type, TypeBound, TypeName}; +use crate::{Extension, Wire}; +use crate::{ + builder::{BuildError, Dataflow}, + extension::SignatureFunc, +}; +use crate::{ + extension::simple_op::{HasConcrete, HasDef, MakeExtensionOp, MakeOpDef, MakeRegisteredOp}, + ops::ExtensionOp, +}; +use crate::{ + extension::{ + OpDef, + prelude::usize_t, + resolution::{ExtensionResolutionError, WeakExtensionRegistry}, + simple_op::{OpLoadError, try_from_name}, + }, + ops::OpName, + types::{FuncValueType, PolyFuncTypeRV}, +}; + +use super::array::op_builder::GenericArrayOpBuilder; +use super::array::{ + Array, ArrayKind, FROM, GenericArrayClone, GenericArrayCloneDef, GenericArrayConvert, + GenericArrayConvertDef, GenericArrayDiscard, GenericArrayDiscardDef, GenericArrayOp, + GenericArrayOpDef, GenericArrayRepeat, GenericArrayRepeatDef, GenericArrayScan, + GenericArrayScanDef, GenericArrayValue, INTO, +}; + +/// Reported unique name of the borrow array type. +pub const BORROW_ARRAY_TYPENAME: TypeName = TypeName::new_inline("borrow_array"); +/// Reported unique name of the borrow array value. +pub const BORROW_ARRAY_VALUENAME: TypeName = TypeName::new_inline("borrow_array"); +/// Reported unique name of the extension +pub const EXTENSION_ID: ExtensionId = ExtensionId::new_unchecked("collections.borrow_arr"); +/// Extension version. +pub const VERSION: semver::Version = semver::Version::new(0, 1, 1); + +/// A linear, unsafe, fixed-length collection of values. +/// +/// Borrow arrays are linear, even if their elements are copyable. +#[derive(Clone, Copy, Debug, derive_more::Display, Eq, PartialEq, Default)] +pub struct BorrowArray; + +impl ArrayKind for BorrowArray { + const EXTENSION_ID: ExtensionId = EXTENSION_ID; + const TYPE_NAME: TypeName = BORROW_ARRAY_TYPENAME; + const VALUE_NAME: ValueName = BORROW_ARRAY_VALUENAME; + + fn extension() -> &'static Arc { + &EXTENSION + } + + fn type_def() -> &'static TypeDef { + EXTENSION.get_type(&BORROW_ARRAY_TYPENAME).unwrap() + } +} + +/// Borrow array operation definitions. +pub type BArrayOpDef = GenericArrayOpDef; +/// Borrow array clone operation definition. +pub type BArrayCloneDef = GenericArrayCloneDef; +/// Borrow array discard operation definition. +pub type BArrayDiscardDef = GenericArrayDiscardDef; +/// Borrow array repeat operation definition. +pub type BArrayRepeatDef = GenericArrayRepeatDef; +/// Borrow array scan operation definition. +pub type BArrayScanDef = GenericArrayScanDef; +/// Borrow array to default array conversion operation definition. +pub type BArrayToArrayDef = GenericArrayConvertDef; +/// Borrow array from default array conversion operation definition. +pub type BArrayFromArrayDef = GenericArrayConvertDef; + +/// Borrow array operations. +pub type BArrayOp = GenericArrayOp; +/// The borrow array clone operation. +pub type BArrayClone = GenericArrayClone; +/// The borrow array discard operation. +pub type BArrayDiscard = GenericArrayDiscard; +/// The borrow array repeat operation. +pub type BArrayRepeat = GenericArrayRepeat; +/// The borrow array scan operation. +pub type BArrayScan = GenericArrayScan; +/// The borrow array to default array conversion operation. +pub type BArrayToArray = GenericArrayConvert; +/// The borrow array from default array conversion operation. +pub type BArrayFromArray = GenericArrayConvert; + +/// A borrow array extension value. +pub type BArrayValue = GenericArrayValue; + +#[derive( + Clone, + Copy, + Debug, + Hash, + PartialEq, + Eq, + strum::EnumIter, + strum::IntoStaticStr, + strum::EnumString, +)] +#[allow(non_camel_case_types, missing_docs)] +#[non_exhaustive] +pub enum BArrayUnsafeOpDef { + /// `borrow: borrow_array, index -> elem_ty, borrow_array` + borrow, + /// `return: borrow_array, index, elem_ty -> borrow_array` + #[strum(serialize = "return")] + r#return, + /// `discard_all_borrowed: borrow_array -> ()` + discard_all_borrowed, + /// `new_all_borrowed: () -> borrow_array` + new_all_borrowed, +} + +impl BArrayUnsafeOpDef { + /// Instantiate a new unsafe borrow array operation with the given element type and array size. + #[must_use] + pub fn to_concrete(self, elem_ty: Type, size: u64) -> BArrayUnsafeOp { + BArrayUnsafeOp { + def: self, + elem_ty, + size, + } + } + + fn signature_from_def(&self, def: &TypeDef, _: &sync::Weak) -> SignatureFunc { + let size_var = TypeArg::new_var_use(0, TypeParam::max_nat_type()); + let elem_ty_var = Type::new_var_use(1, TypeBound::Any); + let array_ty: Type = def + .instantiate(vec![size_var, elem_ty_var.clone().into()]) + .unwrap() + .into(); + + let params = vec![TypeParam::max_nat_type(), TypeBound::Any.into()]; + + let usize_t: Type = usize_t(); + + match self { + Self::borrow => PolyFuncTypeRV::new( + params, + FuncValueType::new(vec![array_ty.clone(), usize_t], vec![elem_ty_var, array_ty]), + ), + Self::r#return => PolyFuncTypeRV::new( + params, + FuncValueType::new( + vec![array_ty.clone(), usize_t, elem_ty_var.clone()], + vec![array_ty], + ), + ), + Self::discard_all_borrowed => { + PolyFuncTypeRV::new(params, FuncValueType::new(vec![array_ty], type_row![])) + } + Self::new_all_borrowed => { + PolyFuncTypeRV::new(params, FuncValueType::new(type_row![], vec![array_ty])) + } + } + .into() + } +} + +impl MakeOpDef for BArrayUnsafeOpDef { + fn opdef_id(&self) -> OpName { + <&'static str>::from(self).into() + } + + fn from_def(op_def: &OpDef) -> Result + where + Self: Sized, + { + try_from_name(op_def.name(), op_def.extension_id()) + } + + fn init_signature(&self, extension_ref: &sync::Weak) -> SignatureFunc { + self.signature_from_def( + EXTENSION.get_type(&BORROW_ARRAY_TYPENAME).unwrap(), + extension_ref, + ) + } + + fn extension_ref(&self) -> sync::Weak { + Arc::downgrade(&EXTENSION) + } + + fn extension(&self) -> ExtensionId { + EXTENSION_ID.clone() + } + + fn description(&self) -> String { + match self { + Self::borrow => { + "Take an element from a borrow array (panicking if it was already taken before)" + } + Self::r#return => { + "Put an element into a borrow array (panicking if there is an element already)" + } + Self::discard_all_borrowed => { + "Discard a borrow array where all elements have been borrowed" + } + Self::new_all_borrowed => "Create a new borrow array that contains no elements", + } + .into() + } + + // This method is re-defined here to avoid recursive loops initializing the extension. + fn add_to_extension( + &self, + extension: &mut Extension, + extension_ref: &sync::Weak, + ) -> Result<(), crate::extension::ExtensionBuildError> { + let sig = self.signature_from_def( + extension.get_type(&BORROW_ARRAY_TYPENAME).unwrap(), + extension_ref, + ); + let def = extension.add_op(self.opdef_id(), self.description(), sig, extension_ref)?; + + self.post_opdef(def); + + Ok(()) + } +} + +#[derive(Clone, Debug, PartialEq)] +/// Concrete array operation. +pub struct BArrayUnsafeOp { + /// The operation definition. + pub def: BArrayUnsafeOpDef, + /// The element type of the array. + pub elem_ty: Type, + /// The size of the array. + pub size: u64, +} + +impl MakeExtensionOp for BArrayUnsafeOp { + fn op_id(&self) -> OpName { + self.def.opdef_id() + } + + fn from_extension_op(ext_op: &ExtensionOp) -> Result + where + Self: Sized, + { + let def = BArrayUnsafeOpDef::from_def(ext_op.def())?; + def.instantiate(ext_op.args()) + } + + fn type_args(&self) -> Vec { + vec![self.size.into(), self.elem_ty.clone().into()] + } +} + +impl HasDef for BArrayUnsafeOp { + type Def = BArrayUnsafeOpDef; +} + +impl HasConcrete for BArrayUnsafeOpDef { + type Concrete = BArrayUnsafeOp; + + fn instantiate(&self, type_args: &[TypeArg]) -> Result { + match type_args { + [Term::BoundedNat(n), Term::Runtime(ty)] => Ok(self.to_concrete(ty.clone(), *n)), + _ => Err(SignatureError::InvalidTypeArgs.into()), + } + } +} + +impl MakeRegisteredOp for BArrayUnsafeOp { + fn extension_id(&self) -> ExtensionId { + EXTENSION_ID.clone() + } + + fn extension_ref(&self) -> sync::Weak { + Arc::downgrade(&EXTENSION) + } +} + +lazy_static! { + /// Extension for borrow array operations. + pub static ref EXTENSION: Arc = { + Extension::new_arc(EXTENSION_ID, VERSION, |extension, extension_ref| { + extension.add_type( + BORROW_ARRAY_TYPENAME, + vec![ TypeParam::max_nat_type(), TypeBound::Any.into()], + "Fixed-length borrow array".into(), + // Borrow array is linear, even if the elements are copyable. + TypeDefBound::any(), + extension_ref, + ) + .unwrap(); + + BArrayOpDef::load_all_ops(extension, extension_ref).unwrap(); + BArrayCloneDef::new().add_to_extension(extension, extension_ref).unwrap(); + BArrayDiscardDef::new().add_to_extension(extension, extension_ref).unwrap(); + BArrayRepeatDef::new().add_to_extension(extension, extension_ref).unwrap(); + BArrayScanDef::new().add_to_extension(extension, extension_ref).unwrap(); + BArrayToArrayDef::new().add_to_extension(extension, extension_ref).unwrap(); + BArrayFromArrayDef::new().add_to_extension(extension, extension_ref).unwrap(); + + BArrayUnsafeOpDef::load_all_ops(extension, extension_ref).unwrap(); + }) + }; +} + +#[typetag::serde(name = "BArrayValue")] +impl CustomConst for BArrayValue { + delegate! { + to self { + fn name(&self) -> ValueName; + fn validate(&self) -> Result<(), CustomCheckFailure>; + fn update_extensions( + &mut self, + extensions: &WeakExtensionRegistry, + ) -> Result<(), ExtensionResolutionError>; + fn get_type(&self) -> Type; + } + } + + fn equal_consts(&self, other: &dyn CustomConst) -> bool { + crate::ops::constant::downcast_equal_consts(self, other) + } +} + +/// Gets the [`TypeDef`] for borrow arrays. Note that instantiations are more easily +/// created via [`borrow_array_type`] and [`borrow_array_type_parametric`] +#[must_use] +pub fn borrow_array_type_def() -> &'static TypeDef { + BorrowArray::type_def() +} + +/// Instantiate a new borrow array type given a size argument and element type. +/// +/// This method is equivalent to [`borrow_array_type_parametric`], but uses concrete +/// arguments types to ensure no errors are possible. +#[must_use] +pub fn borrow_array_type(size: u64, element_ty: Type) -> Type { + BorrowArray::ty(size, element_ty) +} + +/// Instantiate a new borrow array type given the size and element type parameters. +/// +/// This is a generic version of [`borrow_array_type`]. +pub fn borrow_array_type_parametric( + size: impl Into, + element_ty: impl Into, +) -> Result { + BorrowArray::ty_parametric(size, element_ty) +} + +/// Trait for building borrow array operations in a dataflow graph. +pub trait BArrayOpBuilder: GenericArrayOpBuilder { + /// Adds a new array operation to the dataflow graph and return the wire + /// representing the new array. + /// + /// # Arguments + /// + /// * `elem_ty` - The type of the elements in the array. + /// * `values` - An iterator over the values to initialize the array with. + /// + /// # Errors + /// + /// If building the operation fails. + /// + /// # Returns + /// + /// The wire representing the new array. + fn add_new_borrow_array( + &mut self, + elem_ty: Type, + values: impl IntoIterator, + ) -> Result { + self.add_new_generic_array::(elem_ty, values) + } + /// Adds an array unpack operation to the dataflow graph. + /// + /// This operation unpacks an array into individual elements. + /// + /// # Arguments + /// + /// * `elem_ty` - The type of the elements in the array. + /// * `size` - The size of the array. + /// * `input` - The wire representing the array to unpack. + /// + /// # Errors + /// + /// If building the operation fails. + /// + /// # Returns + /// + /// A vector of wires representing the individual elements from the array. + fn add_borrow_array_unpack( + &mut self, + elem_ty: Type, + size: u64, + input: Wire, + ) -> Result, BuildError> { + self.add_generic_array_unpack::(elem_ty, size, input) + } + /// Adds an array clone operation to the dataflow graph and return the wires + /// representing the original and cloned array. + /// + /// # Arguments + /// + /// * `elem_ty` - The type of the elements in the array. + /// * `size` - The size of the array. + /// * `input` - The wire representing the array. + /// + /// # Errors + /// + /// If building the operation fails. + /// + /// # Returns + /// + /// The wires representing the original and cloned array. + fn add_borrow_array_clone( + &mut self, + elem_ty: Type, + size: u64, + input: Wire, + ) -> Result<(Wire, Wire), BuildError> { + self.add_generic_array_clone::(elem_ty, size, input) + } + + /// Adds an array discard operation to the dataflow graph. + /// + /// # Arguments + /// + /// * `elem_ty` - The type of the elements in the array. + /// * `size` - The size of the array. + /// * `input` - The wire representing the array. + /// + /// # Errors + /// + /// If building the operation fails. + fn add_borrow_array_discard( + &mut self, + elem_ty: Type, + size: u64, + input: Wire, + ) -> Result<(), BuildError> { + self.add_generic_array_discard::(elem_ty, size, input) + } + + /// Adds an array get operation to the dataflow graph. + /// + /// # Arguments + /// + /// * `elem_ty` - The type of the elements in the array. + /// * `size` - The size of the array. + /// * `input` - The wire representing the array. + /// * `index` - The wire representing the index to get. + /// + /// # Errors + /// + /// If building the operation fails. + /// + /// # Returns + /// + /// * The wire representing the value at the specified index in the array + /// * The wire representing the array + fn add_borrow_array_get( + &mut self, + elem_ty: Type, + size: u64, + input: Wire, + index: Wire, + ) -> Result<(Wire, Wire), BuildError> { + self.add_generic_array_get::(elem_ty, size, input, index) + } + + /// Adds an array set operation to the dataflow graph. + /// + /// This operation sets the value at a specified index in the array. + /// + /// # Arguments + /// + /// * `elem_ty` - The type of the elements in the array. + /// * `size` - The size of the array. + /// * `input` - The wire representing the array. + /// * `index` - The wire representing the index to set. + /// * `value` - The wire representing the value to set at the specified index. + /// + /// # Errors + /// + /// Returns an error if building the operation fails. + /// + /// # Returns + /// + /// The wire representing the updated array after the set operation. + fn add_borrow_array_set( + &mut self, + elem_ty: Type, + size: u64, + input: Wire, + index: Wire, + value: Wire, + ) -> Result { + self.add_generic_array_set::(elem_ty, size, input, index, value) + } + + /// Adds an array swap operation to the dataflow graph. + /// + /// This operation swaps the values at two specified indices in the array. + /// + /// # Arguments + /// + /// * `elem_ty` - The type of the elements in the array. + /// * `size` - The size of the array. + /// * `input` - The wire representing the array. + /// * `index1` - The wire representing the first index to swap. + /// * `index2` - The wire representing the second index to swap. + /// + /// # Errors + /// + /// Returns an error if building the operation fails. + /// + /// # Returns + /// + /// The wire representing the updated array after the swap operation. + fn add_borrow_array_swap( + &mut self, + elem_ty: Type, + size: u64, + input: Wire, + index1: Wire, + index2: Wire, + ) -> Result { + let op = + GenericArrayOpDef::::swap.instantiate(&[size.into(), elem_ty.into()])?; + let [out] = self + .add_dataflow_op(op, vec![input, index1, index2])? + .outputs_arr(); + Ok(out) + } + + /// Adds an array pop-left operation to the dataflow graph. + /// + /// This operation removes the leftmost element from the array. + /// + /// # Arguments + /// + /// * `elem_ty` - The type of the elements in the array. + /// * `size` - The size of the array. + /// * `input` - The wire representing the array. + /// + /// # Errors + /// + /// Returns an error if building the operation fails. + /// + /// # Returns + /// + /// The wire representing the Option> + fn add_borrow_array_pop_left( + &mut self, + elem_ty: Type, + size: u64, + input: Wire, + ) -> Result { + self.add_generic_array_pop_left::(elem_ty, size, input) + } + + /// Adds an array pop-right operation to the dataflow graph. + /// + /// This operation removes the rightmost element from the array. + /// + /// # Arguments + /// + /// * `elem_ty` - The type of the elements in the array. + /// * `size` - The size of the array. + /// * `input` - The wire representing the array. + /// + /// # Errors + /// + /// Returns an error if building the operation fails. + /// + /// # Returns + /// + /// The wire representing the Option> + fn add_borrow_array_pop_right( + &mut self, + elem_ty: Type, + size: u64, + input: Wire, + ) -> Result { + self.add_generic_array_pop_right::(elem_ty, size, input) + } + + /// Adds an operation to discard an empty array from the dataflow graph. + /// + /// # Arguments + /// + /// * `elem_ty` - The type of the elements in the array. + /// * `input` - The wire representing the array. + /// + /// # Errors + /// + /// Returns an error if building the operation fails. + fn add_borrow_array_discard_empty( + &mut self, + elem_ty: Type, + input: Wire, + ) -> Result<(), BuildError> { + self.add_generic_array_discard_empty::(elem_ty, input) + } + + /// Adds a borrow array borrow operation to the dataflow graph. + /// + /// # Arguments + /// + /// * `elem_ty` - The type of the elements in the array. + /// * `size` - The size of the array. + /// * `input` - The wire representing the array. + /// * `index` - The wire representing the index to get. + /// + /// # Errors + /// + /// Returns an error if building the operation fails. + fn add_borrow_array_borrow( + &mut self, + elem_ty: Type, + size: u64, + input: Wire, + index: Wire, + ) -> Result<(Wire, Wire), BuildError> { + let op = BArrayUnsafeOpDef::borrow.instantiate(&[size.into(), elem_ty.into()])?; + let [out, arr] = self + .add_dataflow_op(op.to_extension_op().unwrap(), vec![input, index])? + .outputs_arr(); + Ok((out, arr)) + } + + /// Adds a borrow array put operation to the dataflow graph. + /// + /// # Arguments + /// + /// * `elem_ty` - The type of the elements in the array. + /// * `size` - The size of the array. + /// * `input` - The wire representing the array. + /// * `index` - The wire representing the index to set. + /// * `value` - The wire representing the value to set at the specified index. + /// + /// # Errors + /// + /// Returns an error if building the operation fails. + fn add_borrow_array_return( + &mut self, + elem_ty: Type, + size: u64, + input: Wire, + index: Wire, + value: Wire, + ) -> Result { + let op = BArrayUnsafeOpDef::r#return.instantiate(&[size.into(), elem_ty.into()])?; + let [arr] = self + .add_dataflow_op(op.to_extension_op().unwrap(), vec![input, index, value])? + .outputs_arr(); + Ok(arr) + } + + /// Adds an operation to discard a borrow array where all elements have been borrowed. + /// + /// # Arguments + /// + /// * `elem_ty` - The type of the elements in the array. + /// * `size` - The size of the array. + /// * `input` - The wire representing the array. + /// + /// # Errors + /// + /// Returns an error if building the operation fails. + fn add_discard_all_borrowed( + &mut self, + elem_ty: Type, + size: u64, + input: Wire, + ) -> Result<(), BuildError> { + let op = + BArrayUnsafeOpDef::discard_all_borrowed.instantiate(&[size.into(), elem_ty.into()])?; + self.add_dataflow_op(op.to_extension_op().unwrap(), vec![input])?; + Ok(()) + } + + /// Adds an operation to create a new empty borrowed array in the dataflow graph. + /// + /// # Arguments + /// + /// * `elem_ty` - The type of the elements in the array. + /// * `size` - The size of the array. + /// + /// # Errors + /// + /// Returns an error if building the operation fails. + fn add_new_all_borrowed(&mut self, elem_ty: Type, size: u64) -> Result { + let op = BArrayUnsafeOpDef::new_all_borrowed.instantiate(&[size.into(), elem_ty.into()])?; + let [arr] = self + .add_dataflow_op(op.to_extension_op().unwrap(), vec![])? + .outputs_arr(); + Ok(arr) + } +} + +impl BArrayOpBuilder for D {} + +#[cfg(test)] +mod test { + use strum::IntoEnumIterator; + + use crate::{ + builder::{DFGBuilder, Dataflow, DataflowHugr as _}, + extension::prelude::{ConstUsize, qb_t, usize_t}, + ops::OpType, + std_extensions::collections::borrow_array::{ + BArrayOpBuilder, BArrayUnsafeOp, BArrayUnsafeOpDef, borrow_array_type, + }, + types::Signature, + }; + + #[test] + fn test_borrow_array_unsafe_ops() { + for def in BArrayUnsafeOpDef::iter() { + let op = def.to_concrete(qb_t(), 2); + let optype: OpType = op.clone().into(); + let new_op: BArrayUnsafeOp = optype.cast().unwrap(); + assert_eq!(new_op, op); + } + } + + #[test] + fn test_borrow_and_return() { + let size = 22; + let elem_ty = qb_t(); + let arr_ty = borrow_array_type(size, elem_ty.clone()); + let _ = { + let mut builder = DFGBuilder::new(Signature::new_endo(vec![arr_ty.clone()])).unwrap(); + let idx1 = builder.add_load_value(ConstUsize::new(11)); + let idx2 = builder.add_load_value(ConstUsize::new(11)); + let [arr] = builder.input_wires_arr(); + let (el, arr_with_take) = builder + .add_borrow_array_borrow(elem_ty.clone(), size, arr, idx1) + .unwrap(); + let arr_with_put = builder + .add_borrow_array_return(elem_ty, size, arr_with_take, idx2, el) + .unwrap(); + builder.finish_hugr_with_outputs([arr_with_put]).unwrap() + }; + } + + #[test] + fn test_discard_all_borrowed() { + let size = 1; + let elem_ty = qb_t(); + let arr_ty = borrow_array_type(size, elem_ty.clone()); + let _ = { + let mut builder = + DFGBuilder::new(Signature::new(vec![arr_ty.clone()], vec![qb_t()])).unwrap(); + let idx = builder.add_load_value(ConstUsize::new(0)); + let [arr] = builder.input_wires_arr(); + let (el, arr_with_borrowed) = builder + .add_borrow_array_borrow(elem_ty.clone(), size, arr, idx) + .unwrap(); + builder + .add_discard_all_borrowed(elem_ty, size, arr_with_borrowed) + .unwrap(); + builder.finish_hugr_with_outputs([el]).unwrap() + }; + } + + #[test] + fn test_new_all_borrowed() { + let size = 5; + let elem_ty = usize_t(); + let arr_ty = borrow_array_type(size, elem_ty.clone()); + let _ = { + let mut builder = + DFGBuilder::new(Signature::new(vec![], vec![arr_ty.clone()])).unwrap(); + let arr = builder.add_new_all_borrowed(elem_ty.clone(), size).unwrap(); + let idx = builder.add_load_value(ConstUsize::new(3)); + let val = builder.add_load_value(ConstUsize::new(202)); + let arr_with_put = builder + .add_borrow_array_return(elem_ty, size, arr, idx, val) + .unwrap(); + builder.finish_hugr_with_outputs([arr_with_put]).unwrap() + }; + } +} diff --git a/hugr-py/src/hugr/std/_json_defs/collections/borrow_arr.json b/hugr-py/src/hugr/std/_json_defs/collections/borrow_arr.json new file mode 100644 index 0000000000..1774b4aea6 --- /dev/null +++ b/hugr-py/src/hugr/std/_json_defs/collections/borrow_arr.json @@ -0,0 +1,1139 @@ +{ + "version": "0.1.1", + "name": "collections.borrow_arr", + "types": { + "borrow_array": { + "extension": "collections.borrow_arr", + "name": "borrow_array", + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "A" + } + ], + "description": "Fixed-length borrow array", + "bound": { + "b": "Explicit", + "bound": "A" + } + } + }, + "operations": { + "borrow": { + "extension": "collections.borrow_arr", + "name": "borrow", + "description": "Take an element from a borrow array (panicking if it was already taken before)", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "A" + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + }, + { + "t": "I" + } + ], + "output": [ + { + "t": "V", + "i": 1, + "b": "A" + }, + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ] + } + }, + "binary": false + }, + "clone": { + "extension": "collections.borrow_arr", + "name": "clone", + "description": "Clones an array with copyable elements", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "C" + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "C" + } + } + ], + "bound": "A" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "C" + } + } + ], + "bound": "A" + }, + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "C" + } + } + ], + "bound": "A" + } + ] + } + }, + "binary": false + }, + "discard": { + "extension": "collections.borrow_arr", + "name": "discard", + "description": "Discards an array with copyable elements", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "C" + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "C" + } + } + ], + "bound": "A" + } + ], + "output": [] + } + }, + "binary": false + }, + "discard_all_borrowed": { + "extension": "collections.borrow_arr", + "name": "discard_all_borrowed", + "description": "Discard a borrow array where all elements have been borrowed", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "A" + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ], + "output": [] + } + }, + "binary": false + }, + "discard_empty": { + "extension": "collections.borrow_arr", + "name": "discard_empty", + "description": "Discard an empty array", + "signature": { + "params": [ + { + "tp": "Type", + "b": "A" + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "BoundedNat", + "n": 0 + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 0, + "b": "A" + } + } + ], + "bound": "A" + } + ], + "output": [] + } + }, + "binary": false + }, + "from_array": { + "extension": "collections.borrow_arr", + "name": "from_array", + "description": "Turns `array` into `borrow_array`", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "A" + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "collections.array", + "id": "array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ] + } + }, + "binary": false + }, + "get": { + "extension": "collections.borrow_arr", + "name": "get", + "description": "Get an element from an array", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "C" + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "C" + } + } + ], + "bound": "A" + }, + { + "t": "I" + } + ], + "output": [ + { + "t": "Sum", + "s": "General", + "rows": [ + [], + [ + { + "t": "V", + "i": 1, + "b": "C" + } + ] + ] + }, + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "C" + } + } + ], + "bound": "A" + } + ] + } + }, + "binary": false + }, + "new_all_borrowed": { + "extension": "collections.borrow_arr", + "name": "new_all_borrowed", + "description": "Create a new borrow array that contains no elements", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "A" + } + ], + "body": { + "input": [], + "output": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ] + } + }, + "binary": false + }, + "new_array": { + "extension": "collections.borrow_arr", + "name": "new_array", + "description": "Create a new array from elements", + "signature": null, + "binary": true + }, + "pop_left": { + "extension": "collections.borrow_arr", + "name": "pop_left", + "description": "Pop an element from the left of an array", + "signature": null, + "binary": true + }, + "pop_right": { + "extension": "collections.borrow_arr", + "name": "pop_right", + "description": "Pop an element from the right of an array", + "signature": null, + "binary": true + }, + "repeat": { + "extension": "collections.borrow_arr", + "name": "repeat", + "description": "Creates a new array whose elements are initialised by calling the given function n times", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "A" + } + ], + "body": { + "input": [ + { + "t": "G", + "input": [], + "output": [ + { + "t": "V", + "i": 1, + "b": "A" + } + ] + } + ], + "output": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ] + } + }, + "binary": false + }, + "return": { + "extension": "collections.borrow_arr", + "name": "return", + "description": "Put an element into a borrow array (panicking if there is an element already)", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "A" + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + }, + { + "t": "I" + }, + { + "t": "V", + "i": 1, + "b": "A" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ] + } + }, + "binary": false + }, + "scan": { + "extension": "collections.borrow_arr", + "name": "scan", + "description": "A combination of map and foldl. Applies a function to each element of the array with an accumulator that is passed through from start to finish. Returns the resulting array and the final state of the accumulator.", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "A" + }, + { + "tp": "Type", + "b": "A" + }, + { + "tp": "List", + "param": { + "tp": "Type", + "b": "A" + } + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + }, + { + "t": "G", + "input": [ + { + "t": "V", + "i": 1, + "b": "A" + }, + { + "t": "R", + "i": 3, + "b": "A" + } + ], + "output": [ + { + "t": "V", + "i": 2, + "b": "A" + }, + { + "t": "R", + "i": 3, + "b": "A" + } + ] + }, + { + "t": "R", + "i": 3, + "b": "A" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 2, + "b": "A" + } + } + ], + "bound": "A" + }, + { + "t": "R", + "i": 3, + "b": "A" + } + ] + } + }, + "binary": false + }, + "set": { + "extension": "collections.borrow_arr", + "name": "set", + "description": "Set an element in an array", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "A" + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + }, + { + "t": "I" + }, + { + "t": "V", + "i": 1, + "b": "A" + } + ], + "output": [ + { + "t": "Sum", + "s": "General", + "rows": [ + [ + { + "t": "V", + "i": 1, + "b": "A" + }, + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ], + [ + { + "t": "V", + "i": 1, + "b": "A" + }, + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ] + ] + } + ] + } + }, + "binary": false + }, + "swap": { + "extension": "collections.borrow_arr", + "name": "swap", + "description": "Swap two elements in an array", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "A" + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + }, + { + "t": "I" + }, + { + "t": "I" + } + ], + "output": [ + { + "t": "Sum", + "s": "General", + "rows": [ + [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ], + [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ] + ] + } + ] + } + }, + "binary": false + }, + "to_array": { + "extension": "collections.borrow_arr", + "name": "to_array", + "description": "Turns `borrow_array` into `array`", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "A" + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "collections.array", + "id": "array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ] + } + }, + "binary": false + }, + "unpack": { + "extension": "collections.borrow_arr", + "name": "unpack", + "description": "Unpack an array into its elements", + "signature": null, + "binary": true + } + } +} diff --git a/specification/std_extensions/collections/borrow_arr.json b/specification/std_extensions/collections/borrow_arr.json new file mode 100644 index 0000000000..1774b4aea6 --- /dev/null +++ b/specification/std_extensions/collections/borrow_arr.json @@ -0,0 +1,1139 @@ +{ + "version": "0.1.1", + "name": "collections.borrow_arr", + "types": { + "borrow_array": { + "extension": "collections.borrow_arr", + "name": "borrow_array", + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "A" + } + ], + "description": "Fixed-length borrow array", + "bound": { + "b": "Explicit", + "bound": "A" + } + } + }, + "operations": { + "borrow": { + "extension": "collections.borrow_arr", + "name": "borrow", + "description": "Take an element from a borrow array (panicking if it was already taken before)", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "A" + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + }, + { + "t": "I" + } + ], + "output": [ + { + "t": "V", + "i": 1, + "b": "A" + }, + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ] + } + }, + "binary": false + }, + "clone": { + "extension": "collections.borrow_arr", + "name": "clone", + "description": "Clones an array with copyable elements", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "C" + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "C" + } + } + ], + "bound": "A" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "C" + } + } + ], + "bound": "A" + }, + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "C" + } + } + ], + "bound": "A" + } + ] + } + }, + "binary": false + }, + "discard": { + "extension": "collections.borrow_arr", + "name": "discard", + "description": "Discards an array with copyable elements", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "C" + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "C" + } + } + ], + "bound": "A" + } + ], + "output": [] + } + }, + "binary": false + }, + "discard_all_borrowed": { + "extension": "collections.borrow_arr", + "name": "discard_all_borrowed", + "description": "Discard a borrow array where all elements have been borrowed", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "A" + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ], + "output": [] + } + }, + "binary": false + }, + "discard_empty": { + "extension": "collections.borrow_arr", + "name": "discard_empty", + "description": "Discard an empty array", + "signature": { + "params": [ + { + "tp": "Type", + "b": "A" + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "BoundedNat", + "n": 0 + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 0, + "b": "A" + } + } + ], + "bound": "A" + } + ], + "output": [] + } + }, + "binary": false + }, + "from_array": { + "extension": "collections.borrow_arr", + "name": "from_array", + "description": "Turns `array` into `borrow_array`", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "A" + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "collections.array", + "id": "array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ] + } + }, + "binary": false + }, + "get": { + "extension": "collections.borrow_arr", + "name": "get", + "description": "Get an element from an array", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "C" + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "C" + } + } + ], + "bound": "A" + }, + { + "t": "I" + } + ], + "output": [ + { + "t": "Sum", + "s": "General", + "rows": [ + [], + [ + { + "t": "V", + "i": 1, + "b": "C" + } + ] + ] + }, + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "C" + } + } + ], + "bound": "A" + } + ] + } + }, + "binary": false + }, + "new_all_borrowed": { + "extension": "collections.borrow_arr", + "name": "new_all_borrowed", + "description": "Create a new borrow array that contains no elements", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "A" + } + ], + "body": { + "input": [], + "output": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ] + } + }, + "binary": false + }, + "new_array": { + "extension": "collections.borrow_arr", + "name": "new_array", + "description": "Create a new array from elements", + "signature": null, + "binary": true + }, + "pop_left": { + "extension": "collections.borrow_arr", + "name": "pop_left", + "description": "Pop an element from the left of an array", + "signature": null, + "binary": true + }, + "pop_right": { + "extension": "collections.borrow_arr", + "name": "pop_right", + "description": "Pop an element from the right of an array", + "signature": null, + "binary": true + }, + "repeat": { + "extension": "collections.borrow_arr", + "name": "repeat", + "description": "Creates a new array whose elements are initialised by calling the given function n times", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "A" + } + ], + "body": { + "input": [ + { + "t": "G", + "input": [], + "output": [ + { + "t": "V", + "i": 1, + "b": "A" + } + ] + } + ], + "output": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ] + } + }, + "binary": false + }, + "return": { + "extension": "collections.borrow_arr", + "name": "return", + "description": "Put an element into a borrow array (panicking if there is an element already)", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "A" + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + }, + { + "t": "I" + }, + { + "t": "V", + "i": 1, + "b": "A" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ] + } + }, + "binary": false + }, + "scan": { + "extension": "collections.borrow_arr", + "name": "scan", + "description": "A combination of map and foldl. Applies a function to each element of the array with an accumulator that is passed through from start to finish. Returns the resulting array and the final state of the accumulator.", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "A" + }, + { + "tp": "Type", + "b": "A" + }, + { + "tp": "List", + "param": { + "tp": "Type", + "b": "A" + } + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + }, + { + "t": "G", + "input": [ + { + "t": "V", + "i": 1, + "b": "A" + }, + { + "t": "R", + "i": 3, + "b": "A" + } + ], + "output": [ + { + "t": "V", + "i": 2, + "b": "A" + }, + { + "t": "R", + "i": 3, + "b": "A" + } + ] + }, + { + "t": "R", + "i": 3, + "b": "A" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 2, + "b": "A" + } + } + ], + "bound": "A" + }, + { + "t": "R", + "i": 3, + "b": "A" + } + ] + } + }, + "binary": false + }, + "set": { + "extension": "collections.borrow_arr", + "name": "set", + "description": "Set an element in an array", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "A" + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + }, + { + "t": "I" + }, + { + "t": "V", + "i": 1, + "b": "A" + } + ], + "output": [ + { + "t": "Sum", + "s": "General", + "rows": [ + [ + { + "t": "V", + "i": 1, + "b": "A" + }, + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ], + [ + { + "t": "V", + "i": 1, + "b": "A" + }, + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ] + ] + } + ] + } + }, + "binary": false + }, + "swap": { + "extension": "collections.borrow_arr", + "name": "swap", + "description": "Swap two elements in an array", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "A" + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + }, + { + "t": "I" + }, + { + "t": "I" + } + ], + "output": [ + { + "t": "Sum", + "s": "General", + "rows": [ + [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ], + [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ] + ] + } + ] + } + }, + "binary": false + }, + "to_array": { + "extension": "collections.borrow_arr", + "name": "to_array", + "description": "Turns `borrow_array` into `array`", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": null + }, + { + "tp": "Type", + "b": "A" + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "collections.borrow_arr", + "id": "borrow_array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "collections.array", + "id": "array", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": null + } + }, + { + "tya": "Type", + "ty": { + "t": "V", + "i": 1, + "b": "A" + } + } + ], + "bound": "A" + } + ] + } + }, + "binary": false + }, + "unpack": { + "extension": "collections.borrow_arr", + "name": "unpack", + "description": "Unpack an array into its elements", + "signature": null, + "binary": true + } + } +}