concurrent

package module
v0.0.0-...-f81e685 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 17, 2026 License: BSD-3-Clause Imports: 7 Imported by: 0

README

go-ruby-concurrent-ruby/concurrent-ruby

concurrent-ruby — go-ruby-concurrent-ruby

Docs License Go Coverage

A pure-Go (no cgo) reimplementation of the core of Ruby's concurrent-ruby gem — the Concurrent:: toolbox of thread-safe data structures, atomics, futures, thread pools, and synchronization primitives — modelling MRI 4.0.5's observable behaviour and vocabulary without any Ruby runtime.

It is the concurrent backend for go-embedded-ruby (a later require "concurrent" binding), but is a standalone, reusable Go module — a sibling of go-ruby-set and go-ruby-bigdecimal.

The block/value seam

Everywhere the gem takes a Ruby block — a Future body, a Promise#then continuation, Map#compute_if_absent, an each_pair iteration — this package takes a Go func, so the rbgo binding threads the host VM's callables through unchanged. Everywhere the gem runs work on an executor, the API takes an Executor interface, so the binding chooses where callbacks run:

type Executor interface{ Post(task func()) bool }

An ImmediateExecutor runs tasks inline (deterministic resolution); a ThreadPoolExecutor / FixedThreadPool runs them on a bounded worker pool.

Install

go get github.com/go-ruby-concurrent-ruby/concurrent-ruby

Usage

package main

import (
	"fmt"
	"time"

	concurrent "github.com/go-ruby-concurrent-ruby/concurrent-ruby"
)

func main() {
	// Atomics
	n := concurrent.NewAtomicFixnum(0)
	n.Increment(1)
	fmt.Println(n.Value()) // 1

	// Concurrent::Map with compute_if_absent
	m := concurrent.NewMap()
	fmt.Println(m.ComputeIfAbsent("k", func() any { return 42 })) // 42

	// Thread pool + Future
	pool := concurrent.NewFixedThreadPool(4)
	defer func() { pool.Shutdown(); pool.WaitForTermination(concurrent.NoTimeout) }()

	f := concurrent.FutureExecute(pool, func() (any, error) { return 6 * 7, nil })
	fmt.Println(f.Value(time.Second)) // 42

	// Promise chaining
	p := concurrent.NewPromise()
	c := p.Then(func(v any) (any, error) { return v.(int) + 1, nil })
	p.Fulfill(1)
	fmt.Println(c.Value(concurrent.NoTimeout)) // 2

	// Synchronization primitives
	latch := concurrent.NewCountDownLatch(1)
	latch.CountDown()
	fmt.Println(latch.Wait(concurrent.NoTimeout)) // true
}

The Concurrent:: surface

Gem class Go type Notable methods
Concurrent::AtomicReference AtomicReference Get Set GetAndSet CompareAndSet Update
Concurrent::AtomicFixnum AtomicFixnum Value Increment Decrement CompareAndSet Update
Concurrent::AtomicBoolean AtomicBoolean Value TrueQ FalseQ MakeTrue MakeFalse CompareAndSet
Concurrent::Map Map Get Set ComputeIfAbsent Compute PutIfAbsent Delete EachPair Size
Concurrent::Array Array Push Pop Shift At Set DeleteAt Each ToSlice
Concurrent::Hash Hash Get Set Delete KeyQ EachPair Keys Values
Concurrent::Future Future FutureExecute Value ValueBang Wait State Reason PendingQ/FulfilledQ/RejectedQ
Concurrent::Promise Promise Fulfill Reject Then Rescue Chain FlatMap Value State Reason
Concurrent::Promises (factory funcs) PromisesFuture PromisesFulfilledFuture PromisesRejectedFuture PromisesResolvableFuture(On) PromisesZip
Concurrent::Delay Delay Value ValueBang State Reason PendingQ/FulfilledQ/RejectedQ
Concurrent::Atom Atom Value Swap Reset CompareAndSet AddObserver (validator-aware)
Concurrent::TVar / Concurrent.atomically TVar / Atomically Value SetValue · tx.Read tx.Write (optimistic STM, auto-retry on conflict)
Concurrent::ScheduledTask ScheduledTask ScheduledTaskExecute Cancel Value ValueBang Wait State CancelledQ
Concurrent::TimerTask TimerTask Execute Shutdown RunningQ ExecutionInterval SetObserver
Concurrent::ThreadLocalVar ThreadLocalVar Value SetValue Bind (per-goroutine)
Concurrent::ThreadPoolExecutor / FixedThreadPool / SingleThreadExecutor ThreadPoolExecutor Post Shutdown WaitForTermination QueueLength CompletedTaskCount
Concurrent::CachedThreadPool CachedThreadPool Post Shutdown WaitForTermination CompletedTaskCount LargestPoolSize
Concurrent.global_*_executor GlobalIOExecutor / GlobalFastExecutor / GlobalImmediateExecutor process-wide singletons
Concurrent::ImmediateExecutor ImmediateExecutor Post
Concurrent::CountDownLatch CountDownLatch CountDown Count Wait
Concurrent::Event Event Set Reset TryQ SetQ Wait
Concurrent::Semaphore Semaphore Acquire Release TryAcquire AvailablePermits Drain ReducePermits
Concurrent::CyclicBarrier CyclicBarrier Wait Parties NumberWaiting BrokenQ Reset

State symbols map to State constants (Pending/Fulfilled/Rejected), and the gem's exceptions map to package sentinel errors — ErrMultipleAssignment (Concurrent::MultipleAssignmentError), ErrRejectedExecution, ErrTimeout, ErrBrokenBarrier — which the binding re-raises as the corresponding Ruby class. Ruby predicate methods (true?, fulfilled?, broken?) are spelled with a Q suffix (TrueQ, FulfilledQ, BrokenQ), following the go-ruby naming convention. Ruby's optional nil timeout (wait forever) is the NoTimeout constant.

Scope

