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.