Under heavy development. This site describes the intended 1.0 language. Current features and performance vary. Development status
Sn50SnThe SnAPI programming language
0.2.0 Preview 1 · Frozen documentation

Channel

Owns a bounded FIFO with suspension-backed send/receive backpressure. Creation pre-reserves all slots. Successful send transfers one owned payload; failed send returns it in ChannelSendError. Immediate receives distinguish temporary Empty from final Closed; asynchronous receives return optional EOF. Close stops new send commits and drains committed items before EOF. Cancellation can remove pending permit waits, never duplicate a committed payload. Published readonly borrows may operate concurrently; moving/disposal requires ordinary synchronization and live-loan rules. No fairness or waiter-order guarantee. Queue operations/Close briefly contend on an internal mutex; guards never cross await. Creation allocates; ordinary successful transfers do not grow backing. Destruction closes before releasing state; pending work retains private leases. Element move/destruction costs and traps remain those of T.

Sn is under heavy development. Reference extracted from this release’s bundled standard library. Public API examples are not an exhaustive compatibility test. Read the matching release guide for tested workflows and limitations. Read the status →

Module std.sync

import std.sync;

Public declaration contracts and authored examples. A page can document several related symbols. Implementation bodies are excluded.

Channel

pub final class Channel<T> where T: Movable

Owns a bounded FIFO with suspension-backed send/receive backpressure. Creation pre-reserves all slots. Successful send transfers one owned payload; failed send returns it in ChannelSendError. Immediate receives distinguish temporary Empty from final Closed; asynchronous receives return optional EOF. Close stops new send commits and drains committed items before EOF. Cancellation can remove pending permit waits, never duplicate a committed payload. Published readonly borrows may operate concurrently; moving/disposal requires ordinary synchronization and live-loan rules. No fairness or waiter-order guarantee. Queue operations/Close briefly contend on an internal mutex; guards never cross await. Creation allocates; ordinary successful transfers do not grow backing. Destruction closes before releasing state; pending work retains private leases. Element move/destruction costs and traps remain those of T. T: Movable payload; stored views retain ordinary origin/transfer rules.

Example

module example.channel;
from std.sync import Channel;
from std.task import Task;
async fn Main() -> Task<i32> {
    var Queue = {
        // The scoped Result keeps its exact writable payload until transfer.
        var QueueCreation = Channel<i32>.TryCreate(1);
        switch QueueCreation {
            case .Ok { Value = Value: mut Channel<i32>& } => break move(Value);
            case .Err => return 1;
        }
    };
    if Queue.Capacity != 1 { return 2; }
    if Queue.TrySend(40) is .Err { Error = _ } { return 3; }
    switch Queue.TrySend(2) {
        case .Ok => return 4;
        case .Err { Error = Error } => {
            if !(Error.Reason is .Full) || Error.Value != 2 { return 5; }
        }
    }
    switch Queue.TryReceive() {
        case .Ok { Value = PatternPayload2 } => {
            switch PatternPayload2 {
                case .Item { Value = Value } => { if Value != 40 { return 6; } }
                default => return 7;
            }
        }
        default => return 7;
    }
    switch Queue.TryReceive() {
        case .Ok { Value = PatternPayload3 } if (PatternPayload3 is .Empty) => {}
        default => return 8;
    }
    if await Queue.SendAsync(42) is .Err { Error = _ } { return 9; }
    if Queue.Close() is .Err { Error = _ } { return 10; }
    switch await Queue.ReceiveAsync() {
        case .Ok { Value = PatternPayload4 } => {
            switch PatternPayload4 {
                case .Some { Value = Value } => { if Value != 42 { return 11; } }
                default => return 12;
            }
        }
        default => return 12;
    }
    switch await Queue.ReceiveAsync() {
        case .Ok { Value = PatternPayload5 } if (PatternPayload5 is .None) => {}
        default => return 13;
    }
    switch Queue.TrySend(99) {
        case .Err { Error = Error } => { if !(Error.Reason is .Closed) || Error.Value != 99 { return 14; } }
        case .Ok => return 15;
    }
    var Moved = move(Queue);
    if !Queue.IsEmpty || Moved.IsEmpty { return 16; }
    if Moved.Close() is .Err { Error = _ } { return 17; }
    return 0;
}

