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

     1  package failure
     2  
     3  import (
     4  	"fmt"
     5  	"runtime"
     6  
     7  	"github.com/pkg/errors"
     8  	"github.com/storacha/go-ucanto/core/ipld"
     9  	"github.com/storacha/go-ucanto/core/result/failure/datamodel"
    10  )
    11  
    12  // Named is an error that you can read a name from
    13  type Named interface {
    14  	Name() string
    15  }
    16  
    17  // WithStackTrace is an error that you can read a stack trace from
    18  type WithStackTrace interface {
    19  	Stack() string
    20  }
    21  
    22  // IPLDConvertableError is an error with a custom method to convert to an IPLD Node
    23  type IPLDConvertableError interface {
    24  	error
    25  	ipld.Builder
    26  }
    27  
    28  type Failure interface {
    29  	error
    30  	Named
    31  }
    32  
    33  type IPLDBuilderFailure interface {
    34  	IPLDConvertableError
    35  	Failure
    36  }
    37  
    38  type NamedWithStackTrace interface {
    39  	Named
    40  	WithStackTrace
    41  }
    42  
    43  type namedWithStackTrace struct {
    44  	name  string
    45  	stack errors.StackTrace
    46  }
    47  
    48  func (n namedWithStackTrace) Name() string {
    49  	return n.name
    50  }
    51  
    52  func (n namedWithStackTrace) Stack() string {
    53  	return fmt.Sprintf("%+v", n.stack)
    54  }
    55  
    56  func NamedWithCurrentStackTrace(name string) NamedWithStackTrace {
    57  	const depth = 32
    58  
    59  	var pcs [depth]uintptr
    60  	n := runtime.Callers(3, pcs[:])
    61  
    62  	f := make(errors.StackTrace, n)
    63  	for i := 0; i < n; i++ {
    64  		f[i] = errors.Frame(pcs[i])
    65  	}
    66  
    67  	return namedWithStackTrace{name, f}
    68  }
    69  
    70  type failure struct {
    71  	model  datamodel.FailureModel
    72  	toIPLD func() (ipld.Node, error)
    73  }
    74  
    75  func (f failure) Name() string {
    76  	if f.model.Name == nil {
    77  		return ""
    78  	}
    79  	return *f.model.Name
    80  }
    81  
    82  func (f failure) Message() string {
    83  	return f.model.Message
    84  }
    85  
    86  func (f failure) Error() string {
    87  	return f.model.Message
    88  }
    89  
    90  func (f failure) Stack() string {
    91  	if f.model.Stack == nil {
    92  		return ""
    93  	}
    94  	return *f.model.Stack
    95  }
    96  
    97  func (f failure) ToIPLD() (ipld.Node, error) {
    98  	if f.toIPLD != nil {
    99  		return f.toIPLD()
   100  	}
   101  	return f.model.ToIPLD()
   102  }
   103  
   104  func FromError(err error) IPLDBuilderFailure {
   105  	model := datamodel.FailureModel{Message: err.Error()}
   106  	if named, ok := err.(Named); ok {
   107  		name := named.Name()
   108  		model.Name = &name
   109  	}
   110  	if withStackTrace, ok := err.(WithStackTrace); ok {
   111  		stack := withStackTrace.Stack()
   112  		model.Stack = &stack
   113  	}
   114  	fail := failure{model: model}
   115  	if builder, ok := err.(ipld.Builder); ok {
   116  		fail.toIPLD = builder.ToIPLD
   117  	}
   118  	return fail
   119  }
   120  
   121  func FromFailureModel(model datamodel.FailureModel) IPLDBuilderFailure {
   122  	// treat a zero value failure as a non-error
   123  	if (model == datamodel.FailureModel{}) {
   124  		return nil
   125  	}
   126  	return failure{model: model}
   127  }