Skip to content

Commit 437e720

Browse files
authored
Merge pull request #765 from Imberflur/safety
Safety
2 parents 89f2826 + 276450e commit 437e720

39 files changed

Lines changed: 2841 additions & 1048 deletions

.config/nextest.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[profile.default-miri]
2+
slow-timeout = { period = "30s", terminate-after = 1 }
3+
fail-fast = false

.github/workflows/ci.yml

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ jobs:
2525
fail-fast: true
2626
matrix:
2727
os: [macos-latest, windows-latest, ubuntu-latest]
28-
toolchain: [stable, beta, nightly, 1.65.0]
28+
toolchain: [stable, beta, nightly, 1.70.0]
2929
steps:
30-
- uses: actions/checkout@v2
30+
- uses: actions/checkout@v3
3131

3232
# install the toolchain we are going to compile and test with
3333
- name: install ${{ matrix.toolchain }} toolchain
@@ -77,3 +77,18 @@ jobs:
7777

7878
# - run: mdbook test -L ./target/debug/deps docs/book
7979
# if: matrix.toolchain == 'stable' && matrix.os == 'ubuntu-latest'
80+
81+
miri:
82+
name: "Miri"
83+
runs-on: ubuntu-latest
84+
steps:
85+
- uses: actions/checkout@v3
86+
- name: Install Miri
87+
run: |
88+
rustup toolchain install nightly --component miri
89+
rustup override set nightly
90+
cargo miri setup
91+
- name: Install latest nextest release
92+
uses: taiki-e/install-action@nextest
93+
- name: Test with Miri
94+
run: ./miri.sh

.github/workflows/deny.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ jobs:
1717
# Prevent sudden announcement of a new advisory from failing ci:
1818
continue-on-error: ${{ matrix.checks == 'advisories' }}
1919

20+
2021
steps:
21-
- uses: actions/checkout@v2
22+
- uses: actions/checkout@v3
2223
- uses: EmbarkStudios/cargo-deny-action@v1
2324
with:
2425
command: check ${{ matrix.checks }}

.rustfmt.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
hard_tabs = false
2-
imports_granularity = "Crate"
32
reorder_impl_items = true
43
use_field_init_shorthand = true
54
use_try_shorthand = true
65
format_code_in_doc_comments = true
76
wrap_comments = true
8-
edition = "2018"
7+
edition = "2021"
98
version = "Two"

