observable

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package observable provides independently owned query streams. Publishing transfers immutable values unless SubjectOptions.Clone is supplied. Closing a stream never completes its shared source. No source construction starts work.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrJoinPending means stream cleanup completion is unknown or incomplete.
	// Retain the stream and continue Close with a fresh budget; do not dispose
	// dependencies beneath its producer. Continuation must not repeat side effects.
	ErrJoinPending = errors.New("observable cleanup join pending")
	// ErrClosed means the source or stream has been closed.
	ErrClosed = errors.New("observable is closed")
	// ErrConcurrentNext rejects overlapping consumption of the same stream.
	ErrConcurrentNext = errors.New("observable Next is already running")
	// ErrOverflow terminates a slow subscriber without affecting other subscribers.
	ErrOverflow = errors.New("observable subscriber buffer exhausted")
	// ErrInvalidOptions rejects invalid construction or operation arguments.
	ErrInvalidOptions = errors.New("invalid observable options")
	// ErrProducerPanic reports a recovered producer panic without exposing its value.
	ErrProducerPanic = errors.New("observable producer panicked")
)

Functions

This section is empty.

Types

type ChannelFactory

type ChannelFactory[T any] func(context.Context) (<-chan T, func(context.Context) error, error)

ChannelFactory opens a borrowed channel and returns a cleanup callback that must cancel and join its producer. The callback must support serialized continuation after a context error, ErrJoinPending or panic, without repeating disposal or side effects: initiate them at most once inside the callback. Any other returned outcome certifies producer completion, including failure. Panics leave completion unknown; Close retains PanicError diagnostics and ErrJoinPending until a later attempt certifies completion. A nonnil callback transfers ownership even when startup fails or returns an invalid channel: Open returns a nonnil stream alongside the error, and the caller must Close it with a separate cleanup budget. Arc never closes the borrowed channel. Closing the channel means normal completion; producer failures should use FromProducer.

type CurrentSource

type CurrentSource[T any] interface {
	Source[T]
	Current(context.Context) (T, bool, error)
}

CurrentSource distinguishes absence from a current zero or nil value. A completed source may expose its last value; a failed source returns its error.

type PublishError

type PublishError struct {
	Delivered  int
	Overflowed int
}

PublishError describes partial publishing. Delivered subscribers accepted the immutable value; Overflowed subscribers terminated. Do not blindly retry.

func (*PublishError) Error

func (e *PublishError) Error() string

func (*PublishError) Unwrap

func (*PublishError) Unwrap() error

Unwrap permits errors.Is(err, ErrOverflow).

type Source

type Source[T any] interface {
	Open(context.Context) (Stream[T], error)
}

Source opens one independently owned stream after admission. Callers must Close even after exhaustion or cancellation. Implementations must honor cancellation.

func FromChannelFactory

func FromChannelFactory[T any](factory ChannelFactory[T]) Source[T]

FromChannelFactory constructs a lazy source with explicit producer cleanup.

func FromIterator

func FromIterator[T any](open func(context.Context) iter.Seq2[T, error]) Source[T]

FromIterator opens and consumes one iterator per stream. Returning false from yield stops iteration, so iterator cleanup must run on early cancellation. A blocking iterator must honor its supplied context; Close never detaches it.

func FromProducer

func FromProducer[T any](run func(context.Context, func(T) error) error) Source[T]

FromProducer defers activation to Open. The stream owns one worker; Close cancels and joins it. The producer must honor cancellation and join any work it creates before returning. Concurrent emit calls are serialized. Values transfer immutably; a producer must not mutate a value after emit returns. Callback use after run returns is unsupported. Producer errors remain locally inspectable.

type State

type State[T any] struct {
	// contains filtered or unexported fields
}

State is a concurrent-safe subject with atomic current-value attachment/replay. Use NewState or NewPendingState. Nil and zero initial values are current values.

Example
package main

