[PATCH 3/7] go: Allow notmuch objects to be garbage collected
Adrien Bustany
adrien at bustany.org
Wed Jul 18 11:34:31 PDT 2012
This makes notmuch appropriately free the underlying notmuch C objects
when garbage collecting their Go wrappers. To make sure we don't break
the underlying links between objects (for example, a notmuch_messages_t
being GC'ed before a notmuch_message_t belonging to it), we add for each
wraper struct a pointer to the owner object (Go objects with a reference
pointing to them don't get garbage collected).
---
bindings/go/src/notmuch/notmuch.go | 153 +++++++++++++++++++++++++++++++-----
1 files changed, 134 insertions(+), 19 deletions(-)
diff --git a/bindings/go/src/notmuch/notmuch.go b/bindings/go/src/notmuch/notmuch.go
index 1d77fd2..3f436a0 100644
--- a/bindings/go/src/notmuch/notmuch.go
+++ b/bindings/go/src/notmuch/notmuch.go
@@ -11,6 +11,7 @@ package notmuch
#include "notmuch.h"
*/
import "C"
+import "runtime"
import "unsafe"
// Status codes used for the return values of most functions
@@ -47,40 +48,152 @@ func (self Status) String() string {
/* Various opaque data types. For each notmuch_<foo>_t see the various
* notmuch_<foo> functions below. */
+type Object interface {}
+
type Database struct {
db *C.notmuch_database_t
}
+func createDatabase(db *C.notmuch_database_t) *Database {
+ self := &Database{db: db}
+
+ runtime.SetFinalizer(self, func(x *Database) {
+ if (x.db != nil) {
+ C.notmuch_database_destroy(x.db)
+ }
+ })
+
+ return self
+}
+
type Query struct {
query *C.notmuch_query_t
+ owner Object
+}
+
+func createQuery(query *C.notmuch_query_t, owner Object) *Query {
+ self := &Query{query: query, owner: owner}
+
+ runtime.SetFinalizer(self, func(x *Query) {
+ if (x.query != nil) {
+ C.notmuch_query_destroy(x.query)
+ }
+ })
+
+ return self
}
type Threads struct {
threads *C.notmuch_threads_t
+ owner Object
+}
+
+func createThreads(threads *C.notmuch_threads_t, owner Object) *Threads {
+ self := &Threads{threads: threads, owner: owner}
+
+ runtime.SetFinalizer(self, func(x *Threads) {
+ if (x.threads != nil) {
+ C.notmuch_threads_destroy(x.threads)
+ }
+ })
+
+ return self
}
type Thread struct {
thread *C.notmuch_thread_t
+ owner Object
+}
+
+func createThread(thread *C.notmuch_thread_t, owner Object) *Thread {
+ self := &Thread{thread: thread, owner: owner}
+
+ runtime.SetFinalizer(self, func(x *Thread) {
+ if (x.thread != nil) {
+ C.notmuch_thread_destroy(x.thread)
+ }
+ })
+
+ return self
}
type Messages struct {
messages *C.notmuch_messages_t
+ owner Object
+}
+
+func createMessages(messages *C.notmuch_messages_t, owner Object) *Messages {
+ self := &Messages{messages: messages, owner: owner}
+
+ return self
}
type Message struct {
message *C.notmuch_message_t
+ owner Object
+}
+
+func createMessage(message *C.notmuch_message_t, owner Object) *Message {
+ self := &Message{message: message, owner: owner}
+
+ runtime.SetFinalizer(self, func(x *Message) {
+ if (x.message != nil) {
+ C.notmuch_message_destroy(x.message)
+ }
+ })
+
+ return self
}
type Tags struct {
tags *C.notmuch_tags_t
+ owner Object
+}
+
+func createTags(tags *C.notmuch_tags_t, owner Object) *Tags {
+ self := &Tags{tags: tags, owner: owner}
+
+ runtime.SetFinalizer(self, func(x *Tags) {
+ if (x.tags != nil) {
+ C.notmuch_tags_destroy(x.tags)
+ }
+ })
+
+ return self
}
type Directory struct {
dir *C.notmuch_directory_t
+ owner Object
+}
+
+func createDirectory(directory *C.notmuch_directory_t, owner Object) *Directory {
+ self := &Directory{dir: directory, owner: owner}
+
+ runtime.SetFinalizer(self, func(x *Directory) {
+ if (x.dir != nil) {
+ C.notmuch_directory_destroy(x.dir)
+ }
+ })
+
+ return self
}
type Filenames struct {
fnames *C.notmuch_filenames_t
+ owner Object
+}
+
+func createFilenames(filenames *C.notmuch_filenames_t, owner Object) *Filenames {
+ self := &Filenames{fnames: filenames, owner: owner}
+
+ runtime.SetFinalizer(self, func(x *Filenames) {
+ if (x.fnames != nil) {
+ C.notmuch_filenames_destroy(x.fnames)
+ }
+ })
+
+ return self
}
type DatabaseMode C.notmuch_database_mode_t
@@ -100,12 +213,13 @@ func NewDatabase(path string) (*Database, Status) {
return nil, STATUS_OUT_OF_MEMORY
}
- self := &Database{db: nil}
- st := Status(C.notmuch_database_create(c_path, &self.db))
+ var db *C.notmuch_database_t;
+ st := Status(C.notmuch_database_create(c_path, &db))
if st != STATUS_SUCCESS {
return nil, st
}
- return self, st
+
+ return createDatabase(db), st
}
/* Open an existing notmuch database located at 'path'.
@@ -134,12 +248,13 @@ func OpenDatabase(path string, mode DatabaseMode) (*Database, Status) {
return nil, STATUS_OUT_OF_MEMORY
}
- self := &Database{db: nil}
- st := Status(C.notmuch_database_open(c_path, C.notmuch_database_mode_t(mode), &self.db))
+ var db *C.notmuch_database_t;
+ st := Status(C.notmuch_database_open(c_path, C.notmuch_database_mode_t(mode), &db))
if st != STATUS_SUCCESS {
return nil, st
}
- return self, st
+
+ return createDatabase(db), st
}
/* Close the given notmuch database, freeing all associated
@@ -204,7 +319,7 @@ func (self *Database) GetDirectory(path string) (*Directory, Status) {
if st != STATUS_SUCCESS || c_dir == nil {
return nil, st
}
- return &Directory{dir: c_dir}, st
+ return createDirectory(c_dir, nil), st
}
/* Add a new message to the given notmuch database.
@@ -258,7 +373,7 @@ func (self *Database) AddMessage(fname string) (*Message, Status) {
var c_msg *C.notmuch_message_t = new(C.notmuch_message_t)
st := Status(C.notmuch_database_add_message(self.db, c_fname, &c_msg))
- return &Message{message: c_msg}, st
+ return createMessage(c_msg, nil), st
}
/* Remove a message from the given notmuch database.
@@ -319,12 +434,12 @@ func (self *Database) FindMessage(message_id string) (*Message, Status) {
return nil, STATUS_OUT_OF_MEMORY
}
- msg := &Message{message: nil}
- st := Status(C.notmuch_database_find_message(self.db, c_msg_id, &msg.message))
+ var msg *C.notmuch_message_t
+ st := Status(C.notmuch_database_find_message(self.db, c_msg_id, &msg))
if st != STATUS_SUCCESS {
return nil, st
}
- return msg, st
+ return createMessage(msg, nil), st
}
/* Return a list of all tags found in the database.
@@ -339,7 +454,7 @@ func (self *Database) GetAllTags() *Tags {
if tags == nil {
return nil
}
- return &Tags{tags: tags}
+ return createTags(tags, nil)
}
/* Create a new query for 'database'.
@@ -379,7 +494,7 @@ func (self *Database) CreateQuery(query string) *Query {
if q == nil {
return nil
}
- return &Query{query: q}
+ return createQuery(q, nil)
}
/* Sort values for notmuch_query_set_sort */
@@ -459,7 +574,7 @@ func (self *Query) SearchThreads() *Threads {
if threads == nil {
return nil
}
- return &Threads{threads: threads}
+ return createThreads(threads, self)
}
/* Execute a query for messages, returning a notmuch_messages_t object
@@ -505,7 +620,7 @@ func (self *Query) SearchMessages() *Messages {
if msgs == nil {
return nil
}
- return &Messages{messages: msgs}
+ return createMessages(msgs, self)
}
/* Destroy a notmuch_query_t along with any associated resources.
@@ -607,7 +722,7 @@ func (self *Messages) Get() *Message {
if msg == nil {
return nil
}
- return &Message{message: msg}
+ return createMessage(msg, self)
}
/* Move the 'messages' iterator to the next message.
@@ -659,7 +774,7 @@ func (self *Messages) CollectTags() *Tags {
if tags == nil {
return nil
}
- return &Tags{tags: tags}
+ return createTags(tags, self)
}
/* Get the message ID of 'message'.
@@ -739,7 +854,7 @@ func (self *Message) GetReplies() *Messages {
if msgs == nil {
return nil
}
- return &Messages{messages: msgs}
+ return createMessages(msgs, self)
}
/* Get a filename for the email corresponding to 'message'.
@@ -871,7 +986,7 @@ func (self *Message) GetTags() *Tags {
if tags == nil {
return nil
}
- return &Tags{tags: tags}
+ return createTags(tags, self)
}
/* The longest possible tag value. */
--
1.7.7.6
More information about the notmuch
mailing list