From 58c5a01312fef4d7416f253a31fae6cf77d66271 Mon Sep 17 00:00:00 2001 From: John Date: Wed, 10 Jul 2024 14:56:17 -0500 Subject: [PATCH] cl-structures: Clean up IndexMap and fix doctests --- compiler/cl-structures/src/index_map.rs | 65 ++++++++++++++++--------- compiler/cl-typeck/examples/typeck.rs | 5 +- compiler/cl-typeck/src/use_importer.rs | 6 +-- 3 files changed, 48 insertions(+), 28 deletions(-) diff --git a/compiler/cl-structures/src/index_map.rs b/compiler/cl-structures/src/index_map.rs index d4229b6..e6c90a7 100644 --- a/compiler/cl-structures/src/index_map.rs +++ b/compiler/cl-structures/src/index_map.rs @@ -6,12 +6,12 @@ //! ```rust //! # use cl_structures::index_map::*; //! // first, create a new MapIndex type (this ensures type safety) -//! make_intern_key!{ -//! NumbersKey +//! make_index! { +//! Number //! } //! //! // then, create a map with that type -//! let mut numbers: IndexMap = IndexMap::new(); +//! let mut numbers: IndexMap = IndexMap::new(); //! let first = numbers.insert(1); //! let second = numbers.insert(2); //! let third = numbers.insert(3); @@ -29,6 +29,10 @@ //! ``` /// Creates newtype indices over [`usize`] for use as [IndexMap] keys. +/// +/// Generated key types implement [Clone], [Copy], +/// [Debug](core::fmt::Debug), [PartialEq], [Eq], [PartialOrd], [Ord], [Hash](core::hash::Hash), +/// and [MapIndex]. #[macro_export] macro_rules! make_index {($($(#[$meta:meta])* $name:ident),*$(,)?) => {$( $(#[$meta])* @@ -39,39 +43,41 @@ macro_rules! make_index {($($(#[$meta:meta])* $name:ident),*$(,)?) => {$( impl $crate::index_map::MapIndex for $name { #[doc = concat!("Constructs a [`", stringify!($name), "`] from a [`usize`] without checking bounds.\n")] /// The provided value should be within the bounds of its associated container + #[inline] fn from_usize(value: usize) -> Self { Self(value) } + #[inline] fn get(&self) -> usize { self.0 } } + impl From< $name > for usize { fn from(value: $name) -> Self { value.0 } } )*}} + +use self::iter::MapIndexIter; use core::slice::GetManyMutError; use std::ops::{Index, IndexMut}; pub use make_index; -use self::iter::MapIndexIter; - /// An index into a [IndexMap]. For full type-safety, /// there should be a unique [MapIndex] for each [IndexMap]. pub trait MapIndex: std::fmt::Debug { /// Constructs an [`MapIndex`] from a [`usize`] without checking bounds. /// /// The provided value should be within the bounds of its associated container. - // ID::from_raw_unchecked here isn't *actually* unsafe, since bounds should always be - // checked, however, the function has unverifiable preconditions. fn from_usize(value: usize) -> Self; /// Gets the index of the [`MapIndex`] by value fn get(&self) -> usize; } +/// It's an array. Lmao. #[derive(Clone, Debug, PartialEq, Eq)] pub struct IndexMap { map: Vec, @@ -79,16 +85,24 @@ pub struct IndexMap { } impl IndexMap { + /// Constructs an empty IndexMap. pub fn new() -> Self { Self::default() } + + /// Gets a reference to the value in slot `index`. pub fn get(&self, index: K) -> Option<&V> { self.map.get(index.get()) } + + /// Gets a mutable reference to the value in slot `index`. pub fn get_mut(&mut self, index: K) -> Option<&mut V> { self.map.get_mut(index.get()) } + /// Returns mutable references to many indices at once. + /// + /// Returns an error if any index is out of bounds, or if the same index was passed twice. pub fn get_many_mut( &mut self, indices: [K; N], @@ -96,13 +110,18 @@ impl IndexMap { self.map.get_many_mut(indices.map(|id| id.get())) } - pub fn iter(&self) -> impl Iterator { + /// Returns an iterator over the IndexMap. + pub fn values(&self) -> impl Iterator { self.map.iter() } - pub fn iter_mut(&mut self) -> impl Iterator { + + /// Returns an iterator that allows modifying each value. + pub fn values_mut(&mut self) -> impl Iterator { self.map.iter_mut() } - pub fn key_iter(&self) -> iter::MapIndexIter { + + /// Returns an iterator over all keys in the IndexMap. + pub fn keys(&self) -> iter::MapIndexIter { // Safety: IndexMap currently has map.len() entries, and data cannot be removed MapIndexIter::new(0..self.map.len()) } @@ -113,6 +132,7 @@ impl IndexMap { (value < self.map.len()).then(|| K::from_usize(value)) } + /// Inserts a new item into the IndexMap, returning the key associated with it. pub fn insert(&mut self, value: V) -> K { let id = self.map.len(); self.map.push(value); @@ -120,6 +140,11 @@ impl IndexMap { // Safety: value was pushed to `self.map[id]` K::from_usize(id) } + + /// Replaces a value in the IndexMap, returning the old value. + pub fn replace(&mut self, key: K, value: V) -> V { + std::mem::replace(&mut self[key], value) + } } impl Default for IndexMap { @@ -138,6 +163,7 @@ impl Index for IndexMap { } } } + impl IndexMut for IndexMap { fn index_mut(&mut self, index: K) -> &mut Self::Output { match self.map.get_mut(index.get()) { @@ -148,15 +174,14 @@ impl IndexMut for IndexMap { } mod iter { - use std::{marker::PhantomData, ops::Range}; - + //! Iterators for [IndexMap](super::IndexMap) use super::MapIndex; + use std::{marker::PhantomData, ops::Range}; /// Iterates over the keys of an [IndexMap](super::IndexMap), independently of the map. /// - /// This is guaranteed to never overrun the length of the map, - /// but is *NOT* guaranteed to iterate over all elements of the map - /// if the map is extended during iteration. + /// This is guaranteed to never overrun the length of the map, but is *NOT* guaranteed + /// to iterate over all elements of the map if the map is extended during iteration. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct MapIndexIter { range: Range, @@ -165,13 +190,8 @@ mod iter { impl MapIndexIter { /// Creates a new [MapIndexIter] producing the given [MapIndex] - /// - /// # Safety: - /// - Range must not exceed bounds of the associated [IndexMap](super::IndexMap) - /// - Items must not be removed from the map - /// - Items must be contiguous within the map pub(super) fn new(range: Range) -> Self { - Self { range, _id: Default::default() } + Self { range, _id: PhantomData } } } @@ -179,18 +199,19 @@ mod iter { type Item = ID; fn next(&mut self) -> Option { - // Safety: MapIndexIter can only be created by MapIndexIter::new() Some(ID::from_usize(self.range.next()?)) } fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } } + impl DoubleEndedIterator for MapIndexIter { fn next_back(&mut self) -> Option { // Safety: see above Some(ID::from_usize(self.range.next_back()?)) } } + impl ExactSizeIterator for MapIndexIter {} } diff --git a/compiler/cl-typeck/examples/typeck.rs b/compiler/cl-typeck/examples/typeck.rs index 23c06f3..03f97c0 100644 --- a/compiler/cl-typeck/examples/typeck.rs +++ b/compiler/cl-typeck/examples/typeck.rs @@ -126,7 +126,7 @@ fn query_type_expression(prj: &mut Project) -> Result<(), RlError> { fn resolve_all(prj: &mut Project) -> Result<(), Box> { prj.resolve_imports()?; - for id in prj.pool.key_iter() { + for id in prj.pool.keys() { resolve(prj, id)?; } println!("Types resolved successfully!"); @@ -135,7 +135,8 @@ fn resolve_all(prj: &mut Project) -> Result<(), Box> { fn list_types(prj: &mut Project) { println!(" name\x1b[30G type"); - for (idx, Def { kind, node: Node { vis, kind: source, .. }, .. }) in prj.pool.iter().enumerate() + for (idx, Def { kind, node: Node { vis, kind: source, .. }, .. }) in + prj.pool.values().enumerate() { print!("{idx:3}: {vis}"); if let Some(Some(name)) = source.as_ref().map(NodeSource::name) { diff --git a/compiler/cl-typeck/src/use_importer.rs b/compiler/cl-typeck/src/use_importer.rs index aaca810..9e0cadd 100644 --- a/compiler/cl-typeck/src/use_importer.rs +++ b/compiler/cl-typeck/src/use_importer.rs @@ -24,7 +24,7 @@ type UseResult = Result<(), String>; impl<'a> Project<'a> { pub fn resolve_imports(&mut self) -> UseResult { - for id in self.pool.key_iter() { + for id in self.pool.keys() { self.visit_def(id)?; } Ok(()) @@ -58,9 +58,7 @@ impl<'a> Project<'a> { } UseTree::Name(name) => self.visit_use_leaf(name, parent, c)?, - UseTree::Alias(from, to) => { - self.visit_use_alias(from, to, parent, c)? - } + UseTree::Alias(from, to) => self.visit_use_alias(from, to, parent, c)?, UseTree::Glob => self.visit_use_glob(parent, c)?, } Ok(())