From: Adrien Bustany <adrien@bustany.org>
To: notmuch@notmuchmail.org
Subject: [PATCH 3/7] go: Allow notmuch objects to be garbage collected
Date: Wed, 18 Jul 2012 21:34:31 +0300 [thread overview]
Message-ID: <1342636475-16057-4-git-send-email-adrien@bustany.org> (raw)
In-Reply-To: <1342636475-16057-1-git-send-email-adrien@bustany.org>
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
next prev parent reply other threads:[~2012-07-18 18:41 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-07-18 18:34 [PATCH 0/7] Various fixes for the Go bindings Adrien Bustany
2012-07-18 18:34 ` [PATCH 1/7] go: Use iota in enum bindings Adrien Bustany
2012-07-18 20:17 ` Austin Clements
2012-07-18 20:36 ` Sebastien Binet
2012-07-18 18:34 ` [PATCH 2/7] go: Add missing MESSAGE_FLAG_EXCLUDED in Flag enum Adrien Bustany
2012-07-18 18:34 ` Adrien Bustany [this message]
2012-07-18 20:40 ` [PATCH 3/7] go: Allow notmuch objects to be garbage collected Austin Clements
2012-07-19 18:25 ` Adrien Bustany
2012-07-20 3:23 ` Austin Clements
2012-07-23 22:03 ` Adrien Bustany
2012-08-04 19:28 ` Austin Clements
2012-10-19 3:55 ` Ethan Glasser-Camp
2012-10-25 18:41 ` Adrien Bustany
2012-07-18 18:34 ` [PATCH 4/7] go: Make Destroy functions safe to call several times Adrien Bustany
2012-07-18 18:34 ` [PATCH 5/7] go: Partially bind notmuch_database_upgrade Adrien Bustany
2012-07-18 20:41 ` Austin Clements
2012-07-18 18:34 ` [PATCH 6/7] go: Bind notmuch_database_find_message_by_filename Adrien Bustany
2012-07-18 18:34 ` [PATCH 7/7] go: Bind notmuch_thread_t functions Adrien Bustany
2012-07-18 20:50 ` Austin Clements
2012-07-18 20:51 ` [PATCH 0/7] Various fixes for the Go bindings Austin Clements
2012-07-19 18:29 ` Adrien Bustany
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://notmuchmail.org/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1342636475-16057-4-git-send-email-adrien@bustany.org \
--to=adrien@bustany.org \
--cc=notmuch@notmuchmail.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://yhetil.org/notmuch.git/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).