commit ac56f5e6c8bc683582afe51a94ab4fef6e5b6af2 Author: mappu Date: Tue May 16 19:34:54 2017 +1200 initial commit diff --git a/.hgignore b/.hgignore new file mode 100644 index 0000000..cc4f7df --- /dev/null +++ b/.hgignore @@ -0,0 +1,3 @@ +mode:regex + +^build-qbolt- diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d799a7f --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ + +.PHONY: all clean + +all: qbolt.o + +clean: + if [ -f qbolt.o ] ; then rm qbolt.o ; fi + if [ -f qbolt ] ; then rm qbolt ; fi + +qbolt.o: *.go + go build -ldflags='-s -w' -buildmode=c-shared -o qbolt.o diff --git a/MemoryStore.go b/MemoryStore.go new file mode 100644 index 0000000..b508229 --- /dev/null +++ b/MemoryStore.go @@ -0,0 +1,46 @@ +package main + +import "C" +import ( + "errors" + "sync" +) + +type ObjectReference int64 + +var NullObjectReference error = errors.New("Null object reference") + +// GoMemoryStore is a int->interface storage structure so that Go pointers are +// never exposed to C code. +type GoMemoryStore struct { + mtx sync.RWMutex + items map[int64]interface{} + next int64 +} + +func (this *GoMemoryStore) Put(itm interface{}) ObjectReference { + this.mtx.Lock() + defer this.mtx.Unlock() + + key := this.next + this.items[key] = itm + this.next++ + return ObjectReference(key) +} + +func (this *GoMemoryStore) Get(i ObjectReference) (interface{}, bool) { + this.mtx.RLock() + defer this.mtx.RUnlock() + + ret, ok := this.items[int64(i)] + return ret, ok +} + +func (this *GoMemoryStore) Delete(i ObjectReference) { + this.mtx.Lock() + defer this.mtx.Unlock() + + delete(this.items, int64(i)) +} + +var gms GoMemoryStore diff --git a/main.go b/main.go new file mode 100644 index 0000000..a3e57a5 --- /dev/null +++ b/main.go @@ -0,0 +1,135 @@ +package main + +import "C" +import ( + "errors" + "os" + + "github.com/boltdb/bolt" +) + +//export Bolt_Options_New +func Bolt_Options_New() ObjectReference { + b := *bolt.DefaultOptions + + return gms.Put(&b) +} + +//export Bolt_Options_New_Readonly +func Bolt_Options_New_Readonly() ObjectReference { + b := *bolt.DefaultOptions + b.ReadOnly = true + + return gms.Put(&b) +} + +//export Recall +func Recall(f func(a int64) int64) int64 { + return f(3) +} + +//export Bolt_Open +func Bolt_Open(path string, mode uint32, opts ObjectReference) (ObjectReference, error) { + optsIFC, ok := gms.Get(opts) + if !ok { + return 0, NullObjectReference + } + + ptrBoltOps, ok := optsIFC.(*bolt.Options) + if !ok { + return 0, NullObjectReference + } + + ptrDB, err := bolt.Open(path, os.FileMode(mode), ptrBoltOps) + if err != nil { + return 0, err + } + + dbRef := gms.Put(ptrDB) + return dbRef, nil +} + +func withBoltDBReference(b ObjectReference, fn func(db *bolt.DB) error) error { + dbIFC, ok := gms.Get(b) + if !ok { + return NullObjectReference + } + + ptrDB, ok := dbIFC.(*bolt.DB) + if !ok { + return NullObjectReference + } + + return fn(ptrDB) +} + +//export Error_Error +func Error_Error(e error) string { + return e.Error() +} + +//export Bolt_ListBuckets +func Bolt_ListBuckets(b ObjectReference, browse []string, withEach func(string)) error { + if len(browse) == 0 { + return Bolt_ListBucketsAtRoot(b, withEach) + } + + err := withBoltDBReference(b, func(db *bolt.DB) error { + return db.View(func(tx *bolt.Tx) error { + + bucket := tx.Bucket([]byte(browse[0])) + if bucket == nil { + return errors.New("Unknown bucket") + } + + for i := 1; i < len(browse); i += 1 { + bucket = bucket.Bucket([]byte(browse[i])) + if bucket == nil { + return errors.New("Unknown bucket") + } + } + + return bucket.ForEach(func(k, v []byte) error { + + withEach(string(k)) + return nil + }) + + }) + }) + return err +} + +//export Bolt_ListBucketsAtRoot +func Bolt_ListBucketsAtRoot(b ObjectReference, withEach func(string)) error { + err := withBoltDBReference(b, func(db *bolt.DB) error { + return db.View(func(tx *bolt.Tx) error { + + return tx.ForEach(func(n []byte, bucket *bolt.Bucket) error { + + withEach(string(n)) + return nil + }) + + }) + }) + return err +} + +//export Bolt_Close +func Bolt_Close(b ObjectReference) error { + err := withBoltDBReference(b, func(db *bolt.DB) error { + return db.Close() + }) + + if err != nil { + return err + } + + gms.Delete(b) + return nil +} + +func main() { + // virtual +} diff --git a/qbolt.h b/qbolt.h new file mode 100644 index 0000000..4f11c33 --- /dev/null +++ b/qbolt.h @@ -0,0 +1,79 @@ +/* Created by "go tool cgo" - DO NOT EDIT. */ + +/* package code.ivysaur.me/qbolt */ + +/* Start of preamble from import "C" comments. */ + + + + +/* End of preamble from import "C" comments. */ + + +/* Start of boilerplate cgo prologue. */ + +#ifndef GO_CGO_PROLOGUE_H +#define GO_CGO_PROLOGUE_H + +typedef signed char GoInt8; +typedef unsigned char GoUint8; +typedef short GoInt16; +typedef unsigned short GoUint16; +typedef int GoInt32; +typedef unsigned int GoUint32; +typedef long long GoInt64; +typedef unsigned long long GoUint64; +typedef GoInt64 GoInt; +typedef GoUint64 GoUint; +typedef __SIZE_TYPE__ GoUintptr; +typedef float GoFloat32; +typedef double GoFloat64; +typedef float _Complex GoComplex64; +typedef double _Complex GoComplex128; + +/* + static assertion to make sure the file is being used on architecture + at least with matching size of GoInt. +*/ +typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1]; + +typedef struct { const char *p; GoInt n; } GoString; +typedef void *GoMap; +typedef void *GoChan; +typedef struct { void *t; void *v; } GoInterface; +typedef struct { void *data; GoInt len; GoInt cap; } GoSlice; + +#endif + +/* End of boilerplate cgo prologue. */ + +#ifdef __cplusplus +extern "C" { +#endif + + +extern GoInt64 Bolt_Options_New(); + +extern GoInt64 Bolt_Options_New_Readonly(); + +extern GoInt64 Recall(void* p0); + +/* Return type for Bolt_Open */ +struct Bolt_Open_return { + GoInt64 r0; + GoInterface r1; +}; + +extern struct Bolt_Open_return Bolt_Open(GoString p0, GoUint32 p1, GoInt64 p2); + +extern GoString Error_Error(GoInterface p0); + +extern GoInterface Bolt_ListBuckets(GoInt64 p0, GoSlice p1, void* p2); + +extern GoInterface Bolt_ListBucketsAtRoot(GoInt64 p0, void* p1); + +extern GoInterface Bolt_Close(GoInt64 p0); + +#ifdef __cplusplus +} +#endif diff --git a/qbolt.o b/qbolt.o new file mode 100644 index 0000000..3bb95a2 Binary files /dev/null and b/qbolt.o differ diff --git a/qbolt/main.cpp b/qbolt/main.cpp new file mode 100644 index 0000000..b48f94e --- /dev/null +++ b/qbolt/main.cpp @@ -0,0 +1,11 @@ +#include "mainwindow.h" +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/qbolt/mainwindow.cpp b/qbolt/mainwindow.cpp new file mode 100644 index 0000000..e30b907 --- /dev/null +++ b/qbolt/mainwindow.cpp @@ -0,0 +1,61 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +#include "../qbolt.h" + +#include +#include + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +static QString GetError(GoInterface err) { + if (err.v == nullptr) { + return ""; // no error + } + + GoString gs = Error_Error(err); + return QString::fromUtf8(gs.p, gs.n); +} + +void MainWindow::on_actionOpen_database_triggered() +{ + QString file = QFileDialog::getOpenFileName(this, tr("Select bolt database...")); + if (! file.length()) { + return; + } + + auto opts = Bolt_Options_New_Readonly(); + + QByteArray filePathBytes(file.toUtf8()); + GoString filePathGS = {filePathBytes.data(), filePathBytes.length()}; + + auto open_ret = Bolt_Open(filePathGS, 0444, opts); + if (open_ret.r1.v != nullptr) { + QMessageBox qmb; + qmb.setText(tr("Error opening database: %s").arg(GetError(open_ret.r1))); + qmb.exec(); + return; + } + + // do something + + // close database + + auto err = Bolt_Close(open_ret.r0); + if (err.v != nullptr) { + QMessageBox qmb; + qmb.setText(tr("Error closing database: %s").arg(GetError(err))); + qmb.exec(); + return; + } +} diff --git a/qbolt/mainwindow.h b/qbolt/mainwindow.h new file mode 100644 index 0000000..7b68fa8 --- /dev/null +++ b/qbolt/mainwindow.h @@ -0,0 +1,25 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + +private slots: + void on_actionOpen_database_triggered(); + +private: + Ui::MainWindow *ui; +}; + +#endif // MAINWINDOW_H diff --git a/qbolt/mainwindow.ui b/qbolt/mainwindow.ui new file mode 100644 index 0000000..a228d9a --- /dev/null +++ b/qbolt/mainwindow.ui @@ -0,0 +1,203 @@ + + + MainWindow + + + + 0 + 0 + 668 + 405 + + + + QBolt + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + false + + + + true + + + + Bucket + + + + + + 0 + + + + Properties + + + + 3 + + + 3 + + + 3 + + + 3 + + + + + QFrame::NoFrame + + + true + + + No selection + + + + + + + + Data + + + + 3 + + + 3 + + + 3 + + + 3 + + + + + QFrame::NoFrame + + + 0 + + + false + + + true + + + false + + + + 1 + + + + + + + + + + + + + + + 0 + 0 + 668 + 21 + + + + + Fi&le + + + + + + + + Help + + + + + + + + + + TopToolBarArea + + + false + + + + + + + + :/rsrc/information.png:/rsrc/information.png + + + About QBolt + + + + + About Qt + + + + + + :/rsrc/database_add.png:/rsrc/database_add.png + + + Open database... + + + + + Exit + + + + + + + + + diff --git a/qbolt/qbolt.pro b/qbolt/qbolt.pro new file mode 100644 index 0000000..6d6b815 --- /dev/null +++ b/qbolt/qbolt.pro @@ -0,0 +1,36 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2017-05-15T19:38:33 +# +#------------------------------------------------- + +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = qbolt +TEMPLATE = app + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which as been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +QMAKE_LFLAGS += ../qbolt.o + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + + +SOURCES += main.cpp\ + mainwindow.cpp + +HEADERS += mainwindow.h + +FORMS += mainwindow.ui + +RESOURCES += \ + resources.qrc diff --git a/qbolt/qbolt.pro.user b/qbolt/qbolt.pro.user new file mode 100644 index 0000000..f9ee740 --- /dev/null +++ b/qbolt/qbolt.pro.user @@ -0,0 +1,336 @@ + + + + + + EnvironmentId + {67050bf3-78d3-448a-82be-9e893e07d9a7} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + true + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop + {4cec843c-77aa-4b21-bd99-b7bf84d54e1f} + 0 + 0 + 0 + + /home/mjg/dev/gopath/src/code.ivysaur.me/qbolt/build-qbolt-Desktop-Debug + + + true + qmake + + QtProjectManager.QMakeBuildStep + true + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Debug + + Qt4ProjectManager.Qt4BuildConfiguration + 2 + true + + + /home/mjg/dev/gopath/src/code.ivysaur.me/qbolt/build-qbolt-Desktop-Release + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Release + + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + + /home/mjg/dev/gopath/src/code.ivysaur.me/qbolt/build-qbolt-Desktop-Profile + + + true + qmake + + QtProjectManager.QMakeBuildStep + true + + false + true + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Profile + + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + 3 + + + 0 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy locally + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + qbolt + + Qt4ProjectManager.Qt4RunConfiguration:/home/mjg/dev/gopath/src/code.ivysaur.me/qbolt/qbolt/qbolt.pro + true + + qbolt.pro + false + + + 3768 + false + true + false + false + true + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 18 + + + Version + 18 + + diff --git a/qbolt/resources.qrc b/qbolt/resources.qrc new file mode 100644 index 0000000..c94596f --- /dev/null +++ b/qbolt/resources.qrc @@ -0,0 +1,7 @@ + + + rsrc/database_add.png + rsrc/table.png + rsrc/information.png + + diff --git a/qbolt/rsrc/add.png b/qbolt/rsrc/add.png new file mode 100755 index 0000000..6332fef Binary files /dev/null and b/qbolt/rsrc/add.png differ diff --git a/qbolt/rsrc/database.png b/qbolt/rsrc/database.png new file mode 100755 index 0000000..3d09261 Binary files /dev/null and b/qbolt/rsrc/database.png differ diff --git a/qbolt/rsrc/database_add.png b/qbolt/rsrc/database_add.png new file mode 100755 index 0000000..802bd6c Binary files /dev/null and b/qbolt/rsrc/database_add.png differ diff --git a/qbolt/rsrc/information.png b/qbolt/rsrc/information.png new file mode 100755 index 0000000..12cd1ae Binary files /dev/null and b/qbolt/rsrc/information.png differ diff --git a/qbolt/rsrc/page.png b/qbolt/rsrc/page.png new file mode 100755 index 0000000..03ddd79 Binary files /dev/null and b/qbolt/rsrc/page.png differ diff --git a/qbolt/rsrc/table.png b/qbolt/rsrc/table.png new file mode 100755 index 0000000..abcd936 Binary files /dev/null and b/qbolt/rsrc/table.png differ diff --git a/qbolt/rsrc/table_add.png b/qbolt/rsrc/table_add.png new file mode 100755 index 0000000..2a3e5c4 Binary files /dev/null and b/qbolt/rsrc/table_add.png differ diff --git a/qbolt/rsrc/table_delete.png b/qbolt/rsrc/table_delete.png new file mode 100755 index 0000000..b85916d Binary files /dev/null and b/qbolt/rsrc/table_delete.png differ