Skip to content

perf!: replace Cow<str> with NodeStr for inline decoded strings - #514

Merged
jlucaso1 merged 3 commits into
mainfrom
perf/packed-nibble-stack-decode
Apr 12, 2026
Merged

perf!: replace Cow<str> with NodeStr for inline decoded strings#514
jlucaso1 merged 3 commits into
mainfrom
perf/packed-nibble-stack-decode

Conversation

@jlucaso1

@jlucaso1 jlucaso1 commented Apr 12, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Introduce NodeStr<'a> enum (Borrowed(&'a str) | Owned(CompactString)) replacing Cow<'a, str> in the borrowed decode model
  • Rewrite packed nibble/hex decode to use a [u8; 254] stack buffer instead of heap Vec<u8>, with SIMD helpers writing directly into the stack buffer
  • Short owned strings (≤24 bytes) stored inline via CompactString — eliminates heap allocations for phone numbers and protocol attribute values
  • Remove dead code: JidRef::new, Jid::actual_agent

Why NodeStr instead of just stack buffer

A stack buffer alone doesn't reduce allocations — String::from(stack_slice) still heap-allocates. The win comes from CompactString's inline storage: phone numbers (10-15 chars), message IDs, timestamps all fit in the 24-byte inline buffer. Cow<'a, str>::Owned holds String which always heap-allocates, so the type must change.

What changed

Type Before After
NodeRef.tag Cow<'a, str> NodeStr<'a>
AttrsRef key Cow<'a, str> NodeStr<'a>
ValueRef::String Cow<'a, str> NodeStr<'a>
NodeContentRef::String Cow<'a, str> NodeStr<'a>
JidRef.user Cow<'a, str> NodeStr<'a>
read_packed return String (heap Vec) CompactString (stack decode)

NodeStr implements Deref<Target=str> so existing code using .as_ref(), .parse(), == "value" works unchanged. AttrParserRef public API still returns Cow<'a, str>.

Breaking changes

  • ValueRef::String inner type changed
  • NodeContentRef::String inner type changed
  • NodeRef.tag type changed
  • JidRef.user type changed
  • AttrsRef key type changed
  • Removed JidRef::new() (unused — all sites use struct literal)
  • Removed Jid::actual_agent() (unused)

Test plan

  • cargo fmt --all
  • cargo clippy --all --tests
  • cargo test --all --exclude e2e-tests (all 619 tests pass)
  • cargo check -p wacore-binary --all-features

Summary by CodeRabbit

  • Refactor

    • Replaced string handling with a compact borrow-or-own string type across core data, reducing allocations and improving memory efficiency.
    • Optimized packed decoding to avoid heap allocations and tightened attribute value handling.
    • Exposed the compact string type in public exports.
  • Breaking Change

    • Public types and signatures for nodes, JID components, and attribute iteration changed; an attribute field’s visibility was narrowed — client code must be updated.

Introduce NodeStr<'a> = Borrowed(&'a str) | Owned(CompactString) to
replace Cow<'a, str> in the borrowed decode model. Short owned strings
(≤24 bytes) are stored inline via CompactString, eliminating heap
allocations for packed phone numbers and protocol values.

Rewrite read_packed to decode into a [u8; 254] stack buffer instead of
a heap Vec, then materialize as CompactString. SIMD helpers now write
directly into the stack buffer.

Also removes dead code: JidRef::new, Jid::actual_agent.
@coderabbitai

coderabbitai Bot commented Apr 12, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Replaces Cow<'a, str> with a new NodeStr<'a> across the binary crate (node/jid/decoder/attrs), narrows AttrParserRef::attrs visibility, and reworks packed-string decoding to use a fixed stack buffer and return CompactString.

Changes

