Skip to content

Instantly share code, notes, and snippets.

@r13l
Created June 6, 2019 15:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save r13l/2911f93cbe66fb4ed50f9d9eb1eb252e to your computer and use it in GitHub Desktop.
Save r13l/2911f93cbe66fb4ed50f9d9eb1eb252e to your computer and use it in GitHub Desktop.
Primitive condition system in Go
package main
import (
"context"
"errors"
"fmt"
"log"
)
type handler func(ctx context.Context, err error)
type handlerRecord struct {
handler handler
prev *handlerRecord
}
func (h handlerRecord) signal(ctx context.Context, err error) {
if h.handler != nil {
h.handler(ctx, err)
}
if h.prev != nil {
h.prev.signal(ctx, err)
}
}
type key int
const handlerKey key = 0
func withHandler(ctx context.Context, h handler) context.Context {
record, _ := ctx.Value(handlerKey).(*handlerRecord)
return context.WithValue(ctx, handlerKey, &handlerRecord{h, record})
}
func signal(ctx context.Context, err error) {
record, ok := ctx.Value(handlerKey).(*handlerRecord)
if ok {
record.signal(ctx, err)
}
panic(fmt.Sprintln("error signaled but not handled:", err))
}
type restart func(context.Context, []interface{})
type restartRecord struct {
name string
restart restart
prev *restartRecord
}
func (r restartRecord) invoke(ctx context.Context, name string, args ...interface{}) {
if name == r.name && r.restart != nil {
r.restart(ctx, args)
}
if r.prev != nil {
r.prev.invoke(ctx, name, args...)
}
}
const restartKey key = 1
func runWithRestart(ctx context.Context, name string, r restart, f func(context.Context)) {
v := new(int)
defer func() {
p := recover()
if p != nil && p != v {
panic(p)
}
}()
rr := func(ctx context.Context, args []interface{}) {
r(ctx, args)
panic(v)
}
record, _ := ctx.Value(restartKey).(*restartRecord)
ctx = context.WithValue(ctx, restartKey, &restartRecord{name, rr, record})
f(ctx)
}
func invokeRestart(ctx context.Context, name string, args ...interface{}) {
record, ok := ctx.Value(restartKey).(*restartRecord)
if ok {
record.invoke(ctx, name, args)
}
}
func main() {
ctx := withHandler(context.Background(), func(ctx context.Context, err error) {
invokeRestart(ctx, "abort", err)
})
var v int
// this will succeed, because the error is handled and restarted
runWithRestart(ctx, "abort", func(ctx context.Context, args []interface{}) {
v = 2
log.Println("aborted:", args)
}, func(ctx context.Context) {
foo(ctx)
})
log.Println(v) // note that abort was called
// this will succeed, because no error is signaled
runWithRestart(ctx, "abort", func(ctx context.Context, args []interface{}) {
v = 3
log.Println("aborted:", args)
}, func(ctx context.Context) {
bar(ctx)
})
log.Println(v) // note that the abort restart was never called
// this will crash because the error is not handled
runWithRestart(ctx, "some-other-handler", func(ctx context.Context, args []interface{}) {
log.Println("handled some other way:", args)
}, func(ctx context.Context) {
foo(ctx)
})
}
func foo(ctx context.Context) {
signal(ctx, errors.New("some bad error"))
}
func bar(ctx context.Context) {
// note no signal
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment