Skip to content

feat!: unified LID-PN lookup via get_lid_pn_entry(&Jid) - #487

Merged
jlucaso1 merged 3 commits into
mainfrom
feat/lid-pn-public-api
Apr 4, 2026
Merged

feat!: unified LID-PN lookup via get_lid_pn_entry(&Jid)#487
jlucaso1 merged 3 commits into
mainfrom
feat/lid-pn-public-api

Conversation

@jlucaso1

@jlucaso1 jlucaso1 commented Apr 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Replace get_phone_number_from_lid(&str) with get_lid_pn_entry(&Jid) — one function that routes by JID type (LID or PN) and returns the full LidPnEntry with both sides of the mapping
  • Zero string parsing, zero extra allocations — borrows jid.user directly into the cache lookup

Breaking change

get_phone_number_from_lid(&str) -> Option<String> is removed.

Migration

// Before
let phone = client.get_phone_number_from_lid("100000012345678").await;

// After — pass a Jid, get both sides back
let entry = client.get_lid_pn_entry(&Jid::lid("100000012345678")).await;
let phone = entry.map(|e| e.phone_number);

// Works in both directions
let entry = client.get_lid_pn_entry(&Jid::pn("559980000001")).await;
let lid = entry.map(|e| e.lid);

Test plan

  • cargo clippy --all --tests passes
  • Tests for both directions (LID→entry, PN→entry)
  • All 17 LID-PN tests pass

Summary by CodeRabbit

  • Refactor
    • Phone-number lookup API changed to accept identifier types and return a mapping entry object; group creation now uses that entry to populate participant phone numbers.
  • Tests
    • Added async tests validating lookup returns none before mappings and returns correct mapping after adding, covering both identifier-input paths.

…t `&Jid`

BREAKING: `get_phone_number_from_lid` now takes `&Jid` instead of `&str`.
Add symmetric `get_lid_from_phone_number(&Jid)` for PN→LID lookup.

Using `&Jid` avoids manual string parsing and allocations — the user
part is already available as a field.
@coderabbitai

coderabbitai Bot commented Apr 4, 2026

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5bc5d0bd-727b-4899-a96e-7b9d61c79b8f

📥 Commits

Reviewing files that changed from the base of the PR and between c530a52 and 9a98c05.

📒 Files selected for processing (1)
  • src/client/lid_pn.rs

📝 Walkthrough

Walkthrough

Replaces Client::get_phone_number_from_lid(&self, lid: &str) with Client::get_lid_pn_entry(&self, jid: &Jid), routing lookups by JID kind (LID → lookup by lid, PN → lookup by phone, others → None). Updates group creation to consume the returned LidPnEntry and adds async tests for both LID and PN input paths.

Changes

Cohort / File(s) Summary
LID↔PN lookup implementation
src/client/lid_pn.rs
Removed get_phone_number_from_lid(&str); added get_lid_pn_entry(&Jid) -> Option<LidPnEntry> that branches on JID type and queries cache by LID or phone. Added async tests covering PN-input and LID-input paths.
Groups callsite
src/features/groups.rs
Groups::create_group now calls client.get_lid_pn_entry(&participant.jid) and uses entry.phone_number to populate participant.with_phone_number(...) when mapping exists.

Sequence Diagram(s)

