github.com/jxskiss/gopkg@v0.17.3/errcode/registry.go (about)

     1  package errcode
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"sync/atomic"
     7  )
     8  
     9  // Registry represents an error code registry.
    10  type Registry struct {
    11  	reserve  func(code int32) bool // check reserved code
    12  	codes    map[int32]struct{}    // registry of all error codes
    13  	messages atomic.Value          // map[int32]string, copy on write
    14  }
    15  
    16  // New creates a new error code registry.
    17  func New() *Registry {
    18  	r := &Registry{
    19  		codes: make(map[int32]struct{}),
    20  	}
    21  	r.messages.Store(make(map[int32]string))
    22  	return r
    23  }
    24  
    25  // NewWithReserved creates a new error code registry with reserved codes,
    26  // calling Register with a reserved code causes a panic.
    27  // Reserved code can be registered by calling RegisterReserved.
    28  func NewWithReserved(reserveFunc func(code int32) bool) *Registry {
    29  	p := New()
    30  	p.reserve = reserveFunc
    31  	return p
    32  }
    33  
    34  // Register register an error code to the registry.
    35  // If the registry is created by NewWithReserved, it checks the code with
    36  // the reserve function and panics if the code is reserved.
    37  func (p *Registry) Register(code int32, msg string) *Code {
    38  	if p.reserve != nil && p.reserve(code) {
    39  		panic(fmt.Sprintf("errcode: code %d is reserved", code))
    40  	}
    41  	return p.add(code, msg)
    42  }
    43  
    44  // RegisterReserved register an error code to the registry.
    45  // It does not checks the reserve function, but simply adds the code
    46  // to the register.
    47  func (p *Registry) RegisterReserved(code int32, msg string) *Code {
    48  	return p.add(code, msg)
    49  }
    50  
    51  func (p *Registry) add(code int32, msg string) *Code {
    52  	if _, ok := p.codes[code]; ok {
    53  		panic(fmt.Sprintf("errcode: code %d is already registered", code))
    54  	}
    55  	p.codes[code] = struct{}{}
    56  	if msg != "" {
    57  		messages := p.messages.Load().(map[int32]string)
    58  		messages[code] = msg
    59  	}
    60  	return &Code{code: code, reg: p}
    61  }
    62  
    63  // UpdateMessages updates error messages to the registry.
    64  // This method copies the underlying message map, it's safe for
    65  // concurrent use.
    66  func (p *Registry) UpdateMessages(messages map[int32]string) {
    67  	oldMsgs, _ := p.messages.Load().(map[int32]string)
    68  	newMsgs := make(map[int32]string, len(oldMsgs))
    69  	for code, msg := range oldMsgs {
    70  		newMsgs[code] = msg
    71  	}
    72  	for code, msg := range messages {
    73  		newMsgs[code] = msg
    74  	}
    75  	p.messages.Store(newMsgs)
    76  }
    77  
    78  // Dump returns all error codes registered with the registry.
    79  func (p *Registry) Dump() []*Code {
    80  	out := make([]*Code, 0, len(p.codes))
    81  	for code := range p.codes {
    82  		out = append(out, &Code{code: code, reg: p})
    83  	}
    84  	sort.Slice(out, func(i, j int) bool {
    85  		return out[i].code < out[j].code
    86  	})
    87  	return out
    88  }
    89  
    90  func (p *Registry) getMessage(code int32) string {
    91  	if p == nil {
    92  		return ""
    93  	}
    94  	msgs, _ := p.messages.Load().(map[int32]string)
    95  	return msgs[code]
    96  }