Skip to content
This repository was archived by the owner on Mar 12, 2026. It is now read-only.

Commit 9040bd8

Browse files
committed
document EntityBundleMap and EntityBitVec
1 parent c8ec410 commit 9040bd8

14 files changed

Lines changed: 118 additions & 81 deletions

File tree

public/entity/src/bitvec.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//! A [`BitVec`] with strongly-typed indices.
12
use core::hash::Hash;
23
use core::marker::PhantomData;
34
use core::ops::Index;
@@ -10,6 +11,7 @@ use crate::id::EntityRange;
1011
use bitvec::order::Lsb0;
1112
use bitvec::vec::BitVec;
1213

14+
/// A [`BitVec`] with strongly-typed indices.
1315
#[derive(Clone, Eq, PartialEq, Hash)]
1416
pub struct EntityBitVec<I: EntityId> {
1517
vals: BitVec,
@@ -124,6 +126,13 @@ impl<I: EntityId> EntityBitVec<I> {
124126
res
125127
}
126128

129+
/// Create a bitvector of size `len`, and fill it with the data from `buf`, starting from the
130+
/// least significant bit of each byte.
131+
///
132+
/// ## Panics
133+
///
134+
/// `buf` must have enough data to fill `len` bits, and there must be less than a full byte
135+
/// left over. Panics if this is not the case.
127136
fn from_bytes(buf: &[u8], len: usize) -> Self {
128137
assert_eq!(buf.len(), len.div_ceil(8));
129138
let mut res = BitVec::repeat(false, len);

public/entity/src/bundle_map.rs

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,48 @@
1+
//! A map where each key-value pair is assigned a contiguous range of IDs.
12
use crate::{EntityId, EntityRange, EntityVec, EntityMap};
23
use crate::map::Entry;
34
use crate::id::{EntityTag, EntityIdU32};
45

6+
/// Indices occupied by a given bundle.
57
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
6-
pub enum EntityBundleIndex<I: EntityId> {
8+
pub enum EntityBundleIndices<I: EntityId> {
9+
/// Singular index occupied by a unit-shaped bundle.
710
Single(I),
11+
/// Range of indices occupied by an array-shaped bundle.
812
Array(EntityRange<I>),
913
}
1014

15+
/// An index within a particular bundle.
1116
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1217
pub enum EntityBundleItemIndex {
18+
/// The bundle is unit-shaped, thus we shall meow no further of indices within it.
1319
Single,
14-
Array { index: usize, total: usize },
20+
/// The bundle is array-shaped.
21+
Array {
22+
/// The index within the array.
23+
index: usize,
24+
/// The total size of the array.
25+
total: usize,
26+
},
1527
}
1628

1729
struct BundleTag;
1830
impl EntityTag for BundleTag {}
1931
type BundleId = EntityIdU32<BundleTag>;
2032

21-
/// A map where each `(K, V)` pair is assigned a contiguous range of IDs.
33+
/// A map where each key-value pair is assigned a contiguous range of IDs.
34+
///
35+
/// An `EntityBundleMap` is a collection of *bundles*. Each bundle consists of a key, a value,
36+
/// and a *range* of IDs assigned to it. The amount of IDs assigned to a bundle is determined by
37+
/// its *shape*: an array of a specified size, or just a single unit.
38+
///
39+
/// Note that we distinguish between a *single unit* and *an array of size one*. This is
40+
/// intentional, as this datastructure is used to implement data models that make this distinction,
41+
/// much like Rust makes a distinction between `u32` and `[u32; 1]`.
2242
#[derive(Clone, Debug, PartialEq, Eq)]
2343
pub struct EntityBundleMap<I: EntityId, T> {
2444
ids: EntityVec<I, BundleId>,
25-
bundles: EntityMap<BundleId, String, (EntityBundleIndex<I>, T)>,
45+
bundles: EntityMap<BundleId, String, (EntityBundleIndices<I>, T)>,
2646
}
2747

2848
impl<I: EntityId, T> EntityBundleMap<I, T> {
@@ -33,6 +53,7 @@ impl<I: EntityId, T> EntityBundleMap<I, T> {
3353
}
3454
}
3555

56+
/// Returns the number of allocated IDs, i.e. the total size of all the bundles.
3657
pub fn len(&self) -> usize {
3758
self.ids.len()
3859
}
@@ -45,12 +66,13 @@ impl<I: EntityId, T> EntityBundleMap<I, T> {
4566
self.ids.ids()
4667
}
4768

48-
pub fn get(&self, key: &str) -> Option<(EntityBundleIndex<I>, &T)> {
69+
/// Retrieve a bundle by its key.
70+
pub fn get(&self, key: &str) -> Option<(EntityBundleIndices<I>, &T)> {
4971
let (_, (idx, val)) = self.bundles.get(key)?;
5072
Some((*idx, val))
5173
}
5274

53-
pub fn get_mut(&mut self, key: &str) -> Option<(EntityBundleIndex<I>, &mut T)> {
75+
pub fn get_mut(&mut self, key: &str) -> Option<(EntityBundleIndices<I>, &mut T)> {
5476
let (_, (idx, val)) = self.bundles.get_mut(key)?;
5577
Some((*idx, val))
5678
}
@@ -59,16 +81,18 @@ impl<I: EntityId, T> EntityBundleMap<I, T> {
5981
self.bundles.contains_key(key)
6082
}
6183

84+
/// Given an ID, returns the key of the bundle which owns that ID, as well as the particular
85+
/// position within the bundle that corresponds to the ID.
6286
pub fn key(&self, id: I) -> (&str, EntityBundleItemIndex) {
6387
let idx = self.ids[id];
6488
let key = self.bundles.key(idx);
6589
let (bidx, _) = self.bundles[idx];
6690
match bidx {
67-
EntityBundleIndex::Single(sid) => {
91+
EntityBundleIndices::Single(sid) => {
6892
assert_eq!(id, sid);
6993
(key, EntityBundleItemIndex::Single)
7094
}
71-
EntityBundleIndex::Array(range) => (
95+
EntityBundleIndices::Array(range) => (
7296
key,
7397
EntityBundleItemIndex::Array {
7498
index: range.index_of(id).unwrap(),
@@ -78,17 +102,19 @@ impl<I: EntityId, T> EntityBundleMap<I, T> {
78102
}
79103
}
80104

105+
/// Insert a unit-shaped bundle.
81106
pub fn insert(&mut self, name: String, value: T) -> Option<I> {
82107
match self.bundles.entry(name) {
83108
Entry::Occupied(_) => None,
84109
Entry::Vacant(e) => {
85110
let id = self.ids.push(e.index());
86-
e.insert((EntityBundleIndex::Single(id), value));
111+
e.insert((EntityBundleIndices::Single(id), value));
87112
Some(id)
88113
}
89114
}
90115
}
91116

117+
/// Insert an array-shaped bundle.
92118
pub fn insert_array(&mut self, name: String, num: usize, value: T) -> Option<EntityRange<I>> {
93119
match self.bundles.entry(name) {
94120
Entry::Occupied(_) => None,
@@ -98,7 +124,7 @@ impl<I: EntityId, T> EntityBundleMap<I, T> {
98124
for _ in 0..num {
99125
self.ids.push(e.index());
100126
}
101-
e.insert((EntityBundleIndex::Array(range), value));
127+
e.insert((EntityBundleIndices::Array(range), value));
102128
Some(range)
103129
}
104130
}
@@ -111,19 +137,19 @@ impl<I: EntityId, T> EntityBundleMap<I, T> {
111137
})
112138
}
113139

114-
pub fn bundles(&self) -> impl Iterator<Item = (EntityBundleIndex<I>, &str, &T)> {
140+
pub fn bundles(&self) -> impl Iterator<Item = (EntityBundleIndices<I>, &str, &T)> {
115141
self.bundles
116142
.iter()
117143
.map(|(_, k, (i, v))| (*i, k.as_str(), v))
118144
}
119145

120-
pub fn bundles_mut(&mut self) -> impl Iterator<Item = (EntityBundleIndex<I>, &str, &mut T)> {
146+
pub fn bundles_mut(&mut self) -> impl Iterator<Item = (EntityBundleIndices<I>, &str, &mut T)> {
121147
self.bundles
122148
.iter_mut()
123149
.map(|(_, k, (i, v))| (*i, k.as_str(), v))
124150
}
125151

126-
pub fn into_bundles(self) -> impl Iterator<Item = (EntityBundleIndex<I>, String, T)> {
152+
pub fn into_bundles(self) -> impl Iterator<Item = (EntityBundleIndices<I>, String, T)> {
127153
self.bundles.into_iter().map(|(_, k, (i, v))| (i, k, v))
128154
}
129155
}

public/entity/src/bundle_map/bincode.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use bincode::{BorrowDecode, Decode, Encode};
22

3-
use crate::{EntityBundleIndex, EntityBundleMap, EntityId};
3+
use crate::{EntityBundleIndices, EntityBundleMap, EntityId};
44

55
impl<I: EntityId, T: Encode> Encode for EntityBundleMap<I, T> {
66
fn encode<E: bincode::enc::Encoder>(
@@ -10,8 +10,8 @@ impl<I: EntityId, T: Encode> Encode for EntityBundleMap<I, T> {
1010
self.bundles.len().encode(encoder)?;
1111
for (_, key, (idx, val)) in &self.bundles {
1212
let num = match idx {
13-
EntityBundleIndex::Single(_) => None,
14-
EntityBundleIndex::Array(range) => Some(range.len()),
13+
EntityBundleIndices::Single(_) => None,
14+
EntityBundleIndices::Array(range) => Some(range.len()),
1515
};
1616
num.encode(encoder)?;
1717
key.encode(encoder)?;

public/entity/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub mod set;
1515

1616
#[cfg(feature = "map")]
1717
pub use {
18-
bundle_map::EntityBundleIndex, bundle_map::EntityBundleItemIndex, bundle_map::EntityBundleMap,
18+
bundle_map::EntityBundleIndices, bundle_map::EntityBundleItemIndex, bundle_map::EntityBundleMap,
1919
map::EntityMap, set::EntitySet,
2020
};
2121

public/entity/src/map.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//! An [`IndexMap`] with strongly-typed indices.
12
use core::hash::{BuildHasher, Hash};
23
use core::marker::PhantomData;
34
use core::ops::{Index, IndexMut};

public/entity/src/set.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//! An [`indexmap::IndexSet`] with strongly-typed indices.
12
use core::hash::{BuildHasher, Hash};
23
use core::marker::PhantomData;
34
use core::ops::Index;

public/interconnect/src/dump.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::db::{
22
BelAttribute, BelAttributeType, BelInfo, BelKind, ConnectorWire, IntDb, PadKind, PinDir,
33
SwitchBoxItem, TableValue, TileClass,
44
};
5-
use prjcombine_entity::{EntityBundleIndex, EntityBundleItemIndex, EntityId};
5+
use prjcombine_entity::{EntityBundleIndices, EntityBundleItemIndex, EntityId};
66
use prjcombine_types::bsdata::{PolTileBit, TileBit};
77
use std::collections::BTreeMap;
88

@@ -552,8 +552,8 @@ impl IntDb {
552552
nr = if pin.nonroutable { "nonroutable " } else { "" }
553553
)?;
554554
match index {
555-
EntityBundleIndex::Single(_) => writeln!(o, ";")?,
556-
EntityBundleIndex::Array(range) => {
555+
EntityBundleIndices::Single(_) => writeln!(o, ";")?,
556+
EntityBundleIndices::Array(range) => {
557557
if pin.indexing == Default::default() {
558558
writeln!(o, "[{n}];", n = range.len())?;
559559
} else {
@@ -574,8 +574,8 @@ impl IntDb {
574574
nr = if pin.nonroutable { "nonroutable " } else { "" }
575575
)?;
576576
match index {
577-
EntityBundleIndex::Single(_) => writeln!(o, ";")?,
578-
EntityBundleIndex::Array(range) => {
577+
EntityBundleIndices::Single(_) => writeln!(o, ";")?,
578+
EntityBundleIndices::Array(range) => {
579579
if pin.indexing == Default::default() {
580580
writeln!(o, "[{n}];", n = range.len())?;
581581
} else {
@@ -596,8 +596,8 @@ impl IntDb {
596596
nr = if pin.nonroutable { "nonroutable " } else { "" }
597597
)?;
598598
match index {
599-
EntityBundleIndex::Single(_) => writeln!(o, ";")?,
600-
EntityBundleIndex::Array(range) => {
599+
EntityBundleIndices::Single(_) => writeln!(o, ";")?,
600+
EntityBundleIndices::Array(range) => {
601601
if pin.indexing == Default::default() {
602602
writeln!(o, "[{n}];", n = range.len())?;
603603
} else {
@@ -614,8 +614,8 @@ impl IntDb {
614614
for (index, pname, pad) in bcls.pads.bundles() {
615615
write!(o, "\t\tpad {pname}")?;
616616
match index {
617-
EntityBundleIndex::Single(_) => (),
618-
EntityBundleIndex::Array(range) => write!(o, "[{n}]", n = range.len())?,
617+
EntityBundleIndices::Single(_) => (),
618+
EntityBundleIndices::Array(range) => write!(o, "[{n}]", n = range.len())?,
619619
}
620620
writeln!(
621621
o,

public/tablegen/src/emit.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::str::FromStr;
22

3-
use prjcombine_entity::{EntityBundleIndex, EntityBundleMap, EntityId, EntityVec};
3+
use prjcombine_entity::{EntityBundleIndices, EntityBundleMap, EntityId, EntityVec};
44
use prjcombine_interconnect::db::{BelPinIndexing, IntDb};
55
use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
66

@@ -67,7 +67,7 @@ fn emit_array_ids<I: EntityId>(
6767

6868
for (index, _, ident) in idents.bundles() {
6969
match index {
70-
EntityBundleIndex::Single(id) => {
70+
EntityBundleIndices::Single(id) => {
7171
res.extend([
7272
keyword("pub"),
7373
keyword("const"),
@@ -83,7 +83,7 @@ fn emit_array_ids<I: EntityId>(
8383
punct(';'),
8484
]);
8585
}
86-
EntityBundleIndex::Array(range) => {
86+
EntityBundleIndices::Array(range) => {
8787
res.extend([
8888
keyword("pub"),
8989
keyword("const"),
@@ -128,10 +128,10 @@ fn emit_pin_array_ids<I: EntityId>(
128128
let mut new_idents: EntityBundleMap<I, _> = EntityBundleMap::new();
129129
for (idx, name, (ident, _)) in idents.bundles() {
130130
match idx {
131-
EntityBundleIndex::Single(_) => {
131+
EntityBundleIndices::Single(_) => {
132132
new_idents.insert(name.into(), ident.clone());
133133
}
134-
EntityBundleIndex::Array(range) => {
134+
EntityBundleIndices::Array(range) => {
135135
new_idents.insert_array(name.into(), range.len(), ident.clone());
136136
}
137137
}

0 commit comments

Comments
 (0)