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 a6100757d02458083516042b2672744022d7664f
Author: [email protected] <[email protected]>
AuthorDate: Mon Mar 30 15:27:04 2026 -0600

    feat(ego-gen): add iterator method template with iter.Seq[T]
    
    Generate iter.Seq[T] closures for methods returning Eina_Iterator.
    Handles Eo pointer, string, scalar, and known struct element types.
    Includes C preamble wrappers and conditional "iter" import.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
---
 cmd/ego-gen/generator_test.go       | 103 ++++++++++++++++++++++++++++++++++++
 cmd/ego-gen/templates/class.go.tmpl |  59 +++++++++++++++++++++
 2 files changed, 162 insertions(+)

diff --git a/cmd/ego-gen/generator_test.go b/cmd/ego-gen/generator_test.go
index 05c89a7..5fc642e 100644
--- a/cmd/ego-gen/generator_test.go
+++ b/cmd/ego-gen/generator_test.go
@@ -746,6 +746,109 @@ func TestGenerateClass_MultiValueMixedTypes(t *testing.T) {
 	}
 }
 
+func TestGenerateClass_IteratorMethodString(t *testing.T) {
+	g, outDir := newTestGenerator(t)
+
+	data := ClassData{
+		PackageName:   "eo",
+		GoName:        "ConfigGlobal",
+		EolianName:    "Efl.Config_Global",
+		CClassName:    "EFL_CONFIG_GLOBAL_CLASS",
+		CClassGetFunc: "efl_config_global_class_get",
+		CPrefix:       "efl_config_global",
+		EOHeaderFile:  "efl_config_global.eo.h",
+		IsAbstract:    true,
+		HasIterators:  true,
+		IteratorMethods: []IteratorMethodData{
+			{
+				GoName: "ProfileIterate",
+				CName:  "efl_config_profile_iterate",
+				Params: []ParamData{
+					{GoName: "hidden", GoType: "bool", CType: "Eina_Bool"},
+				},
+				ElemGoType:   "string",
+				ElemCType:    "const char *",
+				ElemIsString: true,
+			},
+		},
+	}
+
+	if err := g.GenerateClass(data); err != nil {
+		t.Fatalf("GenerateClass: %v", err)
+	}
+
+	outFile := filepath.Join(outDir, "eo", "config_global.go")
+	content, err := os.ReadFile(outFile)
+	if err != nil {
+		t.Fatalf("output file not found at %s: %v", outFile, err)
+	}
+
+	src := string(content)
+
+	mustContain := []string{
+		"func (o *ConfigGlobal) ProfileIterate(hidden bool) iter.Seq[string]",
+		"return func(yield func(string) bool)",
+		"C.GoString((*C.char)(data))",
+		"efl_config_profile_iterate",
+		"if hidden {",
+	}
+
+	for _, want := range mustContain {
+		if !strings.Contains(src, want) {
+			t.Errorf("output missing expected pattern %q\nfile content:\n%s", want, src)
+		}
+	}
+}
+
+func TestGenerateClass_IteratorMethodScalar(t *testing.T) {
+	g, outDir := newTestGenerator(t)
+
+	data := ClassData{
+		PackageName:   "ui",
+		GoName:        "MultiSelectable",
+		EolianName:    "Efl.Ui.Multi_Selectable",
+		CClassName:    "EFL_UI_MULTI_SELECTABLE_CLASS",
+		CClassGetFunc: "efl_ui_multi_selectable_class_get",
+		CPrefix:       "efl_ui_multi_selectable",
+		EOHeaderFile:  "efl_ui_multi_selectable.eo.h",
+		IsAbstract:    true,
+		HasIterators:  true,
+		IteratorMethods: []IteratorMethodData{
+			{
+				GoName:     "SelectedNdxIteratorNew",
+				CName:      "efl_ui_multi_selectable_selected_ndx_iterator_new",
+				Params:     nil,
+				ElemGoType: "uint",
+				ElemCType:  "unsigned int",
+			},
+		},
+	}
+
+	if err := g.GenerateClass(data); err != nil {
+		t.Fatalf("GenerateClass: %v", err)
+	}
+
+	outFile := filepath.Join(outDir, "ui", "multi_selectable.go")
+	content, err := os.ReadFile(outFile)
+	if err != nil {
+		t.Fatalf("output file not found at %s: %v", outFile, err)
+	}
+
+	src := string(content)
+
+	mustContain := []string{
+		"func (o *MultiSelectable) SelectedNdxIteratorNew() iter.Seq[uint]",
+		"return func(yield func(uint) bool)",
+		"uint(*(*C.uint)(data))",
+	}
+
+	for _, want := range mustContain {
+		if !strings.Contains(src, want) {
+			t.Errorf("output missing expected pattern %q\nfile content:\n%s", want, src)
+		}
+	}
+}
+
 func TestGenerateClass_IteratorMethod(t *testing.T) {
 	g, outDir := newTestGenerator(t)
 
diff --git a/cmd/ego-gen/templates/class.go.tmpl b/cmd/ego-gen/templates/class.go.tmpl
index 48ccd05..8f141c6 100644
--- a/cmd/ego-gen/templates/class.go.tmpl
+++ b/cmd/ego-gen/templates/class.go.tmpl
@@ -43,6 +43,17 @@ typedef Eo Efl_Ui_Widget;
 // header, which may reference types from other .eo files that are not included.
 extern const Efl_Class *{{.CClassGetFunc}}(void);
 
+{{- if .HasIterators}}
+// _ego_iter_next wraps eina_iterator_next for safe cgo consumption.
+static Eina_Bool _ego_iter_next(Eina_Iterator *iter, void **data) {
+    return eina_iterator_next(iter, data);
+}
+// _ego_iter_free wraps eina_iterator_free.
+static void _ego_iter_free(Eina_Iterator *iter) {
+    eina_iterator_free(iter);
+}
+{{- end}}
+
 {{- range .Properties}}
 {{- if and .HasGet (isPointerType .GoType)}}
 // _ego_get_{{.CGetName}} wraps the getter, casting the return value through
@@ -155,6 +166,9 @@ import "C"
 
 import (
     "unsafe"
+{{- if .HasIterators}}
+    "iter"
+{{- end}}
 
     "git.enlightenment.org/cedric/ego/efl"
 {{- if and .ParentPkg (ne .ParentPkg .PackageName) (ne .ParentPkg "efl")}}
@@ -523,6 +537,51 @@ func (o *{{$.GoName}}) {{.GoName}}(fn func({{if and .PayloadGoType (not (isPoint
 }
 {{- end}}
 
+{{- range $im := .IteratorMethods}}
+
+// {{$im.GoName}} returns an iterator over the results. Use with range:
+//   for v := range obj.{{$im.GoName}}(...) { ... }
+func (o *{{$.GoName}}) {{$im.GoName}}({{range $i, $p := $im.Params}}{{if $i}}, {{end}}{{$p.GoName}} {{if $p.IsEo}}efl.Objecter{{else}}{{$p.GoType}}{{end}}{{end}}) iter.Seq[{{if $im.ElemIsStruct}}{{$im.StructGoType}}{{else if $im.ElemIsEo}}unsafe.Pointer{{else if $im.ElemIsString}}string{{else}}{{$im.ElemGoType}}{{end}}] {
+    return func(yield func({{if $im.ElemIsStruct}}{{$im.StructGoType}}{{else if $im.ElemIsEo}}unsafe.Pointer{{else if $im.ElemIsString}}string{{else}}{{$im.ElemGoType}}{{end}}) bool) {
+{{- range $im.Params}}
+{{- if needsStringConversion .CType}}
+        c{{.GoName}} := C.CString({{.GoName}})
+        defer C.free(unsafe.Pointer(c{{.GoName}}))
+{{- else if isBoolType .CType}}
+        var c{{.GoName}} C.{{cTypeToCgo .CType}}
+        if {{.GoName}} { c{{.GoName}} = 1 }
+{{- end}}
+{{- end}}
+        cIter := C.{{$im.CName}}((*C.Eo)(o.Eo()){{range $im.Params}}, {{template "paramArg" .}}{{end}})
+        if cIter == nil {
+            return
+        }
+        defer C._ego_iter_free(cIter)
+        var data unsafe.Pointer
+        for C._ego_iter_next(cIter, &data) != 0 {
+{{- if $im.ElemIsString}}
+            if !yield(C.GoString((*C.char)(data))) {
+                return
+            }
+{{- else if $im.ElemIsStruct}}
+            _r := (*C.{{$im.StructCType}})(data)
+            if !yield({{$im.StructGoType}}{ {{- range $i, $gf := $im.StructGoFields}}{{if $i}}, {{end}}{{$gf}}: {{if eq (index $im.StructCFieldTypes $i) "double"}}float64{{else}}int{{end}}(_r{{$im.StructCAccessPrefix}}.{{index $im.StructCFields $i}}){{end -}} }) {
+                return
+            }
+{{- else if $im.ElemIsEo}}
+            if !yield(data) {
+                return
+            }
+{{- else}}
+            if !yield({{$im.ElemGoType}}(*(*C.{{cTypeToCgo $im.ElemCType}})(data))) {
+                return
+            }
+{{- end}}
+        }
+    }
+}
+{{- end}}
+
 {{- define "paramArg"}}
 {{- if .IsEo}}(*C.Eo)({{.GoName}}.Eo())
 {{- else if or (needsStringConversion .CType) (isBoolType .CType)}}c{{.GoName}}

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.

Reply via email to