silk.mem.shared.
Shared ownership of one mutable value on one thread, with access through callbacks.
When to use#
Use Shared when several values that you own separately, such as stored callbacks or
computations that run later, must all use the same mutable state, and a borrow cannot live long
enough. For one owner, use the value directly or silk.mem.box.Box.
Details#
Shared.make allocates one time. Shared.clone, Shared.with, and Shared.withMut do
not allocate. Each handle counts as one owner. When you drop a handle that is not the last one,
the value stays. When you drop the last handle, the value is dropped and the allocation is
released. A handle stays on the thread that made it.
Access is exclusive for the duration of the callback, also for Shared.with. A nested access
to the same value through any handle traps before the nested callback starts. This applies to
all four combinations of with and withMut.
Gotchas#
Handles that refer to each other in a cycle are never dropped, so the value leaks until you break the cycle. There are no weak handles. Do not call code that can access the same value from inside a callback. Get the data you need, return from the callback, and then call that code.
Examples#
Update a value through one handle and read it through another#
import silk.mem.allocator { Allocator, OutOfMemoryError }
import silk.core.effect { Effect }
import silk.mem.shared { Shared }
struct Counter {
value: i32,
}
fn addTwo(counter: &mut Counter) -> i32 {
counter.value = counter.value + 2
return counter.value
}
fn read(counter: &Counter) -> i32 {
return counter.value
}
pub effect fn main() -> i32
! OutOfMemoryError {
let mut allocator = Allocator.systemAllocatorProvider()
let first = run Shared<Counter>.make(Counter { value: 40 })
|> Effect.provideMut<Allocator>(&mut allocator)
let second = Shared<Counter>.clone(&first)
let updated = Shared<Counter>.withMut<i32>(&second, addTwo)
if updated != 42 || Shared<Counter>.with<i32>(&first, read) != 42 {
return 1
}
return 0
}Import as Shared with import silk.mem.shared { Shared }.
Public declarations: 1.
Shared#
pub struct Shared<T>A strong handle to one value of type T that other handles can also own.
When to use#
Use it when several values that you own separately, such as stored callbacks or computations
that run later, must all use the same mutable state, and a borrow cannot live long enough. For
one owner, use the value directly or silk.mem.box.Box.
Details#
Drop is automatic. The value is dropped when the last handle is dropped. A handle cannot move to another thread.
Shared.make allocates one time. Shared.clone, Shared.with, and Shared.withMut do
not allocate. Access is exclusive for the duration of the callback, also for Shared.with. A
nested access to the same value through any handle traps before the nested callback starts.
Gotchas#
Handles that refer to each other in a cycle are never dropped, so the value leaks until you break the cycle. There are no weak handles.
Implementation Shared<T>#
impl<T> Shared<T>Associated function make#
pub effect<'env> fn make<'env>(value: T) -> Shared<T> ! OutOfMemoryError ? &mut AllocatorAllocates storage, moves value into it, and returns the first handle.
Errors#
OutOfMemoryErrorif theAllocatorcannot supply the storage. No handle is made, andvalueis dropped.
Details#
The handle does not keep a reference to the allocator after make returns.
Method clone#
pub fn clone(self: &Self) -> Shared<T>Returns a new handle to the same value. It does not allocate and does not touch the value.
Gotchas#
If the handle count reaches its maximum, clone traps before it changes the count.
Method withMut#
pub fn withMut<A>(self: &Self, use: once fn(&mut T) -> A) -> ACalls use one time with a mutable borrow of the value and returns the result of use.
Details#
The borrow cannot escape the callback, and it cannot stay live across a suspension.
Gotchas#
If use accesses the same value again through any handle, the program traps before the nested
callback starts.
Method with#
pub fn with<A>(self: &Self, use: once fn(&T) -> A) -> ACalls use one time with a shared borrow of the value and returns the result of use.
Details#
with uses Shared.withMut internally, so the access is exclusive for the duration of the
callback. The callback cannot change the value through its &T.
Gotchas#
A nested access to the same value through any handle traps, also when both accesses use
with.
Category: Memory.
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2.