mirror of
https://github.com/italicsjenga/valence.git
synced 2024-12-23 22:41:30 +11:00
Extract slotmap logic into separate modules
This commit is contained in:
parent
cd110c3cbb
commit
1838c290a0
|
@ -83,7 +83,7 @@ impl Config for Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(&self, server: &mut Server<Self>) {
|
fn init(&self, server: &mut Server<Self>) {
|
||||||
let (_, world) = server.worlds.create(DimensionId::default(), ());
|
let (_, world) = server.worlds.insert(DimensionId::default(), ());
|
||||||
world.meta.set_flat(true);
|
world.meta.set_flat(true);
|
||||||
|
|
||||||
let min_y = server.shared.dimension(DimensionId::default()).min_y;
|
let min_y = server.shared.dimension(DimensionId::default()).min_y;
|
||||||
|
@ -92,7 +92,7 @@ impl Config for Game {
|
||||||
let size = 2;
|
let size = 2;
|
||||||
for chunk_z in -size - 2..size + 2 {
|
for chunk_z in -size - 2..size + 2 {
|
||||||
for chunk_x in -size - 2..size + 2 {
|
for chunk_x in -size - 2..size + 2 {
|
||||||
let chunk = world.chunks.create([chunk_x, chunk_z], ());
|
let chunk = world.chunks.insert([chunk_x, chunk_z], ());
|
||||||
let r = -size..size;
|
let r = -size..size;
|
||||||
if r.contains(&chunk_x) && r.contains(&chunk_z) {
|
if r.contains(&chunk_x) && r.contains(&chunk_z) {
|
||||||
for z in 0..16 {
|
for z in 0..16 {
|
||||||
|
@ -131,7 +131,7 @@ impl Config for Game {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (player_id, player) = match server.entities.create_with_uuid(
|
let (player_id, player) = match server.entities.insert_with_uuid(
|
||||||
EntityKind::Player,
|
EntityKind::Player,
|
||||||
client.uuid(),
|
client.uuid(),
|
||||||
EntityState::default(),
|
EntityState::default(),
|
||||||
|
@ -177,7 +177,7 @@ impl Config for Game {
|
||||||
|
|
||||||
if client.is_disconnected() {
|
if client.is_disconnected() {
|
||||||
self.player_count.fetch_sub(1, Ordering::SeqCst);
|
self.player_count.fetch_sub(1, Ordering::SeqCst);
|
||||||
server.entities.delete(client.state.player);
|
server.entities.remove(client.state.player);
|
||||||
world.meta.player_list_mut().remove(client.uuid());
|
world.meta.player_list_mut().remove(client.uuid());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,12 +95,12 @@ impl Config for Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(&self, server: &mut Server<Self>) {
|
fn init(&self, server: &mut Server<Self>) {
|
||||||
let world = server.worlds.create(DimensionId::default(), ()).1;
|
let world = server.worlds.insert(DimensionId::default(), ()).1;
|
||||||
world.meta.set_flat(true);
|
world.meta.set_flat(true);
|
||||||
|
|
||||||
for chunk_z in -2..Integer::div_ceil(&(SIZE_X as i32), &16) + 2 {
|
for chunk_z in -2..Integer::div_ceil(&(SIZE_X as i32), &16) + 2 {
|
||||||
for chunk_x in -2..Integer::div_ceil(&(SIZE_Z as i32), &16) + 2 {
|
for chunk_x in -2..Integer::div_ceil(&(SIZE_Z as i32), &16) + 2 {
|
||||||
world.chunks.create((chunk_x as i32, chunk_z as i32), ());
|
world.chunks.insert((chunk_x as i32, chunk_z as i32), ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,7 @@ impl Config for Game {
|
||||||
|
|
||||||
match server
|
match server
|
||||||
.entities
|
.entities
|
||||||
.create_with_uuid(EntityKind::Player, client.uuid(), ())
|
.insert_with_uuid(EntityKind::Player, client.uuid(), ())
|
||||||
{
|
{
|
||||||
Some((id, _)) => client.state = id,
|
Some((id, _)) => client.state = id,
|
||||||
None => {
|
None => {
|
||||||
|
@ -156,7 +156,7 @@ impl Config for Game {
|
||||||
|
|
||||||
if client.is_disconnected() {
|
if client.is_disconnected() {
|
||||||
self.player_count.fetch_sub(1, Ordering::SeqCst);
|
self.player_count.fetch_sub(1, Ordering::SeqCst);
|
||||||
server.entities.delete(client.state);
|
server.entities.remove(client.state);
|
||||||
world.meta.player_list_mut().remove(client.uuid());
|
world.meta.player_list_mut().remove(client.uuid());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,20 +73,20 @@ impl Config for Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(&self, server: &mut Server<Self>) {
|
fn init(&self, server: &mut Server<Self>) {
|
||||||
let (world_id, world) = server.worlds.create(DimensionId::default(), ());
|
let (world_id, world) = server.worlds.insert(DimensionId::default(), ());
|
||||||
world.meta.set_flat(true);
|
world.meta.set_flat(true);
|
||||||
|
|
||||||
let size = 5;
|
let size = 5;
|
||||||
for z in -size..size {
|
for z in -size..size {
|
||||||
for x in -size..size {
|
for x in -size..size {
|
||||||
world.chunks.create([x, z], ());
|
world.chunks.insert([x, z], ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
world.chunks.set_block_state(SPAWN_POS, BlockState::BEDROCK);
|
world.chunks.set_block_state(SPAWN_POS, BlockState::BEDROCK);
|
||||||
|
|
||||||
server.state.cows.extend((0..200).map(|_| {
|
server.state.cows.extend((0..200).map(|_| {
|
||||||
let (id, e) = server.entities.create(EntityKind::Cow, ());
|
let (id, e) = server.entities.insert(EntityKind::Cow, ());
|
||||||
e.set_world(world_id);
|
e.set_world(world_id);
|
||||||
id
|
id
|
||||||
}));
|
}));
|
||||||
|
@ -110,7 +110,7 @@ impl Config for Game {
|
||||||
|
|
||||||
match server
|
match server
|
||||||
.entities
|
.entities
|
||||||
.create_with_uuid(EntityKind::Player, client.uuid(), ())
|
.insert_with_uuid(EntityKind::Player, client.uuid(), ())
|
||||||
{
|
{
|
||||||
Some((id, _)) => client.state = id,
|
Some((id, _)) => client.state = id,
|
||||||
None => {
|
None => {
|
||||||
|
@ -144,7 +144,7 @@ impl Config for Game {
|
||||||
if client.is_disconnected() {
|
if client.is_disconnected() {
|
||||||
self.player_count.fetch_sub(1, Ordering::SeqCst);
|
self.player_count.fetch_sub(1, Ordering::SeqCst);
|
||||||
world.meta.player_list_mut().remove(client.uuid());
|
world.meta.player_list_mut().remove(client.uuid());
|
||||||
server.entities.delete(client.state);
|
server.entities.remove(client.state);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,13 +72,13 @@ impl Config for Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(&self, server: &mut Server<Self>) {
|
fn init(&self, server: &mut Server<Self>) {
|
||||||
let (world_id, world) = server.worlds.create(DimensionId::default(), ());
|
let (world_id, world) = server.worlds.insert(DimensionId::default(), ());
|
||||||
world.meta.set_flat(true);
|
world.meta.set_flat(true);
|
||||||
|
|
||||||
let size = 5;
|
let size = 5;
|
||||||
for z in -size..size {
|
for z in -size..size {
|
||||||
for x in -size..size {
|
for x in -size..size {
|
||||||
world.chunks.create([x, z], ());
|
world.chunks.insert([x, z], ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ impl Config for Game {
|
||||||
for i in 0..SHEEP_COUNT {
|
for i in 0..SHEEP_COUNT {
|
||||||
let offset = (i as f64 - (SHEEP_COUNT - 1) as f64 / 2.0) * 1.25;
|
let offset = (i as f64 - (SHEEP_COUNT - 1) as f64 / 2.0) * 1.25;
|
||||||
|
|
||||||
let (_, sheep) = server.entities.create(EntityKind::Sheep, false);
|
let (_, sheep) = server.entities.insert(EntityKind::Sheep, false);
|
||||||
sheep.set_world(world_id);
|
sheep.set_world(world_id);
|
||||||
sheep.set_position([offset + 0.5, SPAWN_POS.y as f64 + 1.0, 0.0]);
|
sheep.set_position([offset + 0.5, SPAWN_POS.y as f64 + 1.0, 0.0]);
|
||||||
sheep.set_yaw(180.0);
|
sheep.set_yaw(180.0);
|
||||||
|
@ -114,7 +114,7 @@ impl Config for Game {
|
||||||
|
|
||||||
match server
|
match server
|
||||||
.entities
|
.entities
|
||||||
.create_with_uuid(EntityKind::Player, client.uuid(), false)
|
.insert_with_uuid(EntityKind::Player, client.uuid(), false)
|
||||||
{
|
{
|
||||||
Some((id, _)) => client.state = id,
|
Some((id, _)) => client.state = id,
|
||||||
None => {
|
None => {
|
||||||
|
@ -154,7 +154,7 @@ impl Config for Game {
|
||||||
if client.is_disconnected() {
|
if client.is_disconnected() {
|
||||||
self.player_count.fetch_sub(1, Ordering::SeqCst);
|
self.player_count.fetch_sub(1, Ordering::SeqCst);
|
||||||
world.meta.player_list_mut().remove(client.uuid());
|
world.meta.player_list_mut().remove(client.uuid());
|
||||||
server.entities.delete(client.state);
|
server.entities.remove(client.state);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ impl Config for Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(&self, server: &mut Server<Self>) {
|
fn init(&self, server: &mut Server<Self>) {
|
||||||
let (_, world) = server.worlds.create(DimensionId::default(), ());
|
let (_, world) = server.worlds.insert(DimensionId::default(), ());
|
||||||
world.meta.set_flat(true);
|
world.meta.set_flat(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ impl Config for Game {
|
||||||
|
|
||||||
match server
|
match server
|
||||||
.entities
|
.entities
|
||||||
.create_with_uuid(EntityKind::Player, client.uuid(), ())
|
.insert_with_uuid(EntityKind::Player, client.uuid(), ())
|
||||||
{
|
{
|
||||||
Some((id, _)) => client.state = id,
|
Some((id, _)) => client.state = id,
|
||||||
None => {
|
None => {
|
||||||
|
@ -134,7 +134,7 @@ impl Config for Game {
|
||||||
if client.is_disconnected() {
|
if client.is_disconnected() {
|
||||||
self.player_count.fetch_sub(1, Ordering::SeqCst);
|
self.player_count.fetch_sub(1, Ordering::SeqCst);
|
||||||
world.meta.player_list_mut().remove(client.uuid());
|
world.meta.player_list_mut().remove(client.uuid());
|
||||||
server.entities.delete(client.state);
|
server.entities.remove(client.state);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -149,7 +149,7 @@ impl Config for Game {
|
||||||
for pos in chunks_in_view_distance(ChunkPos::at(p.x, p.z), dist) {
|
for pos in chunks_in_view_distance(ChunkPos::at(p.x, p.z), dist) {
|
||||||
chunks_to_unload.remove(&pos);
|
chunks_to_unload.remove(&pos);
|
||||||
if world.chunks.get(pos).is_none() {
|
if world.chunks.get(pos).is_none() {
|
||||||
world.chunks.create(pos, ());
|
world.chunks.insert(pos, ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ impl Config for Game {
|
||||||
});
|
});
|
||||||
|
|
||||||
for pos in chunks_to_unload {
|
for pos in chunks_to_unload {
|
||||||
world.chunks.delete(pos);
|
world.chunks.remove(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
world.chunks.par_iter_mut().for_each(|(pos, chunk)| {
|
world.chunks.par_iter_mut().for_each(|(pos, chunk)| {
|
||||||
|
|
20
src/chunk.rs
20
src/chunk.rs
|
@ -41,7 +41,7 @@ impl<C: Config> Chunks<C> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an empty chunk at the provided position and returns a mutable
|
/// Creates an empty chunk at the provided position and returns a mutable
|
||||||
/// refernce to it.
|
/// reference to it.
|
||||||
///
|
///
|
||||||
/// If a chunk at the position already exists, then the old chunk
|
/// If a chunk at the position already exists, then the old chunk
|
||||||
/// is overwritten.
|
/// is overwritten.
|
||||||
|
@ -50,9 +50,9 @@ impl<C: Config> Chunks<C> {
|
||||||
/// adjacent to it must also be loaded. It is also important that clients
|
/// adjacent to it must also be loaded. It is also important that clients
|
||||||
/// are not spawned within unloaded chunks via
|
/// are not spawned within unloaded chunks via
|
||||||
/// [`spawn`](crate::client::Client::spawn).
|
/// [`spawn`](crate::client::Client::spawn).
|
||||||
pub fn create(&mut self, pos: impl Into<ChunkPos>, data: C::ChunkState) -> &mut Chunk<C> {
|
pub fn insert(&mut self, pos: impl Into<ChunkPos>, state: C::ChunkState) -> &mut Chunk<C> {
|
||||||
let section_count = (self.server.dimension(self.dimension).height / 16) as u32;
|
let section_count = (self.server.dimension(self.dimension).height / 16) as u32;
|
||||||
let chunk = Chunk::new(section_count, self.server.current_tick(), data);
|
let chunk = Chunk::new(section_count, self.server.current_tick(), state);
|
||||||
|
|
||||||
match self.chunks.entry(pos.into()) {
|
match self.chunks.entry(pos.into()) {
|
||||||
Entry::Occupied(mut oe) => {
|
Entry::Occupied(mut oe) => {
|
||||||
|
@ -67,12 +67,12 @@ impl<C: Config> Chunks<C> {
|
||||||
///
|
///
|
||||||
/// If a chunk exists at the position, then it is deleted and `true` is
|
/// If a chunk exists at the position, then it is deleted and `true` is
|
||||||
/// returned. Otherwise, `false` is returned.
|
/// returned. Otherwise, `false` is returned.
|
||||||
pub fn delete(&mut self, pos: impl Into<ChunkPos>) -> bool {
|
pub fn remove(&mut self, pos: impl Into<ChunkPos>) -> Option<C::ChunkState> {
|
||||||
self.chunks.remove(&pos.into()).is_some()
|
self.chunks.remove(&pos.into()).map(|c| c.state)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of loaded chunks.
|
/// Returns the number of loaded chunks.
|
||||||
pub fn count(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.chunks.len()
|
self.chunks.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,13 +97,17 @@ impl<C: Config> Chunks<C> {
|
||||||
|
|
||||||
/// Returns an immutable iterator over all chunks in the world in an
|
/// Returns an immutable iterator over all chunks in the world in an
|
||||||
/// unspecified order.
|
/// unspecified order.
|
||||||
pub fn iter(&self) -> impl FusedIterator<Item = (ChunkPos, &Chunk<C>)> + Clone + '_ {
|
pub fn iter(
|
||||||
|
&self,
|
||||||
|
) -> impl ExactSizeIterator<Item = (ChunkPos, &Chunk<C>)> + FusedIterator + Clone + '_ {
|
||||||
self.chunks.iter().map(|(&pos, chunk)| (pos, chunk))
|
self.chunks.iter().map(|(&pos, chunk)| (pos, chunk))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a mutable iterator over all chunks in the world in an
|
/// Returns a mutable iterator over all chunks in the world in an
|
||||||
/// unspecified order.
|
/// unspecified order.
|
||||||
pub fn iter_mut(&mut self) -> impl FusedIterator<Item = (ChunkPos, &mut Chunk<C>)> + '_ {
|
pub fn iter_mut(
|
||||||
|
&mut self,
|
||||||
|
) -> impl ExactSizeIterator<Item = (ChunkPos, &mut Chunk<C>)> + FusedIterator + '_ {
|
||||||
self.chunks.iter_mut().map(|(&pos, chunk)| (pos, chunk))
|
self.chunks.iter_mut().map(|(&pos, chunk)| (pos, chunk))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ use crate::protocol_inner::packets::s2c::play::{
|
||||||
};
|
};
|
||||||
use crate::protocol_inner::{BoundedInt, ByteAngle, Nbt, RawBytes, VarInt};
|
use crate::protocol_inner::{BoundedInt, ByteAngle, Nbt, RawBytes, VarInt};
|
||||||
use crate::server::{C2sPacketChannels, NewClientData, S2cPlayMessage, SharedServer};
|
use crate::server::{C2sPacketChannels, NewClientData, S2cPlayMessage, SharedServer};
|
||||||
use crate::slotmap::{Key, SlotMap};
|
use crate::slab_versioned::{Key, VersionedSlab};
|
||||||
use crate::text::Text;
|
use crate::text::Text;
|
||||||
use crate::util::{chunks_in_view_distance, is_chunk_in_view_distance};
|
use crate::util::{chunks_in_view_distance, is_chunk_in_view_distance};
|
||||||
use crate::world::{WorldId, Worlds};
|
use crate::world::{WorldId, Worlds};
|
||||||
|
@ -52,16 +52,18 @@ mod event;
|
||||||
/// are not automatically deleted. It is your responsibility to delete them once
|
/// are not automatically deleted. It is your responsibility to delete them once
|
||||||
/// they disconnect. This can be checked with [`Client::is_disconnected`].
|
/// they disconnect. This can be checked with [`Client::is_disconnected`].
|
||||||
pub struct Clients<C: Config> {
|
pub struct Clients<C: Config> {
|
||||||
sm: SlotMap<Client<C>>,
|
slab: VersionedSlab<Client<C>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Config> Clients<C> {
|
impl<C: Config> Clients<C> {
|
||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
Self { sm: SlotMap::new() }
|
Self {
|
||||||
|
slab: VersionedSlab::new(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn insert(&mut self, client: Client<C>) -> (ClientId, &mut Client<C>) {
|
pub(crate) fn insert(&mut self, client: Client<C>) -> (ClientId, &mut Client<C>) {
|
||||||
let (k, client) = self.sm.insert(client);
|
let (k, client) = self.slab.insert(client);
|
||||||
(ClientId(k), client)
|
(ClientId(k), client)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,8 +71,8 @@ impl<C: Config> Clients<C> {
|
||||||
///
|
///
|
||||||
/// If the given client ID is valid, `true` is returned and the client is
|
/// If the given client ID is valid, `true` is returned and the client is
|
||||||
/// deleted. Otherwise, `false` is returned and the function has no effect.
|
/// deleted. Otherwise, `false` is returned and the function has no effect.
|
||||||
pub fn delete(&mut self, client: ClientId) -> bool {
|
pub fn remove(&mut self, client: ClientId) -> Option<C::ClientState> {
|
||||||
self.sm.remove(client.0).is_some()
|
self.slab.remove(client.0).map(|c| c.state)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deletes all clients from the server for
|
/// Deletes all clients from the server for
|
||||||
|
@ -78,43 +80,47 @@ impl<C: Config> Clients<C> {
|
||||||
///
|
///
|
||||||
/// All clients are visited in an unspecified order.
|
/// All clients are visited in an unspecified order.
|
||||||
pub fn retain(&mut self, mut f: impl FnMut(ClientId, &mut Client<C>) -> bool) {
|
pub fn retain(&mut self, mut f: impl FnMut(ClientId, &mut Client<C>) -> bool) {
|
||||||
self.sm.retain(|k, v| f(ClientId(k), v))
|
self.slab.retain(|k, v| f(ClientId(k), v))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of clients on the server. This includes clients
|
/// Returns the number of clients on the server. This includes clients
|
||||||
/// which may be disconnected.
|
/// which may be disconnected.
|
||||||
pub fn count(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.sm.len()
|
self.slab.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a shared reference to the client with the given ID. If
|
/// Returns a shared reference to the client with the given ID. If
|
||||||
/// the ID is invalid, then `None` is returned.
|
/// the ID is invalid, then `None` is returned.
|
||||||
pub fn get(&self, client: ClientId) -> Option<&Client<C>> {
|
pub fn get(&self, client: ClientId) -> Option<&Client<C>> {
|
||||||
self.sm.get(client.0)
|
self.slab.get(client.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an exclusive reference to the client with the given ID. If the
|
/// Returns an exclusive reference to the client with the given ID. If the
|
||||||
/// ID is invalid, then `None` is returned.
|
/// ID is invalid, then `None` is returned.
|
||||||
pub fn get_mut(&mut self, client: ClientId) -> Option<&mut Client<C>> {
|
pub fn get_mut(&mut self, client: ClientId) -> Option<&mut Client<C>> {
|
||||||
self.sm.get_mut(client.0)
|
self.slab.get_mut(client.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an immutable iterator over all clients on the server in an
|
/// Returns an immutable iterator over all clients on the server in an
|
||||||
/// unspecified order.
|
/// unspecified order.
|
||||||
pub fn iter(&self) -> impl FusedIterator<Item = (ClientId, &Client<C>)> + Clone + '_ {
|
pub fn iter(
|
||||||
self.sm.iter().map(|(k, v)| (ClientId(k), v))
|
&self,
|
||||||
|
) -> impl ExactSizeIterator<Item = (ClientId, &Client<C>)> + FusedIterator + Clone + '_ {
|
||||||
|
self.slab.iter().map(|(k, v)| (ClientId(k), v))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a mutable iterator over all clients on the server in an
|
/// Returns a mutable iterator over all clients on the server in an
|
||||||
/// unspecified order.
|
/// unspecified order.
|
||||||
pub fn iter_mut(&mut self) -> impl FusedIterator<Item = (ClientId, &mut Client<C>)> + '_ {
|
pub fn iter_mut(
|
||||||
self.sm.iter_mut().map(|(k, v)| (ClientId(k), v))
|
&mut self,
|
||||||
|
) -> impl ExactSizeIterator<Item = (ClientId, &mut Client<C>)> + FusedIterator + '_ {
|
||||||
|
self.slab.iter_mut().map(|(k, v)| (ClientId(k), v))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a parallel immutable iterator over all clients on the server in
|
/// Returns a parallel immutable iterator over all clients on the server in
|
||||||
/// an unspecified order.
|
/// an unspecified order.
|
||||||
pub fn par_iter(&self) -> impl ParallelIterator<Item = (ClientId, &Client<C>)> + Clone + '_ {
|
pub fn par_iter(&self) -> impl ParallelIterator<Item = (ClientId, &Client<C>)> + Clone + '_ {
|
||||||
self.sm.par_iter().map(|(k, v)| (ClientId(k), v))
|
self.slab.par_iter().map(|(k, v)| (ClientId(k), v))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a parallel mutable iterator over all clients on the server in an
|
/// Returns a parallel mutable iterator over all clients on the server in an
|
||||||
|
@ -122,7 +128,7 @@ impl<C: Config> Clients<C> {
|
||||||
pub fn par_iter_mut(
|
pub fn par_iter_mut(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> impl ParallelIterator<Item = (ClientId, &mut Client<C>)> + '_ {
|
) -> impl ParallelIterator<Item = (ClientId, &mut Client<C>)> + '_ {
|
||||||
self.sm.par_iter_mut().map(|(k, v)| (ClientId(k), v))
|
self.slab.par_iter_mut().map(|(k, v)| (ClientId(k), v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ use crate::protocol_inner::packets::s2c::play::{
|
||||||
EntitySpawn, EntityTrackerUpdate, ExperienceOrbSpawn, PlayerSpawn, S2cPlayPacket,
|
EntitySpawn, EntityTrackerUpdate, ExperienceOrbSpawn, PlayerSpawn, S2cPlayPacket,
|
||||||
};
|
};
|
||||||
use crate::protocol_inner::{ByteAngle, RawBytes, VarInt};
|
use crate::protocol_inner::{ByteAngle, RawBytes, VarInt};
|
||||||
use crate::slotmap::{Key, SlotMap};
|
use crate::slab_versioned::{Key, VersionedSlab};
|
||||||
use crate::util::aabb_from_bottom_and_size;
|
use crate::util::aabb_from_bottom_and_size;
|
||||||
use crate::world::WorldId;
|
use crate::world::WorldId;
|
||||||
use crate::STANDARD_TPS;
|
use crate::STANDARD_TPS;
|
||||||
|
@ -37,7 +37,7 @@ include!(concat!(env!("OUT_DIR"), "/entity_event.rs"));
|
||||||
/// [`Player`]: crate::entity::types::Player
|
/// [`Player`]: crate::entity::types::Player
|
||||||
/// [`PlayerList`]: crate::player_list::PlayerList
|
/// [`PlayerList`]: crate::player_list::PlayerList
|
||||||
pub struct Entities<C: Config> {
|
pub struct Entities<C: Config> {
|
||||||
sm: SlotMap<Entity<C>>,
|
slab: VersionedSlab<Entity<C>>,
|
||||||
uuid_to_entity: HashMap<Uuid, EntityId>,
|
uuid_to_entity: HashMap<Uuid, EntityId>,
|
||||||
network_id_to_entity: HashMap<NonZeroU32, u32>,
|
network_id_to_entity: HashMap<NonZeroU32, u32>,
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ pub struct Entities<C: Config> {
|
||||||
impl<C: Config> Entities<C> {
|
impl<C: Config> Entities<C> {
|
||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
sm: SlotMap::new(),
|
slab: VersionedSlab::new(),
|
||||||
uuid_to_entity: HashMap::new(),
|
uuid_to_entity: HashMap::new(),
|
||||||
network_id_to_entity: HashMap::new(),
|
network_id_to_entity: HashMap::new(),
|
||||||
}
|
}
|
||||||
|
@ -53,8 +53,12 @@ impl<C: Config> Entities<C> {
|
||||||
|
|
||||||
/// Spawns a new entity with a random UUID. A reference to the entity along
|
/// Spawns a new entity with a random UUID. A reference to the entity along
|
||||||
/// with its ID is returned.
|
/// with its ID is returned.
|
||||||
pub fn create(&mut self, kind: EntityKind, data: C::EntityState) -> (EntityId, &mut Entity<C>) {
|
pub fn insert(
|
||||||
self.create_with_uuid(kind, Uuid::from_bytes(rand::random()), data)
|
&mut self,
|
||||||
|
kind: EntityKind,
|
||||||
|
state: C::EntityState,
|
||||||
|
) -> (EntityId, &mut Entity<C>) {
|
||||||
|
self.insert_with_uuid(kind, Uuid::from_bytes(rand::random()), state)
|
||||||
.expect("UUID collision")
|
.expect("UUID collision")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +67,7 @@ impl<C: Config> Entities<C> {
|
||||||
///
|
///
|
||||||
/// The provided UUID must not conflict with an existing entity UUID. If it
|
/// The provided UUID must not conflict with an existing entity UUID. If it
|
||||||
/// does, `None` is returned and the entity is not spawned.
|
/// does, `None` is returned and the entity is not spawned.
|
||||||
pub fn create_with_uuid(
|
pub fn insert_with_uuid(
|
||||||
&mut self,
|
&mut self,
|
||||||
kind: EntityKind,
|
kind: EntityKind,
|
||||||
uuid: Uuid,
|
uuid: Uuid,
|
||||||
|
@ -72,7 +76,7 @@ impl<C: Config> Entities<C> {
|
||||||
match self.uuid_to_entity.entry(uuid) {
|
match self.uuid_to_entity.entry(uuid) {
|
||||||
Entry::Occupied(_) => None,
|
Entry::Occupied(_) => None,
|
||||||
Entry::Vacant(ve) => {
|
Entry::Vacant(ve) => {
|
||||||
let (k, e) = self.sm.insert(Entity {
|
let (k, e) = self.slab.insert(Entity {
|
||||||
state: data,
|
state: data,
|
||||||
variants: TrackedData::new(kind),
|
variants: TrackedData::new(kind),
|
||||||
events: Vec::new(),
|
events: Vec::new(),
|
||||||
|
@ -101,8 +105,8 @@ impl<C: Config> Entities<C> {
|
||||||
///
|
///
|
||||||
/// If the given entity ID is valid, `true` is returned and the entity is
|
/// If the given entity ID is valid, `true` is returned and the entity is
|
||||||
/// deleted. Otherwise, `false` is returned and the function has no effect.
|
/// deleted. Otherwise, `false` is returned and the function has no effect.
|
||||||
pub fn delete(&mut self, entity: EntityId) -> bool {
|
pub fn remove(&mut self, entity: EntityId) -> Option<C::EntityState> {
|
||||||
if let Some(e) = self.sm.remove(entity.0) {
|
self.slab.remove(entity.0).map(|e| {
|
||||||
self.uuid_to_entity
|
self.uuid_to_entity
|
||||||
.remove(&e.uuid)
|
.remove(&e.uuid)
|
||||||
.expect("UUID should have been in UUID map");
|
.expect("UUID should have been in UUID map");
|
||||||
|
@ -111,17 +115,15 @@ impl<C: Config> Entities<C> {
|
||||||
.remove(&entity.0.version())
|
.remove(&entity.0.version())
|
||||||
.expect("network ID should have been in the network ID map");
|
.expect("network ID should have been in the network ID map");
|
||||||
|
|
||||||
true
|
e.state
|
||||||
} else {
|
})
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes all entities from the server for which `f` returns `true`.
|
/// Removes all entities from the server for which `f` returns `true`.
|
||||||
///
|
///
|
||||||
/// All entities are visited in an unspecified order.
|
/// All entities are visited in an unspecified order.
|
||||||
pub fn retain(&mut self, mut f: impl FnMut(EntityId, &mut Entity<C>) -> bool) {
|
pub fn retain(&mut self, mut f: impl FnMut(EntityId, &mut Entity<C>) -> bool) {
|
||||||
self.sm.retain(|k, v| {
|
self.slab.retain(|k, v| {
|
||||||
if f(EntityId(k), v) {
|
if f(EntityId(k), v) {
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
|
@ -139,8 +141,8 @@ impl<C: Config> Entities<C> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of entities in this container.
|
/// Returns the number of entities in this container.
|
||||||
pub fn count(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.sm.len()
|
self.slab.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the [`EntityId`] of the entity with the given UUID in an efficient
|
/// Gets the [`EntityId`] of the entity with the given UUID in an efficient
|
||||||
|
@ -155,14 +157,14 @@ impl<C: Config> Entities<C> {
|
||||||
///
|
///
|
||||||
/// If the ID is invalid, `None` is returned.
|
/// If the ID is invalid, `None` is returned.
|
||||||
pub fn get(&self, entity: EntityId) -> Option<&Entity<C>> {
|
pub fn get(&self, entity: EntityId) -> Option<&Entity<C>> {
|
||||||
self.sm.get(entity.0)
|
self.slab.get(entity.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets an exclusive reference to the entity with the given [`EntityId`].
|
/// Gets an exclusive reference to the entity with the given [`EntityId`].
|
||||||
///
|
///
|
||||||
/// If the ID is invalid, `None` is returned.
|
/// If the ID is invalid, `None` is returned.
|
||||||
pub fn get_mut(&mut self, entity: EntityId) -> Option<&mut Entity<C>> {
|
pub fn get_mut(&mut self, entity: EntityId) -> Option<&mut Entity<C>> {
|
||||||
self.sm.get_mut(entity.0)
|
self.slab.get_mut(entity.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_with_network_id(&self, network_id: i32) -> Option<EntityId> {
|
pub(crate) fn get_with_network_id(&self, network_id: i32) -> Option<EntityId> {
|
||||||
|
@ -173,20 +175,24 @@ impl<C: Config> Entities<C> {
|
||||||
|
|
||||||
/// Returns an immutable iterator over all entities on the server in an
|
/// Returns an immutable iterator over all entities on the server in an
|
||||||
/// unspecified order.
|
/// unspecified order.
|
||||||
pub fn iter(&self) -> impl FusedIterator<Item = (EntityId, &Entity<C>)> + Clone + '_ {
|
pub fn iter(
|
||||||
self.sm.iter().map(|(k, v)| (EntityId(k), v))
|
&self,
|
||||||
|
) -> impl ExactSizeIterator<Item = (EntityId, &Entity<C>)> + FusedIterator + Clone + '_ {
|
||||||
|
self.slab.iter().map(|(k, v)| (EntityId(k), v))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a mutable iterator over all entities on the server in an
|
/// Returns a mutable iterator over all entities on the server in an
|
||||||
/// unspecified order.
|
/// unspecified order.
|
||||||
pub fn iter_mut(&mut self) -> impl FusedIterator<Item = (EntityId, &mut Entity<C>)> + '_ {
|
pub fn iter_mut(
|
||||||
self.sm.iter_mut().map(|(k, v)| (EntityId(k), v))
|
&mut self,
|
||||||
|
) -> impl ExactSizeIterator<Item = (EntityId, &mut Entity<C>)> + FusedIterator + '_ {
|
||||||
|
self.slab.iter_mut().map(|(k, v)| (EntityId(k), v))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a parallel immutable iterator over all entities on the server in
|
/// Returns a parallel immutable iterator over all entities on the server in
|
||||||
/// an unspecified order.
|
/// an unspecified order.
|
||||||
pub fn par_iter(&self) -> impl ParallelIterator<Item = (EntityId, &Entity<C>)> + Clone + '_ {
|
pub fn par_iter(&self) -> impl ParallelIterator<Item = (EntityId, &Entity<C>)> + Clone + '_ {
|
||||||
self.sm.par_iter().map(|(k, v)| (EntityId(k), v))
|
self.slab.par_iter().map(|(k, v)| (EntityId(k), v))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a parallel mutable iterator over all clients on the server in an
|
/// Returns a parallel mutable iterator over all clients on the server in an
|
||||||
|
@ -194,7 +200,7 @@ impl<C: Config> Entities<C> {
|
||||||
pub fn par_iter_mut(
|
pub fn par_iter_mut(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> impl ParallelIterator<Item = (EntityId, &mut Entity<C>)> + '_ {
|
) -> impl ParallelIterator<Item = (EntityId, &mut Entity<C>)> + '_ {
|
||||||
self.sm.par_iter_mut().map(|(k, v)| (EntityId(k), v))
|
self.slab.par_iter_mut().map(|(k, v)| (EntityId(k), v))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn update(&mut self) {
|
pub(crate) fn update(&mut self) {
|
||||||
|
|
25
src/lib.rs
25
src/lib.rs
|
@ -119,6 +119,17 @@
|
||||||
clippy::comparison_chain
|
clippy::comparison_chain
|
||||||
)]
|
)]
|
||||||
|
|
||||||
|
/// Used on [`Config`](config::Config) to allow for async methods in traits.
|
||||||
|
///
|
||||||
|
/// For more information see the [async_trait] crate.
|
||||||
|
///
|
||||||
|
/// [async_trait]: https://docs.rs/async-trait/latest/async_trait/
|
||||||
|
pub use async_trait::async_trait;
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use server::start_server;
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use {nbt, uuid, vek};
|
||||||
|
|
||||||
pub mod biome;
|
pub mod biome;
|
||||||
pub mod block;
|
pub mod block;
|
||||||
mod block_pos;
|
mod block_pos;
|
||||||
|
@ -135,7 +146,8 @@ pub mod player_textures;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
mod protocol_inner;
|
mod protocol_inner;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
mod slotmap;
|
mod slab;
|
||||||
|
mod slab_versioned;
|
||||||
pub mod spatial_index;
|
pub mod spatial_index;
|
||||||
pub mod text;
|
pub mod text;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
@ -147,17 +159,6 @@ pub mod protocol {
|
||||||
pub use crate::protocol_inner::*;
|
pub use crate::protocol_inner::*;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used on [`Config`](config::Config) to allow for async methods in traits.
|
|
||||||
///
|
|
||||||
/// For more information see the [async_trait] crate.
|
|
||||||
///
|
|
||||||
/// [async_trait]: https://docs.rs/async-trait/latest/async_trait/
|
|
||||||
pub use async_trait::async_trait;
|
|
||||||
#[doc(inline)]
|
|
||||||
pub use server::start_server;
|
|
||||||
#[doc(inline)]
|
|
||||||
pub use {nbt, uuid, vek};
|
|
||||||
|
|
||||||
/// The Minecraft protocol version this library currently targets.
|
/// The Minecraft protocol version this library currently targets.
|
||||||
pub const PROTOCOL_VERSION: i32 = 759;
|
pub const PROTOCOL_VERSION: i32 = 759;
|
||||||
/// The name of the Minecraft version this library currently targets, e.g.
|
/// The name of the Minecraft version this library currently targets, e.g.
|
||||||
|
|
340
src/slab.rs
Normal file
340
src/slab.rs
Normal file
|
@ -0,0 +1,340 @@
|
||||||
|
use std::iter::FusedIterator;
|
||||||
|
use std::{iter, mem, slice};
|
||||||
|
|
||||||
|
use rayon::iter::plumbing::UnindexedConsumer;
|
||||||
|
use rayon::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Slab<T> {
|
||||||
|
entries: Vec<Entry<T>>,
|
||||||
|
next_free_head: usize,
|
||||||
|
len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Default for Slab<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
enum Entry<T> {
|
||||||
|
Occupied(T),
|
||||||
|
Vacant { next_free: usize },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Slab<T> {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
entries: Vec::new(),
|
||||||
|
next_free_head: 0,
|
||||||
|
len: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, key: usize) -> Option<&T> {
|
||||||
|
match self.entries.get(key)? {
|
||||||
|
Entry::Occupied(value) => Some(value),
|
||||||
|
Entry::Vacant { .. } => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mut(&mut self, key: usize) -> Option<&mut T> {
|
||||||
|
match self.entries.get_mut(key)? {
|
||||||
|
Entry::Occupied(value) => Some(value),
|
||||||
|
Entry::Vacant { .. } => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.len
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, value: T) -> (usize, &mut T) {
|
||||||
|
self.insert_with(|_| value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_with(&mut self, f: impl FnOnce(usize) -> T) -> (usize, &mut T) {
|
||||||
|
self.len += 1;
|
||||||
|
|
||||||
|
if self.next_free_head == self.entries.len() {
|
||||||
|
let key = self.next_free_head;
|
||||||
|
|
||||||
|
self.next_free_head += 1;
|
||||||
|
|
||||||
|
self.entries.push(Entry::Occupied(f(key)));
|
||||||
|
|
||||||
|
match self.entries.last_mut() {
|
||||||
|
Some(Entry::Occupied(value)) => (key, value),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let entry = &mut self.entries[self.next_free_head];
|
||||||
|
|
||||||
|
let next_free = match entry {
|
||||||
|
Entry::Occupied(_) => unreachable!("corrupt free list"),
|
||||||
|
Entry::Vacant { next_free } => *next_free,
|
||||||
|
};
|
||||||
|
|
||||||
|
let key = self.next_free_head;
|
||||||
|
|
||||||
|
*entry = Entry::Occupied(f(key));
|
||||||
|
|
||||||
|
self.next_free_head = next_free;
|
||||||
|
|
||||||
|
match entry {
|
||||||
|
Entry::Occupied(value) => (key, value),
|
||||||
|
Entry::Vacant { .. } => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(&mut self, key: usize) -> Option<T> {
|
||||||
|
let entry = self.entries.get_mut(key)?;
|
||||||
|
match entry {
|
||||||
|
Entry::Occupied(_) => {
|
||||||
|
let old_entry = mem::replace(
|
||||||
|
entry,
|
||||||
|
Entry::Vacant {
|
||||||
|
next_free: self.next_free_head,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
self.next_free_head = key;
|
||||||
|
self.len -= 1;
|
||||||
|
|
||||||
|
match old_entry {
|
||||||
|
Entry::Occupied(value) => Some(value),
|
||||||
|
Entry::Vacant { .. } => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Entry::Vacant { .. } => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn retain(&mut self, mut f: impl FnMut(usize, &mut T) -> bool) {
|
||||||
|
for (key, entry) in self.entries.iter_mut().enumerate() {
|
||||||
|
if let Entry::Occupied(value) = entry {
|
||||||
|
if !f(key, value) {
|
||||||
|
*entry = Entry::Vacant {
|
||||||
|
next_free: self.next_free_head,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.next_free_head = key;
|
||||||
|
self.len -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.entries.clear();
|
||||||
|
self.next_free_head = 0;
|
||||||
|
self.len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter(&self) -> Iter<T> {
|
||||||
|
Iter {
|
||||||
|
entries: self.entries.iter().enumerate(),
|
||||||
|
len: self.len,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter_mut(&mut self) -> IterMut<T> {
|
||||||
|
IterMut {
|
||||||
|
entries: self.entries.iter_mut().enumerate(),
|
||||||
|
len: self.len,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> IntoIterator for &'a Slab<T> {
|
||||||
|
type IntoIter = Iter<'a, T>;
|
||||||
|
type Item = (usize, &'a T);
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> IntoIterator for &'a mut Slab<T> {
|
||||||
|
type IntoIter = IterMut<'a, T>;
|
||||||
|
type Item = (usize, &'a mut T);
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.iter_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Send + Sync> IntoParallelIterator for &'a Slab<T> {
|
||||||
|
type Item = (usize, &'a T);
|
||||||
|
type Iter = ParIter<'a, T>;
|
||||||
|
|
||||||
|
fn into_par_iter(self) -> Self::Iter {
|
||||||
|
ParIter { slab: self }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Send + Sync> IntoParallelIterator for &'a mut Slab<T> {
|
||||||
|
type Item = (usize, &'a mut T);
|
||||||
|
type Iter = ParIterMut<'a, T>;
|
||||||
|
|
||||||
|
fn into_par_iter(self) -> Self::Iter {
|
||||||
|
ParIterMut { slab: self }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Iter<'a, T> {
|
||||||
|
entries: iter::Enumerate<slice::Iter<'a, Entry<T>>>,
|
||||||
|
len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IterMut<'a, T> {
|
||||||
|
entries: iter::Enumerate<slice::IterMut<'a, Entry<T>>>,
|
||||||
|
len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ParIter<'a, T> {
|
||||||
|
slab: &'a Slab<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ParIterMut<'a, T> {
|
||||||
|
slab: &'a mut Slab<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Clone for Iter<'a, T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
entries: self.entries.clone(),
|
||||||
|
len: self.len,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Iterator for Iter<'a, T> {
|
||||||
|
type Item = (usize, &'a T);
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
for (key, entry) in &mut self.entries {
|
||||||
|
if let Entry::Occupied(value) = entry {
|
||||||
|
self.len -= 1;
|
||||||
|
return Some((key, value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_assert_eq!(self.len, 0);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
(self.len, Some(self.len))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> DoubleEndedIterator for Iter<'_, T> {
|
||||||
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
|
while let Some((key, entry)) = self.entries.next_back() {
|
||||||
|
if let Entry::Occupied(value) = entry {
|
||||||
|
self.len -= 1;
|
||||||
|
return Some((key, value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_assert_eq!(self.len, 0);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> ExactSizeIterator for Iter<'_, T> {
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.len
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> FusedIterator for Iter<'_, T> {}
|
||||||
|
|
||||||
|
impl<'a, T> Iterator for IterMut<'a, T> {
|
||||||
|
type Item = (usize, &'a mut T);
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
for (key, entry) in &mut self.entries {
|
||||||
|
if let Entry::Occupied(value) = entry {
|
||||||
|
self.len -= 1;
|
||||||
|
return Some((key, value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_assert_eq!(self.len, 0);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
(self.len, Some(self.len))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> DoubleEndedIterator for IterMut<'_, T> {
|
||||||
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
|
while let Some((key, entry)) = self.entries.next_back() {
|
||||||
|
if let Entry::Occupied(value) = entry {
|
||||||
|
self.len -= 1;
|
||||||
|
return Some((key, value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_assert_eq!(self.len, 0);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> ExactSizeIterator for IterMut<'_, T> {
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.len
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> FusedIterator for IterMut<'_, T> {}
|
||||||
|
|
||||||
|
impl<T> Clone for ParIter<'_, T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self { slab: &self.slab }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Send + Sync> ParallelIterator for ParIter<'a, T> {
|
||||||
|
type Item = (usize, &'a T);
|
||||||
|
|
||||||
|
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||||
|
where
|
||||||
|
C: UnindexedConsumer<Self::Item>,
|
||||||
|
{
|
||||||
|
self.slab
|
||||||
|
.entries
|
||||||
|
.par_iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(key, value)| match value {
|
||||||
|
Entry::Occupied(value) => Some((key, value)),
|
||||||
|
Entry::Vacant { .. } => None,
|
||||||
|
})
|
||||||
|
.drive_unindexed(consumer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Send + Sync> ParallelIterator for ParIterMut<'a, T> {
|
||||||
|
type Item = (usize, &'a mut T);
|
||||||
|
|
||||||
|
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||||
|
where
|
||||||
|
C: UnindexedConsumer<Self::Item>,
|
||||||
|
{
|
||||||
|
self.slab
|
||||||
|
.entries
|
||||||
|
.par_iter_mut()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(key, value)| match value {
|
||||||
|
Entry::Occupied(value) => Some((key, value)),
|
||||||
|
Entry::Vacant { .. } => None,
|
||||||
|
})
|
||||||
|
.drive_unindexed(consumer)
|
||||||
|
}
|
||||||
|
}
|
197
src/slab_versioned.rs
Normal file
197
src/slab_versioned.rs
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
use std::iter::FusedIterator;
|
||||||
|
use std::num::NonZeroU32;
|
||||||
|
|
||||||
|
use rayon::iter::{IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator};
|
||||||
|
|
||||||
|
use crate::slab::Slab;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct VersionedSlab<T> {
|
||||||
|
slab: Slab<Slot<T>>,
|
||||||
|
version: NonZeroU32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct Slot<T> {
|
||||||
|
value: T,
|
||||||
|
version: NonZeroU32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||||
|
pub struct Key {
|
||||||
|
pub index: u32,
|
||||||
|
pub version: NonZeroU32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Key {
|
||||||
|
pub const NULL: Self = Self {
|
||||||
|
index: u32::MAX,
|
||||||
|
version: match NonZeroU32::new(u32::MAX) {
|
||||||
|
Some(n) => n,
|
||||||
|
None => unreachable!(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn new(index: u32, version: NonZeroU32) -> Self {
|
||||||
|
Self { index, version }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Key {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::NULL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Key {
|
||||||
|
pub fn index(self) -> u32 {
|
||||||
|
self.index
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn version(self) -> NonZeroU32 {
|
||||||
|
self.version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ONE: NonZeroU32 = match NonZeroU32::new(1) {
|
||||||
|
Some(n) => n,
|
||||||
|
None => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
impl<T> VersionedSlab<T> {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
slab: Slab::new(),
|
||||||
|
version: ONE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, key: Key) -> Option<&T> {
|
||||||
|
let slot = self.slab.get(key.index as usize)?;
|
||||||
|
(slot.version == key.version).then(|| &slot.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mut(&mut self, key: Key) -> Option<&mut T> {
|
||||||
|
let slot = self.slab.get_mut(key.index as usize)?;
|
||||||
|
(slot.version == key.version).then(|| &mut slot.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.slab.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, value: T) -> (Key, &mut T) {
|
||||||
|
self.insert_with(|_| value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_with(&mut self, f: impl FnOnce(Key) -> T) -> (Key, &mut T) {
|
||||||
|
let version = self.version;
|
||||||
|
self.version = NonZeroU32::new(version.get().wrapping_add(1)).unwrap_or_else(|| {
|
||||||
|
log::warn!("slab version overflow");
|
||||||
|
ONE
|
||||||
|
});
|
||||||
|
|
||||||
|
let (index, slot) = self.slab.insert_with(|index| {
|
||||||
|
assert!(
|
||||||
|
index < u32::MAX as usize,
|
||||||
|
"too many values in versioned slab"
|
||||||
|
);
|
||||||
|
Slot {
|
||||||
|
value: f(Key::new(index as u32, version)),
|
||||||
|
version,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
(Key::new(index as u32, version), &mut slot.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(&mut self, key: Key) -> Option<T> {
|
||||||
|
self.get(key)?;
|
||||||
|
Some(self.slab.remove(key.index as usize).unwrap().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn retain(&mut self, mut f: impl FnMut(Key, &mut T) -> bool) {
|
||||||
|
self.slab
|
||||||
|
.retain(|idx, slot| f(Key::new(idx as u32, slot.version), &mut slot.value))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.slab.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter(&self) -> impl ExactSizeIterator<Item = (Key, &T)> + FusedIterator + Clone + '_ {
|
||||||
|
self.slab
|
||||||
|
.iter()
|
||||||
|
.map(|(idx, slot)| (Key::new(idx as u32, slot.version), &slot.value))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter_mut(
|
||||||
|
&mut self,
|
||||||
|
) -> impl ExactSizeIterator<Item = (Key, &mut T)> + FusedIterator + '_ {
|
||||||
|
self.slab
|
||||||
|
.iter_mut()
|
||||||
|
.map(|(idx, slot)| (Key::new(idx as u32, slot.version), &mut slot.value))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn par_iter(&self) -> impl ParallelIterator<Item = (Key, &T)> + Clone + '_
|
||||||
|
where
|
||||||
|
T: Send + Sync,
|
||||||
|
{
|
||||||
|
self.slab
|
||||||
|
.par_iter()
|
||||||
|
.map(|(idx, slot)| (Key::new(idx as u32, slot.version), &slot.value))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn par_iter_mut(&mut self) -> impl ParallelIterator<Item = (Key, &mut T)> + '_
|
||||||
|
where
|
||||||
|
T: Send + Sync,
|
||||||
|
{
|
||||||
|
self.slab
|
||||||
|
.par_iter_mut()
|
||||||
|
.map(|(idx, slot)| (Key::new(idx as u32, slot.version), &mut slot.value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn insert_remove() {
|
||||||
|
let mut slab = VersionedSlab::new();
|
||||||
|
|
||||||
|
let k0 = slab.insert(10).0;
|
||||||
|
let k1 = slab.insert(20).0;
|
||||||
|
let k2 = slab.insert(30).0;
|
||||||
|
assert!(k0 != k1 && k1 != k2 && k0 != k2);
|
||||||
|
|
||||||
|
assert_eq!(slab.remove(k1), Some(20));
|
||||||
|
assert_eq!(slab.get(k1), None);
|
||||||
|
assert_eq!(slab.get(k2), Some(&30));
|
||||||
|
let k3 = slab.insert(40).0;
|
||||||
|
assert_eq!(slab.get(k0), Some(&10));
|
||||||
|
assert_eq!(slab.get_mut(k3), Some(&mut 40));
|
||||||
|
assert_eq!(slab.remove(k0), Some(10));
|
||||||
|
|
||||||
|
slab.clear();
|
||||||
|
assert_eq!(slab.len(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn retain() {
|
||||||
|
let mut sm = VersionedSlab::new();
|
||||||
|
|
||||||
|
let k0 = sm.insert(10).0;
|
||||||
|
let k1 = sm.insert(20).0;
|
||||||
|
let k2 = sm.insert(30).0;
|
||||||
|
|
||||||
|
sm.retain(|k, _| k == k1);
|
||||||
|
|
||||||
|
assert_eq!(sm.get(k1), Some(&20));
|
||||||
|
assert_eq!(sm.len(), 1);
|
||||||
|
|
||||||
|
assert_eq!(sm.get(k0), None);
|
||||||
|
assert_eq!(sm.get(k2), None);
|
||||||
|
}
|
||||||
|
}
|
295
src/slotmap.rs
295
src/slotmap.rs
|
@ -1,295 +0,0 @@
|
||||||
use std::iter::FusedIterator;
|
|
||||||
use std::mem;
|
|
||||||
use std::num::NonZeroU32;
|
|
||||||
|
|
||||||
use rayon::iter::{
|
|
||||||
IndexedParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct SlotMap<T> {
|
|
||||||
slots: Vec<Slot<T>>,
|
|
||||||
/// Top of the free stack.
|
|
||||||
next_free_head: u32,
|
|
||||||
/// The number of occupied slots.
|
|
||||||
count: u32,
|
|
||||||
/// Version counter.
|
|
||||||
version: NonZeroU32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
|
||||||
pub struct Key {
|
|
||||||
index: u32,
|
|
||||||
version: NonZeroU32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Key {
|
|
||||||
pub const NULL: Self = Self {
|
|
||||||
index: u32::MAX,
|
|
||||||
version: match NonZeroU32::new(u32::MAX) {
|
|
||||||
Some(n) => n,
|
|
||||||
None => unreachable!(),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Key {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::NULL
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Key {
|
|
||||||
pub fn new(index: u32, version: NonZeroU32) -> Self {
|
|
||||||
Self { index, version }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_unique(index: u32, version: &mut NonZeroU32) -> Self {
|
|
||||||
*version = NonZeroU32::new(version.get().wrapping_add(1)).unwrap_or_else(|| {
|
|
||||||
log::warn!("slotmap version overflow");
|
|
||||||
ONE
|
|
||||||
});
|
|
||||||
|
|
||||||
Self {
|
|
||||||
index,
|
|
||||||
version: *version,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn index(self) -> u32 {
|
|
||||||
self.index
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn version(self) -> NonZeroU32 {
|
|
||||||
self.version
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const ONE: NonZeroU32 = match NonZeroU32::new(1) {
|
|
||||||
Some(n) => n,
|
|
||||||
None => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
enum Slot<T> {
|
|
||||||
Occupied { value: T, version: NonZeroU32 },
|
|
||||||
Free { next_free: u32 },
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> SlotMap<T> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
slots: Vec::new(),
|
|
||||||
next_free_head: 0,
|
|
||||||
count: 0,
|
|
||||||
version: ONE,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.count as usize
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert(&mut self, val: T) -> (Key, &mut T) {
|
|
||||||
self.insert_with(|_| val)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert_with(&mut self, f: impl FnOnce(Key) -> T) -> (Key, &mut T) {
|
|
||||||
assert!(self.count < u32::MAX, "SlotMap: too many items inserted");
|
|
||||||
|
|
||||||
if self.next_free_head == self.slots.len() as u32 {
|
|
||||||
self.count += 1;
|
|
||||||
self.next_free_head += 1;
|
|
||||||
|
|
||||||
let key = Key::new_unique(self.next_free_head - 1, &mut self.version);
|
|
||||||
|
|
||||||
self.slots.push(Slot::Occupied {
|
|
||||||
value: f(key),
|
|
||||||
version: key.version(),
|
|
||||||
});
|
|
||||||
|
|
||||||
let value = match self.slots.last_mut() {
|
|
||||||
Some(Slot::Occupied { value, .. }) => value,
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
(key, value)
|
|
||||||
} else {
|
|
||||||
let slot = &mut self.slots[self.next_free_head as usize];
|
|
||||||
|
|
||||||
let next_free = match slot {
|
|
||||||
Slot::Occupied { .. } => unreachable!("corrupt free list"),
|
|
||||||
Slot::Free { next_free } => *next_free,
|
|
||||||
};
|
|
||||||
|
|
||||||
let key = Key::new_unique(self.next_free_head, &mut self.version);
|
|
||||||
|
|
||||||
*slot = Slot::Occupied {
|
|
||||||
value: f(key),
|
|
||||||
version: key.version(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let value = match slot {
|
|
||||||
Slot::Occupied { value, .. } => value,
|
|
||||||
Slot::Free { .. } => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
self.next_free_head = next_free;
|
|
||||||
self.count += 1;
|
|
||||||
|
|
||||||
(key, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove(&mut self, key: Key) -> Option<T> {
|
|
||||||
let slot = self.slots.get_mut(key.index as usize)?;
|
|
||||||
match slot {
|
|
||||||
Slot::Occupied { version, .. } if *version == key.version() => {
|
|
||||||
let old_slot = mem::replace(
|
|
||||||
slot,
|
|
||||||
Slot::Free {
|
|
||||||
next_free: self.next_free_head,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
self.next_free_head = key.index;
|
|
||||||
self.count -= 1;
|
|
||||||
|
|
||||||
match old_slot {
|
|
||||||
Slot::Occupied { value, .. } => Some(value),
|
|
||||||
Slot::Free { .. } => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(&self, key: Key) -> Option<&T> {
|
|
||||||
match self.slots.get(key.index as usize)? {
|
|
||||||
Slot::Occupied { value, version } if *version == key.version() => Some(value),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_mut(&mut self, key: Key) -> Option<&mut T> {
|
|
||||||
match self.slots.get_mut(key.index as usize)? {
|
|
||||||
Slot::Occupied { value, version } if *version == key.version() => Some(value),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
self.slots.clear();
|
|
||||||
self.next_free_head = 0;
|
|
||||||
self.count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn retain(&mut self, mut f: impl FnMut(Key, &mut T) -> bool) {
|
|
||||||
for (i, mut slot) in self.slots.iter_mut().enumerate() {
|
|
||||||
if let Slot::Occupied { value, version } = &mut slot {
|
|
||||||
let key = Key::new(i as u32, *version);
|
|
||||||
|
|
||||||
if !f(key, value) {
|
|
||||||
*slot = Slot::Free {
|
|
||||||
next_free: self.next_free_head,
|
|
||||||
};
|
|
||||||
|
|
||||||
self.next_free_head = key.index;
|
|
||||||
self.count -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iter(&self) -> impl FusedIterator<Item = (Key, &T)> + Clone + '_ {
|
|
||||||
self.slots
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.filter_map(|(i, slot)| match &slot {
|
|
||||||
Slot::Occupied { value, version } => Some((Key::new(i as u32, *version), value)),
|
|
||||||
Slot::Free { .. } => None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iter_mut(&mut self) -> impl FusedIterator<Item = (Key, &mut T)> + '_ {
|
|
||||||
self.slots
|
|
||||||
.iter_mut()
|
|
||||||
.enumerate()
|
|
||||||
.filter_map(|(i, slot)| match slot {
|
|
||||||
Slot::Occupied { value, version } => Some((Key::new(i as u32, *version), value)),
|
|
||||||
Slot::Free { .. } => None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Sync> SlotMap<T> {
|
|
||||||
pub fn par_iter(&self) -> impl ParallelIterator<Item = (Key, &T)> + Clone + '_ {
|
|
||||||
self.slots
|
|
||||||
.par_iter()
|
|
||||||
.enumerate()
|
|
||||||
.filter_map(|(i, slot)| match &slot {
|
|
||||||
Slot::Occupied { value, version } => Some((Key::new(i as u32, *version), value)),
|
|
||||||
Slot::Free { .. } => None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Send + Sync> SlotMap<T> {
|
|
||||||
pub fn par_iter_mut(&mut self) -> impl ParallelIterator<Item = (Key, &mut T)> + '_ {
|
|
||||||
self.slots
|
|
||||||
.par_iter_mut()
|
|
||||||
.enumerate()
|
|
||||||
.filter_map(|(i, slot)| match slot {
|
|
||||||
Slot::Occupied { value, version } => Some((Key::new(i as u32, *version), value)),
|
|
||||||
Slot::Free { .. } => None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Default for SlotMap<T> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn insert_remove() {
|
|
||||||
let mut sm = SlotMap::new();
|
|
||||||
|
|
||||||
let k0 = sm.insert(10).0;
|
|
||||||
let k1 = sm.insert(20).0;
|
|
||||||
let k2 = sm.insert(30).0;
|
|
||||||
|
|
||||||
assert_eq!(sm.remove(k1), Some(20));
|
|
||||||
assert_eq!(sm.get(k1), None);
|
|
||||||
assert_eq!(sm.get(k2), Some(&30));
|
|
||||||
let k3 = sm.insert(40).0;
|
|
||||||
assert_eq!(sm.get(k0), Some(&10));
|
|
||||||
assert_eq!(sm.get_mut(k3), Some(&mut 40));
|
|
||||||
assert_eq!(sm.remove(k0), Some(10));
|
|
||||||
|
|
||||||
sm.clear();
|
|
||||||
assert_eq!(sm.len(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn retain() {
|
|
||||||
let mut sm = SlotMap::new();
|
|
||||||
|
|
||||||
let k0 = sm.insert(10).0;
|
|
||||||
let k1 = sm.insert(20).0;
|
|
||||||
let k2 = sm.insert(30).0;
|
|
||||||
|
|
||||||
sm.retain(|k, _| k == k1);
|
|
||||||
|
|
||||||
assert_eq!(sm.get(k1), Some(&20));
|
|
||||||
assert_eq!(sm.len(), 1);
|
|
||||||
|
|
||||||
assert_eq!(sm.get(k0), None);
|
|
||||||
assert_eq!(sm.get(k2), None);
|
|
||||||
}
|
|
||||||
}
|
|
44
src/world.rs
44
src/world.rs
|
@ -9,12 +9,12 @@ use crate::config::Config;
|
||||||
use crate::dimension::DimensionId;
|
use crate::dimension::DimensionId;
|
||||||
use crate::player_list::PlayerList;
|
use crate::player_list::PlayerList;
|
||||||
use crate::server::SharedServer;
|
use crate::server::SharedServer;
|
||||||
use crate::slotmap::{Key, SlotMap};
|
use crate::slab_versioned::{Key, VersionedSlab};
|
||||||
use crate::spatial_index::SpatialIndex;
|
use crate::spatial_index::SpatialIndex;
|
||||||
|
|
||||||
/// A container for all [`World`]s on a [`Server`](crate::server::Server).
|
/// A container for all [`World`]s on a [`Server`](crate::server::Server).
|
||||||
pub struct Worlds<C: Config> {
|
pub struct Worlds<C: Config> {
|
||||||
sm: SlotMap<World<C>>,
|
slab: VersionedSlab<World<C>>,
|
||||||
server: SharedServer<C>,
|
server: SharedServer<C>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,16 +38,16 @@ impl WorldId {
|
||||||
impl<C: Config> Worlds<C> {
|
impl<C: Config> Worlds<C> {
|
||||||
pub(crate) fn new(server: SharedServer<C>) -> Self {
|
pub(crate) fn new(server: SharedServer<C>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
sm: SlotMap::new(),
|
slab: VersionedSlab::new(),
|
||||||
server,
|
server,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new world on the server with the provided dimension. A
|
/// Creates a new world on the server with the provided dimension. A
|
||||||
/// reference to the world along with its ID is returned.
|
/// reference to the world along with its ID is returned.
|
||||||
pub fn create(&mut self, dim: DimensionId, data: C::WorldState) -> (WorldId, &mut World<C>) {
|
pub fn insert(&mut self, dim: DimensionId, state: C::WorldState) -> (WorldId, &mut World<C>) {
|
||||||
let (id, world) = self.sm.insert(World {
|
let (id, world) = self.slab.insert(World {
|
||||||
state: data,
|
state,
|
||||||
spatial_index: SpatialIndex::new(),
|
spatial_index: SpatialIndex::new(),
|
||||||
chunks: Chunks::new(self.server.clone(), dim),
|
chunks: Chunks::new(self.server.clone(), dim),
|
||||||
meta: WorldMeta {
|
meta: WorldMeta {
|
||||||
|
@ -65,8 +65,8 @@ impl<C: Config> Worlds<C> {
|
||||||
/// Note that entities located in the world are not deleted themselves.
|
/// Note that entities located in the world are not deleted themselves.
|
||||||
/// Additionally, any clients that are still in the deleted world at the end
|
/// Additionally, any clients that are still in the deleted world at the end
|
||||||
/// of the tick are disconnected.
|
/// of the tick are disconnected.
|
||||||
pub fn delete(&mut self, world: WorldId) -> bool {
|
pub fn remove(&mut self, world: WorldId) -> bool {
|
||||||
self.sm.remove(world.0).is_some()
|
self.slab.remove(world.0).is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deletes all worlds from the server (as if by [`Self::delete`]) for which
|
/// Deletes all worlds from the server (as if by [`Self::delete`]) for which
|
||||||
|
@ -74,48 +74,52 @@ impl<C: Config> Worlds<C> {
|
||||||
///
|
///
|
||||||
/// All worlds are visited in an unspecified order.
|
/// All worlds are visited in an unspecified order.
|
||||||
pub fn retain(&mut self, mut f: impl FnMut(WorldId, &mut World<C>) -> bool) {
|
pub fn retain(&mut self, mut f: impl FnMut(WorldId, &mut World<C>) -> bool) {
|
||||||
self.sm.retain(|k, v| f(WorldId(k), v))
|
self.slab.retain(|k, v| f(WorldId(k), v))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of worlds on the server.
|
/// Returns the number of worlds on the server.
|
||||||
pub fn count(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.sm.len()
|
self.slab.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a shared reference to the world with the given ID. If
|
/// Returns a shared reference to the world with the given ID. If
|
||||||
/// the ID is invalid, then `None` is returned.
|
/// the ID is invalid, then `None` is returned.
|
||||||
pub fn get(&self, world: WorldId) -> Option<&World<C>> {
|
pub fn get(&self, world: WorldId) -> Option<&World<C>> {
|
||||||
self.sm.get(world.0)
|
self.slab.get(world.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an exclusive reference to the world with the given ID. If the
|
/// Returns an exclusive reference to the world with the given ID. If the
|
||||||
/// ID is invalid, then `None` is returned.
|
/// ID is invalid, then `None` is returned.
|
||||||
pub fn get_mut(&mut self, world: WorldId) -> Option<&mut World<C>> {
|
pub fn get_mut(&mut self, world: WorldId) -> Option<&mut World<C>> {
|
||||||
self.sm.get_mut(world.0)
|
self.slab.get_mut(world.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an immutable iterator over all worlds on the server in an
|
/// Returns an immutable iterator over all worlds on the server in an
|
||||||
/// unspecified order.
|
/// unspecified order.
|
||||||
pub fn iter(&self) -> impl FusedIterator<Item = (WorldId, &World<C>)> + Clone + '_ {
|
pub fn iter(
|
||||||
self.sm.iter().map(|(k, v)| (WorldId(k), v))
|
&self,
|
||||||
|
) -> impl ExactSizeIterator<Item = (WorldId, &World<C>)> + FusedIterator + Clone + '_ {
|
||||||
|
self.slab.iter().map(|(k, v)| (WorldId(k), v))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a mutable iterator over all worlds on the server in an
|
/// Returns a mutable iterator over all worlds on the server in an
|
||||||
/// unspecified ordder.
|
/// unspecified order.
|
||||||
pub fn iter_mut(&mut self) -> impl FusedIterator<Item = (WorldId, &mut World<C>)> + '_ {
|
pub fn iter_mut(
|
||||||
self.sm.iter_mut().map(|(k, v)| (WorldId(k), v))
|
&mut self,
|
||||||
|
) -> impl ExactSizeIterator<Item = (WorldId, &mut World<C>)> + FusedIterator + '_ {
|
||||||
|
self.slab.iter_mut().map(|(k, v)| (WorldId(k), v))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a parallel immutable iterator over all worlds on the server in
|
/// Returns a parallel immutable iterator over all worlds on the server in
|
||||||
/// an unspecified order.
|
/// an unspecified order.
|
||||||
pub fn par_iter(&self) -> impl ParallelIterator<Item = (WorldId, &World<C>)> + Clone + '_ {
|
pub fn par_iter(&self) -> impl ParallelIterator<Item = (WorldId, &World<C>)> + Clone + '_ {
|
||||||
self.sm.par_iter().map(|(k, v)| (WorldId(k), v))
|
self.slab.par_iter().map(|(k, v)| (WorldId(k), v))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a parallel mutable iterator over all worlds on the server in an
|
/// Returns a parallel mutable iterator over all worlds on the server in an
|
||||||
/// unspecified order.
|
/// unspecified order.
|
||||||
pub fn par_iter_mut(&mut self) -> impl ParallelIterator<Item = (WorldId, &mut World<C>)> + '_ {
|
pub fn par_iter_mut(&mut self) -> impl ParallelIterator<Item = (WorldId, &mut World<C>)> + '_ {
|
||||||
self.sm.par_iter_mut().map(|(k, v)| (WorldId(k), v))
|
self.slab.par_iter_mut().map(|(k, v)| (WorldId(k), v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue