logo

Rust crates reviews

Cryptographically verifiable, distributed dependency reviews

crate: specs

https://lib.rs/crates/specs/

Add the last reviewed version to Cargo.toml / [dependencies]:

specs = "0.15.1"

Filter reviews clicking on the numbers in the summary.

Full column names in tooltip hints: rating Negative, rating Neutral, rating Positive, rating Strong, thoroughness, understanding, reviews count.

Neg
Neu
Pos
Str
tho
und
rev
1
1
1
1
crate version
rating
date
reviewer
thoroughness, understanding
specs 0.15.1
neutral
2019-09-19
medium, medium

Pros:

  • Very well documented
  • Well tested
  • Good attention to detail WRT unsafe code.

Cons:

  • Issue #644 Scary partially uninitialized Vec<T>s
  • PR #645println!()s for !is_unconstrained() joins is lame / a perf hazard in and of itself.
  • Complicated as heck
  • I'm not yet convinced the ParJoin s are sound
  • Plenty of unsafe code
    • Some scary lifetime extensions
    • Comments like "// This is horribly unsafe."
  • See -1s for more details

0.15.1

Misc. notes:

  • I still don't have a firm grasp on when world.maintain() is necessary
crev
thoroughnessmedium
understandingmedium
ratingneutral
FileRatingNotes
.github/ISSUE_TEMPLATE/bug_report.md+1
.github/ISSUE_TEMPLATE/feature_request.md+1
.github/stale.yml+1
benches/benches_main.rs+1criterion
benches/big_or_small.rs+1nalgebra, shred
benches/parallel.rs+1
benches/storage_cmp.rs+1
benches/storage_sparse.rs+1
benches/world.rs+1rayon
docs/reference/src/01_system.md0~empty
docs/reference/src/intro.md+1
docs/reference/src/SUMMARY.md+1TOC
docs/reference/book.toml+1
docs/tutorials/src/images/component-tables.svg+1<switch>? <foreignObject>? What is this madness...
docs/tutorials/src/images/entity-component.svg+1
docs/tutorials/src/images/system.svg+1
docs/tutorials/src/01_intro.md+1Java?
docs/tutorials/src/02_hello_world.md0specs 0.15.0, lots of rust,ignores, poor link names
docs/tutorials/src/03_dispatcher.md+1
docs/tutorials/src/04_resources.md+1Option<Read<...>>
docs/tutorials/src/05_storages.md+1
docs/tutorials/src/06_system_data.md+1
docs/tutorials/src/07_setup.md+1
docs/tutorials/src/08_join.md+1
docs/tutorials/src/09_parallel_join.md+1
docs/tutorials/src/10_rendering.md+1
docs/tutorials/src/11_advanced_component.md+1
docs/tutorials/src/12_tracked.md+1
docs/tutorials/src/13_saveload.md+1
docs/tutorials/src/14_troubleshooting.md+1
docs/tutorials/src/SUMMARY.md+1TOC
docs/tutorials/book.toml+1
docs/website/content/pages/about.md+1
docs/website/content/pages/docs.md+1
docs/website/content/_index.md+1
docs/website/content/specs-0.15.md+1draft, "Test"
docs/website/themes/hyde/sass/hyde.scss+1
docs/website/themes/hyde/sass/poole.scss+1
docs/website/themes/hyde/sass/print.scss+1
docs/website/themes/hyde/static/.gitkeep+1
docs/website/themes/hyde/templates/404.html+1some templating engine used
docs/website/themes/hyde/templates/index.html+1
docs/website/themes/hyde/templates/page-nodate.html+1
docs/website/themes/hyde/templates/page.html+1
docs/website/themes/hyde/.gitignore+1
docs/website/themes/hyde/config.toml+1
docs/website/themes/hyde/LICENSE+1MIT
docs/website/themes/hyde/README.md+1
docs/website/themes/hyde/theme.toml+1
docs/website/config.toml+1
examples/async.rs+1
examples/basic.rs+1
examples/bitset.rs+1fizzbuzz! Hah.
examples/cluster_bomb.rs+1
examples/full.rs+1dispatcher.with_barrier()
examples/ordered_track.rs+1
examples/saveload.rs+1ron, structs/impls inside fns
examples/track.rs+1
scripts/build-netlify.sh0Installing things from the internet (zola, mdbook, rustup)
scripts/kcov.sh-1docker - owns/deletes mykcov1, runs images, disables seccomp
src/join/mod.rs0I don't fully grok the ParJoin limitations yet, nor the underlying reason behind unsafe fn open/get.
src/join/par_join.rs-1"[...] technically not allowed" (ab)use of UnsafeCell
src/saveload/de.rs+1
src/saveload/marker.rs+1
src/saveload/mod.rs+1
src/saveload/ser.rs+1
src/saveload/tests.rs+1
src/saveload/uuid.rs+1
src/storage/data.rs+1
src/storage/drain.rs+1
src/storage/entry.rs-1Entries::get seems sketchy
src/storage/flagged.rs+1
src/storage/generic.rs+1
src/storage/mod.rs-1&mut Storage::get_mut is sketchy as heck
src/storage/restrict.rs-1More ParJoin I can't wrap my head around, _unchecked fns sound unsafe but aren't marked as such.
src/storage/storages.rs-1#644, UnprotectedStorage is a scary API in general for perf reasons.
src/storage/tests.rs+1needs more
src/storage/track.rs0
src/world/comp.rs+1
src/world/entity.rs0Possibly missing some self.killed.contains(...) checks in Allocator, ungrokked ParJoin
src/world/lazy.rs+1
src/world/mod.rs+1
src/world/tests.rs+1
src/world/world_ext.rs0Some concerns about create_entity_unchecked, is_alive
src/bitset.rs+1
src/changeset.rs-1Bypasses lifetime checks
src/error.rs+1
src/lib.rs+1
src/prelude.rs+1
tests/saveload.rs+1
tests/tests.rs+1
.cargo_vcs_info.json+1
.cargo-ok+1
.gitignore+1
.rustfmt.toml+1
Cargo.lock+1
Cargo.toml+1
Cargo.toml.orig+1
CHANGELOG.md+1I like the link format here
CODE_OF_CONDUCT.md+1
codecov.yml+1
CONTRIBUTING.md+1
LICENSE-APACHE+1
LICENSE-MIT+1
netlify.toml+1
PULL_REQUEST_TEMPLATE.md+1
README.md+1Dual MIT/Apache 2.0, could use a deps badge
OtherRatingNotes
unsafe-1ParJoin sounds unsound, scary comments like "// This is horribly unsafe."
miri-1N/A (atomics)
fs+1N/A
io+1N/A
docs+1Sets the golden standard for how to document unsafe code in many places... but sadly not all.
tests0Some gaps on a per-module basis, which really seem necessary for some of the scarier nests of unsafe code.

