Commits

Daniel Smith committed 09bea73

More error helpers, add Try function, and more comments.

  • Participants
  • Parent commits e973ecc

Comments (0)

Files changed (2)

 import (
 	"runtime"
 	"fmt"
+	"errors"
 )
 
 //HelpfulError includes a base error and some context from the call stack.
 	//base error
 	Err error
 
+	//ErrChainf will produce/add to the comentary here.
+	Commentary string
+
 	//A few lines of the call stack so you can figure out where
 	//the hell your error came from
 	Context string
 }
 
 func (he HelpfulError) Error() string {
-	return he.Err.Error() + " <" + he.Context + ">"
+	if len(he.Commentary) == 0 {
+		return he.Err.Error() + "\n<callstack:\n" + he.Context + "\n>"
+	}
+	return fmt.Sprintf("%s\n<commentary:\n%s\ncallstack:\n%s\n>", 
+		he.Err.Error(), he.Commentary, he.Context)
 }
 
 //Error makes a HelpfulError out of err. If err is nil, it returns nil.
 	}
 }
 
+//Errorf returns a new error with the given formatted message, plus a call
+//stack for context.
+func Errorf(format string, vargs ...interface{}) error {
+	return HelpfulError{
+		Err: errors.New(fmt.Sprintf(format, vargs...)),
+		Context: CallStackToString(3),
+	}
+}
+
+//ErrChainf returns an error with your commentary and a callstack.
+//If err is already a helpful error, it adds your commentary but
+//doesn't replace the base error or the callstack. If err is nil,
+//it returns nil and ignores your commentary.
+func ErrChainf(err error, format string, vargs ...interface{}) error {
+	if err == nil {
+		return nil
+	}
+	comments := fmt.Sprintf(format, vargs...)
+	if he, ok := err.(HelpfulError); ok {
+		he.Commentary += comments + "\n"
+		return he
+	}
+
+	return HelpfulError{
+		Err: err,
+		Commentary: comments + "\n",
+		Context: CallStackToString(3),
+	}
+}
+
+
 //CallStackToString returns the callstack as a string. For nice error 
 //or panic messages. Probably you want to skip one or two frames, at least.
 func CallStackToString(skipFrames int) (str string) {
 	"reflect"
 )
 
+type EasyIO interface {
+	//Try will call f (if no error has been recorded already) and record
+	//its return error, if any. If f calls additional functions on the 
+	//EasyIO object which error out and then returns nil, the EasyIO 
+	//object is smart enough to not overwrite its error with nil, but
+	//I still recommend that you don't get into that habbit.
+	Try(f func() error)
+
+	//Err will return the error that things stopped at
+	Err() error
+
+	//Close will close the underlying writer iff it is an io.WriteCloser
+	Close() error
+}
+
 type Writer interface {
+	//PutUnsigned writes item as an unsigned varint
 	PutUnsigned(item interface{})
+	//PutSigned writes item as a varint
 	PutSigned(item interface{})
 	Put(item interface{})
-	Err() error
-	Close() error
+	EasyIO
 }
 
 type Reader interface {
 	GetUnsigned() uint64
 	GetSigned() int64
 	Get(item interface{})
-	Err() error
-	Close() error
+	EasyIO
 }
 
 type writeImpl struct {
 	return wi.err
 }
 
-//Close will close the underlying writer iff it is an io.WriteCloser
+func (wi *writeImpl) Try(f func() error) {
+	if wi.err != nil {
+		return
+	}
+	err := Error(f())
+	if wi.err != nil {
+		wi.err = err
+	}
+}
+
 func (wi *writeImpl) Close() error {
 	if wi.err != nil {
 		return wi.err
 	}
 	ri.err = Error(binary.Read(ri, ri.order, item))
 }
+func (ri *readImpl) Try(f func() error) {
+	if ri.err != nil {
+		return
+	}
+	err := Error(f())
+	if ri.err != nil {
+		ri.err = err
+	}
+}
 func (ri *readImpl) Err() error {
 	return ri.err
 }