diff options
| author | Dirk Van Haerenborgh <vhdirk@gmail.com> | 2018-11-01 21:55:00 +0100 |
|---|---|---|
| committer | Dirk Van Haerenborgh <vhdirk@gmail.com> | 2018-11-01 21:55:00 +0100 |
| commit | 7d2be237297c16628cb3d58774e808cac9c92fc1 (patch) | |
| tree | 55cb240828bac9968f94166e740b567b66928e3b | |
| parent | 2932d67d87fa2ff41fcdf46ce269ba5b49294930 (diff) | |
| download | mail-7d2be237297c16628cb3d58774e808cac9c92fc1.tar.gz | |
improve lifetime management with supercow
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | src/database.rs | 199 | ||||
| -rw-r--r-- | src/directory.rs | 62 | ||||
| -rw-r--r-- | src/error.rs | 9 | ||||
| -rw-r--r-- | src/filenames.rs | 53 | ||||
| -rw-r--r-- | src/lib.rs | 28 | ||||
| -rw-r--r-- | src/message.rs | 120 | ||||
| -rw-r--r-- | src/messages.rs | 90 | ||||
| -rw-r--r-- | src/query.rs | 105 | ||||
| -rw-r--r-- | src/tags.rs | 65 | ||||
| -rw-r--r-- | src/thread.rs | 126 | ||||
| -rw-r--r-- | src/threads.rs | 55 | ||||
| -rw-r--r-- | src/utils.rs | 31 | ||||
| -rw-r--r-- | tests/main.rs | 12 |
14 files changed, 421 insertions, 535 deletions
@@ -14,6 +14,7 @@ travis-ci = { repository = "vhdirk/notmuch-rs" } [dependencies] libc = "0.2" clippy = { version = "0.0.193", optional = true } +supercow = "0.1.0" [dev-dependencies] dirs = "1.0" diff --git a/src/database.rs b/src/database.rs index 467c3ba..6390c15 100644 --- a/src/database.rs +++ b/src/database.rs @@ -1,22 +1,17 @@ +use std::ffi::{CStr, CString}; use std::ops::Drop; -use std::ptr; use std::path::Path; -use std::ffi::{CStr, CString}; +use std::ptr; use libc; use error::Result; -use utils::{ - FromPtr, - ToStr, -}; - +use ffi; +use utils::ToStr; use Directory; use Query; use Tags; -use tags::TagsOwner; - -use ffi; +use TagsOwner; // Re-exported under database module for pretty namespacin'. pub use ffi::DatabaseMode; @@ -25,139 +20,145 @@ pub use ffi::DatabaseMode; pub struct Version(libc::c_uint); #[derive(Clone, Debug)] -pub struct Revision{ +pub struct Revision { pub revision: libc::c_ulong, - pub uuid: String + pub uuid: String, } #[derive(Debug)] pub(crate) struct DatabasePtr { - pub ptr: *mut ffi::notmuch_database_t + pub ptr: *mut ffi::notmuch_database_t, } impl Drop for DatabasePtr { fn drop(&mut self) { - unsafe { - ffi::notmuch_database_destroy(self.ptr) - }; + unsafe { ffi::notmuch_database_destroy(self.ptr) }; } } #[derive(Debug)] -pub struct Database{ - pub(crate) handle: DatabasePtr +pub struct Database { + pub(crate) handle: DatabasePtr, } -impl TagsOwner for Database{} +impl TagsOwner for Database {} impl Database { pub fn create<P: AsRef<Path>>(path: &P) -> Result<Self> { let path_str = CString::new(path.as_ref().to_str().unwrap()).unwrap(); let mut db = ptr::null_mut(); - try!(unsafe { - ffi::notmuch_database_create(path_str.as_ptr(), &mut db) - }.as_result()); + try!(unsafe { ffi::notmuch_database_create(path_str.as_ptr(), &mut db) }.as_result()); - Ok(Database{handle:DatabasePtr{ptr:db}}) + Ok(Database { + handle: DatabasePtr { ptr: db }, + }) } pub fn open<P: AsRef<Path>>(path: &P, mode: DatabaseMode) -> Result<Self> { let path_str = CString::new(path.as_ref().to_str().unwrap()).unwrap(); let mut db = ptr::null_mut(); - try!(unsafe { - ffi::notmuch_database_open( - path_str.as_ptr(), - mode.into(), - &mut db, - ) - }.as_result()); + try!( + unsafe { ffi::notmuch_database_open(path_str.as_ptr(), mode.into(), &mut db,) } + .as_result() + ); - Ok(Database{handle:DatabasePtr{ptr:db}}) + Ok(Database { + handle: DatabasePtr { ptr: db }, + }) } pub fn close(&mut self) -> Result<()> { - try!(unsafe { - ffi::notmuch_database_close(self.handle.ptr) - }.as_result()); + try!(unsafe { ffi::notmuch_database_close(self.handle.ptr) }.as_result()); Ok(()) } pub fn compact<P: AsRef<Path>, F: FnMut(&str)>( - path: &P, backup_path: Option<&P>, + path: &P, + backup_path: Option<&P>, ) -> Result<()> { let status: Option<F> = None; Database::_compact(path, backup_path, status) } pub fn compact_with_status<P: AsRef<Path>, F: FnMut(&str)>( - path: &P, backup_path: Option<&P>, status: F, + path: &P, + backup_path: Option<&P>, + status: F, ) -> Result<()> { Database::_compact(path, backup_path, Some(status)) } fn _compact<P: AsRef<Path>, F: FnMut(&str)>( - path: &P, backup_path: Option<&P>, status: Option<F>, + path: &P, + backup_path: Option<&P>, + status: Option<F>, ) -> Result<()> { - - extern fn wrapper<F: FnMut(&str)>( - message:*const libc::c_char, closure: *mut libc::c_void, + extern "C" fn wrapper<F: FnMut(&str)>( + message: *const libc::c_char, + closure: *mut libc::c_void, ) { let closure = closure as *mut F; - unsafe { - (*closure)(message.to_str().unwrap()) - } + unsafe { (*closure)(message.to_str().unwrap()) } } let path_str = CString::new(path.as_ref().to_str().unwrap()).unwrap(); - let backup_path = backup_path.map(|p| { - CString::new(p.as_ref().to_str().unwrap()).unwrap() - }); - - try!(unsafe { - ffi::notmuch_database_compact( - path_str.as_ptr(), backup_path.map_or(ptr::null(), |p| p.as_ptr()), - if status.is_some() { Some(wrapper::<F>) } else { None }, - status.map_or(ptr::null_mut(), |f| { - &f as *const _ as *mut libc::c_void - }), - ) - }.as_result()); + let backup_path = backup_path.map(|p| CString::new(p.as_ref().to_str().unwrap()).unwrap()); + + try!( + unsafe { + ffi::notmuch_database_compact( + path_str.as_ptr(), + backup_path.map_or(ptr::null(), |p| p.as_ptr()), + if status.is_some() { + Some(wrapper::<F>) + } else { + None + }, + status.map_or(ptr::null_mut(), |f| &f as *const _ as *mut libc::c_void), + ) + } + .as_result() + ); Ok(()) } pub fn path(&self) -> &Path { - Path::new(unsafe { - ffi::notmuch_database_get_path(self.handle.ptr) - }.to_str().unwrap()) + Path::new( + unsafe { ffi::notmuch_database_get_path(self.handle.ptr) } + .to_str() + .unwrap(), + ) } pub fn version(&self) -> Version { - Version(unsafe { - ffi::notmuch_database_get_version(self.handle.ptr) - }) + Version(unsafe { ffi::notmuch_database_get_version(self.handle.ptr) }) } #[cfg(feature = "v0_21")] pub fn revision(&self) -> Revision { let uuid_p: *const libc::c_char = ptr::null(); let revision = unsafe { - ffi::notmuch_database_get_revision(self.handle.ptr, (&uuid_p) as *const _ as *mut *const libc::c_char) + ffi::notmuch_database_get_revision( + self.handle.ptr, + (&uuid_p) as *const _ as *mut *const libc::c_char, + ) }; let uuid = unsafe { CStr::from_ptr(uuid_p) }; - Revision{revision, uuid: uuid.to_string_lossy().into_owned()} + Revision { + revision, + uuid: uuid.to_string_lossy().into_owned(), + } } pub fn needs_upgrade(&self) -> bool { - unsafe { - ffi::notmuch_database_needs_upgrade(self.handle.ptr) == 1 - } + unsafe { ffi::notmuch_database_needs_upgrade(self.handle.ptr) == 1 } } pub fn upgrade<F: FnMut(f64)>(&mut self) -> Result<()> { @@ -170,26 +171,26 @@ impl Database { } fn _upgrade<F: FnMut(f64)>(&mut self, status: Option<F>) -> Result<()> { - #[allow(trivial_numeric_casts)] - extern fn wrapper<F: FnMut(f64)>( - closure: *mut libc::c_void, progress: libc::c_double, - ) { + extern "C" fn wrapper<F: FnMut(f64)>(closure: *mut libc::c_void, progress: libc::c_double) { let closure = closure as *mut F; - unsafe { - (*closure)(progress as f64) - } + unsafe { (*closure)(progress as f64) } } - try!(unsafe { - ffi::notmuch_database_upgrade( - self.handle.ptr, - if status.is_some() { Some(wrapper::<F>) } else { None }, - status.map_or(ptr::null_mut(), |f| { - &f as *const _ as *mut libc::c_void - }), - ) - }.as_result()); + try!( + unsafe { + ffi::notmuch_database_upgrade( + self.handle.ptr, + if status.is_some() { + Some(wrapper::<F>) + } else { + None + }, + status.map_or(ptr::null_mut(), |f| &f as *const _ as *mut libc::c_void), + ) + } + .as_result() + ); Ok(()) } @@ -198,32 +199,32 @@ impl Database { let path_str = CString::new(path.as_ref().to_str().unwrap()).unwrap(); let mut dir = ptr::null_mut(); - try!(unsafe { - ffi::notmuch_database_get_directory( - self.handle.ptr, path_str.as_ptr(), &mut dir, - ) - }.as_result()); + try!( + unsafe { + ffi::notmuch_database_get_directory(self.handle.ptr, path_str.as_ptr(), &mut dir) + } + .as_result() + ); - if dir.is_null() { Ok(None) } else { Ok(Some(Directory::from_ptr(dir))) } + if dir.is_null() { + Ok(None) + } else { + Ok(Some(Directory::from_ptr(dir, self))) + } } pub fn create_query<'d>(&'d self, query_string: &str) -> Result<Query<'d>> { let query_str = CString::new(query_string).unwrap(); - let query = unsafe { - ffi::notmuch_query_create(self.handle.ptr, query_str.as_ptr()) - }; + let query = unsafe { ffi::notmuch_query_create(self.handle.ptr, query_str.as_ptr()) }; - Ok(Query::from_ptr(query)) + Ok(Query::from_ptr(query, self)) } - pub fn all_tags<'d>(&self) -> Result<Tags<'d, Self>> { - - let tags = unsafe { - ffi::notmuch_database_get_all_tags(self.handle.ptr) - }; + pub fn all_tags<'d>(&'d self) -> Result<Tags<'d, Self>> { + let tags = unsafe { ffi::notmuch_database_get_all_tags(self.handle.ptr) }; - Ok(Tags::from_ptr(tags)) + Ok(Tags::from_ptr(tags, self)) } } diff --git a/src/directory.rs b/src/directory.rs index ce219f5..9bdae2d 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -1,64 +1,48 @@ use std::ops::Drop; -use std::marker::PhantomData; - -use utils::FromPtr; +use supercow::Phantomcow; +use ffi; use Database; use Filenames; -use filenames::{FilenamesPtr, FilenamesOwner}; - -use ffi; +use FilenamesOwner; #[derive(Debug)] pub(crate) struct DirectoryPtr { - pub ptr: *mut ffi::notmuch_directory_t + pub ptr: *mut ffi::notmuch_directory_t, } impl Drop for DirectoryPtr { fn drop(&mut self) { - unsafe { - ffi::notmuch_directory_destroy(self.ptr) - }; - } -} - -impl DirectoryPtr { - pub fn child_directories(self: &Self) -> FilenamesPtr{ - FilenamesPtr{ - ptr: unsafe { - ffi::notmuch_directory_get_child_directories(self.ptr) - } - } + unsafe { ffi::notmuch_directory_destroy(self.ptr) }; } } - - #[derive(Debug)] -pub struct Directory<'d>{ +pub struct Directory<'d> { handle: DirectoryPtr, - phantom: PhantomData<&'d Database>, + marker: Phantomcow<'d, Database>, } -impl<'d> FilenamesOwner for Directory<'d>{} +impl<'d> FilenamesOwner for Directory<'d> {} -impl<'d> Directory<'d>{ - pub fn child_directories(self: &'d Self) -> Filenames<Self>{ - Filenames{ - handle: self.handle.child_directories(), - phantom: PhantomData +impl<'d> Directory<'d> { + pub fn from_ptr<O: Into<Phantomcow<'d, Database>>>( + ptr: *mut ffi::notmuch_directory_t, + owner: O, + ) -> Directory<'d> { + Directory { + handle: DirectoryPtr { ptr }, + marker: owner.into(), } } -} -impl<'d> FromPtr<*mut ffi::notmuch_directory_t> for Directory<'d> { - fn from_ptr(ptr: *mut ffi::notmuch_directory_t) -> Directory<'d> { - Directory{ - handle: DirectoryPtr{ptr}, - phantom: PhantomData - } + pub fn child_directories(&self) -> Filenames<Self> { + Filenames::from_ptr( + unsafe { ffi::notmuch_directory_get_child_directories(self.handle.ptr) }, + self, + ) } } -unsafe impl<'d> Send for Directory<'d>{} -unsafe impl<'d> Sync for Directory<'d>{} +unsafe impl<'d> Send for Directory<'d> {} +unsafe impl<'d> Sync for Directory<'d> {} diff --git a/src/error.rs b/src/error.rs index 6434ee3..6de4236 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,10 +1,5 @@ use std; -use std::{ - error, - fmt, - io, - result, -}; +use std::{error, fmt, io, result}; use ffi; @@ -36,7 +31,7 @@ impl std::error::Error for Error { match *self { Error::IoError(ref e) => Some(e), Error::NotmuchError(ref e) => Some(e), - Error::UnspecifiedError => None + Error::UnspecifiedError => None, } } } diff --git a/src/filenames.rs b/src/filenames.rs index 5083742..ae90280 100644 --- a/src/filenames.rs +++ b/src/filenames.rs @@ -1,45 +1,43 @@ -use std::ops::Drop; +use std::ffi::CStr; use std::iter::Iterator; -use std::marker::PhantomData; +use std::ops::Drop; use std::path::PathBuf; -use std::ffi::CStr; -use utils::FromPtr; -use Database; +use supercow::Phantomcow; + use ffi; -pub trait FilenamesOwner{} +pub trait FilenamesOwner {} #[derive(Debug)] pub(crate) struct FilenamesPtr { - pub ptr: *mut ffi::notmuch_filenames_t + pub ptr: *mut ffi::notmuch_filenames_t, } impl Drop for FilenamesPtr { fn drop(self: &mut Self) { - let valid = unsafe { - ffi::notmuch_filenames_valid(self.ptr) - }; + let valid = unsafe { ffi::notmuch_filenames_valid(self.ptr) }; if valid != 0 { - unsafe { - ffi::notmuch_filenames_destroy(self.ptr) - }; + unsafe { ffi::notmuch_filenames_destroy(self.ptr) }; } } } - + #[derive(Debug)] -pub struct Filenames<'o, Owner: FilenamesOwner + 'o>{ +pub struct Filenames<'o, Owner: FilenamesOwner + 'o> { pub(crate) handle: FilenamesPtr, - pub(crate) phantom: PhantomData<&'o Owner> + pub(crate) marker: Phantomcow<'o, Owner>, } -impl<'o, Owner: FilenamesOwner + 'o> FromPtr<*mut ffi::notmuch_filenames_t> for Filenames<'o, Owner> { - fn from_ptr(ptr: *mut ffi::notmuch_filenames_t) -> Filenames<'o, Owner> { - Filenames{ - handle: FilenamesPtr{ptr}, - phantom: PhantomData +impl<'o, Owner: FilenamesOwner + 'o> Filenames<'o, Owner> { + pub fn from_ptr<O: Into<Phantomcow<'o, Owner>>>( + ptr: *mut ffi::notmuch_filenames_t, + owner: O, + ) -> Filenames<'o, Owner> { + Filenames { + handle: FilenamesPtr { ptr }, + marker: owner.into(), } } } @@ -48,13 +46,10 @@ impl<'o, Owner: FilenamesOwner + 'o> Iterator for Filenames<'o, Owner> { type Item = PathBuf; fn next(self: &mut Self) -> Option<Self::Item> { + let valid = unsafe { ffi::notmuch_filenames_valid(self.handle.ptr) }; - let valid = unsafe { - ffi::notmuch_filenames_valid(self.handle.ptr) - }; - - if valid == 0{ - return None + if valid == 0 { + return None; } let ctag = unsafe { @@ -67,5 +62,5 @@ impl<'o, Owner: FilenamesOwner + 'o> Iterator for Filenames<'o, Owner> { } } -unsafe impl<'o, Owner: FilenamesOwner + 'o> Send for Filenames<'o, Owner>{} -unsafe impl<'o, Owner: FilenamesOwner + 'o> Sync for Filenames<'o, Owner>{} +unsafe impl<'o, Owner: FilenamesOwner + 'o> Send for Filenames<'o, Owner> {} +unsafe impl<'o, Owner: FilenamesOwner + 'o> Sync for Filenames<'o, Owner> {} @@ -1,34 +1,36 @@ -#![cfg_attr(feature="clippy", feature(plugin))] -#![cfg_attr(feature="clippy", plugin(clippy))] +#![cfg_attr(feature = "clippy", feature(plugin))] +#![cfg_attr(feature = "clippy", plugin(clippy))] #[macro_use] mod macros; extern crate libc; +extern crate supercow; -mod utils; mod ffi; +mod utils; -mod error; mod database; mod directory; -mod query; -mod messages; +mod error; +mod filenames; mod message; +mod messages; +mod query; mod tags; -mod threads; mod thread; -mod filenames; +mod threads; -pub use error::Error; pub use database::Database; pub use directory::Directory; -pub use query::Query; -pub use messages::{Messages, MessagesOwner}; +pub use error::Error; +pub use filenames::{Filenames, FilenamesOwner}; pub use message::{Message, MessageOwner}; +pub use messages::{Messages, MessagesOwner}; +pub use query::Query; pub use tags::{Tags, TagsOwner}; -pub use threads::{Threads, ThreadsOwner}; pub use thread::{Thread, ThreadOwner}; -pub use filenames::{Filenames, FilenamesOwner}; +pub use threads::{Threads, ThreadsOwner}; pub use ffi::{DatabaseMode, Sort}; +pub use utils::StreamingIterator; diff --git a/src/message.rs b/src/message.rs index af04cec..624817d 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,103 +1,92 @@ +use std::ffi::CString; use std::ops::Drop; -use std::marker::PhantomData; use std::path::PathBuf; -use std::ffi::CString; +use supercow::Phantomcow; use error::{Error, Result}; - use ffi; -use utils::{ - ToStr, - FromPtr -}; -use Query; -use Messages; +use utils::ToStr; use Filenames; +use FilenamesOwner; +use Messages; +use MessagesOwner; use Tags; -use messages::MessagesOwner; -use filenames::FilenamesOwner; -use tags::TagsOwner; +use TagsOwner; -pub trait MessageOwner{} +pub trait MessageOwner {} #[derive(Debug)] pub(crate) struct MessagePtr { - pub ptr: *mut ffi::notmuch_message_t + pub ptr: *mut ffi::notmuch_message_t, } impl Drop for MessagePtr { fn drop(&mut self) { - unsafe { - ffi::notmuch_message_destroy(self.ptr) - }; + unsafe { ffi::notmuch_message_destroy(self.ptr) }; } } - + #[derive(Debug)] -pub struct Message<'o, Owner: MessageOwner + 'o>{ +pub struct Message<'o, Owner: MessageOwner + 'o> { pub(crate) handle: MessagePtr, - phantom: PhantomData<&'o Owner>, + marker: Phantomcow<'o, Owner>, } -impl<'o, Owner: MessageOwner + 'o> MessagesOwner for Message<'o, Owner>{} -impl<'o, Owner: MessageOwner + 'o> FilenamesOwner for Message<'o, Owner>{} -impl<'o, Owner: MessageOwner + 'o> TagsOwner for Message<'o, Owner>{} - - -impl<'o, Owner: MessageOwner + 'o> FromPtr<*mut ffi::notmuch_message_t> for Message<'o, Owner> { - fn from_ptr(ptr: *mut ffi::notmuch_message_t) -> Message<'o, Owner> { - Message{ - handle: MessagePtr{ptr}, - phantom: PhantomData +impl<'o, Owner: MessageOwner + 'o> MessagesOwner for Message<'o, Owner> {} +impl<'o, Owner: MessageOwner + 'o> FilenamesOwner for Message<'o, Owner> {} +impl<'o, Owner: MessageOwner + 'o> TagsOwner for Message<'o, Owner> {} + +impl<'o, Owner: MessageOwner + 'o> Message<'o, Owner> { + pub fn from_ptr<O: Into<Phantomcow<'o, Owner>>>( + ptr: *mut ffi::notmuch_message_t, + owner: O, + ) -> Message<'o, Owner> { + Message { + handle: MessagePtr { ptr }, + marker: owner.into(), } } -} - -impl<'o, Owner: MessageOwner + 'o> Message<'o, Owner>{ - pub fn id(self: &Self) -> String{ - let mid = unsafe { - ffi::notmuch_message_get_message_id(self.handle.ptr) - }; + pub fn id(self: &Self) -> String { + let mid = unsafe { ffi::notmuch_message_get_message_id(self.handle.ptr) }; mid.to_str().unwrap().to_string() } - pub fn thread_id(self: &Self) -> String{ - let tid = unsafe { - ffi::notmuch_message_get_thread_id(self.handle.ptr) - }; + pub fn thread_id(self: &Self) -> String { + let tid = unsafe { ffi::notmuch_message_get_thread_id(self.handle.ptr) }; tid.to_str().unwrap().to_string() } - pub fn replies(self: &Self) -> Messages<'o, Self>{ - Messages::from_ptr(unsafe { - ffi::notmuch_message_get_replies(self.handle.ptr) - }) + pub fn replies<'s>(self: &'s Self) -> Messages<'s, Self> { + Messages::from_ptr( + unsafe { ffi::notmuch_message_get_replies(self.handle.ptr) }, + self, + ) } #[cfg(feature = "v0_26")] - pub fn count_files(self: &Self) -> i32{ - unsafe { - ffi::notmuch_message_count_files(self.handle.ptr) - } + pub fn count_files(self: &Self) -> i32 { + unsafe { ffi::notmuch_message_count_files(self.handle.ptr) } } - pub fn filenames(self: &Self) -> Filenames<Self>{ - Filenames::from_ptr(unsafe { - ffi::notmuch_message_get_filenames(self.handle.ptr) - }) + pub fn filenames(self: &Self) -> Filenames<Self> { + Filenames::from_ptr( + unsafe { ffi::notmuch_message_get_filenames(self.handle.ptr) }, + self, + ) } - pub fn filename(self: &Self) -> PathBuf{ - PathBuf::from(unsafe { - ffi::notmuch_message_get_filename(self.handle.ptr) - }.to_str().unwrap()) + pub fn filename(self: &Self) -> PathBuf { + PathBuf::from( + unsafe { ffi::notmuch_message_get_filename(self.handle.ptr) } + .to_str() + .unwrap(), + ) } pub fn header(&self, name: &str) -> Result<&str> { let ret = unsafe { - ffi::notmuch_message_get_header(self.handle.ptr, - CString::new(name).unwrap().as_ptr()) + ffi::notmuch_message_get_header(self.handle.ptr, CString::new(name).unwrap().as_ptr()) }; if ret.is_null() { Err(Error::UnspecifiedError) @@ -106,12 +95,13 @@ impl<'o, Owner: MessageOwner + 'o> Message<'o, Owner>{ } } - pub fn tags<'m>(self: &Self) -> Tags<'m, Self>{ - Tags::from_ptr(unsafe { - ffi::notmuch_message_get_tags(self.handle.ptr) - }) + pub fn tags<'m>(&'m self) -> Tags<'m, Self> { + Tags::from_ptr( + unsafe { ffi::notmuch_message_get_tags(self.handle.ptr) }, + self, + ) } } -unsafe impl<'o, Owner: MessageOwner + 'o> Send for Message<'o, Owner>{} -unsafe impl<'o, Owner: MessageOwner + 'o> Sync for Message<'o, Owner>{} +unsafe impl<'o, Owner: MessageOwner + 'o> Send for Message<'o, Owner> {} +unsafe impl<'o, Owner: MessageOwner + 'o> Sync for Message<'o, Owner> {} diff --git a/src/messages.rs b/src/messages.rs index b0fd47d..08a9cf3 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -1,63 +1,55 @@ use std::ops::Drop; -use std::iter::Iterator; -use std::marker::PhantomData; + +use supercow::{Phantomcow, Supercow}; use ffi; -use utils::{ - FromPtr, -}; -use Query; +use utils::StreamingIterator; use Message; +use MessageOwner; use Tags; -use message::MessageOwner; -use tags::TagsOwner; +use TagsOwner; -pub trait MessagesOwner{ -} +pub trait MessagesOwner {} #[derive(Debug)] -pub(crate) struct MessagesPtr { - pub ptr: *mut ffi::notmuch_messages_t +pub struct MessagesPtr { + pub ptr: *mut ffi::notmuch_messages_t, } impl Drop for MessagesPtr { fn drop(self: &mut Self) { - let valid = unsafe { - ffi::notmuch_messages_valid(self.ptr) - }; + let valid = unsafe { ffi::notmuch_messages_valid(self.ptr) }; - if valid == 0{ + if valid == 0 { return; } - unsafe { - ffi::notmuch_messages_destroy(self.ptr) - }; + unsafe { ffi::notmuch_messages_destroy(self.ptr) }; } } - #[derive(Debug)] -pub struct Messages<'o, Owner: MessagesOwner + 'o>{ +pub struct Messages<'o, Owner: MessagesOwner + 'o> { pub(crate) handle: MessagesPtr, - phantom: PhantomData<&'o Owner>, + marker: Phantomcow<'o, Owner>, } -impl<'o, Owner: MessagesOwner + 'o> FromPtr<*mut ffi::notmuch_messages_t> for Messages<'o, Owner> { - fn from_ptr(ptr: *mut ffi::notmuch_messages_t) -> Messages<'o, Owner> { - Messages{ - handle: MessagesPtr{ptr}, - phantom: PhantomData +impl<'o, Owner: MessagesOwner + 'o> Messages<'o, Owner> { + pub fn from_ptr<O: Into<Phantomcow<'o, Owner>>>( + ptr: *mut ffi::notmuch_messages_t, + owner: O, + ) -> Messages<'o, Owner> { + Messages { + handle: MessagesPtr { ptr }, + marker: owner.into(), } } } -impl<'o, Owner: MessagesOwner + 'o> MessageOwner for Messages<'o, Owner>{} -impl<'o, Owner: MessagesOwner + 'o> TagsOwner for Messages<'o, Owner>{} - - -impl<'o, Owner: MessagesOwner + 'o> Messages<'o, Owner>{ +impl<'o, Owner: MessagesOwner + 'o> MessageOwner for Messages<'o, Owner> {} +impl<'o, Owner: MessagesOwner + 'o> TagsOwner for Messages<'o, Owner> {} +impl<'o, Owner: MessagesOwner + 'o> Messages<'o, Owner> { /** * Return a list of tags from all messages. * @@ -71,26 +63,22 @@ impl<'o, Owner: MessagesOwner + 'o> Messages<'o, Owner>{ * * The function returns NULL on error. */ - pub fn collect_tags<'m>(self: &'o Self) -> Tags<'m, Self>{ - Tags::from_ptr(unsafe { - ffi::notmuch_messages_collect_tags(self.handle.ptr) - }) + pub fn collect_tags<'m>(self: &'o Self) -> Tags<'m, Self> { + Tags::from_ptr( + unsafe { ffi::notmuch_messages_collect_tags(self.handle.ptr) }, + self, + ) } } +impl<'s, 'o: 's, Owner: MessagesOwner + 'o> StreamingIterator<'s, Message<'s, Self>> + for Messages<'o, Owner> +{ + fn next(&'s mut self) -> Option<Message<'s, Self>> { + let valid = unsafe { ffi::notmuch_messages_valid(self.handle.ptr) }; - -impl<'o, Owner: MessagesOwner + 'o> Iterator for Messages<'o, Owner> { - type Item = Message<'o, Self>; - - fn next(&mut self) -> Option<Self::Item> { - - let valid = unsafe { - ffi::notmuch_messages_valid(self.handle.ptr) - }; - - if valid == 0{ - return None + if valid == 0 { + return None; } let cmsg = unsafe { @@ -99,9 +87,9 @@ impl<'o, Owner: MessagesOwner + 'o> Iterator for Messages<'o, Owner> { msg }; - Some(Self::Item::from_ptr(cmsg)) + Some(Message::from_ptr(cmsg, Supercow::borrowed(self))) } } -unsafe impl<'o, Owner: MessagesOwner + 'o> Send for Messages<'o, Owner>{} -unsafe impl<'o, Owner: MessagesOwner + 'o> Sync for Messages<'o, Owner>{} +unsafe impl<'o, Owner: MessagesOwner + 'o> Send for Messages<'o, Owner> {} +unsafe impl<'o, Owner: MessagesOwner + 'o> Sync for Messages<'o, Owner> {} diff --git a/src/query.rs b/src/query.rs index a95c9c2..a90a0fe 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,128 +1,95 @@ use std::ops::Drop; use std::ptr; -use std::marker::PhantomData; +use supercow::Phantomcow; use error::Result; - use ffi; -use utils::FromPtr; - +use ffi::Sort; use Database; use Messages; +use MessagesOwner; use Threads; -use ffi::Sort; -use threads::ThreadsOwner; -use messages::MessagesOwner; +use ThreadsOwner; #[derive(Debug)] pub(crate) struct QueryPtr { - pub ptr: *mut ffi::notmuch_query_t + pub ptr: *mut ffi::notmuch_query_t, } impl Drop for QueryPtr { fn drop(&mut self) { - unsafe { - ffi::notmuch_query_destroy(self.ptr) - }; + unsafe { ffi::notmuch_query_destroy(self.ptr) }; } } #[derive(Debug)] -pub struct Query<'d>{ +pub struct Query<'d> { pub(crate) handle: QueryPtr, - phantom: PhantomData<&'d Database>, + marker: Phantomcow<'d, Database>, } -impl<'d> ThreadsOwner for Query<'d>{} -impl<'d> MessagesOwner for Query<'d>{} - +impl<'d> ThreadsOwner for Query<'d> {} +impl<'d> MessagesOwner for Query<'d> {} -impl<'d> FromPtr<*mut ffi::notmuch_query_t> for Query<'d> { - fn from_ptr(ptr: *mut ffi::notmuch_query_t) -> Query<'d> { - Query{ - handle: QueryPtr{ptr}, - phantom: PhantomData +impl<'d> Query<'d> { + pub fn from_ptr<O: Into<Phantomcow<'d, Database>>>( + ptr: *mut ffi::notmuch_query_t, + owner: O, + ) -> Query<'d> { + Query { + handle: QueryPtr { ptr }, + marker: owner.into(), } } -} -impl<'d> Query<'d> { pub fn create(db: &'d Database, query_string: &str) -> Result<Self> { db.create_query(query_string) } /// Specify the sorting desired for this query. - pub fn set_sort(self: &Self, sort: Sort) - { - unsafe { - ffi::notmuch_query_set_sort( - self.handle.ptr, sort.into(), - ) - } + pub fn set_sort(self: &Self, sort: Sort) { + unsafe { ffi::notmuch_query_set_sort(self.handle.ptr, sort.into()) } } /// Return the sort specified for this query. See /// `set_sort`. - pub fn sort(self: &Self) -> Sort - { - unsafe { - ffi::notmuch_query_get_sort( - self.handle.ptr, - ) - }.into() + pub fn sort(self: &Self) -> Sort { + unsafe { ffi::notmuch_query_get_sort(self.handle.ptr) }.into() } - /// Filter messages according to the query and return - pub fn search_messages<'q>(self: &'d Self) -> Result<Messages<'q, Self>> - { + pub fn search_messages<'q>(self: &'d Self) -> Result<Messages<'q, Self>> { let mut msgs = ptr::null_mut(); - try!(unsafe { - ffi::notmuch_query_search_messages( - self.handle.ptr, &mut msgs, - ) - }.as_result()); + try!( + unsafe { ffi::notmuch_query_search_messages(self.handle.ptr, &mut msgs,) }.as_result() + ); - Ok(Messages::from_ptr(msgs)) + Ok(Messages::from_ptr(msgs, self)) } - pub fn count_messages(self: &Self) -> Result<u32> - { + pub fn count_messages(self: &Self) -> Result<u32> { let mut cnt = 0; - try!(unsafe { - ffi::notmuch_query_count_messages( - self.handle.ptr, &mut cnt, - ) - }.as_result()); + try!(unsafe { ffi::notmuch_query_count_messages(self.handle.ptr, &mut cnt,) }.as_result()); Ok(cnt) } - pub fn search_threads<'q>(self: &'d Self) -> Result<Threads<'q, Self>> - { + pub fn search_threads<'q>(self: &'d Self) -> Result<Threads<'q, Self>> { let mut thrds = ptr::null_mut(); - try!(unsafe { - ffi::notmuch_query_search_threads( - self.handle.ptr, &mut thrds, - ) - }.as_result()); + try!( + unsafe { ffi::notmuch_query_search_threads(self.handle.ptr, &mut thrds,) }.as_result() + ); - Ok(Threads::from_ptr(thrds)) + Ok(Threads::from_ptr(thrds, self)) } - pub fn count_threads(self: &Self) -> Result<u32> - { + pub fn count_threads(self: &Self) -> Result<u32> { let mut cnt = 0; - try!(unsafe { - ffi::notmuch_query_count_threads( - self.handle.ptr, &mut cnt, - ) - }.as_result()); + try!(unsafe { ffi::notmuch_query_count_threads(self.handle.ptr, &mut cnt,) }.as_result()); Ok(cnt) } } - unsafe impl<'d> Send for Query<'d> {} unsafe impl<'d> Sync for Query<'d> {} diff --git a/src/tags.rs b/src/tags.rs index fa21ff7..187e26c 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -1,35 +1,39 @@ -use std::ops::Drop; -use std::iter::Iterator; -use std::marker::PhantomData; use std::ffi::CStr; +use std::iter::Iterator; +use std::ops::Drop; -use utils::{ - FromPtr, -}; +use supercow::Phantomcow; -use Database; use ffi; -pub trait TagsOwner{} - +pub trait TagsOwner {} #[derive(Debug)] -pub struct Tags<'o, Owner: TagsOwner + 'o>( - *mut ffi::notmuch_tags_t, - PhantomData<&'o Owner>, -); - -impl<'o, Owner: TagsOwner + 'o> FromPtr<*mut ffi::notmuch_tags_t> for Tags<'o, Owner> { - fn from_ptr(ptr: *mut ffi::notmuch_tags_t) -> Tags<'o, Owner> { - Tags(ptr, PhantomData) - } +pub(crate) struct TagsPtr { + pub ptr: *mut ffi::notmuch_tags_t, } -impl<'o, Owner: TagsOwner + 'o> Drop for Tags<'o, Owner> { +impl Drop for TagsPtr { fn drop(&mut self) { - unsafe { - ffi::notmuch_tags_destroy(self.0) - }; + unsafe { ffi::notmuch_tags_destroy(self.ptr) }; + } +} + +#[derive(Debug)] +pub struct Tags<'o, Owner: TagsOwner + 'o> { + handle: TagsPtr, + marker: Phantomcow<'o, Owner>, +} + +impl<'o, Owner: TagsOwner + 'o> Tags<'o, Owner> { + pub fn from_ptr<O: Into<Phantomcow<'o, Owner>>>( + ptr: *mut ffi::notmuch_tags_t, + owner: O, + ) -> Tags<'o, Owner> { + Tags { + handle: TagsPtr { ptr }, + marker: owner.into(), + } } } @@ -37,18 +41,15 @@ impl<'o, Owner: TagsOwner + 'o> Iterator for Tags<'o, Owner> { type Item = String; fn next(&mut self) -> Option<Self::Item> { + let valid = unsafe { ffi::notmuch_tags_valid(self.handle.ptr) }; - let valid = unsafe { - ffi::notmuch_tags_valid(self.0) - }; - - if valid == 0{ - return None + if valid == 0 { + return None; } let ctag = unsafe { - let t = ffi::notmuch_tags_get(self.0); - ffi::notmuch_tags_move_to_next(self.0); + let t = ffi::notmuch_tags_get(self.handle.ptr); + ffi::notmuch_tags_move_to_next(self.handle.ptr); CStr::from_ptr(t) }; @@ -57,5 +58,5 @@ impl<'o, Owner: TagsOwner + 'o> Iterator for Tags<'o, Owner> { } } -unsafe impl<'o, Owner: TagsOwner + 'o> Send for Tags<'o, Owner>{} -unsafe impl<'o, Owner: TagsOwner + 'o> Sync for Tags<'o, Owner>{} +unsafe impl<'o, Owner: TagsOwner + 'o> Send for Tags<'o, Owner> {} +unsafe impl<'o, Owner: TagsOwner + 'o> Sync for Tags<'o, Owner> {} diff --git a/src/thread.rs b/src/thread.rs index 55ed982..9a63c94 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -1,128 +1,110 @@ use std::ops::Drop; -use std::marker::PhantomData; +use supercow::Phantomcow; + use ffi; -use utils::{ - FromPtr, - ToStr -}; -use Query; +use utils::ToStr; use Messages; +use MessagesOwner; use Tags; -use messages::MessagesOwner; -use tags::TagsOwner; - -pub trait ThreadOwner{} +use TagsOwner; +pub trait ThreadOwner {} #[derive(Debug)] pub(crate) struct ThreadPtr { - pub ptr: *mut ffi::notmuch_thread_t + pub ptr: *mut ffi::notmuch_thread_t, } impl Drop for ThreadPtr { fn drop(&mut self) { - unsafe { - ffi::notmuch_thread_destroy(self.ptr) - }; + unsafe { ffi::notmuch_thread_destroy(self.ptr) }; } } - #[derive(Debug)] -pub struct Thread<'o, Owner: ThreadOwner + 'o>{ +pub struct Thread<'o, Owner: ThreadOwner + 'o> { pub(crate) handle: ThreadPtr, - phantom: PhantomData<&'o Owner>, + marker: Phantomcow<'o, Owner>, } -impl<'o, Owner: ThreadOwner + 'o> MessagesOwner for Thread<'o, Owner>{} -impl<'o, Owner: ThreadOwner + 'o> TagsOwner for Thread<'o, Owner>{} - - -impl<'o, Owner: ThreadOwner + 'o> FromPtr<*mut ffi::notmuch_thread_t> for Thread<'o, Owner> { - fn from_ptr(ptr: *mut ffi::notmuch_thread_t) -> Thread<'o, Owner> { - Thread{ - handle: ThreadPtr{ptr}, - phantom: PhantomData +impl<'o, Owner: ThreadOwner + 'o> MessagesOwner for Thread<'o, Owner> {} +impl<'o, Owner: ThreadOwner + 'o> TagsOwner for Thread<'o, Owner> {} + +impl<'o, Owner: ThreadOwner + 'o> Thread<'o, Owner> { + pub fn from_ptr<O: Into<Phantomcow<'o, Owner>>>( + ptr: *mut ffi::notmuch_thread_t, + owner: O, + ) -> Thread<'o, Owner> { + Thread { + handle: ThreadPtr { ptr }, + marker: owner.into(), } } -} - -impl<'o, Owner: ThreadOwner + 'o> Thread<'o, Owner>{ - pub fn id(self: &Self) -> String{ - let tid = unsafe { - ffi::notmuch_thread_get_thread_id(self.handle.ptr) - }; + pub fn id(self: &Self) -> String { + let tid = unsafe { ffi::notmuch_thread_get_thread_id(self.handle.ptr) }; tid.to_str().unwrap().to_string() } - - pub fn total_messages(self: &Self) -> i32{ - unsafe { - ffi::notmuch_thread_get_total_messages(self.handle.ptr) - } + pub fn total_messages(self: &Self) -> i32 { + unsafe { ffi::notmuch_thread_get_total_messages(self.handle.ptr) } } #[cfg(feature = "0.26")] - pub fn total_files(self: &Self) -> i32{ - unsafe { - ffi::notmuch_thread_get_total_files(self.handle.ptr) - } + pub fn total_files(self: &Self) -> i32 { + unsafe { ffi::notmuch_thread_get_total_files(self.handle.ptr) } } - - pub fn toplevel_messages(self: &Self) -> Messages<Self>{ - Messages::from_ptr(unsafe { - ffi::notmuch_thread_get_toplevel_messages(self.handle.ptr) - }) + pub fn toplevel_messages(self: &Self) -> Messages<Self> { + Messages::from_ptr( + unsafe { ffi::notmuch_thread_get_toplevel_messages(self.handle.ptr) }, + self, + ) } /// Get a `Messages` iterator for all messages in 'thread' in /// oldest-first order. - pub fn messages(self: &Self) -> Messages<Self>{ - Messages::from_ptr(unsafe { - ffi::notmuch_thread_get_messages(self.handle.ptr) - }) + pub fn messages(self: &Self) -> Messages<Self> { + Messages::from_ptr( + unsafe { ffi::notmuch_thread_get_messages(self.handle.ptr) }, + self, + ) } - - pub fn tags<'t>(self: &Self) -> Tags<'t, Self>{ - Tags::from_ptr(unsafe { - ffi::notmuch_thread_get_tags(self.handle.ptr) - }) + pub fn tags<'t>(&'t self) -> Tags<'t, Self> { + Tags::from_ptr( + unsafe { ffi::notmuch_thread_get_tags(self.handle.ptr) }, + self, + ) } - pub fn subject(self: &Self) -> String{ - let sub = unsafe { - ffi::notmuch_thread_get_subject(self.handle.ptr) - }; + pub fn subject(self: &Self) -> String { + let sub = unsafe { ffi::notmuch_thread_get_subject(self.handle.ptr) }; sub.to_str().unwrap().to_string() } - pub fn authors(self: &Self) -> Vec<String>{ - let athrs = unsafe { - ffi::notmuch_thread_get_authors(self.handle.ptr) - }; + pub fn authors(self: &Self) -> Vec<String> { + let athrs = unsafe { ffi::notmuch_thread_get_authors(self.handle.ptr) }; - athrs.to_str().unwrap().split(',').map(|s| s.to_string()).collect() + athrs + .to_str() + .unwrap() + .split(',') + .map(|s| s.to_string()) + .collect() } /// Get the date of the oldest message in 'thread' as a time_t value. pub fn oldest_date(self: &Self) -> i64 { - unsafe { - ffi::notmuch_thread_get_oldest_date(self.handle.ptr) - } + unsafe { ffi::notmuch_thread_get_oldest_date(self.handle.ptr) } } /// Get the date of the newest message in 'thread' as a time_t value. pub fn newest_date(self: &Self) -> i64 { - unsafe { - ffi::notmuch_thread_get_newest_date(self.handle.ptr) - } + unsafe { ffi::notmuch_thread_get_newest_date(self.handle.ptr) } } } - unsafe impl<'o, Owner: ThreadOwner + 'o> Send for Thread<'o, Owner> {} unsafe impl<'o, Owner: ThreadOwner + 'o> Sync for Thread<'o, Owner> {} diff --git a/src/threads.rs b/src/threads.rs index a2edef8..359569e 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -1,57 +1,52 @@ use std::ops::Drop; -use std::iter::Iterator; -use std::marker::PhantomData; -use utils::FromPtr; -use Query; -use Thread; +use supercow::{Phantomcow, Supercow}; +use utils::StreamingIterator; + use ffi; use thread::ThreadOwner; +use Thread; -pub trait ThreadsOwner{} - +pub trait ThreadsOwner {} #[derive(Debug)] pub(crate) struct ThreadsPtr { - pub ptr: *mut ffi::notmuch_threads_t + pub ptr: *mut ffi::notmuch_threads_t, } impl Drop for ThreadsPtr { fn drop(&mut self) { - unsafe { - ffi::notmuch_threads_destroy(self.ptr) - }; + unsafe { ffi::notmuch_threads_destroy(self.ptr) }; } } #[derive(Debug)] -pub struct Threads<'o, Owner: ThreadsOwner + 'o>{ +pub struct Threads<'o, Owner: ThreadsOwner + 'o> { handle: ThreadsPtr, - phantom: PhantomData<&'o Owner>, + marker: Phantomcow<'o, Owner>, } -impl<'o, Owner: ThreadsOwner + 'o> ThreadOwner for Threads<'o, Owner>{} +impl<'o, Owner: ThreadsOwner + 'o> ThreadOwner for Threads<'o, Owner> {} - -impl<'o, Owner: ThreadsOwner + 'o> FromPtr<*mut ffi::notmuch_threads_t> for Threads<'o, Owner> { - fn from_ptr(ptr: *mut ffi::notmuch_threads_t) -> Threads<'o, Owner> { - Threads{ - handle: ThreadsPtr{ptr}, - phantom: PhantomData +impl<'o, Owner: ThreadsOwner + 'o> Threads<'o, Owner> { + pub fn from_ptr<O: Into<Phantomcow<'o, Owner>>>( + ptr: *mut ffi::notmuch_threads_t, + owner: O, + ) -> Threads<'o, Owner> { + Threads { + handle: ThreadsPtr { ptr }, + marker: owner.into(), } } } -impl<'o, Owner: ThreadsOwner + 'o> Iterator for Threads<'o, Owner> { - type Item = Thread<'o, Self>; - - fn next(self: &mut Self) -> Option<Self::Item> { - - let valid = unsafe { - ffi::notmuch_threads_valid(self.handle.ptr) - }; +impl<'s, 'o: 's, Owner: ThreadsOwner + 'o> StreamingIterator<'s, Thread<'s, Self>> + for Threads<'o, Owner> +{ + fn next(&'s mut self) -> Option<Thread<'s, Self>> { + let valid = unsafe { ffi::notmuch_threads_valid(self.handle.ptr) }; - if valid == 0{ + if valid == 0 { return None; } @@ -61,7 +56,7 @@ impl<'o, Owner: ThreadsOwner + 'o> Iterator for Threads<'o, Owner> { t }; - Some(Self::Item::from_ptr(cthread)) + Some(Thread::from_ptr(cthread, Supercow::borrowed(self))) } } diff --git a/src/utils.rs b/src/utils.rs index 5db8957..5cce04d 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,16 +1,5 @@ -use std::{ - ffi, - str, -}; use libc; - -pub trait FromPtr<T> { - fn from_ptr(ptr: T) -> Self; -} - -// pub trait NewFromPtr<T, P> { -// fn new(ptr: T, parent: Rc<P>) -> Self; -// } +use std::{ffi, str}; pub trait ToStr { fn to_str<'a>(&self) -> Result<&'a str, str::Utf8Error>; @@ -18,9 +7,7 @@ pub trait ToStr { impl ToStr for *const libc::c_char { fn to_str<'a>(&self) -> Result<&'a str, str::Utf8Error> { - str::from_utf8(unsafe { - ffi::CStr::from_ptr(*self) - }.to_bytes()) + str::from_utf8(unsafe { ffi::CStr::from_ptr(*self) }.to_bytes()) } } @@ -30,13 +17,13 @@ pub trait ToString { impl ToString for *const libc::c_char { fn to_string(&self) -> String { - unsafe { - ffi::CStr::from_ptr(*self).to_string_lossy().into_owned() - } + unsafe { ffi::CStr::from_ptr(*self).to_string_lossy().into_owned() } } } - -pub struct Owner; - - +/// A streaming iterator, as found in https://github.com/emk/rust-streaming +pub trait StreamingIterator<'a, T> { + /// Return either the next item in the sequence, or `None` if all items + /// have been consumed. + fn next(&'a mut self) -> Option<T>; +} diff --git a/tests/main.rs b/tests/main.rs index 6840dc0..d790e21 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -1,6 +1,8 @@ extern crate notmuch; extern crate dirs; +use notmuch::StreamingIterator; + fn main() { let mut mail_path = dirs::home_dir().unwrap(); @@ -18,15 +20,11 @@ fn main() { let query = db.create_query(&"".to_string()).unwrap(); let mut threads = query.search_threads().unwrap(); - loop { - match threads.next() { - Some(thread) => { - println!("thread {:?} {:?}", thread.subject(), thread.authors()); - }, - None => { break } - } + while let Some(thread) = threads.next() { + println!("thread {:?} {:?}", thread.subject(), thread.authors()); } + }, Err(err) =>{ println!("Got error while trying to open db: {:?}", err); |
