Skip to content

Commit

Permalink
Move TypeRow into own file, introduce TypeRowElem (#329)
Browse files Browse the repository at this point in the history
TypeRowElem =~= Clone + 'static (blanket impl) allows anything in a TypeRow
Move TypeRow(,Elem) into type_row.rs, used by simple.rs but no in-crate deps
PrimType extends TypeRowElem + sealed (+ Debug)
  • Loading branch information
acl-cqc authored Aug 2, 2023
1 parent b16eb21 commit b9ffa88
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 147 deletions.
2 changes: 1 addition & 1 deletion src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ pub(crate) use impl_box_clone;
macro_rules! type_row {
() => {
{
$crate::types::simple::TypeRow::new()
$crate::types::TypeRow::new()
}
};
($($t:expr),+ $(,)?) => {
Expand Down
5 changes: 3 additions & 2 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
pub mod custom;
pub mod simple;
pub mod type_param;
pub mod type_row;

use std::fmt::{self, Display, Write};
use std::ops::Index;
Expand All @@ -12,9 +13,9 @@ use pyo3::prelude::*;

pub use custom::CustomType;
pub use simple::{
ClassicRow, ClassicType, Container, HashableType, PrimType, SimpleRow, SimpleType, TypeRow,
TypeTag,
ClassicRow, ClassicType, Container, HashableType, PrimType, SimpleRow, SimpleType, TypeTag,
};
pub use type_row::TypeRow;

use delegate::delegate;
use smol_str::SmolStr;
Expand Down
147 changes: 10 additions & 137 deletions src/types/simple.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
//! Dataflow types

use std::{
borrow::Cow,
fmt::{self, Display, Formatter, Write},
ops::{Deref, DerefMut},
};
use std::fmt::{self, Display, Formatter, Write};

use super::type_row::{TypeRow, TypeRowElem};
use super::{custom::CustomType, AbstractSignature};
use crate::{classic_row, ops::constant::HugrIntWidthStore};
use itertools::Itertools;
use serde_repr::{Deserialize_repr, Serialize_repr};
use smol_str::SmolStr;

use super::{custom::CustomType, AbstractSignature};
use crate::{classic_row, ops::constant::HugrIntWidthStore, utils::display_list};

/// A type that represents concrete data. Can include both linear and classical parts.
///
// TODO: Derive pyclass
Expand Down Expand Up @@ -84,8 +80,8 @@ impl TypeTag {
}
}

/// Trait of primitive types (SimpleType or ClassicType).
pub trait PrimType: sealed::Sealed + std::fmt::Debug + Clone + 'static {
/// Trait of primitive types, i.e. that are uniquely identified by a [TypeTag]
pub trait PrimType: TypeRowElem + std::fmt::Debug + sealed::Sealed {
// may be updated with functions in future for necessary shared functionality
// across ClassicType, SimpleType and HashableType.
// Currently used to constrain Container<T>
Expand All @@ -106,7 +102,7 @@ mod sealed {
/// For algebraic types Sum, Tuple if one element of type row is linear, the
/// overall type is too.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Container<T: PrimType> {
pub enum Container<T: TypeRowElem> {
/// Variable sized list of T.
List(Box<T>),
/// Hash map from hashable key type to value T.
Expand Down Expand Up @@ -429,40 +425,19 @@ impl<'a> TryFrom<&'a SimpleType> for &'a ClassicType {
}
}

/// List of types, used for function signatures.
#[derive(Clone, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)]
//#[cfg_attr(feature = "pyo3", pyclass)] // TODO: expose unparameterized versions
#[non_exhaustive]
#[serde(transparent)]
pub struct TypeRow<T: PrimType> {
/// The datatypes in the row.
types: Cow<'static, [T]>,
}

/// A row of [SimpleType]s
pub type SimpleRow = TypeRow<SimpleType>;

/// A row of [ClassicType]s
pub type ClassicRow = TypeRow<ClassicType>;

impl<T: Display + PrimType> Display for TypeRow<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_char('[')?;
display_list(self.types.as_ref(), f)?;
f.write_char(']')
}
}

impl TypeRow<SimpleType> {
/// Returns whether the row contains only classic data.
/// (Note: this is defined only on [`TypeRow<SimpleType>`] because
/// it is guaranteed true for any other TypeRow)
#[inline]
pub fn purely_classical(&self) -> bool {
self.types
.iter()
.map(PrimType::tag)
.all(TypeTag::is_classical)
self.iter().map(PrimType::tag).all(TypeTag::is_classical)
}
}

Expand All @@ -478,121 +453,19 @@ impl TypeRow<ClassicType> {
}
}

// TODO some of these, but not all, will probably want exposing via
// pyo3 wrappers eventually.
impl<T: PrimType> TypeRow<T> {
/// Create a new empty row.
pub const fn new() -> Self {
Self {
types: Cow::Owned(Vec::new()),
}
}

/// Iterator over the types in the row.
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.types.iter()
}

/// Returns the number of types in the row.
#[inline(always)]
pub fn len(&self) -> usize {
self.types.len()
}

/// Returns `true` if the row contains no types.
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.types.len() == 0
}

/// Returns whether the row contains only hashable classic data.
#[inline(always)]
pub fn purely_hashable(&self) -> bool {
self.types
.iter()
.map(PrimType::tag)
.all(TypeTag::is_hashable)
self.iter().map(PrimType::tag).all(TypeTag::is_hashable)
}

/// Returns the smallest [TypeTag] that contains all elements of the row
pub fn containing_tag(&self) -> TypeTag {
self.types
.iter()
self.iter()
.map(PrimType::tag)
.fold(TypeTag::Hashable, TypeTag::union)
}

