Skip to content

Resolver: Arc<dyn Fn> with new(impl Fn) + with_resolver constructors - #16

Open
mwaddip wants to merge 3 commits into
ergoplatform:mainfrom
mwaddip:feat/resolver-with-resolver
Open

Resolver: Arc<dyn Fn> with new(impl Fn) + with_resolver constructors#16
mwaddip wants to merge 3 commits into
ergoplatform:mainfrom
mwaddip:feat/resolver-with-resolver

Conversation

@mwaddip

@mwaddip mwaddip commented Jun 8, 2026

Copy link
Copy Markdown

Replaces #15 (closed). Gives upstream the storage-backend resolver capability without breaking the interpreter or the node, via two shape-matched constructors:

  • Resolver = Arc<dyn Fn(&Digest32) -> Node + Send + Sync> — the persistence need (orig Change Resolver from fn pointer to Arc<dyn Fn> for storage backends #10).
  • new(resolver: impl Fn(&Digest32) -> Node + …) — Arc-wraps internally; lets closure callers pass bare UNANNOTATED closures (e.g. the interpreter's |digest| …` sites) with the param type inferred.
  • with_resolver(resolver: Resolver, …) — takes a pre-built Arc directly (no re-wrap), for storage backends that capture a DB handle.

A single generic constructor cannot serve both: impl Fn rejects Arc<dyn Fn> (not Fn, E0277), and a bound that accepts the Arc breaks unannotated closures (E0282). All crate tests pass.

mwaddip and others added 3 commits April 4, 2026 16:35
…upport

The Resolver type was defined as a bare function pointer (fn(&Digest32) -> Node),
which cannot capture state. This makes it impossible to implement VersionedAVLStorage
with a real storage backend — the resolver needs to load nodes from a database, but
a function pointer cannot hold a database reference.

Changed to Arc<dyn Fn(&Digest32) -> Node + Send + Sync> which allows closures that
capture storage handles. Arc (not Box) because AVLTree derives Clone. Send + Sync
for thread safety with concurrent readers.

All 22 existing tests pass unchanged (modulo wrapping bare functions in Arc::new).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
28862a1 changed Resolver from a plain fn pointer to Arc<dyn Fn> for the
persistence backend, which broke every caller written against the old
signature (sigma-rust's interpreter passes bare closures at 13 sites).
Take `impl Fn(&Digest32) -> Node + Send + Sync + 'static` and wrap it in
the Arc inside the constructor: fn-pointer-era callers compile unchanged,
capturing closures (the persistence resolver) pass straight in without
their own Arc::new. Callers holding a prebuilt Resolver construct the
struct literally — `resolver` is a pub field.

Internal call sites (prover test + tests/common) updated to drop the
now-redundant Arc::new.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
new(impl Fn) (a4a2aa7) serves closure callers — including the
interpreter's bare, unannotated |digest| closures, which infer their
param type only because the bound is literally Fn(&Digest32). But impl Fn
rejects a pre-built Resolver (Arc<dyn Fn> does not impl Fn, E0277), and a
single generic bound cannot serve both: an impl IntoResolver bound that
accepts Arc breaks unannotated closures (E0282).

Add a second constructor with_resolver(resolver: Resolver, ...) taking a
pre-built Arc directly (no re-wrap), for storage-backend callers (the
node). The interpreter keeps using new(); the node uses with_resolver().

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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