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 ¶
- type Generator
- func BytesReader(str []byte) Generator[io.Reader]
- func Cached[T any](g Generator[T]) Generator[T]
- func Chain[I, O any](input Generator[I], f func(context.Context, I) (O, error)) Generator[O]
- func Convert[I, O any](input Generator[I], f func(I) (O, error)) Generator[O]
- func Fixed[T any](v T) Generator[T]
- func FsFile(f fs.FS, name string) Generator[fs.File]
- func G[T any](f func(context.Context) (T, error)) Generator[T]
- func Micro[T any](f func() T) Generator[T]
- func OpenFile(name string) Generator[*os.File]
- func StringReader(str string) Generator[io.Reader]
- func Tiny[T any](f func() (T, error)) Generator[T]
- func (g Generator[T]) Go(ctx context.Context) tbd.TBD[T]
- func (g Generator[T]) HandleErr(f func(error) error) Generator[T]
- func (g Generator[T]) IgnoreErr() Generator[T]
- func (g Generator[T]) IgnoreErrs(errorList ...error) Generator[T]
- func (g Generator[T]) OnlyErrs(errorList ...error) Generator[T]
- func (g Generator[T]) Retry() Generator[T]
- func (g Generator[T]) RetryN(n int) Generator[T]
- func (g Generator[T]) Run(ctx context.Context) (T, error)
- func (g Generator[T]) TBD() tbd.TBD[T]
- func (g Generator[T]) TimedFail(dur time.Duration) Generator[T]
- func (g Generator[T]) TimedFailF(f func(time.Duration) time.Duration) Generator[T]
- func (g Generator[T]) Tiny() (T, error)
- func (g Generator[T]) With(modder task.CtxMod) Generator[T]
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Generator ¶
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 ¶
BytesReader creates a micro generator which generates reader from same byte slice.
func Cached ¶ added in v0.1.1
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 ¶
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 Fixed ¶
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
FsFile wraps fs.FS.Open into a tiny generator.
func StringReader ¶
StringReader creates a micro generator which generates reader from same string.
func (Generator[T]) HandleErr ¶
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 ¶
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 ¶
IgnoreErrs ignores specific error.
func (Generator[T]) Retry ¶
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 ¶
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]) TBD ¶ added in v0.2.0
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 ¶
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 ¶
TimedFailF is like TimedFail, but use function instead.