contextx

package
v0.0.0-...-c5cf874 Latest Latest
Warning

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

Go to latest
Published: May 20, 2024 License: MIT Imports: 5 Imported by: 1

Documentation

Overview

Package contextx provides extended functionality to the context package.

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrCanceled = errors.Join(context.Canceled, errors.New("contextx.Canceled"))

ErrCanceled is the cancel cause returned by Canceled.

Functions

func Anyways

func Anyways(parent context.Context, timeout time.Duration) (context.Context, context.CancelFunc)

Anyways behaves similar to context.WithTimeout. However if the context is already cancelled before Anyways is called, the returned context's Done() channel is only closed after timeout.

Example
const short = 100 * time.Millisecond

// on a non-cancelled context it just behaves like short
{
	ctx, cancel := Anyways(context.Background(), short)
	defer cancel()

	start := time.Now()
	<-ctx.Done()
	waited := time.Since(start) > short

	fmt.Println("Background() waited more than short:", waited)
}

// on a canceled context it delays the cancellation by the timeout
{
	ctx, cancel := Anyways(Canceled(), short)
	defer cancel()

	start := time.Now()
	<-ctx.Done()
	waited := time.Since(start) > short

	fmt.Println("Canceled() waited more than short:", waited)
}
Output:

Background() waited more than short: true
Canceled() waited more than short: true

func CancelRead

func CancelRead(reader io.Reader)

CancelRead attempts to cancel any in-progress and future reads on the given reader. In particular, this function sets the read deadline to the current time and closes the reader.

func CancelWrite

func CancelWrite(writer io.Writer)

CancelWrite attempts to cancel any in-progress and future writes on the given writer. In particular, this function sets the write deadline to the current time and closes the writer.

func Canceled

func Canceled() context.Context

Canceled returns a non-nil, empty Context. It has no deadline, has no values, and is already canceled. The cancel cause is ErrCanceled.

Canceled may or may not return the same context for different invocations.

Example
ctx := Canceled()

select {
case <-ctx.Done():
	fmt.Println("context was canceled")
default:
	fmt.Println("context was not canceled")
}
Output:

context was canceled

func Copy

func Copy(ctx context.Context, dst io.Writer, src io.Reader) (written int64, err error)

Copy copies from src to dst, stopping once ctx is closed. See io.Copy() for a description of the copy behavior.

The operation is cancelled by closing the src and destination (if they support the Close() interface). Futhermore appropriate read and write deadlines are set. Either of these calls may not have any effect, depending on the underlying operation.

func Run

func Run[T any](ctx context.Context, f func(start func()) T, cancel func()) (t T, err error)

Run adds context-like functionality to a function that only supports explicit cancellation functionality.

In principle, it calls f and returns the provided returns f(), nil. If the context is cancelled before f returns, Run instead invokes cancel and returns f(), ctx.Err().

f can control at which point cancellation may occur. It must call start as soon as cancel may be called.

Calling start multiple times or not at all is also permitted. However these use-cases should be carefully considered. In cases where start is not called, cancel will never be called, regardless of when ctx is cancelled. In cases where start is called multiple times, cancel may be invoked immediately after the first invocation.

Run always waits for f to return, and always returns the return value of f as the first argument, even if cancel is called.

Example
// for this example, we create a "work" function that runs until the cancel function is called.
var work func() int
var cancel func()
{
	done := make(chan struct{})

	work = func() int {
		fmt.Println("start working")
		<-done
		fmt.Println("done working")
		return 42
	}
	cancel = func() {
		fmt.Println("cancel called")
		close(done)
	}
}

// create a context that is stopped after 100 milliseconds
ctx, ctxCancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer ctxCancel()

// and run the function with the context and explicit cancel!
result, err := Run(ctx, func(start func()) int {
	start() // allow calling cancel immediately!

	// start the work!
	return work()
}, cancel)

fmt.Println(result, err)
Output:

start working
cancel called
done working
42 context deadline exceeded

func Run2

func Run2[T1, T2 any](ctx context.Context, f func(start func()) (T1, T2), cancel func()) (t1 T1, t2 T2, err error)

Run2 behaves exactly like Run, except that it allows f to return two values.

func WithValues

func WithValues(parent context.Context, values map[any]any) context.Context

WithValues creates a new context that inherits from parent, but has associated values from values.

This function is equivalent to repeated invocations of context.WithValue. See the appropriate documentation for details on restrictions of keys and values to be used.

Example
// create a background context without any values
original := context.Background()

// add two values to it!
derived := WithValues(original, map[any]any{
	oneContextKey: "hello earth",
	twoContextKey: "hello mars",
})

// we just set these above
fmt.Println(derived.Value(oneContextKey))
fmt.Println(derived.Value(twoContextKey))

// this context key has nothing associated with it
fmt.Println(derived.Value(threeContextKey))
Output:

hello earth
hello mars
<nil>

func WithValuesOf

func WithValuesOf(parent, values context.Context) context.Context

WithValuesOf creates a new context that inherits from parent, but values stored in values take precedence over already associated values. If a value is not found in values, the parent context is searched. For explicitly associating a specific map of values see WithValues.

Example
// create a primary context with 'hello' values.
// Note that we only fill '1' and '2' here.
primary := WithValues(context.Background(), map[any]any{
	oneContextKey: "hello earth",
	twoContextKey: "hello mars",
})

// create a secondary context with 'bye' values
// note that we only fill '2' and '3' here.
secondary := WithValues(context.Background(), map[any]any{
	twoContextKey:   "bye mars",
	threeContextKey: "bye venus",
})

// now creates a derived context that overrides the values of primary with secondary.
derived := WithValuesOf(primary, secondary)

// found only in primary
fmt.Println(derived.Value(oneContextKey))

// found in both, the secondary overrides
fmt.Println(derived.Value(twoContextKey))

// found only in secondary
fmt.Println(derived.Value(threeContextKey))

// found in neither
fmt.Println(derived.Value(fourContextKey))
Output:

hello earth
bye mars
bye venus
<nil>

Types

This section is empty.

Jump to

Keyboard shortcuts

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