package errs import ( "encoding/binary" "fmt" "io" "runtime/debug" ) type Error struct { Code int64 Msg string StackTrace string collection string index string err error // Wrapped error } func NewErr(code int64, msg string) *Error { return &Error{ Code: code, Msg: msg, } } func (e *Error) Error() string { if e.collection != "" || e.index != "" { return fmt.Sprintf(`[%d] (%s/%s) %s`, e.Code, e.collection, e.index, e.Msg) } else { return fmt.Sprintf("[%d] %s", e.Code, e.Msg) } } func (e *Error) Is(rhs error) bool { e2, ok := rhs.(*Error) if !ok { return false } return e.Code == e2.Code } func (e *Error) Unwrap() error { return e.err } func (e *Error) WithErr(err error) *Error { if e2, ok := err.(*Error); ok && e2.Code == e.Code { return e2 } e2 := e.WithMsg(err.Error()) e2.err = err return e2 } func (e *Error) WithMsg(msg string, args ...any) *Error { err := *e err.Msg += ": " + fmt.Sprintf(msg, args...) if len(err.StackTrace) == 0 { err.StackTrace = string(debug.Stack()) } return &err } func (e *Error) WithCollection(s string) *Error { err := *e err.collection = s return &err } func (e *Error) WithIndex(s string) *Error { err := *e err.index = s return &err } func (e *Error) msgTruncacted() string { if len(e.Msg) > 255 { return e.Msg[:255] } return e.Msg } func (e *Error) Write(w io.Writer) error { msg := e.msgTruncacted() if err := binary.Write(w, binary.LittleEndian, e.Code); err != nil { return IO.WithErr(err) } if _, err := w.Write([]byte{byte(len(msg))}); err != nil { return err } _, err := w.Write([]byte(msg)) return err } func (e *Error) Read(r io.Reader) error { var ( size uint8 ) if err := binary.Read(r, binary.LittleEndian, &e.Code); err != nil { return IO.WithErr(err) } if err := binary.Read(r, binary.LittleEndian, &size); err != nil { return IO.WithErr(err) } msgBuf := make([]byte, size) if _, err := io.ReadFull(r, msgBuf); err != nil { return IO.WithErr(err) } e.Msg = string(msgBuf) return nil }