This models a faithful, broad core of the gem. In addition to the atomics, thread-safe collections, futures, pools, and synchronizers above, it now implements the composable promise layer (Concurrent::Promises factories plus Promise#rescue/#chain/#flat_map/zip), Delay, ScheduledTask, TimerTask, Atom, Event, ThreadLocalVar, CachedThreadPool / SingleThreadExecutor, the Concurrent.global_* executors, and TVar/Concurrent.atomically software transactional memory (optimistic reads with automatic retry on write conflict).

Still deferred (genuinely higher-level or niche): Actor, Async, dataflow, Agent, MVar, AtomicMarkableReference, and the tuple/exchanger primitives. The seams here (the Executor interface and the Go func callbacks) are the foundation those layers would build on.

Tests & coverage

The suite is deterministic and race-clean: every state transition and error path is driven with latches and channels rather than time.Sleep, so there is no timing flakiness, and every pool is shut down so no goroutine leaks. The coverage gate holds at 100% of statements.

GOWORK=off CGO_ENABLED=1 go test -race -coverprofile=cover.out ./...
go tool cover -func=cover.out | tail -1   # 100.0%

CGO-free, dependency-free, gofmt + go vet clean, and green across the six 64-bit Go targets (amd64, arm64, riscv64, loong64, ppc64le, s390x — including big-endian) and three OSes (Linux, macOS, Windows).

License

BSD-3-Clause — see LICENSE. Copyright the go-ruby-concurrent-ruby/concurrent-ruby authors.

WebAssembly

Being pure Go (CGO=0), this library also compiles to WebAssembly — both GOOS=js GOARCH=wasm (browser / Node.js) and GOOS=wasip1 GOARCH=wasm (WASI). CI builds both targets on every push, alongside the six 64-bit native/qemu arches.

GOOS=js     GOARCH=wasm go build ./...   # browser / Node
GOOS=wasip1 GOARCH=wasm go build ./...   # WASI (wasmtime, wasmer, wasmedge, …)

Documentation

Overview

Package concurrent is a pure-Go (no cgo), MRI-4.0.5-faithful model of the core of Ruby's concurrent-ruby gem — the Concurrent:: toolbox of thread-safe data structures, atomics, futures, thread pools, and synchronization primitives.

It reproduces the observable behaviour and vocabulary of the gem (Concurrent::AtomicReference, Concurrent::Map, Concurrent::Future, Concurrent::ThreadPoolExecutor, Concurrent::CountDownLatch, …) without any Ruby runtime, targeting a later rbgo binding where `require "concurrent"` maps Ruby blocks and values onto the Go func seams exposed here.

Every point where the gem takes a Ruby block — a Future body, a Promise continuation, a Map#compute_if_absent computation, an Enumerable iteration — is expressed as a Go func parameter so the binding can thread the host VM's callables through unchanged. Every point where the gem runs work on an executor takes an Executor, so the binding chooses where callbacks run.

The package is CGO-free, dependency-free, and safe under the race detector.

Index

Constants

View Source
const NoTimeout time.Duration = -1

NoTimeout, passed as a timeout argument, waits indefinitely — the Go equivalent of passing nil (no timeout) in concurrent-ruby's blocking methods.

Variables

View Source
var (
	// ErrMultipleAssignment mirrors Concurrent::MultipleAssignmentError: an
	// IVar/Future/Promise may only be completed once.
	ErrMultipleAssignment = errors.New("concurrent: multiple assignment")

	// ErrRejectedExecution mirrors Concurrent::RejectedExecutionError: a task
	// was posted to an executor that could not accept it (shut down, or its
	// bounded queue is saturated).
	ErrRejectedExecution = errors.New("concurrent: rejected execution")

	// ErrTimeout mirrors Concurrent::TimeoutError.
	ErrTimeout = errors.New("concurrent: operation timed out")

	// ErrBrokenBarrier mirrors the broken state of a CyclicBarrier
	// (Java's BrokenBarrierException), reached on timeout or reset.
	ErrBrokenBarrier = errors.New("concurrent: broken barrier")

	// ErrCancelled mirrors Concurrent::CancelledOperationError: the rejection
	// reason of a ScheduledTask cancelled before it ran.
	ErrCancelled = errors.New("concurrent: cancelled operation")

	// ErrExecution mirrors the reason reported to a TimerTask observer when the
	// task body raises: the gem passes the raised exception; here a panicking
	// body surfaces as this sentinel.
	ErrExecution = errors.New("concurrent: execution error")
)

Package-level sentinel errors mirroring concurrent-ruby's exception classes. A binding maps each to the corresponding Ruby exception when raising into the host VM.

Functions

func Atomically

func Atomically(fn func(tx *Transaction) error) error

Atomically runs fn as an atomic, isolated transaction (Ruby Concurrent.atomically { ... }). If fn returns an error the transaction is aborted, no writes are applied, and the error is returned without retrying. If another transaction commits a conflicting write to a TVar this one read, the whole block is retried against the fresh committed state. On success all buffered writes are applied atomically and nil is returned.

Types

type Array

type Array struct {
	// contains filtered or unexported fields
}

Array models Concurrent::Array: a thread-safe, mutex-guarded ordered list.

func NewArray

func NewArray(items ...any) *Array

NewArray returns an Array seeded with items (Ruby Concurrent::Array.new).

func (*Array) At

func (a *Array) At(i int) (any, bool)

At returns the element at index i and whether i is in range (Ruby #[]).

func (*Array) Clear

func (a *Array) Clear()

Clear removes every element (Ruby #clear).

func (*Array) DeleteAt

func (a *Array) DeleteAt(i int) (any, bool)

DeleteAt removes and returns the element at index i and whether i was in range (Ruby #delete_at).

func (*Array) Each

func (a *Array) Each(fn func(any) error) error

Each calls fn for every element in order, stopping and returning fn's error if it returns one (Ruby #each). Elements are snapshotted under the lock.

func (*Array) Empty

func (a *Array) Empty() bool

Empty reports whether the array has no elements (Ruby #empty?).

func (*Array) Pop

func (a *Array) Pop() (any, bool)

Pop removes and returns the last element and whether one was present (Ruby #pop).

func (*Array) Push

func (a *Array) Push(v any) *Array

Push appends v and returns the array (Ruby #push / #<<).

func (*Array) Set

func (a *Array) Set(i int, v any) bool

Set stores v at index i, returning false if i is out of range (Ruby #[]=).

func (*Array) Shift

func (a *Array) Shift() (any, bool)

Shift removes and returns the first element and whether one was present (Ruby #shift).

func (*Array) Size

func (a *Array) Size() int

Size returns the number of elements (Ruby #size / #length).

func (*Array) ToSlice

func (a *Array) ToSlice() []any

ToSlice returns a copy of the elements (Ruby #to_a).

type Atom

type Atom struct {
	// contains filtered or unexported fields
}

Atom models Concurrent::Atom: an atomically-updatable reference guarded by an optional validator and notifying observers on every successful change. Unlike a bare AtomicReference, an Atom rejects updates its validator refuses and keeps the previous value.

func NewAtom

func NewAtom(initial any) *Atom

NewAtom returns an Atom holding initial with no validator (every value is valid) (Ruby Concurrent::Atom.new(initial)).

func NewAtomWithValidator

func NewAtomWithValidator(initial any, validator func(any) bool) *Atom

NewAtomWithValidator returns an Atom holding initial whose updates are accepted only when validator returns true (Ruby Atom.new(initial, validator:)). A validator that panics is treated as rejecting the value, mirroring the gem rescuing a raising validator into "invalid".

func (*Atom) AddObserver

func (a *Atom) AddObserver(fn func(old, new any))

AddObserver registers fn to run, with the old and new values, after every successful change (Ruby #add_observer).

func (*Atom) CompareAndSet

func (a *Atom) CompareAndSet(oldValue, newValue any) bool

CompareAndSet stores newValue only if the current value equals oldValue (by value equality) and newValue is valid, reporting whether it swapped (Ruby #compare_and_set). Observers fire on a successful change.

func (*Atom) Reset

func (a *Atom) Reset(newValue any) any

Reset stores newValue unconditionally when valid, returning the value now in effect: newValue on success, or the unchanged current value if invalid (Ruby #reset). Observers fire on a successful change.

func (*Atom) Swap

func (a *Atom) Swap(fn func(old any) any) any

Swap replaces the value with fn(current), retrying fn until it produces a valid value, and returns the value in effect afterwards: the new value on success, or the unchanged current value if fn's result is invalid (Ruby #swap { |old| ... }). Observers fire on a successful change.

func (*Atom) Value

func (a *Atom) Value() any

Value returns the current value (Ruby #value / #deref).

type AtomicBoolean

type AtomicBoolean struct {
	// contains filtered or unexported fields
}

AtomicBoolean models Concurrent::AtomicBoolean, backed by sync/atomic.

func NewAtomicBoolean

func NewAtomicBoolean(initial bool) *AtomicBoolean

NewAtomicBoolean returns an AtomicBoolean initialised to initial.

func (*AtomicBoolean) CompareAndSet

func (b *AtomicBoolean) CompareAndSet(old, next bool) bool

CompareAndSet stores next only if the current value equals old, reporting whether the swap happened (Ruby #compare_and_set).

func (*AtomicBoolean) FalseQ

func (b *AtomicBoolean) FalseQ() bool

FalseQ reports whether the value is false (Ruby #false?).

func (*AtomicBoolean) MakeFalse

func (b *AtomicBoolean) MakeFalse() bool

MakeFalse sets the value to false, returning true if it changed (Ruby #make_false).

func (*AtomicBoolean) MakeTrue

func (b *AtomicBoolean) MakeTrue() bool

MakeTrue sets the value to true, returning true if it changed (Ruby #make_true).

func (*AtomicBoolean) SetValue

func (b *AtomicBoolean) SetValue(v bool)

SetValue stores v (Ruby #value=).

func (*AtomicBoolean) TrueQ

func (b *AtomicBoolean) TrueQ() bool

TrueQ reports whether the value is true (Ruby #true?).

func (*AtomicBoolean) Value

func (b *AtomicBoolean) Value() bool

Value returns the current value (Ruby #value).

type AtomicFixnum

type AtomicFixnum struct {
	// contains filtered or unexported fields
}

AtomicFixnum models Concurrent::AtomicFixnum: a 64-bit integer with atomic arithmetic, backed by sync/atomic.

func NewAtomicFixnum

func NewAtomicFixnum(initial int64) *AtomicFixnum

NewAtomicFixnum returns an AtomicFixnum initialised to initial.

func (*AtomicFixnum) CompareAndSet

func (f *AtomicFixnum) CompareAndSet(old, next int64) bool

CompareAndSet stores next only if the current value equals old, reporting whether the swap happened (Ruby #compare_and_set).

func (*AtomicFixnum) Decrement

func (f *AtomicFixnum) Decrement(delta int64) int64

Decrement atomically subtracts delta and returns the new value (Ruby #decrement).

func (*AtomicFixnum) GetAndSet

func (f *AtomicFixnum) GetAndSet(n int64) int64

GetAndSet atomically stores n and returns the previous value (Ruby #update is separate; this is #swap-style get-and-set).

func (*AtomicFixnum) Increment

func (f *AtomicFixnum) Increment(delta int64) int64

Increment atomically adds delta and returns the new value (Ruby #increment, whose default delta is 1 — the binding passes 1).

func (*AtomicFixnum) SetValue

func (f *AtomicFixnum) SetValue(n int64)

SetValue stores n (Ruby #value=).

func (*AtomicFixnum) Update

func (f *AtomicFixnum) Update(fn func(int64) int64) int64

Update atomically replaces the value with fn(current) and returns the new value (Ruby #update), retrying under contention with a compare-and-swap loop.

func (*AtomicFixnum) Value

func (f *AtomicFixnum) Value() int64

Value returns the current value (Ruby #value).

type AtomicReference

type AtomicReference struct {
	// contains filtered or unexported fields
}

AtomicReference models Concurrent::AtomicReference: an object reference that may be read and written atomically, with a compare-and-set primitive. The reference holds any value; compare_and_set uses value equality (the host may override it to Ruby's eql?/equal? semantics).

func NewAtomicReference

func NewAtomicReference(initial any) *AtomicReference

NewAtomicReference returns an AtomicReference holding initial, comparing by value equality on compare_and_set.

func NewAtomicReferenceWith

func NewAtomicReferenceWith(eq func(a, b any) bool, initial any) *AtomicReference

NewAtomicReferenceWith returns an AtomicReference whose compare_and_set uses the host-supplied equality (e.g. Ruby eql?). A nil eq falls back to value equality.

func (*AtomicReference) CompareAndSet

func (r *AtomicReference) CompareAndSet(old, next any) bool

CompareAndSet stores next only if the current value equals old, reporting whether the swap happened (Ruby #compare_and_set / #compare_and_swap).

func (*AtomicReference) Get

func (r *AtomicReference) Get() any

Get returns the current value (Ruby #get / #value).

func (*AtomicReference) GetAndSet

func (r *AtomicReference) GetAndSet(v any) any

GetAndSet atomically stores v and returns the previous value (Ruby #get_and_set / #swap).

func (*AtomicReference) Set

func (r *AtomicReference) Set(v any)

Set stores v (Ruby #set / #value=).

func (*AtomicReference) Update

func (r *AtomicReference) Update(fn func(any) any) any

Update atomically replaces the value with fn(current) and returns the new value (Ruby #update). fn runs while the reference is locked.

type CachedThreadPool

type CachedThreadPool struct {
	// contains filtered or unexported fields
}

CachedThreadPool models Concurrent::CachedThreadPool: an unbounded pool that runs each posted task on its own goroutine, so it never rejects a task for a full queue (only for being shut down). It is the executor of choice for blocking, IO-bound work.

func NewCachedThreadPool

func NewCachedThreadPool() *CachedThreadPool

NewCachedThreadPool returns a running CachedThreadPool (Ruby Concurrent::CachedThreadPool.new).

func (*CachedThreadPool) CompletedTaskCount

func (e *CachedThreadPool) CompletedTaskCount() int64

CompletedTaskCount returns the number of tasks that have finished (Ruby #completed_task_count).

func (*CachedThreadPool) LargestPoolSize

func (e *CachedThreadPool) LargestPoolSize() int64

LargestPoolSize returns the peak number of tasks that ran concurrently (Ruby #largest_length).

func (*CachedThreadPool) Post

func (e *CachedThreadPool) Post(task func()) bool

Post runs task on a fresh goroutine, returning false only if the pool is shut down (Ruby #post). It never blocks and never rejects for capacity.

func (*CachedThreadPool) RunningQ

func (e *CachedThreadPool) RunningQ() bool

RunningQ reports whether the pool still accepts tasks (Ruby #running?).

func (*CachedThreadPool) Shutdown

func (e *CachedThreadPool) Shutdown()

Shutdown stops accepting new tasks; already-running tasks finish. It is idempotent (Ruby #shutdown).

func (*CachedThreadPool) WaitForTermination

func (e *CachedThreadPool) WaitForTermination(timeout time.Duration) bool

WaitForTermination blocks until all running tasks finish (returning true) or timeout elapses (returning false) (Ruby #wait_for_termination). A negative timeout waits forever.

type CountDownLatch

type CountDownLatch struct {
	// contains filtered or unexported fields
}

CountDownLatch models Concurrent::CountDownLatch: a one-shot gate that releases every waiter once the count reaches zero.

func NewCountDownLatch

func NewCountDownLatch(count int) *CountDownLatch

NewCountDownLatch returns a latch with the given initial count. A count <= 0 starts already released.

func (*CountDownLatch) Count

func (l *CountDownLatch) Count() int

Count returns the current count (Ruby #count).

func (*CountDownLatch) CountDown

func (l *CountDownLatch) CountDown()

CountDown decrements the count, releasing all waiters when it reaches zero. Counting below zero is a no-op (Ruby #count_down).

func (*CountDownLatch) Wait

func (l *CountDownLatch) Wait(timeout time.Duration) bool

Wait blocks until the count reaches zero (returning true) or timeout elapses (returning false) (Ruby #wait). A negative timeout waits forever.

type CyclicBarrier

type CyclicBarrier struct {
	// contains filtered or unexported fields
}

CyclicBarrier models Concurrent::CyclicBarrier: a reusable barrier that releases a fixed number of parties once they have all arrived, optionally running a barrier action on the tripping party.

func NewCyclicBarrier

func NewCyclicBarrier(parties int) *CyclicBarrier

NewCyclicBarrier returns a barrier for the given number of parties. A count < 1 is clamped to 1.

func NewCyclicBarrierWithAction

func NewCyclicBarrierWithAction(parties int, action func()) *CyclicBarrier

NewCyclicBarrierWithAction returns a barrier that runs action once, on the party that trips it, before the parties are released (Ruby's barrier action).

func (*CyclicBarrier) BrokenQ

func (b *CyclicBarrier) BrokenQ() bool

BrokenQ reports whether the current generation is broken (Ruby #broken?).

func (*CyclicBarrier) NumberWaiting

func (b *CyclicBarrier) NumberWaiting() int

NumberWaiting returns how many parties are currently waiting (Ruby #number_waiting).

func (*CyclicBarrier) Parties

func (b *CyclicBarrier) Parties() int

Parties returns the number of parties required to trip the barrier (Ruby #parties).

func (*CyclicBarrier) Reset

func (b *CyclicBarrier) Reset()

Reset breaks the current generation, releasing any waiters with a false result, and starts a fresh one (Ruby #reset).

func (*CyclicBarrier) Wait

func (b *CyclicBarrier) Wait(timeout time.Duration) bool

Wait blocks until all parties arrive (returning true), or until timeout elapses or the barrier breaks (returning false) (Ruby #wait). The tripping party runs the barrier action and starts a fresh generation. A negative timeout waits forever.

type Delay

type Delay struct {
	// contains filtered or unexported fields
}

Delay models Concurrent::Delay: a lazy, memoised value. The computation is not run when the Delay is created but on the first call to Value/ValueBang, after which the result (value or rejection reason) is cached forever. It is the lazy sibling of Future — Future runs eagerly on an executor, Delay runs on first access on the calling goroutine.

func NewDelay

func NewDelay(fn func() (any, error)) *Delay

NewDelay returns an unforced Delay whose value is computed by fn on first access (Ruby Concurrent::Delay.new { ... }).

func (*Delay) FulfilledQ

func (d *Delay) FulfilledQ() bool

FulfilledQ reports whether the forced computation succeeded (Ruby #fulfilled?).

func (*Delay) PendingQ

func (d *Delay) PendingQ() bool

PendingQ reports whether the Delay has not been forced yet (Ruby #pending?).

func (*Delay) Reason

func (d *Delay) Reason() error

Reason returns the rejection reason once forced, or nil (Ruby #reason).

func (*Delay) RejectedQ

func (d *Delay) RejectedQ() bool

RejectedQ reports whether the forced computation failed (Ruby #rejected?).

func (*Delay) State

func (d *Delay) State() State

State returns the lifecycle state: Pending until forced, then Fulfilled or Rejected (Ruby #state).

func (*Delay) Value

func (d *Delay) Value() any

Value forces the computation and returns its value, or nil if it was rejected (Ruby #value).

func (*Delay) ValueBang

func (d *Delay) ValueBang() (any, error)

ValueBang forces the computation and returns its value, or the rejection reason as an error (Ruby #value!, which re-raises).

type Event

type Event struct {
	// contains filtered or unexported fields
}

Event models Concurrent::Event: an old-style, manually-controlled thread synchronisation object. It starts in the unset state; Set releases every current and future waiter until Reset returns it to unset. Unlike a CountDownLatch (one-shot), an Event may be set and reset repeatedly.

func NewEvent

func NewEvent() *Event

NewEvent returns an Event in the unset state (Ruby Concurrent::Event.new).

func (*Event) Reset

func (e *Event) Reset() bool

Reset returns the event to the unset state so it can be waited on again; a still-unset event is left unchanged. Always returns true (Ruby #reset).

func (*Event) Set

func (e *Event) Set() bool

Set transitions the event to set, releasing all waiters; it is idempotent and always returns true (Ruby #set).

func (*Event) SetQ

func (e *Event) SetQ() bool

SetQ reports whether the event is currently set (Ruby #set?).

func (*Event) TryQ

func (e *Event) TryQ() bool

TryQ sets the event only if it was unset, reporting whether this call was the one that set it (Ruby #try?).

func (*Event) Wait

func (e *Event) Wait(timeout time.Duration) bool

Wait blocks until the event is set (returning true) or timeout elapses (returning false) (Ruby #wait). A negative timeout waits forever. An already-set event returns true immediately.

type Executor

type Executor interface {
	Post(task func()) bool
}

Executor is the seam every asynchronous primitive posts work through. It mirrors Concurrent::ExecutorService#post: a task is a niladic callable, and Post reports whether the executor accepted it. A binding supplies the Ruby block wrapped as a Go func.

func GlobalFastExecutor

func GlobalFastExecutor() Executor

GlobalFastExecutor returns the shared fixed executor sized to the CPU count, for short non-blocking tasks (Concurrent.global_fast_executor). It is a process-wide singleton.

func GlobalIOExecutor

func GlobalIOExecutor() Executor

GlobalIOExecutor returns the shared unbounded IO executor (Concurrent.global_io_executor). It is a process-wide singleton.

func GlobalImmediateExecutor

func GlobalImmediateExecutor() Executor

GlobalImmediateExecutor returns an executor that runs tasks inline on the caller (Concurrent.global_immediate_executor).

type Future

type Future struct {
	// contains filtered or unexported fields
}

Future models Concurrent::Future: an asynchronous computation posted to an executor whose value is retrieved later. The computation is a Go func returning (value, error); a non-nil error rejects the future.

func FutureExecute

func FutureExecute(exec Executor, fn func() (any, error)) *Future

FutureExecute posts fn to exec and returns a Future for its result (Ruby Concurrent::Future.execute { ... }). fn's returned error rejects the future with that reason; otherwise it is fulfilled with the value.

func (*Future) CompleteQ

func (f *Future) CompleteQ() bool

CompleteQ reports whether the future has settled either way (Ruby #complete?).

func (*Future) FulfilledQ

func (f *Future) FulfilledQ() bool

FulfilledQ reports whether the future was fulfilled (Ruby #fulfilled?).

func (*Future) PendingQ

func (f *Future) PendingQ() bool

PendingQ reports whether the future is still pending (Ruby #pending?).

func (*Future) Reason

func (f *Future) Reason() error

Reason returns the rejection reason, or nil if not rejected (Ruby #reason).

func (*Future) RejectedQ

func (f *Future) RejectedQ() bool

RejectedQ reports whether the future was rejected (Ruby #rejected?).

func (*Future) State

func (f *Future) State() State

State returns the current lifecycle state (Ruby #state).

func (*Future) Value

func (f *Future) Value(timeout time.Duration) any

Value blocks up to timeout and returns the value, or nil if the future timed out or was rejected (Ruby #value).

func (*Future) ValueBang

func (f *Future) ValueBang(timeout time.Duration) (any, error)

ValueBang blocks up to timeout and returns the value, or the rejection reason as an error if the future was rejected (Ruby #value!, which re-raises).

func (*Future) Wait

func (f *Future) Wait(timeout time.Duration) *Future

Wait blocks up to timeout for the future to complete and returns the future (Ruby #wait). A negative timeout waits forever.

type Hash

type Hash struct {
	// contains filtered or unexported fields
}

Hash models Concurrent::Hash: a thread-safe, mutex-guarded key/value map. It is the synchronized-wrapper sibling of Map (which additionally offers atomic read-modify-write operations).

func NewHash

func NewHash() *Hash

NewHash returns an empty Hash.

func (*Hash) Clear

func (h *Hash) Clear()

Clear removes every entry (Ruby #clear).

func (*Hash) Delete

func (h *Hash) Delete(key any) any

Delete removes key, returning its previous value or nil (Ruby #delete).

func (*Hash) EachPair

func (h *Hash) EachPair(fn func(key, value any) error) error

EachPair calls fn for every key/value pair, stopping and returning fn's error if it returns one (Ruby #each_pair).

func (*Hash) Empty

func (h *Hash) Empty() bool

Empty reports whether the hash has no entries (Ruby #empty?).

func (*Hash) Get

func (h *Hash) Get(key any) any

Get returns the value for key, or nil if absent (Ruby #[]).

func (*Hash) KeyQ

func (h *Hash) KeyQ(key any) bool

KeyQ reports whether key is present (Ruby #key?).

func (*Hash) Keys

func (h *Hash) Keys() []any

Keys returns a snapshot of the keys (Ruby #keys).

func (*Hash) Set

func (h *Hash) Set(key, value any) any

Set stores value under key and returns value (Ruby #[]=).

func (*Hash) Size

func (h *Hash) Size() int

Size returns the number of entries (Ruby #size).

func (*Hash) Values

func (h *Hash) Values() []any

Values returns a snapshot of the values (Ruby #values).

type ImmediateExecutor

type ImmediateExecutor struct{}

ImmediateExecutor models Concurrent::ImmediateExecutor: it runs each posted task synchronously on the caller's goroutine. It makes Future/Promise resolution fully deterministic and is the default executor for Promise.

func (ImmediateExecutor) Post

func (ImmediateExecutor) Post(task func()) bool

Post runs task inline and always accepts it.

type Map

type Map struct {
	// contains filtered or unexported fields
}

Map models Concurrent::Map: a thread-safe hash with atomic read-modify-write operations (compute_if_absent, compute, put_if_absent). Keys are keyed by Go equality; a binding maps Ruby hash/eql? keys onto comparable Go keys, exactly as go-ruby-set does for Set members.

func NewMap

func NewMap() *Map

NewMap returns an empty Map.

func (*Map) Clear

func (c *Map) Clear()

Clear removes every entry (Ruby #clear).

func (*Map) Compute

func (c *Map) Compute(key any, fn func(old any, present bool) (value any, keep bool)) any

Compute atomically computes a new value for key from its current value (Ruby #compute). fn receives the current value and whether it was present, and returns the new value and whether to keep the entry; returning keep=false deletes the entry (if present) and yields nil.

func (*Map) ComputeIfAbsent

func (c *Map) ComputeIfAbsent(key any, fn func() any) any

ComputeIfAbsent returns the existing value for key, or atomically computes it with fn, stores, and returns it (Ruby #compute_if_absent). fn runs while the map is locked, so it observes a consistent view.

func (*Map) Delete

func (c *Map) Delete(key any) any

Delete removes key, returning its previous value or nil (Ruby #delete).

func (*Map) EachPair

func (c *Map) EachPair(fn func(key, value any) error) error

EachPair calls fn for every key/value pair, stopping and returning fn's error if it returns one (Ruby #each_pair). Pairs are snapshotted under the lock so fn may safely mutate the map.

func (*Map) Empty

func (c *Map) Empty() bool

Empty reports whether the map has no entries (Ruby #empty?).

func (*Map) Get

func (c *Map) Get(key any) any

Get returns the value for key, or nil if absent (Ruby #[]).

func (*Map) GetOrDefault

func (c *Map) GetOrDefault(key, def any) any

GetOrDefault returns the value for key, or def if absent (Ruby #fetch(k, def)).

func (*Map) GetPair

func (c *Map) GetPair(key any) (any, bool)

GetPair returns the value for key and whether it was present (Ruby #fetch without a default, as a two-value form).

func (*Map) KeyQ

func (c *Map) KeyQ(key any) bool

KeyQ reports whether key is present (Ruby #key?).

func (*Map) Keys

func (c *Map) Keys() []any

Keys returns a snapshot of the keys (Ruby #keys).

func (*Map) PutIfAbsent

func (c *Map) PutIfAbsent(key, value any) any

PutIfAbsent stores value under key only if absent, returning the existing value if present or nil if it stored (Ruby #put_if_absent).

func (*Map) Set

func (c *Map) Set(key, value any) any

Set stores value under key and returns value (Ruby #[]=).

func (*Map) Size

func (c *Map) Size() int

Size returns the number of entries (Ruby #size).

func (*Map) Values

func (c *Map) Values() []any

Values returns a snapshot of the values (Ruby #values).

type Promise

type Promise struct {
	// contains filtered or unexported fields
}

Promise models the settable, composable core of Concurrent::Promise: it can be explicitly fulfilled or rejected, and chained with Then. Continuations run on the promise's executor (ImmediateExecutor by default, for deterministic inline resolution).

func NewPromise

func NewPromise() *Promise

NewPromise returns an unresolved Promise whose continuations run inline.

func NewPromiseOn

func NewPromiseOn(exec Executor) *Promise

NewPromiseOn returns an unresolved Promise whose continuations run on exec.

func PromiseExecute

func PromiseExecute(exec Executor, fn func() (any, error)) *Promise

PromiseExecute posts fn to exec and returns a Promise for its result (Ruby Concurrent::Promise.execute { ... }). fn's error rejects the promise.

func PromiseZip

func PromiseZip(ps ...*Promise) *Promise

PromiseZip returns a Promise fulfilled with the ordered slice of every input promise's value once all are fulfilled, or rejected with the reason of the first input to reject (Ruby Concurrent::Promise.zip / Promises.zip). Zipping no promises fulfils immediately with an empty slice.

func PromisesFulfilledFuture

func PromisesFulfilledFuture(v any) *Promise

PromisesFulfilledFuture returns an already-fulfilled Promise holding v (Ruby Concurrent::Promises.fulfilled_future(v)).

func PromisesFuture

func PromisesFuture(exec Executor, fn func() (any, error)) *Promise

PromisesFuture posts fn to exec and returns its Future-like Promise (Ruby Concurrent::Promises.future_on(executor) { ... }).

func PromisesRejectedFuture

func PromisesRejectedFuture(err error) *Promise

PromisesRejectedFuture returns an already-rejected Promise with reason err (Ruby Concurrent::Promises.rejected_future(err)).

func PromisesResolvableFuture

func PromisesResolvableFuture() *Promise

PromisesResolvableFuture returns an unresolved Promise the caller resolves with Fulfill/Reject, its continuations running inline (Ruby Concurrent::Promises.resolvable_future).

func PromisesResolvableFutureOn

func PromisesResolvableFutureOn(exec Executor) *Promise

PromisesResolvableFutureOn returns an unresolved Promise whose continuations run on exec (Ruby Concurrent::Promises.resolvable_future_on(executor)).

func PromisesZip

func PromisesZip(ps ...*Promise) *Promise

PromisesZip is the Concurrent::Promises spelling of PromiseZip.

func (*Promise) Chain

func (p *Promise) Chain(fn func(state State, value any, reason error) (any, error)) *Promise

Chain returns a child Promise resolved by fn, which runs on any outcome and receives this promise's full result (state, value, reason). fn's (value, error) resolves the child (Ruby Promises::Future#chain, which yields on both fulfilment and rejection).

func (*Promise) FlatMap

func (p *Promise) FlatMap(fn func(value any) *Promise) *Promise

FlatMap returns a child Promise that adopts the resolution of the inner Promise returned by fn(value). A rejection of this promise propagates to the child without calling fn (Ruby Promises::Future#flat_map).

func (*Promise) Fulfill

func (p *Promise) Fulfill(v any) error

Fulfill resolves the promise with v (Ruby #fulfill / #set). Resolving an already-resolved promise returns ErrMultipleAssignment.

func (*Promise) Reason

func (p *Promise) Reason() error

Reason returns the rejection reason, or nil if not rejected (Ruby #reason).

func (*Promise) Reject

func (p *Promise) Reject(err error) error

Reject resolves the promise as failed with reason err (Ruby #reject / #fail).

func (*Promise) Rescue

func (p *Promise) Rescue(handler func(reason error) (any, error)) *Promise

Rescue returns a child Promise that recovers from this promise's rejection: if this promise is fulfilled, its value passes through unchanged; if it is rejected, handler runs with the reason and its (value, error) resolves the child — a nil error fulfils the child with the recovered value, a non-nil error rejects it (Ruby #rescue / #catch / #on_error).

func (*Promise) State

func (p *Promise) State() State

State returns the current lifecycle state (Ruby #state).

func (*Promise) Then

func (p *Promise) Then(onFulfilled func(any) (any, error)) *Promise

Then returns a child Promise resolved by applying onFulfilled to this promise's value once it is fulfilled (Ruby #then). A rejection propagates to the child unchanged; a nil onFulfilled passes the value through; an error returned by onFulfilled rejects the child.

func (*Promise) Value

func (p *Promise) Value(timeout time.Duration) any

Value blocks up to timeout and returns the promise's value, or nil if pending or rejected (Ruby #value).

type ScheduledTask

type ScheduledTask struct {
	// contains filtered or unexported fields
}

ScheduledTask models Concurrent::ScheduledTask: a one-shot computation that runs after a delay and whose result is retrieved like a Future. Until it fires it can be cancelled.

func ScheduledTaskExecute

func ScheduledTaskExecute(exec Executor, delay time.Duration, fn func() (any, error)) *ScheduledTask

ScheduledTaskExecute schedules fn to run on exec after delay and returns the task (Ruby Concurrent::ScheduledTask.execute(delay) { ... }). A non-negative delay is honoured; the task fires once, fulfilling with fn's value or rejecting with its error.

func (*ScheduledTask) Cancel

func (t *ScheduledTask) Cancel() bool

Cancel prevents a not-yet-started task from running, reporting whether it was cancelled in time (Ruby #cancel). A task that has already started or completed cannot be cancelled.

func (*ScheduledTask) CancelledQ

func (t *ScheduledTask) CancelledQ() bool

CancelledQ reports whether the task was cancelled (Ruby #cancelled?).

func (*ScheduledTask) FulfilledQ

func (t *ScheduledTask) FulfilledQ() bool

FulfilledQ reports whether the task completed successfully (Ruby #fulfilled?).

func (*ScheduledTask) PendingQ

func (t *ScheduledTask) PendingQ() bool

PendingQ reports whether the task has not completed yet (Ruby #pending?).

func (*ScheduledTask) Reason

func (t *ScheduledTask) Reason() error

Reason returns the rejection reason, or nil (Ruby #reason).

func (*ScheduledTask) RejectedQ

func (t *ScheduledTask) RejectedQ() bool

RejectedQ reports whether the task failed or was cancelled (Ruby #rejected?).

func (*ScheduledTask) State

func (t *ScheduledTask) State() State

State returns the lifecycle state (Ruby #state).

func (*ScheduledTask) Value

func (t *ScheduledTask) Value(timeout time.Duration) any

Value blocks up to timeout and returns the task's value, or nil if it timed out, was rejected, or was cancelled (Ruby #value).

func (*ScheduledTask) ValueBang

func (t *ScheduledTask) ValueBang(timeout time.Duration) (any, error)

ValueBang blocks up to timeout and returns the value, or the rejection reason as an error (Ruby #value!).

func (*ScheduledTask) Wait

func (t *ScheduledTask) Wait(timeout time.Duration) *ScheduledTask

Wait blocks up to timeout for the task to complete and returns it (Ruby #wait). A negative timeout waits forever.

type Semaphore

type Semaphore struct {
	// contains filtered or unexported fields
}

Semaphore models Concurrent::Semaphore: a counting semaphore. Permits are held as tokens in a buffered channel, so Acquire blocks naturally when none are available and the race detector stays satisfied.

func NewSemaphore

func NewSemaphore(permits int) *Semaphore

NewSemaphore returns a Semaphore with the given number of permits. A negative count is treated as zero.

func (*Semaphore) Acquire

func (s *Semaphore) Acquire(n int)

Acquire blocks until n permits are available, then takes them (Ruby #acquire).

func (*Semaphore) AvailablePermits

func (s *Semaphore) AvailablePermits() int

AvailablePermits returns the number of permits currently available (Ruby #available_permits).

func (*Semaphore) Drain

func (s *Semaphore) Drain() int

Drain takes all available permits and returns how many it took (Ruby #drain_permits).

func (*Semaphore) ReducePermits

func (s *Semaphore) ReducePermits(n int)

ReducePermits removes up to n available permits without blocking (Ruby #reduce_permits).

func (*Semaphore) Release

func (s *Semaphore) Release(n int)

Release returns n permits (Ruby #release).

func (*Semaphore) TryAcquire

func (s *Semaphore) TryAcquire(n int) bool

TryAcquire takes n permits without blocking, reporting whether it succeeded; on failure it returns any partially taken permits (Ruby #try_acquire).

type State

type State string

State is the lifecycle state of a Future, Promise, or other IVar-like value, mirroring the Ruby symbols :pending, :fulfilled, and :rejected.

const (
	// Pending is the initial state, before a value or reason is assigned.
	Pending State = "pending"
	// Fulfilled means a value was assigned successfully.
	Fulfilled State = "fulfilled"
	// Rejected means the computation failed and a reason (error) was assigned.
	Rejected State = "rejected"
)

type TVar

type TVar struct {
	// contains filtered or unexported fields
}

TVar models Concurrent::TVar: a transactional variable that may only be read or written inside a transaction (Atomically). Outside a transaction, Value and SetValue run a one-operation transaction.

func NewTVar

func NewTVar(initial any) *TVar

NewTVar returns a TVar holding initial (Ruby Concurrent::TVar.new(initial)).

func (*TVar) SetValue

func (t *TVar) SetValue(v any) any

SetValue stores v via a single-write transaction and returns it (Ruby #value=, outside an explicit transaction).

func (*TVar) Value

func (t *TVar) Value() any

Value returns the committed value via a single-read transaction (Ruby #value, when called outside an explicit transaction).

type ThreadLocalVar

type ThreadLocalVar struct {
	// contains filtered or unexported fields
}

ThreadLocalVar models Concurrent::ThreadLocalVar: a variable whose value is independent per thread (here, per goroutine). Reads and writes on one goroutine never affect another's; a goroutine that has not set a value sees the default.

func NewThreadLocalVar

func NewThreadLocalVar(def any) *ThreadLocalVar

NewThreadLocalVar returns a ThreadLocalVar whose default value (seen by any goroutine that has not set one) is def (Ruby ThreadLocalVar.new(default)).

func NewThreadLocalVarWith

func NewThreadLocalVarWith(defaultFn func() any) *ThreadLocalVar

NewThreadLocalVarWith returns a ThreadLocalVar whose default value is computed per goroutine by defaultFn on first read (Ruby ThreadLocalVar.new { ... }).

func (*ThreadLocalVar) Bind

func (t *ThreadLocalVar) Bind(v any, fn func())

Bind sets the calling goroutine's value to v for the duration of fn, then restores the previous binding (Ruby #bind(value) { ... }).

func (*ThreadLocalVar) SetValue

func (t *ThreadLocalVar) SetValue(v any) any

SetValue stores v as the calling goroutine's value and returns it (Ruby #value=).

func (*ThreadLocalVar) Value

func (t *ThreadLocalVar) Value() any

Value returns the calling goroutine's value, or the default if it has not set one (Ruby #value).

type ThreadPoolExecutor

type ThreadPoolExecutor struct {
	// contains filtered or unexported fields
}

ThreadPoolExecutor models Concurrent::ThreadPoolExecutor / FixedThreadPool: a fixed set of worker goroutines draining a bounded FIFO queue. It supports graceful shutdown, termination waiting, and task accounting.

func NewFixedThreadPool

func NewFixedThreadPool(n int) *ThreadPoolExecutor

NewFixedThreadPool returns a ThreadPoolExecutor with n workers and the default bounded queue (Ruby Concurrent::FixedThreadPool.new(n)).

func NewSingleThreadExecutor

func NewSingleThreadExecutor() *ThreadPoolExecutor

NewSingleThreadExecutor returns an executor backed by exactly one worker, running tasks in submission order (Ruby Concurrent::SingleThreadExecutor.new).

func NewThreadPoolExecutor

func NewThreadPoolExecutor(workers, queueCap int) *ThreadPoolExecutor

NewThreadPoolExecutor returns a pool with the given number of worker goroutines and bounded queue capacity. workers < 1 is clamped to 1 and a negative queueCap to 0 (a synchronous handoff queue).

func (*ThreadPoolExecutor) CompletedTaskCount

func (e *ThreadPoolExecutor) CompletedTaskCount() int64

CompletedTaskCount returns the number of tasks that have finished running (Ruby #completed_task_count).

func (*ThreadPoolExecutor) Post

func (e *ThreadPoolExecutor) Post(task func()) bool

Post enqueues task, returning false if the pool is shut down or its queue is saturated (the gem's :abort fallback policy). It never blocks.

func (*ThreadPoolExecutor) QueueLength

func (e *ThreadPoolExecutor) QueueLength() int

QueueLength returns the number of tasks currently queued and not yet picked up by a worker (Ruby #queue_length).

func (*ThreadPoolExecutor) RunningQ

func (e *ThreadPoolExecutor) RunningQ() bool

RunningQ reports whether the pool is still accepting tasks (Ruby #running?).

func (*ThreadPoolExecutor) Shutdown

func (e *ThreadPoolExecutor) Shutdown()

Shutdown initiates a graceful shutdown: no new tasks are accepted, already queued tasks still run, and workers exit once the queue drains. It is idempotent (Ruby #shutdown).

func (*ThreadPoolExecutor) ShutdownQ

func (e *ThreadPoolExecutor) ShutdownQ() bool

ShutdownQ reports whether the pool has fully terminated (Ruby #shutdown?).

func (*ThreadPoolExecutor) WaitForTermination

func (e *ThreadPoolExecutor) WaitForTermination(timeout time.Duration) bool

WaitForTermination blocks until every worker has exited, returning true, or until timeout elapses, returning false (Ruby #wait_for_termination). A negative timeout waits forever.

type TimerTask

type TimerTask struct {
	// contains filtered or unexported fields
}

TimerTask models Concurrent::TimerTask: a task run repeatedly on a fixed interval until shut down. Each run's outcome is reported to an optional observer.

func NewTimerTask

func NewTimerTask(interval time.Duration, fn func() (any, error)) *TimerTask

NewTimerTask returns an unstarted TimerTask that will run fn every interval once executed (Ruby Concurrent::TimerTask.new(execution_interval: ...) {}).

func (*TimerTask) Execute

func (t *TimerTask) Execute() bool

Execute starts the timer loop, reporting whether it started (false if it was already running) (Ruby #execute). The first run happens after one interval.

func (*TimerTask) ExecutionInterval

func (t *TimerTask) ExecutionInterval() time.Duration

ExecutionInterval returns the interval between runs (Ruby #execution_interval).

func (*TimerTask) RunningQ

func (t *TimerTask) RunningQ() bool

RunningQ reports whether the timer loop is active (Ruby #running?).

func (*TimerTask) SetObserver

func (t *TimerTask) SetObserver(fn func(value any, reason error))

SetObserver registers fn to receive each run's (value, reason); a run that returns an error reports (nil, err) (Ruby #add_observer). It must be set before Execute.

func (*TimerTask) Shutdown

func (t *TimerTask) Shutdown() bool

Shutdown stops the timer loop and blocks until it has exited, reporting whether it was running (Ruby #shutdown). It is idempotent.

func (*TimerTask) TimesRun

func (t *TimerTask) TimesRun() int

TimesRun returns how many times the body has run (test/observability aid).

type Transaction

type Transaction struct {
	// contains filtered or unexported fields
}

Transaction is the handle threaded through an Atomically block. Reads and writes to TVars go through it so the runtime can buffer writes and validate reads at commit time.

func (*Transaction) Read

func (tx *Transaction) Read(t *TVar) any

Read returns t's value as seen by this transaction: a value written earlier in the same transaction, then a value already read in it (repeatable read), otherwise a fresh committed value whose version is recorded for commit-time validation (Ruby TVar#value inside atomically).

func (*Transaction) Write

func (tx *Transaction) Write(t *TVar, v any)

Write buffers v as t's new value within this transaction; it becomes visible to other transactions only at commit (Ruby TVar#value= inside atomically).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL