default_value_ref allocates a DynamicMessage and clones the pool Arc on every get() of an unset message field
- Vorherrschende Sprache
- Rust
- Sterne
- 883
- Forks
- 88
- Ø Merge
- 3 T. 19 Std.
- Gemergte PRs (30 T.)
- 42
Beschreibung
`default_value_ref` in `buffa-descriptor/src/reflect/dynamic.rs` answers `get()` on an unset singular *message* field by building a value on every call:
```rust
FieldKind::Singular(SingularKind::Message(midx)) => ValueRef::Message(ReflectCow::Owned(
alloc::boxed::Box::new(DynamicMessage::new(Arc::clone(pool), midx)),
)),
```
so each read of an unset message-typed field costs a heap allocation, an `Arc` clone of the pool (an atomic RMW on a line shared across threads — see the companion issue on the pool's count line), and the matching drop, where the list and map arms of the same function hand out `'static` empties for free. A reflective reader that probes optional sub-messages (`has`-then-`get` patterns, or readers that treat unset as the empty message per proto3 semantics) pays this per field per message per request.
Options that keep `get()`'s signature:
- Cache one empty `DynamicMessage` per `MessageIndex` in the pool (built lazily, e.g. a `OnceLock>` slot per message, or a side `Vec` filled at pool build) and return `ValueRef::Message(ReflectCow::Borrowed(&empty))`. The empty message's own `pool` field is the one wrinkle — an empty message never dereferences it for field storage, so it could hold a `Weak` or the pool could store the empties without a back-reference; whichever fits the existing invariants.
- Or return a dedicated `ValueRef::EmptyMessage(MessageIndex)`-style variant and let `ReflectMessage` consumers treat it as the default instance, avoiding the self-referential question altogether at the cost of a new variant.
The first keeps every caller working unchanged.
Beitragsleitfaden
Bewertung
Dieses Issue wurde noch nicht bewertet.