Merge 'bindings/go: Rename to Limbo' from Pekka Enberg

...we'll likely call this Turso eventually, but right now, let's keep
the code consistent.

Reviewed-by: Preston Thorpe (@PThorpe92)

Closes #790
This commit is contained in:
Pekka Enberg
2025-01-26 21:04:43 +02:00
10 changed files with 108 additions and 108 deletions

14
Cargo.lock generated
View File

@@ -1301,6 +1301,13 @@ dependencies = [
"rustyline",
]
[[package]]
name = "limbo-go"
version = "0.0.13"
dependencies = [
"limbo_core",
]
[[package]]
name = "limbo-wasm"
version = "0.0.13"
@@ -2663,13 +2670,6 @@ version = "0.1.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
[[package]]
name = "turso-go"
version = "0.0.13"
dependencies = [
"limbo_core",
]
[[package]]
name = "typenum"
version = "1.17.0"

View File

@@ -1,5 +1,5 @@
[package]
name = "turso-go"
name = "limbo-go"
version.workspace = true
authors.workspace = true
edition.workspace = true
@@ -7,7 +7,7 @@ license.workspace = true
repository.workspace = true
[lib]
name = "_turso_go"
name = "_limbo_go"
crate-type = ["cdylib"]
path = "rs_src/lib.rs"

View File

@@ -1,4 +1,4 @@
module turso
module limbo
go 1.23.4

View File

