Skip to content

Commit 8922b5d

Browse files
authored
Merge pull request #223 from bytecodealliance/ydnar/result-ergonomics
cm: improve ergonomics of Result types
2 parents 8536df2 + b1a34e1 commit 8922b5d

File tree

3 files changed

+53
-18
lines changed

3 files changed

+53
-18
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
77
### Added
88

99
- `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.
10+
- 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)`
1011

1112
### Fixed
1213

cm/result.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,16 @@ func (r *result[Shape, OK, Err]) Err() *Err {
7171
return (*Err)(unsafe.Pointer(&r.data))
7272
}
7373

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+
7484
// This function is sized so it can be inlined and optimized away.
7585
func (r *result[Shape, OK, Err]) validate() {
7686
var shape Shape

cm/result_test.go

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,48 @@ type resulter[OK, Err any] interface {
1717
IsErr() bool
1818
OK() *OK
1919
Err() *Err
20+
Result() (OK, Err, bool)
21+
}
22+
23+
func TestResultOKOrErr(t *testing.T) {
24+
r1 := OK[Result[string, string, struct{}]]("hello")
25+
if ok := r1.OK(); ok == nil {
26+
t.Errorf("OK(): %v, expected non-nil OK", ok)
27+
}
28+
if err := r1.Err(); err != nil {
29+
t.Errorf("Err(): %v, expected nil Err", err)
30+
}
31+
32+
r2 := Err[Result[bool, struct{}, bool]](true)
33+
if ok := r2.OK(); ok != nil {
34+
t.Errorf("OK(): %v, expected nil OK", ok)
35+
}
36+
if err := r2.Err(); err == nil {
37+
t.Errorf("Err(): %v, expected non-nil Err", err)
38+
}
39+
}
40+
41+
func TestResultResult(t *testing.T) {
42+
ok, err, isErr := OK[Result[string, string, int]]("hello").Result()
43+
if got, want := ok, "hello"; got != want {
44+
t.Errorf("Result(): ok = %v; expected %v", got, want)
45+
}
46+
if got, want := err, 0; got != want {
47+
t.Errorf("Result(): err = %v; expected %v", got, want)
48+
}
49+
if got, want := isErr, false; got != want {
50+
t.Errorf("Result(): isErr = %v; expected %v", got, want)
51+
}
52+
ok, err, isErr = Err[Result[string, string, int]](42).Result()
53+
if got, want := ok, ""; got != want {
54+
t.Errorf("Result(): ok = %v; expected %v", got, want)
55+
}
56+
if got, want := err, 42; got != want {
57+
t.Errorf("Result(): err = %v; expected %v", got, want)
58+
}
59+
if got, want := isErr, true; got != want {
60+
t.Errorf("Result(): isErr = %v; expected %v", got, want)
61+
}
2062
}
2163

2264
func TestResultLayout(t *testing.T) {
@@ -70,24 +112,6 @@ func TestResultLayout(t *testing.T) {
70112
}
71113
}
72114

73-
func TestResultOKOrErr(t *testing.T) {
74-
r1 := OK[Result[string, string, struct{}]]("hello")
75-
if ok := r1.OK(); ok == nil {
76-
t.Errorf("OK(): %v, expected non-nil OK", ok)
77-
}
78-
if err := r1.Err(); err != nil {
79-
t.Errorf("Err(): %v, expected nil Err", err)
80-
}
81-
82-
r2 := Err[Result[bool, struct{}, bool]](true)
83-
if ok := r2.OK(); ok != nil {
84-
t.Errorf("OK(): %v, expected nil OK", ok)
85-
}
86-
if err := r2.Err(); err == nil {
87-
t.Errorf("Err(): %v, expected non-nil Err", err)
88-
}
89-
}
90-
91115
func TestAltResult1(t *testing.T) {
92116
type alt1[Shape, OK, Err any] struct {
93117
_ [0]OK

0 commit comments

Comments
 (0)