future

package
v0.0.0-...-caf0cee Latest Latest
Warning

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

Go to latest
Published: Mar 18, 2024 License: MIT, Unlicense Imports: 3 Imported by: 1

Documentation

Overview

Package future provides tools for scheduling asynchronous work and collecting the results synchronously from an event loop.

The main advantage of using this package over invoking goroutines manually is the structured approach this package provides to joining the results of async work to your application event loop.

Applications that are already using a bus.Connection for each window need only invoke future.TryResults on each event coming from the bus and honor the return value (invalidating the window if true) to start taking advantage of this capablility.

An example:

func eventLoop(w *app.Window, conn bus.Connection) error {
    for {
        select {
        case e := <- w.Events():
            switch e := e.(type) {
            case system.DestroyEvent:
                return e.Err
            case system.FrameEvent:
                // Draw your UI
            }
        case e := <- conn.Output():
            var changed bool
            // Do your application-specific event processing here, setting
            // changed appropriately.
            changed = future.TryResults(e) || changed
            if changed {
                w.Invalidate()
            }
        }
    }
}

So elsewhere in your UI, you can now (for example) load data from a database easily:

type UI struct {
    DB *sql.DB
    Todos []string
}

func (ui *UI) loadTodos() {
    future.Run(func() ([]string, error) {
        // This closure will execute asynchronously from the UI.
        rows, err := ui.DB.Query(`SELECT * FROM todos;`)
        if err != nil {
            return nil, err
        }
        defer rows.Close()
        var todos []string
        for rows.Next() {
            var todo string
            if err := rows.Scan(&todo); err != nil {
                return todos, err
            }
            todos=append(todos, todo)
        }
        return todos, err
    }, func(todos []string, err error) bool {
        // This closure will execute synchronously, and can safely modify UI
        // state.
        if err != nil {
            log.Println(err)
            return false
        }
        ui.Todos=todos
        return true
    })
}

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Run

func Run[T any](conn bus.Connection, work WorkFunc[T], andThen ThenFunc[T])

Run schedules work asynchronously and then invokes andThen synchronously on the event loop (when RunSync is invoked). This enables andThen to safely modify UI state because it cannot race against layout code. The most common use for this is to execute a query to a persistent storage API in work, then attach the results to the UI in andThen.

func RunCtx

func RunCtx[T any](ctx context.Context, conn bus.Connection, work WorkFuncCtx[T], andThen ThenFuncCtx[T])

RunCtx schedules work asynchronously and then invokes andThen synchronously on the event loop (when RunSync is invoked). This enables andThen to safely modify UI state because it cannot race against layout code. The most common use for this is to execute a query to a persistent storage API in work, then attach the results to the UI in andThen.

If the provided context is cancelled before the asynchronous work function starts, it will not be executed at all, and zero values will be provided to andThen.

func RunSingle

func RunSingle[T any](task *Single, conn bus.Connection, work WorkFuncCtx[T], andThen ThenFuncCtx[T])

RunSingle acts like RunSingleCtx except that it uses a default context.

func RunSingleCtx

func RunSingleCtx[T any](ctx context.Context, task *Single, conn bus.Connection, work WorkFuncCtx[T], andThen ThenFuncCtx[T])

RunSingleCtx acts like RunCtx except that it accepts a Single. Each time it is invoked, it cancels the context of any future invoked with the same Single parameter. In this way, it implements a sort of queueing, though without any guarantee about the futures not running concurrently. It is safe to invoke RunSingleCtx on the same Single from different goroutines.

func TryResults

func TryResults(event any) bool

TryResults checks if the event is a Results and invokes it synchronously if so. It returns the return value of Results.Run() if event is Results, and false otherwise.

func Update

func Update(conn bus.Connection, fn func() bool)

Update executes a closure synchronous to the event loop. This allows the caller to safely update a ui state for a given window from any goroutine.

Types

type Results

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

Results holds the results of async work completed by a future.

func (Results) Run

func (r Results) Run() bool

Run executes the synchronous handler for the future.

type Single

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

Single holds cancellation state for a running future, allowing old copies of the future to be cancelled in favor of new ones.

type ThenFunc

type ThenFunc[T any] func(T, error) bool

ThenFunc is a synchronous handler designed to process the return values of WorkFunc. It should return false if it makes no external state modifications, and true otherwise.

type ThenFuncCtx

type ThenFuncCtx[T any] func(context.Context, T, error) bool

ThenFuncCtx is a cancellable synchronous handler designed to process the return values of WorkFuncCtx. It should return false if it makes no external state modifications, and true otherwise.

type WorkFunc

type WorkFunc[T any] func() (T, error)

WorkFuncCtx is an asynchronous work function.

type WorkFuncCtx

type WorkFuncCtx[T any] func(context.Context) (T, error)

WorkFuncCtx is a cancellable asynchronous work function.

Jump to

Keyboard shortcuts

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