enumgen

package
v0.9.11 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 9, 2023 License: BSD-3-Clause Imports: 22 Imported by: 2

Documentation

Overview

Package enumgen provides functions for generating enum methods for enum types.

Index

Constants

This section is empty.

Variables

View Source
var AllowedEnumTypes = map[string]bool{"int": true, "int64": true, "int32": true, "int16": true, "int8": true, "uint": true, "uint64": true, "uint32": true, "uint16": true, "uint8": true}

AllowedEnumTypes are the types that can be used for enums that are not bit flags (bit flags can only be int64s). It is stored as a map for quick and convenient access.

View Source
var DescMethodTmpl = template.Must(template.New("DescMethod").Parse(`// Desc returns the description of the {{.TypeName}} value.
func (i {{.TypeName}}) Desc() string {
	if str, ok := _{{.TypeName}}DescMap[i]; ok {
		return str
	} {{if eq .Extends ""}}
	return i.String() {{else}}
	return {{.Extends}}(i).Desc() {{end}}
}
`))
View Source
var GQLMethodsTmpl = template.Must(template.New("GQLMethods").Parse(`
// MarshalGQL implements the [graphql.Marshaler] interface.
func (i {{.TypeName}}) MarshalGQL(w io.Writer) {
	w.Write([]byte(strconv.Quote(i.String())))
}

// UnmarshalGQL implements the [graphql.Unmarshaler] interface.
func (i *{{.TypeName}}) UnmarshalGQL(value any) error {
	str, ok := value.(string)
	if !ok {
		return fmt.Errorf("{{.TypeName}} should be a string, but got a value of type %T instead", value)
	}
	return i.SetString(str)
}
`))
View Source
var HasFlagMethodTmpl = template.Must(template.New("HasFlagMethod").Parse(
	`// HasFlag returns whether these
// bit flags have the given bit flag set.
func (i {{.TypeName}}) HasFlag(f enums.BitFlag) bool {
	return i&(1<<uint32(f.Int64())) != 0
}
`))
View Source
var Int64MethodTmpl = template.Must(template.New("Int64Method").Parse(
	`// Int64 returns the {{.TypeName}} value as an int64.
func (i {{.TypeName}}) Int64() int64 {
	return int64(i)
}
`))
View Source
var IsValidMethodMapTmpl = template.Must(template.New("IsValidMethodMap").Parse(
	`// IsValid returns whether the value is a
// valid option for type {{.TypeName}}.
func (i {{.TypeName}}) IsValid() bool {
	_, ok := _{{.TypeName}}Map[i] {{if ne .Extends ""}}
	if !ok {
		return {{.Extends}}(i).IsValid()
	} {{end}}
	return ok
}
`))
View Source
var JSONMethodsTmpl = template.Must(template.New("JSONMethods").Parse(
	`
// MarshalJSON implements the [json.Marshaler] interface.
func (i {{.TypeName}}) MarshalJSON() ([]byte, error) {
	return json.Marshal(i.String())
}

// UnmarshalJSON implements the [json.Unmarshaler] interface.
func (i *{{.TypeName}}) UnmarshalJSON(data []byte) error {
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return err
	}
	return i.SetString(s)
}
`))
View Source
var NConstantTmpl = template.Must(template.New("StringNConstant").Parse(
	`//{{.TypeName}}N is the highest valid value
// for type {{.TypeName}}, plus one.
const {{.TypeName}}N {{.TypeName}} = {{.MaxValueP1}}
`))
View Source
var ScanMethodTmpl = template.Must(template.New("ScanMethod").Parse(
	`// Value implements the [sql.Scanner] interface.
func (i *{{.TypeName}}) Scan(value any) error {
	if value == nil {
		return nil
	}

	var str string
	switch v := value.(type) {
	case []byte:
		str = string(v)
	case string:
		str = v
	case fmt.Stringer:
		str = v.String()
	default:
		return fmt.Errorf("invalid value for type {{.TypeName}}: %[1]T(%[1]v)", value)
	}

	return i.SetString(str)
}
`))
View Source
var SetFlagMethodTmpl = template.Must(template.New("SetFlagMethod").Parse(
	`// SetFlag sets the value of the given
// flags in these flags to the given value.
func (i *{{.TypeName}}) SetFlag(on bool, f ...enums.BitFlag) {
	var mask int64
	for _, v := range f {
		mask |= 1 << v.Int64()
	}
	in := int64(*i)
	if on {
		in |= mask
		atomic.StoreInt64((*int64)(i), in)
	} else {
		in &^= mask
		atomic.StoreInt64((*int64)(i), in)
	}
}
`))
View Source
var SetInt64MethodTmpl = template.Must(template.New("SetInt64Method").Parse(
	`// SetInt64 sets the {{.TypeName}} value from an int64.
func (i *{{.TypeName}}) SetInt64(in int64) {
	*i = {{.TypeName}}(in)
}
`))
View Source
var SetStringMethodBitFlagTmpl = template.Must(template.New("SetStringMethodBitFlag").Parse(
	`// SetString sets the {{.TypeName}} value from its
// string representation, and returns an
// error if the string is invalid.
func (i *{{.TypeName}}) SetString(s string) error {
	flgs := strings.Split(s, "|")
	for _, flg := range flgs {
		if val, ok := _{{.TypeName}}NameToValueMap[flg]; ok {
			i.SetFlag(true, &val)
		} else if val, ok := _{{.TypeName}}NameToValueMap[strings.ToLower(flg)]; ok {
			i.SetFlag(true, &val)
		} else { {{if eq .Extends ""}}
			return errors.New(flg+" is not a valid value for type {{.TypeName}}"){{else}}
			err := (*{{.Extends}})(i).SetString(flg)
			if err != nil {
				return err
			}{{end}}
		}
	}
	return nil
}
`))
View Source
var SetStringMethodTmpl = template.Must(template.New("SetStringMethod").Parse(
	`// SetString sets the {{.TypeName}} value from its
// string representation, and returns an
// error if the string is invalid.
func (i *{{.TypeName}}) SetString(s string) error {
	if val, ok := _{{.TypeName}}NameToValueMap[s]; ok {
		*i = val
		return nil
	}

	if val, ok := _{{.TypeName}}NameToValueMap[strings.ToLower(s)]; ok {
		*i = val
		return nil
	}{{if eq .Extends ""}}
	return errors.New(s+" is not a valid value for type {{.TypeName}}"){{else}}
	return (*{{.Extends}})(i).SetString(s){{end}}
}
`))
View Source
var StringMethodBitFlagTmpl = template.Must(template.New("StringMethodBitFlag").Parse(
	`// String returns the string representation
// of this {{.TypeName}} value.
func (i {{.TypeName}}) String() string {
	str := "" {{if ne .Extends ""}}
	for _, ie := range _{{.Extends}}Values {
		if i.HasFlag(ie) {
			ies := ie.BitIndexString()
			if str == "" {
				str = ies
			} else {
				str += "|" + ies
			}
		}
	}{{end}}
	for _, ie := range _{{.TypeName}}Values {
		if i.HasFlag(ie) {
			ies := ie.BitIndexString()
			if str == "" {
				str = ies
			} else {
				str += "|" + ies
			}
		}
	}
	return str
}
`))
View Source
var StringMethodMapTmpl = template.Must(template.New("StringMethodMap").Parse(
	`{{.MethodComment}}
func (i {{.TypeName}}) {{.MethodName}}() string {
	if str, ok := _{{.TypeName}}Map[i]; ok {
		return str
	}{{if eq .Extends ""}}
	return strconv.FormatInt(int64(i), 10){{else}}
	return {{.Extends}}(i).{{.MethodName}}(){{end}}
}
`))
View Source
var TextMethodsTmpl = template.Must(template.New("TextMethods").Parse(
	`
// MarshalText implements the [encoding.TextMarshaler] interface.
func (i {{.TypeName}}) MarshalText() ([]byte, error) {
	return []byte(i.String()), nil
}

// UnmarshalText implements the [encoding.TextUnmarshaler] interface.
func (i *{{.TypeName}}) UnmarshalText(text []byte) error {
	return i.SetString(string(text))
}
`))
View Source
var ValueMethodTmpl = template.Must(template.New("ValueMethod").Parse(
	`// Scan implements the [driver.Valuer] interface.
func (i {{.TypeName}}) Value() (driver.Value, error) {
	return i.String(), nil
}
`))
View Source
var ValuesGlobalTmpl = template.Must(template.New("ValuesGlobal").Parse(
	`// {{.TypeName}}Values returns all possible values
// for the type {{.TypeName}}.
func {{.TypeName}}Values() []{{.TypeName}} { {{if eq .Extends ""}}
	return _{{.TypeName}}Values {{else}}
	es := {{.Extends}}Values()
	res := make([]{{.TypeName}}, len(es))
	for i, e := range es {
		res[i] = {{.TypeName}}(e)
	}
	res = append(res, _{{.TypeName}}Values...)
	return res {{end}}
}
`))
View Source
var ValuesMethodTmpl = template.Must(template.New("ValuesMethod").Parse(
	`// Values returns all possible values
// for the type {{.TypeName}}.
func (i {{.TypeName}}) Values() []enums.Enum { {{if eq .Extends ""}}
	res := make([]enums.Enum, len(_{{.TypeName}}Values))
	for i, d := range _{{.TypeName}}Values {
		res[i] = d
	} {{else}}
	es := {{.Extends}}Values()
	les := len(es)
	res := make([]enums.Enum, les + len(_{{.TypeName}}Values))
	for i, d := range es {
		res[i] = d
	}
	for i, d := range _{{.TypeName}}Values {
		res[i + les] = d
	} {{end}}
	return res 
}
`))
View Source
var YAMLMethodsTmpl = template.Must(template.New("YAMLMethods").Parse(
	`
// MarshalYAML implements the [yaml.Marshaler] interface.
func (i {{.TypeName}}) MarshalYAML() (any, error) {
	return i.String(), nil
}

// UnmarshalYAML implements the [yaml.Unmarshaler] interface.
func (i *{{.TypeName}}) UnmarshalYAML(value *yaml.Node) error {
	var s string
	if err := n.Decode(&s); err != nil {
		return err
	}
	return i.SetString(s)
}
`))

