Skip to content

Commit

Permalink
Merge pull request #223 from bytecodealliance/ydnar/result-ergonomics
Browse files Browse the repository at this point in the history
cm: improve ergonomics of Result types
  • Loading branch information
ydnar authored Nov 1, 2024
2 parents 8536df2 + b1a34e1 commit 8922b5d
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 18 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
### Added

- `wit-bindgen-go` now accepts arguments that control the level of logging output on stderr. Verbose mode (`-v` or `--verbose`) will print informational log lines, warnings, and errors. Debug mode (`-vv` or `--debug`) will emit finer-grained debugging information. By default, `wit-bindgen-go` will print warnings or errors.
- New method `(cm.Result).Result() (ok OK, err Err, isErr bool)` added to streamline common patterns using `result` types. It has a value receiver, allowing it to be chained off a function call that returns a `Result`, eliminating the need to declare a temporary variable. For example: `stream, err, isErr := stream.BlockingRead(n)`

### Fixed

Expand Down
10 changes: 10 additions & 0 deletions cm/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,16 @@ func (r *result[Shape, OK, Err]) Err() *Err {
return (*Err)(unsafe.Pointer(&r.data))
}

// Result returns (OK, zero value of Err, false) if r represents the OK case,
// or (zero value of OK, Err, true) if r represents the error case.
// This does not have a pointer receiver, so it can be chained.
func (r result[Shape, OK, Err]) Result() (ok OK, err Err, isErr bool) {
if r.isErr {
return ok, *(*Err)(unsafe.Pointer(&r.data)), true
}
return *(*OK)(unsafe.Pointer(&r.data)), err, false
}

// This function is sized so it can be inlined and optimized away.
func (r *result[Shape, OK, Err]) validate() {
var shape Shape
Expand Down
60 changes: 42 additions & 18 deletions cm/result_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,48 @@ type resulter[OK, Err any] interface {
IsErr() bool
OK() *OK
Err() *Err
Result() (OK, Err, bool)
}

func TestResultOKOrErr(t *testing.T) {
r1 := OK[Result[string, string, struct{}]]("hello")
if ok := r1.OK(); ok == nil {
t.Errorf("OK(): %v, expected non-nil OK", ok)
}
if err := r1.Err(); err != nil {
t.Errorf("Err(): %v, expected nil Err", err)
}

r2 := Err[Result[bool, struct{}, bool]](true)
if ok := r2.OK(); ok != nil {
t.Errorf("OK(): %v, expected nil OK", ok)
}
if err := r2.Err(); err == nil {
t.Errorf("Err(): %v, expected non-nil Err", err)
}
}

func TestResultResult(t *testing.T) {
ok, err, isErr := OK[Result[string, string, int]]("hello").Result()
if got, want := ok, "hello"; got != want {
t.Errorf("Result(): ok = %v; expected %v", got, want)
}
if got, want := err, 0; got != want {
t.Errorf("Result(): err = %v; expected %v", got, want)
}
if got, want := isErr, false; got != want {
t.Errorf("Result(): isErr = %v; expected %v", got, want)
}
ok, err, isErr = Err[Result[string, string, int]](42).Result()
if got, want := ok, ""; got != want {
t.Errorf("Result(): ok = %v; expected %v", got, want)
}
if got, want := err, 42; got != want {
t.Errorf("Result(): err = %v; expected %v", got, want)
}
if got, want := isErr, true; got != want {
t.Errorf("Result(): isErr = %v; expected %v", got, want)
}
}

func TestResultLayout(t *testing.T) {
Expand Down Expand Up @@ -70,24 +112,6 @@ func TestResultLayout(t *testing.T) {
}
}

func TestResultOKOrErr(t *testing.T) {
r1 := OK[Result[string, string, struct{}]]("hello")
if ok := r1.OK(); ok == nil {
t.Errorf("OK(): %v, expected non-nil OK", ok)
}
if err := r1.Err(); err != nil {
t.Errorf("Err(): %v, expected nil Err", err)
}

r2 := Err[Result[bool, struct{}, bool]](true)
if ok := r2.OK(); ok != nil {
t.Errorf("OK(): %v, expected nil OK", ok)
}
if err := r2.Err(); err == nil {
t.Errorf("Err(): %v, expected non-nil Err", err)
}
}

func TestAltResult1(t *testing.T) {
type alt1[Shape, OK, Err any] struct {
_ [0]OK
Expand Down

0 comments on commit 8922b5d

Please sign in to comment.