package x import ( "errors" "fmt" "runtime" ) // Assert evalueates a condition and if it fails, panics. func Assert(cond bool, msg string) { if !cond { panic(errors.New(msg)) } } // Check evaluates a condition, adds an error to its list and continues func Check(cond bool, err error) I { return new(invariants).Check(cond, err) } // func ExampleCheck() { // } type I interface { Check(cond bool, err error) I Join() error First() error All() []error } type invariants struct { errs []error } // Check evaluates a condition, adds an error to its list and continues func (i *invariants) Check(cond bool, err error) I { if !cond { i.errs = append(i.errs, err) } return i } // Join returns all an error wrapping all errors that have been seen by the checks func (i *invariants) Join() error { return errors.Join(i.errs...) } // First returns the first error found by the checks func (i *invariants) First() error { if len(i.errs) > 0 { return i.errs[0] } return nil } // All returns all errors found by the checks as a list of errors func (i *invariants) All() []error { return i.errs } type xError struct { LineNo int File string E error Debug bool } func (e *xError) Error() string { if e.Debug { return fmt.Sprintf( "%s\n\t%s:%d", e.E, e.File, e.LineNo, ) } return e.E.Error() } func (e *xError) Unwrap() error { return e.E } // NewError return an error that wrapped an error and optionally provides the file and line number the error occured on func NewError(unwrapped error, debug bool) error { _, file, line, ok := runtime.Caller(1) if !ok { file = "unknown" line = 0 } return &xError{ LineNo: line, File: file, E: unwrapped, Debug: debug, } }