@@ -1,4 +1,4 @@
package turso
package limbo
import (
"database/sql"
@@ -15,31 +15,31 @@ import (
"golang.org/x/sys/windows"
)
const turso = "../../target/debug/lib_turso_go"
const driverName = "turso"
const limbo = "../../target/debug/lib_limbo_go"
const driverName = "limbo"
var tursoLib uintptr
var limboLib uintptr
func getSystemLibrary() error {
switch runtime.GOOS {
case "darwin":
slib, err := purego.Dlopen(fmt.Sprintf("%s.dylib", turso), purego.RTLD_LAZY)
slib, err := purego.Dlopen(fmt.Sprintf("%s.dylib", limbo), purego.RTLD_LAZY)
if err != nil {
return err
}
tursoLib = slib
limboLib = slib
case "linux":
slib, err := purego.Dlopen(fmt.Sprintf("%s.so", turso), purego.RTLD_LAZY)
slib, err := purego.Dlopen(fmt.Sprintf("%s.so", limbo), purego.RTLD_LAZY)
if err != nil {
return err
}
tursoLib = slib
limboLib = slib
case "windows":
slib, err := windows.LoadLibrary(fmt.Sprintf("%s.dll", turso))
slib, err := windows.LoadLibrary(fmt.Sprintf("%s.dll", limbo))
if err != nil {
return err
}
tursoLib = slib
limboLib = slib
default:
panic(fmt.Errorf("GOOS=%s is not supported", runtime.GOOS))
}
@@ -49,15 +49,15 @@ func getSystemLibrary() error {
func init() {
err := getSystemLibrary()
if err != nil {
slog.Error("Error opening turso library: ", err)
slog.Error("Error opening limbo library: ", err)
os.Exit(1)
}
sql.Register(driverName, &tursoDriver{})
sql.Register(driverName, &limboDriver{})
}
type tursoDriver struct{}
type limboDriver struct{}
func (d tursoDriver) Open(name string) (driver.Conn, error) {
func (d limboDriver) Open(name string) (driver.Conn, error) {
return openConn(name)
}
@@ -66,28 +66,28 @@ func toCString(s string) uintptr {
return uintptr(unsafe.Pointer(&b[0]))
}
// helper to register an FFI function in the lib_turso_go library
// helper to register an FFI function in the lib_limbo_go library
func getFfiFunc(ptr interface{}, name string) {
purego.RegisterLibFunc(&ptr, tursoLib, name)
purego.RegisterLibFunc(&ptr, limboLib, name)
}
type tursoConn struct {
type limboConn struct {
ctx uintptr
sync.Mutex
prepare func(uintptr, uintptr) uintptr
}
func newConn(ctx uintptr) *tursoConn {
func newConn(ctx uintptr) *limboConn {
var prepare func(uintptr, uintptr) uintptr
getFfiFunc(&prepare, FfiDbPrepare)
return &tursoConn{
return &limboConn{
ctx,
sync.Mutex{},
prepare,
}
}
func openConn(dsn string) (*tursoConn, error) {
func openConn(dsn string) (*limboConn, error) {
var dbOpen func(uintptr) uintptr
getFfiFunc(&dbOpen, FfiDbOpen)
@@ -98,10 +98,10 @@ func openConn(dsn string) (*tursoConn, error) {
if ctx == 0 {
return nil, fmt.Errorf("failed to open database for dsn=%q", dsn)
}
return &tursoConn{ctx: ctx}, nil
return &limboConn{ctx: ctx}, nil
}
func (c *tursoConn) Close() error {
func (c *limboConn) Close() error {
if c.ctx == 0 {
return nil
}
@@ -113,7 +113,7 @@ func (c *tursoConn) Close() error {
return nil
}
func (c *tursoConn) Prepare(query string) (driver.Stmt, error) {
func (c *limboConn) Prepare(query string) (driver.Stmt, error) {
if c.ctx == 0 {
return nil, errors.New("connection closed")
}
@@ -129,13 +129,13 @@ func (c *tursoConn) Prepare(query string) (driver.Stmt, error) {
if stmtPtr == 0 {
return nil, fmt.Errorf("prepare failed: %q", query)
}
return &tursoStmt{
return &limboStmt{
ctx: stmtPtr,
sql: query,
}, nil
}
// begin is needed to implement driver.Conn.. for now not implemented
func (c *tursoConn) Begin() (driver.Tx, error) {
func (c *limboConn) Begin() (driver.Tx, error) {
return nil, errors.New("transactions not implemented")
}

View File

@@ -28,7 +28,7 @@ pub unsafe extern "C" fn db_open(path: *const c_char) -> *mut c_void {
Ok(db) => {
println!("Opened database: {}", path);
let conn = db.connect();
return TursoConn::new(conn, io).to_ptr();
return LimboConn::new(conn, io).to_ptr();
}
Err(e) => {
println!("Error opening database: {}", e);
@@ -40,25 +40,25 @@ pub unsafe extern "C" fn db_open(path: *const c_char) -> *mut c_void {
}
#[allow(dead_code)]
struct TursoConn {
struct LimboConn {
conn: Rc<Connection>,
io: Arc<dyn limbo_core::IO>,
}
impl TursoConn {
impl LimboConn {
fn new(conn: Rc<Connection>, io: Arc<dyn limbo_core::IO>) -> Self {
TursoConn { conn, io }
LimboConn { conn, io }
}
#[allow(clippy::wrong_self_convention)]
fn to_ptr(self) -> *mut c_void {
Box::into_raw(Box::new(self)) as *mut c_void
}
fn from_ptr(ptr: *mut c_void) -> &'static mut TursoConn {
fn from_ptr(ptr: *mut c_void) -> &'static mut LimboConn {
if ptr.is_null() {
panic!("Null pointer");
}
unsafe { &mut *(ptr as *mut TursoConn) }
unsafe { &mut *(ptr as *mut LimboConn) }
}
}
@@ -68,7 +68,7 @@ impl TursoConn {
#[no_mangle]
pub unsafe extern "C" fn db_close(db: *mut c_void) {
if !db.is_null() {
let _ = unsafe { Box::from_raw(db as *mut TursoConn) };
let _ = unsafe { Box::from_raw(db as *mut LimboConn) };
}
}

View File

@@ -1,19 +1,19 @@
use crate::{
statement::TursoStatement,
types::{ResultCode, TursoValue},
statement::LimboStatement,
types::{LimboValue, ResultCode},
};
use limbo_core::{Statement, StepResult, Value};
use std::ffi::{c_char, c_void};
pub struct TursoRows<'a> {
pub struct LimboRows<'a> {
rows: Statement,
cursor: Option<Vec<Value<'a>>>,
stmt: Box<TursoStatement<'a>>,
stmt: Box<LimboStatement<'a>>,
}
impl<'a> TursoRows<'a> {
pub fn new(rows: Statement, stmt: Box<TursoStatement<'a>>) -> Self {
TursoRows {
impl<'a> LimboRows<'a> {
pub fn new(rows: Statement, stmt: Box<LimboStatement<'a>>) -> Self {
LimboRows {
rows,
stmt,
cursor: None,
@@ -25,11 +25,11 @@ impl<'a> TursoRows<'a> {
Box::into_raw(Box::new(self)) as *mut c_void
}
pub fn from_ptr(ptr: *mut c_void) -> &'static mut TursoRows<'a> {
pub fn from_ptr(ptr: *mut c_void) -> &'static mut LimboRows<'a> {
if ptr.is_null() {
panic!("Null pointer");
}
unsafe { &mut *(ptr as *mut TursoRows) }
unsafe { &mut *(ptr as *mut LimboRows) }
}
}
@@ -38,7 +38,7 @@ pub extern "C" fn rows_next(ctx: *mut c_void) -> ResultCode {
if ctx.is_null() {
return ResultCode::Error;
}
let ctx = TursoRows::from_ptr(ctx);
let ctx = LimboRows::from_ptr(ctx);
match ctx.rows.step() {
Ok(StepResult::Row(row)) => {
@@ -61,11 +61,11 @@ pub extern "C" fn rows_get_value(ctx: *mut c_void, col_idx: usize) -> *const c_v
if ctx.is_null() {
return std::ptr::null();
}
let ctx = TursoRows::from_ptr(ctx);
let ctx = LimboRows::from_ptr(ctx);
if let Some(ref cursor) = ctx.cursor {
if let Some(value) = cursor.get(col_idx) {
let val = TursoValue::from_value(value);
let val = LimboValue::from_value(value);
return val.to_ptr();
}
}
@@ -87,7 +87,7 @@ pub extern "C" fn rows_get_columns(
if rows_ptr.is_null() || out_length.is_null() {
return std::ptr::null_mut();
}
let rows = TursoRows::from_ptr(rows_ptr);
let rows = LimboRows::from_ptr(rows_ptr);
let c_strings: Vec<std::ffi::CString> = rows
.rows
.columns()
@@ -108,7 +108,7 @@ pub extern "C" fn rows_get_columns(
#[no_mangle]
pub extern "C" fn rows_close(rows_ptr: *mut c_void) {
if !rows_ptr.is_null() {
let _ = unsafe { Box::from_raw(rows_ptr as *mut TursoRows) };
let _ = unsafe { Box::from_raw(rows_ptr as *mut LimboRows) };
}
}

View File

@@ -1,6 +1,6 @@
use crate::rows::TursoRows;
use crate::types::{AllocPool, ResultCode, TursoValue};
use crate::TursoConn;
use crate::rows::LimboRows;
use crate::types::{AllocPool, LimboValue, ResultCode};
use crate::LimboConn;
use limbo_core::{Statement, StepResult};
use std::ffi::{c_char, c_void};
use std::num::NonZero;
@@ -12,11 +12,11 @@ pub extern "C" fn db_prepare(ctx: *mut c_void, query: *const c_char) -> *mut c_v
}
let query_str = unsafe { std::ffi::CStr::from_ptr(query) }.to_str().unwrap();
let db = TursoConn::from_ptr(ctx);
let db = LimboConn::from_ptr(ctx);
let stmt = db.conn.prepare(query_str.to_string());
match stmt {
Ok(stmt) => TursoStatement::new(stmt, db).to_ptr(),
Ok(stmt) => LimboStatement::new(stmt, db).to_ptr(),
Err(_) => std::ptr::null_mut(),
}
}
@@ -24,14 +24,14 @@ pub extern "C" fn db_prepare(ctx: *mut c_void, query: *const c_char) -> *mut c_v
#[no_mangle]
pub extern "C" fn stmt_execute(
ctx: *mut c_void,
args_ptr: *mut TursoValue,
args_ptr: *mut LimboValue,
arg_count: usize,
changes: *mut i64,
) -> ResultCode {
if ctx.is_null() {
return ResultCode::Error;
}
let stmt = TursoStatement::from_ptr(ctx);
let stmt = LimboStatement::from_ptr(ctx);
let args = if !args_ptr.is_null() && arg_count > 0 {
unsafe { std::slice::from_raw_parts(args_ptr, arg_count) }
@@ -78,20 +78,20 @@ pub extern "C" fn stmt_parameter_count(ctx: *mut c_void) -> i32 {
if ctx.is_null() {
return -1;
}
let stmt = TursoStatement::from_ptr(ctx);
let stmt = LimboStatement::from_ptr(ctx);
stmt.statement.parameters_count() as i32
}
#[no_mangle]
pub extern "C" fn stmt_query(
ctx: *mut c_void,
args_ptr: *mut TursoValue,
args_ptr: *mut LimboValue,
args_count: usize,
) -> *mut c_void {
if ctx.is_null() {
return std::ptr::null_mut();
}
let stmt = TursoStatement::from_ptr(ctx);
let stmt = LimboStatement::from_ptr(ctx);
let args = if !args_ptr.is_null() && args_count > 0 {
unsafe { std::slice::from_raw_parts(args_ptr, args_count) }
} else {
@@ -104,21 +104,21 @@ pub extern "C" fn stmt_query(
match stmt.statement.query() {
Ok(rows) => {
let stmt = unsafe { Box::from_raw(stmt) };
TursoRows::new(rows, stmt).to_ptr()
LimboRows::new(rows, stmt).to_ptr()
}
Err(_) => std::ptr::null_mut(),
}
}
pub struct TursoStatement<'conn> {
pub struct LimboStatement<'conn> {
pub statement: Statement,
pub conn: &'conn mut TursoConn,
pub conn: &'conn mut LimboConn,
pub pool: AllocPool,
}
impl<'conn> TursoStatement<'conn> {
pub fn new(statement: Statement, conn: &'conn mut TursoConn) -> Self {
TursoStatement {
impl<'conn> LimboStatement<'conn> {
pub fn new(statement: Statement, conn: &'conn mut LimboConn) -> Self {
LimboStatement {
statement,
conn,
pool: AllocPool::new(),
@@ -130,10 +130,10 @@ impl<'conn> TursoStatement<'conn> {
Box::into_raw(Box::new(self)) as *mut c_void
}
fn from_ptr(ptr: *mut c_void) -> &'static mut TursoStatement<'conn> {
fn from_ptr(ptr: *mut c_void) -> &'static mut LimboStatement<'conn> {
if ptr.is_null() {
panic!("Null pointer");
}
unsafe { &mut *(ptr as *mut TursoStatement) }
unsafe { &mut *(ptr as *mut LimboStatement) }
}
}

View File

@@ -26,7 +26,7 @@ pub enum ValueType {
}
#[repr(C)]
pub struct TursoValue {
pub struct LimboValue {
pub value_type: ValueType,
pub value: ValueUnion,
}
@@ -131,9 +131,9 @@ impl ValueUnion {
}
}
impl TursoValue {
impl LimboValue {
pub fn new(value_type: ValueType, value: ValueUnion) -> Self {
TursoValue { value_type, value }
LimboValue { value_type, value }
}
#[allow(clippy::wrong_self_convention)]
@@ -144,16 +144,16 @@ impl TursoValue {
pub fn from_value(value: &limbo_core::Value<'_>) -> Self {
match value {
limbo_core::Value::Integer(i) => {
TursoValue::new(ValueType::Integer, ValueUnion::from_int(*i))
LimboValue::new(ValueType::Integer, ValueUnion::from_int(*i))
}
limbo_core::Value::Float(r) => {
TursoValue::new(ValueType::Real, ValueUnion::from_real(*r))
LimboValue::new(ValueType::Real, ValueUnion::from_real(*r))
}
limbo_core::Value::Text(s) => TursoValue::new(ValueType::Text, ValueUnion::from_str(s)),
limbo_core::Value::Text(s) => LimboValue::new(ValueType::Text, ValueUnion::from_str(s)),
limbo_core::Value::Blob(b) => {
TursoValue::new(ValueType::Blob, ValueUnion::from_bytes(b))
LimboValue::new(ValueType::Blob, ValueUnion::from_bytes(b))
}
limbo_core::Value::Null => TursoValue::new(ValueType::Null, ValueUnion::from_null()),
limbo_core::Value::Null => LimboValue::new(ValueType::Null, ValueUnion::from_null()),
}
}

View File

@@ -1,4 +1,4 @@
package turso
package limbo
import (
"context"
@@ -9,8 +9,8 @@ import (
"unsafe"
)
// only construct tursoStmt with initStmt function to ensure proper initialization
type tursoStmt struct {
// only construct limboStmt with initStmt function to ensure proper initialization
type limboStmt struct {
ctx uintptr
sql string
query stmtQueryFn
@@ -19,7 +19,7 @@ type tursoStmt struct {
}
// Initialize/register the FFI function pointers for the statement methods
func initStmt(ctx uintptr, sql string) *tursoStmt {
func initStmt(ctx uintptr, sql string) *limboStmt {
var query stmtQueryFn
var execute stmtExecuteFn
var getParamCount func(uintptr) int32
@@ -27,17 +27,17 @@ func initStmt(ctx uintptr, sql string) *tursoStmt {
for i := range methods {
methods[i].initFunc()
}
return &tursoStmt{
return &limboStmt{
ctx: uintptr(ctx),
sql: sql,
}
}
func (st *tursoStmt) NumInput() int {
func (st *limboStmt) NumInput() int {
return int(st.getParamCount(st.ctx))
}
func (st *tursoStmt) Exec(args []driver.Value) (driver.Result, error) {
func (st *limboStmt) Exec(args []driver.Value) (driver.Result, error) {
argArray, err := buildArgs(args)
if err != nil {
return nil, err
@@ -65,7 +65,7 @@ func (st *tursoStmt) Exec(args []driver.Value) (driver.Result, error) {
}
}
func (st *tursoStmt) Query(args []driver.Value) (driver.Rows, error) {
func (st *limboStmt) Query(args []driver.Value) (driver.Rows, error) {
queryArgs, err := buildArgs(args)
if err != nil {
return nil, err
@@ -77,7 +77,7 @@ func (st *tursoStmt) Query(args []driver.Value) (driver.Rows, error) {
return initRows(rowsPtr), nil
}
func (ts *tursoStmt) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
func (ts *limboStmt) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
stripped := namedValueToValue(args)
argArray, err := getArgsPtr(stripped)
if err != nil {
@@ -99,7 +99,7 @@ func (ts *tursoStmt) ExecContext(ctx context.Context, query string, args []drive
}
}
func (st *tursoStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
func (st *limboStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
queryArgs, err := buildNamedArgs(args)
if err != nil {
return nil, err
@@ -111,8 +111,8 @@ func (st *tursoStmt) QueryContext(ctx context.Context, args []driver.NamedValue)
return initRows(rowsPtr), nil
}
// only construct tursoRows with initRows function to ensure proper initialization
type tursoRows struct {
// only construct limboRows with initRows function to ensure proper initialization
type limboRows struct {
ctx uintptr
columns []string
closed bool
@@ -124,8 +124,8 @@ type tursoRows struct {
}
// Initialize/register the FFI function pointers for the rows methods
// DO NOT construct 'tursoRows' without this function
func initRows(ctx uintptr) *tursoRows {
// DO NOT construct 'limboRows' without this function
func initRows(ctx uintptr) *limboRows {
var getCols func(uintptr, *uint) uintptr
var getValue func(uintptr, int32) uintptr
var closeRows func(uintptr) uintptr
@@ -141,7 +141,7 @@ func initRows(ctx uintptr) *tursoRows {
methods[i].initFunc()
}
return &tursoRows{
return &limboRows{
ctx: ctx,
getCols: getCols,
getValue: getValue,
@@ -151,7 +151,7 @@ func initRows(ctx uintptr) *tursoRows {
}
}
func (r *tursoRows) Columns() []string {
func (r *limboRows) Columns() []string {
if r.columns == nil {
var columnCount uint
colArrayPtr := r.getCols(r.ctx, &columnCount)
@@ -166,7 +166,7 @@ func (r *tursoRows) Columns() []string {
return r.columns
}
func (r *tursoRows) Close() error {
func (r *limboRows) Close() error {
if r.closed {
return nil
}
@@ -176,7 +176,7 @@ func (r *tursoRows) Close() error {
return nil
}
func (r *tursoRows) Next(dest []driver.Value) error {
func (r *limboRows) Next(dest []driver.Value) error {
status := r.next(r.ctx)
switch ResultCode(status) {
case Row:

View File

@@ -1,4 +1,4 @@
package turso
package limbo
import (
"database/sql/driver"
@@ -47,7 +47,7 @@ func namedValueToValue(named []driver.NamedValue) []driver.Value {
return out
}
func buildNamedArgs(named []driver.NamedValue) ([]tursoValue, error) {
func buildNamedArgs(named []driver.NamedValue) ([]limboValue, error) {
args := make([]driver.Value, len(named))
for i, nv := range named {
args[i] = nv.Value
@@ -75,7 +75,7 @@ const (
)
// struct to pass Go values over FFI
type tursoValue struct {
type limboValue struct {
Type valueType
Value [8]byte
}
@@ -86,9 +86,9 @@ type Blob struct {
Len uint
}
// convert a tursoValue to a native Go value
// convert a limboValue to a native Go value
func toGoValue(valPtr uintptr) interface{} {
val := (*tursoValue)(unsafe.Pointer(valPtr))
val := (*limboValue)(unsafe.Pointer(valPtr))
switch val.Type {
case intVal:
return *(*int64)(unsafe.Pointer(&val.Value))
@@ -169,9 +169,9 @@ func cArrayToGoStrings(arrayPtr uintptr, length uint) []string {
return out
}
// convert a Go slice of driver.Value to a slice of tursoValue that can be sent over FFI
func buildArgs(args []driver.Value) ([]tursoValue, error) {
argSlice := make([]tursoValue, len(args))
// convert a Go slice of driver.Value to a slice of limboValue that can be sent over FFI
func buildArgs(args []driver.Value) ([]limboValue, error) {
argSlice := make([]limboValue, len(args))
for i, v := range args {
switch val := v.(type) {