Functions

func Generate

func Generate(config *config.Config) error

Generate generates enum methods using the given configuration object. It reads all Go files in the config source directory and writes the result to the config output file. It is a simple entry point to enumgen that does all of the steps; for more specific functionality, create a new Generator with NewGenerator and call methods on it.

func Usize

func Usize(n int) int

Usize returns the number of bits of the smallest unsigned integer type that will hold n. Used to create the smallest possible slice of integers to use as indexes into the concatenated strings.

Types

type ByValue

type ByValue []Value

ByValue is a sorting method that sorts the constants into increasing order. We take care in the Less method to sort in signed or unsigned order, as appropriate.

func (ByValue) Len

func (b ByValue) Len() int

func (ByValue) Less

func (b ByValue) Less(i, j int) bool

func (ByValue) Swap

func (b ByValue) Swap(i, j int)

type File

type File struct {
	Pkg  *Package  // Package to which this file belongs.
	File *ast.File // Parsed AST.
	// These fields are reset for each type being generated.
	Type    *Type          // The constant type we are currently looking for.
	BitFlag bool           // Whether the constant type we are currently looking for is a bitflag.
	Values  []Value        // Accumulator for constant values of that type.
	Config  *config.Config // The configuration information
}

File holds a single parsed file and associated data.

func (*File) GenDecl

