forge

package
v0.2.3 Latest Latest
Warning

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

Go to latest
Published: Apr 17, 2024 License: MPL-2.0 Imports: 10 Imported by: 0

Documentation

Overview

Package forge defines Generator, a (maybe) cancellable funtion that generates one value on each run.

Like in task package, Tiny means the underlying function does not receives a context, and Micro is never-fail Tiny.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Generator

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

Generator much likes task.Task but it generates a new value each time.

A generator should generate n values if it is executed n times successfully. So some helpers like task.Task.Loop or task.Iter cannot applies to it.

Take a look at httptask package to see how generator makes your code more clear.

func BytesReader

func BytesReader(str []byte) Generator[io.Reader]

BytesReader creates a micro generator which generates reader from same byte slice.

func Cached added in v0.1.1

func Cached[T any](g Generator[T]) Generator[T]

Cached wraps g to cache the result, and reuse it in later call without running g.

Example
n := 0
g := G(func(_ context.Context) (int, error) {
	fmt.Print("hey! ")
	n++
	return n, nil
})
ctx := context.Background()

fmt.Println(g.Run(ctx))
fmt.Println(g.Run(ctx))
fmt.Println(g.Run(ctx))

fmt.Println()
c := Cached(g)
fmt.Println(c.Run(ctx))
fmt.Println(c.Run(ctx))

fmt.Println()
fmt.Println(g.Run(ctx))

fmt.Println()
fmt.Println(c.Run(ctx))
Output:

hey! 1 <nil>
hey! 2 <nil>
hey! 3 <nil>

hey! 4 <nil>
4 <nil>

hey! 5 <nil>

4 <nil>

func Chain

func Chain[I, O any](input Generator[I], f func(context.Context, I) (O, error)) Generator[O]

Chain creates a new Generator that generates value from input using f.

Returned generator might use different context with input:

g1 := myGenerator().With(task.Timeout(time.Second))
g2 := Chain(g1, func).With(task.Timeout(3 * time.Second))
g2.Run(ctx)

Running output.Run() will be a max 3 second timeout: The context passed to f is derived from ctx, and context passed to input is derived from the context passed to f.

Returned generator should take extra care if you want to use Generator.RetryN. If the error is returned from f, retrying will feed a new value to f, not the one leads to error. If it's not what you want, you should implement Chain-like code to fit your own need.

func Convert

func Convert[I, O any](input Generator[I], f func(I) (O, error)) Generator[O]

Convert is non-cancellable version of Chain.

func Fixed

func Fixed[T any](v T) Generator[T]

Fixed creates a micro generator that always return same value.

Example
g := Fixed(1)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

v, err := g.Run(ctx)
if err != nil {
	fmt.Println("Unexpected error: ", err)
	return
}

fmt.Println(v)
if v != 1 {
	fmt.Println("Unexpected value: ", v)
	return
}

cancel()

v, err = g.Run(ctx)
if !errors.Is(err, context.Canceled) {
	fmt.Println("Unexpected error: ", err)
	return
}

fmt.Println("context canceled")
Output:

1
context canceled

func FsFile added in v0.1.1

func FsFile(f fs.FS, name string) Generator[fs.File]

FsFile wraps fs.FS.Open into a tiny generator.

func G

func G[T any](f func(context.Context) (T, error)) Generator[T]

G is shortcut to create a generator.

func Micro

func Micro[T any](f func() T) Generator[T]

Micro wraps a never-fail, non-cancellable function into generator.

func OpenFile

func OpenFile(name string) Generator[*os.File]

OpenFile wraps os.Open into a tiny generator.

func StringReader

func StringReader(str string) Generator[io.Reader]

StringReader creates a micro generator which generates reader from same string.

func Tiny

func Tiny[T any](f func() (T, error)) Generator[T]

Tiny wraps a non-cancellable function into generator.

func (Generator[T]) Go

func (g Generator[T]) Go(ctx context.Context) tbd.TBD[T]

Go runs g in separated goroutine and returns a TBD to retrieve result.

