123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- package gott
- import (
- "fmt"
- "log"
- "reflect"
- "runtime"
- )
- type LogLevel int
- const (
- Quiet LogLevel = iota
- Error
- Debug
- Info
- )
- func fnName(fn interface{}) string {
- return runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name()
- }
- func logErr(e error, fn interface{}) {
- log.Printf("Function %s returned error: %v\n", fnName(fn), e)
- }
- func logMsg(msg string, fn interface{}) {
- log.Printf("%s %s\n", msg, fnName(fn))
- }
- type Exception struct {
- E interface{}
- }
- func (e Exception) Error() string {
- return fmt.Sprintf("function panicked with %v", e.E)
- }
- type R[T any] struct {
- S T
- E error
- LogLevel LogLevel
- }
- func (r R[T]) Bind(f func(T) (T, error)) R[T] {
- if r.E == nil {
- if r.LogLevel >= Debug {
- logMsg("running:", f)
- }
- r.S, r.E = f(r.S)
- if r.E != nil {
- if r.LogLevel >= Error {
- logErr(r.E, f)
- }
- r.E = fmt.Errorf("while running %s: %w", fnName(f), r.E)
- }
- } else {
- if r.LogLevel >= Info {
- logMsg("skipping:", f)
- }
- }
- return r
- }
- func (r R[T]) Map(f func(T) T) R[T] {
- if r.E == nil {
- if r.LogLevel >= Debug {
- logMsg("running:", f)
- }
- r.S = f(r.S)
- } else {
- if r.LogLevel >= Info {
- logMsg("skipping:", f)
- }
- }
- return r
- }
- func (r R[T]) Tee(f func(T) error) R[T] {
- if r.E == nil {
- if r.LogLevel >= Debug {
- logMsg("running:", f)
- }
- r.E = f(r.S)
- if r.E != nil {
- if r.LogLevel >= Error {
- logErr(r.E, f)
- }
- r.E = fmt.Errorf("while running %s: %w", fnName(f), r.E)
- }
- } else {
- if r.LogLevel >= Info {
- logMsg("skipping:", f)
- }
- }
- return r
- }
- func (r R[T]) SafeTee(f func(T)) R[T] {
- if r.E == nil {
- if r.LogLevel >= Debug {
- logMsg("running:", f)
- }
- f(r.S)
- } else {
- if r.LogLevel >= Info {
- logMsg("skipping:", f)
- }
- }
- return r
- }
- func (r R[T]) Catch(f func(T) T) (r2 R[T]) {
- r2 = r
- if r2.E == nil {
- if r2.LogLevel >= Debug {
- logMsg("running:", f)
- }
- defer func() {
- if err := recover(); err != nil {
- if r2.LogLevel >= Error {
- logErr(Exception{err}, f)
- }
- r2.E = fmt.Errorf("while running %s: %w", fnName(f), Exception{err})
- }
- }()
- r2.S = f(r.S)
- } else {
- if r.LogLevel >= Info {
- logMsg("skipping:", f)
- }
- }
- return
- }
- func (r R[T]) Recover(f func(T, error) (T, error)) R[T] {
- if r.E != nil {
- if r.LogLevel >= Debug {
- logMsg("running:", f)
- }
- r.S, r.E = f(r.S, r.E)
- if r.E != nil {
- if r.LogLevel >= Error {
- logErr(r.E, f)
- }
- r.E = fmt.Errorf("while running %s: %w", fnName(f), r.E)
- }
- } else {
- if r.LogLevel >= Info {
- logMsg("skipping:", f)
- }
- }
- return r
- }
- func (r R[T]) Handle(onSuccess func(T), onError func(error)) R[T] {
- if r.E == nil {
- if r.LogLevel >= Debug {
- logMsg("running:", onSuccess)
- }
- onSuccess(r.S)
- } else {
- if r.LogLevel >= Debug {
- logMsg("running:", onError)
- }
- onError(r.E)
- }
- return r
- }
|