github.com/qioalice/ekago/v3@v3.3.2-0.20221202205325-5c262d586ee4/ekaerr/class.go (about) 1 // Copyright © 2020-2021. All rights reserved. 2 // Author: Ilya Stroy. 3 // Contacts: iyuryevich@pm.me, https://github.com/qioalice 4 // License: https://opensource.org/licenses/MIT 5 6 package ekaerr 7 8 type ( 9 // Class is a special type that represents Error's abstract class 10 // and provides a mechanism of error classifying. 11 // 12 // Using Class's object you can instantiate an *Error object 13 // using New() or Wrap() methods. See them for more info. 14 // 15 // DO NOT INSTANTIATE Class OBJECTS MANUALLY! THEY WILL NOT BE INITIALIZED 16 // PROPERLY AND WILL BE CONSIDERED BROKEN. THAT CLASS IS NOT VALID. 17 // YOU CAN NOT CREATE ERROR OBJECTS USING INVALID CLASS. 18 // YOU CAN NOT CREATE ANOTHER DERIVED CLASSES USING INVALID CLASS AS BASE. 19 // 20 // A Class can not exist w/o a Namespace. Ekaerr provides you builtin classes 21 // you may use and, typically, that covers ~90% all error classifying models. 22 // But if you need your own classes or even subclasses (yes, you can derive them) 23 // you may: 24 // 25 // - Create your own Class. 26 // Use <Namespace>.NewClass(...) method. 27 // You can use builtin "Common" namespace (allowed by CommonNamespace variable) 28 // or create your own Namespace at first and then create a Class that you want. 29 // 30 // - Create a new class but derive them from another. 31 // Use <Class>.NewSubClass(...) method. 32 // You can use builtin classes (see them at the "class_builtin.go" file) 33 // or crate your own Class (see above how) and derive from them. 34 // 35 // You also need to know that there is a special Class - an 'invalidClass'. 36 // This is a special class that you may get if you instantiate Class object 37 // manually like "new(Class)" or "var c Class". That class IS NOT VALID. 38 // YOU MUST NOT USE INVALID CLASS! 39 // But you may get an invalid class also if you will call "(*Error)(nil).Class()". 40 // So, you can check whether your class is valid using IsValid() method. 41 // 42 // Class is a very lightweight datatype and all Class's methods 43 // (and function that takes Class as argument) uses Class's objects by value. 44 // It means there is no reason to use Class's object by reference in your code. 45 Class struct { 46 47 // id is an unique per Class its ID. 48 // If it's == _ERR_INVALID_CLASS_ID, the Class is considered broken 49 // (has been instantiated manually instead of using Class constructors). 50 id ClassID 51 52 // parentID is an ID of some Class that is base Class for this Class. 53 // (it means that this Class has been created by Class.NewSubClass()). 54 parentID ClassID 55 56 // namespaceID is an ID of some Namespace this Class belongs to. 57 // (it means that this Class has been created by Namespace.NewClass() or 58 // derived from the Class that was created that way). 59 namespaceID NamespaceID 60 61 // name is this Class's name specified by user at the creation. 62 // It's just a class's name as is, nothing more. 63 name string 64 65 // fullName is this Class's name but with base Classes and Namespaces 66 // chaining. E.g: "<Namespace>.<BaseClass1>.<BaseClass2>. ... .<ThisClass>". 67 // 68 // WARNING! 69 // READ THIS FIELD ONLY OF OBJECTS YOU OBTAIN FROM THE CLASS'S POOL! 70 fullName string 71 } 72 ) 73 74 // New is an Error's constructor. Specify what happen by 'message' and key-value 75 // paired arguments 'args' and that is! A new *Error object is returned. 76 // Arguments adding works the same as (*Error).AddFields() do. 77 // 78 // Requirements: 79 // c must be valid Class object. Otherwise nil Error is returned. 80 func (c Class) New(message string, args ...any) *Error { 81 if !isValidClassID(c.id) { 82 return nil 83 } 84 return newError(false, c.id, c.namespaceID, nil, message, args) 85 } 86 87 // LightNew is the same as just New() but creates a lightweight Error instead. 88 // Read more what lightweight error is in Error's doc. 89 func (c Class) LightNew(message string, args ...any) *Error { 90 if !isValidClassID(c.id) { 91 return nil 92 } 93 return newError(true, c.id, c.namespaceID, nil, message, args) 94 } 95 96 // Wrap is an Error's constructor. Specify what legacy Golang error you need 97 // to wrap using 'err', what happen by 'message' and key-value paired arguments 'args' 98 // and that is! A new *Error object is returned. 99 // Arguments adding works the same as (*Error).AddFields() do. 100 // 101 // Requirements: 102 // c must be valid Class object. Otherwise nil Error is returned. 103 // 'err' != nil. Otherwise nil Error is returned. 104 func (c Class) Wrap(err error, message string, args ...any) *Error { 105 if !isValidClassID(c.id) || err == nil { 106 return nil 107 } 108 return newError(false, c.id, c.namespaceID, err, message, args) 109 } 110 111 // LightWrap is the same as just Wrap() but creates a lightweight Error instead. 112 // Read more what lightweight error is in Error's doc. 113 func (c Class) LightWrap(err error, message string, args ...any) *Error { 114 if !isValidClassID(c.id) || err == nil { 115 return nil 116 } 117 return newError(true, c.id, c.namespaceID, err, message, args) 118 } 119 120 // IsValid reports whether c is valid Class object or not. 121 // 122 // It returns false if c has not been initialized properly (instantiated manually 123 // instead of Class's or Namespace's constructors calling or obtaining from the 124 // Error's Class() method). 125 func (c Class) IsValid() bool { 126 return isValidClassID(c.id) 127 } 128 129 // ParentClass returns a copy of Class object that has been used as a base class 130 // for the current's one or a special 'invalidClass' if this Class has been 131 // created directly from the namespace not as a subclass. 132 func (c Class) ParentClass() Class { 133 if !c.IsValid() || !isValidClassID(c.parentID) { 134 return invalidClass 135 } 136 return classByID(c.parentID, true) 137 } 138 139 // Name returns a current Class's name that was used at the Class creation. 140 // If you want to get a full name (without Namespace's and Base classes' use 141 // c.FullName() instead). 142 func (c Class) Name() string { 143 if !c.IsValid() { 144 return "" 145 } 146 return c.name 147 } 148 149 // FullName returns a current Class's full name: 150 // a Class's name but with base Classes and Namespaces chaining. 151 // E.g: "<Namespace>.<BaseClass1>.<BaseClass2>. ... .<ThisClass>". 152 func (c Class) FullName() string { 153 if !c.IsValid() { 154 return "" 155 } 156 return classByID(c.id, true).fullName 157 } 158 159 // NewSubClass is a Class's constructor. Specify the derived Class's name 'name' 160 // and that is! A new Class will be created and its copy is returned 161 // (created class will belongs to the same Namespace as based one). 162 // 163 // Warnings: 164 // A two classes with the same names is the two DIFFERENT classes! 165 // 166 // Requirements: 167 // c must be valid Class object. Otherwise 'invalidClass' is returned. 168 func (c Class) NewSubClass(subClassName string) Class { 169 if !isValidClassID(c.id) { 170 return invalidClass 171 } 172 fullName := classByID(c.id, true).fullName + "." + subClassName 173 return newClass(c.id, c.namespaceID, subClassName, fullName) 174 }