Skip to content

Upgrade flecs core to upstream master 6e4cd338a - #301

Merged
Indra-db merged 37 commits into
mainfrom
update-flecs
Jul 18, 2026
Merged

Indra-db merged 37 commits into
mainfrom
update-flecs

Conversation

@Indra-db

@Indra-db Indra-db commented Jul 18, 2026 •

Copy link
Copy Markdown
Owner

Upgrade flecs core to upstream master 6e4cd338a

Flecs core: Upgrades base from 9930c85 to upstream master 6e4cd338a (474 upstream commits).
Vendored via: Fork integration branch 8a7c39fab (merges indradb/on-replace, table_column_locks_cr_locks, indradb/rust).


User-Facing Additions

Hierarchy & Entities

  • Two hierarchy storage models, named after the mechanism they use:
    • world.entity_child_of(parent) / entity_named_child_of() / prefab_child_of() / prefab_named_child_of() — fragmenting (ChildOf, parent) pair storage. Each distinct parent is a distinct pair id, so children of different parents live in different tables: fast per-parent iteration, full cascade/up query support, but many parents means many tables and reparenting is an archetype move. Same mechanism as the .child_of() builder method.
    • world.entity_with_parent(parent) / entity_named_with_parent() — non-fragmenting hierarchy via the new flecs::Parent component (plus (ParentDepth, depth) value pair). The parent is column data, so all children share tables regardless of parent: no table explosion with thousands of parents, and reparenting is a cheap component write instead of an archetype move. Built for deep or highly dynamic scene graphs.
    • Rule of thumb: few parents / heavy cascade-style queries → child_of; huge parent counts / frequent reparenting → with_parent.
  • Builtins: Added flecs::Parent, flecs::TreeSpawner, and flecs::ParentDepth.
  • World APIs: Added World::each_alive_entity(), World::new_mini(), World::release(), is_defer_suspended(), and the entity range API (entity_range_new/set/get, EntityRange).
  • Entity Pair Support: set_ptr/set_ptr_with_size now accept pairs (impl IntoId, upstream #1866); modules get (With, Singleton).

Queries & Optimization

  • SparseQuery (world.sparse_query::<T>()): Cache-less, allocation-free iteration directly over sparse component storages. Component requirements checked at compile time.
  • Compile-Time Traits: #[flecs(traits(Sparse))], traits(DontFragment), and traits((OnInstantiate, ...)) now emit ComponentInfo consts (IS_SPARSE, IS_DONT_FRAGMENT, ON_INSTANTIATE). Invalid sparse-query combinations fail at compile time.
  • Sparse Get Fast Path: get/try_get/cloned on compile-time sparse/dont_fragment components bypass table-record lookups and read directly from sparse storage. (Parity with C++ is_get_sparse_component; non-pair components only).
  • Query Grouping: group_by is now unsorted by default. Added .group_by_ordered(), group flags, Query::each_group(), System::set_group()/clear_group(), and Query::has()/has_table()/has_table_range().

Systems, Observers & Hooks

  • Re-configuration: Added Observer::update::<T>() and System::update::<T>(). Builders now create entities lazily; system phase is set via desc.phase.
  • Component::on_validate(): Runs before on_set/OnSet. Returning false suppresses them.
  • Component::on_replace(): (entity, prev, next) callback invoked before next overwrites prev.

⚠️ Rust Semantics Difference: Unlike C/C++, this hook only fires if the component already existed (preventing &mut T on unconstructed memory). First-time sets or deferred batch sets do not fire it. Registering this hook disallows mutable-pointer operations (get_mut, ensure, emplace).

Meta & Examples

  • Reflection & Meta: Added UntypedComponent::create_member_entities() (required for member DSL queries/metrics/alerts), flecs::meta::Map/Value types, EcsTypeKind variants, and member accessors.
  • Examples: Added 8 new examples covering traits, hierarchy, validation, and reflection.

API Renames (rust-idiomatic naming)

  • _w_ → _with_ throughout the Rust API (the _w_ abbreviation stays C-only): set_ptr_with_size, path_with_sep, path_from_with_sep, set_rate_with_tick_source, entity_bulk_with_entity_ids, EntityView::new_with_parent/new_with_id/new_with_entity/new_with_entity_ids. FFI symbols (sys::ecs_field_w_size, etc.) are unchanged, they mirror C.

Breaking Changes

  • Hierarchy: Removed EntityView::child() and child_named(). Use world.entity_child_of(parent) or entity_named_child_of(parent, name) instead.
  • Module reparenting: now destructs the old parent scope unconditionally (upstream 4fd6b8dca parity). Entities left in a namespace a module is reparented out of are deleted with it — don't share a module's pre-reparent namespace with your own entities.
  • Internals: Removed flecs::Private/FlecsInternals. Builtin ID renumbering updated to match upstream.
  • Meta: Flecs no longer creates member entities automatically on struct registration. Call create_member_entities() per type if needed.
  • Ordering: group_by iteration order is now unspecified unless group_by_ordered is explicitly used.
  • Traits & Hooks:
    • Dynamically adding (OnInstantiate, Inherit) to a compile-time sparse component now asserts in debug builds. Use #[flecs(traits(...))] instead.
    • on_replace only fires on genuine replacement. Ported C/C++ code relying on it for first-time initialization must migrate to on_add/on_set.

Soundness & Bug Fixes

  • Fixed UB in CachedRef (Release Builds): Fixed a bug where CachedRef read uninitialized memory in release profiles because bindings lacked the FLECS_DEBUG trailing fields. Bindings are now profile-matched, and CachedRef stores the component ID directly.
  • Locks-off builds compile again: Without flecs_safety_locks, ecs_get_ptr_t is a bare void*; field accesses now go through get_ptr_raw()/get_ptr_null() helpers (Rust mirror of C's ECS_GET_PTR_PTR/ECS_GET_PTR_NULL), fixing every feature-subset combination in cargo hack --each-feature.
  • Iterator Contract Rework: Field resolution now defaults to the it.columns primary path with it.trs null-guarded. This fixes multiple null-dereference aborts (hooks, sparse terms, enum systems) that previously caused infinite panic loops.
  • Hardened field::<T> Validation: Pair terms now verify that ecs_get_typeid(term_id) matches T in release builds to prevent type reinterpretation mismatches.
  • Typed-Pair Wildcards: get now resolves the concrete ID via ecs_search before casting; null-table guarded.

Tooling & Infrastructure

  • Profile-Matched Bindings: bindgen now runs twice per regeneration to generate distinct bindings.rs (FLECS_DEBUG) and bindings_release.rs (FLECS_NDEBUG) modules, automatically selected by Cargo's build profile.
  • ABI Drift Guard: Added abi_test using ecs_rust_sizeof_* shims to assert that Rust size_of perfectly matches C sizeof across both profiles.
  • Regeneration hardening: regenerate_binding removed from flecs_ecs_sys default features (standalone sys builds no longer silently clobber committed bindings); regen via cargo make regenerate-bindings (full addon feature set); new CI bindings-check job regenerates and fails on drift.
  • Test Suite: Ported new upstream C++ tests across all major sub-systems (41 new tests, including dynamic-inherit abort tests, debug-gated since ecs_check compiles out under NDEBUG). Integrated rstest templates for fragment/sparse/dont_fragment component lifecycles.

Indra-db added 30 commits July 17, 2026 21:31
# Conflicts:
#	flecs_ecs/src/core/mod.rs
@Indra-db
Indra-db merged commit 456e0f5 into main Jul 18, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant