├── .gitignore ├── .hgignore ├── .idea ├── codeStyles │ └── codeStyleConfig.xml ├── enumeration.iml ├── go.imports.xml ├── inspectionProfiles │ └── Project_Default.xml ├── misc.xml ├── modules.xml ├── run │ └── enumeration month.go.run.xml ├── runConfigurations │ ├── enumeration_example_base.xml │ ├── enumeration_example_channel.xml │ ├── enumeration_example_day.xml │ ├── enumeration_example_method.xml │ ├── enumeration_example_month.xml │ ├── enumeration_example_pet.xml │ └── enumeration_season_json_nc_jj.xml └── vcs.xml ├── LICENSE ├── README.md ├── build.sh ├── contributors.txt ├── enum ├── enum.go ├── enum_test.go ├── representation.go └── representation_enum.go ├── enumeration.go ├── enumeration_test.go ├── example ├── base.go ├── base_enum.go ├── channel.go ├── channel_enum.go ├── country.go ├── country_enum.go ├── day.go ├── day_enum.go ├── example_test.go ├── greekalphabet.go ├── greekalphabet_enum.go ├── method.go ├── method_enum.go ├── month.go ├── month_enum.go ├── pet.go └── pet_enum.go ├── go.mod ├── go.sum ├── internal ├── codegen │ ├── units.go │ └── units_test.go ├── collection │ ├── set.go │ └── set_test.go ├── model │ ├── model.go │ ├── write.go │ ├── write_core.go │ └── write_test.go.txt ├── parse │ ├── convert.go │ ├── convert_test.go │ ├── parse_const.go │ ├── parse_type.go │ └── scanner.go ├── test │ ├── combination_test.go │ ├── combinations.xlsx │ ├── season.go │ ├── season1_enum.go │ ├── season2_enum.go │ ├── season_ic_ji_enum.go │ ├── season_ic_jj_enum.go │ ├── season_ic_jn_enum.go │ ├── season_ic_si_enum.go │ ├── season_ic_sn_enum.go │ ├── season_ic_ss_enum.go │ ├── season_ic_ta_enum.go │ ├── season_ic_ti_enum.go │ ├── season_ic_tn_enum.go │ ├── season_ic_tt_enum.go │ ├── season_json.go │ ├── season_nc_ji_enum.go │ ├── season_nc_jj_enum.go │ ├── season_nc_jn_enum.go │ ├── season_nc_si_enum.go │ ├── season_nc_sn_enum.go │ ├── season_nc_ss_enum.go │ ├── season_nc_ta_enum.go │ ├── season_nc_ti_enum.go │ ├── season_nc_tn_enum.go │ ├── season_nc_tt_enum.go │ ├── season_sql.go │ ├── season_text.go │ ├── season_uc_ji_enum.go │ ├── season_uc_jj_enum.go │ ├── season_uc_jn_enum.go │ ├── season_uc_si_enum.go │ ├── season_uc_sn_enum.go │ ├── season_uc_ta_enum.go │ ├── season_uc_ti_enum.go │ ├── season_uc_tn_enum.go │ ├── season_uc_tt_enum.go │ └── simple │ │ ├── season_json.go │ │ ├── season_sql.go │ │ └── season_text.go ├── transform │ ├── case.go │ ├── case_enum.go │ └── unsnake.go └── util │ └── util.go ├── magefiles └── build.go └── version.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/shelf/ 2 | .idea/workspace.xml 3 | /bin/ 4 | /temp/ 5 | /go.work 6 | /go.work.sum 7 | -------------------------------------------------------------------------------- /.hgignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/enumeration.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/go.imports.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/run/enumeration month.go.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/runConfigurations/enumeration_example_base.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/runConfigurations/enumeration_example_channel.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/runConfigurations/enumeration_example_day.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/runConfigurations/enumeration_example_method.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/runConfigurations/enumeration_example_month.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/runConfigurations/enumeration_example_pet.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/runConfigurations/enumeration_season_json_nc_jj.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Rick Beton 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of enumeration nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -ex 2 | cd "$(dirname "$0")" 3 | go install tool 4 | mage 5 | -------------------------------------------------------------------------------- /contributors.txt: -------------------------------------------------------------------------------- 1 | Rick Beton 2 | -------------------------------------------------------------------------------- /enum/enum.go: -------------------------------------------------------------------------------- 1 | // Package enum provides an API for manipulating enumerations. 2 | // This is support code for the auto-generated enumerations: 3 | // see https://github.com/rickb777/enumeration for further instructions. 4 | package enum 5 | 6 | // Enum is a generic contract for all generated enums. 7 | type Enum interface { 8 | Ordinal() int 9 | String() string 10 | IsValid() bool 11 | } 12 | 13 | // IntEnum is a specialisation for those enums that have int or similar as the underlying type. 14 | type IntEnum interface { 15 | Enum 16 | Int() int 17 | } 18 | 19 | // FloatEnum is a specialisation for those enums that have float32 or float64 as the underlying type. 20 | type FloatEnum interface { 21 | Enum 22 | Float() float64 23 | } 24 | 25 | //------------------------------------------------------------------------------------------------- 26 | 27 | // Enums is a slice of Enum. 28 | type Enums []Enum 29 | 30 | // Strings gets the string values of the enums in the same order. 31 | func (es Enums) Strings() []string { 32 | ss := make([]string, len(es)) 33 | for i, e := range es { 34 | ss[i] = e.String() 35 | } 36 | return ss 37 | } 38 | 39 | // Ordinals gets the ordinal values of the enums in the same order. 40 | func (es Enums) Ordinals() []int { 41 | os := make([]int, len(es)) 42 | for i, e := range es { 43 | os[i] = e.Ordinal() 44 | } 45 | return os 46 | } 47 | 48 | //------------------------------------------------------------------------------------------------- 49 | 50 | // IntEnums is a slice of IntEnum. 51 | type IntEnums []IntEnum 52 | 53 | // Strings gets the string values of the enums in the same order. 54 | func (es IntEnums) Strings() []string { 55 | ss := make([]string, len(es)) 56 | for i, e := range es { 57 | ss[i] = e.String() 58 | } 59 | return ss 60 | } 61 | 62 | // Ordinals gets the ordinal values of the enums in the same order. 63 | func (es IntEnums) Ordinals() []int { 64 | os := make([]int, len(es)) 65 | for i, e := range es { 66 | os[i] = e.Ordinal() 67 | } 68 | return os 69 | } 70 | 71 | // Ints gets the values of the enums in the same order. 72 | func (es IntEnums) Ints() []int { 73 | vs := make([]int, len(es)) 74 | for i, e := range es { 75 | vs[i] = e.Int() 76 | } 77 | return vs 78 | } 79 | 80 | //------------------------------------------------------------------------------------------------- 81 | 82 | // FloatEnums is a slice of FloatEnum. 83 | type FloatEnums []FloatEnum 84 | 85 | // Strings gets the string values of the enums in the same order. 86 | func (es FloatEnums) Strings() []string { 87 | ss := make([]string, len(es)) 88 | for i, e := range es { 89 | ss[i] = e.String() 90 | } 91 | return ss 92 | } 93 | 94 | // Ordinals gets the ordinal values of the enums in the same order. 95 | func (es FloatEnums) Ordinals() []int { 96 | os := make([]int, len(es)) 97 | for i, e := range es { 98 | os[i] = e.Ordinal() 99 | } 100 | return os 101 | } 102 | 103 | // Floats gets the values of the enums in the same order. 104 | func (es FloatEnums) Floats() []float64 { 105 | vs := make([]float64, len(es)) 106 | for i, e := range es { 107 | vs[i] = e.Float() 108 | } 109 | return vs 110 | } 111 | 112 | func QuotedString(s string) []byte { 113 | b := make([]byte, len(s)+2) 114 | b[0] = '"' 115 | copy(b[1:], s) 116 | b[len(s)+1] = '"' 117 | return b 118 | } 119 | -------------------------------------------------------------------------------- /enum/enum_test.go: -------------------------------------------------------------------------------- 1 | package enum_test 2 | 3 | import ( 4 | "github.com/rickb777/expect" 5 | "strings" 6 | "testing" 7 | 8 | "github.com/rickb777/enumeration/v4/enum" 9 | "github.com/rickb777/enumeration/v4/example" 10 | ) 11 | 12 | func TestIntEnums_Strings(t *testing.T) { 13 | methods := example.AllMethodEnums.Strings() 14 | 15 | expect.String(strings.Join(methods, "|")).ToBe(t, "HEAD|GET|PUT|POST|PATCH|DELETE") 16 | 17 | methods = enum.Enums{example.HEAD, example.PUT, example.PATCH}.Strings() 18 | 19 | expect.String(strings.Join(methods, "|")).ToBe(t, "HEAD|PUT|PATCH") 20 | } 21 | 22 | func TestIntEnums_Ordinals(t *testing.T) { 23 | days := enum.Enums{example.Wednesday, example.Friday, example.Sunday}.Ordinals() 24 | 25 | expect.Slice(days).ToBe(t, 3, 5, 0) 26 | 27 | days = enum.IntEnums{example.Wednesday, example.Friday, example.Sunday}.Ordinals() 28 | 29 | expect.Slice(days).ToBe(t, 3, 5, 0) 30 | } 31 | 32 | func TestIntEnums_Ints(t *testing.T) { 33 | days := enum.IntEnums{example.Wednesday, example.Friday, example.Sunday}.Ints() 34 | 35 | expect.Slice(days).ToBe(t, 4, 6, 1) 36 | } 37 | 38 | //------------------------------------------------------------------------------------------------- 39 | 40 | func TestFloatEnums_Strings(t *testing.T) { 41 | es := example.AllBaseEnums.Strings() 42 | 43 | expect.Slice(es).ToBe(t, "a", "c", "g", "t") 44 | } 45 | 46 | func TestFloatEnums_Ordinals(t *testing.T) { 47 | es := enum.Enums{example.C, example.T}.Ordinals() 48 | 49 | expect.Slice(es).ToBe(t, 1, 3) 50 | 51 | es = enum.FloatEnums{example.C, example.T}.Ordinals() 52 | 53 | expect.Slice(es).ToBe(t, 1, 3) 54 | } 55 | 56 | func TestFloatEnums_Floats(t *testing.T) { 57 | es := example.AllBaseEnums.Floats() 58 | 59 | expect.Slice(es).ToBe(t, float64(example.A), float64(example.C), float64(example.G), float64(example.T)) 60 | } 61 | 62 | func TestQuotedString(t *testing.T) { 63 | qs1 := enum.QuotedString("") 64 | expect.String(qs1).ToBe(t, []byte{'"', '"'}) 65 | 66 | qs2 := enum.QuotedString("XYZ") 67 | expect.String(qs2).ToBe(t, []byte{'"', 'X', 'Y', 'Z', '"'}) 68 | } 69 | 70 | func TestRepresentation(t *testing.T) { 71 | r1 := enum.MustParseRepresentation("number") 72 | expect.Number(r1).ToBe(t, enum.Number) 73 | 74 | r2 := enum.MustParseRepresentation("2") 75 | expect.Number(r2).ToBe(t, enum.Number) 76 | 77 | _, err := enum.AsRepresentation("foobar") 78 | expect.Error(err).ToHaveOccurred(t) 79 | 80 | num := enum.Number.String() 81 | expect.String(num).ToBe(t, "Number") 82 | 83 | o1 := enum.RepresentationOf(1) 84 | expect.Number(o1).ToBe(t, enum.Identifier) 85 | expect.Number(o1.Int()).ToBe(t, 1) 86 | expect.Bool(o1.IsValid()).ToBeTrue(t) 87 | 88 | o3 := enum.RepresentationOf(3) 89 | expect.Number(o1.Int()).ToBe(t, 1) 90 | expect.Bool(o3.IsValid()).ToBeFalse(t) 91 | 92 | expect.Bool(enum.None.IsValid()).ToBeTrue(t) 93 | expect.Bool(enum.Representation(4).IsValid()).ToBeFalse(t) 94 | expect.String(enum.Representation(4).String()).ToBe(t, "Representation(4)") 95 | } 96 | -------------------------------------------------------------------------------- /enum/representation.go: -------------------------------------------------------------------------------- 1 | package enum 2 | 3 | //go:generate enumeration -type Representation -ic -alias altReps 4 | 5 | type Representation int 6 | 7 | const ( 8 | None Representation = iota // disables the feature (new in v3) 9 | Identifier // uses the main identifier of the corresponding constant 10 | Number // the value of the enumerant as a decimal number 11 | ) 12 | 13 | var altReps = map[string]Representation{ 14 | "x": None, 15 | "id": Identifier, 16 | "num": Number, 17 | "n": Number, 18 | } 19 | -------------------------------------------------------------------------------- /enum/representation_enum.go: -------------------------------------------------------------------------------- 1 | // generated code - do not edit 2 | // github.com/rickb777/enumeration/v4 3 | 4 | package enum 5 | 6 | import ( 7 | "errors" 8 | "fmt" 9 | "slices" 10 | "strconv" 11 | "strings" 12 | ) 13 | 14 | // AllRepresentations lists all 3 values in order. 15 | var AllRepresentations = []Representation{ 16 | None, Identifier, Number, 17 | } 18 | 19 | const ( 20 | representationEnumStrings = "NoneIdentifierNumber" 21 | representationEnumInputs = "noneidentifiernumber" 22 | ) 23 | 24 | var ( 25 | representationEnumIndex = [...]uint16{0, 4, 14, 20} 26 | ) 27 | 28 | // Ordinal returns the ordinal number of a Representation. This is an integer counting 29 | // from zero. It is *not* the same as the const number assigned to the value. 30 | func (v Representation) Ordinal() int { 31 | switch v { 32 | case None: 33 | return 0 34 | case Identifier: 35 | return 1 36 | case Number: 37 | return 2 38 | } 39 | return -1 40 | } 41 | 42 | // String returns the literal string representation of a Representation, which is 43 | // the same as the const identifier but without prefix or suffix. 44 | func (v Representation) String() string { 45 | o := v.Ordinal() 46 | return v.toString(o, representationEnumStrings, representationEnumIndex[:]) 47 | } 48 | 49 | func (v Representation) toString(o int, concats string, indexes []uint16) string { 50 | if o < 0 || o >= len(AllRepresentations) { 51 | return fmt.Sprintf("Representation(%d)", v) 52 | } 53 | return concats[indexes[o]:indexes[o+1]] 54 | } 55 | 56 | // IsValid determines whether a Representation is one of the defined constants. 57 | func (v Representation) IsValid() bool { 58 | return v.Ordinal() >= 0 59 | } 60 | 61 | // Int returns the int value, which is not necessarily the same as the ordinal. 62 | // This facilitates polymorphism (see enum.IntEnum). 63 | func (v Representation) Int() int { 64 | return int(v) 65 | } 66 | 67 | var invalidRepresentationValue = func() Representation { 68 | var v Representation 69 | for { 70 | if !slices.Contains(AllRepresentations, v) { 71 | return v 72 | } 73 | v++ 74 | } // AllRepresentations is a finite set so loop will terminate eventually 75 | }() 76 | 77 | // RepresentationOf returns a Representation based on an ordinal number. This is the inverse of Ordinal. 78 | // If the ordinal is out of range, an invalid Representation is returned. 79 | func RepresentationOf(v int) Representation { 80 | if 0 <= v && v < len(AllRepresentations) { 81 | return AllRepresentations[v] 82 | } 83 | return invalidRepresentationValue 84 | } 85 | 86 | // Parse parses a string to find the corresponding Representation, accepting one of the string values or 87 | // a number. It is used by AsRepresentation. 88 | // The input case does not matter. 89 | // 90 | // Usage Example 91 | // 92 | // v := new(Representation) 93 | // err := v.Parse(s) 94 | // ... etc 95 | func (v *Representation) Parse(in string) error { 96 | if v.parseNumber(in) { 97 | return nil 98 | } 99 | 100 | s := representationTransformInput(in) 101 | 102 | return v.parseFallback(in, s) 103 | } 104 | 105 | // parseNumber attempts to convert a decimal value. 106 | // Only numbers that correspond to the enumeration are valid. 107 | func (v *Representation) parseNumber(s string) (ok bool) { 108 | num, err := strconv.ParseInt(s, 10, 64) 109 | if err == nil { 110 | *v = Representation(num) 111 | return v.IsValid() 112 | } 113 | return false 114 | } 115 | 116 | func (v *Representation) parseFallback(in, s string) error { 117 | if v.parseString(s, representationEnumInputs, representationEnumIndex[:]) { 118 | return nil 119 | } 120 | 121 | var ok bool 122 | *v, ok = altReps[s] 123 | if ok { 124 | return nil 125 | } 126 | 127 | return errors.New(in + ": unrecognised representation") 128 | } 129 | 130 | func (v *Representation) parseString(s string, concats string, indexes []uint16) (ok bool) { 131 | var i0 uint16 = 0 132 | 133 | for j := 1; j < len(indexes); j++ { 134 | i1 := indexes[j] 135 | p := concats[i0:i1] 136 | if s == p { 137 | *v = AllRepresentations[j-1] 138 | return true 139 | } 140 | i0 = i1 141 | } 142 | *v, ok = altReps[s] 143 | return ok 144 | } 145 | 146 | // representationTransformInput may alter input strings before they are parsed. 147 | // This function is pluggable and is initialised using command-line flags 148 | // -ic -lc -uc -unsnake. 149 | var representationTransformInput = func(in string) string { 150 | return strings.ToLower(in) 151 | } 152 | 153 | // AsRepresentation parses a string to find the corresponding Representation, accepting either one of the string values or 154 | // a number. It wraps Parse. 155 | // The input case does not matter. 156 | func AsRepresentation(s string) (Representation, error) { 157 | var v = new(Representation) 158 | err := v.Parse(s) 159 | return *v, err 160 | } 161 | 162 | // MustParseRepresentation is similar to AsRepresentation except that it panics on error. 163 | // The input case does not matter. 164 | func MustParseRepresentation(s string) Representation { 165 | v, err := AsRepresentation(s) 166 | if err != nil { 167 | panic(err) 168 | } 169 | return v 170 | } 171 | -------------------------------------------------------------------------------- /enumeration.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "io" 7 | "os" 8 | "path/filepath" 9 | "strings" 10 | 11 | "github.com/rickb777/enumeration/v4/enum" 12 | "github.com/rickb777/enumeration/v4/internal/model" 13 | "github.com/rickb777/enumeration/v4/internal/parse" 14 | "github.com/rickb777/enumeration/v4/internal/transform" 15 | "github.com/rickb777/enumeration/v4/internal/util" 16 | ) 17 | 18 | var config model.Config 19 | var inputGo, outputGo, outputJSON, marshalTextRep, marshalJSONRep, storeRep string 20 | var force, nocase, lowercase, uppercase, showVersion bool 21 | 22 | func defineFlags() { 23 | flag.StringVar(&config.MainType, "type", "", "Name of the enumeration type (required).") 24 | flag.StringVar(&model.Prefix, "prefix", "", "Optional prefix to be stripped from the identifiers.") 25 | flag.StringVar(&model.Suffix, "suffix", "", "Optional suffix to be stripped from the identifiers.") 26 | flag.StringVar(&inputGo, "i", "", "Name of the input file. May be '-' for stdin. Default is enumeration type in lower case.") 27 | flag.StringVar(&outputGo, "o", "", "Name of the output file. May be '-' for stdout. Default is enumeration type in lower case plus '_enum'.") 28 | flag.StringVar(&config.Plural, "plural", "", "Plural name of the enumeration type (optional).") 29 | flag.StringVar(&parse.AliasTable, "alias", "", "Uses your own map[string]Type as aliases during parsing.") 30 | flag.StringVar(&config.Pkg, "package", "", "Name of the output package (optional). Defaults to the output directory.") 31 | flag.StringVar(&marshalTextRep, "marshaltext", "None", "Marshal text values using Identifier or Number") 32 | flag.StringVar(&marshalJSONRep, "marshaljson", "None", "Marshal JSON values using Identifier or Number") 33 | flag.StringVar(&storeRep, "store", "None", "Store values in a DB using Identifier, Number or Ordinal") 34 | 35 | flag.BoolVar(&config.Lenient, "lenient", false, "Allow parsing to yield invalid values.") 36 | flag.BoolVar(&force, "f", false, "Force writing the output file even if up to date (not used when piping stdin or stdout).") 37 | flag.BoolVar(&nocase, "nc", false, "Don't convert strings to upper or lowercase (this is the default)") 38 | flag.BoolVar(&lowercase, "lc", false, "Convert strings to lowercase and ignore case when parsing") 39 | flag.BoolVar(&uppercase, "uc", false, "Convert strings to uppercase and ignore case when parsing.") 40 | flag.BoolVar(&config.IgnoreCase, "ic", false, "Ignore case when parsing but keep the mixed case when outputting.") 41 | flag.BoolVar(&config.Unsnake, "unsnake", false, "Convert underscores in identifiers to spaces.") 42 | flag.BoolVar(&config.SimpleOnly, "s", false, "Generate simple enumerations without serialising or parsing functions") 43 | flag.BoolVar(&config.Polymorphic, "poly", false, "Generate polymorphic representation code") 44 | flag.BoolVar(&util.Verbose, "v", false, "Verbose progress messages.") 45 | flag.BoolVar(&util.Dbg, "z", false, "Debug messages.") 46 | flag.BoolVar(&showVersion, "version", false, "Print version number.") 47 | } 48 | 49 | func choosePackage(outputFile string) string { 50 | wd, err := os.Getwd() 51 | if err != nil { 52 | util.Fail(err) 53 | } 54 | 55 | dir := filepath.Base(filepath.Dir(outputFile)) 56 | 57 | if dir != "." { 58 | return dir 59 | } 60 | 61 | return filepath.Base(filepath.FromSlash(wd)) 62 | } 63 | 64 | func notUpToDate() bool { 65 | if inputGo != "-" && outputGo != "-" { 66 | xi, err := os.Stat(inputGo) 67 | if err == nil { 68 | xo, err := os.Stat(outputGo) 69 | if err == nil && xo.ModTime().After(xi.ModTime()) { 70 | util.Info("Skipped %s.\n", outputGo) 71 | return false 72 | } 73 | } 74 | } 75 | return true 76 | } 77 | 78 | func generate() { 79 | util.Debug("ReadFile %s\n", inputGo) 80 | var err error 81 | config.MarshalTextRep, err = enum.AsRepresentation(marshalTextRep) 82 | util.Must(err, "(-marshaltext)") 83 | 84 | config.MarshalJSONRep, err = enum.AsRepresentation(marshalJSONRep) 85 | util.Must(err, "(-marshaljson)") 86 | 87 | config.StoreRep, err = enum.AsRepresentation(storeRep) 88 | util.Must(err, "(-store)") 89 | 90 | var in io.Reader = os.Stdin 91 | if inputGo != "-" { 92 | inf, e2 := os.Open(inputGo) 93 | util.Must(e2) 94 | defer inf.Close() 95 | in = inf 96 | } 97 | 98 | var out model.DualWriter = os.Stdout 99 | if outputGo == "-" { 100 | if config.Pkg == "" { 101 | util.Fail("-pkg is required when piping the output.") 102 | } 103 | } else { 104 | outf, e2 := os.Create(outputGo) 105 | util.Must(e2) 106 | defer outf.Close() 107 | out = outf 108 | config.Pkg = choosePackage(outputGo) 109 | util.Stdout = os.Stdout // ok because it's not going to be interleaved now 110 | } 111 | util.Debug("pkg=%s\n", config.Pkg) 112 | 113 | xCase := transform.Of(lowercase, uppercase) 114 | 115 | m, err := parse.Convert(in, inputGo, xCase, config) 116 | util.Must(err) 117 | 118 | units := m.BuildUnits() 119 | model.WriteGo(units, m, out) 120 | util.Info("Generated %s.\n", outputGo) 121 | } 122 | 123 | func main() { 124 | defineFlags() 125 | flag.Parse() 126 | doMain() 127 | } 128 | 129 | func doMain() { 130 | config.Version = appVersion 131 | 132 | if showVersion { 133 | fmt.Fprintln(os.Stdout, appVersion) 134 | os.Exit(0) 135 | } 136 | 137 | if config.MainType == "" { 138 | util.Fail("Must specify -type.") 139 | } 140 | 141 | if config.Plural == "" { 142 | config.Plural = config.MainType + "s" 143 | } 144 | 145 | if inputGo == "" { 146 | inputGo = strings.ToLower(config.MainType) + ".go" 147 | } 148 | 149 | if outputGo == "" { 150 | outputGo = strings.ToLower(config.MainType) + "_enum.go" 151 | } else if outputGo == "-" { 152 | util.Stdout = os.Stderr // avoiding interleaving with the output of generated code 153 | } 154 | 155 | if outputJSON == "" { 156 | outputJSON = strings.ToLower(config.MainType) + "_enum.json" 157 | } 158 | 159 | if config.SimpleOnly { 160 | config.IgnoreCase = false 161 | config.Lenient = false 162 | } 163 | 164 | util.Debug("type=%s\n", config.MainType) 165 | util.Debug("plural=%s\n", config.Plural) 166 | util.Debug("inputGo=%s\n", inputGo) 167 | util.Debug("outputGo=%s\n", outputGo) 168 | util.Debug("outputJSON=%s\n", outputJSON) 169 | 170 | if force || notUpToDate() { 171 | generate() 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /enumeration_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/rickb777/enumeration/v4/internal/model" 6 | "github.com/rickb777/enumeration/v4/internal/parse" 7 | "github.com/rickb777/expect" 8 | "go/scanner" 9 | "go/token" 10 | "io" 11 | "os" 12 | "strings" 13 | "testing" 14 | ) 15 | 16 | func TestMainApp_Day(t *testing.T) { 17 | outputFile := "temp/example/day_enum.go" 18 | 19 | remove(t, outputGo) 20 | 21 | os.Args = []string{"", "-f", "-type", "Day", "-i", "temp/example/day.go", "-o", outputFile} 22 | 23 | main() 24 | 25 | compareGeneratedFile(t, outputFile) 26 | } 27 | 28 | func TestMainApp_Channel(t *testing.T) { 29 | inputGo = "temp/example/channel.go" 30 | outputGo = "temp/example/channel_enum.go" 31 | 32 | remove(t, outputGo) 33 | 34 | force = true 35 | lowercase, uppercase, showVersion = false, false, false 36 | outputJSON, marshalTextRep, marshalJSONRep, storeRep = "", "None", "None", "None" 37 | 38 | model.Prefix = "" 39 | model.Suffix = "Sales" 40 | parse.AliasTable = "" 41 | 42 | config = model.Config{ 43 | MainType: "SalesChannel", 44 | } 45 | 46 | doMain() 47 | 48 | compareGeneratedFile(t, outputGo) 49 | } 50 | 51 | func TestMainApp_Country(t *testing.T) { 52 | inputGo = "temp/example/country.go" 53 | outputGo = "temp/example/country_enum.go" 54 | 55 | remove(t, outputGo) 56 | 57 | force = true 58 | lowercase, uppercase, showVersion = false, false, false 59 | outputJSON, marshalTextRep, marshalJSONRep, storeRep = "", "None", "None", "Number" 60 | 61 | model.Prefix = "" 62 | model.Suffix = "" 63 | parse.AliasTable = "iso3166_3LetterCodes" 64 | 65 | config = model.Config{ 66 | MainType: "Country", 67 | Plural: "Countries", 68 | IgnoreCase: true, 69 | Unsnake: true, 70 | } 71 | 72 | doMain() 73 | 74 | compareGeneratedFile(t, outputGo) 75 | } 76 | 77 | func TestMainApp_Method(t *testing.T) { 78 | inputGo = "temp/example/method.go" 79 | outputGo = "temp/example/method_enum.go" 80 | 81 | remove(t, outputGo) 82 | 83 | force = true 84 | lowercase, uppercase, showVersion = false, false, false 85 | outputJSON, marshalTextRep, marshalJSONRep, storeRep = "", "None", "None", "Number" 86 | 87 | model.Prefix = "" 88 | model.Suffix = "" 89 | parse.AliasTable = "" 90 | 91 | config = model.Config{ 92 | MainType: "Method", 93 | IgnoreCase: true, 94 | } 95 | 96 | doMain() 97 | 98 | compareGeneratedFile(t, outputGo) 99 | } 100 | 101 | func remove(t *testing.T, file string) { 102 | err := os.Remove(file) 103 | if err != nil { 104 | t.Logf("rm %s: %s", file, err.Error()) 105 | // continue anyway 106 | } 107 | } 108 | 109 | func compareGeneratedFile(t *testing.T, fileName string) { 110 | src, err := os.ReadFile(fileName) 111 | expect.Error(err).Not().ToHaveOccurred(t) 112 | 113 | var s scanner.Scanner 114 | fset := token.NewFileSet() // positions are relative to fset 115 | file := fset.AddFile("", fset.Base(), len(src)) // register input "file" 116 | s.Init(file, src, nil /* no error handler */, scanner.ScanComments) 117 | 118 | // check just the first few lines of the generated Go source code 119 | 120 | pos, tok, lit := s.Scan() 121 | expect.Number(tok).ToBe(t, token.COMMENT) 122 | 123 | _, tok, lit = s.Scan() 124 | expect.Number(tok).ToBe(t, token.COMMENT) 125 | 126 | _, tok, lit = s.Scan() 127 | expect.Number(tok).ToBe(t, token.PACKAGE) 128 | 129 | _, tok, lit = s.Scan() 130 | expect.Number(tok).ToBe(t, token.IDENT) 131 | expect.String(lit).ToBe(t, "example") 132 | 133 | _, tok, lit = s.Scan() 134 | expect.Number(tok).ToBe(t, token.SEMICOLON) 135 | 136 | _, tok, lit = s.Scan() 137 | expect.Number(tok).ToBe(t, token.IMPORT) 138 | 139 | _, tok, lit = s.Scan() 140 | expect.Number(tok).ToBe(t, token.LPAREN) 141 | 142 | if testing.Verbose() { 143 | for { 144 | pos, tok, lit = s.Scan() 145 | if tok == token.EOF { 146 | break 147 | } 148 | fmt.Printf("%s\t%s\t%q\n", fset.Position(pos), tok, lit) 149 | } 150 | } 151 | } 152 | 153 | func TestScannerTryOut(t *testing.T) { 154 | if testing.Verbose() { 155 | for _, n := range []string{"example/base.go", "example/day.go", "example/country.go", "example/month.go"} { 156 | f, err := os.Open(n) 157 | expect.Error(err).Not().ToHaveOccurred(t) 158 | defer f.Close() 159 | 160 | fmt.Printf("-- %s\n", n) 161 | src, err := io.ReadAll(f) 162 | expect.Error(err).Not().ToHaveOccurred(t) 163 | 164 | var s scanner.Scanner 165 | fset := token.NewFileSet() // positions are relative to fset 166 | file := fset.AddFile("", fset.Base(), len(src)) // register input "file" 167 | s.Init(file, src, nil /* no error handler */, 0) 168 | 169 | for { 170 | pos, tok, lit := s.Scan() 171 | if tok == token.EOF { 172 | break 173 | } 174 | fmt.Printf("%s\t%s\t%q\n", fset.Position(pos), tok, lit) 175 | } 176 | fmt.Printf("%s\n", strings.Repeat("-", 80)) 177 | } 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /example/base.go: -------------------------------------------------------------------------------- 1 | package example 2 | 3 | //go:generate enumeration -v -f -type Base -lc -poly 4 | 5 | // Base example demonstrates using floating point values instead of integers. 6 | // These are float32 but could be float64; the only other restriction is that 7 | // no two values can be the same number. 8 | type Base float32 9 | 10 | // Nucleotide Molecular Weights, g/mol 11 | const A Base = 331.2 12 | const C Base = 307.2 13 | const G Base = 347.2 14 | const T Base = 322.2 15 | -------------------------------------------------------------------------------- /example/base_enum.go: -------------------------------------------------------------------------------- 1 | // generated code - do not edit 2 | // github.com/rickb777/enumeration/v4 v4.0.7 3 | 4 | package example 5 | 6 | import ( 7 | "errors" 8 | "fmt" 9 | "github.com/rickb777/enumeration/v4/enum" 10 | "slices" 11 | "strconv" 12 | "strings" 13 | ) 14 | 15 | // AllBases lists all 4 values in order. 16 | var AllBases = []Base{ 17 | A, C, G, T, 18 | } 19 | 20 | // AllBaseEnums lists all 4 values in order. 21 | var AllBaseEnums = enum.FloatEnums{ 22 | A, C, G, T, 23 | } 24 | 25 | const ( 26 | baseEnumStrings = "acgt" 27 | ) 28 | 29 | var ( 30 | baseEnumIndex = [...]uint16{0, 1, 2, 3, 4} 31 | ) 32 | 33 | // String returns the literal string representation of a Base, which is 34 | // the same as the const identifier but without prefix or suffix. 35 | func (v Base) String() string { 36 | o := v.Ordinal() 37 | return v.toString(o, baseEnumStrings, baseEnumIndex[:]) 38 | } 39 | 40 | // Ordinal returns the ordinal number of a Base. This is an integer counting 41 | // from zero. It is *not* the same as the const number assigned to the value. 42 | func (v Base) Ordinal() int { 43 | switch v { 44 | case A: 45 | return 0 46 | case C: 47 | return 1 48 | case G: 49 | return 2 50 | case T: 51 | return 3 52 | } 53 | return -1 54 | } 55 | 56 | func (v Base) toString(o int, concats string, indexes []uint16) string { 57 | if o < 0 || o >= len(AllBases) { 58 | return fmt.Sprintf("Base(%g)", v) 59 | } 60 | return concats[indexes[o]:indexes[o+1]] 61 | } 62 | 63 | // IsValid determines whether a Base is one of the defined constants. 64 | func (v Base) IsValid() bool { 65 | return v.Ordinal() >= 0 66 | } 67 | 68 | // Float returns the float64 value. It serves to facilitate polymorphism (see enum.FloatEnum). 69 | func (v Base) Float() float64 { 70 | return float64(v) 71 | } 72 | 73 | var invalidBaseValue = func() Base { 74 | var v Base 75 | for { 76 | if !slices.Contains(AllBases, v) { 77 | return v 78 | } 79 | v++ 80 | } // AllBases is a finite set so loop will terminate eventually 81 | }() 82 | 83 | // BaseOf returns a Base based on an ordinal number. This is the inverse of Ordinal. 84 | // If the ordinal is out of range, an invalid Base is returned. 85 | func BaseOf(v int) Base { 86 | if 0 <= v && v < len(AllBases) { 87 | return AllBases[v] 88 | } 89 | return invalidBaseValue 90 | } 91 | 92 | // Parse parses a string to find the corresponding Base, accepting one of the string values or 93 | // a number. It is used by AsBase. 94 | // 95 | // Usage Example 96 | // 97 | // v := new(Base) 98 | // err := v.Parse(s) 99 | // ... etc 100 | func (v *Base) Parse(in string) error { 101 | if v.parseNumber(in) { 102 | return nil 103 | } 104 | 105 | s := baseTransformInput(in) 106 | 107 | return v.parseFallback(in, s) 108 | } 109 | 110 | // parseNumber attempts to convert a decimal value. 111 | // Only numbers that correspond to the enumeration are valid. 112 | func (v *Base) parseNumber(s string) (ok bool) { 113 | num, err := strconv.ParseFloat(s, 64) 114 | if err == nil { 115 | *v = Base(num) 116 | return v.IsValid() 117 | } 118 | return false 119 | } 120 | 121 | func (v *Base) parseFallback(in, s string) error { 122 | if v.parseString(s, baseEnumStrings, baseEnumIndex[:]) { 123 | return nil 124 | } 125 | 126 | return errors.New(in + ": unrecognised base") 127 | } 128 | 129 | func (v *Base) parseString(s string, concats string, indexes []uint16) (ok bool) { 130 | var i0 uint16 = 0 131 | 132 | for j := 1; j < len(indexes); j++ { 133 | i1 := indexes[j] 134 | p := concats[i0:i1] 135 | if s == p { 136 | *v = AllBases[j-1] 137 | return true 138 | } 139 | i0 = i1 140 | } 141 | return false 142 | } 143 | 144 | // baseTransformInput may alter input strings before they are parsed. 145 | // This function is pluggable and is initialised using command-line flags 146 | // -ic -lc -uc -unsnake. 147 | var baseTransformInput = func(in string) string { 148 | return strings.ToLower(in) 149 | } 150 | 151 | // AsBase parses a string to find the corresponding Base, accepting either one of the string values or 152 | // a number. It wraps Parse. 153 | func AsBase(s string) (Base, error) { 154 | var v = new(Base) 155 | err := v.Parse(s) 156 | return *v, err 157 | } 158 | 159 | // MustParseBase is similar to AsBase except that it panics on error. 160 | func MustParseBase(s string) Base { 161 | v, err := AsBase(s) 162 | if err != nil { 163 | panic(err) 164 | } 165 | return v 166 | } 167 | -------------------------------------------------------------------------------- /example/channel.go: -------------------------------------------------------------------------------- 1 | package example 2 | 3 | //go:generate enumeration -v -i channel.go -o channel_enum.go -lc -type SalesChannel -suffix Sales -poly 4 | 5 | // preamble const declarations are ignored by the enumeration tool 6 | const IgnoreThisItem, AndThis = 741, "quack" 7 | 8 | const ( 9 | // One is ignored by the enumeration tool too 10 | One = 1 11 | ) 12 | 13 | // SalesChannel example demonstrates the removing of a suffix string from the identifiers 14 | // when their string equivalent is accessed. 15 | // 16 | // The `json` tags in comments control values used for JSON marshalling. 17 | // The `sql` tags in comments control values used for SQL storage. 18 | type SalesChannel int 19 | 20 | const ( 21 | OnlineSales SalesChannel = 3 // json:"webshop" sql:"o" -- String() is "online" 22 | InstoreSales SalesChannel = 5 // json:"store" sql:"s" -- String() is "instore" 23 | TelephoneSales SalesChannel = 7 // json:"phone" sql:"t" -- String() is "telephone" 24 | ) 25 | -------------------------------------------------------------------------------- /example/day.go: -------------------------------------------------------------------------------- 1 | package example 2 | 3 | //go:generate enumeration -v -type Day 4 | 5 | // Day simple example also shows that more than one 'const' block can be used 6 | // provided that the integer values are all distinct. 7 | type Day uint 8 | 9 | const ( 10 | _ Day = iota // throw away zeroth so that Sunday is 1 11 | Sunday 12 | Monday 13 | Tuesday 14 | Wednesday 15 | ) 16 | 17 | // It is allowable to break the constant blocks (although it's a bit 18 | // unnecessary here). However, the numeric values *must* all be distinct, 19 | // otherwise the generated enum will not compile. 20 | const ( 21 | Thursday Day = iota + 5 22 | Friday 23 | Saturday 24 | numberOfDays = int(Saturday) // this is not exported 25 | ) 26 | -------------------------------------------------------------------------------- /example/day_enum.go: -------------------------------------------------------------------------------- 1 | // generated code - do not edit 2 | // github.com/rickb777/enumeration/v4 v4.0.7 3 | 4 | package example 5 | 6 | import ( 7 | "errors" 8 | "fmt" 9 | "slices" 10 | "strconv" 11 | ) 12 | 13 | // AllDays lists all 7 values in order. 14 | var AllDays = []Day{ 15 | Sunday, Monday, Tuesday, Wednesday, 16 | Thursday, Friday, Saturday, 17 | } 18 | 19 | const ( 20 | dayEnumStrings = "SundayMondayTuesdayWednesdayThursdayFridaySaturday" 21 | ) 22 | 23 | var ( 24 | dayEnumIndex = [...]uint16{0, 6, 12, 19, 28, 36, 42, 50} 25 | ) 26 | 27 | // String returns the literal string representation of a Day, which is 28 | // the same as the const identifier but without prefix or suffix. 29 | func (v Day) String() string { 30 | o := v.Ordinal() 31 | return v.toString(o, dayEnumStrings, dayEnumIndex[:]) 32 | } 33 | 34 | // Ordinal returns the ordinal number of a Day. This is an integer counting 35 | // from zero. It is *not* the same as the const number assigned to the value. 36 | func (v Day) Ordinal() int { 37 | switch v { 38 | case Sunday: 39 | return 0 40 | case Monday: 41 | return 1 42 | case Tuesday: 43 | return 2 44 | case Wednesday: 45 | return 3 46 | case Thursday: 47 | return 4 48 | case Friday: 49 | return 5 50 | case Saturday: 51 | return 6 52 | } 53 | return -1 54 | } 55 | 56 | func (v Day) toString(o int, concats string, indexes []uint16) string { 57 | if o < 0 || o >= len(AllDays) { 58 | return fmt.Sprintf("Day(%d)", v) 59 | } 60 | return concats[indexes[o]:indexes[o+1]] 61 | } 62 | 63 | // IsValid determines whether a Day is one of the defined constants. 64 | func (v Day) IsValid() bool { 65 | return v.Ordinal() >= 0 66 | } 67 | 68 | // Int returns the int value, which is not necessarily the same as the ordinal. 69 | // This facilitates polymorphism (see enum.IntEnum). 70 | func (v Day) Int() int { 71 | return int(v) 72 | } 73 | 74 | var invalidDayValue = func() Day { 75 | var v Day 76 | for { 77 | if !slices.Contains(AllDays, v) { 78 | return v 79 | } 80 | v++ 81 | } // AllDays is a finite set so loop will terminate eventually 82 | }() 83 | 84 | // DayOf returns a Day based on an ordinal number. This is the inverse of Ordinal. 85 | // If the ordinal is out of range, an invalid Day is returned. 86 | func DayOf(v int) Day { 87 | if 0 <= v && v < len(AllDays) { 88 | return AllDays[v] 89 | } 90 | return invalidDayValue 91 | } 92 | 93 | // Parse parses a string to find the corresponding Day, accepting one of the string values or 94 | // a number. It is used by AsDay. 95 | // 96 | // Usage Example 97 | // 98 | // v := new(Day) 99 | // err := v.Parse(s) 100 | // ... etc 101 | func (v *Day) Parse(in string) error { 102 | if v.parseNumber(in) { 103 | return nil 104 | } 105 | 106 | s := dayTransformInput(in) 107 | 108 | return v.parseFallback(in, s) 109 | } 110 | 111 | // parseNumber attempts to convert a decimal value. 112 | // Only numbers that correspond to the enumeration are valid. 113 | func (v *Day) parseNumber(s string) (ok bool) { 114 | num, err := strconv.ParseInt(s, 10, 64) 115 | if err == nil { 116 | *v = Day(num) 117 | return v.IsValid() 118 | } 119 | return false 120 | } 121 | 122 | func (v *Day) parseFallback(in, s string) error { 123 | if v.parseString(s, dayEnumStrings, dayEnumIndex[:]) { 124 | return nil 125 | } 126 | 127 | return errors.New(in + ": unrecognised day") 128 | } 129 | 130 | func (v *Day) parseString(s string, concats string, indexes []uint16) (ok bool) { 131 | var i0 uint16 = 0 132 | 133 | for j := 1; j < len(indexes); j++ { 134 | i1 := indexes[j] 135 | p := concats[i0:i1] 136 | if s == p { 137 | *v = AllDays[j-1] 138 | return true 139 | } 140 | i0 = i1 141 | } 142 | return false 143 | } 144 | 145 | // dayTransformInput may alter input strings before they are parsed. 146 | // This function is pluggable and is initialised using command-line flags 147 | // -ic -lc -uc -unsnake. 148 | var dayTransformInput = func(in string) string { 149 | return in 150 | } 151 | 152 | // AsDay parses a string to find the corresponding Day, accepting either one of the string values or 153 | // a number. It wraps Parse. 154 | func AsDay(s string) (Day, error) { 155 | var v = new(Day) 156 | err := v.Parse(s) 157 | return *v, err 158 | } 159 | 160 | // MustParseDay is similar to AsDay except that it panics on error. 161 | func MustParseDay(s string) Day { 162 | v, err := AsDay(s) 163 | if err != nil { 164 | panic(err) 165 | } 166 | return v 167 | } 168 | -------------------------------------------------------------------------------- /example/example_test.go: -------------------------------------------------------------------------------- 1 | package example 2 | 3 | import ( 4 | "bytes" 5 | "encoding/gob" 6 | "encoding/json" 7 | "encoding/xml" 8 | "github.com/rickb777/expect" 9 | "testing" 10 | ) 11 | 12 | func TestString(t *testing.T) { 13 | expect.String(Sunday.String()).ToBe(t, "Sunday") 14 | expect.String(Monday.String()).ToBe(t, "Monday") 15 | expect.String(MyDog.String()).ToBe(t, "dog") 16 | expect.String(OnlineSales.String()).ToBe(t, "online") 17 | } 18 | 19 | func TestOrdinal(t *testing.T) { 20 | expect.Number(int(Sunday)).ToBe(t, 1) 21 | expect.Number(Sunday.Ordinal()).ToBe(t, 0) 22 | expect.Number(int(Monday)).ToBe(t, 2) 23 | expect.Number(Monday.Ordinal()).ToBe(t, 1) 24 | expect.Number(Friday.Ordinal()).ToBe(t, 5) 25 | expect.Number(DayOf(0)).ToBe(t, Sunday) 26 | expect.Number(DayOf(3)).ToBe(t, Wednesday) 27 | expect.Number(DayOf(6)).ToBe(t, Saturday) 28 | expect.Number(DayOf(7)).ToBe(t, 0) 29 | expect.Number(DayOf(13)).ToBe(t, 0) 30 | expect.Bool(Wednesday.IsValid()).ToBeTrue(t) 31 | expect.Bool(Day(10).IsValid()).ToBeFalse(t) 32 | expect.Bool(DayOf(10).IsValid()).ToBeFalse(t) 33 | expect.Number(numberOfDays).ToBe(t, 7) 34 | } 35 | 36 | func TestIntOrFloat(t *testing.T) { 37 | expect.Number(G.Float()).ToBe(t, 347.20001220703125) 38 | expect.Number(Sunday.Int()).ToBe(t, 1) 39 | expect.Number(Wednesday.Int()).ToBe(t, 4) 40 | expect.Number(Θήτα.Int()).ToBe(t, 8) 41 | expect.Number(POST.Int()).ToBe(t, 3) 42 | expect.Number(November.Int()).ToBe(t, 11) 43 | expect.Number(MyKoala_Bear.Int()).ToBe(t, 4) 44 | } 45 | 46 | func TestAllDays(t *testing.T) { 47 | expect.Any(AllDays[0]).ToBe(t, Sunday) 48 | expect.Any(AllDays[5]).ToBe(t, Friday) 49 | } 50 | 51 | func TestAsDay(t *testing.T) { 52 | v, err := AsDay("Tuesday") 53 | expect.Any(v, err).ToBe(t, Tuesday) 54 | _, err = AsDay("Nosuchday") 55 | expect.Error(err).ToHaveOccurred(t) 56 | } 57 | 58 | func TestAsMethod(t *testing.T) { 59 | //methodMarshalTextRep = enum.Identifier 60 | expect.Number(AsMethod("POST")).ToBe(t, POST) 61 | //expect.Number(AsMethod("PO")).ToBe(POST)) 62 | expect.Number(AsMethod("3")).ToBe(t, POST) 63 | 64 | expect.Number(AsMethod("PUT")).ToBe(t, PUT) 65 | //expect.Number( AsMethod("PU")).ToBe(PUT)) 66 | expect.Number(AsMethod("2")).ToBe(t, PUT) 67 | } 68 | 69 | //------------------------------------------------------------------------------------------------- 70 | 71 | type Group struct { 72 | B Base 73 | D Day 74 | G GreekAlphabet 75 | X Method 76 | M Month 77 | P Pet 78 | C SalesChannel 79 | } 80 | 81 | func TestMarshal(t *testing.T) { 82 | //setMarshalReps(enum.Number) 83 | v := Group{G, Tuesday, Θήτα, POST, November, MyKoala_Bear, OnlineSales} 84 | s, err := json.Marshal(v) 85 | expect.Error(err).Not().ToHaveOccurred(t) 86 | x, err := xml.Marshal(v) 87 | expect.Error(err).Not().ToHaveOccurred(t) 88 | expect.String(s).ToEqual(t, `{"B":347.2,"D":3,"G":"theta","X":"PO","M":"November","P":"Phascolarctos Cinereus","C":"webshop"}`) 89 | expect.String(x).ToEqual(t, `347.23theta3November

Phascolarctos Cinereus

3
`) 90 | } 91 | 92 | func TestMethodScan(t *testing.T) { 93 | //methodStoreRep = enum.Ordinal 94 | cases := []interface{}{ 95 | int64(3), int64(3), float64(3), "POST", "post", []byte("POST"), 96 | } 97 | for i, s := range cases { 98 | if i > 0 { 99 | //methodStoreRep = enum.Identifier 100 | } 101 | var m = new(Method) 102 | err := m.Scan(s) 103 | expect.Error(err).Info(i).Not().ToHaveOccurred(t) 104 | expect.Number(*m).Info(i).ToBe(t, POST) 105 | } 106 | } 107 | 108 | //func TestMonthScan(t *testing.T) { 109 | // g := gomega.NewWithT(t) 110 | // 111 | // //monthStoreRep = enum.Ordinal 112 | // cases := []interface{}{ 113 | // int64(10), int64(11), float64(11), "november", []byte("NOVEMBER"), 114 | // } 115 | // for i, s := range cases { 116 | // if i > 0 { 117 | // //monthStoreRep = enum.Identifier 118 | // } 119 | // var m = new(Month) 120 | // err := m.Scan(s) 121 | // expect.String(t, err).NotTo(gomega.HaveOccurred()) 122 | // expect.String(t, *m).ToBe(November)) 123 | // } 124 | //} 125 | 126 | //func TestPetScan(t *testing.T) { 127 | // g := gomega.NewWithT(t) 128 | // 129 | // //petStoreRep = enum.Ordinal 130 | // cases := []interface{}{ 131 | // int64(4), int64(4), float64(4), "Koala Bear", "koala bear", "koala_bear", []byte("Koala Bear"), "Phascolarctos Cinereus", 132 | // } 133 | // for i, s := range cases { 134 | // if i > 0 { 135 | // //petStoreRep = enum.Identifier 136 | // } 137 | // var m = new(Pet) 138 | // err := m.Scan(s) 139 | // expect.String(t, err).NotTo(gomega.HaveOccurred()) 140 | // expect.String(t, *m).ToBe(MyKoala_Bear)) 141 | // } 142 | //} 143 | 144 | func TestSalesChannelScan(t *testing.T) { 145 | cases := []struct { 146 | in interface{} 147 | expected SalesChannel 148 | }{ 149 | {in: int64(7), expected: TelephoneSales}, 150 | {in: float64(7), expected: TelephoneSales}, 151 | {in: "5", expected: InstoreSales}, 152 | {in: "s", expected: InstoreSales}, 153 | {in: []byte("o"), expected: OnlineSales}, 154 | {in: nil, expected: 0}, 155 | } 156 | for _, c := range cases { 157 | var m = new(SalesChannel) 158 | err := m.Scan(c.in) 159 | expect.Error(err).Info("%#v", c.in).ToBeNil(t) 160 | expect.Any(*m).Info("%#v", c.in).ToBe(t, c.expected) 161 | } 162 | } 163 | 164 | func TestValue(t *testing.T) { 165 | expect.Any(TelephoneSales.Value()).ToEqual(t, "t") 166 | expect.Any(Egypt.Value()).ToEqual(t, "eg") 167 | expect.Any(Ζήτα.Value()).ToEqual(t, "\u0396") 168 | expect.Any(POST.Value()).ToEqual(t, int64(3)) 169 | } 170 | 171 | func TestGobEncodeAndDecode(t *testing.T) { 172 | v1 := Group{B: G, D: Tuesday, G: Θήτα, X: POST, M: November, P: MyKoala_Bear} 173 | gob.Register(v1) 174 | 175 | // gob-encode 176 | buf := &bytes.Buffer{} 177 | enc := gob.NewEncoder(buf) 178 | err := enc.Encode(v1) 179 | expect.Error(err).Not().ToHaveOccurred(t) 180 | 181 | // gob-decode 182 | var v2 Group 183 | dec := gob.NewDecoder(buf) 184 | err = dec.Decode(&v2) 185 | expect.Error(err).Not().ToHaveOccurred(t) 186 | expect.Any(v2).ToBe(t, v1) 187 | } 188 | -------------------------------------------------------------------------------- /example/greekalphabet.go: -------------------------------------------------------------------------------- 1 | package example 2 | 3 | //go:generate enumeration -v -type GreekAlphabet 4 | 5 | // GreekAlphabet example shows non-ASCII characters in use. There is also a cross-mapping 6 | // table specified via the '-using' option. So the parser recognises inputs from both 7 | // sets of strings. 8 | // 9 | // See also 10 | // https://unicode.org/charts/PDF/U0370.pdf 11 | // https://en.wikipedia.org/wiki/Greek_alphabet 12 | type GreekAlphabet int 13 | 14 | const ( 15 | Αλφα GreekAlphabet = iota + 1 // text:"alpha" sql:"\u0391" = Α 16 | Βήτα // text:"beta" sql:"\u0392" 17 | Γάμμα // text:"gamma" sql:"\u0393" 18 | Δέλτα // text:"delta" sql:"\u0394" 19 | Εψιλον // text:"epsilon" sql:"\u0395" 20 | Ζήτα // text:"zeta" sql:"\u0396" 21 | Ητα // text:"eta" sql:"\u0397" 22 | Θήτα // text:"theta" sql:"\u0398" 23 | Ιώτα // text:"iota" sql:"\u0399" 24 | Κάππα // text:"kappa" sql:"\u039A" 25 | Λάμβδα // text:"lambda" sql:"\u039B" 26 | Μυ // text:"mu" sql:"\u039C" 27 | Νυ // text:"nu" sql:"\u039D" 28 | Ξι // text:"xi" sql:"\u039E" 29 | Ομικρον // text:"omicron" sql:"\u039F" 30 | Πι // text:"pi" sql:"\u03A0" 31 | Ρώ // text:"rho" sql:"\u03A1" 32 | Σίγμα // text:"sigma" sql:"\u03A3" 33 | Ταυ // text:"tau" sql:"\u03A4" 34 | Υψιλον // text:"upsilon" sql:"\u03A5" 35 | Φι // text:"phi" sql:"\u03A6" 36 | Χι // text:"chi" sql:"\u03A7" 37 | Ψι // text:"psi" sql:"\u03A8" 38 | Ωμέγα // text:"omega" sql:"\u03A9" 39 | // n.b. there is no u03A2 40 | ) 41 | -------------------------------------------------------------------------------- /example/method.go: -------------------------------------------------------------------------------- 1 | package example 2 | 3 | //go:generate enumeration -v -type Method -ic -store number -poly 4 | 5 | // Method example has json tags that control the JSON representations. So the parser 6 | // recognises inputs from thes and the identifiers too. The '-ic' option means the parser ignores 7 | // the case of its inputs. 8 | // 9 | // See also SalesChannel. 10 | type Method uint 11 | 12 | const ( 13 | HEAD Method = iota // json:"HE" 14 | GET // json:"GE" 15 | PUT // json:"PU" 16 | POST // json:"PO" 17 | PATCH // json:"PA" 18 | DELETE // json:"DE" 19 | ) 20 | -------------------------------------------------------------------------------- /example/month.go: -------------------------------------------------------------------------------- 1 | package example 2 | 3 | //go:generate enumeration -v -type Month -ic -marshaltext identifier 4 | 5 | // Month example shows that several comma-separated enumeration constants can 6 | // be on each line, and they can have explicit values. The '-ic' option means 7 | // the parser ignores the case of its inputs. 8 | type Month uint 9 | 10 | const ( 11 | January, February, March Month = 1, 2, 3 12 | April, May, June Month = 4, 5, 6 13 | July, August, September Month = 7, 8, 9 14 | October, November, December Month = 10, 11, 12 15 | ) 16 | -------------------------------------------------------------------------------- /example/pet.go: -------------------------------------------------------------------------------- 1 | package example 2 | 3 | //go:generate enumeration -v -type Pet -prefix My -unsnake -lc -alias petAliases -lenient 4 | 5 | // Pet example has a cross-mapping table specified via the 'text' tags. So the parser 6 | // recognises inputs from both sets of strings. Also: 7 | // 8 | // - The '-lc' option means the parser expects lowercase inputs and the String method 9 | // gives lowercase values. 10 | // 11 | // - The -prefix option means each identifer, MyCat etc, is stored in the enumeration 12 | // as just "cat" without the "My" prefix. 13 | // 14 | // - Because of '-unsnake', underscores are replaced with spaces so "MyKoala_Bear" is 15 | // treated as "koala bear". 16 | // 17 | // - Because of the '-lenient' option, the parser will allow numbers outside the valid 18 | // range 0 to 4. 19 | type Pet uint16 20 | 21 | // These all have prefix "My", which is stripped from the String representation. 22 | const ( 23 | MyCat Pet = iota // text:"Felis Catus" 24 | MyDog // text:"Canis Lupus" 25 | MyMouse // text:"Mus Musculus" 26 | MyElephant // text:"Loxodonta Africana" 27 | MyKoala_Bear // text:"Phascolarctos Cinereus" 28 | ) 29 | 30 | // petAliases provide more strings that are recognised during parsing. 31 | // Although the map keys must be unique, the values do not need to be. 32 | // Note that -lc means the keys here mus also be lowercase. 33 | var petAliases = map[string]Pet{ 34 | "sid": MyCat, 35 | "diego": MyCat, 36 | "pooch": MyDog, 37 | "whiskers": MyMouse, 38 | "faithful": MyElephant, 39 | "cuddly": MyKoala_Bear, 40 | } 41 | -------------------------------------------------------------------------------- /example/pet_enum.go: -------------------------------------------------------------------------------- 1 | // generated code - do not edit 2 | // github.com/rickb777/enumeration/v4 v4.0.7 3 | 4 | package example 5 | 6 | import ( 7 | "errors" 8 | "fmt" 9 | "slices" 10 | "strconv" 11 | "strings" 12 | ) 13 | 14 | // AllPets lists all 5 values in order. 15 | var AllPets = []Pet{ 16 | MyCat, MyDog, MyMouse, MyElephant, 17 | MyKoala_Bear, 18 | } 19 | 20 | const ( 21 | petEnumStrings = "catdogmouseelephantkoala bear" 22 | petTextStrings = "Felis CatusCanis LupusMus MusculusLoxodonta AfricanaPhascolarctos Cinereus" 23 | ) 24 | 25 | var ( 26 | petEnumIndex = [...]uint16{0, 3, 6, 11, 19, 29} 27 | petTextIndex = [...]uint16{0, 11, 22, 34, 52, 74} 28 | ) 29 | 30 | // String returns the literal string representation of a Pet, which is 31 | // the same as the const identifier but without prefix or suffix. 32 | func (v Pet) String() string { 33 | o := v.Ordinal() 34 | return v.toString(o, petEnumStrings, petEnumIndex[:]) 35 | } 36 | 37 | // Ordinal returns the ordinal number of a Pet. This is an integer counting 38 | // from zero. It is *not* the same as the const number assigned to the value. 39 | func (v Pet) Ordinal() int { 40 | switch v { 41 | case MyCat: 42 | return 0 43 | case MyDog: 44 | return 1 45 | case MyMouse: 46 | return 2 47 | case MyElephant: 48 | return 3 49 | case MyKoala_Bear: 50 | return 4 51 | } 52 | return -1 53 | } 54 | 55 | func (v Pet) toString(o int, concats string, indexes []uint16) string { 56 | if o < 0 || o >= len(AllPets) { 57 | return fmt.Sprintf("Pet(%d)", v) 58 | } 59 | return concats[indexes[o]:indexes[o+1]] 60 | } 61 | 62 | // IsValid determines whether a Pet is one of the defined constants. 63 | func (v Pet) IsValid() bool { 64 | return v.Ordinal() >= 0 65 | } 66 | 67 | // Int returns the int value, which is not necessarily the same as the ordinal. 68 | // This facilitates polymorphism (see enum.IntEnum). 69 | func (v Pet) Int() int { 70 | return int(v) 71 | } 72 | 73 | var invalidPetValue = func() Pet { 74 | var v Pet 75 | for { 76 | if !slices.Contains(AllPets, v) { 77 | return v 78 | } 79 | v++ 80 | } // AllPets is a finite set so loop will terminate eventually 81 | }() 82 | 83 | // PetOf returns a Pet based on an ordinal number. This is the inverse of Ordinal. 84 | // If the ordinal is out of range, an invalid Pet is returned. 85 | func PetOf(v int) Pet { 86 | if 0 <= v && v < len(AllPets) { 87 | return AllPets[v] 88 | } 89 | return invalidPetValue 90 | } 91 | 92 | // Parse parses a string to find the corresponding Pet, accepting one of the string values or 93 | // a number. It is used by AsPet. 94 | // 95 | // Usage Example 96 | // 97 | // v := new(Pet) 98 | // err := v.Parse(s) 99 | // ... etc 100 | func (v *Pet) Parse(in string) error { 101 | if v.parseNumber(in) { 102 | return nil 103 | } 104 | 105 | s := petTransformInput(in) 106 | 107 | return v.parseFallback(in, s) 108 | } 109 | 110 | // parseNumber attempts to convert a decimal value. 111 | // Any number is allowed, even if the result is invalid. 112 | func (v *Pet) parseNumber(s string) (ok bool) { 113 | num, err := strconv.ParseInt(s, 10, 64) 114 | if err == nil { 115 | *v = Pet(num) 116 | return true 117 | } 118 | return false 119 | } 120 | 121 | func (v *Pet) parseFallback(in, s string) error { 122 | if v.parseString(s, petEnumStrings, petEnumIndex[:]) { 123 | return nil 124 | } 125 | 126 | var ok bool 127 | *v, ok = petAliases[s] 128 | if ok { 129 | return nil 130 | } 131 | 132 | return errors.New(in + ": unrecognised pet") 133 | } 134 | 135 | func (v *Pet) parseString(s string, concats string, indexes []uint16) (ok bool) { 136 | var i0 uint16 = 0 137 | 138 | for j := 1; j < len(indexes); j++ { 139 | i1 := indexes[j] 140 | p := concats[i0:i1] 141 | if s == p { 142 | *v = AllPets[j-1] 143 | return true 144 | } 145 | i0 = i1 146 | } 147 | *v, ok = petAliases[s] 148 | return ok 149 | } 150 | 151 | // petTransformInput may alter input strings before they are parsed. 152 | // This function is pluggable and is initialised using command-line flags 153 | // -ic -lc -uc -unsnake. 154 | var petTransformInput = func(in string) string { 155 | return strings.ReplaceAll(strings.ToLower(in), "_", " ") 156 | } 157 | 158 | // AsPet parses a string to find the corresponding Pet, accepting either one of the string values or 159 | // a number. It wraps Parse. 160 | func AsPet(s string) (Pet, error) { 161 | var v = new(Pet) 162 | err := v.Parse(s) 163 | return *v, err 164 | } 165 | 166 | // MustParsePet is similar to AsPet except that it panics on error. 167 | func MustParsePet(s string) Pet { 168 | v, err := AsPet(s) 169 | if err != nil { 170 | panic(err) 171 | } 172 | return v 173 | } 174 | 175 | // MarshalText converts values to bytes suitable for transmission via XML, JSON etc. 176 | func (v Pet) MarshalText() ([]byte, error) { 177 | s, err := v.marshalText() 178 | return []byte(s), err 179 | } 180 | 181 | // Text returns the representation used for transmission via XML, JSON etc. 182 | func (v Pet) Text() string { 183 | s, _ := v.marshalText() 184 | return s 185 | } 186 | 187 | // marshalText converts values to bytes suitable for transmission via XML, JSON etc. 188 | // The representation is chosen according to 'text' struct tags. 189 | func (v Pet) marshalText() (string, error) { 190 | o := v.Ordinal() 191 | if o < 0 { 192 | return v.marshalNumberStringOrError() 193 | } 194 | 195 | return v.toString(o, petTextStrings, petTextIndex[:]), nil 196 | } 197 | 198 | func (v Pet) marshalNumberStringOrError() (string, error) { 199 | bs, err := v.marshalNumberOrError() 200 | return string(bs), err 201 | } 202 | 203 | func (v Pet) marshalNumberOrError() ([]byte, error) { 204 | // allow lenient marshaling 205 | return []byte(petMarshalNumber(v)), nil 206 | } 207 | 208 | // petMarshalNumber handles marshaling where a number is required or where 209 | // the value is out of range. 210 | // This function can be replaced with any bespoke function than matches signature. 211 | var petMarshalNumber = func(v Pet) string { 212 | return strconv.FormatInt(int64(v), 10) 213 | } 214 | 215 | // UnmarshalText converts transmitted values to ordinary values. 216 | func (v *Pet) UnmarshalText(bs []byte) error { 217 | return v.unmarshalText(string(bs)) 218 | } 219 | 220 | func (v *Pet) unmarshalText(in string) error { 221 | if v.parseNumber(in) { 222 | return nil 223 | } 224 | 225 | s := petTransformInput(in) 226 | 227 | if v.parseString(s, petTextStrings, petTextIndex[:]) { 228 | return nil 229 | } 230 | 231 | return v.parseFallback(in, s) 232 | } 233 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/rickb777/enumeration/v4 2 | 3 | require ( 4 | github.com/magefile/mage v1.15.0 5 | github.com/rickb777/expect v0.24.0 6 | ) 7 | 8 | require ( 9 | github.com/google/go-cmp v0.7.0 // indirect 10 | github.com/rickb777/plural v1.4.4 // indirect 11 | ) 12 | 13 | go 1.24.1 14 | 15 | tool github.com/magefile/mage 16 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= 2 | github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 3 | github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= 4 | github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= 5 | github.com/rickb777/expect v0.21.0 h1:d06fVjsz2zGVfbEVRWetStwv/YKaxM4A0t39IzzST88= 6 | github.com/rickb777/expect v0.21.0/go.mod h1:NQTOf7atJ/89U2FLV1ghRp5XJDdZ8dV+8iW47kJ9q7c= 7 | github.com/rickb777/expect v0.24.0 h1:IzFxn4jINkVuCmx4jdQP7LxaIBhG60bDVbeGWk3xnzo= 8 | github.com/rickb777/expect v0.24.0/go.mod h1:jwwS3gmukQ7wPxzEtOhMJEv43UxSwOBE7MUgTt8CX0k= 9 | github.com/rickb777/plural v1.4.4 h1:OpZU8uRr9P2NkYAbkLMwlKNVJyJ5HvRcRBFyXGJtKGI= 10 | github.com/rickb777/plural v1.4.4/go.mod h1:DB19dtrplGS5s6VJVHn7tvmFYPoE83p1xqio3oVnNRM= 11 | -------------------------------------------------------------------------------- /internal/codegen/units.go: -------------------------------------------------------------------------------- 1 | package codegen 2 | 3 | import ( 4 | "github.com/rickb777/enumeration/v4/internal/collection" 5 | "slices" 6 | "unicode" 7 | ) 8 | 9 | type Unit struct { 10 | Declares string 11 | Requires []string 12 | Extra map[string]any 13 | Imports collection.Set[string] 14 | Transforms bool 15 | Template string 16 | } 17 | 18 | func (u Unit) Exported() bool { 19 | d := u.Declares 20 | if d[:2] == "v." { 21 | d = d[2:] 22 | } 23 | return unicode.IsUpper(rune(d[0])) 24 | } 25 | 26 | type Units struct { 27 | m map[string]Unit 28 | l []string 29 | } 30 | 31 | func New() *Units { 32 | return &Units{m: make(map[string]Unit)} 33 | } 34 | 35 | func (units *Units) Add(unit Unit) *Units { 36 | _, exists := units.m[unit.Declares] 37 | if !exists { 38 | units.l = append(units.l, unit.Declares) 39 | units.m[unit.Declares] = unit 40 | } 41 | return units 42 | } 43 | 44 | func (units *Units) Take(identifier string) (u Unit, found bool) { 45 | units.l = slices.DeleteFunc(units.l, func(id string) bool { 46 | return id == identifier 47 | }) 48 | u, found = units.m[identifier] 49 | //delete(units.m, identifier) 50 | return u, found 51 | } 52 | 53 | func (units *Units) Slice() []Unit { 54 | us := make([]Unit, 0, len(units.m)) 55 | for _, id := range units.l { 56 | us = append(us, units.m[id]) 57 | } 58 | return us 59 | } 60 | -------------------------------------------------------------------------------- /internal/codegen/units_test.go: -------------------------------------------------------------------------------- 1 | package codegen 2 | 3 | import ( 4 | "github.com/rickb777/enumeration/v4/internal/collection" 5 | "github.com/rickb777/expect" 6 | "testing" 7 | ) 8 | 9 | func TestUnits(t *testing.T) { 10 | us1 := New() 11 | u1 := Unit{ 12 | Declares: "aaa", 13 | Requires: []string{"bbb"}, 14 | Extra: map[string]any{"eee": 1}, 15 | Imports: collection.NewSet[string]("iii"), 16 | Template: "ttt", 17 | } 18 | us1.Add(u1) 19 | expect.Number(len(us1.m)).ToBe(t, 1) 20 | expect.Number(len(us1.l)).ToBe(t, 1) 21 | 22 | s := us1.Slice() 23 | expect.Number(len(s)).ToBe(t, 1) 24 | expect.Any(s).ToBe(t, []Unit{u1}) 25 | 26 | q1, found := us1.Take("aaa") 27 | expect.Bool(found).ToBeTrue(t) 28 | expect.Any(q1).ToBe(t, u1) 29 | //Ω(len(us1.m)).ToBe(0,t) 30 | expect.Slice(us1.l).ToHaveLength(t, 0) 31 | } 32 | -------------------------------------------------------------------------------- /internal/collection/set.go: -------------------------------------------------------------------------------- 1 | package collection 2 | 3 | import ( 4 | "cmp" 5 | "slices" 6 | ) 7 | 8 | type Set[T cmp.Ordered] map[T]struct{} 9 | 10 | func NewSet[T cmp.Ordered](vs ...T) Set[T] { 11 | return make(Set[T]).AddAll(vs...) 12 | } 13 | 14 | func (s Set[T]) AddAll(vs ...T) Set[T] { 15 | for _, v := range vs { 16 | s[v] = struct{}{} 17 | } 18 | return s 19 | } 20 | 21 | func (s Set[T]) Union(other Set[T]) Set[T] { 22 | for k := range other { 23 | s[k] = struct{}{} 24 | } 25 | return s 26 | } 27 | 28 | func (s Set[T]) Add(v T) { 29 | s[v] = struct{}{} 30 | } 31 | 32 | func (s Set[T]) Contains(v T) bool { 33 | _, exists := s[v] 34 | return exists 35 | } 36 | 37 | // Sorted returns the set as a sorted slice. 38 | func (s Set[T]) Sorted() []T { 39 | ss := make([]T, 0, len(s)) 40 | for k := range s { 41 | ss = append(ss, k) 42 | } 43 | slices.Sort(ss) 44 | return ss 45 | } 46 | -------------------------------------------------------------------------------- /internal/collection/set_test.go: -------------------------------------------------------------------------------- 1 | package collection 2 | 3 | import ( 4 | "github.com/rickb777/expect" 5 | "testing" 6 | ) 7 | 8 | func TestSetUnits(t *testing.T) { 9 | s1 := NewSet[string]("a", "b", "c") 10 | expect.Number(len(s1)).ToBe(t, 3) 11 | expect.Bool(s1.Contains("b")).ToBeTrue(t) 12 | expect.Bool(s1.Contains("x")).ToBeFalse(t) 13 | 14 | s1.AddAll("a", "x", "y") 15 | expect.Number(len(s1)).ToBe(t, 5) 16 | expect.Bool(s1.Contains("x")).ToBeTrue(t) 17 | 18 | s1.Add("z") 19 | expect.Number(len(s1)).ToBe(t, 6) 20 | expect.Bool(s1.Contains("z")).ToBeTrue(t) 21 | 22 | s1.Union(NewSet("a", "1", "b", "2")) 23 | expect.Number(len(s1)).ToBe(t, 8) 24 | expect.Bool(s1.Contains("2")).ToBeTrue(t) 25 | 26 | ss := s1.Sorted() 27 | expect.Slice(ss).ToBe(t, "1", "2", "a", "b", "c", "x", "y", "z") 28 | } 29 | -------------------------------------------------------------------------------- /internal/parse/convert.go: -------------------------------------------------------------------------------- 1 | package parse 2 | 3 | import ( 4 | "fmt" 5 | "go/token" 6 | "go/types" 7 | "io" 8 | "regexp" 9 | "strings" 10 | 11 | "github.com/rickb777/enumeration/v4/internal/collection" 12 | "github.com/rickb777/enumeration/v4/internal/model" 13 | "github.com/rickb777/enumeration/v4/internal/transform" 14 | "github.com/rickb777/enumeration/v4/internal/util" 15 | ) 16 | 17 | var ( 18 | AliasTable string 19 | MainType string 20 | ) 21 | 22 | var fset *token.FileSet 23 | 24 | var tagRE = regexp.MustCompile(`[a-z]:"`) 25 | 26 | // https://go.dev/doc/go1.17_spec#Type_declarations (without type parameters) 27 | // TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) . 28 | // TypeSpec = AliasDecl | TypeDef . 29 | // 30 | // TypeDef = identifier Type . 31 | // 32 | // Type = TypeName | TypeLit | "(" Type ")" . 33 | // TypeName = identifier | QualifiedIdent . 34 | // TypeLit = ArrayType | StructType | PointerType | FunctionType | InterfaceType | SliceType | MapType | ChannelType . 35 | 36 | func Convert(in io.Reader, input string, xCase transform.Case, config model.Config) (model.Model, error) { 37 | src, err := io.ReadAll(in) 38 | if err != nil { 39 | return model.Model{}, err 40 | } 41 | 42 | MainType = config.MainType 43 | 44 | outTrans := transform.ListOf(xCase, transform.Unsnake(config.Unsnake)) 45 | inTrans := outTrans 46 | if config.IgnoreCase && xCase == transform.Stet { 47 | inTrans = transform.ListOf(transform.Lower, transform.Unsnake(config.Unsnake)) 48 | } 49 | 50 | m := model.Model{ 51 | Config: config, 52 | LcType: strings.ToLower(config.MainType), 53 | BaseType: "int", 54 | InTrans: inTrans, 55 | OutTrans: outTrans, 56 | AliasTable: AliasTable, 57 | Extra: make(map[string]interface{}), 58 | Imports: collection.NewSet[string]("fmt"), 59 | } 60 | 61 | s := newFileScanner(input, src) 62 | 63 | var numFound = 0 64 | var constItems []constItem 65 | var baseType string 66 | var baseKind types.BasicKind 67 | 68 | for s.Scan() != token.EOF { 69 | switch s.Tok { 70 | case token.TYPE: 71 | baseType, baseKind, err = parseType(s, MainType, numFound) 72 | if err != nil { 73 | return m, fmt.Errorf("%s: %w", s.Position(), err) 74 | } 75 | if baseKind != types.Invalid { 76 | numFound++ 77 | m.BaseType = baseType 78 | m.BaseKind = baseKind 79 | } 80 | 81 | case token.CONST: 82 | constItems = parseConst(s, constItems) 83 | } 84 | } 85 | 86 | debugConstItems(constItems) 87 | 88 | m.Values, _ = filterExportedItems(config.MainType, constItems) 89 | 90 | debugValues(m.Values) 91 | 92 | if s.gs.ErrorCount > 0 { 93 | return model.Model{}, fmt.Errorf("%s: syntax error\n%s", input, strings.Join(s.errs, "\n")) 94 | } 95 | 96 | if numFound == 0 { 97 | return model.Model{}, fmt.Errorf("%s: failed to find type %s", input, config.MainType) 98 | } 99 | 100 | if len(m.Values) == 0 { 101 | return model.Model{}, fmt.Errorf("%s: failed to find any values for %s", input, config.MainType) 102 | } 103 | 104 | if e2 := m.CheckBadPrefixSuffix(); e2 != nil { 105 | return model.Model{}, e2 106 | } 107 | 108 | if e2 := m.CheckBadTags(); e2 != nil { 109 | return model.Model{}, e2 110 | } 111 | 112 | return m, nil 113 | } 114 | 115 | func filterExportedItems(mainType string, ids []constItem) (exported model.Values, defaultValue string) { 116 | var currentType string 117 | exported = make(model.Values, 0, len(ids)) 118 | 119 | for _, v := range ids { 120 | if v.typ == mainType { 121 | if token.IsExported(v.id) { 122 | exported = exported.Append(v.id, v.tag) 123 | switch v.expression { 124 | case "0", "iota": 125 | defaultValue = v.id 126 | } 127 | } 128 | 129 | } else if v.typ == "" && v.expression == "" && currentType == mainType { 130 | if token.IsExported(v.id) { 131 | exported = exported.Append(v.id, v.tag) 132 | } 133 | } 134 | 135 | if v.typ != "" { 136 | currentType = v.typ 137 | } 138 | } 139 | 140 | return exported, defaultValue 141 | } 142 | 143 | func debugConstItems(ids []constItem) { 144 | if util.Dbg { 145 | util.Debug("\n %-25s %-25s %-25s %s\n", "id", "type", "expression", "tag") 146 | for i, v := range ids { 147 | util.Debug("%-2d %-25s %-25s %-25s %s\n", i, v.id, v.typ, v.expression, v.tag) 148 | } 149 | } 150 | } 151 | 152 | func debugValues(values model.Values) { 153 | if util.Dbg { 154 | util.Debug("\n %-25s %-25s %-25s %s\n", "id", "short", "json", "sql") 155 | for i, v := range values { 156 | util.Debug("%-2d %-25s %-25s %-25s %s\n", i, v.Identifier, v.Shortened, v.JSON, v.SQL) 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /internal/parse/parse_const.go: -------------------------------------------------------------------------------- 1 | package parse 2 | 3 | import ( 4 | "github.com/rickb777/enumeration/v4/internal/util" 5 | "go/token" 6 | "reflect" 7 | "strings" 8 | ) 9 | 10 | type constItem struct { 11 | id, typ, expression string 12 | tag reflect.StructTag 13 | } 14 | 15 | func appendConstItems(items []constItem, ids []string, typ string, number string, tag reflect.StructTag) []constItem { 16 | if len(ids) == 1 { 17 | // include the tag 18 | return append(items, constItem{id: ids[0], typ: typ, expression: number, tag: tag}) 19 | } 20 | 21 | // don't include the tag 22 | for _, id := range ids { 23 | items = append(items, constItem{id: id, typ: typ, expression: number}) 24 | } 25 | return items 26 | } 27 | 28 | //------------------------------------------------------------------------------------------------- 29 | // https://go.dev/doc/go1.17_spec#Constant_declarations 30 | // ConstDecl = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) . 31 | // ConstSpec = IdentifierList [ [ Type ] "=" ExpressionList ] . 32 | // 33 | // IdentifierList = identifier { "," identifier } . 34 | // ExpressionList = Expression { "," Expression } . 35 | 36 | func parseConst(s *scanner, items []constItem) []constItem { 37 | for s.Tok != token.EOF { 38 | switch s.Scan() { 39 | case token.IDENT: 40 | return parseConstSpec(s, items) 41 | 42 | case token.LPAREN: 43 | return parseConstBlock(s, items) 44 | } 45 | } 46 | return items 47 | } 48 | 49 | func parseConstSpec(s *scanner, items []constItem) []constItem { 50 | ids := parseStringList(s) 51 | 52 | // parse the Type and the ExpressionList 53 | for s.Scan() != token.EOF { 54 | switch s.Tok { 55 | case token.IDENT: 56 | typeName := s.Lit 57 | switch s.Scan() { 58 | case token.ASSIGN: 59 | restOfLine, tag := readToEndOfLine(s) 60 | return appendConstItems(items, ids, typeName, restOfLine, tag) 61 | } 62 | 63 | case token.ASSIGN: 64 | restOfLine, tag := readToEndOfLine(s) 65 | return appendConstItems(items, ids, "", restOfLine, tag) 66 | } 67 | } 68 | 69 | return items 70 | } 71 | 72 | func parseStringList(s *scanner) []string { 73 | var ids []string 74 | for s.Tok == token.IDENT { 75 | ids = append(ids, s.Lit) 76 | 77 | if s.Peek() != token.COMMA { 78 | return ids 79 | } 80 | 81 | s.Scan() // the comma 82 | s.Scan() // the next ident? 83 | } 84 | 85 | return ids 86 | } 87 | 88 | func parseConstBlock(s *scanner, items []constItem) []constItem { 89 | for s.Scan() != token.EOF { 90 | switch s.Tok { 91 | case token.IDENT: 92 | ids := parseStringList(s) 93 | 94 | switch s.Scan() { 95 | case token.IDENT: 96 | typeName := s.Lit 97 | if s.Scan() == token.ASSIGN { 98 | restOfLine, tag := readToEndOfLine(s) 99 | items = appendConstItems(items, ids, typeName, restOfLine, tag) 100 | ids = nil 101 | } else { 102 | readToEndOfLine(s) // discard likely compilation error 103 | } 104 | 105 | case token.COMMENT: 106 | _, tag := readToEndOfLine(s) 107 | items = appendConstItems(items, ids, "", "", tag) 108 | ids = nil 109 | 110 | case token.SEMICOLON: 111 | restOfLine, tag := readToEndOfLine(s) 112 | items = appendConstItems(items, ids, "", restOfLine, tag) 113 | ids = nil 114 | } 115 | 116 | case token.RPAREN, token.EOF: 117 | return items 118 | 119 | //default: 120 | // _, _ = readToEndOfLine(s) 121 | } 122 | } 123 | 124 | return items 125 | } 126 | 127 | func readToEndOfLine(s *scanner) (rest string, commentTag reflect.StructTag) { 128 | if s.Tok == token.ASSIGN { 129 | s.Scan() 130 | } 131 | 132 | for s.Tok != token.SEMICOLON && s.Tok != token.EOF { 133 | if rest != "" { 134 | rest += " " 135 | } 136 | if s.Lit != "" { 137 | rest += s.Lit 138 | } else { 139 | rest += s.Tok.String() 140 | } 141 | 142 | if s.Tok == token.COMMENT { 143 | comment := strings.TrimSpace(s.Lit) 144 | if strings.HasPrefix(comment, "//") { 145 | comment = strings.TrimSpace(comment[2:]) 146 | if tagRE.MatchString(comment) { 147 | commentTag = reflect.StructTag(comment) 148 | } 149 | 150 | // COMMENT is optionally followed by SEMICOLON/EOF 151 | // but if not, then we've reached the end of the line anyway 152 | if s.nextTok != token.SEMICOLON && s.nextTok != token.EOF { 153 | util.Debug("%s ----- comment return %q %s\n", fset.Position(s.Pos), rest, commentTag) 154 | return rest, commentTag 155 | } 156 | } 157 | } 158 | 159 | s.Scan() 160 | } 161 | 162 | util.Debug("%s ----- return %q %s\n", fset.Position(s.Pos), rest, commentTag) 163 | return rest, commentTag 164 | } 165 | -------------------------------------------------------------------------------- /internal/parse/parse_type.go: -------------------------------------------------------------------------------- 1 | package parse 2 | 3 | import ( 4 | "fmt" 5 | "go/token" 6 | "go/types" 7 | "math" 8 | ) 9 | 10 | func parseType(s *scanner, mainType string, numFound int) (string, types.BasicKind, error) { 11 | for s.Tok != token.EOF { 12 | switch s.Scan() { 13 | case token.IDENT: 14 | return parseTypeSpec(s, mainType, numFound, 1) 15 | 16 | case token.LPAREN: 17 | switch s.Scan() { 18 | case token.IDENT: 19 | return parseTypeSpec(s, mainType, numFound, math.MaxInt) 20 | } 21 | } 22 | } 23 | 24 | return "", 0, nil 25 | } 26 | 27 | func parseTypeSpec(s *scanner, mainType string, numFound int, inBlock int) (string, types.BasicKind, error) { 28 | for s.Tok != token.EOF && inBlock > 0 { 29 | if s.Tok == token.IDENT && s.Lit == mainType { 30 | if numFound > 0 { 31 | return "", types.Invalid, fmt.Errorf("found multiple type %s declarations", mainType) 32 | } 33 | switch s.Scan() { 34 | case token.IDENT: 35 | switch s.Lit { 36 | case "int", "uint", 37 | "int8", "uint8", 38 | "int16", "uint16", 39 | "int32", "uint32", 40 | "int64", "uint64", 41 | "byte", "rune": 42 | return s.Lit, types.Int, nil 43 | case "float32", "float64": 44 | return s.Lit, types.Float64, nil 45 | default: 46 | return "", types.Invalid, fmt.Errorf("enumeration type %s must be an integer or float type", mainType) 47 | } 48 | 49 | case token.ASSIGN: 50 | return "", types.Invalid, fmt.Errorf("type %s is a type alias (not supported)", mainType) 51 | 52 | default: 53 | return "", types.Invalid, fmt.Errorf("syntax error in type %s declaration", mainType) 54 | } 55 | } 56 | s.Scan() 57 | inBlock-- 58 | } 59 | 60 | return "", 0, nil 61 | } 62 | -------------------------------------------------------------------------------- /internal/parse/scanner.go: -------------------------------------------------------------------------------- 1 | package parse 2 | 3 | import ( 4 | "fmt" 5 | "github.com/rickb777/enumeration/v4/internal/util" 6 | goscanner "go/scanner" 7 | "go/token" 8 | ) 9 | 10 | // scanner implements a one-place lookahead wrapper around the Go scanner. 11 | // It also coalesces SEMICOLON and COMMENT into one apparent SEMICOLON 12 | // with the literal from the COMMENT. 13 | type scanner struct { 14 | gs *goscanner.Scanner 15 | errs []string 16 | Pos token.Pos 17 | Tok token.Token 18 | Lit string 19 | nextPos token.Pos 20 | nextTok token.Token 21 | nextLit string 22 | } 23 | 24 | func (s *scanner) Peek() token.Token { 25 | return s.nextTok 26 | } 27 | 28 | func (s *scanner) doScan() { 29 | s.nextPos, s.nextTok, s.nextLit = s.gs.Scan() 30 | s.debug() 31 | } 32 | 33 | func (s *scanner) debug() { 34 | if s.Lit == "" { 35 | util.Debug("%-18s %s\n", fset.Position(s.Pos), s.Tok) 36 | } else { 37 | util.Debug("%-18s %-8s %q\n", fset.Position(s.Pos), s.Tok, s.Lit) 38 | } 39 | } 40 | 41 | func (s *scanner) Position() token.Position { 42 | return fset.Position(s.Pos) 43 | } 44 | 45 | func (s *scanner) Scan() token.Token { 46 | switch s.Tok { 47 | case token.EOF: 48 | return token.EOF 49 | } 50 | 51 | s.Pos = s.nextPos 52 | s.Tok = s.nextTok 53 | s.Lit = s.nextLit 54 | 55 | s.doScan() 56 | 57 | return s.Tok 58 | } 59 | 60 | func newFileScanner(input string, src []byte) *scanner { 61 | gs := new(goscanner.Scanner) 62 | sc := &scanner{gs: gs} 63 | eh := func(pos token.Position, msg string) { 64 | sc.errs = append(sc.errs, fmt.Sprintf("%s: %s", pos, msg)) 65 | } 66 | 67 | fset = token.NewFileSet() // positions are relative to fset 68 | file := fset.AddFile(input, fset.Base(), len(src)) // register input "file" 69 | gs.Init(file, src, eh, goscanner.ScanComments) 70 | return sc 71 | } 72 | -------------------------------------------------------------------------------- /internal/test/combinations.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rickb777/enumeration/eb21a46ef340fe393a3d41a02cffedb45348ef92/internal/test/combinations.xlsx -------------------------------------------------------------------------------- /internal/test/season.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | //go:generate enumeration -v -f -i season.go -type Season1 -suffix 1 4 | 5 | type Season1 uint 6 | 7 | const ( 8 | _ Season1 = iota 9 | Spring1 10 | Summer1 11 | Autumn1 12 | Winter1 13 | ) 14 | 15 | //------------------------------------------------------------------------------------------------- 16 | //go:generate enumeration -v -f -i season.go -type Season2 -suffix 2 -alias season2Alias 17 | 18 | type Season2 uint 19 | 20 | const ( 21 | _ Season2 = iota 22 | Spring2 23 | Summer2 24 | Autumn2 25 | Winter2 26 | ) 27 | 28 | var season2Alias = map[string]Season2{ 29 | "Fall2": Autumn2, 30 | } 31 | -------------------------------------------------------------------------------- /internal/test/season1_enum.go: -------------------------------------------------------------------------------- 1 | // generated code - do not edit 2 | // github.com/rickb777/enumeration/v4 v4.0.7 3 | 4 | package test 5 | 6 | import ( 7 | "errors" 8 | "fmt" 9 | "slices" 10 | "strconv" 11 | ) 12 | 13 | // AllSeason1s lists all 4 values in order. 14 | var AllSeason1s = []Season1{ 15 | Spring1, Summer1, Autumn1, Winter1, 16 | } 17 | 18 | const ( 19 | season1EnumStrings = "SpringSummerAutumnWinter" 20 | ) 21 | 22 | var ( 23 | season1EnumIndex = [...]uint16{0, 6, 12, 18, 24} 24 | ) 25 | 26 | // String returns the literal string representation of a Season1, which is 27 | // the same as the const identifier but without prefix or suffix. 28 | func (v Season1) String() string { 29 | o := v.Ordinal() 30 | return v.toString(o, season1EnumStrings, season1EnumIndex[:]) 31 | } 32 | 33 | // Ordinal returns the ordinal number of a Season1. This is an integer counting 34 | // from zero. It is *not* the same as the const number assigned to the value. 35 | func (v Season1) Ordinal() int { 36 | switch v { 37 | case Spring1: 38 | return 0 39 | case Summer1: 40 | return 1 41 | case Autumn1: 42 | return 2 43 | case Winter1: 44 | return 3 45 | } 46 | return -1 47 | } 48 | 49 | func (v Season1) toString(o int, concats string, indexes []uint16) string { 50 | if o < 0 || o >= len(AllSeason1s) { 51 | return fmt.Sprintf("Season1(%d)", v) 52 | } 53 | return concats[indexes[o]:indexes[o+1]] 54 | } 55 | 56 | // IsValid determines whether a Season1 is one of the defined constants. 57 | func (v Season1) IsValid() bool { 58 | return v.Ordinal() >= 0 59 | } 60 | 61 | // Int returns the int value, which is not necessarily the same as the ordinal. 62 | // This facilitates polymorphism (see enum.IntEnum). 63 | func (v Season1) Int() int { 64 | return int(v) 65 | } 66 | 67 | var invalidSeason1Value = func() Season1 { 68 | var v Season1 69 | for { 70 | if !slices.Contains(AllSeason1s, v) { 71 | return v 72 | } 73 | v++ 74 | } // AllSeason1s is a finite set so loop will terminate eventually 75 | }() 76 | 77 | // Season1Of returns a Season1 based on an ordinal number. This is the inverse of Ordinal. 78 | // If the ordinal is out of range, an invalid Season1 is returned. 79 | func Season1Of(v int) Season1 { 80 | if 0 <= v && v < len(AllSeason1s) { 81 | return AllSeason1s[v] 82 | } 83 | return invalidSeason1Value 84 | } 85 | 86 | // Parse parses a string to find the corresponding Season1, accepting one of the string values or 87 | // a number. It is used by AsSeason1. 88 | // 89 | // Usage Example 90 | // 91 | // v := new(Season1) 92 | // err := v.Parse(s) 93 | // ... etc 94 | func (v *Season1) Parse(in string) error { 95 | if v.parseNumber(in) { 96 | return nil 97 | } 98 | 99 | s := season1TransformInput(in) 100 | 101 | return v.parseFallback(in, s) 102 | } 103 | 104 | // parseNumber attempts to convert a decimal value. 105 | // Only numbers that correspond to the enumeration are valid. 106 | func (v *Season1) parseNumber(s string) (ok bool) { 107 | num, err := strconv.ParseInt(s, 10, 64) 108 | if err == nil { 109 | *v = Season1(num) 110 | return v.IsValid() 111 | } 112 | return false 113 | } 114 | 115 | func (v *Season1) parseFallback(in, s string) error { 116 | if v.parseString(s, season1EnumStrings, season1EnumIndex[:]) { 117 | return nil 118 | } 119 | 120 | return errors.New(in + ": unrecognised season1") 121 | } 122 | 123 | func (v *Season1) parseString(s string, concats string, indexes []uint16) (ok bool) { 124 | var i0 uint16 = 0 125 | 126 | for j := 1; j < len(indexes); j++ { 127 | i1 := indexes[j] 128 | p := concats[i0:i1] 129 | if s == p { 130 | *v = AllSeason1s[j-1] 131 | return true 132 | } 133 | i0 = i1 134 | } 135 | return false 136 | } 137 | 138 | // season1TransformInput may alter input strings before they are parsed. 139 | // This function is pluggable and is initialised using command-line flags 140 | // -ic -lc -uc -unsnake. 141 | var season1TransformInput = func(in string) string { 142 | return in 143 | } 144 | 145 | // AsSeason1 parses a string to find the corresponding Season1, accepting either one of the string values or 146 | // a number. It wraps Parse. 147 | func AsSeason1(s string) (Season1, error) { 148 | var v = new(Season1) 149 | err := v.Parse(s) 150 | return *v, err 151 | } 152 | 153 | // MustParseSeason1 is similar to AsSeason1 except that it panics on error. 154 | func MustParseSeason1(s string) Season1 { 155 | v, err := AsSeason1(s) 156 | if err != nil { 157 | panic(err) 158 | } 159 | return v 160 | } 161 | -------------------------------------------------------------------------------- /internal/test/season2_enum.go: -------------------------------------------------------------------------------- 1 | // generated code - do not edit 2 | // github.com/rickb777/enumeration/v4 v4.0.7 3 | 4 | package test 5 | 6 | import ( 7 | "errors" 8 | "fmt" 9 | "slices" 10 | "strconv" 11 | ) 12 | 13 | // AllSeason2s lists all 4 values in order. 14 | var AllSeason2s = []Season2{ 15 | Spring2, Summer2, Autumn2, Winter2, 16 | } 17 | 18 | const ( 19 | season2EnumStrings = "SpringSummerAutumnWinter" 20 | ) 21 | 22 | var ( 23 | season2EnumIndex = [...]uint16{0, 6, 12, 18, 24} 24 | ) 25 | 26 | // String returns the literal string representation of a Season2, which is 27 | // the same as the const identifier but without prefix or suffix. 28 | func (v Season2) String() string { 29 | o := v.Ordinal() 30 | return v.toString(o, season2EnumStrings, season2EnumIndex[:]) 31 | } 32 | 33 | // Ordinal returns the ordinal number of a Season2. This is an integer counting 34 | // from zero. It is *not* the same as the const number assigned to the value. 35 | func (v Season2) Ordinal() int { 36 | switch v { 37 | case Spring2: 38 | return 0 39 | case Summer2: 40 | return 1 41 | case Autumn2: 42 | return 2 43 | case Winter2: 44 | return 3 45 | } 46 | return -1 47 | } 48 | 49 | func (v Season2) toString(o int, concats string, indexes []uint16) string { 50 | if o < 0 || o >= len(AllSeason2s) { 51 | return fmt.Sprintf("Season2(%d)", v) 52 | } 53 | return concats[indexes[o]:indexes[o+1]] 54 | } 55 | 56 | // IsValid determines whether a Season2 is one of the defined constants. 57 | func (v Season2) IsValid() bool { 58 | return v.Ordinal() >= 0 59 | } 60 | 61 | // Int returns the int value, which is not necessarily the same as the ordinal. 62 | // This facilitates polymorphism (see enum.IntEnum). 63 | func (v Season2) Int() int { 64 | return int(v) 65 | } 66 | 67 | var invalidSeason2Value = func() Season2 { 68 | var v Season2 69 | for { 70 | if !slices.Contains(AllSeason2s, v) { 71 | return v 72 | } 73 | v++ 74 | } // AllSeason2s is a finite set so loop will terminate eventually 75 | }() 76 | 77 | // Season2Of returns a Season2 based on an ordinal number. This is the inverse of Ordinal. 78 | // If the ordinal is out of range, an invalid Season2 is returned. 79 | func Season2Of(v int) Season2 { 80 | if 0 <= v && v < len(AllSeason2s) { 81 | return AllSeason2s[v] 82 | } 83 | return invalidSeason2Value 84 | } 85 | 86 | // Parse parses a string to find the corresponding Season2, accepting one of the string values or 87 | // a number. It is used by AsSeason2. 88 | // 89 | // Usage Example 90 | // 91 | // v := new(Season2) 92 | // err := v.Parse(s) 93 | // ... etc 94 | func (v *Season2) Parse(in string) error { 95 | if v.parseNumber(in) { 96 | return nil 97 | } 98 | 99 | s := season2TransformInput(in) 100 | 101 | return v.parseFallback(in, s) 102 | } 103 | 104 | // parseNumber attempts to convert a decimal value. 105 | // Only numbers that correspond to the enumeration are valid. 106 | func (v *Season2) parseNumber(s string) (ok bool) { 107 | num, err := strconv.ParseInt(s, 10, 64) 108 | if err == nil { 109 | *v = Season2(num) 110 | return v.IsValid() 111 | } 112 | return false 113 | } 114 | 115 | func (v *Season2) parseFallback(in, s string) error { 116 | if v.parseString(s, season2EnumStrings, season2EnumIndex[:]) { 117 | return nil 118 | } 119 | 120 | var ok bool 121 | *v, ok = season2Alias[s] 122 | if ok { 123 | return nil 124 | } 125 | 126 | return errors.New(in + ": unrecognised season2") 127 | } 128 | 129 | func (v *Season2) parseString(s string, concats string, indexes []uint16) (ok bool) { 130 | var i0 uint16 = 0 131 | 132 | for j := 1; j < len(indexes); j++ { 133 | i1 := indexes[j] 134 | p := concats[i0:i1] 135 | if s == p { 136 | *v = AllSeason2s[j-1] 137 | return true 138 | } 139 | i0 = i1 140 | } 141 | *v, ok = season2Alias[s] 142 | return ok 143 | } 144 | 145 | // season2TransformInput may alter input strings before they are parsed. 146 | // This function is pluggable and is initialised using command-line flags 147 | // -ic -lc -uc -unsnake. 148 | var season2TransformInput = func(in string) string { 149 | return in 150 | } 151 | 152 | // AsSeason2 parses a string to find the corresponding Season2, accepting either one of the string values or 153 | // a number. It wraps Parse. 154 | func AsSeason2(s string) (Season2, error) { 155 | var v = new(Season2) 156 | err := v.Parse(s) 157 | return *v, err 158 | } 159 | 160 | // MustParseSeason2 is similar to AsSeason2 except that it panics on error. 161 | func MustParseSeason2(s string) Season2 { 162 | v, err := AsSeason2(s) 163 | if err != nil { 164 | panic(err) 165 | } 166 | return v 167 | } 168 | -------------------------------------------------------------------------------- /internal/test/season_ic_jn_enum.go: -------------------------------------------------------------------------------- 1 | // generated code - do not edit 2 | // github.com/rickb777/enumeration/v4 v4.0.7 3 | 4 | package test 5 | 6 | import ( 7 | "errors" 8 | "fmt" 9 | "slices" 10 | "strconv" 11 | "strings" 12 | ) 13 | 14 | // AllSeason_Ic_Jns lists all 4 values in order. 15 | var AllSeason_Ic_Jns = []Season_Ic_Jn{ 16 | Spring_Ic_Jn, Summer_Ic_Jn, Autumn_Ic_Jn, Winter_Ic_Jn, 17 | } 18 | 19 | const ( 20 | season_ic_jnEnumStrings = "SpringSummerAutumnWinter" 21 | season_ic_jnEnumInputs = "springsummerautumnwinter" 22 | ) 23 | 24 | var ( 25 | season_ic_jnEnumIndex = [...]uint16{0, 6, 12, 18, 24} 26 | ) 27 | 28 | // String returns the literal string representation of a Season_Ic_Jn, which is 29 | // the same as the const identifier but without prefix or suffix. 30 | func (v Season_Ic_Jn) String() string { 31 | o := v.Ordinal() 32 | return v.toString(o, season_ic_jnEnumStrings, season_ic_jnEnumIndex[:]) 33 | } 34 | 35 | // Ordinal returns the ordinal number of a Season_Ic_Jn. This is an integer counting 36 | // from zero. It is *not* the same as the const number assigned to the value. 37 | func (v Season_Ic_Jn) Ordinal() int { 38 | switch v { 39 | case Spring_Ic_Jn: 40 | return 0 41 | case Summer_Ic_Jn: 42 | return 1 43 | case Autumn_Ic_Jn: 44 | return 2 45 | case Winter_Ic_Jn: 46 | return 3 47 | } 48 | return -1 49 | } 50 | 51 | func (v Season_Ic_Jn) toString(o int, concats string, indexes []uint16) string { 52 | if o < 0 || o >= len(AllSeason_Ic_Jns) { 53 | return fmt.Sprintf("Season_Ic_Jn(%d)", v) 54 | } 55 | return concats[indexes[o]:indexes[o+1]] 56 | } 57 | 58 | // IsValid determines whether a Season_Ic_Jn is one of the defined constants. 59 | func (v Season_Ic_Jn) IsValid() bool { 60 | return v.Ordinal() >= 0 61 | } 62 | 63 | // Int returns the int value, which is not necessarily the same as the ordinal. 64 | // This facilitates polymorphism (see enum.IntEnum). 65 | func (v Season_Ic_Jn) Int() int { 66 | return int(v) 67 | } 68 | 69 | var invalidSeason_Ic_JnValue = func() Season_Ic_Jn { 70 | var v Season_Ic_Jn 71 | for { 72 | if !slices.Contains(AllSeason_Ic_Jns, v) { 73 | return v 74 | } 75 | v++ 76 | } // AllSeason_Ic_Jns is a finite set so loop will terminate eventually 77 | }() 78 | 79 | // Season_Ic_JnOf returns a Season_Ic_Jn based on an ordinal number. This is the inverse of Ordinal. 80 | // If the ordinal is out of range, an invalid Season_Ic_Jn is returned. 81 | func Season_Ic_JnOf(v int) Season_Ic_Jn { 82 | if 0 <= v && v < len(AllSeason_Ic_Jns) { 83 | return AllSeason_Ic_Jns[v] 84 | } 85 | return invalidSeason_Ic_JnValue 86 | } 87 | 88 | // Parse parses a string to find the corresponding Season_Ic_Jn, accepting one of the string values or 89 | // a number. It is used by AsSeason_Ic_Jn. 90 | // The input case does not matter. 91 | // 92 | // Usage Example 93 | // 94 | // v := new(Season_Ic_Jn) 95 | // err := v.Parse(s) 96 | // ... etc 97 | func (v *Season_Ic_Jn) Parse(in string) error { 98 | if v.parseNumber(in) { 99 | return nil 100 | } 101 | 102 | s := season_ic_jnTransformInput(in) 103 | 104 | return v.parseFallback(in, s) 105 | } 106 | 107 | // parseNumber attempts to convert a decimal value. 108 | // Only numbers that correspond to the enumeration are valid. 109 | func (v *Season_Ic_Jn) parseNumber(s string) (ok bool) { 110 | num, err := strconv.ParseInt(s, 10, 64) 111 | if err == nil { 112 | *v = Season_Ic_Jn(num) 113 | return v.IsValid() 114 | } 115 | return false 116 | } 117 | 118 | func (v *Season_Ic_Jn) parseFallback(in, s string) error { 119 | if v.parseString(s, season_ic_jnEnumInputs, season_ic_jnEnumIndex[:]) { 120 | return nil 121 | } 122 | 123 | return errors.New(in + ": unrecognised season_ic_jn") 124 | } 125 | 126 | func (v *Season_Ic_Jn) parseString(s string, concats string, indexes []uint16) (ok bool) { 127 | var i0 uint16 = 0 128 | 129 | for j := 1; j < len(indexes); j++ { 130 | i1 := indexes[j] 131 | p := concats[i0:i1] 132 | if s == p { 133 | *v = AllSeason_Ic_Jns[j-1] 134 | return true 135 | } 136 | i0 = i1 137 | } 138 | return false 139 | } 140 | 141 | // season_ic_jnTransformInput may alter input strings before they are parsed. 142 | // This function is pluggable and is initialised using command-line flags 143 | // -ic -lc -uc -unsnake. 144 | var season_ic_jnTransformInput = func(in string) string { 145 | return strings.ToLower(in) 146 | } 147 | 148 | // AsSeason_Ic_Jn parses a string to find the corresponding Season_Ic_Jn, accepting either one of the string values or 149 | // a number. It wraps Parse. 150 | // The input case does not matter. 151 | func AsSeason_Ic_Jn(s string) (Season_Ic_Jn, error) { 152 | var v = new(Season_Ic_Jn) 153 | err := v.Parse(s) 154 | return *v, err 155 | } 156 | 157 | // MustParseSeason_Ic_Jn is similar to AsSeason_Ic_Jn except that it panics on error. 158 | // The input case does not matter. 159 | func MustParseSeason_Ic_Jn(s string) Season_Ic_Jn { 160 | v, err := AsSeason_Ic_Jn(s) 161 | if err != nil { 162 | panic(err) 163 | } 164 | return v 165 | } 166 | 167 | // MarshalJSON converts values to bytes suitable for transmission via JSON. 168 | // The number representation is chosen according to -marshaljson. 169 | func (v Season_Ic_Jn) MarshalJSON() ([]byte, error) { 170 | if !v.IsValid() { 171 | return v.marshalNumberOrError() 172 | } 173 | 174 | s := season_ic_jnMarshalNumber(v) 175 | return []byte(s), nil 176 | } 177 | 178 | func (v Season_Ic_Jn) marshalNumberOrError() ([]byte, error) { 179 | // disallow lenient marshaling 180 | return nil, v.invalidError() 181 | } 182 | 183 | func (v Season_Ic_Jn) invalidError() error { 184 | return fmt.Errorf("%d is not a valid season_ic_jn", v) 185 | } 186 | 187 | // season_ic_jnMarshalNumber handles marshaling where a number is required or where 188 | // the value is out of range. 189 | // This function can be replaced with any bespoke function than matches signature. 190 | var season_ic_jnMarshalNumber = func(v Season_Ic_Jn) string { 191 | return strconv.FormatInt(int64(v), 10) 192 | } 193 | 194 | // UnmarshalJSON converts transmitted JSON values to ordinary values. It allows both 195 | // ordinals and strings to represent the values. 196 | func (v *Season_Ic_Jn) UnmarshalJSON(text []byte) error { 197 | s := string(text) 198 | if s == "null" { 199 | // Ignore null, like in the main JSON package. 200 | return nil 201 | } 202 | s = strings.Trim(s, "\"") 203 | return v.unmarshalJSON(s) 204 | } 205 | 206 | func (v *Season_Ic_Jn) unmarshalJSON(in string) error { 207 | if v.parseNumber(in) { 208 | return nil 209 | } 210 | 211 | s := season_ic_jnTransformInput(in) 212 | 213 | if v.parseString(s, season_ic_jnEnumInputs, season_ic_jnEnumIndex[:]) { 214 | return nil 215 | } 216 | 217 | return errors.New(in + ": unrecognised season_ic_jn") 218 | } 219 | -------------------------------------------------------------------------------- /internal/test/season_ic_si_enum.go: -------------------------------------------------------------------------------- 1 | // generated code - do not edit 2 | // github.com/rickb777/enumeration/v4 v4.0.7 3 | 4 | package test 5 | 6 | import ( 7 | "database/sql/driver" 8 | "errors" 9 | "fmt" 10 | "slices" 11 | "strconv" 12 | "strings" 13 | ) 14 | 15 | // AllSeason_Ic_Sis lists all 4 values in order. 16 | var AllSeason_Ic_Sis = []Season_Ic_Si{ 17 | Spring_Ic_Si, Summer_Ic_Si, Autumn_Ic_Si, Winter_Ic_Si, 18 | } 19 | 20 | const ( 21 | season_ic_siEnumStrings = "SpringSummerAutumnWinter" 22 | season_ic_siEnumInputs = "springsummerautumnwinter" 23 | ) 24 | 25 | var ( 26 | season_ic_siEnumIndex = [...]uint16{0, 6, 12, 18, 24} 27 | ) 28 | 29 | // String returns the literal string representation of a Season_Ic_Si, which is 30 | // the same as the const identifier but without prefix or suffix. 31 | func (v Season_Ic_Si) String() string { 32 | o := v.Ordinal() 33 | return v.toString(o, season_ic_siEnumStrings, season_ic_siEnumIndex[:]) 34 | } 35 | 36 | // Ordinal returns the ordinal number of a Season_Ic_Si. This is an integer counting 37 | // from zero. It is *not* the same as the const number assigned to the value. 38 | func (v Season_Ic_Si) Ordinal() int { 39 | switch v { 40 | case Spring_Ic_Si: 41 | return 0 42 | case Summer_Ic_Si: 43 | return 1 44 | case Autumn_Ic_Si: 45 | return 2 46 | case Winter_Ic_Si: 47 | return 3 48 | } 49 | return -1 50 | } 51 | 52 | func (v Season_Ic_Si) toString(o int, concats string, indexes []uint16) string { 53 | if o < 0 || o >= len(AllSeason_Ic_Sis) { 54 | return fmt.Sprintf("Season_Ic_Si(%d)", v) 55 | } 56 | return concats[indexes[o]:indexes[o+1]] 57 | } 58 | 59 | // IsValid determines whether a Season_Ic_Si is one of the defined constants. 60 | func (v Season_Ic_Si) IsValid() bool { 61 | return v.Ordinal() >= 0 62 | } 63 | 64 | // Int returns the int value, which is not necessarily the same as the ordinal. 65 | // This facilitates polymorphism (see enum.IntEnum). 66 | func (v Season_Ic_Si) Int() int { 67 | return int(v) 68 | } 69 | 70 | var invalidSeason_Ic_SiValue = func() Season_Ic_Si { 71 | var v Season_Ic_Si 72 | for { 73 | if !slices.Contains(AllSeason_Ic_Sis, v) { 74 | return v 75 | } 76 | v++ 77 | } // AllSeason_Ic_Sis is a finite set so loop will terminate eventually 78 | }() 79 | 80 | // Season_Ic_SiOf returns a Season_Ic_Si based on an ordinal number. This is the inverse of Ordinal. 81 | // If the ordinal is out of range, an invalid Season_Ic_Si is returned. 82 | func Season_Ic_SiOf(v int) Season_Ic_Si { 83 | if 0 <= v && v < len(AllSeason_Ic_Sis) { 84 | return AllSeason_Ic_Sis[v] 85 | } 86 | return invalidSeason_Ic_SiValue 87 | } 88 | 89 | // Parse parses a string to find the corresponding Season_Ic_Si, accepting one of the string values or 90 | // a number. It is used by AsSeason_Ic_Si. 91 | // The input case does not matter. 92 | // 93 | // Usage Example 94 | // 95 | // v := new(Season_Ic_Si) 96 | // err := v.Parse(s) 97 | // ... etc 98 | func (v *Season_Ic_Si) Parse(in string) error { 99 | if v.parseNumber(in) { 100 | return nil 101 | } 102 | 103 | s := season_ic_siTransformInput(in) 104 | 105 | return v.parseFallback(in, s) 106 | } 107 | 108 | // parseNumber attempts to convert a decimal value. 109 | // Only numbers that correspond to the enumeration are valid. 110 | func (v *Season_Ic_Si) parseNumber(s string) (ok bool) { 111 | num, err := strconv.ParseInt(s, 10, 64) 112 | if err == nil { 113 | *v = Season_Ic_Si(num) 114 | return v.IsValid() 115 | } 116 | return false 117 | } 118 | 119 | func (v *Season_Ic_Si) parseFallback(in, s string) error { 120 | if v.parseString(s, season_ic_siEnumInputs, season_ic_siEnumIndex[:]) { 121 | return nil 122 | } 123 | 124 | return errors.New(in + ": unrecognised season_ic_si") 125 | } 126 | 127 | func (v *Season_Ic_Si) parseString(s string, concats string, indexes []uint16) (ok bool) { 128 | var i0 uint16 = 0 129 | 130 | for j := 1; j < len(indexes); j++ { 131 | i1 := indexes[j] 132 | p := concats[i0:i1] 133 | if s == p { 134 | *v = AllSeason_Ic_Sis[j-1] 135 | return true 136 | } 137 | i0 = i1 138 | } 139 | return false 140 | } 141 | 142 | // season_ic_siTransformInput may alter input strings before they are parsed. 143 | // This function is pluggable and is initialised using command-line flags 144 | // -ic -lc -uc -unsnake. 145 | var season_ic_siTransformInput = func(in string) string { 146 | return strings.ToLower(in) 147 | } 148 | 149 | // AsSeason_Ic_Si parses a string to find the corresponding Season_Ic_Si, accepting either one of the string values or 150 | // a number. It wraps Parse. 151 | // The input case does not matter. 152 | func AsSeason_Ic_Si(s string) (Season_Ic_Si, error) { 153 | var v = new(Season_Ic_Si) 154 | err := v.Parse(s) 155 | return *v, err 156 | } 157 | 158 | // MustParseSeason_Ic_Si is similar to AsSeason_Ic_Si except that it panics on error. 159 | // The input case does not matter. 160 | func MustParseSeason_Ic_Si(s string) Season_Ic_Si { 161 | v, err := AsSeason_Ic_Si(s) 162 | if err != nil { 163 | panic(err) 164 | } 165 | return v 166 | } 167 | 168 | // Scan parses some value, which can be a number, a string or []byte. 169 | // It implements sql.Scanner, https://golang.org/pkg/database/sql/#Scanner 170 | func (v *Season_Ic_Si) Scan(value interface{}) error { 171 | if value == nil { 172 | return nil 173 | } 174 | 175 | var s string 176 | switch x := value.(type) { 177 | case int64: 178 | *v = Season_Ic_Si(x) 179 | return v.errorIfInvalid() 180 | case float64: 181 | *v = Season_Ic_Si(x) 182 | return v.errorIfInvalid() 183 | case []byte: 184 | s = string(x) 185 | case string: 186 | s = x 187 | default: 188 | return fmt.Errorf("%T %+v is not a meaningful season_ic_si", value, value) 189 | } 190 | 191 | return v.scanParse(s) 192 | } 193 | 194 | func (v Season_Ic_Si) errorIfInvalid() error { 195 | if v.IsValid() { 196 | return nil 197 | } 198 | return v.invalidError() 199 | } 200 | 201 | func (v Season_Ic_Si) invalidError() error { 202 | return fmt.Errorf("%d is not a valid season_ic_si", v) 203 | } 204 | 205 | func (v *Season_Ic_Si) scanParse(in string) error { 206 | if v.parseNumber(in) { 207 | return nil 208 | } 209 | 210 | s := season_ic_siTransformInput(in) 211 | 212 | return v.parseFallback(in, s) 213 | } 214 | 215 | // Value converts the Season_Ic_Si to a string (based on '-store identifier'). 216 | // It implements driver.Valuer, https://golang.org/pkg/database/sql/driver/#Valuer 217 | func (v Season_Ic_Si) Value() (driver.Value, error) { 218 | if !v.IsValid() { 219 | return nil, fmt.Errorf("%v: cannot be stored", v) 220 | } 221 | 222 | return v.String(), nil 223 | } 224 | -------------------------------------------------------------------------------- /internal/test/season_ic_sn_enum.go: -------------------------------------------------------------------------------- 1 | // generated code - do not edit 2 | // github.com/rickb777/enumeration/v4 v4.0.7 3 | 4 | package test 5 | 6 | import ( 7 | "database/sql/driver" 8 | "errors" 9 | "fmt" 10 | "slices" 11 | "strconv" 12 | "strings" 13 | ) 14 | 15 | // AllSeason_Ic_Sns lists all 4 values in order. 16 | var AllSeason_Ic_Sns = []Season_Ic_Sn{ 17 | Spring_Ic_Sn, Summer_Ic_Sn, Autumn_Ic_Sn, Winter_Ic_Sn, 18 | } 19 | 20 | const ( 21 | season_ic_snEnumStrings = "SpringSummerAutumnWinter" 22 | season_ic_snEnumInputs = "springsummerautumnwinter" 23 | ) 24 | 25 | var ( 26 | season_ic_snEnumIndex = [...]uint16{0, 6, 12, 18, 24} 27 | ) 28 | 29 | // String returns the literal string representation of a Season_Ic_Sn, which is 30 | // the same as the const identifier but without prefix or suffix. 31 | func (v Season_Ic_Sn) String() string { 32 | o := v.Ordinal() 33 | return v.toString(o, season_ic_snEnumStrings, season_ic_snEnumIndex[:]) 34 | } 35 | 36 | // Ordinal returns the ordinal number of a Season_Ic_Sn. This is an integer counting 37 | // from zero. It is *not* the same as the const number assigned to the value. 38 | func (v Season_Ic_Sn) Ordinal() int { 39 | switch v { 40 | case Spring_Ic_Sn: 41 | return 0 42 | case Summer_Ic_Sn: 43 | return 1 44 | case Autumn_Ic_Sn: 45 | return 2 46 | case Winter_Ic_Sn: 47 | return 3 48 | } 49 | return -1 50 | } 51 | 52 | func (v Season_Ic_Sn) toString(o int, concats string, indexes []uint16) string { 53 | if o < 0 || o >= len(AllSeason_Ic_Sns) { 54 | return fmt.Sprintf("Season_Ic_Sn(%d)", v) 55 | } 56 | return concats[indexes[o]:indexes[o+1]] 57 | } 58 | 59 | // IsValid determines whether a Season_Ic_Sn is one of the defined constants. 60 | func (v Season_Ic_Sn) IsValid() bool { 61 | return v.Ordinal() >= 0 62 | } 63 | 64 | // Int returns the int value, which is not necessarily the same as the ordinal. 65 | // This facilitates polymorphism (see enum.IntEnum). 66 | func (v Season_Ic_Sn) Int() int { 67 | return int(v) 68 | } 69 | 70 | var invalidSeason_Ic_SnValue = func() Season_Ic_Sn { 71 | var v Season_Ic_Sn 72 | for { 73 | if !slices.Contains(AllSeason_Ic_Sns, v) { 74 | return v 75 | } 76 | v++ 77 | } // AllSeason_Ic_Sns is a finite set so loop will terminate eventually 78 | }() 79 | 80 | // Season_Ic_SnOf returns a Season_Ic_Sn based on an ordinal number. This is the inverse of Ordinal. 81 | // If the ordinal is out of range, an invalid Season_Ic_Sn is returned. 82 | func Season_Ic_SnOf(v int) Season_Ic_Sn { 83 | if 0 <= v && v < len(AllSeason_Ic_Sns) { 84 | return AllSeason_Ic_Sns[v] 85 | } 86 | return invalidSeason_Ic_SnValue 87 | } 88 | 89 | // Parse parses a string to find the corresponding Season_Ic_Sn, accepting one of the string values or 90 | // a number. It is used by AsSeason_Ic_Sn. 91 | // The input case does not matter. 92 | // 93 | // Usage Example 94 | // 95 | // v := new(Season_Ic_Sn) 96 | // err := v.Parse(s) 97 | // ... etc 98 | func (v *Season_Ic_Sn) Parse(in string) error { 99 | if v.parseNumber(in) { 100 | return nil 101 | } 102 | 103 | s := season_ic_snTransformInput(in) 104 | 105 | return v.parseFallback(in, s) 106 | } 107 | 108 | // parseNumber attempts to convert a decimal value. 109 | // Only numbers that correspond to the enumeration are valid. 110 | func (v *Season_Ic_Sn) parseNumber(s string) (ok bool) { 111 | num, err := strconv.ParseInt(s, 10, 64) 112 | if err == nil { 113 | *v = Season_Ic_Sn(num) 114 | return v.IsValid() 115 | } 116 | return false 117 | } 118 | 119 | func (v *Season_Ic_Sn) parseFallback(in, s string) error { 120 | if v.parseString(s, season_ic_snEnumInputs, season_ic_snEnumIndex[:]) { 121 | return nil 122 | } 123 | 124 | return errors.New(in + ": unrecognised season_ic_sn") 125 | } 126 | 127 | func (v *Season_Ic_Sn) parseString(s string, concats string, indexes []uint16) (ok bool) { 128 | var i0 uint16 = 0 129 | 130 | for j := 1; j < len(indexes); j++ { 131 | i1 := indexes[j] 132 | p := concats[i0:i1] 133 | if s == p { 134 | *v = AllSeason_Ic_Sns[j-1] 135 | return true 136 | } 137 | i0 = i1 138 | } 139 | return false 140 | } 141 | 142 | // season_ic_snTransformInput may alter input strings before they are parsed. 143 | // This function is pluggable and is initialised using command-line flags 144 | // -ic -lc -uc -unsnake. 145 | var season_ic_snTransformInput = func(in string) string { 146 | return strings.ToLower(in) 147 | } 148 | 149 | // AsSeason_Ic_Sn parses a string to find the corresponding Season_Ic_Sn, accepting either one of the string values or 150 | // a number. It wraps Parse. 151 | // The input case does not matter. 152 | func AsSeason_Ic_Sn(s string) (Season_Ic_Sn, error) { 153 | var v = new(Season_Ic_Sn) 154 | err := v.Parse(s) 155 | return *v, err 156 | } 157 | 158 | // MustParseSeason_Ic_Sn is similar to AsSeason_Ic_Sn except that it panics on error. 159 | // The input case does not matter. 160 | func MustParseSeason_Ic_Sn(s string) Season_Ic_Sn { 161 | v, err := AsSeason_Ic_Sn(s) 162 | if err != nil { 163 | panic(err) 164 | } 165 | return v 166 | } 167 | 168 | // Scan parses some value, which can be a number, a string or []byte. 169 | // It implements sql.Scanner, https://golang.org/pkg/database/sql/#Scanner 170 | func (v *Season_Ic_Sn) Scan(value interface{}) error { 171 | if value == nil { 172 | return nil 173 | } 174 | 175 | var s string 176 | switch x := value.(type) { 177 | case int64: 178 | *v = Season_Ic_Sn(x) 179 | return v.errorIfInvalid() 180 | case float64: 181 | *v = Season_Ic_Sn(x) 182 | return v.errorIfInvalid() 183 | case []byte: 184 | s = string(x) 185 | case string: 186 | s = x 187 | default: 188 | return fmt.Errorf("%T %+v is not a meaningful season_ic_sn", value, value) 189 | } 190 | 191 | return v.scanParse(s) 192 | } 193 | 194 | func (v Season_Ic_Sn) errorIfInvalid() error { 195 | if v.IsValid() { 196 | return nil 197 | } 198 | return v.invalidError() 199 | } 200 | 201 | func (v Season_Ic_Sn) invalidError() error { 202 | return fmt.Errorf("%d is not a valid season_ic_sn", v) 203 | } 204 | 205 | func (v *Season_Ic_Sn) scanParse(in string) error { 206 | if v.parseNumber(in) { 207 | return nil 208 | } 209 | 210 | s := season_ic_snTransformInput(in) 211 | 212 | return v.parseFallback(in, s) 213 | } 214 | 215 | // Value converts the Season_Ic_Sn to a number (based on '-store number'). 216 | // It implements driver.Valuer, https://golang.org/pkg/database/sql/driver/#Valuer 217 | func (v Season_Ic_Sn) Value() (driver.Value, error) { 218 | return int64(v), nil 219 | } 220 | -------------------------------------------------------------------------------- /internal/test/season_json.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | //go:generate enumeration -v -f -i season_json.go -type Season_Nc_Ji -suffix _Nc_Ji -marshaljson identifier 4 | //go:generate enumeration -v -f -i season_json.go -type Season_Nc_Jn -suffix _Nc_Jn -marshaljson number 5 | //go:generate enumeration -v -f -i season_json.go -type Season_Nc_Jj -suffix _Nc_Jj 6 | 7 | type ( 8 | Season_Nc_Ji uint 9 | Season_Nc_Jn uint 10 | Season_Nc_Jj uint 11 | ) 12 | 13 | const ( 14 | Spring_Nc_Ji, Summer_Nc_Ji, Autumn_Nc_Ji, Winter_Nc_Ji Season_Nc_Ji = 1, 2, 3, 4 15 | ) 16 | 17 | const ( 18 | Spring_Nc_Jn, Summer_Nc_Jn, Autumn_Nc_Jn, Winter_Nc_Jn Season_Nc_Jn = 1, 2, 3, 4 19 | ) 20 | 21 | const ( 22 | _ Season_Nc_Jj = iota 23 | Spring_Nc_Jj // json:"Sprg" 24 | Summer_Nc_Jj // json:"Sumr" 25 | Autumn_Nc_Jj // json:"Autm" 26 | Winter_Nc_Jj // json:"Wint" 27 | ) 28 | 29 | //================================================================================================= 30 | //go:generate enumeration -v -f -i season_json.go -type Season_Ic_Ji -suffix _Ic_Ji -ic -marshaljson identifier 31 | //go:generate enumeration -v -f -i season_json.go -type Season_Ic_Jn -suffix _Ic_Jn -ic -marshaljson number 32 | //go:generate enumeration -v -f -i season_json.go -type Season_Ic_Jj -suffix _Ic_Jj -ic 33 | 34 | type ( 35 | Season_Ic_Ji uint 36 | Season_Ic_Jn uint 37 | Season_Ic_Jj uint 38 | ) 39 | 40 | const ( 41 | Spring_Ic_Ji, Summer_Ic_Ji, Autumn_Ic_Ji, Winter_Ic_Ji Season_Ic_Ji = 1, 2, 3, 4 42 | ) 43 | 44 | const ( 45 | Spring_Ic_Jn, Summer_Ic_Jn, Autumn_Ic_Jn, Winter_Ic_Jn Season_Ic_Jn = 1, 2, 3, 4 46 | ) 47 | 48 | const ( 49 | _ Season_Ic_Jj = iota 50 | Spring_Ic_Jj // json:"Sprg" 51 | Summer_Ic_Jj // json:"Sumr" 52 | Autumn_Ic_Jj // json:"Autm" 53 | Winter_Ic_Jj // json:"Wint" 54 | ) 55 | 56 | //================================================================================================= 57 | //go:generate enumeration -v -f -i season_json.go -type Season_Uc_Ji -suffix _Uc_Ji -uc -marshaljson identifier 58 | //go:generate enumeration -v -f -i season_json.go -type Season_Uc_Jn -suffix _Uc_Jn -uc -marshaljson number 59 | //go:generate enumeration -v -f -i season_json.go -type Season_Uc_Jj -suffix _Uc_Jj -uc 60 | 61 | type ( 62 | Season_Uc_Ji uint 63 | Season_Uc_Jn uint 64 | Season_Uc_Jj uint 65 | ) 66 | 67 | const ( 68 | Spring_Uc_Ji, Summer_Uc_Ji, Autumn_Uc_Ji, Winter_Uc_Ji Season_Uc_Ji = 1, 2, 3, 4 69 | ) 70 | 71 | const ( 72 | _ Season_Uc_Jn = iota 73 | Spring_Uc_Jn 74 | Summer_Uc_Jn 75 | Autumn_Uc_Jn // 3 76 | Winter_Uc_Jn 77 | ) 78 | 79 | const ( 80 | _ Season_Uc_Jj = iota 81 | Spring_Uc_Jj // json:"Sprg" 82 | Summer_Uc_Jj // json:"Sumr" 83 | Autumn_Uc_Jj // json:"Autm" 84 | Winter_Uc_Jj // json:"Wint" 85 | ) 86 | -------------------------------------------------------------------------------- /internal/test/season_nc_jn_enum.go: -------------------------------------------------------------------------------- 1 | // generated code - do not edit 2 | // github.com/rickb777/enumeration/v4 v4.0.7 3 | 4 | package test 5 | 6 | import ( 7 | "errors" 8 | "fmt" 9 | "slices" 10 | "strconv" 11 | "strings" 12 | ) 13 | 14 | // AllSeason_Nc_Jns lists all 4 values in order. 15 | var AllSeason_Nc_Jns = []Season_Nc_Jn{ 16 | Spring_Nc_Jn, Summer_Nc_Jn, Autumn_Nc_Jn, Winter_Nc_Jn, 17 | } 18 | 19 | const ( 20 | season_nc_jnEnumStrings = "SpringSummerAutumnWinter" 21 | ) 22 | 23 | var ( 24 | season_nc_jnEnumIndex = [...]uint16{0, 6, 12, 18, 24} 25 | ) 26 | 27 | // String returns the literal string representation of a Season_Nc_Jn, which is 28 | // the same as the const identifier but without prefix or suffix. 29 | func (v Season_Nc_Jn) String() string { 30 | o := v.Ordinal() 31 | return v.toString(o, season_nc_jnEnumStrings, season_nc_jnEnumIndex[:]) 32 | } 33 | 34 | // Ordinal returns the ordinal number of a Season_Nc_Jn. This is an integer counting 35 | // from zero. It is *not* the same as the const number assigned to the value. 36 | func (v Season_Nc_Jn) Ordinal() int { 37 | switch v { 38 | case Spring_Nc_Jn: 39 | return 0 40 | case Summer_Nc_Jn: 41 | return 1 42 | case Autumn_Nc_Jn: 43 | return 2 44 | case Winter_Nc_Jn: 45 | return 3 46 | } 47 | return -1 48 | } 49 | 50 | func (v Season_Nc_Jn) toString(o int, concats string, indexes []uint16) string { 51 | if o < 0 || o >= len(AllSeason_Nc_Jns) { 52 | return fmt.Sprintf("Season_Nc_Jn(%d)", v) 53 | } 54 | return concats[indexes[o]:indexes[o+1]] 55 | } 56 | 57 | // IsValid determines whether a Season_Nc_Jn is one of the defined constants. 58 | func (v Season_Nc_Jn) IsValid() bool { 59 | return v.Ordinal() >= 0 60 | } 61 | 62 | // Int returns the int value, which is not necessarily the same as the ordinal. 63 | // This facilitates polymorphism (see enum.IntEnum). 64 | func (v Season_Nc_Jn) Int() int { 65 | return int(v) 66 | } 67 | 68 | var invalidSeason_Nc_JnValue = func() Season_Nc_Jn { 69 | var v Season_Nc_Jn 70 | for { 71 | if !slices.Contains(AllSeason_Nc_Jns, v) { 72 | return v 73 | } 74 | v++ 75 | } // AllSeason_Nc_Jns is a finite set so loop will terminate eventually 76 | }() 77 | 78 | // Season_Nc_JnOf returns a Season_Nc_Jn based on an ordinal number. This is the inverse of Ordinal. 79 | // If the ordinal is out of range, an invalid Season_Nc_Jn is returned. 80 | func Season_Nc_JnOf(v int) Season_Nc_Jn { 81 | if 0 <= v && v < len(AllSeason_Nc_Jns) { 82 | return AllSeason_Nc_Jns[v] 83 | } 84 | return invalidSeason_Nc_JnValue 85 | } 86 | 87 | // Parse parses a string to find the corresponding Season_Nc_Jn, accepting one of the string values or 88 | // a number. It is used by AsSeason_Nc_Jn. 89 | // 90 | // Usage Example 91 | // 92 | // v := new(Season_Nc_Jn) 93 | // err := v.Parse(s) 94 | // ... etc 95 | func (v *Season_Nc_Jn) Parse(in string) error { 96 | if v.parseNumber(in) { 97 | return nil 98 | } 99 | 100 | s := season_nc_jnTransformInput(in) 101 | 102 | return v.parseFallback(in, s) 103 | } 104 | 105 | // parseNumber attempts to convert a decimal value. 106 | // Only numbers that correspond to the enumeration are valid. 107 | func (v *Season_Nc_Jn) parseNumber(s string) (ok bool) { 108 | num, err := strconv.ParseInt(s, 10, 64) 109 | if err == nil { 110 | *v = Season_Nc_Jn(num) 111 | return v.IsValid() 112 | } 113 | return false 114 | } 115 | 116 | func (v *Season_Nc_Jn) parseFallback(in, s string) error { 117 | if v.parseString(s, season_nc_jnEnumStrings, season_nc_jnEnumIndex[:]) { 118 | return nil 119 | } 120 | 121 | return errors.New(in + ": unrecognised season_nc_jn") 122 | } 123 | 124 | func (v *Season_Nc_Jn) parseString(s string, concats string, indexes []uint16) (ok bool) { 125 | var i0 uint16 = 0 126 | 127 | for j := 1; j < len(indexes); j++ { 128 | i1 := indexes[j] 129 | p := concats[i0:i1] 130 | if s == p { 131 | *v = AllSeason_Nc_Jns[j-1] 132 | return true 133 | } 134 | i0 = i1 135 | } 136 | return false 137 | } 138 | 139 | // season_nc_jnTransformInput may alter input strings before they are parsed. 140 | // This function is pluggable and is initialised using command-line flags 141 | // -ic -lc -uc -unsnake. 142 | var season_nc_jnTransformInput = func(in string) string { 143 | return in 144 | } 145 | 146 | // AsSeason_Nc_Jn parses a string to find the corresponding Season_Nc_Jn, accepting either one of the string values or 147 | // a number. It wraps Parse. 148 | func AsSeason_Nc_Jn(s string) (Season_Nc_Jn, error) { 149 | var v = new(Season_Nc_Jn) 150 | err := v.Parse(s) 151 | return *v, err 152 | } 153 | 154 | // MustParseSeason_Nc_Jn is similar to AsSeason_Nc_Jn except that it panics on error. 155 | func MustParseSeason_Nc_Jn(s string) Season_Nc_Jn { 156 | v, err := AsSeason_Nc_Jn(s) 157 | if err != nil { 158 | panic(err) 159 | } 160 | return v 161 | } 162 | 163 | // MarshalJSON converts values to bytes suitable for transmission via JSON. 164 | // The number representation is chosen according to -marshaljson. 165 | func (v Season_Nc_Jn) MarshalJSON() ([]byte, error) { 166 | if !v.IsValid() { 167 | return v.marshalNumberOrError() 168 | } 169 | 170 | s := season_nc_jnMarshalNumber(v) 171 | return []byte(s), nil 172 | } 173 | 174 | func (v Season_Nc_Jn) marshalNumberOrError() ([]byte, error) { 175 | // disallow lenient marshaling 176 | return nil, v.invalidError() 177 | } 178 | 179 | func (v Season_Nc_Jn) invalidError() error { 180 | return fmt.Errorf("%d is not a valid season_nc_jn", v) 181 | } 182 | 183 | // season_nc_jnMarshalNumber handles marshaling where a number is required or where 184 | // the value is out of range. 185 | // This function can be replaced with any bespoke function than matches signature. 186 | var season_nc_jnMarshalNumber = func(v Season_Nc_Jn) string { 187 | return strconv.FormatInt(int64(v), 10) 188 | } 189 | 190 | // UnmarshalJSON converts transmitted JSON values to ordinary values. It allows both 191 | // ordinals and strings to represent the values. 192 | func (v *Season_Nc_Jn) UnmarshalJSON(text []byte) error { 193 | s := string(text) 194 | if s == "null" { 195 | // Ignore null, like in the main JSON package. 196 | return nil 197 | } 198 | s = strings.Trim(s, "\"") 199 | return v.unmarshalJSON(s) 200 | } 201 | 202 | func (v *Season_Nc_Jn) unmarshalJSON(in string) error { 203 | if v.parseNumber(in) { 204 | return nil 205 | } 206 | 207 | s := season_nc_jnTransformInput(in) 208 | 209 | if v.parseString(s, season_nc_jnEnumStrings, season_nc_jnEnumIndex[:]) { 210 | return nil 211 | } 212 | 213 | return errors.New(in + ": unrecognised season_nc_jn") 214 | } 215 | -------------------------------------------------------------------------------- /internal/test/season_nc_si_enum.go: -------------------------------------------------------------------------------- 1 | // generated code - do not edit 2 | // github.com/rickb777/enumeration/v4 v4.0.7 3 | 4 | package test 5 | 6 | import ( 7 | "database/sql/driver" 8 | "errors" 9 | "fmt" 10 | "slices" 11 | "strconv" 12 | ) 13 | 14 | // AllSeason_Nc_Sis lists all 4 values in order. 15 | var AllSeason_Nc_Sis = []Season_Nc_Si{ 16 | Spring_Nc_Si, Summer_Nc_Si, Autumn_Nc_Si, Winter_Nc_Si, 17 | } 18 | 19 | const ( 20 | season_nc_siEnumStrings = "SpringSummerAutumnWinter" 21 | ) 22 | 23 | var ( 24 | season_nc_siEnumIndex = [...]uint16{0, 6, 12, 18, 24} 25 | ) 26 | 27 | // String returns the literal string representation of a Season_Nc_Si, which is 28 | // the same as the const identifier but without prefix or suffix. 29 | func (v Season_Nc_Si) String() string { 30 | o := v.Ordinal() 31 | return v.toString(o, season_nc_siEnumStrings, season_nc_siEnumIndex[:]) 32 | } 33 | 34 | // Ordinal returns the ordinal number of a Season_Nc_Si. This is an integer counting 35 | // from zero. It is *not* the same as the const number assigned to the value. 36 | func (v Season_Nc_Si) Ordinal() int { 37 | switch v { 38 | case Spring_Nc_Si: 39 | return 0 40 | case Summer_Nc_Si: 41 | return 1 42 | case Autumn_Nc_Si: 43 | return 2 44 | case Winter_Nc_Si: 45 | return 3 46 | } 47 | return -1 48 | } 49 | 50 | func (v Season_Nc_Si) toString(o int, concats string, indexes []uint16) string { 51 | if o < 0 || o >= len(AllSeason_Nc_Sis) { 52 | return fmt.Sprintf("Season_Nc_Si(%d)", v) 53 | } 54 | return concats[indexes[o]:indexes[o+1]] 55 | } 56 | 57 | // IsValid determines whether a Season_Nc_Si is one of the defined constants. 58 | func (v Season_Nc_Si) IsValid() bool { 59 | return v.Ordinal() >= 0 60 | } 61 | 62 | // Int returns the int value, which is not necessarily the same as the ordinal. 63 | // This facilitates polymorphism (see enum.IntEnum). 64 | func (v Season_Nc_Si) Int() int { 65 | return int(v) 66 | } 67 | 68 | var invalidSeason_Nc_SiValue = func() Season_Nc_Si { 69 | var v Season_Nc_Si 70 | for { 71 | if !slices.Contains(AllSeason_Nc_Sis, v) { 72 | return v 73 | } 74 | v++ 75 | } // AllSeason_Nc_Sis is a finite set so loop will terminate eventually 76 | }() 77 | 78 | // Season_Nc_SiOf returns a Season_Nc_Si based on an ordinal number. This is the inverse of Ordinal. 79 | // If the ordinal is out of range, an invalid Season_Nc_Si is returned. 80 | func Season_Nc_SiOf(v int) Season_Nc_Si { 81 | if 0 <= v && v < len(AllSeason_Nc_Sis) { 82 | return AllSeason_Nc_Sis[v] 83 | } 84 | return invalidSeason_Nc_SiValue 85 | } 86 | 87 | // Parse parses a string to find the corresponding Season_Nc_Si, accepting one of the string values or 88 | // a number. It is used by AsSeason_Nc_Si. 89 | // 90 | // Usage Example 91 | // 92 | // v := new(Season_Nc_Si) 93 | // err := v.Parse(s) 94 | // ... etc 95 | func (v *Season_Nc_Si) Parse(in string) error { 96 | if v.parseNumber(in) { 97 | return nil 98 | } 99 | 100 | s := season_nc_siTransformInput(in) 101 | 102 | return v.parseFallback(in, s) 103 | } 104 | 105 | // parseNumber attempts to convert a decimal value. 106 | // Only numbers that correspond to the enumeration are valid. 107 | func (v *Season_Nc_Si) parseNumber(s string) (ok bool) { 108 | num, err := strconv.ParseInt(s, 10, 64) 109 | if err == nil { 110 | *v = Season_Nc_Si(num) 111 | return v.IsValid() 112 | } 113 | return false 114 | } 115 | 116 | func (v *Season_Nc_Si) parseFallback(in, s string) error { 117 | if v.parseString(s, season_nc_siEnumStrings, season_nc_siEnumIndex[:]) { 118 | return nil 119 | } 120 | 121 | return errors.New(in + ": unrecognised season_nc_si") 122 | } 123 | 124 | func (v *Season_Nc_Si) parseString(s string, concats string, indexes []uint16) (ok bool) { 125 | var i0 uint16 = 0 126 | 127 | for j := 1; j < len(indexes); j++ { 128 | i1 := indexes[j] 129 | p := concats[i0:i1] 130 | if s == p { 131 | *v = AllSeason_Nc_Sis[j-1] 132 | return true 133 | } 134 | i0 = i1 135 | } 136 | return false 137 | } 138 | 139 | // season_nc_siTransformInput may alter input strings before they are parsed. 140 | // This function is pluggable and is initialised using command-line flags 141 | // -ic -lc -uc -unsnake. 142 | var season_nc_siTransformInput = func(in string) string { 143 | return in 144 | } 145 | 146 | // AsSeason_Nc_Si parses a string to find the corresponding Season_Nc_Si, accepting either one of the string values or 147 | // a number. It wraps Parse. 148 | func AsSeason_Nc_Si(s string) (Season_Nc_Si, error) { 149 | var v = new(Season_Nc_Si) 150 | err := v.Parse(s) 151 | return *v, err 152 | } 153 | 154 | // MustParseSeason_Nc_Si is similar to AsSeason_Nc_Si except that it panics on error. 155 | func MustParseSeason_Nc_Si(s string) Season_Nc_Si { 156 | v, err := AsSeason_Nc_Si(s) 157 | if err != nil { 158 | panic(err) 159 | } 160 | return v 161 | } 162 | 163 | // Scan parses some value, which can be a number, a string or []byte. 164 | // It implements sql.Scanner, https://golang.org/pkg/database/sql/#Scanner 165 | func (v *Season_Nc_Si) Scan(value interface{}) error { 166 | if value == nil { 167 | return nil 168 | } 169 | 170 | var s string 171 | switch x := value.(type) { 172 | case int64: 173 | *v = Season_Nc_Si(x) 174 | return v.errorIfInvalid() 175 | case float64: 176 | *v = Season_Nc_Si(x) 177 | return v.errorIfInvalid() 178 | case []byte: 179 | s = string(x) 180 | case string: 181 | s = x 182 | default: 183 | return fmt.Errorf("%T %+v is not a meaningful season_nc_si", value, value) 184 | } 185 | 186 | return v.scanParse(s) 187 | } 188 | 189 | func (v Season_Nc_Si) errorIfInvalid() error { 190 | if v.IsValid() { 191 | return nil 192 | } 193 | return v.invalidError() 194 | } 195 | 196 | func (v Season_Nc_Si) invalidError() error { 197 | return fmt.Errorf("%d is not a valid season_nc_si", v) 198 | } 199 | 200 | func (v *Season_Nc_Si) scanParse(in string) error { 201 | if v.parseNumber(in) { 202 | return nil 203 | } 204 | 205 | s := season_nc_siTransformInput(in) 206 | 207 | return v.parseFallback(in, s) 208 | } 209 | 210 | // Value converts the Season_Nc_Si to a string (based on '-store identifier'). 211 | // It implements driver.Valuer, https://golang.org/pkg/database/sql/driver/#Valuer 212 | func (v Season_Nc_Si) Value() (driver.Value, error) { 213 | if !v.IsValid() { 214 | return nil, fmt.Errorf("%v: cannot be stored", v) 215 | } 216 | 217 | return v.String(), nil 218 | } 219 | -------------------------------------------------------------------------------- /internal/test/season_nc_sn_enum.go: -------------------------------------------------------------------------------- 1 | // generated code - do not edit 2 | // github.com/rickb777/enumeration/v4 v4.0.7 3 | 4 | package test 5 | 6 | import ( 7 | "database/sql/driver" 8 | "errors" 9 | "fmt" 10 | "slices" 11 | "strconv" 12 | ) 13 | 14 | // AllSeason_Nc_Sns lists all 4 values in order. 15 | var AllSeason_Nc_Sns = []Season_Nc_Sn{ 16 | Spring_Nc_Sn, Summer_Nc_Sn, Autumn_Nc_Sn, Winter_Nc_Sn, 17 | } 18 | 19 | const ( 20 | season_nc_snEnumStrings = "SpringSummerAutumnWinter" 21 | ) 22 | 23 | var ( 24 | season_nc_snEnumIndex = [...]uint16{0, 6, 12, 18, 24} 25 | ) 26 | 27 | // String returns the literal string representation of a Season_Nc_Sn, which is 28 | // the same as the const identifier but without prefix or suffix. 29 | func (v Season_Nc_Sn) String() string { 30 | o := v.Ordinal() 31 | return v.toString(o, season_nc_snEnumStrings, season_nc_snEnumIndex[:]) 32 | } 33 | 34 | // Ordinal returns the ordinal number of a Season_Nc_Sn. This is an integer counting 35 | // from zero. It is *not* the same as the const number assigned to the value. 36 | func (v Season_Nc_Sn) Ordinal() int { 37 | switch v { 38 | case Spring_Nc_Sn: 39 | return 0 40 | case Summer_Nc_Sn: 41 | return 1 42 | case Autumn_Nc_Sn: 43 | return 2 44 | case Winter_Nc_Sn: 45 | return 3 46 | } 47 | return -1 48 | } 49 | 50 | func (v Season_Nc_Sn) toString(o int, concats string, indexes []uint16) string { 51 | if o < 0 || o >= len(AllSeason_Nc_Sns) { 52 | return fmt.Sprintf("Season_Nc_Sn(%d)", v) 53 | } 54 | return concats[indexes[o]:indexes[o+1]] 55 | } 56 | 57 | // IsValid determines whether a Season_Nc_Sn is one of the defined constants. 58 | func (v Season_Nc_Sn) IsValid() bool { 59 | return v.Ordinal() >= 0 60 | } 61 | 62 | // Int returns the int value, which is not necessarily the same as the ordinal. 63 | // This facilitates polymorphism (see enum.IntEnum). 64 | func (v Season_Nc_Sn) Int() int { 65 | return int(v) 66 | } 67 | 68 | var invalidSeason_Nc_SnValue = func() Season_Nc_Sn { 69 | var v Season_Nc_Sn 70 | for { 71 | if !slices.Contains(AllSeason_Nc_Sns, v) { 72 | return v 73 | } 74 | v++ 75 | } // AllSeason_Nc_Sns is a finite set so loop will terminate eventually 76 | }() 77 | 78 | // Season_Nc_SnOf returns a Season_Nc_Sn based on an ordinal number. This is the inverse of Ordinal. 79 | // If the ordinal is out of range, an invalid Season_Nc_Sn is returned. 80 | func Season_Nc_SnOf(v int) Season_Nc_Sn { 81 | if 0 <= v && v < len(AllSeason_Nc_Sns) { 82 | return AllSeason_Nc_Sns[v] 83 | } 84 | return invalidSeason_Nc_SnValue 85 | } 86 | 87 | // Parse parses a string to find the corresponding Season_Nc_Sn, accepting one of the string values or 88 | // a number. It is used by AsSeason_Nc_Sn. 89 | // 90 | // Usage Example 91 | // 92 | // v := new(Season_Nc_Sn) 93 | // err := v.Parse(s) 94 | // ... etc 95 | func (v *Season_Nc_Sn) Parse(in string) error { 96 | if v.parseNumber(in) { 97 | return nil 98 | } 99 | 100 | s := season_nc_snTransformInput(in) 101 | 102 | return v.parseFallback(in, s) 103 | } 104 | 105 | // parseNumber attempts to convert a decimal value. 106 | // Only numbers that correspond to the enumeration are valid. 107 | func (v *Season_Nc_Sn) parseNumber(s string) (ok bool) { 108 | num, err := strconv.ParseInt(s, 10, 64) 109 | if err == nil { 110 | *v = Season_Nc_Sn(num) 111 | return v.IsValid() 112 | } 113 | return false 114 | } 115 | 116 | func (v *Season_Nc_Sn) parseFallback(in, s string) error { 117 | if v.parseString(s, season_nc_snEnumStrings, season_nc_snEnumIndex[:]) { 118 | return nil 119 | } 120 | 121 | return errors.New(in + ": unrecognised season_nc_sn") 122 | } 123 | 124 | func (v *Season_Nc_Sn) parseString(s string, concats string, indexes []uint16) (ok bool) { 125 | var i0 uint16 = 0 126 | 127 | for j := 1; j < len(indexes); j++ { 128 | i1 := indexes[j] 129 | p := concats[i0:i1] 130 | if s == p { 131 | *v = AllSeason_Nc_Sns[j-1] 132 | return true 133 | } 134 | i0 = i1 135 | } 136 | return false 137 | } 138 | 139 | // season_nc_snTransformInput may alter input strings before they are parsed. 140 | // This function is pluggable and is initialised using command-line flags 141 | // -ic -lc -uc -unsnake. 142 | var season_nc_snTransformInput = func(in string) string { 143 | return in 144 | } 145 | 146 | // AsSeason_Nc_Sn parses a string to find the corresponding Season_Nc_Sn, accepting either one of the string values or 147 | // a number. It wraps Parse. 148 | func AsSeason_Nc_Sn(s string) (Season_Nc_Sn, error) { 149 | var v = new(Season_Nc_Sn) 150 | err := v.Parse(s) 151 | return *v, err 152 | } 153 | 154 | // MustParseSeason_Nc_Sn is similar to AsSeason_Nc_Sn except that it panics on error. 155 | func MustParseSeason_Nc_Sn(s string) Season_Nc_Sn { 156 | v, err := AsSeason_Nc_Sn(s) 157 | if err != nil { 158 | panic(err) 159 | } 160 | return v 161 | } 162 | 163 | // Scan parses some value, which can be a number, a string or []byte. 164 | // It implements sql.Scanner, https://golang.org/pkg/database/sql/#Scanner 165 | func (v *Season_Nc_Sn) Scan(value interface{}) error { 166 | if value == nil { 167 | return nil 168 | } 169 | 170 | var s string 171 | switch x := value.(type) { 172 | case int64: 173 | *v = Season_Nc_Sn(x) 174 | return v.errorIfInvalid() 175 | case float64: 176 | *v = Season_Nc_Sn(x) 177 | return v.errorIfInvalid() 178 | case []byte: 179 | s = string(x) 180 | case string: 181 | s = x 182 | default: 183 | return fmt.Errorf("%T %+v is not a meaningful season_nc_sn", value, value) 184 | } 185 | 186 | return v.scanParse(s) 187 | } 188 | 189 | func (v Season_Nc_Sn) errorIfInvalid() error { 190 | if v.IsValid() { 191 | return nil 192 | } 193 | return v.invalidError() 194 | } 195 | 196 | func (v Season_Nc_Sn) invalidError() error { 197 | return fmt.Errorf("%d is not a valid season_nc_sn", v) 198 | } 199 | 200 | func (v *Season_Nc_Sn) scanParse(in string) error { 201 | if v.parseNumber(in) { 202 | return nil 203 | } 204 | 205 | s := season_nc_snTransformInput(in) 206 | 207 | return v.parseFallback(in, s) 208 | } 209 | 210 | // Value converts the Season_Nc_Sn to a number (based on '-store number'). 211 | // It implements driver.Valuer, https://golang.org/pkg/database/sql/driver/#Valuer 212 | func (v Season_Nc_Sn) Value() (driver.Value, error) { 213 | return int64(v), nil 214 | } 215 | -------------------------------------------------------------------------------- /internal/test/season_nc_ss_enum.go: -------------------------------------------------------------------------------- 1 | // generated code - do not edit 2 | // github.com/rickb777/enumeration/v4 v4.0.7 3 | 4 | package test 5 | 6 | import ( 7 | "database/sql/driver" 8 | "errors" 9 | "fmt" 10 | "slices" 11 | "strconv" 12 | ) 13 | 14 | // AllSeason_Nc_Sss lists all 4 values in order. 15 | var AllSeason_Nc_Sss = []Season_Nc_Ss{ 16 | Spring_Nc_Ss, Summer_Nc_Ss, Autumn_Nc_Ss, Winter_Nc_Ss, 17 | } 18 | 19 | const ( 20 | season_nc_ssEnumStrings = "SpringSummerAutumnWinter" 21 | season_nc_ssSQLStrings = "SprgSumrAutmWint" 22 | ) 23 | 24 | var ( 25 | season_nc_ssEnumIndex = [...]uint16{0, 6, 12, 18, 24} 26 | season_nc_ssSQLIndex = [...]uint16{0, 4, 8, 12, 16} 27 | ) 28 | 29 | // String returns the literal string representation of a Season_Nc_Ss, which is 30 | // the same as the const identifier but without prefix or suffix. 31 | func (v Season_Nc_Ss) String() string { 32 | o := v.Ordinal() 33 | return v.toString(o, season_nc_ssEnumStrings, season_nc_ssEnumIndex[:]) 34 | } 35 | 36 | // Ordinal returns the ordinal number of a Season_Nc_Ss. This is an integer counting 37 | // from zero. It is *not* the same as the const number assigned to the value. 38 | func (v Season_Nc_Ss) Ordinal() int { 39 | switch v { 40 | case Spring_Nc_Ss: 41 | return 0 42 | case Summer_Nc_Ss: 43 | return 1 44 | case Autumn_Nc_Ss: 45 | return 2 46 | case Winter_Nc_Ss: 47 | return 3 48 | } 49 | return -1 50 | } 51 | 52 | func (v Season_Nc_Ss) toString(o int, concats string, indexes []uint16) string { 53 | if o < 0 || o >= len(AllSeason_Nc_Sss) { 54 | return fmt.Sprintf("Season_Nc_Ss(%d)", v) 55 | } 56 | return concats[indexes[o]:indexes[o+1]] 57 | } 58 | 59 | // IsValid determines whether a Season_Nc_Ss is one of the defined constants. 60 | func (v Season_Nc_Ss) IsValid() bool { 61 | return v.Ordinal() >= 0 62 | } 63 | 64 | // Int returns the int value, which is not necessarily the same as the ordinal. 65 | // This facilitates polymorphism (see enum.IntEnum). 66 | func (v Season_Nc_Ss) Int() int { 67 | return int(v) 68 | } 69 | 70 | var invalidSeason_Nc_SsValue = func() Season_Nc_Ss { 71 | var v Season_Nc_Ss 72 | for { 73 | if !slices.Contains(AllSeason_Nc_Sss, v) { 74 | return v 75 | } 76 | v++ 77 | } // AllSeason_Nc_Sss is a finite set so loop will terminate eventually 78 | }() 79 | 80 | // Season_Nc_SsOf returns a Season_Nc_Ss based on an ordinal number. This is the inverse of Ordinal. 81 | // If the ordinal is out of range, an invalid Season_Nc_Ss is returned. 82 | func Season_Nc_SsOf(v int) Season_Nc_Ss { 83 | if 0 <= v && v < len(AllSeason_Nc_Sss) { 84 | return AllSeason_Nc_Sss[v] 85 | } 86 | return invalidSeason_Nc_SsValue 87 | } 88 | 89 | // Parse parses a string to find the corresponding Season_Nc_Ss, accepting one of the string values or 90 | // a number. It is used by AsSeason_Nc_Ss. 91 | // 92 | // Usage Example 93 | // 94 | // v := new(Season_Nc_Ss) 95 | // err := v.Parse(s) 96 | // ... etc 97 | func (v *Season_Nc_Ss) Parse(in string) error { 98 | if v.parseNumber(in) { 99 | return nil 100 | } 101 | 102 | s := season_nc_ssTransformInput(in) 103 | 104 | return v.parseFallback(in, s) 105 | } 106 | 107 | // parseNumber attempts to convert a decimal value. 108 | // Only numbers that correspond to the enumeration are valid. 109 | func (v *Season_Nc_Ss) parseNumber(s string) (ok bool) { 110 | num, err := strconv.ParseInt(s, 10, 64) 111 | if err == nil { 112 | *v = Season_Nc_Ss(num) 113 | return v.IsValid() 114 | } 115 | return false 116 | } 117 | 118 | func (v *Season_Nc_Ss) parseFallback(in, s string) error { 119 | if v.parseString(s, season_nc_ssEnumStrings, season_nc_ssEnumIndex[:]) { 120 | return nil 121 | } 122 | 123 | return errors.New(in + ": unrecognised season_nc_ss") 124 | } 125 | 126 | func (v *Season_Nc_Ss) parseString(s string, concats string, indexes []uint16) (ok bool) { 127 | var i0 uint16 = 0 128 | 129 | for j := 1; j < len(indexes); j++ { 130 | i1 := indexes[j] 131 | p := concats[i0:i1] 132 | if s == p { 133 | *v = AllSeason_Nc_Sss[j-1] 134 | return true 135 | } 136 | i0 = i1 137 | } 138 | return false 139 | } 140 | 141 | // season_nc_ssTransformInput may alter input strings before they are parsed. 142 | // This function is pluggable and is initialised using command-line flags 143 | // -ic -lc -uc -unsnake. 144 | var season_nc_ssTransformInput = func(in string) string { 145 | return in 146 | } 147 | 148 | // AsSeason_Nc_Ss parses a string to find the corresponding Season_Nc_Ss, accepting either one of the string values or 149 | // a number. It wraps Parse. 150 | func AsSeason_Nc_Ss(s string) (Season_Nc_Ss, error) { 151 | var v = new(Season_Nc_Ss) 152 | err := v.Parse(s) 153 | return *v, err 154 | } 155 | 156 | // MustParseSeason_Nc_Ss is similar to AsSeason_Nc_Ss except that it panics on error. 157 | func MustParseSeason_Nc_Ss(s string) Season_Nc_Ss { 158 | v, err := AsSeason_Nc_Ss(s) 159 | if err != nil { 160 | panic(err) 161 | } 162 | return v 163 | } 164 | 165 | // Scan parses some value, which can be a number, a string or []byte. 166 | // It implements sql.Scanner, https://golang.org/pkg/database/sql/#Scanner 167 | func (v *Season_Nc_Ss) Scan(value interface{}) error { 168 | if value == nil { 169 | return nil 170 | } 171 | 172 | var s string 173 | switch x := value.(type) { 174 | case int64: 175 | *v = Season_Nc_Ss(x) 176 | return v.errorIfInvalid() 177 | case float64: 178 | *v = Season_Nc_Ss(x) 179 | return v.errorIfInvalid() 180 | case []byte: 181 | s = string(x) 182 | case string: 183 | s = x 184 | default: 185 | return fmt.Errorf("%T %+v is not a meaningful season_nc_ss", value, value) 186 | } 187 | 188 | return v.scanParse(s) 189 | } 190 | 191 | func (v Season_Nc_Ss) errorIfInvalid() error { 192 | if v.IsValid() { 193 | return nil 194 | } 195 | return v.invalidError() 196 | } 197 | 198 | func (v Season_Nc_Ss) invalidError() error { 199 | return fmt.Errorf("%d is not a valid season_nc_ss", v) 200 | } 201 | 202 | func (v *Season_Nc_Ss) scanParse(in string) error { 203 | if v.parseNumber(in) { 204 | return nil 205 | } 206 | 207 | s := season_nc_ssTransformInput(in) 208 | 209 | if v.parseString(s, season_nc_ssSQLStrings, season_nc_ssSQLIndex[:]) { 210 | return nil 211 | } 212 | 213 | return v.parseFallback(in, s) 214 | } 215 | 216 | // Value converts the Season_Nc_Ss to a string. 217 | // The representation is chosen according to 'sql' struct tags. 218 | // It implements driver.Valuer, https://golang.org/pkg/database/sql/driver/#Valuer 219 | func (v Season_Nc_Ss) Value() (driver.Value, error) { 220 | o := v.Ordinal() 221 | if o < 0 { 222 | return nil, fmt.Errorf("%v: cannot be stored", v) 223 | } 224 | 225 | return v.toString(o, season_nc_ssSQLStrings, season_nc_ssSQLIndex[:]), nil 226 | } 227 | -------------------------------------------------------------------------------- /internal/test/season_nc_ti_enum.go: -------------------------------------------------------------------------------- 1 | // generated code - do not edit 2 | // github.com/rickb777/enumeration/v4 v4.0.7 3 | 4 | package test 5 | 6 | import ( 7 | "errors" 8 | "fmt" 9 | "slices" 10 | "strconv" 11 | ) 12 | 13 | // AllSeason_Nc_Tis lists all 4 values in order. 14 | var AllSeason_Nc_Tis = []Season_Nc_Ti{ 15 | Spring_Nc_Ti, Summer_Nc_Ti, Autumn_Nc_Ti, Winter_Nc_Ti, 16 | } 17 | 18 | const ( 19 | season_nc_tiEnumStrings = "SpringSummerAutumnWinter" 20 | ) 21 | 22 | var ( 23 | season_nc_tiEnumIndex = [...]uint16{0, 6, 12, 18, 24} 24 | ) 25 | 26 | // String returns the literal string representation of a Season_Nc_Ti, which is 27 | // the same as the const identifier but without prefix or suffix. 28 | func (v Season_Nc_Ti) String() string { 29 | o := v.Ordinal() 30 | return v.toString(o, season_nc_tiEnumStrings, season_nc_tiEnumIndex[:]) 31 | } 32 | 33 | // Ordinal returns the ordinal number of a Season_Nc_Ti. This is an integer counting 34 | // from zero. It is *not* the same as the const number assigned to the value. 35 | func (v Season_Nc_Ti) Ordinal() int { 36 | switch v { 37 | case Spring_Nc_Ti: 38 | return 0 39 | case Summer_Nc_Ti: 40 | return 1 41 | case Autumn_Nc_Ti: 42 | return 2 43 | case Winter_Nc_Ti: 44 | return 3 45 | } 46 | return -1 47 | } 48 | 49 | func (v Season_Nc_Ti) toString(o int, concats string, indexes []uint16) string { 50 | if o < 0 || o >= len(AllSeason_Nc_Tis) { 51 | return fmt.Sprintf("Season_Nc_Ti(%d)", v) 52 | } 53 | return concats[indexes[o]:indexes[o+1]] 54 | } 55 | 56 | // IsValid determines whether a Season_Nc_Ti is one of the defined constants. 57 | func (v Season_Nc_Ti) IsValid() bool { 58 | return v.Ordinal() >= 0 59 | } 60 | 61 | // Int returns the int value, which is not necessarily the same as the ordinal. 62 | // This facilitates polymorphism (see enum.IntEnum). 63 | func (v Season_Nc_Ti) Int() int { 64 | return int(v) 65 | } 66 | 67 | var invalidSeason_Nc_TiValue = func() Season_Nc_Ti { 68 | var v Season_Nc_Ti 69 | for { 70 | if !slices.Contains(AllSeason_Nc_Tis, v) { 71 | return v 72 | } 73 | v++ 74 | } // AllSeason_Nc_Tis is a finite set so loop will terminate eventually 75 | }() 76 | 77 | // Season_Nc_TiOf returns a Season_Nc_Ti based on an ordinal number. This is the inverse of Ordinal. 78 | // If the ordinal is out of range, an invalid Season_Nc_Ti is returned. 79 | func Season_Nc_TiOf(v int) Season_Nc_Ti { 80 | if 0 <= v && v < len(AllSeason_Nc_Tis) { 81 | return AllSeason_Nc_Tis[v] 82 | } 83 | return invalidSeason_Nc_TiValue 84 | } 85 | 86 | // Parse parses a string to find the corresponding Season_Nc_Ti, accepting one of the string values or 87 | // a number. The input representation is determined by Identifier. It is used by AsSeason_Nc_Ti. 88 | // 89 | // Usage Example 90 | // 91 | // v := new(Season_Nc_Ti) 92 | // err := v.Parse(s) 93 | // ... etc 94 | func (v *Season_Nc_Ti) Parse(in string) error { 95 | if v.parseNumber(in) { 96 | return nil 97 | } 98 | 99 | s := season_nc_tiTransformInput(in) 100 | 101 | return v.parseFallback(in, s) 102 | } 103 | 104 | // parseNumber attempts to convert a decimal value. 105 | // Only numbers that correspond to the enumeration are valid. 106 | func (v *Season_Nc_Ti) parseNumber(s string) (ok bool) { 107 | num, err := strconv.ParseInt(s, 10, 64) 108 | if err == nil { 109 | *v = Season_Nc_Ti(num) 110 | return v.IsValid() 111 | } 112 | return false 113 | } 114 | 115 | func (v *Season_Nc_Ti) parseFallback(in, s string) error { 116 | if v.parseString(s, season_nc_tiEnumStrings, season_nc_tiEnumIndex[:]) { 117 | return nil 118 | } 119 | 120 | return errors.New(in + ": unrecognised season_nc_ti") 121 | } 122 | 123 | func (v *Season_Nc_Ti) parseString(s string, concats string, indexes []uint16) (ok bool) { 124 | var i0 uint16 = 0 125 | 126 | for j := 1; j < len(indexes); j++ { 127 | i1 := indexes[j] 128 | p := concats[i0:i1] 129 | if s == p { 130 | *v = AllSeason_Nc_Tis[j-1] 131 | return true 132 | } 133 | i0 = i1 134 | } 135 | return false 136 | } 137 | 138 | // season_nc_tiTransformInput may alter input strings before they are parsed. 139 | // This function is pluggable and is initialised using command-line flags 140 | // -ic -lc -uc -unsnake. 141 | var season_nc_tiTransformInput = func(in string) string { 142 | return in 143 | } 144 | 145 | // AsSeason_Nc_Ti parses a string to find the corresponding Season_Nc_Ti, accepting either one of the string values or 146 | // a number. The input representation is determined by season_nc_tiMarshalTextRep. It wraps Parse. 147 | func AsSeason_Nc_Ti(s string) (Season_Nc_Ti, error) { 148 | var v = new(Season_Nc_Ti) 149 | err := v.Parse(s) 150 | return *v, err 151 | } 152 | 153 | // MustParseSeason_Nc_Ti is similar to AsSeason_Nc_Ti except that it panics on error. 154 | func MustParseSeason_Nc_Ti(s string) Season_Nc_Ti { 155 | v, err := AsSeason_Nc_Ti(s) 156 | if err != nil { 157 | panic(err) 158 | } 159 | return v 160 | } 161 | 162 | // MarshalText converts values to bytes suitable for transmission via XML, JSON etc. 163 | func (v Season_Nc_Ti) MarshalText() ([]byte, error) { 164 | s, err := v.marshalText() 165 | return []byte(s), err 166 | } 167 | 168 | // Text returns the representation used for transmission via XML, JSON etc. 169 | func (v Season_Nc_Ti) Text() string { 170 | s, _ := v.marshalText() 171 | return s 172 | } 173 | 174 | // marshalText converts values to a form suitable for transmission via XML, JSON etc. 175 | // The identifier representation is chosen according to -marshaltext. 176 | func (v Season_Nc_Ti) marshalText() (string, error) { 177 | o := v.Ordinal() 178 | if o < 0 { 179 | return v.marshalNumberStringOrError() 180 | } 181 | 182 | return v.toString(o, season_nc_tiEnumStrings, season_nc_tiEnumIndex[:]), nil 183 | } 184 | 185 | func (v Season_Nc_Ti) marshalNumberStringOrError() (string, error) { 186 | bs, err := v.marshalNumberOrError() 187 | return string(bs), err 188 | } 189 | 190 | func (v Season_Nc_Ti) marshalNumberOrError() ([]byte, error) { 191 | // disallow lenient marshaling 192 | return nil, v.invalidError() 193 | } 194 | 195 | func (v Season_Nc_Ti) invalidError() error { 196 | return fmt.Errorf("%d is not a valid season_nc_ti", v) 197 | } 198 | 199 | // UnmarshalText converts transmitted values to ordinary values. 200 | func (v *Season_Nc_Ti) UnmarshalText(bs []byte) error { 201 | return v.unmarshalText(string(bs)) 202 | } 203 | 204 | func (v *Season_Nc_Ti) unmarshalText(in string) error { 205 | if v.parseNumber(in) { 206 | return nil 207 | } 208 | 209 | s := season_nc_tiTransformInput(in) 210 | 211 | return v.parseFallback(in, s) 212 | } 213 | -------------------------------------------------------------------------------- /internal/test/season_nc_tn_enum.go: -------------------------------------------------------------------------------- 1 | // generated code - do not edit 2 | // github.com/rickb777/enumeration/v4 v4.0.7 3 | 4 | package test 5 | 6 | import ( 7 | "errors" 8 | "fmt" 9 | "slices" 10 | "strconv" 11 | ) 12 | 13 | // AllSeason_Nc_Tns lists all 4 values in order. 14 | var AllSeason_Nc_Tns = []Season_Nc_Tn{ 15 | Spring_Nc_Tn, Summer_Nc_Tn, Autumn_Nc_Tn, Winter_Nc_Tn, 16 | } 17 | 18 | const ( 19 | season_nc_tnEnumStrings = "SpringSummerAutumnWinter" 20 | ) 21 | 22 | var ( 23 | season_nc_tnEnumIndex = [...]uint16{0, 6, 12, 18, 24} 24 | ) 25 | 26 | // String returns the literal string representation of a Season_Nc_Tn, which is 27 | // the same as the const identifier but without prefix or suffix. 28 | func (v Season_Nc_Tn) String() string { 29 | o := v.Ordinal() 30 | return v.toString(o, season_nc_tnEnumStrings, season_nc_tnEnumIndex[:]) 31 | } 32 | 33 | // Ordinal returns the ordinal number of a Season_Nc_Tn. This is an integer counting 34 | // from zero. It is *not* the same as the const number assigned to the value. 35 | func (v Season_Nc_Tn) Ordinal() int { 36 | switch v { 37 | case Spring_Nc_Tn: 38 | return 0 39 | case Summer_Nc_Tn: 40 | return 1 41 | case Autumn_Nc_Tn: 42 | return 2 43 | case Winter_Nc_Tn: 44 | return 3 45 | } 46 | return -1 47 | } 48 | 49 | func (v Season_Nc_Tn) toString(o int, concats string, indexes []uint16) string { 50 | if o < 0 || o >= len(AllSeason_Nc_Tns) { 51 | return fmt.Sprintf("Season_Nc_Tn(%d)", v) 52 | } 53 | return concats[indexes[o]:indexes[o+1]] 54 | } 55 | 56 | // IsValid determines whether a Season_Nc_Tn is one of the defined constants. 57 | func (v Season_Nc_Tn) IsValid() bool { 58 | return v.Ordinal() >= 0 59 | } 60 | 61 | // Int returns the int value, which is not necessarily the same as the ordinal. 62 | // This facilitates polymorphism (see enum.IntEnum). 63 | func (v Season_Nc_Tn) Int() int { 64 | return int(v) 65 | } 66 | 67 | var invalidSeason_Nc_TnValue = func() Season_Nc_Tn { 68 | var v Season_Nc_Tn 69 | for { 70 | if !slices.Contains(AllSeason_Nc_Tns, v) { 71 | return v 72 | } 73 | v++ 74 | } // AllSeason_Nc_Tns is a finite set so loop will terminate eventually 75 | }() 76 | 77 | // Season_Nc_TnOf returns a Season_Nc_Tn based on an ordinal number. This is the inverse of Ordinal. 78 | // If the ordinal is out of range, an invalid Season_Nc_Tn is returned. 79 | func Season_Nc_TnOf(v int) Season_Nc_Tn { 80 | if 0 <= v && v < len(AllSeason_Nc_Tns) { 81 | return AllSeason_Nc_Tns[v] 82 | } 83 | return invalidSeason_Nc_TnValue 84 | } 85 | 86 | // Parse parses a string to find the corresponding Season_Nc_Tn, accepting one of the string values or 87 | // a number. The input representation is determined by Number. It is used by AsSeason_Nc_Tn. 88 | // 89 | // Usage Example 90 | // 91 | // v := new(Season_Nc_Tn) 92 | // err := v.Parse(s) 93 | // ... etc 94 | func (v *Season_Nc_Tn) Parse(in string) error { 95 | if v.parseNumber(in) { 96 | return nil 97 | } 98 | 99 | s := season_nc_tnTransformInput(in) 100 | 101 | return v.parseFallback(in, s) 102 | } 103 | 104 | // parseNumber attempts to convert a decimal value. 105 | // Only numbers that correspond to the enumeration are valid. 106 | func (v *Season_Nc_Tn) parseNumber(s string) (ok bool) { 107 | num, err := strconv.ParseInt(s, 10, 64) 108 | if err == nil { 109 | *v = Season_Nc_Tn(num) 110 | return v.IsValid() 111 | } 112 | return false 113 | } 114 | 115 | func (v *Season_Nc_Tn) parseFallback(in, s string) error { 116 | if v.parseString(s, season_nc_tnEnumStrings, season_nc_tnEnumIndex[:]) { 117 | return nil 118 | } 119 | 120 | return errors.New(in + ": unrecognised season_nc_tn") 121 | } 122 | 123 | func (v *Season_Nc_Tn) parseString(s string, concats string, indexes []uint16) (ok bool) { 124 | var i0 uint16 = 0 125 | 126 | for j := 1; j < len(indexes); j++ { 127 | i1 := indexes[j] 128 | p := concats[i0:i1] 129 | if s == p { 130 | *v = AllSeason_Nc_Tns[j-1] 131 | return true 132 | } 133 | i0 = i1 134 | } 135 | return false 136 | } 137 | 138 | // season_nc_tnTransformInput may alter input strings before they are parsed. 139 | // This function is pluggable and is initialised using command-line flags 140 | // -ic -lc -uc -unsnake. 141 | var season_nc_tnTransformInput = func(in string) string { 142 | return in 143 | } 144 | 145 | // AsSeason_Nc_Tn parses a string to find the corresponding Season_Nc_Tn, accepting either one of the string values or 146 | // a number. The input representation is determined by season_nc_tnMarshalTextRep. It wraps Parse. 147 | func AsSeason_Nc_Tn(s string) (Season_Nc_Tn, error) { 148 | var v = new(Season_Nc_Tn) 149 | err := v.Parse(s) 150 | return *v, err 151 | } 152 | 153 | // MustParseSeason_Nc_Tn is similar to AsSeason_Nc_Tn except that it panics on error. 154 | func MustParseSeason_Nc_Tn(s string) Season_Nc_Tn { 155 | v, err := AsSeason_Nc_Tn(s) 156 | if err != nil { 157 | panic(err) 158 | } 159 | return v 160 | } 161 | 162 | // MarshalText converts values to bytes suitable for transmission via XML, JSON etc. 163 | func (v Season_Nc_Tn) MarshalText() ([]byte, error) { 164 | s, err := v.marshalText() 165 | return []byte(s), err 166 | } 167 | 168 | // marshalText converts values to a form suitable for transmission via XML, JSON etc. 169 | // The number representation is chosen according to -marshaltext. 170 | func (v Season_Nc_Tn) marshalText() (string, error) { 171 | if !v.IsValid() { 172 | return v.marshalNumberStringOrError() 173 | } 174 | 175 | return season_nc_tnMarshalNumber(v), nil 176 | } 177 | 178 | func (v Season_Nc_Tn) marshalNumberStringOrError() (string, error) { 179 | bs, err := v.marshalNumberOrError() 180 | return string(bs), err 181 | } 182 | 183 | func (v Season_Nc_Tn) marshalNumberOrError() ([]byte, error) { 184 | // disallow lenient marshaling 185 | return nil, v.invalidError() 186 | } 187 | 188 | func (v Season_Nc_Tn) invalidError() error { 189 | return fmt.Errorf("%d is not a valid season_nc_tn", v) 190 | } 191 | 192 | // season_nc_tnMarshalNumber handles marshaling where a number is required or where 193 | // the value is out of range. 194 | // This function can be replaced with any bespoke function than matches signature. 195 | var season_nc_tnMarshalNumber = func(v Season_Nc_Tn) string { 196 | return strconv.FormatInt(int64(v), 10) 197 | } 198 | 199 | // UnmarshalText converts transmitted values to ordinary values. 200 | func (v *Season_Nc_Tn) UnmarshalText(bs []byte) error { 201 | return v.unmarshalText(string(bs)) 202 | } 203 | 204 | func (v *Season_Nc_Tn) unmarshalText(in string) error { 205 | if v.parseNumber(in) { 206 | return nil 207 | } 208 | 209 | s := season_nc_tnTransformInput(in) 210 | 211 | return v.parseFallback(in, s) 212 | } 213 | -------------------------------------------------------------------------------- /internal/test/season_nc_tt_enum.go: -------------------------------------------------------------------------------- 1 | // generated code - do not edit 2 | // github.com/rickb777/enumeration/v4 v4.0.7 3 | 4 | package test 5 | 6 | import ( 7 | "errors" 8 | "fmt" 9 | "slices" 10 | "strconv" 11 | ) 12 | 13 | // AllSeason_Nc_Tts lists all 4 values in order. 14 | var AllSeason_Nc_Tts = []Season_Nc_Tt{ 15 | Spring_Nc_Tt, Summer_Nc_Tt, Autumn_Nc_Tt, Winter_Nc_Tt, 16 | } 17 | 18 | const ( 19 | season_nc_ttEnumStrings = "SpringSummerAutumnWinter" 20 | season_nc_ttTextStrings = "SprgSumrAutmWint" 21 | ) 22 | 23 | var ( 24 | season_nc_ttEnumIndex = [...]uint16{0, 6, 12, 18, 24} 25 | season_nc_ttTextIndex = [...]uint16{0, 4, 8, 12, 16} 26 | ) 27 | 28 | // String returns the literal string representation of a Season_Nc_Tt, which is 29 | // the same as the const identifier but without prefix or suffix. 30 | func (v Season_Nc_Tt) String() string { 31 | o := v.Ordinal() 32 | return v.toString(o, season_nc_ttEnumStrings, season_nc_ttEnumIndex[:]) 33 | } 34 | 35 | // Ordinal returns the ordinal number of a Season_Nc_Tt. This is an integer counting 36 | // from zero. It is *not* the same as the const number assigned to the value. 37 | func (v Season_Nc_Tt) Ordinal() int { 38 | switch v { 39 | case Spring_Nc_Tt: 40 | return 0 41 | case Summer_Nc_Tt: 42 | return 1 43 | case Autumn_Nc_Tt: 44 | return 2 45 | case Winter_Nc_Tt: 46 | return 3 47 | } 48 | return -1 49 | } 50 | 51 | func (v Season_Nc_Tt) toString(o int, concats string, indexes []uint16) string { 52 | if o < 0 || o >= len(AllSeason_Nc_Tts) { 53 | return fmt.Sprintf("Season_Nc_Tt(%d)", v) 54 | } 55 | return concats[indexes[o]:indexes[o+1]] 56 | } 57 | 58 | // IsValid determines whether a Season_Nc_Tt is one of the defined constants. 59 | func (v Season_Nc_Tt) IsValid() bool { 60 | return v.Ordinal() >= 0 61 | } 62 | 63 | // Int returns the int value, which is not necessarily the same as the ordinal. 64 | // This facilitates polymorphism (see enum.IntEnum). 65 | func (v Season_Nc_Tt) Int() int { 66 | return int(v) 67 | } 68 | 69 | var invalidSeason_Nc_TtValue = func() Season_Nc_Tt { 70 | var v Season_Nc_Tt 71 | for { 72 | if !slices.Contains(AllSeason_Nc_Tts, v) { 73 | return v 74 | } 75 | v++ 76 | } // AllSeason_Nc_Tts is a finite set so loop will terminate eventually 77 | }() 78 | 79 | // Season_Nc_TtOf returns a Season_Nc_Tt based on an ordinal number. This is the inverse of Ordinal. 80 | // If the ordinal is out of range, an invalid Season_Nc_Tt is returned. 81 | func Season_Nc_TtOf(v int) Season_Nc_Tt { 82 | if 0 <= v && v < len(AllSeason_Nc_Tts) { 83 | return AllSeason_Nc_Tts[v] 84 | } 85 | return invalidSeason_Nc_TtValue 86 | } 87 | 88 | // Parse parses a string to find the corresponding Season_Nc_Tt, accepting one of the string values or 89 | // a number. It is used by AsSeason_Nc_Tt. 90 | // 91 | // Usage Example 92 | // 93 | // v := new(Season_Nc_Tt) 94 | // err := v.Parse(s) 95 | // ... etc 96 | func (v *Season_Nc_Tt) Parse(in string) error { 97 | if v.parseNumber(in) { 98 | return nil 99 | } 100 | 101 | s := season_nc_ttTransformInput(in) 102 | 103 | return v.parseFallback(in, s) 104 | } 105 | 106 | // parseNumber attempts to convert a decimal value. 107 | // Only numbers that correspond to the enumeration are valid. 108 | func (v *Season_Nc_Tt) parseNumber(s string) (ok bool) { 109 | num, err := strconv.ParseInt(s, 10, 64) 110 | if err == nil { 111 | *v = Season_Nc_Tt(num) 112 | return v.IsValid() 113 | } 114 | return false 115 | } 116 | 117 | func (v *Season_Nc_Tt) parseFallback(in, s string) error { 118 | if v.parseString(s, season_nc_ttEnumStrings, season_nc_ttEnumIndex[:]) { 119 | return nil 120 | } 121 | 122 | return errors.New(in + ": unrecognised season_nc_tt") 123 | } 124 | 125 | func (v *Season_Nc_Tt) parseString(s string, concats string, indexes []uint16) (ok bool) { 126 | var i0 uint16 = 0 127 | 128 | for j := 1; j < len(indexes); j++ { 129 | i1 := indexes[j] 130 | p := concats[i0:i1] 131 | if s == p { 132 | *v = AllSeason_Nc_Tts[j-1] 133 | return true 134 | } 135 | i0 = i1 136 | } 137 | return false 138 | } 139 | 140 | // season_nc_ttTransformInput may alter input strings before they are parsed. 141 | // This function is pluggable and is initialised using command-line flags 142 | // -ic -lc -uc -unsnake. 143 | var season_nc_ttTransformInput = func(in string) string { 144 | return in 145 | } 146 | 147 | // AsSeason_Nc_Tt parses a string to find the corresponding Season_Nc_Tt, accepting either one of the string values or 148 | // a number. It wraps Parse. 149 | func AsSeason_Nc_Tt(s string) (Season_Nc_Tt, error) { 150 | var v = new(Season_Nc_Tt) 151 | err := v.Parse(s) 152 | return *v, err 153 | } 154 | 155 | // MustParseSeason_Nc_Tt is similar to AsSeason_Nc_Tt except that it panics on error. 156 | func MustParseSeason_Nc_Tt(s string) Season_Nc_Tt { 157 | v, err := AsSeason_Nc_Tt(s) 158 | if err != nil { 159 | panic(err) 160 | } 161 | return v 162 | } 163 | 164 | // MarshalText converts values to bytes suitable for transmission via XML, JSON etc. 165 | func (v Season_Nc_Tt) MarshalText() ([]byte, error) { 166 | s, err := v.marshalText() 167 | return []byte(s), err 168 | } 169 | 170 | // Text returns the representation used for transmission via XML, JSON etc. 171 | func (v Season_Nc_Tt) Text() string { 172 | s, _ := v.marshalText() 173 | return s 174 | } 175 | 176 | // marshalText converts values to bytes suitable for transmission via XML, JSON etc. 177 | // The representation is chosen according to 'text' struct tags. 178 | func (v Season_Nc_Tt) marshalText() (string, error) { 179 | o := v.Ordinal() 180 | if o < 0 { 181 | return v.marshalNumberStringOrError() 182 | } 183 | 184 | return v.toString(o, season_nc_ttTextStrings, season_nc_ttTextIndex[:]), nil 185 | } 186 | 187 | func (v Season_Nc_Tt) marshalNumberStringOrError() (string, error) { 188 | bs, err := v.marshalNumberOrError() 189 | return string(bs), err 190 | } 191 | 192 | func (v Season_Nc_Tt) marshalNumberOrError() ([]byte, error) { 193 | // disallow lenient marshaling 194 | return nil, v.invalidError() 195 | } 196 | 197 | func (v Season_Nc_Tt) invalidError() error { 198 | return fmt.Errorf("%d is not a valid season_nc_tt", v) 199 | } 200 | 201 | // UnmarshalText converts transmitted values to ordinary values. 202 | func (v *Season_Nc_Tt) UnmarshalText(bs []byte) error { 203 | return v.unmarshalText(string(bs)) 204 | } 205 | 206 | func (v *Season_Nc_Tt) unmarshalText(in string) error { 207 | if v.parseNumber(in) { 208 | return nil 209 | } 210 | 211 | s := season_nc_ttTransformInput(in) 212 | 213 | if v.parseString(s, season_nc_ttTextStrings, season_nc_ttTextIndex[:]) { 214 | return nil 215 | } 216 | 217 | return v.parseFallback(in, s) 218 | } 219 | -------------------------------------------------------------------------------- /internal/test/season_sql.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | //go:generate enumeration -v -f -i season_sql.go -type Season_Nc_Si -suffix _Nc_Si -store identifier 4 | //go:generate enumeration -v -f -i season_sql.go -type Season_Nc_Sn -suffix _Nc_Sn -store number 5 | //go:generate enumeration -v -f -i season_sql.go -type Season_Nc_Ss -suffix _Nc_Ss 6 | 7 | type ( 8 | Season_Nc_Si uint 9 | Season_Nc_Sn uint 10 | Season_Nc_Ss uint 11 | ) 12 | 13 | const ( 14 | Spring_Nc_Si, Summer_Nc_Si, Autumn_Nc_Si, Winter_Nc_Si Season_Nc_Si = 1, 2, 3, 4 15 | ) 16 | 17 | const ( 18 | Spring_Nc_Sn, Summer_Nc_Sn, Autumn_Nc_Sn, Winter_Nc_Sn Season_Nc_Sn = 1, 2, 3, 4 19 | ) 20 | 21 | const ( 22 | _ Season_Nc_Ss = iota 23 | Spring_Nc_Ss // sql:"Sprg" 24 | Summer_Nc_Ss // sql:"Sumr" 25 | Autumn_Nc_Ss // sql:"Autm" 26 | Winter_Nc_Ss // sql:"Wint" 27 | ) 28 | 29 | //================================================================================================= 30 | //go:generate enumeration -v -f -i season_sql.go -type Season_Ic_Si -suffix _Ic_Si -ic -store identifier 31 | //go:generate enumeration -v -f -i season_sql.go -type Season_Ic_Sn -suffix _Ic_Sn -ic -store number 32 | //go:generate enumeration -v -f -i season_sql.go -type Season_Ic_Ss -suffix _Ic_Ss -ic 33 | 34 | type ( 35 | Season_Ic_Si uint 36 | Season_Ic_Sn uint 37 | Season_Ic_Ss uint 38 | ) 39 | 40 | const ( 41 | Spring_Ic_Si, Summer_Ic_Si, Autumn_Ic_Si, Winter_Ic_Si Season_Ic_Si = 1, 2, 3, 4 42 | ) 43 | 44 | const ( 45 | Spring_Ic_Sn, Summer_Ic_Sn, Autumn_Ic_Sn, Winter_Ic_Sn Season_Ic_Sn = 1, 2, 3, 4 46 | ) 47 | 48 | const ( 49 | _ Season_Ic_Ss = iota 50 | Spring_Ic_Ss // sql:"Sprg" 51 | Summer_Ic_Ss // sql:"Sumr" 52 | Autumn_Ic_Ss // sql:"Autm" 53 | Winter_Ic_Ss // sql:"Wint" 54 | ) 55 | 56 | //================================================================================================= 57 | //go:generate enumeration -v -f -i season_sql.go -type Season_Uc_Si -suffix _Uc_Si -uc -store identifier 58 | //go:generate enumeration -v -f -i season_sql.go -type Season_Uc_Sn -suffix _Uc_Sn -uc -store number 59 | 60 | type ( 61 | Season_Uc_Si uint 62 | Season_Uc_Sn uint 63 | ) 64 | 65 | const ( 66 | Spring_Uc_Si, Summer_Uc_Si, Autumn_Uc_Si, Winter_Uc_Si Season_Uc_Si = 1, 2, 3, 4 67 | ) 68 | 69 | const ( 70 | Spring_Uc_Sn, Summer_Uc_Sn, Autumn_Uc_Sn, Winter_Uc_Sn Season_Uc_Sn = 1, 2, 3, 4 71 | ) 72 | -------------------------------------------------------------------------------- /internal/test/season_text.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | //================================================================================================= 4 | //go:generate enumeration -v -f -i season_text.go -type Season_Nc_Ti -suffix _Nc_Ti -marshaltext identifier 5 | //go:generate enumeration -v -f -i season_text.go -type Season_Nc_Tn -suffix _Nc_Tn -marshaltext number 6 | //go:generate enumeration -v -f -i season_text.go -type Season_Nc_Tt -suffix _Nc_Tt 7 | //go:generate enumeration -v -f -i season_text.go -type Season_Nc_Ta -suffix _Nc_Ta 8 | 9 | type ( 10 | Season_Nc_Ti uint 11 | Season_Nc_Tn uint 12 | Season_Nc_Tt uint 13 | Season_Nc_Ta uint 14 | ) 15 | 16 | const ( 17 | Spring_Nc_Ti, Summer_Nc_Ti, Autumn_Nc_Ti, Winter_Nc_Ti Season_Nc_Ti = 1, 2, 3, 4 18 | ) 19 | 20 | const ( 21 | Spring_Nc_Tn, Summer_Nc_Tn, Autumn_Nc_Tn, Winter_Nc_Tn Season_Nc_Tn = 1, 2, 3, 4 22 | ) 23 | 24 | const ( 25 | _ Season_Nc_Tt = iota 26 | Spring_Nc_Tt // text:"Sprg" 27 | Summer_Nc_Tt // text:"Sumr" 28 | Autumn_Nc_Tt // text:"Autm" 29 | Winter_Nc_Tt // text:"Wint" 30 | ) 31 | 32 | const ( 33 | _ Season_Nc_Ta = iota 34 | Spring_Nc_Ta // all:"Sprg" 35 | Summer_Nc_Ta // all:"Sumr" 36 | Autumn_Nc_Ta // all:"Autm" 37 | Winter_Nc_Ta // all:"Wint" 38 | ) 39 | 40 | //================================================================================================= 41 | //go:generate enumeration -v -f -i season_text.go -type Season_Ic_Ti -suffix _Ic_Ti -ic -marshaltext identifier 42 | //go:generate enumeration -v -f -i season_text.go -type Season_Ic_Tn -suffix _Ic_Tn -ic -marshaltext number 43 | //go:generate enumeration -v -f -i season_text.go -type Season_Ic_Tt -suffix _Ic_Tt -ic 44 | //go:generate enumeration -v -f -i season_text.go -type Season_Ic_Ta -suffix _Ic_Ta -ic 45 | 46 | type ( 47 | Season_Ic_Ti uint 48 | Season_Ic_Tn uint 49 | Season_Ic_Tt uint 50 | Season_Ic_Ta uint 51 | ) 52 | 53 | const ( 54 | Spring_Ic_Ti, Summer_Ic_Ti, Autumn_Ic_Ti, Winter_Ic_Ti Season_Ic_Ti = 1, 2, 3, 4 55 | ) 56 | 57 | const ( 58 | Spring_Ic_Tn, Summer_Ic_Tn, Autumn_Ic_Tn, Winter_Ic_Tn Season_Ic_Tn = 1, 2, 3, 4 59 | ) 60 | 61 | const ( 62 | _ Season_Ic_Tt = iota 63 | Spring_Ic_Tt // text:"Sprg" 64 | Summer_Ic_Tt // text:"Sumr" 65 | Autumn_Ic_Tt // text:"Autm" 66 | Winter_Ic_Tt // text:"Wint" 67 | ) 68 | 69 | const ( 70 | _ Season_Ic_Ta = iota 71 | Spring_Ic_Ta // all:"Sprg" 72 | Summer_Ic_Ta // all:"Sumr" 73 | Autumn_Ic_Ta // all:"Autm" 74 | Winter_Ic_Ta // all:"Wint" 75 | ) 76 | 77 | //================================================================================================= 78 | //go:generate enumeration -v -f -i season_text.go -type Season_Uc_Ti -suffix _Uc_Ti -uc -marshaltext identifier 79 | //go:generate enumeration -v -f -i season_text.go -type Season_Uc_Tn -suffix _Uc_Tn -uc -marshaltext number 80 | //go:generate enumeration -v -f -i season_text.go -type Season_Uc_Tt -suffix _Uc_Tt -uc 81 | //go:generate enumeration -v -f -i season_text.go -type Season_Uc_Ta -suffix _Uc_Ta -uc 82 | 83 | type ( 84 | Season_Uc_Ti uint 85 | Season_Uc_Tn uint 86 | Season_Uc_Tt uint 87 | Season_Uc_Ta uint 88 | ) 89 | 90 | const ( 91 | Spring_Uc_Ti, Summer_Uc_Ti, Autumn_Uc_Ti, Winter_Uc_Ti Season_Uc_Ti = 1, 2, 3, 4 92 | ) 93 | 94 | const ( 95 | Spring_Uc_Tn, Summer_Uc_Tn, Autumn_Uc_Tn, Winter_Uc_Tn Season_Uc_Tn = 1, 2, 3, 4 96 | ) 97 | 98 | const ( 99 | _ Season_Uc_Tt = iota 100 | Spring_Uc_Tt // text:"Sprg" 101 | Summer_Uc_Tt // text:"Sumr" 102 | Autumn_Uc_Tt // text:"Autm" 103 | Winter_Uc_Tt // text:"Wint" 104 | ) 105 | 106 | const ( 107 | _ Season_Uc_Ta = iota 108 | Spring_Uc_Ta // all:"Sprg" 109 | Summer_Uc_Ta // all:"Sumr" 110 | Autumn_Uc_Ta // all:"Autm" 111 | Winter_Uc_Ta // all:"Wint" 112 | ) 113 | -------------------------------------------------------------------------------- /internal/test/season_uc_jn_enum.go: -------------------------------------------------------------------------------- 1 | // generated code - do not edit 2 | // github.com/rickb777/enumeration/v4 v4.0.7 3 | 4 | package test 5 | 6 | import ( 7 | "errors" 8 | "fmt" 9 | "slices" 10 | "strconv" 11 | "strings" 12 | ) 13 | 14 | // AllSeason_Uc_Jns lists all 4 values in order. 15 | var AllSeason_Uc_Jns = []Season_Uc_Jn{ 16 | Spring_Uc_Jn, Summer_Uc_Jn, Autumn_Uc_Jn, Winter_Uc_Jn, 17 | } 18 | 19 | const ( 20 | season_uc_jnEnumStrings = "SPRINGSUMMERAUTUMNWINTER" 21 | ) 22 | 23 | var ( 24 | season_uc_jnEnumIndex = [...]uint16{0, 6, 12, 18, 24} 25 | ) 26 | 27 | // String returns the literal string representation of a Season_Uc_Jn, which is 28 | // the same as the const identifier but without prefix or suffix. 29 | func (v Season_Uc_Jn) String() string { 30 | o := v.Ordinal() 31 | return v.toString(o, season_uc_jnEnumStrings, season_uc_jnEnumIndex[:]) 32 | } 33 | 34 | // Ordinal returns the ordinal number of a Season_Uc_Jn. This is an integer counting 35 | // from zero. It is *not* the same as the const number assigned to the value. 36 | func (v Season_Uc_Jn) Ordinal() int { 37 | switch v { 38 | case Spring_Uc_Jn: 39 | return 0 40 | case Summer_Uc_Jn: 41 | return 1 42 | case Autumn_Uc_Jn: 43 | return 2 44 | case Winter_Uc_Jn: 45 | return 3 46 | } 47 | return -1 48 | } 49 | 50 | func (v Season_Uc_Jn) toString(o int, concats string, indexes []uint16) string { 51 | if o < 0 || o >= len(AllSeason_Uc_Jns) { 52 | return fmt.Sprintf("Season_Uc_Jn(%d)", v) 53 | } 54 | return concats[indexes[o]:indexes[o+1]] 55 | } 56 | 57 | // IsValid determines whether a Season_Uc_Jn is one of the defined constants. 58 | func (v Season_Uc_Jn) IsValid() bool { 59 | return v.Ordinal() >= 0 60 | } 61 | 62 | // Int returns the int value, which is not necessarily the same as the ordinal. 63 | // This facilitates polymorphism (see enum.IntEnum). 64 | func (v Season_Uc_Jn) Int() int { 65 | return int(v) 66 | } 67 | 68 | var invalidSeason_Uc_JnValue = func() Season_Uc_Jn { 69 | var v Season_Uc_Jn 70 | for { 71 | if !slices.Contains(AllSeason_Uc_Jns, v) { 72 | return v 73 | } 74 | v++ 75 | } // AllSeason_Uc_Jns is a finite set so loop will terminate eventually 76 | }() 77 | 78 | // Season_Uc_JnOf returns a Season_Uc_Jn based on an ordinal number. This is the inverse of Ordinal. 79 | // If the ordinal is out of range, an invalid Season_Uc_Jn is returned. 80 | func Season_Uc_JnOf(v int) Season_Uc_Jn { 81 | if 0 <= v && v < len(AllSeason_Uc_Jns) { 82 | return AllSeason_Uc_Jns[v] 83 | } 84 | return invalidSeason_Uc_JnValue 85 | } 86 | 87 | // Parse parses a string to find the corresponding Season_Uc_Jn, accepting one of the string values or 88 | // a number. It is used by AsSeason_Uc_Jn. 89 | // 90 | // Usage Example 91 | // 92 | // v := new(Season_Uc_Jn) 93 | // err := v.Parse(s) 94 | // ... etc 95 | func (v *Season_Uc_Jn) Parse(in string) error { 96 | if v.parseNumber(in) { 97 | return nil 98 | } 99 | 100 | s := season_uc_jnTransformInput(in) 101 | 102 | return v.parseFallback(in, s) 103 | } 104 | 105 | // parseNumber attempts to convert a decimal value. 106 | // Only numbers that correspond to the enumeration are valid. 107 | func (v *Season_Uc_Jn) parseNumber(s string) (ok bool) { 108 | num, err := strconv.ParseInt(s, 10, 64) 109 | if err == nil { 110 | *v = Season_Uc_Jn(num) 111 | return v.IsValid() 112 | } 113 | return false 114 | } 115 | 116 | func (v *Season_Uc_Jn) parseFallback(in, s string) error { 117 | if v.parseString(s, season_uc_jnEnumStrings, season_uc_jnEnumIndex[:]) { 118 | return nil 119 | } 120 | 121 | return errors.New(in + ": unrecognised season_uc_jn") 122 | } 123 | 124 | func (v *Season_Uc_Jn) parseString(s string, concats string, indexes []uint16) (ok bool) { 125 | var i0 uint16 = 0 126 | 127 | for j := 1; j < len(indexes); j++ { 128 | i1 := indexes[j] 129 | p := concats[i0:i1] 130 | if s == p { 131 | *v = AllSeason_Uc_Jns[j-1] 132 | return true 133 | } 134 | i0 = i1 135 | } 136 | return false 137 | } 138 | 139 | // season_uc_jnTransformInput may alter input strings before they are parsed. 140 | // This function is pluggable and is initialised using command-line flags 141 | // -ic -lc -uc -unsnake. 142 | var season_uc_jnTransformInput = func(in string) string { 143 | return strings.ToUpper(in) 144 | } 145 | 146 | // AsSeason_Uc_Jn parses a string to find the corresponding Season_Uc_Jn, accepting either one of the string values or 147 | // a number. It wraps Parse. 148 | func AsSeason_Uc_Jn(s string) (Season_Uc_Jn, error) { 149 | var v = new(Season_Uc_Jn) 150 | err := v.Parse(s) 151 | return *v, err 152 | } 153 | 154 | // MustParseSeason_Uc_Jn is similar to AsSeason_Uc_Jn except that it panics on error. 155 | func MustParseSeason_Uc_Jn(s string) Season_Uc_Jn { 156 | v, err := AsSeason_Uc_Jn(s) 157 | if err != nil { 158 | panic(err) 159 | } 160 | return v 161 | } 162 | 163 | // MarshalJSON converts values to bytes suitable for transmission via JSON. 164 | // The number representation is chosen according to -marshaljson. 165 | func (v Season_Uc_Jn) MarshalJSON() ([]byte, error) { 166 | if !v.IsValid() { 167 | return v.marshalNumberOrError() 168 | } 169 | 170 | s := season_uc_jnMarshalNumber(v) 171 | return []byte(s), nil 172 | } 173 | 174 | func (v Season_Uc_Jn) marshalNumberOrError() ([]byte, error) { 175 | // disallow lenient marshaling 176 | return nil, v.invalidError() 177 | } 178 | 179 | func (v Season_Uc_Jn) invalidError() error { 180 | return fmt.Errorf("%d is not a valid season_uc_jn", v) 181 | } 182 | 183 | // season_uc_jnMarshalNumber handles marshaling where a number is required or where 184 | // the value is out of range. 185 | // This function can be replaced with any bespoke function than matches signature. 186 | var season_uc_jnMarshalNumber = func(v Season_Uc_Jn) string { 187 | return strconv.FormatInt(int64(v), 10) 188 | } 189 | 190 | // UnmarshalJSON converts transmitted JSON values to ordinary values. It allows both 191 | // ordinals and strings to represent the values. 192 | func (v *Season_Uc_Jn) UnmarshalJSON(text []byte) error { 193 | s := string(text) 194 | if s == "null" { 195 | // Ignore null, like in the main JSON package. 196 | return nil 197 | } 198 | s = strings.Trim(s, "\"") 199 | return v.unmarshalJSON(s) 200 | } 201 | 202 | func (v *Season_Uc_Jn) unmarshalJSON(in string) error { 203 | if v.parseNumber(in) { 204 | return nil 205 | } 206 | 207 | s := season_uc_jnTransformInput(in) 208 | 209 | if v.parseString(s, season_uc_jnEnumStrings, season_uc_jnEnumIndex[:]) { 210 | return nil 211 | } 212 | 213 | return errors.New(in + ": unrecognised season_uc_jn") 214 | } 215 | -------------------------------------------------------------------------------- /internal/test/season_uc_si_enum.go: -------------------------------------------------------------------------------- 1 | // generated code - do not edit 2 | // github.com/rickb777/enumeration/v4 v4.0.7 3 | 4 | package test 5 | 6 | import ( 7 | "database/sql/driver" 8 | "errors" 9 | "fmt" 10 | "slices" 11 | "strconv" 12 | "strings" 13 | ) 14 | 15 | // AllSeason_Uc_Sis lists all 4 values in order. 16 | var AllSeason_Uc_Sis = []Season_Uc_Si{ 17 | Spring_Uc_Si, Summer_Uc_Si, Autumn_Uc_Si, Winter_Uc_Si, 18 | } 19 | 20 | const ( 21 | season_uc_siEnumStrings = "SPRINGSUMMERAUTUMNWINTER" 22 | ) 23 | 24 | var ( 25 | season_uc_siEnumIndex = [...]uint16{0, 6, 12, 18, 24} 26 | ) 27 | 28 | // String returns the literal string representation of a Season_Uc_Si, which is 29 | // the same as the const identifier but without prefix or suffix. 30 | func (v Season_Uc_Si) String() string { 31 | o := v.Ordinal() 32 | return v.toString(o, season_uc_siEnumStrings, season_uc_siEnumIndex[:]) 33 | } 34 | 35 | // Ordinal returns the ordinal number of a Season_Uc_Si. This is an integer counting 36 | // from zero. It is *not* the same as the const number assigned to the value. 37 | func (v Season_Uc_Si) Ordinal() int { 38 | switch v { 39 | case Spring_Uc_Si: 40 | return 0 41 | case Summer_Uc_Si: 42 | return 1 43 | case Autumn_Uc_Si: 44 | return 2 45 | case Winter_Uc_Si: 46 | return 3 47 | } 48 | return -1 49 | } 50 | 51 | func (v Season_Uc_Si) toString(o int, concats string, indexes []uint16) string { 52 | if o < 0 || o >= len(AllSeason_Uc_Sis) { 53 | return fmt.Sprintf("Season_Uc_Si(%d)", v) 54 | } 55 | return concats[indexes[o]:indexes[o+1]] 56 | } 57 | 58 | // IsValid determines whether a Season_Uc_Si is one of the defined constants. 59 | func (v Season_Uc_Si) IsValid() bool { 60 | return v.Ordinal() >= 0 61 | } 62 | 63 | // Int returns the int value, which is not necessarily the same as the ordinal. 64 | // This facilitates polymorphism (see enum.IntEnum). 65 | func (v Season_Uc_Si) Int() int { 66 | return int(v) 67 | } 68 | 69 | var invalidSeason_Uc_SiValue = func() Season_Uc_Si { 70 | var v Season_Uc_Si 71 | for { 72 | if !slices.Contains(AllSeason_Uc_Sis, v) { 73 | return v 74 | } 75 | v++ 76 | } // AllSeason_Uc_Sis is a finite set so loop will terminate eventually 77 | }() 78 | 79 | // Season_Uc_SiOf returns a Season_Uc_Si based on an ordinal number. This is the inverse of Ordinal. 80 | // If the ordinal is out of range, an invalid Season_Uc_Si is returned. 81 | func Season_Uc_SiOf(v int) Season_Uc_Si { 82 | if 0 <= v && v < len(AllSeason_Uc_Sis) { 83 | return AllSeason_Uc_Sis[v] 84 | } 85 | return invalidSeason_Uc_SiValue 86 | } 87 | 88 | // Parse parses a string to find the corresponding Season_Uc_Si, accepting one of the string values or 89 | // a number. It is used by AsSeason_Uc_Si. 90 | // 91 | // Usage Example 92 | // 93 | // v := new(Season_Uc_Si) 94 | // err := v.Parse(s) 95 | // ... etc 96 | func (v *Season_Uc_Si) Parse(in string) error { 97 | if v.parseNumber(in) { 98 | return nil 99 | } 100 | 101 | s := season_uc_siTransformInput(in) 102 | 103 | return v.parseFallback(in, s) 104 | } 105 | 106 | // parseNumber attempts to convert a decimal value. 107 | // Only numbers that correspond to the enumeration are valid. 108 | func (v *Season_Uc_Si) parseNumber(s string) (ok bool) { 109 | num, err := strconv.ParseInt(s, 10, 64) 110 | if err == nil { 111 | *v = Season_Uc_Si(num) 112 | return v.IsValid() 113 | } 114 | return false 115 | } 116 | 117 | func (v *Season_Uc_Si) parseFallback(in, s string) error { 118 | if v.parseString(s, season_uc_siEnumStrings, season_uc_siEnumIndex[:]) { 119 | return nil 120 | } 121 | 122 | return errors.New(in + ": unrecognised season_uc_si") 123 | } 124 | 125 | func (v *Season_Uc_Si) parseString(s string, concats string, indexes []uint16) (ok bool) { 126 | var i0 uint16 = 0 127 | 128 | for j := 1; j < len(indexes); j++ { 129 | i1 := indexes[j] 130 | p := concats[i0:i1] 131 | if s == p { 132 | *v = AllSeason_Uc_Sis[j-1] 133 | return true 134 | } 135 | i0 = i1 136 | } 137 | return false 138 | } 139 | 140 | // season_uc_siTransformInput may alter input strings before they are parsed. 141 | // This function is pluggable and is initialised using command-line flags 142 | // -ic -lc -uc -unsnake. 143 | var season_uc_siTransformInput = func(in string) string { 144 | return strings.ToUpper(in) 145 | } 146 | 147 | // AsSeason_Uc_Si parses a string to find the corresponding Season_Uc_Si, accepting either one of the string values or 148 | // a number. It wraps Parse. 149 | func AsSeason_Uc_Si(s string) (Season_Uc_Si, error) { 150 | var v = new(Season_Uc_Si) 151 | err := v.Parse(s) 152 | return *v, err 153 | } 154 | 155 | // MustParseSeason_Uc_Si is similar to AsSeason_Uc_Si except that it panics on error. 156 | func MustParseSeason_Uc_Si(s string) Season_Uc_Si { 157 | v, err := AsSeason_Uc_Si(s) 158 | if err != nil { 159 | panic(err) 160 | } 161 | return v 162 | } 163 | 164 | // Scan parses some value, which can be a number, a string or []byte. 165 | // It implements sql.Scanner, https://golang.org/pkg/database/sql/#Scanner 166 | func (v *Season_Uc_Si) Scan(value interface{}) error { 167 | if value == nil { 168 | return nil 169 | } 170 | 171 | var s string 172 | switch x := value.(type) { 173 | case int64: 174 | *v = Season_Uc_Si(x) 175 | return v.errorIfInvalid() 176 | case float64: 177 | *v = Season_Uc_Si(x) 178 | return v.errorIfInvalid() 179 | case []byte: 180 | s = string(x) 181 | case string: 182 | s = x 183 | default: 184 | return fmt.Errorf("%T %+v is not a meaningful season_uc_si", value, value) 185 | } 186 | 187 | return v.scanParse(s) 188 | } 189 | 190 | func (v Season_Uc_Si) errorIfInvalid() error { 191 | if v.IsValid() { 192 | return nil 193 | } 194 | return v.invalidError() 195 | } 196 | 197 | func (v Season_Uc_Si) invalidError() error { 198 | return fmt.Errorf("%d is not a valid season_uc_si", v) 199 | } 200 | 201 | func (v *Season_Uc_Si) scanParse(in string) error { 202 | if v.parseNumber(in) { 203 | return nil 204 | } 205 | 206 | s := season_uc_siTransformInput(in) 207 | 208 | return v.parseFallback(in, s) 209 | } 210 | 211 | // Value converts the Season_Uc_Si to a string (based on '-store identifier'). 212 | // It implements driver.Valuer, https://golang.org/pkg/database/sql/driver/#Valuer 213 | func (v Season_Uc_Si) Value() (driver.Value, error) { 214 | if !v.IsValid() { 215 | return nil, fmt.Errorf("%v: cannot be stored", v) 216 | } 217 | 218 | return v.String(), nil 219 | } 220 | -------------------------------------------------------------------------------- /internal/test/season_uc_sn_enum.go: -------------------------------------------------------------------------------- 1 | // generated code - do not edit 2 | // github.com/rickb777/enumeration/v4 v4.0.7 3 | 4 | package test 5 | 6 | import ( 7 | "database/sql/driver" 8 | "errors" 9 | "fmt" 10 | "slices" 11 | "strconv" 12 | "strings" 13 | ) 14 | 15 | // AllSeason_Uc_Sns lists all 4 values in order. 16 | var AllSeason_Uc_Sns = []Season_Uc_Sn{ 17 | Spring_Uc_Sn, Summer_Uc_Sn, Autumn_Uc_Sn, Winter_Uc_Sn, 18 | } 19 | 20 | const ( 21 | season_uc_snEnumStrings = "SPRINGSUMMERAUTUMNWINTER" 22 | ) 23 | 24 | var ( 25 | season_uc_snEnumIndex = [...]uint16{0, 6, 12, 18, 24} 26 | ) 27 | 28 | // String returns the literal string representation of a Season_Uc_Sn, which is 29 | // the same as the const identifier but without prefix or suffix. 30 | func (v Season_Uc_Sn) String() string { 31 | o := v.Ordinal() 32 | return v.toString(o, season_uc_snEnumStrings, season_uc_snEnumIndex[:]) 33 | } 34 | 35 | // Ordinal returns the ordinal number of a Season_Uc_Sn. This is an integer counting 36 | // from zero. It is *not* the same as the const number assigned to the value. 37 | func (v Season_Uc_Sn) Ordinal() int { 38 | switch v { 39 | case Spring_Uc_Sn: 40 | return 0 41 | case Summer_Uc_Sn: 42 | return 1 43 | case Autumn_Uc_Sn: 44 | return 2 45 | case Winter_Uc_Sn: 46 | return 3 47 | } 48 | return -1 49 | } 50 | 51 | func (v Season_Uc_Sn) toString(o int, concats string, indexes []uint16) string { 52 | if o < 0 || o >= len(AllSeason_Uc_Sns) { 53 | return fmt.Sprintf("Season_Uc_Sn(%d)", v) 54 | } 55 | return concats[indexes[o]:indexes[o+1]] 56 | } 57 | 58 | // IsValid determines whether a Season_Uc_Sn is one of the defined constants. 59 | func (v Season_Uc_Sn) IsValid() bool { 60 | return v.Ordinal() >= 0 61 | } 62 | 63 | // Int returns the int value, which is not necessarily the same as the ordinal. 64 | // This facilitates polymorphism (see enum.IntEnum). 65 | func (v Season_Uc_Sn) Int() int { 66 | return int(v) 67 | } 68 | 69 | var invalidSeason_Uc_SnValue = func() Season_Uc_Sn { 70 | var v Season_Uc_Sn 71 | for { 72 | if !slices.Contains(AllSeason_Uc_Sns, v) { 73 | return v 74 | } 75 | v++ 76 | } // AllSeason_Uc_Sns is a finite set so loop will terminate eventually 77 | }() 78 | 79 | // Season_Uc_SnOf returns a Season_Uc_Sn based on an ordinal number. This is the inverse of Ordinal. 80 | // If the ordinal is out of range, an invalid Season_Uc_Sn is returned. 81 | func Season_Uc_SnOf(v int) Season_Uc_Sn { 82 | if 0 <= v && v < len(AllSeason_Uc_Sns) { 83 | return AllSeason_Uc_Sns[v] 84 | } 85 | return invalidSeason_Uc_SnValue 86 | } 87 | 88 | // Parse parses a string to find the corresponding Season_Uc_Sn, accepting one of the string values or 89 | // a number. It is used by AsSeason_Uc_Sn. 90 | // 91 | // Usage Example 92 | // 93 | // v := new(Season_Uc_Sn) 94 | // err := v.Parse(s) 95 | // ... etc 96 | func (v *Season_Uc_Sn) Parse(in string) error { 97 | if v.parseNumber(in) { 98 | return nil 99 | } 100 | 101 | s := season_uc_snTransformInput(in) 102 | 103 | return v.parseFallback(in, s) 104 | } 105 | 106 | // parseNumber attempts to convert a decimal value. 107 | // Only numbers that correspond to the enumeration are valid. 108 | func (v *Season_Uc_Sn) parseNumber(s string) (ok bool) { 109 | num, err := strconv.ParseInt(s, 10, 64) 110 | if err == nil { 111 | *v = Season_Uc_Sn(num) 112 | return v.IsValid() 113 | } 114 | return false 115 | } 116 | 117 | func (v *Season_Uc_Sn) parseFallback(in, s string) error { 118 | if v.parseString(s, season_uc_snEnumStrings, season_uc_snEnumIndex[:]) { 119 | return nil 120 | } 121 | 122 | return errors.New(in + ": unrecognised season_uc_sn") 123 | } 124 | 125 | func (v *Season_Uc_Sn) parseString(s string, concats string, indexes []uint16) (ok bool) { 126 | var i0 uint16 = 0 127 | 128 | for j := 1; j < len(indexes); j++ { 129 | i1 := indexes[j] 130 | p := concats[i0:i1] 131 | if s == p { 132 | *v = AllSeason_Uc_Sns[j-1] 133 | return true 134 | } 135 | i0 = i1 136 | } 137 | return false 138 | } 139 | 140 | // season_uc_snTransformInput may alter input strings before they are parsed. 141 | // This function is pluggable and is initialised using command-line flags 142 | // -ic -lc -uc -unsnake. 143 | var season_uc_snTransformInput = func(in string) string { 144 | return strings.ToUpper(in) 145 | } 146 | 147 | // AsSeason_Uc_Sn parses a string to find the corresponding Season_Uc_Sn, accepting either one of the string values or 148 | // a number. It wraps Parse. 149 | func AsSeason_Uc_Sn(s string) (Season_Uc_Sn, error) { 150 | var v = new(Season_Uc_Sn) 151 | err := v.Parse(s) 152 | return *v, err 153 | } 154 | 155 | // MustParseSeason_Uc_Sn is similar to AsSeason_Uc_Sn except that it panics on error. 156 | func MustParseSeason_Uc_Sn(s string) Season_Uc_Sn { 157 | v, err := AsSeason_Uc_Sn(s) 158 | if err != nil { 159 | panic(err) 160 | } 161 | return v 162 | } 163 | 164 | // Scan parses some value, which can be a number, a string or []byte. 165 | // It implements sql.Scanner, https://golang.org/pkg/database/sql/#Scanner 166 | func (v *Season_Uc_Sn) Scan(value interface{}) error { 167 | if value == nil { 168 | return nil 169 | } 170 | 171 | var s string 172 | switch x := value.(type) { 173 | case int64: 174 | *v = Season_Uc_Sn(x) 175 | return v.errorIfInvalid() 176 | case float64: 177 | *v = Season_Uc_Sn(x) 178 | return v.errorIfInvalid() 179 | case []byte: 180 | s = string(x) 181 | case string: 182 | s = x 183 | default: 184 | return fmt.Errorf("%T %+v is not a meaningful season_uc_sn", value, value) 185 | } 186 | 187 | return v.scanParse(s) 188 | } 189 | 190 | func (v Season_Uc_Sn) errorIfInvalid() error { 191 | if v.IsValid() { 192 | return nil 193 | } 194 | return v.invalidError() 195 | } 196 | 197 | func (v Season_Uc_Sn) invalidError() error { 198 | return fmt.Errorf("%d is not a valid season_uc_sn", v) 199 | } 200 | 201 | func (v *Season_Uc_Sn) scanParse(in string) error { 202 | if v.parseNumber(in) { 203 | return nil 204 | } 205 | 206 | s := season_uc_snTransformInput(in) 207 | 208 | return v.parseFallback(in, s) 209 | } 210 | 211 | // Value converts the Season_Uc_Sn to a number (based on '-store number'). 212 | // It implements driver.Valuer, https://golang.org/pkg/database/sql/driver/#Valuer 213 | func (v Season_Uc_Sn) Value() (driver.Value, error) { 214 | return int64(v), nil 215 | } 216 | -------------------------------------------------------------------------------- /internal/test/season_uc_ti_enum.go: -------------------------------------------------------------------------------- 1 | // generated code - do not edit 2 | // github.com/rickb777/enumeration/v4 v4.0.7 3 | 4 | package test 5 | 6 | import ( 7 | "errors" 8 | "fmt" 9 | "slices" 10 | "strconv" 11 | "strings" 12 | ) 13 | 14 | // AllSeason_Uc_Tis lists all 4 values in order. 15 | var AllSeason_Uc_Tis = []Season_Uc_Ti{ 16 | Spring_Uc_Ti, Summer_Uc_Ti, Autumn_Uc_Ti, Winter_Uc_Ti, 17 | } 18 | 19 | const ( 20 | season_uc_tiEnumStrings = "SPRINGSUMMERAUTUMNWINTER" 21 | ) 22 | 23 | var ( 24 | season_uc_tiEnumIndex = [...]uint16{0, 6, 12, 18, 24} 25 | ) 26 | 27 | // String returns the literal string representation of a Season_Uc_Ti, which is 28 | // the same as the const identifier but without prefix or suffix. 29 | func (v Season_Uc_Ti) String() string { 30 | o := v.Ordinal() 31 | return v.toString(o, season_uc_tiEnumStrings, season_uc_tiEnumIndex[:]) 32 | } 33 | 34 | // Ordinal returns the ordinal number of a Season_Uc_Ti. This is an integer counting 35 | // from zero. It is *not* the same as the const number assigned to the value. 36 | func (v Season_Uc_Ti) Ordinal() int { 37 | switch v { 38 | case Spring_Uc_Ti: 39 | return 0 40 | case Summer_Uc_Ti: 41 | return 1 42 | case Autumn_Uc_Ti: 43 | return 2 44 | case Winter_Uc_Ti: 45 | return 3 46 | } 47 | return -1 48 | } 49 | 50 | func (v Season_Uc_Ti) toString(o int, concats string, indexes []uint16) string { 51 | if o < 0 || o >= len(AllSeason_Uc_Tis) { 52 | return fmt.Sprintf("Season_Uc_Ti(%d)", v) 53 | } 54 | return concats[indexes[o]:indexes[o+1]] 55 | } 56 | 57 | // IsValid determines whether a Season_Uc_Ti is one of the defined constants. 58 | func (v Season_Uc_Ti) IsValid() bool { 59 | return v.Ordinal() >= 0 60 | } 61 | 62 | // Int returns the int value, which is not necessarily the same as the ordinal. 63 | // This facilitates polymorphism (see enum.IntEnum). 64 | func (v Season_Uc_Ti) Int() int { 65 | return int(v) 66 | } 67 | 68 | var invalidSeason_Uc_TiValue = func() Season_Uc_Ti { 69 | var v Season_Uc_Ti 70 | for { 71 | if !slices.Contains(AllSeason_Uc_Tis, v) { 72 | return v 73 | } 74 | v++ 75 | } // AllSeason_Uc_Tis is a finite set so loop will terminate eventually 76 | }() 77 | 78 | // Season_Uc_TiOf returns a Season_Uc_Ti based on an ordinal number. This is the inverse of Ordinal. 79 | // If the ordinal is out of range, an invalid Season_Uc_Ti is returned. 80 | func Season_Uc_TiOf(v int) Season_Uc_Ti { 81 | if 0 <= v && v < len(AllSeason_Uc_Tis) { 82 | return AllSeason_Uc_Tis[v] 83 | } 84 | return invalidSeason_Uc_TiValue 85 | } 86 | 87 | // Parse parses a string to find the corresponding Season_Uc_Ti, accepting one of the string values or 88 | // a number. The input representation is determined by Identifier. It is used by AsSeason_Uc_Ti. 89 | // 90 | // Usage Example 91 | // 92 | // v := new(Season_Uc_Ti) 93 | // err := v.Parse(s) 94 | // ... etc 95 | func (v *Season_Uc_Ti) Parse(in string) error { 96 | if v.parseNumber(in) { 97 | return nil 98 | } 99 | 100 | s := season_uc_tiTransformInput(in) 101 | 102 | return v.parseFallback(in, s) 103 | } 104 | 105 | // parseNumber attempts to convert a decimal value. 106 | // Only numbers that correspond to the enumeration are valid. 107 | func (v *Season_Uc_Ti) parseNumber(s string) (ok bool) { 108 | num, err := strconv.ParseInt(s, 10, 64) 109 | if err == nil { 110 | *v = Season_Uc_Ti(num) 111 | return v.IsValid() 112 | } 113 | return false 114 | } 115 | 116 | func (v *Season_Uc_Ti) parseFallback(in, s string) error { 117 | if v.parseString(s, season_uc_tiEnumStrings, season_uc_tiEnumIndex[:]) { 118 | return nil 119 | } 120 | 121 | return errors.New(in + ": unrecognised season_uc_ti") 122 | } 123 | 124 | func (v *Season_Uc_Ti) parseString(s string, concats string, indexes []uint16) (ok bool) { 125 | var i0 uint16 = 0 126 | 127 | for j := 1; j < len(indexes); j++ { 128 | i1 := indexes[j] 129 | p := concats[i0:i1] 130 | if s == p { 131 | *v = AllSeason_Uc_Tis[j-1] 132 | return true 133 | } 134 | i0 = i1 135 | } 136 | return false 137 | } 138 | 139 | // season_uc_tiTransformInput may alter input strings before they are parsed. 140 | // This function is pluggable and is initialised using command-line flags 141 | // -ic -lc -uc -unsnake. 142 | var season_uc_tiTransformInput = func(in string) string { 143 | return strings.ToUpper(in) 144 | } 145 | 146 | // AsSeason_Uc_Ti parses a string to find the corresponding Season_Uc_Ti, accepting either one of the string values or 147 | // a number. The input representation is determined by season_uc_tiMarshalTextRep. It wraps Parse. 148 | func AsSeason_Uc_Ti(s string) (Season_Uc_Ti, error) { 149 | var v = new(Season_Uc_Ti) 150 | err := v.Parse(s) 151 | return *v, err 152 | } 153 | 154 | // MustParseSeason_Uc_Ti is similar to AsSeason_Uc_Ti except that it panics on error. 155 | func MustParseSeason_Uc_Ti(s string) Season_Uc_Ti { 156 | v, err := AsSeason_Uc_Ti(s) 157 | if err != nil { 158 | panic(err) 159 | } 160 | return v 161 | } 162 | 163 | // MarshalText converts values to bytes suitable for transmission via XML, JSON etc. 164 | func (v Season_Uc_Ti) MarshalText() ([]byte, error) { 165 | s, err := v.marshalText() 166 | return []byte(s), err 167 | } 168 | 169 | // Text returns the representation used for transmission via XML, JSON etc. 170 | func (v Season_Uc_Ti) Text() string { 171 | s, _ := v.marshalText() 172 | return s 173 | } 174 | 175 | // marshalText converts values to a form suitable for transmission via XML, JSON etc. 176 | // The identifier representation is chosen according to -marshaltext. 177 | func (v Season_Uc_Ti) marshalText() (string, error) { 178 | o := v.Ordinal() 179 | if o < 0 { 180 | return v.marshalNumberStringOrError() 181 | } 182 | 183 | return v.toString(o, season_uc_tiEnumStrings, season_uc_tiEnumIndex[:]), nil 184 | } 185 | 186 | func (v Season_Uc_Ti) marshalNumberStringOrError() (string, error) { 187 | bs, err := v.marshalNumberOrError() 188 | return string(bs), err 189 | } 190 | 191 | func (v Season_Uc_Ti) marshalNumberOrError() ([]byte, error) { 192 | // disallow lenient marshaling 193 | return nil, v.invalidError() 194 | } 195 | 196 | func (v Season_Uc_Ti) invalidError() error { 197 | return fmt.Errorf("%d is not a valid season_uc_ti", v) 198 | } 199 | 200 | // UnmarshalText converts transmitted values to ordinary values. 201 | func (v *Season_Uc_Ti) UnmarshalText(bs []byte) error { 202 | return v.unmarshalText(string(bs)) 203 | } 204 | 205 | func (v *Season_Uc_Ti) unmarshalText(in string) error { 206 | if v.parseNumber(in) { 207 | return nil 208 | } 209 | 210 | s := season_uc_tiTransformInput(in) 211 | 212 | return v.parseFallback(in, s) 213 | } 214 | -------------------------------------------------------------------------------- /internal/test/season_uc_tn_enum.go: -------------------------------------------------------------------------------- 1 | // generated code - do not edit 2 | // github.com/rickb777/enumeration/v4 v4.0.7 3 | 4 | package test 5 | 6 | import ( 7 | "errors" 8 | "fmt" 9 | "slices" 10 | "strconv" 11 | "strings" 12 | ) 13 | 14 | // AllSeason_Uc_Tns lists all 4 values in order. 15 | var AllSeason_Uc_Tns = []Season_Uc_Tn{ 16 | Spring_Uc_Tn, Summer_Uc_Tn, Autumn_Uc_Tn, Winter_Uc_Tn, 17 | } 18 | 19 | const ( 20 | season_uc_tnEnumStrings = "SPRINGSUMMERAUTUMNWINTER" 21 | ) 22 | 23 | var ( 24 | season_uc_tnEnumIndex = [...]uint16{0, 6, 12, 18, 24} 25 | ) 26 | 27 | // String returns the literal string representation of a Season_Uc_Tn, which is 28 | // the same as the const identifier but without prefix or suffix. 29 | func (v Season_Uc_Tn) String() string { 30 | o := v.Ordinal() 31 | return v.toString(o, season_uc_tnEnumStrings, season_uc_tnEnumIndex[:]) 32 | } 33 | 34 | // Ordinal returns the ordinal number of a Season_Uc_Tn. This is an integer counting 35 | // from zero. It is *not* the same as the const number assigned to the value. 36 | func (v Season_Uc_Tn) Ordinal() int { 37 | switch v { 38 | case Spring_Uc_Tn: 39 | return 0 40 | case Summer_Uc_Tn: 41 | return 1 42 | case Autumn_Uc_Tn: 43 | return 2 44 | case Winter_Uc_Tn: 45 | return 3 46 | } 47 | return -1 48 | } 49 | 50 | func (v Season_Uc_Tn) toString(o int, concats string, indexes []uint16) string { 51 | if o < 0 || o >= len(AllSeason_Uc_Tns) { 52 | return fmt.Sprintf("Season_Uc_Tn(%d)", v) 53 | } 54 | return concats[indexes[o]:indexes[o+1]] 55 | } 56 | 57 | // IsValid determines whether a Season_Uc_Tn is one of the defined constants. 58 | func (v Season_Uc_Tn) IsValid() bool { 59 | return v.Ordinal() >= 0 60 | } 61 | 62 | // Int returns the int value, which is not necessarily the same as the ordinal. 63 | // This facilitates polymorphism (see enum.IntEnum). 64 | func (v Season_Uc_Tn) Int() int { 65 | return int(v) 66 | } 67 | 68 | var invalidSeason_Uc_TnValue = func() Season_Uc_Tn { 69 | var v Season_Uc_Tn 70 | for { 71 | if !slices.Contains(AllSeason_Uc_Tns, v) { 72 | return v 73 | } 74 | v++ 75 | } // AllSeason_Uc_Tns is a finite set so loop will terminate eventually 76 | }() 77 | 78 | // Season_Uc_TnOf returns a Season_Uc_Tn based on an ordinal number. This is the inverse of Ordinal. 79 | // If the ordinal is out of range, an invalid Season_Uc_Tn is returned. 80 | func Season_Uc_TnOf(v int) Season_Uc_Tn { 81 | if 0 <= v && v < len(AllSeason_Uc_Tns) { 82 | return AllSeason_Uc_Tns[v] 83 | } 84 | return invalidSeason_Uc_TnValue 85 | } 86 | 87 | // Parse parses a string to find the corresponding Season_Uc_Tn, accepting one of the string values or 88 | // a number. The input representation is determined by Number. It is used by AsSeason_Uc_Tn. 89 | // 90 | // Usage Example 91 | // 92 | // v := new(Season_Uc_Tn) 93 | // err := v.Parse(s) 94 | // ... etc 95 | func (v *Season_Uc_Tn) Parse(in string) error { 96 | if v.parseNumber(in) { 97 | return nil 98 | } 99 | 100 | s := season_uc_tnTransformInput(in) 101 | 102 | return v.parseFallback(in, s) 103 | } 104 | 105 | // parseNumber attempts to convert a decimal value. 106 | // Only numbers that correspond to the enumeration are valid. 107 | func (v *Season_Uc_Tn) parseNumber(s string) (ok bool) { 108 | num, err := strconv.ParseInt(s, 10, 64) 109 | if err == nil { 110 | *v = Season_Uc_Tn(num) 111 | return v.IsValid() 112 | } 113 | return false 114 | } 115 | 116 | func (v *Season_Uc_Tn) parseFallback(in, s string) error { 117 | if v.parseString(s, season_uc_tnEnumStrings, season_uc_tnEnumIndex[:]) { 118 | return nil 119 | } 120 | 121 | return errors.New(in + ": unrecognised season_uc_tn") 122 | } 123 | 124 | func (v *Season_Uc_Tn) parseString(s string, concats string, indexes []uint16) (ok bool) { 125 | var i0 uint16 = 0 126 | 127 | for j := 1; j < len(indexes); j++ { 128 | i1 := indexes[j] 129 | p := concats[i0:i1] 130 | if s == p { 131 | *v = AllSeason_Uc_Tns[j-1] 132 | return true 133 | } 134 | i0 = i1 135 | } 136 | return false 137 | } 138 | 139 | // season_uc_tnTransformInput may alter input strings before they are parsed. 140 | // This function is pluggable and is initialised using command-line flags 141 | // -ic -lc -uc -unsnake. 142 | var season_uc_tnTransformInput = func(in string) string { 143 | return strings.ToUpper(in) 144 | } 145 | 146 | // AsSeason_Uc_Tn parses a string to find the corresponding Season_Uc_Tn, accepting either one of the string values or 147 | // a number. The input representation is determined by season_uc_tnMarshalTextRep. It wraps Parse. 148 | func AsSeason_Uc_Tn(s string) (Season_Uc_Tn, error) { 149 | var v = new(Season_Uc_Tn) 150 | err := v.Parse(s) 151 | return *v, err 152 | } 153 | 154 | // MustParseSeason_Uc_Tn is similar to AsSeason_Uc_Tn except that it panics on error. 155 | func MustParseSeason_Uc_Tn(s string) Season_Uc_Tn { 156 | v, err := AsSeason_Uc_Tn(s) 157 | if err != nil { 158 | panic(err) 159 | } 160 | return v 161 | } 162 | 163 | // MarshalText converts values to bytes suitable for transmission via XML, JSON etc. 164 | func (v Season_Uc_Tn) MarshalText() ([]byte, error) { 165 | s, err := v.marshalText() 166 | return []byte(s), err 167 | } 168 | 169 | // marshalText converts values to a form suitable for transmission via XML, JSON etc. 170 | // The number representation is chosen according to -marshaltext. 171 | func (v Season_Uc_Tn) marshalText() (string, error) { 172 | if !v.IsValid() { 173 | return v.marshalNumberStringOrError() 174 | } 175 | 176 | return season_uc_tnMarshalNumber(v), nil 177 | } 178 | 179 | func (v Season_Uc_Tn) marshalNumberStringOrError() (string, error) { 180 | bs, err := v.marshalNumberOrError() 181 | return string(bs), err 182 | } 183 | 184 | func (v Season_Uc_Tn) marshalNumberOrError() ([]byte, error) { 185 | // disallow lenient marshaling 186 | return nil, v.invalidError() 187 | } 188 | 189 | func (v Season_Uc_Tn) invalidError() error { 190 | return fmt.Errorf("%d is not a valid season_uc_tn", v) 191 | } 192 | 193 | // season_uc_tnMarshalNumber handles marshaling where a number is required or where 194 | // the value is out of range. 195 | // This function can be replaced with any bespoke function than matches signature. 196 | var season_uc_tnMarshalNumber = func(v Season_Uc_Tn) string { 197 | return strconv.FormatInt(int64(v), 10) 198 | } 199 | 200 | // UnmarshalText converts transmitted values to ordinary values. 201 | func (v *Season_Uc_Tn) UnmarshalText(bs []byte) error { 202 | return v.unmarshalText(string(bs)) 203 | } 204 | 205 | func (v *Season_Uc_Tn) unmarshalText(in string) error { 206 | if v.parseNumber(in) { 207 | return nil 208 | } 209 | 210 | s := season_uc_tnTransformInput(in) 211 | 212 | return v.parseFallback(in, s) 213 | } 214 | -------------------------------------------------------------------------------- /internal/test/season_uc_tt_enum.go: -------------------------------------------------------------------------------- 1 | // generated code - do not edit 2 | // github.com/rickb777/enumeration/v4 v4.0.7 3 | 4 | package test 5 | 6 | import ( 7 | "errors" 8 | "fmt" 9 | "slices" 10 | "strconv" 11 | "strings" 12 | ) 13 | 14 | // AllSeason_Uc_Tts lists all 4 values in order. 15 | var AllSeason_Uc_Tts = []Season_Uc_Tt{ 16 | Spring_Uc_Tt, Summer_Uc_Tt, Autumn_Uc_Tt, Winter_Uc_Tt, 17 | } 18 | 19 | const ( 20 | season_uc_ttEnumStrings = "SPRINGSUMMERAUTUMNWINTER" 21 | season_uc_ttTextStrings = "SprgSumrAutmWint" 22 | ) 23 | 24 | var ( 25 | season_uc_ttEnumIndex = [...]uint16{0, 6, 12, 18, 24} 26 | season_uc_ttTextIndex = [...]uint16{0, 4, 8, 12, 16} 27 | ) 28 | 29 | // String returns the literal string representation of a Season_Uc_Tt, which is 30 | // the same as the const identifier but without prefix or suffix. 31 | func (v Season_Uc_Tt) String() string { 32 | o := v.Ordinal() 33 | return v.toString(o, season_uc_ttEnumStrings, season_uc_ttEnumIndex[:]) 34 | } 35 | 36 | // Ordinal returns the ordinal number of a Season_Uc_Tt. This is an integer counting 37 | // from zero. It is *not* the same as the const number assigned to the value. 38 | func (v Season_Uc_Tt) Ordinal() int { 39 | switch v { 40 | case Spring_Uc_Tt: 41 | return 0 42 | case Summer_Uc_Tt: 43 | return 1 44 | case Autumn_Uc_Tt: 45 | return 2 46 | case Winter_Uc_Tt: 47 | return 3 48 | } 49 | return -1 50 | } 51 | 52 | func (v Season_Uc_Tt) toString(o int, concats string, indexes []uint16) string { 53 | if o < 0 || o >= len(AllSeason_Uc_Tts) { 54 | return fmt.Sprintf("Season_Uc_Tt(%d)", v) 55 | } 56 | return concats[indexes[o]:indexes[o+1]] 57 | } 58 | 59 | // IsValid determines whether a Season_Uc_Tt is one of the defined constants. 60 | func (v Season_Uc_Tt) IsValid() bool { 61 | return v.Ordinal() >= 0 62 | } 63 | 64 | // Int returns the int value, which is not necessarily the same as the ordinal. 65 | // This facilitates polymorphism (see enum.IntEnum). 66 | func (v Season_Uc_Tt) Int() int { 67 | return int(v) 68 | } 69 | 70 | var invalidSeason_Uc_TtValue = func() Season_Uc_Tt { 71 | var v Season_Uc_Tt 72 | for { 73 | if !slices.Contains(AllSeason_Uc_Tts, v) { 74 | return v 75 | } 76 | v++ 77 | } // AllSeason_Uc_Tts is a finite set so loop will terminate eventually 78 | }() 79 | 80 | // Season_Uc_TtOf returns a Season_Uc_Tt based on an ordinal number. This is the inverse of Ordinal. 81 | // If the ordinal is out of range, an invalid Season_Uc_Tt is returned. 82 | func Season_Uc_TtOf(v int) Season_Uc_Tt { 83 | if 0 <= v && v < len(AllSeason_Uc_Tts) { 84 | return AllSeason_Uc_Tts[v] 85 | } 86 | return invalidSeason_Uc_TtValue 87 | } 88 | 89 | // Parse parses a string to find the corresponding Season_Uc_Tt, accepting one of the string values or 90 | // a number. It is used by AsSeason_Uc_Tt. 91 | // 92 | // Usage Example 93 | // 94 | // v := new(Season_Uc_Tt) 95 | // err := v.Parse(s) 96 | // ... etc 97 | func (v *Season_Uc_Tt) Parse(in string) error { 98 | if v.parseNumber(in) { 99 | return nil 100 | } 101 | 102 | s := season_uc_ttTransformInput(in) 103 | 104 | return v.parseFallback(in, s) 105 | } 106 | 107 | // parseNumber attempts to convert a decimal value. 108 | // Only numbers that correspond to the enumeration are valid. 109 | func (v *Season_Uc_Tt) parseNumber(s string) (ok bool) { 110 | num, err := strconv.ParseInt(s, 10, 64) 111 | if err == nil { 112 | *v = Season_Uc_Tt(num) 113 | return v.IsValid() 114 | } 115 | return false 116 | } 117 | 118 | func (v *Season_Uc_Tt) parseFallback(in, s string) error { 119 | if v.parseString(s, season_uc_ttEnumStrings, season_uc_ttEnumIndex[:]) { 120 | return nil 121 | } 122 | 123 | return errors.New(in + ": unrecognised season_uc_tt") 124 | } 125 | 126 | func (v *Season_Uc_Tt) parseString(s string, concats string, indexes []uint16) (ok bool) { 127 | var i0 uint16 = 0 128 | 129 | for j := 1; j < len(indexes); j++ { 130 | i1 := indexes[j] 131 | p := concats[i0:i1] 132 | if s == p { 133 | *v = AllSeason_Uc_Tts[j-1] 134 | return true 135 | } 136 | i0 = i1 137 | } 138 | return false 139 | } 140 | 141 | // season_uc_ttTransformInput may alter input strings before they are parsed. 142 | // This function is pluggable and is initialised using command-line flags 143 | // -ic -lc -uc -unsnake. 144 | var season_uc_ttTransformInput = func(in string) string { 145 | return strings.ToUpper(in) 146 | } 147 | 148 | // AsSeason_Uc_Tt parses a string to find the corresponding Season_Uc_Tt, accepting either one of the string values or 149 | // a number. It wraps Parse. 150 | func AsSeason_Uc_Tt(s string) (Season_Uc_Tt, error) { 151 | var v = new(Season_Uc_Tt) 152 | err := v.Parse(s) 153 | return *v, err 154 | } 155 | 156 | // MustParseSeason_Uc_Tt is similar to AsSeason_Uc_Tt except that it panics on error. 157 | func MustParseSeason_Uc_Tt(s string) Season_Uc_Tt { 158 | v, err := AsSeason_Uc_Tt(s) 159 | if err != nil { 160 | panic(err) 161 | } 162 | return v 163 | } 164 | 165 | // MarshalText converts values to bytes suitable for transmission via XML, JSON etc. 166 | func (v Season_Uc_Tt) MarshalText() ([]byte, error) { 167 | s, err := v.marshalText() 168 | return []byte(s), err 169 | } 170 | 171 | // Text returns the representation used for transmission via XML, JSON etc. 172 | func (v Season_Uc_Tt) Text() string { 173 | s, _ := v.marshalText() 174 | return s 175 | } 176 | 177 | // marshalText converts values to bytes suitable for transmission via XML, JSON etc. 178 | // The representation is chosen according to 'text' struct tags. 179 | func (v Season_Uc_Tt) marshalText() (string, error) { 180 | o := v.Ordinal() 181 | if o < 0 { 182 | return v.marshalNumberStringOrError() 183 | } 184 | 185 | return v.toString(o, season_uc_ttTextStrings, season_uc_ttTextIndex[:]), nil 186 | } 187 | 188 | func (v Season_Uc_Tt) marshalNumberStringOrError() (string, error) { 189 | bs, err := v.marshalNumberOrError() 190 | return string(bs), err 191 | } 192 | 193 | func (v Season_Uc_Tt) marshalNumberOrError() ([]byte, error) { 194 | // disallow lenient marshaling 195 | return nil, v.invalidError() 196 | } 197 | 198 | func (v Season_Uc_Tt) invalidError() error { 199 | return fmt.Errorf("%d is not a valid season_uc_tt", v) 200 | } 201 | 202 | // UnmarshalText converts transmitted values to ordinary values. 203 | func (v *Season_Uc_Tt) UnmarshalText(bs []byte) error { 204 | return v.unmarshalText(string(bs)) 205 | } 206 | 207 | func (v *Season_Uc_Tt) unmarshalText(in string) error { 208 | if v.parseNumber(in) { 209 | return nil 210 | } 211 | 212 | s := season_uc_ttTransformInput(in) 213 | 214 | if v.parseString(s, season_uc_ttTextStrings, season_uc_ttTextIndex[:]) { 215 | return nil 216 | } 217 | 218 | return v.parseFallback(in, s) 219 | } 220 | -------------------------------------------------------------------------------- /internal/test/simple/season_json.go: -------------------------------------------------------------------------------- 1 | package simple 2 | 3 | //go:generate enumeration -v -f -i season_json.go -type Season_Nc_Ji -suffix _Nc_Ji -s -marshaljson identifier 4 | //go:generate enumeration -v -f -i season_json.go -type Season_Nc_Jn -suffix _Nc_Jn -s -marshaljson number 5 | //go:generate enumeration -v -f -i season_json.go -type Season_Nc_Js -suffix _Nc_Js -s 6 | 7 | type ( 8 | Season_Nc_Ji uint 9 | Season_Nc_Jn uint 10 | Season_Nc_Js uint 11 | ) 12 | 13 | const ( 14 | Spring_Nc_Ji, Summer_Nc_Ji, Autumn_Nc_Ji, Winter_Nc_Ji Season_Nc_Ji = 1, 2, 3, 4 15 | ) 16 | 17 | const ( 18 | Spring_Nc_Jn, Summer_Nc_Jn, Autumn_Nc_Jn, Winter_Nc_Jn Season_Nc_Jn = 1, 2, 3, 4 19 | ) 20 | 21 | const ( 22 | _ Season_Nc_Js = iota 23 | Spring_Nc_Js // json:"Sprg" 24 | Summer_Nc_Js // json:"Sumr" 25 | Autumn_Nc_Js // json:"Autm" 26 | Winter_Nc_Js // json:"Wint" 27 | ) 28 | 29 | //================================================================================================= 30 | //go:generate enumeration -v -f -i season_json.go -type Season_Uc_Ji -suffix _Uc_Ji -uc -s -marshaljson identifier 31 | //go:generate enumeration -v -f -i season_json.go -type Season_Uc_Jn -suffix _Uc_Jn -uc -s -marshaljson number 32 | //go:generate enumeration -v -f -i season_json.go -type Season_Uc_Js -suffix _Uc_Js -uc -s 33 | 34 | type ( 35 | Season_Uc_Ji uint 36 | Season_Uc_Jn uint 37 | Season_Uc_Js uint 38 | ) 39 | 40 | const ( 41 | Spring_Uc_Ji, Summer_Uc_Ji, Autumn_Uc_Ji, Winter_Uc_Ji Season_Uc_Ji = 1, 2, 3, 4 42 | ) 43 | 44 | const ( 45 | _ Season_Uc_Jn = iota 46 | Spring_Uc_Jn 47 | Summer_Uc_Jn 48 | Autumn_Uc_Jn // 3 49 | Winter_Uc_Jn 50 | ) 51 | 52 | const ( 53 | _ Season_Uc_Js = iota 54 | Spring_Uc_Js // json:"Sprg" 55 | Summer_Uc_Js // json:"Sumr" 56 | Autumn_Uc_Js // json:"Autm" 57 | Winter_Uc_Js // json:"Wint" 58 | ) 59 | -------------------------------------------------------------------------------- /internal/test/simple/season_sql.go: -------------------------------------------------------------------------------- 1 | package simple 2 | 3 | //go:generate enumeration -v -f -i season_sql.go -type Season_Nc_Si -suffix _Nc_Si -s -store identifier 4 | //go:generate enumeration -v -f -i season_sql.go -type Season_Nc_Sn -suffix _Nc_Sn -s -store number 5 | //go:generate enumeration -v -f -i season_sql.go -type Season_Nc_Ss -suffix _Nc_Ss -s 6 | 7 | type ( 8 | Season_Nc_Si uint 9 | Season_Nc_Sn uint 10 | Season_Nc_Ss uint 11 | ) 12 | 13 | const ( 14 | Spring_Nc_Si, Summer_Nc_Si, Autumn_Nc_Si, Winter_Nc_Si Season_Nc_Si = 1, 2, 3, 4 15 | ) 16 | 17 | const ( 18 | Spring_Nc_Sn, Summer_Nc_Sn, Autumn_Nc_Sn, Winter_Nc_Sn Season_Nc_Sn = 1, 2, 3, 4 19 | ) 20 | 21 | const ( 22 | _ Season_Nc_Ss = iota 23 | Spring_Nc_Ss // sql:"Sprg" 24 | Summer_Nc_Ss // sql:"Sumr" 25 | Autumn_Nc_Ss // sql:"Autm" 26 | Winter_Nc_Ss // sql:"Wint" 27 | ) 28 | 29 | //================================================================================================= 30 | //go:generate enumeration -v -f -i season_sql.go -type Season_Uc_Si -suffix _Uc_Si -uc -s -store identifier 31 | //go:generate enumeration -v -f -i season_sql.go -type Season_Uc_Sn -suffix _Uc_Sn -uc -s -store number 32 | 33 | type ( 34 | Season_Uc_Si uint 35 | Season_Uc_Sn uint 36 | ) 37 | 38 | const ( 39 | Spring_Uc_Si, Summer_Uc_Si, Autumn_Uc_Si, Winter_Uc_Si Season_Uc_Si = 1, 2, 3, 4 40 | ) 41 | 42 | const ( 43 | Spring_Uc_Sn, Summer_Uc_Sn, Autumn_Uc_Sn, Winter_Uc_Sn Season_Uc_Sn = 1, 2, 3, 4 44 | ) 45 | -------------------------------------------------------------------------------- /internal/test/simple/season_text.go: -------------------------------------------------------------------------------- 1 | package simple 2 | 3 | //go:generate enumeration -v -f -i season_text.go -type Season_Nc_Ti -suffix _Nc_Ti -s -marshaltext identifier 4 | //go:generate enumeration -v -f -i season_text.go -type Season_Nc_Tn -suffix _Nc_Tn -s -marshaltext number 5 | //go:generate enumeration -v -f -i season_text.go -type Season_Nc_Ts -suffix _Nc_Ts -s 6 | 7 | type ( 8 | Season_Nc_Ti uint 9 | Season_Nc_Tn uint 10 | Season_Nc_Ts uint 11 | ) 12 | 13 | const ( 14 | Spring_Nc_Ti, Summer_Nc_Ti, Autumn_Nc_Ti, Winter_Nc_Ti Season_Nc_Ti = 1, 2, 3, 4 15 | ) 16 | 17 | const ( 18 | Spring_Nc_Tn, Summer_Nc_Tn, Autumn_Nc_Tn, Winter_Nc_Tn Season_Nc_Tn = 1, 2, 3, 4 19 | ) 20 | 21 | const ( 22 | _ Season_Nc_Ts = iota 23 | Spring_Nc_Tt // text:"Sprg" 24 | Summer_Nc_Tt // text:"Sumr" 25 | Autumn_Nc_Tt // text:"Autm" 26 | Winter_Nc_Tt // text:"Wint" 27 | ) 28 | 29 | //================================================================================================= 30 | //go:generate enumeration -v -f -i season_text.go -type Season_Uc_Ti -suffix _Uc_Ti -uc -s -marshaltext identifier 31 | //go:generate enumeration -v -f -i season_text.go -type Season_Uc_Tn -suffix _Uc_Tn -uc -s -marshaltext number 32 | //go:generate enumeration -v -f -i season_text.go -type Season_Uc_Ts -suffix _Uc_Ts -uc -s 33 | 34 | type ( 35 | Season_Uc_Ti uint 36 | Season_Uc_Tn uint 37 | Season_Uc_Ts uint 38 | ) 39 | 40 | const ( 41 | Spring_Uc_Ti, Summer_Uc_Ti, Autumn_Uc_Ti, Winter_Uc_Ti Season_Uc_Ti = 1, 2, 3, 4 42 | ) 43 | 44 | const ( 45 | Spring_Uc_Tn, Summer_Uc_Tn, Autumn_Uc_Tn, Winter_Uc_Tn Season_Uc_Tn = 1, 2, 3, 4 46 | ) 47 | 48 | const ( 49 | _ Season_Uc_Ts = iota 50 | Spring_Uc_Tt // text:"Sprg" 51 | Summer_Uc_Tt // text:"Sumr" 52 | Autumn_Uc_Tt // text:"Autm" 53 | Winter_Uc_Tt // text:"Wint" 54 | ) 55 | -------------------------------------------------------------------------------- /internal/transform/case.go: -------------------------------------------------------------------------------- 1 | package transform 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | //go:generate enumeration -type Case 9 | 10 | type Case int 11 | 12 | const ( 13 | Stet Case = iota 14 | Upper 15 | Lower 16 | ) 17 | 18 | func Of(lowercase, uppercase bool) Case { 19 | if lowercase { 20 | return Lower 21 | } else if uppercase { 22 | return Upper 23 | } 24 | return Stet 25 | } 26 | 27 | func (c Case) NoOp() bool { 28 | return c == Stet 29 | } 30 | 31 | func (c Case) Transform(s string) string { 32 | switch c { 33 | case Upper: 34 | return strings.ToUpper(s) 35 | case Lower: 36 | return strings.ToLower(s) 37 | } 38 | return s 39 | } 40 | 41 | func (c Case) Expression(s string) string { 42 | switch c { 43 | case Upper: 44 | return fmt.Sprintf("strings.ToUpper(%s)", s) 45 | case Lower: 46 | return fmt.Sprintf("strings.ToLower(%s)", s) 47 | } 48 | return s 49 | } 50 | 51 | func (c Case) Imports() []string { 52 | switch c { 53 | case Upper, Lower: 54 | return []string{"strings"} 55 | } 56 | return nil 57 | } 58 | -------------------------------------------------------------------------------- /internal/transform/case_enum.go: -------------------------------------------------------------------------------- 1 | // generated code - do not edit 2 | // github.com/rickb777/enumeration/v4 v3.0.2 3 | 4 | package transform 5 | 6 | import ( 7 | "errors" 8 | "fmt" 9 | "strconv" 10 | ) 11 | 12 | // AllCases lists all 3 values in order. 13 | var AllCases = []Case{ 14 | Stet, Upper, Lower, 15 | } 16 | 17 | const ( 18 | caseEnumStrings = "StetUpperLower" 19 | ) 20 | 21 | var ( 22 | caseEnumIndex = [...]uint16{0, 4, 9, 14} 23 | ) 24 | 25 | // String returns the literal string representation of a Case, which is 26 | // the same as the const identifier but without prefix or suffix. 27 | func (v Case) String() string { 28 | o := v.Ordinal() 29 | return v.toString(o, caseEnumStrings, caseEnumIndex[:]) 30 | } 31 | 32 | func (v Case) toString(o int, concats string, indexes []uint16) string { 33 | if o < 0 || o >= len(AllCases) { 34 | return fmt.Sprintf("Case(%d)", v) 35 | } 36 | return concats[indexes[o]:indexes[o+1]] 37 | } 38 | 39 | // Ordinal returns the ordinal number of a Case. This is an integer counting 40 | // from zero. It is *not* the same as the const number assigned to the value. 41 | func (v Case) Ordinal() int { 42 | switch v { 43 | case Stet: 44 | return 0 45 | case Upper: 46 | return 1 47 | case Lower: 48 | return 2 49 | } 50 | return -1 51 | } 52 | 53 | // IsValid determines whether a Case is one of the defined constants. 54 | func (v Case) IsValid() bool { 55 | return v.Ordinal() >= 0 56 | } 57 | 58 | // CaseOf returns a Case based on an ordinal number. This is the inverse of Ordinal. 59 | // If the ordinal is out of range, an invalid Case is returned. 60 | func CaseOf(v int) Case { 61 | if 0 <= v && v < len(AllCases) { 62 | return AllCases[v] 63 | } 64 | // an invalid result 65 | return Stet + Upper + Lower + 1 66 | } 67 | 68 | // parseNumber attempts to convert a decimal value. 69 | // Only numbers that correspond to the enumeration are valid. 70 | func (v *Case) parseNumber(s string) (ok bool) { 71 | num, err := strconv.ParseInt(s, 10, 64) 72 | if err == nil { 73 | *v = Case(num) 74 | return v.IsValid() 75 | } 76 | return false 77 | } 78 | 79 | // Parse parses a string to find the corresponding Case, accepting one of the string values or 80 | // a number. The input representation is determined by None. It is used by AsCase. 81 | // 82 | // Usage Example 83 | // 84 | // v := new(Case) 85 | // err := v.Parse(s) 86 | // ... etc 87 | func (v *Case) Parse(in string) error { 88 | if v.parseNumber(in) { 89 | return nil 90 | } 91 | 92 | s := caseTransformInput(in) 93 | 94 | return v.parseFallback(in, s) 95 | } 96 | 97 | func (v *Case) parseFallback(in, s string) error { 98 | if v.parseString(s, caseEnumStrings, caseEnumIndex[:]) { 99 | return nil 100 | } 101 | 102 | return errors.New(in + ": unrecognised case") 103 | } 104 | 105 | // caseTransformInput may alter input strings before they are parsed. 106 | // This function is pluggable and is initialised using command-line flags 107 | // -ic -lc -uc -unsnake. 108 | var caseTransformInput = func(in string) string { 109 | return in 110 | } 111 | 112 | func (v *Case) parseString(s string, concats string, indexes []uint16) (ok bool) { 113 | var i0 uint16 = 0 114 | 115 | for j := 1; j < len(indexes); j++ { 116 | i1 := indexes[j] 117 | p := concats[i0:i1] 118 | if s == p { 119 | *v = AllCases[j-1] 120 | return true 121 | } 122 | i0 = i1 123 | } 124 | return false 125 | } 126 | 127 | // AsCase parses a string to find the corresponding Case, accepting either one of the string values or 128 | // a number. The input representation is determined by caseMarshalTextRep. It wraps Parse. 129 | func AsCase(s string) (Case, error) { 130 | var v = new(Case) 131 | err := v.Parse(s) 132 | return *v, err 133 | } 134 | 135 | // MustParseCase is similar to AsCase except that it panics on error. 136 | func MustParseCase(s string) Case { 137 | v, err := AsCase(s) 138 | if err != nil { 139 | panic(err) 140 | } 141 | return v 142 | } 143 | -------------------------------------------------------------------------------- /internal/transform/unsnake.go: -------------------------------------------------------------------------------- 1 | package transform 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | type Transform interface { 9 | NoOp() bool 10 | Transform(s string) string 11 | Expression(s string) string 12 | Imports() []string 13 | } 14 | 15 | type Transforms []Transform 16 | 17 | func ListOf(ts ...Transform) (list Transforms) { 18 | for _, t := range ts { 19 | if !t.NoOp() { 20 | list = append(list, t) 21 | } 22 | } 23 | return list 24 | } 25 | 26 | func (ts Transforms) Transform(s string) string { 27 | for _, t := range ts { 28 | s = t.Transform(s) 29 | } 30 | return s 31 | } 32 | 33 | func (ts Transforms) Expression(s string) string { 34 | for _, t := range ts { 35 | s = t.Expression(s) 36 | } 37 | return s 38 | } 39 | 40 | func (ts Transforms) Imports() (list []string) { 41 | for _, t := range ts { 42 | list = append(list, t.Imports()...) 43 | } 44 | return list // may contain duplicates 45 | } 46 | 47 | //------------------------------------------------------------------------------------------------- 48 | 49 | type Unsnake bool 50 | 51 | func (u Unsnake) NoOp() bool { 52 | return !bool(u) 53 | } 54 | 55 | func (u Unsnake) Transform(s string) string { 56 | if u { 57 | return strings.ReplaceAll(s, "_", " ") 58 | } 59 | return s 60 | } 61 | 62 | func (u Unsnake) Expression(s string) string { 63 | if u { 64 | return fmt.Sprintf(`strings.ReplaceAll(%s, "_", " ")`, s) 65 | } 66 | return s 67 | } 68 | 69 | func (u Unsnake) Imports() []string { 70 | if u { 71 | return []string{"strings"} 72 | } 73 | return nil 74 | } 75 | -------------------------------------------------------------------------------- /internal/util/util.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | ) 8 | 9 | var Verbose, Dbg bool 10 | var Stdout = os.Stdout 11 | 12 | func Must(err error, args ...interface{}) { 13 | if err != nil { 14 | a2 := make([]interface{}, 0, len(args)+1) 15 | a2 = append(a2, err.Error()) 16 | a2 = append(a2, args...) 17 | Fail(a2...) 18 | } 19 | } 20 | 21 | func Fail(args ...interface{}) { 22 | fmt.Fprint(os.Stderr, "Error: ") 23 | fmt.Fprintln(os.Stderr, args...) 24 | os.Exit(1) 25 | } 26 | 27 | func Info(msg string, args ...interface{}) { 28 | if Verbose { 29 | fmt.Fprintf(Stdout, msg, args...) 30 | } 31 | } 32 | 33 | func Debug(msg string, args ...interface{}) { 34 | if Dbg { 35 | fmt.Fprintf(Stdout, msg, args...) 36 | } 37 | } 38 | 39 | func removeAfterS(s, sep string) string { 40 | p := strings.Index(s, sep) 41 | if p < 0 { 42 | return s 43 | } 44 | return s[:p] 45 | } 46 | 47 | func listIndexOf(words []string, target string) int { 48 | for i, w := range words { 49 | if w == target { 50 | return i 51 | } 52 | } 53 | return -1 54 | } 55 | -------------------------------------------------------------------------------- /magefiles/build.go: -------------------------------------------------------------------------------- 1 | // See https://magefile.org/ 2 | 3 | //go:build mage 4 | 5 | // Build steps for the enumeration tool: 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | "github.com/magefile/mage/mg" 11 | "github.com/magefile/mage/sh" 12 | "os" 13 | "path/filepath" 14 | "strings" 15 | "time" 16 | ) 17 | 18 | var Default = Build 19 | 20 | func Build() error { 21 | if err := os.MkdirAll("bin", 0777); err != nil { 22 | return err 23 | } 24 | 25 | x := ternary(mg.Verbose(), "-x ", "") 26 | 27 | if err := run( 28 | "go build -o bin/enumeration .", 29 | "go clean -testcache", 30 | "rm -f internal/test/*_enum.go internal/test/simple/*_enum.go", 31 | "go test ./internal/parse", 32 | "go generate "+x+"./internal/test", 33 | "rm -f example/*_enum.go", 34 | "go generate "+x+"./example", 35 | "gofmt -l -w -s .", 36 | ); err != nil { 37 | return err 38 | } 39 | 40 | time.Sleep(250 * time.Millisecond) // wait for the files to be stable 41 | 42 | //--- the following section is used in ./enumeration_test.go --- 43 | 44 | if err := os.MkdirAll("temp/example", 0777); err != nil { 45 | return err 46 | } 47 | 48 | if err := run( 49 | "cp -r example temp", 50 | "rm -f temp/example/*_*.go", 51 | "go test ./...", 52 | "go vet ./...", 53 | "rm -rf temp/", 54 | ); err != nil { 55 | return err 56 | } 57 | 58 | return nil 59 | } 60 | 61 | func run(cmds ...string) error { 62 | for _, cmd := range cmds { 63 | parts := dropBlanks(strings.Split(cmd, " ")) 64 | if len(parts) > 0 { 65 | expanded, err := expandGlob(parts[1:]) 66 | if err != nil { 67 | return err 68 | } 69 | fmt.Println(strings.Join(parts, " ")) 70 | err = sh.RunWith(env, parts[0], expanded...) 71 | if err != nil { 72 | return err 73 | } 74 | } 75 | } 76 | return nil 77 | } 78 | 79 | func dropBlanks(value []string) []string { 80 | words := make([]string, 0, len(value)) 81 | for _, word := range value { 82 | word = strings.TrimSpace(word) 83 | if word != "" { 84 | words = append(words, word) 85 | } 86 | } 87 | return words 88 | } 89 | 90 | func expandGlob(value []string) ([]string, error) { 91 | var files []string 92 | for _, v := range value { 93 | matches, err := filepath.Glob(v) 94 | if err != nil { 95 | return nil, err 96 | } 97 | if len(matches) > 0 { 98 | for _, x := range matches { 99 | files = append(files, x) 100 | } 101 | } else { 102 | files = append(files, v) 103 | } 104 | } 105 | return files, nil 106 | } 107 | 108 | var env = setupPathWithBinDir() 109 | 110 | func setupPathWithBinDir() map[string]string { 111 | dir, _ := os.Getwd() 112 | bindir := filepath.Join(dir, "bin") 113 | path := bindir + ":" + os.Getenv("PATH") 114 | return map[string]string{"PATH": path} 115 | } 116 | 117 | func ternary(pred bool, a, b string) string { 118 | if pred { 119 | return a 120 | } 121 | return b 122 | } 123 | -------------------------------------------------------------------------------- /version.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // appVersion is updated manually just prior to the next tag to be used. 4 | const appVersion = "v4.0.7" 5 | --------------------------------------------------------------------------------