feat: add go bindings package

What does this MR do and why?

Adds go bindings package:

  • adds Go module so the indexer can be seamlessly called from Go
  • updates CI to build c_bindings static lib as part of the release
  • adds CI test for building/using go bindings

This thin go package can be used when using knowledge graph from Go.

Related Issues

Related to gitlab-org/gitlab-zoekt-indexer#90 (closed)

Testing

Go test(s) can be either executed in CI by triggering "build-bindings" job, or executed locally with:

mise build_lib
cd bindings/go/indexer
go test

Also it can be tested with a simple program:

package main

import "gitlab.com/gitlab-org/rust/knowledge-graph/bindings/go/indexer"

const RepoDir = "/home/honza/tmp/repos/repo-small"
const DbDir = "/home/honza/tmp/kuzu_dbs/repo1"

func main() {
	indexer.FullIndex(RepoDir, DbDir, "/tmp/parquet", 1)
}

Also may be necessary to replace the package with local version:

honza@jprovaznik--181201391-Z5N94 ~/dev/binding-test (master)$ cat go.mod
module main

go 1.24.5

require (
    gitlab.com/gitlab-org/rust/knowledge-graph/bindings/go v0.0.0-00010101000000-000000000000 // indirect
)

replace gitlab.com/gitlab-org/rust/knowledge-graph/bindings/go => ../../dev/knowledge-graph/bindings/go

Performance Analysis

Performance Checklist

  • Have you reviewed your memory allocations to ensure you're optimizing correctly? Are you cloning or copying unnecessary data?
  • Have you profiled with cargo bench or criterion to measure performance impact?
  • Are you using zero-copy operations where possible (e.g., &str instead of String, slice references)?
  • Have you considered using Cow<'_, T> for conditional ownership to avoid unnecessary clones?
  • Are iterator chains and lazy evaluation being used effectively instead of intermediate collections?
  • Are you reusing allocations where possible (e.g., Vec::clear() and reuse vs new allocation)?
  • Have you considered using SmallVec or similar for small, stack-allocated collections?
  • Are async operations properly structured to avoid blocking the executor?
  • Have you reviewed unsafe code blocks for both safety and performance implications?
  • Are you using appropriate data structures (e.g., HashMap vs BTreeMap vs IndexMap)?
  • Have you considered compile-time optimizations (e.g., const fn, generics instead of trait objects)?
  • Are debug assertions (debug_assert!) used instead of runtime checks where appropriate?
Edited by Jan Provaznik

Merge request reports

Loading