Introduce ruff_index crate (#4597)

This commit is contained in:
Micha Reiser 2023-05-23 17:40:35 +02:00 committed by GitHub
parent 04d273bcc7
commit 652c644c2a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 681 additions and 149 deletions

View file

@ -1,6 +1,6 @@
use std::num::{NonZeroU32, TryFromIntError};
use std::ops::{Index, IndexMut};
use ruff_index::{newtype_index, IndexVec};
use rustc_hash::FxHashMap;
use rustpython_parser::ast::Stmt;
@ -11,24 +11,9 @@ use ruff_python_ast::types::RefEquality;
/// Using a `u32` is sufficient because Ruff only supports parsing documents with a size of max `u32::max`
/// and it is impossible to have more statements than characters in the file. We use a `NonZeroU32` to
/// take advantage of memory layout optimizations.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct NodeId(NonZeroU32);
/// Convert a `usize` to a `NodeId` (by adding 1 to the value, and casting to `NonZeroU32`).
impl TryFrom<usize> for NodeId {
type Error = TryFromIntError;
fn try_from(value: usize) -> Result<Self, Self::Error> {
Ok(Self(NonZeroU32::try_from(u32::try_from(value)? + 1)?))
}
}
/// Convert a `NodeId` to a `usize` (by subtracting 1 from the value, and casting to `usize`).
impl From<NodeId> for usize {
fn from(value: NodeId) -> Self {
value.0.get() as usize - 1
}
}
#[newtype_index]
#[derive(Ord, PartialOrd)]
pub struct NodeId;
/// A [`Node`] represents a statement in a program, along with a pointer to its parent (if any).
#[derive(Debug)]
@ -44,7 +29,7 @@ struct Node<'a> {
/// The nodes of a program indexed by [`NodeId`]
#[derive(Debug, Default)]
pub struct Nodes<'a> {
nodes: Vec<Node<'a>>,
nodes: IndexVec<NodeId, Node<'a>>,
node_to_id: FxHashMap<RefEquality<'a, Stmt>, NodeId>,
}
@ -53,16 +38,15 @@ impl<'a> Nodes<'a> {
///
/// Panics if a node with the same pointer already exists.
pub fn insert(&mut self, stmt: &'a Stmt, parent: Option<NodeId>) -> NodeId {
let next_id = NodeId::try_from(self.nodes.len()).unwrap();
let next_id = self.nodes.next_index();
if let Some(existing_id) = self.node_to_id.insert(RefEquality(stmt), next_id) {
panic!("Node already exists with id {existing_id:?}");
}
self.nodes.push(Node {
stmt,
parent,
depth: parent.map_or(0, |parent| self.nodes[usize::from(parent)].depth + 1),
});
next_id
depth: parent.map_or(0, |parent| self.nodes[parent].depth + 1),
})
}
/// Returns the [`NodeId`] of the given node.
@ -74,26 +58,24 @@ impl<'a> Nodes<'a> {
/// Return the [`NodeId`] of the parent node.
#[inline]
pub fn parent_id(&self, node_id: NodeId) -> Option<NodeId> {
self.nodes[usize::from(node_id)].parent
self.nodes[node_id].parent
}
/// Return the depth of the node.
#[inline]
pub fn depth(&self, node_id: NodeId) -> u32 {
self.nodes[usize::from(node_id)].depth
self.nodes[node_id].depth
}
/// Returns an iterator over all [`NodeId`] ancestors, starting from the given [`NodeId`].
pub fn ancestor_ids(&self, node_id: NodeId) -> impl Iterator<Item = NodeId> + '_ {
std::iter::successors(Some(node_id), |&node_id| {
self.nodes[usize::from(node_id)].parent
})
std::iter::successors(Some(node_id), |&node_id| self.nodes[node_id].parent)
}
/// Return the parent of the given node.
pub fn parent(&self, node: &'a Stmt) -> Option<&'a Stmt> {
let node_id = self.node_to_id.get(&RefEquality(node))?;
let parent_id = self.nodes[usize::from(*node_id)].parent?;
let parent_id = self.nodes[*node_id].parent?;
Some(self[parent_id])
}
}
@ -101,13 +83,15 @@ impl<'a> Nodes<'a> {
impl<'a> Index<NodeId> for Nodes<'a> {
type Output = &'a Stmt;
#[inline]
fn index(&self, index: NodeId) -> &Self::Output {
&self.nodes[usize::from(index)].stmt
&self.nodes[index].stmt
}
}
impl<'a> IndexMut<NodeId> for Nodes<'a> {
#[inline]
fn index_mut(&mut self, index: NodeId) -> &mut Self::Output {
&mut self.nodes[usize::from(index)].stmt
&mut self.nodes[index].stmt
}
}