Files
aleesa-phrases-go/vendor/github.com/cockroachdb/errors/errbase/adapters.go
2022-05-21 01:38:58 +03:00

206 lines
6.5 KiB
Go

// Copyright 2019 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
package errbase
import (
"context"
goErr "errors"
"fmt"
"os"
"github.com/cockroachdb/errors/errorspb"
"github.com/gogo/protobuf/proto"
pkgErr "github.com/pkg/errors"
)
// This file provides the library the ability to encode/decode
// standard error types.
// errors.errorString from base Go does not need an encoding
// function, because the base encoding logic in EncodeLeaf() is
// able to extract everything about it.
// we can then decode it exactly.
func decodeErrorString(_ context.Context, msg string, _ []string, _ proto.Message) error {
return goErr.New(msg)
}
// errors.fundamental from github.com/pkg/errors cannot be encoded
// exactly because it includes a non-serializable stack trace
// object. In order to work with it, we encode it by dumping
// the stack trace in a safe reporting detail field, and decode
// it as an opaqueLeaf instance in this package.
func encodePkgFundamental(
_ context.Context, err error,
) (msg string, safe []string, _ proto.Message) {
msg = err.Error()
iErr := err.(interface{ StackTrace() pkgErr.StackTrace })
safeDetails := []string{fmt.Sprintf("%+v", iErr.StackTrace())}
return msg, safeDetails, nil
}
// errors.withMessage from github.com/pkg/errors can be encoded
// exactly because it just has a message prefix. The base encoding
// logic in EncodeWrapper() is able to extract everything from it.
// we can then decode it exactly.
func decodeWithMessage(
_ context.Context, cause error, msgPrefix string, _ []string, _ proto.Message,
) error {
return pkgErr.WithMessage(cause, msgPrefix)
}
// errors.withStack from github.com/pkg/errors cannot be encoded
// exactly because it includes a non-serializable stack trace
// object. In order to work with it, we encode it by dumping
// the stack trace in a safe reporting detail field, and decode
// it as an opaqueWrapper instance in this package.
func encodePkgWithStack(
_ context.Context, err error,
) (msgPrefix string, safe []string, _ proto.Message) {
iErr := err.(interface{ StackTrace() pkgErr.StackTrace })
safeDetails := []string{fmt.Sprintf("%+v", iErr.StackTrace())}
return "" /* withStack does not have a message prefix */, safeDetails, nil
}
func encodePathError(
_ context.Context, err error,
) (msgPrefix string, safe []string, details proto.Message) {
p := err.(*os.PathError)
msg := p.Op + " " + p.Path
details = &errorspb.StringsPayload{
Details: []string{p.Op, p.Path},
}
return msg, []string{p.Op}, details
}
func decodePathError(
_ context.Context, cause error, _ string, _ []string, payload proto.Message,
) (result error) {
m, ok := payload.(*errorspb.StringsPayload)
if !ok || len(m.Details) < 2 {
// If this ever happens, this means some version of the library
// (presumably future) changed the payload type, and we're
// receiving this here. In this case, give up and let
// DecodeError use the opaque type.
return nil
}
return &os.PathError{
Op: m.Details[0],
Path: m.Details[1],
Err: cause,
}
}
func encodeLinkError(
_ context.Context, err error,
) (msgPrefix string, safe []string, details proto.Message) {
p := err.(*os.LinkError)
msg := p.Op + " " + p.Old + " " + p.New
details = &errorspb.StringsPayload{
Details: []string{p.Op, p.Old, p.New},
}
return msg, []string{p.Op}, details
}
func decodeLinkError(
_ context.Context, cause error, _ string, _ []string, payload proto.Message,
) (result error) {
m, ok := payload.(*errorspb.StringsPayload)
if !ok || len(m.Details) < 3 {
// If this ever happens, this means some version of the library
// (presumably future) changed the payload type, and we're
// receiving this here. In this case, give up and let
// DecodeError use the opaque type.
return nil
}
return &os.LinkError{
Op: m.Details[0],
Old: m.Details[1],
New: m.Details[2],
Err: cause,
}
}
func encodeSyscallError(
_ context.Context, err error,
) (msgPrefix string, safe []string, details proto.Message) {
p := err.(*os.SyscallError)
return p.Syscall, nil, nil
}
func decodeSyscallError(
_ context.Context, cause error, msg string, _ []string, _ proto.Message,
) (result error) {
return os.NewSyscallError(msg, cause)
}
// OpaqueErrno represents a syscall.Errno error object that
// was constructed on a different OS/platform combination.
type OpaqueErrno struct {
msg string
details *errorspb.ErrnoPayload
}
// Error implements the error interface.
func (o *OpaqueErrno) Error() string { return o.msg }
// Is tests whether this opaque errno object represents a special os error type.
func (o *OpaqueErrno) Is(target error) bool {
return (target == os.ErrPermission && o.details.IsPermission) ||
(target == os.ErrExist && o.details.IsExist) ||
(target == os.ErrNotExist && o.details.IsNotExist)
}
// Temporary tests whether this opaque errno object encodes a temporary error.
func (o *OpaqueErrno) Temporary() bool { return o.details.IsTemporary }
// Timeout tests whether this opaque errno object encodes a timeout error.
func (o *OpaqueErrno) Timeout() bool { return o.details.IsTimeout }
func encodeOpaqueErrno(
_ context.Context, err error,
) (msg string, safe []string, payload proto.Message) {
e := err.(*OpaqueErrno)
return e.Error(), []string{e.Error()}, e.details
}
func init() {
baseErr := goErr.New("")
RegisterLeafDecoder(GetTypeKey(baseErr), decodeErrorString)
pkgE := pkgErr.New("")
RegisterLeafEncoder(GetTypeKey(pkgE), encodePkgFundamental)
RegisterWrapperDecoder(GetTypeKey(pkgErr.WithMessage(baseErr, "")), decodeWithMessage)
ws := pkgErr.WithStack(baseErr)
RegisterWrapperEncoder(GetTypeKey(ws), encodePkgWithStack)
pKey := GetTypeKey(&os.PathError{})
RegisterWrapperEncoder(pKey, encodePathError)
RegisterWrapperDecoder(pKey, decodePathError)
pKey = GetTypeKey(&os.LinkError{})
RegisterWrapperEncoder(pKey, encodeLinkError)
RegisterWrapperDecoder(pKey, decodeLinkError)
pKey = GetTypeKey(&os.SyscallError{})
RegisterWrapperEncoder(pKey, encodeSyscallError)
RegisterWrapperDecoder(pKey, decodeSyscallError)
RegisterLeafEncoder(GetTypeKey(&OpaqueErrno{}), encodeOpaqueErrno)
}