Return-Path: X-Original-To: notmuch@notmuchmail.org Delivered-To: notmuch@notmuchmail.org Received: from localhost (localhost [127.0.0.1]) by olra.theworths.org (Postfix) with ESMTP id 677E7431FDE for ; Wed, 18 Jul 2012 11:41:09 -0700 (PDT) X-Virus-Scanned: Debian amavisd-new at olra.theworths.org X-Spam-Flag: NO X-Spam-Score: 0 X-Spam-Level: X-Spam-Status: No, score=0 tagged_above=-999 required=5 tests=[none] autolearn=disabled Received: from olra.theworths.org ([127.0.0.1]) by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Fgysct7-kN8i for ; Wed, 18 Jul 2012 11:41:07 -0700 (PDT) Received: from mail.bustany.org (bustany.org [176.31.244.208]) by olra.theworths.org (Postfix) with ESMTP id 81E4A431FC4 for ; Wed, 18 Jul 2012 11:41:05 -0700 (PDT) Received: from localhost.localdomain (91-158-2-79.elisa-laajakaista.fi [91.158.2.79]) by mail.bustany.org (Postfix) with ESMTPSA id 6A6D91400C2 for ; Wed, 18 Jul 2012 20:37:08 +0200 (CEST) From: Adrien Bustany 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 Message-Id: <1342636475-16057-4-git-send-email-adrien@bustany.org> X-Mailer: git-send-email 1.7.7.6 In-Reply-To: <1342636475-16057-1-git-send-email-adrien@bustany.org> References: <1342636475-16057-1-git-send-email-adrien@bustany.org> X-BeenThere: notmuch@notmuchmail.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: "Use and development of the notmuch mail system." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 18 Jul 2012 18:41:10 -0000 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__t see the various * notmuch_ 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