func (f *File) GenDecl(node ast.Node) (bool, error)

GenDecl processes one declaration clause. It returns whether the AST inspector should continue, and an error if there is one. It should only be called in ast.Inspect.

type Generator

type Generator struct {
	Config *config.Config // The configuration information
	Buf    bytes.Buffer   // The accumulated output.
	Pkgs   []*Package     // The packages we are scanning.
	Pkg    *Package       // The packages we are currently on.
	Types  []*Type        // The enum types
}

Generator holds the state of the generator. It is primarily used to buffer the output.

func NewGenerator

func NewGenerator(config *config.Config) *Generator

NewGenerator returns a new generator with the given configuration information.

func (*Generator) AddPackage

func (g *Generator) AddPackage(pkg *packages.Package)

AddPackage adds a package and its syntax files to the generator.

func (*Generator) AddValueAndScanMethod added in v0.9.11

func (g *Generator) AddValueAndScanMethod(typ *Type)

func (*Generator) BuildBasicMethods added in v0.9.11

func (g *Generator) BuildBasicMethods(values []Value, typ *Type)

BuildBasicMethods builds methods common to all types, like Desc and SetString.

func (*Generator) BuildBitFlagMethods

func (g *Generator) BuildBitFlagMethods(runs []Value, typ *Type)

BuildBitFlagMethods builds methods specific to bit flag types.

func (*Generator) BuildGQLMethods added in v0.9.11

func (g *Generator) BuildGQLMethods(runs []Value, typ *Type)

func (*Generator) BuildJSONMethods

func (g *Generator) BuildJSONMethods(runs []Value, typ *Type)

func (*Generator) BuildNoOpOrderChangeDetect

func (g *Generator) BuildNoOpOrderChangeDetect(values []Value, typ *Type)

BuildNoOpOrderChangeDetect lets the compiler and the user know if the order/value of the enum values has changed.

func (*Generator) BuildString added in v0.9.11

func (g *Generator) BuildString(values []Value, typ *Type)

BuildString builds the string function using a map access approach.

func (*Generator) BuildTextMethods

func (g *Generator) BuildTextMethods(runs []Value, typ *Type)

func (*Generator) BuildYAMLMethods

func (g *Generator) BuildYAMLMethods(runs []Value, typ *Type)

func (*Generator) ExecTmpl added in v0.9.11

func (g *Generator) ExecTmpl(t *template.Template, data *TmplData)

ExecTmpl executes the given template with the given data and writes the result to [Generator.Buf]. It fatally logs any error.

func (*Generator) FindEnumTypes

func (g *Generator) FindEnumTypes() error