/// Mutable iterator over the types in the row.
pub fn to_mut(&mut self) -> &mut Vec<T> {
self.types.to_mut()
}

/// Allow access (consumption) of the contained elements
pub fn into_owned(self) -> Vec<T> {
self.types.into_owned()
}

#[inline(always)]
/// Returns the port type given an offset. Returns `None` if the offset is out of bounds.
pub fn get(&self, offset: usize) -> Option<&T> {
self.types.get(offset)
}

#[inline(always)]
/// Returns the port type given an offset. Returns `None` if the offset is out of bounds.
pub fn get_mut(&mut self, offset: usize) -> Option<&mut T> {
self.types.to_mut().get_mut(offset)
}

fn try_convert_elems<D: PrimType + TryFrom<T>>(self) -> Result<TypeRow<D>, D::Error> {
let elems: Vec<D> = self
.into_owned()
.into_iter()
.map(D::try_from)
.collect::<Result<_, _>>()?;
Ok(TypeRow::from(elems))
}

/// Converts the elements of this TypeRow into some other type that they can `.into()`
pub fn map_into<T2: PrimType + From<T>>(self) -> TypeRow<T2> {
TypeRow::from(
self.into_owned()
.into_iter()
.map(T2::from)
.collect::<Vec<T2>>(),
)
}
}

impl<T: PrimType> Default for TypeRow<T> {
fn default() -> Self {
Self::new()
}
}

impl<F, T: PrimType> From<F> for TypeRow<T>
where
F: Into<Cow<'static, [T]>>,
{
fn from(types: F) -> Self {
Self {
types: types.into(),
}
}
}

impl<T: PrimType> Deref for TypeRow<T> {
type Target = [T];

fn deref(&self) -> &Self::Target {
&self.types
}
}

impl<T: PrimType> DerefMut for TypeRow<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.types.to_mut()
}
}

#[cfg(test)]
Expand Down
7 changes: 0 additions & 7 deletions src/types/simple/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,6 @@ pub(crate) enum SerSimpleType {
},
}

impl super::sealed::Sealed for SerSimpleType {}
impl PrimType for SerSimpleType {
fn tag(&self) -> TypeTag {
unimplemented!()
}
}

trait SerializableType: PrimType {
const TAG: TypeTag;
}
Expand Down
134 changes: 134 additions & 0 deletions src/types/type_row.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
//! Rows of types, used for function signatures,
//! designed to support efficient static allocation.

use std::{
borrow::Cow,
fmt::{self, Display, Write},
ops::{Deref, DerefMut},
};

use crate::utils::display_list;

/// Base trait for anything that can be put in a [TypeRow]
pub trait TypeRowElem: Clone + 'static {}

impl<T: Clone + 'static> TypeRowElem for T {}

/// List of types, used for function signatures.
#[derive(Clone, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)]
//#[cfg_attr(feature = "pyo3", pyclass)] // TODO: expose unparameterized versions
#[non_exhaustive]
#[serde(transparent)]
pub struct TypeRow<T: TypeRowElem> {
/// The datatypes in the row.
types: Cow<'static, [T]>,
}

impl<T: Display + TypeRowElem> Display for TypeRow<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_char('[')?;
display_list(self.types.as_ref(), f)?;
f.write_char(']')
}
}

// TODO some of these, but not all, will probably want exposing via
// pyo3 wrappers eventually.
impl<T: TypeRowElem> TypeRow<T> {
/// Create a new empty row.
pub const fn new() -> Self {
Self {
types: Cow::Owned(Vec::new()),
}
}

/// Iterator over the types in the row.
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.types.iter()
}

/// Returns the number of types in the row.
#[inline(always)]
pub fn len(&self) -> usize {
self.types.len()
}

/// Returns `true` if the row contains no types.
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.types.len() == 0
}
/// Mutable iterator over the types in the row.
pub fn to_mut(&mut self) -> &mut Vec<T> {
self.types.to_mut()
}

/// Allow access (consumption) of the contained elements
pub fn into_owned(self) -> Vec<T> {
self.types.into_owned()
}

#[inline(always)]
/// Returns the port type given an offset. Returns `None` if the offset is out of bounds.
pub fn get(&self, offset: usize) -> Option<&T> {
self.types.get(offset)
}

#[inline(always)]
/// Returns the port type given an offset. Returns `None` if the offset is out of bounds.
pub fn get_mut(&mut self, offset: usize) -> Option<&mut T> {
self.types.to_mut().get_mut(offset)
}

pub(super) fn try_convert_elems<D: TypeRowElem + TryFrom<T>>(
self,
) -> Result<TypeRow<D>, D::Error> {
let elems: Vec<D> = self
.into_owned()
.into_iter()
.map(D::try_from)
.collect::<Result<_, _>>()?;
Ok(TypeRow::from(elems))
}

/// Converts the elements of this TypeRow into some other type that they can `.into()`
pub fn map_into<T2: TypeRowElem + From<T>>(self) -> TypeRow<T2> {
TypeRow::from(
self.into_owned()
.into_iter()
.map(T2::from)
.collect::<Vec<T2>>(),
)
}
}

impl<T: TypeRowElem> Default for TypeRow<T> {
fn default() -> Self {
Self::new()
}
}

impl<F, T: TypeRowElem> From<F> for TypeRow<T>
where
F: Into<Cow<'static, [T]>>,
{
fn from(types: F) -> Self {
Self {
types: types.into(),
}
}
}

impl<T: TypeRowElem> Deref for TypeRow<T> {
type Target = [T];

fn deref(&self) -> &Self::Target {
&self.types
}
}

impl<T: TypeRowElem> DerefMut for TypeRow<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.types.to_mut()
}
}

0 comments on commit b9ffa88

Please sign in to comment.