Closed rcoreilly closed 1 year ago
plan:
fork this: https://github.com/dmarkham/enumer
change global functions to methods that return slices of Values and Strings, which is another thing the registry provides. To make these accessible via the Enumer
interface, these must be methods, not global functions!
enumer/enumer
package that defines an interface:
type Enumer interface {
fmt.Stringer
FromString(s string) error
Values() []int64
Strings() []string
}
type BitEnumer interface {
Enumer
HasBitFlag(f int64) bool // note: generic version of flag methods always taking int64 -- for use in generic gui code etc
SetBitFlag(f int64)
}
// MyEnum is an enum
type MyEnum int //enumer:enum
// MyBitEnum is a bitflag enum
type MyBitEnum int //enumer:bitflag
Make main code available as library that goki tool includes and does as part of its mega generate function.
also auto-generate an MyEnumN
const value that is the number of enums (only for contiguous ones)
bitflag functions:
func (e *MyBitEnum) Has(f MyBitEnum) bool {
// bitflag.HasFlagAtomic((*int64)(e), int64(f)) // key point: generator knows to use 64 vs 32 bit versions here
// also, just use the actual code instead of requiring bitflag:
return (atomic.LoadInt64((*int64)(e) & int64(f)) != 0 // note: atomic not much more expensive and almost always preferred
}
// etc for set flag
Add support for enums and bitflags that extend existing enums -- does range checking, etc.
in current ki-based code:
var TypeNodeFlags = kit.Enums.AddEnumExt(ki.KiT_Flags, NodeFlagsN, kit.BitFlag, nil)
const (
// NoLayout means that this node does not participate in the layout
// process (Size, Layout, Move) -- set by e.g., SVG nodes
NoLayout NodeFlags = NodeFlags(ki.FlagsN) + iota
new way -- generator reads the base type to know that it extends
type NewEnum MyEnum //enumer:enum
This does the following:
// in package ki:
type Flags int64 //enumer:bitflag
type Node struct {
Flag Flags // this must be of type Flags so the gui knows how to treat it.
}
// in package ki:
type ButtonFlags ki.Flags //enumer:bitflag
// access inherited flag in random code
var f ki.Flags // some random enum var
if f.Has(ki.Updating) // this works automatically
// using extended flag, you have to use an explicit cast to access extended enum values
if ButtonFlags(f).Has(Hovered) // this only works for actual ButtonFlags..
// the other way:
var bf ButtonFlags
if bf.Has(Hovered) // no problem
if ki.Flags(bf).Has(ki.Updating) // same thing
// generic global method version:
// in enumer, generic method working with any BitEnumer type:
func Has[B BitEnumer, F constraints.Integer](b B, f F) bool {
return b.HasBitFlag(int64(f))
}
// for the above cases of f, bf -- bf or f works the same
if enumer.Has(f, ki.Updating)
if enumer.Has(f, Hovered)
Is
, Set
methodsBenefit: embedded types will automatically inherit these methods Cost: lots of methods!
// Button is a ...
type Button struct { //enumer:structflag=ButtonFlags field=Flag
...
}
// generates methods for only the new flags in ButtonFlags:
func (b *Button) IsHovered() bool
func (b *Button) SetHovered(b bool)
...
(flag can default to Flag but I think it is better not to have magic default behavior)
HasFlag
, SetFlag
methods// generated code:
func (b *Button) HasFlag(f ButtonFlag) bool
func (b *Button) SetFlag(f ButtonFlag)
// access parent version using embedded type:
b.HasFlag(Hovered) // easy access of button flags
b.Node.HasFlag(ki.Updating) // requires knowing which level has what flags..
This is not really relevant to enumer because it is just hand coded and would require a similar hand-coded case for anyone else to impl.
// in ki.go:
func HasFlag[T constraints.Integer](k Ki, f T) bool {
return k.HasFlag(int64(f)) // note: can then use proper int64 instead of
}
// use case:
ki.HasFlag(b, Hovered)
enumer.Has(b.Flag, Hovered)
// button Hovered case:
b.Flag.Has(ki.Flags(Hovered)) // no!
enumer.Has(b.Flag, Hovered) // free -- going to need anyway
ki.HasFlag(b, Hovered) // also easy
b.HasFlag(Hovered) // no!
b.IsHovered()
// ki.Updating case:
b.Flag.Has(ki.Updating) // no!
enumer.Has(b.Flag, ki.Updating) // free
ki.HasFlag(b, ki.Updating) // easy
b.Node.HasFlag(ki.Updating) // no!
b.IsUpdating()
So obviously the question is: Is?
optional type registry functionality, needed for loading arbitrary enum types and values from files. This adds the kit.AddEnum
code in generate.
enums package all good!
Basic Enumer would just require
FromString
method -- very easy. Add akit.SetEnumFromString
that just checks for the interface and calls it directly. Much simpler than what is there now.BitEnumer
FromStringBits
would call akit.BitFlagsFromString
method -- it just parses the | and uses FromString.The main missing part here would be the alt strings -- need to see exactly what this is, but it may just be lower case versions?