github.com/jxskiss/gopkg/v2@v2.14.9-0.20240514120614-899f3e7952b4/infra/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(options ...Option) *Registry {
    18  	r := &Registry{
    19  		codes: make(map[int32]struct{}),
    20  	}
    21  	r.applyOptions(options...)
    22  	r.messages.Store(make(map[int32]string))
    23  	return r
    24  }
    25  
    26  // Register registers an error code to the registry.
    27  // If the registry is created by NewWithReserved, it checks the code with
    28  // the reserve function and panics if the code is reserved.
    29  func (p *Registry) Register(code int32, msg string) *Code {
    30  	if p.reserve != nil && p.reserve(code) {
    31  		panic(fmt.Sprintf("errcode: code %d is reserved", code))
    32  	}
    33  	return p.add(code, msg)
    34  }
    35  
    36  // RegisterReserved registers an error code to the registry.
    37  // It does not check the reserve function, but simply adds the code
    38  // to the register.
    39  func (p *Registry) RegisterReserved(code int32, msg string) *Code {
    40  	return p.add(code, msg)
    41  }
    42  
    43  func (p *Registry) add(code int32, msg string) *Code {
    44  	if _, ok := p.codes[code]; ok {
    45  		panic(fmt.Sprintf("errcode: code %d is already registered", code))
    46  	}
    47  	p.codes[code] = struct{}{}
    48  	if msg != "" {
    49  		messages := p.messages.Load().(map[int32]string)
    50  		messages[code] = msg
    51  	}
    52  	return &Code{code: code, reg: p}
    53  }
    54  
    55  // UpdateMessages updates error messages to the registry.
    56  // This method copies the underlying message map, it's safe for
    57  // concurrent use.
    58  func (p *Registry) UpdateMessages(messages map[int32]string) {
    59  	oldMsgs, _ := p.messages.Load().(map[int32]string)
    60  	newMsgs := make(map[int32]string, len(oldMsgs))
    61  	for code, msg := range oldMsgs {
    62  		newMsgs[code] = msg
    63  	}
    64  	for code, msg := range messages {
    65  		newMsgs[code] = msg
    66  	}
    67  	p.messages.Store(newMsgs)
    68  }
    69  
    70  // Dump returns all error codes registered with the registry.
    71  func (p *Registry) Dump() []*Code {
    72  	msgs, _ := p.messages.Load().(map[int32]string)
    73  	out := make([]*Code, 0, len(p.codes))
    74  	for code := range p.codes {
    75  		msg := msgs[code]
    76  		out = append(out, &Code{code: code, msg: msg})
    77  	}
    78  	sort.Slice(out, func(i, j int) bool {
    79  		return out[i].code < out[j].code
    80  	})
    81  	return out
    82  }
    83  
    84  func (p *Registry) getMessage(code int32) string {
    85  	if p == nil {
    86  		return ""
    87  	}
    88  	msgs, _ := p.messages.Load().(map[int32]string)
    89  	return msgs[code]
    90  }