Channel.init

pub init()

Creates inert owner without allocating.

Channel.init

pub init(Source: readonly Self&) = delete;

Rejects duplicate visible closing authority. Source: Existing owner.

Channel.init

pub init(Source: mut Self&&)

Transfers closing authority, preserving separately retained operations. Source: Owner left inert.

Channel.operator

pub fn operator =(Source: readonly Self&) -> void = delete;

Rejects duplicate closing authority. Source: Existing owner. Return: No runtime result; this assignment is deleted and cannot be invoked.

Channel.operator

pub fn operator =(Source: mut Self&&) -> void = delete;

Rejects implicit close-and-replace because close can report failure. Source: Existing owner. Return: No runtime result; this assignment is deleted and cannot be invoked.

Channel.IsEmpty

pub IsEmpty: bool;

Observes default/moved owner identity; not queue occupancy.

Channel.Capacity

pub Capacity: usize;

Observes logical bound, or zero for inert owner.

Channel.TryCreate

pub static fn TryCreate(Capacity: usize) -> Result<Self, ChannelError>

Allocates bounded FIFO and native/shared synchronization transactionally. Capacity: Positive logical capacity representable as u64; zero/overflow return InvalidCapacity. Return: Published owner or portable error; partial resources clean up normally. Warning: May allocate and acquire provider resources.

Channel.TrySend

pub readonly fn TrySend(mut Value: T) -> Result<void, ChannelSendError<T>>

Attempts one send without waiting for capacity. Value: Owned item transferred on success, returned on failure. Return: Ok or exact owning error, including Full/Closed/EmptyOwner. Warning: May briefly contend on queue mutex.

Channel.SendAsync

pub readonly async fn SendAsync(mut Value: T, mut Token: CancellationToken) -> Task<Result<void, ChannelSendError<T>>>

Waits asynchronously for capacity, then attempts an owned FIFO commit. Value: Owned input held until commit or returned failure. Token: Owned cancellation observation; cancellation only removes pending wait. Return: Task yielding Ok or error retaining the exact unsent value. Warning: Receiver/storage loans last through completion; no mutex guard crosses await.

Channel.SendAsync

pub readonly fn SendAsync(mut Value: T) -> Task<Result<void, ChannelSendError<T>>>

Supplies the omitted arguments to SendAsync. Note: Defaults: Token = CancellationToken(). Value: Same input, ownership and lifetime contract as the full operation. Return: Exact full-operation result; no additional async frame is created.

Channel.TryReceive

pub readonly fn TryReceive() -> Result<ChannelReceive<T>, ChannelError>

Attempts receive without waiting for item arrival. Return: Owned Item, open Empty, final Closed, or portable failure. Warning: May briefly contend on queue mutex.

Channel.ReceiveAsync

pub readonly async fn ReceiveAsync(mut Token: CancellationToken) -> Task<Result<T?, ChannelError>>

Waits asynchronously for one item, draining buffered values after close. Token: Owned cancellation observation, effective only while pending. Return: Task yielding owned optional item, none for closed EOF, or portable error. Warning: Receiver/storage loans last through completion; no guard crosses await.

Channel.ReceiveAsync

pub readonly fn ReceiveAsync() -> Task<Result<T?, ChannelError>>

Supplies the omitted arguments to ReceiveAsync. Note: Defaults: Token = CancellationToken(). Return: Exact full-operation result; no additional async frame is created.

Channel.CreateAsyncIterator

pub readonly fn CreateAsyncIterator() -> ChannelAsyncIterator<T>

Creates retained consumer state without receiving or allocating backing. Return: Noncopy cursor competing for this FIFO; inert owner yields inert cursor. Warning: Cursor retention does not prevent visible-owner cleanup from closing the channel; committed items remain drainable afterward.

Channel.Close

pub readonly fn Close() -> Result<void, ChannelError>

Idempotently forbids sends and wakes waits; committed values remain drainable. Return: Ok for inert/already closed owner, or unchanged-state lock error. Warning: May briefly contend on queue mutex.

Documentation snapshot: October 24, 2026 About versions ↗
Searching Development · language & standard library