src/join/mod.rs

LineWhatNotes
227unsafe fn Join::openHmm... will this truly be unsound? Will need to read more...
237unsafe fn Join::get"The implementation [...] has no invariants to meet" - I don't grok why this is unsafe yet, but tat least the doc comments seem clear.
273unsafe fn MaybeJoin::open+1, just forwards, good doc comments about held constraints
280unsafe fn MaybeJoin::get+1, meets documented constraints, good doc comments about held constraints
305fn JoinIter::new0, fix pending: #645 println! isn't an appropriate mechanism for this and possibly adds another perf issue. PR switches to log crate.
312fn JoinIter::new0, relies on constraint of impl
370fn JoinIter::get+1, documents and abides by safety constraints
386fn JoinIter::get_unchecked+1, documents and abides by safety constraints
399fn JoinIter::next+1, documents and abides by safety constraints
422unsafe fn (A,B,...)::open+1, documents and abides by safety constraints
434unsafe fn (A,B,...)::get+1, documents and abides by safety constraints
440fn (A,B,...)::is_unconstrained+1
451unsafe impl ParJoin for (A,B,...)0, sounds accurate but I don't fully grok
500unsafe fn _Readers_::open+1, just forwards sanely
506unsafe fn _Readers_::get+1, just forwards sanely
511unsafe fn _Readers_::is_unconstrained+1
519unsafe impl ParJoin for _Readers_0, sounds accurate but I don't fully grok
542unsafe fn _Writers_::open+1, just forwards sanely
548unsafe fn _Writers_::get+1, just forwards sanely
553unsafe fn _Writers_::is_unconstrained+1
561unsafe impl ParJoin for _Writers_0, sounds accurate but I don't fully grok
EOF