Cohort / File(s) Summary
Core string type & node model
wacore/binary/src/node.rs
Adds pub enum NodeStr<'a> { Borrowed(&'a str), Owned(CompactString) }, to_compact_string(), and replaces Cow<'a, str> with NodeStr<'a> in AttrsRef, ValueRef::String, NodeContentRef::String, NodeRef::tag, constructors, iterators, and related APIs.
Decoder changes & packed decoding
wacore/binary/src/decoder.rs
String materialization paths now return NodeStr (borrowed or owned); JID formatting uses a compact helper producing NodeStr::Owned; packed nibble/hex decoding rewritten to decode into a fixed [u8; 254] stack buffer and produce CompactString (no Vec allocations).
Attrs parsing & visibility
wacore/binary/src/attrs.rs
AttrParserRef::attrs type changed to &'a [(NodeStr<'a>, ValueRef<'a>)] and visibility narrowed to pub(crate); get_raw compares keys via deref and preserves required-key error recording.
JID representation
wacore/binary/src/jid.rs
JidRef::user changed from Cow<'a, str> to NodeStr<'a>; removed Jid::actual_agent() and JidRef::new(); to_owned() uses NodeStr::to_compact_string().
Public re-exports
wacore/binary/src/lib.rs
Public re-exports extended to include NodeStr from the node module alongside existing node-related items.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐇 I hop through bytes both short and long,
Borrowed lines and owned ones song,
Compact crates hold every name,
Cows step back — a sleeker game! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 73.17% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: replacing Cow with NodeStr for inline decoded strings, a performance optimization indicated by 'perf!' prefix.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch perf/packed-nibble-stack-decode

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
wacore/binary/src/node.rs (1)

551-556: 🧹 Nitpick | 🔵 Trivial

Make NodeRef::new accept impl Into<NodeStr<'a>>.

You already added From<&str> and From<CompactString> for NodeStr, but the constructor still forces callers to spell NodeStr::Borrowed(...)/NodeStr::Owned(...) manually. Accepting impl Into<NodeStr<'a>> keeps the public API ergonomic during the migration.

