Skip to content

Commit

Permalink
[naga] Break naga::arena up into submodules.
Browse files Browse the repository at this point in the history
This commit is almost entirely code motion. The only meaningful
changes should be:

- changes to imports
- changes to visibility
- changes to use visible associated constructor functions instead of
  trying to construct values directly using now-invisible fields
- moving the crate-level "Arena" docs into the `arena` module
  • Loading branch information
jimblandy committed Jun 24, 2024
1 parent bef9eb4 commit a5d57db
Show file tree
Hide file tree
Showing 6 changed files with 652 additions and 600 deletions.
126 changes: 126 additions & 0 deletions naga/src/arena/handle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
//! Well-typed indices into [`Arena`]s and [`UniqueArena`]s.
//!
//! This module defines [`Handle`] and related types.
//!
//! [`Arena`]: super::Arena
//! [`UniqueArena`]: super::UniqueArena
use std::{cmp::Ordering, fmt, hash, marker::PhantomData};

/// An unique index in the arena array that a handle points to.
/// The "non-max" part ensures that an `Option<Handle<T>>` has
/// the same size and representation as `Handle<T>`.
pub type Index = crate::non_max_u32::NonMaxU32;

#[derive(Clone, Copy, Debug, thiserror::Error, PartialEq)]
#[error("Handle {index} of {kind} is either not present, or inaccessible yet")]
pub struct BadHandle {
pub kind: &'static str,
pub index: usize,
}

impl BadHandle {
pub fn new<T>(handle: Handle<T>) -> Self {
Self {
kind: std::any::type_name::<T>(),
index: handle.index(),
}
}
}

/// A strongly typed reference to an arena item.
///
/// A `Handle` value can be used as an index into an [`Arena`] or [`UniqueArena`].
///
/// [`Arena`]: super::Arena
/// [`UniqueArena`]: super::UniqueArena
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
#[cfg_attr(
any(feature = "serialize", feature = "deserialize"),
serde(transparent)
)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Handle<T> {
index: Index,
#[cfg_attr(any(feature = "serialize", feature = "deserialize"), serde(skip))]
marker: PhantomData<T>,
}

impl<T> Clone for Handle<T> {
fn clone(&self) -> Self {
*self
}
}

impl<T> Copy for Handle<T> {}

impl<T> PartialEq for Handle<T> {
fn eq(&self, other: &Self) -> bool {
self.index == other.index
}
}

impl<T> Eq for Handle<T> {}

impl<T> PartialOrd for Handle<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}

impl<T> Ord for Handle<T> {
fn cmp(&self, other: &Self) -> Ordering {
self.index.cmp(&other.index)
}
}

impl<T> fmt::Debug for Handle<T> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "[{}]", self.index)
}
}

impl<T> hash::Hash for Handle<T> {
fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
self.index.hash(hasher)
}
}

impl<T> Handle<T> {
pub(crate) const fn new(index: Index) -> Self {
Handle {
index,
marker: PhantomData,
}
}

/// Returns the index of this handle.
pub const fn index(self) -> usize {
self.index.get() as usize
}

/// Convert a `usize` index into a `Handle<T>`.
pub(super) fn from_usize(index: usize) -> Self {
let handle_index = u32::try_from(index)
.ok()
.and_then(Index::new)
.expect("Failed to insert into arena. Handle overflows");
Handle::new(handle_index)
}

/// Convert a `usize` index into a `Handle<T>`, without range checks.
pub(super) const unsafe fn from_usize_unchecked(index: usize) -> Self {
Handle::new(Index::new_unchecked(index as u32))
}

/// Write this handle's index to `formatter`, preceded by `prefix`.
pub fn write_prefixed(
&self,
formatter: &mut fmt::Formatter,
prefix: &'static str,
) -> fmt::Result {
formatter.write_str(prefix)?;
<usize as fmt::Display>::fmt(&self.index(), formatter)
}
}
105 changes: 105 additions & 0 deletions naga/src/arena/handlevec.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
//! The [`HandleVec`] type and associated definitions.
use super::handle::Handle;

use std::marker::PhantomData;
use std::ops;

/// A [`Vec`] indexed by [`Handle`]s.
///
/// A `HandleVec<T, U>` is a [`Vec<U>`] indexed by values of type `Handle<T>`,
/// rather than `usize`.
///
/// Rather than a `push` method, `HandleVec` has an [`insert`] method, analogous
/// to [`HashMap::insert`], that requires you to provide the handle at which the
/// new value should appear. However, since `HandleVec` only supports insertion
/// at the end, the given handle's index must be equal to the the `HandleVec`'s
/// current length; otherwise, the insertion will panic.
///
/// [`insert`]: HandleVec::insert
/// [`HashMap::insert`]: std::collections::HashMap::insert
#[derive(Debug)]
pub(crate) struct HandleVec<T, U> {
inner: Vec<U>,
as_keys: PhantomData<T>,
}

impl<T, U> Default for HandleVec<T, U> {
fn default() -> Self {
Self {
inner: vec![],
as_keys: PhantomData,
}
}
}

#[allow(dead_code)]
impl<T, U> HandleVec<T, U> {
pub(crate) const fn new() -> Self {
Self {
inner: vec![],
as_keys: PhantomData,
}
}

pub(crate) fn with_capacity(capacity: usize) -> Self {
Self {
inner: Vec::with_capacity(capacity),
as_keys: PhantomData,
}
}

pub(crate) fn len(&self) -> usize {
self.inner.len()
}

/// Insert a mapping from `handle` to `value`.
///
/// Unlike a [`HashMap`], a `HandleVec` can only have new entries inserted at
/// the end, like [`Vec::push`]. So the index of `handle` must equal
/// [`self.len()`].
///
/// [`HashMap`]: std::collections::HashMap
/// [`self.len()`]: HandleVec::len
pub(crate) fn insert(&mut self, handle: Handle<T>, value: U) {
assert_eq!(handle.index(), self.inner.len());
self.inner.push(value);
}

pub(crate) fn get(&self, handle: Handle<T>) -> Option<&U> {
self.inner.get(handle.index())
}

pub(crate) fn clear(&mut self) {
self.inner.clear()
}

pub(crate) fn resize(&mut self, len: usize, fill: U)
where
U: Clone,
{
self.inner.resize(len, fill);
}

pub(crate) fn iter(&self) -> impl Iterator<Item = &U> {
self.inner.iter()
}

pub(crate) fn iter_mut(&mut self) -> impl Iterator<Item = &mut U> {
self.inner.iter_mut()
}
}

impl<T, U> ops::Index<Handle<T>> for HandleVec<T, U> {
type Output = U;

fn index(&self, handle: Handle<T>) -> &Self::Output {
&self.inner[handle.index()]
}
}

impl<T, U> ops::IndexMut<Handle<T>> for HandleVec<T, U> {
fn index_mut(&mut self, handle: Handle<T>) -> &mut Self::Output {
&mut self.inner[handle.index()]
}
}
Loading

0 comments on commit a5d57db

Please sign in to comment.