func (Generator[T]) HandleErr

func (g Generator[T]) HandleErr(f func(error) error) Generator[T]

HandleErr creates a Generator that handles specific error after running g. It will change the error returned by Run. f is called only if g.Run returns an error.

func (Generator[T]) IgnoreErr

func (g Generator[T]) IgnoreErr() Generator[T]

IgnoreErr ignores the error returned by g.Run if it is not context error.

Context error means context.Canceled and context.DeadlineExceeded.

func (Generator[T]) IgnoreErrs

func (g Generator[T]) IgnoreErrs(errorList ...error) Generator[T]

IgnoreErrs ignores specific error.

func (Generator[T]) OnlyErrs

func (g Generator[T]) OnlyErrs(errorList ...error) Generator[T]

OnlyErrs preserves only specific error.

func (Generator[T]) Retry

func (g Generator[T]) Retry() Generator[T]

Retry creates a Generator thats repeatedly runs g with same context until it generates a value without error.

For generators created using Chain, you should take extra care.

Retrying Micro generator is resource-wasting as it never fail.

Example
ctx := context.Background()
n := 1
errTask := func(_ context.Context) (int, error) {
	fmt.Println(n)
	if n >= 3 {
		return 100, nil
	}

	n++
	return 0, errors.New("")
}

retry := G(errTask).Retry()
fu := retry.Go(ctx)
fmt.Printf("result: %d", tbd.Value(fu))
Output:

1
2
3
result: 100

func (Generator[T]) RetryN

func (g Generator[T]) RetryN(n int) Generator[T]

RetryN is like Retry, but retries no more than n times.

In other words, RetryN(2) will run at most 3 times:

  • first try
  • first retry
  • second retry

For generators created using Chain, you should take extra care.

Retrying Micro generator is resource-wasting as it never fail.

Example
ctx := context.Background()
n := 1
errTask := func(_ context.Context) (int, error) {
	fmt.Println(n)
	n++
	return 0, errors.New("")
}

retry := G(errTask).RetryN(2)
retry.Run(ctx)
Output:

1
2
3

func (Generator[T]) Run

func (g Generator[T]) Run(ctx context.Context) (T, error)

Run runs the Generator.

func (Generator[T]) TBD added in v0.2.0

func (g Generator[T]) TBD() tbd.TBD[T]

TBD creates a binded tbd.TBD that resolved by g.

It's semantically identical to following code, with bettor performance:

ret, resolve := tbd.Create[T]()
return tbd.Bind(ret, func(ctx context.Context) error {
	return resolve(g.Run(ctx))
}

func (Generator[T]) TimedFail

func (g Generator[T]) TimedFail(dur time.Duration) Generator[T]

TimedFail creates a Generator and ensures the run time is longer than dur if it failed.

It focuses on "How long I should wait before returning". Take a look at example for how it works.

Example
ctx := context.Background()
begin := time.Now()
doneTask := Generator[int](func(_ context.Context) (int, error) {
	// a task which always success
	return 1, nil
}).TimedFail(time.Second)
doneTask.Run(ctx)
fmt.Printf("done returns at +%d second\n", time.Since(begin)/time.Second)

begin = time.Now()
failTask := Generator[int](func(_ context.Context) (int, error) {
	return 0, errors.New("a task which always fail")
}).TimedFail(time.Second)
failTask.Run(ctx)
fmt.Printf("fail returns at +%d second\n", time.Since(begin)/time.Second)
Output:

done returns at +0 second
fail returns at +1 second

func (Generator[T]) TimedFailF

func (g Generator[T]) TimedFailF(f func(time.Duration) time.Duration) Generator[T]

TimedFailF is like TimedFail, but use function instead.

func (Generator[T]) Tiny added in v0.2.0

func (g Generator[T]) Tiny() (T, error)

Tiny transforms g to be a non-cancellable generator.

func (Generator[T]) With

func (g Generator[T]) With(modder task.CtxMod) Generator[T]

With creates a Generator that the context is derived using modder before running.

Jump to

Keyboard shortcuts

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