sequenceDiagram
    participant Groups
    participant Client
    participant LidPnCache

    Groups->>Client: get_lid_pn_entry(jid)
    alt jid.is_lid()
        Client->>LidPnCache: get_entry_by_lid(jid.user)
        LidPnCache-->>Client: Option<LidPnEntry>
    else jid.is_pn()
        Client->>LidPnCache: get_entry_by_phone(jid.user)
        LidPnCache-->>Client: Option<LidPnEntry>
    else
        Client-->>Groups: None
    end
    Client-->>Groups: Option<LidPnEntry>
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰
I hopped from lid to phone with glee,
I checked the Jid — left, right, then see.
Cache whispered secrets, a mapping true,
I brought the number back to you. 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: replacing separate lookup methods with a unified get_lid_pn_entry(&Jid) method that handles both LID and PN JID types.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ 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 feat/lid-pn-public-api

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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/client/lid_pn.rs`:
- Around line 241-249: The two methods get_phone_number_from_lid and
get_lid_from_phone_number currently assume callers pass the correct JID kind;
add a defensive check at the start of each (e.g., debug_assert or a runtime
check) that verifies the Jid is the expected type and either log a debug/warn
message and return None on mismatch or panic in debug builds; also update the
doc comments for both functions to explicitly state the expected JID type (LID
for get_phone_number_from_lid, phone-number/PN for get_lid_from_phone_number) so
callers know the contract.
🪄 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: 6fd84da1-d4bd-438b-bd15-ebb21dce0c4b

📥 Commits

Reviewing files that changed from the base of the PR and between f48983d and 8307758.

📒 Files selected for processing (2)
  • src/client/lid_pn.rs
  • src/features/groups.rs

Comment thread src/client/lid_pn.rs Outdated
@github-actions

github-actions Bot commented Apr 4, 2026

Copy link
Copy Markdown

🐰 Bencher Report

Branchfeat/lid-pn-public-api
Testbedubuntu-latest

🚨 1 Alert

BenchmarkMeasure
Units
ViewBenchmark Result
(Result Δ%)
Upper Boundary
(Limit %)
libsignal_benchmark::session_optimization_group::bench_decrypt_with_previous_session previous_session:setup_with_archived_sessions()Instructions
instructions x 1e3
📈 plot
🚷 threshold
🚨 alert (🔔)
47.13 x 1e3
(+8.26%)Baseline: 43.53 x 1e3
45.71 x 1e3
(103.10%)

Click to view all benchmark results
BenchmarkInstructionsBenchmark Result
instructions
(Result Δ%)
Upper Boundary
instructions
(Limit %)
binary_benchmark::attr_parser_group::bench_attr_parser attr_lookup:setup_attr_marshaled()📈 view plot
🚷 view threshold
6,197.00
(-3.63%)Baseline: 6,430.42
6,751.94
(91.78%)
binary_benchmark::child_iteration_group::bench_get_children_by_tag📈 view plot
🚷 view threshold
524,304.00
(-25.03%)Baseline: 699,318.55
734,284.48
(71.40%)
binary_benchmark::jid_optimization_group::bench_jid_to_owned_access jid_access:setup_jid_heavy_marshaled()📈 view plot
🚷 view threshold
20,868.00
(-5.12%)Baseline: 21,994.14
23,093.85
(90.36%)
binary_benchmark::marshal_group::bench_marshal_allocating📈 view plot
🚷 view threshold
98,202.00
(-12.65%)Baseline: 112,424.64
118,045.87
(83.19%)
binary_benchmark::marshal_group::bench_marshal_auto_allocating📈 view plot
🚷 view threshold
98,230.00
(-9.03%)Baseline: 107,981.56
113,380.64
(86.64%)
binary_benchmark::marshal_group::bench_marshal_auto_huge_bytes_allocating📈 view plot
🚷 view threshold
532,948.00
(-0.10%)Baseline: 533,456.02
560,128.82
(95.15%)
binary_benchmark::marshal_group::bench_marshal_auto_long_string📈 view plot
🚷 view threshold
15,870.00
(-4.18%)Baseline: 16,562.03
17,390.13
(91.26%)
binary_benchmark::marshal_group::bench_marshal_auto_many_children_allocating📈 view plot
🚷 view threshold
14,715,201.00
(-7.11%)Baseline: 15,841,846.54
16,633,938.87
(88.46%)
binary_benchmark::marshal_group::bench_marshal_exact_allocating📈 view plot
🚷 view threshold
118,358.00
(-18.61%)Baseline: 145,418.69
152,689.63
(77.52%)
binary_benchmark::marshal_group::bench_marshal_exact_huge_bytes_allocating📈 view plot
🚷 view threshold
534,378.00
(-0.09%)Baseline: 534,877.97
561,621.87
(95.15%)
binary_benchmark::marshal_group::bench_marshal_exact_long_string📈 view plot
🚷 view threshold
17,919.00
(-3.73%)Baseline: 18,613.06
19,543.71
(91.69%)
binary_benchmark::marshal_group::bench_marshal_exact_many_children_allocating📈 view plot
🚷 view threshold
28,066,347.00
(-19.56%)Baseline: 34,891,007.86
36,635,558.25
(76.61%)
binary_benchmark::marshal_group::bench_marshal_huge_bytes_allocating📈 view plot
🚷 view threshold
533,387.00
(-0.10%)Baseline: 533,895.02
560,589.77
(95.15%)
binary_benchmark::marshal_group::bench_marshal_long_string📈 view plot
🚷 view threshold
15,843.00
(-6.68%)Baseline: 16,977.53
17,826.41
(88.87%)
binary_benchmark::marshal_group::bench_marshal_many_children_allocating📈 view plot
🚷 view threshold
14,716,627.00
(-7.11%)Baseline: 15,843,003.78
16,635,153.96
(88.47%)
binary_benchmark::marshal_group::bench_marshal_reusing_buffer📈 view plot
🚷 view threshold
107,945.00
(-9.93%)Baseline: 119,844.11
125,836.32
(85.78%)
binary_benchmark::marshal_group::bench_marshal_reusing_buffer_vec_writer📈 view plot
🚷 view threshold
98,302.00
(-9.02%)Baseline: 108,053.56
113,456.24
(86.64%)
binary_benchmark::roundtrip_group::bench_roundtrip large:setup_large_marshaled()📈 view plot
🚷 view threshold
90,974.00
(-4.89%)Baseline: 95,655.78
100,438.56
(90.58%)
binary_benchmark::roundtrip_group::bench_roundtrip small:setup_small_marshaled()📈 view plot
🚷 view threshold
7,378.00
(-3.15%)Baseline: 7,617.61
7,998.49
(92.24%)
binary_benchmark::roundtrip_group::bench_roundtrip_auto large:setup_large_marshaled()📈 view plot
🚷 view threshold
91,005.00
(-1.58%)Baseline: 92,468.97
97,092.42
(93.73%)
binary_benchmark::roundtrip_group::bench_roundtrip_auto small:setup_small_marshaled()📈 view plot
🚷 view threshold
7,401.00
(+0.32%)Baseline: 7,377.48
7,746.36
(95.54%)
binary_benchmark::roundtrip_group::bench_roundtrip_exact large:setup_large_marshaled()📈 view plot
🚷 view threshold
106,790.00
(-1.35%)Baseline: 108,253.97
113,666.67
(93.95%)
binary_benchmark::roundtrip_group::bench_roundtrip_exact small:setup_small_marshaled()📈 view plot
🚷 view threshold
8,913.00
(+0.26%)Baseline: 8,889.48
9,333.96
(95.49%)
binary_benchmark::unmarshal_group::bench_unmarshal large:setup_large_marshaled()📈 view plot
🚷 view threshold
41,989.00
(-6.52%)Baseline: 44,917.80
47,163.69
(89.03%)
binary_benchmark::unmarshal_group::bench_unmarshal small:setup_small_marshaled()📈 view plot
🚷 view threshold
2,717.00
(-2.09%)Baseline: 2,775.01
2,913.76
(93.25%)
binary_benchmark::unpack_group::bench_unpack_compressed📈 view plot
🚷 view threshold
556,092.00
(+0.80%)Baseline: 551,652.97
579,235.62
(96.00%)
binary_benchmark::unpack_group::bench_unpack_uncompressed📈 view plot
🚷 view threshold
771.00
(-0.21%)Baseline: 772.60
811.23
(95.04%)
libsignal_benchmark::conversation_group::bench_full_dm_conversation full:setup_conversation_data()📈 view plot
🚷 view threshold
27,556,931.00
(-0.51%)Baseline: 27,698,514.05
29,083,439.75
(94.75%)
libsignal_benchmark::dm_group::bench_dm_decrypt_first_message decrypt_prekey:setup_dm_with_first_message()📈 view plot
🚷 view threshold
5,544,828.00
(-0.05%)Baseline: 5,547,622.35
5,825,003.47
(95.19%)
libsignal_benchmark::dm_group::bench_dm_encrypt_first_message first_msg:setup_dm_session()📈 view plot
🚷 view threshold
175,061.00
(-1.23%)Baseline: 177,248.19
186,110.60
(94.06%)
libsignal_benchmark::dm_group::bench_dm_encrypt_subsequent_message subsequent:setup_established_dm_session()📈 view plot
🚷 view threshold
175,710.00
(-1.29%)Baseline: 178,015.03
186,915.78
(94.00%)
libsignal_benchmark::dm_group::bench_dm_session_establishment setup:setup_dm_users()📈 view plot
🚷 view threshold
17,459,129.00
(+1.03%)Baseline: 17,280,679.51
18,144,713.48
(96.22%)
libsignal_benchmark::group_messaging_group::bench_group_create_distribution_message create:setup_group_sender()📈 view plot
🚷 view threshold
298,417.00
(+0.51%)Baseline: 296,894.04
311,738.74
(95.73%)
libsignal_benchmark::group_messaging_group::bench_group_decrypt_message decrypt:setup_group_with_encrypted_message()📈 view plot
🚷 view threshold
12,549,749.00
(-0.37%)Baseline: 12,596,287.89
13,226,102.29
(94.89%)
libsignal_benchmark::group_messaging_group::bench_group_encrypt_message encrypt:setup_group_with_distribution()📈 view plot
🚷 view threshold
719,597.00
(+0.35%)Baseline: 717,070.65
752,924.18
(95.57%)
libsignal_benchmark::session_optimization_group::bench_decrypt_with_previous_session previous_session:setup_with_archived_sessions()📈 view plot
🚷 view threshold
🚨 view alert (🔔)
47,129.00
(+8.26%)Baseline: 43,533.21
45,709.87
(103.10%)

libsignal_benchmark::session_optimization_group::bench_message_key_eviction eviction:setup_message_key_eviction()📈 view plot
🚷 view threshold
15,561,842.00
(+0.00%)Baseline: 15,561,770.93
16,339,859.47
(95.24%)
libsignal_benchmark::session_optimization_group::bench_out_of_order_decryption out_of_order:setup_out_of_order_messages()📈 view plot
🚷 view threshold
5,378,778.00
(-1.68%)Baseline: 5,470,879.04
5,744,423.00
(93.63%)
libsignal_benchmark::session_optimization_group::bench_promote_matching_session promote:setup_promote_matching_session()📈 view plot
🚷 view threshold
312,188.00
(-59.45%)Baseline: 769,965.24
808,463.51
(38.61%)
libsignal_benchmark::signature_group::bench_key_generation keygen📈 view plot
🚷 view threshold
2,830,547.00
(+0.17%)Baseline: 2,825,882.40
2,967,176.52
(95.40%)
libsignal_benchmark::signature_group::bench_signature_creation sign:setup_keypair_with_message()📈 view plot
🚷 view threshold
3,452,844.00
(-0.49%)Baseline: 3,469,699.73
3,643,184.71
(94.78%)
libsignal_benchmark::signature_group::bench_signature_verification verify:setup_keypair_with_message()📈 view plot
🚷 view threshold
125,379,678.00
(+0.01%)Baseline: 125,364,461.90
131,632,684.99
(95.25%)
reporting_token_benchmark::content_extraction_group::bench_content_extraction extended:setup_extended_message()📈 view plot
🚷 view threshold
12,002.00
(+1.40%)Baseline: 11,836.29
12,428.11
(96.57%)
reporting_token_benchmark::content_extraction_group::bench_content_extraction simple:setup_simple_message()📈 view plot
🚷 view threshold
3,930.00
(+2.27%)Baseline: 3,842.75
4,034.89
(97.40%)
reporting_token_benchmark::full_generation_group::bench_full_token_generation extended:setup_full_gen_extended()📈 view plot
🚷 view threshold
87,073.00
(-0.72%)Baseline: 87,700.45
92,085.47
(94.56%)
reporting_token_benchmark::full_generation_group::bench_full_token_generation simple:setup_full_gen_simple()📈 view plot
🚷 view threshold
79,022.00
(-0.89%)Baseline: 79,729.01
83,715.46
(94.39%)
reporting_token_benchmark::key_derivation_group::bench_key_derivation📈 view plot
🚷 view threshold
50,375.00
(-0.97%)Baseline: 50,870.41
53,413.93
(94.31%)
reporting_token_benchmark::message_encoding_group::bench_message_encoding extended:setup_extended_message()📈 view plot
🚷 view threshold
5,956.00
(+2.86%)Baseline: 5,790.31
6,079.82
(97.96%)
reporting_token_benchmark::message_encoding_group::bench_message_encoding simple:setup_simple_message()📈 view plot
🚷 view threshold
2,227.00
(+4.09%)Baseline: 2,139.54
2,246.51
(99.13%)
reporting_token_benchmark::token_calculation_group::bench_token_calculation📈 view plot
🚷 view threshold
21,920.00
(-0.00%)Baseline: 21,920.20
23,016.21
(95.24%)
🐰 View full continuous benchmarking report in Bencher

…id)`

