Skip to content

Commit 6c636c5

Browse files
committed
Split Arena API into its own crate
1 parent f2900fa commit 6c636c5

18 files changed

Lines changed: 81 additions & 27 deletions

File tree

Cargo.lock

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[workspace]
22
resolver = "3"
3-
members = [ "poniescript","poniescript-core", "poniescript-lsp", "poniescript-gc" , "poni-build", "poni-build-cli", "poni-doc", "poni-doc-cli"]
3+
members = [ "poniescript","poniescript-core", "poniescript-lsp", "poniescript-gc" , "poni-build", "poni-build-cli", "poni-doc", "poni-doc-cli", "poni-arena"]
44

55
[workspace.dependencies]
66
clap = { version = "4.5.8", features = ["derive"] }

poni-arena/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[package]
2+
name = "poni-arena"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[dependencies]
Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ use std::{cell::UnsafeCell, marker::PhantomData, num::{NonZeroU32, NonZeroUsize}
22

33
const DEFAULT_CAPACITY: usize = 256;
44

5+
/// Trait for keys for Arenas.
6+
///
7+
/// These are the core methods necessary to use a particular opaque type as
8+
/// a key for the various Arena types. However, for the most part you do not need
9+
/// to implement ArenaKey manually. Instead, use [`define_arena_key!`] for defining
10+
/// your opaque key types.
511
pub trait ArenaKey: Copy {
612
fn to_nonzero_usize(self) -> NonZeroUsize;
713
unsafe fn from_nonzero_u32(id: NonZeroU32) -> Self;
@@ -13,30 +19,44 @@ pub trait ArenaKey: Copy {
1319

1420
#[inline(always)]
1521
unsafe fn from_index(index: usize) -> Self {
16-
#[cfg(debug_assertions)]
17-
{
18-
Self::from_nonzero_u32(NonZeroU32::new(index as u32 + 1).unwrap())
19-
}
22+
unsafe {
23+
#[cfg(debug_assertions)]
24+
{
25+
Self::from_nonzero_u32(NonZeroU32::new(index as u32 + 1).unwrap())
26+
}
2027

21-
#[cfg(not(debug_assertions))]
22-
{
23-
Self::from_nonzero_u32(NonZeroU32::new_unchecked(index as u32 + 1))
28+
#[cfg(not(debug_assertions))]
29+
{
30+
Self::from_nonzero_u32(NonZeroU32::new_unchecked(index as u32 + 1))
31+
}
2432
}
2533
}
2634

2735
#[inline(always)]
2836
unsafe fn invalid() -> Self {
29-
Self::from_index(0)
37+
unsafe { Self::from_index(0) }
3038
}
3139
}
3240

41+
/// Defines a new key type for an Arena.
42+
///
43+
/// The idea here is to associate a new opaque type with each kind of Arena.
44+
/// For example, if you have an Arena of Exprs and an Arena of Stmts, you may
45+
/// want an ExprKey/ExprId and a StmtKey/StmtId.
46+
///
47+
/// In this case, you could `define_arena_key!(ExprId);` and then later construct
48+
/// a new arena such as `let arena: Arena<Expr, ExprId> = ...;`
49+
///
50+
/// Note that Arena keys are currently not associated in any way with the Arena
51+
/// instance they belong to. This may change in the future.
52+
#[macro_export]
3353
macro_rules! define_arena_key {
3454
($key_name:ident) => {
3555
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
3656
pub struct $key_name(std::num::NonZeroU32);
3757

3858
// TODO: Is this the best fully qualified name for this trait?
39-
impl crate::arena::ArenaKey for $key_name {
59+
impl $crate::ArenaKey for $key_name {
4060
#[inline(always)]
4161
fn to_nonzero_usize(self) -> std::num::NonZeroUsize {
4262
// Safety: Our self.0 is always nonzero, so this should always also
@@ -52,6 +72,11 @@ macro_rules! define_arena_key {
5272
}
5373
}
5474

75+
/// The simplest Arena type.
76+
///
77+
/// This Arena is essentially a `Vec<Ty>`, indexed by the `Key` type. The main
78+
/// value it provides is to enable the Key types to be opaque, rather than
79+
/// normal `usize`s, and to enable conversion into an ArenaCell.
5580
pub struct Arena<Ty, Key: ArenaKey> {
5681
objects: Vec<Ty>,
5782
phantom: PhantomData<Key>
@@ -137,6 +162,21 @@ impl<Ty, Key: ArenaKey> Arena<Ty, Key> {
137162
}
138163
}
139164

165+
/// This type is essentially a Vec<RefCell<T>>, except that the borrow checking
166+
/// for the inner T happens entirely in a side table, rather than per-item.
167+
///
168+
/// There is also an additional caveat that, as of this writing, ArenaCell
169+
/// is *intentionally* unsound. In particular, the runtime borrow-checking rules
170+
/// (a la RefCell) are only enabled when `debug_assertions` are enabled. In
171+
/// release mode, the borrow checking rules are entirely elided.
172+
///
173+
/// The motivation for this is that the target use-case of ArenaCell, namely
174+
/// compiler data structures, does not really enable 'accidentally' forgetting
175+
/// to drop a borrow. If you have a half-decent test suite, and you have an
176+
/// accidental double-borrow, you WILL see the panic in debug mode, and you
177+
/// will be able to trivially fix it.
178+
///
179+
/// In the future, there may be some
140180
pub struct ArenaCell<Ty, Key: ArenaKey> {
141181
objects: UnsafeCell<Vec<Ty>>,
142182

poniescript-core/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ anstyle = "1.0.7"
1010
clap = { workspace = true }
1111
crossbeam = { version = "0.8.4", features = ["crossbeam-channel", "crossbeam-queue"] }
1212
log = "0.4.28"
13+
poni-arena = { version = "0.1.0", path = "../poni-arena" }
1314
rustc-hash = "2.0.0"
1415
ufmt = { version = "0.2.0", features = ["std"] }

poniescript-core/build/build_db.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ fn generate_impl(file: &mut File, pairs: &Vec<(&str, &str)>) {
4848
let mut init = String::new();
4949
let mut struct_ = String::new();
5050
let mut db_impl = String::new();
51-
writeln!(file, "use crate::arena::Arena;").unwrap();
51+
writeln!(file, "use poni_arena::Arena;").unwrap();
5252
writeln!(file, "pub type IdType = {TY};").unwrap();
5353
writeln!(init, "impl DbArenas {{").unwrap();
5454
writeln!(init, "\tpub fn new() -> Self {{").unwrap();

poniescript-core/src/binder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::module::Module;
77
use crate::source::SourceLocation;
88
use crate::typ::Type;
99

10-
use crate::arena::IndexCell;
10+
use poni_arena::IndexCell;
1111

1212
struct NameChecker {
1313
buffer: String,

poniescript-core/src/codegen.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crossbeam::channel;
44
use std::fs::File;
55
use std::io::Write;
66

7-
use crate::arena::ArenaKey;
7+
use poni_arena::ArenaKey;
88
use crate::{db::*, Args};
99
use crate::typ::Type;
1010

poniescript-core/src/codegen/single_codegen.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use rustc_hash::FxHashSet;
22
use ufmt::uwrite;
33

4-
use crate::arena::ArenaKey;
4+
use poni_arena::ArenaKey;
55
use crate::codegen::*;
66
use crate::db::*;
77
use crate::lexer::Tok;

poniescript-core/src/db.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,16 @@ use crate::expr::Var;
1919
use crate::typ::RangeEnd;
2020
use crate::typ::Type;
2121
use crate::source::{PathBufFileSource, Source, SourceLocation, SyntheticSource};
22-
use crate::{arena::*, inf_writeln, Args};
22+
use crate::{inf_writeln, Args};
2323

2424
use crate::glue::lexer::GlueTok;
2525

2626
use crate::lexer::{Tok, Token};
2727

2828
use rustc_hash::{FxHashMap, FxHashSet};
2929

30-
use crate::arena::IndexCell;
30+
use poni_arena::*;
31+
use poni_arena::define_arena_key;
3132

3233
// Include arenas
3334
include!(concat!(env!("OUT_DIR"), "/db.arenas.rs"));

0 commit comments

Comments
 (0)