src/join/par_join.rs

LineWhatNotes
21fn ParJoin::par_join comment-1, "NOTE: This is currently unspecified behavior." - concerning...
30fn ParJoin::par_join0, fix pending: #645 println! isn't an appropriate mechanism for this and possibly adds another perf issue. PR switches to log crate.
56fn JoinParIter::drive_unindexed0, unsafe { ... } relies on constraint of impl
98unsafe impl Send for JoinProducer-1, "[...] technically not allowed" abuse of UnsafeCell
130fn UnindexedProducer::fold_with0, logic makes sense to me here
EOF

src/storage/drain.rs

LineWhatNotes
25unsafe fn Drain::open+1, just forwards sanely
32unsafe fn Drain::get+1, uses remove sanely
EOF

src/storage/entry.rs

LineWhatNotes
41fn Storage::entry+1, unsafe { ... } documents and abides by safety constraints
121fn Storage::entries+1
140unsafe fn Entries::open+1
146unsafe fn Entries::get-1, unsafe { ... } - I can't verify how this lifetime extension is possibly sound either.
164fn Entries::is_unconstrained+1
184fn OccupiedEntry::get+1, unsafe { ... } - documents and abides by safety constraints
197fn OccupiedEntry::get_mut+1, unsafe { ... } - documents and abides by safety constraints
205fn OccupiedEntry::into_mut+1, unsafe { ... } - documents and abides by safety constraints
209fn OccupiedEntry::insert+1
215fn OccupiedEntry::remove+1
236fn VacantEntry::insert+1, unsafe { ... } - documents and abides by safety constraints
EOF

src/storage/flagged.rs

LineWhatNotes
203unsafe fn FlaggedStorage::clean+1, just forwards sanely
210unsafe fn FlaggedStorage::get+1, just forwards sanely
214unsafe fn FlaggedStorage::get_mut+1, just forwards sanely
221unsafe fn FlaggedStorage::insert+1, just forwards sanely
228unsafe fn FlaggedStorage::remove+1, just forwards sanely
EOF

src/storage/mod.rs

LineWhatNotes
57unsafe fn AntiStorage::open+1, safe and sound
62unsafe fn AntiStorage::get+1, safe and sound
66unsafe impl DistinctStorage for AntiStorage+1, safe and sound
70unsafe impl ParJoin for AntiStorage+1, safe and sound
78unsafe impl CastFrom for dyn AnyStorage0, don't fully grok why this is unsafe, but looks 100% safe and sound and matches shred examples.
122unsafe trait DistinctStorage+1, safe and sound
155fn MaskedStorage::clear+1, unsafe { ... } - documents and abides by safety constraints
165fn MaskedStorage::remove+1, unsafe { ... } - documents and abides by safety constraints
175fn MaskedStorage::drop+1, unsafe { ... } - documents and abides by safety constraints
231fn Storage::get+1, unsafe { ... } - documents and abides by safety constraints
274unsafe fn Storage::unprotected_storage_mut+1, documents constraints
282fn Storage::get_mut+1, unsafe { ... } - documents and abides by safety constraints
299fn Storage::insert+1, unsafe { ... } - documents and abides by safety constraints
304fn Storage::insert+1, unsafe { ... } - documents and abides by safety constraints
341unsafe impl DistinctStorage for Storage+1, proper constraints
356unsafe fn &Storage::open+1, documents constraints
362unsafe fn &Storage::get+1, just forwards sanely
400unsafe fn &mut Storage::open+1, documents constraints
409unsafe fn &mut Storage::get-1, WTF? Lifetime extension? Can't this just be v.get_mut(i)?
449trait UnprotectedStorage-1, needs to make it clearer that clearmust be called before dropping as currently stands, unless that's just a bug.
457unsafe fn UnprotectedStorage::clear+1, documents constraints
472unsafe fn UnprotectedStorage::get+1, documents constraints
485unsafe fn UnprotectedStorage::get_mut+1, documents constraints
496unsafe fn UnprotectedStorage::insert+1, documents constraints
504unsafe fn UnprotectedStorage::remove+1, documents constraints
514unsafe fn UnprotectedStorage::drop+1, documents constraints, default impl sane/sound
EOF

