github.com/storacha/go-ucanto@v0.7.2/core/result/result.go (about)

     1  package result
     2  
     3  import (
     4  	"github.com/storacha/go-ucanto/core/ipld"
     5  	"github.com/storacha/go-ucanto/core/result/failure"
     6  	"github.com/storacha/go-ucanto/core/result/failure/datamodel"
     7  )
     8  
     9  // Result is a golang compatible generic result type
    10  type Result[O any, X any] interface {
    11  	isResult(ok O, err X)
    12  }
    13  
    14  type okResult[O any, X any] struct {
    15  	value O
    16  }
    17  type errResult[O any, X any] struct {
    18  	value X
    19  }
    20  
    21  func (o *okResult[O, X]) isResult(ok O, err X)  {}
    22  func (e *errResult[O, X]) isResult(ok O, err X) {}
    23  
    24  // MatchResultR3 handles a result with functions returning 3 values
    25  func MatchResultR3[O any, X any, R0, R1, R2 any](
    26  	result Result[O, X],
    27  	onOk func(ok O) (R0, R1, R2),
    28  	onError func(err X) (R0, R1, R2),
    29  ) (R0, R1, R2) {
    30  	switch v := result.(type) {
    31  	case *okResult[O, X]:
    32  		return onOk(v.value)
    33  	case *errResult[O, X]:
    34  		return onError(v.value)
    35  	default:
    36  		panic("unexpected result type")
    37  	}
    38  }
    39  
    40  // MatchResultR2 handles a result with functions returning two values
    41  func MatchResultR2[O any, X any, R0, R1 any](
    42  	result Result[O, X],
    43  	onOk func(ok O) (R0, R1),
    44  	onError func(err X) (R0, R1),
    45  ) (R0, R1) {
    46  	switch v := result.(type) {
    47  	case *okResult[O, X]:
    48  		return onOk(v.value)
    49  	case *errResult[O, X]:
    50  		return onError(v.value)
    51  	default:
    52  		panic("unexpected result type")
    53  	}
    54  }
    55  
    56  // MatchResultR1 handles a result with functions returning one value
    57  func MatchResultR1[O any, X any, T0 any](
    58  	result Result[O, X],
    59  	onOk func(ok O) T0,
    60  	onError func(err X) T0,
    61  ) T0 {
    62  	switch v := result.(type) {
    63  	case *okResult[O, X]:
    64  		return onOk(v.value)
    65  	case *errResult[O, X]:
    66  		return onError(v.value)
    67  	default:
    68  		panic("unexpected result type")
    69  	}
    70  }
    71  
    72  // MatchResultR1 handles a result with a functions that has no return value
    73  func MatchResultR0[O any, X any](
    74  	result Result[O, X],
    75  	onOk func(ok O),
    76  	onError func(err X),
    77  ) {
    78  	switch v := result.(type) {
    79  	case *okResult[O, X]:
    80  		onOk(v.value)
    81  	case *errResult[O, X]:
    82  		onError(v.value)
    83  	default:
    84  		panic("unexpected result type")
    85  	}
    86  }
    87  
    88  // Ok returns a success result type
    89  func Ok[O, X any](value O) Result[O, X] {
    90  	return &okResult[O, X]{value}
    91  }
    92  
    93  // Error returns an error result type
    94  func Error[O, X any](value X) Result[O, X] {
    95  	return &errResult[O, X]{value}
    96  }
    97  
    98  // MapOk transforms a successful result while leaving an error result unchanged
    99  func MapOk[O, X, O2 any](result Result[O, X], mapFn func(O) O2) Result[O2, X] {
   100  	return MapResultR0(result, mapFn, func(err X) X { return err })
   101  }
   102  
   103  // MapError transforms an error result while leaving a success result unchanged
   104  func MapError[O, X, X2 any](result Result[O, X], mapFn func(X) X2) Result[O, X2] {
   105  	return MapResultR0(result, func(ok O) O { return ok }, mapFn)
   106  }
   107  
   108  // MapResultR0 transforms a result --
   109  // with seperate functions to modify both the success type and error type
   110  func MapResultR0[O, X, O2, X2 any](result Result[O, X], mapOkFn func(O) O2, mapErrFn func(X) X2) Result[O2, X2] {
   111  	return MatchResultR1(result, func(ok O) Result[O2, X2] {
   112  		return Ok[O2, X2](mapOkFn(ok))
   113  	}, func(err X) Result[O2, X2] {
   114  		return Error[O2, X2](mapErrFn(err))
   115  	})
   116  }
   117  
   118  // MapResultR1 transforms a result --
   119  // with seperate functions to modify both the success type and error type that also returna one additional value
   120  func MapResultR1[O, X, O2, X2, R1 any](result Result[O, X], mapOkFn func(O) (O2, R1), mapErrFn func(X) (X2, R1)) (Result[O2, X2], R1) {
   121  	return MatchResultR2(result, func(ok O) (Result[O2, X2], R1) {
   122  		ok2, r1 := mapOkFn(ok)
   123  		return Ok[O2, X2](ok2), r1
   124  	}, func(err X) (Result[O2, X2], R1) {
   125  		err2, r1 := mapErrFn(err)
   126  		return Error[O2, X2](err2), r1
   127  	})
   128  }
   129  
   130  // And treats a result as a boolean, returning the second result only if the
   131  // the first is succcessful
   132  func And[O, O2, X any](res1 Result[O, X], res2 Result[O2, X]) Result[O2, X] {
   133  	return AndThen(res1, func(_ O) Result[O2, X] { return res2 })
   134  }
   135  
   136  // AndThen takes a result and if it is success type,
   137  // runs an additional function that returns a subsequent result type
   138  func AndThen[O, X, O2 any](result Result[O, X], thenFunc func(O) Result[O2, X]) Result[O2, X] {
   139  	return MatchResultR1(result, func(ok O) Result[O2, X] {
   140  		return thenFunc(ok)
   141  	}, func(err X) Result[O2, X] {
   142  		return Error[O2, X](err)
   143  	})
   144  }
   145  
   146  // Or treats a result as a boolean, returning the second result if the first
   147  // result is an error
   148  func Or[O, X, X2 any](res1 Result[O, X], res2 Result[O, X2]) Result[O, X2] {
   149  	return OrElse(res1, func(err X) Result[O, X2] { return res2 })
   150  }
   151  
   152  // OrElse takes a result and if it is an error type,
   153  // runs an additional function that returns a subsequent result type
   154  func OrElse[O, X, X2 any](result Result[O, X], elseFunc func(X) Result[O, X2]) Result[O, X2] {
   155  	return MatchResultR1(result, func(ok O) Result[O, X2] {
   156  		return Ok[O, X2](ok)
   157  	}, func(err X) Result[O, X2] {
   158  		return elseFunc(err)
   159  	})
   160  }
   161  
   162  // Wrap wraps a traditional golang pattern for two value functions with the
   163  // second being an error where the zero value indicates absence, converting
   164  // it to a result
   165  func Wrap[O any, X comparable](inner func() (O, X)) Result[O, X] {
   166  	o, err := inner()
   167  	var nilErr X
   168  	if err != nilErr {
   169  		return Error[O, X](err)
   170  	}
   171  	return Ok[O, X](o)
   172  }
   173  
   174  func Unwrap[O any, X any](result Result[O, X]) (O, X) {
   175  	return MatchResultR2(result, func(ok O) (O, X) {
   176  		var err X
   177  		return ok, err
   178  	}, func(err X) (O, X) {
   179  		var ok O
   180  		return ok, err
   181  	})
   182  }
   183  
   184  func NewFailure(err error) Result[ipld.Builder, ipld.Builder] {
   185  	if ipldConvertableError, ok := err.(failure.IPLDConvertableError); ok {
   186  		return Error[ipld.Builder, ipld.Builder](ipldConvertableError)
   187  	}
   188  
   189  	model := datamodel.FailureModel{Message: err.Error()}
   190  	if named, ok := err.(failure.Named); ok {
   191  		name := named.Name()
   192  		model.Name = &name
   193  	}
   194  	if withStackTrace, ok := err.(failure.WithStackTrace); ok {
   195  		stack := withStackTrace.Stack()
   196  		model.Stack = &stack
   197  	}
   198  	return Error[ipld.Builder, ipld.Builder](&model)
   199  }
   200  
   201  // https://en.wikipedia.org/wiki/Unit_type
   202  type Unit interface{}