FindEnumTypes goes through all of the types in the package and finds all integer (signed or unsigned) types labeled with enums:enum or enums:bitflag. It stores the resulting types in [Generator.Types].

func (*Generator) Format

func (g *Generator) Format() ([]byte, error)

Format returns the contents of the Generator's buffer ([Generator.Buf]) with goimports applied.

func (*Generator) Generate

func (g *Generator) Generate() (bool, error)

Generate produces the enum methods for the types stored in [Generator.Types] and stores them in [Generator.Buf]. It returns whether there were any enum types to generate methods for, and any error that occurred.

func (*Generator) InspectForType

func (g *Generator) InspectForType(n ast.Node) (bool, error)

InspectForType looks at the given AST node and adds it to [Generator.Types] if it is marked with an appropriate comment directive. It returns whether the AST inspector should continue, and an error if there is one. It should only be called in ast.Inspect.

func (*Generator) ParsePackage

func (g *Generator) ParsePackage() error

ParsePackage parses the package(s) located in the configuration source directory.

func (*Generator) PrefixValueNames

func (g *Generator) PrefixValueNames(values []Value, c *config.Config)

PrefixValueNames adds the prefix specified in config.Config.AddPrefix to each name of the given values.

func (*Generator) PrintDescMap

func (g *Generator) PrintDescMap(values []Value, typ *Type)

PrintDescMap prints the map of values to descriptions

func (*Generator) PrintHeader

func (g *Generator) PrintHeader()

PrintHeader prints the header and package clause to the accumulated output

func (*Generator) PrintValueMap

func (g *Generator) PrintValueMap(values []Value, typ *Type)

PrintValueMap prints the map between name and value

func (*Generator) Printf

func (g *Generator) Printf(format string, args ...any)

Printf prints the formatted string to the accumulated output in [Generator.Buf]

func (*Generator) TransformValueNames

func (g *Generator) TransformValueNames(values []Value, c *config.Config) error

TransformValueNames transforms the names of the given values according to the transform method specified in config.Config.Transform

func (*Generator) TrimValueNames

func (g *Generator) TrimValueNames(values []Value, c *config.Config)

TrimValueNames removes the prefixes specified in config.Config.TrimPrefix from each name of the given values.

func (*Generator) Write

func (g *Generator) Write() error

Write formats the data in the the Generator's buffer ([Generator.Buf]) and writes it to the file specified by [Generator.Config.Output].

type Package

type Package struct {
	Dir      string
	Name     string
	Defs     map[*ast.Ident]types.Object
	Files    []*File
	TypesPkg *types.Package
}

Package holds information about a Go package

type TmplData added in v0.9.11

type TmplData struct {
	TypeName      string // the name of the enum type
	IsBitFlag     bool   // whether the type is a bit flag
	Extends       string // the type this type extends, if any
	MaxValueP1    string // the highest defined value for the type, plus one, as a string
	MethodName    string // method name (String or BitIndexString)
	MethodComment string // doc comment for the method
}

TmplData contains the data passed to a generation template

func NewTmplData added in v0.9.11

func NewTmplData(typ *Type) *TmplData

NewTmplData creates a new TmplData from the given type.

func (*TmplData) SetMethod added in v0.9.11

func (td *TmplData) SetMethod()

SetMethod sets [TmplData.MethodName] and [TmplData.MethodComment] based on whether the type is a bit flag type. It assumes that [TmplData.TypeName] and [TmplData.IsBitFlag] are already set.

type Type

type Type struct {
	Name      string         // The name of the type
	Type      *ast.TypeSpec  // The standard AST type value
	IsBitFlag bool           // Whether the type is a bit flag type
	Extends   string         // The type that this type extends, if any ("" if it doesn't extend)
	Config    *config.Config // Configuration information set in the comment directive for the type; is initialized to generator config info first
}

Type represents a parsed enum type.

type Value

type Value struct {
	OriginalName string // The name of the constant before transformation
	Name         string // The name of the constant after transformation (i.e. camel case => snake case)
	Desc         string // The comment description of the constant
	// The Value is stored as a bit pattern alone. The boolean tells us
	// whether to interpret it as an int64 or a uint64; the only place
	// this matters is when sorting.
	// Much of the time the str field is all we need; it is printed
	// by Value.String.
	Value  uint64 // Will be converted to int64 when needed.
	Signed bool   // Whether the constant is a signed type.
	Str    string // The string representation given by the "go/constant" package.
}

Value represents a declared constant.

func SortValues added in v0.9.11

func SortValues(values []Value) []Value

SortValues sorts the values and ensures there are no duplicates. The input slice is known to be non-empty.

func (*Value) String

func (v *Value) String() string

Directories

Path Synopsis
Package config contains the configuration information used by enumgen
Package config contains the configuration information used by enumgen

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL