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

     1  package schema
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"github.com/storacha/go-ucanto/core/result/failure"
     9  )
    10  
    11  type unionError struct {
    12  	failures []failure.Failure
    13  }
    14  
    15  func (ue unionError) Unwrap() []error {
    16  	errors := make([]error, 0, len(ue.failures))
    17  	for _, failure := range ue.failures {
    18  		errors = append(errors, failure)
    19  	}
    20  	return errors
    21  }
    22  
    23  func indent(message string) string {
    24  	indent := "  "
    25  	return indent + strings.Join(strings.Split(message, "\n"), "\n"+indent)
    26  }
    27  
    28  func li(message string) string {
    29  	return indent("- " + message)
    30  }
    31  
    32  func (ue unionError) Error() string {
    33  	return fmt.Sprintf("Value does not match any type of the union:\n%s", li(errors.Join(ue.Unwrap()...).Error()))
    34  }
    35  
    36  func (ue unionError) Name() string {
    37  	return "Union Error"
    38  }
    39  
    40  type orReader[I, O any] struct {
    41  	readers []Reader[I, O]
    42  }
    43  
    44  func (or orReader[I, O]) Read(input I) (O, failure.Failure) {
    45  	failures := make([]failure.Failure, 0, len(or.readers))
    46  	for _, reader := range or.readers {
    47  		o, err := reader.Read(input)
    48  		if err != nil {
    49  			failures = append(failures, err)
    50  		} else {
    51  			return o, nil
    52  		}
    53  	}
    54  	var o O
    55  	return o, failure.FromError(unionError{failures: failures})
    56  }
    57  
    58  func Or[I, O any](readers ...Reader[I, O]) Reader[I, O] {
    59  	return orReader[I, O]{readers}
    60  }