github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/kit/enumgen/enum.go (about) 1 package enumgen 2 3 import ( 4 "path/filepath" 5 "runtime" 6 "strings" 7 8 . "github.com/machinefi/w3bstream/pkg/depends/gen/codegen" 9 "github.com/machinefi/w3bstream/pkg/depends/x/misc/must" 10 "github.com/machinefi/w3bstream/pkg/depends/x/pkgx" 11 "github.com/machinefi/w3bstream/pkg/depends/x/stringsx" 12 ) 13 14 type Enum struct { 15 Path string 16 Name string 17 Options Options 18 } 19 20 func NewEnum(name string, options Options) *Enum { 21 enum := &Enum{Options: options} 22 parts := strings.Split(name, ".") 23 switch len(parts) { 24 case 1: 25 enum.Path = "" 26 enum.Name = parts[0] 27 default: 28 enum.Path = strings.Join(parts[0:len(parts)-1], ".") 29 enum.Name = parts[len(parts)-1] 30 } 31 return enum 32 } 33 34 func (e Enum) ConstUnknown() Snippet { 35 return Ident(stringsx.UpperSnakeCase(e.Name) + "_UNKNOWN") 36 } 37 38 func (e Enum) ConstName(value string) Snippet { 39 return Ident(stringsx.UpperSnakeCase(e.Name) + "__" + value) 40 } 41 42 func (e Enum) VarInvalidError() Snippet { return Ident("Invalid" + e.Name) } 43 44 func (e Enum) Receiver(name string) *SnippetField { return Var(Type(e.Name), name) } 45 46 func (e Enum) StarReceiver(name string) *SnippetField { return Var(Star(Type(e.Name)), name) } 47 48 func (e Enum) WriteToFile(f *File) { 49 f.WriteSnippet( 50 e.Errors(f), 51 e.StringParser(f), 52 e.LabelParser(f), 53 e.Integer(f), 54 e.Stringer(f), 55 e.Labeler(f), 56 e.TypeName(f), 57 e.ConstValues(f), 58 e.TextMarshaler(f), 59 e.TextUnmarshaler(f), 60 e.Scanner(f), 61 e.Valuer(f), 62 ) 63 } 64 65 func (e Enum) Errors(f *File) Snippet { 66 return Exprer( 67 `var ? = ?("invalid ? type")`, 68 e.VarInvalidError(), 69 Ident(f.Use("errors", "New")), 70 Ident(e.Name), 71 ) 72 } 73 74 func (e Enum) StringParser(f *File) Snippet { 75 clauses := []*SnippetCaseClause{ 76 CaseClause().Do(Return(e.ConstUnknown(), e.VarInvalidError())), 77 CaseClause(f.Value("")).Do(Return(e.ConstUnknown(), Nil)), 78 } 79 80 for _, o := range e.Options { 81 clauses = append( 82 clauses, 83 CaseClause(f.Value(*o.Str)).Do(Return(e.ConstName(*o.Str), Nil)), 84 ) 85 } 86 87 return Func(Var(String, "s")). 88 Named("Parse"+e.Name+"FromString"). 89 Return(Var(Type(e.Name)), Var(Error)). 90 Do(Switch(Ident("s")).When(clauses...)) 91 } 92 93 func (e Enum) LabelParser(f *File) Snippet { 94 clauses := []*SnippetCaseClause{ 95 CaseClause().Do(Return(e.ConstUnknown(), e.VarInvalidError())), 96 CaseClause(f.Value("")).Do(Return(e.ConstUnknown(), Nil)), 97 } 98 99 for _, o := range e.Options { 100 clauses = append( 101 clauses, 102 CaseClause(f.Value(o.Label)).Do(Return(e.ConstName(*o.Str), Nil)), 103 ) 104 } 105 106 return Func(Var(String, "s")). 107 Named("Parse"+e.Name+"FromLabel"). 108 Return(Var(Type(e.Name)), Var(Error)). 109 Do(Switch(Ident("s")).When(clauses...)) 110 } 111 112 func (e Enum) Stringer(f *File) Snippet { 113 clauses := []*SnippetCaseClause{ 114 CaseClause().Do(Return(f.Value("UNKNOWN"))), 115 CaseClause(e.ConstUnknown()).Do(Return(f.Value(""))), 116 } 117 118 for _, o := range e.Options { 119 clauses = append( 120 clauses, 121 CaseClause(e.ConstName(*o.Str)).Do(Return(f.Value(*o.Str))), 122 ) 123 } 124 125 return Func(). 126 MethodOf(e.Receiver("v")). 127 Named("String"). 128 Return(Var(String)). 129 Do(Switch(Ident("v")).When(clauses...)) 130 } 131 132 func (e Enum) Integer(f *File) Snippet { 133 return Func(). 134 MethodOf(e.Receiver("v")). 135 Named("Int"). 136 Return(Var(Int)). 137 Do(Return(Casting(Int, Ident("v")))) 138 } 139 140 func (e Enum) Labeler(f *File) Snippet { 141 clauses := []*SnippetCaseClause{ 142 CaseClause().Do(Return(f.Value("UNKNOWN"))), 143 CaseClause(e.ConstUnknown()).Do(Return(f.Value(""))), 144 } 145 146 for _, o := range e.Options { 147 clauses = append( 148 clauses, 149 CaseClause(e.ConstName(*o.Str)).Do(Return(f.Value(o.Label))), 150 ) 151 } 152 153 return Func(). 154 MethodOf(e.Receiver("v")). 155 Named("Label"). 156 Return(Var(String)). 157 Do(Switch(Ident("v")).When(clauses...)) 158 } 159 160 func (e Enum) TypeName(f *File) Snippet { 161 return Func(). 162 MethodOf(e.Receiver("v")). 163 Named("TypeName"). 164 Return(Var(String)). 165 Do(Return(f.Value(e.Path + "." + e.Name))) 166 } 167 168 func (e Enum) ConstValues(f *File) Snippet { 169 typ := Slice(Type(f.Use(PkgPath, IntStringerName))) 170 return Func(). 171 MethodOf(e.Receiver("v")). 172 Named("ConstValues"). 173 Return(Var(typ)). 174 Do(Return(func() Snippet { 175 lst := []interface{}{typ} 176 holder := "?" 177 for i, o := range e.Options { 178 if i > 0 { 179 holder += ", ?" 180 } 181 lst = append(lst, e.ConstName(*o.Str)) 182 } 183 return f.Expr("?{"+holder+"}", lst...) 184 }())) 185 } 186 187 func (e Enum) TextMarshaler(f *File) Snippet { 188 return Func(). 189 MethodOf(e.Receiver("v")). 190 Named("MarshalText"). 191 Return(Var(Slice(Byte)), Var(Error)). 192 Do( 193 Define(Ident("s")).By(Ref(Ident("v"), Call("String"))), 194 If(f.Expr(`s == "UNKNOWN"`)). 195 Do(Return(Nil, e.VarInvalidError())), 196 Return(Casting(Slice(Byte), Ident("s")), Nil), 197 ) 198 199 } 200 201 func (e Enum) TextUnmarshaler(f *File) Snippet { 202 return Func(Var(Slice(Byte), "data")). 203 MethodOf(e.StarReceiver("v")). 204 Named("UnmarshalText"). 205 Return(Var(Error)). 206 Do( 207 Define(Ident("s")). 208 By( 209 Casting(String, Call(f.Use("bytes", "ToUpper"), Ident("data"))), 210 ), 211 Define(Ident("val"), Ident("err")). 212 By( 213 CallWith( 214 f.Expr("Parse?FromString", Ident(e.Name)), 215 Ident("s"), 216 ), 217 ), 218 If(Exprer("err != nil")).Do(Return(Ident("err"))), 219 Assign(AccessValue(Ident("v"))).By(Ident("val")), 220 Return(Nil), 221 ) 222 } 223 224 func (e Enum) Scanner(f *File) Snippet { 225 return Func(Var(Interface(), "src")). 226 MethodOf(e.StarReceiver("v")). 227 Named("Scan"). 228 Return(Var(Error)). 229 Do( 230 Define(Ident("offset")).By(Valuer(0)), 231 Define(Ident("o"), Ident("ok")). 232 By( 233 Ref( 234 Casting(Interface(), Ident("v")), 235 Paren(Exprer(f.Use(PkgPath, ValueOffsetName))), 236 ), 237 ), 238 If(Ident("ok")). 239 Do( 240 Assign(Ident("offset")). 241 By(Ref(Ident("o"), Call("Offset"))), 242 ), 243 Define(Ident("i"), Ident("err")). 244 By( 245 Call( 246 f.Use(PkgPath, ScanIntEnumStringerName), 247 Ident("src"), Ident("offset"), 248 ), 249 ), 250 If(Exprer("err != nil")). 251 Do(Return(Ident("err"))), 252 Assign(AccessValue(Ident("v"))). 253 By( 254 Casting(Type(e.Name), Ident("i")), 255 ), 256 Return(Nil), 257 ) 258 } 259 260 func (e Enum) Valuer(f *File) Snippet { 261 return Func(). 262 MethodOf(e.Receiver("v")). 263 Named("Value"). 264 Return( 265 Var(Type(f.Use("database/sql/driver", "Value"))), 266 Var(Error)). 267 Do( 268 Define(Ident("offset")).By(Valuer(0)), 269 Define(Ident("o"), Ident("ok")). 270 By( 271 Ref( 272 Casting(Interface(), Ident("v")), 273 Paren(Exprer(f.Use(PkgPath, ValueOffsetName))), 274 ), 275 ), 276 If(Ident("ok")). 277 Do( 278 Assign(Ident("offset")). 279 By(Ref(Ident("o"), Call("Offset"))), 280 ), 281 Return(Exprer(`int64(v) + int64(offset)`), Nil), 282 ) 283 } 284 285 var ( 286 PkgPath string 287 IntStringerName = "IntStringerEnum" 288 ValueOffsetName = "ValueOffset" 289 ScanIntEnumStringerName = "ScanIntEnumStringer" 290 ) 291 292 func init() { 293 _, current, _, _ := runtime.Caller(0) 294 dir := filepath.Join(filepath.Dir(current), "../enum") 295 PkgPath = must.String(pkgx.PkgIdByPath(dir)) 296 }