Skip to content

Comments

Use type-erased facet APIs for persistence callbacks#52

Merged
fasterthanlime merged 1 commit intomainfrom
fix-51-type-erased-persistence
Jan 26, 2026
Merged

Use type-erased facet APIs for persistence callbacks#52
fasterthanlime merged 1 commit intomainfrom
fix-51-type-erased-persistence

Conversation

@fasterthanlime
Copy link
Contributor

Summary

How it works

The key insight is that while Peek::new and heap_value.materialize() are still generic, they are tiny (just pointer/shape manipulation). The heavy lifting happens in:

  • peek_to_vec(peek) - non-generic, compiled once
  • from_slice_into(bytes, partial) - non-generic, compiled once

This reduces monomorphization in the persistence callbacks:

  • make_encode_record
  • make_decode_record
  • make_encode_incremental
  • make_apply_wal_entry

Test plan

  • All 66 picante tests pass

Closes #51

Replace `facet_postcard::to_vec` with `peek_to_vec(Peek::new(...))` for
serialization, and `facet_postcard::from_slice` with `from_slice_into`
for deserialization in the persistence callbacks.

The key insight is that while `Peek::new` and `heap_value.materialize()`
are still generic, they are tiny (just pointer/shape manipulation). The
heavy lifting happens in `peek_to_vec` and `from_slice_into` which are
non-generic and compiled once.

This reduces monomorphization in:
- make_encode_record
- make_decode_record
- make_encode_incremental
- make_apply_wal_entry

Also updates facet to include the new `from_slice_into` API from
facet-rs/facet#1932.

Closes #51
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR reduces monomorphization in picante's persistence layer by replacing generic serialization/deserialization APIs with type-erased alternatives. The key innovation is that while Peek::new and materialize() remain generic (but are tiny operations), the heavy lifting is done by non-generic functions peek_to_vec and from_slice_into that are compiled only once.

Changes:

  • Replace facet_postcard::to_vec with peek_to_vec(Peek::new(...)) for serialization
  • Replace facet_postcard::from_slice with a multi-step type-erased deserialization flow using from_slice_into
  • Update facet dependency from 0.42.0 to 0.43.2 to access new type-erased APIs

Reviewed changes

Copilot reviewed 1 out of 2 changed files in this pull request and generated no comments.

File Description
crates/picante/src/ingredient/derived.rs Updated four persistence callback functions (make_encode_record, make_decode_record, make_encode_incremental, make_apply_wal_entry) to use type-erased serialization/deserialization APIs, reducing monomorphization while maintaining functionality
Cargo.lock Updated facet dependencies from 0.42.0 to 0.43.2, added new transitive dependencies (cobs, corosensei, embedded-io, foldhash, iddqd, object, postcard, thiserror), and updated cranelift and wasmtime dependencies to newer versions

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@fasterthanlime fasterthanlime merged commit 43a7de1 into main Jan 26, 2026
10 checks passed
@fasterthanlime fasterthanlime deleted the fix-51-type-erased-persistence branch January 26, 2026 17:08
@github-actions github-actions bot mentioned this pull request Jan 26, 2026
fasterthanlime added a commit that referenced this pull request Jan 26, 2026
… functions

PR #52 added type-erased APIs but kept them inside the generic closures,
causing the entire closure body to be monomorphized for each K,V combination.

This extracts the heavy lifting into two non-generic helper functions:
- encode_with_peek: wraps peek_to_vec, compiled once
- decode_to_heap_value: wraps alloc + from_slice_into + build, compiled once

The closures now only contain the tiny generic parts (Peek::new, materialize).

Measured impact on dodeca:
- Before this PR (PR #52): 2,349k LLVM IR lines
- After this PR: 2,294k LLVM IR lines
- Savings: 55k lines (also 21k better than pre-#52 baseline)
fasterthanlime added a commit that referenced this pull request Jan 26, 2026
… functions (#53)

PR #52 added type-erased APIs but kept them inside the generic closures,
causing the entire closure body to be monomorphized for each K,V combination.

This extracts the heavy lifting into two non-generic helper functions:
- encode_with_peek: wraps peek_to_vec, compiled once
- decode_to_heap_value: wraps alloc + from_slice_into + build, compiled once

The closures now only contain the tiny generic parts (Peek::new, materialize).

Measured impact on dodeca:
- Before this PR (PR #52): 2,349k LLVM IR lines
- After this PR: 2,294k LLVM IR lines
- Savings: 55k lines (also 21k better than pre-#52 baseline)
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.

Remaining monomorphization reduction opportunities

1 participant