src/storage/restrict.rs

LineWhatNotes
83unsafe impl ParJoin for &mut RestrictedStorage<..., MutableParallelRestriction>-1, no idea
93unsafe impl ParJoin for &RestrictedStorage<..., ImmutableAliasing>-1, no idea
113unsafe fn &RestrictedStorage::open0, could maybe document safety more, but I believe sound?
118unsafe fn &RestrictedStorage::get0, could maybe document safety more, but I believe sound?
144unsafe fn &mut RestrictedStorage::open0, could maybe document safety more, but I believe sound?
149unsafe fn &mut RestrictedStorage::get0, could maybe document safety more, but I believe sound?
239fn PairedStorage::get_unchecked-1, unsafe { ... } - maybe fine, but safety undocumented and get_unchecked sounds like something that should itself be an unsafe fn?
252fn PariedStorage::get_mut_unchecked-1, unsafe { ... } - maybe fine, but safety undocumented and get_unchecked sounds like something that should itself be an unsafe fn?
272fn PairedStorage::get+1, abides by safety constraints
294fn PairedStorage::get_mut+1, abides by safety constraints
EOF

src/storage/storages.rs

Careful auditing gives a good idea for what the actual API requirements of UnprotectedStorage are, and it's a doozy.

  1. VecStorage makes it unsound to not call clean
  2. Noop cleans on several storages make me think it should consume self instead of taking &mut self - maybe can't due to API limitations?
  3. Need clearer UnprotectedStorage docs
LineWhatNotes
20unsafe fn BTreeStorage::clean0, should maybe clear storage?
27unsafe fn BTreeStorage::get+1
31unsafe fn BTreeStorage::get_mut+1
35unsafe fn BTreeStorage::insert+1
39unsafe fn BTreeStorage::remove+1
44unsafe impl DistinctStorage for BTreeStorage+1 as I grok DistinctStorage
54unsafe fn HashMapStorage::clean0, should maybe clear storage?
61unsafe fn HashMapStorage::get+1
65unsafe fn HashMapStorage::get_mut+1
69unsafe fn HashMapStorage::insert+1
73unsafe fn HashMapStorage::remove+1
78unsafe impl DistinctStorage for HashMapStorage+1
95unsafe fn DenseVecStorage::clean0, should maybe clear storage?
102unsafe fn DenseVecStorage::get0, unsound on bad index, but fn is unsafe. Otherwise sound.
107unsafe fn DenseVecStorage::get_mut0, unsound on bad index, but fn is unsafe. Otherwise sound.
112unsafe fn DenseVecStorage::insert0, set_len leaves uninitialized gaps in the data_id Vec. Maybe sound, but at least violates std docs. See #644
124unsafe fn DenseVecStorage::remove0, unsound on bad index, but fn is unsafe. Otherwise sound.
133unsafe impl DistinctStorage for DenseVecStorage+1
143unsafe fn NullStorage::clean+1
149unsafe fn NullStorage::get+1
153unsafe fn NullStorage::get_mut+1
157unsafe fn NullStorage::insert+1
159unsafe fn NullStorage::remove+1
178unsafe impl DistinctStorage for NullStorage+1, precondition enforced by Default::default()
187unsafe fn VecStorage::clean+1
200unsafe fn VecStorage::get0, unsound on bad index, but fn is unsafe. Otherwise sound.
204unsafe fn VecStorage::get_mut0, unsound on bad index, but fn is unsafe. Otherwise sound.
208unsafe fn VecStorage::insert-1, set_len leaves uninitialized gaps in the data_id Vec, making it unsound to drop before calling clean. Sound if perfectly used (e.g. call clean), but a timebomb as stands IMO. See #644
222unsafe fn VecStorage::remove0, unsound on bad index, but fn is unsafe. Otherwise sound.
229unsafe impl DistinctStorage for VecStorage+1
EOF

