From bea90977999c184a7705dc80c563d1282334b3b6 Mon Sep 17 00:00:00 2001 From: Seyon Sivarajah Date: Thu, 27 Jul 2023 16:17:07 +0100 Subject: [PATCH 1/4] Enable TypeDef reporting of type tag. Closes #286 --- src/extensions/rotation.rs | 1 + src/resource.rs | 41 ++++++++++++++++++++++++++++++++++++++ src/types/simple.rs | 2 +- src/types/type_param.rs | 15 +++++++++++++- 4 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/extensions/rotation.rs b/src/extensions/rotation.rs index d33b4d349..a3489d394 100644 --- a/src/extensions/rotation.rs +++ b/src/extensions/rotation.rs @@ -75,6 +75,7 @@ impl Type { params: vec![], description: self.description().to_string(), resource: None, + tag: crate::types::TypeTag::Classic.into(), } } } diff --git a/src/resource.rs b/src/resource.rs index a031162ff..e1219cc39 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -12,6 +12,7 @@ use smol_str::SmolStr; use thiserror::Error; use crate::types::type_param::{check_type_arg, TypeArgError}; +use crate::types::TypeTag; use crate::types::{ type_param::{TypeArg, TypeParam}, Signature, SignatureDescription, SimpleRow, @@ -288,6 +289,20 @@ impl OpDef { } } +/// The type tag of a [`TypeDef`] +#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] +pub enum TypeDefTag { + /// Defined by an explicit tag. + Explicit(TypeTag), + /// Derived as the tag containing all marked type parameters. + FromParams(Vec), +} + +impl From for TypeDefTag { + fn from(tag: TypeTag) -> Self { + Self::Explicit(tag) + } +} /// A declaration of an opaque type. /// Note this does not provide any way to create instances /// - typically these are operations also provided by the Resource. @@ -304,6 +319,32 @@ pub struct TypeDef { pub resource: Option, /// Human readable description of the type definition. pub description: String, + /// The definition of the type tag of this definition. + pub tag: TypeDefTag, +} + +impl TypeDef { + /// The [`TypeTag`] of the definition. + pub fn tag(&self, args: &[TypeArg]) -> TypeTag { + match &self.tag { + TypeDefTag::Explicit(tag) => *tag, + TypeDefTag::FromParams(indices) => { + let args: Vec<_> = args.iter().collect(); + if indices.is_empty() { + // Assume most general case + return TypeTag::Simple; + } + indices + .iter() + .map(|i| { + args.get(*i) + .and_then(|ta| ta.tag()) + .expect("TypeParam index invalid or param does not have a TypeTag.") + }) + .fold(TypeTag::Hashable, TypeTag::union) + } + } + } } /// A unique identifier for a resource. diff --git a/src/types/simple.rs b/src/types/simple.rs index b83ade047..0f80c9e35 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -62,7 +62,7 @@ pub enum TypeTag { impl TypeTag { /// Returns the smallest TypeTag containing both the receiver and argument. /// (This will be one of the receiver or the argument.) - fn union(self, other: Self) -> Self { + pub fn union(self, other: Self) -> Self { if self == Self::Simple || other == Self::Simple { Self::Simple } else if self == Self::Classic || other == Self::Classic { diff --git a/src/types/type_param.rs b/src/types/type_param.rs index f659c0bfd..32661ad3a 100644 --- a/src/types/type_param.rs +++ b/src/types/type_param.rs @@ -8,7 +8,7 @@ use thiserror::Error; use crate::ops::constant::HugrIntValueStore; -use super::{ClassicType, SimpleType}; +use super::{ClassicType, PrimType, SimpleType, TypeTag}; /// A parameter declared by an OpDef. Specifies a value /// that must be provided by each operation node. @@ -51,6 +51,19 @@ pub enum TypeArg { Value(serde_yaml::Value), } +impl TypeArg { + /// Report [`TypeArg`] if param is a type + pub fn tag(&self) -> Option { + match self { + TypeArg::Type(s) => Some(s.tag()), + TypeArg::ClassicType(c) => Some(c.tag()), + // assume list is well formed - all elements of same type + TypeArg::List(t) => t.iter().next().and_then(TypeArg::tag), + _ => None, + } + } +} + /// Checks a [TypeArg] is as expected for a [TypeParam] pub fn check_type_arg(arg: &TypeArg, param: &TypeParam) -> Result<(), TypeArgError> { match (arg, param) { From 48b5ef052f7b7ce0e7589c46afdfe88aa9eed9f4 Mon Sep 17 00:00:00 2001 From: Seyon Sivarajah Date: Fri, 28 Jul 2023 15:24:00 +0100 Subject: [PATCH 2/4] generalise TypeParam handling under trait + to_custom --- src/extensions/rotation.rs | 10 +++- src/resource.rs | 101 ++++++++++++++++++++++++++++++++++--- src/types/custom.rs | 22 ++++++-- 3 files changed, 119 insertions(+), 14 deletions(-) diff --git a/src/extensions/rotation.rs b/src/extensions/rotation.rs index a3489d394..a8d86841c 100644 --- a/src/extensions/rotation.rs +++ b/src/extensions/rotation.rs @@ -66,7 +66,7 @@ impl Type { } pub fn custom_type(self) -> CustomType { - CustomType::new(self.name(), []) + CustomType::new(self.name(), [], resource_id()) } pub fn type_def(self) -> TypeDef { @@ -288,3 +288,11 @@ impl Neg for &AngleValue { self.unary_op(|x| -x, |x| -x) } } + +#[cfg(test)] +mod test { + #[test] + fn test_types() { + todo!() + } +} diff --git a/src/resource.rs b/src/resource.rs index e1219cc39..07235829f 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -11,12 +11,13 @@ use std::sync::Arc; use smol_str::SmolStr; use thiserror::Error; +use crate::ops::custom::OpaqueOp; use crate::types::type_param::{check_type_arg, TypeArgError}; -use crate::types::TypeTag; use crate::types::{ type_param::{TypeArg, TypeParam}, Signature, SignatureDescription, SimpleRow, }; +use crate::types::{CustomType, TypeTag}; use crate::Hugr; /// Trait for resources to provide custom binary code for computing signature. @@ -139,6 +140,41 @@ impl Debug for LowerFunc { } } +/// Sealed trait for shared type parametrised functionality between [`TypeDef`] and [`OpDef`]. +pub trait TypeParametrisedInternal: sealed::Sealed { + /// The concrete object built by binding type arguments to parameters + type Concrete; + /// The resource-unique name. + fn name(&self) -> &SmolStr; + /// Type parameters. + fn params(&self) -> &[TypeParam]; + /// The parent resource. if any. + fn resource(&self) -> Option<&ResourceId>; + /// Check provided type arguments are valid against parameters. + fn check_args(&self, args: &[TypeArg]) -> Result<(), SignatureError> { + for (a, p) in args.iter().zip(self.params().iter()) { + check_type_arg(a, p).map_err(SignatureError::TypeArgMismatch)?; + } + Ok(()) + } + + /// Instantiate a concrete instance by providing type arguments. + /// + /// # Errors + /// + /// This function will return an error if the provided arguments are not + /// valid instances of the TypeDef parameters. + fn to_custom(&self, args: impl Into>) -> Result; +} + +mod sealed { + use super::{OpDef, TypeDef}; + + pub trait Sealed {} + impl Sealed for OpDef {} + impl Sealed for TypeDef {} +} + /// Serializable definition for dynamically loaded operations. /// /// TODO: Define a way to construct new OpDef's from a serialized definition. @@ -165,6 +201,36 @@ pub struct OpDef { lower_funcs: Vec, } +impl TypeParametrisedInternal for OpDef { + type Concrete = OpaqueOp; + + fn params(&self) -> &[TypeParam] { + &self.params + } + + fn name(&self) -> &SmolStr { + &self.name + } + + fn to_custom(&self, args: impl Into>) -> Result { + let args = args.into(); + self.check_args(&args)?; + + Ok(OpaqueOp::new( + self.resource().expect("Resource not set.").clone(), + self.name().clone(), + // TODO add description + "".to_string(), + args, + None, + )) + } + + fn resource(&self) -> Option<&ResourceId> { + self.resource.as_ref() + } +} + impl OpDef { /// Create an OpDef with a signature (inputs+outputs) read from the YAML pub fn new_with_yaml_types( @@ -244,13 +310,6 @@ impl OpDef { Ok(sig) } - fn check_args(&self, args: &[TypeArg]) -> Result<(), SignatureError> { - for (a, p) in args.iter().zip(self.params.iter()) { - check_type_arg(a, p).map_err(SignatureError::TypeArgMismatch)?; - } - Ok(()) - } - /// Optional description of the ports in the signature. pub fn signature_desc(&self, args: &[TypeArg]) -> SignatureDescription { match &self.signature_func { @@ -323,6 +382,32 @@ pub struct TypeDef { pub tag: TypeDefTag, } +impl TypeParametrisedInternal for TypeDef { + type Concrete = CustomType; + + fn params(&self) -> &[TypeParam] { + &self.params + } + + fn name(&self) -> &SmolStr { + &self.name + } + + fn to_custom(&self, args: impl Into>) -> Result { + let args = args.into(); + self.check_args(&args)?; + Ok(CustomType::new( + self.name().clone(), + args, + self.resource().expect("Resource not set.").clone(), + )) + } + + fn resource(&self) -> Option<&ResourceId> { + self.resource.as_ref() + } +} + impl TypeDef { /// The [`TypeTag`] of the definition. pub fn tag(&self, args: &[TypeArg]) -> TypeTag { diff --git a/src/types/custom.rs b/src/types/custom.rs index fc3a8f89c..807bbc5ac 100644 --- a/src/types/custom.rs +++ b/src/types/custom.rs @@ -4,11 +4,14 @@ use smol_str::SmolStr; use std::fmt::{self, Display}; +use crate::resource::ResourceId; + use super::{type_param::TypeArg, ClassicType, Container}; /// An opaque type element. Contains the unique identifier of its definition. #[derive(Debug, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize)] pub struct CustomType { + resource: ResourceId, /// Unique identifier of the opaque type. /// Same as the corresponding [`TypeDef`] /// @@ -22,17 +25,26 @@ pub struct CustomType { impl CustomType { /// Creates a new opaque type. - pub fn new(id: impl Into, args: impl Into>) -> Self { + pub fn new( + id: impl Into, + args: impl Into>, + resource: impl Into, + ) -> Self { Self { id: id.into(), args: args.into(), + resource: resource.into(), } } - /// Creates a new opaque type with no parameters - pub const fn new_simple(id: SmolStr) -> Self { - Self { id, args: vec![] } - } + // /// Creates a new opaque type with no parameters + // pub const fn new_simple(id: SmolStr) -> Self { + // Self { + // id, + // args: vec![], + // resource: ResourceId::default(), + // } + // } /// Returns the unique identifier of the opaque type. pub fn id(&self) -> &str { From f5a41dfc9b1b49366d9126a5a1e1c4ea5100710b Mon Sep 17 00:00:00 2001 From: Seyon Sivarajah Date: Fri, 28 Jul 2023 17:27:05 +0100 Subject: [PATCH 3/4] add trait for custom ops and types + check against def --- src/extensions/rotation.rs | 22 ++++++++++++- src/ops/custom.rs | 15 +++++++-- src/resource.rs | 64 ++++++++++++++++++++++++++++++++++---- src/types/custom.rs | 27 +++++++--------- 4 files changed, 102 insertions(+), 26 deletions(-) diff --git a/src/extensions/rotation.rs b/src/extensions/rotation.rs index a8d86841c..0ad596a7c 100644 --- a/src/extensions/rotation.rs +++ b/src/extensions/rotation.rs @@ -291,8 +291,28 @@ impl Neg for &AngleValue { #[cfg(test)] mod test { + + use crate::resource::{CustomConcrete, SignatureError, TypeParametrisedInternal}; + + use super::*; + #[test] fn test_types() { - todo!() + let resource = resource(); + + let angle = resource.types().get("angle").unwrap(); + + let custom = angle.to_custom([]).unwrap(); + + angle.check_custom(&custom).unwrap(); + + let false_custom = CustomType::new(custom.name().clone(), vec![], "wrong_resource"); + assert_eq!( + angle.check_custom(&false_custom), + Err(SignatureError::ResourceMismatch( + Some("rotations".into()), + Some("wrong_resource".into()), + )) + ); } } diff --git a/src/ops/custom.rs b/src/ops/custom.rs index 3762b919f..edfabdbb5 100644 --- a/src/ops/custom.rs +++ b/src/ops/custom.rs @@ -6,7 +6,7 @@ use std::sync::Arc; use thiserror::Error; use crate::hugr::{HugrMut, HugrView}; -use crate::resource::{OpDef, ResourceId, ResourceSet, SignatureError}; +use crate::resource::{CustomConcrete, OpDef, ResourceId, ResourceSet, SignatureError}; use crate::types::{type_param::TypeArg, Signature, SignatureDescription}; use crate::{Hugr, Node, Resource}; @@ -186,11 +186,20 @@ impl OpaqueOp { signature, } } +} - /// Return the argument values for this operation. - pub fn args(&self) -> &[TypeArg] { +impl CustomConcrete for OpaqueOp { + fn name(&self) -> &SmolStr { + &self.op_name + } + + fn args(&self) -> &[TypeArg] { &self.args } + + fn resource(&self) -> &ResourceId { + &self.resource + } } /// Resolve serialized names of operations into concrete implementation (OpDefs) where possible diff --git a/src/resource.rs b/src/resource.rs index 07235829f..7c7d376ab 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -63,8 +63,14 @@ where /// TODO: decide on failure modes #[derive(Debug, Clone, Error, PartialEq, Eq)] pub enum SignatureError { + /// Name mismatch + #[error("Definition name ({0}) and instantiation name ({1}) do not match.")] + NameMismatch(SmolStr, SmolStr), + /// Resource mismatch + #[error("Definition resource ({0:?}) and instantiation resource ({1:?}) do not match.")] + ResourceMismatch(Option, Option), /// When the type arguments of the node did not match the params declared by the OpDef - #[error("Type arguments of node did not match params declared by OpDef: {0}")] + #[error("Type arguments of node did not match params declared by definition: {0}")] TypeArgMismatch(#[from] TypeArgError), } @@ -141,9 +147,9 @@ impl Debug for LowerFunc { } /// Sealed trait for shared type parametrised functionality between [`TypeDef`] and [`OpDef`]. -pub trait TypeParametrisedInternal: sealed::Sealed { +pub trait TypeParametrisedInternal: sealed::SealedDef { /// The concrete object built by binding type arguments to parameters - type Concrete; + type Concrete: CustomConcrete; /// The resource-unique name. fn name(&self) -> &SmolStr; /// Type parameters. @@ -165,14 +171,45 @@ pub trait TypeParametrisedInternal: sealed::Sealed { /// This function will return an error if the provided arguments are not /// valid instances of the TypeDef parameters. fn to_custom(&self, args: impl Into>) -> Result; + + /// Check custom instance is a valid instantiation of this definition. + /// + /// # Errors + /// + /// This function will return an error if the type of the instance does not + /// match the definition. + fn check_custom(&self, custom: &Self::Concrete) -> Result<(), SignatureError> { + if self.resource() != Some(custom.resource()) { + return Err(SignatureError::ResourceMismatch( + self.resource().cloned(), + Some(custom.resource().clone()), + )); + } + if self.name() != custom.name() { + return Err(SignatureError::NameMismatch( + self.name().clone(), + custom.name().clone(), + )); + } + + self.check_args(custom.args())?; + + Ok(()) + } } mod sealed { + use crate::{ops::custom::OpaqueOp, types::CustomType}; + use super::{OpDef, TypeDef}; - pub trait Sealed {} - impl Sealed for OpDef {} - impl Sealed for TypeDef {} + pub trait SealedDef {} + impl SealedDef for OpDef {} + impl SealedDef for TypeDef {} + + pub trait SealedConcrete {} + impl SealedConcrete for OpaqueOp {} + impl SealedConcrete for CustomType {} } /// Serializable definition for dynamically loaded operations. @@ -382,6 +419,16 @@ pub struct TypeDef { pub tag: TypeDefTag, } +/// Concrete instantiations of types and operations defined in resources. +pub trait CustomConcrete: sealed::SealedConcrete { + /// Name of the definition. + fn name(&self) -> &SmolStr; + /// Type arguments. + fn args(&self) -> &[TypeArg]; + /// Parent resource. + fn resource(&self) -> &ResourceId; +} + impl TypeParametrisedInternal for TypeDef { type Concrete = CustomType; @@ -472,6 +519,11 @@ impl Resource { &self.operations } + /// Allows read-only access to the types in this Resource + pub fn types(&self) -> &HashMap { + &self.types + } + /// Returns the name of the resource. pub fn name(&self) -> &str { &self.name diff --git a/src/types/custom.rs b/src/types/custom.rs index 807bbc5ac..d6422cb88 100644 --- a/src/types/custom.rs +++ b/src/types/custom.rs @@ -4,7 +4,7 @@ use smol_str::SmolStr; use std::fmt::{self, Display}; -use crate::resource::ResourceId; +use crate::resource::{CustomConcrete, ResourceId}; use super::{type_param::TypeArg, ClassicType, Container}; @@ -37,28 +37,23 @@ impl CustomType { } } - // /// Creates a new opaque type with no parameters - // pub const fn new_simple(id: SmolStr) -> Self { - // Self { - // id, - // args: vec![], - // resource: ResourceId::default(), - // } - // } + /// Returns a [`ClassicType`] containing this opaque type. + pub const fn classic_type(self) -> ClassicType { + ClassicType::Container(Container::Opaque(self)) + } +} - /// Returns the unique identifier of the opaque type. - pub fn id(&self) -> &str { +impl CustomConcrete for CustomType { + fn name(&self) -> &SmolStr { &self.id } - /// Returns the arguments of the opaque type. - pub fn args(&self) -> &[TypeArg] { + fn args(&self) -> &[TypeArg] { &self.args } - /// Returns a [`ClassicType`] containing this opaque type. - pub const fn classic_type(self) -> ClassicType { - ClassicType::Container(Container::Opaque(self)) + fn resource(&self) -> &ResourceId { + &self.resource } } From b222db2990fcd332a0680a8e9b7ab33c383455e8 Mon Sep 17 00:00:00 2001 From: Seyon Sivarajah Date: Mon, 31 Jul 2023 15:37:09 +0100 Subject: [PATCH 4/4] make traits private just use shared trait code method implementations --- src/extensions/rotation.rs | 4 +- src/ops/custom.rs | 13 +-- src/resource.rs | 157 ++++++++++++++++++++++++++----------- src/types/custom.rs | 13 +-- 4 files changed, 131 insertions(+), 56 deletions(-) diff --git a/src/extensions/rotation.rs b/src/extensions/rotation.rs index 0ad596a7c..d02d27187 100644 --- a/src/extensions/rotation.rs +++ b/src/extensions/rotation.rs @@ -292,7 +292,7 @@ impl Neg for &AngleValue { #[cfg(test)] mod test { - use crate::resource::{CustomConcrete, SignatureError, TypeParametrisedInternal}; + use crate::resource::SignatureError; use super::*; @@ -302,7 +302,7 @@ mod test { let angle = resource.types().get("angle").unwrap(); - let custom = angle.to_custom([]).unwrap(); + let custom = angle.instantiate_concrete([]).unwrap(); angle.check_custom(&custom).unwrap(); diff --git a/src/ops/custom.rs b/src/ops/custom.rs index edfabdbb5..a8c222620 100644 --- a/src/ops/custom.rs +++ b/src/ops/custom.rs @@ -6,7 +6,7 @@ use std::sync::Arc; use thiserror::Error; use crate::hugr::{HugrMut, HugrView}; -use crate::resource::{CustomConcrete, OpDef, ResourceId, ResourceSet, SignatureError}; +use crate::resource::{OpDef, ResourceId, ResourceSet, SignatureError}; use crate::types::{type_param::TypeArg, Signature, SignatureDescription}; use crate::{Hugr, Node, Resource}; @@ -188,16 +188,19 @@ impl OpaqueOp { } } -impl CustomConcrete for OpaqueOp { - fn name(&self) -> &SmolStr { +impl OpaqueOp { + /// Unique name of the operation. + pub fn name(&self) -> &SmolStr { &self.op_name } - fn args(&self) -> &[TypeArg] { + /// Type arguments. + pub fn args(&self) -> &[TypeArg] { &self.args } - fn resource(&self) -> &ResourceId { + /// Parent resource. + pub fn resource(&self) -> &ResourceId { &self.resource } } diff --git a/src/resource.rs b/src/resource.rs index 20e0b3582..33b552ab6 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -147,8 +147,43 @@ impl Debug for LowerFunc { } } -/// Sealed trait for shared type parametrised functionality between [`TypeDef`] and [`OpDef`]. -pub trait TypeParametrisedInternal: sealed::SealedDef { +/// Concrete instantiations of types and operations defined in resources. +trait CustomConcrete { + fn def_name(&self) -> &SmolStr; + fn type_args(&self) -> &[TypeArg]; + fn parent_resource(&self) -> &ResourceId; +} + +impl CustomConcrete for OpaqueOp { + fn def_name(&self) -> &SmolStr { + self.name() + } + + fn type_args(&self) -> &[TypeArg] { + self.args() + } + + fn parent_resource(&self) -> &ResourceId { + self.resource() + } +} + +impl CustomConcrete for CustomType { + fn def_name(&self) -> &SmolStr { + self.name() + } + + fn type_args(&self) -> &[TypeArg] { + self.args() + } + + fn parent_resource(&self) -> &ResourceId { + self.resource() + } +} + +/// Type-parametrised functionality shared between [`TypeDef`] and [`OpDef`]. +trait TypeParametrised: sealed::SealedDef { /// The concrete object built by binding type arguments to parameters type Concrete: CustomConcrete; /// The resource-unique name. @@ -158,42 +193,34 @@ pub trait TypeParametrisedInternal: sealed::SealedDef { /// The parent resource. if any. fn resource(&self) -> Option<&ResourceId>; /// Check provided type arguments are valid against parameters. - fn check_args(&self, args: &[TypeArg]) -> Result<(), SignatureError> { + fn check_args_impl(&self, args: &[TypeArg]) -> Result<(), SignatureError> { for (a, p) in args.iter().zip(self.params().iter()) { check_type_arg(a, p).map_err(SignatureError::TypeArgMismatch)?; } Ok(()) } - /// Instantiate a concrete instance by providing type arguments. - /// - /// # Errors - /// - /// This function will return an error if the provided arguments are not - /// valid instances of the TypeDef parameters. - fn to_custom(&self, args: impl Into>) -> Result; - /// Check custom instance is a valid instantiation of this definition. /// /// # Errors /// /// This function will return an error if the type of the instance does not /// match the definition. - fn check_custom(&self, custom: &Self::Concrete) -> Result<(), SignatureError> { - if self.resource() != Some(custom.resource()) { + fn check_concrete_impl(&self, custom: &Self::Concrete) -> Result<(), SignatureError> { + if self.resource() != Some(custom.parent_resource()) { return Err(SignatureError::ResourceMismatch( self.resource().cloned(), - Some(custom.resource().clone()), + Some(custom.parent_resource().clone()), )); } - if self.name() != custom.name() { + if self.name() != custom.def_name() { return Err(SignatureError::NameMismatch( self.name().clone(), - custom.name().clone(), + custom.def_name().clone(), )); } - self.check_args(custom.args())?; + self.check_args_impl(custom.type_args())?; Ok(()) } @@ -239,18 +266,32 @@ pub struct OpDef { lower_funcs: Vec, } -impl TypeParametrisedInternal for OpDef { - type Concrete = OpaqueOp; - - fn params(&self) -> &[TypeParam] { - &self.params +impl OpDef { + /// Check provided type arguments are valid against parameters. + pub fn check_args(&self, args: &[TypeArg]) -> Result<(), SignatureError> { + self.check_args_impl(args) } - fn name(&self) -> &SmolStr { - &self.name + /// Check [`OpaqueOp`] is a valid instantiation of this definition. + /// + /// # Errors + /// + /// This function will return an error if the type of the instance does not + /// match the definition. + pub fn check_opaque(&self, opaque: &OpaqueOp) -> Result<(), SignatureError> { + self.check_concrete_impl(opaque) } - fn to_custom(&self, args: impl Into>) -> Result { + /// Instantiate a concrete [`OpaqueOp`] by providing type arguments. + /// + /// # Errors + /// + /// This function will return an error if the provided arguments are not + /// valid instances of the type parameters. + pub fn instantiate_opaque( + &self, + args: impl Into>, + ) -> Result { let args = args.into(); self.check_args(&args)?; @@ -263,6 +304,18 @@ impl TypeParametrisedInternal for OpDef { None, )) } +} + +impl TypeParametrised for OpDef { + type Concrete = OpaqueOp; + + fn params(&self) -> &[TypeParam] { + &self.params + } + + fn name(&self) -> &SmolStr { + &self.name + } fn resource(&self) -> Option<&ResourceId> { self.resource.as_ref() @@ -420,36 +473,52 @@ pub struct TypeDef { pub tag: TypeDefTag, } -/// Concrete instantiations of types and operations defined in resources. -pub trait CustomConcrete: sealed::SealedConcrete { - /// Name of the definition. - fn name(&self) -> &SmolStr; - /// Type arguments. - fn args(&self) -> &[TypeArg]; - /// Parent resource. - fn resource(&self) -> &ResourceId; -} - -impl TypeParametrisedInternal for TypeDef { - type Concrete = CustomType; - - fn params(&self) -> &[TypeParam] { - &self.params +impl TypeDef { + /// Check provided type arguments are valid against parameters. + pub fn check_args(&self, args: &[TypeArg]) -> Result<(), SignatureError> { + self.check_args_impl(args) } - fn name(&self) -> &SmolStr { - &self.name + /// Check [`CustomType`] is a valid instantiation of this definition. + /// + /// # Errors + /// + /// This function will return an error if the type of the instance does not + /// match the definition. + pub fn check_custom(&self, custom: &CustomType) -> Result<(), SignatureError> { + self.check_concrete_impl(custom) } - fn to_custom(&self, args: impl Into>) -> Result { + /// Instantiate a concrete [`CustomType`] by providing type arguments. + /// + /// # Errors + /// + /// This function will return an error if the provided arguments are not + /// valid instances of the type parameters. + pub fn instantiate_concrete( + &self, + args: impl Into>, + ) -> Result { let args = args.into(); - self.check_args(&args)?; + self.check_args_impl(&args)?; Ok(CustomType::new( self.name().clone(), args, self.resource().expect("Resource not set.").clone(), )) } +} + +impl TypeParametrised for TypeDef { + type Concrete = CustomType; + + fn params(&self) -> &[TypeParam] { + &self.params + } + + fn name(&self) -> &SmolStr { + &self.name + } fn resource(&self) -> Option<&ResourceId> { self.resource.as_ref() diff --git a/src/types/custom.rs b/src/types/custom.rs index d6422cb88..b2fd97990 100644 --- a/src/types/custom.rs +++ b/src/types/custom.rs @@ -4,7 +4,7 @@ use smol_str::SmolStr; use std::fmt::{self, Display}; -use crate::resource::{CustomConcrete, ResourceId}; +use crate::resource::ResourceId; use super::{type_param::TypeArg, ClassicType, Container}; @@ -43,16 +43,19 @@ impl CustomType { } } -impl CustomConcrete for CustomType { - fn name(&self) -> &SmolStr { +impl CustomType { + /// unique name of the type. + pub fn name(&self) -> &SmolStr { &self.id } - fn args(&self) -> &[TypeArg] { + /// Type arguments. + pub fn args(&self) -> &[TypeArg] { &self.args } - fn resource(&self) -> &ResourceId { + /// Parent resource. + pub fn resource(&self) -> &ResourceId { &self.resource } }