result.mx raw

   1  package cm
   2  
   3  import "unsafe"
   4  
   5  const (
   6  	// ResultOK represents the OK case of a result.
   7  	ResultOK = false
   8  
   9  	// ResultErr represents the error case of a result.
  10  	ResultErr = true
  11  )
  12  
  13  // BoolResult represents a result with no OK or error type.
  14  // False represents the OK case and true represents the error case.
  15  type BoolResult bool
  16  
  17  // Result represents a result sized to hold the Shape type.
  18  // The size of the Shape type must be greater than or equal to the size of OK and Err types.
  19  // For results with two zero-length types, use [BoolResult].
  20  type Result[Shape, OK, Err any] struct {
  21  	_ HostLayout
  22  	result[Shape, OK, Err]
  23  }
  24  
  25  // AnyResult is a type constraint for generic functions that accept any [Result] type.
  26  type AnyResult[Shape, OK, Err any] interface {
  27  	~struct {
  28  		_ HostLayout
  29  		result[Shape, OK, Err]
  30  	}
  31  }
  32  
  33  // result represents the internal representation of a Component Model result type.
  34  type result[Shape, OK, Err any] struct {
  35  	_     HostLayout
  36  	isErr bool
  37  	_     [0]OK
  38  	_     [0]Err
  39  	data  Shape // [unsafe.Sizeof(*(*Shape)(unsafe.Pointer(nil)))]byte
  40  }
  41  
  42  // IsOK returns true if r represents the OK case.
  43  func (r *result[Shape, OK, Err]) IsOK() bool {
  44  	r.validate()
  45  	return !r.isErr
  46  }
  47  
  48  // IsErr returns true if r represents the error case.
  49  func (r *result[Shape, OK, Err]) IsErr() bool {
  50  	r.validate()
  51  	return r.isErr
  52  }
  53  
  54  // OK returns a non-nil *OK pointer if r represents the OK case.
  55  // If r represents an error, then it returns nil.
  56  func (r *result[Shape, OK, Err]) OK() *OK {
  57  	r.validate()
  58  	if r.isErr {
  59  		return nil
  60  	}
  61  	return (*OK)(unsafe.Pointer(&r.data))
  62  }
  63  
  64  // Err returns a non-nil *Err pointer if r represents the error case.
  65  // If r represents the OK case, then it returns nil.
  66  func (r *result[Shape, OK, Err]) Err() *Err {
  67  	r.validate()
  68  	if !r.isErr {
  69  		return nil
  70  	}
  71  	return (*Err)(unsafe.Pointer(&r.data))
  72  }
  73  
  74  // Result returns (OK, zero value of Err, false) if r represents the OK case,
  75  // or (zero value of OK, Err, true) if r represents the error case.
  76  // This does not have a pointer receiver, so it can be chained.
  77  func (r result[Shape, OK, Err]) Result() (ok OK, err Err, isErr bool) {
  78  	if r.isErr {
  79  		return ok, *(*Err)(unsafe.Pointer(&r.data)), true
  80  	}
  81  	return *(*OK)(unsafe.Pointer(&r.data)), err, false
  82  }
  83  
  84  // This function is sized so it can be inlined and optimized away.
  85  func (r *result[Shape, OK, Err]) validate() {
  86  	var shape Shape
  87  	var ok OK
  88  	var err Err
  89  
  90  	// Check if size of Shape is greater than both OK and Err
  91  	if unsafe.Sizeof(shape) > unsafe.Sizeof(ok) && unsafe.Sizeof(shape) > unsafe.Sizeof(err) {
  92  		panic("result: size of data type > OK and Err types")
  93  	}
  94  
  95  	// Check if size of OK is greater than Shape
  96  	if unsafe.Sizeof(ok) > unsafe.Sizeof(shape) {
  97  		panic("result: size of OK type > data type")
  98  	}
  99  
 100  	// Check if size of Err is greater than Shape
 101  	if unsafe.Sizeof(err) > unsafe.Sizeof(shape) {
 102  		panic("result: size of Err type > data type")
 103  	}
 104  
 105  	// Check if Shape is zero-sized, but size of result != 1
 106  	if unsafe.Sizeof(shape) == 0 && unsafe.Sizeof(*r) != 1 {
 107  		panic("result: size of data type == 0, but result size != 1")
 108  	}
 109  }
 110  
 111  // OK returns an OK result with shape Shape and type OK and Err.
 112  // Pass Result[OK, OK, Err] or Result[Err, OK, Err] as the first type argument.
 113  func OK[R AnyResult[Shape, OK, Err], Shape, OK, Err any](ok OK) R {
 114  	var r Result[Shape, OK, Err]
 115  	r.validate()
 116  	r.isErr = ResultOK
 117  	*((*OK)(unsafe.Pointer(&r.data))) = ok
 118  	return R(r)
 119  }
 120  
 121  // Err returns an error result with shape Shape and type OK and Err.
 122  // Pass Result[OK, OK, Err] or Result[Err, OK, Err] as the first type argument.
 123  func Err[R AnyResult[Shape, OK, Err], Shape, OK, Err any](err Err) R {
 124  	var r Result[Shape, OK, Err]
 125  	r.validate()
 126  	r.isErr = ResultErr
 127  	*((*Err)(unsafe.Pointer(&r.data))) = err
 128  	return R(r)
 129  }
 130