✂️ Suggested API tweak
-    pub fn new(tag: NodeStr<'a>, attrs: AttrsRef<'a>, content: Option<NodeContentRef<'a>>) -> Self {
+    pub fn new(
+        tag: impl Into<NodeStr<'a>>,
+        attrs: AttrsRef<'a>,
+        content: Option<NodeContentRef<'a>>,
+    ) -> Self {
         Self {
-            tag,
+            tag: tag.into(),
             attrs,
             content: content.map(Box::new),
         }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wacore/binary/src/node.rs` around lines 551 - 556, Change the NodeRef
constructor to accept a flexible tag type by replacing the tag parameter type
from NodeStr<'a> to impl Into<NodeStr<'a>> (i.e., update pub fn new(tag:
NodeStr<'a>, ...) -> Self to pub fn new(tag: impl Into<NodeStr<'a>>, ... ) ->
Self) and then call tag.into() when storing it (e.g., tag: tag.into()). This
leverages your existing From<&str>/From<CompactString> implementations for
NodeStr and makes NodeRef::new ergonomic without callers needing
NodeStr::Borrowed/Owned; leave attrs and content handling unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@wacore/binary/src/attrs.rs`:
- Around line 13-15: Public field AttrParserRef::attrs leaks NodeStr through its
pub declaration causing downstream breaks; make the storage private (remove pub
from attrs) and provide a public accessor that projects the internal
representation back to the original Cow-based API (e.g., pub fn attrs(&self) ->
Cow<'a, [(NodeStr<'a>, ValueRef<'a>)]> or an iterator producing
(Cow<NodeStr<'a>>, ValueRef<'a>) pairs) so callers that previously read
parser.attrs continue to get Cow-backed values; update code that used direct
field access to call the new accessor; keep the internal type as the changed &'a
[(NodeStr<'a>, ValueRef<'a>)] but only expose it via the Cow-returning accessor
to preserve ABI/behavior.

In `@wacore/binary/src/node.rs`:
- Around line 7-13: Add a clone-preserving helper on NodeStr, e.g. pub fn
to_compact_string(&self) -> CompactString, that returns the inner CompactString
when NodeStr::Owned (cloning the CompactString) and builds a CompactString from
the &str when NodeStr::Borrowed; then update NodeRef::to_owned() and
JidRef::to_owned() to call NodeStr::to_compact_string() instead of
round-tripping via as_ref() so owned NodeStr values keep the fast path and avoid
reallocating heap strings.

---

Outside diff comments:
In `@wacore/binary/src/node.rs`:
- Around line 551-556: Change the NodeRef constructor to accept a flexible tag
type by replacing the tag parameter type from NodeStr<'a> to impl
Into<NodeStr<'a>> (i.e., update pub fn new(tag: NodeStr<'a>, ...) -> Self to pub
fn new(tag: impl Into<NodeStr<'a>>, ... ) -> Self) and then call tag.into() when
storing it (e.g., tag: tag.into()). This leverages your existing
From<&str>/From<CompactString> implementations for NodeStr and makes
NodeRef::new ergonomic without callers needing NodeStr::Borrowed/Owned; leave
attrs and content handling unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3381b605-d6dd-4320-96cd-422020c1e542

📥 Commits

Reviewing files that changed from the base of the PR and between bfe434a and 579fbb4.

📒 Files selected for processing (5)
  • wacore/binary/src/attrs.rs
  • wacore/binary/src/decoder.rs
  • wacore/binary/src/jid.rs
  • wacore/binary/src/lib.rs
  • wacore/binary/src/node.rs

Comment on lines 13 to 15
pub struct AttrParserRef<'a> {
pub attrs: &'a [(Cow<'a, str>, ValueRef<'a>)],
pub attrs: &'a [(NodeStr<'a>, ValueRef<'a>)],
pub errors: Vec<BinaryError>,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Public AttrParserRef now leaks NodeStr through a pub field.

Changing attrs to &[(NodeStr<'a>, ValueRef<'a>)] is a downstream compile break for any caller that reads parser.attrs directly. The accessor methods still return Cow, but the struct’s public surface no longer does. If preserving the old API is important, this storage needs to stay internal or be projected back through a Cow-based accessor.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wacore/binary/src/attrs.rs` around lines 13 - 15, Public field
AttrParserRef::attrs leaks NodeStr through its pub declaration causing
downstream breaks; make the storage private (remove pub from attrs) and provide
a public accessor that projects the internal representation back to the original
Cow-based API (e.g., pub fn attrs(&self) -> Cow<'a, [(NodeStr<'a>,
ValueRef<'a>)]> or an iterator producing (Cow<NodeStr<'a>>, ValueRef<'a>) pairs)
so callers that previously read parser.attrs continue to get Cow-backed values;
update code that used direct field access to call the new accessor; keep the
internal type as the changed &'a [(NodeStr<'a>, ValueRef<'a>)] but only expose
it via the Cow-returning accessor to preserve ABI/behavior.

Comment thread wacore/binary/src/node.rs
Comment on lines +7 to +13
/// Borrowed-or-inline string for decoded nodes. Short owned values (≤24 bytes)
/// are stored inline via `CompactString`, avoiding heap allocation.
#[derive(Clone, yoke::Yokeable)]
pub enum NodeStr<'a> {
Borrowed(&'a str),
Owned(CompactString),
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Add a clone-preserving escape hatch on NodeStr.

Right now the new type only has conversions into NodeStr, so downstream owned conversions have to round-trip through as_ref() and rebuild a CompactString. A small helper like to_compact_string() would let NodeRef::to_owned() and JidRef::to_owned() preserve the already-owned fast path instead of copying heap-backed strings again.

♻️ Suggested helper
+impl NodeStr<'_> {
+    #[inline]
+    pub fn to_compact_string(&self) -> CompactString {
+        match self {
+            NodeStr::Borrowed(s) => CompactString::from(*s),
+            NodeStr::Owned(s) => s.clone(),
+        }
+    }
+}

Also applies to: 15-38, 82-94

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wacore/binary/src/node.rs` around lines 7 - 13, Add a clone-preserving helper
on NodeStr, e.g. pub fn to_compact_string(&self) -> CompactString, that returns
the inner CompactString when NodeStr::Owned (cloning the CompactString) and
builds a CompactString from the &str when NodeStr::Borrowed; then update
NodeRef::to_owned() and JidRef::to_owned() to call NodeStr::to_compact_string()
instead of round-tripping via as_ref() so owned NodeStr values keep the fast
path and avoid reallocating heap strings.

@github-actions

github-actions Bot commented Apr 12, 2026

Copy link
Copy Markdown

Benchmark Results

2 improvement(s):

Benchmark Current Baseline Change
binary_benchmark::jid_optimization_group::bench_jid_to_owned_access jid_access:setup_jid_heavy_marshaled() 13,493 15,731 -14.2%
binary_benchmark::attr_parser_group::bench_attr_parser attr_lookup:setup_attr_marshaled() 5,039 5,382 -6.4%
57 unchanged benchmark(s)
Benchmark Current Baseline Change
reporting_token_benchmark::content_extraction_group::bench_content_extraction simple:setup_simple_message() 3,879 3,879 +0.0%
reporting_token_benchmark::content_extraction_group::bench_content_extraction extended:setup_extended_message() 11,851 11,851 +0.0%
reporting_token_benchmark::key_derivation_group::bench_key_derivation 43,398 43,398 +0.0%
reporting_token_benchmark::token_calculation_group::bench_token_calculation 19,365 19,365 +0.0%
reporting_token_benchmark::full_generation_group::bench_full_token_generation simple:setup_full_gen_simple() 68,814 68,814 +0.0%
reporting_token_benchmark::full_generation_group::bench_full_token_generation extended:setup_full_gen_extended() 76,781 76,781 +0.0%
reporting_token_benchmark::message_encoding_group::bench_message_encoding simple:setup_simple_message() 2,214 2,214 +0.0%
reporting_token_benchmark::message_encoding_group::bench_message_encoding extended:setup_extended_message() 5,939 5,939 +0.0%
send_receive_benchmark::dm_send::bench_dm_send text:setup_dm_send() 179,518 179,581 -0.0%
send_receive_benchmark::dm_recv::bench_dm_recv text:setup_dm_recv() 193,123 193,123 +0.0%
send_receive_benchmark::group_send::bench_group_send group_10:setup_group_send_10() 893,735 893,158 +0.1%
send_receive_benchmark::group_send::bench_group_send group_50:setup_group_send_50() 995,926 994,413 +0.2%
send_receive_benchmark::group_send::bench_group_send group_256:setup_group_send_256() 1,537,869 1,537,293 +0.0%
send_receive_benchmark::group_send_skdm::bench_group_send_skdm skdm_10:setup_group_skdm_10() 2,783,006 2,772,530 +0.4%
send_receive_benchmark::group_send_skdm::bench_group_send_skdm skdm_50:setup_group_skdm_50() 10,326,738 10,309,024 +0.2%
send_receive_benchmark::group_send_skdm::bench_group_send_skdm skdm_256:setup_group_skdm_256() 49,248,332 49,166,273 +0.2%
send_receive_benchmark::group_recv::bench_group_recv text:setup_group_recv() 12,615,499 12,463,773 +1.2%
binary_benchmark::marshal_group::bench_marshal_allocating 95,585 93,109 +2.7%
binary_benchmark::marshal_group::bench_marshal_auto_allocating 95,618 93,142 +2.7%
binary_benchmark::marshal_group::bench_marshal_exact_allocating 113,974 113,496 +0.4%
binary_benchmark::marshal_group::bench_marshal_reusing_buffer 102,895 102,873 +0.0%
binary_benchmark::marshal_group::bench_marshal_reusing_buffer_vec_writer 95,685 93,209 +2.7%
binary_benchmark::marshal_group::bench_marshal_long_string 15,762 15,416 +2.2%
binary_benchmark::marshal_group::bench_marshal_auto_long_string 15,806 15,460 +2.2%
binary_benchmark::marshal_group::bench_marshal_exact_long_string 17,592 17,558 +0.2%
binary_benchmark::marshal_group::bench_marshal_huge_bytes_allocating 533,122 532,934 +0.0%
binary_benchmark::marshal_group::bench_marshal_auto_huge_bytes_allocating 532,688 532,500 +0.0%
binary_benchmark::marshal_group::bench_marshal_exact_huge_bytes_allocating 534,046 533,970 +0.0%
binary_benchmark::marshal_group::bench_marshal_many_children_allocating 13,413,012 13,085,769 +2.5%
binary_benchmark::marshal_group::bench_marshal_auto_many_children_allocating 13,357,245 13,030,095 +2.5%
binary_benchmark::marshal_group::bench_marshal_exact_many_children_allocating 26,652,528 26,573,210 +0.3%
binary_benchmark::unmarshal_group::bench_unmarshal small:setup_small_marshaled() 2,498 2,621 -4.7%
binary_benchmark::unmarshal_group::bench_unmarshal large:setup_large_marshaled() 38,500 37,886 +1.6%
binary_benchmark::unpack_group::bench_unpack_uncompressed 773 773 +0.0%
binary_benchmark::unpack_group::bench_unpack_compressed 556,090 556,090 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip small:setup_small_marshaled() 7,484 7,345 +1.9%
binary_benchmark::roundtrip_group::bench_roundtrip large:setup_large_marshaled() 90,824 87,464 +3.8%
binary_benchmark::roundtrip_group::bench_roundtrip_auto small:setup_small_marshaled() 7,511 7,368 +1.9%
binary_benchmark::roundtrip_group::bench_roundtrip_auto large:setup_large_marshaled() 90,860 87,495 +3.8%
binary_benchmark::roundtrip_group::bench_roundtrip_exact small:setup_small_marshaled() 8,838 8,881 -0.5%
binary_benchmark::roundtrip_group::bench_roundtrip_exact large:setup_large_marshaled() 104,670 102,993 +1.6%
binary_benchmark::child_iteration_group::bench_get_children_by_tag 475,970 475,970 +0.0%
libsignal_benchmark::dm_group::bench_dm_session_establishment setup:setup_dm_users() 17,148,248 17,379,778 -1.3%
libsignal_benchmark::dm_group::bench_dm_encrypt_first_message first_msg:setup_dm_session() 162,069 162,069 +0.0%
libsignal_benchmark::dm_group::bench_dm_decrypt_first_message decrypt_prekey:setup_dm_with_first_message() 5,512,660 5,512,660 +0.0%
libsignal_benchmark::dm_group::bench_dm_encrypt_subsequent_message subsequent:setup_established_dm_session() 163,085 163,085 +0.0%
libsignal_benchmark::group_messaging_group::bench_group_create_distribution_message create:setup_group_sender() 298,493 298,493 +0.0%
libsignal_benchmark::group_messaging_group::bench_group_encrypt_message encrypt:setup_group_with_distribution() 713,231 713,231 +0.0%
libsignal_benchmark::group_messaging_group::bench_group_decrypt_message decrypt:setup_group_with_encrypted_message() 12,544,252 12,657,691 -0.9%
libsignal_benchmark::conversation_group::bench_full_dm_conversation full:setup_conversation_data() 27,526,053 27,614,141 -0.3%
libsignal_benchmark::signature_group::bench_signature_creation sign:setup_keypair_with_message() 3,467,011 3,467,011 +0.0%
libsignal_benchmark::signature_group::bench_signature_verification verify:setup_keypair_with_message() 127,086,233 124,988,273 +1.7%
libsignal_benchmark::signature_group::bench_key_generation keygen 2,830,452 2,830,452 +0.0%
libsignal_benchmark::session_optimization_group::bench_decrypt_with_previous_session previous_session:setup_with_archived_sessions() 46,970 46,970 +0.0%
libsignal_benchmark::session_optimization_group::bench_out_of_order_decryption out_of_order:setup_out_of_order_messages() 5,119,851 5,119,851 +0.0%
libsignal_benchmark::session_optimization_group::bench_promote_matching_session promote:setup_promote_matching_session() 299,173 299,173 +0.0%
libsignal_benchmark::session_optimization_group::bench_message_key_eviction eviction:setup_message_key_eviction() 14,247,117 14,247,117 +0.0%

- Format JidRef directly into CompactString via write!(), eliminating
  the intermediate String allocation in read_value_as_string JID paths
- Add NodeStr::to_compact_string() for clone-preserving conversion;
  use it in NodeRef::to_owned() and JidRef::to_owned() to avoid
  re-parsing owned CompactString values through as_ref()
- Make AttrParserRef.attrs pub(crate) to avoid leaking NodeStr in the
  public field API
Use #[inline(always)] to ensure the discriminant match is eliminated
at every call site in the encode hot path.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
wacore/binary/src/node.rs (1)

563-568: 🧹 Nitpick | 🔵 Trivial

Align NodeRef::new signature with Node::new for API consistency.

The constructor currently requires explicit NodeStr wrapping despite NodeStr implementing From<&'a str> and From<CompactString>. Since Node::new already accepts impl Into<Cow<'static, str>>, NodeRef::new should accept impl Into<NodeStr<'a>> to provide consistent ergonomics across the public API. This change is backward compatible—code passing NodeStr directly will continue to work.

♻️ Proposed fix
-    pub fn new(tag: NodeStr<'a>, attrs: AttrsRef<'a>, content: Option<NodeContentRef<'a>>) -> Self {
+    pub fn new(
+        tag: impl Into<NodeStr<'a>>,
+        attrs: AttrsRef<'a>,
+        content: Option<NodeContentRef<'a>>,
+    ) -> Self {
         Self {
-            tag,
+            tag: tag.into(),
             attrs,
             content: content.map(Box::new),
         }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wacore/binary/src/node.rs` around lines 563 - 568, Change the NodeRef::new
constructor to accept a generic input that can be converted into NodeStr by
changing the first parameter from NodeStr<'a> to impl Into<NodeStr<'a>> (keeping
the other params AttrsRef<'a> and Option<NodeContentRef<'a>> unchanged); inside
NodeRef::new call .into() on that parameter to obtain a NodeStr when building
Self so callers can pass &str, CompactString, or NodeStr just like Node::new.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@wacore/binary/src/node.rs`:
- Around line 563-568: Change the NodeRef::new constructor to accept a generic
input that can be converted into NodeStr by changing the first parameter from
NodeStr<'a> to impl Into<NodeStr<'a>> (keeping the other params AttrsRef<'a> and
Option<NodeContentRef<'a>> unchanged); inside NodeRef::new call .into() on that
parameter to obtain a NodeStr when building Self so callers can pass &str,
CompactString, or NodeStr just like Node::new.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: e7929167-acc3-4612-87f4-dcde9acfecda

📥 Commits

Reviewing files that changed from the base of the PR and between c17b1d8 and 9390ba6.

📒 Files selected for processing (1)
  • wacore/binary/src/node.rs

@jlucaso1
jlucaso1 merged commit 61d6ed2 into main Apr 12, 2026
9 checks passed
@jlucaso1
jlucaso1 deleted the perf/packed-nibble-stack-decode branch April 12, 2026 14:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant