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.

Reply via email to