CHANGELOG.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
1+
# Unreleased
2+
3+
* MSRV to 1.70.0 ([#765])
4+
* Significant refactor of `Join` and related traits to alleviate soundness
5+
issues. Includes introduction of a lending/streaming join via the `LendJoin`
6+
trait which is the new common denominator implemented by joinable types.
7+
([#765])
8+
9+
[#765]: https://github.com/amethyst/specs/pull/765
10+
111
# 0.19.0 (2023-06-10)
212

313
* Bump MSRV to 1.65.0 ([#766])
414
* Added index where entity deletion stopped to the error returned from `WorldExt::delete_entities` ([#766])
515
* Fix bug where deleting an entity with the wrong generation could clear the components of an existing entity. ([#766])
6-
* Bump shred to version `0.14.1`, MSRV to 1.60.0 ([shred changelog][shred-changelog], [#756])
16+
* Bump shred to version `0.14.1`, MSRV to 1.60.0 ([shred changelog][shred_changelog], [#756])
717

18+
[shred_changelog]: https://github.com/amethyst/shred/blob/master/CHANGELOG.md#0141-2022-07-14
819
[#756]: https://github.com/amethyst/specs/pull/756
920
[#766]: https://github.com/amethyst/specs/pull/766
10-
[shred-changelog]: https://github.com/amethyst/shred/blob/6b754812e304cf6c63ba0364a82a7e0e5025aaa4/CHANGELOG.md#0140-2022-07-12
1121

1222
# 0.18.0 (2022-07-02)
1323

Cargo.toml

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,20 @@ license = "MIT OR Apache-2.0"
1414
authors = ["slide-rs hackers"]
1515
include = ["/src", "/examples", "/benches", "/README.md", "/LICENSE-MIT", "/LICENSE-APACHE"]
1616
edition = "2021"
17-
rust-version = "1.65.0"
17+
rust-version = "1.70.0"
1818

1919
# the `storage_cmp` and `storage_sparse` benches are called from `benches_main`
2020
autobenches = false
2121

2222
[dependencies]
2323
ahash = "0.7.6"
2424
crossbeam-queue = "0.3"
25-
hibitset = { version = "0.6.3", default-features = false }
25+
hibitset = { version = "0.6.4", default-features = false }
2626
log = "0.4.8"
27-
shred = { version = "0.14.1", default-features = false }
27+
shred = { version = "0.15.0", default-features = false }
2828
shrev = "1.1.1"
2929
tuple_utils = "0.4.0"
30+
nougat = "0.2.3"
3031

3132
rayon = { version = "1.5.1", optional = true }
3233
serde = { version = "1.0.104", optional = true, features = ["serde_derive"] }
@@ -40,7 +41,7 @@ uuid_entity = ["uuid", "serde"]
4041
stdweb = ["uuid/js"]
4142
storage-event-control = []
4243
derive = ["shred-derive", "specs-derive"]
43-
nightly = []
44+
nightly = ["shred/nightly"]
4445

4546
shred-derive = ["shred/shred-derive"]
4647

@@ -53,30 +54,31 @@ criterion = "0.3.1"
5354
ron = "0.7.1"
5455
rand = "0.8"
5556
serde_json = "1.0.48"
56-
shred = { version = "0.14.1", default-features = false, features = ["shred-derive"] }
57+
shred = { version = "0.15.0", default-features = false, features = ["shred-derive"] }
5758
specs-derive = { path = "specs-derive", version = "0.4.1" }
5859

60+
[[example]]
61+
name = "async"
5962
[[example]]
6063
name = "basic"
61-
6264
[[example]]
63-
name = "full"
64-
65+
name = "bitset"
6566
[[example]]
6667
name = "cluster_bomb"
67-
6868
[[example]]
69-
name = "bitset"
70-
69+
name = "full"
7170
[[example]]
72-
name = "track"
73-
71+
name = "lend_join"
72+
test = true
7473
[[example]]
7574
name = "ordered_track"
76-
7775
[[example]]
7876
name = "saveload"
7977
required-features = ["serde"]
78+
[[example]]
79+
name = "slices"
80+
[[example]]
81+
name = "track"
8082

8183
[[bench]]
8284
name = "benches_main"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Unlike most other ECS libraries out there, it provides
3535
other and you can use barriers to force several stages in system execution
3636
* high performance for real-world applications
3737

38-
Minimum Rust version: 1.65
38+
Minimum Rust version: 1.70
3939

4040
## [Link to the book][book]
4141

benches/parallel.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ impl Component for Lifetime {
5555
}
5656

5757
#[derive(Clone, Copy, Debug)]
58+
#[allow(dead_code)]
5859
struct Ball {
5960
radius: f32,
6061
}
@@ -64,6 +65,7 @@ impl Component for Ball {
6465
}
6566

6667
#[derive(Clone, Copy, Debug)]
68+
#[allow(dead_code)]
6769
struct Rect {
6870
a: f32,
6971
b: f32,
@@ -91,6 +93,7 @@ impl Component for SpawnRequests {
9193
}
9294

9395
#[derive(Clone, Copy, Debug)]
96+
#[allow(dead_code)]
9497
struct Collision {
9598
a: Entity,
9699
b: Entity,
@@ -102,6 +105,7 @@ impl Component for Collision {
102105
}
103106

104107
#[derive(Clone, Copy, Debug)]
108+
#[allow(dead_code)]
105109
struct Room {
106110
inner_width: f32,
107111
inner_height: f32,

docs/tutorials/src/12_tracked.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,8 @@ fetch the component as mutable if/when needed.
117117
for (entity, mut comp) in (&entities, &mut comps.restrict_mut()).join() {
118118
// Check whether this component should be modified, without fetching it as
119119
// mutable.
120-
if comp.get_unchecked().condition < 5 {
121-
let mut comp = comp.get_mut_unchecked();
120+
if comp.get().condition < 5 {
121+
let mut comp = comp.get_mut();
122122
// ...
123123
}
124124
}
@@ -137,4 +137,4 @@ simply call `storage.set_event_emission(true)`.
137137

138138
_See
139139
[FlaggedStorage Doc](https://docs.rs/specs/latest/specs/struct.FlaggedStorage.html)
140-
for more into._
140+
for more into._

examples/lend_join.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
use specs::prelude::*;
2+
struct Pos(f32);
3+
4+
impl Component for Pos {
5+
type Storage = VecStorage<Self>;
6+
}
7+
8+
fn main() {
9+
let mut world = World::new();
10+
11+
world.register::<Pos>();
12+
13+
let entity0 = world.create_entity().with(Pos(0.0)).build();
14+
world.create_entity().with(Pos(1.6)).build();
15+
world.create_entity().with(Pos(5.4)).build();
16+
17+
let mut pos = world.write_storage::<Pos>();
18+
let entities = world.entities();
19+
20+
// Unlike `join` the type return from `lend_join` does not implement
21+
// `Iterator`. Instead, a `next` method is provided that only allows one
22+
// element to be accessed at once.
23+
let mut lending = (&mut pos).lend_join();
24+
25+
// We copy the value out here so the borrow of `lending` is released.
26+
let a = lending.next().unwrap().0;
27+
// Here we keep the reference from `lending.next()` alive, so `lending`
28+
// remains exclusively borrowed for the lifetime of `b`.
29+
let b = lending.next().unwrap();
30+
// This right fails to compile since `b` is used below:
31+
// let d = lending.next().unwrap();
32+
b.0 = a;
33+
34+
// Items can be iterated with `while let` loop:
35+
let mut lending = (&mut pos).lend_join();
36+
while let Some(pos) = lending.next() {
37+
pos.0 *= 1.5;
38+
}
39+
40+
// A `for_each` method is also available:
41+
(&mut pos).lend_join().for_each(|pos| {
42+
pos.0 += 1.0;
43+
});
44+
45+
// Finally, there is one bonus feature which `.join()` can't soundly provide.
46+
let mut lending = (&mut pos).lend_join();
47+
// That is, there is a method to get the joined result for a particular
48+
// entity:
49+
if let Some(pos) = lending.get(entity0, &entities) {
50+
pos.0 += 5.0;
51+
}
52+
}

0 commit comments

Comments
 (0)