Lindenii Project Forge
Login

hare-lmdb

Hare bindings for LMDB
Commit info
ID
44a437178d8e3839895e36deda9b324586185cad
Author
Runxi Yu <me@runxiyu.org>
Author date
Sun, 10 Aug 2025 08:54:19 +0800
Committer
Runxi Yu <me@runxiyu.org>
Committer date
Sun, 10 Aug 2025 08:54:19 +0800
Actions
Support nomem
use fmt;
use io;
use lmdb_ffi = lmdb::ffi;
use lmdb;
use strings;
use types;
use types::c;
use os;

export fn main() void = {
	if (len(os::args) != 3) {
		fmt::fprintln(os::stderr, "need two arguments (db dir, key)")!;
		return;
	};

	match (real()) {
	case void => void;
	case let e: lmdb::error =>
		fmt::fprintln(os::stderr, lmdb::strerror(e))!;
	case let e: io::error =>
		fmt::fprintln(os::stderr, io::strerror(e))!;
	case nomem =>
		fmt::fprintln(os::stderr, "OOM")!;
	};
};

export fn real() (void | lmdb::error | io::error) = {
export fn real() (void | lmdb::error | io::error | nomem) = {
	const key = lmdb::val{
		mv_size = len(strings::toutf8(os::args[2])),
		mv_data = c::unterminatedstr(os::args[2]): *opaque,
	};

	let env = lmdb::env_create()?;

	lmdb::env_open(env, os::args[1], 0, 0o644)?;

	let txn = lmdb::txn_begin(env, 0)?;

	let dbi = lmdb::dbi_open(txn, null, lmdb_ffi::CREATE)?;

	let val = lmdb::get(dbi, &key)?;

	let data = lmdb::val_u8s(&val);

	io::write(os::stdout, data)?;

	lmdb::txn_abort(txn)?;
};
use fmt;
use io;
use lmdb;
use lmdb_ffi = lmdb::ffi;
use strings;
use types;
use types::c;
use os;

export fn main() void = {
	if (len(os::args) != 3) {
		fmt::fprintln(os::stderr, "need two arguments (db dir, key)")!;
		return;
	};

	match (real()) {
	case void => void;
	case let e: lmdb::error =>
		fmt::fprintln(os::stderr, lmdb::strerror(e))!;
	case let e: io::error =>
		fmt::fprintln(os::stderr, io::strerror(e))!;
	case nomem =>
		fmt::fprintln(os::stderr, "OOM")!;
	};
};

export fn real() (void | lmdb::error | io::error) = {
export fn real() (void | lmdb::error | io::error | nomem) = {
	const key = lmdb::val {
		mv_size = len(strings::toutf8(os::args[2])),
		mv_data = c::unterminatedstr(os::args[2]): *opaque,
	};
	

	let v = io::drain(os::stdin)!;
	defer free(v);

	const val = lmdb::u8s_val(v);

	let env = lmdb::env_create()?;

	lmdb::env_open(env, os::args[1], 0, 0o644)?;

	let txn = lmdb::txn_begin(env, 0)?;

	let dbi = lmdb::dbi_open(txn, null, lmdb_ffi::CREATE)?;

	let val = lmdb::put(dbi, &key, &val, 0)?;

	lmdb::txn_commit(txn)?;
};
use lmdb::ffi;
use types::c;

// An individual LMDB database, i.e. one key-value store.
//
// They are only valid for the lifetime of their parent transaction.
export type dbi = struct {
	txn: *ffi::txn,
	dbi: ffi::dbi,
};

// Opens a database from a transaction.
export fn dbi_open(txn: *txn, name: nullable *str, flags: uint) (dbi | error) = {
export fn dbi_open(txn: *txn, name: nullable *str, flags: uint) (dbi | error | nomem) = {
	const n: nullable *c::char = match (name) {
	case *str => yield c::fromstr(*(name as *str));
	case *str => yield c::fromstr(*(name as *str))?;
	case null => yield null;
	};
	defer free(n);

	let d: ffi::dbi = 0;

	const rc = ffi::dbi_open(txn: *ffi::txn, n, flags, &d): error;

	switch (rc) {
	case 0 =>
		return dbi {
			txn = txn: *ffi::txn,
			dbi = d,
		};
	case =>
		return rc;
	};
};

// Get a value from the database. The returned value is only valid for the
// lifetime of the transaction associated with the dbi.
export fn get(dbi: dbi, key: *val) (val | error) = {
	let data = ffi::val {
		mv_size = 0,
		mv_data = null,
	};

	const rc = ffi::get(dbi.txn, dbi.dbi, key: *ffi::val, &data): error;

	switch (rc) {
	case 0 => return data: val;
	case => return rc;
	};
};

// Put a value into the database.
export fn put(dbi: dbi, key: *val, data: *val, flags: uint) (void | error) = {
	const rc = ffi::put(dbi.txn, dbi.dbi, key: *ffi::val, data: *ffi::val, flags): error;

	switch (rc) {
	case 0 => return void;
	case => return rc;
	};
};
use lmdb::ffi;
use types::c;

// Opaque structure for a database environment.
//
// A DB environment supports multiple databases, all residing in the same
// shared-memory map.
export type env = ffi::env;

// Creates an [[env]]. The caller must free it with [[env_close]].
export fn env_create() (*env | error) = {
	let e: nullable *ffi::env = null;

	const rc = ffi::env_create(&e): error;

	switch (rc) {
	case 0 => return e: *env;
	case => return rc;
	};
};

// Closes an [[env]].
export fn env_close(env: *env) void = {
	ffi::env_close(env: *ffi::env);
};

// Associates an [[env]] with a on-disk environment.
export fn env_open(env: *env, path: str, flag: uint, mode: u32) (void | error) = {
	const p = c::fromstr(path);
export fn env_open(env: *env, path: str, flag: uint, mode: u32) (void | error | nomem) = {
	const p = c::fromstr(path)?;
	defer free(p);

	const rc = ffi::env_open(env: *ffi::env, p, flag, mode): error;

	return switch (rc) {
	case 0 => yield;
	case => yield rc;
	};
};