import (
	"context"
	"fmt"
	"slices"

	"github.com/cratis/arc.go/observable"
)

func main() {
	ctx := context.Background()
	state, err := observable.NewState([]string{}, observable.SubjectOptions[[]string]{Clone: func(value []string) ([]string, error) { return slices.Clone(value), nil }})
	if err != nil {
		panic(err)
	}
	stream, err := state.Open(ctx)
	if err != nil {
		panic(err)
	}
	initial, err := stream.Next(ctx)
	if err != nil {
		panic(err)
	}
	fmt.Println(len(initial))
	if err := state.Publish(ctx, []string{"Ada"}); err != nil {
		panic(err)
	}
	current, err := stream.Next(ctx)
	if err != nil {
		panic(err)
	}
	fmt.Println(current)
	if err := stream.Close(ctx); err != nil {
		panic(err)
	}
}
Output:
0
[Ada]

func NewPendingState

func NewPendingState[T any](options SubjectOptions[T]) (*State[T], error)

NewPendingState constructs a state with no current value.

func NewState

func NewState[T any](initial T, options SubjectOptions[T]) (*State[T], error)

NewState clones initial if configured. Construction performs no I/O or work.

func (*State[T]) Complete

func (s *State[T]) Complete() error

Complete retains the last current value, if any, and completes subscriptions.

func (*State[T]) Current

func (s *State[T]) Current(ctx context.Context) (T, bool, error)

Current returns a detached current value when configured, preserving presence.

func (*State[T]) Fail

func (s *State[T]) Fail(err error) error

Fail prevents subsequent reads from presenting a stale successful current value.

func (*State[T]) Open

func (s *State[T]) Open(ctx context.Context) (Stream[T], error)

Open attaches and queues the current value atomically with publication.

func (*State[T]) Publish

func (s *State[T]) Publish(ctx context.Context, value T) error

Publish replaces the current immutable snapshot and broadcasts it.

type Stream

type Stream[T any] interface {
	Next(context.Context) (T, error)
	Close(context.Context) error
}

Stream has a single consumer. Next returns io.EOF only for normal completion; zero and nil values are real emissions. Close cancels and joins owned work. Repeated Close is safe; a timed-out Close may be continued with a later budget. Context errors or ErrJoinPending mean joining is incomplete or unknown; any other returned result certifies completion, including a final failure.

type Subject

type Subject[T any] struct {
	// contains filtered or unexported fields
}

Subject is a concurrent-safe multicast source without current-value replay. Use NewSubject; the zero value is not initialized. Complete and Fail terminate subscribers, while closing one stream affects only that subscription.

func NewSubject

func NewSubject[T any](options SubjectOptions[T]) (*Subject[T], error)

NewSubject constructs a subject without activating any work.

func (*Subject[T]) Complete

func (s *Subject[T]) Complete() error

Complete closes the subject normally. Queued values precede io.EOF.

func (*Subject[T]) Fail

func (s *Subject[T]) Fail(err error) error

Fail terminates subscriptions with err, discarding buffered stale values. Nil and io.EOF are invalid failures. Repeating the same terminal action is safe.

func (*Subject[T]) Open

func (s *Subject[T]) Open(ctx context.Context) (Stream[T], error)

Open attaches one subscriber. Closing it never affects the subject.

func (*Subject[T]) Publish

func (s *Subject[T]) Publish(ctx context.Context, value T) error

Publish serializes concurrent publishers and never waits for a slow subscriber. An overflow terminates only that subscriber and returns a partial PublishError.

type SubjectOptions

type SubjectOptions[T any] struct {
	Buffer int
	Clone  func(T) (T, error)
}

SubjectOptions bounds each subscriber's queue. Buffer zero defaults to 16; negative values are rejected. Clone must detach nested mutable values and be concurrent-safe. It runs outside framework locks. Without Clone, values must remain immutable after publishing, including after completion.

Jump to

Keyboard shortcuts

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