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 }