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

Reply via email to