Silk

silk/shared

Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc.

Explicitly allocated, single-threaded shared ownership Shared.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: Shared.make allocates once, while Shared.clone, Shared.with, and Shared.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 Shared.with: nesting Shared.with under Shared.with, Shared.withMut under Shared.with, Shared.with under Shared.withMut, or Shared.withMut under Shared.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 Shared.withMut and invoke external callbacks only after the access call returns.

Examples

Share and update one local value

import silk.allocator { Allocator, OutOfMemoryError }

import silk.effect { Effect }

import silk.shared { Shared }

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
! OutOfMemoryError {
  let mut allocator = Allocator.systemAllocatorProvider()
  let creating = Shared.make<Counter>(Counter { value: 20 })
    |> Effect.provideMut<Allocator>(&mut allocator)
  let cell = run creating
  let alias = Shared.clone<Counter>(&cell)
  let updated = Shared.withMut<Counter, i32>(&alias, increment)
  return Shared.with<Counter, i32>(&cell, read)
}

effect fn recover(error: OutOfMemoryError) -> i32 {
  return 0
}

pub fn main() -> i32 {
  return run Effect.catchAll(useCell(), recover)
}

Import as Shared with import silk.shared { Shared }.

Public declarations: 1.

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.

Associated function Shared.make

pub effect<'env> fn make<T: 'env, 'env>(value: T) -> silk/shared.Shared<T> ! OutOfMemoryError ? &mut Allocator

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

Method Shared.clone

pub fn clone<T, 'life1>(self: &'life1 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.

Method Shared.withMut

pub fn withMut<T, A, 'life2, 'life3>(self: &'life2 Shared<T>, use: for<'call0> once fn<'life3>(&'call0 mut T) -> A) -> A

Runs one take-once callback Shared.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.

Method Shared.with

pub fn with<T, A, 'life2, 'life3>(self: &'life2 Shared<T>, use: for<'call0> once fn<'life3>(&'call0 T) -> A) -> A

Runs one take-once callback Shared.with shared access to the stored value.

Details

Inspection delegates through Shared.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.

On this page