Back to Turso

Bindings

bindings/go/go-bindings-db.mdx

0.5.35.9 KB
Original Source
<Output path="./bindings_db.go"> <Code model="openai/gpt-5" language="go">

Generate Go functions bindings for the Turso - SQLite-compatible embedded database written in Rust. You must use C API bridge implemented in Rust which expose ABI compatible functions to interact with the database.

The main goal is to translate C code to Go-friendly bindings which will have no additional logic, but more ergonomic API:

  1. Return (err error) when possible
  2. Manipulate with strings accordingly

Bindings

You must generate bindings for C interface defined in turso.h file:

<File path="../../sdk-kit/turso.h" />

Rules

General rules for driver implementation you MUST follow and never go against these rules:

  • DO NOT USE cgo, USE purego instead
  • DO NOT introduce any new public methods - export turso.h content as-is
  • DO NOT register library - this will be done externally
  • AVOID unnecessary FFI calls as their cost is non zero
  • AVOID unnecessary strings transformations - replace them with more efficient alternatives if possible
  • DO NOT ever mix turso_statement_execute and turso_statement_step methods: every statement must be either "stepped" or "executed"
    • This is because execute ignores all rows
  • SQL query can be arbitrary, be very careful writing the code which relies on properties derived from the simple string analysis
  • FOCUS on code readability: if possible extract helper function but make sure that it will be used more than once and that it really contribute to the code readability
  • WATCH OUT for variables scopes and do not use variables which are no longer accessible
  • WATCH OUT for string representations: in some cases library expected zero terminated C-string and in some cases library operates with string/byte slices
  • BE AWARE, that purego marshal only explicit parameters of the function calls. If you have C struct passed by reference - you need to do marshalling by yourself (e.g. convert strings to zero-terminated C strings, etc)
  • STRUCTURE of the implementation
    • Declaration order of elements and semantic blocks MUST be exsactly the same
    • (details and full enumerations omited in the example for brevity but you must generate full code)
go
package turso

// define all package level errors here

// note, that OK, DONE, ROW, IO are statuses - so you don't need to create errors for them
var (
    TursoBusyErr = errors.New("turso: database is busy") // provide short but concise error message
    ...
)

// define all necessary constants first
type TursoStatusCode int32

// note, that the only real statuses are OK, DONE, ROW, IO - everything else is errors
const (
	TURSO_OK TursoStatusCode = 0
    ...
)

type TursoType int32

const (
	TURSO_TYPE_INTEGER TursoType = 1
    ...
)

// define opaque pointers as-is and accept them as exact arguments (e.g. func turso_database_connect(self TursoDatabase) ... - DO NOT add extra indirection)
type TursoDatabase *turso_database_t

// define all public binding types
// the public binding types MUST have fields with native safe go types 
type TursoConfig struct { ... }

// define all necessary private C structs
// private C structs MUST have fields with low level types (e.g. uintptr, numbers)
type turso_config_t struct { ... }

// then, define C extern methods
var (
    // always use c_ structs here - never mix them with exported public types
	c_turso_setup                                 func(config turso_config_t) turso_status_code_t
    ...
)

// implement a function to register extern methods from loaded lib
// DO NOT load lib - as it will be done externally
func register_turso_db(handle uintptr) error {
    purego.RegisterLibFunc(&c_turso_setup, handle, "turso_setup")
    ...
}

// Go wrappers over imported C bindings
// always use exported public types here - never mix them with c_ structs
func turso_setup(config TursoConig) error { ... }

Implementation

  • The package name is "github.com/tursodatabase/turso/go"
  • Use exactly same names as in turso.h for Go method names and prepend c_ prefix for C extern functions
  • Separate "public" types from "private" types:
    • public types MUST be used ONLY in Go bindings methods (turso_.*) and have fields with native safe go types (string, slice, etc)
    • public types MUST NOT use low level types explicitly (e.g. unintptr) - they must be either replaced with wrapper public type or native alternative must be used instead (e.g. int instead of uinptrt if this is size_t)
    • private types MUST be used ONLY in C wrapper functions (c_turso_.*) and have fields with low-level C-compatible go types (uintptr, numbers, etc)
  • Document generated methods with docstrings
  • Replace turso_status_code_t and out error parameter with proper native golang error
    • If function returns only OK or error code, do not return status explicitly from the Go binding - just return error (and any value if it was returned as out parameter)
  • Convert C-strings back and forth appropriately
    • Remember, that Golang strings are not null-terminated - so you will need to convert them to zero-terminated strings by copying data in some cases
  • Support callback in turso_setup with purego.NewCallback
  • Make one exception and implement turso_statement_row_value_bytes and turso_statement_row_value_text methods which will use c_turso_statement_row_value_bytes_ptr and c_turso_statement_row_value_bytes_count extern methods under the hood
    • This MUST be the only non-direct translation of C extern functions

Purego

Inspect following docstring from the official purego repository in order to understand how marshalling works:

<Link url="https://raw.githubusercontent.com/ebitengine/purego/refs/heads/main/func.go" selector="RegisterFunc#comment" /> <Link url="https://raw.githubusercontent.com/ebitengine/purego/refs/heads/main/func.go" selector="RegisterLibFunc#comment" /> <Link url="https://raw.githubusercontent.com/ebitengine/purego/refs/heads/main/syscall_sysv.go" selector="NewCallback#comment" /> </Code> </Output>