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 }