Replace `get_phone_number_from_lid` and `get_lid_from_phone_number` with
a single `get_lid_pn_entry` that routes by JID type and returns the full
`LidPnEntry` (both lid and phone_number in one lookup).
@jlucaso1 jlucaso1 changed the title feat!: LID-PN bidirectional public API with &Jid feat!: unified LID-PN lookup via get_lid_pn_entry(&Jid) Apr 4, 2026

@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.

♻️ Duplicate comments (1)
src/client/lid_pn.rs (1)

244-249: ⚠️ Potential issue | 🟠 Major

Restrict lookup routing to PN/LID JIDs only

On Line 247, the fallback branch treats every non-LID JID as PN. That includes g.us/broadcast/newsletter JIDs, which can incorrectly hit get_entry_by_phone(&jid.user). Return None for non-user JIDs instead of routing them as PN.

Suggested fix
 pub async fn get_lid_pn_entry(&self, jid: &Jid) -> Option<LidPnEntry> {
     if jid.is_lid() {
         self.lid_pn_cache.get_entry_by_lid(&jid.user).await
-    } else {
+    } else if jid.is_pn() {
         self.lid_pn_cache.get_entry_by_phone(&jid.user).await
+    } else {
+        debug!("get_lid_pn_entry called with non-user JID: {}", jid);
+        None
     }
 }