src/storage/tests.rs

LineWhatNotes
460vec_arc+1, unsafe { ... }
-1, would like to see more tests involving drop types
-1, would like to see more tests involving specific storages
EOF

src/storage/track.rs

LineWhatNotes
53fn Storage::channel0, unsafe { ... } - I don't grok the safety invariants we need to hold here
59fn Storage::event_emission0, unsafe { ... } - I don't grok the safety invariants we need to hold here
72fn Storage::channel_mut0, unsafe { ... } - I don't grok the safety invariants we need to hold here
92fn Storage::set_event_emission0, unsafe { ... } - I don't grok the safety invariants we need to hold here
EOF

src/world/entity.rs

Well, this is a bit more complicated than simply doing generational indicies. Atomics... oh boy.

LineWhatNotes
51struct Allocator0, interplay of fields is underdocumented
Allocator::aliveLagging bitset derived from aliveness of generations, used for Join and not much else. Lags behind when *_atomic is used.
Allocator::raised, killedTracks atomic ops specifically for later merge, otherwise ignored/internal.
Allocator::cacheLIFO queue of entity IDs to reuse
Allocator::max_idnext entity ID if no entity IDs to reuse
90fn Allocator::kill_atomic0, leaves generations alone? Is this an async kill?
114fn Allocator::is_alive-1, doesn't this need to check !self.killed.contains(id) too?
131fn Allocator::entity-1, doesn't this need to check !self.killed.contains(id) too?
188fn Allocator::merge0, why not push directly into cache?
211struct CreateIterAtomic+1
223struct Entity+1
256struct EntitiesRes+1
321unsafe fn EntitiesRes::open+1? don't fully grok preconds but this seems fine/safe
321unsafe fn EntitiesRes::get+1? don't fully grok preconds but this seems fine/safe
336unsafe impl ParJoin for EntitiesRes-1, don't fully grok preconds
341struct EntityResBuilder+1
376struct Generation+1, should maybe have a struct-level comment that negative = dead though? Although obvious from fn is_alive...
420struct ZeroableGeneration+1
441fn ZeroableGeneration::die0, is debug_assert! enough? Seems like it'll go super off the rails in release builds, and other fns like raised panic. Internal method though...
451fn ZeroableGeneration::raised0, explicit checked_sub vs implicit for Generation::raised
470struct EntityCache0, needs better docs. Seems to be a semi-concurrent FILO index list for entity realloc.
EOF

src/world/world_ext.rs

LineWhatNotes
240fn WorldExt::create_entity_unchecked-1, does this need to be an unsafe fn? What isn't checked? Just that you have exclusive world access?
281fn WorldExt::is_alive0, sketchy edge cases
392fn World::is_alive0, should this really be panicing on a dead generation? Doesn't that just mean the entity is dead?!?
EOF

src/bitset.rs

LineWhatNotes
24unsafe fn BitSet*::open+1, sure?
29unsafe fn BitSet*::get+1, sure?
35unsafe impl ParJoin for BitSet*0, think this is fine?
EOF

src/changeset.rs

LineWhatNotes
61fn ChangeSet::add+1, unsafe { ... } - documents and abides by safety constraints
66fn ChangeSet::add+1, unsafe { ... } - abides by safety constraints, docs seem a little off
77fn ChangeSet::clear+1, unsafe { ... } - documents and abides by safety constraints
115unsafe fn &mut ChangeSet::open+1, sure?
123unsafe fn &mut ChangeSet::get-1, bypasses lifetime checks!
134unsafe fn &ChangeSet::open+1, sure?
141unsafe fn &ChangeSet::get+1, sure?
154unsafe fn ChangeSet::open+1, sure?
161unsafe fn ChangeSet::get+1, sure?
EOF

TIL

  • std::num::NonZeroI32
  • std::fmt::Formatter .debug_tuple().field().finish()
  • #[must_use] makes a lot of sense for builder patterns terminating in .build()

© bestia.dev 2023, MIT License, Version: 2023.608.1636

Open source repository for this web app: https://github.com/bestia-dev/cargo_crev_web/