This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch main
in repository ego.
View the commit online.
commit 49e629b63ade7ca0d022c45b281e16fd383b09e9
Author: [email protected] <[email protected]>
AuthorDate: Sun Mar 29 22:04:03 2026 -0600
feat(ego-gen): add buildIndexedPropertyData and key type validation
New indexed_property.go with the build function that converts Eolian
indexed properties into IndexedPropertyData, reusing existing type
mapping infrastructure.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
---
cmd/ego-gen/generator_test.go | 27 +++++++
cmd/ego-gen/indexed_property.go | 168 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 195 insertions(+)
diff --git a/cmd/ego-gen/generator_test.go b/cmd/ego-gen/generator_test.go
index 76da170..8c5a741 100644
--- a/cmd/ego-gen/generator_test.go
+++ b/cmd/ego-gen/generator_test.go
@@ -564,3 +564,30 @@ func TestNewGenerator_MissingTemplateDir(t *testing.T) {
t.Fatal("expected error for missing template directory, got nil")
}
}
+
+func TestBuildIndexedPropertyData_SingleKeyString(t *testing.T) {
+ tests := []struct {
+ ctype string
+ want bool
+ }{
+ {"const char *", true},
+ {"Eina_Stringshare", true},
+ {"int", true},
+ {"unsigned int", true},
+ {"Eina_Bool", true},
+ {"double", true},
+ {"Efl_Gfx_Color_Class_Layer", true}, // enum, maps to unsafe.Pointer which is a pointer
+ {"Eina_File *", false}, // opaque pointer — not supported
+ {"Eina_Rect", false}, // struct by value — not supported
+ {"void *", false}, // raw void pointer — not supported
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.ctype, func(t *testing.T) {
+ got := isSupportedKeyType(tc.ctype)
+ if got != tc.want {
+ t.Errorf("isSupportedKeyType(%q) = %v, want %v", tc.ctype, got, tc.want)
+ }
+ })
+ }
+}
diff --git a/cmd/ego-gen/indexed_property.go b/cmd/ego-gen/indexed_property.go
new file mode 100644
index 0000000..c073167
--- /dev/null
+++ b/cmd/ego-gen/indexed_property.go
@@ -0,0 +1,168 @@
+package main
+
+import "fmt"
+
+// isSupportedKeyType reports whether a C type can be used as an indexed
+// property key parameter. Supported types are: strings, numeric scalars,
+// booleans, and enum typedefs (which are integer-sized non-pointer,
+// non-struct types). Opaque pointers (void *, Eo *) and struct-by-value
+// types are not supported as keys.
+func isSupportedKeyType(ctype string) bool {
+ if NeedsStringConversion(ctype) {
+ return true
+ }
+ if IsBoolType(ctype) {
+ return true
+ }
+ if isSimpleCgoType(ctype) {
+ return true
+ }
+ // Reject known struct types.
+ if IsStructType(ctype) {
+ return false
+ }
+ // Reject pointer types (void *, Eo *, Eina_File *, etc.).
+ goType := CTypeToGo(ctype)
+ if goType == "unsafe.Pointer" {
+ // Check if it is an Eo class type — those are supported.
+ if IsEoType(ctype) {
+ return true
+ }
+ // Non-pointer, non-struct C types that map to unsafe.Pointer are
+ // enum typedefs (e.g. Efl_Gfx_Color_Class_Layer). These are
+ // integer-sized and safe to pass as keys.
+ if !IsCPointerType(ctype) {
+ return true
+ }
+ return false
+ }
+ return true
+}
+
+// buildIndexedPropertyData converts an Eolian indexed property Function into
+// an IndexedPropertyData. Returns an error if any key type is unsupported.
+func buildIndexedPropertyData(f *Function, cPrefix string) (IndexedPropertyData, error) {
+ propName := f.Name()
+
+ ft := f.Type()
+ hasGet := ft == FunctionProperty || ft == FunctionPropGet
+ hasSet := ft == FunctionProperty || ft == FunctionPropSet
+
+ // Extract keys — prefer getter keys; fall back to setter.
+ keys := f.PropertyKeys(FunctionPropGet)
+ if len(keys) == 0 {
+ keys = f.PropertyKeys(FunctionPropSet)
+ }
+ if len(keys) == 0 {
+ return IndexedPropertyData{}, fmt.Errorf("property %q has no keys", propName)
+ }
+
+ // Build key params, rejecting unsupported types.
+ var keyParams []ParamData
+ for _, k := range keys {
+ pd := buildParamData(k)
+ if !isSupportedKeyType(pd.CType) {
+ return IndexedPropertyData{}, fmt.Errorf("property %q key %q has unsupported type %q", propName, pd.GoName, pd.CType)
+ }
+ keyParams = append(keyParams, pd)
+ }
+
+ cGetName := f.FullCName(FunctionPropGet)
+ cSetName := f.FullCName(FunctionPropSet)
+
+ goAccessor, _ := PropertyToGetterSetter(propName)
+ accessorType := snakeToLowerCamel(propName) + "Property"
+
+ ipd := IndexedPropertyData{
+ GoAccessorMethod: goAccessor,
+ AccessorTypeName: accessorType,
+ CGetName: cGetName,
+ CSetName: cSetName,
+ HasGet: hasGet,
+ HasSet: hasSet,
+ Keys: keyParams,
+ }
+
+ // Determine value types — same logic branches as buildPropertyData.
+ // Check for multi-value first.
+ getVals := f.PropertyValues(FunctionPropGet)
+ setVals := f.PropertyValues(FunctionPropSet)
+
+ if len(getVals) > 1 || len(setVals) > 1 {
+ getMulti, getOK := buildMultiValueData(getVals)
+ setMulti, setOK := buildMultiValueData(setVals)
+ if (!hasGet || getOK) && (!hasSet || setOK) {
+ ipd.IsMultiValue = true
+ ipd.MultiGetValues = getMulti
+ ipd.MultiSetValues = setMulti
+ ipd.HasGet = hasGet && len(getMulti) > 0
+ ipd.HasSet = hasSet && len(setMulti) > 0
+ return ipd, nil
+ }
+ return IndexedPropertyData{}, fmt.Errorf("indexed property %q has multi-value with unsupported types", propName)
+ }
+
+ // Single-value: determine type from getter return, getter value, or setter value.
+ var cType, goType string
+ var isEo, isStruct bool
+
+ if rt := f.ReturnType(FunctionPropGet); rt != nil && hasGet {
+ cType = rt.CType()
+ goType = CTypeToGo(cType)
+ isEo = rt.IsClass()
+ if IsKnownStruct(cType) {
+ isStruct = true
+ }
+ } else if len(getVals) == 1 {
+ if pt := getVals[0].Type(); pt != nil {
+ cType = pt.CType()
+ goType = CTypeToGo(cType)
+ isEo = pt.IsClass()
+ if IsKnownStruct(cType) {
+ isStruct = true
+ } else if IsStructType(cType) {
+ // Unknown struct — disable getter.
+ hasGet = false
+ }
+ }
+ } else if len(setVals) == 1 {
+ hasGet = false
+ if pt := setVals[0].Type(); pt != nil {
+ cType = pt.CType()
+ goType = CTypeToGo(cType)
+ isEo = pt.IsClass()
+ if IsKnownStruct(cType) {
+ isStruct = true
+ }
+ }
+ } else {
+ // No values at all — nothing to get or set.
+ return IndexedPropertyData{}, fmt.Errorf("indexed property %q has no value params", propName)
+ }
+
+ if goType == "" {
+ goType = "unsafe.Pointer"
+ cType = "void *"
+ }
+
+ ipd.GoType = goType
+ ipd.CType = cType
+ ipd.IsEo = isEo
+ ipd.IsStruct = isStruct
+ ipd.HasGet = hasGet
+ ipd.HasSet = hasSet
+
+ if isStruct {
+ si := GetStructInfo(cType)
+ ipd.GoType = si.GoType
+ ipd.StructGoType = si.GoType
+ ipd.StructCType = si.CType
+ ipd.StructGoFields = si.GoFields
+ ipd.StructCFields = si.CFields
+ ipd.StructCFieldTypes = si.CFieldTypes
+ ipd.StructCMacro = si.CMacro
+ ipd.StructCAccessPrefix = si.CAccessPrefix
+ }
+
+ return ipd, nil
+}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.