#!/bin/bash
# Verify current call sites and whether non-user JIDs may flow into get_lid_pn_entry.
rg -nP --type=rust -C2 '\bget_lid_pn_entry\s*\('
rg -nP --type=rust -C2 'Jid::(group|newsletter|status_broadcast)\('
rg -nP --type=rust -C2 'test_.*get_lid_pn_entry'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/client/lid_pn.rs` around lines 244 - 249, The current get_lid_pn_entry
routes every non-LID JID to get_entry_by_phone, which wrongly handles
group/newsletter/status JIDs; update get_lid_pn_entry so it first ensures the
Jid is a user/phone-type JID (e.g., check a predicate like jid.is_user() or
jid.is_phone()) and only then call lid_pn_cache.get_entry_by_phone(&jid.user).
For non-user JIDs (groups, broadcasts, newsletter, etc.) return None
immediately; keep the existing lid branch using jid.is_lid() and
lid_pn_cache.get_entry_by_lid(&jid.user).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/client/lid_pn.rs`:
- Around line 244-249: The current get_lid_pn_entry routes every non-LID JID to
get_entry_by_phone, which wrongly handles group/newsletter/status JIDs; update
get_lid_pn_entry so it first ensures the Jid is a user/phone-type JID (e.g.,
check a predicate like jid.is_user() or jid.is_phone()) and only then call
lid_pn_cache.get_entry_by_phone(&jid.user). For non-user JIDs (groups,
broadcasts, newsletter, etc.) return None immediately; keep the existing lid
branch using jid.is_lid() and lid_pn_cache.get_entry_by_lid(&jid.user).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6c83d65a-6c93-4bf7-8bed-3b394eb29316

📥 Commits

Reviewing files that changed from the base of the PR and between 8307758 and c530a52.

📒 Files selected for processing (2)
  • src/client/lid_pn.rs
  • src/features/groups.rs

Group, newsletter, and broadcast JIDs should return None instead of
hitting the phone-number cache with a non-phone user part.
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