silk/shared
Explicitly allocated, single-threaded shared ownership with callback-scoped access.
When to use
Use Shared when several independently owned local values or dormant computations must retain
one mutable state without retaining a lexical borrow for their whole lifetimes. Construction is
the only implicit storage boundary: make allocates once, while clone, with, and
withMut allocate nothing themselves.
Details
Every handle is affine and local to one execution thread. Cloning adds one strong obligation;
dropping a non-last handle preserves the value and allocation, while dropping the last handle
cleans the value and then releases the allocation. Access is callback-scoped and exclusive even
through with: nesting with under with, withMut under with, with under withMut, or
withMut under withMut through an alias traps before the nested callback receives a reference.
Gotchas
Strong-reference cycles leak until ordinary source breaks them. This module does not expose weak
handles, allocation identity, raw addresses, thread transfer, or post-trap cleanup guarantees.
Extract work under withMut and invoke external callbacks only after the access call returns.
Examples
Share and update one local value
import silk.allocator { Allocator }
import silk.effect { Effect }
import silk.shared { clone, make, with, withMut }
struct Counter { value: i32 }
fn increment(value: &mut Counter) -> i32 {
value.value = value.value + 22
return value.value
}
fn read(value: &Counter) -> i32 { return value.value }
effect fn useCell() -> i32
! Allocator.OutOfMemoryError {
let mut allocator = Allocator.systemAllocatorProvider()
let creating = make<Counter>(Counter { value: 20 })
|> Effect.provideMut<Allocator>(&mut allocator)
let cell = run creating
let alias = clone<Counter>(&cell)
let updated = withMut<Counter, i32>(&alias, increment)
return with<Counter, i32>(&cell, read)
}
effect fn recover(error: Allocator.OutOfMemoryError) -> i32 {
return 0
}
pub fn main() -> i32 {
return run Effect.catchAll(useCell(), recover)
}Import as Shared with import silk.shared.
Public declarations: 5.
Shared
pub struct Shared<T>An affine, non-thread-transferable strong handle to one local value.
Details
The opaque core is the sole field and supplies recursively derived cleanup and local execution
affinity. Shared declares no source Drop hook.
make
pub effect fn make<T>(value: T) -> silk/shared.Shared<T> ! OutOfMemoryError ? &mut AllocatorAllocates one control block and transfers value into a new strong handle.
Details
Allocation failure leaves value under ordinary Effect-frame cleanup and produces no handle.
The returned handle carries no allocator requirement after construction completes.
clone
pub fn clone<T>(self: &silk/shared.Shared<T>) -> silk/shared.Shared<T>Adds one strong handle without allocating or touching the stored value.
Details
Count exhaustion traps before mutation and does not produce a partial handle.
withMut
pub fn withMut<T, A>(self: &silk/shared.Shared<T>, use: once fn(&mut T) -> A) -> ARuns one take-once callback with exclusive access to the stored value.
Details
The borrow cannot escape the callback or remain live across suspension. Reentrant access through any alias traps before the nested callback receives a reference.
with
pub fn with<T, A>(self: &silk/shared.Shared<T>, use: once fn(&T) -> A) -> ARuns one take-once callback with shared access to the stored value.
Details
Inspection delegates through withMut, so it has the same exclusive runtime access state and
the same four-way reentrant conflict policy. The callback cannot mutate through its &T.