From ba1fe92db346363ffb19521b06c146ba8f6ffc37 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Fri, 13 Mar 2015 15:52:55 -0400 Subject: Create empty crate. Initial version of Cargo.toml. --- Cargo.toml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 Cargo.toml diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..416db6c --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,5 @@ +[package] + +name = "notmuch" +version = "0.0.1" +authors = ["C. Morgan Hamill "] -- cgit v1.2.1 From a7dfdf8bf6a9576f26a50543b03f0fb83e35dec6 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Fri, 13 Mar 2015 15:53:40 -0400 Subject: Add .gitignore file. Set to ignore Cargo.lock and /target/. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..80faede --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +Cargo.lock +/target/ -- cgit v1.2.1 From b58ecb89aa5048420244145dfd5ae51e218f9ea4 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Fri, 13 Mar 2015 15:55:41 -0400 Subject: Add root module at src/lib.rs. Use libc crate. --- src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 src/lib.rs diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..8316b8e --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,2 @@ +#![feature(libc)] +extern crate libc; -- cgit v1.2.1 From 8d22f9ea2d316889a529ea7a5526dcc23a12cfb1 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Fri, 13 Mar 2015 16:00:43 -0400 Subject: Add empty ffi module. --- src/ffi.rs | 3 +++ src/lib.rs | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 src/ffi.rs diff --git a/src/ffi.rs b/src/ffi.rs new file mode 100644 index 0000000..fa541d6 --- /dev/null +++ b/src/ffi.rs @@ -0,0 +1,3 @@ +#![allow(dead_code, non_camel_case_types)] + +//! Re-presentation of the notmuch C API. diff --git a/src/lib.rs b/src/lib.rs index 8316b8e..5c2fbd6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,4 @@ #![feature(libc)] extern crate libc; + +mod ffi; -- cgit v1.2.1 From a0f345202299b5f5214f1a791e896376e6cb7a04 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Tue, 17 Mar 2015 10:20:15 -0400 Subject: Add notmuch C API bindings. The ffi module now reproduces the notmuch C API, as defined in `notmuch.h`, more-or-less verbatim. --- src/ffi.rs | 427 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 427 insertions(+) diff --git a/src/ffi.rs b/src/ffi.rs index fa541d6..dba98b5 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -1,3 +1,430 @@ #![allow(dead_code, non_camel_case_types)] //! Re-presentation of the notmuch C API. + +use libc::{ + c_char, + c_double, + c_int, + c_uint, + c_void, + time_t, +}; + +pub type notmuch_bool_t = c_int; + +pub type notmuch_compact_status_cb_t = extern fn(*const c_char, *mut c_void); + +#[repr(C)] +#[derive(Copy, Debug)] +pub enum notmuch_status_t { + NOTMUCH_STATUS_SUCCESS = 0, + NOTMUCH_STATUS_OUT_OF_MEMORY, + NOTMUCH_STATUS_READ_ONLY_DATABASE, + NOTMUCH_STATUS_XAPIAN_EXCEPTION, + NOTMUCH_STATUS_FILE_ERROR, + NOTMUCH_STATUS_FILE_NOT_EMAIL, + NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID, + NOTMUCH_STATUS_NULL_POINTER, + NOTMUCH_STATUS_TAG_TOO_LONG, + NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW, + NOTMUCH_STATUS_UNBALANCED_ATOMIC, + NOTMUCH_STATUS_UNSUPPORTED_OPERATION, + NOTMUCH_STATUS_UPGRADE_REQUIRED, + // Not an actual status value. Just a way to find out how many + // valid status values there are. + NOTMUCH_STATUS_LAST_STATUS, +} + +#[repr(C)] +#[derive(Copy, Debug)] +pub enum notmuch_database_mode_t { + NOTMUCH_DATABASE_MODE_READ_ONLY = 0, + NOTMUCH_DATABASE_MODE_READ_WRITE, +} + +#[repr(C)] +#[derive(Copy, Debug)] +pub enum notmuch_sort_t { + NOTMUCH_SORT_OLDEST_FIRST = 0, + NOTMUCH_SORT_NEWEST_FIRST, + NOTMUCH_SORT_MESSAGE_ID, + NOTMUCH_SORT_UNSORTED, +} + +#[repr(C)] +#[derive(Copy, Debug)] +pub enum notmuch_exclude_t { + NOTMUCH_EXCLUDE_FLAG = 0, + NOTMUCH_EXCLUDE_TRUE, + NOTMUCH_EXCLUDE_FALSE, + NOTMUCH_EXCLUDE_ALL, +} + +#[repr(C)] +#[derive(Copy, Debug)] +pub enum notmuch_message_flag_t { + NOTMUCH_MESSAGE_FLAG_MATCH = 0, + NOTMUCH_MESSAGE_FLAG_EXCLUDED, + NOTMUCH_MESSAGE_FLAG_GHOST, +} + +#[repr(C)] pub struct notmuch_database_t; +#[repr(C)] pub struct notmuch_query_t; +#[repr(C)] pub struct notmuch_threads_t; +#[repr(C)] pub struct notmuch_thread_t; +#[repr(C)] pub struct notmuch_messages_t; +#[repr(C)] pub struct notmuch_message_t; +#[repr(C)] pub struct notmuch_tags_t; +#[repr(C)] pub struct notmuch_directory_t; +#[repr(C)] pub struct notmuch_filenames_t; + +#[link(name = "notmuch")] +extern { + pub fn notmuch_status_to_string( + status: notmuch_status_t, + ) -> *const c_char; + + pub fn notmuch_database_create( + path: *const c_char, + database: *mut *mut notmuch_database_t, + ) -> notmuch_status_t; + + pub fn notmuch_database_open( + path: *const c_char, + mode: notmuch_database_mode_t, + database: *mut *mut notmuch_database_t, + ) -> notmuch_status_t; + + pub fn notmuch_database_close( + database: *mut notmuch_database_t, + ) -> notmuch_status_t; + + pub fn notmuch_database_compact( + path: *const c_char, + backup_path: *const c_char, + status_cb: Option, + closure: *mut c_void, + ) -> notmuch_status_t; + + pub fn notmuch_database_destroy( + database: *mut notmuch_database_t, + ) -> notmuch_status_t; + + pub fn notmuch_database_get_path( + database: *mut notmuch_database_t, + ) -> *const c_char; + + pub fn notmuch_database_get_version( + database: *mut notmuch_database_t, + ) -> c_uint; + + pub fn notmuch_database_needs_upgrade( + database: *mut notmuch_database_t, + ) -> notmuch_bool_t; + + pub fn notmuch_database_upgrade( + database: *mut notmuch_database_t, + progress_notify: Option, + closure: *mut c_void, + ) -> notmuch_status_t; + + pub fn notmuch_database_begin_atomic( + notmuch: *mut notmuch_database_t, + ) -> notmuch_status_t; + + pub fn notmuch_database_end_atomic( + notmuch: *mut notmuch_database_t, + ) -> notmuch_status_t; + + pub fn notmuch_database_get_directory( + database: *mut notmuch_database_t, + path: *const c_char, + directory: *mut *mut notmuch_directory_t, + ) -> notmuch_status_t; + + pub fn notmuch_database_add_message( + database: *mut notmuch_database_t, + filename: *const c_char, + message: *mut *mut notmuch_message_t, + ) -> notmuch_status_t; + + pub fn notmuch_database_remove_message( + database: *mut notmuch_database_t, + filename: *const c_char, + ) -> notmuch_status_t; + + pub fn notmuch_database_find_message( + database: *mut notmuch_database_t, + message_id: *const c_char, + message: *mut *mut notmuch_message_t, + ) -> notmuch_status_t; + + pub fn notmuch_database_find_message_by_filename( + database: *mut notmuch_database_t, + filename: *const c_char, + message: *mut *mut notmuch_message_t, + ) -> notmuch_status_t; + + pub fn notmuch_database_get_all_tags( + db: *mut notmuch_database_t, + ) -> *mut notmuch_tags_t; + + pub fn notmuch_query_create( + database: *mut notmuch_database_t, + query_string: *const c_char, + ) -> *mut notmuch_query_t; + + pub fn notmuch_query_get_string( + query: *mut notmuch_query_t, + ) -> *const c_char; + + pub fn notmuch_query_set_omit_excluded( + query: *mut notmuch_query_t, + omit_excluded: notmuch_exclude_t, + ); + + pub fn notmuch_query_set_sort( + query: *mut notmuch_query_t, + sort: notmuch_sort_t, + ); + + pub fn notmuch_query_get_sort( + query: *mut notmuch_query_t, + ) -> notmuch_sort_t; + + pub fn notmuch_query_add_tag_exclude( + query: *mut notmuch_query_t, + tag: *const c_char, + ); + + pub fn notmuch_query_search_threads( + query: *mut notmuch_query_t, + ) -> *mut notmuch_threads_t; + + pub fn notmuch_query_search_messages( + query: *mut notmuch_query_t, + ) -> *mut notmuch_messages_t; + + pub fn notmuch_query_destroy( + query: *mut notmuch_query_t, + ); + + pub fn notmuch_threads_valid( + threads: *mut notmuch_threads_t, + ) -> notmuch_bool_t; + + pub fn notmuch_threads_get( + threads: *mut notmuch_threads_t, + ) -> *mut notmuch_thread_t; + + pub fn notmuch_threads_move_to_next( + threads: *mut notmuch_threads_t, + ); + + pub fn notmuch_threads_destroy( + threads: *mut notmuch_threads_t, + ); + + pub fn notmuch_query_count_messages( + query: *mut notmuch_query_t, + ) -> c_uint; + + pub fn notmuch_count_threads( + query: *mut notmuch_query_t, + ) -> c_uint; + + pub fn notmuch_thread_get_thread_id( + thread: *mut notmuch_thread_t, + ) -> *const c_char; + + pub fn notmuch_thread_get_total_messages( + thread: *mut notmuch_thread_t, + ) -> c_int; + + pub fn notmuch_thread_get_toplevel_messages( + thread: *mut notmuch_thread_t, + ) -> *mut notmuch_messages_t; + + pub fn notmuch_thread_get_messages( + thread: *mut notmuch_thread_t, + ) -> *mut notmuch_messages_t; + + pub fn notmuch_thread_get_matched_messages( + thread: *mut notmuch_thread_t, + ) -> c_int; + + pub fn notmuch_thread_get_authors( + thread: *mut notmuch_thread_t, + ) -> *const c_char; + + pub fn notmuch_thread_get_subject( + thread: *mut notmuch_thread_t, + ) -> *const c_char; + + pub fn notmuch_thread_get_oldest_date( + thread: *mut notmuch_thread_t, + ) -> time_t; + + pub fn notmuch_thread_get_newest_date( + thread: *mut notmuch_thread_t, + ) -> time_t; + + pub fn notmuch_thread_get_tags( + thread: *mut notmuch_thread_t, + ) -> *mut notmuch_tags_t; + + pub fn notmuch_thread_destroy( + thread: *mut notmuch_thread_t, + ); + + pub fn notmuch_messages_valid( + messages: *mut notmuch_messages_t, + ) -> notmuch_bool_t; + + pub fn notmuch_messages_get( + messages: *mut notmuch_messages_t, + ) -> *mut notmuch_message_t; + + pub fn notmuch_messages_move_to_next( + messages: *mut notmuch_messages_t, + ); + + pub fn notmuch_messages_destroy( + messages: *mut notmuch_messages_t, + ); + + pub fn notmuch_messages_collect_tags( + messages: *mut notmuch_messages_t, + ) -> *mut notmuch_tags_t; + + pub fn notmuch_message_get_message_id( + message: *mut notmuch_message_t, + ) -> *const c_char; + + pub fn notmuch_message_get_thread_id( + message: *mut notmuch_message_t, + ) -> *const c_char; + + pub fn notmuch_message_get_replies( + message: *mut notmuch_message_t, + ) -> *mut notmuch_messages_t; + + pub fn notmuch_message_get_filename( + message: *mut notmuch_message_t, + ) -> *const c_char; + + pub fn notmuch_message_get_filenames( + message: *mut notmuch_message_t, + ) -> *mut notmuch_filenames_t; + + pub fn notmuch_message_get_flag( + message: *mut notmuch_message_t, + flag: notmuch_message_flag_t, + ) -> notmuch_bool_t; + + pub fn notmuch_message_set_flag( + message: *mut notmuch_message_t, + flag: notmuch_message_flag_t, + value: notmuch_bool_t, + ); + + pub fn notmuch_message_get_date( + message: *mut notmuch_message_t, + ) -> time_t; + + pub fn notmuch_message_get_header( + message: *mut notmuch_message_t, + header: *const c_char, + ) -> *const c_char; + + pub fn notmuch_message_get_tags( + message: *mut notmuch_message_t, + ) -> *mut notmuch_tags_t; + + pub fn notmuch_message_add_tag( + message: *mut notmuch_message_t, + tag: *const c_char, + ) -> notmuch_status_t; + + pub fn notmuch_message_remove_tag( + message: *mut notmuch_message_t, + tag: *const c_char, + ) -> notmuch_status_t; + + pub fn notmuch_message_remove_all_tags( + message: *mut notmuch_message_t, + ) -> notmuch_status_t; + + pub fn notmuch_message_maildir_flags_to_tags( + message: *mut notmuch_message_t, + ) -> notmuch_status_t; + + pub fn notmuch_message_tags_to_maildir_flags( + message: *mut notmuch_message_t, + ) -> notmuch_status_t; + + pub fn notmuch_message_freeze( + message: *mut notmuch_message_t, + ) -> notmuch_status_t; + + pub fn notmuch_message_thaw( + message: *mut notmuch_message_t, + ) -> notmuch_status_t; + + pub fn notmuch_message_destroy( + message: *mut notmuch_message_t, + ); + + pub fn notmuch_tags_valid( + tags: *mut notmuch_tags_t, + ) -> notmuch_bool_t; + + pub fn notmuch_tags_get( + tags: *mut notmuch_tags_t, + ) -> *const c_char; + + pub fn notmuch_tags_move_to_next( + tags: *mut notmuch_tags_t, + ); + + pub fn notmuch_tags_destroy( + tags: *mut notmuch_tags_t, + ); + + pub fn notmuch_directory_set_mtime( + directory: *mut notmuch_directory_t, + ) -> notmuch_status_t; + + pub fn notmuch_directory_get_mtime( + directory: *mut notmuch_directory_t, + ) -> time_t; + + pub fn notmuch_directory_get_child_files( + directory: *mut notmuch_directory_t, + ) -> *mut notmuch_filenames_t; + + pub fn notmuch_directory_get_child_directories( + directory: *mut notmuch_directory_t, + ) -> *mut notmuch_filenames_t; + + pub fn notmuch_directory_destroy( + directory: *mut notmuch_directory_t, + ); + + pub fn notmuch_filenames_valid( + filenames: *mut notmuch_filenames_t, + ) -> notmuch_bool_t; + + pub fn notmuch_filenames_get( + filenames: *mut notmuch_filenames_t, + ) -> *const c_char; + + pub fn notmuch_filenames_move_to_next( + filenames: *mut notmuch_filenames_t, + ); + + pub fn notmuch_filenames_destroy( + filenames: *mut notmuch_filenames_t, + ); +} -- cgit v1.2.1 From acb67e3d7fef9e83e0be3150d42af3dd02e33fa6 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Thu, 19 Mar 2015 11:43:51 -0400 Subject: Add `NotmuchEnum` trait and `notmuch_enum!` macro. Implements enum types in pairs, specifying the type and variant names of each, like so: notmuch_enum! { pub enum enum_name => EnumName { variant_one => VariantOne, variant_two => VariantTwo } } Which expands to: pub enum enum_name { variant_one, variant_two } pub enum EnumName { VariantOne, VariantTwo } The `NotmuchEnum` trait also entails two functions to convert between the defined pairs, `from_notmuch_t()` and `to_notmuch_t()`. The macro takes care of their implementation, also. Yes, this is purely aesthetic whimsy: I wanted the types in the `ffi` module to match the types from the `notmuch.h` file, and I wanted the types I used within (and exported by) this crate to match the expected Rust convention. --- src/ffi.rs | 101 +++++++++++++++++++++++++++++++++------------------------- src/lib.rs | 4 +++ src/macros.rs | 35 ++++++++++++++++++++ src/utils.rs | 6 ++++ 4 files changed, 102 insertions(+), 44 deletions(-) create mode 100644 src/macros.rs create mode 100644 src/utils.rs diff --git a/src/ffi.rs b/src/ffi.rs index dba98b5..9cc6f47 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -11,62 +11,75 @@ use libc::{ time_t, }; +use utils::NotmuchEnum; + pub type notmuch_bool_t = c_int; pub type notmuch_compact_status_cb_t = extern fn(*const c_char, *mut c_void); -#[repr(C)] -#[derive(Copy, Debug)] -pub enum notmuch_status_t { - NOTMUCH_STATUS_SUCCESS = 0, - NOTMUCH_STATUS_OUT_OF_MEMORY, - NOTMUCH_STATUS_READ_ONLY_DATABASE, - NOTMUCH_STATUS_XAPIAN_EXCEPTION, - NOTMUCH_STATUS_FILE_ERROR, - NOTMUCH_STATUS_FILE_NOT_EMAIL, - NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID, - NOTMUCH_STATUS_NULL_POINTER, - NOTMUCH_STATUS_TAG_TOO_LONG, - NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW, - NOTMUCH_STATUS_UNBALANCED_ATOMIC, - NOTMUCH_STATUS_UNSUPPORTED_OPERATION, - NOTMUCH_STATUS_UPGRADE_REQUIRED, - // Not an actual status value. Just a way to find out how many - // valid status values there are. - NOTMUCH_STATUS_LAST_STATUS, +notmuch_enum! { + #[repr(C)] + #[derive(Copy, Debug)] + pub enum notmuch_status_t => NotmuchStatus { + NOTMUCH_STATUS_SUCCESS => Success, + NOTMUCH_STATUS_OUT_OF_MEMORY => OutOfMemory, + NOTMUCH_STATUS_READ_ONLY_DATABASE => ReadOnlyDatabase, + NOTMUCH_STATUS_XAPIAN_EXCEPTION => XapianException, + NOTMUCH_STATUS_FILE_ERROR => FileError, + NOTMUCH_STATUS_FILE_NOT_EMAIL => FileNotEmail, + NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID => DuplicateMessageID, + NOTMUCH_STATUS_NULL_POINTER => NullPointer, + NOTMUCH_STATUS_TAG_TOO_LONG => TagTooLong, + NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW => UnbalancedFreezeThaw, + NOTMUCH_STATUS_UNBALANCED_ATOMIC => UnbalancedAtomic, + NOTMUCH_STATUS_UNSUPPORTED_OPERATION => UnsupportedOperation, + NOTMUCH_STATUS_UPGRADE_REQUIRED => UpgradeRequired, + // Not an actual status value. Just a way to find out how many + // valid status values there are. + NOTMUCH_STATUS_LAST_STATUS => LastStatus + } +} } -#[repr(C)] -#[derive(Copy, Debug)] -pub enum notmuch_database_mode_t { - NOTMUCH_DATABASE_MODE_READ_ONLY = 0, - NOTMUCH_DATABASE_MODE_READ_WRITE, +notmuch_enum! { + #[repr(C)] + #[derive(Copy, Debug)] + pub enum notmuch_database_mode_t => NotmuchDatabaseMode { + NOTMUCH_DATABASE_MODE_READ_ONLY => ReadOnly, + NOTMUCH_DATABASE_MODE_READ_WRITE => ReadWrite + } } -#[repr(C)] -#[derive(Copy, Debug)] -pub enum notmuch_sort_t { - NOTMUCH_SORT_OLDEST_FIRST = 0, - NOTMUCH_SORT_NEWEST_FIRST, - NOTMUCH_SORT_MESSAGE_ID, - NOTMUCH_SORT_UNSORTED, +notmuch_enum! { + #[repr(C)] + #[derive(Copy, Debug)] + pub enum notmuch_sort_t => NotmuchSort { + NOTMUCH_SORT_OLDEST_FIRST => OldestFirst, + NOTMUCH_SORT_NEWEST_FIRST => NewestFirst, + NOTMUCH_SORT_MESSAGE_ID => MessageID, + NOTMUCH_SORT_UNSORTED => ReadWrite + } } -#[repr(C)] -#[derive(Copy, Debug)] -pub enum notmuch_exclude_t { - NOTMUCH_EXCLUDE_FLAG = 0, - NOTMUCH_EXCLUDE_TRUE, - NOTMUCH_EXCLUDE_FALSE, - NOTMUCH_EXCLUDE_ALL, +notmuch_enum! { + #[repr(C)] + #[derive(Copy, Debug)] + pub enum notmuch_exclude_t => NotmuchExclude { + NOTMUCH_EXCLUDE_FLAG => Flag, + NOTMUCH_EXCLUDE_TRUE => True, + NOTMUCH_EXCLUDE_FALSE => False, + NOTMUCH_EXCLUDE_ALL => All + } } -#[repr(C)] -#[derive(Copy, Debug)] -pub enum notmuch_message_flag_t { - NOTMUCH_MESSAGE_FLAG_MATCH = 0, - NOTMUCH_MESSAGE_FLAG_EXCLUDED, - NOTMUCH_MESSAGE_FLAG_GHOST, +notmuch_enum! { + #[repr(C)] + #[derive(Copy, Debug)] + pub enum notmuch_message_flag_t => NotmuchMessageFlag { + NOTMUCH_MESSAGE_FLAG_MATCH => Match, + NOTMUCH_MESSAGE_FLAG_EXCLUDED => Excluded, + NOTMUCH_MESSAGE_FLAG_GHOST => Ghost + } } #[repr(C)] pub struct notmuch_database_t; diff --git a/src/lib.rs b/src/lib.rs index 5c2fbd6..0f88f60 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,8 @@ #![feature(libc)] extern crate libc; +#[macro_use] +mod macros; + mod ffi; +mod utils; diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000..836be63 --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,35 @@ +#[macro_escape] +macro_rules! notmuch_enum { + ( + $(#[$enum_attr:meta])* + pub enum $name:ident => $name_alias:ident { + $($variant:ident => $variant_alias:ident),* + } + ) => { + $(#[$enum_attr])* + pub enum $name { + $($variant),* + } + + $(#[$enum_attr])* + pub enum $name_alias { + $($variant_alias),* + } + + impl NotmuchEnum for $name_alias { + type NotmuchT = $name; + + fn from_notmuch_t(notmuch_t: $name) -> Self { + match notmuch_t { + $($name::$variant => $name_alias::$variant_alias),* + } + } + + fn to_notmuch_t(self) -> $name { + match self { + $($name_alias::$variant_alias => $name::$variant),* + } + } + } + } +} diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..77e6e5e --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,6 @@ +pub trait NotmuchEnum { + type NotmuchT; + + fn from_notmuch_t(notmuch_t: Self::NotmuchT) -> Self; + fn to_notmuch_t(self) -> Self::NotmuchT; +} -- cgit v1.2.1 From 2c0a26ddf8385a4363cb8d4c54259abb33932ea8 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Thu, 19 Mar 2015 11:54:16 -0400 Subject: Add convenience methods to `notmuch_status_t`. Convenience methods for working the result of many of the native notmuch functions. --- src/ffi.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/ffi.rs b/src/ffi.rs index 9cc6f47..2ee99e0 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -39,6 +39,21 @@ notmuch_enum! { NOTMUCH_STATUS_LAST_STATUS => LastStatus } } + +impl notmuch_status_t { + pub fn is_ok(&self) -> bool { + match *self { + notmuch_status_t::NOTMUCH_STATUS_SUCCESS => true, + _ => false, + } + } + + pub fn as_result(self) -> Result<(), Self> { + match self.is_ok() { + true => Ok(()), + false => Err(self), + } + } } notmuch_enum! { -- cgit v1.2.1 From fb76ee5ec2368c6f36d8a4f73234e614ee6ca0d0 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Thu, 19 Mar 2015 17:18:10 -0400 Subject: Add `ToStr` and `ToStaticStr` traits. Allow easy mapping of borrowed C strings to borrowed strings with appropriate lifetimes. I have some doubts about this, as I'm not 100% on how lifetimes interact with the notmuch-provided strings yet. --- src/lib.rs | 2 +- src/utils.rs | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 0f88f60..f490df7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(libc)] +#![feature(core, libc)] extern crate libc; #[macro_use] diff --git a/src/utils.rs b/src/utils.rs index 77e6e5e..ad8bcac 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,6 +1,37 @@ +use std::{ + ffi, + str, +}; + +use libc; + pub trait NotmuchEnum { type NotmuchT; fn from_notmuch_t(notmuch_t: Self::NotmuchT) -> Self; fn to_notmuch_t(self) -> Self::NotmuchT; } + +pub trait ToStr { + fn to_str(&self) -> Result<&str, str::Utf8Error>; +} + +impl ToStr for *const libc::c_char { + fn to_str(&self) -> Result<&str, str::Utf8Error> { + str::from_utf8(unsafe { + ffi::CStr::from_ptr(*self) + }.to_bytes()) + } +} + +pub trait ToStaticStr { + fn to_static_str(&self) -> Result<&'static str, str::Utf8Error>; +} + +impl ToStaticStr for *const libc::c_char { + fn to_static_str(&self) -> Result<&'static str, str::Utf8Error> { + str::from_utf8(unsafe { + ffi::CStr::from_ptr(*self) + }.to_bytes()) + } +} -- cgit v1.2.1 From d3f5ca027545db5c0e54ceb758bcd4e27e2ce003 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Fri, 20 Mar 2015 08:46:32 -0400 Subject: Implement `Error` for `NotmuchStatus`. Entails implementation of `ToStr` and `Display`, also. Note that the `to_str()` method uses the `to_static_str()` method on the `ToStaticStr` trait internally --- this is how I expect to use the latter. This lets me provide a uniform `to_str()` method in the rest of the API, while transparently handling the differences between C string lifetimes. --- src/ffi.rs | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/ffi.rs b/src/ffi.rs index 2ee99e0..45a1f17 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -11,7 +11,17 @@ use libc::{ time_t, }; -use utils::NotmuchEnum; +use std::{ + error, + fmt, + str, +}; + +use utils::{ + NotmuchEnum, + ToStaticStr, + ToStr, +}; pub type notmuch_bool_t = c_int; @@ -56,6 +66,26 @@ impl notmuch_status_t { } } +impl ToStr for NotmuchStatus { + fn to_str(&self) -> Result<&str, str::Utf8Error> { + unsafe { + notmuch_status_to_string(self.to_notmuch_t()) + }.to_static_str() + } +} + +impl fmt::Display for NotmuchStatus { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.to_str().unwrap()) + } +} + +impl error::Error for NotmuchStatus { + fn description(&self) -> &str { + self.to_str().unwrap() + } +} + notmuch_enum! { #[repr(C)] #[derive(Copy, Debug)] -- cgit v1.2.1 From 107624c5bb11e6ab8c72d85392f9645efd7c6545 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Fri, 20 Mar 2015 09:15:02 -0400 Subject: Add error module with crate's `Error` type. Implement `Display`, `Error`, and various `FromError` traits on `Error`, allowing the use of `try!` on the various `Result` types in the crate. Note that currently the only error variants are those thrown from a lower-level operation. --- src/error.rs | 47 +++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 ++ 2 files changed, 49 insertions(+) create mode 100644 src/error.rs diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..57d636a --- /dev/null +++ b/src/error.rs @@ -0,0 +1,47 @@ +use std::{ + error, + fmt, + io, +}; + +use utils::NotmuchEnum; +use ffi; + +#[derive(Debug)] +pub enum Error { + IoError(io::Error), + NotmuchError(ffi::NotmuchStatus), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", error::Error::description(self)) + } +} + +impl error::Error for Error { + fn description(&self) -> &str { + match *self { + Error::IoError(ref e) => error::Error::description(e), + Error::NotmuchError(ref e) => e.description(), + } + } +} + +impl error::FromError for Error { + fn from_error(err: io::Error) -> Error { + Error::IoError(err) + } +} + +impl error::FromError for Error { + fn from_error(err: ffi::NotmuchStatus) -> Error { + Error::NotmuchError(err) + } +} + +impl error::FromError for Error { + fn from_error(err: ffi::notmuch_status_t) -> Error { + Error::NotmuchError(ffi::NotmuchStatus::from_notmuch_t(err)) + } +} diff --git a/src/lib.rs b/src/lib.rs index f490df7..f7358b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,3 +6,5 @@ mod macros; mod ffi; mod utils; + +pub mod error; -- cgit v1.2.1 From 0b098ba55c3cd6e0790a517f0259dd444a067b00 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Fri, 20 Mar 2015 09:21:14 -0400 Subject: Add `cause()` method to `Error` type. Returns the underlying error type, if any. --- src/error.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/error.rs b/src/error.rs index 57d636a..b26a21d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -26,6 +26,13 @@ impl error::Error for Error { Error::NotmuchError(ref e) => e.description(), } } + + fn cause(&self) -> Option<&error::Error> { + match *self { + Error::IoError(ref e) => Some(e), + Error::NotmuchError(ref e) => Some(e), + } + } } impl error::FromError for Error { -- cgit v1.2.1 From b94a736f5d4ba73182e1c6b2b1f49a1a718a5216 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Fri, 20 Mar 2015 10:41:17 -0400 Subject: Add crate-level `Result` type to error module. `Result` where `E` is always the local `Error` type. --- src/error.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/error.rs b/src/error.rs index b26a21d..795b4d7 100644 --- a/src/error.rs +++ b/src/error.rs @@ -2,11 +2,14 @@ use std::{ error, fmt, io, + result, }; use utils::NotmuchEnum; use ffi; +pub type Result = result::Result; + #[derive(Debug)] pub enum Error { IoError(io::Error), -- cgit v1.2.1 From 8a9a4314f0a39b3e2ea626e7fdbbbbf20ba8e0e8 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Fri, 20 Mar 2015 10:43:06 -0400 Subject: Add `ToCString` trait. Allows easy conversion of any `T: AsOsStr` to a `CString`, whose `as_ptr()` method is quite convenient for FFI calls. Note that `std::path::Path` implements `AsOsStr`, which means we can easily take paths and get a pointer to `*const libc::c_char`. --- src/lib.rs | 2 +- src/utils.rs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index f7358b7..379be2f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(core, libc)] +#![feature(core, libc, std_misc)] extern crate libc; #[macro_use] diff --git a/src/utils.rs b/src/utils.rs index ad8bcac..7e17ab9 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -3,6 +3,8 @@ use std::{ str, }; +use std::os::unix::ffi::OsStrExt; + use libc; pub trait NotmuchEnum { @@ -12,6 +14,16 @@ pub trait NotmuchEnum { fn to_notmuch_t(self) -> Self::NotmuchT; } +pub trait ToCString { + fn to_cstring(&self) -> Result; +} + +impl ToCString for T { + fn to_cstring(&self) -> Result { + self.as_os_str().to_cstring() + } +} + pub trait ToStr { fn to_str(&self) -> Result<&str, str::Utf8Error>; } -- cgit v1.2.1 From 8a564a9a1f9e4ac9475a43455dd30b2d176243e9 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Fri, 20 Mar 2015 10:49:59 -0400 Subject: Add database module. Add `database::Database`, `database::Version`, and `database::Mode` types. --- src/database.rs | 11 +++++++++++ src/lib.rs | 1 + 2 files changed, 12 insertions(+) create mode 100644 src/database.rs diff --git a/src/database.rs b/src/database.rs new file mode 100644 index 0000000..196932c --- /dev/null +++ b/src/database.rs @@ -0,0 +1,11 @@ +use libc; + +use ffi; + +// Re-exported under database module for pretty namespacin'. +pub use ffi::NotmuchDatabaseMode as Mode; + +#[derive(Copy, Debug)] +pub struct Version(libc::c_uint); + +pub struct Database(*mut ffi::notmuch_database_t); diff --git a/src/lib.rs b/src/lib.rs index 379be2f..0e3b871 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,3 +8,4 @@ mod ffi; mod utils; pub mod error; +pub mod database; -- cgit v1.2.1 From cba797fea1d9bf9d4b12b991b73a11b6d082faed Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Fri, 20 Mar 2015 10:55:05 -0400 Subject: Add `Database::create()` method. Simple wrapper around notmuch API's `notmuch_database_create()` function. --- src/database.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/database.rs b/src/database.rs index 196932c..c431254 100644 --- a/src/database.rs +++ b/src/database.rs @@ -1,5 +1,13 @@ +use std::{ + path, + ptr, +}; + use libc; +use error::Result; +use utils::ToCString; + use ffi; // Re-exported under database module for pretty namespacin'. @@ -9,3 +17,16 @@ pub use ffi::NotmuchDatabaseMode as Mode; pub struct Version(libc::c_uint); pub struct Database(*mut ffi::notmuch_database_t); + +impl Database { + pub fn create(path: &P) -> Result { + let path = path.as_path().to_cstring().unwrap(); + + let mut db = ptr::null_mut(); + try!(unsafe { + ffi::notmuch_database_create(path.as_ptr(), &mut db) + }.as_result()); + + Ok(Database(db)) + } +} -- cgit v1.2.1 From b7ea6953d44978ae3dadbd277f001bf35ae06822 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Fri, 20 Mar 2015 10:58:50 -0400 Subject: Add `Database::open()` method. Simple wrapper around notmuch API's `notmuch_database_open()` function. --- src/database.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/database.rs b/src/database.rs index c431254..5a7cec4 100644 --- a/src/database.rs +++ b/src/database.rs @@ -6,7 +6,10 @@ use std::{ use libc; use error::Result; -use utils::ToCString; +use utils::{ + NotmuchEnum, + ToCString, +}; use ffi; @@ -29,4 +32,18 @@ impl Database { Ok(Database(db)) } + + pub fn open(path: &P, mode: Mode) -> Result { + let path = path.as_path().to_cstring().unwrap(); + + let mut db = ptr::null_mut(); + try!(unsafe { + ffi::notmuch_database_open( + path.as_ptr(), mode.to_notmuch_t(), &mut db, + ) + }.as_result()); + + Ok(Database(db)) + } + } -- cgit v1.2.1 From de63975fbe66607f8a1ad0ac8332a6bca15d3a01 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Fri, 20 Mar 2015 11:28:47 -0400 Subject: Add `Database::compact()` and related methods. Not so simple wrapper around notmuch API's `notmuch_database_compact()` function. Variants with and without a callback parameter are provided. --- src/database.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/database.rs b/src/database.rs index 5a7cec4..7364942 100644 --- a/src/database.rs +++ b/src/database.rs @@ -9,6 +9,7 @@ use error::Result; use utils::{ NotmuchEnum, ToCString, + ToStr, }; use ffi; @@ -46,4 +47,48 @@ impl Database { Ok(Database(db)) } + pub fn compact( + path: &P, backup_path: Option<&P>, + ) -> Result<()> { + let status: Option = None; + Database::_compact(path, backup_path, status) + } + + pub fn compact_with_status( + path: &P, backup_path: Option<&P>, status: F, + ) -> Result<()> { + Database::_compact(path, backup_path, Some(status)) + } + + fn _compact( + path: &P, backup_path: Option<&P>, status: Option, + ) -> Result<()> { + + extern fn wrapper( + message:*const libc::c_char, closure: *mut libc::c_void, + ) { + let closure = closure as *mut F; + unsafe { + (*closure)(message.to_str().unwrap()) + } + } + + let path = path.as_path().to_cstring().unwrap(); + let backup_path = backup_path.map(|p| { + p.as_path().to_cstring().unwrap() + }); + + try!(unsafe { + ffi::notmuch_database_compact( + path.as_ptr(), backup_path.map_or(ptr::null(), |p| p.as_ptr()), + if status.is_some() { Some(wrapper::) } else { None }, + status.map_or(ptr::null_mut(), |f| { + &f as *const _ as *mut libc::c_void + }), + ) + }.as_result()); + + Ok(()) + } + } -- cgit v1.2.1 From 98cba2aa2f2aea029ef498560658d862284db6ca Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Fri, 20 Mar 2015 11:35:00 -0400 Subject: Implement `Drop` for `Database`. Simple wrapper around notmuch API's `notmuch_database_destroy()` function. --- src/database.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/database.rs b/src/database.rs index 7364942..3955865 100644 --- a/src/database.rs +++ b/src/database.rs @@ -1,4 +1,5 @@ use std::{ + ops, path, ptr, }; @@ -90,5 +91,12 @@ impl Database { Ok(()) } +} +impl ops::Drop for Database { + fn drop(&mut self) { + unsafe { + ffi::notmuch_database_destroy(self.0) + }; + } } -- cgit v1.2.1 From 08a7366e0e561160a2b5a1dc01330f3f7f467469 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Fri, 20 Mar 2015 11:38:32 -0400 Subject: Add `Database::close()` method. Simple wrapper around notmuch API's `notmuch_database_close()` function. --- src/database.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/database.rs b/src/database.rs index 3955865..1915ffe 100644 --- a/src/database.rs +++ b/src/database.rs @@ -48,6 +48,14 @@ impl Database { Ok(Database(db)) } + pub fn close(self) -> Result<()> { + try!(unsafe { + ffi::notmuch_database_close(self.0) + }.as_result()); + + Ok(()) + } + pub fn compact( path: &P, backup_path: Option<&P>, ) -> Result<()> { -- cgit v1.2.1 From 95d4fba8436417a6c27522ed9b51c19a9fd7c6f9 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Fri, 20 Mar 2015 13:31:22 -0400 Subject: Make `to_str()` method generic over lifetime. If I have this correct: The output `&str` will have the same lifetime as whatever the lifetime of the block in which it is called. This allows using it one the output of notmuch FFI calls, by propogating the lifetime of the safe wrapper object (e.g., `Database`) to the `&str` returned from `to_str()`. This mirrors the lifetime of the actual underlying C string. If I don't grok lifetimes as well as I think, this could be a lie. Future self: you should add unit tests to test the above explanation. --- src/ffi.rs | 2 +- src/utils.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ffi.rs b/src/ffi.rs index 45a1f17..5f71778 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -67,7 +67,7 @@ impl notmuch_status_t { } impl ToStr for NotmuchStatus { - fn to_str(&self) -> Result<&str, str::Utf8Error> { + fn to_str<'a>(&self) -> Result<&'a str, str::Utf8Error> { unsafe { notmuch_status_to_string(self.to_notmuch_t()) }.to_static_str() diff --git a/src/utils.rs b/src/utils.rs index 7e17ab9..dbabe21 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -25,11 +25,11 @@ impl ToCString for T { } pub trait ToStr { - fn to_str(&self) -> Result<&str, str::Utf8Error>; + fn to_str<'a>(&self) -> Result<&'a str, str::Utf8Error>; } impl ToStr for *const libc::c_char { - fn to_str(&self) -> Result<&str, str::Utf8Error> { + fn to_str<'a>(&self) -> Result<&'a str, str::Utf8Error> { str::from_utf8(unsafe { ffi::CStr::from_ptr(*self) }.to_bytes()) -- cgit v1.2.1 From 4226ff7a9a93764ec22721b65c6aac3fdafd85cb Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Fri, 20 Mar 2015 13:36:27 -0400 Subject: Add `Database::path()' method. Simple wrapper around notmuch API's `notmuch_database_get_path()` function. --- src/database.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/database.rs b/src/database.rs index 1915ffe..7d09e24 100644 --- a/src/database.rs +++ b/src/database.rs @@ -99,6 +99,12 @@ impl Database { Ok(()) } + + pub fn path(&self) -> &path::Path { + path::Path::new(unsafe { + ffi::notmuch_database_get_path(self.0) + }.to_str().unwrap()) + } } impl ops::Drop for Database { -- cgit v1.2.1 From 64c7d51bf507def6a2c660cf5d3cb4163514c5ae Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Fri, 20 Mar 2015 13:38:13 -0400 Subject: Add `Database::version()` method. Simple wrapper around notmuch API's `notmuch_database_get_version()` function. --- src/database.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/database.rs b/src/database.rs index 7d09e24..3feca76 100644 --- a/src/database.rs +++ b/src/database.rs @@ -105,6 +105,12 @@ impl Database { ffi::notmuch_database_get_path(self.0) }.to_str().unwrap()) } + + pub fn version(&self) -> Version { + Version(unsafe { + ffi::notmuch_database_get_version(self.0) + }) + } } impl ops::Drop for Database { -- cgit v1.2.1 From 3deae99643336c653bb3ed8926ba3ac300e340ed Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Fri, 20 Mar 2015 13:40:42 -0400 Subject: Add `Databased::needs_upgrade()` method. Simple wrapper around notmuch API's `notmuch_database_needs_upgrade()` function. --- src/database.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/database.rs b/src/database.rs index 3feca76..b3812eb 100644 --- a/src/database.rs +++ b/src/database.rs @@ -111,6 +111,12 @@ impl Database { ffi::notmuch_database_get_version(self.0) }) } + + pub fn needs_upgrade(&self) -> bool { + unsafe { + ffi::notmuch_database_needs_upgrade(self.0) == 1 + } + } } impl ops::Drop for Database { -- cgit v1.2.1 From 99e3507507e114fb4d1d27de6a7dcf1f8caaa73d Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Fri, 20 Mar 2015 13:56:28 -0400 Subject: Add `Database::upgrade()` and related methods. Not so simple wrapper around notmuch API's `notmuch_database_upgrade()` function. Variants with and without a callback parameter are provided. --- src/database.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/database.rs b/src/database.rs index b3812eb..20c2a24 100644 --- a/src/database.rs +++ b/src/database.rs @@ -117,6 +117,39 @@ impl Database { ffi::notmuch_database_needs_upgrade(self.0) == 1 } } + + pub fn upgrade(&self) -> Result<()> { + let status: Option = None; + self._upgrade(status) + } + + pub fn upgrade_with_status(&self, status: F) -> Result<()> { + self._upgrade(Some(status)) + } + + fn _upgrade(&self, status: Option) -> Result<()> { + + extern fn wrapper( + closure: *mut libc::c_void, progress: libc::c_double, + ) { + let closure = closure as *mut F; + unsafe { + (*closure)(progress as f64) + } + } + + try!(unsafe { + ffi::notmuch_database_upgrade( + self.0, + if status.is_some() { Some(wrapper::) } else { None }, + status.map_or(ptr::null_mut(), |f| { + &f as *const _ as *mut libc::c_void + }), + ) + }.as_result()); + + Ok(()) + } } impl ops::Drop for Database { -- cgit v1.2.1 From a644db096a6f783a75c34eaa3ad4bf6a57615e62 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Tue, 24 Mar 2015 14:44:37 -0400 Subject: Fix errors in FFI function signatures. --- src/ffi.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ffi.rs b/src/ffi.rs index 5f71778..ff8d287 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -233,7 +233,7 @@ extern { query_string: *const c_char, ) -> *mut notmuch_query_t; - pub fn notmuch_query_get_string( + pub fn notmuch_query_get_query_string( query: *mut notmuch_query_t, ) -> *const c_char; @@ -452,6 +452,7 @@ extern { pub fn notmuch_directory_set_mtime( directory: *mut notmuch_directory_t, + mtime: time_t, ) -> notmuch_status_t; pub fn notmuch_directory_get_mtime( -- cgit v1.2.1 From 4a1e068f7ec752ef51891f04494f52c26ce7090c Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Tue, 24 Mar 2015 14:46:02 -0400 Subject: Rename `NotmuchEnum` trait to `NotmuchType`. Turns out to be useful outside of just enums. --- src/database.rs | 2 +- src/error.rs | 2 +- src/ffi.rs | 2 +- src/macros.rs | 2 +- src/utils.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/database.rs b/src/database.rs index 20c2a24..46ca45d 100644 --- a/src/database.rs +++ b/src/database.rs @@ -8,7 +8,7 @@ use libc; use error::Result; use utils::{ - NotmuchEnum, + NotmuchType, ToCString, ToStr, }; diff --git a/src/error.rs b/src/error.rs index 795b4d7..22c1f6e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -5,7 +5,7 @@ use std::{ result, }; -use utils::NotmuchEnum; +use utils::NotmuchType; use ffi; pub type Result = result::Result; diff --git a/src/ffi.rs b/src/ffi.rs index ff8d287..29b2ea7 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -18,7 +18,7 @@ use std::{ }; use utils::{ - NotmuchEnum, + NotmuchType, ToStaticStr, ToStr, }; diff --git a/src/macros.rs b/src/macros.rs index 836be63..8802a71 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -16,7 +16,7 @@ macro_rules! notmuch_enum { $($variant_alias),* } - impl NotmuchEnum for $name_alias { + impl NotmuchType for $name_alias { type NotmuchT = $name; fn from_notmuch_t(notmuch_t: $name) -> Self { diff --git a/src/utils.rs b/src/utils.rs index dbabe21..ad6cf9b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -7,7 +7,7 @@ use std::os::unix::ffi::OsStrExt; use libc; -pub trait NotmuchEnum { +pub trait NotmuchType { type NotmuchT; fn from_notmuch_t(notmuch_t: Self::NotmuchT) -> Self; -- cgit v1.2.1 From 4a314517ad9d52884232e4ed7e3b0d01e6e9b1e3 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Tue, 24 Mar 2015 14:53:42 -0400 Subject: Remove `ToStaticStr` trait. Changes in commit 95d4fba8436417a6c27522ed9b51c19a9fd7c6f9 make the trait unnecessary. The `ToStr` trait is now sufficient. --- src/ffi.rs | 3 +-- src/utils.rs | 12 ------------ 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/src/ffi.rs b/src/ffi.rs index 29b2ea7..1ee940a 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -19,7 +19,6 @@ use std::{ use utils::{ NotmuchType, - ToStaticStr, ToStr, }; @@ -70,7 +69,7 @@ impl ToStr for NotmuchStatus { fn to_str<'a>(&self) -> Result<&'a str, str::Utf8Error> { unsafe { notmuch_status_to_string(self.to_notmuch_t()) - }.to_static_str() + }.to_str() } } diff --git a/src/utils.rs b/src/utils.rs index ad6cf9b..75a5788 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -35,15 +35,3 @@ impl ToStr for *const libc::c_char { }.to_bytes()) } } - -pub trait ToStaticStr { - fn to_static_str(&self) -> Result<&'static str, str::Utf8Error>; -} - -impl ToStaticStr for *const libc::c_char { - fn to_static_str(&self) -> Result<&'static str, str::Utf8Error> { - str::from_utf8(unsafe { - ffi::CStr::from_ptr(*self) - }.to_bytes()) - } -} -- cgit v1.2.1 From 0c55e4e4d5bb8b9098fc6f780a74e99f436153c0 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Tue, 24 Mar 2015 14:55:02 -0400 Subject: Make methods borrow self mutably when appropriate. Use of raw pointers and FFI functions mean that the compiler won't force us to be correct in our usage of `&self` vs. `&mut self`. These functions make changes to the notmuch database, and we want the type system to ensure we can't simultaneously manipulate the database from different functions. --- src/database.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/database.rs b/src/database.rs index 46ca45d..7469bb0 100644 --- a/src/database.rs +++ b/src/database.rs @@ -118,16 +118,16 @@ impl Database { } } - pub fn upgrade(&self) -> Result<()> { + pub fn upgrade(&mut self) -> Result<()> { let status: Option = None; self._upgrade(status) } - pub fn upgrade_with_status(&self, status: F) -> Result<()> { + pub fn upgrade_with_status(&mut self, status: F) -> Result<()> { self._upgrade(Some(status)) } - fn _upgrade(&self, status: Option) -> Result<()> { + fn _upgrade(&mut self, status: Option) -> Result<()> { extern fn wrapper( closure: *mut libc::c_void, progress: libc::c_double, -- cgit v1.2.1 From 7c1b8bc9574f19b6ea3536155c13d55cf5dbee92 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Wed, 25 Mar 2015 12:01:30 -0400 Subject: Change usage of `AsPath` to `AsRef`. RFC 529[1] has landed. [1] https://github.com/rust-lang/rfcs/pull/529 --- src/database.rs | 18 +++++++++--------- src/lib.rs | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/database.rs b/src/database.rs index 7469bb0..9e0c001 100644 --- a/src/database.rs +++ b/src/database.rs @@ -24,8 +24,8 @@ pub struct Version(libc::c_uint); pub struct Database(*mut ffi::notmuch_database_t); impl Database { - pub fn create(path: &P) -> Result { - let path = path.as_path().to_cstring().unwrap(); + pub fn create>(path: &P) -> Result { + let path = path.as_ref().to_cstring().unwrap(); let mut db = ptr::null_mut(); try!(unsafe { @@ -35,8 +35,8 @@ impl Database { Ok(Database(db)) } - pub fn open(path: &P, mode: Mode) -> Result { - let path = path.as_path().to_cstring().unwrap(); + pub fn open>(path: &P, mode: Mode) -> Result { + let path = path.as_ref().to_cstring().unwrap(); let mut db = ptr::null_mut(); try!(unsafe { @@ -56,20 +56,20 @@ impl Database { Ok(()) } - pub fn compact( + pub fn compact, F: FnMut(&str)>( path: &P, backup_path: Option<&P>, ) -> Result<()> { let status: Option = None; Database::_compact(path, backup_path, status) } - pub fn compact_with_status( + pub fn compact_with_status, F: FnMut(&str)>( path: &P, backup_path: Option<&P>, status: F, ) -> Result<()> { Database::_compact(path, backup_path, Some(status)) } - fn _compact( + fn _compact, F: FnMut(&str)>( path: &P, backup_path: Option<&P>, status: Option, ) -> Result<()> { @@ -82,9 +82,9 @@ impl Database { } } - let path = path.as_path().to_cstring().unwrap(); + let path = path.as_ref().to_cstring().unwrap(); let backup_path = backup_path.map(|p| { - p.as_path().to_cstring().unwrap() + p.as_ref().to_cstring().unwrap() }); try!(unsafe { diff --git a/src/lib.rs b/src/lib.rs index 0e3b871..91c4c5f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(core, libc, std_misc)] +#![feature(convert, core, libc, std_misc, unsafe_destructor)] extern crate libc; #[macro_use] -- cgit v1.2.1 From a2300c78a747124003c8415b805712aed31e4959 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Thu, 26 Mar 2015 14:33:08 -0400 Subject: Make `ToCString` trait use std::convert traits. Use `AsRef` instead of `AsOsStr`. --- src/database.rs | 8 ++++---- src/lib.rs | 2 +- src/utils.rs | 6 ++++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/database.rs b/src/database.rs index 9e0c001..6b0542d 100644 --- a/src/database.rs +++ b/src/database.rs @@ -25,7 +25,7 @@ pub struct Database(*mut ffi::notmuch_database_t); impl Database { pub fn create>(path: &P) -> Result { - let path = path.as_ref().to_cstring().unwrap(); + let path = path.to_cstring().unwrap(); let mut db = ptr::null_mut(); try!(unsafe { @@ -36,7 +36,7 @@ impl Database { } pub fn open>(path: &P, mode: Mode) -> Result { - let path = path.as_ref().to_cstring().unwrap(); + let path = path.to_cstring().unwrap(); let mut db = ptr::null_mut(); try!(unsafe { @@ -82,9 +82,9 @@ impl Database { } } - let path = path.as_ref().to_cstring().unwrap(); + let path = path.to_cstring().unwrap(); let backup_path = backup_path.map(|p| { - p.as_ref().to_cstring().unwrap() + p.to_cstring().unwrap() }); try!(unsafe { diff --git a/src/lib.rs b/src/lib.rs index 91c4c5f..265589e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(convert, core, libc, std_misc, unsafe_destructor)] +#![feature(convert, core, libc, unsafe_destructor)] extern crate libc; #[macro_use] diff --git a/src/utils.rs b/src/utils.rs index 75a5788..ec5b5b3 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,5 +1,6 @@ use std::{ ffi, + path, str, }; @@ -18,9 +19,10 @@ pub trait ToCString { fn to_cstring(&self) -> Result; } -impl ToCString for T { +impl> ToCString for T { fn to_cstring(&self) -> Result { - self.as_os_str().to_cstring() + let path: &ffi::OsStr = self.as_ref().as_ref(); + path.to_cstring() } } -- cgit v1.2.1 From e4523dd5d6e2fe3f9afa99671baadfdf8eef5385 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Thu, 26 Mar 2015 14:41:54 -0400 Subject: Remove `NotmuchType` trait. No longer necessary with the `From` and `Into` traits from std::convert. --- src/database.rs | 3 +-- src/error.rs | 3 +-- src/ffi.rs | 3 +-- src/macros.rs | 12 ++++++------ src/utils.rs | 7 ------- 5 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/database.rs b/src/database.rs index 6b0542d..d082f3a 100644 --- a/src/database.rs +++ b/src/database.rs @@ -8,7 +8,6 @@ use libc; use error::Result; use utils::{ - NotmuchType, ToCString, ToStr, }; @@ -41,7 +40,7 @@ impl Database { let mut db = ptr::null_mut(); try!(unsafe { ffi::notmuch_database_open( - path.as_ptr(), mode.to_notmuch_t(), &mut db, + path.as_ptr(), mode.into(), &mut db, ) }.as_result()); diff --git a/src/error.rs b/src/error.rs index 22c1f6e..01c28fb 100644 --- a/src/error.rs +++ b/src/error.rs @@ -5,7 +5,6 @@ use std::{ result, }; -use utils::NotmuchType; use ffi; pub type Result = result::Result; @@ -52,6 +51,6 @@ impl error::FromError for Error { impl error::FromError for Error { fn from_error(err: ffi::notmuch_status_t) -> Error { - Error::NotmuchError(ffi::NotmuchStatus::from_notmuch_t(err)) + Error::NotmuchError(ffi::NotmuchStatus::from(err)) } } diff --git a/src/ffi.rs b/src/ffi.rs index 1ee940a..871cefd 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -18,7 +18,6 @@ use std::{ }; use utils::{ - NotmuchType, ToStr, }; @@ -68,7 +67,7 @@ impl notmuch_status_t { impl ToStr for NotmuchStatus { fn to_str<'a>(&self) -> Result<&'a str, str::Utf8Error> { unsafe { - notmuch_status_to_string(self.to_notmuch_t()) + notmuch_status_to_string((*self).into()) }.to_str() } } diff --git a/src/macros.rs b/src/macros.rs index 8802a71..a36197b 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -16,16 +16,16 @@ macro_rules! notmuch_enum { $($variant_alias),* } - impl NotmuchType for $name_alias { - type NotmuchT = $name; - - fn from_notmuch_t(notmuch_t: $name) -> Self { - match notmuch_t { + impl From<$name> for $name_alias { + fn from(t: $name) -> Self { + match t { $($name::$variant => $name_alias::$variant_alias),* } } + } - fn to_notmuch_t(self) -> $name { + impl Into<$name> for $name_alias { + fn into(self) -> $name { match self { $($name_alias::$variant_alias => $name::$variant),* } diff --git a/src/utils.rs b/src/utils.rs index ec5b5b3..b5acb66 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -8,13 +8,6 @@ use std::os::unix::ffi::OsStrExt; use libc; -pub trait NotmuchType { - type NotmuchT; - - fn from_notmuch_t(notmuch_t: Self::NotmuchT) -> Self; - fn to_notmuch_t(self) -> Self::NotmuchT; -} - pub trait ToCString { fn to_cstring(&self) -> Result; } -- cgit v1.2.1 From ed50bef4947c739032f7282054cd41103e9d1192 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Thu, 26 Mar 2015 14:58:22 -0400 Subject: Disable trivial_numeric_casts lint in FFI callback. We're casting from `c_double` to `f64`, which are the same thing, but I want to do it anyway to be explicit. --- src/database.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/database.rs b/src/database.rs index d082f3a..b046600 100644 --- a/src/database.rs +++ b/src/database.rs @@ -128,6 +128,7 @@ impl Database { fn _upgrade(&mut self, status: Option) -> Result<()> { + #[allow(trivial_numeric_casts)] extern fn wrapper( closure: *mut libc::c_void, progress: libc::c_double, ) { -- cgit v1.2.1 From 9005a1b8656ed0bcd8526810206836eeeb919d38 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Fri, 27 Mar 2015 15:39:02 -0400 Subject: Add `NewFromPtr` trait. Crate-private utility trait for `new()` methods on types. --- src/utils.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/utils.rs b/src/utils.rs index b5acb66..af3ce29 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -8,6 +8,10 @@ use std::os::unix::ffi::OsStrExt; use libc; +pub trait NewFromPtr { + fn new(ptr: T) -> Self; +} + pub trait ToCString { fn to_cstring(&self) -> Result; } -- cgit v1.2.1 From 211c96c4a57769202de6c194480601570a1cd8f1 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Fri, 27 Mar 2015 15:47:52 -0400 Subject: Add directory module and `Directory` type. Wrapper type for `ffi::notmuch_directory_t` pointer. --- src/directory.rs | 22 ++++++++++++++++++++++ src/lib.rs | 1 + 2 files changed, 23 insertions(+) create mode 100644 src/directory.rs diff --git a/src/directory.rs b/src/directory.rs new file mode 100644 index 0000000..eaf706e --- /dev/null +++ b/src/directory.rs @@ -0,0 +1,22 @@ +use std::{ + marker, +}; + +use utils::{ + NewFromPtr, +}; + +use database; + +use ffi; + +pub struct Directory<'d>( + *mut ffi::notmuch_directory_t, + marker::PhantomData<&'d mut database::Database>, +); + +impl<'d> NewFromPtr<*mut ffi::notmuch_directory_t> for Directory<'d> { + fn new(ptr: *mut ffi::notmuch_directory_t) -> Directory<'d> { + Directory(ptr, marker::PhantomData) + } +} diff --git a/src/lib.rs b/src/lib.rs index 265589e..aa21751 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,3 +9,4 @@ mod utils; pub mod error; pub mod database; +pub mod directory; -- cgit v1.2.1 From 89b177046d8fbe8fa0597a5468bfbc082d9fa7da Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Fri, 27 Mar 2015 15:52:05 -0400 Subject: Add `Database::directory()` method. Simple wrapper around notmuch API's `notmuch_database_get_directory` function. --- src/database.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/database.rs b/src/database.rs index b046600..7f16900 100644 --- a/src/database.rs +++ b/src/database.rs @@ -8,10 +8,13 @@ use libc; use error::Result; use utils::{ + NewFromPtr, ToCString, ToStr, }; +use directory::Directory; + use ffi; // Re-exported under database module for pretty namespacin'. @@ -150,6 +153,22 @@ impl Database { Ok(()) } + + pub fn directory>(&self, path: &P) -> Result> { + let path = path.to_cstring().unwrap(); + + let mut dir = ptr::null_mut(); + try!(unsafe { + ffi::notmuch_database_get_directory( + self.0, path.as_ptr(), &mut dir, + ) + }.as_result()); + + match dir.is_null() { + false => Ok(None), + true => Ok(Some(Directory::new(dir))), + } + } } impl ops::Drop for Database { -- cgit v1.2.1 From e7beb173b8cb83e9a6cfdf02cc2a61bfc7761ba3 Mon Sep 17 00:00:00 2001 From: "C. Morgan Hamill" Date: Tue, 31 Mar 2015 10:47:49 -0400 Subject: Rename Notmuch enum types. Remove the 'Notmuch' prefix, as it pollutes the generated documentation. It's rendundant, anyhow. --- src/database.rs | 2 +- src/error.rs | 8 ++++---- src/ffi.rs | 16 ++++++++-------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/database.rs b/src/database.rs index 7f16900..f1c56c5 100644 --- a/src/database.rs +++ b/src/database.rs @@ -18,7 +18,7 @@ use directory::Directory; use ffi; // Re-exported under database module for pretty namespacin'. -pub use ffi::NotmuchDatabaseMode as Mode; +pub use ffi::Mode; #[derive(Copy, Debug)] pub struct Version(libc::c_uint); diff --git a/src/error.rs b/src/error.rs index 01c28fb..069ae93 100644 --- a/src/error.rs +++ b/src/error.rs @@ -12,7 +12,7 @@ pub type Result = result::Result; #[derive(Debug)] pub enum Error { IoError(io::Error), - NotmuchError(ffi::NotmuchStatus), + NotmuchError(ffi::Status), } impl fmt::Display for Error { @@ -43,14 +43,14 @@ impl error::FromError for Error { } } -impl error::FromError for Error { - fn from_error(err: ffi::NotmuchStatus) -> Error { +impl error::FromError for Error { + fn from_error(err: ffi::Status) -> Error { Error::NotmuchError(err) } } impl error::FromError for Error { fn from_error(err: ffi::notmuch_status_t) -> Error { - Error::NotmuchError(ffi::NotmuchStatus::from(err)) + Error::NotmuchError(ffi::Status::from(err)) } } diff --git a/src/ffi.rs b/src/ffi.rs index 871cefd..da862d8 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -28,7 +28,7 @@ pub type notmuch_compact_status_cb_t = extern fn(*const c_char, *mut c_void); notmuch_enum! { #[repr(C)] #[derive(Copy, Debug)] - pub enum notmuch_status_t => NotmuchStatus { + pub enum notmuch_status_t => Status { NOTMUCH_STATUS_SUCCESS => Success, NOTMUCH_STATUS_OUT_OF_MEMORY => OutOfMemory, NOTMUCH_STATUS_READ_ONLY_DATABASE => ReadOnlyDatabase, @@ -64,7 +64,7 @@ impl notmuch_status_t { } } -impl ToStr for NotmuchStatus { +impl ToStr for Status { fn to_str<'a>(&self) -> Result<&'a str, str::Utf8Error> { unsafe { notmuch_status_to_string((*self).into()) @@ -72,13 +72,13 @@ impl ToStr for NotmuchStatus { } } -impl fmt::Display for NotmuchStatus { +impl fmt::Display for Status { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.to_str().unwrap()) } } -impl error::Error for NotmuchStatus { +impl error::Error for Status { fn description(&self) -> &str { self.to_str().unwrap() } @@ -87,7 +87,7 @@ impl error::Error for NotmuchStatus { notmuch_enum! { #[repr(C)] #[derive(Copy, Debug)] - pub enum notmuch_database_mode_t => NotmuchDatabaseMode { + pub enum notmuch_database_mode_t => Mode { NOTMUCH_DATABASE_MODE_READ_ONLY => ReadOnly, NOTMUCH_DATABASE_MODE_READ_WRITE => ReadWrite } @@ -96,7 +96,7 @@ notmuch_enum! { notmuch_enum! { #[repr(C)] #[derive(Copy, Debug)] - pub enum notmuch_sort_t => NotmuchSort { + pub enum notmuch_sort_t => Sort { NOTMUCH_SORT_OLDEST_FIRST => OldestFirst, NOTMUCH_SORT_NEWEST_FIRST => NewestFirst, NOTMUCH_SORT_MESSAGE_ID => MessageID, @@ -107,7 +107,7 @@ notmuch_enum! { notmuch_enum! { #[repr(C)] #[derive(Copy, Debug)] - pub enum notmuch_exclude_t => NotmuchExclude { + pub enum notmuch_exclude_t => Exclude { NOTMUCH_EXCLUDE_FLAG => Flag, NOTMUCH_EXCLUDE_TRUE => True, NOTMUCH_EXCLUDE_FALSE => False, @@ -118,7 +118,7 @@ notmuch_enum! { notmuch_enum! { #[repr(C)] #[derive(Copy, Debug)] - pub enum notmuch_message_flag_t => NotmuchMessageFlag { + pub enum notmuch_message_flag_t => MessageFlag { NOTMUCH_MESSAGE_FLAG_MATCH => Match, NOTMUCH_MESSAGE_FLAG_EXCLUDED => Excluded, NOTMUCH_MESSAGE_FLAG_GHOST => Ghost -- cgit v1.2.1 From 0694f95bfac3be74c33605f947d324890d843c0e Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 20 Mar 2018 19:58:28 +0100 Subject: resurrect --- Cargo.toml | 8 ++++++-- src/database.rs | 2 +- src/error.rs | 16 +++++++++------- src/ffi.rs | 10 +++++----- src/lib.rs | 7 ++++--- 5 files changed, 25 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 416db6c..a67079f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,9 @@ [package] - name = "notmuch" version = "0.0.1" -authors = ["C. Morgan Hamill "] +authors = ["C. Morgan Hamill ", + "Dirk Van Haerenborgh "] + +[dependencies] +notmuch-sys = "*" +libc = "0.2" diff --git a/src/database.rs b/src/database.rs index f1c56c5..ddba507 100644 --- a/src/database.rs +++ b/src/database.rs @@ -20,7 +20,7 @@ use ffi; // Re-exported under database module for pretty namespacin'. pub use ffi::Mode; -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub struct Version(libc::c_uint); pub struct Database(*mut ffi::notmuch_database_t); diff --git a/src/error.rs b/src/error.rs index 069ae93..046e17f 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,3 +1,4 @@ +use std; use std::{ error, fmt, @@ -5,6 +6,7 @@ use std::{ result, }; +use ffi_sys; use ffi; pub type Result = result::Result; @@ -21,7 +23,7 @@ impl fmt::Display for Error { } } -impl error::Error for Error { +impl std::error::Error for Error { fn description(&self) -> &str { match *self { Error::IoError(ref e) => error::Error::description(e), @@ -37,20 +39,20 @@ impl error::Error for Error { } } -impl error::FromError for Error { - fn from_error(err: io::Error) -> Error { +impl std::convert::From for Error { + fn from(err: io::Error) -> Error { Error::IoError(err) } } -impl error::FromError for Error { - fn from_error(err: ffi::Status) -> Error { +impl std::convert::From for Error { + fn from(err: ffi::Status) -> Error { Error::NotmuchError(err) } } -impl error::FromError for Error { - fn from_error(err: ffi::notmuch_status_t) -> Error { +impl std::convert::From for Error { + fn from(err: ffi::notmuch_status_t) -> Error { Error::NotmuchError(ffi::Status::from(err)) } } diff --git a/src/ffi.rs b/src/ffi.rs index da862d8..6d2ceeb 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -27,7 +27,7 @@ pub type notmuch_compact_status_cb_t = extern fn(*const c_char, *mut c_void); notmuch_enum! { #[repr(C)] - #[derive(Copy, Debug)] + #[derive(Copy, Clone, Debug)] pub enum notmuch_status_t => Status { NOTMUCH_STATUS_SUCCESS => Success, NOTMUCH_STATUS_OUT_OF_MEMORY => OutOfMemory, @@ -86,7 +86,7 @@ impl error::Error for Status { notmuch_enum! { #[repr(C)] - #[derive(Copy, Debug)] + #[derive(Copy, Clone, Debug)] pub enum notmuch_database_mode_t => Mode { NOTMUCH_DATABASE_MODE_READ_ONLY => ReadOnly, NOTMUCH_DATABASE_MODE_READ_WRITE => ReadWrite @@ -95,7 +95,7 @@ notmuch_enum! { notmuch_enum! { #[repr(C)] - #[derive(Copy, Debug)] + #[derive(Copy, Clone, Debug)] pub enum notmuch_sort_t => Sort { NOTMUCH_SORT_OLDEST_FIRST => OldestFirst, NOTMUCH_SORT_NEWEST_FIRST => NewestFirst, @@ -106,7 +106,7 @@ notmuch_enum! { notmuch_enum! { #[repr(C)] - #[derive(Copy, Debug)] + #[derive(Copy, Clone, Debug)] pub enum notmuch_exclude_t => Exclude { NOTMUCH_EXCLUDE_FLAG => Flag, NOTMUCH_EXCLUDE_TRUE => True, @@ -117,7 +117,7 @@ notmuch_enum! { notmuch_enum! { #[repr(C)] - #[derive(Copy, Debug)] + #[derive(Copy, Clone, Debug)] pub enum notmuch_message_flag_t => MessageFlag { NOTMUCH_MESSAGE_FLAG_MATCH => Match, NOTMUCH_MESSAGE_FLAG_EXCLUDED => Excluded, diff --git a/src/lib.rs b/src/lib.rs index aa21751..63d190f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,12 @@ -#![feature(convert, core, libc, unsafe_destructor)] -extern crate libc; #[macro_use] mod macros; -mod ffi; +extern crate notmuch_sys as ffi_sys; +extern crate libc; + mod utils; +mod ffi; pub mod error; pub mod database; -- cgit v1.2.1 From ad9ab3f0761af1751e0e2d19b140f8c8fc5e3324 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 20 Mar 2018 20:17:26 +0100 Subject: fix some compiler warning regarding opaque structs --- Cargo.toml | 1 - src/error.rs | 1 - src/ffi.rs | 26 +++++++++++++------------- src/lib.rs | 2 -- src/utils.rs | 2 -- 5 files changed, 13 insertions(+), 19 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a67079f..1f9adc5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,5 +5,4 @@ authors = ["C. Morgan Hamill ", "Dirk Van Haerenborgh "] [dependencies] -notmuch-sys = "*" libc = "0.2" diff --git a/src/error.rs b/src/error.rs index 046e17f..b1e5cdc 100644 --- a/src/error.rs +++ b/src/error.rs @@ -6,7 +6,6 @@ use std::{ result, }; -use ffi_sys; use ffi; pub type Result = result::Result; diff --git a/src/ffi.rs b/src/ffi.rs index 6d2ceeb..bd59941 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -27,7 +27,7 @@ pub type notmuch_compact_status_cb_t = extern fn(*const c_char, *mut c_void); notmuch_enum! { #[repr(C)] - #[derive(Copy, Clone, Debug)] + #[derive(Debug, Eq, PartialEq, Clone, Copy)] pub enum notmuch_status_t => Status { NOTMUCH_STATUS_SUCCESS => Success, NOTMUCH_STATUS_OUT_OF_MEMORY => OutOfMemory, @@ -86,7 +86,7 @@ impl error::Error for Status { notmuch_enum! { #[repr(C)] - #[derive(Copy, Clone, Debug)] + #[derive(Debug, Eq, PartialEq, Clone, Copy)] pub enum notmuch_database_mode_t => Mode { NOTMUCH_DATABASE_MODE_READ_ONLY => ReadOnly, NOTMUCH_DATABASE_MODE_READ_WRITE => ReadWrite @@ -95,7 +95,7 @@ notmuch_enum! { notmuch_enum! { #[repr(C)] - #[derive(Copy, Clone, Debug)] + #[derive(Debug, Eq, PartialEq, Clone, Copy)] pub enum notmuch_sort_t => Sort { NOTMUCH_SORT_OLDEST_FIRST => OldestFirst, NOTMUCH_SORT_NEWEST_FIRST => NewestFirst, @@ -117,7 +117,7 @@ notmuch_enum! { notmuch_enum! { #[repr(C)] - #[derive(Copy, Clone, Debug)] + #[derive(Debug, Eq, PartialEq, Clone, Copy)] pub enum notmuch_message_flag_t => MessageFlag { NOTMUCH_MESSAGE_FLAG_MATCH => Match, NOTMUCH_MESSAGE_FLAG_EXCLUDED => Excluded, @@ -125,15 +125,15 @@ notmuch_enum! { } } -#[repr(C)] pub struct notmuch_database_t; -#[repr(C)] pub struct notmuch_query_t; -#[repr(C)] pub struct notmuch_threads_t; -#[repr(C)] pub struct notmuch_thread_t; -#[repr(C)] pub struct notmuch_messages_t; -#[repr(C)] pub struct notmuch_message_t; -#[repr(C)] pub struct notmuch_tags_t; -#[repr(C)] pub struct notmuch_directory_t; -#[repr(C)] pub struct notmuch_filenames_t; +#[repr(C)] pub struct notmuch_database_t(c_void); +#[repr(C)] pub struct notmuch_query_t(c_void); +#[repr(C)] pub struct notmuch_threads_t(c_void); +#[repr(C)] pub struct notmuch_thread_t(c_void); +#[repr(C)] pub struct notmuch_messages_t(c_void); +#[repr(C)] pub struct notmuch_message_t(c_void); +#[repr(C)] pub struct notmuch_tags_t(c_void); +#[repr(C)] pub struct notmuch_directory_t(c_void); +#[repr(C)] pub struct notmuch_filenames_t(c_void); #[link(name = "notmuch")] extern { diff --git a/src/lib.rs b/src/lib.rs index 63d190f..c7984e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,6 @@ - #[macro_use] mod macros; -extern crate notmuch_sys as ffi_sys; extern crate libc; mod utils; diff --git a/src/utils.rs b/src/utils.rs index af3ce29..8aad8f7 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -4,8 +4,6 @@ use std::{ str, }; -use std::os::unix::ffi::OsStrExt; - use libc; pub trait NewFromPtr { -- cgit v1.2.1 From e5dae2152ab7b1322362de01881744953cbb241f Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 20 Mar 2018 21:16:24 +0100 Subject: fix infinite recursion --- src/database.rs | 26 ++++++++++++++------------ src/ffi.rs | 2 +- src/lib.rs | 3 +++ src/utils.rs | 12 ------------ 4 files changed, 18 insertions(+), 25 deletions(-) diff --git a/src/database.rs b/src/database.rs index ddba507..79e519e 100644 --- a/src/database.rs +++ b/src/database.rs @@ -4,12 +4,13 @@ use std::{ ptr, }; +use std::ffi::CString; + use libc; use error::Result; use utils::{ NewFromPtr, - ToCString, ToStr, }; @@ -18,7 +19,7 @@ use directory::Directory; use ffi; // Re-exported under database module for pretty namespacin'. -pub use ffi::Mode; +pub use ffi::DatabaseOpenMode; #[derive(Copy, Clone, Debug)] pub struct Version(libc::c_uint); @@ -27,23 +28,23 @@ pub struct Database(*mut ffi::notmuch_database_t); impl Database { pub fn create>(path: &P) -> Result { - let path = path.to_cstring().unwrap(); + 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.as_ptr(), &mut db) + ffi::notmuch_database_create(path_str.as_ptr(), &mut db) }.as_result()); Ok(Database(db)) } - pub fn open>(path: &P, mode: Mode) -> Result { - let path = path.to_cstring().unwrap(); + pub fn open>(path: &P, mode: DatabaseOpenMode) -> Result { + 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.as_ptr(), mode.into(), &mut db, + path_str.as_ptr(), mode.into(), &mut db, ) }.as_result()); @@ -84,14 +85,15 @@ impl Database { } } - let path = path.to_cstring().unwrap(); + let path_str = CString::new(path.as_ref().to_str().unwrap()).unwrap(); + let backup_path = backup_path.map(|p| { - p.to_cstring().unwrap() + CString::new(p.as_ref().to_str().unwrap()).unwrap() }); try!(unsafe { ffi::notmuch_database_compact( - path.as_ptr(), backup_path.map_or(ptr::null(), |p| p.as_ptr()), + path_str.as_ptr(), backup_path.map_or(ptr::null(), |p| p.as_ptr()), if status.is_some() { Some(wrapper::) } else { None }, status.map_or(ptr::null_mut(), |f| { &f as *const _ as *mut libc::c_void @@ -155,12 +157,12 @@ impl Database { } pub fn directory>(&self, path: &P) -> Result> { - let path = path.to_cstring().unwrap(); + 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.0, path.as_ptr(), &mut dir, + self.0, path_str.as_ptr(), &mut dir, ) }.as_result()); diff --git a/src/ffi.rs b/src/ffi.rs index bd59941..1d68d15 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -87,7 +87,7 @@ impl error::Error for Status { notmuch_enum! { #[repr(C)] #[derive(Debug, Eq, PartialEq, Clone, Copy)] - pub enum notmuch_database_mode_t => Mode { + pub enum notmuch_database_mode_t => DatabaseOpenMode { NOTMUCH_DATABASE_MODE_READ_ONLY => ReadOnly, NOTMUCH_DATABASE_MODE_READ_WRITE => ReadWrite } diff --git a/src/lib.rs b/src/lib.rs index c7984e0..1348c7e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,3 +9,6 @@ mod ffi; pub mod error; pub mod database; pub mod directory; + +pub use database::Database; +pub use ffi::DatabaseOpenMode; diff --git a/src/utils.rs b/src/utils.rs index 8aad8f7..fa24029 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,6 +1,5 @@ use std::{ ffi, - path, str, }; @@ -10,17 +9,6 @@ pub trait NewFromPtr { fn new(ptr: T) -> Self; } -pub trait ToCString { - fn to_cstring(&self) -> Result; -} - -impl> ToCString for T { - fn to_cstring(&self) -> Result { - let path: &ffi::OsStr = self.as_ref().as_ref(); - path.to_cstring() - } -} - pub trait ToStr { fn to_str<'a>(&self) -> Result<&'a str, str::Utf8Error>; } -- cgit v1.2.1 From 318a3a99474e29594e88e4510df3b21633dba4d3 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 20 Mar 2018 21:18:49 +0100 Subject: add debug trait to database --- src/database.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/database.rs b/src/database.rs index 79e519e..8f64fdd 100644 --- a/src/database.rs +++ b/src/database.rs @@ -24,6 +24,7 @@ pub use ffi::DatabaseOpenMode; #[derive(Copy, Clone, Debug)] pub struct Version(libc::c_uint); +#[derive(Debug)] pub struct Database(*mut ffi::notmuch_database_t); impl Database { -- cgit v1.2.1 From 20d8795672f44660ba4dc7a8a8736133f35a7754 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 21 Mar 2018 09:26:25 +0100 Subject: Update ffi interface Most of this is plain copied from https://github.com/Stebalien/notmuch-sys. At some point, I would like to split this up again, but not right now. --- src/ffi.rs | 1406 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 1345 insertions(+), 61 deletions(-) diff --git a/src/ffi.rs b/src/ffi.rs index 1d68d15..f3ddb41 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -8,6 +8,7 @@ use libc::{ c_int, c_uint, c_void, + c_ulong, time_t, }; @@ -21,9 +22,6 @@ use utils::{ ToStr, }; -pub type notmuch_bool_t = c_int; - -pub type notmuch_compact_status_cb_t = extern fn(*const c_char, *mut c_void); notmuch_enum! { #[repr(C)] @@ -134,28 +132,158 @@ notmuch_enum! { #[repr(C)] pub struct notmuch_tags_t(c_void); #[repr(C)] pub struct notmuch_directory_t(c_void); #[repr(C)] pub struct notmuch_filenames_t(c_void); +#[repr(C)] pub struct notmuch_message_properties_t(c_void); +#[repr(C)] pub struct notmuch_config_list_t(c_void); + +pub type notmuch_compact_status_cb_t = extern "C" fn(message: *const c_char, closure: *mut c_void); +pub type notmuch_database_upgrade_cb_t = extern "C" fn(closure: *mut c_void, progress: c_double); + +pub type notmuch_bool_t = c_int; +pub const TRUE: notmuch_bool_t = 1; +pub const FALSE: notmuch_bool_t = 0; #[link(name = "notmuch")] extern { + + /// Get a string representation of a `notmuch_status_t` value. + /// + /// The result is read-only. pub fn notmuch_status_to_string( status: notmuch_status_t, ) -> *const c_char; + /// Create a new, empty notmuch database located at 'path'. + /// + /// The path should be a top-level directory to a collection of + /// plain-text email messages (one message per file). This call will + /// create a new ".notmuch" directory within 'path' where notmuch will + /// store its data. + /// + /// After a successful call to `notmuch_database_create`, the returned + /// database will be open so the caller should call + /// `notmuch_database_destroy` when finished with it. + /// + /// The database will not yet have any data in it + /// (`notmuch_database_create` itself is a very cheap function). Messages + /// contained within 'path' can be added to the database by calling + /// `notmuch_database_add_message`. + /// + /// In case of any failure, this function returns an error status and + /// sets *database to NULL (after printing an error message on stderr). + /// + /// Return value: + /// + /// * `notmuch_status_t::SUCCESS`: Successfully created the database. + /// + /// * `notmuch_status_t::NULL_POINTER`: The given 'path' argument is NULL. + /// + /// * `notmuch_status_t::OUT_OF_MEMORY`: Out of memory. + /// + /// * `notmuch_status_t::FILE_ERROR`: An error occurred trying to create the + /// database file (such as permission denied, or file not found, + /// etc.), or the database already exists. + /// + /// * `notmuch_status_t::XAPIAN_EXCEPTION`: A Xapian exception occurred. pub fn notmuch_database_create( path: *const c_char, database: *mut *mut notmuch_database_t, ) -> notmuch_status_t; + /// Like `notmuch_database_create`, except optionally return an error + /// message. This message is allocated by malloc and should be freed by + /// the caller. + pub fn notmuch_database_create_verbose(path: *const c_char, + database: *mut *mut notmuch_database_t, + error_message: *mut *const c_char) + -> notmuch_status_t; + + /// Open an existing notmuch database located at 'path'. + /// + /// The database should have been created at some time in the past, + /// (not necessarily by this process), by calling + /// notmuch_database_create with 'path'. By default the database should be + /// opened for reading only. In order to write to the database you need to + /// pass the `notmuch_database_mode_t::READ_WRITE` mode. + /// + /// An existing notmuch database can be identified by the presence of a + /// directory named ".notmuch" below 'path'. + /// + /// The caller should call notmuch_database_destroy when finished with + /// this database. + /// + /// In case of any failure, this function returns an error status and + /// sets *database to NULL (after printing an error message on stderr). + /// + /// Return value: + /// + /// * `notmuch_status_t::SUCCESS`: Successfully opened the database. + /// + /// * `notmuch_status_t::NULL_POINTER`: The given 'path' argument is NULL. + /// + /// * `notmuch_status_t::OUT_OF_MEMORY`: Out of memory. + /// + /// * `notmuch_status_t::FILE_ERROR`: An error occurred trying to open the + /// database file (such as permission denied, or file not found, + /// etc.), or the database version is unknown. + /// + /// * `notmuch_status_t::XAPIAN_EXCEPTION`: A Xapian exception occurred. pub fn notmuch_database_open( path: *const c_char, mode: notmuch_database_mode_t, database: *mut *mut notmuch_database_t, ) -> notmuch_status_t; + /// Like notmuch_database_open, except optionally return an error + /// message. This message is allocated by malloc and should be freed by + /// the caller. + pub fn notmuch_database_open_verbose(path: *const c_char, + mode: notmuch_database_mode_t, + database: *mut *mut notmuch_database_t, + error_message: *mut *mut c_char) + -> notmuch_status_t; + + /// Retrieve last status string for given database. + pub fn notmuch_database_status_string(notmuch: *mut notmuch_database_t) -> *const c_char; + + /// Commit changes and close the given notmuch database. + /// + /// After `notmuch_database_close` has been called, calls to other + /// functions on objects derived from this database may either behave + /// as if the database had not been closed (e.g., if the required data + /// has been cached) or may fail with a + /// `notmuch_status_t::XAPIAN_EXCEPTION`. The only further operation + /// permitted on the database itself is to call `notmuch_database_destroy`. + /// + /// `notmuch_database_close` can be called multiple times. Later calls have + /// no effect. + /// + /// For writable databases, `notmuch_database_close` commits all changes + /// to disk before closing the database. If the caller is currently in + /// an atomic section (there was a `notmuch_database_begin_atomic` + /// without a matching `notmuch_database_end_atomic`), this will discard + /// changes made in that atomic section (but still commit changes made + /// prior to entering the atomic section). + /// + /// Return value: + /// + /// * `notmuch_status_t::SUCCESS`: Successfully closed the database. + /// + /// * `notmuch_status_t::XAPIAN_EXCEPTION`: A Xapian exception occurred; the + /// database has been closed but there are no guarantees the + /// changes to the database, if any, have been flushed to disk. pub fn notmuch_database_close( database: *mut notmuch_database_t, ) -> notmuch_status_t; + /// Compact a notmuch database, backing up the original database to the + /// given path. + /// + /// The database will be opened with notmuch_database_mode_t::READ_WRITE + /// during the compaction process to ensure no writes are made. + /// + /// If the optional callback function 'status_cb' is non-NULL, it will + /// be called with diagnostic and informational messages. The argument + /// 'closure' is passed verbatim to any callback invoked. pub fn notmuch_database_compact( path: *const c_char, backup_path: *const c_char, @@ -163,325 +291,1481 @@ extern { closure: *mut c_void, ) -> notmuch_status_t; + /// Destroy the notmuch database, closing it if necessary and freeing + /// all associated resources. + /// + /// Return value as in `notmuch_database_close` if the database was open; + /// `notmuch_database_destroy` itself has no failure modes. pub fn notmuch_database_destroy( database: *mut notmuch_database_t, ) -> notmuch_status_t; + /// Return the database path of the given database. + /// + /// The return value is a string owned by notmuch so should not be + /// modified nor freed by the caller. pub fn notmuch_database_get_path( database: *mut notmuch_database_t, ) -> *const c_char; + /// Return the database format version of the given database. pub fn notmuch_database_get_version( database: *mut notmuch_database_t, ) -> c_uint; + /// Can the database be upgraded to a newer database version? + /// + /// If this function returns TRUE, then the caller may call + /// `notmuch_database_upgrade` to upgrade the database. If the caller + /// does not upgrade an out-of-date database, then some functions may + /// fail with `notmuch_status_t::UPGRADE_REQUIRED`. This always returns + /// FALSE for a read-only database because there's no way to upgrade a + /// read-only database. pub fn notmuch_database_needs_upgrade( database: *mut notmuch_database_t, ) -> notmuch_bool_t; - pub fn notmuch_database_upgrade( - database: *mut notmuch_database_t, - progress_notify: Option, - closure: *mut c_void, - ) -> notmuch_status_t; - + /// Upgrade the current database to the latest supported version. + /// + /// This ensures that all current notmuch functionality will be + /// available on the database. After opening a database in read-write + /// mode, it is recommended that clients check if an upgrade is needed + /// (`notmuch_database_needs_upgrade`) and if so, upgrade with this + /// function before making any modifications. If + /// `notmuch_database_needs_upgrade` returns FALSE, this will be a no-op. + /// + /// The optional progress_notify callback can be used by the caller to + /// provide progress indication to the user. If non-NULL it will be + /// called periodically with 'progress' as a floating-point value in + /// the range of [0.0 .. 1.0] indicating the progress made so far in + /// the upgrade process. The argument 'closure' is passed verbatim to + /// any callback invoked. + pub fn notmuch_database_upgrade(database: *mut notmuch_database_t, + progress_notify: Option, + closure: *mut c_void) + -> notmuch_status_t; + + /// Begin an atomic database operation. + /// + /// Any modifications performed between a successful begin and a + /// `notmuch_database_end_atomic` will be applied to the database + /// atomically. Note that, unlike a typical database transaction, this + /// only ensures atomicity, not durability; neither begin nor end + /// necessarily flush modifications to disk. + /// + /// Atomic sections may be nested. begin_atomic and end_atomic must + /// always be called in pairs. + /// + /// Return value: + /// + /// * `notmuch_status_t::SUCCESS`: Successfully entered atomic section. + /// + /// * `notmuch_status_t::XAPIAN_EXCEPTION`: A Xapian exception occurred; + /// atomic section not entered. pub fn notmuch_database_begin_atomic( notmuch: *mut notmuch_database_t, ) -> notmuch_status_t; + /// Indicate the end of an atomic database operation. + /// + /// Return value: + /// + /// * `notmuch_status_t::SUCCESS`: Successfully completed atomic section. + /// + /// * `notmuch_status_t::XAPIAN_EXCEPTION`: A Xapian exception occurred; + /// atomic section not ended. + /// + /// * `notmuch_status_t::UNBALANCED_ATOMIC`: The database is not currently in + /// an atomic section. pub fn notmuch_database_end_atomic( notmuch: *mut notmuch_database_t, ) -> notmuch_status_t; + /// Return the committed database revision and UUID. + /// + /// The database revision number increases monotonically with each + /// commit to the database. Hence, all messages and message changes + /// committed to the database (that is, visible to readers) have a last + /// modification revision <= the committed database revision. Any + /// messages committed in the future will be assigned a modification + /// revision > the committed database revision. + /// + /// The UUID is a NUL-terminated opaque string that uniquely identifies + /// this database. Two revision numbers are only comparable if they + /// have the same database UUID. + pub fn notmuch_database_get_revision(notmuch: *mut notmuch_database_t, + uuid: *mut *const c_char) + -> c_ulong; + + /// Retrieve a directory object from the database for 'path'. + /// + /// Here, 'path' should be a path relative to the path of 'database' + /// (see `notmuch_database_get_path`), or else should be an absolute path + /// with initial components that match the path of 'database'. + /// + /// If this directory object does not exist in the database, this + /// returns `notmuch_status_t::SUCCESS` and sets *directory to NULL. + /// + /// Otherwise the returned directory object is owned by the database + /// and as such, will only be valid until `notmuch_database_destroy` is + /// called. + /// + /// Return value: + /// + /// * `notmuch_status_t::SUCCESS`: Successfully retrieved directory. + /// + /// * `notmuch_status_t::NULL_POINTER`: The given 'directory' argument is NULL. + /// + /// * `notmuch_status_t::XAPIAN_EXCEPTION`: A Xapian exception occurred; + /// directory not retrieved. + /// + /// * `notmuch_status_t::UPGRADE_REQUIRED`: The caller must upgrade the + /// database to use this function. pub fn notmuch_database_get_directory( database: *mut notmuch_database_t, path: *const c_char, directory: *mut *mut notmuch_directory_t, ) -> notmuch_status_t; + /// Add a new message to the given notmuch database or associate an + /// additional filename with an existing message. + /// + /// Here, 'filename' should be a path relative to the path of + /// 'database' (see `notmuch_database_get_path`), or else should be an + /// absolute filename with initial components that match the path of + /// 'database'. + /// + /// The file should be a single mail message (not a multi-message mbox) + /// that is expected to remain at its current location, (since the + /// notmuch database will reference the filename, and will not copy the + /// entire contents of the file. + /// + /// If another message with the same message ID already exists in the + /// database, rather than creating a new message, this adds 'filename' + /// to the list of the filenames for the existing message. + /// + /// If 'message' is not NULL, then, on successful return + /// (notmuch_status_t::SUCCESS or `notmuch_status_t::DUPLICATE_MESSAGE_ID`) '*message' + /// will be initialized to a message object that can be used for things + /// such as adding tags to the just-added message. The user should call + /// `notmuch_message_destroy` when done with the message. On any failure + /// '*message' will be set to NULL. + /// + /// Return value: + /// + /// * `notmuch_status_t::SUCCESS`: Message successfully added to database. + /// + /// * `notmuch_status_t::XAPIAN_EXCEPTION`: A Xapian exception occurred, + /// message not added. + /// + /// * `notmuch_status_t::DUPLICATE_MESSAGE_ID`: Message has the same message + /// ID as another message already in the database. The new + /// filename was successfully added to the message in the database + /// (if not already present) and the existing message is returned. + /// + /// * `notmuch_status_t::FILE_ERROR`: an error occurred trying to open the + /// file, (such as permission denied, or file not found, + /// etc.). Nothing added to the database. + /// + /// * `notmuch_status_t::FILE_NOT_EMAIL`: the contents of filename don't look + /// like an email message. Nothing added to the database. + /// + /// * `notmuch_status_t::READ_ONLY_DATABASE`: Database was opened in read-only + /// mode so no message can be added. + /// + /// * `notmuch_status_t::UPGRADE_REQUIRED`: The caller must upgrade the + /// database to use this function. pub fn notmuch_database_add_message( database: *mut notmuch_database_t, filename: *const c_char, message: *mut *mut notmuch_message_t, ) -> notmuch_status_t; + /// Remove a message filename from the given notmuch database. If the + /// message has no more filenames, remove the message. + /// + /// If the same message (as determined by the message ID) is still + /// available via other filenames, then the message will persist in the + /// database for those filenames. When the last filename is removed for + /// a particular message, the database content for that message will be + /// entirely removed. + /// + /// Return value: + /// + /// * `notmuch_status_t::SUCCESS`: The last filename was removed and the + /// message was removed from the database. + /// + /// * `notmuch_status_t::XAPIAN_EXCEPTION`: A Xapian exception occurred, + /// message not removed. + /// + /// * `notmuch_status_t::DUPLICATE_MESSAGE_ID`: This filename was removed but + /// the message persists in the database with at least one other + /// filename. + /// + /// * `notmuch_status_t::READ_ONLY_DATABASE`: Database was opened in read-only + /// mode so no message can be removed. + /// + /// * `notmuch_status_t::UPGRADE_REQUIRED`: The caller must upgrade the + /// database to use this function. pub fn notmuch_database_remove_message( database: *mut notmuch_database_t, filename: *const c_char, ) -> notmuch_status_t; + /// Find a message with the given message_id. + /// + /// If a message with the given message_id is found then, on successful return + /// (`notmuch_status_t::SUCCESS`) '*message' will be initialized to a message + /// object. The caller should call `notmuch_message_destroy` when done with the + /// message. + /// + /// On any failure or when the message is not found, this function initializes + /// '*message' to NULL. This means, when `notmuch_status_t::SUCCESS` is returned, the + /// caller is supposed to check '*message' for NULL to find out whether the + /// message with the given message_id was found. + /// + /// Return value: + /// + /// * `notmuch_status_t::SUCCESS`: Successful return, check '*message'. + /// + /// * `notmuch_status_t::NULL_POINTER`: The given 'message' argument is NULL + /// + /// * `notmuch_status_t::OUT_OF_MEMORY`: Out of memory, creating message object + /// + /// * `notmuch_status_t::XAPIAN_EXCEPTION`: A Xapian exception occurred pub fn notmuch_database_find_message( database: *mut notmuch_database_t, message_id: *const c_char, message: *mut *mut notmuch_message_t, ) -> notmuch_status_t; + /// Find a message with the given filename. + /// + /// If the database contains a message with the given filename then, on + /// successful return (`notmuch_status_t::SUCCESS`) '*message' will be initialized to + /// a message object. The caller should call `notmuch_message_destroy` when done + /// with the message. + /// + /// On any failure or when the message is not found, this function initializes + /// '*message' to NULL. This means, when `notmuch_status_t::SUCCESS` is returned, the + /// caller is supposed to check '*message' for NULL to find out whether the + /// message with the given filename is found. + /// + /// Return value: + /// + /// * `notmuch_status_t::SUCCESS`: Successful return, check '*message' + /// + /// * `notmuch_status_t::NULL_POINTER`: The given 'message' argument is NULL + /// + /// * `notmuch_status_t::OUT_OF_MEMORY`: Out of memory, creating the message object + /// + /// * `notmuch_status_t::XAPIAN_EXCEPTION`: A Xapian exception occurred + /// + /// * `notmuch_status_t::UPGRADE_REQUIRED`: The caller must upgrade the + /// database to use this function. pub fn notmuch_database_find_message_by_filename( database: *mut notmuch_database_t, filename: *const c_char, message: *mut *mut notmuch_message_t, ) -> notmuch_status_t; + /// Return a list of all tags found in the database. + /// + /// This function creates a list of all tags found in the database. The + /// resulting list contains all tags from all messages found in the database. + /// + /// On error this function returns NULL. pub fn notmuch_database_get_all_tags( db: *mut notmuch_database_t, ) -> *mut notmuch_tags_t; + /// Create a new query for 'database'. + /// + /// Here, 'database' should be an open database, (see + /// notmuch_database_open and `notmuch_database_create`). + /// + /// For the query string, we'll document the syntax here more + /// completely in the future, but it's likely to be a specialized + /// version of the general Xapian query syntax: + /// + /// https://xapian.org/docs/queryparser.html + /// + /// As a special case, passing either a length-zero string, (that is ""), + /// or a string consisting of a single asterisk (that is "*"), will + /// result in a query that returns all messages in the database. + /// + /// See `notmuch_query_set_sort` for controlling the order of results. + /// See notmuch_query_search_messages and `notmuch_query_search_threads` + /// to actually execute the query. + /// + /// User should call `notmuch_query_destroy` when finished with this + /// query. + /// + /// Will return NULL if insufficient memory is available. pub fn notmuch_query_create( database: *mut notmuch_database_t, query_string: *const c_char, ) -> *mut notmuch_query_t; + /// Return the query_string of this query. See `notmuch_query_create`. pub fn notmuch_query_get_query_string( query: *mut notmuch_query_t, ) -> *const c_char; + /// Return the notmuch database of this query. See `notmuch_query_create`. + pub fn notmuch_query_get_database(query: *const notmuch_query_t) -> *mut notmuch_database_t; + + /// Specify whether to omit excluded results or simply flag them. By + /// default, this is set to TRUE. + /// + /// If set to TRUE or ALL, `notmuch_query_search_messages` will omit excluded + /// messages from the results, and `notmuch_query_search_threads` will omit + /// threads that match only in excluded messages. If set to TRUE, + /// `notmuch_query_search_threads` will include all messages in threads that + /// match in at least one non-excluded message. Otherwise, if set to ALL, + /// `notmuch_query_search_threads` will omit excluded messages from all threads. + /// + /// If set to FALSE or FLAG then both `notmuch_query_search_messages` and + /// `notmuch_query_search_threads` will return all matching + /// messages/threads regardless of exclude status. If set to FLAG then + /// the exclude flag will be set for any excluded message that is + /// returned by `notmuch_query_search_messages`, and the thread counts + /// for threads returned by `notmuch_query_search_threads` will be the + /// number of non-excluded messages/matches. Otherwise, if set to + /// FALSE, then the exclude status is completely ignored. + /// + /// The performance difference when calling + /// `notmuch_query_search_messages` should be relatively small (and both + /// should be very fast). However, in some cases, + /// `notmuch_query_search_threads` is very much faster when omitting + /// excluded messages as it does not need to construct the threads that + /// only match in excluded messages. pub fn notmuch_query_set_omit_excluded( query: *mut notmuch_query_t, omit_excluded: notmuch_exclude_t, ); + /// Specify the sorting desired for this query. pub fn notmuch_query_set_sort( query: *mut notmuch_query_t, sort: notmuch_sort_t, ); + /// Return the sort specified for this query. See + /// `notmuch_query_set_sort`. pub fn notmuch_query_get_sort( query: *mut notmuch_query_t, ) -> notmuch_sort_t; + /// Add a tag that will be excluded from the query results by default. + /// This exclusion will be overridden if this tag appears explicitly in + /// the query. pub fn notmuch_query_add_tag_exclude( query: *mut notmuch_query_t, tag: *const c_char, ); + /// Execute a query for threads, returning a `notmuch_threads_t` object + /// which can be used to iterate over the results. The returned threads + /// object is owned by the query and as such, will only be valid until + /// `notmuch_query_destroy`. + /// + /// Typical usage might be: + /// + /// ```norun + /// notmuch_query_t *query; + /// notmuch_threads_t *threads; + /// notmuch_thread_t *thread; + /// + /// query = notmuch_query_create (database, query_string); + /// + /// for (threads = notmuch_query_search_threads (query); + /// notmuch_threads_valid (threads); + /// notmuch_threads_move_to_next (threads)) + /// { + /// thread = notmuch_threads_get (threads); + /// .... + /// notmuch_thread_destroy (thread); + /// } + /// + /// notmuch_query_destroy (query); + /// ``` + /// + /// Note: If you are finished with a thread before its containing + /// query, you can call `notmuch_thread_destroy` to clean up some memory + /// sooner (as in the above example). Otherwise, if your thread objects + /// are long-lived, then you don't need to call `notmuch_thread_destroy` + /// and all the memory will still be reclaimed when the query is + /// destroyed. + /// + /// Note that there's no explicit destructor needed for the + /// `notmuch_threads_t` object. (For consistency, we do provide a + /// `notmuch_threads_destroy` function, but there's no good reason + /// to call it if the query is about to be destroyed). + /// + /// @since libnotmuch 4.2 (notmuch 0.20) pub fn notmuch_query_search_threads( query: *mut notmuch_query_t, ) -> *mut notmuch_threads_t; + /// Execute a query for messages, returning a `notmuch_messages_t` object + /// which can be used to iterate over the results. The returned + /// messages object is owned by the query and as such, will only be + /// valid until `notmuch_query_destroy`. + /// + /// Typical usage might be: + /// + /// ```norun + /// notmuch_query_t *query; + /// notmuch_messages_t *messages; + /// notmuch_message_t *message; + /// + /// query = notmuch_query_create (database, query_string); + /// + /// for (messages = notmuch_query_search_messages (query); + /// notmuch_messages_valid (messages); + /// notmuch_messages_move_to_next (messages)) + /// { + /// message = notmuch_messages_get (messages); + /// .... + /// notmuch_message_destroy (message); + /// } + /// + /// notmuch_query_destroy (query); + /// ``` + /// + /// Note: If you are finished with a message before its containing + /// query, you can call `notmuch_message_destroy` to clean up some memory + /// sooner (as in the above example). Otherwise, if your message + /// objects are long-lived, then you don't need to call + /// `notmuch_message_destroy` and all the memory will still be reclaimed + /// when the query is destroyed. + /// + /// Note that there's no explicit destructor needed for the + /// `notmuch_messages_t` object. (For consistency, we do provide a + /// `notmuch_messages_destroy` function, but there's no good + /// reason to call it if the query is about to be destroyed). + /// + /// If a Xapian exception occurs this function will return NULL. + /// + /// @since libnotmuch 4.2 (notmuch 0.20) pub fn notmuch_query_search_messages( query: *mut notmuch_query_t, ) -> *mut notmuch_messages_t; + /// Destroy a `notmuch_query_t` along with any associated resources. + /// + /// This will in turn destroy any `notmuch_threads_t` and + /// `notmuch_messages_t` objects generated by this query, (and in + /// turn any notmuch_thread_t and `notmuch_message_t` objects generated + /// from those results, etc.), if such objects haven't already been + /// destroyed. pub fn notmuch_query_destroy( query: *mut notmuch_query_t, ); + /// Is the given 'threads' iterator pointing at a valid thread. + /// + /// When this function returns TRUE, `notmuch_threads_get` will return a + /// valid object. Whereas when this function returns FALSE, + /// `notmuch_threads_get` will return NULL. + /// + /// If passed a NULL pointer, this function returns FALSE + /// + /// See the documentation of `notmuch_query_search_threads` for example + /// code showing how to iterate over a `notmuch_threads_t` object. pub fn notmuch_threads_valid( threads: *mut notmuch_threads_t, ) -> notmuch_bool_t; + /// Get the current thread from 'threads' as a `notmuch_thread_t`. + /// + /// Note: The returned thread belongs to 'threads' and has a lifetime + /// identical to it (and the query to which it belongs). + /// + /// See the documentation of `notmuch_query_search_threads` for example + /// code showing how to iterate over a `notmuch_threads_t` object. + /// + /// If an out-of-memory situation occurs, this function will return + /// NULL. pub fn notmuch_threads_get( threads: *mut notmuch_threads_t, ) -> *mut notmuch_thread_t; + /// Move the 'threads' iterator to the next thread. + /// + /// If 'threads' is already pointing at the last thread then the + /// iterator will be moved to a point just beyond that last thread, + /// (where `notmuch_threads_valid` will return FALSE and + /// `notmuch_threads_get` will return NULL). + /// + /// See the documentation of `notmuch_query_search_threads` for example + /// code showing how to iterate over a `notmuch_threads_t` object. pub fn notmuch_threads_move_to_next( threads: *mut notmuch_threads_t, ); + /// Destroy a `notmuch_threads_t` object. + /// + /// It's not strictly necessary to call this function. All memory from + /// the `notmuch_threads_t` object will be reclaimed when the + /// containing query object is destroyed. pub fn notmuch_threads_destroy( threads: *mut notmuch_threads_t, ); + /// Return the number of messages matching a search. + /// + /// This function performs a search and returns the number of matching + /// messages. + /// + /// @returns + /// + /// `notmuch_status_t::SUCCESS`: query completed successfully. + /// + /// `notmuch_status_t::XAPIAN_EXCEPTION`: a Xapian exception occured. The + /// value of *count is not defined. + /// + /// @since libnotmuch 4.3 (notmuch 0.21) pub fn notmuch_query_count_messages( query: *mut notmuch_query_t, ) -> c_uint; + + /// Return the number of threads matching a search. + /// + /// This function performs a search and returns the number of unique thread IDs + /// in the matching messages. This is the same as number of threads matching a + /// search. + /// + /// Note that this is a significantly heavier operation than + /// `notmuch_query_count_messages`{_st}(). + /// + /// @returns + /// + /// * `notmuch_status_t::OUT_OF_MEMORY`: Memory allocation failed. The value + /// of *count is not defined + + /// * `notmuch_status_t::SUCCESS`: query completed successfully. + /// + /// * `notmuch_status_t::XAPIAN_EXCEPTION`: a Xapian exception occured. The + /// value of *count is not defined. + /// + /// @since libnotmuch 4.3 (notmuch 0.21) pub fn notmuch_count_threads( query: *mut notmuch_query_t, ) -> c_uint; + /// Get the thread ID of 'thread'. + /// + /// The returned string belongs to 'thread' and as such, should not be + /// modified by the caller and will only be valid for as long as the + /// thread is valid, (which is until `notmuch_thread_destroy` or until + /// the query from which it derived is destroyed). pub fn notmuch_thread_get_thread_id( thread: *mut notmuch_thread_t, ) -> *const c_char; + /// Get the total number of messages in 'thread'. + /// + /// This count consists of all messages in the database belonging to + /// this thread. Contrast with `notmuch_thread_get_matched_messages`(). pub fn notmuch_thread_get_total_messages( thread: *mut notmuch_thread_t, ) -> c_int; + /// Get a `notmuch_messages_t` iterator for the top-level messages in + /// 'thread' in oldest-first order. + /// + /// This iterator will not necessarily iterate over all of the messages + /// in the thread. It will only iterate over the messages in the thread + /// which are not replies to other messages in the thread. + /// + /// The returned list will be destroyed when the thread is destroyed. pub fn notmuch_thread_get_toplevel_messages( thread: *mut notmuch_thread_t, ) -> *mut notmuch_messages_t; + /// Get a `notmuch_thread_t` iterator for all messages in 'thread' in + /// oldest-first order. + /// + /// The returned list will be destroyed when the thread is destroyed. pub fn notmuch_thread_get_messages( thread: *mut notmuch_thread_t, ) -> *mut notmuch_messages_t; + /// Get the number of messages in 'thread' that matched the search. + /// + /// This count includes only the messages in this thread that were + /// matched by the search from which the thread was created and were + /// not excluded by any exclude tags passed in with the query (see + /// `notmuch_query_add_tag_exclude`). Contrast with + /// `notmuch_thread_get_total_messages`() . pub fn notmuch_thread_get_matched_messages( thread: *mut notmuch_thread_t, ) -> c_int; + /// Get the authors of 'thread' as a UTF-8 string. + /// + /// The returned string is a comma-separated list of the names of the + /// authors of mail messages in the query results that belong to this + /// thread. + /// + /// The string contains authors of messages matching the query first, then + /// non-matched authors (with the two groups separated by '|'). Within + /// each group, authors are ordered by date. + /// + /// The returned string belongs to 'thread' and as such, should not be + /// modified by the caller and will only be valid for as long as the + /// thread is valid, (which is until `notmuch_thread_destroy` or until + /// the query from which it derived is destroyed). pub fn notmuch_thread_get_authors( thread: *mut notmuch_thread_t, ) -> *const c_char; + /// Get the subject of 'thread' as a UTF-8 string. + /// + /// The subject is taken from the first message (according to the query + /// order---see `notmuch_query_set_sort`) in the query results that + /// belongs to this thread. + /// + /// The returned string belongs to 'thread' and as such, should not be + /// modified by the caller and will only be valid for as long as the + /// thread is valid, (which is until `notmuch_thread_destroy` or until + /// the query from which it derived is destroyed). pub fn notmuch_thread_get_subject( thread: *mut notmuch_thread_t, ) -> *const c_char; + /// Get the date of the oldest message in 'thread' as a time_t value. pub fn notmuch_thread_get_oldest_date( thread: *mut notmuch_thread_t, ) -> time_t; + /// Get the date of the newest message in 'thread' as a time_t value. pub fn notmuch_thread_get_newest_date( thread: *mut notmuch_thread_t, ) -> time_t; + /// Get the tags for 'thread', returning a `notmuch_tags_t` object which + /// can be used to iterate over all tags. + /// + /// Note: In the Notmuch database, tags are stored on individual + /// messages, not on threads. So the tags returned here will be all + /// tags of the messages which matched the search and which belong to + /// this thread. + /// + /// The tags object is owned by the thread and as such, will only be + /// valid for as long as the thread is valid, (for example, until + /// `notmuch_thread_destroy` or until the query from which it derived is + /// destroyed). + /// + /// Typical usage might be: + /// + /// ```norun + /// notmuch_thread_t *thread; + /// notmuch_tags_t *tags; + /// const char *tag; + /// + /// thread = notmuch_threads_get (threads); + /// + /// for (tags = notmuch_thread_get_tags (thread); + /// notmuch_tags_valid (tags); + /// notmuch_tags_move_to_next (tags)) + /// { + /// tag = notmuch_tags_get (tags); + /// .... + /// } + /// + /// notmuch_thread_destroy (thread); + /// ``` + /// + /// Note that there's no explicit destructor needed for the + /// `notmuch_tags_t` object. (For consistency, we do provide a + /// `notmuch_tags_destroy` function, but there's no good reason to call + /// it if the message is about to be destroyed). pub fn notmuch_thread_get_tags( thread: *mut notmuch_thread_t, ) -> *mut notmuch_tags_t; + /// Destroy a `notmuch_thread_t` object. pub fn notmuch_thread_destroy( thread: *mut notmuch_thread_t, ); + /// Is the given 'messages' iterator pointing at a valid message. + /// + /// When this function returns TRUE, `notmuch_messages_get` will return a + /// valid object. Whereas when this function returns FALSE, + /// `notmuch_messages_get` will return NULL. + /// + /// See the documentation of `notmuch_query_search_messages` for example + /// code showing how to iterate over a `notmuch_messages_t` object. pub fn notmuch_messages_valid( messages: *mut notmuch_messages_t, ) -> notmuch_bool_t; + /// Get the current message from 'messages' as a `notmuch_message_t`. + /// + /// Note: The returned message belongs to 'messages' and has a lifetime + /// identical to it (and the query to which it belongs). + /// + /// See the documentation of `notmuch_query_search_messages` for example + /// code showing how to iterate over a `notmuch_messages_t` object. + /// + /// If an out-of-memory situation occurs, this function will return + /// NULL. pub fn notmuch_messages_get( messages: *mut notmuch_messages_t, ) -> *mut notmuch_message_t; + /// Move the 'messages' iterator to the next message. + /// + /// If 'messages' is already pointing at the last message then the + /// iterator will be moved to a point just beyond that last message, + /// (where `notmuch_messages_valid` will return FALSE and + /// `notmuch_messages_get` will return NULL). + /// + /// See the documentation of `notmuch_query_search_messages` for example + /// code showing how to iterate over a `notmuch_messages_t` object. pub fn notmuch_messages_move_to_next( messages: *mut notmuch_messages_t, ); + /// Destroy a `notmuch_messages_t` object. + /// + /// It's not strictly necessary to call this function. All memory from + /// the `notmuch_messages_t` object will be reclaimed when the containing + /// query object is destroyed. pub fn notmuch_messages_destroy( messages: *mut notmuch_messages_t, ); + /// Return a list of tags from all messages. + /// + /// The resulting list is guaranteed not to contain duplicated tags. + /// + /// WARNING: You can no longer iterate over messages after calling this + /// function, because the iterator will point at the end of the list. + /// We do not have a function to reset the iterator yet and the only + /// way how you can iterate over the list again is to recreate the + /// message list. + /// + /// The function returns NULL on error. pub fn notmuch_messages_collect_tags( messages: *mut notmuch_messages_t, ) -> *mut notmuch_tags_t; + + /// Get the message ID of 'message'. + /// + /// The returned string belongs to 'message' and as such, should not be + /// modified by the caller and will only be valid for as long as the + /// message is valid, (which is until the query from which it derived + /// is destroyed). + /// + /// This function will not return NULL since Notmuch ensures that every + /// message has a unique message ID, (Notmuch will generate an ID for a + /// message if the original file does not contain one). pub fn notmuch_message_get_message_id( message: *mut notmuch_message_t, ) -> *const c_char; + /// Get the thread ID of 'message'. + /// + /// The returned string belongs to 'message' and as such, should not be + /// modified by the caller and will only be valid for as long as the + /// message is valid, (for example, until the user calls + /// `notmuch_message_destroy` on 'message' or until a query from which it + /// derived is destroyed). + /// + /// This function will not return NULL since Notmuch ensures that every + /// message belongs to a single thread. pub fn notmuch_message_get_thread_id( message: *mut notmuch_message_t, ) -> *const c_char; + /// Get a `notmuch_messages_t` iterator for all of the replies to + /// 'message'. + /// + /// Note: This call only makes sense if 'message' was ultimately + /// obtained from a `notmuch_thread_t` object, (such as by coming + /// directly from the result of calling + /// `notmuch_thread_get_toplevel_messages` or by any number of subsequent + /// calls to `notmuch_message_get_replies`). + /// + /// If 'message' was obtained through some non-thread means, (such as + /// by a call to `notmuch_query_search_messages`), then this function + /// will return NULL. + /// + /// If there are no replies to 'message', this function will return + /// NULL. (Note that `notmuch_messages_valid` will accept that NULL + /// value as legitimate, and simply return FALSE for it.) pub fn notmuch_message_get_replies( message: *mut notmuch_message_t, ) -> *mut notmuch_messages_t; + /// Get a filename for the email corresponding to 'message'. + /// + /// The returned filename is an absolute filename, (the initial + /// component will match `notmuch_database_get_path`() ). + /// + /// The returned string belongs to the message so should not be + /// modified or freed by the caller (nor should it be referenced after + /// the message is destroyed). + /// + /// Note: If this message corresponds to multiple files in the mail + /// store, (that is, multiple files contain identical message IDs), + /// this function will arbitrarily return a single one of those + /// filenames. See `notmuch_message_get_filenames` for returning the + /// complete list of filenames. pub fn notmuch_message_get_filename( message: *mut notmuch_message_t, ) -> *const c_char; + /// Get all filenames for the email corresponding to 'message'. + /// + /// Returns a `notmuch_filenames_t` iterator listing all the filenames + /// associated with 'message'. These files may not have identical + /// content, but each will have the identical Message-ID. + /// + /// Each filename in the iterator is an absolute filename, (the initial + /// component will match `notmuch_database_get_path`() ). pub fn notmuch_message_get_filenames( message: *mut notmuch_message_t, ) -> *mut notmuch_filenames_t; + /// Get a value of a flag for the email corresponding to 'message'. pub fn notmuch_message_get_flag( message: *mut notmuch_message_t, flag: notmuch_message_flag_t, ) -> notmuch_bool_t; + /// Set a value of a flag for the email corresponding to 'message'. pub fn notmuch_message_set_flag( message: *mut notmuch_message_t, flag: notmuch_message_flag_t, value: notmuch_bool_t, ); + /// Get the date of 'message' as a time_t value. + /// + /// For the original textual representation of the Date header from the + /// message call `notmuch_message_get_header`() with a header value of + /// "date". pub fn notmuch_message_get_date( message: *mut notmuch_message_t, ) -> time_t; + /// Get the value of the specified header from 'message' as a UTF-8 string. + /// + /// Common headers are stored in the database when the message is + /// indexed and will be returned from the database. Other headers will + /// be read from the actual message file. + /// + /// The header name is case insensitive. + /// + /// The returned string belongs to the message so should not be + /// modified or freed by the caller (nor should it be referenced after + /// the message is destroyed). + /// + /// Returns an empty string ("") if the message does not contain a + /// header line matching 'header'. Returns NULL if any error occurs. pub fn notmuch_message_get_header( message: *mut notmuch_message_t, header: *const c_char, ) -> *const c_char; + /// Get the tags for 'message', returning a `notmuch_tags_t` object which + /// can be used to iterate over all tags. + /// + /// The tags object is owned by the message and as such, will only be + /// valid for as long as the message is valid, (which is until the + /// query from which it derived is destroyed). + /// + /// Typical usage might be: + /// + /// ```norun + /// notmuch_message_t *message; + /// notmuch_tags_t *tags; + /// const char *tag; + /// + /// message = notmuch_database_find_message (database, message_id); + /// + /// for (tags = `notmuch_message_get_tags` (message); + /// notmuch_tags_valid (tags); + /// notmuch_tags_move_to_next (tags)) + /// { + /// tag = notmuch_tags_get (tags); + /// .... + /// } + /// + /// notmuch_message_destroy (message); + /// ``` + /// + /// Note that there's no explicit destructor needed for the + /// `notmuch_tags_t` object. (For consistency, we do provide a + /// `notmuch_tags_destroy` function, but there's no good reason to call + /// it if the message is about to be destroyed). pub fn notmuch_message_get_tags( message: *mut notmuch_message_t, ) -> *mut notmuch_tags_t; + /// Add a tag to the given message. + /// + /// Return value: + /// + /// * `notmuch_status_t::SUCCESS`: Tag successfully added to message + /// + /// * `notmuch_status_t::NULL_POINTER`: The 'tag' argument is NULL + /// + /// * `notmuch_status_t::TAG_TOO_LONG`: The length of 'tag' is too long + /// (exceeds TAG_MAX) + /// + /// * `notmuch_status_t::READ_ONLY_DATABASE`: Database was opened in read-only + /// mode so message cannot be modified. pub fn notmuch_message_add_tag( message: *mut notmuch_message_t, tag: *const c_char, ) -> notmuch_status_t; + /// Remove a tag from the given message. + /// + /// Return value: + /// + /// * `notmuch_status_t::SUCCESS`: Tag successfully removed from message + /// * `notmuch_status_t::NULL_POINTER`: The 'tag' argument is NULL + /// * `notmuch_status_t::TAG_TOO_LONG`: The length of 'tag' is too long (exceeds `TAG_MAX`) + /// * `notmuch_status_t::READ_ONLY_DATABASE`: Database was opened in read-only mode so message + /// cannot be modified. pub fn notmuch_message_remove_tag( message: *mut notmuch_message_t, tag: *const c_char, ) -> notmuch_status_t; + + /// Remove all tags from the given message. + /// + /// See `notmuch_message_freeze` for an example showing how to safely + /// replace tag values. + /// + /// `notmuch_status_t::READ_ONLY_DATABASE`: Database was opened in read-only + /// mode so message cannot be modified. pub fn notmuch_message_remove_all_tags( message: *mut notmuch_message_t, ) -> notmuch_status_t; + + /// Add/remove tags according to maildir flags in the message filename(s). + /// + /// This function examines the filenames of 'message' for maildir flags, and adds or removes + /// tags on 'message' as follows when these flags are present: + /// + /// ```norun + /// Flag Action if present + /// ---- ----------------- + /// 'D' Adds the "draft" tag to the message + /// 'F' Adds the "flagged" tag to the message + /// 'P' Adds the "passed" tag to the message + /// 'R' Adds the "replied" tag to the message + /// 'S' Removes the "unread" tag from the message + /// ``` + /// + /// For each flag that is not present, the opposite action (add/remove) + /// is performed for the corresponding tags. + /// + /// Flags are identified as trailing components of the filename after a + /// sequence of ":2,". + /// + /// If there are multiple filenames associated with this message, the + /// flag is considered present if it appears in one or more + /// filenames. (That is, the flags from the multiple filenames are + /// combined with the logical OR operator.) + /// + /// A client can ensure that notmuch database tags remain synchronized + /// with maildir flags by calling this function after each call to + /// `notmuch_database_add_message`. See also + /// `notmuch_message_tags_to_maildir_flags` for synchronizing tag changes + /// back to maildir flags. pub fn notmuch_message_maildir_flags_to_tags( message: *mut notmuch_message_t, ) -> notmuch_status_t; + /// Rename message filename(s) to encode tags as maildir flags. + /// + /// Specifically, for each filename corresponding to this message: + /// + /// If the filename is not in a maildir directory, do nothing. (A + /// maildir directory is determined as a directory named "new" or + /// "cur".) Similarly, if the filename has invalid maildir info, + /// (repeated or outof-ASCII-order flag characters after ":2,"), then + /// do nothing. + /// + /// If the filename is in a maildir directory, rename the file so that + /// its filename ends with the sequence ":2," followed by zero or more + /// of the following single-character flags (in ASCII order): + /// + /// 'D' iff the message has the "draft" tag + /// 'F' iff the message has the "flagged" tag + /// 'P' iff the message has the "passed" tag + /// 'R' iff the message has the "replied" tag + /// 'S' iff the message does not have the "unread" tag + /// + /// Any existing flags unmentioned in the list above will be preserved + /// in the renaming. + /// + /// Also, if this filename is in a directory named "new", rename it to + /// be within the neighboring directory named "cur". + /// + /// A client can ensure that maildir filename flags remain synchronized + /// with notmuch database tags by calling this function after changing + /// tags, (after calls to `notmuch_message_add_tag`, + /// notmuch_message_remove_tag, or `notmuch_message_freeze`/ + /// notmuch_message_thaw). See also `notmuch_message_maildir_flags_to_tags` + /// for synchronizing maildir flag changes back to tags. pub fn notmuch_message_tags_to_maildir_flags( message: *mut notmuch_message_t, ) -> notmuch_status_t; + /// Freeze the current state of 'message' within the database. + /// + /// This means that changes to the message state, (via + /// notmuch_message_add_tag, `notmuch_message_remove_tag`, and + /// `notmuch_message_remove_all_tags`), will not be committed to the + /// database until the message is thawed with `notmuch_message_thaw`. + /// + /// Multiple calls to freeze/thaw are valid and these calls will + /// "stack". That is there must be as many calls to thaw as to freeze + /// before a message is actually thawed. + /// + /// The ability to do freeze/thaw allows for safe transactions to + /// change tag values. For example, explicitly setting a message to + /// have a given set of tags might look like this: + /// + /// ```norun + /// notmuch_message_freeze (message); + /// + /// notmuch_message_remove_all_tags (message); + /// + /// for (i = 0; i < NUM_TAGS; i++) + /// notmuch_message_add_tag (message, tags[i]); + /// + /// notmuch_message_thaw (message); + /// ``` + /// + /// With freeze/thaw used like this, the message in the database is + /// guaranteed to have either the full set of original tag values, or + /// the full set of new tag values, but nothing in between. + /// + /// Imagine the example above without freeze/thaw and the operation + /// somehow getting interrupted. This could result in the message being + /// left with no tags if the interruption happened after + /// notmuch_message_remove_all_tags but before `notmuch_message_add_tag`. + /// + /// Return value: + /// + /// `notmuch_status_t::SUCCESS`: Message successfully frozen. + /// + /// `notmuch_status_t::READ_ONLY_DATABASE`: Database was opened in read-only + /// mode so message cannot be modified. pub fn notmuch_message_freeze( message: *mut notmuch_message_t, ) -> notmuch_status_t; + /// Thaw the current 'message', synchronizing any changes that may have + /// occurred while 'message' was frozen into the notmuch database. + /// + /// See `notmuch_message_freeze` for an example of how to use this + /// function to safely provide tag changes. + /// + /// Multiple calls to freeze/thaw are valid and these calls with + /// "stack". That is there must be as many calls to thaw as to freeze + /// before a message is actually thawed. + /// + /// Return value: + /// + /// `notmuch_status_t::SUCCESS`: Message successfully thawed, (or at least + /// its frozen count has successfully been reduced by 1). + /// + /// `notmuch_status_t::UNBALANCED_FREEZE_THAW`: An attempt was made to thaw + /// an unfrozen message. That is, there have been an unbalanced + /// number of calls to `notmuch_message_freeze` and + /// `notmuch_message_thaw`. pub fn notmuch_message_thaw( message: *mut notmuch_message_t, ) -> notmuch_status_t; + /// Destroy a `notmuch_message_t` object. + /// + /// It can be useful to call this function in the case of a single + /// query object with many messages in the result, (such as iterating + /// over the entire database). Otherwise, it's fine to never call this + /// function and there will still be no memory leaks. (The memory from + /// the messages get reclaimed when the containing query is destroyed.) pub fn notmuch_message_destroy( message: *mut notmuch_message_t, ); - pub fn notmuch_tags_valid( - tags: *mut notmuch_tags_t, - ) -> notmuch_bool_t; - - pub fn notmuch_tags_get( - tags: *mut notmuch_tags_t, - ) -> *const c_char; - - pub fn notmuch_tags_move_to_next( - tags: *mut notmuch_tags_t, - ); - - pub fn notmuch_tags_destroy( - tags: *mut notmuch_tags_t, - ); - - pub fn notmuch_directory_set_mtime( - directory: *mut notmuch_directory_t, - mtime: time_t, - ) -> notmuch_status_t; - - pub fn notmuch_directory_get_mtime( - directory: *mut notmuch_directory_t, - ) -> time_t; - - pub fn notmuch_directory_get_child_files( - directory: *mut notmuch_directory_t, - ) -> *mut notmuch_filenames_t; - - pub fn notmuch_directory_get_child_directories( - directory: *mut notmuch_directory_t, - ) -> *mut notmuch_filenames_t; - - pub fn notmuch_directory_destroy( - directory: *mut notmuch_directory_t, - ); - - pub fn notmuch_filenames_valid( - filenames: *mut notmuch_filenames_t, - ) -> notmuch_bool_t; - - pub fn notmuch_filenames_get( - filenames: *mut notmuch_filenames_t, - ) -> *const c_char; - - pub fn notmuch_filenames_move_to_next( - filenames: *mut notmuch_filenames_t, - ); - - pub fn notmuch_filenames_destroy( - filenames: *mut notmuch_filenames_t, - ); + /// Retrieve the value for a single property key + /// + /// *value* is set to a string owned by the message or NULL if there is + /// no such key. In the case of multiple values for the given key, the + /// first one is retrieved. + /// + /// @returns + /// - `notmuch_status_t::NULL_POINTER`: *value* may not be NULL. + /// - `notmuch_status_t::SUCCESS`: No error occured. + /// @since libnotmuch 4.4 (notmuch 0.23) + pub fn notmuch_message_get_property(message: *mut notmuch_message_t, + key: *const c_char, + value: *mut *const c_char) + -> notmuch_status_t; + + /// Add a (key,value) pair to a message + /// + /// @returns + /// - `notmuch_status_t::ILLEGAL_ARGUMENT`: *key* may not contain an '=' character. + /// - `notmuch_status_t::NULL_POINTER`: Neither *key* nor *value* may be NULL. + /// - `notmuch_status_t::SUCCESS`: No error occured. + /// @since libnotmuch 4.4 (notmuch 0.23) + pub fn notmuch_message_add_property(message: *mut notmuch_message_t, + key: *const c_char, + value: *const c_char) + -> notmuch_status_t; + + /// + /// Remove a `(key,value)` pair from a message. + /// + /// It is not an error to remove a non-existant `(key,value)` pair + /// + /// @returns + /// - `notmuch_status_t::ILLEGAL_ARGUMENT`: `key` may not contain an '=' character. + /// - `notmuch_status_t::NULL_POINTER`: Neither `key` nor *value* may be NULL. + /// - `notmuch_status_t::SUCCESS`: No error occured. + /// @since libnotmuch 4.4 (notmuch 0.23) + pub fn notmuch_message_remove_property(message: *mut notmuch_message_t, + key: *const c_char, + value: *const c_char) + -> notmuch_status_t; + + /// Remove all `(key,value)` pairs from the given message. + /// + /// @param[in,out] message message to operate on. + /// @param[in] key key to delete properties for. If NULL, delete + /// properties for all keys + /// @returns + /// - `notmuch_status_::READ_ONLY_DATABASE`: Database was opened in + /// read-only mode so message cannot be modified. + /// - `notmuch_status_t::SUCCESS`: No error occured. + /// + /// @since libnotmuch 4.4 (notmuch 0.23) + pub fn notmuch_message_remove_all_properties(message: *mut notmuch_message_t, + key: *const c_char) + -> notmuch_status_t; + + /// Get the properties for *message*, returning a + /// `notmuch_message_properties_t` object which can be used to iterate over + /// all properties. + /// + /// The `notmuch_message_properties_t` object is owned by the message and as + /// such, will only be valid for as long as the message is valid, (which is + /// until the query from which it derived is destroyed). + /// + /// @param[in] message The message to examine + /// @param[in] key key or key prefix + /// @param[in] exact if TRUE, require exact match with key. Otherwise + /// treat as prefix. + /// + /// Typical usage might be: + /// + /// ```norun + /// notmuch_message_properties_t *list; + /// + /// for (list = notmuch_message_get_properties (message, "testkey1", TRUE); + /// notmuch_message_properties_valid (list); notmuch_message_properties_move_to_next (list)) { + /// printf("%s\n", notmuch_message_properties_value(list)); + /// } + /// + /// notmuch_message_properties_destroy (list); + /// ``` + /// + /// Note that there's no explicit destructor needed for the + /// `notmuch_message_properties_t` object. (For consistency, we do provide a + /// `notmuch_message_properities_destroy` function, but there's no good + /// reason to call it if the message is about to be destroyed). + /// + /// @since libnotmuch 4.4 (notmuch 0.23) + /// + pub fn notmuch_message_get_properties(message: *mut notmuch_message_t, + key: *const c_char, + exact: notmuch_bool_t) + -> *mut notmuch_message_properties_t; + + /// Is the given *properties* iterator pointing at a valid `(key,value)` pair. + /// + /// When this function returns TRUE, `notmuch_message_properties_{key,value}` + /// will return a valid string, and `notmuch_message_properties_move_to_next` + /// will do what it says. Whereas when this function returns FALSE, calling any + /// of these functions results in undefined behaviour. + /// + /// See the documentation of `notmuch_message_properties_get` for example code + /// showing how to iterate over a `notmuch_message_properties_t` object. + /// + /// @since libnotmuch 4.4 (notmuch 0.23) + pub fn notmuch_message_properties_valid(properties: *const notmuch_message_properties_t) -> notmuch_bool_t; + + /// Move the *properties* iterator to the next `(key,value)` pair + /// + /// If *properties* is already pointing at the last pair then the iterator + /// will be moved to a point just beyond that last pair, (where + /// `notmuch_message_properties_valid` will return FALSE). + /// + /// See the documentation of `notmuch_message_get_properties` for example + /// code showing how to iterate over a `notmuch_message_properties_t` object. + /// + /// @since libnotmuch 4.4 (notmuch 0.23) + pub fn notmuch_message_properties_move_to_next(properties: *mut notmuch_message_properties_t); + + /// Return the `key` from the current `(key,value)` pair. + /// + /// this could be useful if iterating for a prefix + /// + /// @since libnotmuch 4.4 (notmuch 0.23) + /// + pub fn notmuch_message_properties_key(properties: *mut notmuch_message_properties_t) -> *const c_char; + + /// Return the `value` from the current `(key,value)` pair. + /// + /// This could be useful if iterating for a prefix. + /// + /// @since libnotmuch 4.4 (notmuch 0.23) + pub fn notmuch_message_properties_value(properties: *const notmuch_message_properties_t) -> *const c_char; + + + /// Destroy a `notmuch_message_properties_t` object. + /// + /// It's not strictly necessary to call this function. All memory from + /// the `notmuch_message_properties_t` object will be reclaimed when the + /// containing message object is destroyed. + /// + /// @since libnotmuch 4.4 (notmuch 0.23) + pub fn notmuch_message_properties_destroy(properties: *mut notmuch_message_properties_t); + + /// Is the given 'tags' iterator pointing at a valid tag. + /// + /// When this function returns TRUE, `notmuch_tags_get` will return a + /// valid string. Whereas when this function returns FALSE, + /// `notmuch_tags_get` will return NULL. + /// + /// See the documentation of `notmuch_message_get_tags` for example code + /// showing how to iterate over a `notmuch_tags_t` object. + pub fn notmuch_tags_valid(tags: *mut notmuch_tags_t) -> notmuch_bool_t; + + /// Get the current tag from 'tags' as a string. + /// + /// Note: The returned string belongs to 'tags' and has a lifetime + /// identical to it (and the query to which it ultimately belongs). + /// + /// See the documentation of `notmuch_message_get_tags` for example code + /// showing how to iterate over a `notmuch_tags_t` object. + pub fn notmuch_tags_get(tags: *mut notmuch_tags_t) -> *const c_char; + + /// Move the 'tags' iterator to the next tag. + /// + /// If 'tags' is already pointing at the last tag then the iterator + /// will be moved to a point just beyond that last tag, (where + /// notmuch_tags_valid will return FALSE and `notmuch_tags_get` will + /// return NULL). + /// + /// See the documentation of `notmuch_message_get_tags` for example code + /// showing how to iterate over a `notmuch_tags_t` object. + pub fn notmuch_tags_move_to_next(tags: *mut notmuch_tags_t); + + /// Destroy a `notmuch_tags_t` object. + /// + /// It's not strictly necessary to call this function. All memory from + /// the `notmuch_tags_t` object will be reclaimed when the containing + /// message or query objects are destroyed. + pub fn notmuch_tags_destroy(tags: *mut notmuch_tags_t); + + /// Store an mtime within the database for 'directory'. + /// + /// The 'directory' should be an object retrieved from the database + /// with `notmuch_database_get_directory` for a particular path. + /// + /// The intention is for the caller to use the mtime to allow efficient + /// identification of new messages to be added to the database. The + /// recommended usage is as follows: + /// + /// * Read the mtime of a directory from the filesystem + /// + /// * Call add_message for all mail files in the directory + /// + /// * Call `notmuch_directory_set_mtime` with the mtime read from the filesystem. + /// + /// Then, when wanting to check for updates to the directory in the + /// future, the client can call `notmuch_directory_get_mtime` and know + /// that it only needs to add files if the mtime of the directory and + /// files are newer than the stored timestamp. + /// + /// Note: The `notmuch_directory_get_mtime` function does not allow the + /// caller to distinguish a timestamp of 0 from a non-existent + /// timestamp. So don't store a timestamp of 0 unless you are + /// comfortable with that. + /// + /// Return value: + /// + /// * `notmuch_status_t::SUCCESS`: mtime successfully stored in database. + /// + /// * `notmuch_status_t::XAPIAN_EXCEPTION`: A Xapian exception occurred, mtime not stored. + /// + /// * `notmuch_status_t::READ_ONLY_DATABASE`: Database was opened in read-only mode so + /// directory mtime cannot be modified. + pub fn notmuch_directory_set_mtime(directory: *mut notmuch_directory_t, + mtime: time_t) + -> notmuch_status_t; + + /// Get the mtime of a directory, (as previously stored with + /// `notmuch_directory_set_mtime`). + /// + /// Returns 0 if no mtime has previously been stored for this + /// directory. + pub fn notmuch_directory_get_mtime(directory: *mut notmuch_directory_t) -> time_t; + + /// Get a `notmuch_filenames_t` iterator listing all the filenames of + /// messages in the database within the given directory. + /// + /// The returned filenames will be the basename-entries only (not + /// complete paths). + pub fn notmuch_directory_get_child_files(directory: *mut notmuch_directory_t) + -> *mut notmuch_filenames_t; + + /// Get a `notmuch_filenames_t` iterator listing all the filenames of + /// sub-directories in the database within the given directory. + /// + /// The returned filenames will be the basename-entries only (not + /// complete paths). + pub fn notmuch_directory_get_child_directories(directory: *mut notmuch_directory_t) + -> *mut notmuch_filenames_t; + + /// Delete directory document from the database, and destroy the + /// `notmuch_directory_t` object. Assumes any child directories and files + /// have been deleted by the caller. + /// + /// @since libnotmuch 4.3 (notmuch 0.21) + pub fn notmuch_directory_delete(directory: *mut notmuch_directory_t) -> notmuch_status_t; + + /// Destroy a `notmuch_directory_t` object. + pub fn notmuch_directory_destroy(directory: *mut notmuch_directory_t); + + /// Is the given 'filenames' iterator pointing at a valid filename. + /// + /// When this function returns TRUE, `notmuch_filenames_get` will return + /// a valid string. Whereas when this function returns FALSE, + /// `notmuch_filenames_get` will return NULL. + /// + /// It is acceptable to pass NULL for 'filenames', in which case this + /// function will always return FALSE. + pub fn notmuch_filenames_valid(filenames: *mut notmuch_filenames_t) -> notmuch_bool_t; + + /// Get the current filename from 'filenames' as a string. + /// + /// Note: The returned string belongs to 'filenames' and has a lifetime + /// identical to it (and the directory to which it ultimately belongs). + /// + /// It is acceptable to pass NULL for 'filenames', in which case this + /// function will always return NULL. + pub fn notmuch_filenames_get(filenames: *mut notmuch_filenames_t) -> *const c_char; + + /// Move the 'filenames' iterator to the next filename. + /// + /// If 'filenames' is already pointing at the last filename then the + /// iterator will be moved to a point just beyond that last filename, + /// (where `notmuch_filenames_valid` will return FALSE and + /// `notmuch_filenames_get` will return NULL). + /// + /// It is acceptable to pass NULL for 'filenames', in which case this + /// function will do nothing. + pub fn notmuch_filenames_move_to_next(filenames: *mut notmuch_filenames_t); + + /// Destroy a `notmuch_filenames_t` object. + /// + /// It's not strictly necessary to call this function. All memory from + /// the `notmuch_filenames_t` object will be reclaimed when the + /// containing directory object is destroyed. + /// + /// It is acceptable to pass NULL for 'filenames', in which case this + /// function will do nothing. + pub fn notmuch_filenames_destroy(filenames: *mut notmuch_filenames_t); + + + /// set config 'key' to 'value' + /// + /// @since libnotmuch 4.4 (notmuch 0.23) + pub fn notmuch_database_set_config(db: *mut notmuch_database_t, + key: *const c_char, + value: *const c_char) + -> notmuch_status_t; + + /// retrieve config item 'key', assign to 'value' + /// + /// keys which have not been previously set with n_d_set_config will + /// return an empty string. + /// + /// return value is allocated by malloc and should be freed by the + /// caller. + /// + /// @since libnotmuch 4.4 (notmuch 0.23) + pub fn notmuch_database_get_config(db: *mut notmuch_database_t, + key: *const c_char, + value: *mut *mut c_char) + -> notmuch_status_t; + + /// Create an iterator for all config items with keys matching a given prefix + /// + /// @since libnotmuch 4.4 (notmuch 0.23) + pub fn notmuch_database_get_config_list(db: *mut notmuch_database_t, + prefix: *const c_char, + out: *mut *mut notmuch_config_list_t) + -> notmuch_status_t; + + /// Is 'config_list' iterator valid (i.e. _key, _value, _move_to_next can be called). + /// + /// @since libnotmuch 4.4 (notmuch 0.23) + pub fn notmuch_config_list_valid(config_list: *mut notmuch_config_list_t) + -> notmuch_bool_t; + + /// return key for current config pair + /// + /// return value is owned by the iterator, and will be destroyed by the + /// next call to `notmuch_config_list_key` or `notmuch_config_list_destroy`. + /// + /// @since libnotmuch 4.4 (notmuch 0.23) + pub fn notmuch_config_list_key (config_list: *mut notmuch_config_list_t) + -> *const c_char; + + /// return 'value' for current config pair + /// + /// return value is owned by the iterator, and will be destroyed by the + /// next call to `notmuch_config_list_value` or notmuch `config_list_destroy` + /// + /// @since libnotmuch 4.4 (notmuch 0.23) + pub fn notmuch_config_list_value(config_list: *mut notmuch_config_list_t) -> *const c_char; + + /// move 'config_list' iterator to the next pair + /// + /// @since libnotmuch 4.4 (notmuch 0.23) + pub fn notmuch_config_list_move_to_next(config_list: *mut notmuch_config_list_t); + + /// free any resources held by 'config_list' + /// + /// @since libnotmuch 4.4 (notmuch 0.23) + pub fn notmuch_config_list_destroy(config_list: *mut notmuch_config_list_t); + + /// interrogate the library for compile time features + /// + /// @since libnotmuch 4.4 (notmuch 0.23) + pub fn notmuch_built_with(name: *const c_char) -> notmuch_bool_t; } -- cgit v1.2.1 From baf4a61a6879ed2b94106ab627e88585359395f4 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 21 Mar 2018 09:33:17 +0100 Subject: update package description --- Cargo.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 1f9adc5..2b7f414 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,5 +4,10 @@ version = "0.0.1" authors = ["C. Morgan Hamill ", "Dirk Van Haerenborgh "] +homepage = "https://github.com/vhdirk/notmuch-rs" +repository = "https://github.com/vhdirk/notmuch-rs" +description = "Rust interface and bindings for notmuch" +license = "GPL-3.0-or-later" + [dependencies] libc = "0.2" -- cgit v1.2.1 From db6f7a872ae5404e813f461b63e3f3d8158a3a8d Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 21 Mar 2018 09:36:44 +0100 Subject: cargo only seems to support spdx v2 licenses --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 2b7f414..65358ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ authors = ["C. Morgan Hamill ", homepage = "https://github.com/vhdirk/notmuch-rs" repository = "https://github.com/vhdirk/notmuch-rs" description = "Rust interface and bindings for notmuch" -license = "GPL-3.0-or-later" +license = "GPL-3.0+" [dependencies] libc = "0.2" -- cgit v1.2.1 From 199e066d8c92287f0868fceec9f719e1c6005df2 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 22 Mar 2018 07:31:33 +0100 Subject: get notmuch db revision --- src/database.rs | 18 +++++++++++++++--- src/ffi.rs | 2 +- src/lib.rs | 2 +- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/database.rs b/src/database.rs index 8f64fdd..a809e3d 100644 --- a/src/database.rs +++ b/src/database.rs @@ -19,11 +19,14 @@ use directory::Directory; use ffi; // Re-exported under database module for pretty namespacin'. -pub use ffi::DatabaseOpenMode; +pub use ffi::DatabaseMode; #[derive(Copy, Clone, Debug)] pub struct Version(libc::c_uint); +#[derive(Copy, Clone, Debug)] +pub struct Revision(libc::c_ulong); + #[derive(Debug)] pub struct Database(*mut ffi::notmuch_database_t); @@ -39,13 +42,15 @@ impl Database { Ok(Database(db)) } - pub fn open>(path: &P, mode: DatabaseOpenMode) -> Result { + pub fn open>(path: &P, mode: DatabaseMode) -> Result { 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, + path_str.as_ptr(), + mode.into(), + &mut db, ) }.as_result()); @@ -117,6 +122,13 @@ impl Database { }) } + pub fn revision(&self) -> Revision { + let uuid = ptr::null_mut(); + Revision(unsafe { + ffi::notmuch_database_get_revision(self.0, uuid) + }) + } + pub fn needs_upgrade(&self) -> bool { unsafe { ffi::notmuch_database_needs_upgrade(self.0) == 1 diff --git a/src/ffi.rs b/src/ffi.rs index f3ddb41..b5dcca3 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -85,7 +85,7 @@ impl error::Error for Status { notmuch_enum! { #[repr(C)] #[derive(Debug, Eq, PartialEq, Clone, Copy)] - pub enum notmuch_database_mode_t => DatabaseOpenMode { + pub enum notmuch_database_mode_t => DatabaseMode { NOTMUCH_DATABASE_MODE_READ_ONLY => ReadOnly, NOTMUCH_DATABASE_MODE_READ_WRITE => ReadWrite } diff --git a/src/lib.rs b/src/lib.rs index 1348c7e..7ee28ac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,4 +11,4 @@ pub mod database; pub mod directory; pub use database::Database; -pub use ffi::DatabaseOpenMode; +pub use ffi::DatabaseMode; -- cgit v1.2.1 From e3d445ae0c845d27956550c0f37859106a9a7ea5 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 22 Mar 2018 07:40:51 +0100 Subject: thread stub --- src/thread.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/thread.rs diff --git a/src/thread.rs b/src/thread.rs new file mode 100644 index 0000000..e69de29 -- cgit v1.2.1 From 1a8e183ab11f644ba22ab7e0474551147a2bac34 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 22 Mar 2018 07:41:26 +0100 Subject: bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 65358ca..7ef1354 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "notmuch" -version = "0.0.1" +version = "0.0.2" authors = ["C. Morgan Hamill ", "Dirk Van Haerenborgh "] -- cgit v1.2.1 From 24cb7a5e07518129e0bf839cf2b1654a0ed8bd0e Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 22 Mar 2018 08:55:48 +0100 Subject: create query --- Cargo.toml | 2 +- src/database.rs | 17 +++++++++++++++-- src/lib.rs | 3 +++ src/query.rs | 29 +++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 src/query.rs diff --git a/Cargo.toml b/Cargo.toml index 7ef1354..0e0c7c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "notmuch" -version = "0.0.2" +version = "0.0.3" authors = ["C. Morgan Hamill ", "Dirk Van Haerenborgh "] diff --git a/src/database.rs b/src/database.rs index a809e3d..986d638 100644 --- a/src/database.rs +++ b/src/database.rs @@ -15,6 +15,7 @@ use utils::{ }; use directory::Directory; +use query::Query; use ffi; @@ -31,7 +32,7 @@ pub struct Revision(libc::c_ulong); pub struct Database(*mut ffi::notmuch_database_t); impl Database { - pub fn create>(path: &P) -> Result { + pub fn create>(path: &P) -> Result { let path_str = CString::new(path.as_ref().to_str().unwrap()).unwrap(); let mut db = ptr::null_mut(); @@ -42,7 +43,7 @@ impl Database { Ok(Database(db)) } - pub fn open>(path: &P, mode: DatabaseMode) -> Result { + pub fn open>(path: &P, mode: DatabaseMode) -> Result { let path_str = CString::new(path.as_ref().to_str().unwrap()).unwrap(); let mut db = ptr::null_mut(); @@ -184,6 +185,18 @@ impl Database { true => Ok(Some(Directory::new(dir))), } } + + pub fn create_query(&self, query_string: &String) -> Result { + let query_str = CString::new(query_string.as_str()).unwrap(); + + let mut query = ptr::null_mut(); + unsafe { + query = ffi::notmuch_query_create(self.0, query_str.as_ptr()); + } + + Ok(Query(query)) + } + } impl ops::Drop for Database { diff --git a/src/lib.rs b/src/lib.rs index 7ee28ac..4dd635e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,9 @@ mod ffi; pub mod error; pub mod database; pub mod directory; +pub mod query; pub use database::Database; +pub use query::Query; + pub use ffi::DatabaseMode; diff --git a/src/query.rs b/src/query.rs new file mode 100644 index 0000000..364c001 --- /dev/null +++ b/src/query.rs @@ -0,0 +1,29 @@ +use std::{ + ops, + path, + ptr, +}; + +use std::ffi::CString; +use std::os::raw::c_char; + +use libc; + +use error::Result; +use utils::{ + NewFromPtr, + ToStr, +}; + +use ffi; + +use database::Database; + +#[derive(Debug)] +pub struct Query(pub(crate) *mut ffi::notmuch_query_t); + +impl Query { + pub fn create(db: &Database, query_string: &String) -> Result { + db.create_query(query_string) + } +} -- cgit v1.2.1 From c1a67ae3ca45cffc1166d2f980a225ff29394bf8 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 22 Mar 2018 09:49:28 +0100 Subject: implement drop for query --- src/query.rs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/query.rs b/src/query.rs index 364c001..24a2a1b 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,19 +1,8 @@ use std::{ ops, - path, - ptr, }; -use std::ffi::CString; -use std::os::raw::c_char; - -use libc; - use error::Result; -use utils::{ - NewFromPtr, - ToStr, -}; use ffi; @@ -27,3 +16,12 @@ impl Query { db.create_query(query_string) } } + + +impl ops::Drop for Query { + fn drop(&mut self) { + unsafe { + ffi::notmuch_query_destroy(self.0) + }; + } +} -- cgit v1.2.1 From 64304118fcd8a876815450194a315846b1a95422 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 22 Mar 2018 09:56:54 +0100 Subject: correct lifetime for query --- src/directory.rs | 9 +++++++++ src/query.rs | 24 +++++++++++++++++++----- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/directory.rs b/src/directory.rs index eaf706e..3d9de6e 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -1,4 +1,5 @@ use std::{ + ops, marker, }; @@ -20,3 +21,11 @@ impl<'d> NewFromPtr<*mut ffi::notmuch_directory_t> for Directory<'d> { Directory(ptr, marker::PhantomData) } } + +impl<'d> ops::Drop for Directory<'d> { + fn drop(&mut self) { + unsafe { + ffi::notmuch_directory_destroy(self.0) + }; + } +} diff --git a/src/query.rs b/src/query.rs index 24a2a1b..18d44d7 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,24 +1,38 @@ use std::{ ops, + marker }; use error::Result; use ffi; +use utils::{ + NewFromPtr, +}; +use Database; -use database::Database; #[derive(Debug)] -pub struct Query(pub(crate) *mut ffi::notmuch_query_t); +pub struct Query<'d>( + pub(crate) *mut ffi::notmuch_query_t, + marker::PhantomData<&'d mut Database>, +); + -impl Query { - pub fn create(db: &Database, query_string: &String) -> Result { +impl<'d> Query<'d> { + pub fn create(db: &'d Database, query_string: &String) -> Result { db.create_query(query_string) } } +impl<'d> NewFromPtr<*mut ffi::notmuch_query_t> for Query<'d> { + fn new(ptr: *mut ffi::notmuch_query_t) -> Query<'d> { + Query(ptr, marker::PhantomData) + } +} + -impl ops::Drop for Query { +impl<'d> ops::Drop for Query<'d> { fn drop(&mut self) { unsafe { ffi::notmuch_query_destroy(self.0) -- cgit v1.2.1 From 7ba23076164413f4fa54d6f2dcb98c9dfc90a28c Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 22 Mar 2018 09:58:19 +0100 Subject: fix query constructor --- src/database.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/database.rs b/src/database.rs index 986d638..85567f5 100644 --- a/src/database.rs +++ b/src/database.rs @@ -194,7 +194,7 @@ impl Database { query = ffi::notmuch_query_create(self.0, query_str.as_ptr()); } - Ok(Query(query)) + Ok(Query::new(query)) } } -- cgit v1.2.1 From 0e532a6f2d4f6e85d2ce48ea3770fafa5706d275 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 22 Mar 2018 19:44:00 +0100 Subject: search messages --- src/lib.rs | 2 ++ src/messages.rs | 35 +++++++++++++++++++++++++++++++++++ src/query.rs | 15 ++++++++++++++- 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/messages.rs diff --git a/src/lib.rs b/src/lib.rs index 4dd635e..b6c187e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,8 +10,10 @@ pub mod error; pub mod database; pub mod directory; pub mod query; +pub mod messages; pub use database::Database; pub use query::Query; +pub use messages::Messages; pub use ffi::DatabaseMode; diff --git a/src/messages.rs b/src/messages.rs new file mode 100644 index 0000000..5144fb9 --- /dev/null +++ b/src/messages.rs @@ -0,0 +1,35 @@ +use std::{ + ops, + marker +}; + +use error::Result; + +use ffi; +use utils::{ + NewFromPtr, +}; +use Database; +use Query; + +#[derive(Debug)] +pub struct Messages<'q>( + // TODO: is this lifetime specifier correct? + pub(crate) *mut ffi::notmuch_messages_t, + marker::PhantomData<&'q Query<'q>> +); + +impl<'q> NewFromPtr<*mut ffi::notmuch_messages_t> for Messages<'q> { + fn new(ptr: *mut ffi::notmuch_messages_t) -> Messages<'q> { + Messages(ptr, marker::PhantomData) + } +} + + +impl<'q> ops::Drop for Messages<'q> { + fn drop(&mut self) { + unsafe { + ffi::notmuch_messages_destroy(self.0) + }; + } +} diff --git a/src/query.rs b/src/query.rs index 18d44d7..8e8514c 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,6 +1,7 @@ use std::{ ops, - marker + marker, + ptr, }; use error::Result; @@ -10,6 +11,7 @@ use utils::{ NewFromPtr, }; use Database; +use Messages; #[derive(Debug)] @@ -23,6 +25,17 @@ impl<'d> Query<'d> { pub fn create(db: &'d Database, query_string: &String) -> Result { db.create_query(query_string) } + + /// Filter messages according to the query and return + pub fn search_messages(self: &Self) -> Result + { + let mut msgs = ptr::null_mut(); + unsafe { + msgs = ffi::notmuch_query_search_messages(self.0); + } + + Ok(Messages::new(msgs)) + } } impl<'d> NewFromPtr<*mut ffi::notmuch_query_t> for Query<'d> { -- cgit v1.2.1 From 95053bfc0010cb0bc00154a12f154063b6134375 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 22 Mar 2018 19:54:36 +0100 Subject: test messages return value --- src/query.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/query.rs b/src/query.rs index 8e8514c..2fbe031 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,3 +1,4 @@ +use std; use std::{ ops, marker, @@ -27,14 +28,18 @@ impl<'d> Query<'d> { } /// Filter messages according to the query and return - pub fn search_messages(self: &Self) -> Result + pub fn search_messages(self: &Self) -> std::result::Result { let mut msgs = ptr::null_mut(); unsafe { msgs = ffi::notmuch_query_search_messages(self.0); } + if !msgs.is_null() { + return Ok(Messages::new(msgs)); + }else{ + return Err(()); + } - Ok(Messages::new(msgs)) } } -- cgit v1.2.1 From 9c51895af08f367c112e77634cb534ecdc430bbf Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 22 Mar 2018 20:06:50 +0100 Subject: slightly better interface, but still returning a null pointer... --- src/ffi.rs | 9 ++++++--- src/query.rs | 19 ++++++++++--------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/ffi.rs b/src/ffi.rs index b5dcca3..e341df8 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -751,9 +751,12 @@ extern { /// If a Xapian exception occurs this function will return NULL. /// /// @since libnotmuch 4.2 (notmuch 0.20) - pub fn notmuch_query_search_messages( - query: *mut notmuch_query_t, - ) -> *mut notmuch_messages_t; + pub fn notmuch_query_search_messages(query: *mut notmuch_query_t, + out: *mut *mut notmuch_messages_t) + -> notmuch_status_t; + pub fn notmuch_query_search_messages_st(query: *mut notmuch_query_t, + out: *mut *mut notmuch_messages_t) + -> notmuch_status_t; /// Destroy a `notmuch_query_t` along with any associated resources. /// diff --git a/src/query.rs b/src/query.rs index 2fbe031..654d4c6 100644 --- a/src/query.rs +++ b/src/query.rs @@ -28,18 +28,19 @@ impl<'d> Query<'d> { } /// Filter messages according to the query and return - pub fn search_messages(self: &Self) -> std::result::Result + pub fn search_messages(self: &Self) -> Result> { let mut msgs = ptr::null_mut(); - unsafe { - msgs = ffi::notmuch_query_search_messages(self.0); - } - if !msgs.is_null() { - return Ok(Messages::new(msgs)); - }else{ - return Err(()); + try!(unsafe { + ffi::notmuch_query_search_messages( + self.0, &mut msgs, + ) + }.as_result()); + + match msgs.is_null() { + false => Ok(None), + true => Ok(Some(Messages::new(msgs))), } - } } -- cgit v1.2.1 From bc968e0da07e8e80e19eec1e8efbdb347746d6e2 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 23 Mar 2018 03:51:04 +0100 Subject: proper tags iterator --- src/database.rs | 14 +++++++++++ src/directory.rs | 1 + src/ffi.rs | 76 ++++++++++++++++++++++++++++++++++++-------------------- src/lib.rs | 4 +++ src/message.rs | 0 src/messages.rs | 12 +++++---- src/query.rs | 24 +++++++++++++++++- src/tags.rs | 61 +++++++++++++++++++++++++++++++++++++++++++++ src/threads.rs | 32 ++++++++++++++++++++++++ 9 files changed, 191 insertions(+), 33 deletions(-) create mode 100644 src/message.rs create mode 100644 src/tags.rs create mode 100644 src/threads.rs diff --git a/src/database.rs b/src/database.rs index 85567f5..85ddcfb 100644 --- a/src/database.rs +++ b/src/database.rs @@ -16,6 +16,7 @@ use utils::{ use directory::Directory; use query::Query; +use tags::Tags; use ffi; @@ -197,6 +198,19 @@ impl Database { Ok(Query::new(query)) } + pub fn all_tags(&self) -> Result { + + let mut tags = ptr::null_mut(); + unsafe { + tags = ffi::notmuch_database_get_all_tags(self.0); + } + + Ok(Tags::new(tags)) + } + + + + } impl ops::Drop for Database { diff --git a/src/directory.rs b/src/directory.rs index 3d9de6e..1d75f35 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -11,6 +11,7 @@ use database; use ffi; +#[derive(Debug)] pub struct Directory<'d>( *mut ffi::notmuch_directory_t, marker::PhantomData<&'d mut database::Database>, diff --git a/src/ffi.rs b/src/ffi.rs index e341df8..76045e3 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -134,6 +134,8 @@ notmuch_enum! { #[repr(C)] pub struct notmuch_filenames_t(c_void); #[repr(C)] pub struct notmuch_message_properties_t(c_void); #[repr(C)] pub struct notmuch_config_list_t(c_void); +#[repr(C)] pub struct notmuch_indexopts_t(c_void); + pub type notmuch_compact_status_cb_t = extern "C" fn(message: *const c_char, closure: *mut c_void); pub type notmuch_database_upgrade_cb_t = extern "C" fn(closure: *mut c_void, progress: c_double); @@ -429,11 +431,13 @@ extern { directory: *mut *mut notmuch_directory_t, ) -> notmuch_status_t; - /// Add a new message to the given notmuch database or associate an - /// additional filename with an existing message. + /// Add a message file to a database, indexing it for retrieval by + /// future searches. If a message already exists with the same message + /// ID as the specified file, their indexes will be merged, and this + /// new filename will also be associated with the existing message. /// /// Here, 'filename' should be a path relative to the path of - /// 'database' (see `notmuch_database_get_path`), or else should be an + /// 'database' (see notmuch_database_get_path), or else should be an /// absolute filename with initial components that match the path of /// 'database'. /// @@ -443,40 +447,61 @@ extern { /// entire contents of the file. /// /// If another message with the same message ID already exists in the - /// database, rather than creating a new message, this adds 'filename' - /// to the list of the filenames for the existing message. + /// database, rather than creating a new message, this adds the search + /// terms from the identified file to the existing message's index, and + /// adds 'filename' to the list of filenames known for the message. + /// + /// The 'indexopts' parameter can be NULL (meaning, use the indexing + /// defaults from the database), or can be an explicit choice of + /// indexing options that should govern the indexing of this specific + /// 'filename'. /// /// If 'message' is not NULL, then, on successful return - /// (notmuch_status_t::SUCCESS or `notmuch_status_t::DUPLICATE_MESSAGE_ID`) '*message' + /// (NOTMUCH_STATUS_SUCCESS or NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) '*message' /// will be initialized to a message object that can be used for things /// such as adding tags to the just-added message. The user should call - /// `notmuch_message_destroy` when done with the message. On any failure + /// notmuch_message_destroy when done with the message. On any failure /// '*message' will be set to NULL. /// /// Return value: /// - /// * `notmuch_status_t::SUCCESS`: Message successfully added to database. + /// NOTMUCH_STATUS_SUCCESS: Message successfully added to database. /// - /// * `notmuch_status_t::XAPIAN_EXCEPTION`: A Xapian exception occurred, - /// message not added. + /// NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred, + /// message not added. /// - /// * `notmuch_status_t::DUPLICATE_MESSAGE_ID`: Message has the same message - /// ID as another message already in the database. The new - /// filename was successfully added to the message in the database - /// (if not already present) and the existing message is returned. + /// NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: Message has the same message + /// ID as another message already in the database. The new + /// filename was successfully added to the message in the database + /// (if not already present) and the existing message is returned. /// - /// * `notmuch_status_t::FILE_ERROR`: an error occurred trying to open the - /// file, (such as permission denied, or file not found, - /// etc.). Nothing added to the database. + /// NOTMUCH_STATUS_FILE_ERROR: an error occurred trying to open the + /// file, (such as permission denied, or file not found, + /// etc.). Nothing added to the database. /// - /// * `notmuch_status_t::FILE_NOT_EMAIL`: the contents of filename don't look - /// like an email message. Nothing added to the database. + /// NOTMUCH_STATUS_FILE_NOT_EMAIL: the contents of filename don't look + /// like an email message. Nothing added to the database. /// - /// * `notmuch_status_t::READ_ONLY_DATABASE`: Database was opened in read-only - /// mode so no message can be added. + /// NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only + /// mode so no message can be added. /// - /// * `notmuch_status_t::UPGRADE_REQUIRED`: The caller must upgrade the - /// database to use this function. + /// NOTMUCH_STATUS_UPGRADE_REQUIRED: The caller must upgrade the + /// database to use this function. + /// + /// @since libnotmuch 5.1 (notmuch 0.26) + pub fn notmuch_database_index_file( + database: *mut notmuch_database_t, + filename: *const c_char, + indexopts: *mut notmuch_indexopts_t, + message: *mut *mut notmuch_message_t, + ) -> notmuch_status_t; + + + /// Deprecated alias for notmuch_database_index_file called with + /// NULL indexopts. + /// + /// @deprecated Deprecated as of libnotmuch 5.1 (notmuch 0.26). Please + /// use notmuch_database_index_file instead. pub fn notmuch_database_add_message( database: *mut notmuch_database_t, filename: *const c_char, @@ -750,13 +775,10 @@ extern { /// /// If a Xapian exception occurs this function will return NULL. /// - /// @since libnotmuch 4.2 (notmuch 0.20) + /// @since libnotmuch 5 (notmuch 0.25) pub fn notmuch_query_search_messages(query: *mut notmuch_query_t, out: *mut *mut notmuch_messages_t) -> notmuch_status_t; - pub fn notmuch_query_search_messages_st(query: *mut notmuch_query_t, - out: *mut *mut notmuch_messages_t) - -> notmuch_status_t; /// Destroy a `notmuch_query_t` along with any associated resources. /// diff --git a/src/lib.rs b/src/lib.rs index b6c187e..147df58 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,9 +11,13 @@ pub mod database; pub mod directory; pub mod query; pub mod messages; +pub mod tags; +pub mod threads; pub use database::Database; pub use query::Query; pub use messages::Messages; +pub use tags::Tags; +pub use threads::Threads; pub use ffi::DatabaseMode; diff --git a/src/message.rs b/src/message.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/messages.rs b/src/messages.rs index 5144fb9..c21c701 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -13,20 +13,22 @@ use Database; use Query; #[derive(Debug)] -pub struct Messages<'q>( +pub struct Messages<'q, 'd:'q>( // TODO: is this lifetime specifier correct? + // query may outlive messages. pub(crate) *mut ffi::notmuch_messages_t, - marker::PhantomData<&'q Query<'q>> + marker::PhantomData<&'q Query<'d>> ); -impl<'q> NewFromPtr<*mut ffi::notmuch_messages_t> for Messages<'q> { - fn new(ptr: *mut ffi::notmuch_messages_t) -> Messages<'q> { +impl<'q, 'd:'q> NewFromPtr<*mut ffi::notmuch_messages_t> for Messages<'q, 'd> { + fn new(ptr: *mut ffi::notmuch_messages_t) -> Messages<'q, 'd> { Messages(ptr, marker::PhantomData) } } -impl<'q> ops::Drop for Messages<'q> { + +impl<'q, 'd:'q> ops::Drop for Messages<'q, 'd> { fn drop(&mut self) { unsafe { ffi::notmuch_messages_destroy(self.0) diff --git a/src/query.rs b/src/query.rs index 654d4c6..6d7da64 100644 --- a/src/query.rs +++ b/src/query.rs @@ -13,7 +13,7 @@ use utils::{ }; use Database; use Messages; - +use ffi::Sort; #[derive(Debug)] pub struct Query<'d>( @@ -27,6 +27,28 @@ impl<'d> Query<'d> { 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.0, 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.0, + ) + }.into() + } + + /// Filter messages according to the query and return pub fn search_messages(self: &Self) -> Result> { diff --git a/src/tags.rs b/src/tags.rs new file mode 100644 index 0000000..9eb2779 --- /dev/null +++ b/src/tags.rs @@ -0,0 +1,61 @@ +use std::{ + ops, + marker, + iter +}; + +use std::ffi::{ + CString, + CStr +}; + +use utils::{ + NewFromPtr, +}; + +use database; +use ffi; + +#[derive(Debug)] +pub struct Tags<'d>( + *mut ffi::notmuch_tags_t, + marker::PhantomData<&'d mut database::Database>, +); + +impl<'d> NewFromPtr<*mut ffi::notmuch_tags_t> for Tags<'d> { + fn new(ptr: *mut ffi::notmuch_tags_t) -> Tags<'d> { + Tags(ptr, marker::PhantomData) + } +} + +impl<'d> ops::Drop for Tags<'d> { + fn drop(&mut self) { + unsafe { + ffi::notmuch_tags_destroy(self.0) + }; + } +} + +impl<'d> iter::Iterator for Tags<'d> { + type Item = String; + + fn next(&mut self) -> Option { + + let valid = unsafe { + ffi::notmuch_tags_valid(self.0) + }; + + if valid == 0{ + return None + } + + let ctag = unsafe { + ffi::notmuch_tags_move_to_next(self.0); + CStr::from_ptr(ffi::notmuch_tags_get(self.0)) + }; + + Some(ctag.to_str().unwrap().to_string()) + } + + +} diff --git a/src/threads.rs b/src/threads.rs new file mode 100644 index 0000000..75f4549 --- /dev/null +++ b/src/threads.rs @@ -0,0 +1,32 @@ +use std::{ + ops, + marker, +}; + +use utils::{ + NewFromPtr, +}; + +use database; + +use ffi; + +#[derive(Debug)] +pub struct Threads<'d>( + *mut ffi::notmuch_threads_t, + marker::PhantomData<&'d mut database::Database>, +); + +impl<'d> NewFromPtr<*mut ffi::notmuch_threads_t> for Threads<'d> { + fn new(ptr: *mut ffi::notmuch_threads_t) -> Threads<'d> { + Threads(ptr, marker::PhantomData) + } +} + +impl<'d> ops::Drop for Threads<'d> { + fn drop(&mut self) { + unsafe { + ffi::notmuch_threads_destroy(self.0) + }; + } +} -- cgit v1.2.1 From 4513eafb2017b93850153fa978497335df9845be Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 23 Mar 2018 04:02:26 +0100 Subject: message and thread iterators --- src/directory.rs | 4 ++-- src/lib.rs | 4 ++++ src/message.rs | 35 +++++++++++++++++++++++++++++++++++ src/messages.rs | 39 ++++++++++++++++++++++++++++++--------- src/tags.rs | 2 -- src/thread.rs | 34 ++++++++++++++++++++++++++++++++++ src/threads.rs | 29 ++++++++++++++++++++++++++--- 7 files changed, 131 insertions(+), 16 deletions(-) diff --git a/src/directory.rs b/src/directory.rs index 1d75f35..7b00d70 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -7,14 +7,14 @@ use utils::{ NewFromPtr, }; -use database; +use Database; use ffi; #[derive(Debug)] pub struct Directory<'d>( *mut ffi::notmuch_directory_t, - marker::PhantomData<&'d mut database::Database>, + marker::PhantomData<&'d mut Database>, ); impl<'d> NewFromPtr<*mut ffi::notmuch_directory_t> for Directory<'d> { diff --git a/src/lib.rs b/src/lib.rs index 147df58..70cb7c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,13 +11,17 @@ pub mod database; pub mod directory; pub mod query; pub mod messages; +pub mod message; pub mod tags; pub mod threads; +pub mod thread; pub use database::Database; pub use query::Query; pub use messages::Messages; +pub use message::Message; pub use tags::Tags; pub use threads::Threads; +pub use thread::Thread; pub use ffi::DatabaseMode; diff --git a/src/message.rs b/src/message.rs index e69de29..d774043 100644 --- a/src/message.rs +++ b/src/message.rs @@ -0,0 +1,35 @@ +use std; +use std::{ + ops, + marker, + ptr, +}; + +use error::Result; + +use ffi; +use utils::{ + NewFromPtr, +}; +use Database; + +#[derive(Debug)] +pub struct Message<'d>( + pub(crate) *mut ffi::notmuch_message_t, + marker::PhantomData<&'d mut Database>, +); + +impl<'d> NewFromPtr<*mut ffi::notmuch_message_t> for Message<'d> { + fn new(ptr: *mut ffi::notmuch_message_t) -> Message<'d> { + Message(ptr, marker::PhantomData) + } +} + + +impl<'d> ops::Drop for Message<'d> { + fn drop(&mut self) { + unsafe { + ffi::notmuch_message_destroy(self.0) + }; + } +} diff --git a/src/messages.rs b/src/messages.rs index c21c701..706cfda 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -1,6 +1,7 @@ use std::{ ops, - marker + marker, + iter }; use error::Result; @@ -10,28 +11,48 @@ use utils::{ NewFromPtr, }; use Database; -use Query; +use Message; #[derive(Debug)] -pub struct Messages<'q, 'd:'q>( +pub struct Messages<'d>( // TODO: is this lifetime specifier correct? // query may outlive messages. pub(crate) *mut ffi::notmuch_messages_t, - marker::PhantomData<&'q Query<'d>> + marker::PhantomData<&'d mut Database>, ); -impl<'q, 'd:'q> NewFromPtr<*mut ffi::notmuch_messages_t> for Messages<'q, 'd> { - fn new(ptr: *mut ffi::notmuch_messages_t) -> Messages<'q, 'd> { +impl<'d> NewFromPtr<*mut ffi::notmuch_messages_t> for Messages<'d> { + fn new(ptr: *mut ffi::notmuch_messages_t) -> Messages<'d> { Messages(ptr, marker::PhantomData) } } - - -impl<'q, 'd:'q> ops::Drop for Messages<'q, 'd> { +impl<'d> ops::Drop for Messages<'d> { fn drop(&mut self) { unsafe { ffi::notmuch_messages_destroy(self.0) }; } } + +impl<'d> iter::Iterator for Messages<'d> { + type Item = Message<'d>; + + fn next(&mut self) -> Option { + + let valid = unsafe { + ffi::notmuch_messages_valid(self.0) + }; + + if valid == 0{ + return None + } + + let cmsg = unsafe { + ffi::notmuch_messages_move_to_next(self.0); + ffi::notmuch_messages_get(self.0) + }; + + Some(Message::new(cmsg)) + } +} diff --git a/src/tags.rs b/src/tags.rs index 9eb2779..0ffb7ae 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -56,6 +56,4 @@ impl<'d> iter::Iterator for Tags<'d> { Some(ctag.to_str().unwrap().to_string()) } - - } diff --git a/src/thread.rs b/src/thread.rs index e69de29..980ff39 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -0,0 +1,34 @@ +use std; +use std::{ + ops, + marker, + ptr, +}; + +use error::Result; + +use ffi; +use utils::{ + NewFromPtr, +}; +use Database; + +#[derive(Debug)] +pub struct Thread<'d>( + pub(crate) *mut ffi::notmuch_thread_t, + marker::PhantomData<&'d mut Database>, +); + +impl<'d> NewFromPtr<*mut ffi::notmuch_thread_t> for Thread<'d> { + fn new(ptr: *mut ffi::notmuch_thread_t) -> Thread<'d> { + Thread(ptr, marker::PhantomData) + } +} + +impl<'d> ops::Drop for Thread<'d> { + fn drop(&mut self) { + unsafe { + ffi::notmuch_thread_destroy(self.0) + }; + } +} diff --git a/src/threads.rs b/src/threads.rs index 75f4549..5f62a8d 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -1,20 +1,21 @@ use std::{ ops, marker, + iter }; use utils::{ NewFromPtr, }; -use database; - +use Database; +use Thread; use ffi; #[derive(Debug)] pub struct Threads<'d>( *mut ffi::notmuch_threads_t, - marker::PhantomData<&'d mut database::Database>, + marker::PhantomData<&'d mut Database>, ); impl<'d> NewFromPtr<*mut ffi::notmuch_threads_t> for Threads<'d> { @@ -30,3 +31,25 @@ impl<'d> ops::Drop for Threads<'d> { }; } } + +impl<'d> iter::Iterator for Threads<'d> { + type Item = Thread<'d>; + + fn next(&mut self) -> Option { + + let valid = unsafe { + ffi::notmuch_threads_valid(self.0) + }; + + if valid == 0{ + return None + } + + let cthread = unsafe { + ffi::notmuch_threads_move_to_next(self.0); + ffi::notmuch_threads_get(self.0) + }; + + Some(Thread::new(cthread)) + } +} -- cgit v1.2.1 From ccfa3d4864ff043abf1800e5397251afad7693d5 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 23 Mar 2018 04:03:50 +0100 Subject: bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 0e0c7c3..4145e46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "notmuch" -version = "0.0.3" +version = "0.0.4" authors = ["C. Morgan Hamill ", "Dirk Van Haerenborgh "] -- cgit v1.2.1 From 257e61b035c8fa80458f3aa44e068a3522b6686c Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 23 Mar 2018 06:49:37 +0100 Subject: search threads --- src/database.rs | 2 +- src/ffi.rs | 6 +++--- src/query.rs | 18 +++++++++++++++++- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/database.rs b/src/database.rs index 85ddcfb..b0e8b75 100644 --- a/src/database.rs +++ b/src/database.rs @@ -189,7 +189,7 @@ impl Database { pub fn create_query(&self, query_string: &String) -> Result { let query_str = CString::new(query_string.as_str()).unwrap(); - + println!("query {:?}", query_str); let mut query = ptr::null_mut(); unsafe { query = ffi::notmuch_query_create(self.0, query_str.as_ptr()); diff --git a/src/ffi.rs b/src/ffi.rs index 76045e3..caecc0e 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -731,9 +731,9 @@ extern { /// to call it if the query is about to be destroyed). /// /// @since libnotmuch 4.2 (notmuch 0.20) - pub fn notmuch_query_search_threads( - query: *mut notmuch_query_t, - ) -> *mut notmuch_threads_t; + pub fn notmuch_query_search_threads(query: *mut notmuch_query_t, + out: *mut *mut notmuch_threads_t) + -> notmuch_status_t; /// Execute a query for messages, returning a `notmuch_messages_t` object /// which can be used to iterate over the results. The returned diff --git a/src/query.rs b/src/query.rs index 6d7da64..68e9baf 100644 --- a/src/query.rs +++ b/src/query.rs @@ -13,6 +13,7 @@ use utils::{ }; use Database; use Messages; +use Threads; use ffi::Sort; #[derive(Debug)] @@ -53,7 +54,7 @@ impl<'d> Query<'d> { pub fn search_messages(self: &Self) -> Result> { let mut msgs = ptr::null_mut(); - try!(unsafe { + let ret = try!(unsafe { ffi::notmuch_query_search_messages( self.0, &mut msgs, ) @@ -64,6 +65,21 @@ impl<'d> Query<'d> { true => Ok(Some(Messages::new(msgs))), } } + + pub fn search_threads(self: &Self) -> Result> + { + let mut thrds = ptr::null_mut(); + let ret = try!(unsafe { + ffi::notmuch_query_search_threads( + self.0, &mut thrds, + ) + }.as_result()); + + match thrds.is_null() { + false => Ok(None), + true => Ok(Some(Threads::new(thrds))), + } + } } impl<'d> NewFromPtr<*mut ffi::notmuch_query_t> for Query<'d> { -- cgit v1.2.1 From 8e76db5f75c9c315236bc6f8c6e195cec6103537 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 23 Mar 2018 07:01:03 +0100 Subject: count threads and messages --- src/ffi.rs | 8 +++++--- src/query.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/ffi.rs b/src/ffi.rs index caecc0e..58965cc 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -856,7 +856,8 @@ extern { /// @since libnotmuch 4.3 (notmuch 0.21) pub fn notmuch_query_count_messages( query: *mut notmuch_query_t, - ) -> c_uint; + count: *mut c_uint + ) -> notmuch_status_t; /// Return the number of threads matching a search. @@ -879,9 +880,10 @@ extern { /// value of *count is not defined. /// /// @since libnotmuch 4.3 (notmuch 0.21) - pub fn notmuch_count_threads( + pub fn notmuch_query_count_threads( query: *mut notmuch_query_t, - ) -> c_uint; + count: *mut c_uint + ) -> notmuch_status_t; /// Get the thread ID of 'thread'. /// diff --git a/src/query.rs b/src/query.rs index 68e9baf..2873b27 100644 --- a/src/query.rs +++ b/src/query.rs @@ -66,6 +66,21 @@ impl<'d> Query<'d> { } } + pub fn count_messages(self: &Self) -> Result + { + let mut cnt = 0; + let ret = try!(unsafe { + ffi::notmuch_query_count_messages( + self.0, &mut cnt, + ) + }.as_result()); + + // if ret.is_err(){ + // return ret; + // } + return Ok(cnt); + } + pub fn search_threads(self: &Self) -> Result> { let mut thrds = ptr::null_mut(); @@ -80,6 +95,21 @@ impl<'d> Query<'d> { true => Ok(Some(Threads::new(thrds))), } } + + pub fn count_threads(self: &Self) -> Result + { + let mut cnt = 0; + let ret = try!(unsafe { + ffi::notmuch_query_count_threads( + self.0, &mut cnt, + ) + }.as_result()); + + // if ret.is_err(){ + // return ret; + // } + return Ok(cnt); + } } impl<'d> NewFromPtr<*mut ffi::notmuch_query_t> for Query<'d> { -- cgit v1.2.1 From be546fe6e4b709d1bb8770fdf0763ce4f494d0d6 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 23 Mar 2018 07:16:39 +0100 Subject: improve lifetime definitions --- src/ffi.rs | 4 ++++ src/message.rs | 12 ++++++------ src/messages.rs | 16 ++++++++-------- src/thread.rs | 19 +++++++++++++------ src/threads.rs | 16 ++++++++-------- 5 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/ffi.rs b/src/ffi.rs index 58965cc..765b180 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -54,6 +54,10 @@ impl notmuch_status_t { } } + pub fn is_err(&self) -> bool { + !self.is_ok() + } + pub fn as_result(self) -> Result<(), Self> { match self.is_ok() { true => Ok(()), diff --git a/src/message.rs b/src/message.rs index d774043..79fb19c 100644 --- a/src/message.rs +++ b/src/message.rs @@ -11,22 +11,22 @@ use ffi; use utils::{ NewFromPtr, }; -use Database; +use Query; #[derive(Debug)] -pub struct Message<'d>( +pub struct Message<'q, 'd:'q>( pub(crate) *mut ffi::notmuch_message_t, - marker::PhantomData<&'d mut Database>, + marker::PhantomData<&'q mut Query<'d>>, ); -impl<'d> NewFromPtr<*mut ffi::notmuch_message_t> for Message<'d> { - fn new(ptr: *mut ffi::notmuch_message_t) -> Message<'d> { +impl<'q, 'd> NewFromPtr<*mut ffi::notmuch_message_t> for Message<'q, 'd> { + fn new(ptr: *mut ffi::notmuch_message_t) -> Message<'q, 'd> { Message(ptr, marker::PhantomData) } } -impl<'d> ops::Drop for Message<'d> { +impl<'q, 'd> ops::Drop for Message<'q, 'd> { fn drop(&mut self) { unsafe { ffi::notmuch_message_destroy(self.0) diff --git a/src/messages.rs b/src/messages.rs index 706cfda..bb86866 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -10,24 +10,24 @@ use ffi; use utils::{ NewFromPtr, }; -use Database; +use Query; use Message; #[derive(Debug)] -pub struct Messages<'d>( +pub struct Messages<'q, 'd:'q>( // TODO: is this lifetime specifier correct? // query may outlive messages. pub(crate) *mut ffi::notmuch_messages_t, - marker::PhantomData<&'d mut Database>, + marker::PhantomData<&'q mut Query<'d>>, ); -impl<'d> NewFromPtr<*mut ffi::notmuch_messages_t> for Messages<'d> { - fn new(ptr: *mut ffi::notmuch_messages_t) -> Messages<'d> { +impl<'q, 'd> NewFromPtr<*mut ffi::notmuch_messages_t> for Messages<'q, 'd> { + fn new(ptr: *mut ffi::notmuch_messages_t) -> Messages<'q, 'd> { Messages(ptr, marker::PhantomData) } } -impl<'d> ops::Drop for Messages<'d> { +impl<'q, 'd> ops::Drop for Messages<'q, 'd> { fn drop(&mut self) { unsafe { ffi::notmuch_messages_destroy(self.0) @@ -35,8 +35,8 @@ impl<'d> ops::Drop for Messages<'d> { } } -impl<'d> iter::Iterator for Messages<'d> { - type Item = Message<'d>; +impl<'q, 'd> iter::Iterator for Messages<'q, 'd> { + type Item = Message<'q, 'd>; fn next(&mut self) -> Option { diff --git a/src/thread.rs b/src/thread.rs index 980ff39..cf5440c 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -11,21 +11,28 @@ use ffi; use utils::{ NewFromPtr, }; -use Database; +use Query; #[derive(Debug)] -pub struct Thread<'d>( +pub struct Thread<'q, 'd:'q>( pub(crate) *mut ffi::notmuch_thread_t, - marker::PhantomData<&'d mut Database>, + marker::PhantomData<&'q mut Query<'d>>, ); -impl<'d> NewFromPtr<*mut ffi::notmuch_thread_t> for Thread<'d> { - fn new(ptr: *mut ffi::notmuch_thread_t) -> Thread<'d> { +impl<'q, 'd> NewFromPtr<*mut ffi::notmuch_thread_t> for Thread<'q, 'd> { + fn new(ptr: *mut ffi::notmuch_thread_t) -> Thread<'q, 'd> { Thread(ptr, marker::PhantomData) } } -impl<'d> ops::Drop for Thread<'d> { +// impl<'d> Thread<'d>( +// +// +// +// }; +// + +impl<'q, 'd> ops::Drop for Thread<'q, 'd> { fn drop(&mut self) { unsafe { ffi::notmuch_thread_destroy(self.0) diff --git a/src/threads.rs b/src/threads.rs index 5f62a8d..eb8452e 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -8,23 +8,23 @@ use utils::{ NewFromPtr, }; -use Database; +use Query; use Thread; use ffi; #[derive(Debug)] -pub struct Threads<'d>( +pub struct Threads<'q, 'd:'q>( *mut ffi::notmuch_threads_t, - marker::PhantomData<&'d mut Database>, + marker::PhantomData<&'q mut Query<'d>>, ); -impl<'d> NewFromPtr<*mut ffi::notmuch_threads_t> for Threads<'d> { - fn new(ptr: *mut ffi::notmuch_threads_t) -> Threads<'d> { +impl<'q, 'd> NewFromPtr<*mut ffi::notmuch_threads_t> for Threads<'q, 'd> { + fn new(ptr: *mut ffi::notmuch_threads_t) -> Threads<'q, 'd> { Threads(ptr, marker::PhantomData) } } -impl<'d> ops::Drop for Threads<'d> { +impl<'q, 'd> ops::Drop for Threads<'q, 'd> { fn drop(&mut self) { unsafe { ffi::notmuch_threads_destroy(self.0) @@ -32,8 +32,8 @@ impl<'d> ops::Drop for Threads<'d> { } } -impl<'d> iter::Iterator for Threads<'d> { - type Item = Thread<'d>; +impl<'q, 'd> iter::Iterator for Threads<'q, 'd> { + type Item = Thread<'q, 'd>; fn next(&mut self) -> Option { -- cgit v1.2.1 From ba417206ed8bb2341dcad5655d91ad09f6a0f073 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 23 Mar 2018 07:28:07 +0100 Subject: thread: count messages and files --- src/ffi.rs | 11 +++++++++++ src/thread.rs | 22 ++++++++++++++++------ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/ffi.rs b/src/ffi.rs index 765b180..db67390 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -907,6 +907,17 @@ extern { thread: *mut notmuch_thread_t, ) -> c_int; + /// Get the total number of files in 'thread'. + /// + /// This sums notmuch_message_count_files over all messages in the + /// thread + /// @returns Non-negative integer + /// @since libnotmuch 5.0 (notmuch 0.25) + /// + pub fn notmuch_thread_get_total_files( + thread: *mut notmuch_thread_t, + ) -> c_int; + /// Get a `notmuch_messages_t` iterator for the top-level messages in /// 'thread' in oldest-first order. /// diff --git a/src/thread.rs b/src/thread.rs index cf5440c..2a502b4 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -25,12 +25,22 @@ impl<'q, 'd> NewFromPtr<*mut ffi::notmuch_thread_t> for Thread<'q, 'd> { } } -// impl<'d> Thread<'d>( -// -// -// -// }; -// +impl<'q, 'd> Thread<'q, 'd>{ + + pub fn total_messages(self: &Self) -> i32{ + unsafe { + ffi::notmuch_thread_get_total_messages(self.0) + } + } + + pub fn total_files(self: &Self) -> i32{ + unsafe { + ffi::notmuch_thread_get_total_files(self.0) + } + } + +} + impl<'q, 'd> ops::Drop for Thread<'q, 'd> { fn drop(&mut self) { -- cgit v1.2.1 From 188068f051976f8dd4bf1b0da5fcb4bc2c6ae185 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 23 Mar 2018 07:50:00 +0100 Subject: cleanup --- Cargo.toml | 5 ++--- src/database.rs | 12 +++--------- src/query.rs | 14 ++++---------- src/thread.rs | 13 ++++++++++++- src/utils.rs | 12 ++++++++++++ 5 files changed, 33 insertions(+), 23 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4145e46..cec9c63 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,7 @@ [package] name = "notmuch" -version = "0.0.4" -authors = ["C. Morgan Hamill ", - "Dirk Van Haerenborgh "] +version = "0.0.5" +authors = ["Dirk Van Haerenborgh "] homepage = "https://github.com/vhdirk/notmuch-rs" repository = "https://github.com/vhdirk/notmuch-rs" diff --git a/src/database.rs b/src/database.rs index b0e8b75..121a87c 100644 --- a/src/database.rs +++ b/src/database.rs @@ -62,9 +62,7 @@ impl Database { pub fn close(self) -> Result<()> { try!(unsafe { ffi::notmuch_database_close(self.0) - }.as_result()); - - Ok(()) + }.as_result()) } pub fn compact, F: FnMut(&str)>( @@ -107,9 +105,7 @@ impl Database { &f as *const _ as *mut libc::c_void }), ) - }.as_result()); - - Ok(()) + }.as_result()) } pub fn path(&self) -> &path::Path { @@ -166,9 +162,7 @@ impl Database { &f as *const _ as *mut libc::c_void }), ) - }.as_result()); - - Ok(()) + }.as_result()) } pub fn directory>(&self, path: &P) -> Result> { diff --git a/src/query.rs b/src/query.rs index 2873b27..36e9be6 100644 --- a/src/query.rs +++ b/src/query.rs @@ -54,7 +54,7 @@ impl<'d> Query<'d> { pub fn search_messages(self: &Self) -> Result> { let mut msgs = ptr::null_mut(); - let ret = try!(unsafe { + try!(unsafe { ffi::notmuch_query_search_messages( self.0, &mut msgs, ) @@ -69,22 +69,19 @@ impl<'d> Query<'d> { pub fn count_messages(self: &Self) -> Result { let mut cnt = 0; - let ret = try!(unsafe { + try!(unsafe { ffi::notmuch_query_count_messages( self.0, &mut cnt, ) }.as_result()); - // if ret.is_err(){ - // return ret; - // } return Ok(cnt); } pub fn search_threads(self: &Self) -> Result> { let mut thrds = ptr::null_mut(); - let ret = try!(unsafe { + try!(unsafe { ffi::notmuch_query_search_threads( self.0, &mut thrds, ) @@ -99,15 +96,12 @@ impl<'d> Query<'d> { pub fn count_threads(self: &Self) -> Result { let mut cnt = 0; - let ret = try!(unsafe { + try!(unsafe { ffi::notmuch_query_count_threads( self.0, &mut cnt, ) }.as_result()); - // if ret.is_err(){ - // return ret; - // } return Ok(cnt); } } diff --git a/src/thread.rs b/src/thread.rs index 2a502b4..2743f0a 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -2,14 +2,17 @@ use std; use std::{ ops, marker, - ptr, + str, + result }; +use std::ffi::{CString, CStr}; use error::Result; use ffi; use utils::{ NewFromPtr, + ToStr }; use Query; @@ -27,6 +30,14 @@ impl<'q, 'd> NewFromPtr<*mut ffi::notmuch_thread_t> for Thread<'q, 'd> { impl<'q, 'd> Thread<'q, 'd>{ + pub fn id(self: &Self) -> result::Result<&'q str, str::Utf8Error>{ + let tid = unsafe { + ffi::notmuch_thread_get_thread_id(self.0) + }; + tid.to_str() + } + + pub fn total_messages(self: &Self) -> i32{ unsafe { ffi::notmuch_thread_get_total_messages(self.0) diff --git a/src/utils.rs b/src/utils.rs index fa24029..e1f691c 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -20,3 +20,15 @@ impl ToStr for *const libc::c_char { }.to_bytes()) } } + +pub trait ToString { + fn to_string(&self) -> String; +} + +impl ToString for *const libc::c_char { + fn to_string(&self) -> String { + unsafe { + ffi::CStr::from_ptr(*self).to_string_lossy().into_owned() + } + } +} -- cgit v1.2.1 From 6e465aae88a81d849803f964e681974043ca368d Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 23 Mar 2018 07:55:21 +0100 Subject: oops --- src/database.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/database.rs b/src/database.rs index 121a87c..b0e8b75 100644 --- a/src/database.rs +++ b/src/database.rs @@ -62,7 +62,9 @@ impl Database { pub fn close(self) -> Result<()> { try!(unsafe { ffi::notmuch_database_close(self.0) - }.as_result()) + }.as_result()); + + Ok(()) } pub fn compact, F: FnMut(&str)>( @@ -105,7 +107,9 @@ impl Database { &f as *const _ as *mut libc::c_void }), ) - }.as_result()) + }.as_result()); + + Ok(()) } pub fn path(&self) -> &path::Path { @@ -162,7 +166,9 @@ impl Database { &f as *const _ as *mut libc::c_void }), ) - }.as_result()) + }.as_result()); + + Ok(()) } pub fn directory>(&self, path: &P) -> Result> { -- cgit v1.2.1 From b8eafc5c26f2bab0e2dedad177a8e3b4ecd9e17c Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 23 Mar 2018 07:58:09 +0100 Subject: filenames iterator --- src/filenames.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 2 files changed, 60 insertions(+) create mode 100644 src/filenames.rs diff --git a/src/filenames.rs b/src/filenames.rs new file mode 100644 index 0000000..618d7a8 --- /dev/null +++ b/src/filenames.rs @@ -0,0 +1,59 @@ +use std::{ + ops, + marker, + iter +}; + +use std::ffi::{ + CString, + CStr +}; + +use utils::{ + NewFromPtr, +}; + +use database; +use ffi; + +#[derive(Debug)] +pub struct Filenames<'d>( + *mut ffi::notmuch_filenames_t, + marker::PhantomData<&'d mut database::Database>, +); + +impl<'d> NewFromPtr<*mut ffi::notmuch_filenames_t> for Filenames<'d> { + fn new(ptr: *mut ffi::notmuch_filenames_t) -> Filenames<'d> { + Filenames(ptr, marker::PhantomData) + } +} + +impl<'d> ops::Drop for Filenames<'d> { + fn drop(&mut self) { + unsafe { + ffi::notmuch_filenames_destroy(self.0) + }; + } +} + +impl<'d> iter::Iterator for Filenames<'d> { + type Item = String; + + fn next(&mut self) -> Option { + + let valid = unsafe { + ffi::notmuch_filenames_valid(self.0) + }; + + if valid == 0{ + return None + } + + let ctag = unsafe { + ffi::notmuch_filenames_move_to_next(self.0); + CStr::from_ptr(ffi::notmuch_filenames_get(self.0)) + }; + + Some(ctag.to_str().unwrap().to_string()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 70cb7c9..5daeeb8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,5 +23,6 @@ pub use message::Message; pub use tags::Tags; pub use threads::Threads; pub use thread::Thread; +pub use filenames::Filenames; pub use ffi::DatabaseMode; -- cgit v1.2.1 From f94818acc6c2feaa37973b23593d575b1f9215b3 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 23 Mar 2018 07:59:19 +0100 Subject: do not export all modules, just the structs --- src/lib.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5daeeb8..8a718ee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,15 +6,16 @@ extern crate libc; mod utils; mod ffi; -pub mod error; -pub mod database; -pub mod directory; -pub mod query; -pub mod messages; -pub mod message; -pub mod tags; -pub mod threads; -pub mod thread; +mod error; +mod database; +mod directory; +mod query; +mod messages; +mod message; +mod tags; +mod threads; +mod thread; +mod filenames; pub use database::Database; pub use query::Query; -- cgit v1.2.1 From 39aba7b077f0285bd31298d2c270e11409252937 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 23 Mar 2018 10:27:46 +0100 Subject: the iterator can handle null pointers --- src/query.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/query.rs b/src/query.rs index 36e9be6..bedd758 100644 --- a/src/query.rs +++ b/src/query.rs @@ -51,7 +51,7 @@ impl<'d> Query<'d> { /// Filter messages according to the query and return - pub fn search_messages(self: &Self) -> Result> + pub fn search_messages(self: &Self) -> Result { let mut msgs = ptr::null_mut(); try!(unsafe { @@ -60,10 +60,7 @@ impl<'d> Query<'d> { ) }.as_result()); - match msgs.is_null() { - false => Ok(None), - true => Ok(Some(Messages::new(msgs))), - } + Ok(Messages::new(msgs)) } pub fn count_messages(self: &Self) -> Result @@ -78,7 +75,7 @@ impl<'d> Query<'d> { return Ok(cnt); } - pub fn search_threads(self: &Self) -> Result> + pub fn search_threads(self: &Self) -> Result { let mut thrds = ptr::null_mut(); try!(unsafe { @@ -87,10 +84,7 @@ impl<'d> Query<'d> { ) }.as_result()); - match thrds.is_null() { - false => Ok(None), - true => Ok(Some(Threads::new(thrds))), - } + Ok(Threads::new(thrds)) } pub fn count_threads(self: &Self) -> Result -- cgit v1.2.1 From c7f1127b960d1208b12a1abbd33885826fb6dd0c Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 23 Mar 2018 10:35:30 +0100 Subject: bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cec9c63..6a788ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "notmuch" -version = "0.0.5" +version = "0.0.6" authors = ["Dirk Van Haerenborgh "] homepage = "https://github.com/vhdirk/notmuch-rs" -- cgit v1.2.1 From 7719c3b31f67eded7af6cd63d99b56c0f74c97cd Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 23 Mar 2018 11:56:52 +0100 Subject: wip --- src/ffi.rs | 7 +++++++ src/message.rs | 35 ++++++++++++++++++++++++++++++++++- src/messages.rs | 11 +++++++++++ src/thread.rs | 24 ++++++++++++++++++++++++ 4 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/ffi.rs b/src/ffi.rs index db67390..d181ea0 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -1149,6 +1149,13 @@ extern { message: *mut notmuch_message_t, ) -> *mut notmuch_messages_t; + /// Get the total number of files associated with a message. + /// @returns Non-negative integer + /// @since libnotmuch 5.0 (notmuch 0.25) + pub fn notmuch_message_count_files( + message: *mut notmuch_message_t, + ) -> c_int; + /// Get a filename for the email corresponding to 'message'. /// /// The returned filename is an absolute filename, (the initial diff --git a/src/message.rs b/src/message.rs index 79fb19c..eb94cc8 100644 --- a/src/message.rs +++ b/src/message.rs @@ -2,7 +2,8 @@ use std; use std::{ ops, marker, - ptr, + str, + result }; use error::Result; @@ -10,8 +11,11 @@ use error::Result; use ffi; use utils::{ NewFromPtr, + ToStr }; use Query; +use Messages; +use Filenames; #[derive(Debug)] pub struct Message<'q, 'd:'q>( @@ -25,6 +29,35 @@ impl<'q, 'd> NewFromPtr<*mut ffi::notmuch_message_t> for Message<'q, 'd> { } } +impl<'q, 'd> Message<'q, 'd>{ + + pub fn id(self: &Self) -> result::Result<&'q str, str::Utf8Error>{ + let tid = unsafe { + ffi::notmuch_message_get_message_id(self.0) + }; + tid.to_str() + } + + pub fn replies(self: &Self) -> Messages<'q, 'd>{ + Messages::new(unsafe { + ffi::notmuch_message_get_replies(self.0) + }) + } + + pub fn count_files(self: &Self) -> i32 + { + unsafe { + ffi::notmuch_message_count_files(self.0) + } + } + + pub fn filenames(self: &Self) -> Filenames<'d>{ + Filenames::new(unsafe { + ffi::notmuch_message_get_filenames(self.0) + }) + } +} + impl<'q, 'd> ops::Drop for Message<'q, 'd> { fn drop(&mut self) { diff --git a/src/messages.rs b/src/messages.rs index bb86866..8466387 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -12,6 +12,7 @@ use utils::{ }; use Query; use Message; +use Tags; #[derive(Debug)] pub struct Messages<'q, 'd:'q>( @@ -27,6 +28,16 @@ impl<'q, 'd> NewFromPtr<*mut ffi::notmuch_messages_t> for Messages<'q, 'd> { } } +impl<'q, 'd> Messages<'q, 'd>{ + + pub fn collect_tags(self: &Self) -> Tags{ + Tags::new(unsafe { + ffi::notmuch_messages_collect_tags(self.0) + }) + } + +} + impl<'q, 'd> ops::Drop for Messages<'q, 'd> { fn drop(&mut self) { unsafe { diff --git a/src/thread.rs b/src/thread.rs index 2743f0a..87e1f0c 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -15,6 +15,8 @@ use utils::{ ToStr }; use Query; +use Messages; +use Tags; #[derive(Debug)] pub struct Thread<'q, 'd:'q>( @@ -50,6 +52,28 @@ impl<'q, 'd> Thread<'q, 'd>{ } } + + pub fn toplevel_messages(self: &Self) -> Messages{ + Messages::new(unsafe { + ffi::notmuch_thread_get_toplevel_messages(self.0) + }) + } + + /// Get a `Messages` iterator for all messages in 'thread' in + /// oldest-first order. + pub fn messages(self: &Self) -> Messages{ + Messages::new(unsafe { + ffi::notmuch_thread_get_messages(self.0) + }) + } + + + pub fn tags(self: &Self) -> Tags{ + Tags::new(unsafe { + ffi::notmuch_thread_get_tags(self.0) + }) + } + } -- cgit v1.2.1 From 688a4eb106db42cb50509c61216efc42bf3a4b1f Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 23 Mar 2018 12:20:57 +0100 Subject: get thread authors and subject --- src/thread.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/thread.rs b/src/thread.rs index 87e1f0c..2182d69 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -32,11 +32,11 @@ impl<'q, 'd> NewFromPtr<*mut ffi::notmuch_thread_t> for Thread<'q, 'd> { impl<'q, 'd> Thread<'q, 'd>{ - pub fn id(self: &Self) -> result::Result<&'q str, str::Utf8Error>{ + pub fn id(self: &Self) -> String{ let tid = unsafe { ffi::notmuch_thread_get_thread_id(self.0) }; - tid.to_str() + tid.to_str().unwrap().to_string() } @@ -74,6 +74,24 @@ impl<'q, 'd> Thread<'q, 'd>{ }) } + pub fn subject(self: &Self) -> String{ + let sub = unsafe { + ffi::notmuch_thread_get_subject(self.0) + }; + + sub.to_str().unwrap().to_string() + } + + pub fn authors(self: &Self) -> Vec{ + let athrs = unsafe { + ffi::notmuch_thread_get_authors(self.0) + }; + + athrs.to_str().unwrap().split(",").map(|s| s.to_string()).collect() + } + + + } -- cgit v1.2.1 From dada4a5f126f79cc0bb7376343ceeb2575a65969 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 23 Mar 2018 14:14:36 +0100 Subject: lifetime parameters are cool --- src/database.rs | 10 +++++----- src/messages.rs | 2 +- src/query.rs | 4 ++-- src/threads.rs | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/database.rs b/src/database.rs index b0e8b75..c212745 100644 --- a/src/database.rs +++ b/src/database.rs @@ -171,7 +171,7 @@ impl Database { Ok(()) } - pub fn directory>(&self, path: &P) -> Result> { + pub fn directory<'d, P: AsRef>(&self, path: &P) -> Result>> { let path_str = CString::new(path.as_ref().to_str().unwrap()).unwrap(); let mut dir = ptr::null_mut(); @@ -182,12 +182,12 @@ impl Database { }.as_result()); match dir.is_null() { - false => Ok(None), - true => Ok(Some(Directory::new(dir))), + true => Ok(None), + false => Ok(Some(Directory::new(dir))), } } - pub fn create_query(&self, query_string: &String) -> Result { + pub fn create_query<'d>(&self, query_string: &String) -> Result> { let query_str = CString::new(query_string.as_str()).unwrap(); println!("query {:?}", query_str); let mut query = ptr::null_mut(); @@ -198,7 +198,7 @@ impl Database { Ok(Query::new(query)) } - pub fn all_tags(&self) -> Result { + pub fn all_tags<'d>(&self) -> Result> { let mut tags = ptr::null_mut(); unsafe { diff --git a/src/messages.rs b/src/messages.rs index 8466387..9a539c9 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -64,6 +64,6 @@ impl<'q, 'd> iter::Iterator for Messages<'q, 'd> { ffi::notmuch_messages_get(self.0) }; - Some(Message::new(cmsg)) + Some(Self::Item::new(cmsg)) } } diff --git a/src/query.rs b/src/query.rs index bedd758..1fe4e0d 100644 --- a/src/query.rs +++ b/src/query.rs @@ -51,7 +51,7 @@ impl<'d> Query<'d> { /// Filter messages according to the query and return - pub fn search_messages(self: &Self) -> Result + pub fn search_messages<'q>(self: &Self) -> Result> { let mut msgs = ptr::null_mut(); try!(unsafe { @@ -75,7 +75,7 @@ impl<'d> Query<'d> { return Ok(cnt); } - pub fn search_threads(self: &Self) -> Result + pub fn search_threads<'q>(self: &Self) -> Result> { let mut thrds = ptr::null_mut(); try!(unsafe { diff --git a/src/threads.rs b/src/threads.rs index eb8452e..dadb137 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -42,7 +42,7 @@ impl<'q, 'd> iter::Iterator for Threads<'q, 'd> { }; if valid == 0{ - return None + return None; } let cthread = unsafe { @@ -50,6 +50,6 @@ impl<'q, 'd> iter::Iterator for Threads<'q, 'd> { ffi::notmuch_threads_get(self.0) }; - Some(Thread::new(cthread)) + Some(Self::Item::new(cthread)) } } -- cgit v1.2.1 From 42c5b215ddcc154d647ec268d4da044f32948227 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 23 Mar 2018 14:23:05 +0100 Subject: return filenames as path --- src/filenames.rs | 9 +++++++-- src/message.rs | 21 ++++++++++++++++++--- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/filenames.rs b/src/filenames.rs index 618d7a8..5d6a19c 100644 --- a/src/filenames.rs +++ b/src/filenames.rs @@ -4,6 +4,11 @@ use std::{ iter }; +use std::path::{ + PathBuf, + Path +}; + use std::ffi::{ CString, CStr @@ -37,7 +42,7 @@ impl<'d> ops::Drop for Filenames<'d> { } impl<'d> iter::Iterator for Filenames<'d> { - type Item = String; + type Item = PathBuf; fn next(&mut self) -> Option { @@ -54,6 +59,6 @@ impl<'d> iter::Iterator for Filenames<'d> { CStr::from_ptr(ffi::notmuch_filenames_get(self.0)) }; - Some(ctag.to_str().unwrap().to_string()) + Some(PathBuf::from(ctag.to_str().unwrap())) } } diff --git a/src/message.rs b/src/message.rs index eb94cc8..6edfd7e 100644 --- a/src/message.rs +++ b/src/message.rs @@ -6,6 +6,8 @@ use std::{ result }; +use std::path::PathBuf; + use error::Result; use ffi; @@ -31,11 +33,18 @@ impl<'q, 'd> NewFromPtr<*mut ffi::notmuch_message_t> for Message<'q, 'd> { impl<'q, 'd> Message<'q, 'd>{ - pub fn id(self: &Self) -> result::Result<&'q str, str::Utf8Error>{ - let tid = unsafe { + pub fn id(self: &Self) -> String{ + let mid = unsafe { ffi::notmuch_message_get_message_id(self.0) }; - tid.to_str() + mid.to_str().unwrap().to_string() + } + + pub fn thread_id(self: &Self) -> String{ + let tid = unsafe { + ffi::notmuch_message_get_thread_id(self.0) + }; + tid.to_str().unwrap().to_string() } pub fn replies(self: &Self) -> Messages<'q, 'd>{ @@ -56,6 +65,12 @@ impl<'q, 'd> Message<'q, 'd>{ ffi::notmuch_message_get_filenames(self.0) }) } + + pub fn filename(self: &Self) -> PathBuf{ + PathBuf::from(unsafe { + ffi::notmuch_message_get_filename(self.0) + }.to_str().unwrap()) + } } -- cgit v1.2.1 From c522a72b61c943841da9ba8324694af8ffbce1dc Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 23 Mar 2018 20:51:21 +0100 Subject: threads: oldest and newest date --- src/thread.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/thread.rs b/src/thread.rs index 2182d69..9148c44 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -5,6 +5,7 @@ use std::{ str, result }; + use std::ffi::{CString, CStr}; use error::Result; @@ -90,8 +91,19 @@ impl<'q, 'd> Thread<'q, 'd>{ 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.0) + } + } - + /// 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.0) + } + } } -- cgit v1.2.1 From 7502d59c614a35360cf90fbb6bdc7ad4e395da46 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 23 Mar 2018 20:51:54 +0100 Subject: bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 6a788ff..37b6cff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "notmuch" -version = "0.0.6" +version = "0.0.7" authors = ["Dirk Van Haerenborgh "] homepage = "https://github.com/vhdirk/notmuch-rs" -- cgit v1.2.1 From 4427467501fc702a84a52a6e304789db31ea8329 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 27 Mar 2018 09:42:41 +0200 Subject: also export error --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 8a718ee..0c807f4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ mod threads; mod thread; mod filenames; +pub use error::Error; pub use database::Database; pub use query::Query; pub use messages::Messages; -- cgit v1.2.1 From 65c58afe84b81ee0567eb9a6f38a2d36fbcf67f6 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 27 Mar 2018 09:43:33 +0200 Subject: bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 37b6cff..e1fec5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "notmuch" -version = "0.0.7" +version = "0.0.8" authors = ["Dirk Van Haerenborgh "] homepage = "https://github.com/vhdirk/notmuch-rs" -- cgit v1.2.1 From 7452e9061b397c5f1876fa6a0db4d4539aeea7d8 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 27 Mar 2018 10:35:42 +0200 Subject: fix the iterators --- src/filenames.rs | 3 ++- src/messages.rs | 3 ++- src/tags.rs | 4 +++- src/threads.rs | 3 ++- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/filenames.rs b/src/filenames.rs index 5d6a19c..bf65700 100644 --- a/src/filenames.rs +++ b/src/filenames.rs @@ -55,8 +55,9 @@ impl<'d> iter::Iterator for Filenames<'d> { } let ctag = unsafe { + let t = ffi::notmuch_filenames_get(self.0); ffi::notmuch_filenames_move_to_next(self.0); - CStr::from_ptr(ffi::notmuch_filenames_get(self.0)) + CStr::from_ptr(t) }; Some(PathBuf::from(ctag.to_str().unwrap())) diff --git a/src/messages.rs b/src/messages.rs index 9a539c9..16cf741 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -60,8 +60,9 @@ impl<'q, 'd> iter::Iterator for Messages<'q, 'd> { } let cmsg = unsafe { + let msg = ffi::notmuch_messages_get(self.0); ffi::notmuch_messages_move_to_next(self.0); - ffi::notmuch_messages_get(self.0) + msg }; Some(Self::Item::new(cmsg)) diff --git a/src/tags.rs b/src/tags.rs index 0ffb7ae..52fa440 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -50,8 +50,10 @@ impl<'d> iter::Iterator for Tags<'d> { } let ctag = unsafe { + let t = ffi::notmuch_tags_get(self.0); ffi::notmuch_tags_move_to_next(self.0); - CStr::from_ptr(ffi::notmuch_tags_get(self.0)) + + CStr::from_ptr(t) }; Some(ctag.to_str().unwrap().to_string()) diff --git a/src/threads.rs b/src/threads.rs index dadb137..ebfa52c 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -46,8 +46,9 @@ impl<'q, 'd> iter::Iterator for Threads<'q, 'd> { } let cthread = unsafe { + let t = ffi::notmuch_threads_get(self.0); ffi::notmuch_threads_move_to_next(self.0); - ffi::notmuch_threads_get(self.0) + t }; Some(Self::Item::new(cthread)) -- cgit v1.2.1 From 015f6bc0a403399307374fcf44326eb50096fca6 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 27 Mar 2018 10:36:06 +0200 Subject: bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e1fec5b..2bcb248 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "notmuch" -version = "0.0.8" +version = "0.0.9" authors = ["Dirk Van Haerenborgh "] homepage = "https://github.com/vhdirk/notmuch-rs" -- cgit v1.2.1 From 10e38b49f57734f2397e395b48faab593268402c Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 12 Apr 2018 07:12:52 +0200 Subject: make some types Send'able --- src/database.rs | 2 ++ src/directory.rs | 2 ++ src/filenames.rs | 4 +--- src/message.rs | 2 ++ src/thread.rs | 2 ++ 5 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/database.rs b/src/database.rs index c212745..488cff5 100644 --- a/src/database.rs +++ b/src/database.rs @@ -220,3 +220,5 @@ impl ops::Drop for Database { }; } } + +unsafe impl Send for Database {} diff --git a/src/directory.rs b/src/directory.rs index 7b00d70..e5ad11f 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -30,3 +30,5 @@ impl<'d> ops::Drop for Directory<'d> { }; } } + +unsafe impl<'d> Send for Directory<'d> {} diff --git a/src/filenames.rs b/src/filenames.rs index bf65700..42d43d4 100644 --- a/src/filenames.rs +++ b/src/filenames.rs @@ -5,12 +5,10 @@ use std::{ }; use std::path::{ - PathBuf, - Path + PathBuf }; use std::ffi::{ - CString, CStr }; diff --git a/src/message.rs b/src/message.rs index 6edfd7e..7098a68 100644 --- a/src/message.rs +++ b/src/message.rs @@ -81,3 +81,5 @@ impl<'q, 'd> ops::Drop for Message<'q, 'd> { }; } } + +unsafe impl<'q, 'd> Send for Message<'q, 'd> {} diff --git a/src/thread.rs b/src/thread.rs index 9148c44..37f7cb7 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -114,3 +114,5 @@ impl<'q, 'd> ops::Drop for Thread<'q, 'd> { }; } } + +unsafe impl<'q, 'd> Send for Thread<'q, 'd> {} -- cgit v1.2.1 From 3e39497cf25cab014100f27f486080e93961db9d Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 12 Apr 2018 07:16:35 +0200 Subject: bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 2bcb248..cdb58ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "notmuch" -version = "0.0.9" +version = "0.0.10" authors = ["Dirk Van Haerenborgh "] homepage = "https://github.com/vhdirk/notmuch-rs" -- cgit v1.2.1 From c621f5cf919cfc8c94b5eaf0a9df6074a4e7a6cf Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 12 Apr 2018 23:58:45 +0200 Subject: notmuch is not thread safe. do not let the user think it is --- src/database.rs | 2 -- src/directory.rs | 2 -- src/message.rs | 2 -- src/thread.rs | 2 -- 4 files changed, 8 deletions(-) diff --git a/src/database.rs b/src/database.rs index 488cff5..c212745 100644 --- a/src/database.rs +++ b/src/database.rs @@ -220,5 +220,3 @@ impl ops::Drop for Database { }; } } - -unsafe impl Send for Database {} diff --git a/src/directory.rs b/src/directory.rs index e5ad11f..7b00d70 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -30,5 +30,3 @@ impl<'d> ops::Drop for Directory<'d> { }; } } - -unsafe impl<'d> Send for Directory<'d> {} diff --git a/src/message.rs b/src/message.rs index 7098a68..6edfd7e 100644 --- a/src/message.rs +++ b/src/message.rs @@ -81,5 +81,3 @@ impl<'q, 'd> ops::Drop for Message<'q, 'd> { }; } } - -unsafe impl<'q, 'd> Send for Message<'q, 'd> {} diff --git a/src/thread.rs b/src/thread.rs index 37f7cb7..9148c44 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -114,5 +114,3 @@ impl<'q, 'd> ops::Drop for Thread<'q, 'd> { }; } } - -unsafe impl<'q, 'd> Send for Thread<'q, 'd> {} -- cgit v1.2.1 From 1f2c854d2045257352363b80559332cea4e24dcd Mon Sep 17 00:00:00 2001 From: rhn Date: Fri, 13 Apr 2018 11:21:42 +0200 Subject: Add Directory::child_directories --- src/directory.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/directory.rs b/src/directory.rs index 7b00d70..c3b313b 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -8,6 +8,7 @@ use utils::{ }; use Database; +use Filenames; use ffi; @@ -17,6 +18,14 @@ pub struct Directory<'d>( marker::PhantomData<&'d mut Database>, ); +impl<'d> Directory<'d>{ + pub fn child_directories(self: &Self) -> Filenames<'d>{ + Filenames::new(unsafe { + ffi::notmuch_directory_get_child_directories(self.0) + }) + } +} + impl<'d> NewFromPtr<*mut ffi::notmuch_directory_t> for Directory<'d> { fn new(ptr: *mut ffi::notmuch_directory_t) -> Directory<'d> { Directory(ptr, marker::PhantomData) -- cgit v1.2.1 From 088ad8644f91448853754bbf189f52c81a5bc695 Mon Sep 17 00:00:00 2001 From: rhn Date: Fri, 13 Apr 2018 11:22:42 +0200 Subject: Make 0.26 functions available after setting "0.26" config --- src/message.rs | 2 +- src/thread.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/message.rs b/src/message.rs index 6edfd7e..ec4473f 100644 --- a/src/message.rs +++ b/src/message.rs @@ -52,7 +52,7 @@ impl<'q, 'd> Message<'q, 'd>{ ffi::notmuch_message_get_replies(self.0) }) } - +#[cfg(feature = "0.26")] pub fn count_files(self: &Self) -> i32 { unsafe { diff --git a/src/thread.rs b/src/thread.rs index 9148c44..98832a6 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -46,7 +46,7 @@ impl<'q, 'd> Thread<'q, 'd>{ ffi::notmuch_thread_get_total_messages(self.0) } } - +#[cfg(feature = "0.26")] pub fn total_files(self: &Self) -> i32{ unsafe { ffi::notmuch_thread_get_total_files(self.0) -- cgit v1.2.1 From 8228f44604478bdf0028b39320d1448e68b5ebf7 Mon Sep 17 00:00:00 2001 From: rhn Date: Fri, 13 Apr 2018 11:23:04 +0200 Subject: Fix enum name for unsorted sorting --- src/ffi.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ffi.rs b/src/ffi.rs index d181ea0..63c83ba 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -102,7 +102,7 @@ notmuch_enum! { NOTMUCH_SORT_OLDEST_FIRST => OldestFirst, NOTMUCH_SORT_NEWEST_FIRST => NewestFirst, NOTMUCH_SORT_MESSAGE_ID => MessageID, - NOTMUCH_SORT_UNSORTED => ReadWrite + NOTMUCH_SORT_UNSORTED => Unsorted } } -- cgit v1.2.1 From 52050a5e1dcd613915135e217439bc6293bea257 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 13 Apr 2018 17:19:17 +0200 Subject: I think these are actually Send'able, but certainly no Sync --- src/database.rs | 2 ++ src/directory.rs | 2 ++ src/filenames.rs | 3 +++ src/message.rs | 2 ++ src/messages.rs | 2 ++ src/query.rs | 2 ++ src/tags.rs | 2 ++ src/thread.rs | 2 ++ src/threads.rs | 2 ++ 9 files changed, 19 insertions(+) diff --git a/src/database.rs b/src/database.rs index c212745..314c354 100644 --- a/src/database.rs +++ b/src/database.rs @@ -220,3 +220,5 @@ impl ops::Drop for Database { }; } } + +unsafe impl Send for Database{} diff --git a/src/directory.rs b/src/directory.rs index c3b313b..7237100 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -39,3 +39,5 @@ impl<'d> ops::Drop for Directory<'d> { }; } } + +unsafe impl<'d> Send for Directory<'d>{} diff --git a/src/filenames.rs b/src/filenames.rs index 42d43d4..0d32bd6 100644 --- a/src/filenames.rs +++ b/src/filenames.rs @@ -61,3 +61,6 @@ impl<'d> iter::Iterator for Filenames<'d> { Some(PathBuf::from(ctag.to_str().unwrap())) } } + + +unsafe impl<'d> Send for Filenames<'d>{} diff --git a/src/message.rs b/src/message.rs index ec4473f..a1f7816 100644 --- a/src/message.rs +++ b/src/message.rs @@ -81,3 +81,5 @@ impl<'q, 'd> ops::Drop for Message<'q, 'd> { }; } } + +unsafe impl<'q, 'd> Send for Message<'q, 'd>{} diff --git a/src/messages.rs b/src/messages.rs index 16cf741..94b823c 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -68,3 +68,5 @@ impl<'q, 'd> iter::Iterator for Messages<'q, 'd> { Some(Self::Item::new(cmsg)) } } + +unsafe impl<'q, 'd> Send for Messages<'q, 'd>{} diff --git a/src/query.rs b/src/query.rs index 1fe4e0d..aa5d9f5 100644 --- a/src/query.rs +++ b/src/query.rs @@ -114,3 +114,5 @@ impl<'d> ops::Drop for Query<'d> { }; } } + +unsafe impl<'d> Send for Query<'d>{} diff --git a/src/tags.rs b/src/tags.rs index 52fa440..c58f670 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -59,3 +59,5 @@ impl<'d> iter::Iterator for Tags<'d> { Some(ctag.to_str().unwrap().to_string()) } } + +unsafe impl<'d> Send for Tags<'d>{} diff --git a/src/thread.rs b/src/thread.rs index 98832a6..97b005a 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -114,3 +114,5 @@ impl<'q, 'd> ops::Drop for Thread<'q, 'd> { }; } } + +unsafe impl<'q, 'd> Send for Thread<'q, 'd>{} diff --git a/src/threads.rs b/src/threads.rs index ebfa52c..2d6d7c4 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -54,3 +54,5 @@ impl<'q, 'd> iter::Iterator for Threads<'q, 'd> { Some(Self::Item::new(cthread)) } } + +unsafe impl<'q, 'd> Send for Threads<'q, 'd>{} -- cgit v1.2.1 From 3f02ab97bea870111aa23c32291de129b824de89 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 13 Apr 2018 18:51:55 +0200 Subject: add missing lifetime parameters --- src/database.rs | 24 ++++++++++++------------ src/directory.rs | 7 ++++--- src/filenames.rs | 7 ++++--- src/message.rs | 12 +++++++----- src/messages.rs | 7 ++++--- src/query.rs | 9 +++++---- src/tags.rs | 3 ++- src/thread.rs | 6 ++++-- src/threads.rs | 5 +++-- 9 files changed, 45 insertions(+), 35 deletions(-) diff --git a/src/database.rs b/src/database.rs index 314c354..6dcbd0d 100644 --- a/src/database.rs +++ b/src/database.rs @@ -171,7 +171,7 @@ impl Database { Ok(()) } - pub fn directory<'d, P: AsRef>(&self, path: &P) -> Result>> { + pub fn directory<'d, P: AsRef>(&'d self, path: &P) -> Result>> { let path_str = CString::new(path.as_ref().to_str().unwrap()).unwrap(); let mut dir = ptr::null_mut(); @@ -187,23 +187,22 @@ impl Database { } } - pub fn create_query<'d>(&self, query_string: &String) -> Result> { + pub fn create_query<'d>(&'d self, query_string: &String) -> Result> { let query_str = CString::new(query_string.as_str()).unwrap(); println!("query {:?}", query_str); - let mut query = ptr::null_mut(); - unsafe { - query = ffi::notmuch_query_create(self.0, query_str.as_ptr()); - } + + let mut query = unsafe { + ffi::notmuch_query_create(self.0, query_str.as_ptr()) + }; Ok(Query::new(query)) } - pub fn all_tags<'d>(&self) -> Result> { + pub fn all_tags<'d>(&'d self) -> Result> { - let mut tags = ptr::null_mut(); - unsafe { - tags = ffi::notmuch_database_get_all_tags(self.0); - } + let mut tags = unsafe { + ffi::notmuch_database_get_all_tags(self.0) + }; Ok(Tags::new(tags)) } @@ -221,4 +220,5 @@ impl ops::Drop for Database { } } -unsafe impl Send for Database{} +unsafe impl Send for Database {} +// unsafe impl Sync for Database {} diff --git a/src/directory.rs b/src/directory.rs index 7237100..d01f21e 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -15,11 +15,11 @@ use ffi; #[derive(Debug)] pub struct Directory<'d>( *mut ffi::notmuch_directory_t, - marker::PhantomData<&'d mut Database>, + marker::PhantomData<&'d Database>, ); impl<'d> Directory<'d>{ - pub fn child_directories(self: &Self) -> Filenames<'d>{ + pub fn child_directories(self: &'d Self) -> Filenames<'d>{ Filenames::new(unsafe { ffi::notmuch_directory_get_child_directories(self.0) }) @@ -33,7 +33,7 @@ impl<'d> NewFromPtr<*mut ffi::notmuch_directory_t> for Directory<'d> { } impl<'d> ops::Drop for Directory<'d> { - fn drop(&mut self) { + fn drop(self: &mut Self) { unsafe { ffi::notmuch_directory_destroy(self.0) }; @@ -41,3 +41,4 @@ impl<'d> ops::Drop for Directory<'d> { } unsafe impl<'d> Send for Directory<'d>{} +//unsafe impl<'d> Sync for Directory<'d>{} diff --git a/src/filenames.rs b/src/filenames.rs index 0d32bd6..30367a9 100644 --- a/src/filenames.rs +++ b/src/filenames.rs @@ -22,7 +22,7 @@ use ffi; #[derive(Debug)] pub struct Filenames<'d>( *mut ffi::notmuch_filenames_t, - marker::PhantomData<&'d mut database::Database>, + marker::PhantomData<&'d database::Database>, ); impl<'d> NewFromPtr<*mut ffi::notmuch_filenames_t> for Filenames<'d> { @@ -32,7 +32,7 @@ impl<'d> NewFromPtr<*mut ffi::notmuch_filenames_t> for Filenames<'d> { } impl<'d> ops::Drop for Filenames<'d> { - fn drop(&mut self) { + fn drop(self: &mut Self) { unsafe { ffi::notmuch_filenames_destroy(self.0) }; @@ -42,7 +42,7 @@ impl<'d> ops::Drop for Filenames<'d> { impl<'d> iter::Iterator for Filenames<'d> { type Item = PathBuf; - fn next(&mut self) -> Option { + fn next(self: &mut Self) -> Option { let valid = unsafe { ffi::notmuch_filenames_valid(self.0) @@ -64,3 +64,4 @@ impl<'d> iter::Iterator for Filenames<'d> { unsafe impl<'d> Send for Filenames<'d>{} +// unsafe impl<'d> Sync for Filenames<'d>{} diff --git a/src/message.rs b/src/message.rs index a1f7816..409c101 100644 --- a/src/message.rs +++ b/src/message.rs @@ -22,7 +22,7 @@ use Filenames; #[derive(Debug)] pub struct Message<'q, 'd:'q>( pub(crate) *mut ffi::notmuch_message_t, - marker::PhantomData<&'q mut Query<'d>>, + marker::PhantomData<&'q Query<'d>>, ); impl<'q, 'd> NewFromPtr<*mut ffi::notmuch_message_t> for Message<'q, 'd> { @@ -47,12 +47,13 @@ impl<'q, 'd> Message<'q, 'd>{ tid.to_str().unwrap().to_string() } - pub fn replies(self: &Self) -> Messages<'q, 'd>{ + pub fn replies(self: &'q Self) -> Messages<'q, 'd>{ Messages::new(unsafe { ffi::notmuch_message_get_replies(self.0) }) } -#[cfg(feature = "0.26")] + + #[cfg(feature = "0.26")] pub fn count_files(self: &Self) -> i32 { unsafe { @@ -60,7 +61,7 @@ impl<'q, 'd> Message<'q, 'd>{ } } - pub fn filenames(self: &Self) -> Filenames<'d>{ + pub fn filenames(self: &'d Self) -> Filenames<'d>{ Filenames::new(unsafe { ffi::notmuch_message_get_filenames(self.0) }) @@ -75,7 +76,7 @@ impl<'q, 'd> Message<'q, 'd>{ impl<'q, 'd> ops::Drop for Message<'q, 'd> { - fn drop(&mut self) { + fn drop(self: &mut Self) { unsafe { ffi::notmuch_message_destroy(self.0) }; @@ -83,3 +84,4 @@ impl<'q, 'd> ops::Drop for Message<'q, 'd> { } unsafe impl<'q, 'd> Send for Message<'q, 'd>{} +// unsafe impl<'q, 'd> Sync for Message<'q, 'd>{} diff --git a/src/messages.rs b/src/messages.rs index 94b823c..925b027 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -19,7 +19,7 @@ pub struct Messages<'q, 'd:'q>( // TODO: is this lifetime specifier correct? // query may outlive messages. pub(crate) *mut ffi::notmuch_messages_t, - marker::PhantomData<&'q mut Query<'d>>, + marker::PhantomData<&'q Query<'d>>, ); impl<'q, 'd> NewFromPtr<*mut ffi::notmuch_messages_t> for Messages<'q, 'd> { @@ -30,7 +30,7 @@ impl<'q, 'd> NewFromPtr<*mut ffi::notmuch_messages_t> for Messages<'q, 'd> { impl<'q, 'd> Messages<'q, 'd>{ - pub fn collect_tags(self: &Self) -> Tags{ + pub fn collect_tags(self: &'d Self) -> Tags<'d>{ Tags::new(unsafe { ffi::notmuch_messages_collect_tags(self.0) }) @@ -39,7 +39,7 @@ impl<'q, 'd> Messages<'q, 'd>{ } impl<'q, 'd> ops::Drop for Messages<'q, 'd> { - fn drop(&mut self) { + fn drop(self: &mut Self) { unsafe { ffi::notmuch_messages_destroy(self.0) }; @@ -70,3 +70,4 @@ impl<'q, 'd> iter::Iterator for Messages<'q, 'd> { } unsafe impl<'q, 'd> Send for Messages<'q, 'd>{} +// unsafe impl<'q, 'd> Sync for Messages<'q, 'd>{} diff --git a/src/query.rs b/src/query.rs index aa5d9f5..660c86c 100644 --- a/src/query.rs +++ b/src/query.rs @@ -19,7 +19,7 @@ use ffi::Sort; #[derive(Debug)] pub struct Query<'d>( pub(crate) *mut ffi::notmuch_query_t, - marker::PhantomData<&'d mut Database>, + marker::PhantomData<&'d Database>, ); @@ -51,7 +51,7 @@ impl<'d> Query<'d> { /// Filter messages according to the query and return - pub fn search_messages<'q>(self: &Self) -> Result> + pub fn search_messages<'q>(self: &'d Self) -> Result> { let mut msgs = ptr::null_mut(); try!(unsafe { @@ -75,7 +75,7 @@ impl<'d> Query<'d> { return Ok(cnt); } - pub fn search_threads<'q>(self: &Self) -> Result> + pub fn search_threads<'q>(self: &'d Self) -> Result> { let mut thrds = ptr::null_mut(); try!(unsafe { @@ -115,4 +115,5 @@ impl<'d> ops::Drop for Query<'d> { } } -unsafe impl<'d> Send for Query<'d>{} +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 c58f670..37cc33d 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -19,7 +19,7 @@ use ffi; #[derive(Debug)] pub struct Tags<'d>( *mut ffi::notmuch_tags_t, - marker::PhantomData<&'d mut database::Database>, + marker::PhantomData<&'d database::Database>, ); impl<'d> NewFromPtr<*mut ffi::notmuch_tags_t> for Tags<'d> { @@ -61,3 +61,4 @@ impl<'d> iter::Iterator for Tags<'d> { } unsafe impl<'d> Send for Tags<'d>{} +// unsafe impl<'d> Sync for Tags<'d>{} diff --git a/src/thread.rs b/src/thread.rs index 97b005a..ef6023d 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -5,6 +5,7 @@ use std::{ str, result }; +use std::sync::atomic::AtomicPtr; use std::ffi::{CString, CStr}; @@ -22,7 +23,7 @@ use Tags; #[derive(Debug)] pub struct Thread<'q, 'd:'q>( pub(crate) *mut ffi::notmuch_thread_t, - marker::PhantomData<&'q mut Query<'d>>, + marker::PhantomData<&'q Query<'d>>, ); impl<'q, 'd> NewFromPtr<*mut ffi::notmuch_thread_t> for Thread<'q, 'd> { @@ -115,4 +116,5 @@ impl<'q, 'd> ops::Drop for Thread<'q, 'd> { } } -unsafe impl<'q, 'd> Send for Thread<'q, 'd>{} +unsafe impl<'q, 'd> Send for Thread<'q, 'd> {} +// unsafe impl<'q, 'd> Sync for Thread<'q, 'd> {} diff --git a/src/threads.rs b/src/threads.rs index 2d6d7c4..596874a 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -15,7 +15,7 @@ use ffi; #[derive(Debug)] pub struct Threads<'q, 'd:'q>( *mut ffi::notmuch_threads_t, - marker::PhantomData<&'q mut Query<'d>>, + marker::PhantomData<&'q Query<'d>>, ); impl<'q, 'd> NewFromPtr<*mut ffi::notmuch_threads_t> for Threads<'q, 'd> { @@ -55,4 +55,5 @@ impl<'q, 'd> iter::Iterator for Threads<'q, 'd> { } } -unsafe impl<'q, 'd> Send for Threads<'q, 'd>{} +unsafe impl<'q, 'd> Send for Threads<'q, 'd> {} +// unsafe impl<'q, 'd> Sync for Threads<'q, 'd> {} -- cgit v1.2.1 From 096a1e7443e2dcd301f08645074af19a878b3905 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 14 Apr 2018 11:48:34 +0200 Subject: add license --- LICENSE.md | 675 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 675 insertions(+) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..2fb2e74 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,675 @@ +### GNU GENERAL PUBLIC LICENSE + +Version 3, 29 June 2007 + +Copyright (C) 2007 Free Software Foundation, Inc. + + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +### Preamble + +The GNU General Public License is a free, copyleft license for +software and other kinds of works. + +The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom +to share and change all versions of a program--to make sure it remains +free software for all its users. We, the Free Software Foundation, use +the GNU General Public License for most of our software; it applies +also to any other work released this way by its authors. You can apply +it to your programs, too. + +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + +To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you +have certain responsibilities if you distribute copies of the +software, or if you modify it: responsibilities to respect the freedom +of others. + +For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + +Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + +For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + +Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the +manufacturer can do so. This is fundamentally incompatible with the +aim of protecting users' freedom to change the software. The +systematic pattern of such abuse occurs in the area of products for +individuals to use, which is precisely where it is most unacceptable. +Therefore, we have designed this version of the GPL to prohibit the +practice for those products. If such problems arise substantially in +other domains, we stand ready to extend this provision to those +domains in future versions of the GPL, as needed to protect the +freedom of users. + +Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish +to avoid the special danger that patents applied to a free program +could make it effectively proprietary. To prevent this, the GPL +assures that patents cannot be used to render the program non-free. + +The precise terms and conditions for copying, distribution and +modification follow. + +### TERMS AND CONDITIONS + +#### 0. Definitions. + +"This License" refers to version 3 of the GNU General Public License. + +"Copyright" also means copyright-like laws that apply to other kinds +of works, such as semiconductor masks. + +"The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + +To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of +an exact copy. The resulting work is called a "modified version" of +the earlier work or a work "based on" the earlier work. + +A "covered work" means either the unmodified Program or a work based +on the Program. + +To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + +To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user +through a computer network, with no transfer of a copy, is not +conveying. + +An interactive user interface displays "Appropriate Legal Notices" to +the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + +#### 1. Source Code. + +The "source code" for a work means the preferred form of the work for +making modifications to it. "Object code" means any non-source form of +a work. + +A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + +The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + +The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + +The Corresponding Source need not include anything that users can +regenerate automatically from other parts of the Corresponding Source. + +The Corresponding Source for a work in source code form is that same +work. + +#### 2. Basic Permissions. + +All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not convey, +without conditions so long as your license otherwise remains in force. +You may convey covered works to others for the sole purpose of having +them make modifications exclusively for you, or provide you with +facilities for running those works, provided that you comply with the +terms of this License in conveying all material for which you do not +control copyright. Those thus making or running the covered works for +you must do so exclusively on your behalf, under your direction and +control, on terms that prohibit them from making any copies of your +copyrighted material outside their relationship with you. + +Conveying under any other circumstances is permitted solely under the +conditions stated below. Sublicensing is not allowed; section 10 makes +it unnecessary. + +#### 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + +No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + +When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such +circumvention is effected by exercising rights under this License with +respect to the covered work, and you disclaim any intention to limit +operation or modification of the work as a means of enforcing, against +the work's users, your or third parties' legal rights to forbid +circumvention of technological measures. + +#### 4. Conveying Verbatim Copies. + +You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + +You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + +#### 5. Conveying Modified Source Versions. + +You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these +conditions: + +- a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. +- b) The work must carry prominent notices stating that it is + released under this License and any conditions added under + section 7. This requirement modifies the requirement in section 4 + to "keep intact all notices". +- c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. +- d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + +A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + +#### 6. Conveying Non-Source Forms. + +You may convey a covered work in object code form under the terms of +sections 4 and 5, provided that you also convey the machine-readable +Corresponding Source under the terms of this License, in one of these +ways: + +- a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. +- b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the Corresponding + Source from a network server at no charge. +- c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. +- d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. +- e) Convey the object code using peer-to-peer transmission, + provided you inform other peers where the object code and + Corresponding Source of the work are being offered to the general + public at no charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + +A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, +family, or household purposes, or (2) anything designed or sold for +incorporation into a dwelling. In determining whether a product is a +consumer product, doubtful cases shall be resolved in favor of +coverage. For a particular product received by a particular user, +"normally used" refers to a typical or common use of that class of +product, regardless of the status of the particular user or of the way +in which the particular user actually uses, or expects or is expected +to use, the product. A product is a consumer product regardless of +whether the product has substantial commercial, industrial or +non-consumer uses, unless such uses represent the only significant +mode of use of the product. + +"Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to +install and execute modified versions of a covered work in that User +Product from a modified version of its Corresponding Source. The +information must suffice to ensure that the continued functioning of +the modified object code is in no case prevented or interfered with +solely because modification has been made. + +If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + +The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or +updates for a work that has been modified or installed by the +recipient, or for the User Product in which it has been modified or +installed. Access to a network may be denied when the modification +itself materially and adversely affects the operation of the network +or violates the rules and protocols for communication across the +network. + +Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + +#### 7. Additional Terms. + +"Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders +of that material) supplement the terms of this License with terms: + +- a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or +- b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or +- c) Prohibiting misrepresentation of the origin of that material, + or requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or +- d) Limiting the use for publicity purposes of names of licensors + or authors of the material; or +- e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or +- f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions + of it) with contractual assumptions of liability to the recipient, + for any liability that these contractual assumptions directly + impose on those licensors and authors. + +All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + +If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; the +above requirements apply either way. + +#### 8. Termination. + +You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + +However, if you cease all violation of this License, then your license +from a particular copyright holder is reinstated (a) provisionally, +unless and until the copyright holder explicitly and finally +terminates your license, and (b) permanently, if the copyright holder +fails to notify you of the violation by some reasonable means prior to +60 days after the cessation. + +Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + +#### 9. Acceptance Not Required for Having Copies. + +You are not required to accept this License in order to receive or run +a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + +#### 10. Automatic Licensing of Downstream Recipients. + +Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + +An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + +#### 11. Patents. + +A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + +A contributor's "essential patent claims" are all patent claims owned +or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + +In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + +If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + +A patent license is "discriminatory" if it does not include within the +scope of its coverage, prohibits the exercise of, or is conditioned on +the non-exercise of one or more of the rights that are specifically +granted under this License. You may not convey a covered work if you +are a party to an arrangement with a third party that is in the +business of distributing software, under which you make payment to the +third party based on the extent of your activity of conveying the +work, and under which the third party grants, to any of the parties +who would receive the covered work from you, a discriminatory patent +license (a) in connection with copies of the covered work conveyed by +you (or copies made from those copies), or (b) primarily for and in +connection with specific products or compilations that contain the +covered work, unless you entered into that arrangement, or that patent +license was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + +#### 12. No Surrender of Others' Freedom. + +If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under +this License and any other pertinent obligations, then as a +consequence you may not convey it at all. For example, if you agree to +terms that obligate you to collect a royalty for further conveying +from those to whom you convey the Program, the only way you could +satisfy both those terms and this License would be to refrain entirely +from conveying the Program. + +#### 13. Use with the GNU Affero General Public License. + +Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + +#### 14. Revised Versions of this License. + +The Free Software Foundation may publish revised and/or new versions +of the GNU General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in +detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies that a certain numbered version of the GNU General Public +License "or any later version" applies to it, you have the option of +following the terms and conditions either of that numbered version or +of any later version published by the Free Software Foundation. If the +Program does not specify a version number of the GNU General Public +License, you may choose any version ever published by the Free +Software Foundation. + +If the Program specifies that a proxy can decide which future versions +of the GNU General Public License can be used, that proxy's public +statement of acceptance of a version permanently authorizes you to +choose that version for the Program. + +Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + +#### 15. Disclaimer of Warranty. + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT +WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND +PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR +CORRECTION. + +#### 16. Limitation of Liability. + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR +CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT +NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR +LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM +TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER +PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +#### 17. Interpretation of Sections 15 and 16. + +If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + +END OF TERMS AND CONDITIONS + +### How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these +terms. + +To do so, attach the following notices to the program. It is safest to +attach them to the start of each source file to most effectively state +the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper +mail. + +If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands \`show w' and \`show c' should show the +appropriate parts of the General Public License. Of course, your +program's commands might be different; for a GUI interface, you would +use an "about box". + +You should also get your employer (if you work as a programmer) or +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. For more information on this, and how to apply and follow +the GNU GPL, see . + +The GNU General Public License does not permit incorporating your +program into proprietary programs. If your program is a subroutine +library, you may consider it more useful to permit linking proprietary +applications with the library. If this is what you want to do, use the +GNU Lesser General Public License instead of this License. But first, +please read . -- cgit v1.2.1 From 2601c34228f88b572642149a8fef64a6a3e3570c Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 14 Apr 2018 11:49:00 +0200 Subject: make everything Send+Sync --- src/database.rs | 2 +- src/directory.rs | 2 +- src/filenames.rs | 2 +- src/message.rs | 2 +- src/messages.rs | 2 +- src/query.rs | 2 +- src/tags.rs | 2 +- src/thread.rs | 2 +- src/threads.rs | 4 ++-- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/database.rs b/src/database.rs index 6dcbd0d..70e7ebb 100644 --- a/src/database.rs +++ b/src/database.rs @@ -221,4 +221,4 @@ impl ops::Drop for Database { } unsafe impl Send for Database {} -// unsafe impl Sync for Database {} +unsafe impl Sync for Database {} diff --git a/src/directory.rs b/src/directory.rs index d01f21e..d3097f2 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -41,4 +41,4 @@ impl<'d> ops::Drop for Directory<'d> { } unsafe impl<'d> Send for Directory<'d>{} -//unsafe impl<'d> Sync for Directory<'d>{} +unsafe impl<'d> Sync for Directory<'d>{} diff --git a/src/filenames.rs b/src/filenames.rs index 30367a9..67c03a5 100644 --- a/src/filenames.rs +++ b/src/filenames.rs @@ -64,4 +64,4 @@ impl<'d> iter::Iterator for Filenames<'d> { unsafe impl<'d> Send for Filenames<'d>{} -// unsafe impl<'d> Sync for Filenames<'d>{} +unsafe impl<'d> Sync for Filenames<'d>{} diff --git a/src/message.rs b/src/message.rs index 409c101..05effd2 100644 --- a/src/message.rs +++ b/src/message.rs @@ -84,4 +84,4 @@ impl<'q, 'd> ops::Drop for Message<'q, 'd> { } unsafe impl<'q, 'd> Send for Message<'q, 'd>{} -// unsafe impl<'q, 'd> Sync for Message<'q, 'd>{} +unsafe impl<'q, 'd> Sync for Message<'q, 'd>{} diff --git a/src/messages.rs b/src/messages.rs index 925b027..3ef39e9 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -70,4 +70,4 @@ impl<'q, 'd> iter::Iterator for Messages<'q, 'd> { } unsafe impl<'q, 'd> Send for Messages<'q, 'd>{} -// unsafe impl<'q, 'd> Sync for Messages<'q, 'd>{} +unsafe impl<'q, 'd> Sync for Messages<'q, 'd>{} diff --git a/src/query.rs b/src/query.rs index 660c86c..b84d321 100644 --- a/src/query.rs +++ b/src/query.rs @@ -116,4 +116,4 @@ impl<'d> ops::Drop for Query<'d> { } unsafe impl<'d> Send for Query<'d> {} -// unsafe impl<'d> Sync for Query<'d> {} +unsafe impl<'d> Sync for Query<'d> {} diff --git a/src/tags.rs b/src/tags.rs index 37cc33d..cc5b05f 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -61,4 +61,4 @@ impl<'d> iter::Iterator for Tags<'d> { } unsafe impl<'d> Send for Tags<'d>{} -// unsafe impl<'d> Sync for Tags<'d>{} +unsafe impl<'d> Sync for Tags<'d>{} diff --git a/src/thread.rs b/src/thread.rs index ef6023d..ee19c7e 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -117,4 +117,4 @@ impl<'q, 'd> ops::Drop for Thread<'q, 'd> { } unsafe impl<'q, 'd> Send for Thread<'q, 'd> {} -// unsafe impl<'q, 'd> Sync for Thread<'q, 'd> {} +unsafe impl<'q, 'd> Sync for Thread<'q, 'd> {} diff --git a/src/threads.rs b/src/threads.rs index 596874a..8ec7c95 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -35,7 +35,7 @@ impl<'q, 'd> ops::Drop for Threads<'q, 'd> { impl<'q, 'd> iter::Iterator for Threads<'q, 'd> { type Item = Thread<'q, 'd>; - fn next(&mut self) -> Option { + fn next(self: &mut Self) -> Option { let valid = unsafe { ffi::notmuch_threads_valid(self.0) @@ -56,4 +56,4 @@ impl<'q, 'd> iter::Iterator for Threads<'q, 'd> { } unsafe impl<'q, 'd> Send for Threads<'q, 'd> {} -// unsafe impl<'q, 'd> Sync for Threads<'q, 'd> {} +unsafe impl<'q, 'd> Sync for Threads<'q, 'd> {} -- cgit v1.2.1 From 6f343b3105eceef728d94ec120bd3320bce27225 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 14 Apr 2018 12:03:16 +0200 Subject: add readme and test --- Cargo.toml | 7 +++++- README.md | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/main.rs | 20 ++++++++++++++++ 3 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 README.md create mode 100644 tests/main.rs diff --git a/Cargo.toml b/Cargo.toml index cdb58ea..4d107a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,11 +2,16 @@ name = "notmuch" version = "0.0.10" authors = ["Dirk Van Haerenborgh "] - homepage = "https://github.com/vhdirk/notmuch-rs" repository = "https://github.com/vhdirk/notmuch-rs" description = "Rust interface and bindings for notmuch" license = "GPL-3.0+" +readme = "README.md" [dependencies] libc = "0.2" + + +[[test]] +name = "main" +harness = false diff --git a/README.md b/README.md new file mode 100644 index 0000000..f4de423 --- /dev/null +++ b/README.md @@ -0,0 +1,74 @@ +notmuch-rs +========== + +This is not much more than a wrapper for the [notmuch](https://notmuchmail.org/) C api. + +## Building +**notmuch-rs** expects libnotmuch development files to be installed on your system. + + +## Using + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +notmuch = "*" +``` + +and this to your crate root: + +```rust +extern crate notmuch; +``` + +## Example + +```rust +extern crate notmuch; + +fn main() { + + let mut mail_path = std::env::home_dir().unwrap(); + mail_path.push(".mail"); + + let db = notmuch::Database::open(&mail_path.to_str().unwrap().to_string(), notmuch::DatabaseMode::ReadOnly).unwrap(); + 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 } + } + } +} + +``` + +## Concurrency + +Notmuch makes no claims regarding thread safety. It does not seem to use any +thread locals, but I did not spot any locks. So, as far as I am concerned, it is +not thread safe. +So why do all structs implement ```Send``` and ```Sync```? Well, it _is_ safe to +access pointers from different threads (as long as you know what you are doing :) ). +But, more importantly, all structs are strictly linked together with their +lifetime. The root of the tree is ```notmuch::Database```, which has a lifetime +that must outlive any related objects, for instance ```notmuch::Query```. The +```notmuch::Threads``` iterator that you can get from a ```notmuch::Query``` is +always outlived by the parent query. +This means that you can only use these structs accross thread bounds if you +figure out how to satisfy the lifetime requirements. Up until now, I haven't +been able to do that (though my knowledge of Rust is still rather basic). +So, concurrency seems currently limited to scoped threads. + +## Acknowledgements + +notmuch-rs started out from the following projects: + - https://github.com/Stebalien/notmuch-sys/blob/master/src/lib.rs + - https://github.com/cmhamill/rust-notmuch + +Any contributions are welcome! diff --git a/tests/main.rs b/tests/main.rs new file mode 100644 index 0000000..a6dd022 --- /dev/null +++ b/tests/main.rs @@ -0,0 +1,20 @@ +extern crate notmuch; + +fn main() { + + let mut mail_path = std::env::home_dir().unwrap(); + mail_path.push(".mail"); + + let db = notmuch::Database::open(&mail_path.to_str().unwrap().to_string(), notmuch::DatabaseMode::ReadOnly).unwrap(); + 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 } + } + } +} -- cgit v1.2.1 From 236b1c821cd58faf5ab980175b80d4da32e9ccbc Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 14 Apr 2018 12:03:40 +0200 Subject: bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4d107a2..bd3b279 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "notmuch" -version = "0.0.10" +version = "0.0.11" authors = ["Dirk Van Haerenborgh "] homepage = "https://github.com/vhdirk/notmuch-rs" repository = "https://github.com/vhdirk/notmuch-rs" -- cgit v1.2.1 From 80634a5adea2f45aff8bda691bcedb871d0a60d2 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 14 Apr 2018 12:13:41 +0200 Subject: experimental travis --- .travis.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..f25e24f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,14 @@ +language: rust +sudo: false +rust: + - 1.16.0 + - stable + - beta + - nightly + +matrix: + include: + - addons: + apt: + packages: + - notmuch -- cgit v1.2.1 From 518e131c6a796fd6eca4347c9b0ba34a118b80e8 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 14 Apr 2018 12:18:25 +0200 Subject: travis: fix dependencies --- .travis.yml | 2 +- README.md | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f25e24f..e982f87 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,4 +11,4 @@ matrix: - addons: apt: packages: - - notmuch + - libnotmuch-dev diff --git a/README.md b/README.md index f4de423..28ea256 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ notmuch-rs This is not much more than a wrapper for the [notmuch](https://notmuchmail.org/) C api. +[![Build Status](https://travis-ci.org/vhdirk/notmuch-rs.svg?branch=master)](https://travis-ci.org/vhdirk/notmuch-rs) + ## Building **notmuch-rs** expects libnotmuch development files to be installed on your system. -- cgit v1.2.1 From a45f084c5064da77b0b6afde3aae1e83c15e3efd Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 14 Apr 2018 12:25:24 +0200 Subject: travis: try again --- .travis.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index e982f87..de3b708 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,9 +6,6 @@ rust: - beta - nightly -matrix: - include: - - addons: - apt: - packages: - - libnotmuch-dev +before_install: + - sudo apt-get -qq update + - sudo apt-get install -y libnotmuch-dev -- cgit v1.2.1 From f4e2389d809e297db9684e7561278d78a5c09130 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 14 Apr 2018 12:32:05 +0200 Subject: fix unit test for travis --- README.md | 1 + tests/main.rs | 25 ++++++++++++++++--------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 28ea256..3f5886f 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ notmuch-rs This is not much more than a wrapper for the [notmuch](https://notmuchmail.org/) C api. [![Build Status](https://travis-ci.org/vhdirk/notmuch-rs.svg?branch=master)](https://travis-ci.org/vhdirk/notmuch-rs) +[![Crates.io](https://img.shields.io/crates/v/notmuch.svg)](https://crates.io/crates/notmuch) ## Building **notmuch-rs** expects libnotmuch development files to be installed on your system. diff --git a/tests/main.rs b/tests/main.rs index a6dd022..b92bcf7 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -5,16 +5,23 @@ fn main() { let mut mail_path = std::env::home_dir().unwrap(); mail_path.push(".mail"); - let db = notmuch::Database::open(&mail_path.to_str().unwrap().to_string(), notmuch::DatabaseMode::ReadOnly).unwrap(); - let query = db.create_query(&"".to_string()).unwrap(); - let mut threads = query.search_threads().unwrap(); + match notmuch::Database::open(&mail_path.to_str().unwrap().to_string(), notmuch::DatabaseMode::ReadOnly){ + Ok(db) => { + 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 } + loop { + match threads.next() { + Some(thread) => { + println!("thread {:?} {:?}", thread.subject(), thread.authors()); + }, + None => { break } + } + } + + }, + Err(err) =>{ + println!("Got error while trying to open db: {:?}", err); } } } -- cgit v1.2.1 From e9296075b60ae3e1ada16b512f80b257fa71310f Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 14 Apr 2018 12:34:28 +0200 Subject: travis: only build on stable, beta and nightly --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index de3b708..3388276 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: rust sudo: false rust: - - 1.16.0 - stable - beta - nightly -- cgit v1.2.1 From 3bdaf395f7f396b9ad6b1744417c955c13480f26 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 14 Apr 2018 12:43:27 +0200 Subject: bump version because of change in unit test --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index bd3b279..8a8c63f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "notmuch" -version = "0.0.11" +version = "0.0.12" authors = ["Dirk Van Haerenborgh "] homepage = "https://github.com/vhdirk/notmuch-rs" repository = "https://github.com/vhdirk/notmuch-rs" -- cgit v1.2.1 From e2ede208b4e859a36434f9eec9d9d9cd02bd63ea Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 14 Apr 2018 12:51:02 +0200 Subject: add badges --- Cargo.toml | 3 +++ README.md | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 8a8c63f..70a82e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,9 @@ description = "Rust interface and bindings for notmuch" license = "GPL-3.0+" readme = "README.md" +[badges] +travis-ci = { repository = "vhdirk/notmuch-rs" } + [dependencies] libc = "0.2" diff --git a/README.md b/README.md index 3f5886f..a636d6c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,9 @@ notmuch-rs This is not much more than a wrapper for the [notmuch](https://notmuchmail.org/) C api. [![Build Status](https://travis-ci.org/vhdirk/notmuch-rs.svg?branch=master)](https://travis-ci.org/vhdirk/notmuch-rs) -[![Crates.io](https://img.shields.io/crates/v/notmuch.svg)](https://crates.io/crates/notmuch) +[![Crate version](https://img.shields.io/crates/v/notmuch.svg)](https://crates.io/crates/notmuch) +[![Download statistics](https://img.shields.io/crates/d/notmuch.svg)](https://crates.io/crates/notmuch) +[![License](https://img.shields.io/crates/l/notmuch.svg)](https://crates.io/crates/notmuch) ## Building **notmuch-rs** expects libnotmuch development files to be installed on your system. -- cgit v1.2.1 From caf1b053912d5fe5a893eb545bea20bfc4619d5d Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 14 Apr 2018 17:40:00 +0200 Subject: travis: use apt addon --- .travis.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3388276..67e3a01 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ rust: - beta - nightly -before_install: - - sudo apt-get -qq update - - sudo apt-get install -y libnotmuch-dev +addons: + apt: + packages: + - libnotmuch-dev -- cgit v1.2.1 From 1be0cc6ab7920208b3d6986dbb6076846d758c17 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 17 Apr 2018 21:16:13 +0200 Subject: make clippy happy --- Cargo.toml | 1 + src/database.rs | 15 ++++++--------- src/ffi.rs | 5 +---- src/lib.rs | 3 +++ src/message.rs | 7 +------ src/messages.rs | 2 -- src/query.rs | 7 +++---- src/tags.rs | 1 - src/thread.rs | 12 ++---------- 9 files changed, 17 insertions(+), 36 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 70a82e1..d846862 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ travis-ci = { repository = "vhdirk/notmuch-rs" } [dependencies] libc = "0.2" +clippy = { version = "0.0.193", optional = true } [[test]] diff --git a/src/database.rs b/src/database.rs index 70e7ebb..2b95a7a 100644 --- a/src/database.rs +++ b/src/database.rs @@ -181,26 +181,23 @@ impl Database { ) }.as_result()); - match dir.is_null() { - true => Ok(None), - false => Ok(Some(Directory::new(dir))), - } + if dir.is_null() { Ok(None) } else { Ok(Some(Directory::new(dir))) } } - pub fn create_query<'d>(&'d self, query_string: &String) -> Result> { - let query_str = CString::new(query_string.as_str()).unwrap(); + pub fn create_query<'d>(&'d self, query_string: &str) -> Result> { + let query_str = CString::new(query_string).unwrap(); println!("query {:?}", query_str); - let mut query = unsafe { + let query = unsafe { ffi::notmuch_query_create(self.0, query_str.as_ptr()) }; Ok(Query::new(query)) } - pub fn all_tags<'d>(&'d self) -> Result> { + pub fn all_tags<'d>(&self) -> Result> { - let mut tags = unsafe { + let tags = unsafe { ffi::notmuch_database_get_all_tags(self.0) }; diff --git a/src/ffi.rs b/src/ffi.rs index 63c83ba..3c281fa 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -59,10 +59,7 @@ impl notmuch_status_t { } pub fn as_result(self) -> Result<(), Self> { - match self.is_ok() { - true => Ok(()), - false => Err(self), - } + if self.is_ok() { Ok(()) } else { Err(self) } } } diff --git a/src/lib.rs b/src/lib.rs index 0c807f4..db3c276 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,6 @@ +#![cfg_attr(feature="clippy", feature(plugin))] +#![cfg_attr(feature="clippy", plugin(clippy))] + #[macro_use] mod macros; diff --git a/src/message.rs b/src/message.rs index 05effd2..60011d1 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,15 +1,10 @@ -use std; use std::{ ops, - marker, - str, - result + marker }; use std::path::PathBuf; -use error::Result; - use ffi; use utils::{ NewFromPtr, diff --git a/src/messages.rs b/src/messages.rs index 3ef39e9..1d3b3c2 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -4,8 +4,6 @@ use std::{ iter }; -use error::Result; - use ffi; use utils::{ NewFromPtr, diff --git a/src/query.rs b/src/query.rs index b84d321..125e63d 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,4 +1,3 @@ -use std; use std::{ ops, marker, @@ -24,7 +23,7 @@ pub struct Query<'d>( impl<'d> Query<'d> { - pub fn create(db: &'d Database, query_string: &String) -> Result { + pub fn create(db: &'d Database, query_string: &str) -> Result { db.create_query(query_string) } @@ -72,7 +71,7 @@ impl<'d> Query<'d> { ) }.as_result()); - return Ok(cnt); + Ok(cnt) } pub fn search_threads<'q>(self: &'d Self) -> Result> @@ -96,7 +95,7 @@ impl<'d> Query<'d> { ) }.as_result()); - return Ok(cnt); + Ok(cnt) } } diff --git a/src/tags.rs b/src/tags.rs index cc5b05f..02ee767 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -5,7 +5,6 @@ use std::{ }; use std::ffi::{ - CString, CStr }; diff --git a/src/thread.rs b/src/thread.rs index ee19c7e..47166d4 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -1,15 +1,7 @@ -use std; use std::{ ops, - marker, - str, - result + marker }; -use std::sync::atomic::AtomicPtr; - -use std::ffi::{CString, CStr}; - -use error::Result; use ffi; use utils::{ @@ -89,7 +81,7 @@ impl<'q, 'd> Thread<'q, 'd>{ ffi::notmuch_thread_get_authors(self.0) }; - 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. -- cgit v1.2.1 From f021813ed443b4ef7224d1934881abecf53977a7 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 19 Apr 2018 10:21:14 +0200 Subject: cleanup & export db revision uuid --- README.md | 4 +--- src/database.rs | 58 ++++++++++++++++++++++++++++---------------------------- src/directory.rs | 16 ++++++---------- src/ffi.rs | 2 +- src/filenames.rs | 40 +++++++++++++++++++------------------- src/lib.rs | 1 + src/message.rs | 17 +++++++---------- src/messages.rs | 24 ++++++++++++++--------- src/query.rs | 19 ++++++++----------- src/tags.rs | 23 +++++++++------------- src/thread.rs | 16 +++++++--------- src/threads.rs | 21 ++++++++------------ src/utils.rs | 1 - tests/main.rs | 3 +++ 14 files changed, 115 insertions(+), 130 deletions(-) diff --git a/README.md b/README.md index a636d6c..4e1d86b 100644 --- a/README.md +++ b/README.md @@ -66,9 +66,7 @@ that must outlive any related objects, for instance ```notmuch::Query```. The ```notmuch::Threads``` iterator that you can get from a ```notmuch::Query``` is always outlived by the parent query. This means that you can only use these structs accross thread bounds if you -figure out how to satisfy the lifetime requirements. Up until now, I haven't -been able to do that (though my knowledge of Rust is still rather basic). -So, concurrency seems currently limited to scoped threads. +figure out how to satisfy the lifetime requirements. ## Acknowledgements diff --git a/src/database.rs b/src/database.rs index 2b95a7a..f1d743b 100644 --- a/src/database.rs +++ b/src/database.rs @@ -1,9 +1,7 @@ -use std::{ - ops, - path, - ptr, -}; - +use std::ops::Drop; +use std::iter::Iterator; +use std::ptr; +use std::path::Path; use std::ffi::CString; use libc; @@ -14,9 +12,9 @@ use utils::{ ToStr, }; -use directory::Directory; -use query::Query; -use tags::Tags; +use Directory; +use Query; +use Tags; use ffi; @@ -26,14 +24,17 @@ pub use ffi::DatabaseMode; #[derive(Copy, Clone, Debug)] pub struct Version(libc::c_uint); -#[derive(Copy, Clone, Debug)] -pub struct Revision(libc::c_ulong); +#[derive(Clone, Debug)] +pub struct Revision{ + revision: libc::c_ulong, + uuid: String +} #[derive(Debug)] pub struct Database(*mut ffi::notmuch_database_t); impl Database { - pub fn create>(path: &P) -> Result { + pub fn create>(path: &P) -> Result { let path_str = CString::new(path.as_ref().to_str().unwrap()).unwrap(); let mut db = ptr::null_mut(); @@ -44,7 +45,7 @@ impl Database { Ok(Database(db)) } - pub fn open>(path: &P, mode: DatabaseMode) -> Result { + pub fn open>(path: &P, mode: DatabaseMode) -> Result { let path_str = CString::new(path.as_ref().to_str().unwrap()).unwrap(); let mut db = ptr::null_mut(); @@ -67,20 +68,20 @@ impl Database { Ok(()) } - pub fn compact, F: FnMut(&str)>( + pub fn compact, F: FnMut(&str)>( path: &P, backup_path: Option<&P>, ) -> Result<()> { let status: Option = None; Database::_compact(path, backup_path, status) } - pub fn compact_with_status, F: FnMut(&str)>( + pub fn compact_with_status, F: FnMut(&str)>( path: &P, backup_path: Option<&P>, status: F, ) -> Result<()> { Database::_compact(path, backup_path, Some(status)) } - fn _compact, F: FnMut(&str)>( + fn _compact, F: FnMut(&str)>( path: &P, backup_path: Option<&P>, status: Option, ) -> Result<()> { @@ -112,8 +113,8 @@ impl Database { Ok(()) } - pub fn path(&self) -> &path::Path { - path::Path::new(unsafe { + pub fn path(&self) -> &Path { + Path::new(unsafe { ffi::notmuch_database_get_path(self.0) }.to_str().unwrap()) } @@ -125,10 +126,14 @@ impl Database { } pub fn revision(&self) -> Revision { - let uuid = ptr::null_mut(); - Revision(unsafe { - ffi::notmuch_database_get_revision(self.0, uuid) - }) + let uuid_p: *mut libc::c_char = ptr::null_mut(); + let revision = unsafe { + ffi::notmuch_database_get_revision(self.0, (&uuid_p) as *const _ as *const *mut libc::c_char) + }; + + let uuid = unsafe { CString::from_raw(uuid_p) }; + + Revision{revision, uuid: uuid.to_str().unwrap().to_string()} } pub fn needs_upgrade(&self) -> bool { @@ -171,7 +176,7 @@ impl Database { Ok(()) } - pub fn directory<'d, P: AsRef>(&'d self, path: &P) -> Result>> { + pub fn directory<'d, P: AsRef>(&'d self, path: &P) -> Result>> { let path_str = CString::new(path.as_ref().to_str().unwrap()).unwrap(); let mut dir = ptr::null_mut(); @@ -186,7 +191,6 @@ impl Database { pub fn create_query<'d>(&'d self, query_string: &str) -> Result> { let query_str = CString::new(query_string).unwrap(); - println!("query {:?}", query_str); let query = unsafe { ffi::notmuch_query_create(self.0, query_str.as_ptr()) @@ -203,13 +207,9 @@ impl Database { Ok(Tags::new(tags)) } - - - - } -impl ops::Drop for Database { +impl Drop for Database { fn drop(&mut self) { unsafe { ffi::notmuch_database_destroy(self.0) diff --git a/src/directory.rs b/src/directory.rs index d3097f2..b0bb415 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -1,11 +1,7 @@ -use std::{ - ops, - marker, -}; +use std::ops::Drop; +use std::marker::PhantomData; -use utils::{ - NewFromPtr, -}; +use utils::NewFromPtr; use Database; use Filenames; @@ -15,7 +11,7 @@ use ffi; #[derive(Debug)] pub struct Directory<'d>( *mut ffi::notmuch_directory_t, - marker::PhantomData<&'d Database>, + PhantomData<&'d Database>, ); impl<'d> Directory<'d>{ @@ -28,11 +24,11 @@ impl<'d> Directory<'d>{ impl<'d> NewFromPtr<*mut ffi::notmuch_directory_t> for Directory<'d> { fn new(ptr: *mut ffi::notmuch_directory_t) -> Directory<'d> { - Directory(ptr, marker::PhantomData) + Directory(ptr, PhantomData) } } -impl<'d> ops::Drop for Directory<'d> { +impl<'d> Drop for Directory<'d> { fn drop(self: &mut Self) { unsafe { ffi::notmuch_directory_destroy(self.0) diff --git a/src/ffi.rs b/src/ffi.rs index 3c281fa..5091b43 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -399,7 +399,7 @@ extern { /// this database. Two revision numbers are only comparable if they /// have the same database UUID. pub fn notmuch_database_get_revision(notmuch: *mut notmuch_database_t, - uuid: *mut *const c_char) + uuid: *const *mut c_char) -> c_ulong; /// Retrieve a directory object from the database for 'path'. diff --git a/src/filenames.rs b/src/filenames.rs index 67c03a5..b698b78 100644 --- a/src/filenames.rs +++ b/src/filenames.rs @@ -1,45 +1,45 @@ -use std::{ - ops, - marker, - iter -}; - -use std::path::{ - PathBuf -}; - -use std::ffi::{ - CStr -}; +use std::ops::Drop; +use std::iter::Iterator; +use std::marker::PhantomData; +use std::path::PathBuf; +use std::ffi::CStr; use utils::{ NewFromPtr, }; -use database; +use Database; +use Directory; +use Message; use ffi; #[derive(Debug)] pub struct Filenames<'d>( *mut ffi::notmuch_filenames_t, - marker::PhantomData<&'d database::Database>, + PhantomData<&'d Database>, ); impl<'d> NewFromPtr<*mut ffi::notmuch_filenames_t> for Filenames<'d> { fn new(ptr: *mut ffi::notmuch_filenames_t) -> Filenames<'d> { - Filenames(ptr, marker::PhantomData) + Filenames(ptr, PhantomData) } } -impl<'d> ops::Drop for Filenames<'d> { +impl<'d> Drop for Filenames<'d> { fn drop(self: &mut Self) { - unsafe { - ffi::notmuch_filenames_destroy(self.0) + let valid = unsafe { + ffi::notmuch_filenames_valid(self.0) }; + + if valid != 0 { + unsafe { + ffi::notmuch_filenames_destroy(self.0) + }; + } } } -impl<'d> iter::Iterator for Filenames<'d> { +impl<'d> Iterator for Filenames<'d> { type Item = PathBuf; fn next(self: &mut Self) -> Option { diff --git a/src/lib.rs b/src/lib.rs index db3c276..8120bd0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,6 +22,7 @@ mod filenames; pub use error::Error; pub use database::Database; +pub use directory::Directory; pub use query::Query; pub use messages::Messages; pub use message::Message; diff --git a/src/message.rs b/src/message.rs index 60011d1..c3b100f 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,14 +1,11 @@ -use std::{ - ops, - marker -}; - +use std::ops::Drop; +use std::marker::PhantomData; use std::path::PathBuf; use ffi; use utils::{ - NewFromPtr, - ToStr + ToStr, + NewFromPtr }; use Query; use Messages; @@ -17,12 +14,12 @@ use Filenames; #[derive(Debug)] pub struct Message<'q, 'd:'q>( pub(crate) *mut ffi::notmuch_message_t, - marker::PhantomData<&'q Query<'d>>, + PhantomData<&'q Query<'d>>, ); impl<'q, 'd> NewFromPtr<*mut ffi::notmuch_message_t> for Message<'q, 'd> { fn new(ptr: *mut ffi::notmuch_message_t) -> Message<'q, 'd> { - Message(ptr, marker::PhantomData) + Message(ptr, PhantomData) } } @@ -70,7 +67,7 @@ impl<'q, 'd> Message<'q, 'd>{ } -impl<'q, 'd> ops::Drop for Message<'q, 'd> { +impl<'q, 'd> Drop for Message<'q, 'd> { fn drop(self: &mut Self) { unsafe { ffi::notmuch_message_destroy(self.0) diff --git a/src/messages.rs b/src/messages.rs index 1d3b3c2..139b9a8 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -1,8 +1,6 @@ -use std::{ - ops, - marker, - iter -}; +use std::ops::Drop; +use std::iter::Iterator; +use std::marker::PhantomData; use ffi; use utils::{ @@ -17,12 +15,12 @@ pub struct Messages<'q, 'd:'q>( // TODO: is this lifetime specifier correct? // query may outlive messages. pub(crate) *mut ffi::notmuch_messages_t, - marker::PhantomData<&'q Query<'d>>, + PhantomData<&'q Query<'d>>, ); impl<'q, 'd> NewFromPtr<*mut ffi::notmuch_messages_t> for Messages<'q, 'd> { fn new(ptr: *mut ffi::notmuch_messages_t) -> Messages<'q, 'd> { - Messages(ptr, marker::PhantomData) + Messages(ptr, PhantomData) } } @@ -36,15 +34,23 @@ impl<'q, 'd> Messages<'q, 'd>{ } -impl<'q, 'd> ops::Drop for Messages<'q, 'd> { +impl<'q, 'd> Drop for Messages<'q, 'd> { fn drop(self: &mut Self) { + let valid = unsafe { + ffi::notmuch_messages_valid(self.0) + }; + + if valid == 0{ + return; + } + unsafe { ffi::notmuch_messages_destroy(self.0) }; } } -impl<'q, 'd> iter::Iterator for Messages<'q, 'd> { +impl<'q, 'd> Iterator for Messages<'q, 'd> { type Item = Message<'q, 'd>; fn next(&mut self) -> Option { diff --git a/src/query.rs b/src/query.rs index 125e63d..e0c748e 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,15 +1,12 @@ -use std::{ - ops, - marker, - ptr, -}; +use std::ops::Drop; +use std::ptr; +use std::marker::PhantomData; use error::Result; use ffi; -use utils::{ - NewFromPtr, -}; +use utils::NewFromPtr; + use Database; use Messages; use Threads; @@ -18,7 +15,7 @@ use ffi::Sort; #[derive(Debug)] pub struct Query<'d>( pub(crate) *mut ffi::notmuch_query_t, - marker::PhantomData<&'d Database>, + PhantomData<&'d Database>, ); @@ -101,12 +98,12 @@ impl<'d> Query<'d> { impl<'d> NewFromPtr<*mut ffi::notmuch_query_t> for Query<'d> { fn new(ptr: *mut ffi::notmuch_query_t) -> Query<'d> { - Query(ptr, marker::PhantomData) + Query(ptr, PhantomData) } } -impl<'d> ops::Drop for Query<'d> { +impl<'d> Drop for Query<'d> { fn drop(&mut self) { unsafe { ffi::notmuch_query_destroy(self.0) diff --git a/src/tags.rs b/src/tags.rs index 02ee767..04c7cd5 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -1,33 +1,28 @@ -use std::{ - ops, - marker, - iter -}; - -use std::ffi::{ - CStr -}; +use std::ops::Drop; +use std::iter::Iterator; +use std::marker::PhantomData; +use std::ffi::CStr; use utils::{ NewFromPtr, }; -use database; +use Database; use ffi; #[derive(Debug)] pub struct Tags<'d>( *mut ffi::notmuch_tags_t, - marker::PhantomData<&'d database::Database>, + PhantomData<&'d Database>, ); impl<'d> NewFromPtr<*mut ffi::notmuch_tags_t> for Tags<'d> { fn new(ptr: *mut ffi::notmuch_tags_t) -> Tags<'d> { - Tags(ptr, marker::PhantomData) + Tags(ptr, PhantomData) } } -impl<'d> ops::Drop for Tags<'d> { +impl<'d> Drop for Tags<'d> { fn drop(&mut self) { unsafe { ffi::notmuch_tags_destroy(self.0) @@ -35,7 +30,7 @@ impl<'d> ops::Drop for Tags<'d> { } } -impl<'d> iter::Iterator for Tags<'d> { +impl<'d> Iterator for Tags<'d> { type Item = String; fn next(&mut self) -> Option { diff --git a/src/thread.rs b/src/thread.rs index 47166d4..dfe0a69 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -1,8 +1,5 @@ -use std::{ - ops, - marker -}; - +use std::ops::Drop; +use std::marker::PhantomData; use ffi; use utils::{ NewFromPtr, @@ -15,12 +12,12 @@ use Tags; #[derive(Debug)] pub struct Thread<'q, 'd:'q>( pub(crate) *mut ffi::notmuch_thread_t, - marker::PhantomData<&'q Query<'d>>, + PhantomData<&'q Query<'d>>, ); impl<'q, 'd> NewFromPtr<*mut ffi::notmuch_thread_t> for Thread<'q, 'd> { fn new(ptr: *mut ffi::notmuch_thread_t) -> Thread<'q, 'd> { - Thread(ptr, marker::PhantomData) + Thread(ptr, PhantomData) } } @@ -39,7 +36,8 @@ impl<'q, 'd> Thread<'q, 'd>{ ffi::notmuch_thread_get_total_messages(self.0) } } -#[cfg(feature = "0.26")] + + #[cfg(feature = "0.26")] pub fn total_files(self: &Self) -> i32{ unsafe { ffi::notmuch_thread_get_total_files(self.0) @@ -100,7 +98,7 @@ impl<'q, 'd> Thread<'q, 'd>{ } -impl<'q, 'd> ops::Drop for Thread<'q, 'd> { +impl<'q, 'd> Drop for Thread<'q, 'd> { fn drop(&mut self) { unsafe { ffi::notmuch_thread_destroy(self.0) diff --git a/src/threads.rs b/src/threads.rs index 8ec7c95..9a0117f 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -1,13 +1,8 @@ -use std::{ - ops, - marker, - iter -}; - -use utils::{ - NewFromPtr, -}; +use std::ops::Drop; +use std::iter::Iterator; +use std::marker::PhantomData; +use utils::NewFromPtr; use Query; use Thread; use ffi; @@ -15,16 +10,16 @@ use ffi; #[derive(Debug)] pub struct Threads<'q, 'd:'q>( *mut ffi::notmuch_threads_t, - marker::PhantomData<&'q Query<'d>>, + PhantomData<&'q Query<'d>>, ); impl<'q, 'd> NewFromPtr<*mut ffi::notmuch_threads_t> for Threads<'q, 'd> { fn new(ptr: *mut ffi::notmuch_threads_t) -> Threads<'q, 'd> { - Threads(ptr, marker::PhantomData) + Threads(ptr, PhantomData) } } -impl<'q, 'd> ops::Drop for Threads<'q, 'd> { +impl<'q, 'd> Drop for Threads<'q, 'd> { fn drop(&mut self) { unsafe { ffi::notmuch_threads_destroy(self.0) @@ -32,7 +27,7 @@ impl<'q, 'd> ops::Drop for Threads<'q, 'd> { } } -impl<'q, 'd> iter::Iterator for Threads<'q, 'd> { +impl<'q, 'd> Iterator for Threads<'q, 'd> { type Item = Thread<'q, 'd>; fn next(self: &mut Self) -> Option { diff --git a/src/utils.rs b/src/utils.rs index e1f691c..bdc8c4f 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -2,7 +2,6 @@ use std::{ ffi, str, }; - use libc; pub trait NewFromPtr { diff --git a/tests/main.rs b/tests/main.rs index b92bcf7..ca31225 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -7,6 +7,9 @@ fn main() { match notmuch::Database::open(&mail_path.to_str().unwrap().to_string(), notmuch::DatabaseMode::ReadOnly){ Ok(db) => { + let rev = db.revision(); + println!("db revision: {:?}", rev); + let query = db.create_query(&"".to_string()).unwrap(); let mut threads = query.search_threads().unwrap(); -- cgit v1.2.1 From ff66e24475e24eddfa6b86903405f3dbcf6bb456 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 19 Apr 2018 10:50:23 +0200 Subject: fix ffi for db revision --- src/database.rs | 10 +++++----- src/ffi.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/database.rs b/src/database.rs index f1d743b..3fc2c4e 100644 --- a/src/database.rs +++ b/src/database.rs @@ -2,7 +2,7 @@ use std::ops::Drop; use std::iter::Iterator; use std::ptr; use std::path::Path; -use std::ffi::CString; +use std::ffi::{CStr, CString}; use libc; @@ -126,14 +126,14 @@ impl Database { } pub fn revision(&self) -> Revision { - let uuid_p: *mut libc::c_char = ptr::null_mut(); + let uuid_p: *const libc::c_char = ptr::null(); let revision = unsafe { - ffi::notmuch_database_get_revision(self.0, (&uuid_p) as *const _ as *const *mut libc::c_char) + ffi::notmuch_database_get_revision(self.0, (&uuid_p) as *const _ as *mut *const libc::c_char) }; - let uuid = unsafe { CString::from_raw(uuid_p) }; + let uuid = unsafe { CStr::from_ptr(uuid_p) }; - Revision{revision, uuid: uuid.to_str().unwrap().to_string()} + Revision{revision, uuid: uuid.to_string_lossy().into_owned()} } pub fn needs_upgrade(&self) -> bool { diff --git a/src/ffi.rs b/src/ffi.rs index 5091b43..3c281fa 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -399,7 +399,7 @@ extern { /// this database. Two revision numbers are only comparable if they /// have the same database UUID. pub fn notmuch_database_get_revision(notmuch: *mut notmuch_database_t, - uuid: *const *mut c_char) + uuid: *mut *const c_char) -> c_ulong; /// Retrieve a directory object from the database for 'path'. -- cgit v1.2.1 From 26384a8ceeec69d109543defb341bf2f37a665d2 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 6 Oct 2018 10:09:48 +0200 Subject: remove unused imports --- src/database.rs | 1 - src/filenames.rs | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/database.rs b/src/database.rs index 3fc2c4e..5e70ada 100644 --- a/src/database.rs +++ b/src/database.rs @@ -1,5 +1,4 @@ use std::ops::Drop; -use std::iter::Iterator; use std::ptr; use std::path::Path; use std::ffi::{CStr, CString}; diff --git a/src/filenames.rs b/src/filenames.rs index b698b78..87a1495 100644 --- a/src/filenames.rs +++ b/src/filenames.rs @@ -9,8 +9,6 @@ use utils::{ }; use Database; -use Directory; -use Message; use ffi; #[derive(Debug)] -- cgit v1.2.1 From 35535148a9f073886a42d6d3a32f70fa4767d9fd Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 19 Apr 2018 11:17:17 +0200 Subject: db revision is only available from 0.21 onwards --- src/database.rs | 3 ++- src/filenames.rs | 5 +---- tests/main.rs | 1 + 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/database.rs b/src/database.rs index 5e70ada..34fe4fd 100644 --- a/src/database.rs +++ b/src/database.rs @@ -1,7 +1,7 @@ use std::ops::Drop; use std::ptr; use std::path::Path; -use std::ffi::{CStr, CString}; +use std::ffi::CString; use libc; @@ -124,6 +124,7 @@ impl Database { }) } + #[cfg(feature = "0.21")] pub fn revision(&self) -> Revision { let uuid_p: *const libc::c_char = ptr::null(); let revision = unsafe { diff --git a/src/filenames.rs b/src/filenames.rs index 87a1495..d9e5bd8 100644 --- a/src/filenames.rs +++ b/src/filenames.rs @@ -4,10 +4,7 @@ use std::marker::PhantomData; use std::path::PathBuf; use std::ffi::CStr; -use utils::{ - NewFromPtr, -}; - +use utils::NewFromPtr; use Database; use ffi; diff --git a/tests/main.rs b/tests/main.rs index ca31225..0407699 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -7,6 +7,7 @@ fn main() { match notmuch::Database::open(&mail_path.to_str().unwrap().to_string(), notmuch::DatabaseMode::ReadOnly){ Ok(db) => { + let rev = db.revision(); println!("db revision: {:?}", rev); -- cgit v1.2.1 From b49b9959b5375ed44c94f968bcebb07a7b8eac94 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 19 Apr 2018 11:29:00 +0200 Subject: prevent travis from building with features that are not available --- .travis.yml | 4 ++++ Cargo.toml | 5 +++++ src/database.rs | 4 ++-- src/message.rs | 5 ++--- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 67e3a01..ab21b0a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,3 +9,7 @@ addons: apt: packages: - libnotmuch-dev + +script: + - cargo build --no-default-features --verbose --all + - cargo test --no-default-features --verbose --all diff --git a/Cargo.toml b/Cargo.toml index d846862..401d553 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,11 @@ travis-ci = { repository = "vhdirk/notmuch-rs" } libc = "0.2" clippy = { version = "0.0.193", optional = true } +[features] +v0_21 = [] +v0_26 = ["v0_21"] +default = ["v0_26"] + [[test]] name = "main" diff --git a/src/database.rs b/src/database.rs index 34fe4fd..a597b2d 100644 --- a/src/database.rs +++ b/src/database.rs @@ -1,7 +1,7 @@ use std::ops::Drop; use std::ptr; use std::path::Path; -use std::ffi::CString; +use std::ffi::{CStr, CString}; use libc; @@ -124,7 +124,7 @@ impl Database { }) } - #[cfg(feature = "0.21")] + #[cfg(feature = "v0_21")] pub fn revision(&self) -> Revision { let uuid_p: *const libc::c_char = ptr::null(); let revision = unsafe { diff --git a/src/message.rs b/src/message.rs index c3b100f..d28257c 100644 --- a/src/message.rs +++ b/src/message.rs @@ -45,9 +45,8 @@ impl<'q, 'd> Message<'q, 'd>{ }) } - #[cfg(feature = "0.26")] - pub fn count_files(self: &Self) -> i32 - { + #[cfg(feature = "v0_26")] + pub fn count_files(self: &Self) -> i32{ unsafe { ffi::notmuch_message_count_files(self.0) } -- cgit v1.2.1 From e647569bfa492600955d5ad371086d4838063639 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 19 Apr 2018 13:57:49 +0200 Subject: make fields public --- src/database.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/database.rs b/src/database.rs index a597b2d..90f6574 100644 --- a/src/database.rs +++ b/src/database.rs @@ -25,8 +25,8 @@ pub struct Version(libc::c_uint); #[derive(Clone, Debug)] pub struct Revision{ - revision: libc::c_ulong, - uuid: String + pub revision: libc::c_ulong, + pub uuid: String } #[derive(Debug)] -- cgit v1.2.1 From 50b06bb85c4c1e58629dca4f1eb2cbc404244b7b Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 19 Apr 2018 11:29:31 +0200 Subject: bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 401d553..fee587e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "notmuch" -version = "0.0.12" +version = "0.2.0" authors = ["Dirk Van Haerenborgh "] homepage = "https://github.com/vhdirk/notmuch-rs" repository = "https://github.com/vhdirk/notmuch-rs" -- cgit v1.2.1 From b48156d31489e4ee18bae0da99484792d9568faf Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 6 Oct 2018 12:19:45 +0200 Subject: fix test for older notmuch version --- tests/main.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/main.rs b/tests/main.rs index 0407699..8c68ca3 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -8,9 +8,12 @@ fn main() { match notmuch::Database::open(&mail_path.to_str().unwrap().to_string(), notmuch::DatabaseMode::ReadOnly){ Ok(db) => { - let rev = db.revision(); - println!("db revision: {:?}", rev); - + #[cfg(feature = "v0_21")] + { + let rev = db.revision(); + println!("db revision: {:?}", rev); + } + let query = db.create_query(&"".to_string()).unwrap(); let mut threads = query.search_threads().unwrap(); -- cgit v1.2.1 From 6804f1d38c587638b9cd47ca37d8dbb7815cf954 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 9 Oct 2018 06:44:26 +0200 Subject: more logical lifetime param structuring --- Cargo.toml | 2 +- src/message.rs | 16 ++++++++-------- src/messages.rs | 18 +++++++++--------- src/thread.rs | 14 +++++++------- src/threads.rs | 16 ++++++++-------- 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fee587e..7711237 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "notmuch" -version = "0.2.0" +version = "0.2.1" authors = ["Dirk Van Haerenborgh "] homepage = "https://github.com/vhdirk/notmuch-rs" repository = "https://github.com/vhdirk/notmuch-rs" diff --git a/src/message.rs b/src/message.rs index d28257c..81d2417 100644 --- a/src/message.rs +++ b/src/message.rs @@ -12,18 +12,18 @@ use Messages; use Filenames; #[derive(Debug)] -pub struct Message<'q, 'd:'q>( +pub struct Message<'d:'q, 'q>( pub(crate) *mut ffi::notmuch_message_t, PhantomData<&'q Query<'d>>, ); -impl<'q, 'd> NewFromPtr<*mut ffi::notmuch_message_t> for Message<'q, 'd> { - fn new(ptr: *mut ffi::notmuch_message_t) -> Message<'q, 'd> { +impl<'d, 'q> NewFromPtr<*mut ffi::notmuch_message_t> for Message<'d, 'q> { + fn new(ptr: *mut ffi::notmuch_message_t) -> Message<'d, 'q> { Message(ptr, PhantomData) } } -impl<'q, 'd> Message<'q, 'd>{ +impl<'d, 'q> Message<'d, 'q>{ pub fn id(self: &Self) -> String{ let mid = unsafe { @@ -39,7 +39,7 @@ impl<'q, 'd> Message<'q, 'd>{ tid.to_str().unwrap().to_string() } - pub fn replies(self: &'q Self) -> Messages<'q, 'd>{ + pub fn replies(self: &'q Self) -> Messages<'d, 'q>{ Messages::new(unsafe { ffi::notmuch_message_get_replies(self.0) }) @@ -66,7 +66,7 @@ impl<'q, 'd> Message<'q, 'd>{ } -impl<'q, 'd> Drop for Message<'q, 'd> { +impl<'d, 'q> Drop for Message<'d, 'q> { fn drop(self: &mut Self) { unsafe { ffi::notmuch_message_destroy(self.0) @@ -74,5 +74,5 @@ impl<'q, 'd> Drop for Message<'q, 'd> { } } -unsafe impl<'q, 'd> Send for Message<'q, 'd>{} -unsafe impl<'q, 'd> Sync for Message<'q, 'd>{} +unsafe impl<'d, 'q> Send for Message<'d, 'q>{} +unsafe impl<'d, 'q> Sync for Message<'d, 'q>{} diff --git a/src/messages.rs b/src/messages.rs index 139b9a8..65e1248 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -11,20 +11,20 @@ use Message; use Tags; #[derive(Debug)] -pub struct Messages<'q, 'd:'q>( +pub struct Messages<'d:'q, 'q>( // TODO: is this lifetime specifier correct? // query may outlive messages. pub(crate) *mut ffi::notmuch_messages_t, PhantomData<&'q Query<'d>>, ); -impl<'q, 'd> NewFromPtr<*mut ffi::notmuch_messages_t> for Messages<'q, 'd> { - fn new(ptr: *mut ffi::notmuch_messages_t) -> Messages<'q, 'd> { +impl<'d, 'q> NewFromPtr<*mut ffi::notmuch_messages_t> for Messages<'d, 'q> { + fn new(ptr: *mut ffi::notmuch_messages_t) -> Messages<'d, 'q> { Messages(ptr, PhantomData) } } -impl<'q, 'd> Messages<'q, 'd>{ +impl<'d, 'q> Messages<'d, 'q>{ pub fn collect_tags(self: &'d Self) -> Tags<'d>{ Tags::new(unsafe { @@ -34,7 +34,7 @@ impl<'q, 'd> Messages<'q, 'd>{ } -impl<'q, 'd> Drop for Messages<'q, 'd> { +impl<'d, 'q> Drop for Messages<'d, 'q> { fn drop(self: &mut Self) { let valid = unsafe { ffi::notmuch_messages_valid(self.0) @@ -50,8 +50,8 @@ impl<'q, 'd> Drop for Messages<'q, 'd> { } } -impl<'q, 'd> Iterator for Messages<'q, 'd> { - type Item = Message<'q, 'd>; +impl<'d, 'q> Iterator for Messages<'d, 'q> { + type Item = Message<'d, 'q>; fn next(&mut self) -> Option { @@ -73,5 +73,5 @@ impl<'q, 'd> Iterator for Messages<'q, 'd> { } } -unsafe impl<'q, 'd> Send for Messages<'q, 'd>{} -unsafe impl<'q, 'd> Sync for Messages<'q, 'd>{} +unsafe impl<'d, 'q> Send for Messages<'d, 'q>{} +unsafe impl<'d, 'q> Sync for Messages<'d, 'q>{} diff --git a/src/thread.rs b/src/thread.rs index dfe0a69..4f98c26 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -10,18 +10,18 @@ use Messages; use Tags; #[derive(Debug)] -pub struct Thread<'q, 'd:'q>( +pub struct Thread<'d:'q, 'q>( pub(crate) *mut ffi::notmuch_thread_t, PhantomData<&'q Query<'d>>, ); -impl<'q, 'd> NewFromPtr<*mut ffi::notmuch_thread_t> for Thread<'q, 'd> { - fn new(ptr: *mut ffi::notmuch_thread_t) -> Thread<'q, 'd> { +impl<'d, 'q> NewFromPtr<*mut ffi::notmuch_thread_t> for Thread<'d, 'q> { + fn new(ptr: *mut ffi::notmuch_thread_t) -> Thread<'d, 'q> { Thread(ptr, PhantomData) } } -impl<'q, 'd> Thread<'q, 'd>{ +impl<'d, 'q> Thread<'d, 'q>{ pub fn id(self: &Self) -> String{ let tid = unsafe { @@ -98,7 +98,7 @@ impl<'q, 'd> Thread<'q, 'd>{ } -impl<'q, 'd> Drop for Thread<'q, 'd> { +impl<'d, 'q> Drop for Thread<'d, 'q> { fn drop(&mut self) { unsafe { ffi::notmuch_thread_destroy(self.0) @@ -106,5 +106,5 @@ impl<'q, 'd> Drop for Thread<'q, 'd> { } } -unsafe impl<'q, 'd> Send for Thread<'q, 'd> {} -unsafe impl<'q, 'd> Sync for Thread<'q, 'd> {} +unsafe impl<'d, 'q> Send for Thread<'d, 'q> {} +unsafe impl<'d, 'q> Sync for Thread<'d, 'q> {} diff --git a/src/threads.rs b/src/threads.rs index 9a0117f..20fc302 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -8,18 +8,18 @@ use Thread; use ffi; #[derive(Debug)] -pub struct Threads<'q, 'd:'q>( +pub struct Threads<'d:'q, 'q>( *mut ffi::notmuch_threads_t, PhantomData<&'q Query<'d>>, ); -impl<'q, 'd> NewFromPtr<*mut ffi::notmuch_threads_t> for Threads<'q, 'd> { - fn new(ptr: *mut ffi::notmuch_threads_t) -> Threads<'q, 'd> { +impl<'d, 'q> NewFromPtr<*mut ffi::notmuch_threads_t> for Threads<'d, 'q> { + fn new(ptr: *mut ffi::notmuch_threads_t) -> Threads<'d, 'q> { Threads(ptr, PhantomData) } } -impl<'q, 'd> Drop for Threads<'q, 'd> { +impl<'d, 'q> Drop for Threads<'d, 'q> { fn drop(&mut self) { unsafe { ffi::notmuch_threads_destroy(self.0) @@ -27,8 +27,8 @@ impl<'q, 'd> Drop for Threads<'q, 'd> { } } -impl<'q, 'd> Iterator for Threads<'q, 'd> { - type Item = Thread<'q, 'd>; +impl<'d, 'q> Iterator for Threads<'d, 'q> { + type Item = Thread<'d, 'q>; fn next(self: &mut Self) -> Option { @@ -50,5 +50,5 @@ impl<'q, 'd> Iterator for Threads<'q, 'd> { } } -unsafe impl<'q, 'd> Send for Threads<'q, 'd> {} -unsafe impl<'q, 'd> Sync for Threads<'q, 'd> {} +unsafe impl<'d, 'q> Send for Threads<'d, 'q> {} +unsafe impl<'d, 'q> Sync for Threads<'d, 'q> {} -- cgit v1.2.1 From 971e42d7ce8981ef145e02dc99bbcb6d0559eebf Mon Sep 17 00:00:00 2001 From: rhn Date: Sun, 29 Apr 2018 15:45:02 +0200 Subject: Add Message::header --- src/error.rs | 3 +++ src/message.rs | 15 +++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/error.rs b/src/error.rs index b1e5cdc..6434ee3 100644 --- a/src/error.rs +++ b/src/error.rs @@ -14,6 +14,7 @@ pub type Result = result::Result; pub enum Error { IoError(io::Error), NotmuchError(ffi::Status), + UnspecifiedError, } impl fmt::Display for Error { @@ -27,6 +28,7 @@ impl std::error::Error for Error { match *self { Error::IoError(ref e) => error::Error::description(e), Error::NotmuchError(ref e) => e.description(), + Error::UnspecifiedError => "Generic notmuch error", } } @@ -34,6 +36,7 @@ impl std::error::Error for Error { match *self { Error::IoError(ref e) => Some(e), Error::NotmuchError(ref e) => Some(e), + Error::UnspecifiedError => None } } } diff --git a/src/message.rs b/src/message.rs index 81d2417..094f5dc 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,6 +1,9 @@ use std::ops::Drop; use std::marker::PhantomData; use std::path::PathBuf; +use std::ffi::CString; + +use error::{Error, Result}; use ffi; use utils::{ @@ -63,6 +66,18 @@ impl<'d, 'q> Message<'d, 'q>{ ffi::notmuch_message_get_filename(self.0) }.to_str().unwrap()) } + + pub fn header(&self, name: &str) -> Result<&str> { + let ret = unsafe { + ffi::notmuch_message_get_header(self.0, + CString::new(name).unwrap().as_ptr()) + }; + if ret.is_null() { + Err(Error::UnspecifiedError) + } else { + Ok(ret.to_str().unwrap()) + } + } } -- cgit v1.2.1 From 927812b908b2e0eb494bf25278eaa6978781c7e7 Mon Sep 17 00:00:00 2001 From: eaon Date: Sat, 20 Oct 2018 14:53:22 -0400 Subject: Add Message::tags --- src/message.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/message.rs b/src/message.rs index 094f5dc..086670c 100644 --- a/src/message.rs +++ b/src/message.rs @@ -13,6 +13,7 @@ use utils::{ use Query; use Messages; use Filenames; +use Tags; #[derive(Debug)] pub struct Message<'d:'q, 'q>( @@ -78,6 +79,12 @@ impl<'d, 'q> Message<'d, 'q>{ Ok(ret.to_str().unwrap()) } } + + pub fn tags(self: &'d Self) -> Tags<'d>{ + Tags::new(unsafe { + ffi::notmuch_message_get_tags(self.0) + }) + } } -- cgit v1.2.1 From a4ffe47c51d1617fc0e728c7bbd7e9b3738878cb Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 16 Oct 2018 21:01:58 +0200 Subject: some tries towards better lifetimes --- src/database.rs | 57 ++++++++++++++++++++++------------------ src/directory.rs | 44 ++++++++++++++++++------------- src/filenames.rs | 41 +++++++++++++++++------------ src/message.rs | 66 ++++++++++++++++++++++++++-------------------- src/messages.rs | 80 ++++++++++++++++++++++++++++++++++++-------------------- src/query.rs | 61 +++++++++++++++++++++++------------------- src/tags.rs | 6 ++--- src/thread.rs | 71 +++++++++++++++++++++++++++---------------------- src/threads.rs | 40 ++++++++++++++++------------ src/utils.rs | 10 +++++-- 10 files changed, 279 insertions(+), 197 deletions(-) diff --git a/src/database.rs b/src/database.rs index 90f6574..6d98413 100644 --- a/src/database.rs +++ b/src/database.rs @@ -7,7 +7,7 @@ use libc; use error::Result; use utils::{ - NewFromPtr, + FromPtr, ToStr, }; @@ -30,7 +30,22 @@ pub struct Revision{ } #[derive(Debug)] -pub struct Database(*mut ffi::notmuch_database_t); +pub(crate) struct DatabasePtr { + pub ptr: *mut ffi::notmuch_database_t +} + +impl Drop for DatabasePtr { + fn drop(&mut self) { + unsafe { + ffi::notmuch_database_destroy(self.ptr) + }; + } +} + +#[derive(Debug)] +pub struct Database{ + pub(crate) handle: DatabasePtr +} impl Database { pub fn create>(path: &P) -> Result { @@ -41,7 +56,7 @@ impl Database { ffi::notmuch_database_create(path_str.as_ptr(), &mut db) }.as_result()); - Ok(Database(db)) + Ok(Database{handle:DatabasePtr{ptr:db}}) } pub fn open>(path: &P, mode: DatabaseMode) -> Result { @@ -56,12 +71,12 @@ impl Database { ) }.as_result()); - Ok(Database(db)) + Ok(Database{handle:DatabasePtr{ptr:db}}) } pub fn close(self) -> Result<()> { try!(unsafe { - ffi::notmuch_database_close(self.0) + ffi::notmuch_database_close(self.handle.ptr) }.as_result()); Ok(()) @@ -114,13 +129,13 @@ impl Database { pub fn path(&self) -> &Path { Path::new(unsafe { - ffi::notmuch_database_get_path(self.0) + ffi::notmuch_database_get_path(self.handle.ptr) }.to_str().unwrap()) } pub fn version(&self) -> Version { Version(unsafe { - ffi::notmuch_database_get_version(self.0) + ffi::notmuch_database_get_version(self.handle.ptr) }) } @@ -128,7 +143,7 @@ impl Database { pub fn revision(&self) -> Revision { let uuid_p: *const libc::c_char = ptr::null(); let revision = unsafe { - ffi::notmuch_database_get_revision(self.0, (&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) }; @@ -138,7 +153,7 @@ impl Database { pub fn needs_upgrade(&self) -> bool { unsafe { - ffi::notmuch_database_needs_upgrade(self.0) == 1 + ffi::notmuch_database_needs_upgrade(self.handle.ptr) == 1 } } @@ -165,7 +180,7 @@ impl Database { try!(unsafe { ffi::notmuch_database_upgrade( - self.0, + self.handle.ptr, if status.is_some() { Some(wrapper::) } else { None }, status.map_or(ptr::null_mut(), |f| { &f as *const _ as *mut libc::c_void @@ -182,38 +197,30 @@ impl Database { let mut dir = ptr::null_mut(); try!(unsafe { ffi::notmuch_database_get_directory( - self.0, path_str.as_ptr(), &mut dir, + self.handle.ptr, path_str.as_ptr(), &mut dir, ) }.as_result()); - if dir.is_null() { Ok(None) } else { Ok(Some(Directory::new(dir))) } + if dir.is_null() { Ok(None) } else { Ok(Some(Directory::from_ptr(dir))) } } pub fn create_query<'d>(&'d self, query_string: &str) -> Result> { let query_str = CString::new(query_string).unwrap(); let query = unsafe { - ffi::notmuch_query_create(self.0, query_str.as_ptr()) + ffi::notmuch_query_create(self.handle.ptr, query_str.as_ptr()) }; - Ok(Query::new(query)) + Ok(Query::from_ptr(query)) } - pub fn all_tags<'d>(&self) -> Result> { + pub fn all_tags<'d>(&self) -> Result { let tags = unsafe { - ffi::notmuch_database_get_all_tags(self.0) + ffi::notmuch_database_get_all_tags(self.handle.ptr) }; - Ok(Tags::new(tags)) - } -} - -impl Drop for Database { - fn drop(&mut self) { - unsafe { - ffi::notmuch_database_destroy(self.0) - }; + Ok(Tags::from_ptr(tags)) } } diff --git a/src/directory.rs b/src/directory.rs index b0bb415..4bf0a7a 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -1,7 +1,7 @@ use std::ops::Drop; use std::marker::PhantomData; -use utils::NewFromPtr; +use utils::FromPtr; use Database; use Filenames; @@ -9,30 +9,38 @@ use Filenames; use ffi; #[derive(Debug)] -pub struct Directory<'d>( - *mut ffi::notmuch_directory_t, - PhantomData<&'d Database>, -); +pub(crate) struct DirectoryPtr { + pub ptr: *mut ffi::notmuch_directory_t +} -impl<'d> Directory<'d>{ - pub fn child_directories(self: &'d Self) -> Filenames<'d>{ - Filenames::new(unsafe { - ffi::notmuch_directory_get_child_directories(self.0) - }) +impl Drop for DirectoryPtr { + fn drop(&mut self) { + unsafe { + ffi::notmuch_directory_destroy(self.ptr) + }; } } -impl<'d> NewFromPtr<*mut ffi::notmuch_directory_t> for Directory<'d> { - fn new(ptr: *mut ffi::notmuch_directory_t) -> Directory<'d> { - Directory(ptr, PhantomData) +#[derive(Debug)] +pub struct Directory<'d>{ + handle: DirectoryPtr, + phantom: PhantomData<&'d Database>, +} + +impl<'d> Directory<'d>{ + pub fn child_directories(self: &'d Self) -> Filenames<'d>{ + Filenames::from_ptr(unsafe { + ffi::notmuch_directory_get_child_directories(self.handle.ptr) + }) } } -impl<'d> Drop for Directory<'d> { - fn drop(self: &mut Self) { - unsafe { - ffi::notmuch_directory_destroy(self.0) - }; +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 + } } } diff --git a/src/filenames.rs b/src/filenames.rs index d9e5bd8..5f369e8 100644 --- a/src/filenames.rs +++ b/src/filenames.rs @@ -4,35 +4,43 @@ use std::marker::PhantomData; use std::path::PathBuf; use std::ffi::CStr; -use utils::NewFromPtr; +use utils::FromPtr; use Database; use ffi; #[derive(Debug)] -pub struct Filenames<'d>( - *mut ffi::notmuch_filenames_t, - PhantomData<&'d Database>, -); - -impl<'d> NewFromPtr<*mut ffi::notmuch_filenames_t> for Filenames<'d> { - fn new(ptr: *mut ffi::notmuch_filenames_t) -> Filenames<'d> { - Filenames(ptr, PhantomData) - } +pub(crate) struct FilenamesPtr { + pub ptr: *mut ffi::notmuch_filenames_t } -impl<'d> Drop for Filenames<'d> { +impl Drop for FilenamesPtr { fn drop(self: &mut Self) { let valid = unsafe { - ffi::notmuch_filenames_valid(self.0) + ffi::notmuch_filenames_valid(self.ptr) }; if valid != 0 { unsafe { - ffi::notmuch_filenames_destroy(self.0) + ffi::notmuch_filenames_destroy(self.ptr) }; } } } + +#[derive(Debug)] +pub struct Filenames<'d>{ + pub(crate) handle: FilenamesPtr, + phantom: PhantomData<&'d Database> +} + +impl<'d> FromPtr<*mut ffi::notmuch_filenames_t> for Filenames<'d> { + fn from_ptr(ptr: *mut ffi::notmuch_filenames_t) -> Filenames<'d> { + Filenames{ + handle: FilenamesPtr{ptr}, + phantom: PhantomData + } + } +} impl<'d> Iterator for Filenames<'d> { type Item = PathBuf; @@ -40,7 +48,7 @@ impl<'d> Iterator for Filenames<'d> { fn next(self: &mut Self) -> Option { let valid = unsafe { - ffi::notmuch_filenames_valid(self.0) + ffi::notmuch_filenames_valid(self.handle.ptr) }; if valid == 0{ @@ -48,8 +56,8 @@ impl<'d> Iterator for Filenames<'d> { } let ctag = unsafe { - let t = ffi::notmuch_filenames_get(self.0); - ffi::notmuch_filenames_move_to_next(self.0); + let t = ffi::notmuch_filenames_get(self.handle.ptr); + ffi::notmuch_filenames_move_to_next(self.handle.ptr); CStr::from_ptr(t) }; @@ -57,6 +65,5 @@ impl<'d> Iterator for Filenames<'d> { } } - unsafe impl<'d> Send for Filenames<'d>{} unsafe impl<'d> Sync for Filenames<'d>{} diff --git a/src/message.rs b/src/message.rs index 086670c..ddcb356 100644 --- a/src/message.rs +++ b/src/message.rs @@ -8,22 +8,39 @@ use error::{Error, Result}; use ffi; use utils::{ ToStr, - NewFromPtr + FromPtr }; use Query; use Messages; use Filenames; use Tags; + #[derive(Debug)] -pub struct Message<'d:'q, 'q>( - pub(crate) *mut ffi::notmuch_message_t, - PhantomData<&'q Query<'d>>, -); - -impl<'d, 'q> NewFromPtr<*mut ffi::notmuch_message_t> for Message<'d, 'q> { - fn new(ptr: *mut ffi::notmuch_message_t) -> Message<'d, 'q> { - Message(ptr, PhantomData) +pub(crate) struct MessagePtr { + pub ptr: *mut ffi::notmuch_message_t +} + +impl Drop for MessagePtr { + fn drop(&mut self) { + unsafe { + ffi::notmuch_message_destroy(self.ptr) + }; + } +} + +#[derive(Debug)] +pub struct Message<'d:'q, 'q>{ + pub(crate) handle: MessagePtr, + phantom: PhantomData<&'q Query<'d>>, +} + +impl<'d, 'q> FromPtr<*mut ffi::notmuch_message_t> for Message<'d, 'q> { + fn from_ptr(ptr: *mut ffi::notmuch_message_t) -> Message<'d, 'q> { + Message{ + handle: MessagePtr{ptr}, + phantom: PhantomData + } } } @@ -31,46 +48,46 @@ impl<'d, 'q> Message<'d, 'q>{ pub fn id(self: &Self) -> String{ let mid = unsafe { - ffi::notmuch_message_get_message_id(self.0) + 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.0) + ffi::notmuch_message_get_thread_id(self.handle.ptr) }; tid.to_str().unwrap().to_string() } pub fn replies(self: &'q Self) -> Messages<'d, 'q>{ - Messages::new(unsafe { - ffi::notmuch_message_get_replies(self.0) + Messages::from_ptr(unsafe { + ffi::notmuch_message_get_replies(self.handle.ptr) }) } #[cfg(feature = "v0_26")] pub fn count_files(self: &Self) -> i32{ unsafe { - ffi::notmuch_message_count_files(self.0) + ffi::notmuch_message_count_files(self.handle.ptr) } } pub fn filenames(self: &'d Self) -> Filenames<'d>{ - Filenames::new(unsafe { - ffi::notmuch_message_get_filenames(self.0) + Filenames::from_ptr(unsafe { + ffi::notmuch_message_get_filenames(self.handle.ptr) }) } pub fn filename(self: &Self) -> PathBuf{ PathBuf::from(unsafe { - ffi::notmuch_message_get_filename(self.0) + 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.0, + ffi::notmuch_message_get_header(self.handle.ptr, CString::new(name).unwrap().as_ptr()) }; if ret.is_null() { @@ -81,20 +98,11 @@ impl<'d, 'q> Message<'d, 'q>{ } pub fn tags(self: &'d Self) -> Tags<'d>{ - Tags::new(unsafe { - ffi::notmuch_message_get_tags(self.0) + Tags::from_ptr(unsafe { + ffi::notmuch_message_get_tags(self.handle.ptr) }) } } - -impl<'d, 'q> Drop for Message<'d, 'q> { - fn drop(self: &mut Self) { - unsafe { - ffi::notmuch_message_destroy(self.0) - }; - } -} - unsafe impl<'d, 'q> Send for Message<'d, 'q>{} unsafe impl<'d, 'q> Sync for Message<'d, 'q>{} diff --git a/src/messages.rs b/src/messages.rs index 65e1248..4bc90e9 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -4,40 +4,22 @@ use std::marker::PhantomData; use ffi; use utils::{ - NewFromPtr, + FromPtr, }; use Query; use Message; use Tags; -#[derive(Debug)] -pub struct Messages<'d:'q, 'q>( - // TODO: is this lifetime specifier correct? - // query may outlive messages. - pub(crate) *mut ffi::notmuch_messages_t, - PhantomData<&'q Query<'d>>, -); - -impl<'d, 'q> NewFromPtr<*mut ffi::notmuch_messages_t> for Messages<'d, 'q> { - fn new(ptr: *mut ffi::notmuch_messages_t) -> Messages<'d, 'q> { - Messages(ptr, PhantomData) - } -} - -impl<'d, 'q> Messages<'d, 'q>{ - - pub fn collect_tags(self: &'d Self) -> Tags<'d>{ - Tags::new(unsafe { - ffi::notmuch_messages_collect_tags(self.0) - }) - } +#[derive(Debug)] +pub(crate) struct MessagesPtr { + pub ptr: *mut ffi::notmuch_messages_t } -impl<'d, 'q> Drop for Messages<'d, 'q> { +impl Drop for MessagesPtr { fn drop(self: &mut Self) { let valid = unsafe { - ffi::notmuch_messages_valid(self.0) + ffi::notmuch_messages_valid(self.ptr) }; if valid == 0{ @@ -45,18 +27,58 @@ impl<'d, 'q> Drop for Messages<'d, 'q> { } unsafe { - ffi::notmuch_messages_destroy(self.0) + ffi::notmuch_messages_destroy(self.ptr) }; } } + +#[derive(Debug)] +pub struct Messages<'d:'q, 'q>{ + pub(crate) handle: MessagesPtr, + phantom: PhantomData<&'q Query<'d>>, +} + +impl<'d, 'q> FromPtr<*mut ffi::notmuch_messages_t> for Messages<'d, 'q> { + fn from_ptr(ptr: *mut ffi::notmuch_messages_t) -> Messages<'d, 'q> { + Messages{ + handle: MessagesPtr{ptr}, + phantom: PhantomData + } + } +} + +impl<'d, 'q> Messages<'d, 'q>{ + + /** + * Return a list of tags from all messages. + * + * The resulting list is guaranteed not to contain duplicated tags. + * + * WARNING: You can no longer iterate over messages after calling this + * function, because the iterator will point at the end of the list. + * We do not have a function to reset the iterator yet and the only + * way how you can iterate over the list again is to recreate the + * message list. + * + * The function returns NULL on error. + */ + pub fn collect_tags(self: &'d Self) -> Tags{ + Tags::from_ptr(unsafe { + ffi::notmuch_messages_collect_tags(self.handle.ptr) + }) + } +} + + + impl<'d, 'q> Iterator for Messages<'d, 'q> { type Item = Message<'d, 'q>; fn next(&mut self) -> Option { let valid = unsafe { - ffi::notmuch_messages_valid(self.0) + ffi::notmuch_messages_valid(self.handle.ptr) }; if valid == 0{ @@ -64,12 +86,12 @@ impl<'d, 'q> Iterator for Messages<'d, 'q> { } let cmsg = unsafe { - let msg = ffi::notmuch_messages_get(self.0); - ffi::notmuch_messages_move_to_next(self.0); + let msg = ffi::notmuch_messages_get(self.handle.ptr); + ffi::notmuch_messages_move_to_next(self.handle.ptr); msg }; - Some(Self::Item::new(cmsg)) + Some(Self::Item::from_ptr(cmsg)) } } diff --git a/src/query.rs b/src/query.rs index e0c748e..b4cd9a2 100644 --- a/src/query.rs +++ b/src/query.rs @@ -5,7 +5,7 @@ use std::marker::PhantomData; use error::Result; use ffi; -use utils::NewFromPtr; +use utils::FromPtr; use Database; use Messages; @@ -13,11 +13,32 @@ use Threads; use ffi::Sort; #[derive(Debug)] -pub struct Query<'d>( - pub(crate) *mut ffi::notmuch_query_t, - PhantomData<&'d Database>, -); +pub(crate) struct QueryPtr { + pub ptr: *mut ffi::notmuch_query_t +} +impl Drop for QueryPtr { + fn drop(&mut self) { + unsafe { + ffi::notmuch_query_destroy(self.ptr) + }; + } +} + +#[derive(Debug)] +pub struct Query<'d>{ + pub(crate) handle: QueryPtr, + phantom: PhantomData<&'d Database>, +} + +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 create(db: &'d Database, query_string: &str) -> Result { @@ -29,7 +50,7 @@ impl<'d> Query<'d> { { unsafe { ffi::notmuch_query_set_sort( - self.0, sort.into(), + self.handle.ptr, sort.into(), ) } } @@ -40,7 +61,7 @@ impl<'d> Query<'d> { { unsafe { ffi::notmuch_query_get_sort( - self.0, + self.handle.ptr, ) }.into() } @@ -52,11 +73,11 @@ impl<'d> Query<'d> { let mut msgs = ptr::null_mut(); try!(unsafe { ffi::notmuch_query_search_messages( - self.0, &mut msgs, + self.handle.ptr, &mut msgs, ) }.as_result()); - Ok(Messages::new(msgs)) + Ok(Messages::from_ptr(msgs)) } pub fn count_messages(self: &Self) -> Result @@ -64,7 +85,7 @@ impl<'d> Query<'d> { let mut cnt = 0; try!(unsafe { ffi::notmuch_query_count_messages( - self.0, &mut cnt, + self.handle.ptr, &mut cnt, ) }.as_result()); @@ -76,11 +97,11 @@ impl<'d> Query<'d> { let mut thrds = ptr::null_mut(); try!(unsafe { ffi::notmuch_query_search_threads( - self.0, &mut thrds, + self.handle.ptr, &mut thrds, ) }.as_result()); - Ok(Threads::new(thrds)) + Ok(Threads::from_ptr(thrds)) } pub fn count_threads(self: &Self) -> Result @@ -88,7 +109,7 @@ impl<'d> Query<'d> { let mut cnt = 0; try!(unsafe { ffi::notmuch_query_count_threads( - self.0, &mut cnt, + self.handle.ptr, &mut cnt, ) }.as_result()); @@ -96,20 +117,6 @@ impl<'d> Query<'d> { } } -impl<'d> NewFromPtr<*mut ffi::notmuch_query_t> for Query<'d> { - fn new(ptr: *mut ffi::notmuch_query_t) -> Query<'d> { - Query(ptr, PhantomData) - } -} - - -impl<'d> Drop for Query<'d> { - fn drop(&mut self) { - unsafe { - ffi::notmuch_query_destroy(self.0) - }; - } -} 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 04c7cd5..61f99b7 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -4,7 +4,7 @@ use std::marker::PhantomData; use std::ffi::CStr; use utils::{ - NewFromPtr, + FromPtr, }; use Database; @@ -16,8 +16,8 @@ pub struct Tags<'d>( PhantomData<&'d Database>, ); -impl<'d> NewFromPtr<*mut ffi::notmuch_tags_t> for Tags<'d> { - fn new(ptr: *mut ffi::notmuch_tags_t) -> Tags<'d> { +impl<'d> FromPtr<*mut ffi::notmuch_tags_t> for Tags<'d> { + fn from_ptr(ptr: *mut ffi::notmuch_tags_t) -> Tags<'d> { Tags(ptr, PhantomData) } } diff --git a/src/thread.rs b/src/thread.rs index 4f98c26..60782f5 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -2,7 +2,7 @@ use std::ops::Drop; use std::marker::PhantomData; use ffi; use utils::{ - NewFromPtr, + FromPtr, ToStr }; use Query; @@ -10,14 +10,31 @@ use Messages; use Tags; #[derive(Debug)] -pub struct Thread<'d:'q, 'q>( - pub(crate) *mut ffi::notmuch_thread_t, - PhantomData<&'q Query<'d>>, -); - -impl<'d, 'q> NewFromPtr<*mut ffi::notmuch_thread_t> for Thread<'d, 'q> { - fn new(ptr: *mut ffi::notmuch_thread_t) -> Thread<'d, 'q> { - Thread(ptr, PhantomData) +pub(crate) struct ThreadPtr { + pub ptr: *mut ffi::notmuch_thread_t +} + +impl Drop for ThreadPtr { + fn drop(&mut self) { + unsafe { + ffi::notmuch_thread_destroy(self.ptr) + }; + } +} + + +#[derive(Debug)] +pub struct Thread<'d:'q, 'q>{ + pub(crate) handle: ThreadPtr, + phantom: PhantomData<&'q Query<'d>>, +} + +impl<'d, 'q> FromPtr<*mut ffi::notmuch_thread_t> for Thread<'d, 'q> { + fn from_ptr(ptr: *mut ffi::notmuch_thread_t) -> Thread<'d, 'q> { + Thread{ + handle: ThreadPtr{ptr}, + phantom: PhantomData + } } } @@ -25,7 +42,7 @@ impl<'d, 'q> Thread<'d, 'q>{ pub fn id(self: &Self) -> String{ let tid = unsafe { - ffi::notmuch_thread_get_thread_id(self.0) + ffi::notmuch_thread_get_thread_id(self.handle.ptr) }; tid.to_str().unwrap().to_string() } @@ -33,42 +50,42 @@ impl<'d, 'q> Thread<'d, 'q>{ pub fn total_messages(self: &Self) -> i32{ unsafe { - ffi::notmuch_thread_get_total_messages(self.0) + 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.0) + ffi::notmuch_thread_get_total_files(self.handle.ptr) } } pub fn toplevel_messages(self: &Self) -> Messages{ - Messages::new(unsafe { - ffi::notmuch_thread_get_toplevel_messages(self.0) + Messages::from_ptr(unsafe { + ffi::notmuch_thread_get_toplevel_messages(self.handle.ptr) }) } /// Get a `Messages` iterator for all messages in 'thread' in /// oldest-first order. pub fn messages(self: &Self) -> Messages{ - Messages::new(unsafe { - ffi::notmuch_thread_get_messages(self.0) + Messages::from_ptr(unsafe { + ffi::notmuch_thread_get_messages(self.handle.ptr) }) } - pub fn tags(self: &Self) -> Tags{ - Tags::new(unsafe { - ffi::notmuch_thread_get_tags(self.0) + pub fn tags<'t>(self: &Self) -> Tags{ + Tags::from_ptr(unsafe { + ffi::notmuch_thread_get_tags(self.handle.ptr) }) } pub fn subject(self: &Self) -> String{ let sub = unsafe { - ffi::notmuch_thread_get_subject(self.0) + ffi::notmuch_thread_get_subject(self.handle.ptr) }; sub.to_str().unwrap().to_string() @@ -76,7 +93,7 @@ impl<'d, 'q> Thread<'d, 'q>{ pub fn authors(self: &Self) -> Vec{ let athrs = unsafe { - ffi::notmuch_thread_get_authors(self.0) + ffi::notmuch_thread_get_authors(self.handle.ptr) }; athrs.to_str().unwrap().split(',').map(|s| s.to_string()).collect() @@ -85,26 +102,18 @@ impl<'d, 'q> Thread<'d, 'q>{ /// 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.0) + 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.0) + ffi::notmuch_thread_get_newest_date(self.handle.ptr) } } } -impl<'d, 'q> Drop for Thread<'d, 'q> { - fn drop(&mut self) { - unsafe { - ffi::notmuch_thread_destroy(self.0) - }; - } -} - unsafe impl<'d, 'q> Send for Thread<'d, 'q> {} unsafe impl<'d, 'q> Sync for Thread<'d, 'q> {} diff --git a/src/threads.rs b/src/threads.rs index 20fc302..a98caba 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -2,38 +2,46 @@ use std::ops::Drop; use std::iter::Iterator; use std::marker::PhantomData; -use utils::NewFromPtr; +use utils::FromPtr; use Query; use Thread; use ffi; #[derive(Debug)] -pub struct Threads<'d:'q, 'q>( - *mut ffi::notmuch_threads_t, - PhantomData<&'q Query<'d>>, -); - -impl<'d, 'q> NewFromPtr<*mut ffi::notmuch_threads_t> for Threads<'d, 'q> { - fn new(ptr: *mut ffi::notmuch_threads_t) -> Threads<'d, 'q> { - Threads(ptr, PhantomData) - } +pub(crate) struct ThreadsPtr { + pub ptr: *mut ffi::notmuch_threads_t } -impl<'d, 'q> Drop for Threads<'d, 'q> { +impl Drop for ThreadsPtr { fn drop(&mut self) { unsafe { - ffi::notmuch_threads_destroy(self.0) + ffi::notmuch_threads_destroy(self.ptr) }; } } +#[derive(Debug)] +pub struct Threads<'d:'q, 'q>{ + handle: ThreadsPtr, + phantom: PhantomData<&'q Query<'d>>, +} + +impl<'d, 'q> FromPtr<*mut ffi::notmuch_threads_t> for Threads<'d, 'q> { + fn from_ptr(ptr: *mut ffi::notmuch_threads_t) -> Threads<'d, 'q> { + Threads{ + handle: ThreadsPtr{ptr}, + phantom: PhantomData + } + } +} + impl<'d, 'q> Iterator for Threads<'d, 'q> { type Item = Thread<'d, 'q>; fn next(self: &mut Self) -> Option { let valid = unsafe { - ffi::notmuch_threads_valid(self.0) + ffi::notmuch_threads_valid(self.handle.ptr) }; if valid == 0{ @@ -41,12 +49,12 @@ impl<'d, 'q> Iterator for Threads<'d, 'q> { } let cthread = unsafe { - let t = ffi::notmuch_threads_get(self.0); - ffi::notmuch_threads_move_to_next(self.0); + let t = ffi::notmuch_threads_get(self.handle.ptr); + ffi::notmuch_threads_move_to_next(self.handle.ptr); t }; - Some(Self::Item::new(cthread)) + Some(Self::Item::from_ptr(cthread)) } } diff --git a/src/utils.rs b/src/utils.rs index bdc8c4f..9de7e08 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -4,10 +4,14 @@ use std::{ }; use libc; -pub trait NewFromPtr { - fn new(ptr: T) -> Self; +pub trait FromPtr { + fn from_ptr(ptr: T) -> Self; } +// pub trait NewFromPtr { +// fn new(ptr: T, parent: Rc

) -> Self; +// } + pub trait ToStr { fn to_str<'a>(&self) -> Result<&'a str, str::Utf8Error>; } @@ -31,3 +35,5 @@ impl ToString for *const libc::c_char { } } } + + -- cgit v1.2.1 From bd1a184600a0d42c36d7d2fc5f010692d0ab46aa Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 25 Oct 2018 08:02:04 +0200 Subject: more correct lifetimes --- src/database.rs | 3 +++ src/directory.rs | 24 ++++++++++++++++++++---- src/filenames.rs | 16 +++++++++------- src/message.rs | 27 +++++++++++++++++---------- src/messages.rs | 26 ++++++++++++++++---------- src/query.rs | 10 ++++++++-- src/tags.rs | 3 +++ src/thread.rs | 27 ++++++++++++++++++--------- src/threads.rs | 23 +++++++++++++++-------- src/utils.rs | 3 +++ 10 files changed, 112 insertions(+), 50 deletions(-) diff --git a/src/database.rs b/src/database.rs index 6d98413..7a1bb63 100644 --- a/src/database.rs +++ b/src/database.rs @@ -14,6 +14,7 @@ use utils::{ use Directory; use Query; use Tags; +use tags::TagsOwner; use ffi; @@ -47,6 +48,8 @@ pub struct Database{ pub(crate) handle: DatabasePtr } +impl TagsOwner for Database{} + impl Database { pub fn create>(path: &P) -> Result { let path_str = CString::new(path.as_ref().to_str().unwrap()).unwrap(); diff --git a/src/directory.rs b/src/directory.rs index 4bf0a7a..ce219f5 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -5,6 +5,7 @@ use utils::FromPtr; use Database; use Filenames; +use filenames::{FilenamesPtr, FilenamesOwner}; use ffi; @@ -21,17 +22,32 @@ impl Drop for DirectoryPtr { } } +impl DirectoryPtr { + pub fn child_directories(self: &Self) -> FilenamesPtr{ + FilenamesPtr{ + ptr: unsafe { + ffi::notmuch_directory_get_child_directories(self.ptr) + } + } + } +} + + + #[derive(Debug)] pub struct Directory<'d>{ handle: DirectoryPtr, phantom: PhantomData<&'d Database>, } +impl<'d> FilenamesOwner for Directory<'d>{} + impl<'d> Directory<'d>{ - pub fn child_directories(self: &'d Self) -> Filenames<'d>{ - Filenames::from_ptr(unsafe { - ffi::notmuch_directory_get_child_directories(self.handle.ptr) - }) + pub fn child_directories(self: &'d Self) -> Filenames{ + Filenames{ + handle: self.handle.child_directories(), + phantom: PhantomData + } } } diff --git a/src/filenames.rs b/src/filenames.rs index 5f369e8..3c167df 100644 --- a/src/filenames.rs +++ b/src/filenames.rs @@ -8,6 +8,8 @@ use utils::FromPtr; use Database; use ffi; +pub trait FilenamesOwner{} + #[derive(Debug)] pub(crate) struct FilenamesPtr { pub ptr: *mut ffi::notmuch_filenames_t @@ -28,13 +30,13 @@ impl Drop for FilenamesPtr { } #[derive(Debug)] -pub struct Filenames<'d>{ +pub struct Filenames<'o, Owner: FilenamesOwner>{ pub(crate) handle: FilenamesPtr, - phantom: PhantomData<&'d Database> + pub(crate) phantom: PhantomData<&'o Owner> } -impl<'d> FromPtr<*mut ffi::notmuch_filenames_t> for Filenames<'d> { - fn from_ptr(ptr: *mut ffi::notmuch_filenames_t) -> Filenames<'d> { +impl<'o, Owner: FilenamesOwner> 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 @@ -42,7 +44,7 @@ impl<'d> FromPtr<*mut ffi::notmuch_filenames_t> for Filenames<'d> { } } -impl<'d> Iterator for Filenames<'d> { +impl<'o, Owner: FilenamesOwner> Iterator for Filenames<'o, Owner> { type Item = PathBuf; fn next(self: &mut Self) -> Option { @@ -65,5 +67,5 @@ impl<'d> Iterator for Filenames<'d> { } } -unsafe impl<'d> Send for Filenames<'d>{} -unsafe impl<'d> Sync for Filenames<'d>{} +unsafe impl<'o, Owner: FilenamesOwner> Send for Filenames<'o, Owner>{} +unsafe impl<'o, Owner: FilenamesOwner> Sync for Filenames<'o, Owner>{} diff --git a/src/message.rs b/src/message.rs index ddcb356..c5a6404 100644 --- a/src/message.rs +++ b/src/message.rs @@ -14,7 +14,10 @@ use Query; use Messages; use Filenames; use Tags; +use messages::MessagesOwner; +use filenames::FilenamesOwner; +pub trait MessageOwner{} #[derive(Debug)] pub(crate) struct MessagePtr { @@ -30,13 +33,17 @@ impl Drop for MessagePtr { } #[derive(Debug)] -pub struct Message<'d:'q, 'q>{ +pub struct Message<'o, Owner: MessageOwner>{ pub(crate) handle: MessagePtr, - phantom: PhantomData<&'q Query<'d>>, + phantom: PhantomData<&'o Owner>, } -impl<'d, 'q> FromPtr<*mut ffi::notmuch_message_t> for Message<'d, 'q> { - fn from_ptr(ptr: *mut ffi::notmuch_message_t) -> Message<'d, 'q> { +impl<'o, Owner: MessageOwner> MessagesOwner for Message<'o, Owner>{} +impl<'o, Owner: MessageOwner> FilenamesOwner for Message<'o, Owner>{} + + +impl<'o, Owner: MessageOwner> 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 @@ -44,7 +51,7 @@ impl<'d, 'q> FromPtr<*mut ffi::notmuch_message_t> for Message<'d, 'q> { } } -impl<'d, 'q> Message<'d, 'q>{ +impl<'o, Owner: MessageOwner> Message<'o, Owner>{ pub fn id(self: &Self) -> String{ let mid = unsafe { @@ -60,7 +67,7 @@ impl<'d, 'q> Message<'d, 'q>{ tid.to_str().unwrap().to_string() } - pub fn replies(self: &'q Self) -> Messages<'d, 'q>{ + pub fn replies(self: &Self) -> Messages<'o, Self>{ Messages::from_ptr(unsafe { ffi::notmuch_message_get_replies(self.handle.ptr) }) @@ -73,7 +80,7 @@ impl<'d, 'q> Message<'d, 'q>{ } } - pub fn filenames(self: &'d Self) -> Filenames<'d>{ + pub fn filenames(self: &Self) -> Filenames{ Filenames::from_ptr(unsafe { ffi::notmuch_message_get_filenames(self.handle.ptr) }) @@ -97,12 +104,12 @@ impl<'d, 'q> Message<'d, 'q>{ } } - pub fn tags(self: &'d Self) -> Tags<'d>{ + pub fn tags(self: &Self) -> Tags{ Tags::from_ptr(unsafe { ffi::notmuch_message_get_tags(self.handle.ptr) }) } } -unsafe impl<'d, 'q> Send for Message<'d, 'q>{} -unsafe impl<'d, 'q> Sync for Message<'d, 'q>{} +unsafe impl<'o, Owner: MessageOwner> Send for Message<'o, Owner>{} +unsafe impl<'o, Owner: MessageOwner> Sync for Message<'o, Owner>{} diff --git a/src/messages.rs b/src/messages.rs index 4bc90e9..40929eb 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -9,7 +9,10 @@ use utils::{ use Query; use Message; use Tags; +use message::MessageOwner; +pub trait MessagesOwner{ +} #[derive(Debug)] pub(crate) struct MessagesPtr { @@ -34,13 +37,13 @@ impl Drop for MessagesPtr { #[derive(Debug)] -pub struct Messages<'d:'q, 'q>{ +pub struct Messages<'o, Owner: MessagesOwner>{ pub(crate) handle: MessagesPtr, - phantom: PhantomData<&'q Query<'d>>, + phantom: PhantomData<&'o Owner>, } -impl<'d, 'q> FromPtr<*mut ffi::notmuch_messages_t> for Messages<'d, 'q> { - fn from_ptr(ptr: *mut ffi::notmuch_messages_t) -> Messages<'d, 'q> { +impl<'o, Owner: MessagesOwner> 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 @@ -48,7 +51,10 @@ impl<'d, 'q> FromPtr<*mut ffi::notmuch_messages_t> for Messages<'d, 'q> { } } -impl<'d, 'q> Messages<'d, 'q>{ +impl<'o, Owner: MessagesOwner> MessageOwner for Messages<'o, Owner>{} + + +impl<'o, Owner: MessagesOwner> Messages<'o, Owner>{ /** * Return a list of tags from all messages. @@ -63,7 +69,7 @@ impl<'d, 'q> Messages<'d, 'q>{ * * The function returns NULL on error. */ - pub fn collect_tags(self: &'d Self) -> Tags{ + pub fn collect_tags(self: &'o Self) -> Tags{ Tags::from_ptr(unsafe { ffi::notmuch_messages_collect_tags(self.handle.ptr) }) @@ -72,8 +78,8 @@ impl<'d, 'q> Messages<'d, 'q>{ -impl<'d, 'q> Iterator for Messages<'d, 'q> { - type Item = Message<'d, 'q>; +impl<'o, Owner: MessagesOwner> Iterator for Messages<'o, Owner> { + type Item = Message<'o, Self>; fn next(&mut self) -> Option { @@ -95,5 +101,5 @@ impl<'d, 'q> Iterator for Messages<'d, 'q> { } } -unsafe impl<'d, 'q> Send for Messages<'d, 'q>{} -unsafe impl<'d, 'q> Sync for Messages<'d, 'q>{} +unsafe impl<'o, Owner: MessagesOwner> Send for Messages<'o, Owner>{} +unsafe impl<'o, Owner: MessagesOwner> Sync for Messages<'o, Owner>{} diff --git a/src/query.rs b/src/query.rs index b4cd9a2..a95c9c2 100644 --- a/src/query.rs +++ b/src/query.rs @@ -11,6 +11,8 @@ use Database; use Messages; use Threads; use ffi::Sort; +use threads::ThreadsOwner; +use messages::MessagesOwner; #[derive(Debug)] pub(crate) struct QueryPtr { @@ -31,6 +33,10 @@ pub struct Query<'d>{ phantom: PhantomData<&'d Database>, } +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{ @@ -68,7 +74,7 @@ impl<'d> Query<'d> { /// Filter messages according to the query and return - pub fn search_messages<'q>(self: &'d Self) -> Result> + pub fn search_messages<'q>(self: &'d Self) -> Result> { let mut msgs = ptr::null_mut(); try!(unsafe { @@ -92,7 +98,7 @@ impl<'d> Query<'d> { Ok(cnt) } - pub fn search_threads<'q>(self: &'d Self) -> Result> + pub fn search_threads<'q>(self: &'d Self) -> Result> { let mut thrds = ptr::null_mut(); try!(unsafe { diff --git a/src/tags.rs b/src/tags.rs index 61f99b7..5cac5ba 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -10,6 +10,9 @@ use utils::{ use Database; use ffi; +pub trait TagsOwner{} + + #[derive(Debug)] pub struct Tags<'d>( *mut ffi::notmuch_tags_t, diff --git a/src/thread.rs b/src/thread.rs index 60782f5..1cf163e 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -8,6 +8,11 @@ use utils::{ use Query; use Messages; use Tags; +use messages::MessagesOwner; +use tags::TagsOwner; + +pub trait ThreadOwner{} + #[derive(Debug)] pub(crate) struct ThreadPtr { @@ -24,13 +29,17 @@ impl Drop for ThreadPtr { #[derive(Debug)] -pub struct Thread<'d:'q, 'q>{ +pub struct Thread<'o, Owner: ThreadOwner>{ pub(crate) handle: ThreadPtr, - phantom: PhantomData<&'q Query<'d>>, + phantom: PhantomData<&'o Owner>, } -impl<'d, 'q> FromPtr<*mut ffi::notmuch_thread_t> for Thread<'d, 'q> { - fn from_ptr(ptr: *mut ffi::notmuch_thread_t) -> Thread<'d, 'q> { +impl<'o, Owner: ThreadOwner> MessagesOwner for Thread<'o, Owner>{} +impl<'o, Owner: ThreadOwner> TagsOwner for Thread<'o, Owner>{} + + +impl<'o, Owner: ThreadOwner> 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 @@ -38,7 +47,7 @@ impl<'d, 'q> FromPtr<*mut ffi::notmuch_thread_t> for Thread<'d, 'q> { } } -impl<'d, 'q> Thread<'d, 'q>{ +impl<'o, Owner: ThreadOwner> Thread<'o, Owner>{ pub fn id(self: &Self) -> String{ let tid = unsafe { @@ -62,7 +71,7 @@ impl<'d, 'q> Thread<'d, 'q>{ } - pub fn toplevel_messages(self: &Self) -> Messages{ + pub fn toplevel_messages(self: &Self) -> Messages{ Messages::from_ptr(unsafe { ffi::notmuch_thread_get_toplevel_messages(self.handle.ptr) }) @@ -70,7 +79,7 @@ impl<'d, 'q> Thread<'d, 'q>{ /// Get a `Messages` iterator for all messages in 'thread' in /// oldest-first order. - pub fn messages(self: &Self) -> Messages{ + pub fn messages(self: &Self) -> Messages{ Messages::from_ptr(unsafe { ffi::notmuch_thread_get_messages(self.handle.ptr) }) @@ -115,5 +124,5 @@ impl<'d, 'q> Thread<'d, 'q>{ } -unsafe impl<'d, 'q> Send for Thread<'d, 'q> {} -unsafe impl<'d, 'q> Sync for Thread<'d, 'q> {} +unsafe impl<'o, Owner: ThreadOwner> Send for Thread<'o, Owner> {} +unsafe impl<'o, Owner: ThreadOwner> Sync for Thread<'o, Owner> {} diff --git a/src/threads.rs b/src/threads.rs index a98caba..09f51bf 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -6,6 +6,10 @@ use utils::FromPtr; use Query; use Thread; use ffi; +use thread::ThreadOwner; + +pub trait ThreadsOwner{} + #[derive(Debug)] pub(crate) struct ThreadsPtr { @@ -21,13 +25,16 @@ impl Drop for ThreadsPtr { } #[derive(Debug)] -pub struct Threads<'d:'q, 'q>{ +pub struct Threads<'o, Owner: ThreadsOwner>{ handle: ThreadsPtr, - phantom: PhantomData<&'q Query<'d>>, + phantom: PhantomData<&'o Owner>, } -impl<'d, 'q> FromPtr<*mut ffi::notmuch_threads_t> for Threads<'d, 'q> { - fn from_ptr(ptr: *mut ffi::notmuch_threads_t) -> Threads<'d, 'q> { +impl<'o, Owner: ThreadsOwner> ThreadOwner for Threads<'o, Owner>{} + + +impl<'o, Owner: ThreadsOwner> 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 @@ -35,8 +42,8 @@ impl<'d, 'q> FromPtr<*mut ffi::notmuch_threads_t> for Threads<'d, 'q> { } } -impl<'d, 'q> Iterator for Threads<'d, 'q> { - type Item = Thread<'d, 'q>; +impl<'o, Owner: ThreadsOwner> Iterator for Threads<'o, Owner> { + type Item = Thread<'o, Self>; fn next(self: &mut Self) -> Option { @@ -58,5 +65,5 @@ impl<'d, 'q> Iterator for Threads<'d, 'q> { } } -unsafe impl<'d, 'q> Send for Threads<'d, 'q> {} -unsafe impl<'d, 'q> Sync for Threads<'d, 'q> {} +unsafe impl<'o, Owner: ThreadsOwner> Send for Threads<'o, Owner> {} +unsafe impl<'o, Owner: ThreadsOwner> Sync for Threads<'o, Owner> {} diff --git a/src/utils.rs b/src/utils.rs index 9de7e08..5db8957 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -37,3 +37,6 @@ impl ToString for *const libc::c_char { } +pub struct Owner; + + -- cgit v1.2.1 From 304786cbfd8d2d425eb7119b974ca9cb416a6ee0 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 29 Oct 2018 21:54:48 +0100 Subject: fix lifetimes of tags --- Cargo.toml | 3 +++ src/database.rs | 4 ++-- src/message.rs | 4 +++- src/messages.rs | 4 +++- src/tags.rs | 16 ++++++++-------- src/thread.rs | 2 +- tests/main.rs | 3 ++- 7 files changed, 22 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7711237..cc152bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,9 @@ travis-ci = { repository = "vhdirk/notmuch-rs" } libc = "0.2" clippy = { version = "0.0.193", optional = true } +[dev-dependencies] +dirs = "1.0" + [features] v0_21 = [] v0_26 = ["v0_21"] diff --git a/src/database.rs b/src/database.rs index 7a1bb63..467c3ba 100644 --- a/src/database.rs +++ b/src/database.rs @@ -77,7 +77,7 @@ impl Database { Ok(Database{handle:DatabasePtr{ptr:db}}) } - pub fn close(self) -> Result<()> { + pub fn close(&mut self) -> Result<()> { try!(unsafe { ffi::notmuch_database_close(self.handle.ptr) }.as_result()); @@ -217,7 +217,7 @@ impl Database { Ok(Query::from_ptr(query)) } - pub fn all_tags<'d>(&self) -> Result { + pub fn all_tags<'d>(&self) -> Result> { let tags = unsafe { ffi::notmuch_database_get_all_tags(self.handle.ptr) diff --git a/src/message.rs b/src/message.rs index c5a6404..2825c1a 100644 --- a/src/message.rs +++ b/src/message.rs @@ -16,6 +16,7 @@ use Filenames; use Tags; use messages::MessagesOwner; use filenames::FilenamesOwner; +use tags::TagsOwner; pub trait MessageOwner{} @@ -40,6 +41,7 @@ pub struct Message<'o, Owner: MessageOwner>{ impl<'o, Owner: MessageOwner> MessagesOwner for Message<'o, Owner>{} impl<'o, Owner: MessageOwner> FilenamesOwner for Message<'o, Owner>{} +impl<'o, Owner: MessageOwner> TagsOwner for Message<'o, Owner>{} impl<'o, Owner: MessageOwner> FromPtr<*mut ffi::notmuch_message_t> for Message<'o, Owner> { @@ -104,7 +106,7 @@ impl<'o, Owner: MessageOwner> Message<'o, Owner>{ } } - pub fn tags(self: &Self) -> Tags{ + pub fn tags<'m>(self: &Self) -> Tags<'m, Self>{ Tags::from_ptr(unsafe { ffi::notmuch_message_get_tags(self.handle.ptr) }) diff --git a/src/messages.rs b/src/messages.rs index 40929eb..ef196e5 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -10,6 +10,7 @@ use Query; use Message; use Tags; use message::MessageOwner; +use tags::TagsOwner; pub trait MessagesOwner{ } @@ -52,6 +53,7 @@ impl<'o, Owner: MessagesOwner> FromPtr<*mut ffi::notmuch_messages_t> for Message } impl<'o, Owner: MessagesOwner> MessageOwner for Messages<'o, Owner>{} +impl<'o, Owner: MessagesOwner> TagsOwner for Messages<'o, Owner>{} impl<'o, Owner: MessagesOwner> Messages<'o, Owner>{ @@ -69,7 +71,7 @@ impl<'o, Owner: MessagesOwner> Messages<'o, Owner>{ * * The function returns NULL on error. */ - pub fn collect_tags(self: &'o Self) -> Tags{ + pub fn collect_tags<'m>(self: &'o Self) -> Tags<'m, Self>{ Tags::from_ptr(unsafe { ffi::notmuch_messages_collect_tags(self.handle.ptr) }) diff --git a/src/tags.rs b/src/tags.rs index 5cac5ba..7df5e5d 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -14,18 +14,18 @@ pub trait TagsOwner{} #[derive(Debug)] -pub struct Tags<'d>( +pub struct Tags<'o, Owner: TagsOwner>( *mut ffi::notmuch_tags_t, - PhantomData<&'d Database>, + PhantomData<&'o Owner>, ); -impl<'d> FromPtr<*mut ffi::notmuch_tags_t> for Tags<'d> { - fn from_ptr(ptr: *mut ffi::notmuch_tags_t) -> Tags<'d> { +impl<'o, Owner: TagsOwner> 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) } } -impl<'d> Drop for Tags<'d> { +impl<'o, Owner: TagsOwner> Drop for Tags<'o, Owner> { fn drop(&mut self) { unsafe { ffi::notmuch_tags_destroy(self.0) @@ -33,7 +33,7 @@ impl<'d> Drop for Tags<'d> { } } -impl<'d> Iterator for Tags<'d> { +impl<'o, Owner: TagsOwner> Iterator for Tags<'o, Owner> { type Item = String; fn next(&mut self) -> Option { @@ -57,5 +57,5 @@ impl<'d> Iterator for Tags<'d> { } } -unsafe impl<'d> Send for Tags<'d>{} -unsafe impl<'d> Sync for Tags<'d>{} +unsafe impl<'o, Owner: TagsOwner> Send for Tags<'o, Owner>{} +unsafe impl<'o, Owner: TagsOwner> Sync for Tags<'o, Owner>{} diff --git a/src/thread.rs b/src/thread.rs index 1cf163e..1ba865e 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -86,7 +86,7 @@ impl<'o, Owner: ThreadOwner> Thread<'o, Owner>{ } - pub fn tags<'t>(self: &Self) -> Tags{ + pub fn tags<'t>(self: &Self) -> Tags<'t, Self>{ Tags::from_ptr(unsafe { ffi::notmuch_thread_get_tags(self.handle.ptr) }) diff --git a/tests/main.rs b/tests/main.rs index 8c68ca3..6840dc0 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -1,8 +1,9 @@ extern crate notmuch; +extern crate dirs; fn main() { - let mut mail_path = std::env::home_dir().unwrap(); + let mut mail_path = dirs::home_dir().unwrap(); mail_path.push(".mail"); match notmuch::Database::open(&mail_path.to_str().unwrap().to_string(), notmuch::DatabaseMode::ReadOnly){ -- cgit v1.2.1 From 29a30f26523bc50a792dc917938b71049de025aa Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 29 Oct 2018 21:58:21 +0100 Subject: export owner traits --- src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 8120bd0..2a083d6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,11 +24,11 @@ pub use error::Error; pub use database::Database; pub use directory::Directory; pub use query::Query; -pub use messages::Messages; -pub use message::Message; -pub use tags::Tags; -pub use threads::Threads; -pub use thread::Thread; -pub use filenames::Filenames; +pub use messages::{Messages, MessagesOwner}; +pub use message::{Message, MessageOwner}; +pub use tags::{Tags, TagsOwner}; +pub use threads::{Threads, ThreadsOwner}; +pub use thread::{Thread, ThreadOwner}; +pub use filenames::{Filenames, FilenamesOwner}; pub use ffi::DatabaseMode; -- cgit v1.2.1 From 7d2c7b44508291b319d95e8689e9cabf8760bef4 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 29 Oct 2018 23:25:37 +0100 Subject: bind type param to lifetime --- src/filenames.rs | 10 +++++----- src/message.rs | 16 ++++++++-------- src/messages.rs | 16 ++++++++-------- src/tags.rs | 12 ++++++------ src/thread.rs | 14 +++++++------- src/threads.rs | 12 ++++++------ 6 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/filenames.rs b/src/filenames.rs index 3c167df..5083742 100644 --- a/src/filenames.rs +++ b/src/filenames.rs @@ -30,12 +30,12 @@ impl Drop for FilenamesPtr { } #[derive(Debug)] -pub struct Filenames<'o, Owner: FilenamesOwner>{ +pub struct Filenames<'o, Owner: FilenamesOwner + 'o>{ pub(crate) handle: FilenamesPtr, pub(crate) phantom: PhantomData<&'o Owner> } -impl<'o, Owner: FilenamesOwner> FromPtr<*mut ffi::notmuch_filenames_t> for Filenames<'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}, @@ -44,7 +44,7 @@ impl<'o, Owner: FilenamesOwner> FromPtr<*mut ffi::notmuch_filenames_t> for Filen } } -impl<'o, Owner: FilenamesOwner> Iterator for Filenames<'o, Owner> { +impl<'o, Owner: FilenamesOwner + 'o> Iterator for Filenames<'o, Owner> { type Item = PathBuf; fn next(self: &mut Self) -> Option { @@ -67,5 +67,5 @@ impl<'o, Owner: FilenamesOwner> Iterator for Filenames<'o, Owner> { } } -unsafe impl<'o, Owner: FilenamesOwner> Send for Filenames<'o, Owner>{} -unsafe impl<'o, Owner: FilenamesOwner> 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>{} diff --git a/src/message.rs b/src/message.rs index 2825c1a..af04cec 100644 --- a/src/message.rs +++ b/src/message.rs @@ -34,17 +34,17 @@ impl Drop for MessagePtr { } #[derive(Debug)] -pub struct Message<'o, Owner: MessageOwner>{ +pub struct Message<'o, Owner: MessageOwner + 'o>{ pub(crate) handle: MessagePtr, phantom: PhantomData<&'o Owner>, } -impl<'o, Owner: MessageOwner> MessagesOwner for Message<'o, Owner>{} -impl<'o, Owner: MessageOwner> FilenamesOwner for Message<'o, Owner>{} -impl<'o, Owner: MessageOwner> TagsOwner for Message<'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> FromPtr<*mut ffi::notmuch_message_t> 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}, @@ -53,7 +53,7 @@ impl<'o, Owner: MessageOwner> FromPtr<*mut ffi::notmuch_message_t> for Message<' } } -impl<'o, Owner: MessageOwner> Message<'o, Owner>{ +impl<'o, Owner: MessageOwner + 'o> Message<'o, Owner>{ pub fn id(self: &Self) -> String{ let mid = unsafe { @@ -113,5 +113,5 @@ impl<'o, Owner: MessageOwner> Message<'o, Owner>{ } } -unsafe impl<'o, Owner: MessageOwner> Send for Message<'o, Owner>{} -unsafe impl<'o, Owner: MessageOwner> 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 ef196e5..b0fd47d 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -38,12 +38,12 @@ impl Drop for MessagesPtr { #[derive(Debug)] -pub struct Messages<'o, Owner: MessagesOwner>{ +pub struct Messages<'o, Owner: MessagesOwner + 'o>{ pub(crate) handle: MessagesPtr, phantom: PhantomData<&'o Owner>, } -impl<'o, Owner: MessagesOwner> FromPtr<*mut ffi::notmuch_messages_t> for Messages<'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}, @@ -52,11 +52,11 @@ impl<'o, Owner: MessagesOwner> FromPtr<*mut ffi::notmuch_messages_t> for Message } } -impl<'o, Owner: MessagesOwner> MessageOwner for Messages<'o, Owner>{} -impl<'o, Owner: MessagesOwner> TagsOwner for 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> Messages<'o, Owner>{ +impl<'o, Owner: MessagesOwner + 'o> Messages<'o, Owner>{ /** * Return a list of tags from all messages. @@ -80,7 +80,7 @@ impl<'o, Owner: MessagesOwner> Messages<'o, Owner>{ -impl<'o, Owner: MessagesOwner> Iterator for Messages<'o, Owner> { +impl<'o, Owner: MessagesOwner + 'o> Iterator for Messages<'o, Owner> { type Item = Message<'o, Self>; fn next(&mut self) -> Option { @@ -103,5 +103,5 @@ impl<'o, Owner: MessagesOwner> Iterator for Messages<'o, Owner> { } } -unsafe impl<'o, Owner: MessagesOwner> Send for Messages<'o, Owner>{} -unsafe impl<'o, Owner: MessagesOwner> 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/tags.rs b/src/tags.rs index 7df5e5d..fa21ff7 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -14,18 +14,18 @@ pub trait TagsOwner{} #[derive(Debug)] -pub struct Tags<'o, Owner: TagsOwner>( +pub struct Tags<'o, Owner: TagsOwner + 'o>( *mut ffi::notmuch_tags_t, PhantomData<&'o Owner>, ); -impl<'o, Owner: TagsOwner> FromPtr<*mut ffi::notmuch_tags_t> for Tags<'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) } } -impl<'o, Owner: TagsOwner> Drop for Tags<'o, Owner> { +impl<'o, Owner: TagsOwner + 'o> Drop for Tags<'o, Owner> { fn drop(&mut self) { unsafe { ffi::notmuch_tags_destroy(self.0) @@ -33,7 +33,7 @@ impl<'o, Owner: TagsOwner> Drop for Tags<'o, Owner> { } } -impl<'o, Owner: TagsOwner> Iterator for Tags<'o, Owner> { +impl<'o, Owner: TagsOwner + 'o> Iterator for Tags<'o, Owner> { type Item = String; fn next(&mut self) -> Option { @@ -57,5 +57,5 @@ impl<'o, Owner: TagsOwner> Iterator for Tags<'o, Owner> { } } -unsafe impl<'o, Owner: TagsOwner> Send for Tags<'o, Owner>{} -unsafe impl<'o, Owner: TagsOwner> 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 1ba865e..55ed982 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -29,16 +29,16 @@ impl Drop for ThreadPtr { #[derive(Debug)] -pub struct Thread<'o, Owner: ThreadOwner>{ +pub struct Thread<'o, Owner: ThreadOwner + 'o>{ pub(crate) handle: ThreadPtr, phantom: PhantomData<&'o Owner>, } -impl<'o, Owner: ThreadOwner> MessagesOwner for Thread<'o, Owner>{} -impl<'o, Owner: ThreadOwner> TagsOwner for Thread<'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> FromPtr<*mut ffi::notmuch_thread_t> 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}, @@ -47,7 +47,7 @@ impl<'o, Owner: ThreadOwner> FromPtr<*mut ffi::notmuch_thread_t> for Thread<'o, } } -impl<'o, Owner: ThreadOwner> Thread<'o, Owner>{ +impl<'o, Owner: ThreadOwner + 'o> Thread<'o, Owner>{ pub fn id(self: &Self) -> String{ let tid = unsafe { @@ -124,5 +124,5 @@ impl<'o, Owner: ThreadOwner> Thread<'o, Owner>{ } -unsafe impl<'o, Owner: ThreadOwner> Send for Thread<'o, Owner> {} -unsafe impl<'o, Owner: ThreadOwner> Sync for Thread<'o, Owner> {} +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 09f51bf..a2edef8 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -25,15 +25,15 @@ impl Drop for ThreadsPtr { } #[derive(Debug)] -pub struct Threads<'o, Owner: ThreadsOwner>{ +pub struct Threads<'o, Owner: ThreadsOwner + 'o>{ handle: ThreadsPtr, phantom: PhantomData<&'o Owner>, } -impl<'o, Owner: ThreadsOwner> ThreadOwner for Threads<'o, Owner>{} +impl<'o, Owner: ThreadsOwner + 'o> ThreadOwner for Threads<'o, Owner>{} -impl<'o, Owner: ThreadsOwner> FromPtr<*mut ffi::notmuch_threads_t> 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}, @@ -42,7 +42,7 @@ impl<'o, Owner: ThreadsOwner> FromPtr<*mut ffi::notmuch_threads_t> for Threads<' } } -impl<'o, Owner: ThreadsOwner> Iterator for Threads<'o, Owner> { +impl<'o, Owner: ThreadsOwner + 'o> Iterator for Threads<'o, Owner> { type Item = Thread<'o, Self>; fn next(self: &mut Self) -> Option { @@ -65,5 +65,5 @@ impl<'o, Owner: ThreadsOwner> Iterator for Threads<'o, Owner> { } } -unsafe impl<'o, Owner: ThreadsOwner> Send for Threads<'o, Owner> {} -unsafe impl<'o, Owner: ThreadsOwner> Sync for Threads<'o, Owner> {} +unsafe impl<'o, Owner: ThreadsOwner + 'o> Send for Threads<'o, Owner> {} +unsafe impl<'o, Owner: ThreadsOwner + 'o> Sync for Threads<'o, Owner> {} -- cgit v1.2.1 From 2932d67d87fa2ff41fcdf46ce269ba5b49294930 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 30 Oct 2018 20:31:09 +0100 Subject: export the sort enum --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 2a083d6..c8ab078 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,4 +31,4 @@ pub use threads::{Threads, ThreadsOwner}; pub use thread::{Thread, ThreadOwner}; pub use filenames::{Filenames, FilenamesOwner}; -pub use ffi::DatabaseMode; +pub use ffi::{DatabaseMode, Sort}; -- cgit v1.2.1 From 7d2be237297c16628cb3d58774e808cac9c92fc1 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 1 Nov 2018 21:55:00 +0100 Subject: improve lifetime management with supercow --- Cargo.toml | 1 + src/database.rs | 199 ++++++++++++++++++++++++++++--------------------------- src/directory.rs | 62 +++++++---------- src/error.rs | 9 +-- src/filenames.rs | 53 +++++++-------- src/lib.rs | 28 ++++---- src/message.rs | 120 +++++++++++++++------------------ src/messages.rs | 90 +++++++++++-------------- src/query.rs | 105 ++++++++++------------------- src/tags.rs | 65 +++++++++--------- src/thread.rs | 126 +++++++++++++++-------------------- src/threads.rs | 55 +++++++-------- src/utils.rs | 31 +++------ tests/main.rs | 12 ++-- 14 files changed, 421 insertions(+), 535 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index cc152bf..0d8ee81 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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>(path: &P) -> Result { 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>(path: &P, mode: DatabaseMode) -> Result { 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, F: FnMut(&str)>( - path: &P, backup_path: Option<&P>, + path: &P, + backup_path: Option<&P>, ) -> Result<()> { let status: Option = None; Database::_compact(path, backup_path, status) } pub fn compact_with_status, 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, F: FnMut(&str)>( - path: &P, backup_path: Option<&P>, status: Option, + path: &P, + backup_path: Option<&P>, + status: Option, ) -> Result<()> { - - extern fn wrapper( - message:*const libc::c_char, closure: *mut libc::c_void, + extern "C" fn wrapper( + 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::) } 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::) + } 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(&mut self) -> Result<()> { @@ -170,26 +171,26 @@ impl Database { } fn _upgrade(&mut self, status: Option) -> Result<()> { - #[allow(trivial_numeric_casts)] - extern fn wrapper( - closure: *mut libc::c_void, progress: libc::c_double, - ) { + extern "C" fn wrapper(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::) } 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::) + } 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> { 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> { - - let tags = unsafe { - ffi::notmuch_database_get_all_tags(self.handle.ptr) - }; + pub fn all_tags<'d>(&'d self) -> Result> { + 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{ - Filenames{ - handle: self.handle.child_directories(), - phantom: PhantomData +impl<'d> Directory<'d> { + pub fn from_ptr>>( + 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 { + 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>>( + 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 { + 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> {} diff --git a/src/lib.rs b/src/lib.rs index c8ab078..595088d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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>>( + 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{ - Filenames::from_ptr(unsafe { - ffi::notmuch_message_get_filenames(self.handle.ptr) - }) + pub fn filenames(self: &Self) -> Filenames { + 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>>( + 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> { + 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 { - - 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>>( + 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 { 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> - { + pub fn search_messages<'q>(self: &'d Self) -> Result> { 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 - { + pub fn count_messages(self: &Self) -> Result { 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> - { + pub fn search_threads<'q>(self: &'d Self) -> Result> { 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 - { + pub fn count_threads(self: &Self) -> Result { 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>>( + 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 { + 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>>( + 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{ - Messages::from_ptr(unsafe { - ffi::notmuch_thread_get_toplevel_messages(self.handle.ptr) - }) + pub fn toplevel_messages(self: &Self) -> Messages { + 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{ - Messages::from_ptr(unsafe { - ffi::notmuch_thread_get_messages(self.handle.ptr) - }) + pub fn messages(self: &Self) -> Messages { + 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{ - let athrs = unsafe { - ffi::notmuch_thread_get_authors(self.handle.ptr) - }; + pub fn authors(self: &Self) -> Vec { + 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>>( + 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 { - - 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> { + 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 { - fn from_ptr(ptr: T) -> Self; -} - -// pub trait NewFromPtr { -// fn new(ptr: T, parent: Rc

) -> 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; +} 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); -- cgit v1.2.1 From 9d7bb8e01a7ec9fea02b31334822a95e10d5a7e4 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 1 Nov 2018 21:58:03 +0100 Subject: bump version --- Cargo.toml | 2 +- README.md | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0d8ee81..8809644 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "notmuch" -version = "0.2.1" +version = "0.3.0" authors = ["Dirk Van Haerenborgh "] homepage = "https://github.com/vhdirk/notmuch-rs" repository = "https://github.com/vhdirk/notmuch-rs" diff --git a/README.md b/README.md index 4e1d86b..2847e32 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -notmuch-rs -========== +# notmuch-rs This is not much more than a wrapper for the [notmuch](https://notmuchmail.org/) C api. @@ -9,8 +8,8 @@ This is not much more than a wrapper for the [notmuch](https://notmuchmail.org/) [![License](https://img.shields.io/crates/l/notmuch.svg)](https://crates.io/crates/notmuch) ## Building -**notmuch-rs** expects libnotmuch development files to be installed on your system. +**notmuch-rs** expects libnotmuch development files to be installed on your system. ## Using -- cgit v1.2.1 From 361e1a8f12590c49b969fc4c01ede1454ec69776 Mon Sep 17 00:00:00 2001 From: eaon Date: Fri, 2 Nov 2018 18:02:37 -0400 Subject: Add Message::{date,add_tag,remove_tag,remove_all_tags} and make clippy usable (#6) * Removing unnecessary lifetimes and borrows * Add Message::{date,add_tag,remove_tag,remove_all_tags} * Make sure clippy doesn't error out --- src/ffi.rs | 6 +++--- src/message.rs | 34 +++++++++++++++++++++++++++++++--- src/thread.rs | 2 +- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/ffi.rs b/src/ffi.rs index 3c281fa..373dc53 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -47,14 +47,14 @@ notmuch_enum! { } impl notmuch_status_t { - pub fn is_ok(&self) -> bool { - match *self { + pub fn is_ok(self) -> bool { + match self { notmuch_status_t::NOTMUCH_STATUS_SUCCESS => true, _ => false, } } - pub fn is_err(&self) -> bool { + pub fn is_err(self) -> bool { !self.is_ok() } diff --git a/src/message.rs b/src/message.rs index 624817d..ed72997 100644 --- a/src/message.rs +++ b/src/message.rs @@ -5,6 +5,7 @@ use supercow::Phantomcow; use error::{Error, Result}; use ffi; +use ffi::Status; use utils::ToStr; use Filenames; use FilenamesOwner; @@ -57,7 +58,7 @@ impl<'o, Owner: MessageOwner + 'o> Message<'o, Owner> { tid.to_str().unwrap().to_string() } - pub fn replies<'s>(self: &'s Self) -> Messages<'s, Self> { + pub fn replies(self: &Self) -> Messages { Messages::from_ptr( unsafe { ffi::notmuch_message_get_replies(self.handle.ptr) }, self, @@ -84,9 +85,16 @@ impl<'o, Owner: MessageOwner + 'o> Message<'o, Owner> { ) } + pub fn date(&self) -> i64 { + unsafe { + ffi::notmuch_message_get_date(self.handle.ptr) + } + } + pub fn header(&self, name: &str) -> Result<&str> { + let name = CString::new(name).unwrap(); 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, name.as_ptr()) }; if ret.is_null() { Err(Error::UnspecifiedError) @@ -95,12 +103,32 @@ impl<'o, Owner: MessageOwner + 'o> Message<'o, Owner> { } } - pub fn tags<'m>(&'m self) -> Tags<'m, Self> { + pub fn tags(&self) -> Tags { Tags::from_ptr( unsafe { ffi::notmuch_message_get_tags(self.handle.ptr) }, self, ) } + + pub fn add_tag(self: &Self, tag: &str) -> Status { + let tag = CString::new(tag).unwrap(); + Status::from(unsafe { + ffi::notmuch_message_add_tag(self.handle.ptr, tag.as_ptr()) + }) + } + + pub fn remove_tag(self: &Self, tag: &str) -> Status { + let tag = CString::new(tag).unwrap(); + Status::from(unsafe { + ffi::notmuch_message_remove_tag(self.handle.ptr, tag.as_ptr()) + }) + } + + pub fn remove_all_tags(self: &Self) -> Status { + Status::from(unsafe { + ffi::notmuch_message_remove_all_tags(self.handle.ptr) + }) + } } unsafe impl<'o, Owner: MessageOwner + 'o> Send for Message<'o, Owner> {} diff --git a/src/thread.rs b/src/thread.rs index 9a63c94..c112e06 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -71,7 +71,7 @@ impl<'o, Owner: ThreadOwner + 'o> Thread<'o, Owner> { ) } - pub fn tags<'t>(&'t self) -> Tags<'t, Self> { + pub fn tags(&self) -> Tags { Tags::from_ptr( unsafe { ffi::notmuch_thread_get_tags(self.handle.ptr) }, self, -- cgit v1.2.1 From f2e74aad70b3dceab9c9d78db333f6d71066cbff Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 2 Nov 2018 23:03:56 +0100 Subject: bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 8809644..37d48cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "notmuch" -version = "0.3.0" +version = "0.3.1" authors = ["Dirk Van Haerenborgh "] homepage = "https://github.com/vhdirk/notmuch-rs" repository = "https://github.com/vhdirk/notmuch-rs" -- cgit v1.2.1 From 08aa3be11a25c8ccbdf4806a4a08c9267cae9140 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 4 Nov 2018 19:42:46 +0100 Subject: start adding 'Ext' threads to enable more flexible supercow api --- src/database.rs | 22 +++++++++++++------ src/directory.rs | 30 +++++++++++++++++++++++++- src/lib.rs | 2 +- src/messages.rs | 12 ++++++++++- src/query.rs | 66 +++++++++++++++++++++++++++++++++++++++++--------------- src/threads.rs | 9 ++++++++ tests/main.rs | 15 +++++++++++-- 7 files changed, 128 insertions(+), 28 deletions(-) diff --git a/src/database.rs b/src/database.rs index 6390c15..67ed3da 100644 --- a/src/database.rs +++ b/src/database.rs @@ -10,6 +10,7 @@ use ffi; use utils::ToStr; use Directory; use Query; +use query::QueryPtr; use Tags; use TagsOwner; @@ -36,6 +37,17 @@ impl Drop for DatabasePtr { } } +impl DatabasePtr { + + pub(crate) fn create_query(&self, query_string: &str) -> Result { + let query_str = CString::new(query_string).unwrap(); + + let query = unsafe { ffi::notmuch_query_create(self.ptr, query_str.as_ptr()) }; + + Ok(QueryPtr { ptr: query }) + } +} + #[derive(Debug)] pub struct Database { pub(crate) handle: DatabasePtr, @@ -74,7 +86,7 @@ impl Database { Ok(()) } - + pub fn compact, F: FnMut(&str)>( path: &P, backup_path: Option<&P>, @@ -214,11 +226,9 @@ impl Database { } pub fn create_query<'d>(&'d self, query_string: &str) -> Result> { - let query_str = CString::new(query_string).unwrap(); - - let query = unsafe { ffi::notmuch_query_create(self.handle.ptr, query_str.as_ptr()) }; - - Ok(Query::from_ptr(query, self)) + self.handle.create_query(query_string).map(move |handle|{ + Query::from_handle(handle, self) + }) } pub fn all_tags<'d>(&'d self) -> Result> { diff --git a/src/directory.rs b/src/directory.rs index 9bdae2d..c179eb8 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -1,6 +1,10 @@ +use std::ffi::{CStr, CString}; use std::ops::Drop; -use supercow::Phantomcow; +use std::path::Path; +use std::ptr; +use supercow::{Supercow, Phantomcow}; +use error::Result; use ffi; use Database; use Filenames; @@ -36,6 +40,30 @@ impl<'d> Directory<'d> { } } + pub fn new>, + P: AsRef>(owner: O, path: &P) -> Result>> { + let db = owner.into(); + 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(db.handle.ptr, path_str.as_ptr(), &mut dir) + } + .as_result() + ); + + if dir.is_null() { + Ok(None) + } else { + Ok(Some(Directory { + handle: DirectoryPtr { ptr: dir }, + marker: Supercow::phantom(db), + })) + } + } + + pub fn child_directories(&self) -> Filenames { Filenames::from_ptr( unsafe { ffi::notmuch_directory_get_child_directories(self.handle.ptr) }, diff --git a/src/lib.rs b/src/lib.rs index 595088d..d8f72d3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,7 +27,7 @@ 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 query::{Query, QueryExt}; pub use tags::{Tags, TagsOwner}; pub use thread::{Thread, ThreadOwner}; pub use threads::{Threads, ThreadsOwner}; diff --git a/src/messages.rs b/src/messages.rs index 08a9cf3..8863bef 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -35,7 +35,7 @@ pub struct Messages<'o, Owner: MessagesOwner + 'o> { } impl<'o, Owner: MessagesOwner + 'o> Messages<'o, Owner> { - pub fn from_ptr>>( + pub(crate) fn from_ptr>>( ptr: *mut ffi::notmuch_messages_t, owner: O, ) -> Messages<'o, Owner> { @@ -44,6 +44,16 @@ impl<'o, Owner: MessagesOwner + 'o> Messages<'o, Owner> { marker: owner.into(), } } + + pub(crate) fn from_handle>>( + handle: MessagesPtr, + owner: O, + ) -> Messages<'o, Owner> { + Messages { + handle, + marker: owner.into(), + } + } } impl<'o, Owner: MessagesOwner + 'o> MessageOwner for Messages<'o, Owner> {} diff --git a/src/query.rs b/src/query.rs index a90a0fe..7cf940c 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,6 +1,8 @@ use std::ops::Drop; use std::ptr; -use supercow::Phantomcow; +use std::ffi::{CStr, CString}; + +use supercow::{Supercow, Phantomcow}; use error::Result; use ffi; @@ -10,6 +12,8 @@ use Messages; use MessagesOwner; use Threads; use ThreadsOwner; +use threads::ThreadsPtr; +use messages::MessagesPtr; #[derive(Debug)] pub(crate) struct QueryPtr { @@ -32,18 +36,23 @@ impl<'d> ThreadsOwner for Query<'d> {} impl<'d> MessagesOwner for Query<'d> {} impl<'d> Query<'d> { - pub fn from_ptr>>( - ptr: *mut ffi::notmuch_query_t, + pub(crate) fn from_handle>>( + handle: QueryPtr, owner: O, ) -> Query<'d> { Query { - handle: QueryPtr { ptr }, + handle, marker: owner.into(), } } - pub fn create(db: &'d Database, query_string: &str) -> Result { - db.create_query(query_string) + pub fn create>>(db: D, + query_string: &str) -> Result { + + let dbref = db.into(); + dbref.handle.create_query(query_string).map(move |handle|{ + Query::from_handle(handle, Supercow::phantom(dbref)) + }) } /// Specify the sorting desired for this query. @@ -59,12 +68,7 @@ impl<'d> Query<'d> { /// Filter messages according to the query and return pub fn search_messages<'q>(self: &'d Self) -> Result> { - let mut msgs = ptr::null_mut(); - try!( - unsafe { ffi::notmuch_query_search_messages(self.handle.ptr, &mut msgs,) }.as_result() - ); - - Ok(Messages::from_ptr(msgs, self)) + ::search_messages(self) } pub fn count_messages(self: &Self) -> Result { @@ -75,12 +79,8 @@ impl<'d> Query<'d> { } pub fn search_threads<'q>(self: &'d Self) -> Result> { - let mut thrds = ptr::null_mut(); - try!( - unsafe { ffi::notmuch_query_search_threads(self.handle.ptr, &mut thrds,) }.as_result() - ); + ::search_threads(self) - Ok(Threads::from_ptr(thrds, self)) } pub fn count_threads(self: &Self) -> Result { @@ -91,5 +91,37 @@ impl<'d> Query<'d> { } } +pub trait QueryExt<'d>{ + fn search_threads<'q, Q: Into>>>(query: Q) -> Result>>; + fn search_messages<'q, Q: Into>>>(query: Q) -> Result>>; + +} + +impl<'d> QueryExt<'d> for Query<'d>{ + fn search_threads<'q, Q: Into>>>(query: Q) -> Result>>{ + let queryref = query.into(); + + let mut thrds = ptr::null_mut(); + try!( + unsafe { ffi::notmuch_query_search_threads(queryref.handle.ptr, &mut thrds) }.as_result() + ); + + Ok(Threads::from_ptr(thrds, Supercow::phantom(queryref))) + } + + fn search_messages<'q, Q: Into>>>(query: Q) -> Result>>{ + let queryref = query.into(); + + let mut msgs = ptr::null_mut(); + try!( + unsafe { ffi::notmuch_query_search_messages(queryref.handle.ptr, &mut msgs) }.as_result() + ); + + Ok(Messages::from_ptr(msgs, Supercow::phantom(queryref))) + } + +} + + unsafe impl<'d> Send for Query<'d> {} unsafe impl<'d> Sync for Query<'d> {} diff --git a/src/threads.rs b/src/threads.rs index 359569e..6dfa047 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -38,6 +38,15 @@ impl<'o, Owner: ThreadsOwner + 'o> Threads<'o, Owner> { marker: owner.into(), } } + pub(crate) fn from_handle>>( + handle: ThreadsPtr, + owner: O, + ) -> Threads<'o, Owner> { + Threads { + handle, + marker: owner.into(), + } + } } impl<'s, 'o: 's, Owner: ThreadsOwner + 'o> StreamingIterator<'s, Thread<'s, Self>> diff --git a/tests/main.rs b/tests/main.rs index d790e21..fd7e511 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -1,6 +1,8 @@ extern crate notmuch; extern crate dirs; +use std::sync::Arc; + use notmuch::StreamingIterator; fn main() { @@ -16,10 +18,19 @@ fn main() { let rev = db.revision(); println!("db revision: {:?}", rev); } - - let query = db.create_query(&"".to_string()).unwrap(); + let query = { + let dbr = Arc::new(db); + + notmuch::Query::create(dbr.clone(), &"".to_string()).unwrap() + }; + + let mut threads = query.search_threads().unwrap(); + + + //let mut threads = db.create_query(&"".to_string()).unwrap().search_threads().unwrap(); + while let Some(thread) = threads.next() { println!("thread {:?} {:?}", thread.subject(), thread.authors()); } -- cgit v1.2.1 From 228e7665bc4dc20929ea2a8cb52600da3d4dd839 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 4 Nov 2018 21:11:59 +0100 Subject: add MessageExt trait --- src/database.rs | 5 +++++ src/directory.rs | 4 ++++ src/message.rs | 22 +++++++++++++++++++++- src/query.rs | 1 - src/tags.rs | 5 +++++ src/thread.rs | 4 ++++ src/threads.rs | 4 ++++ tests/main.rs | 8 ++++++-- 8 files changed, 49 insertions(+), 4 deletions(-) diff --git a/src/database.rs b/src/database.rs index 67ed3da..8a125b4 100644 --- a/src/database.rs +++ b/src/database.rs @@ -238,5 +238,10 @@ impl Database { } } +pub trait DatabaseExt{ + +} + + unsafe impl Send for Database {} unsafe impl Sync for Database {} diff --git a/src/directory.rs b/src/directory.rs index c179eb8..8ddc044 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -72,5 +72,9 @@ impl<'d> Directory<'d> { } } +pub trait DirectoryExt<'d>{ + +} + unsafe impl<'d> Send for Directory<'d> {} unsafe impl<'d> Sync for Directory<'d> {} diff --git a/src/message.rs b/src/message.rs index ed72997..f825e03 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,7 +1,7 @@ use std::ffi::CString; use std::ops::Drop; use std::path::PathBuf; -use supercow::Phantomcow; +use supercow::{Supercow, Phantomcow}; use error::{Error, Result}; use ffi; @@ -131,5 +131,25 @@ impl<'o, Owner: MessageOwner + 'o> Message<'o, Owner> { } } + +pub trait MessageExt<'o, Owner: MessageOwner + 'o>{ + + fn replies<'s, M: Into>>>(message: M) -> Messages<'s, Message<'o, Owner>> { + let messageref = message.into(); + Messages::from_ptr( + unsafe { ffi::notmuch_message_get_replies(messageref.handle.ptr) }, + Supercow::phantom(messageref) + ) + } + + fn filenames<'s, M: Into>>>(message: M) -> Filenames<'s, Message<'o, Owner>> { + let messageref = message.into(); + Filenames::from_ptr( + unsafe { ffi::notmuch_message_get_filenames(messageref.handle.ptr) }, + Supercow::phantom(messageref) + ) + } +} + 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/query.rs b/src/query.rs index 7cf940c..4839f3b 100644 --- a/src/query.rs +++ b/src/query.rs @@ -94,7 +94,6 @@ impl<'d> Query<'d> { pub trait QueryExt<'d>{ fn search_threads<'q, Q: Into>>>(query: Q) -> Result>>; fn search_messages<'q, Q: Into>>>(query: Q) -> Result>>; - } impl<'d> QueryExt<'d> for Query<'d>{ diff --git a/src/tags.rs b/src/tags.rs index 187e26c..243cfbc 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -58,5 +58,10 @@ impl<'o, Owner: TagsOwner + 'o> Iterator for Tags<'o, Owner> { } } + +pub trait TagsExt<'o, Owner: TagsOwner + 'o>{ + +} + 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 c112e06..36da638 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -106,5 +106,9 @@ impl<'o, Owner: ThreadOwner + 'o> Thread<'o, Owner> { } } +pub trait ThreadExt<'o, Owner: ThreadOwner + 'o>{ + +} + 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 6dfa047..bf869ab 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -69,5 +69,9 @@ impl<'s, 'o: 's, Owner: ThreadsOwner + 'o> StreamingIterator<'s, Thread<'s, Self } } +pub trait ThreadsExt<'o, Owner: ThreadsOwner + 'o>{ + +} + unsafe impl<'o, Owner: ThreadsOwner + 'o> Send for Threads<'o, Owner> {} unsafe impl<'o, Owner: ThreadsOwner + 'o> Sync for Threads<'o, Owner> {} diff --git a/tests/main.rs b/tests/main.rs index fd7e511..11723b2 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -4,6 +4,7 @@ extern crate dirs; use std::sync::Arc; use notmuch::StreamingIterator; +use notmuch::{Query, QueryExt}; fn main() { @@ -25,11 +26,14 @@ fn main() { }; - let mut threads = query.search_threads().unwrap(); + // let mut threads = query.search_threads().unwrap(); - //let mut threads = db.create_query(&"".to_string()).unwrap().search_threads().unwrap(); + // let mut threads = db.create_query(&"".to_string()).unwrap().search_threads().unwrap(); + + let mut threads = ::search_threads(query).unwrap(); + while let Some(thread) = threads.next() { println!("thread {:?} {:?}", thread.subject(), thread.authors()); -- cgit v1.2.1 From 942740b143c8f07f402da8e20338c8f769fe5447 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 5 Nov 2018 08:15:27 +0100 Subject: implement 'Ext' traits for all types exept iterators --- src/database.rs | 56 +++++++++++++++++++++++++++++++++++++++----------------- src/directory.rs | 36 ++++++++++-------------------------- src/message.rs | 31 +++++++++++++++++-------------- src/messages.rs | 9 +++++++++ src/query.rs | 20 ++++++++++++++------ src/tags.rs | 4 ++++ src/thread.rs | 46 +++++++++++++++++++++++++++++++++------------- src/threads.rs | 4 ++++ 8 files changed, 130 insertions(+), 76 deletions(-) diff --git a/src/database.rs b/src/database.rs index 8a125b4..b73c5c2 100644 --- a/src/database.rs +++ b/src/database.rs @@ -3,6 +3,8 @@ use std::ops::Drop; use std::path::Path; use std::ptr; +use supercow::Supercow; + use libc; use error::Result; @@ -208,12 +210,46 @@ impl Database { } pub fn directory<'d, P: AsRef>(&'d self, path: &P) -> Result>> { + ::directory(self, path) + } + + pub fn create_query<'d>(&'d self, query_string: &str) -> Result> { + ::create_query(self, query_string) + } + + pub fn all_tags<'d>(&'d self) -> Result> { + ::all_tags(self) + } +} + +pub trait DatabaseExt{ + fn create_query<'d, D: Into>>(database: D, query_string: &str) -> Result> { + let dbref = database.into(); + let query_str = CString::new(query_string).unwrap(); + + let query = unsafe { ffi::notmuch_query_create(dbref.handle.ptr, query_str.as_ptr()) }; + + Ok(Query::from_ptr(query, Supercow::phantom(dbref))) + } + + fn all_tags<'d, D: Into>>(database: D) -> Result> { + let dbref = database.into(); + + let tags = unsafe { ffi::notmuch_database_get_all_tags(dbref.handle.ptr) }; + + Ok(Tags::from_ptr(tags, Supercow::phantom(dbref))) + } + + + fn directory<'d, D: Into>, P: AsRef>(database: D, path: &P) -> Result>> { + let dbref = database.into(); + 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) + ffi::notmuch_database_get_directory(dbref.handle.ptr, path_str.as_ptr(), &mut dir) } .as_result() ); @@ -221,26 +257,12 @@ impl Database { if dir.is_null() { Ok(None) } else { - Ok(Some(Directory::from_ptr(dir, self))) + Ok(Some(Directory::from_ptr(dir, Supercow::phantom(dbref)))) } } - - pub fn create_query<'d>(&'d self, query_string: &str) -> Result> { - self.handle.create_query(query_string).map(move |handle|{ - Query::from_handle(handle, self) - }) - } - - pub fn all_tags<'d>(&'d self) -> Result> { - let tags = unsafe { ffi::notmuch_database_get_all_tags(self.handle.ptr) }; - - Ok(Tags::from_ptr(tags, self)) - } } -pub trait DatabaseExt{ - -} +impl DatabaseExt for Database{} unsafe impl Send for Database {} diff --git a/src/directory.rs b/src/directory.rs index 8ddc044..0aa5b80 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -40,41 +40,25 @@ impl<'d> Directory<'d> { } } - pub fn new>, - P: AsRef>(owner: O, path: &P) -> Result>> { - let db = owner.into(); - 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(db.handle.ptr, path_str.as_ptr(), &mut dir) - } - .as_result() - ); - - if dir.is_null() { - Ok(None) - } else { - Ok(Some(Directory { - handle: DirectoryPtr { ptr: dir }, - marker: Supercow::phantom(db), - })) - } + pub fn child_directories(&self) -> Filenames { + ::child_directories(self) } +} - - pub fn child_directories(&self) -> Filenames { +pub trait DirectoryExt<'d>{ + fn child_directories<'s, S: Into>>>(directory: S) -> Filenames<'s, Directory<'d>> { + let dir = directory.into(); Filenames::from_ptr( - unsafe { ffi::notmuch_directory_get_child_directories(self.handle.ptr) }, - self, + unsafe { ffi::notmuch_directory_get_child_directories(dir.handle.ptr) }, + Supercow::phantom(dir), ) } } -pub trait DirectoryExt<'d>{ +impl<'d> DirectoryExt<'d> for Directory<'d>{ } + unsafe impl<'d> Send for Directory<'d> {} unsafe impl<'d> Sync for Directory<'d> {} diff --git a/src/message.rs b/src/message.rs index f825e03..4c35544 100644 --- a/src/message.rs +++ b/src/message.rs @@ -59,10 +59,7 @@ impl<'o, Owner: MessageOwner + 'o> Message<'o, Owner> { } pub fn replies(self: &Self) -> Messages { - Messages::from_ptr( - unsafe { ffi::notmuch_message_get_replies(self.handle.ptr) }, - self, - ) + >::replies(self) } #[cfg(feature = "v0_26")] @@ -71,10 +68,7 @@ impl<'o, Owner: MessageOwner + 'o> Message<'o, Owner> { } pub fn filenames(self: &Self) -> Filenames { - Filenames::from_ptr( - unsafe { ffi::notmuch_message_get_filenames(self.handle.ptr) }, - self, - ) + >::filenames(self) } pub fn filename(self: &Self) -> PathBuf { @@ -104,10 +98,7 @@ impl<'o, Owner: MessageOwner + 'o> Message<'o, Owner> { } pub fn tags(&self) -> Tags { - Tags::from_ptr( - unsafe { ffi::notmuch_message_get_tags(self.handle.ptr) }, - self, - ) + >::tags(self) } pub fn add_tag(self: &Self, tag: &str) -> Status { @@ -134,7 +125,15 @@ impl<'o, Owner: MessageOwner + 'o> Message<'o, Owner> { pub trait MessageExt<'o, Owner: MessageOwner + 'o>{ - fn replies<'s, M: Into>>>(message: M) -> Messages<'s, Message<'o, Owner>> { + fn tags<'s, S: Into>>>(message: S) -> Tags<'s, Message<'o, Owner>> { + let messageref = message.into(); + Tags::from_ptr( + unsafe { ffi::notmuch_message_get_tags(messageref.handle.ptr) }, + Supercow::phantom(messageref) + ) + } + + fn replies<'s, S: Into>>>(message: S) -> Messages<'s, Message<'o, Owner>> { let messageref = message.into(); Messages::from_ptr( unsafe { ffi::notmuch_message_get_replies(messageref.handle.ptr) }, @@ -142,7 +141,7 @@ pub trait MessageExt<'o, Owner: MessageOwner + 'o>{ ) } - fn filenames<'s, M: Into>>>(message: M) -> Filenames<'s, Message<'o, Owner>> { + fn filenames<'s, S: Into>>>(message: S) -> Filenames<'s, Message<'o, Owner>> { let messageref = message.into(); Filenames::from_ptr( unsafe { ffi::notmuch_message_get_filenames(messageref.handle.ptr) }, @@ -151,5 +150,9 @@ pub trait MessageExt<'o, Owner: MessageOwner + 'o>{ } } +impl<'o, Owner: MessageOwner + 'o> MessageExt<'o, Owner> 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 8863bef..7aa1c45 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -56,6 +56,15 @@ impl<'o, Owner: MessagesOwner + 'o> Messages<'o, Owner> { } } + +pub trait MessagesExt<'o, Owner: MessagesOwner + 'o>{ + +} + +impl<'o, Owner: MessagesOwner + 'o> MessagesExt<'o, Owner> for Messages<'o, Owner>{ + +} + impl<'o, Owner: MessagesOwner + 'o> MessageOwner for Messages<'o, Owner> {} impl<'o, Owner: MessagesOwner + 'o> TagsOwner for Messages<'o, Owner> {} diff --git a/src/query.rs b/src/query.rs index 4839f3b..b502542 100644 --- a/src/query.rs +++ b/src/query.rs @@ -36,6 +36,17 @@ impl<'d> ThreadsOwner for Query<'d> {} impl<'d> MessagesOwner for Query<'d> {} impl<'d> Query<'d> { + + pub(crate) fn from_ptr>>( + ptr: *mut ffi::notmuch_query_t, + owner: O, + ) -> Query<'d> { + Query { + handle: QueryPtr{ptr}, + marker: owner.into(), + } + } + pub(crate) fn from_handle>>( handle: QueryPtr, owner: O, @@ -80,7 +91,6 @@ impl<'d> Query<'d> { pub fn search_threads<'q>(self: &'d Self) -> Result> { ::search_threads(self) - } pub fn count_threads(self: &Self) -> Result { @@ -92,11 +102,7 @@ impl<'d> Query<'d> { } pub trait QueryExt<'d>{ - fn search_threads<'q, Q: Into>>>(query: Q) -> Result>>; - fn search_messages<'q, Q: Into>>>(query: Q) -> Result>>; -} - -impl<'d> QueryExt<'d> for Query<'d>{ + fn search_threads<'q, Q: Into>>>(query: Q) -> Result>>{ let queryref = query.into(); @@ -121,6 +127,8 @@ impl<'d> QueryExt<'d> for Query<'d>{ } +impl<'d> QueryExt<'d> for Query<'d>{} + 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 243cfbc..dcf205a 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -63,5 +63,9 @@ pub trait TagsExt<'o, Owner: TagsOwner + 'o>{ } +impl<'o, Owner: TagsOwner + 'o> TagsExt<'o, Owner> 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 36da638..e9ecdad 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -1,5 +1,5 @@ use std::ops::Drop; -use supercow::Phantomcow; +use supercow::{Supercow, Phantomcow}; use ffi; use utils::ToStr; @@ -56,26 +56,17 @@ impl<'o, Owner: ThreadOwner + 'o> Thread<'o, Owner> { } pub fn toplevel_messages(self: &Self) -> Messages { - Messages::from_ptr( - unsafe { ffi::notmuch_thread_get_toplevel_messages(self.handle.ptr) }, - self, - ) + >::toplevel_messages(self) } /// Get a `Messages` iterator for all messages in 'thread' in /// oldest-first order. pub fn messages(self: &Self) -> Messages { - Messages::from_ptr( - unsafe { ffi::notmuch_thread_get_messages(self.handle.ptr) }, - self, - ) + >::messages(self) } pub fn tags(&self) -> Tags { - Tags::from_ptr( - unsafe { ffi::notmuch_thread_get_tags(self.handle.ptr) }, - self, - ) + >::tags(self) } pub fn subject(self: &Self) -> String { @@ -107,7 +98,36 @@ impl<'o, Owner: ThreadOwner + 'o> Thread<'o, Owner> { } pub trait ThreadExt<'o, Owner: ThreadOwner + 'o>{ + fn tags<'s, S: Into>>>(thread: S) -> Tags<'s, Thread<'o, Owner>> { + let threadref = thread.into(); + Tags::from_ptr( + unsafe { ffi::notmuch_thread_get_tags(threadref.handle.ptr) }, + Supercow::phantom(threadref) + ) + } + + fn toplevel_messages<'s, S: Into>>>(thread: S) -> Messages<'s, Thread<'o, Owner>> { + let threadref = thread.into(); + Messages::from_ptr( + unsafe { ffi::notmuch_thread_get_toplevel_messages(threadref.handle.ptr) }, + Supercow::phantom(threadref) + ) + } + + /// Get a `Messages` iterator for all messages in 'thread' in + /// oldest-first order. + fn messages<'s, S: Into>>>(thread: S) -> Messages<'s, Thread<'o, Owner>> { + let threadref = thread.into(); + Messages::from_ptr( + unsafe { ffi::notmuch_thread_get_messages(threadref.handle.ptr) }, + Supercow::phantom(threadref) + ) + } + +} +impl<'o, Owner: ThreadOwner + 'o> ThreadExt<'o, Owner> for Thread<'o, Owner>{ + } unsafe impl<'o, Owner: ThreadOwner + 'o> Send for Thread<'o, Owner> {} diff --git a/src/threads.rs b/src/threads.rs index bf869ab..54b49a9 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -73,5 +73,9 @@ pub trait ThreadsExt<'o, Owner: ThreadsOwner + 'o>{ } +impl<'o, Owner: ThreadsOwner + 'o> ThreadsExt<'o, Owner> for Threads<'o, Owner>{ + +} + unsafe impl<'o, Owner: ThreadsOwner + 'o> Send for Threads<'o, Owner> {} unsafe impl<'o, Owner: ThreadsOwner + 'o> Sync for Threads<'o, Owner> {} -- cgit v1.2.1 From cc92fea48a3c444822c14ccb6cdfd748f065ef27 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 5 Nov 2018 08:41:39 +0100 Subject: implement StreamingIteratorExt for iterator types --- src/lib.rs | 16 ++++++++-------- src/messages.rs | 35 +++++++++++++++++++++-------------- src/threads.rs | 45 ++++++++++++++++++++++----------------------- src/utils.rs | 10 ++++++++++ tests/main.rs | 8 ++++---- 5 files changed, 65 insertions(+), 49 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d8f72d3..80916e2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,16 +21,16 @@ mod tags; mod thread; mod threads; -pub use database::Database; -pub use directory::Directory; +pub use database::{Database, DatabaseExt}; +pub use directory::{Directory, DirectoryExt}; pub use error::Error; pub use filenames::{Filenames, FilenamesOwner}; -pub use message::{Message, MessageOwner}; -pub use messages::{Messages, MessagesOwner}; +pub use message::{Message, MessageExt, MessageOwner}; +pub use messages::{Messages, MessagesExt, MessagesOwner}; pub use query::{Query, QueryExt}; -pub use tags::{Tags, TagsOwner}; -pub use thread::{Thread, ThreadOwner}; -pub use threads::{Threads, ThreadsOwner}; +pub use tags::{Tags, TagsExt, TagsOwner}; +pub use thread::{Thread, ThreadExt, ThreadOwner}; +pub use threads::{Threads, ThreadsExt, ThreadsOwner}; pub use ffi::{DatabaseMode, Sort}; -pub use utils::StreamingIterator; +pub use utils::{StreamingIterator, StreamingIteratorExt}; diff --git a/src/messages.rs b/src/messages.rs index 7aa1c45..7a0a48c 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -3,7 +3,7 @@ use std::ops::Drop; use supercow::{Phantomcow, Supercow}; use ffi; -use utils::StreamingIterator; +use utils::{StreamingIterator, StreamingIteratorExt}; use Message; use MessageOwner; use Tags; @@ -56,15 +56,6 @@ impl<'o, Owner: MessagesOwner + 'o> Messages<'o, Owner> { } } - -pub trait MessagesExt<'o, Owner: MessagesOwner + 'o>{ - -} - -impl<'o, Owner: MessagesOwner + 'o> MessagesExt<'o, Owner> for Messages<'o, Owner>{ - -} - impl<'o, Owner: MessagesOwner + 'o> MessageOwner for Messages<'o, Owner> {} impl<'o, Owner: MessagesOwner + 'o> TagsOwner for Messages<'o, Owner> {} @@ -94,19 +85,35 @@ impl<'s, 'o: 's, Owner: MessagesOwner + 'o> StreamingIterator<'s, Message<'s, Se for Messages<'o, Owner> { fn next(&'s mut self) -> Option> { - let valid = unsafe { ffi::notmuch_messages_valid(self.handle.ptr) }; + >>::next(Supercow::borrowed(self)) + } +} + +pub trait MessagesExt<'o, Owner: MessagesOwner + 'o> { + +} + +impl<'o, Owner: MessagesOwner + 'o> MessagesExt<'o, Owner> for Messages<'o, Owner>{ + +} + +impl<'s, 'o: 's, Owner: MessagesOwner + 'o> StreamingIteratorExt<'s, Message<'s, Self>> for Messages<'o, Owner> +{ + fn next>>>(messages: S) -> Option>{ + let messagesref = messages.into(); + let valid = unsafe { ffi::notmuch_messages_valid(messagesref.handle.ptr) }; if valid == 0 { return None; } let cmsg = unsafe { - let msg = ffi::notmuch_messages_get(self.handle.ptr); - ffi::notmuch_messages_move_to_next(self.handle.ptr); + let msg = ffi::notmuch_messages_get(messagesref.handle.ptr); + ffi::notmuch_messages_move_to_next(messagesref.handle.ptr); msg }; - Some(Message::from_ptr(cmsg, Supercow::borrowed(self))) + Some(Message::from_ptr(cmsg, Supercow::phantom(messagesref))) } } diff --git a/src/threads.rs b/src/threads.rs index 54b49a9..5083f87 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -1,7 +1,7 @@ use std::ops::Drop; use supercow::{Phantomcow, Supercow}; -use utils::StreamingIterator; +use utils::{StreamingIterator, StreamingIteratorExt}; use ffi; use thread::ThreadOwner; @@ -38,34 +38,13 @@ impl<'o, Owner: ThreadsOwner + 'o> Threads<'o, Owner> { marker: owner.into(), } } - pub(crate) fn from_handle>>( - handle: ThreadsPtr, - owner: O, - ) -> Threads<'o, Owner> { - Threads { - handle, - marker: owner.into(), - } - } } impl<'s, 'o: 's, Owner: ThreadsOwner + 'o> StreamingIterator<'s, Thread<'s, Self>> for Threads<'o, Owner> { fn next(&'s mut self) -> Option> { - let valid = unsafe { ffi::notmuch_threads_valid(self.handle.ptr) }; - - if valid == 0 { - return None; - } - - let cthread = unsafe { - let t = ffi::notmuch_threads_get(self.handle.ptr); - ffi::notmuch_threads_move_to_next(self.handle.ptr); - t - }; - - Some(Thread::from_ptr(cthread, Supercow::borrowed(self))) + >>::next(Supercow::borrowed(self)) } } @@ -77,5 +56,25 @@ impl<'o, Owner: ThreadsOwner + 'o> ThreadsExt<'o, Owner> for Threads<'o, Owner>{ } +impl<'s, 'o: 's, Owner: ThreadsOwner + 'o> StreamingIteratorExt<'s, Thread<'s, Self>> for Threads<'o, Owner> +{ + fn next>>>(threads: S) -> Option>{ + let threadsref = threads.into(); + let valid = unsafe { ffi::notmuch_threads_valid(threadsref.handle.ptr) }; + + if valid == 0 { + return None; + } + + let cmsg = unsafe { + let msg = ffi::notmuch_threads_get(threadsref.handle.ptr); + ffi::notmuch_threads_move_to_next(threadsref.handle.ptr); + msg + }; + + Some(Thread::from_ptr(cmsg, Supercow::phantom(threadsref))) + } +} + unsafe impl<'o, Owner: ThreadsOwner + 'o> Send for Threads<'o, Owner> {} unsafe impl<'o, Owner: ThreadsOwner + 'o> Sync for Threads<'o, Owner> {} diff --git a/src/utils.rs b/src/utils.rs index 5cce04d..def8d93 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,6 +1,8 @@ use libc; use std::{ffi, str}; +use supercow::Supercow; + pub trait ToStr { fn to_str<'a>(&self) -> Result<&'a str, str::Utf8Error>; } @@ -27,3 +29,11 @@ pub trait StreamingIterator<'a, T> { /// have been consumed. fn next(&'a mut self) -> Option; } + +pub trait StreamingIteratorExt<'a, T> { + /// Return either the next item in the sequence, or `None` if all items + /// have been consumed. + fn next>>(s: S) -> Option + where Self: Sized + 'a; +} + diff --git a/tests/main.rs b/tests/main.rs index 11723b2..512aa84 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -3,8 +3,8 @@ extern crate dirs; use std::sync::Arc; -use notmuch::StreamingIterator; -use notmuch::{Query, QueryExt}; +use notmuch::{StreamingIterator, StreamingIteratorExt}; +use notmuch::{Threads, Thread, Query, QueryExt}; fn main() { @@ -32,10 +32,10 @@ fn main() { // let mut threads = db.create_query(&"".to_string()).unwrap().search_threads().unwrap(); - let mut threads = ::search_threads(query).unwrap(); + let threads = Arc::new(::search_threads(query).unwrap()); - while let Some(thread) = threads.next() { + while let Some(thread) = as StreamingIteratorExt>>>::next(threads.clone()) { println!("thread {:?} {:?}", thread.subject(), thread.authors()); } -- cgit v1.2.1 From 1b65d6fd6dddae3a365459c7ea744cca3942b6d5 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 5 Nov 2018 08:46:59 +0100 Subject: rustfmt --- src/database.rs | 25 ++-- src/directory.rs | 13 +- src/ffi.rs | 436 ++++++++++++++++++++++--------------------------------- src/message.rs | 48 +++--- src/messages.rs | 13 +- src/query.rs | 43 +++--- src/tags.rs | 9 +- src/thread.rs | 27 ++-- src/threads.rs | 13 +- src/utils.rs | 4 +- tests/main.rs | 26 ++-- 11 files changed, 280 insertions(+), 377 deletions(-) diff --git a/src/database.rs b/src/database.rs index b73c5c2..c5cb917 100644 --- a/src/database.rs +++ b/src/database.rs @@ -9,10 +9,10 @@ use libc; use error::Result; use ffi; +use query::QueryPtr; use utils::ToStr; use Directory; use Query; -use query::QueryPtr; use Tags; use TagsOwner; @@ -40,12 +40,11 @@ impl Drop for DatabasePtr { } impl DatabasePtr { - pub(crate) fn create_query(&self, query_string: &str) -> Result { let query_str = CString::new(query_string).unwrap(); let query = unsafe { ffi::notmuch_query_create(self.ptr, query_str.as_ptr()) }; - + Ok(QueryPtr { ptr: query }) } } @@ -88,7 +87,7 @@ impl Database { Ok(()) } - + pub fn compact, F: FnMut(&str)>( path: &P, backup_path: Option<&P>, @@ -222,13 +221,16 @@ impl Database { } } -pub trait DatabaseExt{ - fn create_query<'d, D: Into>>(database: D, query_string: &str) -> Result> { +pub trait DatabaseExt { + fn create_query<'d, D: Into>>( + database: D, + query_string: &str, + ) -> Result> { let dbref = database.into(); let query_str = CString::new(query_string).unwrap(); let query = unsafe { ffi::notmuch_query_create(dbref.handle.ptr, query_str.as_ptr()) }; - + Ok(Query::from_ptr(query, Supercow::phantom(dbref))) } @@ -240,8 +242,10 @@ pub trait DatabaseExt{ Ok(Tags::from_ptr(tags, Supercow::phantom(dbref))) } - - fn directory<'d, D: Into>, P: AsRef>(database: D, path: &P) -> Result>> { + fn directory<'d, D: Into>, P: AsRef>( + database: D, + path: &P, + ) -> Result>> { let dbref = database.into(); let path_str = CString::new(path.as_ref().to_str().unwrap()).unwrap(); @@ -262,8 +266,7 @@ pub trait DatabaseExt{ } } -impl DatabaseExt for Database{} - +impl DatabaseExt for Database {} unsafe impl Send for Database {} unsafe impl Sync for Database {} diff --git a/src/directory.rs b/src/directory.rs index 0aa5b80..1d14568 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -2,7 +2,7 @@ use std::ffi::{CStr, CString}; use std::ops::Drop; use std::path::Path; use std::ptr; -use supercow::{Supercow, Phantomcow}; +use supercow::{Phantomcow, Supercow}; use error::Result; use ffi; @@ -45,8 +45,10 @@ impl<'d> Directory<'d> { } } -pub trait DirectoryExt<'d>{ - fn child_directories<'s, S: Into>>>(directory: S) -> Filenames<'s, Directory<'d>> { +pub trait DirectoryExt<'d> { + fn child_directories<'s, S: Into>>>( + directory: S, + ) -> Filenames<'s, Directory<'d>> { let dir = directory.into(); Filenames::from_ptr( unsafe { ffi::notmuch_directory_get_child_directories(dir.handle.ptr) }, @@ -55,10 +57,7 @@ pub trait DirectoryExt<'d>{ } } -impl<'d> DirectoryExt<'d> for Directory<'d>{ - -} - +impl<'d> DirectoryExt<'d> for Directory<'d> {} unsafe impl<'d> Send for Directory<'d> {} unsafe impl<'d> Sync for Directory<'d> {} diff --git a/src/ffi.rs b/src/ffi.rs index 373dc53..16f9db3 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -2,26 +2,11 @@ //! Re-presentation of the notmuch C API. -use libc::{ - c_char, - c_double, - c_int, - c_uint, - c_void, - c_ulong, - time_t, -}; - -use std::{ - error, - fmt, - str, -}; - -use utils::{ - ToStr, -}; +use libc::{c_char, c_double, c_int, c_uint, c_ulong, c_void, time_t}; +use std::{error, fmt, str}; + +use utils::ToStr; notmuch_enum! { #[repr(C)] @@ -48,26 +33,28 @@ notmuch_enum! { impl notmuch_status_t { pub fn is_ok(self) -> bool { - match self { + match self { notmuch_status_t::NOTMUCH_STATUS_SUCCESS => true, _ => false, } } pub fn is_err(self) -> bool { - !self.is_ok() + !self.is_ok() } pub fn as_result(self) -> Result<(), Self> { - if self.is_ok() { Ok(()) } else { Err(self) } + if self.is_ok() { + Ok(()) + } else { + Err(self) + } } } impl ToStr for Status { fn to_str<'a>(&self) -> Result<&'a str, str::Utf8Error> { - unsafe { - notmuch_status_to_string((*self).into()) - }.to_str() + unsafe { notmuch_status_to_string((*self).into()) }.to_str() } } @@ -124,19 +111,30 @@ notmuch_enum! { } } -#[repr(C)] pub struct notmuch_database_t(c_void); -#[repr(C)] pub struct notmuch_query_t(c_void); -#[repr(C)] pub struct notmuch_threads_t(c_void); -#[repr(C)] pub struct notmuch_thread_t(c_void); -#[repr(C)] pub struct notmuch_messages_t(c_void); -#[repr(C)] pub struct notmuch_message_t(c_void); -#[repr(C)] pub struct notmuch_tags_t(c_void); -#[repr(C)] pub struct notmuch_directory_t(c_void); -#[repr(C)] pub struct notmuch_filenames_t(c_void); -#[repr(C)] pub struct notmuch_message_properties_t(c_void); -#[repr(C)] pub struct notmuch_config_list_t(c_void); -#[repr(C)] pub struct notmuch_indexopts_t(c_void); - +#[repr(C)] +pub struct notmuch_database_t(c_void); +#[repr(C)] +pub struct notmuch_query_t(c_void); +#[repr(C)] +pub struct notmuch_threads_t(c_void); +#[repr(C)] +pub struct notmuch_thread_t(c_void); +#[repr(C)] +pub struct notmuch_messages_t(c_void); +#[repr(C)] +pub struct notmuch_message_t(c_void); +#[repr(C)] +pub struct notmuch_tags_t(c_void); +#[repr(C)] +pub struct notmuch_directory_t(c_void); +#[repr(C)] +pub struct notmuch_filenames_t(c_void); +#[repr(C)] +pub struct notmuch_message_properties_t(c_void); +#[repr(C)] +pub struct notmuch_config_list_t(c_void); +#[repr(C)] +pub struct notmuch_indexopts_t(c_void); pub type notmuch_compact_status_cb_t = extern "C" fn(message: *const c_char, closure: *mut c_void); pub type notmuch_database_upgrade_cb_t = extern "C" fn(closure: *mut c_void, progress: c_double); @@ -146,14 +144,12 @@ pub const TRUE: notmuch_bool_t = 1; pub const FALSE: notmuch_bool_t = 0; #[link(name = "notmuch")] -extern { +extern "C" { /// Get a string representation of a `notmuch_status_t` value. /// /// The result is read-only. - pub fn notmuch_status_to_string( - status: notmuch_status_t, - ) -> *const c_char; + pub fn notmuch_status_to_string(status: notmuch_status_t) -> *const c_char; /// Create a new, empty notmuch database located at 'path'. /// @@ -195,10 +191,11 @@ extern { /// Like `notmuch_database_create`, except optionally return an error /// message. This message is allocated by malloc and should be freed by /// the caller. - pub fn notmuch_database_create_verbose(path: *const c_char, - database: *mut *mut notmuch_database_t, - error_message: *mut *const c_char) - -> notmuch_status_t; + pub fn notmuch_database_create_verbose( + path: *const c_char, + database: *mut *mut notmuch_database_t, + error_message: *mut *const c_char, + ) -> notmuch_status_t; /// Open an existing notmuch database located at 'path'. /// @@ -239,11 +236,12 @@ extern { /// Like notmuch_database_open, except optionally return an error /// message. This message is allocated by malloc and should be freed by /// the caller. - pub fn notmuch_database_open_verbose(path: *const c_char, - mode: notmuch_database_mode_t, - database: *mut *mut notmuch_database_t, - error_message: *mut *mut c_char) - -> notmuch_status_t; + pub fn notmuch_database_open_verbose( + path: *const c_char, + mode: notmuch_database_mode_t, + database: *mut *mut notmuch_database_t, + error_message: *mut *mut c_char, + ) -> notmuch_status_t; /// Retrieve last status string for given database. pub fn notmuch_database_status_string(notmuch: *mut notmuch_database_t) -> *const c_char; @@ -274,9 +272,7 @@ extern { /// * `notmuch_status_t::XAPIAN_EXCEPTION`: A Xapian exception occurred; the /// database has been closed but there are no guarantees the /// changes to the database, if any, have been flushed to disk. - pub fn notmuch_database_close( - database: *mut notmuch_database_t, - ) -> notmuch_status_t; + pub fn notmuch_database_close(database: *mut notmuch_database_t) -> notmuch_status_t; /// Compact a notmuch database, backing up the original database to the /// given path. @@ -299,22 +295,16 @@ extern { /// /// Return value as in `notmuch_database_close` if the database was open; /// `notmuch_database_destroy` itself has no failure modes. - pub fn notmuch_database_destroy( - database: *mut notmuch_database_t, - ) -> notmuch_status_t; + pub fn notmuch_database_destroy(database: *mut notmuch_database_t) -> notmuch_status_t; /// Return the database path of the given database. /// /// The return value is a string owned by notmuch so should not be /// modified nor freed by the caller. - pub fn notmuch_database_get_path( - database: *mut notmuch_database_t, - ) -> *const c_char; + pub fn notmuch_database_get_path(database: *mut notmuch_database_t) -> *const c_char; /// Return the database format version of the given database. - pub fn notmuch_database_get_version( - database: *mut notmuch_database_t, - ) -> c_uint; + pub fn notmuch_database_get_version(database: *mut notmuch_database_t) -> c_uint; /// Can the database be upgraded to a newer database version? /// @@ -324,9 +314,7 @@ extern { /// fail with `notmuch_status_t::UPGRADE_REQUIRED`. This always returns /// FALSE for a read-only database because there's no way to upgrade a /// read-only database. - pub fn notmuch_database_needs_upgrade( - database: *mut notmuch_database_t, - ) -> notmuch_bool_t; + pub fn notmuch_database_needs_upgrade(database: *mut notmuch_database_t) -> notmuch_bool_t; /// Upgrade the current database to the latest supported version. /// @@ -343,12 +331,11 @@ extern { /// the range of [0.0 .. 1.0] indicating the progress made so far in /// the upgrade process. The argument 'closure' is passed verbatim to /// any callback invoked. - pub fn notmuch_database_upgrade(database: *mut notmuch_database_t, - progress_notify: Option, - closure: *mut c_void) - -> notmuch_status_t; + pub fn notmuch_database_upgrade( + database: *mut notmuch_database_t, + progress_notify: Option, + closure: *mut c_void, + ) -> notmuch_status_t; /// Begin an atomic database operation. /// @@ -367,9 +354,7 @@ extern { /// /// * `notmuch_status_t::XAPIAN_EXCEPTION`: A Xapian exception occurred; /// atomic section not entered. - pub fn notmuch_database_begin_atomic( - notmuch: *mut notmuch_database_t, - ) -> notmuch_status_t; + pub fn notmuch_database_begin_atomic(notmuch: *mut notmuch_database_t) -> notmuch_status_t; /// Indicate the end of an atomic database operation. /// @@ -382,9 +367,7 @@ extern { /// /// * `notmuch_status_t::UNBALANCED_ATOMIC`: The database is not currently in /// an atomic section. - pub fn notmuch_database_end_atomic( - notmuch: *mut notmuch_database_t, - ) -> notmuch_status_t; + pub fn notmuch_database_end_atomic(notmuch: *mut notmuch_database_t) -> notmuch_status_t; /// Return the committed database revision and UUID. /// @@ -398,9 +381,10 @@ extern { /// The UUID is a NUL-terminated opaque string that uniquely identifies /// this database. Two revision numbers are only comparable if they /// have the same database UUID. - pub fn notmuch_database_get_revision(notmuch: *mut notmuch_database_t, - uuid: *mut *const c_char) - -> c_ulong; + pub fn notmuch_database_get_revision( + notmuch: *mut notmuch_database_t, + uuid: *mut *const c_char, + ) -> c_ulong; /// Retrieve a directory object from the database for 'path'. /// @@ -491,12 +475,11 @@ extern { /// /// @since libnotmuch 5.1 (notmuch 0.26) pub fn notmuch_database_index_file( - database: *mut notmuch_database_t, - filename: *const c_char, - indexopts: *mut notmuch_indexopts_t, - message: *mut *mut notmuch_message_t, - ) -> notmuch_status_t; - + database: *mut notmuch_database_t, + filename: *const c_char, + indexopts: *mut notmuch_indexopts_t, + message: *mut *mut notmuch_message_t, + ) -> notmuch_status_t; /// Deprecated alias for notmuch_database_index_file called with /// NULL indexopts. @@ -603,9 +586,7 @@ extern { /// resulting list contains all tags from all messages found in the database. /// /// On error this function returns NULL. - pub fn notmuch_database_get_all_tags( - db: *mut notmuch_database_t, - ) -> *mut notmuch_tags_t; + pub fn notmuch_database_get_all_tags(db: *mut notmuch_database_t) -> *mut notmuch_tags_t; /// Create a new query for 'database'. /// @@ -636,9 +617,7 @@ extern { ) -> *mut notmuch_query_t; /// Return the query_string of this query. See `notmuch_query_create`. - pub fn notmuch_query_get_query_string( - query: *mut notmuch_query_t, - ) -> *const c_char; + pub fn notmuch_query_get_query_string(query: *mut notmuch_query_t) -> *const c_char; /// Return the notmuch database of this query. See `notmuch_query_create`. pub fn notmuch_query_get_database(query: *const notmuch_query_t) -> *mut notmuch_database_t; @@ -674,24 +653,16 @@ extern { ); /// Specify the sorting desired for this query. - pub fn notmuch_query_set_sort( - query: *mut notmuch_query_t, - sort: notmuch_sort_t, - ); + pub fn notmuch_query_set_sort(query: *mut notmuch_query_t, sort: notmuch_sort_t); /// Return the sort specified for this query. See /// `notmuch_query_set_sort`. - pub fn notmuch_query_get_sort( - query: *mut notmuch_query_t, - ) -> notmuch_sort_t; + pub fn notmuch_query_get_sort(query: *mut notmuch_query_t) -> notmuch_sort_t; /// Add a tag that will be excluded from the query results by default. /// This exclusion will be overridden if this tag appears explicitly in /// the query. - pub fn notmuch_query_add_tag_exclude( - query: *mut notmuch_query_t, - tag: *const c_char, - ); + pub fn notmuch_query_add_tag_exclude(query: *mut notmuch_query_t, tag: *const c_char); /// Execute a query for threads, returning a `notmuch_threads_t` object /// which can be used to iterate over the results. The returned threads @@ -732,9 +703,10 @@ extern { /// to call it if the query is about to be destroyed). /// /// @since libnotmuch 4.2 (notmuch 0.20) - pub fn notmuch_query_search_threads(query: *mut notmuch_query_t, - out: *mut *mut notmuch_threads_t) - -> notmuch_status_t; + pub fn notmuch_query_search_threads( + query: *mut notmuch_query_t, + out: *mut *mut notmuch_threads_t, + ) -> notmuch_status_t; /// Execute a query for messages, returning a `notmuch_messages_t` object /// which can be used to iterate over the results. The returned @@ -777,9 +749,10 @@ extern { /// If a Xapian exception occurs this function will return NULL. /// /// @since libnotmuch 5 (notmuch 0.25) - pub fn notmuch_query_search_messages(query: *mut notmuch_query_t, - out: *mut *mut notmuch_messages_t) - -> notmuch_status_t; + pub fn notmuch_query_search_messages( + query: *mut notmuch_query_t, + out: *mut *mut notmuch_messages_t, + ) -> notmuch_status_t; /// Destroy a `notmuch_query_t` along with any associated resources. /// @@ -788,9 +761,7 @@ extern { /// turn any notmuch_thread_t and `notmuch_message_t` objects generated /// from those results, etc.), if such objects haven't already been /// destroyed. - pub fn notmuch_query_destroy( - query: *mut notmuch_query_t, - ); + pub fn notmuch_query_destroy(query: *mut notmuch_query_t); /// Is the given 'threads' iterator pointing at a valid thread. /// @@ -802,9 +773,7 @@ extern { /// /// See the documentation of `notmuch_query_search_threads` for example /// code showing how to iterate over a `notmuch_threads_t` object. - pub fn notmuch_threads_valid( - threads: *mut notmuch_threads_t, - ) -> notmuch_bool_t; + pub fn notmuch_threads_valid(threads: *mut notmuch_threads_t) -> notmuch_bool_t; /// Get the current thread from 'threads' as a `notmuch_thread_t`. /// @@ -816,9 +785,7 @@ extern { /// /// If an out-of-memory situation occurs, this function will return /// NULL. - pub fn notmuch_threads_get( - threads: *mut notmuch_threads_t, - ) -> *mut notmuch_thread_t; + pub fn notmuch_threads_get(threads: *mut notmuch_threads_t) -> *mut notmuch_thread_t; /// Move the 'threads' iterator to the next thread. /// @@ -829,18 +796,14 @@ extern { /// /// See the documentation of `notmuch_query_search_threads` for example /// code showing how to iterate over a `notmuch_threads_t` object. - pub fn notmuch_threads_move_to_next( - threads: *mut notmuch_threads_t, - ); + pub fn notmuch_threads_move_to_next(threads: *mut notmuch_threads_t); /// Destroy a `notmuch_threads_t` object. /// /// It's not strictly necessary to call this function. All memory from /// the `notmuch_threads_t` object will be reclaimed when the /// containing query object is destroyed. - pub fn notmuch_threads_destroy( - threads: *mut notmuch_threads_t, - ); + pub fn notmuch_threads_destroy(threads: *mut notmuch_threads_t); /// Return the number of messages matching a search. /// @@ -857,10 +820,9 @@ extern { /// @since libnotmuch 4.3 (notmuch 0.21) pub fn notmuch_query_count_messages( query: *mut notmuch_query_t, - count: *mut c_uint + count: *mut c_uint, ) -> notmuch_status_t; - /// Return the number of threads matching a search. /// /// This function performs a search and returns the number of unique thread IDs @@ -883,7 +845,7 @@ extern { /// @since libnotmuch 4.3 (notmuch 0.21) pub fn notmuch_query_count_threads( query: *mut notmuch_query_t, - count: *mut c_uint + count: *mut c_uint, ) -> notmuch_status_t; /// Get the thread ID of 'thread'. @@ -892,17 +854,13 @@ extern { /// modified by the caller and will only be valid for as long as the /// thread is valid, (which is until `notmuch_thread_destroy` or until /// the query from which it derived is destroyed). - pub fn notmuch_thread_get_thread_id( - thread: *mut notmuch_thread_t, - ) -> *const c_char; + pub fn notmuch_thread_get_thread_id(thread: *mut notmuch_thread_t) -> *const c_char; /// Get the total number of messages in 'thread'. /// /// This count consists of all messages in the database belonging to /// this thread. Contrast with `notmuch_thread_get_matched_messages`(). - pub fn notmuch_thread_get_total_messages( - thread: *mut notmuch_thread_t, - ) -> c_int; + pub fn notmuch_thread_get_total_messages(thread: *mut notmuch_thread_t) -> c_int; /// Get the total number of files in 'thread'. /// @@ -911,9 +869,7 @@ extern { /// @returns Non-negative integer /// @since libnotmuch 5.0 (notmuch 0.25) /// - pub fn notmuch_thread_get_total_files( - thread: *mut notmuch_thread_t, - ) -> c_int; + pub fn notmuch_thread_get_total_files(thread: *mut notmuch_thread_t) -> c_int; /// Get a `notmuch_messages_t` iterator for the top-level messages in /// 'thread' in oldest-first order. @@ -931,9 +887,7 @@ extern { /// oldest-first order. /// /// The returned list will be destroyed when the thread is destroyed. - pub fn notmuch_thread_get_messages( - thread: *mut notmuch_thread_t, - ) -> *mut notmuch_messages_t; + pub fn notmuch_thread_get_messages(thread: *mut notmuch_thread_t) -> *mut notmuch_messages_t; /// Get the number of messages in 'thread' that matched the search. /// @@ -942,9 +896,7 @@ extern { /// not excluded by any exclude tags passed in with the query (see /// `notmuch_query_add_tag_exclude`). Contrast with /// `notmuch_thread_get_total_messages`() . - pub fn notmuch_thread_get_matched_messages( - thread: *mut notmuch_thread_t, - ) -> c_int; + pub fn notmuch_thread_get_matched_messages(thread: *mut notmuch_thread_t) -> c_int; /// Get the authors of 'thread' as a UTF-8 string. /// @@ -960,9 +912,7 @@ extern { /// modified by the caller and will only be valid for as long as the /// thread is valid, (which is until `notmuch_thread_destroy` or until /// the query from which it derived is destroyed). - pub fn notmuch_thread_get_authors( - thread: *mut notmuch_thread_t, - ) -> *const c_char; + pub fn notmuch_thread_get_authors(thread: *mut notmuch_thread_t) -> *const c_char; /// Get the subject of 'thread' as a UTF-8 string. /// @@ -974,19 +924,13 @@ extern { /// modified by the caller and will only be valid for as long as the /// thread is valid, (which is until `notmuch_thread_destroy` or until /// the query from which it derived is destroyed). - pub fn notmuch_thread_get_subject( - thread: *mut notmuch_thread_t, - ) -> *const c_char; + pub fn notmuch_thread_get_subject(thread: *mut notmuch_thread_t) -> *const c_char; /// Get the date of the oldest message in 'thread' as a time_t value. - pub fn notmuch_thread_get_oldest_date( - thread: *mut notmuch_thread_t, - ) -> time_t; + pub fn notmuch_thread_get_oldest_date(thread: *mut notmuch_thread_t) -> time_t; /// Get the date of the newest message in 'thread' as a time_t value. - pub fn notmuch_thread_get_newest_date( - thread: *mut notmuch_thread_t, - ) -> time_t; + pub fn notmuch_thread_get_newest_date(thread: *mut notmuch_thread_t) -> time_t; /// Get the tags for 'thread', returning a `notmuch_tags_t` object which /// can be used to iterate over all tags. @@ -1025,14 +969,10 @@ extern { /// `notmuch_tags_t` object. (For consistency, we do provide a /// `notmuch_tags_destroy` function, but there's no good reason to call /// it if the message is about to be destroyed). - pub fn notmuch_thread_get_tags( - thread: *mut notmuch_thread_t, - ) -> *mut notmuch_tags_t; + pub fn notmuch_thread_get_tags(thread: *mut notmuch_thread_t) -> *mut notmuch_tags_t; /// Destroy a `notmuch_thread_t` object. - pub fn notmuch_thread_destroy( - thread: *mut notmuch_thread_t, - ); + pub fn notmuch_thread_destroy(thread: *mut notmuch_thread_t); /// Is the given 'messages' iterator pointing at a valid message. /// @@ -1042,9 +982,7 @@ extern { /// /// See the documentation of `notmuch_query_search_messages` for example /// code showing how to iterate over a `notmuch_messages_t` object. - pub fn notmuch_messages_valid( - messages: *mut notmuch_messages_t, - ) -> notmuch_bool_t; + pub fn notmuch_messages_valid(messages: *mut notmuch_messages_t) -> notmuch_bool_t; /// Get the current message from 'messages' as a `notmuch_message_t`. /// @@ -1056,9 +994,7 @@ extern { /// /// If an out-of-memory situation occurs, this function will return /// NULL. - pub fn notmuch_messages_get( - messages: *mut notmuch_messages_t, - ) -> *mut notmuch_message_t; + pub fn notmuch_messages_get(messages: *mut notmuch_messages_t) -> *mut notmuch_message_t; /// Move the 'messages' iterator to the next message. /// @@ -1069,18 +1005,14 @@ extern { /// /// See the documentation of `notmuch_query_search_messages` for example /// code showing how to iterate over a `notmuch_messages_t` object. - pub fn notmuch_messages_move_to_next( - messages: *mut notmuch_messages_t, - ); + pub fn notmuch_messages_move_to_next(messages: *mut notmuch_messages_t); /// Destroy a `notmuch_messages_t` object. /// /// It's not strictly necessary to call this function. All memory from /// the `notmuch_messages_t` object will be reclaimed when the containing /// query object is destroyed. - pub fn notmuch_messages_destroy( - messages: *mut notmuch_messages_t, - ); + pub fn notmuch_messages_destroy(messages: *mut notmuch_messages_t); /// Return a list of tags from all messages. /// @@ -1093,10 +1025,7 @@ extern { /// message list. /// /// The function returns NULL on error. - pub fn notmuch_messages_collect_tags( - messages: *mut notmuch_messages_t, - ) -> *mut notmuch_tags_t; - + pub fn notmuch_messages_collect_tags(messages: *mut notmuch_messages_t) -> *mut notmuch_tags_t; /// Get the message ID of 'message'. /// @@ -1108,9 +1037,7 @@ extern { /// This function will not return NULL since Notmuch ensures that every /// message has a unique message ID, (Notmuch will generate an ID for a /// message if the original file does not contain one). - pub fn notmuch_message_get_message_id( - message: *mut notmuch_message_t, - ) -> *const c_char; + pub fn notmuch_message_get_message_id(message: *mut notmuch_message_t) -> *const c_char; /// Get the thread ID of 'message'. /// @@ -1122,9 +1049,7 @@ extern { /// /// This function will not return NULL since Notmuch ensures that every /// message belongs to a single thread. - pub fn notmuch_message_get_thread_id( - message: *mut notmuch_message_t, - ) -> *const c_char; + pub fn notmuch_message_get_thread_id(message: *mut notmuch_message_t) -> *const c_char; /// Get a `notmuch_messages_t` iterator for all of the replies to /// 'message'. @@ -1142,16 +1067,12 @@ extern { /// If there are no replies to 'message', this function will return /// NULL. (Note that `notmuch_messages_valid` will accept that NULL /// value as legitimate, and simply return FALSE for it.) - pub fn notmuch_message_get_replies( - message: *mut notmuch_message_t, - ) -> *mut notmuch_messages_t; + pub fn notmuch_message_get_replies(message: *mut notmuch_message_t) -> *mut notmuch_messages_t; /// Get the total number of files associated with a message. /// @returns Non-negative integer /// @since libnotmuch 5.0 (notmuch 0.25) - pub fn notmuch_message_count_files( - message: *mut notmuch_message_t, - ) -> c_int; + pub fn notmuch_message_count_files(message: *mut notmuch_message_t) -> c_int; /// Get a filename for the email corresponding to 'message'. /// @@ -1167,9 +1088,7 @@ extern { /// this function will arbitrarily return a single one of those /// filenames. See `notmuch_message_get_filenames` for returning the /// complete list of filenames. - pub fn notmuch_message_get_filename( - message: *mut notmuch_message_t, - ) -> *const c_char; + pub fn notmuch_message_get_filename(message: *mut notmuch_message_t) -> *const c_char; /// Get all filenames for the email corresponding to 'message'. /// @@ -1201,9 +1120,7 @@ extern { /// For the original textual representation of the Date header from the /// message call `notmuch_message_get_header`() with a header value of /// "date". - pub fn notmuch_message_get_date( - message: *mut notmuch_message_t, - ) -> time_t; + pub fn notmuch_message_get_date(message: *mut notmuch_message_t) -> time_t; /// Get the value of the specified header from 'message' as a UTF-8 string. /// @@ -1255,9 +1172,7 @@ extern { /// `notmuch_tags_t` object. (For consistency, we do provide a /// `notmuch_tags_destroy` function, but there's no good reason to call /// it if the message is about to be destroyed). - pub fn notmuch_message_get_tags( - message: *mut notmuch_message_t, - ) -> *mut notmuch_tags_t; + pub fn notmuch_message_get_tags(message: *mut notmuch_message_t) -> *mut notmuch_tags_t; /// Add a tag to the given message. /// @@ -1291,7 +1206,6 @@ extern { tag: *const c_char, ) -> notmuch_status_t; - /// Remove all tags from the given message. /// /// See `notmuch_message_freeze` for an example showing how to safely @@ -1299,10 +1213,7 @@ extern { /// /// `notmuch_status_t::READ_ONLY_DATABASE`: Database was opened in read-only /// mode so message cannot be modified. - pub fn notmuch_message_remove_all_tags( - message: *mut notmuch_message_t, - ) -> notmuch_status_t; - + pub fn notmuch_message_remove_all_tags(message: *mut notmuch_message_t) -> notmuch_status_t; /// Add/remove tags according to maildir flags in the message filename(s). /// @@ -1416,9 +1327,7 @@ extern { /// /// `notmuch_status_t::READ_ONLY_DATABASE`: Database was opened in read-only /// mode so message cannot be modified. - pub fn notmuch_message_freeze( - message: *mut notmuch_message_t, - ) -> notmuch_status_t; + pub fn notmuch_message_freeze(message: *mut notmuch_message_t) -> notmuch_status_t; /// Thaw the current 'message', synchronizing any changes that may have /// occurred while 'message' was frozen into the notmuch database. @@ -1439,9 +1348,7 @@ extern { /// an unfrozen message. That is, there have been an unbalanced /// number of calls to `notmuch_message_freeze` and /// `notmuch_message_thaw`. - pub fn notmuch_message_thaw( - message: *mut notmuch_message_t, - ) -> notmuch_status_t; + pub fn notmuch_message_thaw(message: *mut notmuch_message_t) -> notmuch_status_t; /// Destroy a `notmuch_message_t` object. /// @@ -1450,9 +1357,7 @@ extern { /// over the entire database). Otherwise, it's fine to never call this /// function and there will still be no memory leaks. (The memory from /// the messages get reclaimed when the containing query is destroyed.) - pub fn notmuch_message_destroy( - message: *mut notmuch_message_t, - ); + pub fn notmuch_message_destroy(message: *mut notmuch_message_t); /// Retrieve the value for a single property key /// @@ -1464,10 +1369,11 @@ extern { /// - `notmuch_status_t::NULL_POINTER`: *value* may not be NULL. /// - `notmuch_status_t::SUCCESS`: No error occured. /// @since libnotmuch 4.4 (notmuch 0.23) - pub fn notmuch_message_get_property(message: *mut notmuch_message_t, - key: *const c_char, - value: *mut *const c_char) - -> notmuch_status_t; + pub fn notmuch_message_get_property( + message: *mut notmuch_message_t, + key: *const c_char, + value: *mut *const c_char, + ) -> notmuch_status_t; /// Add a (key,value) pair to a message /// @@ -1476,10 +1382,11 @@ extern { /// - `notmuch_status_t::NULL_POINTER`: Neither *key* nor *value* may be NULL. /// - `notmuch_status_t::SUCCESS`: No error occured. /// @since libnotmuch 4.4 (notmuch 0.23) - pub fn notmuch_message_add_property(message: *mut notmuch_message_t, - key: *const c_char, - value: *const c_char) - -> notmuch_status_t; + pub fn notmuch_message_add_property( + message: *mut notmuch_message_t, + key: *const c_char, + value: *const c_char, + ) -> notmuch_status_t; /// /// Remove a `(key,value)` pair from a message. @@ -1491,10 +1398,11 @@ extern { /// - `notmuch_status_t::NULL_POINTER`: Neither `key` nor *value* may be NULL. /// - `notmuch_status_t::SUCCESS`: No error occured. /// @since libnotmuch 4.4 (notmuch 0.23) - pub fn notmuch_message_remove_property(message: *mut notmuch_message_t, - key: *const c_char, - value: *const c_char) - -> notmuch_status_t; + pub fn notmuch_message_remove_property( + message: *mut notmuch_message_t, + key: *const c_char, + value: *const c_char, + ) -> notmuch_status_t; /// Remove all `(key,value)` pairs from the given message. /// @@ -1507,9 +1415,10 @@ extern { /// - `notmuch_status_t::SUCCESS`: No error occured. /// /// @since libnotmuch 4.4 (notmuch 0.23) - pub fn notmuch_message_remove_all_properties(message: *mut notmuch_message_t, - key: *const c_char) - -> notmuch_status_t; + pub fn notmuch_message_remove_all_properties( + message: *mut notmuch_message_t, + key: *const c_char, + ) -> notmuch_status_t; /// Get the properties for *message*, returning a /// `notmuch_message_properties_t` object which can be used to iterate over @@ -1544,10 +1453,11 @@ extern { /// /// @since libnotmuch 4.4 (notmuch 0.23) /// - pub fn notmuch_message_get_properties(message: *mut notmuch_message_t, - key: *const c_char, - exact: notmuch_bool_t) - -> *mut notmuch_message_properties_t; + pub fn notmuch_message_get_properties( + message: *mut notmuch_message_t, + key: *const c_char, + exact: notmuch_bool_t, + ) -> *mut notmuch_message_properties_t; /// Is the given *properties* iterator pointing at a valid `(key,value)` pair. /// @@ -1560,7 +1470,9 @@ extern { /// showing how to iterate over a `notmuch_message_properties_t` object. /// /// @since libnotmuch 4.4 (notmuch 0.23) - pub fn notmuch_message_properties_valid(properties: *const notmuch_message_properties_t) -> notmuch_bool_t; + pub fn notmuch_message_properties_valid( + properties: *const notmuch_message_properties_t, + ) -> notmuch_bool_t; /// Move the *properties* iterator to the next `(key,value)` pair /// @@ -1580,15 +1492,18 @@ extern { /// /// @since libnotmuch 4.4 (notmuch 0.23) /// - pub fn notmuch_message_properties_key(properties: *mut notmuch_message_properties_t) -> *const c_char; + pub fn notmuch_message_properties_key( + properties: *mut notmuch_message_properties_t, + ) -> *const c_char; /// Return the `value` from the current `(key,value)` pair. /// /// This could be useful if iterating for a prefix. /// /// @since libnotmuch 4.4 (notmuch 0.23) - pub fn notmuch_message_properties_value(properties: *const notmuch_message_properties_t) -> *const c_char; - + pub fn notmuch_message_properties_value( + properties: *const notmuch_message_properties_t, + ) -> *const c_char; /// Destroy a `notmuch_message_properties_t` object. /// @@ -1669,9 +1584,10 @@ extern { /// /// * `notmuch_status_t::READ_ONLY_DATABASE`: Database was opened in read-only mode so /// directory mtime cannot be modified. - pub fn notmuch_directory_set_mtime(directory: *mut notmuch_directory_t, - mtime: time_t) - -> notmuch_status_t; + pub fn notmuch_directory_set_mtime( + directory: *mut notmuch_directory_t, + mtime: time_t, + ) -> notmuch_status_t; /// Get the mtime of a directory, (as previously stored with /// `notmuch_directory_set_mtime`). @@ -1685,16 +1601,18 @@ extern { /// /// The returned filenames will be the basename-entries only (not /// complete paths). - pub fn notmuch_directory_get_child_files(directory: *mut notmuch_directory_t) - -> *mut notmuch_filenames_t; + pub fn notmuch_directory_get_child_files( + directory: *mut notmuch_directory_t, + ) -> *mut notmuch_filenames_t; /// Get a `notmuch_filenames_t` iterator listing all the filenames of /// sub-directories in the database within the given directory. /// /// The returned filenames will be the basename-entries only (not /// complete paths). - pub fn notmuch_directory_get_child_directories(directory: *mut notmuch_directory_t) - -> *mut notmuch_filenames_t; + pub fn notmuch_directory_get_child_directories( + directory: *mut notmuch_directory_t, + ) -> *mut notmuch_filenames_t; /// Delete directory document from the database, and destroy the /// `notmuch_directory_t` object. Assumes any child directories and files @@ -1746,14 +1664,14 @@ extern { /// function will do nothing. pub fn notmuch_filenames_destroy(filenames: *mut notmuch_filenames_t); - /// set config 'key' to 'value' /// /// @since libnotmuch 4.4 (notmuch 0.23) - pub fn notmuch_database_set_config(db: *mut notmuch_database_t, - key: *const c_char, - value: *const c_char) - -> notmuch_status_t; + pub fn notmuch_database_set_config( + db: *mut notmuch_database_t, + key: *const c_char, + value: *const c_char, + ) -> notmuch_status_t; /// retrieve config item 'key', assign to 'value' /// @@ -1764,24 +1682,25 @@ extern { /// caller. /// /// @since libnotmuch 4.4 (notmuch 0.23) - pub fn notmuch_database_get_config(db: *mut notmuch_database_t, - key: *const c_char, - value: *mut *mut c_char) - -> notmuch_status_t; + pub fn notmuch_database_get_config( + db: *mut notmuch_database_t, + key: *const c_char, + value: *mut *mut c_char, + ) -> notmuch_status_t; /// Create an iterator for all config items with keys matching a given prefix /// /// @since libnotmuch 4.4 (notmuch 0.23) - pub fn notmuch_database_get_config_list(db: *mut notmuch_database_t, - prefix: *const c_char, - out: *mut *mut notmuch_config_list_t) - -> notmuch_status_t; + pub fn notmuch_database_get_config_list( + db: *mut notmuch_database_t, + prefix: *const c_char, + out: *mut *mut notmuch_config_list_t, + ) -> notmuch_status_t; /// Is 'config_list' iterator valid (i.e. _key, _value, _move_to_next can be called). /// /// @since libnotmuch 4.4 (notmuch 0.23) - pub fn notmuch_config_list_valid(config_list: *mut notmuch_config_list_t) - -> notmuch_bool_t; + pub fn notmuch_config_list_valid(config_list: *mut notmuch_config_list_t) -> notmuch_bool_t; /// return key for current config pair /// @@ -1789,8 +1708,7 @@ extern { /// next call to `notmuch_config_list_key` or `notmuch_config_list_destroy`. /// /// @since libnotmuch 4.4 (notmuch 0.23) - pub fn notmuch_config_list_key (config_list: *mut notmuch_config_list_t) - -> *const c_char; + pub fn notmuch_config_list_key(config_list: *mut notmuch_config_list_t) -> *const c_char; /// return 'value' for current config pair /// diff --git a/src/message.rs b/src/message.rs index 4c35544..dbf7cf2 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,7 +1,7 @@ use std::ffi::CString; use std::ops::Drop; use std::path::PathBuf; -use supercow::{Supercow, Phantomcow}; +use supercow::{Phantomcow, Supercow}; use error::{Error, Result}; use ffi; @@ -80,16 +80,12 @@ impl<'o, Owner: MessageOwner + 'o> Message<'o, Owner> { } pub fn date(&self) -> i64 { - unsafe { - ffi::notmuch_message_get_date(self.handle.ptr) - } + unsafe { ffi::notmuch_message_get_date(self.handle.ptr) } } pub fn header(&self, name: &str) -> Result<&str> { let name = CString::new(name).unwrap(); - let ret = unsafe { - ffi::notmuch_message_get_header(self.handle.ptr, name.as_ptr()) - }; + let ret = unsafe { ffi::notmuch_message_get_header(self.handle.ptr, name.as_ptr()) }; if ret.is_null() { Err(Error::UnspecifiedError) } else { @@ -103,56 +99,52 @@ impl<'o, Owner: MessageOwner + 'o> Message<'o, Owner> { pub fn add_tag(self: &Self, tag: &str) -> Status { let tag = CString::new(tag).unwrap(); - Status::from(unsafe { - ffi::notmuch_message_add_tag(self.handle.ptr, tag.as_ptr()) - }) + Status::from(unsafe { ffi::notmuch_message_add_tag(self.handle.ptr, tag.as_ptr()) }) } pub fn remove_tag(self: &Self, tag: &str) -> Status { let tag = CString::new(tag).unwrap(); - Status::from(unsafe { - ffi::notmuch_message_remove_tag(self.handle.ptr, tag.as_ptr()) - }) + Status::from(unsafe { ffi::notmuch_message_remove_tag(self.handle.ptr, tag.as_ptr()) }) } pub fn remove_all_tags(self: &Self) -> Status { - Status::from(unsafe { - ffi::notmuch_message_remove_all_tags(self.handle.ptr) - }) + Status::from(unsafe { ffi::notmuch_message_remove_all_tags(self.handle.ptr) }) } } - -pub trait MessageExt<'o, Owner: MessageOwner + 'o>{ - - fn tags<'s, S: Into>>>(message: S) -> Tags<'s, Message<'o, Owner>> { +pub trait MessageExt<'o, Owner: MessageOwner + 'o> { + fn tags<'s, S: Into>>>( + message: S, + ) -> Tags<'s, Message<'o, Owner>> { let messageref = message.into(); Tags::from_ptr( unsafe { ffi::notmuch_message_get_tags(messageref.handle.ptr) }, - Supercow::phantom(messageref) + Supercow::phantom(messageref), ) } - fn replies<'s, S: Into>>>(message: S) -> Messages<'s, Message<'o, Owner>> { + fn replies<'s, S: Into>>>( + message: S, + ) -> Messages<'s, Message<'o, Owner>> { let messageref = message.into(); Messages::from_ptr( unsafe { ffi::notmuch_message_get_replies(messageref.handle.ptr) }, - Supercow::phantom(messageref) + Supercow::phantom(messageref), ) } - fn filenames<'s, S: Into>>>(message: S) -> Filenames<'s, Message<'o, Owner>> { + fn filenames<'s, S: Into>>>( + message: S, + ) -> Filenames<'s, Message<'o, Owner>> { let messageref = message.into(); Filenames::from_ptr( unsafe { ffi::notmuch_message_get_filenames(messageref.handle.ptr) }, - Supercow::phantom(messageref) + Supercow::phantom(messageref), ) } } -impl<'o, Owner: MessageOwner + 'o> MessageExt<'o, Owner> for Message<'o, Owner>{ - -} +impl<'o, Owner: MessageOwner + 'o> MessageExt<'o, Owner> 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 7a0a48c..8537f90 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -89,17 +89,14 @@ impl<'s, 'o: 's, Owner: MessagesOwner + 'o> StreamingIterator<'s, Message<'s, Se } } -pub trait MessagesExt<'o, Owner: MessagesOwner + 'o> { +pub trait MessagesExt<'o, Owner: MessagesOwner + 'o> {} -} - -impl<'o, Owner: MessagesOwner + 'o> MessagesExt<'o, Owner> for Messages<'o, Owner>{ - -} +impl<'o, Owner: MessagesOwner + 'o> MessagesExt<'o, Owner> for Messages<'o, Owner> {} -impl<'s, 'o: 's, Owner: MessagesOwner + 'o> StreamingIteratorExt<'s, Message<'s, Self>> for Messages<'o, Owner> +impl<'s, 'o: 's, Owner: MessagesOwner + 'o> StreamingIteratorExt<'s, Message<'s, Self>> + for Messages<'o, Owner> { - fn next>>>(messages: S) -> Option>{ + fn next>>>(messages: S) -> Option> { let messagesref = messages.into(); let valid = unsafe { ffi::notmuch_messages_valid(messagesref.handle.ptr) }; diff --git a/src/query.rs b/src/query.rs index b502542..c3eb1a2 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,19 +1,19 @@ +use std::ffi::{CStr, CString}; use std::ops::Drop; use std::ptr; -use std::ffi::{CStr, CString}; -use supercow::{Supercow, Phantomcow}; +use supercow::{Phantomcow, Supercow}; use error::Result; use ffi; use ffi::Sort; +use messages::MessagesPtr; +use threads::ThreadsPtr; use Database; use Messages; use MessagesOwner; use Threads; use ThreadsOwner; -use threads::ThreadsPtr; -use messages::MessagesPtr; #[derive(Debug)] pub(crate) struct QueryPtr { @@ -36,13 +36,12 @@ impl<'d> ThreadsOwner for Query<'d> {} impl<'d> MessagesOwner for Query<'d> {} impl<'d> Query<'d> { - pub(crate) fn from_ptr>>( ptr: *mut ffi::notmuch_query_t, owner: O, ) -> Query<'d> { Query { - handle: QueryPtr{ptr}, + handle: QueryPtr { ptr }, marker: owner.into(), } } @@ -57,13 +56,12 @@ impl<'d> Query<'d> { } } - pub fn create>>(db: D, - query_string: &str) -> Result { - + pub fn create>>(db: D, query_string: &str) -> Result { let dbref = db.into(); - dbref.handle.create_query(query_string).map(move |handle|{ - Query::from_handle(handle, Supercow::phantom(dbref)) - }) + dbref + .handle + .create_query(query_string) + .map(move |handle| Query::from_handle(handle, Supercow::phantom(dbref))) } /// Specify the sorting desired for this query. @@ -101,34 +99,37 @@ impl<'d> Query<'d> { } } -pub trait QueryExt<'d>{ - - fn search_threads<'q, Q: Into>>>(query: Q) -> Result>>{ +pub trait QueryExt<'d> { + fn search_threads<'q, Q: Into>>>( + query: Q, + ) -> Result>> { let queryref = query.into(); let mut thrds = ptr::null_mut(); try!( - unsafe { ffi::notmuch_query_search_threads(queryref.handle.ptr, &mut thrds) }.as_result() + unsafe { ffi::notmuch_query_search_threads(queryref.handle.ptr, &mut thrds) } + .as_result() ); Ok(Threads::from_ptr(thrds, Supercow::phantom(queryref))) } - fn search_messages<'q, Q: Into>>>(query: Q) -> Result>>{ + fn search_messages<'q, Q: Into>>>( + query: Q, + ) -> Result>> { let queryref = query.into(); let mut msgs = ptr::null_mut(); try!( - unsafe { ffi::notmuch_query_search_messages(queryref.handle.ptr, &mut msgs) }.as_result() + unsafe { ffi::notmuch_query_search_messages(queryref.handle.ptr, &mut msgs) } + .as_result() ); Ok(Messages::from_ptr(msgs, Supercow::phantom(queryref))) } - } -impl<'d> QueryExt<'d> for Query<'d>{} - +impl<'d> QueryExt<'d> for Query<'d> {} 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 dcf205a..573a491 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -58,14 +58,9 @@ impl<'o, Owner: TagsOwner + 'o> Iterator for Tags<'o, Owner> { } } +pub trait TagsExt<'o, Owner: TagsOwner + 'o> {} -pub trait TagsExt<'o, Owner: TagsOwner + 'o>{ - -} - -impl<'o, Owner: TagsOwner + 'o> TagsExt<'o, Owner> for Tags<'o, Owner>{ - -} +impl<'o, Owner: TagsOwner + 'o> TagsExt<'o, Owner> 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 e9ecdad..a529508 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -1,5 +1,5 @@ use std::ops::Drop; -use supercow::{Supercow, Phantomcow}; +use supercow::{Phantomcow, Supercow}; use ffi; use utils::ToStr; @@ -97,38 +97,41 @@ impl<'o, Owner: ThreadOwner + 'o> Thread<'o, Owner> { } } -pub trait ThreadExt<'o, Owner: ThreadOwner + 'o>{ - fn tags<'s, S: Into>>>(thread: S) -> Tags<'s, Thread<'o, Owner>> { +pub trait ThreadExt<'o, Owner: ThreadOwner + 'o> { + fn tags<'s, S: Into>>>( + thread: S, + ) -> Tags<'s, Thread<'o, Owner>> { let threadref = thread.into(); Tags::from_ptr( unsafe { ffi::notmuch_thread_get_tags(threadref.handle.ptr) }, - Supercow::phantom(threadref) + Supercow::phantom(threadref), ) } - fn toplevel_messages<'s, S: Into>>>(thread: S) -> Messages<'s, Thread<'o, Owner>> { + fn toplevel_messages<'s, S: Into>>>( + thread: S, + ) -> Messages<'s, Thread<'o, Owner>> { let threadref = thread.into(); Messages::from_ptr( unsafe { ffi::notmuch_thread_get_toplevel_messages(threadref.handle.ptr) }, - Supercow::phantom(threadref) + Supercow::phantom(threadref), ) } /// Get a `Messages` iterator for all messages in 'thread' in /// oldest-first order. - fn messages<'s, S: Into>>>(thread: S) -> Messages<'s, Thread<'o, Owner>> { + fn messages<'s, S: Into>>>( + thread: S, + ) -> Messages<'s, Thread<'o, Owner>> { let threadref = thread.into(); Messages::from_ptr( unsafe { ffi::notmuch_thread_get_messages(threadref.handle.ptr) }, - Supercow::phantom(threadref) + Supercow::phantom(threadref), ) } - } -impl<'o, Owner: ThreadOwner + 'o> ThreadExt<'o, Owner> for Thread<'o, Owner>{ - -} +impl<'o, Owner: ThreadOwner + 'o> ThreadExt<'o, Owner> for Thread<'o, Owner> {} 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 5083f87..e2312c7 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -48,17 +48,14 @@ impl<'s, 'o: 's, Owner: ThreadsOwner + 'o> StreamingIterator<'s, Thread<'s, Self } } -pub trait ThreadsExt<'o, Owner: ThreadsOwner + 'o>{ +pub trait ThreadsExt<'o, Owner: ThreadsOwner + 'o> {} -} - -impl<'o, Owner: ThreadsOwner + 'o> ThreadsExt<'o, Owner> for Threads<'o, Owner>{ - -} +impl<'o, Owner: ThreadsOwner + 'o> ThreadsExt<'o, Owner> for Threads<'o, Owner> {} -impl<'s, 'o: 's, Owner: ThreadsOwner + 'o> StreamingIteratorExt<'s, Thread<'s, Self>> for Threads<'o, Owner> +impl<'s, 'o: 's, Owner: ThreadsOwner + 'o> StreamingIteratorExt<'s, Thread<'s, Self>> + for Threads<'o, Owner> { - fn next>>>(threads: S) -> Option>{ + fn next>>>(threads: S) -> Option> { let threadsref = threads.into(); let valid = unsafe { ffi::notmuch_threads_valid(threadsref.handle.ptr) }; diff --git a/src/utils.rs b/src/utils.rs index def8d93..be5f66c 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -34,6 +34,6 @@ pub trait StreamingIteratorExt<'a, T> { /// Return either the next item in the sequence, or `None` if all items /// have been consumed. fn next>>(s: S) -> Option - where Self: Sized + 'a; + where + Self: Sized + 'a; } - diff --git a/tests/main.rs b/tests/main.rs index 512aa84..4a81792 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -1,19 +1,20 @@ -extern crate notmuch; extern crate dirs; +extern crate notmuch; use std::sync::Arc; +use notmuch::{Query, QueryExt, Thread, Threads}; use notmuch::{StreamingIterator, StreamingIteratorExt}; -use notmuch::{Threads, Thread, Query, QueryExt}; fn main() { - let mut mail_path = dirs::home_dir().unwrap(); mail_path.push(".mail"); - match notmuch::Database::open(&mail_path.to_str().unwrap().to_string(), notmuch::DatabaseMode::ReadOnly){ + match notmuch::Database::open( + &mail_path.to_str().unwrap().to_string(), + notmuch::DatabaseMode::ReadOnly, + ) { Ok(db) => { - #[cfg(feature = "v0_21")] { let rev = db.revision(); @@ -25,23 +26,20 @@ fn main() { notmuch::Query::create(dbr.clone(), &"".to_string()).unwrap() }; - // let mut threads = query.search_threads().unwrap(); - - // let mut threads = db.create_query(&"".to_string()).unwrap().search_threads().unwrap(); let threads = Arc::new(::search_threads(query).unwrap()); - - while let Some(thread) = as StreamingIteratorExt>>>::next(threads.clone()) { + while let Some(thread) = as StreamingIteratorExt< + Thread>, + >>::next(threads.clone()) + { println!("thread {:?} {:?}", thread.subject(), thread.authors()); } - - - }, - Err(err) =>{ + } + Err(err) => { println!("Got error while trying to open db: {:?}", err); } } -- cgit v1.2.1 From 1c20f406dcdcff08cee39159935ddac4e0e7c1d9 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 5 Nov 2018 18:22:12 +0100 Subject: compacter trait object notations --- tests/main.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/main.rs b/tests/main.rs index 4a81792..4c74115 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -32,9 +32,7 @@ fn main() { let threads = Arc::new(::search_threads(query).unwrap()); - while let Some(thread) = as StreamingIteratorExt< - Thread>, - >>::next(threads.clone()) + while let Some(thread) = as StreamingIteratorExt<_>>::next(threads.clone()) { println!("thread {:?} {:?}", thread.subject(), thread.authors()); } -- cgit v1.2.1 From 2afe04b9aa9b2a7b23ed338448091a56b9d1cb7e Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 5 Nov 2018 19:54:28 +0100 Subject: update readme --- README.md | 61 +++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 2847e32..4719ee0 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,8 @@ extern crate notmuch; ```rust extern crate notmuch; +use notmuch::StreamingIterator; + fn main() { @@ -40,13 +42,8 @@ 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()); } } @@ -59,13 +56,49 @@ thread locals, but I did not spot any locks. So, as far as I am concerned, it is not thread safe. So why do all structs implement ```Send``` and ```Sync```? Well, it _is_ safe to access pointers from different threads (as long as you know what you are doing :) ). -But, more importantly, all structs are strictly linked together with their -lifetime. The root of the tree is ```notmuch::Database```, which has a lifetime -that must outlive any related objects, for instance ```notmuch::Query```. The -```notmuch::Threads``` iterator that you can get from a ```notmuch::Query``` is -always outlived by the parent query. -This means that you can only use these structs accross thread bounds if you -figure out how to satisfy the lifetime requirements. +Up till now I haven't done a lot of multithreaded stuff with notmuch-rs. If you +feel this is too permissive, let me know. + +## Lifetime + +All structs are strictly linked together with their lifetime. The root of the +tree is ```Database```, which has a lifetime that must outlive any child +objects, for instance ```Query```. The ```Threads``` iterator that you can get +from a ```Query``` is always outlived by the parent query. ```Threads``` in its +turn must have a longer life than ```Thread```, which in turn must outlive +```Messages``` and so on. Each structure keeps a ```PhantomData``` marker of its +owner. + +Using this in an application poses significant difficulties in satisfying these +lifetime requirements. To alleviate this, ```notmuch-rs``` makes use of the +excellent [Supercow](https://crates.io/crates/supercow), so you don't have to +use crates like ```owningref``` or ```rental``` to get around this. + +This way, you get to choose your own container type, and even keep the parent +object alive so you don't have to juggle lifetimes. To use this, most types +are accompagnied with an ```*Ext``` trait, that accepts ```Rc```, ```Arc``` or +comparable. + +```rust + use std::sync::Arc; + use notmuch::{DatabaseExt}; + + let query = { + let dbr = Arc::new(db); + + ::create_query(dbr.clone(), &"".to_string()).unwrap() + }; + +``` + +## Iterators + +Since the lifetime of a ```Thread``` or a ```Message``` is dependent on the +```Threads``` and ```Messages``` iterator respectively, using the regular rust +```Iterator``` trait proved impossible. As such, ```notmuch-rs``` includes a +```StreamingIterator``` (and additional ```StreamingIteratorExt```) trait that +is used to iterate while satisfying the lifetime constraints. + ## Acknowledgements -- cgit v1.2.1 From 49416d12e98ce3c97262ab8ac73cca57adb978b9 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 5 Nov 2018 19:57:25 +0100 Subject: bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 37d48cf..5e76b6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "notmuch" -version = "0.3.1" +version = "0.4.0" authors = ["Dirk Van Haerenborgh "] homepage = "https://github.com/vhdirk/notmuch-rs" repository = "https://github.com/vhdirk/notmuch-rs" -- cgit v1.2.1 From 214eba6f5b9a8bfefc778ce3e22cd7d2245f9628 Mon Sep 17 00:00:00 2001 From: eaon Date: Tue, 6 Nov 2018 09:04:41 -0500 Subject: Make Message::header return an Option in its Result (#9) * Distinguishing between (non-)empty Message::header returns * Switch Message::header Ok result to use nicer match syntax --- src/message.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/message.rs b/src/message.rs index dbf7cf2..ef9079f 100644 --- a/src/message.rs +++ b/src/message.rs @@ -83,13 +83,16 @@ impl<'o, Owner: MessageOwner + 'o> Message<'o, Owner> { unsafe { ffi::notmuch_message_get_date(self.handle.ptr) } } - pub fn header(&self, name: &str) -> Result<&str> { + pub fn header(&self, name: &str) -> Result> { let name = CString::new(name).unwrap(); let ret = unsafe { ffi::notmuch_message_get_header(self.handle.ptr, name.as_ptr()) }; if ret.is_null() { Err(Error::UnspecifiedError) } else { - Ok(ret.to_str().unwrap()) + Ok(match ret.to_str().unwrap() { + "" => None, + ret => Some(ret) + }) } } -- cgit v1.2.1 From 780ba5face4f9d324c7ac973d83445eaf224bb2b Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 7 Nov 2018 21:08:15 +0100 Subject: trust clippy and rustfmt --- src/directory.rs | 4 ---- src/message.rs | 2 +- src/messages.rs | 10 ---------- src/query.rs | 3 --- tests/main.rs | 4 ++-- 5 files changed, 3 insertions(+), 20 deletions(-) diff --git a/src/directory.rs b/src/directory.rs index 1d14568..c2bb88d 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -1,10 +1,6 @@ -use std::ffi::{CStr, CString}; use std::ops::Drop; -use std::path::Path; -use std::ptr; use supercow::{Phantomcow, Supercow}; -use error::Result; use ffi; use Database; use Filenames; diff --git a/src/message.rs b/src/message.rs index ef9079f..4b3c92f 100644 --- a/src/message.rs +++ b/src/message.rs @@ -91,7 +91,7 @@ impl<'o, Owner: MessageOwner + 'o> Message<'o, Owner> { } else { Ok(match ret.to_str().unwrap() { "" => None, - ret => Some(ret) + ret => Some(ret), }) } } diff --git a/src/messages.rs b/src/messages.rs index 8537f90..34a9bb5 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -44,16 +44,6 @@ impl<'o, Owner: MessagesOwner + 'o> Messages<'o, Owner> { marker: owner.into(), } } - - pub(crate) fn from_handle>>( - handle: MessagesPtr, - owner: O, - ) -> Messages<'o, Owner> { - Messages { - handle, - marker: owner.into(), - } - } } impl<'o, Owner: MessagesOwner + 'o> MessageOwner for Messages<'o, Owner> {} diff --git a/src/query.rs b/src/query.rs index c3eb1a2..95a4d56 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,4 +1,3 @@ -use std::ffi::{CStr, CString}; use std::ops::Drop; use std::ptr; @@ -7,8 +6,6 @@ use supercow::{Phantomcow, Supercow}; use error::Result; use ffi; use ffi::Sort; -use messages::MessagesPtr; -use threads::ThreadsPtr; use Database; use Messages; use MessagesOwner; diff --git a/tests/main.rs b/tests/main.rs index 4c74115..dd96644 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -3,8 +3,8 @@ extern crate notmuch; use std::sync::Arc; -use notmuch::{Query, QueryExt, Thread, Threads}; -use notmuch::{StreamingIterator, StreamingIteratorExt}; +use notmuch::StreamingIteratorExt; +use notmuch::{Query, QueryExt, Threads}; fn main() { let mut mail_path = dirs::home_dir().unwrap(); -- cgit v1.2.1 From 9dad03a829708985a8ff9428c176decd1679ca51 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 7 Nov 2018 21:09:22 +0100 Subject: bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 5e76b6e..6cfd5a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "notmuch" -version = "0.4.0" +version = "0.4.1" authors = ["Dirk Van Haerenborgh "] homepage = "https://github.com/vhdirk/notmuch-rs" repository = "https://github.com/vhdirk/notmuch-rs" -- cgit v1.2.1 From 9402ef4cf81e711ca59a1cc24748c6d6c8f7071e Mon Sep 17 00:00:00 2001 From: eaon Date: Mon, 12 Nov 2018 07:58:34 -0500 Subject: Simplify example in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4719ee0..7c7811d 100644 --- a/README.md +++ b/README.md @@ -38,8 +38,8 @@ fn main() { let mut mail_path = std::env::home_dir().unwrap(); mail_path.push(".mail"); - let db = notmuch::Database::open(&mail_path.to_str().unwrap().to_string(), notmuch::DatabaseMode::ReadOnly).unwrap(); - let query = db.create_query(&"".to_string()).unwrap(); + let db = notmuch::Database::open(&mail_path, notmuch::DatabaseMode::ReadOnly).unwrap(); + let query = db.create_query("").unwrap(); let mut threads = query.search_threads().unwrap(); while let Some(thread) = threads.next() { -- cgit v1.2.1 From ba03b994b3318c84923f4a9a23cfc4270a5ace75 Mon Sep 17 00:00:00 2001 From: eaon Date: Mon, 12 Nov 2018 07:58:50 -0500 Subject: Switch to `where` syntax --- src/database.rs | 86 ++++++++++++++++++++++++++++++++++++-------------------- src/directory.rs | 15 +++++----- src/filenames.rs | 29 ++++++++++++------- src/message.rs | 66 +++++++++++++++++++++++++------------------ src/messages.rs | 56 +++++++++++++++++++++++------------- src/query.rs | 35 +++++++++++++---------- src/tags.rs | 30 +++++++++++++------- src/thread.rs | 64 ++++++++++++++++++++++++----------------- src/threads.rs | 49 +++++++++++++++++++++----------- 9 files changed, 269 insertions(+), 161 deletions(-) diff --git a/src/database.rs b/src/database.rs index c5cb917..d5e6700 100644 --- a/src/database.rs +++ b/src/database.rs @@ -57,7 +57,10 @@ pub struct Database { impl TagsOwner for Database {} impl Database { - pub fn create>(path: &P) -> Result { + pub fn create

(path: &P) -> Result + where + P: AsRef, + { let path_str = CString::new(path.as_ref().to_str().unwrap()).unwrap(); let mut db = ptr::null_mut(); @@ -68,7 +71,10 @@ impl Database { }) } - pub fn open>(path: &P, mode: DatabaseMode) -> Result { + pub fn open

(path: &P, mode: DatabaseMode) -> Result + where + P: AsRef, + { let path_str = CString::new(path.as_ref().to_str().unwrap()).unwrap(); let mut db = ptr::null_mut(); @@ -88,27 +94,28 @@ impl Database { Ok(()) } - pub fn compact, F: FnMut(&str)>( - path: &P, - backup_path: Option<&P>, - ) -> Result<()> { + pub fn compact(path: &P, backup_path: Option<&P>) -> Result<()> + where + P: AsRef, + F: FnMut(&str), + { let status: Option = None; Database::_compact(path, backup_path, status) } - pub fn compact_with_status, F: FnMut(&str)>( - path: &P, - backup_path: Option<&P>, - status: F, - ) -> Result<()> { + pub fn compact_with_status(path: &P, backup_path: Option<&P>, status: F) -> Result<()> + where + P: AsRef, + F: FnMut(&str), + { Database::_compact(path, backup_path, Some(status)) } - fn _compact, F: FnMut(&str)>( - path: &P, - backup_path: Option<&P>, - status: Option, - ) -> Result<()> { + fn _compact(path: &P, backup_path: Option<&P>, status: Option) -> Result<()> + where + P: AsRef, + F: FnMut(&str), + { extern "C" fn wrapper( message: *const libc::c_char, closure: *mut libc::c_void, @@ -174,18 +181,30 @@ impl Database { unsafe { ffi::notmuch_database_needs_upgrade(self.handle.ptr) == 1 } } - pub fn upgrade(&mut self) -> Result<()> { + pub fn upgrade(&mut self) -> Result<()> + where + F: FnMut(f64), + { let status: Option = None; self._upgrade(status) } - pub fn upgrade_with_status(&mut self, status: F) -> Result<()> { + pub fn upgrade_with_status(&mut self, status: F) -> Result<()> + where + F: FnMut(f64), + { self._upgrade(Some(status)) } - fn _upgrade(&mut self, status: Option) -> Result<()> { + fn _upgrade(&mut self, status: Option) -> Result<()> + where + F: FnMut(f64), + { #[allow(trivial_numeric_casts)] - extern "C" fn wrapper(closure: *mut libc::c_void, progress: libc::c_double) { + extern "C" fn wrapper(closure: *mut libc::c_void, progress: libc::c_double) + where + F: FnMut(f64), + { let closure = closure as *mut F; unsafe { (*closure)(progress as f64) } } @@ -208,7 +227,10 @@ impl Database { Ok(()) } - pub fn directory<'d, P: AsRef>(&'d self, path: &P) -> Result>> { + pub fn directory<'d, P>(&'d self, path: &P) -> Result>> + where + P: AsRef, + { ::directory(self, path) } @@ -222,10 +244,10 @@ impl Database { } pub trait DatabaseExt { - fn create_query<'d, D: Into>>( - database: D, - query_string: &str, - ) -> Result> { + fn create_query<'d, D>(database: D, query_string: &str) -> Result> + where + D: Into>, + { let dbref = database.into(); let query_str = CString::new(query_string).unwrap(); @@ -234,7 +256,10 @@ pub trait DatabaseExt { Ok(Query::from_ptr(query, Supercow::phantom(dbref))) } - fn all_tags<'d, D: Into>>(database: D) -> Result> { + fn all_tags<'d, D>(database: D) -> Result> + where + D: Into>, + { let dbref = database.into(); let tags = unsafe { ffi::notmuch_database_get_all_tags(dbref.handle.ptr) }; @@ -242,10 +267,11 @@ pub trait DatabaseExt { Ok(Tags::from_ptr(tags, Supercow::phantom(dbref))) } - fn directory<'d, D: Into>, P: AsRef>( - database: D, - path: &P, - ) -> Result>> { + fn directory<'d, D, P>(database: D, path: &P) -> Result>> + where + D: Into>, + P: AsRef, + { let dbref = database.into(); let path_str = CString::new(path.as_ref().to_str().unwrap()).unwrap(); diff --git a/src/directory.rs b/src/directory.rs index c2bb88d..e3abcf5 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -26,10 +26,10 @@ pub struct Directory<'d> { impl<'d> FilenamesOwner for Directory<'d> {} impl<'d> Directory<'d> { - pub fn from_ptr>>( - ptr: *mut ffi::notmuch_directory_t, - owner: O, - ) -> Directory<'d> { + pub fn from_ptr(ptr: *mut ffi::notmuch_directory_t, owner: O) -> Directory<'d> + where + O: Into>, + { Directory { handle: DirectoryPtr { ptr }, marker: owner.into(), @@ -42,9 +42,10 @@ impl<'d> Directory<'d> { } pub trait DirectoryExt<'d> { - fn child_directories<'s, S: Into>>>( - directory: S, - ) -> Filenames<'s, Directory<'d>> { + fn child_directories<'s, S>(directory: S) -> Filenames<'s, Directory<'d>> + where + S: Into>>, + { let dir = directory.into(); Filenames::from_ptr( unsafe { ffi::notmuch_directory_get_child_directories(dir.handle.ptr) }, diff --git a/src/filenames.rs b/src/filenames.rs index ae90280..3eef82d 100644 --- a/src/filenames.rs +++ b/src/filenames.rs @@ -25,16 +25,22 @@ impl Drop for FilenamesPtr { } #[derive(Debug)] -pub struct Filenames<'o, Owner: FilenamesOwner + 'o> { +pub struct Filenames<'o, O> +where + O: FilenamesOwner + 'o, +{ pub(crate) handle: FilenamesPtr, - pub(crate) marker: Phantomcow<'o, Owner>, + pub(crate) marker: Phantomcow<'o, O>, } -impl<'o, Owner: FilenamesOwner + 'o> Filenames<'o, Owner> { - pub fn from_ptr>>( - ptr: *mut ffi::notmuch_filenames_t, - owner: O, - ) -> Filenames<'o, Owner> { +impl<'o, O> Filenames<'o, O> +where + O: FilenamesOwner + 'o, +{ + pub fn from_ptr

(ptr: *mut ffi::notmuch_filenames_t, owner: P) -> Filenames<'o, O> + where + P: Into>, + { Filenames { handle: FilenamesPtr { ptr }, marker: owner.into(), @@ -42,7 +48,10 @@ impl<'o, Owner: FilenamesOwner + 'o> Filenames<'o, Owner> { } } -impl<'o, Owner: FilenamesOwner + 'o> Iterator for Filenames<'o, Owner> { +impl<'o, O> Iterator for Filenames<'o, O> +where + O: FilenamesOwner + 'o, +{ type Item = PathBuf; fn next(self: &mut Self) -> Option { @@ -62,5 +71,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, O> Send for Filenames<'o, O> where O: FilenamesOwner + 'o {} +unsafe impl<'o, O> Sync for Filenames<'o, O> where O: FilenamesOwner + 'o {} diff --git a/src/message.rs b/src/message.rs index 4b3c92f..b253d68 100644 --- a/src/message.rs +++ b/src/message.rs @@ -28,20 +28,26 @@ impl Drop for MessagePtr { } #[derive(Debug)] -pub struct Message<'o, Owner: MessageOwner + 'o> { +pub struct Message<'o, O> +where + O: MessageOwner + 'o, +{ pub(crate) handle: MessagePtr, - marker: Phantomcow<'o, Owner>, + marker: Phantomcow<'o, O>, } -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>>( - ptr: *mut ffi::notmuch_message_t, - owner: O, - ) -> Message<'o, Owner> { +impl<'o, O> MessagesOwner for Message<'o, O> where O: MessageOwner + 'o {} +impl<'o, O> FilenamesOwner for Message<'o, O> where O: MessageOwner + 'o {} +impl<'o, O> TagsOwner for Message<'o, O> where O: MessageOwner + 'o {} + +impl<'o, O> Message<'o, O> +where + O: MessageOwner + 'o, +{ + pub fn from_ptr

(ptr: *mut ffi::notmuch_message_t, owner: P) -> Message<'o, O> + where + P: Into>, + { Message { handle: MessagePtr { ptr }, marker: owner.into(), @@ -59,7 +65,7 @@ impl<'o, Owner: MessageOwner + 'o> Message<'o, Owner> { } pub fn replies(self: &Self) -> Messages { - >::replies(self) + >::replies(self) } #[cfg(feature = "v0_26")] @@ -68,7 +74,7 @@ impl<'o, Owner: MessageOwner + 'o> Message<'o, Owner> { } pub fn filenames(self: &Self) -> Filenames { - >::filenames(self) + >::filenames(self) } pub fn filename(self: &Self) -> PathBuf { @@ -97,7 +103,7 @@ impl<'o, Owner: MessageOwner + 'o> Message<'o, Owner> { } pub fn tags(&self) -> Tags { - >::tags(self) + >::tags(self) } pub fn add_tag(self: &Self, tag: &str) -> Status { @@ -115,10 +121,14 @@ impl<'o, Owner: MessageOwner + 'o> Message<'o, Owner> { } } -pub trait MessageExt<'o, Owner: MessageOwner + 'o> { - fn tags<'s, S: Into>>>( - message: S, - ) -> Tags<'s, Message<'o, Owner>> { +pub trait MessageExt<'o, O> +where + O: MessageOwner + 'o, +{ + fn tags<'s, S>(message: S) -> Tags<'s, Message<'o, O>> + where + S: Into>>, + { let messageref = message.into(); Tags::from_ptr( unsafe { ffi::notmuch_message_get_tags(messageref.handle.ptr) }, @@ -126,9 +136,10 @@ pub trait MessageExt<'o, Owner: MessageOwner + 'o> { ) } - fn replies<'s, S: Into>>>( - message: S, - ) -> Messages<'s, Message<'o, Owner>> { + fn replies<'s, S>(message: S) -> Messages<'s, Message<'o, O>> + where + S: Into>>, + { let messageref = message.into(); Messages::from_ptr( unsafe { ffi::notmuch_message_get_replies(messageref.handle.ptr) }, @@ -136,9 +147,10 @@ pub trait MessageExt<'o, Owner: MessageOwner + 'o> { ) } - fn filenames<'s, S: Into>>>( - message: S, - ) -> Filenames<'s, Message<'o, Owner>> { + fn filenames<'s, S>(message: S) -> Filenames<'s, Message<'o, O>> + where + S: Into>>, + { let messageref = message.into(); Filenames::from_ptr( unsafe { ffi::notmuch_message_get_filenames(messageref.handle.ptr) }, @@ -147,7 +159,7 @@ pub trait MessageExt<'o, Owner: MessageOwner + 'o> { } } -impl<'o, Owner: MessageOwner + 'o> MessageExt<'o, Owner> for Message<'o, Owner> {} +impl<'o, O> MessageExt<'o, O> for Message<'o, O> where O: MessageOwner + 'o {} -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, O> Send for Message<'o, O> where O: MessageOwner + 'o {} +unsafe impl<'o, O> Sync for Message<'o, O> where O: MessageOwner + 'o {} diff --git a/src/messages.rs b/src/messages.rs index 34a9bb5..5977e42 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -29,16 +29,22 @@ impl Drop for MessagesPtr { } #[derive(Debug)] -pub struct Messages<'o, Owner: MessagesOwner + 'o> { +pub struct Messages<'o, O> +where + O: MessagesOwner + 'o, +{ pub(crate) handle: MessagesPtr, - marker: Phantomcow<'o, Owner>, + marker: Phantomcow<'o, O>, } -impl<'o, Owner: MessagesOwner + 'o> Messages<'o, Owner> { - pub(crate) fn from_ptr>>( - ptr: *mut ffi::notmuch_messages_t, - owner: O, - ) -> Messages<'o, Owner> { +impl<'o, O> Messages<'o, O> +where + O: MessagesOwner + 'o, +{ + pub(crate) fn from_ptr

(ptr: *mut ffi::notmuch_messages_t, owner: P) -> Messages<'o, O> + where + P: Into>, + { Messages { handle: MessagesPtr { ptr }, marker: owner.into(), @@ -46,10 +52,13 @@ 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, O> MessageOwner for Messages<'o, O> where O: MessagesOwner + 'o {} +impl<'o, O> TagsOwner for Messages<'o, O> where O: MessagesOwner + 'o {} -impl<'o, Owner: MessagesOwner + 'o> Messages<'o, Owner> { +impl<'o, O> Messages<'o, O> +where + O: MessagesOwner + 'o, +{ /** * Return a list of tags from all messages. * @@ -71,22 +80,31 @@ impl<'o, Owner: MessagesOwner + 'o> Messages<'o, Owner> { } } -impl<'s, 'o: 's, Owner: MessagesOwner + 'o> StreamingIterator<'s, Message<'s, Self>> - for Messages<'o, Owner> +impl<'s, 'o: 's, O> StreamingIterator<'s, Message<'s, Self>> for Messages<'o, O> +where + O: MessagesOwner + 'o, { fn next(&'s mut self) -> Option> { >>::next(Supercow::borrowed(self)) } } -pub trait MessagesExt<'o, Owner: MessagesOwner + 'o> {} +pub trait MessagesExt<'o, O> +where + O: MessagesOwner + 'o, +{ +} -impl<'o, Owner: MessagesOwner + 'o> MessagesExt<'o, Owner> for Messages<'o, Owner> {} +impl<'o, O> MessagesExt<'o, O> for Messages<'o, O> where O: MessagesOwner + 'o {} -impl<'s, 'o: 's, Owner: MessagesOwner + 'o> StreamingIteratorExt<'s, Message<'s, Self>> - for Messages<'o, Owner> +impl<'s, 'o: 's, O> StreamingIteratorExt<'s, Message<'s, Self>> for Messages<'o, O> +where + O: MessagesOwner + 'o, { - fn next>>>(messages: S) -> Option> { + fn next(messages: S) -> Option> + where + S: Into>>, + { let messagesref = messages.into(); let valid = unsafe { ffi::notmuch_messages_valid(messagesref.handle.ptr) }; @@ -104,5 +122,5 @@ impl<'s, 'o: 's, Owner: MessagesOwner + 'o> StreamingIteratorExt<'s, Message<'s, } } -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, O> Send for Messages<'o, O> where O: MessagesOwner + 'o {} +unsafe impl<'o, O> Sync for Messages<'o, O> where O: MessagesOwner + 'o {} diff --git a/src/query.rs b/src/query.rs index 95a4d56..c73d4ca 100644 --- a/src/query.rs +++ b/src/query.rs @@ -33,27 +33,30 @@ impl<'d> ThreadsOwner for Query<'d> {} impl<'d> MessagesOwner for Query<'d> {} impl<'d> Query<'d> { - pub(crate) fn from_ptr>>( - ptr: *mut ffi::notmuch_query_t, - owner: O, - ) -> Query<'d> { + pub(crate) fn from_ptr(ptr: *mut ffi::notmuch_query_t, owner: O) -> Query<'d> + where + O: Into>, + { Query { handle: QueryPtr { ptr }, marker: owner.into(), } } - pub(crate) fn from_handle>>( - handle: QueryPtr, - owner: O, - ) -> Query<'d> { + pub(crate) fn from_handle(handle: QueryPtr, owner: O) -> Query<'d> + where + O: Into>, + { Query { handle, marker: owner.into(), } } - pub fn create>>(db: D, query_string: &str) -> Result { + pub fn create(db: D, query_string: &str) -> Result + where + D: Into>, + { let dbref = db.into(); dbref .handle @@ -97,9 +100,10 @@ impl<'d> Query<'d> { } pub trait QueryExt<'d> { - fn search_threads<'q, Q: Into>>>( - query: Q, - ) -> Result>> { + fn search_threads<'q, Q>(query: Q) -> Result>> + where + Q: Into>>, + { let queryref = query.into(); let mut thrds = ptr::null_mut(); @@ -111,9 +115,10 @@ pub trait QueryExt<'d> { Ok(Threads::from_ptr(thrds, Supercow::phantom(queryref))) } - fn search_messages<'q, Q: Into>>>( - query: Q, - ) -> Result>> { + fn search_messages<'q, Q>(query: Q) -> Result>> + where + Q: Into>>, + { let queryref = query.into(); let mut msgs = ptr::null_mut(); diff --git a/src/tags.rs b/src/tags.rs index 573a491..96afdf6 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -25,11 +25,14 @@ pub struct Tags<'o, Owner: TagsOwner + 'o> { marker: Phantomcow<'o, Owner>, } -impl<'o, Owner: TagsOwner + 'o> Tags<'o, Owner> { - pub fn from_ptr>>( - ptr: *mut ffi::notmuch_tags_t, - owner: O, - ) -> Tags<'o, Owner> { +impl<'o, O> Tags<'o, O> +where + O: TagsOwner + 'o, +{ + pub fn from_ptr

(ptr: *mut ffi::notmuch_tags_t, owner: P) -> Tags<'o, O> + where + P: Into>, + { Tags { handle: TagsPtr { ptr }, marker: owner.into(), @@ -37,7 +40,10 @@ impl<'o, Owner: TagsOwner + 'o> Tags<'o, Owner> { } } -impl<'o, Owner: TagsOwner + 'o> Iterator for Tags<'o, Owner> { +impl<'o, O> Iterator for Tags<'o, O> +where + O: TagsOwner + 'o, +{ type Item = String; fn next(&mut self) -> Option { @@ -58,9 +64,13 @@ impl<'o, Owner: TagsOwner + 'o> Iterator for Tags<'o, Owner> { } } -pub trait TagsExt<'o, Owner: TagsOwner + 'o> {} +pub trait TagsExt<'o, O> +where + O: TagsOwner + 'o, +{ +} -impl<'o, Owner: TagsOwner + 'o> TagsExt<'o, Owner> for Tags<'o, Owner> {} +impl<'o, O> TagsExt<'o, O> for Tags<'o, O> where O: TagsOwner + 'o {} -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, O> Send for Tags<'o, O> where O: TagsOwner + 'o {} +unsafe impl<'o, O> Sync for Tags<'o, O> where O: TagsOwner + 'o {} diff --git a/src/thread.rs b/src/thread.rs index a529508..fce026d 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -22,19 +22,25 @@ impl Drop for ThreadPtr { } #[derive(Debug)] -pub struct Thread<'o, Owner: ThreadOwner + 'o> { +pub struct Thread<'o, O> +where + O: ThreadOwner + 'o, +{ pub(crate) handle: ThreadPtr, - marker: Phantomcow<'o, Owner>, + marker: Phantomcow<'o, O>, } -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>>( - ptr: *mut ffi::notmuch_thread_t, - owner: O, - ) -> Thread<'o, Owner> { +impl<'o, O> MessagesOwner for Thread<'o, O> where O: ThreadOwner + 'o {} +impl<'o, O> TagsOwner for Thread<'o, O> where O: ThreadOwner + 'o {} + +impl<'o, O> Thread<'o, O> +where + O: ThreadOwner + 'o, +{ + pub fn from_ptr

(ptr: *mut ffi::notmuch_thread_t, owner: P) -> Thread<'o, O> + where + P: Into>, + { Thread { handle: ThreadPtr { ptr }, marker: owner.into(), @@ -56,17 +62,17 @@ impl<'o, Owner: ThreadOwner + 'o> Thread<'o, Owner> { } pub fn toplevel_messages(self: &Self) -> Messages { - >::toplevel_messages(self) + >::toplevel_messages(self) } /// Get a `Messages` iterator for all messages in 'thread' in /// oldest-first order. pub fn messages(self: &Self) -> Messages { - >::messages(self) + >::messages(self) } pub fn tags(&self) -> Tags { - >::tags(self) + >::tags(self) } pub fn subject(self: &Self) -> String { @@ -97,10 +103,14 @@ impl<'o, Owner: ThreadOwner + 'o> Thread<'o, Owner> { } } -pub trait ThreadExt<'o, Owner: ThreadOwner + 'o> { - fn tags<'s, S: Into>>>( - thread: S, - ) -> Tags<'s, Thread<'o, Owner>> { +pub trait ThreadExt<'o, O> +where + O: ThreadOwner + 'o, +{ + fn tags<'s, S>(thread: S) -> Tags<'s, Thread<'o, O>> + where + S: Into>>, + { let threadref = thread.into(); Tags::from_ptr( unsafe { ffi::notmuch_thread_get_tags(threadref.handle.ptr) }, @@ -108,9 +118,10 @@ pub trait ThreadExt<'o, Owner: ThreadOwner + 'o> { ) } - fn toplevel_messages<'s, S: Into>>>( - thread: S, - ) -> Messages<'s, Thread<'o, Owner>> { + fn toplevel_messages<'s, S>(thread: S) -> Messages<'s, Thread<'o, O>> + where + S: Into>>, + { let threadref = thread.into(); Messages::from_ptr( unsafe { ffi::notmuch_thread_get_toplevel_messages(threadref.handle.ptr) }, @@ -120,9 +131,10 @@ pub trait ThreadExt<'o, Owner: ThreadOwner + 'o> { /// Get a `Messages` iterator for all messages in 'thread' in /// oldest-first order. - fn messages<'s, S: Into>>>( - thread: S, - ) -> Messages<'s, Thread<'o, Owner>> { + fn messages<'s, S>(thread: S) -> Messages<'s, Thread<'o, O>> + where + S: Into>>, + { let threadref = thread.into(); Messages::from_ptr( unsafe { ffi::notmuch_thread_get_messages(threadref.handle.ptr) }, @@ -131,7 +143,7 @@ pub trait ThreadExt<'o, Owner: ThreadOwner + 'o> { } } -impl<'o, Owner: ThreadOwner + 'o> ThreadExt<'o, Owner> for Thread<'o, Owner> {} +impl<'o, O> ThreadExt<'o, O> for Thread<'o, O> where O: ThreadOwner + 'o {} -unsafe impl<'o, Owner: ThreadOwner + 'o> Send for Thread<'o, Owner> {} -unsafe impl<'o, Owner: ThreadOwner + 'o> Sync for Thread<'o, Owner> {} +unsafe impl<'o, O> Send for Thread<'o, O> where O: ThreadOwner + 'o {} +unsafe impl<'o, O> Sync for Thread<'o, O> where O: ThreadOwner + 'o {} diff --git a/src/threads.rs b/src/threads.rs index e2312c7..f99ffb1 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -21,18 +21,24 @@ impl Drop for ThreadsPtr { } #[derive(Debug)] -pub struct Threads<'o, Owner: ThreadsOwner + 'o> { +pub struct Threads<'o, O> +where + O: ThreadsOwner + 'o, +{ handle: ThreadsPtr, - marker: Phantomcow<'o, Owner>, + marker: Phantomcow<'o, O>, } -impl<'o, Owner: ThreadsOwner + 'o> ThreadOwner for Threads<'o, Owner> {} +impl<'o, O> ThreadOwner for Threads<'o, O> where O: ThreadsOwner + 'o {} -impl<'o, Owner: ThreadsOwner + 'o> Threads<'o, Owner> { - pub fn from_ptr>>( - ptr: *mut ffi::notmuch_threads_t, - owner: O, - ) -> Threads<'o, Owner> { +impl<'o, O> Threads<'o, O> +where + O: ThreadsOwner + 'o, +{ + pub fn from_ptr

(ptr: *mut ffi::notmuch_threads_t, owner: P) -> Threads<'o, O> + where + P: Into>, + { Threads { handle: ThreadsPtr { ptr }, marker: owner.into(), @@ -40,22 +46,31 @@ impl<'o, Owner: ThreadsOwner + 'o> Threads<'o, Owner> { } } -impl<'s, 'o: 's, Owner: ThreadsOwner + 'o> StreamingIterator<'s, Thread<'s, Self>> - for Threads<'o, Owner> +impl<'s, 'o: 's, O> StreamingIterator<'s, Thread<'s, Self>> for Threads<'o, O> +where + O: ThreadsOwner + 'o, { fn next(&'s mut self) -> Option> { >>::next(Supercow::borrowed(self)) } } -pub trait ThreadsExt<'o, Owner: ThreadsOwner + 'o> {} +pub trait ThreadsExt<'o, O> +where + O: ThreadsOwner + 'o, +{ +} -impl<'o, Owner: ThreadsOwner + 'o> ThreadsExt<'o, Owner> for Threads<'o, Owner> {} +impl<'o, O> ThreadsExt<'o, O> for Threads<'o, O> where O: ThreadsOwner + 'o {} -impl<'s, 'o: 's, Owner: ThreadsOwner + 'o> StreamingIteratorExt<'s, Thread<'s, Self>> - for Threads<'o, Owner> +impl<'s, 'o: 's, O> StreamingIteratorExt<'s, Thread<'s, Self>> for Threads<'o, O> +where + O: ThreadsOwner + 'o, { - fn next>>>(threads: S) -> Option> { + fn next(threads: S) -> Option> + where + S: Into>>, + { let threadsref = threads.into(); let valid = unsafe { ffi::notmuch_threads_valid(threadsref.handle.ptr) }; @@ -73,5 +88,5 @@ impl<'s, 'o: 's, Owner: ThreadsOwner + 'o> StreamingIteratorExt<'s, Thread<'s, S } } -unsafe impl<'o, Owner: ThreadsOwner + 'o> Send for Threads<'o, Owner> {} -unsafe impl<'o, Owner: ThreadsOwner + 'o> Sync for Threads<'o, Owner> {} +unsafe impl<'o, O> Send for Threads<'o, O> where O: ThreadsOwner + 'o {} +unsafe impl<'o, O> Sync for Threads<'o, O> where O: ThreadsOwner + 'o {} -- cgit v1.2.1 From d4d8969c83077b409137a32c11e6b18b6ca2fdff Mon Sep 17 00:00:00 2001 From: eaon Date: Mon, 19 Nov 2018 17:21:58 -0500 Subject: Add Database::remove_message --- src/database.rs | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/database.rs b/src/database.rs index d5e6700..8f365cb 100644 --- a/src/database.rs +++ b/src/database.rs @@ -9,6 +9,7 @@ use libc; use error::Result; use ffi; +use ffi::Status; use query::QueryPtr; use utils::ToStr; use Directory; @@ -140,8 +141,7 @@ impl Database { }, status.map_or(ptr::null_mut(), |f| &f as *const _ as *mut libc::c_void), ) - } - .as_result() + }.as_result() ); Ok(()) @@ -220,8 +220,7 @@ impl Database { }, status.map_or(ptr::null_mut(), |f| &f as *const _ as *mut libc::c_void), ) - } - .as_result() + }.as_result() ); Ok(()) @@ -241,6 +240,13 @@ impl Database { pub fn all_tags<'d>(&'d self) -> Result> { ::all_tags(self) } + + pub fn remove_message<'d, P>(&'d self, path: &P) -> Status + where + P: AsRef, + { + ::remove_message(self, path) + } } pub trait DatabaseExt { @@ -280,8 +286,7 @@ pub trait DatabaseExt { try!( unsafe { ffi::notmuch_database_get_directory(dbref.handle.ptr, path_str.as_ptr(), &mut dir) - } - .as_result() + }.as_result() ); if dir.is_null() { @@ -290,6 +295,19 @@ pub trait DatabaseExt { Ok(Some(Directory::from_ptr(dir, Supercow::phantom(dbref)))) } } + + fn remove_message<'d, D, P>(database: D, path: &P) -> Status + where + D: Into>, + P: AsRef, + { + let dbref = database.into(); + let msg_path = CString::new(path.as_ref()).unwrap(); + + Status::from(unsafe { + ffi::notmuch_database_remove_message(dbref.handle.ptr, msg_path.as_ptr()) + }) + } } impl DatabaseExt for Database {} -- cgit v1.2.1 From 020efa44a914d72b16575b3380d5a364e6d0b0ca Mon Sep 17 00:00:00 2001 From: eaon Date: Mon, 12 Nov 2018 19:04:27 -0500 Subject: If we get a i32 timestamp make sure we cast it to i64 --- src/message.rs | 2 +- src/thread.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/message.rs b/src/message.rs index b253d68..83a834f 100644 --- a/src/message.rs +++ b/src/message.rs @@ -86,7 +86,7 @@ where } pub fn date(&self) -> i64 { - unsafe { ffi::notmuch_message_get_date(self.handle.ptr) } + unsafe { ffi::notmuch_message_get_date(self.handle.ptr) as i64 } } pub fn header(&self, name: &str) -> Result> { diff --git a/src/thread.rs b/src/thread.rs index fce026d..8a8c1d7 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -94,12 +94,12 @@ where /// 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) as i64 } } /// 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) as i64 } } } -- cgit v1.2.1 From 47a084069c9b253dc5ec5c92c14527845ed89bec Mon Sep 17 00:00:00 2001 From: eaon Date: Tue, 20 Nov 2018 22:36:29 -0500 Subject: Match up Database::remove_message with Message::filename return type --- src/database.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/database.rs b/src/database.rs index 8f365cb..82579f3 100644 --- a/src/database.rs +++ b/src/database.rs @@ -243,7 +243,7 @@ impl Database { pub fn remove_message<'d, P>(&'d self, path: &P) -> Status where - P: AsRef, + P: AsRef, { ::remove_message(self, path) } @@ -299,14 +299,19 @@ pub trait DatabaseExt { fn remove_message<'d, D, P>(database: D, path: &P) -> Status where D: Into>, - P: AsRef, + P: AsRef, { let dbref = database.into(); - let msg_path = CString::new(path.as_ref()).unwrap(); - - Status::from(unsafe { - ffi::notmuch_database_remove_message(dbref.handle.ptr, msg_path.as_ptr()) - }) + match path.as_ref().to_str() { + Some(path_str) => { + let msg_path = CString::new(path_str).unwrap(); + + Status::from(unsafe { + ffi::notmuch_database_remove_message(dbref.handle.ptr, msg_path.as_ptr()) + }) + } + None => Status::FileError + } } } -- cgit v1.2.1 From bed2b54ea403872b7e540ade251e9609090a7cf5 Mon Sep 17 00:00:00 2001 From: eaon Date: Wed, 21 Nov 2018 11:30:36 -0500 Subject: Use the ? operator instead of the try! macro --- src/database.rs | 70 +++++++++++++++++++++++++-------------------------------- src/query.rs | 16 +++++-------- 2 files changed, 37 insertions(+), 49 deletions(-) diff --git a/src/database.rs b/src/database.rs index 82579f3..5ed9537 100644 --- a/src/database.rs +++ b/src/database.rs @@ -65,7 +65,7 @@ impl Database { 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()); + unsafe { ffi::notmuch_database_create(path_str.as_ptr(), &mut db) }.as_result()?; Ok(Database { handle: DatabasePtr { ptr: db }, @@ -79,10 +79,8 @@ impl Database { 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() - ); + unsafe { ffi::notmuch_database_open(path_str.as_ptr(), mode.into(), &mut db) } + .as_result()?; Ok(Database { handle: DatabasePtr { ptr: db }, @@ -90,7 +88,7 @@ impl Database { } pub fn close(&mut self) -> Result<()> { - try!(unsafe { ffi::notmuch_database_close(self.handle.ptr) }.as_result()); + unsafe { ffi::notmuch_database_close(self.handle.ptr) }.as_result()?; Ok(()) } @@ -129,20 +127,18 @@ impl Database { 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::) - } else { - None - }, - status.map_or(ptr::null_mut(), |f| &f as *const _ as *mut libc::c_void), - ) - }.as_result() - ); + 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::) + } else { + None + }, + status.map_or(ptr::null_mut(), |f| &f as *const _ as *mut libc::c_void), + ) + }.as_result()?; Ok(()) } @@ -209,19 +205,17 @@ impl Database { unsafe { (*closure)(progress as f64) } } - try!( - unsafe { - ffi::notmuch_database_upgrade( - self.handle.ptr, - if status.is_some() { - Some(wrapper::) - } else { - None - }, - status.map_or(ptr::null_mut(), |f| &f as *const _ as *mut libc::c_void), - ) - }.as_result() - ); + unsafe { + ffi::notmuch_database_upgrade( + self.handle.ptr, + if status.is_some() { + Some(wrapper::) + } else { + None + }, + status.map_or(ptr::null_mut(), |f| &f as *const _ as *mut libc::c_void), + ) + }.as_result()?; Ok(()) } @@ -283,11 +277,9 @@ pub trait DatabaseExt { 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(dbref.handle.ptr, path_str.as_ptr(), &mut dir) - }.as_result() - ); + unsafe { + ffi::notmuch_database_get_directory(dbref.handle.ptr, path_str.as_ptr(), &mut dir) + }.as_result()?; if dir.is_null() { Ok(None) @@ -310,7 +302,7 @@ pub trait DatabaseExt { ffi::notmuch_database_remove_message(dbref.handle.ptr, msg_path.as_ptr()) }) } - None => Status::FileError + None => Status::FileError, } } } diff --git a/src/query.rs b/src/query.rs index c73d4ca..38711e9 100644 --- a/src/query.rs +++ b/src/query.rs @@ -82,7 +82,7 @@ impl<'d> Query<'d> { pub fn count_messages(self: &Self) -> Result { let mut cnt = 0; - try!(unsafe { ffi::notmuch_query_count_messages(self.handle.ptr, &mut cnt,) }.as_result()); + unsafe { ffi::notmuch_query_count_messages(self.handle.ptr, &mut cnt) }.as_result()?; Ok(cnt) } @@ -93,7 +93,7 @@ impl<'d> Query<'d> { pub fn count_threads(self: &Self) -> Result { let mut cnt = 0; - try!(unsafe { ffi::notmuch_query_count_threads(self.handle.ptr, &mut cnt,) }.as_result()); + unsafe { ffi::notmuch_query_count_threads(self.handle.ptr, &mut cnt) }.as_result()?; Ok(cnt) } @@ -107,10 +107,8 @@ pub trait QueryExt<'d> { let queryref = query.into(); let mut thrds = ptr::null_mut(); - try!( - unsafe { ffi::notmuch_query_search_threads(queryref.handle.ptr, &mut thrds) } - .as_result() - ); + unsafe { ffi::notmuch_query_search_threads(queryref.handle.ptr, &mut thrds) } + .as_result()?; Ok(Threads::from_ptr(thrds, Supercow::phantom(queryref))) } @@ -122,10 +120,8 @@ pub trait QueryExt<'d> { let queryref = query.into(); let mut msgs = ptr::null_mut(); - try!( - unsafe { ffi::notmuch_query_search_messages(queryref.handle.ptr, &mut msgs) } - .as_result() - ); + unsafe { ffi::notmuch_query_search_messages(queryref.handle.ptr, &mut msgs) } + .as_result()?; Ok(Messages::from_ptr(msgs, Supercow::phantom(queryref))) } -- cgit v1.2.1 From 4ca963a68258abed7f158ffa5289030026e11720 Mon Sep 17 00:00:00 2001 From: eaon Date: Wed, 21 Nov 2018 14:06:21 -0500 Subject: Return Result<(), Status::NotmuchError> instead of Status --- src/database.rs | 13 ++++++------- src/ffi.rs | 7 ++++--- src/message.rs | 13 ++++++------- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/database.rs b/src/database.rs index 5ed9537..102a7a9 100644 --- a/src/database.rs +++ b/src/database.rs @@ -7,7 +7,7 @@ use supercow::Supercow; use libc; -use error::Result; +use error::{Error, Result}; use ffi; use ffi::Status; use query::QueryPtr; @@ -235,7 +235,7 @@ impl Database { ::all_tags(self) } - pub fn remove_message<'d, P>(&'d self, path: &P) -> Status + pub fn remove_message<'d, P>(&'d self, path: &P) -> Result<()> where P: AsRef, { @@ -288,7 +288,7 @@ pub trait DatabaseExt { } } - fn remove_message<'d, D, P>(database: D, path: &P) -> Status + fn remove_message<'d, D, P>(database: D, path: &P) -> Result<()> where D: Into>, P: AsRef, @@ -298,11 +298,10 @@ pub trait DatabaseExt { Some(path_str) => { let msg_path = CString::new(path_str).unwrap(); - Status::from(unsafe { - ffi::notmuch_database_remove_message(dbref.handle.ptr, msg_path.as_ptr()) - }) + unsafe { ffi::notmuch_database_remove_message(dbref.handle.ptr, msg_path.as_ptr()) } + .as_result() } - None => Status::FileError, + None => Err(Error::NotmuchError(Status::FileError)), } } } diff --git a/src/ffi.rs b/src/ffi.rs index 16f9db3..3874ae5 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -4,6 +4,7 @@ use libc::{c_char, c_double, c_int, c_uint, c_ulong, c_void, time_t}; +use error::{Error, Result}; use std::{error, fmt, str}; use utils::ToStr; @@ -43,17 +44,17 @@ impl notmuch_status_t { !self.is_ok() } - pub fn as_result(self) -> Result<(), Self> { + pub fn as_result(self) -> Result<()> { if self.is_ok() { Ok(()) } else { - Err(self) + Err(Error::NotmuchError(Status::from(self))) } } } impl ToStr for Status { - fn to_str<'a>(&self) -> Result<&'a str, str::Utf8Error> { + fn to_str<'a>(&self) -> std::result::Result<&'a str, str::Utf8Error> { unsafe { notmuch_status_to_string((*self).into()) }.to_str() } } diff --git a/src/message.rs b/src/message.rs index 83a834f..6feffde 100644 --- a/src/message.rs +++ b/src/message.rs @@ -5,7 +5,6 @@ use supercow::{Phantomcow, Supercow}; use error::{Error, Result}; use ffi; -use ffi::Status; use utils::ToStr; use Filenames; use FilenamesOwner; @@ -106,18 +105,18 @@ where >::tags(self) } - pub fn add_tag(self: &Self, tag: &str) -> Status { + pub fn add_tag(self: &Self, tag: &str) -> Result<()> { let tag = CString::new(tag).unwrap(); - Status::from(unsafe { ffi::notmuch_message_add_tag(self.handle.ptr, tag.as_ptr()) }) + unsafe { ffi::notmuch_message_add_tag(self.handle.ptr, tag.as_ptr()) }.as_result() } - pub fn remove_tag(self: &Self, tag: &str) -> Status { + pub fn remove_tag(self: &Self, tag: &str) -> Result<()> { let tag = CString::new(tag).unwrap(); - Status::from(unsafe { ffi::notmuch_message_remove_tag(self.handle.ptr, tag.as_ptr()) }) + unsafe { ffi::notmuch_message_remove_tag(self.handle.ptr, tag.as_ptr()) }.as_result() } - pub fn remove_all_tags(self: &Self) -> Status { - Status::from(unsafe { ffi::notmuch_message_remove_all_tags(self.handle.ptr) }) + pub fn remove_all_tags(self: &Self) -> Result<()> { + unsafe { ffi::notmuch_message_remove_all_tags(self.handle.ptr) }.as_result() } } -- cgit v1.2.1 From b5b0f7e97abe0dbd5b54a1fc69e764a124c271b2 Mon Sep 17 00:00:00 2001 From: eaon Date: Sun, 9 Dec 2018 12:48:24 -0500 Subject: =?UTF-8?q?Edition=202018=20hit=20stable=20=F0=9F=99=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 1 + src/database.rs | 20 ++++++++++---------- src/directory.rs | 10 +++++----- src/error.rs | 6 +++--- src/ffi.rs | 6 +++--- src/filenames.rs | 4 ++-- src/lib.rs | 28 ++++++++++++++-------------- src/message.rs | 26 +++++++++++++------------- src/messages.rs | 14 +++++++------- src/query.rs | 20 ++++++++++---------- src/tags.rs | 4 ++-- src/thread.rs | 20 ++++++++++---------- src/threads.rs | 10 +++++----- tests/main.rs | 8 ++++---- 14 files changed, 89 insertions(+), 88 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6cfd5a4..30e26c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ repository = "https://github.com/vhdirk/notmuch-rs" description = "Rust interface and bindings for notmuch" license = "GPL-3.0+" readme = "README.md" +edition = "2018" [badges] travis-ci = { repository = "vhdirk/notmuch-rs" } diff --git a/src/database.rs b/src/database.rs index 102a7a9..fe9a39b 100644 --- a/src/database.rs +++ b/src/database.rs @@ -7,18 +7,18 @@ use supercow::Supercow; use libc; -use error::{Error, Result}; -use ffi; -use ffi::Status; -use query::QueryPtr; -use utils::ToStr; -use Directory; -use Query; -use Tags; -use TagsOwner; +use crate::error::{Error, Result}; +use crate::ffi; +use crate::ffi::Status; +use crate::query::QueryPtr; +use crate::utils::ToStr; +use crate::Directory; +use crate::Query; +use crate::Tags; +use crate::TagsOwner; // Re-exported under database module for pretty namespacin'. -pub use ffi::DatabaseMode; +pub use crate::ffi::DatabaseMode; #[derive(Copy, Clone, Debug)] pub struct Version(libc::c_uint); diff --git a/src/directory.rs b/src/directory.rs index e3abcf5..be2ea5c 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -1,10 +1,10 @@ use std::ops::Drop; use supercow::{Phantomcow, Supercow}; -use ffi; -use Database; -use Filenames; -use FilenamesOwner; +use crate::ffi; +use crate::Database; +use crate::Filenames; +use crate::FilenamesOwner; #[derive(Debug)] pub(crate) struct DirectoryPtr { @@ -36,7 +36,7 @@ impl<'d> Directory<'d> { } } - pub fn child_directories(&self) -> Filenames { + pub fn child_directories(&self) -> Filenames<'_, Self> { ::child_directories(self) } } diff --git a/src/error.rs b/src/error.rs index 6de4236..33e1f78 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,7 +1,7 @@ use std; use std::{error, fmt, io, result}; -use ffi; +use crate::ffi; pub type Result = result::Result; @@ -13,7 +13,7 @@ pub enum Error { } impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", error::Error::description(self)) } } @@ -27,7 +27,7 @@ impl std::error::Error for Error { } } - fn cause(&self) -> Option<&error::Error> { + fn cause(&self) -> Option<&dyn error::Error> { match *self { Error::IoError(ref e) => Some(e), Error::NotmuchError(ref e) => Some(e), diff --git a/src/ffi.rs b/src/ffi.rs index 3874ae5..1434ee0 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -4,10 +4,10 @@ use libc::{c_char, c_double, c_int, c_uint, c_ulong, c_void, time_t}; -use error::{Error, Result}; +use crate::error::{Error, Result}; use std::{error, fmt, str}; -use utils::ToStr; +use crate::utils::ToStr; notmuch_enum! { #[repr(C)] @@ -60,7 +60,7 @@ impl ToStr for Status { } impl fmt::Display for Status { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.to_str().unwrap()) } } diff --git a/src/filenames.rs b/src/filenames.rs index 3eef82d..ad4c3e9 100644 --- a/src/filenames.rs +++ b/src/filenames.rs @@ -5,7 +5,7 @@ use std::path::PathBuf; use supercow::Phantomcow; -use ffi; +use crate::ffi; pub trait FilenamesOwner {} @@ -27,7 +27,7 @@ impl Drop for FilenamesPtr { #[derive(Debug)] pub struct Filenames<'o, O> where - O: FilenamesOwner + 'o, + O: FilenamesOwner, { pub(crate) handle: FilenamesPtr, pub(crate) marker: Phantomcow<'o, O>, diff --git a/src/lib.rs b/src/lib.rs index 80916e2..005f142 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,8 +4,8 @@ #[macro_use] mod macros; -extern crate libc; -extern crate supercow; +use libc; + mod ffi; mod utils; @@ -21,16 +21,16 @@ mod tags; mod thread; mod threads; -pub use database::{Database, DatabaseExt}; -pub use directory::{Directory, DirectoryExt}; -pub use error::Error; -pub use filenames::{Filenames, FilenamesOwner}; -pub use message::{Message, MessageExt, MessageOwner}; -pub use messages::{Messages, MessagesExt, MessagesOwner}; -pub use query::{Query, QueryExt}; -pub use tags::{Tags, TagsExt, TagsOwner}; -pub use thread::{Thread, ThreadExt, ThreadOwner}; -pub use threads::{Threads, ThreadsExt, ThreadsOwner}; +pub use crate::database::{Database, DatabaseExt}; +pub use crate::directory::{Directory, DirectoryExt}; +pub use crate::error::Error; +pub use crate::filenames::{Filenames, FilenamesOwner}; +pub use crate::message::{Message, MessageExt, MessageOwner}; +pub use crate::messages::{Messages, MessagesExt, MessagesOwner}; +pub use crate::query::{Query, QueryExt}; +pub use crate::tags::{Tags, TagsExt, TagsOwner}; +pub use crate::thread::{Thread, ThreadExt, ThreadOwner}; +pub use crate::threads::{Threads, ThreadsExt, ThreadsOwner}; -pub use ffi::{DatabaseMode, Sort}; -pub use utils::{StreamingIterator, StreamingIteratorExt}; +pub use crate::ffi::{DatabaseMode, Sort}; +pub use crate::utils::{StreamingIterator, StreamingIteratorExt}; diff --git a/src/message.rs b/src/message.rs index 6feffde..52ff63c 100644 --- a/src/message.rs +++ b/src/message.rs @@ -3,15 +3,15 @@ use std::ops::Drop; use std::path::PathBuf; use supercow::{Phantomcow, Supercow}; -use error::{Error, Result}; -use ffi; -use utils::ToStr; -use Filenames; -use FilenamesOwner; -use Messages; -use MessagesOwner; -use Tags; -use TagsOwner; +use crate::error::{Error, Result}; +use crate::ffi; +use crate::utils::ToStr; +use crate::Filenames; +use crate::FilenamesOwner; +use crate::Messages; +use crate::MessagesOwner; +use crate::Tags; +use crate::TagsOwner; pub trait MessageOwner {} @@ -29,7 +29,7 @@ impl Drop for MessagePtr { #[derive(Debug)] pub struct Message<'o, O> where - O: MessageOwner + 'o, + O: MessageOwner, { pub(crate) handle: MessagePtr, marker: Phantomcow<'o, O>, @@ -63,7 +63,7 @@ where tid.to_str().unwrap().to_string() } - pub fn replies(self: &Self) -> Messages { + pub fn replies(self: &Self) -> Messages<'_, Self> { >::replies(self) } @@ -72,7 +72,7 @@ where unsafe { ffi::notmuch_message_count_files(self.handle.ptr) } } - pub fn filenames(self: &Self) -> Filenames { + pub fn filenames(self: &Self) -> Filenames<'_, Self> { >::filenames(self) } @@ -101,7 +101,7 @@ where } } - pub fn tags(&self) -> Tags { + pub fn tags(&self) -> Tags<'_, Self> { >::tags(self) } diff --git a/src/messages.rs b/src/messages.rs index 5977e42..88c52ec 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -2,12 +2,12 @@ use std::ops::Drop; use supercow::{Phantomcow, Supercow}; -use ffi; -use utils::{StreamingIterator, StreamingIteratorExt}; -use Message; -use MessageOwner; -use Tags; -use TagsOwner; +use crate::ffi; +use crate::utils::{StreamingIterator, StreamingIteratorExt}; +use crate::Message; +use crate::MessageOwner; +use crate::Tags; +use crate::TagsOwner; pub trait MessagesOwner {} @@ -31,7 +31,7 @@ impl Drop for MessagesPtr { #[derive(Debug)] pub struct Messages<'o, O> where - O: MessagesOwner + 'o, + O: MessagesOwner, { pub(crate) handle: MessagesPtr, marker: Phantomcow<'o, O>, diff --git a/src/query.rs b/src/query.rs index 38711e9..3dba264 100644 --- a/src/query.rs +++ b/src/query.rs @@ -3,14 +3,14 @@ use std::ptr; use supercow::{Phantomcow, Supercow}; -use error::Result; -use ffi; -use ffi::Sort; -use Database; -use Messages; -use MessagesOwner; -use Threads; -use ThreadsOwner; +use crate::error::Result; +use crate::ffi; +use crate::ffi::Sort; +use crate::Database; +use crate::Messages; +use crate::MessagesOwner; +use crate::Threads; +use crate::ThreadsOwner; #[derive(Debug)] pub(crate) struct QueryPtr { @@ -77,7 +77,7 @@ impl<'d> Query<'d> { /// Filter messages according to the query and return pub fn search_messages<'q>(self: &'d Self) -> Result> { - ::search_messages(self) + as QueryExt>::search_messages(self) } pub fn count_messages(self: &Self) -> Result { @@ -88,7 +88,7 @@ impl<'d> Query<'d> { } pub fn search_threads<'q>(self: &'d Self) -> Result> { - ::search_threads(self) + as QueryExt>::search_threads(self) } pub fn count_threads(self: &Self) -> Result { diff --git a/src/tags.rs b/src/tags.rs index 96afdf6..f400f63 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -4,7 +4,7 @@ use std::ops::Drop; use supercow::Phantomcow; -use ffi; +use crate::ffi; pub trait TagsOwner {} @@ -20,7 +20,7 @@ impl Drop for TagsPtr { } #[derive(Debug)] -pub struct Tags<'o, Owner: TagsOwner + 'o> { +pub struct Tags<'o, Owner: TagsOwner> { handle: TagsPtr, marker: Phantomcow<'o, Owner>, } diff --git a/src/thread.rs b/src/thread.rs index 8a8c1d7..1fb6814 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -1,12 +1,12 @@ use std::ops::Drop; use supercow::{Phantomcow, Supercow}; -use ffi; -use utils::ToStr; -use Messages; -use MessagesOwner; -use Tags; -use TagsOwner; +use crate::ffi; +use crate::utils::ToStr; +use crate::Messages; +use crate::MessagesOwner; +use crate::Tags; +use crate::TagsOwner; pub trait ThreadOwner {} @@ -24,7 +24,7 @@ impl Drop for ThreadPtr { #[derive(Debug)] pub struct Thread<'o, O> where - O: ThreadOwner + 'o, + O: ThreadOwner, { pub(crate) handle: ThreadPtr, marker: Phantomcow<'o, O>, @@ -61,17 +61,17 @@ where unsafe { ffi::notmuch_thread_get_total_files(self.handle.ptr) } } - pub fn toplevel_messages(self: &Self) -> Messages { + pub fn toplevel_messages(self: &Self) -> Messages<'_, Self> { >::toplevel_messages(self) } /// Get a `Messages` iterator for all messages in 'thread' in /// oldest-first order. - pub fn messages(self: &Self) -> Messages { + pub fn messages(self: &Self) -> Messages<'_, Self> { >::messages(self) } - pub fn tags(&self) -> Tags { + pub fn tags(&self) -> Tags<'_, Self> { >::tags(self) } diff --git a/src/threads.rs b/src/threads.rs index f99ffb1..2bd3d24 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -1,11 +1,11 @@ use std::ops::Drop; use supercow::{Phantomcow, Supercow}; -use utils::{StreamingIterator, StreamingIteratorExt}; +use crate::utils::{StreamingIterator, StreamingIteratorExt}; -use ffi; -use thread::ThreadOwner; -use Thread; +use crate::ffi; +use crate::thread::ThreadOwner; +use crate::Thread; pub trait ThreadsOwner {} @@ -23,7 +23,7 @@ impl Drop for ThreadsPtr { #[derive(Debug)] pub struct Threads<'o, O> where - O: ThreadsOwner + 'o, + O: ThreadsOwner, { handle: ThreadsPtr, marker: Phantomcow<'o, O>, diff --git a/tests/main.rs b/tests/main.rs index dd96644..05cd79f 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -1,5 +1,5 @@ -extern crate dirs; -extern crate notmuch; +use dirs; +use notmuch; use std::sync::Arc; @@ -30,9 +30,9 @@ fn main() { // let mut threads = db.create_query(&"".to_string()).unwrap().search_threads().unwrap(); - let threads = Arc::new(::search_threads(query).unwrap()); + let threads = Arc::new( as QueryExt>::search_threads(query).unwrap()); - while let Some(thread) = as StreamingIteratorExt<_>>::next(threads.clone()) + while let Some(thread) = as StreamingIteratorExt<_>>::next(threads.clone()) { println!("thread {:?} {:?}", thread.subject(), thread.authors()); } -- cgit v1.2.1 From 4d4c778171ea979fb716b94a78c612d2c8fa5249 Mon Sep 17 00:00:00 2001 From: eaon Date: Sun, 9 Dec 2018 16:32:37 -0500 Subject: Remove unnecessary (de)refs --- src/error.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/error.rs b/src/error.rs index 33e1f78..3eba2ba 100644 --- a/src/error.rs +++ b/src/error.rs @@ -20,17 +20,17 @@ impl fmt::Display for Error { impl std::error::Error for Error { fn description(&self) -> &str { - match *self { - Error::IoError(ref e) => error::Error::description(e), - Error::NotmuchError(ref e) => e.description(), + match self { + Error::IoError(e) => error::Error::description(e), + Error::NotmuchError(e) => e.description(), Error::UnspecifiedError => "Generic notmuch error", } } fn cause(&self) -> Option<&dyn error::Error> { - match *self { - Error::IoError(ref e) => Some(e), - Error::NotmuchError(ref e) => Some(e), + match self { + Error::IoError(e) => Some(e), + Error::NotmuchError(e) => Some(e), Error::UnspecifiedError => None, } } -- cgit v1.2.1 From b20e8bffb4165d378d8d8703628913c3cb86ed4f Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 13 Dec 2018 06:36:47 +0100 Subject: remove unneeded lifetime annotations --- tests/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/main.rs b/tests/main.rs index 05cd79f..def2e5f 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -30,9 +30,9 @@ fn main() { // let mut threads = db.create_query(&"".to_string()).unwrap().search_threads().unwrap(); - let threads = Arc::new( as QueryExt>::search_threads(query).unwrap()); + let threads = Arc::new(::search_threads(query).unwrap()); - while let Some(thread) = as StreamingIteratorExt<_>>::next(threads.clone()) + while let Some(thread) = as StreamingIteratorExt<_>>::next(threads.clone()) { println!("thread {:?} {:?}", thread.subject(), thread.authors()); } -- cgit v1.2.1 From 69bcbb269d3d40d173cda8e0ccca5a614ab6a428 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 13 Dec 2018 06:41:05 +0100 Subject: do not drop message and thread --- src/message.rs | 12 +++++++----- src/thread.rs | 12 +++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/message.rs b/src/message.rs index 52ff63c..b4bb581 100644 --- a/src/message.rs +++ b/src/message.rs @@ -20,11 +20,13 @@ pub(crate) struct MessagePtr { pub ptr: *mut ffi::notmuch_message_t, } -impl Drop for MessagePtr { - fn drop(&mut self) { - unsafe { ffi::notmuch_message_destroy(self.ptr) }; - } -} +// TODO: The iterator doesn't actually own these, so dropping these will +// generate a segfault when a new iterator is constructed. +// impl Drop for MessagePtr { +// fn drop(&mut self) { +// unsafe { ffi::notmuch_message_destroy(self.ptr) }; +// } +// } #[derive(Debug)] pub struct Message<'o, O> diff --git a/src/thread.rs b/src/thread.rs index 1fb6814..3b58a3e 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -15,11 +15,13 @@ pub(crate) struct ThreadPtr { pub ptr: *mut ffi::notmuch_thread_t, } -impl Drop for ThreadPtr { - fn drop(&mut self) { - unsafe { ffi::notmuch_thread_destroy(self.ptr) }; - } -} +// TODO: The iterator doesn't actually own these, so dropping these will +// generate a segfault when a new iterator is constructed. +// impl Drop for ThreadPtr { +// fn drop(&mut self) { +// unsafe { ffi::notmuch_thread_destroy(self.ptr) }; +// } +// } #[derive(Debug)] pub struct Thread<'o, O> -- cgit v1.2.1 From 022fb6eebf7774b19a1e1b3c6cee7bd7e1b75cd9 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 13 Dec 2018 06:41:18 +0100 Subject: bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 30e26c0..1dc00d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "notmuch" -version = "0.4.1" +version = "0.4.2" authors = ["Dirk Van Haerenborgh "] homepage = "https://github.com/vhdirk/notmuch-rs" repository = "https://github.com/vhdirk/notmuch-rs" -- cgit v1.2.1 From 4b19b951dd2fb7aa7bc662170c91401f2e8fac3b Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 14 Dec 2018 18:45:20 +0100 Subject: remove StreamingIterator again as the iterators don't actually have ownership over items --- src/database.rs | 7 +++--- src/directory.rs | 7 +++--- src/filenames.rs | 5 +++-- src/lib.rs | 5 ++--- src/message.rs | 28 ++++++++--------------- src/messages.rs | 65 ++++++++++------------------------------------------- src/query.rs | 17 +++++++------- src/tags.rs | 5 +++-- src/thread.rs | 32 ++++++++++---------------- src/threads.rs | 68 +++++++++++++++++++++++--------------------------------- src/utils.rs | 30 +++++++++++++------------ tests/main.rs | 5 ++--- 12 files changed, 104 insertions(+), 170 deletions(-) diff --git a/src/database.rs b/src/database.rs index fe9a39b..0ff443a 100644 --- a/src/database.rs +++ b/src/database.rs @@ -16,6 +16,7 @@ use crate::Directory; use crate::Query; use crate::Tags; use crate::TagsOwner; +use crate::utils::{ScopedSupercow, ScopedPhantomcow}; // Re-exported under database module for pretty namespacin'. pub use crate::ffi::DatabaseMode; @@ -258,18 +259,18 @@ pub trait DatabaseExt { fn all_tags<'d, D>(database: D) -> Result> where - D: Into>, + D: Into>, { let dbref = database.into(); let tags = unsafe { ffi::notmuch_database_get_all_tags(dbref.handle.ptr) }; - Ok(Tags::from_ptr(tags, Supercow::phantom(dbref))) + Ok(Tags::from_ptr(tags, ScopedSupercow::phantom(dbref))) } fn directory<'d, D, P>(database: D, path: &P) -> Result>> where - D: Into>, + D: Into>, P: AsRef, { let dbref = database.into(); diff --git a/src/directory.rs b/src/directory.rs index be2ea5c..09baf77 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -5,6 +5,7 @@ use crate::ffi; use crate::Database; use crate::Filenames; use crate::FilenamesOwner; +use crate::utils::{ScopedSupercow, ScopedPhantomcow}; #[derive(Debug)] pub(crate) struct DirectoryPtr { @@ -20,7 +21,7 @@ impl Drop for DirectoryPtr { #[derive(Debug)] pub struct Directory<'d> { handle: DirectoryPtr, - marker: Phantomcow<'d, Database>, + marker: ScopedPhantomcow<'d, Database>, } impl<'d> FilenamesOwner for Directory<'d> {} @@ -28,7 +29,7 @@ impl<'d> FilenamesOwner for Directory<'d> {} impl<'d> Directory<'d> { pub fn from_ptr(ptr: *mut ffi::notmuch_directory_t, owner: O) -> Directory<'d> where - O: Into>, + O: Into>, { Directory { handle: DirectoryPtr { ptr }, @@ -44,7 +45,7 @@ impl<'d> Directory<'d> { pub trait DirectoryExt<'d> { fn child_directories<'s, S>(directory: S) -> Filenames<'s, Directory<'d>> where - S: Into>>, + S: Into>>, { let dir = directory.into(); Filenames::from_ptr( diff --git a/src/filenames.rs b/src/filenames.rs index ad4c3e9..ce06289 100644 --- a/src/filenames.rs +++ b/src/filenames.rs @@ -6,6 +6,7 @@ use std::path::PathBuf; use supercow::Phantomcow; use crate::ffi; +use crate::utils::ScopedPhantomcow; pub trait FilenamesOwner {} @@ -30,7 +31,7 @@ where O: FilenamesOwner, { pub(crate) handle: FilenamesPtr, - pub(crate) marker: Phantomcow<'o, O>, + pub(crate) marker: ScopedPhantomcow<'o, O>, } impl<'o, O> Filenames<'o, O> @@ -39,7 +40,7 @@ where { pub fn from_ptr

(ptr: *mut ffi::notmuch_filenames_t, owner: P) -> Filenames<'o, O> where - P: Into>, + P: Into>, { Filenames { handle: FilenamesPtr { ptr }, diff --git a/src/lib.rs b/src/lib.rs index 005f142..2dd6958 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,11 +26,10 @@ pub use crate::directory::{Directory, DirectoryExt}; pub use crate::error::Error; pub use crate::filenames::{Filenames, FilenamesOwner}; pub use crate::message::{Message, MessageExt, MessageOwner}; -pub use crate::messages::{Messages, MessagesExt, MessagesOwner}; +pub use crate::messages::{Messages, MessagesExt}; pub use crate::query::{Query, QueryExt}; pub use crate::tags::{Tags, TagsExt, TagsOwner}; pub use crate::thread::{Thread, ThreadExt, ThreadOwner}; -pub use crate::threads::{Threads, ThreadsExt, ThreadsOwner}; +pub use crate::threads::{Threads, ThreadsExt}; pub use crate::ffi::{DatabaseMode, Sort}; -pub use crate::utils::{StreamingIterator, StreamingIteratorExt}; diff --git a/src/message.rs b/src/message.rs index b4bb581..baa638d 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,43 +1,33 @@ use std::ffi::CString; -use std::ops::Drop; use std::path::PathBuf; -use supercow::{Phantomcow, Supercow}; +use supercow::{Supercow}; use crate::error::{Error, Result}; use crate::ffi; -use crate::utils::ToStr; +use crate::utils::{ToStr, ScopedPhantomcow, ScopedSupercow}; use crate::Filenames; use crate::FilenamesOwner; use crate::Messages; -use crate::MessagesOwner; use crate::Tags; use crate::TagsOwner; -pub trait MessageOwner {} +pub trait MessageOwner: Send + Sync {} #[derive(Debug)] pub(crate) struct MessagePtr { pub ptr: *mut ffi::notmuch_message_t, } -// TODO: The iterator doesn't actually own these, so dropping these will -// generate a segfault when a new iterator is constructed. -// impl Drop for MessagePtr { -// fn drop(&mut self) { -// unsafe { ffi::notmuch_message_destroy(self.ptr) }; -// } -// } - #[derive(Debug)] pub struct Message<'o, O> where O: MessageOwner, { pub(crate) handle: MessagePtr, - marker: Phantomcow<'o, O>, + marker: ScopedPhantomcow<'o, O>, } -impl<'o, O> MessagesOwner for Message<'o, O> where O: MessageOwner + 'o {} +impl<'o, O> MessageOwner for Message<'o, O> where O: MessageOwner + 'o {} impl<'o, O> FilenamesOwner for Message<'o, O> where O: MessageOwner + 'o {} impl<'o, O> TagsOwner for Message<'o, O> where O: MessageOwner + 'o {} @@ -47,7 +37,7 @@ where { pub fn from_ptr

(ptr: *mut ffi::notmuch_message_t, owner: P) -> Message<'o, O> where - P: Into>, + P: Into>, { Message { handle: MessagePtr { ptr }, @@ -128,7 +118,7 @@ where { fn tags<'s, S>(message: S) -> Tags<'s, Message<'o, O>> where - S: Into>>, + S: Into>>, { let messageref = message.into(); Tags::from_ptr( @@ -139,7 +129,7 @@ where fn replies<'s, S>(message: S) -> Messages<'s, Message<'o, O>> where - S: Into>>, + S: Into>>, { let messageref = message.into(); Messages::from_ptr( @@ -150,7 +140,7 @@ where fn filenames<'s, S>(message: S) -> Filenames<'s, Message<'o, O>> where - S: Into>>, + S: Into>>, { let messageref = message.into(); Filenames::from_ptr( diff --git a/src/messages.rs b/src/messages.rs index 88c52ec..3082512 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -3,14 +3,12 @@ use std::ops::Drop; use supercow::{Phantomcow, Supercow}; use crate::ffi; -use crate::utils::{StreamingIterator, StreamingIteratorExt}; +use crate::utils::{ScopedSupercow, ScopedPhantomcow}; use crate::Message; use crate::MessageOwner; use crate::Tags; use crate::TagsOwner; -pub trait MessagesOwner {} - #[derive(Debug)] pub struct MessagesPtr { pub ptr: *mut ffi::notmuch_messages_t, @@ -18,12 +16,6 @@ pub struct MessagesPtr { impl Drop for MessagesPtr { fn drop(self: &mut Self) { - let valid = unsafe { ffi::notmuch_messages_valid(self.ptr) }; - - if valid == 0 { - return; - } - unsafe { ffi::notmuch_messages_destroy(self.ptr) }; } } @@ -31,19 +23,19 @@ impl Drop for MessagesPtr { #[derive(Debug)] pub struct Messages<'o, O> where - O: MessagesOwner, + O: MessageOwner, { pub(crate) handle: MessagesPtr, - marker: Phantomcow<'o, O>, + marker: ScopedPhantomcow<'o, O>, } impl<'o, O> Messages<'o, O> where - O: MessagesOwner + 'o, + O: MessageOwner + 'o, { pub(crate) fn from_ptr

(ptr: *mut ffi::notmuch_messages_t, owner: P) -> Messages<'o, O> where - P: Into>, + P: Into>, { Messages { handle: MessagesPtr { ptr }, @@ -52,12 +44,12 @@ where } } -impl<'o, O> MessageOwner for Messages<'o, O> where O: MessagesOwner + 'o {} -impl<'o, O> TagsOwner for Messages<'o, O> where O: MessagesOwner + 'o {} +impl<'o, O> MessageOwner for Messages<'o, O> where O: MessageOwner + 'o {} +impl<'o, O> TagsOwner for Messages<'o, O> where O: MessageOwner + 'o {} impl<'o, O> Messages<'o, O> where - O: MessagesOwner + 'o, + O: MessageOwner + 'o, { /** * Return a list of tags from all messages. @@ -80,47 +72,14 @@ where } } -impl<'s, 'o: 's, O> StreamingIterator<'s, Message<'s, Self>> for Messages<'o, O> -where - O: MessagesOwner + 'o, -{ - fn next(&'s mut self) -> Option> { - >>::next(Supercow::borrowed(self)) - } -} - pub trait MessagesExt<'o, O> where - O: MessagesOwner + 'o, + O: MessageOwner + 'o, { } -impl<'o, O> MessagesExt<'o, O> for Messages<'o, O> where O: MessagesOwner + 'o {} +impl<'o, O> MessagesExt<'o, O> for Messages<'o, O> where O: MessageOwner + 'o {} -impl<'s, 'o: 's, O> StreamingIteratorExt<'s, Message<'s, Self>> for Messages<'o, O> -where - O: MessagesOwner + 'o, -{ - fn next(messages: S) -> Option> - where - S: Into>>, - { - let messagesref = messages.into(); - let valid = unsafe { ffi::notmuch_messages_valid(messagesref.handle.ptr) }; - - if valid == 0 { - return None; - } - - let cmsg = unsafe { - let msg = ffi::notmuch_messages_get(messagesref.handle.ptr); - ffi::notmuch_messages_move_to_next(messagesref.handle.ptr); - msg - }; - - Some(Message::from_ptr(cmsg, Supercow::phantom(messagesref))) - } -} -unsafe impl<'o, O> Send for Messages<'o, O> where O: MessagesOwner + 'o {} -unsafe impl<'o, O> Sync for Messages<'o, O> where O: MessagesOwner + 'o {} +unsafe impl<'o, O> Send for Messages<'o, O> where O: MessageOwner + 'o {} +unsafe impl<'o, O> Sync for Messages<'o, O> where O: MessageOwner + 'o {} diff --git a/src/query.rs b/src/query.rs index 3dba264..dbe5400 100644 --- a/src/query.rs +++ b/src/query.rs @@ -8,9 +8,10 @@ use crate::ffi; use crate::ffi::Sort; use crate::Database; use crate::Messages; -use crate::MessagesOwner; +use crate::MessageOwner; use crate::Threads; -use crate::ThreadsOwner; +use crate::ThreadOwner; +use crate::utils::{ScopedSupercow, ScopedPhantomcow}; #[derive(Debug)] pub(crate) struct QueryPtr { @@ -29,8 +30,8 @@ pub struct Query<'d> { marker: Phantomcow<'d, Database>, } -impl<'d> ThreadsOwner for Query<'d> {} -impl<'d> MessagesOwner for Query<'d> {} +impl<'d> ThreadOwner for Query<'d> {} +impl<'d> MessageOwner for Query<'d> {} impl<'d> Query<'d> { pub(crate) fn from_ptr(ptr: *mut ffi::notmuch_query_t, owner: O) -> Query<'d> @@ -102,7 +103,7 @@ impl<'d> Query<'d> { pub trait QueryExt<'d> { fn search_threads<'q, Q>(query: Q) -> Result>> where - Q: Into>>, + Q: Into>>, { let queryref = query.into(); @@ -110,12 +111,12 @@ pub trait QueryExt<'d> { unsafe { ffi::notmuch_query_search_threads(queryref.handle.ptr, &mut thrds) } .as_result()?; - Ok(Threads::from_ptr(thrds, Supercow::phantom(queryref))) + Ok(Threads::from_ptr(thrds, ScopedSupercow::phantom(queryref))) } fn search_messages<'q, Q>(query: Q) -> Result>> where - Q: Into>>, + Q: Into>>, { let queryref = query.into(); @@ -123,7 +124,7 @@ pub trait QueryExt<'d> { unsafe { ffi::notmuch_query_search_messages(queryref.handle.ptr, &mut msgs) } .as_result()?; - Ok(Messages::from_ptr(msgs, Supercow::phantom(queryref))) + Ok(Messages::from_ptr(msgs, ScopedSupercow::phantom(queryref))) } } diff --git a/src/tags.rs b/src/tags.rs index f400f63..bf7b777 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -5,6 +5,7 @@ use std::ops::Drop; use supercow::Phantomcow; use crate::ffi; +use crate::utils::ScopedPhantomcow; pub trait TagsOwner {} @@ -22,7 +23,7 @@ impl Drop for TagsPtr { #[derive(Debug)] pub struct Tags<'o, Owner: TagsOwner> { handle: TagsPtr, - marker: Phantomcow<'o, Owner>, + marker: ScopedPhantomcow<'o, Owner>, } impl<'o, O> Tags<'o, O> @@ -31,7 +32,7 @@ where { pub fn from_ptr

(ptr: *mut ffi::notmuch_tags_t, owner: P) -> Tags<'o, O> where - P: Into>, + P: Into>, { Tags { handle: TagsPtr { ptr }, diff --git a/src/thread.rs b/src/thread.rs index 3b58a3e..9569cbc 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -2,37 +2,29 @@ use std::ops::Drop; use supercow::{Phantomcow, Supercow}; use crate::ffi; -use crate::utils::ToStr; +use crate::utils::{ToStr, ScopedSupercow, ScopedPhantomcow}; use crate::Messages; -use crate::MessagesOwner; +use crate::MessageOwner; use crate::Tags; use crate::TagsOwner; -pub trait ThreadOwner {} +pub trait ThreadOwner: Send + Sync {} #[derive(Debug)] pub(crate) struct ThreadPtr { pub ptr: *mut ffi::notmuch_thread_t, } -// TODO: The iterator doesn't actually own these, so dropping these will -// generate a segfault when a new iterator is constructed. -// impl Drop for ThreadPtr { -// fn drop(&mut self) { -// unsafe { ffi::notmuch_thread_destroy(self.ptr) }; -// } -// } - #[derive(Debug)] pub struct Thread<'o, O> where O: ThreadOwner, { pub(crate) handle: ThreadPtr, - marker: Phantomcow<'o, O>, + pub(crate) marker: ScopedPhantomcow<'o, O>, } -impl<'o, O> MessagesOwner for Thread<'o, O> where O: ThreadOwner + 'o {} +impl<'o, O> MessageOwner for Thread<'o, O> where O: ThreadOwner + 'o {} impl<'o, O> TagsOwner for Thread<'o, O> where O: ThreadOwner + 'o {} impl<'o, O> Thread<'o, O> @@ -41,7 +33,7 @@ where { pub fn from_ptr

(ptr: *mut ffi::notmuch_thread_t, owner: P) -> Thread<'o, O> where - P: Into>, + P: Into>, { Thread { handle: ThreadPtr { ptr }, @@ -111,23 +103,23 @@ where { fn tags<'s, S>(thread: S) -> Tags<'s, Thread<'o, O>> where - S: Into>>, + S: Into>>, { let threadref = thread.into(); Tags::from_ptr( unsafe { ffi::notmuch_thread_get_tags(threadref.handle.ptr) }, - Supercow::phantom(threadref), + ScopedSupercow::phantom(threadref), ) } fn toplevel_messages<'s, S>(thread: S) -> Messages<'s, Thread<'o, O>> where - S: Into>>, + S: Into>>, { let threadref = thread.into(); Messages::from_ptr( unsafe { ffi::notmuch_thread_get_toplevel_messages(threadref.handle.ptr) }, - Supercow::phantom(threadref), + ScopedSupercow::phantom(threadref), ) } @@ -135,12 +127,12 @@ where /// oldest-first order. fn messages<'s, S>(thread: S) -> Messages<'s, Thread<'o, O>> where - S: Into>>, + S: Into>>, { let threadref = thread.into(); Messages::from_ptr( unsafe { ffi::notmuch_thread_get_messages(threadref.handle.ptr) }, - Supercow::phantom(threadref), + ScopedSupercow::phantom(threadref), ) } } diff --git a/src/threads.rs b/src/threads.rs index 2bd3d24..d182625 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -1,13 +1,12 @@ use std::ops::Drop; use supercow::{Phantomcow, Supercow}; -use crate::utils::{StreamingIterator, StreamingIteratorExt}; use crate::ffi; -use crate::thread::ThreadOwner; +use crate::thread::{ThreadOwner, ThreadPtr}; use crate::Thread; +use crate::utils::{ScopedPhantomcow, ScopedSupercow}; -pub trait ThreadsOwner {} #[derive(Debug)] pub(crate) struct ThreadsPtr { @@ -23,21 +22,19 @@ impl Drop for ThreadsPtr { #[derive(Debug)] pub struct Threads<'o, O> where - O: ThreadsOwner, + O: ThreadOwner, { handle: ThreadsPtr, - marker: Phantomcow<'o, O>, + marker: ScopedPhantomcow<'o, O>, } -impl<'o, O> ThreadOwner for Threads<'o, O> where O: ThreadsOwner + 'o {} - impl<'o, O> Threads<'o, O> where - O: ThreadsOwner + 'o, + O: ThreadOwner + 'o, { pub fn from_ptr

(ptr: *mut ffi::notmuch_threads_t, owner: P) -> Threads<'o, O> where - P: Into>, + P: Into>, { Threads { handle: ThreadsPtr { ptr }, @@ -46,47 +43,38 @@ where } } -impl<'s, 'o: 's, O> StreamingIterator<'s, Thread<'s, Self>> for Threads<'o, O> +impl<'o, O> Iterator for Threads<'o, O> where - O: ThreadsOwner + 'o, + O: ThreadOwner, { - fn next(&'s mut self) -> Option> { - >>::next(Supercow::borrowed(self)) - } -} + type Item = Thread<'o, O>; -pub trait ThreadsExt<'o, O> -where - O: ThreadsOwner + 'o, -{ -} - -impl<'o, O> ThreadsExt<'o, O> for Threads<'o, O> where O: ThreadsOwner + 'o {} - -impl<'s, 'o: 's, O> StreamingIteratorExt<'s, Thread<'s, Self>> for Threads<'o, O> -where - O: ThreadsOwner + 'o, -{ - fn next(threads: S) -> Option> - where - S: Into>>, - { - let threadsref = threads.into(); - let valid = unsafe { ffi::notmuch_threads_valid(threadsref.handle.ptr) }; + fn next(&mut self) -> Option> { + let valid = unsafe { ffi::notmuch_threads_valid(self.handle.ptr) }; if valid == 0 { return None; } - let cmsg = unsafe { - let msg = ffi::notmuch_threads_get(threadsref.handle.ptr); - ffi::notmuch_threads_move_to_next(threadsref.handle.ptr); - msg + let cthrd = unsafe { + let thrd = ffi::notmuch_threads_get(self.handle.ptr); + ffi::notmuch_threads_move_to_next(self.handle.ptr); + thrd }; - Some(Thread::from_ptr(cmsg, Supercow::phantom(threadsref))) + Some(Thread::from_ptr(cthrd, ScopedPhantomcow::<'o, O>::share(&mut self.marker))) } } -unsafe impl<'o, O> Send for Threads<'o, O> where O: ThreadsOwner + 'o {} -unsafe impl<'o, O> Sync for Threads<'o, O> where O: ThreadsOwner + 'o {} + +pub trait ThreadsExt<'o, O> +where + O: ThreadOwner + 'o, +{ +} + +impl<'o, O> ThreadsExt<'o, O> for Threads<'o, O> where O: ThreadOwner + 'o {} + + +unsafe impl<'o, O> Send for Threads<'o, O> where O: ThreadOwner + 'o {} +unsafe impl<'o, O> Sync for Threads<'o, O> where O: ThreadOwner + 'o {} diff --git a/src/utils.rs b/src/utils.rs index be5f66c..353093f 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,7 +1,8 @@ use libc; use std::{ffi, str}; -use supercow::Supercow; +use supercow::{Supercow, DefaultFeatures, NonSyncFeatures}; +use supercow::ext::{BoxedStorage}; pub trait ToStr { fn to_str<'a>(&self) -> Result<&'a str, str::Utf8Error>; @@ -23,17 +24,18 @@ impl ToString for *const libc::c_char { } } -/// 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; -} +pub type ScopedNonSyncSupercow<'a, OWNED, BORROWED = OWNED> = + Supercow<'a, OWNED, BORROWED, + Box + 'a>, + BoxedStorage>; + +pub type ScopedPhantomcow<'a, OWNED, BORROWED = OWNED, + SHARED = Box + 'a>, + STORAGE = BoxedStorage> = + Supercow<'a, OWNED, BORROWED, SHARED, STORAGE, ()>; + +pub type ScopedSupercow<'a, OWNED, BORROWED = OWNED, SHARED = Box + 'a>> = + Supercow<'a, OWNED, BORROWED, SHARED, BoxedStorage>; + + -pub trait StreamingIteratorExt<'a, T> { - /// Return either the next item in the sequence, or `None` if all items - /// have been consumed. - fn next>>(s: S) -> Option - where - Self: Sized + 'a; -} diff --git a/tests/main.rs b/tests/main.rs index def2e5f..8a857dd 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -3,7 +3,6 @@ use notmuch; use std::sync::Arc; -use notmuch::StreamingIteratorExt; use notmuch::{Query, QueryExt, Threads}; fn main() { @@ -30,9 +29,9 @@ fn main() { // let mut threads = db.create_query(&"".to_string()).unwrap().search_threads().unwrap(); - let threads = Arc::new(::search_threads(query).unwrap()); + let mut threads = Arc::new(::search_threads(query).unwrap()); - while let Some(thread) = as StreamingIteratorExt<_>>::next(threads.clone()) + for thread in Arc::get_mut(&mut threads).unwrap() { println!("thread {:?} {:?}", thread.subject(), thread.authors()); } -- cgit v1.2.1 From 16704244a19bf896ce2d42c4dfb63feb5ac319c5 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 15 Dec 2018 07:19:38 +0100 Subject: Threads are only ever owned by a Query. Nothing else --- src/database.rs | 2 +- src/directory.rs | 2 +- src/filenames.rs | 2 -- src/lib.rs | 2 +- src/messages.rs | 5 +---- src/query.rs | 10 ++++------ src/tags.rs | 2 -- src/thread.rs | 56 ++++++++++++++++++++++++++++++-------------------------- src/threads.rs | 40 +++++++++++++++++++--------------------- src/utils.rs | 10 ++++++---- 10 files changed, 63 insertions(+), 68 deletions(-) diff --git a/src/database.rs b/src/database.rs index 0ff443a..19d33c7 100644 --- a/src/database.rs +++ b/src/database.rs @@ -16,7 +16,7 @@ use crate::Directory; use crate::Query; use crate::Tags; use crate::TagsOwner; -use crate::utils::{ScopedSupercow, ScopedPhantomcow}; +use crate::utils::ScopedSupercow; // Re-exported under database module for pretty namespacin'. pub use crate::ffi::DatabaseMode; diff --git a/src/directory.rs b/src/directory.rs index 09baf77..6402902 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -1,5 +1,5 @@ use std::ops::Drop; -use supercow::{Phantomcow, Supercow}; +use supercow::Supercow; use crate::ffi; use crate::Database; diff --git a/src/filenames.rs b/src/filenames.rs index ce06289..24ce513 100644 --- a/src/filenames.rs +++ b/src/filenames.rs @@ -3,8 +3,6 @@ use std::iter::Iterator; use std::ops::Drop; use std::path::PathBuf; -use supercow::Phantomcow; - use crate::ffi; use crate::utils::ScopedPhantomcow; diff --git a/src/lib.rs b/src/lib.rs index 2dd6958..8f60a3f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,7 +29,7 @@ pub use crate::message::{Message, MessageExt, MessageOwner}; pub use crate::messages::{Messages, MessagesExt}; pub use crate::query::{Query, QueryExt}; pub use crate::tags::{Tags, TagsExt, TagsOwner}; -pub use crate::thread::{Thread, ThreadExt, ThreadOwner}; +pub use crate::thread::{Thread, ThreadExt}; pub use crate::threads::{Threads, ThreadsExt}; pub use crate::ffi::{DatabaseMode, Sort}; diff --git a/src/messages.rs b/src/messages.rs index 3082512..69b6dcc 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -1,10 +1,7 @@ use std::ops::Drop; -use supercow::{Phantomcow, Supercow}; - use crate::ffi; -use crate::utils::{ScopedSupercow, ScopedPhantomcow}; -use crate::Message; +use crate::utils::ScopedPhantomcow; use crate::MessageOwner; use crate::Tags; use crate::TagsOwner; diff --git a/src/query.rs b/src/query.rs index dbe5400..9a04c7a 100644 --- a/src/query.rs +++ b/src/query.rs @@ -10,8 +10,7 @@ use crate::Database; use crate::Messages; use crate::MessageOwner; use crate::Threads; -use crate::ThreadOwner; -use crate::utils::{ScopedSupercow, ScopedPhantomcow}; +use crate::utils::ScopedSupercow; #[derive(Debug)] pub(crate) struct QueryPtr { @@ -30,7 +29,6 @@ pub struct Query<'d> { marker: Phantomcow<'d, Database>, } -impl<'d> ThreadOwner for Query<'d> {} impl<'d> MessageOwner for Query<'d> {} impl<'d> Query<'d> { @@ -88,8 +86,8 @@ impl<'d> Query<'d> { Ok(cnt) } - pub fn search_threads<'q>(self: &'d Self) -> Result> { - as QueryExt>::search_threads(self) + pub fn search_threads<'q>(self: &'d Self) -> Result> { + as QueryExt>::search_threads(self) } pub fn count_threads(self: &Self) -> Result { @@ -101,7 +99,7 @@ impl<'d> Query<'d> { } pub trait QueryExt<'d> { - fn search_threads<'q, Q>(query: Q) -> Result>> + fn search_threads<'q, Q>(query: Q) -> Result> where Q: Into>>, { diff --git a/src/tags.rs b/src/tags.rs index bf7b777..215bb8a 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -2,8 +2,6 @@ use std::ffi::CStr; use std::iter::Iterator; use std::ops::Drop; -use supercow::Phantomcow; - use crate::ffi; use crate::utils::ScopedPhantomcow; diff --git a/src/thread.rs b/src/thread.rs index 9569cbc..b3cd151 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -1,5 +1,4 @@ use std::ops::Drop; -use supercow::{Phantomcow, Supercow}; use crate::ffi; use crate::utils::{ToStr, ScopedSupercow, ScopedPhantomcow}; @@ -7,33 +6,38 @@ use crate::Messages; use crate::MessageOwner; use crate::Tags; use crate::TagsOwner; - -pub trait ThreadOwner: Send + Sync {} +use crate::Query; #[derive(Debug)] pub(crate) struct ThreadPtr { pub ptr: *mut ffi::notmuch_thread_t, } +impl Drop for ThreadPtr { + fn drop(&mut self) { + unsafe { ffi::notmuch_thread_destroy(self.ptr) }; + } +} + #[derive(Debug)] -pub struct Thread<'o, O> +pub struct Thread<'d, 'q> where - O: ThreadOwner, + 'd: 'q { pub(crate) handle: ThreadPtr, - pub(crate) marker: ScopedPhantomcow<'o, O>, + pub(crate) marker: ScopedPhantomcow<'q, Query<'d>>, } -impl<'o, O> MessageOwner for Thread<'o, O> where O: ThreadOwner + 'o {} -impl<'o, O> TagsOwner for Thread<'o, O> where O: ThreadOwner + 'o {} +impl<'d, 'q> MessageOwner for Thread<'d, 'q> where 'd: 'q {} +impl<'d, 'q> TagsOwner for Thread<'d, 'q> where 'd: 'q {} -impl<'o, O> Thread<'o, O> +impl<'d, 'q> Thread<'d, 'q> where - O: ThreadOwner + 'o, + 'd: 'q { - pub fn from_ptr

(ptr: *mut ffi::notmuch_thread_t, owner: P) -> Thread<'o, O> + pub fn from_ptr

(ptr: *mut ffi::notmuch_thread_t, owner: P) -> Thread<'d, 'q> where - P: Into>, + P: Into>>, { Thread { handle: ThreadPtr { ptr }, @@ -56,17 +60,17 @@ where } pub fn toplevel_messages(self: &Self) -> Messages<'_, Self> { - >::toplevel_messages(self) + >::toplevel_messages(self) } /// Get a `Messages` iterator for all messages in 'thread' in /// oldest-first order. pub fn messages(self: &Self) -> Messages<'_, Self> { - >::messages(self) + >::messages(self) } pub fn tags(&self) -> Tags<'_, Self> { - >::tags(self) + >::tags(self) } pub fn subject(self: &Self) -> String { @@ -97,13 +101,13 @@ where } } -pub trait ThreadExt<'o, O> +pub trait ThreadExt<'d, 'q> where - O: ThreadOwner + 'o, + 'd: 'q { - fn tags<'s, S>(thread: S) -> Tags<'s, Thread<'o, O>> + fn tags<'s, S>(thread: S) -> Tags<'s, Thread<'d, 'q>> where - S: Into>>, + S: Into>>, { let threadref = thread.into(); Tags::from_ptr( @@ -112,9 +116,9 @@ where ) } - fn toplevel_messages<'s, S>(thread: S) -> Messages<'s, Thread<'o, O>> + fn toplevel_messages<'s, S>(thread: S) -> Messages<'s, Thread<'d, 'q>> where - S: Into>>, + S: Into>>, { let threadref = thread.into(); Messages::from_ptr( @@ -125,9 +129,9 @@ where /// Get a `Messages` iterator for all messages in 'thread' in /// oldest-first order. - fn messages<'s, S>(thread: S) -> Messages<'s, Thread<'o, O>> + fn messages<'s, S>(thread: S) -> Messages<'s, Thread<'d, 'q>> where - S: Into>>, + S: Into>>, { let threadref = thread.into(); Messages::from_ptr( @@ -137,7 +141,7 @@ where } } -impl<'o, O> ThreadExt<'o, O> for Thread<'o, O> where O: ThreadOwner + 'o {} +impl<'d, 'q> ThreadExt<'d, 'q> for Thread<'d, 'q> where 'd: 'q {} -unsafe impl<'o, O> Send for Thread<'o, O> where O: ThreadOwner + 'o {} -unsafe impl<'o, O> Sync for Thread<'o, O> where O: ThreadOwner + 'o {} +unsafe impl<'d, 'q> Send for Thread<'d, 'q> where 'd: 'q {} +unsafe impl<'d, 'q> Sync for Thread<'d, 'q> where 'd: 'q {} diff --git a/src/threads.rs b/src/threads.rs index d182625..4aa5a9b 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -1,11 +1,9 @@ use std::ops::Drop; -use supercow::{Phantomcow, Supercow}; - use crate::ffi; -use crate::thread::{ThreadOwner, ThreadPtr}; use crate::Thread; -use crate::utils::{ScopedPhantomcow, ScopedSupercow}; +use crate::Query; +use crate::utils::ScopedPhantomcow; #[derive(Debug)] @@ -20,21 +18,21 @@ impl Drop for ThreadsPtr { } #[derive(Debug)] -pub struct Threads<'o, O> +pub struct Threads<'d, 'q> where - O: ThreadOwner, + 'd: 'q { handle: ThreadsPtr, - marker: ScopedPhantomcow<'o, O>, + marker: ScopedPhantomcow<'q, Query<'d>>, } -impl<'o, O> Threads<'o, O> +impl<'d, 'q> Threads<'d, 'q> where - O: ThreadOwner + 'o, + 'd: 'q, { - pub fn from_ptr

(ptr: *mut ffi::notmuch_threads_t, owner: P) -> Threads<'o, O> + pub fn from_ptr

(ptr: *mut ffi::notmuch_threads_t, owner: P) -> Threads<'d, 'q> where - P: Into>, + P: Into>>, { Threads { handle: ThreadsPtr { ptr }, @@ -43,13 +41,13 @@ where } } -impl<'o, O> Iterator for Threads<'o, O> +impl<'d, 'q> Iterator for Threads<'d, 'q> where - O: ThreadOwner, + 'd: 'q, { - type Item = Thread<'o, O>; + type Item = Thread<'d, 'q>; - fn next(&mut self) -> Option> { + fn next(&mut self) -> Option { let valid = unsafe { ffi::notmuch_threads_valid(self.handle.ptr) }; if valid == 0 { @@ -62,19 +60,19 @@ where thrd }; - Some(Thread::from_ptr(cthrd, ScopedPhantomcow::<'o, O>::share(&mut self.marker))) + Some(Thread::from_ptr(cthrd, ScopedPhantomcow::<'q, Query<'d>>::share(&mut self.marker))) } } -pub trait ThreadsExt<'o, O> +pub trait ThreadsExt<'d, 'q> where - O: ThreadOwner + 'o, + 'd: 'q, { } -impl<'o, O> ThreadsExt<'o, O> for Threads<'o, O> where O: ThreadOwner + 'o {} +impl<'d, 'q> ThreadsExt<'d, 'q> for Threads<'d, 'q> where 'd: 'q {} -unsafe impl<'o, O> Send for Threads<'o, O> where O: ThreadOwner + 'o {} -unsafe impl<'o, O> Sync for Threads<'o, O> where O: ThreadOwner + 'o {} +unsafe impl<'d, 'q> Send for Threads<'d, 'q> where 'd: 'q {} +unsafe impl<'d, 'q> Sync for Threads<'d, 'q> where 'd: 'q {} diff --git a/src/utils.rs b/src/utils.rs index 353093f..409534c 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -24,10 +24,10 @@ impl ToString for *const libc::c_char { } } -pub type ScopedNonSyncSupercow<'a, OWNED, BORROWED = OWNED> = - Supercow<'a, OWNED, BORROWED, - Box + 'a>, - BoxedStorage>; +// pub type ScopedNonSyncSupercow<'a, OWNED, BORROWED = OWNED> = +// Supercow<'a, OWNED, BORROWED, +// Box + 'a>, +// BoxedStorage>; pub type ScopedPhantomcow<'a, OWNED, BORROWED = OWNED, SHARED = Box + 'a>, @@ -39,3 +39,5 @@ pub type ScopedSupercow<'a, OWNED, BORROWED = OWNED, SHARED = Box Date: Sat, 15 Dec 2018 15:28:54 +0100 Subject: re-add erroneously removed messages iterator --- src/messages.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/messages.rs b/src/messages.rs index 69b6dcc..64b4090 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -3,6 +3,7 @@ use std::ops::Drop; use crate::ffi; use crate::utils::ScopedPhantomcow; use crate::MessageOwner; +use crate::Message; use crate::Tags; use crate::TagsOwner; @@ -69,6 +70,31 @@ where } } +impl<'o, O> Iterator for Messages<'o, O> +where + O: MessageOwner + 'o, +{ + type Item = Message<'o, O>; + + fn next(&mut self) -> Option { + let valid = unsafe { ffi::notmuch_messages_valid(self.handle.ptr) }; + + if valid == 0 { + return None; + } + + let cthrd = unsafe { + let thrd = ffi::notmuch_messages_get(self.handle.ptr); + ffi::notmuch_messages_move_to_next(self.handle.ptr); + thrd + }; + + Some(Message::from_ptr(cthrd, ScopedPhantomcow::<'o, O>::share(&mut self.marker))) + } +} + + + pub trait MessagesExt<'o, O> where O: MessageOwner + 'o, -- cgit v1.2.1 From 895fee066eed58e18c2633cf7d0fa870a65ac06d Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 15 Dec 2018 15:36:21 +0100 Subject: =?UTF-8?q?Revert=20"Edition=202018=20hit=20stable=20=F0=9F=99=8C"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit b5b0f7e97abe0dbd5b54a1fc69e764a124c271b2. --- Cargo.toml | 1 - src/database.rs | 23 ++++++++++++----------- src/directory.rs | 12 ++++++------ src/error.rs | 12 ++++++------ src/ffi.rs | 6 +++--- src/filenames.rs | 6 +++--- src/lib.rs | 26 +++++++++++++------------- src/message.rs | 24 ++++++++++++------------ src/messages.rs | 14 +++++++------- src/query.rs | 18 +++++++++--------- src/tags.rs | 6 +++--- src/thread.rs | 14 +++++++------- src/threads.rs | 8 ++++---- tests/main.rs | 4 ++-- 14 files changed, 87 insertions(+), 87 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1dc00d0..d04896d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,6 @@ repository = "https://github.com/vhdirk/notmuch-rs" description = "Rust interface and bindings for notmuch" license = "GPL-3.0+" readme = "README.md" -edition = "2018" [badges] travis-ci = { repository = "vhdirk/notmuch-rs" } diff --git a/src/database.rs b/src/database.rs index 19d33c7..f4ef444 100644 --- a/src/database.rs +++ b/src/database.rs @@ -7,19 +7,20 @@ use supercow::Supercow; use libc; -use crate::error::{Error, Result}; -use crate::ffi; -use crate::ffi::Status; -use crate::query::QueryPtr; -use crate::utils::ToStr; -use crate::Directory; -use crate::Query; -use crate::Tags; -use crate::TagsOwner; -use crate::utils::ScopedSupercow; +use error::{Error, Result}; +use ffi; +use ffi::Status; +use query::QueryPtr; +use utils::ToStr; +use Directory; +use Query; +use Tags; +use TagsOwner; +use utils::ScopedSupercow; + // Re-exported under database module for pretty namespacin'. -pub use crate::ffi::DatabaseMode; +pub use ffi::DatabaseMode; #[derive(Copy, Clone, Debug)] pub struct Version(libc::c_uint); diff --git a/src/directory.rs b/src/directory.rs index 6402902..1aff32b 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -1,11 +1,11 @@ use std::ops::Drop; use supercow::Supercow; -use crate::ffi; -use crate::Database; -use crate::Filenames; -use crate::FilenamesOwner; -use crate::utils::{ScopedSupercow, ScopedPhantomcow}; +use ffi; +use Database; +use Filenames; +use FilenamesOwner; +use utils::{ScopedSupercow, ScopedPhantomcow}; #[derive(Debug)] pub(crate) struct DirectoryPtr { @@ -37,7 +37,7 @@ impl<'d> Directory<'d> { } } - pub fn child_directories(&self) -> Filenames<'_, Self> { + pub fn child_directories(&self) -> Filenames { ::child_directories(self) } } diff --git a/src/error.rs b/src/error.rs index 3eba2ba..824cc39 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,7 +1,7 @@ use std; use std::{error, fmt, io, result}; -use crate::ffi; +use ffi; pub type Result = result::Result; @@ -13,7 +13,7 @@ pub enum Error { } impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", error::Error::description(self)) } } @@ -27,10 +27,10 @@ impl std::error::Error for Error { } } - fn cause(&self) -> Option<&dyn error::Error> { - match self { - Error::IoError(e) => Some(e), - Error::NotmuchError(e) => Some(e), + fn cause(&self) -> Option<&error::Error> { + match *self { + Error::IoError(ref e) => Some(e), + Error::NotmuchError(ref e) => Some(e), Error::UnspecifiedError => None, } } diff --git a/src/ffi.rs b/src/ffi.rs index 1434ee0..3874ae5 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -4,10 +4,10 @@ use libc::{c_char, c_double, c_int, c_uint, c_ulong, c_void, time_t}; -use crate::error::{Error, Result}; +use error::{Error, Result}; use std::{error, fmt, str}; -use crate::utils::ToStr; +use utils::ToStr; notmuch_enum! { #[repr(C)] @@ -60,7 +60,7 @@ impl ToStr for Status { } impl fmt::Display for Status { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.to_str().unwrap()) } } diff --git a/src/filenames.rs b/src/filenames.rs index 24ce513..94eb5b7 100644 --- a/src/filenames.rs +++ b/src/filenames.rs @@ -3,8 +3,8 @@ use std::iter::Iterator; use std::ops::Drop; use std::path::PathBuf; -use crate::ffi; -use crate::utils::ScopedPhantomcow; +use ffi; +use utils::ScopedPhantomcow; pub trait FilenamesOwner {} @@ -26,7 +26,7 @@ impl Drop for FilenamesPtr { #[derive(Debug)] pub struct Filenames<'o, O> where - O: FilenamesOwner, + O: FilenamesOwner + 'o, { pub(crate) handle: FilenamesPtr, pub(crate) marker: ScopedPhantomcow<'o, O>, diff --git a/src/lib.rs b/src/lib.rs index 8f60a3f..ef8cc33 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,8 +4,8 @@ #[macro_use] mod macros; -use libc; - +extern crate libc; +extern crate supercow; mod ffi; mod utils; @@ -21,15 +21,15 @@ mod tags; mod thread; mod threads; -pub use crate::database::{Database, DatabaseExt}; -pub use crate::directory::{Directory, DirectoryExt}; -pub use crate::error::Error; -pub use crate::filenames::{Filenames, FilenamesOwner}; -pub use crate::message::{Message, MessageExt, MessageOwner}; -pub use crate::messages::{Messages, MessagesExt}; -pub use crate::query::{Query, QueryExt}; -pub use crate::tags::{Tags, TagsExt, TagsOwner}; -pub use crate::thread::{Thread, ThreadExt}; -pub use crate::threads::{Threads, ThreadsExt}; +pub use database::{Database, DatabaseExt}; +pub use directory::{Directory, DirectoryExt}; +pub use error::Error; +pub use filenames::{Filenames, FilenamesOwner}; +pub use message::{Message, MessageExt, MessageOwner}; +pub use messages::{Messages, MessagesExt}; +pub use query::{Query, QueryExt}; +pub use tags::{Tags, TagsExt, TagsOwner}; +pub use thread::{Thread, ThreadExt}; +pub use threads::{Threads, ThreadsExt}; -pub use crate::ffi::{DatabaseMode, Sort}; +pub use ffi::{DatabaseMode, Sort}; \ No newline at end of file diff --git a/src/message.rs b/src/message.rs index baa638d..8cc7af2 100644 --- a/src/message.rs +++ b/src/message.rs @@ -2,14 +2,14 @@ use std::ffi::CString; use std::path::PathBuf; use supercow::{Supercow}; -use crate::error::{Error, Result}; -use crate::ffi; -use crate::utils::{ToStr, ScopedPhantomcow, ScopedSupercow}; -use crate::Filenames; -use crate::FilenamesOwner; -use crate::Messages; -use crate::Tags; -use crate::TagsOwner; +use error::{Error, Result}; +use ffi; +use utils::{ToStr, ScopedPhantomcow, ScopedSupercow}; +use Filenames; +use FilenamesOwner; +use Messages; +use Tags; +use TagsOwner; pub trait MessageOwner: Send + Sync {} @@ -21,7 +21,7 @@ pub(crate) struct MessagePtr { #[derive(Debug)] pub struct Message<'o, O> where - O: MessageOwner, + O: MessageOwner + 'o, { pub(crate) handle: MessagePtr, marker: ScopedPhantomcow<'o, O>, @@ -55,7 +55,7 @@ where tid.to_str().unwrap().to_string() } - pub fn replies(self: &Self) -> Messages<'_, Self> { + pub fn replies(self: &Self) -> Messages { >::replies(self) } @@ -64,7 +64,7 @@ where unsafe { ffi::notmuch_message_count_files(self.handle.ptr) } } - pub fn filenames(self: &Self) -> Filenames<'_, Self> { + pub fn filenames(self: &Self) -> Filenames { >::filenames(self) } @@ -93,7 +93,7 @@ where } } - pub fn tags(&self) -> Tags<'_, Self> { + pub fn tags(&self) -> Tags { >::tags(self) } diff --git a/src/messages.rs b/src/messages.rs index 64b4090..db92f73 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -1,11 +1,11 @@ use std::ops::Drop; -use crate::ffi; -use crate::utils::ScopedPhantomcow; -use crate::MessageOwner; -use crate::Message; -use crate::Tags; -use crate::TagsOwner; +use ffi; +use utils::ScopedPhantomcow; +use MessageOwner; +use Message; +use Tags; +use TagsOwner; #[derive(Debug)] pub struct MessagesPtr { @@ -21,7 +21,7 @@ impl Drop for MessagesPtr { #[derive(Debug)] pub struct Messages<'o, O> where - O: MessageOwner, + O: MessageOwner + 'o, { pub(crate) handle: MessagesPtr, marker: ScopedPhantomcow<'o, O>, diff --git a/src/query.rs b/src/query.rs index 9a04c7a..adbed58 100644 --- a/src/query.rs +++ b/src/query.rs @@ -3,14 +3,14 @@ use std::ptr; use supercow::{Phantomcow, Supercow}; -use crate::error::Result; -use crate::ffi; -use crate::ffi::Sort; -use crate::Database; -use crate::Messages; -use crate::MessageOwner; -use crate::Threads; -use crate::utils::ScopedSupercow; +use error::Result; +use ffi; +use ffi::Sort; +use Database; +use Messages; +use MessageOwner; +use Threads; +use utils::ScopedSupercow; #[derive(Debug)] pub(crate) struct QueryPtr { @@ -76,7 +76,7 @@ impl<'d> Query<'d> { /// Filter messages according to the query and return pub fn search_messages<'q>(self: &'d Self) -> Result> { - as QueryExt>::search_messages(self) + ::search_messages(self) } pub fn count_messages(self: &Self) -> Result { diff --git a/src/tags.rs b/src/tags.rs index 215bb8a..df9e854 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -2,8 +2,8 @@ use std::ffi::CStr; use std::iter::Iterator; use std::ops::Drop; -use crate::ffi; -use crate::utils::ScopedPhantomcow; +use ffi; +use utils::ScopedPhantomcow; pub trait TagsOwner {} @@ -19,7 +19,7 @@ impl Drop for TagsPtr { } #[derive(Debug)] -pub struct Tags<'o, Owner: TagsOwner> { +pub struct Tags<'o, Owner: TagsOwner + 'o> { handle: TagsPtr, marker: ScopedPhantomcow<'o, Owner>, } diff --git a/src/thread.rs b/src/thread.rs index b3cd151..137c936 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -1,12 +1,12 @@ use std::ops::Drop; -use crate::ffi; -use crate::utils::{ToStr, ScopedSupercow, ScopedPhantomcow}; -use crate::Messages; -use crate::MessageOwner; -use crate::Tags; -use crate::TagsOwner; -use crate::Query; +use ffi; +use utils::{ToStr, ScopedSupercow, ScopedPhantomcow}; +use Messages; +use MessageOwner; +use Tags; +use TagsOwner; +use Query; #[derive(Debug)] pub(crate) struct ThreadPtr { diff --git a/src/threads.rs b/src/threads.rs index 4aa5a9b..6d1e8e4 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -1,9 +1,9 @@ use std::ops::Drop; -use crate::ffi; -use crate::Thread; -use crate::Query; -use crate::utils::ScopedPhantomcow; +use ffi; +use Thread; +use Query; +use utils::ScopedPhantomcow; #[derive(Debug)] diff --git a/tests/main.rs b/tests/main.rs index 8a857dd..5789824 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -1,5 +1,5 @@ -use dirs; -use notmuch; +extern crate dirs; +extern crate notmuch; use std::sync::Arc; -- cgit v1.2.1 From a285f7e181d7b07615bb8aba097177ecc0fec99b Mon Sep 17 00:00:00 2001 From: The Gitter Badger Date: Sat, 15 Dec 2018 15:10:11 +0000 Subject: Add Gitter badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7c7811d..8f2e9e8 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ This is not much more than a wrapper for the [notmuch](https://notmuchmail.org/) [![Build Status](https://travis-ci.org/vhdirk/notmuch-rs.svg?branch=master)](https://travis-ci.org/vhdirk/notmuch-rs) [![Crate version](https://img.shields.io/crates/v/notmuch.svg)](https://crates.io/crates/notmuch) [![Download statistics](https://img.shields.io/crates/d/notmuch.svg)](https://crates.io/crates/notmuch) -[![License](https://img.shields.io/crates/l/notmuch.svg)](https://crates.io/crates/notmuch) +[![License](https://img.shields.io/crates/l/notmuch.svg)](https://crates.io/crates/notmuch) [![Join the chat at https://gitter.im/notmuch-rs/Lobby](https://badges.gitter.im/notmuch-rs/Lobby.svg)](https://gitter.im/notmuch-rs/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ## Building -- cgit v1.2.1 From 0d510d55c4238ff0a1175985b27ca38c71a3cfc2 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 17 Dec 2018 15:52:59 +0100 Subject: link lifetime of message to Query --- src/lib.rs | 2 +- src/message.rs | 71 ++++++++++++++++++++++++++++++--------------------------- src/messages.rs | 43 +++++++++++++++++----------------- src/query.rs | 4 ++-- src/thread.rs | 60 ++++++++++++++++++++++++++---------------------- src/utils.rs | 4 ---- 6 files changed, 96 insertions(+), 88 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ef8cc33..7948f77 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,4 +32,4 @@ pub use tags::{Tags, TagsExt, TagsOwner}; pub use thread::{Thread, ThreadExt}; pub use threads::{Threads, ThreadsExt}; -pub use ffi::{DatabaseMode, Sort}; \ No newline at end of file +pub use ffi::{DatabaseMode, Sort}; diff --git a/src/message.rs b/src/message.rs index 8cc7af2..80e7c46 100644 --- a/src/message.rs +++ b/src/message.rs @@ -10,6 +10,7 @@ use FilenamesOwner; use Messages; use Tags; use TagsOwner; +use Query; pub trait MessageOwner: Send + Sync {} @@ -19,25 +20,25 @@ pub(crate) struct MessagePtr { } #[derive(Debug)] -pub struct Message<'o, O> +pub struct Message<'d, 'q> where - O: MessageOwner + 'o, + 'd: 'q, { pub(crate) handle: MessagePtr, - marker: ScopedPhantomcow<'o, O>, + marker: ScopedPhantomcow<'q, Query<'d>>, } -impl<'o, O> MessageOwner for Message<'o, O> where O: MessageOwner + 'o {} -impl<'o, O> FilenamesOwner for Message<'o, O> where O: MessageOwner + 'o {} -impl<'o, O> TagsOwner for Message<'o, O> where O: MessageOwner + 'o {} +impl<'d, 'q> MessageOwner for Message<'d, 'q> where 'd: 'q {} +impl<'d, 'q> FilenamesOwner for Message<'d, 'q> where 'd: 'q {} +impl<'d, 'q> TagsOwner for Message<'d, 'q> where 'd: 'q {} -impl<'o, O> Message<'o, O> +impl<'d, 'q> Message<'d, 'q> where - O: MessageOwner + 'o, + 'd: 'q, { - pub fn from_ptr

(ptr: *mut ffi::notmuch_message_t, owner: P) -> Message<'o, O> + pub fn from_ptr

(ptr: *mut ffi::notmuch_message_t, owner: P) -> Message<'d, 'q> where - P: Into>, + P: Into>>, { Message { handle: MessagePtr { ptr }, @@ -55,8 +56,12 @@ where tid.to_str().unwrap().to_string() } - pub fn replies(self: &Self) -> Messages { - >::replies(self) + pub fn replies(self: &mut Self) -> Messages<'d, 'q> + { + Messages::from_ptr( + unsafe { ffi::notmuch_message_get_replies(self.handle.ptr) }, + ScopedPhantomcow::<'q, Query<'d>>::share(&mut self.marker), + ) } #[cfg(feature = "v0_26")] @@ -65,7 +70,7 @@ where } pub fn filenames(self: &Self) -> Filenames { - >::filenames(self) + >::filenames(self) } pub fn filename(self: &Self) -> PathBuf { @@ -94,7 +99,7 @@ where } pub fn tags(&self) -> Tags { - >::tags(self) + >::tags(self) } pub fn add_tag(self: &Self, tag: &str) -> Result<()> { @@ -112,13 +117,13 @@ where } } -pub trait MessageExt<'o, O> +pub trait MessageExt<'d, 'q> where - O: MessageOwner + 'o, + 'd: 'q, { - fn tags<'s, S>(message: S) -> Tags<'s, Message<'o, O>> + fn tags<'s, S>(message: S) -> Tags<'s, Message<'d, 'q>> where - S: Into>>, + S: Into>>, { let messageref = message.into(); Tags::from_ptr( @@ -127,20 +132,20 @@ where ) } - fn replies<'s, S>(message: S) -> Messages<'s, Message<'o, O>> - where - S: Into>>, - { - let messageref = message.into(); - Messages::from_ptr( - unsafe { ffi::notmuch_message_get_replies(messageref.handle.ptr) }, - Supercow::phantom(messageref), - ) - } + // fn replies<'s, S>(message: S) -> Messages<'d, 'q> + // where + // S: Into>>, + // { + // let messageref = message.into(); + // Messages::from_ptr( + // unsafe { ffi::notmuch_message_get_replies(messageref.handle.ptr) }, + // Supercow::phantom(messageref), + // ) + // } - fn filenames<'s, S>(message: S) -> Filenames<'s, Message<'o, O>> + fn filenames<'s, S>(message: S) -> Filenames<'s, Message<'d, 'q>> where - S: Into>>, + S: Into>>, { let messageref = message.into(); Filenames::from_ptr( @@ -150,7 +155,7 @@ where } } -impl<'o, O> MessageExt<'o, O> for Message<'o, O> where O: MessageOwner + 'o {} +impl<'d, 'q> MessageExt<'d, 'q> for Message<'d, 'q> where 'd: 'q {} -unsafe impl<'o, O> Send for Message<'o, O> where O: MessageOwner + 'o {} -unsafe impl<'o, O> Sync for Message<'o, O> where O: MessageOwner + 'o {} +unsafe impl<'d, 'q> Send for Message<'d, 'q> where 'd: 'q {} +unsafe impl<'d, 'q> Sync for Message<'d, 'q> where 'd: 'q {} diff --git a/src/messages.rs b/src/messages.rs index db92f73..2401293 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -6,6 +6,7 @@ use MessageOwner; use Message; use Tags; use TagsOwner; +use Query; #[derive(Debug)] pub struct MessagesPtr { @@ -19,21 +20,21 @@ impl Drop for MessagesPtr { } #[derive(Debug)] -pub struct Messages<'o, O> +pub struct Messages<'d, 'q> where - O: MessageOwner + 'o, + 'd: 'q, { pub(crate) handle: MessagesPtr, - marker: ScopedPhantomcow<'o, O>, + marker: ScopedPhantomcow<'q, Query<'d>>, } -impl<'o, O> Messages<'o, O> +impl<'d, 'q> Messages<'d, 'q> where - O: MessageOwner + 'o, + 'd: 'q, { - pub(crate) fn from_ptr

(ptr: *mut ffi::notmuch_messages_t, owner: P) -> Messages<'o, O> + pub(crate) fn from_ptr

(ptr: *mut ffi::notmuch_messages_t, owner: P) -> Messages<'d, 'q> where - P: Into>, + P: Into>>, { Messages { handle: MessagesPtr { ptr }, @@ -42,12 +43,12 @@ where } } -impl<'o, O> MessageOwner for Messages<'o, O> where O: MessageOwner + 'o {} -impl<'o, O> TagsOwner for Messages<'o, O> where O: MessageOwner + 'o {} +impl<'d, 'q> MessageOwner for Messages<'d, 'q> where 'd: 'q {} +impl<'d, 'q> TagsOwner for Messages<'d, 'q> where 'd: 'q {} -impl<'o, O> Messages<'o, O> +impl<'d, 'q> Messages<'d, 'q> where - O: MessageOwner + 'o, + 'd: 'q, { /** * Return a list of tags from all messages. @@ -62,7 +63,7 @@ where * * The function returns NULL on error. */ - pub fn collect_tags<'m>(self: &'o Self) -> Tags<'m, Self> { + pub fn collect_tags<'m>(self: &'m Self) -> Tags<'m, Self> { Tags::from_ptr( unsafe { ffi::notmuch_messages_collect_tags(self.handle.ptr) }, self, @@ -70,11 +71,11 @@ where } } -impl<'o, O> Iterator for Messages<'o, O> +impl<'d, 'q> Iterator for Messages<'d, 'q> where - O: MessageOwner + 'o, + 'd: 'q, { - type Item = Message<'o, O>; + type Item = Message<'d, 'q>; fn next(&mut self) -> Option { let valid = unsafe { ffi::notmuch_messages_valid(self.handle.ptr) }; @@ -89,20 +90,20 @@ where thrd }; - Some(Message::from_ptr(cthrd, ScopedPhantomcow::<'o, O>::share(&mut self.marker))) + Some(Message::from_ptr(cthrd, ScopedPhantomcow::<'q, Query<'d>>::share(&mut self.marker))) } } -pub trait MessagesExt<'o, O> +pub trait MessagesExt<'d, 'q> where - O: MessageOwner + 'o, + 'd: 'q, { } -impl<'o, O> MessagesExt<'o, O> for Messages<'o, O> where O: MessageOwner + 'o {} +impl<'d, 'q> MessagesExt<'q, 'q> for Messages<'d, 'q> where 'd: 'q {} -unsafe impl<'o, O> Send for Messages<'o, O> where O: MessageOwner + 'o {} -unsafe impl<'o, O> Sync for Messages<'o, O> where O: MessageOwner + 'o {} +unsafe impl<'d, 'q> Send for Messages<'d, 'q> where 'd: 'q {} +unsafe impl<'d, 'q> Sync for Messages<'d, 'q> where 'd: 'q {} diff --git a/src/query.rs b/src/query.rs index adbed58..97a3f52 100644 --- a/src/query.rs +++ b/src/query.rs @@ -75,7 +75,7 @@ impl<'d> Query<'d> { } /// Filter messages according to the query and return - pub fn search_messages<'q>(self: &'d Self) -> Result> { + pub fn search_messages<'q>(self: &'d Self) -> Result> { ::search_messages(self) } @@ -112,7 +112,7 @@ pub trait QueryExt<'d> { Ok(Threads::from_ptr(thrds, ScopedSupercow::phantom(queryref))) } - fn search_messages<'q, Q>(query: Q) -> Result>> + fn search_messages<'q, Q>(query: Q) -> Result> where Q: Into>>, { diff --git a/src/thread.rs b/src/thread.rs index 137c936..20280e1 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -59,14 +59,20 @@ where unsafe { ffi::notmuch_thread_get_total_files(self.handle.ptr) } } - pub fn toplevel_messages(self: &Self) -> Messages<'_, Self> { - >::toplevel_messages(self) + pub fn toplevel_messages(self: &mut Self) -> Messages<'d, 'q> { + Messages::from_ptr( + unsafe { ffi::notmuch_thread_get_toplevel_messages(self.handle.ptr) }, + ScopedPhantomcow::<'q, Query<'d>>::share(&mut self.marker), + ) } /// Get a `Messages` iterator for all messages in 'thread' in /// oldest-first order. - pub fn messages(self: &Self) -> Messages<'_, Self> { - >::messages(self) + pub fn messages(self: &mut Self) -> Messages<'d, 'q> { + Messages::from_ptr( + unsafe { ffi::notmuch_thread_get_messages(self.handle.ptr) }, + ScopedPhantomcow::<'q, Query<'d>>::share(&mut self.marker), + ) } pub fn tags(&self) -> Tags<'_, Self> { @@ -116,29 +122,29 @@ where ) } - fn toplevel_messages<'s, S>(thread: S) -> Messages<'s, Thread<'d, 'q>> - where - S: Into>>, - { - let threadref = thread.into(); - Messages::from_ptr( - unsafe { ffi::notmuch_thread_get_toplevel_messages(threadref.handle.ptr) }, - ScopedSupercow::phantom(threadref), - ) - } - - /// Get a `Messages` iterator for all messages in 'thread' in - /// oldest-first order. - fn messages<'s, S>(thread: S) -> Messages<'s, Thread<'d, 'q>> - where - S: Into>>, - { - let threadref = thread.into(); - Messages::from_ptr( - unsafe { ffi::notmuch_thread_get_messages(threadref.handle.ptr) }, - ScopedSupercow::phantom(threadref), - ) - } + // fn toplevel_messages<'s, S>(thread: S) -> Messages<'d, 'q> + // where + // S: Into>>, + // { + // let threadref = thread.into(); + // Messages::from_ptr( + // unsafe { ffi::notmuch_thread_get_toplevel_messages(threadref.handle.ptr) }, + // ScopedPhantomcow::<'q, Query<'d>>::share(&mut self.marker), + // ) + // } + + // /// Get a `Messages` iterator for all messages in 'thread' in + // /// oldest-first order. + // fn messages<'s, S>(thread: S) -> Messages<'d, 'q> + // where + // S: Into>>, + // { + // let threadref = thread.into(); + // Messages::from_ptr( + // unsafe { ffi::notmuch_thread_get_messages(threadref.handle.ptr) }, + // ScopedPhantomcow::<'q, Query<'d>>::share(&mut self.marker), + // ) + // } } impl<'d, 'q> ThreadExt<'d, 'q> for Thread<'d, 'q> where 'd: 'q {} diff --git a/src/utils.rs b/src/utils.rs index 409534c..ab21d13 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -37,7 +37,3 @@ pub type ScopedPhantomcow<'a, OWNED, BORROWED = OWNED, pub type ScopedSupercow<'a, OWNED, BORROWED = OWNED, SHARED = Box + 'a>> = Supercow<'a, OWNED, BORROWED, SHARED, BoxedStorage>; - - - - -- cgit v1.2.1 From d74e6fee5dc34e8015f4d9699b5624d7a60a3c8a Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 17 Dec 2018 18:29:55 +0100 Subject: Revert "link lifetime of message to Query" This reverts commit 0d510d55c4238ff0a1175985b27ca38c71a3cfc2. --- src/lib.rs | 2 +- src/message.rs | 71 +++++++++++++++++++++++++++------------------------------ src/messages.rs | 43 +++++++++++++++++----------------- src/query.rs | 4 ++-- src/thread.rs | 60 ++++++++++++++++++++++-------------------------- src/utils.rs | 4 ++++ 6 files changed, 88 insertions(+), 96 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7948f77..ef8cc33 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,4 +32,4 @@ pub use tags::{Tags, TagsExt, TagsOwner}; pub use thread::{Thread, ThreadExt}; pub use threads::{Threads, ThreadsExt}; -pub use ffi::{DatabaseMode, Sort}; +pub use ffi::{DatabaseMode, Sort}; \ No newline at end of file diff --git a/src/message.rs b/src/message.rs index 80e7c46..8cc7af2 100644 --- a/src/message.rs +++ b/src/message.rs @@ -10,7 +10,6 @@ use FilenamesOwner; use Messages; use Tags; use TagsOwner; -use Query; pub trait MessageOwner: Send + Sync {} @@ -20,25 +19,25 @@ pub(crate) struct MessagePtr { } #[derive(Debug)] -pub struct Message<'d, 'q> +pub struct Message<'o, O> where - 'd: 'q, + O: MessageOwner + 'o, { pub(crate) handle: MessagePtr, - marker: ScopedPhantomcow<'q, Query<'d>>, + marker: ScopedPhantomcow<'o, O>, } -impl<'d, 'q> MessageOwner for Message<'d, 'q> where 'd: 'q {} -impl<'d, 'q> FilenamesOwner for Message<'d, 'q> where 'd: 'q {} -impl<'d, 'q> TagsOwner for Message<'d, 'q> where 'd: 'q {} +impl<'o, O> MessageOwner for Message<'o, O> where O: MessageOwner + 'o {} +impl<'o, O> FilenamesOwner for Message<'o, O> where O: MessageOwner + 'o {} +impl<'o, O> TagsOwner for Message<'o, O> where O: MessageOwner + 'o {} -impl<'d, 'q> Message<'d, 'q> +impl<'o, O> Message<'o, O> where - 'd: 'q, + O: MessageOwner + 'o, { - pub fn from_ptr

(ptr: *mut ffi::notmuch_message_t, owner: P) -> Message<'d, 'q> + pub fn from_ptr

(ptr: *mut ffi::notmuch_message_t, owner: P) -> Message<'o, O> where - P: Into>>, + P: Into>, { Message { handle: MessagePtr { ptr }, @@ -56,12 +55,8 @@ where tid.to_str().unwrap().to_string() } - pub fn replies(self: &mut Self) -> Messages<'d, 'q> - { - Messages::from_ptr( - unsafe { ffi::notmuch_message_get_replies(self.handle.ptr) }, - ScopedPhantomcow::<'q, Query<'d>>::share(&mut self.marker), - ) + pub fn replies(self: &Self) -> Messages { + >::replies(self) } #[cfg(feature = "v0_26")] @@ -70,7 +65,7 @@ where } pub fn filenames(self: &Self) -> Filenames { - >::filenames(self) + >::filenames(self) } pub fn filename(self: &Self) -> PathBuf { @@ -99,7 +94,7 @@ where } pub fn tags(&self) -> Tags { - >::tags(self) + >::tags(self) } pub fn add_tag(self: &Self, tag: &str) -> Result<()> { @@ -117,13 +112,13 @@ where } } -pub trait MessageExt<'d, 'q> +pub trait MessageExt<'o, O> where - 'd: 'q, + O: MessageOwner + 'o, { - fn tags<'s, S>(message: S) -> Tags<'s, Message<'d, 'q>> + fn tags<'s, S>(message: S) -> Tags<'s, Message<'o, O>> where - S: Into>>, + S: Into>>, { let messageref = message.into(); Tags::from_ptr( @@ -132,20 +127,20 @@ where ) } - // fn replies<'s, S>(message: S) -> Messages<'d, 'q> - // where - // S: Into>>, - // { - // let messageref = message.into(); - // Messages::from_ptr( - // unsafe { ffi::notmuch_message_get_replies(messageref.handle.ptr) }, - // Supercow::phantom(messageref), - // ) - // } + fn replies<'s, S>(message: S) -> Messages<'s, Message<'o, O>> + where + S: Into>>, + { + let messageref = message.into(); + Messages::from_ptr( + unsafe { ffi::notmuch_message_get_replies(messageref.handle.ptr) }, + Supercow::phantom(messageref), + ) + } - fn filenames<'s, S>(message: S) -> Filenames<'s, Message<'d, 'q>> + fn filenames<'s, S>(message: S) -> Filenames<'s, Message<'o, O>> where - S: Into>>, + S: Into>>, { let messageref = message.into(); Filenames::from_ptr( @@ -155,7 +150,7 @@ where } } -impl<'d, 'q> MessageExt<'d, 'q> for Message<'d, 'q> where 'd: 'q {} +impl<'o, O> MessageExt<'o, O> for Message<'o, O> where O: MessageOwner + 'o {} -unsafe impl<'d, 'q> Send for Message<'d, 'q> where 'd: 'q {} -unsafe impl<'d, 'q> Sync for Message<'d, 'q> where 'd: 'q {} +unsafe impl<'o, O> Send for Message<'o, O> where O: MessageOwner + 'o {} +unsafe impl<'o, O> Sync for Message<'o, O> where O: MessageOwner + 'o {} diff --git a/src/messages.rs b/src/messages.rs index 2401293..db92f73 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -6,7 +6,6 @@ use MessageOwner; use Message; use Tags; use TagsOwner; -use Query; #[derive(Debug)] pub struct MessagesPtr { @@ -20,21 +19,21 @@ impl Drop for MessagesPtr { } #[derive(Debug)] -pub struct Messages<'d, 'q> +pub struct Messages<'o, O> where - 'd: 'q, + O: MessageOwner + 'o, { pub(crate) handle: MessagesPtr, - marker: ScopedPhantomcow<'q, Query<'d>>, + marker: ScopedPhantomcow<'o, O>, } -impl<'d, 'q> Messages<'d, 'q> +impl<'o, O> Messages<'o, O> where - 'd: 'q, + O: MessageOwner + 'o, { - pub(crate) fn from_ptr

(ptr: *mut ffi::notmuch_messages_t, owner: P) -> Messages<'d, 'q> + pub(crate) fn from_ptr

(ptr: *mut ffi::notmuch_messages_t, owner: P) -> Messages<'o, O> where - P: Into>>, + P: Into>, { Messages { handle: MessagesPtr { ptr }, @@ -43,12 +42,12 @@ where } } -impl<'d, 'q> MessageOwner for Messages<'d, 'q> where 'd: 'q {} -impl<'d, 'q> TagsOwner for Messages<'d, 'q> where 'd: 'q {} +impl<'o, O> MessageOwner for Messages<'o, O> where O: MessageOwner + 'o {} +impl<'o, O> TagsOwner for Messages<'o, O> where O: MessageOwner + 'o {} -impl<'d, 'q> Messages<'d, 'q> +impl<'o, O> Messages<'o, O> where - 'd: 'q, + O: MessageOwner + 'o, { /** * Return a list of tags from all messages. @@ -63,7 +62,7 @@ where * * The function returns NULL on error. */ - pub fn collect_tags<'m>(self: &'m Self) -> Tags<'m, Self> { + pub fn collect_tags<'m>(self: &'o Self) -> Tags<'m, Self> { Tags::from_ptr( unsafe { ffi::notmuch_messages_collect_tags(self.handle.ptr) }, self, @@ -71,11 +70,11 @@ where } } -impl<'d, 'q> Iterator for Messages<'d, 'q> +impl<'o, O> Iterator for Messages<'o, O> where - 'd: 'q, + O: MessageOwner + 'o, { - type Item = Message<'d, 'q>; + type Item = Message<'o, O>; fn next(&mut self) -> Option { let valid = unsafe { ffi::notmuch_messages_valid(self.handle.ptr) }; @@ -90,20 +89,20 @@ where thrd }; - Some(Message::from_ptr(cthrd, ScopedPhantomcow::<'q, Query<'d>>::share(&mut self.marker))) + Some(Message::from_ptr(cthrd, ScopedPhantomcow::<'o, O>::share(&mut self.marker))) } } -pub trait MessagesExt<'d, 'q> +pub trait MessagesExt<'o, O> where - 'd: 'q, + O: MessageOwner + 'o, { } -impl<'d, 'q> MessagesExt<'q, 'q> for Messages<'d, 'q> where 'd: 'q {} +impl<'o, O> MessagesExt<'o, O> for Messages<'o, O> where O: MessageOwner + 'o {} -unsafe impl<'d, 'q> Send for Messages<'d, 'q> where 'd: 'q {} -unsafe impl<'d, 'q> Sync for Messages<'d, 'q> where 'd: 'q {} +unsafe impl<'o, O> Send for Messages<'o, O> where O: MessageOwner + 'o {} +unsafe impl<'o, O> Sync for Messages<'o, O> where O: MessageOwner + 'o {} diff --git a/src/query.rs b/src/query.rs index 97a3f52..adbed58 100644 --- a/src/query.rs +++ b/src/query.rs @@ -75,7 +75,7 @@ impl<'d> Query<'d> { } /// Filter messages according to the query and return - pub fn search_messages<'q>(self: &'d Self) -> Result> { + pub fn search_messages<'q>(self: &'d Self) -> Result> { ::search_messages(self) } @@ -112,7 +112,7 @@ pub trait QueryExt<'d> { Ok(Threads::from_ptr(thrds, ScopedSupercow::phantom(queryref))) } - fn search_messages<'q, Q>(query: Q) -> Result> + fn search_messages<'q, Q>(query: Q) -> Result>> where Q: Into>>, { diff --git a/src/thread.rs b/src/thread.rs index 20280e1..137c936 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -59,20 +59,14 @@ where unsafe { ffi::notmuch_thread_get_total_files(self.handle.ptr) } } - pub fn toplevel_messages(self: &mut Self) -> Messages<'d, 'q> { - Messages::from_ptr( - unsafe { ffi::notmuch_thread_get_toplevel_messages(self.handle.ptr) }, - ScopedPhantomcow::<'q, Query<'d>>::share(&mut self.marker), - ) + pub fn toplevel_messages(self: &Self) -> Messages<'_, Self> { + >::toplevel_messages(self) } /// Get a `Messages` iterator for all messages in 'thread' in /// oldest-first order. - pub fn messages(self: &mut Self) -> Messages<'d, 'q> { - Messages::from_ptr( - unsafe { ffi::notmuch_thread_get_messages(self.handle.ptr) }, - ScopedPhantomcow::<'q, Query<'d>>::share(&mut self.marker), - ) + pub fn messages(self: &Self) -> Messages<'_, Self> { + >::messages(self) } pub fn tags(&self) -> Tags<'_, Self> { @@ -122,29 +116,29 @@ where ) } - // fn toplevel_messages<'s, S>(thread: S) -> Messages<'d, 'q> - // where - // S: Into>>, - // { - // let threadref = thread.into(); - // Messages::from_ptr( - // unsafe { ffi::notmuch_thread_get_toplevel_messages(threadref.handle.ptr) }, - // ScopedPhantomcow::<'q, Query<'d>>::share(&mut self.marker), - // ) - // } - - // /// Get a `Messages` iterator for all messages in 'thread' in - // /// oldest-first order. - // fn messages<'s, S>(thread: S) -> Messages<'d, 'q> - // where - // S: Into>>, - // { - // let threadref = thread.into(); - // Messages::from_ptr( - // unsafe { ffi::notmuch_thread_get_messages(threadref.handle.ptr) }, - // ScopedPhantomcow::<'q, Query<'d>>::share(&mut self.marker), - // ) - // } + fn toplevel_messages<'s, S>(thread: S) -> Messages<'s, Thread<'d, 'q>> + where + S: Into>>, + { + let threadref = thread.into(); + Messages::from_ptr( + unsafe { ffi::notmuch_thread_get_toplevel_messages(threadref.handle.ptr) }, + ScopedSupercow::phantom(threadref), + ) + } + + /// Get a `Messages` iterator for all messages in 'thread' in + /// oldest-first order. + fn messages<'s, S>(thread: S) -> Messages<'s, Thread<'d, 'q>> + where + S: Into>>, + { + let threadref = thread.into(); + Messages::from_ptr( + unsafe { ffi::notmuch_thread_get_messages(threadref.handle.ptr) }, + ScopedSupercow::phantom(threadref), + ) + } } impl<'d, 'q> ThreadExt<'d, 'q> for Thread<'d, 'q> where 'd: 'q {} diff --git a/src/utils.rs b/src/utils.rs index ab21d13..409534c 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -37,3 +37,7 @@ pub type ScopedPhantomcow<'a, OWNED, BORROWED = OWNED, pub type ScopedSupercow<'a, OWNED, BORROWED = OWNED, SHARED = Box + 'a>> = Supercow<'a, OWNED, BORROWED, SHARED, BoxedStorage>; + + + + -- cgit v1.2.1 From e5a7acf1a0ced9b9d5ccfef79c46579f359fac94 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Mon, 17 Dec 2018 18:37:01 +0100 Subject: messages may depend on thread, not just query. But never on other messages --- src/message.rs | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/message.rs b/src/message.rs index 8cc7af2..bf46a4e 100644 --- a/src/message.rs +++ b/src/message.rs @@ -35,7 +35,7 @@ impl<'o, O> Message<'o, O> where O: MessageOwner + 'o, { - pub fn from_ptr

(ptr: *mut ffi::notmuch_message_t, owner: P) -> Message<'o, O> + pub(crate) fn from_ptr

(ptr: *mut ffi::notmuch_message_t, owner: P) -> Message<'o, O> where P: Into>, { @@ -55,8 +55,11 @@ where tid.to_str().unwrap().to_string() } - pub fn replies(self: &Self) -> Messages { - >::replies(self) + pub fn replies(self: &mut Self) -> Messages<'o, O> { + Messages::<'o, O>::from_ptr( + unsafe { ffi::notmuch_message_get_replies(self.handle.ptr) }, + ScopedPhantomcow::<'o, O>::share(&mut self.marker) + ) } #[cfg(feature = "v0_26")] @@ -127,16 +130,16 @@ where ) } - fn replies<'s, S>(message: S) -> Messages<'s, Message<'o, O>> - where - S: Into>>, - { - let messageref = message.into(); - Messages::from_ptr( - unsafe { ffi::notmuch_message_get_replies(messageref.handle.ptr) }, - Supercow::phantom(messageref), - ) - } + // fn replies<'s, S>(message: S) -> Messages<'s, Message<'o, O>> + // where + // S: Into>>, + // { + // let messageref = message.into(); + // Messages::from_ptr( + // unsafe { ffi::notmuch_message_get_replies(messageref.handle.ptr) }, + // Supercow::phantom(messageref), + // ) + // } fn filenames<'s, S>(message: S) -> Filenames<'s, Message<'o, O>> where -- cgit v1.2.1 From 2baa9d13ad4c5c2c6e55b6ca49c92a4d2434fba7 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 18 Dec 2018 07:41:02 +0100 Subject: do not require a mutable reference for getting message replies --- src/message.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/message.rs b/src/message.rs index bf46a4e..b2b466f 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,5 +1,6 @@ use std::ffi::CString; use std::path::PathBuf; +use std::cell::RefCell; use supercow::{Supercow}; use error::{Error, Result}; @@ -24,7 +25,7 @@ where O: MessageOwner + 'o, { pub(crate) handle: MessagePtr, - marker: ScopedPhantomcow<'o, O>, + marker: RefCell>, } impl<'o, O> MessageOwner for Message<'o, O> where O: MessageOwner + 'o {} @@ -41,7 +42,7 @@ where { Message { handle: MessagePtr { ptr }, - marker: owner.into(), + marker: RefCell::new(owner.into()), } } @@ -55,10 +56,11 @@ where tid.to_str().unwrap().to_string() } - pub fn replies(self: &mut Self) -> Messages<'o, O> { + pub fn replies(self: &Self) -> Messages<'o, O> { Messages::<'o, O>::from_ptr( unsafe { ffi::notmuch_message_get_replies(self.handle.ptr) }, - ScopedPhantomcow::<'o, O>::share(&mut self.marker) + // will never panic since the borrow is released immediately + ScopedPhantomcow::<'o, O>::share(&mut *(self.marker.borrow_mut())) ) } -- cgit v1.2.1 From bb8a60ddc9fdecc6c1004639514b538578e37532 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 20 Dec 2018 08:21:03 +0100 Subject: remove ptr indirection --- src/database.rs | 47 ++++++++++++++++------------------------------- src/directory.rs | 18 +++++++----------- src/filenames.rs | 34 ++++++++++++++-------------------- src/message.rs | 35 +++++++++++++++-------------------- src/messages.rs | 32 +++++++++++++++----------------- src/query.rs | 44 +++++++++++++------------------------------- src/tags.rs | 26 +++++++++++++------------- src/thread.rs | 44 +++++++++++++++++++++----------------------- src/threads.rs | 30 ++++++++++++++---------------- 9 files changed, 128 insertions(+), 182 deletions(-) diff --git a/src/database.rs b/src/database.rs index f4ef444..027a43f 100644 --- a/src/database.rs +++ b/src/database.rs @@ -10,7 +10,6 @@ use libc; use error::{Error, Result}; use ffi; use ffi::Status; -use query::QueryPtr; use utils::ToStr; use Directory; use Query; @@ -31,32 +30,18 @@ pub struct Revision { pub uuid: String, } + #[derive(Debug)] -pub(crate) struct DatabasePtr { - pub ptr: *mut ffi::notmuch_database_t, +pub struct Database { + pub(crate) ptr: *mut ffi::notmuch_database_t, } -impl Drop for DatabasePtr { +impl Drop for Database { fn drop(&mut self) { unsafe { ffi::notmuch_database_destroy(self.ptr) }; } } -impl DatabasePtr { - pub(crate) fn create_query(&self, query_string: &str) -> Result { - let query_str = CString::new(query_string).unwrap(); - - let query = unsafe { ffi::notmuch_query_create(self.ptr, query_str.as_ptr()) }; - - Ok(QueryPtr { ptr: query }) - } -} - -#[derive(Debug)] -pub struct Database { - pub(crate) handle: DatabasePtr, -} - impl TagsOwner for Database {} impl Database { @@ -70,7 +55,7 @@ impl Database { unsafe { ffi::notmuch_database_create(path_str.as_ptr(), &mut db) }.as_result()?; Ok(Database { - handle: DatabasePtr { ptr: db }, + ptr: db, }) } @@ -85,12 +70,12 @@ impl Database { .as_result()?; Ok(Database { - handle: DatabasePtr { ptr: db }, + ptr: db, }) } pub fn close(&mut self) -> Result<()> { - unsafe { ffi::notmuch_database_close(self.handle.ptr) }.as_result()?; + unsafe { ffi::notmuch_database_close(self.ptr) }.as_result()?; Ok(()) } @@ -147,14 +132,14 @@ impl Database { pub fn path(&self) -> &Path { Path::new( - unsafe { ffi::notmuch_database_get_path(self.handle.ptr) } + unsafe { ffi::notmuch_database_get_path(self.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.ptr) }) } #[cfg(feature = "v0_21")] @@ -162,7 +147,7 @@ impl Database { let uuid_p: *const libc::c_char = ptr::null(); let revision = unsafe { ffi::notmuch_database_get_revision( - self.handle.ptr, + self.ptr, (&uuid_p) as *const _ as *mut *const libc::c_char, ) }; @@ -176,7 +161,7 @@ impl Database { } pub fn needs_upgrade(&self) -> bool { - unsafe { ffi::notmuch_database_needs_upgrade(self.handle.ptr) == 1 } + unsafe { ffi::notmuch_database_needs_upgrade(self.ptr) == 1 } } pub fn upgrade(&mut self) -> Result<()> @@ -209,7 +194,7 @@ impl Database { unsafe { ffi::notmuch_database_upgrade( - self.handle.ptr, + self.ptr, if status.is_some() { Some(wrapper::) } else { @@ -253,7 +238,7 @@ pub trait DatabaseExt { let dbref = database.into(); let query_str = CString::new(query_string).unwrap(); - let query = unsafe { ffi::notmuch_query_create(dbref.handle.ptr, query_str.as_ptr()) }; + let query = unsafe { ffi::notmuch_query_create(dbref.ptr, query_str.as_ptr()) }; Ok(Query::from_ptr(query, Supercow::phantom(dbref))) } @@ -264,7 +249,7 @@ pub trait DatabaseExt { { let dbref = database.into(); - let tags = unsafe { ffi::notmuch_database_get_all_tags(dbref.handle.ptr) }; + let tags = unsafe { ffi::notmuch_database_get_all_tags(dbref.ptr) }; Ok(Tags::from_ptr(tags, ScopedSupercow::phantom(dbref))) } @@ -280,7 +265,7 @@ pub trait DatabaseExt { let mut dir = ptr::null_mut(); unsafe { - ffi::notmuch_database_get_directory(dbref.handle.ptr, path_str.as_ptr(), &mut dir) + ffi::notmuch_database_get_directory(dbref.ptr, path_str.as_ptr(), &mut dir) }.as_result()?; if dir.is_null() { @@ -300,7 +285,7 @@ pub trait DatabaseExt { Some(path_str) => { let msg_path = CString::new(path_str).unwrap(); - unsafe { ffi::notmuch_database_remove_message(dbref.handle.ptr, msg_path.as_ptr()) } + unsafe { ffi::notmuch_database_remove_message(dbref.ptr, msg_path.as_ptr()) } .as_result() } None => Err(Error::NotmuchError(Status::FileError)), diff --git a/src/directory.rs b/src/directory.rs index 1aff32b..8f09ed7 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -7,23 +7,19 @@ use Filenames; use FilenamesOwner; use utils::{ScopedSupercow, ScopedPhantomcow}; + #[derive(Debug)] -pub(crate) struct DirectoryPtr { - pub ptr: *mut ffi::notmuch_directory_t, +pub struct Directory<'d> { + ptr: *mut ffi::notmuch_directory_t, + marker: ScopedPhantomcow<'d, Database>, } -impl Drop for DirectoryPtr { +impl<'d> Drop for Directory<'d> { fn drop(&mut self) { unsafe { ffi::notmuch_directory_destroy(self.ptr) }; } } -#[derive(Debug)] -pub struct Directory<'d> { - handle: DirectoryPtr, - marker: ScopedPhantomcow<'d, Database>, -} - impl<'d> FilenamesOwner for Directory<'d> {} impl<'d> Directory<'d> { @@ -32,7 +28,7 @@ impl<'d> Directory<'d> { O: Into>, { Directory { - handle: DirectoryPtr { ptr }, + ptr, marker: owner.into(), } } @@ -49,7 +45,7 @@ pub trait DirectoryExt<'d> { { let dir = directory.into(); Filenames::from_ptr( - unsafe { ffi::notmuch_directory_get_child_directories(dir.handle.ptr) }, + unsafe { ffi::notmuch_directory_get_child_directories(dir.ptr) }, Supercow::phantom(dir), ) } diff --git a/src/filenames.rs b/src/filenames.rs index 94eb5b7..a4440d3 100644 --- a/src/filenames.rs +++ b/src/filenames.rs @@ -8,30 +8,24 @@ use utils::ScopedPhantomcow; pub trait FilenamesOwner {} -#[derive(Debug)] -pub(crate) struct FilenamesPtr { - 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) }; - - if valid != 0 { - unsafe { ffi::notmuch_filenames_destroy(self.ptr) }; - } - } -} - #[derive(Debug)] pub struct Filenames<'o, O> where O: FilenamesOwner + 'o, { - pub(crate) handle: FilenamesPtr, + pub(crate) ptr: *mut ffi::notmuch_filenames_t, pub(crate) marker: ScopedPhantomcow<'o, O>, } +impl<'o, O> Drop for Filenames<'o, O> +where + O: FilenamesOwner + 'o, +{ + fn drop(self: &mut Self) { + unsafe { ffi::notmuch_filenames_destroy(self.ptr) }; + } +} + impl<'o, O> Filenames<'o, O> where O: FilenamesOwner + 'o, @@ -41,7 +35,7 @@ where P: Into>, { Filenames { - handle: FilenamesPtr { ptr }, + ptr, marker: owner.into(), } } @@ -54,15 +48,15 @@ where type Item = PathBuf; fn next(self: &mut Self) -> Option { - let valid = unsafe { ffi::notmuch_filenames_valid(self.handle.ptr) }; + let valid = unsafe { ffi::notmuch_filenames_valid(self.ptr) }; if valid == 0 { return None; } let ctag = unsafe { - let t = ffi::notmuch_filenames_get(self.handle.ptr); - ffi::notmuch_filenames_move_to_next(self.handle.ptr); + let t = ffi::notmuch_filenames_get(self.ptr); + ffi::notmuch_filenames_move_to_next(self.ptr); CStr::from_ptr(t) }; diff --git a/src/message.rs b/src/message.rs index b2b466f..226d3b8 100644 --- a/src/message.rs +++ b/src/message.rs @@ -14,17 +14,12 @@ use TagsOwner; pub trait MessageOwner: Send + Sync {} -#[derive(Debug)] -pub(crate) struct MessagePtr { - pub ptr: *mut ffi::notmuch_message_t, -} - #[derive(Debug)] pub struct Message<'o, O> where O: MessageOwner + 'o, { - pub(crate) handle: MessagePtr, + pub(crate) ptr: *mut ffi::notmuch_message_t, marker: RefCell>, } @@ -41,24 +36,24 @@ where P: Into>, { Message { - handle: MessagePtr { ptr }, + ptr, marker: RefCell::new(owner.into()), } } pub fn id(self: &Self) -> String { - let mid = unsafe { ffi::notmuch_message_get_message_id(self.handle.ptr) }; + let mid = unsafe { ffi::notmuch_message_get_message_id(self.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) }; + let tid = unsafe { ffi::notmuch_message_get_thread_id(self.ptr) }; tid.to_str().unwrap().to_string() } pub fn replies(self: &Self) -> Messages<'o, O> { Messages::<'o, O>::from_ptr( - unsafe { ffi::notmuch_message_get_replies(self.handle.ptr) }, + unsafe { ffi::notmuch_message_get_replies(self.ptr) }, // will never panic since the borrow is released immediately ScopedPhantomcow::<'o, O>::share(&mut *(self.marker.borrow_mut())) ) @@ -66,7 +61,7 @@ where #[cfg(feature = "v0_26")] pub fn count_files(self: &Self) -> i32 { - unsafe { ffi::notmuch_message_count_files(self.handle.ptr) } + unsafe { ffi::notmuch_message_count_files(self.ptr) } } pub fn filenames(self: &Self) -> Filenames { @@ -75,19 +70,19 @@ where pub fn filename(self: &Self) -> PathBuf { PathBuf::from( - unsafe { ffi::notmuch_message_get_filename(self.handle.ptr) } + unsafe { ffi::notmuch_message_get_filename(self.ptr) } .to_str() .unwrap(), ) } pub fn date(&self) -> i64 { - unsafe { ffi::notmuch_message_get_date(self.handle.ptr) as i64 } + unsafe { ffi::notmuch_message_get_date(self.ptr) as i64 } } pub fn header(&self, name: &str) -> Result> { let name = CString::new(name).unwrap(); - let ret = unsafe { ffi::notmuch_message_get_header(self.handle.ptr, name.as_ptr()) }; + let ret = unsafe { ffi::notmuch_message_get_header(self.ptr, name.as_ptr()) }; if ret.is_null() { Err(Error::UnspecifiedError) } else { @@ -104,16 +99,16 @@ where pub fn add_tag(self: &Self, tag: &str) -> Result<()> { let tag = CString::new(tag).unwrap(); - unsafe { ffi::notmuch_message_add_tag(self.handle.ptr, tag.as_ptr()) }.as_result() + unsafe { ffi::notmuch_message_add_tag(self.ptr, tag.as_ptr()) }.as_result() } pub fn remove_tag(self: &Self, tag: &str) -> Result<()> { let tag = CString::new(tag).unwrap(); - unsafe { ffi::notmuch_message_remove_tag(self.handle.ptr, tag.as_ptr()) }.as_result() + unsafe { ffi::notmuch_message_remove_tag(self.ptr, tag.as_ptr()) }.as_result() } pub fn remove_all_tags(self: &Self) -> Result<()> { - unsafe { ffi::notmuch_message_remove_all_tags(self.handle.ptr) }.as_result() + unsafe { ffi::notmuch_message_remove_all_tags(self.ptr) }.as_result() } } @@ -127,7 +122,7 @@ where { let messageref = message.into(); Tags::from_ptr( - unsafe { ffi::notmuch_message_get_tags(messageref.handle.ptr) }, + unsafe { ffi::notmuch_message_get_tags(messageref.ptr) }, Supercow::phantom(messageref), ) } @@ -138,7 +133,7 @@ where // { // let messageref = message.into(); // Messages::from_ptr( - // unsafe { ffi::notmuch_message_get_replies(messageref.handle.ptr) }, + // unsafe { ffi::notmuch_message_get_replies(messageref.ptr) }, // Supercow::phantom(messageref), // ) // } @@ -149,7 +144,7 @@ where { let messageref = message.into(); Filenames::from_ptr( - unsafe { ffi::notmuch_message_get_filenames(messageref.handle.ptr) }, + unsafe { ffi::notmuch_message_get_filenames(messageref.ptr) }, Supercow::phantom(messageref), ) } diff --git a/src/messages.rs b/src/messages.rs index db92f73..01e0ea4 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -7,26 +7,24 @@ use Message; use Tags; use TagsOwner; -#[derive(Debug)] -pub struct MessagesPtr { - pub ptr: *mut ffi::notmuch_messages_t, -} - -impl Drop for MessagesPtr { - fn drop(self: &mut Self) { - unsafe { ffi::notmuch_messages_destroy(self.ptr) }; - } -} - #[derive(Debug)] pub struct Messages<'o, O> where O: MessageOwner + 'o, { - pub(crate) handle: MessagesPtr, + pub(crate) ptr: *mut ffi::notmuch_messages_t, marker: ScopedPhantomcow<'o, O>, } +impl<'o, O> Drop for Messages<'o, O> +where + O: MessageOwner + 'o, +{ + fn drop(self: &mut Self) { + unsafe { ffi::notmuch_messages_destroy(self.ptr) }; + } +} + impl<'o, O> Messages<'o, O> where O: MessageOwner + 'o, @@ -36,7 +34,7 @@ where P: Into>, { Messages { - handle: MessagesPtr { ptr }, + ptr, marker: owner.into(), } } @@ -64,7 +62,7 @@ where */ pub fn collect_tags<'m>(self: &'o Self) -> Tags<'m, Self> { Tags::from_ptr( - unsafe { ffi::notmuch_messages_collect_tags(self.handle.ptr) }, + unsafe { ffi::notmuch_messages_collect_tags(self.ptr) }, self, ) } @@ -77,15 +75,15 @@ where type Item = Message<'o, O>; fn next(&mut self) -> Option { - let valid = unsafe { ffi::notmuch_messages_valid(self.handle.ptr) }; + let valid = unsafe { ffi::notmuch_messages_valid(self.ptr) }; if valid == 0 { return None; } let cthrd = unsafe { - let thrd = ffi::notmuch_messages_get(self.handle.ptr); - ffi::notmuch_messages_move_to_next(self.handle.ptr); + let thrd = ffi::notmuch_messages_get(self.ptr); + ffi::notmuch_messages_move_to_next(self.ptr); thrd }; diff --git a/src/query.rs b/src/query.rs index adbed58..127a9ab 100644 --- a/src/query.rs +++ b/src/query.rs @@ -10,25 +10,21 @@ use Database; use Messages; use MessageOwner; use Threads; +use DatabaseExt; use utils::ScopedSupercow; #[derive(Debug)] -pub(crate) struct QueryPtr { - pub ptr: *mut ffi::notmuch_query_t, +pub struct Query<'d> { + pub(crate) ptr: *mut ffi::notmuch_query_t, + marker: Phantomcow<'d, Database>, } -impl Drop for QueryPtr { +impl<'d> Drop for Query<'d> { fn drop(&mut self) { unsafe { ffi::notmuch_query_destroy(self.ptr) }; } } -#[derive(Debug)] -pub struct Query<'d> { - pub(crate) handle: QueryPtr, - marker: Phantomcow<'d, Database>, -} - impl<'d> MessageOwner for Query<'d> {} impl<'d> Query<'d> { @@ -37,17 +33,7 @@ impl<'d> Query<'d> { O: Into>, { Query { - handle: QueryPtr { ptr }, - marker: owner.into(), - } - } - - pub(crate) fn from_handle(handle: QueryPtr, owner: O) -> Query<'d> - where - O: Into>, - { - Query { - handle, + ptr, marker: owner.into(), } } @@ -56,22 +42,18 @@ impl<'d> Query<'d> { where D: Into>, { - let dbref = db.into(); - dbref - .handle - .create_query(query_string) - .map(move |handle| Query::from_handle(handle, Supercow::phantom(dbref))) + ::create_query(db, 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()) } + unsafe { ffi::notmuch_query_set_sort(self.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() + unsafe { ffi::notmuch_query_get_sort(self.ptr) }.into() } /// Filter messages according to the query and return @@ -81,7 +63,7 @@ impl<'d> Query<'d> { pub fn count_messages(self: &Self) -> Result { let mut cnt = 0; - unsafe { ffi::notmuch_query_count_messages(self.handle.ptr, &mut cnt) }.as_result()?; + unsafe { ffi::notmuch_query_count_messages(self.ptr, &mut cnt) }.as_result()?; Ok(cnt) } @@ -92,7 +74,7 @@ impl<'d> Query<'d> { pub fn count_threads(self: &Self) -> Result { let mut cnt = 0; - unsafe { ffi::notmuch_query_count_threads(self.handle.ptr, &mut cnt) }.as_result()?; + unsafe { ffi::notmuch_query_count_threads(self.ptr, &mut cnt) }.as_result()?; Ok(cnt) } @@ -106,7 +88,7 @@ pub trait QueryExt<'d> { let queryref = query.into(); let mut thrds = ptr::null_mut(); - unsafe { ffi::notmuch_query_search_threads(queryref.handle.ptr, &mut thrds) } + unsafe { ffi::notmuch_query_search_threads(queryref.ptr, &mut thrds) } .as_result()?; Ok(Threads::from_ptr(thrds, ScopedSupercow::phantom(queryref))) @@ -119,7 +101,7 @@ pub trait QueryExt<'d> { let queryref = query.into(); let mut msgs = ptr::null_mut(); - unsafe { ffi::notmuch_query_search_messages(queryref.handle.ptr, &mut msgs) } + unsafe { ffi::notmuch_query_search_messages(queryref.ptr, &mut msgs) } .as_result()?; Ok(Messages::from_ptr(msgs, ScopedSupercow::phantom(queryref))) diff --git a/src/tags.rs b/src/tags.rs index df9e854..ad8e421 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -8,22 +8,22 @@ use utils::ScopedPhantomcow; pub trait TagsOwner {} #[derive(Debug)] -pub(crate) struct TagsPtr { - pub ptr: *mut ffi::notmuch_tags_t, +pub struct Tags<'o, O> where + O: TagsOwner + 'o, +{ + ptr: *mut ffi::notmuch_tags_t, + marker: ScopedPhantomcow<'o, O>, } -impl Drop for TagsPtr { +impl<'o, O> Drop for Tags<'o, O> +where + O: TagsOwner + 'o, +{ fn drop(&mut self) { unsafe { ffi::notmuch_tags_destroy(self.ptr) }; } } -#[derive(Debug)] -pub struct Tags<'o, Owner: TagsOwner + 'o> { - handle: TagsPtr, - marker: ScopedPhantomcow<'o, Owner>, -} - impl<'o, O> Tags<'o, O> where O: TagsOwner + 'o, @@ -33,7 +33,7 @@ where P: Into>, { Tags { - handle: TagsPtr { ptr }, + ptr, marker: owner.into(), } } @@ -46,15 +46,15 @@ where type Item = String; fn next(&mut self) -> Option { - let valid = unsafe { ffi::notmuch_tags_valid(self.handle.ptr) }; + let valid = unsafe { ffi::notmuch_tags_valid(self.ptr) }; if valid == 0 { return None; } let ctag = unsafe { - let t = ffi::notmuch_tags_get(self.handle.ptr); - ffi::notmuch_tags_move_to_next(self.handle.ptr); + let t = ffi::notmuch_tags_get(self.ptr); + ffi::notmuch_tags_move_to_next(self.ptr); CStr::from_ptr(t) }; diff --git a/src/thread.rs b/src/thread.rs index 137c936..9634a57 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -8,26 +8,24 @@ use Tags; use TagsOwner; use Query; -#[derive(Debug)] -pub(crate) struct ThreadPtr { - pub ptr: *mut ffi::notmuch_thread_t, -} - -impl Drop for ThreadPtr { - fn drop(&mut self) { - unsafe { ffi::notmuch_thread_destroy(self.ptr) }; - } -} - #[derive(Debug)] pub struct Thread<'d, 'q> where 'd: 'q { - pub(crate) handle: ThreadPtr, + pub(crate) ptr: *mut ffi::notmuch_thread_t, pub(crate) marker: ScopedPhantomcow<'q, Query<'d>>, } +impl<'d, 'q> Drop for Thread<'d, 'q> +where + 'd: 'q +{ + fn drop(&mut self) { + unsafe { ffi::notmuch_thread_destroy(self.ptr) }; + } +} + impl<'d, 'q> MessageOwner for Thread<'d, 'q> where 'd: 'q {} impl<'d, 'q> TagsOwner for Thread<'d, 'q> where 'd: 'q {} @@ -40,23 +38,23 @@ where P: Into>>, { Thread { - handle: ThreadPtr { ptr }, + ptr, marker: owner.into(), } } pub fn id(self: &Self) -> String { - let tid = unsafe { ffi::notmuch_thread_get_thread_id(self.handle.ptr) }; + let tid = unsafe { ffi::notmuch_thread_get_thread_id(self.ptr) }; tid.to_str().unwrap().to_string() } pub fn total_messages(self: &Self) -> i32 { - unsafe { ffi::notmuch_thread_get_total_messages(self.handle.ptr) } + unsafe { ffi::notmuch_thread_get_total_messages(self.ptr) } } #[cfg(feature = "0.26")] pub fn total_files(self: &Self) -> i32 { - unsafe { ffi::notmuch_thread_get_total_files(self.handle.ptr) } + unsafe { ffi::notmuch_thread_get_total_files(self.ptr) } } pub fn toplevel_messages(self: &Self) -> Messages<'_, Self> { @@ -74,13 +72,13 @@ where } pub fn subject(self: &Self) -> String { - let sub = unsafe { ffi::notmuch_thread_get_subject(self.handle.ptr) }; + let sub = unsafe { ffi::notmuch_thread_get_subject(self.ptr) }; sub.to_str().unwrap().to_string() } pub fn authors(self: &Self) -> Vec { - let athrs = unsafe { ffi::notmuch_thread_get_authors(self.handle.ptr) }; + let athrs = unsafe { ffi::notmuch_thread_get_authors(self.ptr) }; athrs .to_str() @@ -92,12 +90,12 @@ where /// 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) as i64 } + unsafe { ffi::notmuch_thread_get_oldest_date(self.ptr) as i64 } } /// 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) as i64 } + unsafe { ffi::notmuch_thread_get_newest_date(self.ptr) as i64 } } } @@ -111,7 +109,7 @@ where { let threadref = thread.into(); Tags::from_ptr( - unsafe { ffi::notmuch_thread_get_tags(threadref.handle.ptr) }, + unsafe { ffi::notmuch_thread_get_tags(threadref.ptr) }, ScopedSupercow::phantom(threadref), ) } @@ -122,7 +120,7 @@ where { let threadref = thread.into(); Messages::from_ptr( - unsafe { ffi::notmuch_thread_get_toplevel_messages(threadref.handle.ptr) }, + unsafe { ffi::notmuch_thread_get_toplevel_messages(threadref.ptr) }, ScopedSupercow::phantom(threadref), ) } @@ -135,7 +133,7 @@ where { let threadref = thread.into(); Messages::from_ptr( - unsafe { ffi::notmuch_thread_get_messages(threadref.handle.ptr) }, + unsafe { ffi::notmuch_thread_get_messages(threadref.ptr) }, ScopedSupercow::phantom(threadref), ) } diff --git a/src/threads.rs b/src/threads.rs index 6d1e8e4..0359e20 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -6,26 +6,24 @@ use Query; use utils::ScopedPhantomcow; -#[derive(Debug)] -pub(crate) struct ThreadsPtr { - pub ptr: *mut ffi::notmuch_threads_t, -} - -impl Drop for ThreadsPtr { - fn drop(&mut self) { - unsafe { ffi::notmuch_threads_destroy(self.ptr) }; - } -} - #[derive(Debug)] pub struct Threads<'d, 'q> where 'd: 'q { - handle: ThreadsPtr, + ptr: *mut ffi::notmuch_threads_t, marker: ScopedPhantomcow<'q, Query<'d>>, } +impl<'d, 'q> Drop for Threads<'d, 'q> +where + 'd: 'q, +{ + fn drop(&mut self) { + unsafe { ffi::notmuch_threads_destroy(self.ptr) }; + } +} + impl<'d, 'q> Threads<'d, 'q> where 'd: 'q, @@ -35,7 +33,7 @@ where P: Into>>, { Threads { - handle: ThreadsPtr { ptr }, + ptr, marker: owner.into(), } } @@ -48,15 +46,15 @@ where type Item = Thread<'d, 'q>; fn next(&mut self) -> Option { - let valid = unsafe { ffi::notmuch_threads_valid(self.handle.ptr) }; + let valid = unsafe { ffi::notmuch_threads_valid(self.ptr) }; if valid == 0 { return None; } let cthrd = unsafe { - let thrd = ffi::notmuch_threads_get(self.handle.ptr); - ffi::notmuch_threads_move_to_next(self.handle.ptr); + let thrd = ffi::notmuch_threads_get(self.ptr); + ffi::notmuch_threads_move_to_next(self.ptr); thrd }; -- cgit v1.2.1 From abc1c7835a904332654d8adce4b8a13b7a939775 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 20 Dec 2018 08:23:02 +0100 Subject: silence compiler warnings --- src/utils.rs | 2 +- tests/main.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils.rs b/src/utils.rs index 409534c..5bfb5d0 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,7 +1,7 @@ use libc; use std::{ffi, str}; -use supercow::{Supercow, DefaultFeatures, NonSyncFeatures}; +use supercow::{Supercow, DefaultFeatures/*, NonSyncFeatures*/}; use supercow::ext::{BoxedStorage}; pub trait ToStr { diff --git a/tests/main.rs b/tests/main.rs index 5789824..9ad0a36 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -3,7 +3,7 @@ extern crate notmuch; use std::sync::Arc; -use notmuch::{Query, QueryExt, Threads}; +use notmuch::{Query, QueryExt}; fn main() { let mut mail_path = dirs::home_dir().unwrap(); -- cgit v1.2.1 From 08df34cdc7574383d857f9ee9d76f4f3c4ae02b8 Mon Sep 17 00:00:00 2001 From: eaon Date: Sat, 22 Dec 2018 13:22:13 -0500 Subject: Add Maildir flag / tag syncing --- src/message.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/message.rs b/src/message.rs index 226d3b8..0013497 100644 --- a/src/message.rs +++ b/src/message.rs @@ -110,6 +110,14 @@ where pub fn remove_all_tags(self: &Self) -> Result<()> { unsafe { ffi::notmuch_message_remove_all_tags(self.ptr) }.as_result() } + + pub fn tags_to_maildir_flags(self: &Self) -> Result<()> { + unsafe { ffi::notmuch_message_tags_to_maildir_flags(self.ptr) }.as_result() + } + + pub fn maildir_flags_to_tags(self: &Self) -> Result<()> { + unsafe { ffi::notmuch_message_maildir_flags_to_tags(self.ptr) }.as_result() + } } pub trait MessageExt<'o, O> -- cgit v1.2.1 From 319d03f6d8b63a932c96c5a518a9c46030f60a98 Mon Sep 17 00:00:00 2001 From: rhn Date: Mon, 17 Dec 2018 13:42:35 +0000 Subject: Messages: test recursion --- src/messages.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/messages.rs b/src/messages.rs index 01e0ea4..dc0f59e 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -104,3 +104,35 @@ impl<'o, O> MessagesExt<'o, O> for Messages<'o, O> where O: MessageOwner + 'o {} unsafe impl<'o, O> Send for Messages<'o, O> where O: MessageOwner + 'o {} unsafe impl<'o, O> Sync for Messages<'o, O> where O: MessageOwner + 'o {} + +#[cfg(test)] +mod tests { + // This will not compile if ownership can't be subject to recursion + fn descend<'o, O: 'o + super::MessageOwner, T: Iterator>>(iter: T) + -> usize { + iter.map(|msg| descend(msg.replies()) ).count() + } + + use query::Query; + use database; + + #[test] + #[should_panic] // until test data is filled in + fn recurse() -> () { + match database::Database::open( + &String::new(), + database::DatabaseMode::ReadOnly, + ) { + /* This will not happen without test data, but will force the compiler to compile + * the descend function. + */ + Ok(db) => { + let q = Query::create(db, &String::new()).unwrap(); + descend::>(q.search_messages().unwrap()); + } + Err(err) => { + panic!("Got error while trying to open db: {:?}", err); + } + } + } +} -- cgit v1.2.1 From ceb1ed661f1769efd73bd519c909b4bb59aca488 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 23 Dec 2018 22:05:55 +0100 Subject: bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d04896d..6cbdfad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "notmuch" -version = "0.4.2" +version = "0.5.0" authors = ["Dirk Van Haerenborgh "] homepage = "https://github.com/vhdirk/notmuch-rs" repository = "https://github.com/vhdirk/notmuch-rs" -- cgit v1.2.1 From a2a415cde2bbf62f2d8351900e0fcd9373cb3d67 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 23 Dec 2018 22:14:39 +0100 Subject: remove streaming iterators from readme --- README.md | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 8f2e9e8..1fcbddf 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,6 @@ extern crate notmuch; ```rust extern crate notmuch; -use notmuch::StreamingIterator; fn main() { @@ -42,7 +41,7 @@ fn main() { let query = db.create_query("").unwrap(); let mut threads = query.search_threads().unwrap(); - while let Some(thread) = threads.next() { + for thread in threads { println!("thread {:?} {:?}", thread.subject(), thread.authors()); } } @@ -64,15 +63,16 @@ feel this is too permissive, let me know. All structs are strictly linked together with their lifetime. The root of the tree is ```Database```, which has a lifetime that must outlive any child objects, for instance ```Query```. The ```Threads``` iterator that you can get -from a ```Query``` is always outlived by the parent query. ```Threads``` in its -turn must have a longer life than ```Thread```, which in turn must outlive -```Messages``` and so on. Each structure keeps a ```PhantomData``` marker of its -owner. +from a ```Query``` is always outlived by the parent query. The ```Threads``` +does not own any individual ```Thread```. These are bound to the owner of +the ```Threads``` iterator itself. Each structure keeps a ```PhantomCow``` +marker for its owner. -Using this in an application poses significant difficulties in satisfying these -lifetime requirements. To alleviate this, ```notmuch-rs``` makes use of the -excellent [Supercow](https://crates.io/crates/supercow), so you don't have to -use crates like ```owningref``` or ```rental``` to get around this. +Typically, using a lifetimes structure like this in an application poses +significant difficulties in satisfying these lifetime requirements. While other +libraries force the application developers towards crates like ```owningref``` +or ```rental``` to get around this, ```notmuch-rs``` makes use of the +excellent [Supercow](https://crates.io/crates/supercow), to alleviate this. This way, you get to choose your own container type, and even keep the parent object alive so you don't have to juggle lifetimes. To use this, most types @@ -91,15 +91,6 @@ comparable. ``` -## Iterators - -Since the lifetime of a ```Thread``` or a ```Message``` is dependent on the -```Threads``` and ```Messages``` iterator respectively, using the regular rust -```Iterator``` trait proved impossible. As such, ```notmuch-rs``` includes a -```StreamingIterator``` (and additional ```StreamingIteratorExt```) trait that -is used to iterate while satisfying the lifetime constraints. - - ## Acknowledgements notmuch-rs started out from the following projects: -- cgit v1.2.1 From 5814ba78327e8194c4999c73d4334a4f840f75fa Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 18 Oct 2019 12:37:03 +0200 Subject: support updated toolchain --- Cargo.toml | 2 +- src/utils.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6cbdfad..5b8191c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ travis-ci = { repository = "vhdirk/notmuch-rs" } [dependencies] libc = "0.2" -clippy = { version = "0.0.193", optional = true } +# clippy = { version = "0.0.211", optional = true } supercow = "0.1.0" [dev-dependencies] diff --git a/src/utils.rs b/src/utils.rs index 5bfb5d0..022d508 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -30,11 +30,11 @@ impl ToString for *const libc::c_char { // BoxedStorage>; pub type ScopedPhantomcow<'a, OWNED, BORROWED = OWNED, - SHARED = Box + 'a>, + SHARED = Box + 'a>, STORAGE = BoxedStorage> = Supercow<'a, OWNED, BORROWED, SHARED, STORAGE, ()>; -pub type ScopedSupercow<'a, OWNED, BORROWED = OWNED, SHARED = Box + 'a>> = +pub type ScopedSupercow<'a, OWNED, BORROWED = OWNED, SHARED = Box + 'a>> = Supercow<'a, OWNED, BORROWED, SHARED, BoxedStorage>; -- cgit v1.2.1 From 469e67f7ac8e6fad605e03a22c2f0234674f66e6 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 18 Oct 2019 12:37:19 +0200 Subject: add database_find_message --- src/database.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/database.rs b/src/database.rs index 027a43f..d591575 100644 --- a/src/database.rs +++ b/src/database.rs @@ -15,6 +15,8 @@ use Directory; use Query; use Tags; use TagsOwner; +use Message; +use MessageOwner; use utils::ScopedSupercow; @@ -43,6 +45,7 @@ impl Drop for Database { } impl TagsOwner for Database {} +impl MessageOwner for Database {} impl Database { pub fn create

(path: &P) -> Result @@ -222,6 +225,11 @@ impl Database { ::all_tags(self) } + pub fn find_message<'d, P>(&'d self, message_id: &str) -> Result>> + { + ::find_message(self, message_id) + } + pub fn remove_message<'d, P>(&'d self, path: &P) -> Result<()> where P: AsRef, @@ -275,6 +283,25 @@ pub trait DatabaseExt { } } + fn find_message<'d, D>(database: D, message_id: &str) -> Result>> + where + D: Into> + { + let dbref = database.into(); + let message_id_str = CString::new(message_id).unwrap(); + + let mut msg = ptr::null_mut(); + unsafe { + ffi::notmuch_database_find_message(dbref.ptr, message_id_str.as_ptr(), &mut msg) + }.as_result()?; + + if msg.is_null() { + Ok(None) + } else { + Ok(Some(Message::from_ptr(msg, Supercow::phantom(dbref)))) + } + } + fn remove_message<'d, D, P>(database: D, path: &P) -> Result<()> where D: Into>, -- cgit v1.2.1 From eb2ba635b2e6e35af4791c569c924043acecc357 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 18 Oct 2019 12:37:42 +0200 Subject: message: minor cleanup --- src/message.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/message.rs b/src/message.rs index 0013497..2172713 100644 --- a/src/message.rs +++ b/src/message.rs @@ -124,9 +124,9 @@ pub trait MessageExt<'o, O> where O: MessageOwner + 'o, { - fn tags<'s, S>(message: S) -> Tags<'s, Message<'o, O>> + fn tags<'m, M>(message: M) -> Tags<'m, Message<'o, O>> where - S: Into>>, + M: Into>>, { let messageref = message.into(); Tags::from_ptr( @@ -146,9 +146,9 @@ where // ) // } - fn filenames<'s, S>(message: S) -> Filenames<'s, Message<'o, O>> + fn filenames<'m, M>(message: M) -> Filenames<'m, Message<'o, O>> where - S: Into>>, + M: Into>>, { let messageref = message.into(); Filenames::from_ptr( -- cgit v1.2.1 From cab95623832c0473228f5ad12272f2438620aa68 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 18 Oct 2019 12:38:37 +0200 Subject: messages: do not implement Drop for now --- src/messages.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/messages.rs b/src/messages.rs index dc0f59e..60a6f7d 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -16,14 +16,14 @@ where marker: ScopedPhantomcow<'o, O>, } -impl<'o, O> Drop for Messages<'o, O> -where - O: MessageOwner + 'o, -{ - fn drop(self: &mut Self) { - unsafe { ffi::notmuch_messages_destroy(self.ptr) }; - } -} +// impl<'o, O> Drop for Messages<'o, O> +// where +// O: MessageOwner + 'o, +// { +// fn drop(self: &mut Self) { +// unsafe { ffi::notmuch_messages_destroy(self.ptr) }; +// } +// } impl<'o, O> Messages<'o, O> where -- cgit v1.2.1 From 24936ad1d0a3489c766c819f2f824962c770cce0 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 18 Oct 2019 14:12:28 +0200 Subject: implement: database_index_message --- src/database.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++--- src/directory.rs | 2 +- src/ffi.rs | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/index.rs | 46 +++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 4 +++- 5 files changed, 164 insertions(+), 5 deletions(-) create mode 100644 src/index.rs diff --git a/src/database.rs b/src/database.rs index d591575..b6f68a0 100644 --- a/src/database.rs +++ b/src/database.rs @@ -17,6 +17,7 @@ use Tags; use TagsOwner; use Message; use MessageOwner; +use IndexOpts; use utils::ScopedSupercow; @@ -225,8 +226,7 @@ impl Database { ::all_tags(self) } - pub fn find_message<'d, P>(&'d self, message_id: &str) -> Result>> - { + pub fn find_message<'d>(&'d self, message_id: &str) -> Result>> { ::find_message(self, message_id) } @@ -236,6 +236,18 @@ impl Database { { ::remove_message(self, path) } + + pub fn get_default_indexopts<'d, P>(&'d self) -> Result> + { + ::get_default_indexopts(self) + } + + pub fn index_file<'d, P>(&'d self, path: &P, indexopts: Option>) -> Result>> + where + P: AsRef, + { + ::index_file(self, path, indexopts) + } } pub trait DatabaseExt { @@ -304,7 +316,7 @@ pub trait DatabaseExt { fn remove_message<'d, D, P>(database: D, path: &P) -> Result<()> where - D: Into>, + D: Into>, P: AsRef, { let dbref = database.into(); @@ -318,6 +330,45 @@ pub trait DatabaseExt { None => Err(Error::NotmuchError(Status::FileError)), } } + + fn get_default_indexopts<'d, D>(database: D) -> Result> + where + D: Into> + { + let dbref = database.into(); + + let opts = unsafe { ffi::notmuch_database_get_default_indexopts(dbref.ptr) }; + + Ok(IndexOpts::from_ptr(opts, ScopedSupercow::phantom(dbref))) + } + + + fn index_file<'d, D, P>(database: D, path: &P, indexopts: Option>) -> Result>> + where + D: Into>, + P: AsRef, + { + let dbref = database.into(); + + let opts = indexopts.map_or(ptr::null_mut(), |opt| opt.ptr); + + match path.as_ref().to_str() { + Some(path_str) => { + let msg_path = CString::new(path_str).unwrap(); + + let mut msg = ptr::null_mut(); + unsafe { ffi::notmuch_database_index_file(dbref.ptr, msg_path.as_ptr(), opts, &mut msg) } + .as_result()?; + + if msg.is_null() { + Ok(None) + } else { + Ok(Some(Message::from_ptr(msg, Supercow::phantom(dbref)))) + } + } + None => Err(Error::NotmuchError(Status::FileError)), + } + } } impl DatabaseExt for Database {} diff --git a/src/directory.rs b/src/directory.rs index 8f09ed7..1c8a3df 100644 --- a/src/directory.rs +++ b/src/directory.rs @@ -23,7 +23,7 @@ impl<'d> Drop for Directory<'d> { impl<'d> FilenamesOwner for Directory<'d> {} impl<'d> Directory<'d> { - pub fn from_ptr(ptr: *mut ffi::notmuch_directory_t, owner: O) -> Directory<'d> + pub(crate) fn from_ptr(ptr: *mut ffi::notmuch_directory_t, owner: O) -> Directory<'d> where O: Into>, { diff --git a/src/ffi.rs b/src/ffi.rs index 3874ae5..7533b06 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -112,6 +112,17 @@ notmuch_enum! { } } +notmuch_enum! { + #[repr(C)] + #[derive(Debug, Eq, PartialEq, Clone, Copy)] + pub enum notmuch_decryption_policy_t => DecryptionPolicy { + NOTMUCH_DECRYPT_FALSE => False, + NOTMUCH_DECRYPT_TRUE => True, + NOTMUCH_DECRYPT_AUTO => Auto, + NOTMUCH_DECRYPT_NOSTASH => NoStash + } +} + #[repr(C)] pub struct notmuch_database_t(c_void); #[repr(C)] @@ -1729,6 +1740,55 @@ extern "C" { /// @since libnotmuch 4.4 (notmuch 0.23) pub fn notmuch_config_list_destroy(config_list: *mut notmuch_config_list_t); + /// get the current default indexing options for a given database. + /// + /// This object will survive until the database itself is destroyed, + /// but the caller may also release it earlier with + /// notmuch_indexopts_destroy. + /// + /// This object represents a set of options on how a message can be + /// added to the index. At the moment it is a featureless stub. + /// + /// @since libnotmuch 5.1 (notmuch 0.26) + pub fn notmuch_database_get_default_indexopts(db: *mut notmuch_database_t) -> *mut notmuch_indexopts_t; + + + //// + //// Stating a policy about how to decrypt messages. + //// + //// See index.decrypt in notmuch-config(1) for more details. + //// + //// typedef enum { + //// NOTMUCH_DECRYPT_FALSE, + //// NOTMUCH_DECRYPT_TRUE, + //// NOTMUCH_DECRYPT_AUTO, + //// NOTMUCH_DECRYPT_NOSTASH, + //// } notmuch_decryption_policy_t; + //// + //// + //// Specify whether to decrypt encrypted parts while indexing. + //// + //// Be aware that the index is likely sufficient to reconstruct the + //// cleartext of the message itself, so please ensure that the notmuch + //// message index is adequately protected. DO NOT SET THIS FLAG TO TRUE + //// without considering the security of your index. + //// + //// @since libnotmuch 5.1 (notmuch 0.26) + pub fn notmuch_indexopts_set_decrypt_policy(options: *mut notmuch_indexopts_t, + decrypt_policy: notmuch_decryption_policy_t) -> notmuch_status_t; + + //// Return whether to decrypt encrypted parts while indexing. + //// see notmuch_indexopts_set_decrypt_policy. + //// + //// @since libnotmuch 5.1 (notmuch 0.26) + pub fn notmuch_indexopts_get_decrypt_policy(options: *const notmuch_indexopts_t) -> notmuch_decryption_policy_t; + + + /// Destroy a notmuch_indexopts_t object. + /// + /// @since libnotmuch 5.1 (notmuch 0.26) + pub fn notmuch_indexopts_destroy(options: *mut notmuch_indexopts_t); + /// interrogate the library for compile time features /// /// @since libnotmuch 4.4 (notmuch 0.23) diff --git a/src/index.rs b/src/index.rs new file mode 100644 index 0000000..41505b6 --- /dev/null +++ b/src/index.rs @@ -0,0 +1,46 @@ +use std::ops::Drop; +use supercow::Supercow; + +use error::{Error, Result}; +use ffi; +use ffi::DecryptionPolicy; +use Database; +use Filenames; +use FilenamesOwner; +use utils::{ScopedSupercow, ScopedPhantomcow}; + + +#[derive(Debug)] +pub struct IndexOpts<'d> { + pub(crate) ptr: *mut ffi::notmuch_indexopts_t, + marker: ScopedPhantomcow<'d, Database>, +} + +impl<'d> Drop for IndexOpts<'d> { + fn drop(&mut self) { + unsafe { ffi::notmuch_indexopts_destroy(self.ptr) }; + } +} + +impl<'d> IndexOpts<'d> { + pub fn from_ptr(ptr: *mut ffi::notmuch_indexopts_t, owner: O) -> IndexOpts<'d> + where + O: Into>, + { + IndexOpts { + ptr, + marker: owner.into(), + } + } + + pub fn set_decrypt_policy(self: &Self, decrypt_policy: DecryptionPolicy) -> Result<()> { + unsafe { ffi::notmuch_indexopts_set_decrypt_policy(self.ptr, decrypt_policy.into()) }.as_result() + } + + pub fn get_decrypt_policy(self: &Self) -> DecryptionPolicy { + unsafe { ffi::notmuch_indexopts_get_decrypt_policy(self.ptr)}.into() + } +} + +unsafe impl<'d> Send for IndexOpts<'d> {} +unsafe impl<'d> Sync for IndexOpts<'d> {} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index ef8cc33..2d43f21 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,7 @@ mod query; mod tags; mod thread; mod threads; +mod index; pub use database::{Database, DatabaseExt}; pub use directory::{Directory, DirectoryExt}; @@ -31,5 +32,6 @@ pub use query::{Query, QueryExt}; pub use tags::{Tags, TagsExt, TagsOwner}; pub use thread::{Thread, ThreadExt}; pub use threads::{Threads, ThreadsExt}; +pub use index::IndexOpts; -pub use ffi::{DatabaseMode, Sort}; \ No newline at end of file +pub use ffi::{DatabaseMode, Sort, DecryptionPolicy}; \ No newline at end of file -- cgit v1.2.1 From 9b0d6458bdac2d9cc99a0fc2abbfd11a2c7115d2 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 18 Oct 2019 15:11:26 +0200 Subject: query: implement add_tag_exclude --- src/ffi.rs | 2 +- src/query.rs | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ffi.rs b/src/ffi.rs index 7533b06..6075014 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -674,7 +674,7 @@ extern "C" { /// Add a tag that will be excluded from the query results by default. /// This exclusion will be overridden if this tag appears explicitly in /// the query. - pub fn notmuch_query_add_tag_exclude(query: *mut notmuch_query_t, tag: *const c_char); + pub fn notmuch_query_add_tag_exclude(query: *mut notmuch_query_t, tag: *const c_char) -> notmuch_status_t; /// Execute a query for threads, returning a `notmuch_threads_t` object /// which can be used to iterate over the results. The returned threads diff --git a/src/query.rs b/src/query.rs index 127a9ab..f9afed5 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,5 +1,6 @@ use std::ops::Drop; use std::ptr; +use std::ffi::{CStr, CString}; use supercow::{Phantomcow, Supercow}; @@ -78,6 +79,12 @@ impl<'d> Query<'d> { Ok(cnt) } + + pub fn add_tag_exclude(self: &Self, tag: &str) -> Result<()> + { + let tag_str = CString::new(tag).unwrap(); + unsafe { ffi::notmuch_query_add_tag_exclude(self.ptr, tag_str.as_ptr()) }.as_result() + } } pub trait QueryExt<'d> { -- cgit v1.2.1 From 5ad80a002ef0a2ace544faf058fe82b6cdd83fb0 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 18 Oct 2019 15:14:18 +0200 Subject: query: implement set_omit_excluded --- src/query.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/query.rs b/src/query.rs index f9afed5..0ea5268 100644 --- a/src/query.rs +++ b/src/query.rs @@ -6,7 +6,7 @@ use supercow::{Phantomcow, Supercow}; use error::Result; use ffi; -use ffi::Sort; +use ffi::{Sort, Exclude}; use Database; use Messages; use MessageOwner; @@ -85,6 +85,10 @@ impl<'d> Query<'d> { let tag_str = CString::new(tag).unwrap(); unsafe { ffi::notmuch_query_add_tag_exclude(self.ptr, tag_str.as_ptr()) }.as_result() } + + pub fn set_omit_excluded(self: &Self, omit_excluded: Exclude) { + unsafe { ffi::notmuch_query_set_omit_excluded(self.ptr, omit_excluded.into()) } + } } pub trait QueryExt<'d> { -- cgit v1.2.1 From cf3b912a94dd18cb3f5af664e11a0e2391d16b0b Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 18 Oct 2019 15:38:17 +0200 Subject: database: implement find_message_by_filename --- src/database.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/database.rs b/src/database.rs index b6f68a0..c26b5a8 100644 --- a/src/database.rs +++ b/src/database.rs @@ -230,6 +230,13 @@ impl Database { ::find_message(self, message_id) } + pub fn find_message_by_filename<'d, P>(&'d self, filename: &P) -> Result>> + where + P: AsRef, + { + ::find_message_by_filename(self, filename) + } + pub fn remove_message<'d, P>(&'d self, path: &P) -> Result<()> where P: AsRef, @@ -314,6 +321,26 @@ pub trait DatabaseExt { } } + fn find_message_by_filename<'d, D, P>(database: D, filename: &P) -> Result>> + where + D: Into>, + P: AsRef + { + let dbref = database.into(); + let path_str = CString::new(filename.as_ref().to_str().unwrap()).unwrap(); + + let mut msg = ptr::null_mut(); + unsafe { + ffi::notmuch_database_find_message_by_filename(dbref.ptr, path_str.as_ptr(), &mut msg) + }.as_result()?; + + if msg.is_null() { + Ok(None) + } else { + Ok(Some(Message::from_ptr(msg, Supercow::phantom(dbref)))) + } + } + fn remove_message<'d, D, P>(database: D, path: &P) -> Result<()> where D: Into>, -- cgit v1.2.1 From 1e4e67fde1a7c75c9a81312d71340801d0ee06d3 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 18 Oct 2019 16:09:48 +0200 Subject: message: implement reindex --- src/ffi.rs | 13 +++++++++++++ src/message.rs | 5 +++++ 2 files changed, 18 insertions(+) diff --git a/src/ffi.rs b/src/ffi.rs index 6075014..1e29783 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -1114,6 +1114,19 @@ extern "C" { message: *mut notmuch_message_t, ) -> *mut notmuch_filenames_t; + /// Re-index the e-mail corresponding to 'message' using the supplied index options + /// + /// Returns the status of the re-index operation. (see the return + /// codes documented in notmuch_database_index_file) + /// + /// After reindexing, the user should discard the message object passed + /// in here by calling notmuch_message_destroy, since it refers to the + /// original message, not to the reindexed message. + pub fn notmuch_message_reindex( + message: *mut notmuch_message_t, + indexopts: *mut notmuch_indexopts_t + ) -> notmuch_status_t; + /// Get a value of a flag for the email corresponding to 'message'. pub fn notmuch_message_get_flag( message: *mut notmuch_message_t, diff --git a/src/message.rs b/src/message.rs index 2172713..73727f9 100644 --- a/src/message.rs +++ b/src/message.rs @@ -11,6 +11,7 @@ use FilenamesOwner; use Messages; use Tags; use TagsOwner; +use IndexOpts; pub trait MessageOwner: Send + Sync {} @@ -118,6 +119,10 @@ where pub fn maildir_flags_to_tags(self: &Self) -> Result<()> { unsafe { ffi::notmuch_message_maildir_flags_to_tags(self.ptr) }.as_result() } + + pub fn reindex<'d>(self: &Self, indexopts: IndexOpts<'d>) -> Result<()> { + unsafe { ffi::notmuch_message_reindex(self.ptr, indexopts.ptr) }.as_result() + } } pub trait MessageExt<'o, O> -- cgit v1.2.1 From edf986b7888a97ad434f08c1900d5ae4356ec44a Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 23 Oct 2019 06:55:03 +0200 Subject: fix index_file and add freeze/thaw --- src/database.rs | 18 +++++++++++------- src/lib.rs | 4 +++- src/message.rs | 8 ++++++++ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/database.rs b/src/database.rs index c26b5a8..f3733ef 100644 --- a/src/database.rs +++ b/src/database.rs @@ -249,12 +249,20 @@ impl Database { ::get_default_indexopts(self) } - pub fn index_file<'d, P>(&'d self, path: &P, indexopts: Option>) -> Result>> + pub fn index_file<'d, P>(&'d self, path: &P, indexopts: Option>) -> Result> where P: AsRef, { ::index_file(self, path, indexopts) } + + pub fn begin_atomic(&self) -> Result<()> { + unsafe { ffi::notmuch_database_begin_atomic(self.ptr) }.as_result() + } + + pub fn end_atomic(&self) -> Result<()> { + unsafe { ffi::notmuch_database_end_atomic(self.ptr) }.as_result() + } } pub trait DatabaseExt { @@ -370,7 +378,7 @@ pub trait DatabaseExt { } - fn index_file<'d, D, P>(database: D, path: &P, indexopts: Option>) -> Result>> + fn index_file<'d, D, P>(database: D, path: &P, indexopts: Option>) -> Result> where D: Into>, P: AsRef, @@ -387,11 +395,7 @@ pub trait DatabaseExt { unsafe { ffi::notmuch_database_index_file(dbref.ptr, msg_path.as_ptr(), opts, &mut msg) } .as_result()?; - if msg.is_null() { - Ok(None) - } else { - Ok(Some(Message::from_ptr(msg, Supercow::phantom(dbref)))) - } + Ok(Message::from_ptr(msg, Supercow::phantom(dbref))) } None => Err(Error::NotmuchError(Status::FileError)), } diff --git a/src/lib.rs b/src/lib.rs index 2d43f21..0336e8a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,4 +34,6 @@ pub use thread::{Thread, ThreadExt}; pub use threads::{Threads, ThreadsExt}; pub use index::IndexOpts; -pub use ffi::{DatabaseMode, Sort, DecryptionPolicy}; \ No newline at end of file +pub use ffi::{DatabaseMode, Sort, DecryptionPolicy}; + +pub use utils::{ScopedSupercow, ScopedPhantomcow}; \ No newline at end of file diff --git a/src/message.rs b/src/message.rs index 73727f9..f5d0542 100644 --- a/src/message.rs +++ b/src/message.rs @@ -123,6 +123,14 @@ where pub fn reindex<'d>(self: &Self, indexopts: IndexOpts<'d>) -> Result<()> { unsafe { ffi::notmuch_message_reindex(self.ptr, indexopts.ptr) }.as_result() } + + pub fn freeze(self: &Self) -> Result<()> { + unsafe { ffi::notmuch_message_freeze(self.ptr) }.as_result() + } + + pub fn thaw(self: &Self) -> Result<()> { + unsafe { ffi::notmuch_message_thaw(self.ptr) }.as_result() + } } pub trait MessageExt<'o, O> -- cgit v1.2.1 From 6813fbb5226acfa53e30f41564bb41c93d808656 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 23 Oct 2019 12:18:44 +0200 Subject: add scopeable version of message.freeze/thaw --- src/database.rs | 2 +- src/index.rs | 2 +- src/lib.rs | 2 +- src/message.rs | 36 ++++++++++++++ tests/commands.rs | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 179 insertions(+), 3 deletions(-) create mode 100644 tests/commands.rs diff --git a/src/database.rs b/src/database.rs index f3733ef..c828bb2 100644 --- a/src/database.rs +++ b/src/database.rs @@ -395,7 +395,7 @@ pub trait DatabaseExt { unsafe { ffi::notmuch_database_index_file(dbref.ptr, msg_path.as_ptr(), opts, &mut msg) } .as_result()?; - Ok(Message::from_ptr(msg, Supercow::phantom(dbref))) + Ok(Message::from_ptr(msg, ScopedSupercow::phantom(dbref))) } None => Err(Error::NotmuchError(Status::FileError)), } diff --git a/src/index.rs b/src/index.rs index 41505b6..a672dfb 100644 --- a/src/index.rs +++ b/src/index.rs @@ -1,5 +1,5 @@ use std::ops::Drop; -use supercow::Supercow; +use supercow::{Supercow, Phantomcow}; use error::{Error, Result}; use ffi; diff --git a/src/lib.rs b/src/lib.rs index 0336e8a..f32ce95 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,7 +26,7 @@ pub use database::{Database, DatabaseExt}; pub use directory::{Directory, DirectoryExt}; pub use error::Error; pub use filenames::{Filenames, FilenamesOwner}; -pub use message::{Message, MessageExt, MessageOwner}; +pub use message::{Message, MessageExt, MessageOwner, FrozenMessage}; pub use messages::{Messages, MessagesExt}; pub use query::{Query, QueryExt}; pub use tags::{Tags, TagsExt, TagsOwner}; diff --git a/src/message.rs b/src/message.rs index f5d0542..77aecc3 100644 --- a/src/message.rs +++ b/src/message.rs @@ -175,3 +175,39 @@ impl<'o, O> MessageExt<'o, O> for Message<'o, O> where O: MessageOwner + 'o {} unsafe impl<'o, O> Send for Message<'o, O> where O: MessageOwner + 'o {} unsafe impl<'o, O> Sync for Message<'o, O> where O: MessageOwner + 'o {} + + +pub struct FrozenMessage<'m ,'o, O> +where + O: MessageOwner + 'o +{ + message: ScopedSupercow<'m, Message<'o, O>> +} + + +impl<'m, 'o, O> FrozenMessage<'m, 'o, O> +where + O: MessageOwner + 'o +{ + pub fn new(message: M) -> Result + where + M: Into>> + { + let msg = message.into(); + msg.freeze()?; + Ok(FrozenMessage{ + message: msg + }) + } +} + +impl<'m, 'o, O> Drop for FrozenMessage<'m, 'o, O> +where + O: MessageOwner + 'o +{ + fn drop(&mut self) { + let _ = self.message.thaw(); + } +} + + diff --git a/tests/commands.rs b/tests/commands.rs new file mode 100644 index 0000000..c9f9d60 --- /dev/null +++ b/tests/commands.rs @@ -0,0 +1,140 @@ +extern crate dirs; +extern crate notmuch; +extern crate supercow; + +use std::path::Path; +use std::sync::Arc; +use std::result::Result; +use supercow::Supercow; +use notmuch::ScopedSupercow; + +use notmuch::{ + Database, + DatabaseExt, + Query, + QueryExt, + Message, + FrozenMessage, + Error +}; + +#[derive(Debug)] +pub struct AtomicOperation<'d> { + database: ScopedSupercow<'d, Database>, +} + +impl<'d> AtomicOperation<'d> { + pub fn new(db: D) -> Result + where + D: Into>, + { + let database = db.into(); + database.begin_atomic()?; + Ok(AtomicOperation{ + database + }) + } +} + +impl<'d> Drop for AtomicOperation<'d> { + fn drop(&mut self) { + let _ = self.database.end_atomic(); + } +} + +/// Add a single file to the database +pub fn add_file<'d, D, P>(db: D, filename: &P) -> Result, Error> +where + D: Into>, + P: AsRef +{ + let mut database = db.into(); + + let _atomic = AtomicOperation::new(Supercow::share(&mut database)).unwrap(); + + match ::index_file(Supercow::share(&mut database), filename, None) { + Ok(msg) => { + + // scoped version of freezing a message + { + let _fmsg = FrozenMessage::new(&msg); + + + } + Ok(msg) + }, + Err(err) => { + Err(err) + } + } + + +} + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_add_file() { + + + + } +} + + + +// status = notmuch_database_index_file (notmuch, filename, indexing_cli_choices.opts, &message); +// switch (status) { +// /* Success. */ +// case NOTMUCH_STATUS_SUCCESS: +// state->added_messages++; +// notmuch_message_freeze (message); +// if (state->synchronize_flags) +// notmuch_message_maildir_flags_to_tags (message); + +// for (tag = state->new_tags; *tag != NULL; tag++) { +// if (strcmp ("unread", *tag) != 0 || +// ! notmuch_message_has_maildir_flag (message, 'S')) { +// notmuch_message_add_tag (message, *tag); +// } +// } + +// notmuch_message_thaw (message); +// break; +// /* Non-fatal issues (go on to next file). */ +// case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: +// if (state->synchronize_flags) +// notmuch_message_maildir_flags_to_tags (message); +// break; +// case NOTMUCH_STATUS_FILE_NOT_EMAIL: +// fprintf (stderr, "Note: Ignoring non-mail file: %s\n", filename); +// break; +// case NOTMUCH_STATUS_FILE_ERROR: +// /* Someone renamed/removed the file between scandir and now. */ +// state->vanished_files++; +// fprintf (stderr, "Unexpected error with file %s\n", filename); +// (void) print_status_database ("add_file", notmuch, status); +// break; +// /* Fatal issues. Don't process anymore. */ +// case NOTMUCH_STATUS_READ_ONLY_DATABASE: +// case NOTMUCH_STATUS_XAPIAN_EXCEPTION: +// case NOTMUCH_STATUS_OUT_OF_MEMORY: +// (void) print_status_database ("add_file", notmuch, status); +// goto DONE; +// default: +// INTERNAL_ERROR ("add_message returned unexpected value: %d", status); +// goto DONE; +// } + +// status = notmuch_database_end_atomic (notmuch); + +// DONE: +// if (message) +// notmuch_message_destroy (message); + +// return status; +// } + \ No newline at end of file -- cgit v1.2.1 From 51f063aaf2cab590a6cfe42e1da3f7bbd6423ba5 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 25 Oct 2019 09:12:59 +0200 Subject: add scopable atomic operation and configlist --- src/config_list.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/database.rs | 48 ++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 6 ++++-- 3 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 src/config_list.rs diff --git a/src/config_list.rs b/src/config_list.rs new file mode 100644 index 0000000..632603c --- /dev/null +++ b/src/config_list.rs @@ -0,0 +1,62 @@ +use std::ops::Drop; +use std::ffi::{CStr, CString}; +use supercow::Supercow; + +use ffi; +use Database; +use Filenames; +use FilenamesOwner; +use utils::{ScopedSupercow, ScopedPhantomcow}; + + +#[derive(Debug)] +pub struct ConfigList<'d> { + ptr: *mut ffi::notmuch_config_list_t, + marker: ScopedPhantomcow<'d, Database>, +} + +impl<'d> Drop for ConfigList<'d> { + fn drop(&mut self) { + unsafe { ffi::notmuch_config_list_destroy(self.ptr) }; + } +} + +impl<'d> ConfigList<'d> { + pub(crate) fn from_ptr(ptr: *mut ffi::notmuch_config_list_t, owner: O) -> ConfigList<'d> + where + O: Into>, + { + ConfigList { + ptr, + marker: owner.into(), + } + } +} + + +impl<'d> Iterator for ConfigList<'d> +{ + type Item = (String, String); + + fn next(&mut self) -> Option { + let valid = unsafe { ffi::notmuch_config_list_valid(self.ptr) }; + + if valid == 0 { + return None; + } + + let (k, v) = unsafe { + let key = CStr::from_ptr(ffi::notmuch_config_list_key(self.ptr)); + let value = CStr::from_ptr(ffi::notmuch_config_list_value(self.ptr)); + + ffi::notmuch_config_list_move_to_next(self.ptr); + + (key, value) + }; + + Some((k.to_str().unwrap().to_string(), v.to_str().unwrap().to_string())) + } +} + +unsafe impl<'d> Send for ConfigList<'d> {} +unsafe impl<'d> Sync for ConfigList<'d> {} diff --git a/src/database.rs b/src/database.rs index c828bb2..089976d 100644 --- a/src/database.rs +++ b/src/database.rs @@ -18,6 +18,7 @@ use TagsOwner; use Message; use MessageOwner; use IndexOpts; +use ConfigList; use utils::ScopedSupercow; @@ -218,6 +219,11 @@ impl Database { ::directory(self, path) } + pub fn get_config_list<'d>(&'d self, prefix: &str) -> Result> + { + ::get_config_list(self, prefix) + } + pub fn create_query<'d>(&'d self, query_string: &str) -> Result> { ::create_query(self, query_string) } @@ -310,6 +316,22 @@ pub trait DatabaseExt { } } + fn get_config_list<'d, D>(database: D, prefix: &str) -> Result> + where + D: Into> + { + let dbref = database.into(); + + let prefix_str = CString::new(prefix).unwrap(); + + let mut cfgs = ptr::null_mut(); + unsafe { + ffi::notmuch_database_get_config_list(dbref.ptr, prefix_str.as_ptr(), &mut cfgs) + }.as_result()?; + + Ok(ConfigList::from_ptr(cfgs, Supercow::phantom(dbref))) + } + fn find_message<'d, D>(database: D, message_id: &str) -> Result>> where D: Into> @@ -406,3 +428,29 @@ impl DatabaseExt for Database {} unsafe impl Send for Database {} unsafe impl Sync for Database {} + + +#[derive(Debug)] +pub struct AtomicOperation<'d> { + database: ScopedSupercow<'d, Database>, +} + +impl<'d> AtomicOperation<'d> { + pub fn new(db: D) -> Result + where + D: Into>, + { + let database = db.into(); + database.begin_atomic()?; + Ok(AtomicOperation{ + database + }) + } +} + +impl<'d> Drop for AtomicOperation<'d> { + fn drop(&mut self) { + let _ = self.database.end_atomic(); + } +} + diff --git a/src/lib.rs b/src/lib.rs index f32ce95..69bf015 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,8 +21,9 @@ mod tags; mod thread; mod threads; mod index; +mod config_list; -pub use database::{Database, DatabaseExt}; +pub use database::{Database, DatabaseExt, AtomicOperation}; pub use directory::{Directory, DirectoryExt}; pub use error::Error; pub use filenames::{Filenames, FilenamesOwner}; @@ -33,7 +34,8 @@ pub use tags::{Tags, TagsExt, TagsOwner}; pub use thread::{Thread, ThreadExt}; pub use threads::{Threads, ThreadsExt}; pub use index::IndexOpts; +pub use config_list::ConfigList; -pub use ffi::{DatabaseMode, Sort, DecryptionPolicy}; +pub use ffi::{Status, DatabaseMode, Sort, DecryptionPolicy}; pub use utils::{ScopedSupercow, ScopedPhantomcow}; \ No newline at end of file -- cgit v1.2.1 From 9d3eaa7aa7e2be84e150075fb12e97083d7c61f8 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 25 Oct 2019 09:52:00 +0200 Subject: implement message_properties --- src/lib.rs | 2 ++ src/message.rs | 20 +++++++++++++ src/message_properties.rs | 75 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 src/message_properties.rs diff --git a/src/lib.rs b/src/lib.rs index 69bf015..1eefaf2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,6 +22,7 @@ mod thread; mod threads; mod index; mod config_list; +mod message_properties; pub use database::{Database, DatabaseExt, AtomicOperation}; pub use directory::{Directory, DirectoryExt}; @@ -29,6 +30,7 @@ pub use error::Error; pub use filenames::{Filenames, FilenamesOwner}; pub use message::{Message, MessageExt, MessageOwner, FrozenMessage}; pub use messages::{Messages, MessagesExt}; +pub use message_properties::{MessageProperties}; pub use query::{Query, QueryExt}; pub use tags::{Tags, TagsExt, TagsOwner}; pub use thread::{Thread, ThreadExt}; diff --git a/src/message.rs b/src/message.rs index 77aecc3..b4eacc8 100644 --- a/src/message.rs +++ b/src/message.rs @@ -9,6 +9,7 @@ use utils::{ToStr, ScopedPhantomcow, ScopedSupercow}; use Filenames; use FilenamesOwner; use Messages; +use MessageProperties; use Tags; use TagsOwner; use IndexOpts; @@ -131,6 +132,11 @@ where pub fn thaw(self: &Self) -> Result<()> { unsafe { ffi::notmuch_message_thaw(self.ptr) }.as_result() } + + pub fn get_properties<'m>(&'m self, key: &str, exact: bool) -> MessageProperties<'m, 'o, O> + { + >::get_properties(self, key, exact) + } } pub trait MessageExt<'o, O> @@ -169,6 +175,20 @@ where Supercow::phantom(messageref), ) } + + fn get_properties<'m, M>(message: M, key: &str, exact: bool) -> MessageProperties<'m, 'o, O> + where + M: Into>>, + { + let messageref = message.into(); + let key_str = CString::new(key).unwrap(); + + let props = unsafe { + ffi::notmuch_message_get_properties(messageref.ptr, key_str.as_ptr(), exact as i32) + }; + + MessageProperties::from_ptr(props, Supercow::phantom(messageref)) + } } impl<'o, O> MessageExt<'o, O> for Message<'o, O> where O: MessageOwner + 'o {} diff --git a/src/message_properties.rs b/src/message_properties.rs new file mode 100644 index 0000000..2c2ceb0 --- /dev/null +++ b/src/message_properties.rs @@ -0,0 +1,75 @@ +use std::ops::Drop; +use std::ffi::{CStr, CString}; +use supercow::Supercow; + +use ffi; +use Message; +use MessageOwner; +use MessageExt; +use utils::{ScopedSupercow, ScopedPhantomcow}; + + +#[derive(Debug)] +pub struct MessageProperties<'m, 'o, O> +where + O: MessageOwner + 'o +{ + ptr: *mut ffi::notmuch_message_properties_t, + marker: ScopedPhantomcow<'m, Message<'o, O>>, +} + +impl<'m, 'o, O> Drop for MessageProperties<'m, 'o, O> +where + O: MessageOwner + 'o +{ + fn drop(&mut self) { + unsafe { ffi::notmuch_message_properties_destroy(self.ptr) }; + } +} + +impl<'m, 'o, O> MessageProperties<'m, 'o, O> +where + O: MessageOwner + 'o +{ + pub(crate) fn from_ptr(ptr: *mut ffi::notmuch_message_properties_t, owner: S) -> MessageProperties<'m, 'o, O> + where + S: Into>>, + { + MessageProperties { + ptr, + marker: owner.into(), + } + } +} + + +impl<'m, 'o, O> Iterator for MessageProperties<'m, 'o, O> +where + O: MessageOwner + 'o +{ + type Item = (String, String); + + fn next(&mut self) -> Option { + let valid = unsafe { ffi::notmuch_message_properties_valid(self.ptr) }; + + if valid == 0 { + return None; + } + + let (k, v) = unsafe { + let key = CStr::from_ptr(ffi::notmuch_message_properties_key(self.ptr)); + let value = CStr::from_ptr(ffi::notmuch_message_properties_value(self.ptr)); + + ffi::notmuch_message_properties_move_to_next(self.ptr); + + (key, value) + }; + + Some((k.to_str().unwrap().to_string(), v.to_str().unwrap().to_string())) + } +} + +unsafe impl<'m, 'o, O> Send for MessageProperties<'m, 'o, O> where + O: MessageOwner + 'o {} +unsafe impl<'m, 'o, O> Sync for MessageProperties<'m, 'o, O> where + O: MessageOwner + 'o {} -- cgit v1.2.1 From 03461235f381df7b22caa1bf8d1afac57079b189 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 25 Oct 2019 10:00:28 +0200 Subject: limit visibility of 'from_ptr' functions to crate --- src/filenames.rs | 2 +- src/index.rs | 2 +- src/message_properties.rs | 1 - src/tags.rs | 2 +- src/thread.rs | 2 +- src/threads.rs | 2 +- 6 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/filenames.rs b/src/filenames.rs index a4440d3..12e5857 100644 --- a/src/filenames.rs +++ b/src/filenames.rs @@ -30,7 +30,7 @@ impl<'o, O> Filenames<'o, O> where O: FilenamesOwner + 'o, { - pub fn from_ptr

(ptr: *mut ffi::notmuch_filenames_t, owner: P) -> Filenames<'o, O> + pub(crate) fn from_ptr

(ptr: *mut ffi::notmuch_filenames_t, owner: P) -> Filenames<'o, O> where P: Into>, { diff --git a/src/index.rs b/src/index.rs index a672dfb..ba89c1a 100644 --- a/src/index.rs +++ b/src/index.rs @@ -23,7 +23,7 @@ impl<'d> Drop for IndexOpts<'d> { } impl<'d> IndexOpts<'d> { - pub fn from_ptr(ptr: *mut ffi::notmuch_indexopts_t, owner: O) -> IndexOpts<'d> + pub(crate) fn from_ptr(ptr: *mut ffi::notmuch_indexopts_t, owner: O) -> IndexOpts<'d> where O: Into>, { diff --git a/src/message_properties.rs b/src/message_properties.rs index 2c2ceb0..4802383 100644 --- a/src/message_properties.rs +++ b/src/message_properties.rs @@ -5,7 +5,6 @@ use supercow::Supercow; use ffi; use Message; use MessageOwner; -use MessageExt; use utils::{ScopedSupercow, ScopedPhantomcow}; diff --git a/src/tags.rs b/src/tags.rs index ad8e421..3fb1613 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -28,7 +28,7 @@ impl<'o, O> Tags<'o, O> where O: TagsOwner + 'o, { - pub fn from_ptr

(ptr: *mut ffi::notmuch_tags_t, owner: P) -> Tags<'o, O> + pub(crate) fn from_ptr

(ptr: *mut ffi::notmuch_tags_t, owner: P) -> Tags<'o, O> where P: Into>, { diff --git a/src/thread.rs b/src/thread.rs index 9634a57..34cebd3 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -33,7 +33,7 @@ impl<'d, 'q> Thread<'d, 'q> where 'd: 'q { - pub fn from_ptr

(ptr: *mut ffi::notmuch_thread_t, owner: P) -> Thread<'d, 'q> + pub(crate) fn from_ptr

(ptr: *mut ffi::notmuch_thread_t, owner: P) -> Thread<'d, 'q> where P: Into>>, { diff --git a/src/threads.rs b/src/threads.rs index 0359e20..9adb2c5 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -28,7 +28,7 @@ impl<'d, 'q> Threads<'d, 'q> where 'd: 'q, { - pub fn from_ptr

(ptr: *mut ffi::notmuch_threads_t, owner: P) -> Threads<'d, 'q> + pub(crate) fn from_ptr

(ptr: *mut ffi::notmuch_threads_t, owner: P) -> Threads<'d, 'q> where P: Into>>, { -- cgit v1.2.1 From 422377021f9a15b30d297b6ead7864098d5b2c2d Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 25 Oct 2019 10:05:05 +0200 Subject: remove 'get_' from getter functions --- src/database.rs | 12 ++++++------ src/index.rs | 2 +- src/message.rs | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/database.rs b/src/database.rs index 089976d..53ba76b 100644 --- a/src/database.rs +++ b/src/database.rs @@ -219,9 +219,9 @@ impl Database { ::directory(self, path) } - pub fn get_config_list<'d>(&'d self, prefix: &str) -> Result> + pub fn config_list<'d>(&'d self, prefix: &str) -> Result> { - ::get_config_list(self, prefix) + ::config_list(self, prefix) } pub fn create_query<'d>(&'d self, query_string: &str) -> Result> { @@ -250,9 +250,9 @@ impl Database { ::remove_message(self, path) } - pub fn get_default_indexopts<'d, P>(&'d self) -> Result> + pub fn default_indexopts<'d, P>(&'d self) -> Result> { - ::get_default_indexopts(self) + ::default_indexopts(self) } pub fn index_file<'d, P>(&'d self, path: &P, indexopts: Option>) -> Result> @@ -316,7 +316,7 @@ pub trait DatabaseExt { } } - fn get_config_list<'d, D>(database: D, prefix: &str) -> Result> + fn config_list<'d, D>(database: D, prefix: &str) -> Result> where D: Into> { @@ -388,7 +388,7 @@ pub trait DatabaseExt { } } - fn get_default_indexopts<'d, D>(database: D) -> Result> + fn default_indexopts<'d, D>(database: D) -> Result> where D: Into> { diff --git a/src/index.rs b/src/index.rs index ba89c1a..f070020 100644 --- a/src/index.rs +++ b/src/index.rs @@ -37,7 +37,7 @@ impl<'d> IndexOpts<'d> { unsafe { ffi::notmuch_indexopts_set_decrypt_policy(self.ptr, decrypt_policy.into()) }.as_result() } - pub fn get_decrypt_policy(self: &Self) -> DecryptionPolicy { + pub fn decrypt_policy(self: &Self) -> DecryptionPolicy { unsafe { ffi::notmuch_indexopts_get_decrypt_policy(self.ptr)}.into() } } diff --git a/src/message.rs b/src/message.rs index b4eacc8..feafcb3 100644 --- a/src/message.rs +++ b/src/message.rs @@ -133,9 +133,9 @@ where unsafe { ffi::notmuch_message_thaw(self.ptr) }.as_result() } - pub fn get_properties<'m>(&'m self, key: &str, exact: bool) -> MessageProperties<'m, 'o, O> + pub fn properties<'m>(&'m self, key: &str, exact: bool) -> MessageProperties<'m, 'o, O> { - >::get_properties(self, key, exact) + >::properties(self, key, exact) } } @@ -176,7 +176,7 @@ where ) } - fn get_properties<'m, M>(message: M, key: &str, exact: bool) -> MessageProperties<'m, 'o, O> + fn properties<'m, M>(message: M, key: &str, exact: bool) -> MessageProperties<'m, 'o, O> where M: Into>>, { -- cgit v1.2.1 From 3f795961db8228da27bb4823fac2f68e57e7276a Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 13 Nov 2019 14:56:32 +0100 Subject: port tests from notmuch-python-cffi --- .travis.yml | 4 + Cargo.toml | 12 +- src/database.rs | 24 +++- src/query.rs | 7 + src/tags.rs | 12 +- tests/fixtures.rs | 216 +++++++++++++++++++++++++++++++ tests/lib.rs | 11 ++ tests/main.rs | 91 +++++++------ tests/test_database.rs | 337 +++++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 669 insertions(+), 45 deletions(-) create mode 100644 tests/fixtures.rs create mode 100644 tests/lib.rs create mode 100644 tests/test_database.rs diff --git a/.travis.yml b/.travis.yml index ab21b0a..b4c0414 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,11 @@ addons: apt: packages: - libnotmuch-dev + - notmuch + - git script: - cargo build --no-default-features --verbose --all + # clone notmuch to have mail corpora + - git clone git://git.notmuchmail.org/git/notmuch /tmp/notmuch - cargo test --no-default-features --verbose --all diff --git a/Cargo.toml b/Cargo.toml index 5b8191c..c88b049 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ repository = "https://github.com/vhdirk/notmuch-rs" description = "Rust interface and bindings for notmuch" license = "GPL-3.0+" readme = "README.md" +keywords = ["email", "notmuch"] [badges] travis-ci = { repository = "vhdirk/notmuch-rs" } @@ -18,13 +19,18 @@ supercow = "0.1.0" [dev-dependencies] dirs = "1.0" +tempfile = "3" +gethostname = "0.2.0" +maildir = "0.3.2" +lettre = "0.9.2" +lettre_email = "0.9.2" [features] v0_21 = [] v0_26 = ["v0_21"] default = ["v0_26"] - [[test]] -name = "main" -harness = false +name = "tests" +path = "tests/lib.rs" +harness = true \ No newline at end of file diff --git a/src/database.rs b/src/database.rs index 53ba76b..44ad040 100644 --- a/src/database.rs +++ b/src/database.rs @@ -6,6 +6,7 @@ use std::ptr; use supercow::Supercow; use libc; +use std::cmp::{PartialEq, PartialOrd, Ordering}; use error::{Error, Result}; use ffi; @@ -25,8 +26,6 @@ use utils::ScopedSupercow; // Re-exported under database module for pretty namespacin'. pub use ffi::DatabaseMode; -#[derive(Copy, Clone, Debug)] -pub struct Version(libc::c_uint); #[derive(Clone, Debug)] pub struct Revision { @@ -34,6 +33,21 @@ pub struct Revision { pub uuid: String, } +impl PartialEq for Revision { + fn eq(&self, other: &Revision) -> bool{ + self.uuid == other.uuid && self.revision == other.revision + } +} + +impl PartialOrd for Revision { + fn partial_cmp(&self, other: &Revision) -> Option{ + if self.uuid != other.uuid { + return None; + } + self.revision.partial_cmp(&other.revision) + } +} + #[derive(Debug)] pub struct Database { @@ -79,7 +93,7 @@ impl Database { }) } - pub fn close(&mut self) -> Result<()> { + pub fn close(&self) -> Result<()> { unsafe { ffi::notmuch_database_close(self.ptr) }.as_result()?; Ok(()) @@ -143,8 +157,8 @@ impl Database { ) } - pub fn version(&self) -> Version { - Version(unsafe { ffi::notmuch_database_get_version(self.ptr) }) + pub fn version(&self) -> u32 { + unsafe { ffi::notmuch_database_get_version(self.ptr) } } #[cfg(feature = "v0_21")] diff --git a/src/query.rs b/src/query.rs index 0ea5268..50b56e5 100644 --- a/src/query.rs +++ b/src/query.rs @@ -46,6 +46,13 @@ impl<'d> Query<'d> { ::create_query(db, query_string) } + pub fn query_string(self: &Self) -> String { + let qstring = unsafe { + CStr::from_ptr(ffi::notmuch_query_get_query_string(self.ptr)) + }; + qstring.to_str().unwrap().to_string() + } + /// Specify the sorting desired for this query. pub fn set_sort(self: &Self, sort: Sort) { unsafe { ffi::notmuch_query_set_sort(self.ptr, sort.into()) } diff --git a/src/tags.rs b/src/tags.rs index 3fb1613..40a45c8 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -1,3 +1,4 @@ +use std::cmp::PartialEq; use std::ffi::CStr; use std::iter::Iterator; use std::ops::Drop; @@ -11,7 +12,7 @@ pub trait TagsOwner {} pub struct Tags<'o, O> where O: TagsOwner + 'o, { - ptr: *mut ffi::notmuch_tags_t, + pub(crate) ptr: *mut ffi::notmuch_tags_t, marker: ScopedPhantomcow<'o, O>, } @@ -24,6 +25,15 @@ where } } +impl<'o, O> PartialEq for Tags<'o, O> +where + O: TagsOwner + 'o, +{ + fn eq(&self, other: &Self) -> bool { + self.ptr == other.ptr + } +} + impl<'o, O> Tags<'o, O> where O: TagsOwner + 'o, diff --git a/tests/fixtures.rs b/tests/fixtures.rs new file mode 100644 index 0000000..8887da8 --- /dev/null +++ b/tests/fixtures.rs @@ -0,0 +1,216 @@ +extern crate dirs; +extern crate tempfile; +extern crate notmuch; +extern crate gethostname; +extern crate maildir; +extern crate lettre; +extern crate lettre_email; + +use std::ffi::OsStr; +use std::io::{self, Result, Write}; +use std::fs::{self, File}; +use std::rc::Rc; +use std::path::{Path, PathBuf}; +use tempfile::{tempdir, tempdir_in, Builder, TempDir}; +use std::net::ToSocketAddrs; +use std::process::Command; +use std::time::{SystemTime, UNIX_EPOCH}; +use maildir::Maildir; +use lettre_email::{EmailBuilder, Header}; +use lettre::SendableEmail; + + +pub fn timestamp_ms() -> u128 { + let start = SystemTime::now(); + let time_since_epoch = start.duration_since(UNIX_EPOCH).unwrap(); + time_since_epoch.as_millis() +} + +// A basic test interface to a valid maildir directory. +// +// This creates a valid maildir and provides a simple mechanism to +// deliver test emails to it. It also writes a notmuch-config file +// in the top of the maildir. +pub struct MailBox { + root_dir: TempDir, + idcount: u32, + maildir: Maildir +} + +impl MailBox { + + // Creates a new maildir fixture. Since this is only used for tests, + // may just panic of something is wrong + pub fn new() -> Self { + + let root_dir = tempdir().unwrap(); + let root_path = root_dir.path().to_path_buf(); + + let tmp_path = root_path.join("tmp"); + fs::create_dir(&tmp_path).unwrap(); + + let cfg_fname = root_path.join("notmuch-config"); + let mut cfg_file = File::create(cfg_fname).unwrap(); + write!(cfg_file, r#" + [database] + path={tmppath} + [user] + name=Some Hacker + primary_email=dst@example.com + [new] + tags=unread;inbox; + ignore= + [search] + exclude_tags=deleted;spam; + [maildir] + synchronize_flags=true + [crypto] + gpg_path=gpg + "#, tmppath=root_path.to_string_lossy()).unwrap(); + + let maildir = Maildir::from(root_path.to_path_buf()); + maildir.create_dirs().unwrap(); + + Self { + root_dir, + idcount: 0, + maildir + } + } + + /// Return a new unique message ID + // fn next_msgid(&mut self) -> String{ + // let hostname = gethostname::gethostname(); + // let msgid = format!("{}@{}", self.idcount, hostname.to_string_lossy()); + // self.idcount += 1; + // msgid + // } + + pub fn path(&self) -> PathBuf + { + self.root_dir.path().into() + } + + pub fn hostname(&self) -> String { + let hname = gethostname::gethostname(); + hname.to_string_lossy().into() + } + + /// Deliver a new mail message in the mbox. + /// This does only adds the message to maildir, does not insert it + /// into the notmuch database. + /// returns a tuple of (msgid, pathname). + pub fn deliver(&self, + subject: Option, + body: Option, + to: Option, + from: Option, + headers: Vec<(String, String)>, + is_new: bool, // Move to new dir or cur dir? + keywords: Option>, // List of keywords or labels + seen: bool, // Seen flag (cur dir only) + replied: bool, // Replied flag (cur dir only) + flagged: bool) // Flagged flag (cur dir only) + -> Result<(String, PathBuf)> + { + + let mut builder = EmailBuilder::new(); + + if let Some(val) = subject { + builder = builder.subject(val); + } + if let Some(val) = body { + builder = builder.text(val); + } + builder = match to { + Some(val) => builder.to(val), + None => builder.to(format!("to@{}.localhost", self.hostname())) + }; + builder = match from { + Some(val) => builder.from(val), + None => builder.from(format!("from@{}.localhost", self.hostname())) + }; + + for h in headers.into_iter(){ + let hdr: Header = h.into(); + builder = builder.header(hdr); + } + + let msg:SendableEmail = builder.build().unwrap().into(); + + // not sure why lettre doesn't add the host suffix itself + let msg_id = msg.message_id().to_string() + ".lettre@localhost"; + let id = if is_new { + self.maildir.store_new(&msg.message_to_string().unwrap().as_bytes()).unwrap() + }else{ + let mut flags = String::from(""); + if flagged { + flags += "F"; + } + if replied { + flags += "R"; + } + if seen { + flags += "S"; + } + self.maildir.store_cur_with_flags(&msg.message_to_string().unwrap().as_bytes(), flags.as_str()).unwrap() + }; + + let mut msgpath = self.path(); + msgpath = if is_new { + msgpath.join("new") + } else { + msgpath.join("cur") + }; + + msgpath = msgpath.join(&id); + + Ok((msg_id, msgpath)) + } +} + +impl Drop for MailBox { + fn drop(&mut self) { + } +} + + +#[derive(Clone, Debug)] +pub struct NotmuchCommand { + maildir_path: PathBuf +} + +impl NotmuchCommand { + + /// Return a function which runs notmuch commands on our test maildir. + /// + /// This uses the notmuch-config file created by the ``maildir`` + /// fixture. + pub fn new(maildir_path: &PathBuf) -> Self { + Self { + maildir_path: maildir_path.clone() + } + } + + /// Run a notmuch comand. + /// + /// This function runs with a timeout error as many notmuch + /// commands may block if multiple processes are trying to open + /// the database in write-mode. It is all too easy to + /// accidentally do this in the unittests. + pub fn run(&self, args: I) -> Result<()> + where + I: IntoIterator, + S: AsRef + { + let cfg_fname = self.maildir_path.join("notmuch-config"); + + Command::new("notmuch").env("NOTMUCH_CONFIG", &cfg_fname) + .args(args) + .status()?; + Ok(()) + } + +} + + diff --git a/tests/lib.rs b/tests/lib.rs new file mode 100644 index 0000000..c5095f4 --- /dev/null +++ b/tests/lib.rs @@ -0,0 +1,11 @@ +extern crate dirs; +extern crate tempfile; +extern crate notmuch; +extern crate gethostname; +extern crate maildir; +extern crate lettre; +extern crate lettre_email; + +mod fixtures; +mod test_database; + diff --git a/tests/main.rs b/tests/main.rs index 9ad0a36..17db2bc 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -1,43 +1,62 @@ extern crate dirs; +extern crate tempfile; extern crate notmuch; +extern crate gethostname; +extern crate maildir; +extern crate lettre; +extern crate lettre_email; use std::sync::Arc; use notmuch::{Query, QueryExt}; -fn main() { - let mut mail_path = dirs::home_dir().unwrap(); - mail_path.push(".mail"); - - match notmuch::Database::open( - &mail_path.to_str().unwrap().to_string(), - notmuch::DatabaseMode::ReadOnly, - ) { - Ok(db) => { - #[cfg(feature = "v0_21")] - { - let rev = db.revision(); - println!("db revision: {:?}", rev); - } - let query = { - let dbr = Arc::new(db); - - notmuch::Query::create(dbr.clone(), &"".to_string()).unwrap() - }; - - // let mut threads = query.search_threads().unwrap(); - - // let mut threads = db.create_query(&"".to_string()).unwrap().search_threads().unwrap(); - - let mut threads = Arc::new(::search_threads(query).unwrap()); - - for thread in Arc::get_mut(&mut threads).unwrap() - { - println!("thread {:?} {:?}", thread.subject(), thread.authors()); - } - } - Err(err) => { - println!("Got error while trying to open db: {:?}", err); - } - } -} +mod fixtures; +use fixtures::{MailBox, NotmuchCommand}; + + + + +// fn main() { +// let mut mail_path = dirs::home_dir().unwrap(); +// mail_path.push(".mail"); + +// let md = MailBox::new(); +// let nmcmd = NotMuchCommand::new(md.path()); + +// match notmuch::Database::open( +// &mail_path.to_str().unwrap().to_string(), +// notmuch::DatabaseMode::ReadOnly, +// ) { +// Ok(db) => { +// #[cfg(feature = "v0_21")] +// { +// let rev = db.revision(); +// println!("db revision: {:?}", rev); +// } +// let query = { +// let dbr = Arc::new(db); + +// notmuch::Query::create(dbr.clone(), &"".to_string()).unwrap() +// }; + +// // let mut threads = query.search_threads().unwrap(); + +// // let mut threads = db.create_query(&"".to_string()).unwrap().search_threads().unwrap(); + +// let mut threads = Arc::new(::search_threads(query).unwrap()); + +// for thread in Arc::get_mut(&mut threads).unwrap() +// { +// println!("thread {:?} {:?}", thread.subject(), thread.authors()); +// } +// } +// Err(err) => { +// println!("Got error while trying to open db: {:?}", err); +// } +// } +// } + + + + + diff --git a/tests/test_database.rs b/tests/test_database.rs new file mode 100644 index 0000000..96d9bcc --- /dev/null +++ b/tests/test_database.rs @@ -0,0 +1,337 @@ +use fixtures::{NotmuchCommand, MailBox}; + +// #[test] +// // fn test_config_pathname_default(){ + +// // monkeypatch.delenv('NOTMUCH_CONFIG', raising=False) +// // user = pathlib.Path('~/.notmuch-config').expanduser() +// // assert dbmod._config_pathname() == user + +// // } + +mod database { + + use super::*; + + #[test] + fn test_create(){ + let mailbox = MailBox::new(); + let db = notmuch::Database::create(&mailbox.path()); + assert!(db.is_ok()); + + assert!(mailbox.path().join(".notmuch/xapian").exists()); + } + + #[test] + fn test_create_already_open(){ + let mailbox = MailBox::new(); + let db1 = notmuch::Database::create(&mailbox.path()); + assert!(db1.is_ok()); + + let db2 = notmuch::Database::create(&mailbox.path()); + assert!(db2.is_err()); + } + + + #[test] + fn test_create_existing(){ + let mailbox = MailBox::new(); + notmuch::Database::create(&mailbox.path()).unwrap(); + + let db2 = notmuch::Database::create(&mailbox.path()); + assert!(db2.is_err()); + } + + + #[test] + fn test_close(){ + let mailbox = MailBox::new(); + let db = notmuch::Database::create(&mailbox.path()).unwrap(); + + assert!(db.close().is_ok()); + } + + #[test] + fn test_drop_noclose(){ + let mailbox = MailBox::new(); + let db = notmuch::Database::create(&mailbox.path()).unwrap(); + + drop(db); + } + + #[test] + fn test_close_drop(){ + let mailbox = MailBox::new(); + let db = notmuch::Database::create(&mailbox.path()).unwrap(); + db.close().unwrap(); + drop(db); + } + + #[test] + fn test_path(){ + let mailbox = MailBox::new(); + let db = notmuch::Database::create(&mailbox.path()).unwrap(); + assert!(db.path() == mailbox.path()); + } + + #[test] + fn test_version(){ + let mailbox = MailBox::new(); + let db = notmuch::Database::create(&mailbox.path()).unwrap(); + assert!(db.version() > 0); + } + +} + + +mod atomic { + use super::*; + + // TODO: how do I test this?? + +} + + +mod revision { + use super::*; + + #[test] + fn test_single_rev(){ + let mailbox = MailBox::new(); + let db = notmuch::Database::create(&mailbox.path()).unwrap(); + + let rev0 = db.revision(); + let rev1 = db.revision(); + + assert!(rev0 == rev1); + assert!(rev0 <= rev1); + assert!(rev0 >= rev1); + assert!(!(rev0 < rev1)); + assert!(!(rev0 > rev1)); + } + + #[test] + fn test_diff_db(){ + let mailbox0 = MailBox::new(); + let db0 = notmuch::Database::create(&mailbox0.path()).unwrap(); + let rev0 = db0.revision(); + + + let mailbox1 = MailBox::new(); + let db1 = notmuch::Database::create(&mailbox1.path()).unwrap(); + let rev1 = db1.revision(); + + assert!(rev0 != rev1); + assert!(rev0.uuid != rev1.uuid); + } + + #[test] + fn test_cmp(){ + let mailbox = MailBox::new(); + let db = notmuch::Database::create(&mailbox.path()).unwrap(); + + let rev0 = db.revision(); + + let (_, filename) = mailbox.deliver(None, None, None, None, vec![], true, None, false, false, false).unwrap(); + + db.index_file(&filename, None).unwrap(); + + let rev1 = db.revision(); + + assert!(rev0 < rev1); + assert!(rev0 <= rev1); + assert!(!(rev0 > rev1)); + assert!(!(rev0 >= rev1)); + assert!(!(rev0 == rev1)); + assert!(rev0 != rev1); + + + } + + // TODO: add tests for revisions comparisons + +} + + +mod messages { + use super::*; + + #[test] + fn test_add_message() { + let mailbox = MailBox::new(); + let db = notmuch::Database::create(&mailbox.path()).unwrap(); + + let (msgid, filename) = mailbox.deliver(None, None, None, None, vec![], true, None, false, false, false).unwrap(); + let msg = db.index_file(&filename, None).unwrap(); + + assert!(msg.filename() == filename); + assert!(msg.id() == msgid); + + } + + #[test] + fn test_remove_message() { + let mailbox = MailBox::new(); + let db = notmuch::Database::create(&mailbox.path()).unwrap(); + + let (msgid, filename) = mailbox.deliver(None, None, None, None, vec![], true, None, false, false, false).unwrap(); + let msg = db.index_file(&filename, None).unwrap(); + assert!(db.find_message(&msgid).unwrap().is_some()); + + db.remove_message(&filename).unwrap(); + assert!(db.find_message(&msgid).unwrap().is_none()); + } + + #[test] + fn test_find_message() { + let mailbox = MailBox::new(); + let db = notmuch::Database::create(&mailbox.path()).unwrap(); + + let (msgid, filename) = mailbox.deliver(None, None, None, None, vec![], true, None, false, false, false).unwrap(); + let msg0 = db.index_file(&filename, None).unwrap(); + + let msg1 = db.find_message(&msgid).unwrap().unwrap(); + assert!(msg0.id() == msgid); + assert!(msg0.id() == msg1.id()); + + assert!(msg0.filename() == filename); + assert!(msg0.filename() == msg1.filename()); + } + + #[test] + fn test_find_message_notfound() { + let mailbox = MailBox::new(); + let db = notmuch::Database::create(&mailbox.path()).unwrap(); + + assert!(db.find_message(&"foo").unwrap().is_none()); + } + +} + +mod tags { + use super::*; + + #[test] + fn test_none() { + let mailbox = MailBox::new(); + let db = notmuch::Database::create(&mailbox.path()).unwrap(); + + let tags = db.all_tags().unwrap(); + + assert!(tags.count() == 0); + } + + #[test] + fn test_some() { + let mailbox = MailBox::new(); + let db = notmuch::Database::create(&mailbox.path()).unwrap(); + let (_, filename) = mailbox.deliver(None, None, None, None, vec![], true, None, false, false, false).unwrap(); + let msg = db.index_file(&filename, None).unwrap(); + + msg.add_tag(&"hello").unwrap(); + let tags: Vec = db.all_tags().unwrap().collect(); + + assert!(tags.len() == 1); + assert!(tags.iter().any(|x| x == "hello")); + } + + #[test] + fn test_iters() { + let mailbox = MailBox::new(); + let db = notmuch::Database::create(&mailbox.path()).unwrap(); + + let t1: Vec = db.all_tags().unwrap().collect(); + let t2: Vec = db.all_tags().unwrap().collect(); + assert!(t1 == t2); + } + +} + +struct PopulatedDatabase { + // Return a read-write Database. + // The database will have 3 messages, 2 threads. + + pub mailbox: MailBox, + pub database: notmuch::Database, +} + +impl PopulatedDatabase { + pub fn new() -> Self{ + let mailbox = MailBox::new(); + + let (msgid, _) = mailbox.deliver(None, Some("foo".to_string()), None, None, vec![], true, None, false, false, false).unwrap(); + mailbox.deliver(None, Some("bar".to_string()), None, None, vec![], true, None, false, false, false).unwrap(); + mailbox.deliver(None, Some("baz".to_string()), None, None, vec![("In-Reply-To".to_string(), format!("<{}>", msgid))], true, None, false, false, false).unwrap(); + + let cmd = NotmuchCommand::new(&mailbox.path()); + cmd.run(vec!["new"]).unwrap(); + + let database = notmuch::Database::open(&mailbox.path(), notmuch::DatabaseMode::ReadWrite).unwrap(); + + Self { + mailbox, + database + } + } +} + +mod query { + use super::*; + + #[test] + fn test_count_messages() { + let db = PopulatedDatabase::new(); + + let query = db.database.create_query("*").unwrap(); + assert!(query.count_messages().unwrap() == 3); + } + + #[test] + fn test_message_no_results() { + let db = PopulatedDatabase::new(); + + let query = db.database.create_query("not_a_matching_query").unwrap(); + let mut messages = query.search_messages().unwrap(); + let msg = messages.next(); + assert!(msg.is_none()); + } + + #[test] + fn test_message_match() { + let db = PopulatedDatabase::new(); + + let query = db.database.create_query("*").unwrap(); + let mut messages = query.search_messages().unwrap(); + let msg = messages.next(); + assert!(msg.is_some()); + } + + #[test] + fn test_count_threads() { + let db = PopulatedDatabase::new(); + + let query = db.database.create_query("*").unwrap(); + assert!(query.count_threads().unwrap() == 2); + } + + #[test] + fn test_threads_no_results() { + let db = PopulatedDatabase::new(); + + let query = db.database.create_query("not_a_matching_query").unwrap(); + let mut threads = query.search_threads().unwrap(); + let thrd = threads.next(); + assert!(thrd.is_none()); + } + + #[test] + fn test_threads_match() { + let db = PopulatedDatabase::new(); + + let query = db.database.create_query("*").unwrap(); + let mut threads = query.search_threads().unwrap(); + let thrd = threads.next(); + assert!(thrd.is_some()); + } +} + -- cgit v1.2.1 From a129dafb25dc5fd22302ae769af9d9c441a8e687 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 13 Nov 2019 15:15:57 +0100 Subject: make revision tests optional --- tests/test_database.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_database.rs b/tests/test_database.rs index 96d9bcc..09dcd3c 100644 --- a/tests/test_database.rs +++ b/tests/test_database.rs @@ -92,6 +92,7 @@ mod atomic { } +#[cfg(feature = "v0_21")] mod revision { use super::*; -- cgit v1.2.1 From 1e060f14736922bfbd065a2ac611c64b9e2f5104 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 13 Nov 2019 15:20:48 +0100 Subject: update travis dist --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index b4c0414..5099a5d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ +dist: bionic language: rust sudo: false rust: -- cgit v1.2.1 From cc6896cca0839f5d97c5daee8ffba824c3c0d229 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 14 Nov 2019 19:22:38 +0100 Subject: add more tests --- .travis.yml | 11 +- Cargo.toml | 1 + src/ffi.rs | 18 +++ src/message.rs | 65 +++++++++- src/thread.rs | 4 + tests/fixtures.rs | 18 +-- tests/lib.rs | 2 + tests/test_database.rs | 44 +++---- tests/test_message.rs | 316 +++++++++++++++++++++++++++++++++++++++++++++++++ tests/test_thread.rs | 108 +++++++++++++++++ 10 files changed, 551 insertions(+), 36 deletions(-) create mode 100644 tests/test_message.rs create mode 100644 tests/test_thread.rs diff --git a/.travis.yml b/.travis.yml index 5099a5d..26d147c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,14 @@ dist: bionic language: rust -sudo: false +sudo: required rust: - stable - beta - nightly +# Cache cargo symbols for faster build +cache: cargo + addons: apt: packages: @@ -13,6 +16,12 @@ addons: - notmuch - git +before_script: + - export PATH=$HOME/.cargo/bin:$PATH + - cargo install cargo-update || echo "cargo-update already installed" + - cargo install cargo-travis || echo "cargo-travis already installed" + - cargo install-update -a # update outdated cached binaries + script: - cargo build --no-default-features --verbose --all # clone notmuch to have mail corpora diff --git a/Cargo.toml b/Cargo.toml index c88b049..f51bda2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ description = "Rust interface and bindings for notmuch" license = "GPL-3.0+" readme = "README.md" keywords = ["email", "notmuch"] +autotests = false [badges] travis-ci = { repository = "vhdirk/notmuch-rs" } diff --git a/src/ffi.rs b/src/ffi.rs index 1e29783..5dc93aa 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -1484,6 +1484,24 @@ extern "C" { exact: notmuch_bool_t, ) -> *mut notmuch_message_properties_t; + + /// Return the number of properties named "key" belonging to the specific message. + /// + /// @param[in] message The message to examine + /// @param[in] key key to count + /// @param[out] count The number of matching properties associated with this message. + /// + /// @returns + /// + /// NOTMUCH_STATUS_SUCCESS: successful count, possibly some other error. + /// + /// @since libnotmuch 5.2 (notmuch 0.27) + pub fn notmuch_message_count_properties( + message: *mut notmuch_message_t, + key: *const c_char, + count: *mut c_uint, + ) -> notmuch_status_t; + /// Is the given *properties* iterator pointing at a valid `(key,value)` pair. /// /// When this function returns TRUE, `notmuch_message_properties_{key,value}` diff --git a/src/message.rs b/src/message.rs index feafcb3..03623a1 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,6 +1,7 @@ -use std::ffi::CString; +use std::ffi::{CString, CStr}; use std::path::PathBuf; use std::cell::RefCell; +use std::ptr; use supercow::{Supercow}; use error::{Error, Result}; @@ -29,6 +30,16 @@ impl<'o, O> MessageOwner for Message<'o, O> where O: MessageOwner + 'o {} impl<'o, O> FilenamesOwner for Message<'o, O> where O: MessageOwner + 'o {} impl<'o, O> TagsOwner for Message<'o, O> where O: MessageOwner + 'o {} + +// impl<'o, O> PartialEq for Message<'o, O> +// where +// O: MessageOwner + 'o +// { +// fn eq(self: &Self, other: &Message<'o, O>) -> bool{ +// self.id() == other.id() +// } +// } + impl<'o, O> Message<'o, O> where O: MessageOwner + 'o, @@ -137,6 +148,58 @@ where { >::properties(self, key, exact) } + + pub fn remove_all_properties(&self, key: &str) -> Result<()> + { + let key_str = CString::new(key).unwrap(); + unsafe { + ffi::notmuch_message_remove_all_properties(self.ptr, key_str.as_ptr()) + }.as_result() + } + + pub fn count_properties(&self, key: &str) -> Result + { + let key_str = CString::new(key).unwrap(); + let mut cnt = 0; + unsafe { + ffi::notmuch_message_count_properties(self.ptr, key_str.as_ptr(), &mut cnt) + }.as_result()?; + + Ok(cnt) + } + + pub fn property(&self, key: &str, exact: bool) -> Result + { + let key_str = CString::new(key).unwrap(); + let mut prop = ptr::null(); + unsafe { + ffi::notmuch_message_get_property(self.ptr, key_str.as_ptr(), &mut prop) + }.as_result()?; + + // TODO: the unwrap here is not good + Ok(unsafe{ + CStr::from_ptr(prop) + }.to_str().unwrap().to_string()) + } + + pub fn add_property(&self, key: &str, value: &str) -> Result<()> + { + let key_str = CString::new(key).unwrap(); + let value_str = CString::new(value).unwrap(); + unsafe { + ffi::notmuch_message_add_property(self.ptr, key_str.as_ptr(), value_str.as_ptr()) + }.as_result() + } + + pub fn remove_property(&self, key: &str, value: &str) -> Result<()> + { + let key_str = CString::new(key).unwrap(); + let value_str = CString::new(value).unwrap(); + unsafe { + ffi::notmuch_message_remove_property(self.ptr, key_str.as_ptr(), value_str.as_ptr()) + }.as_result() + } + } pub trait MessageExt<'o, O> diff --git a/src/thread.rs b/src/thread.rs index 34cebd3..1ebcc24 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -61,6 +61,10 @@ where >::toplevel_messages(self) } + pub fn matched_messages(self: &Self) -> i32 { + unsafe { ffi::notmuch_thread_get_matched_messages(self.ptr) } + } + /// Get a `Messages` iterator for all messages in 'thread' in /// oldest-first order. pub fn messages(self: &Self) -> Messages<'_, Self> { diff --git a/tests/fixtures.rs b/tests/fixtures.rs index 8887da8..c9e04c8 100644 --- a/tests/fixtures.rs +++ b/tests/fixtures.rs @@ -114,22 +114,16 @@ impl MailBox { -> Result<(String, PathBuf)> { - let mut builder = EmailBuilder::new(); + let mut builder = EmailBuilder::new() + .subject(subject.unwrap_or_else(|| "Test mail".to_string())); + - if let Some(val) = subject { - builder = builder.subject(val); - } if let Some(val) = body { builder = builder.text(val); } - builder = match to { - Some(val) => builder.to(val), - None => builder.to(format!("to@{}.localhost", self.hostname())) - }; - builder = match from { - Some(val) => builder.from(val), - None => builder.from(format!("from@{}.localhost", self.hostname())) - }; + + builder = builder.to(to.unwrap_or_else(|| "to@example.com".to_string())) + .from(from.unwrap_or_else(|| "src@example.com".to_string())); for h in headers.into_iter(){ let hdr: Header = h.into(); diff --git a/tests/lib.rs b/tests/lib.rs index c5095f4..bd3138d 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -8,4 +8,6 @@ extern crate lettre_email; mod fixtures; mod test_database; +mod test_thread; +mod test_message; diff --git a/tests/test_database.rs b/tests/test_database.rs index 09dcd3c..557e0c3 100644 --- a/tests/test_database.rs +++ b/tests/test_database.rs @@ -71,7 +71,7 @@ mod database { fn test_path(){ let mailbox = MailBox::new(); let db = notmuch::Database::create(&mailbox.path()).unwrap(); - assert!(db.path() == mailbox.path()); + assert_eq!(db.path(), mailbox.path()); } #[test] @@ -122,8 +122,8 @@ mod revision { let db1 = notmuch::Database::create(&mailbox1.path()).unwrap(); let rev1 = db1.revision(); - assert!(rev0 != rev1); - assert!(rev0.uuid != rev1.uuid); + assert_ne!(rev0, rev1); + assert_ne!(rev0.uuid, rev1.uuid); } #[test] @@ -165,8 +165,8 @@ mod messages { let (msgid, filename) = mailbox.deliver(None, None, None, None, vec![], true, None, false, false, false).unwrap(); let msg = db.index_file(&filename, None).unwrap(); - assert!(msg.filename() == filename); - assert!(msg.id() == msgid); + assert_eq!(msg.filename(), filename); + assert_eq!(msg.id(), msgid); } @@ -192,11 +192,11 @@ mod messages { let msg0 = db.index_file(&filename, None).unwrap(); let msg1 = db.find_message(&msgid).unwrap().unwrap(); - assert!(msg0.id() == msgid); - assert!(msg0.id() == msg1.id()); + assert_eq!(msg0.id(), msgid); + assert_eq!(msg0.id(), msg1.id()); - assert!(msg0.filename() == filename); - assert!(msg0.filename() == msg1.filename()); + assert_eq!(msg0.filename(), filename); + assert_eq!(msg0.filename(), msg1.filename()); } #[test] @@ -219,7 +219,7 @@ mod tags { let tags = db.all_tags().unwrap(); - assert!(tags.count() == 0); + assert_eq!(tags.count(), 0); } #[test] @@ -232,7 +232,7 @@ mod tags { msg.add_tag(&"hello").unwrap(); let tags: Vec = db.all_tags().unwrap().collect(); - assert!(tags.len() == 1); + assert_eq!(tags.len(), 1); assert!(tags.iter().any(|x| x == "hello")); } @@ -243,12 +243,12 @@ mod tags { let t1: Vec = db.all_tags().unwrap().collect(); let t2: Vec = db.all_tags().unwrap().collect(); - assert!(t1 == t2); + assert_eq!(t1, t2); } } -struct PopulatedDatabase { +struct DatabaseFixture { // Return a read-write Database. // The database will have 3 messages, 2 threads. @@ -256,7 +256,7 @@ struct PopulatedDatabase { pub database: notmuch::Database, } -impl PopulatedDatabase { +impl DatabaseFixture { pub fn new() -> Self{ let mailbox = MailBox::new(); @@ -281,15 +281,15 @@ mod query { #[test] fn test_count_messages() { - let db = PopulatedDatabase::new(); + let db = DatabaseFixture::new(); let query = db.database.create_query("*").unwrap(); - assert!(query.count_messages().unwrap() == 3); + assert_eq!(query.count_messages().unwrap(), 3); } #[test] fn test_message_no_results() { - let db = PopulatedDatabase::new(); + let db = DatabaseFixture::new(); let query = db.database.create_query("not_a_matching_query").unwrap(); let mut messages = query.search_messages().unwrap(); @@ -299,7 +299,7 @@ mod query { #[test] fn test_message_match() { - let db = PopulatedDatabase::new(); + let db = DatabaseFixture::new(); let query = db.database.create_query("*").unwrap(); let mut messages = query.search_messages().unwrap(); @@ -309,15 +309,15 @@ mod query { #[test] fn test_count_threads() { - let db = PopulatedDatabase::new(); + let db = DatabaseFixture::new(); let query = db.database.create_query("*").unwrap(); - assert!(query.count_threads().unwrap() == 2); + assert_eq!(query.count_threads().unwrap(), 2); } #[test] fn test_threads_no_results() { - let db = PopulatedDatabase::new(); + let db = DatabaseFixture::new(); let query = db.database.create_query("not_a_matching_query").unwrap(); let mut threads = query.search_threads().unwrap(); @@ -327,7 +327,7 @@ mod query { #[test] fn test_threads_match() { - let db = PopulatedDatabase::new(); + let db = DatabaseFixture::new(); let query = db.database.create_query("*").unwrap(); let mut threads = query.search_threads().unwrap(); diff --git a/tests/test_message.rs b/tests/test_message.rs new file mode 100644 index 0000000..ce86df0 --- /dev/null +++ b/tests/test_message.rs @@ -0,0 +1,316 @@ +use std::sync::Arc; +use std::path::PathBuf; +use fixtures::MailBox; + +struct MessageFixture { + // Return a single thread with 2 messages + pub mailbox: MailBox, + pub database: Arc, + pub maildir_msg: (String, PathBuf), + pub message: notmuch::Message<'static, notmuch::Database>, +} + +impl MessageFixture { + pub fn new() -> Self{ + let mailbox = MailBox::new(); + + let (msgid, filename) = mailbox.deliver(None, None, None, None, vec![], true, None, false, false, false).unwrap(); + + let database = Arc::new(notmuch::Database::create(&mailbox.path()).unwrap()); + let message = ::index_file(database.clone(), &filename, None).unwrap(); + + Self { + mailbox, + database, + maildir_msg: (msgid, filename), + message + } + } +} + +mod message { + + use super::*; + + #[test] + fn test_messageid() { + let msg = MessageFixture::new(); + let copy = ::find_message_by_filename(msg.database.clone(), &msg.message.filename()).unwrap().unwrap(); + assert_eq!(msg.message.id(), copy.id()) + } + + #[test] + fn test_messageid_find() { + let msg = MessageFixture::new(); + let copy = ::find_message(msg.database.clone(), &msg.message.id()).unwrap().unwrap(); + assert_eq!(msg.message.id(), copy.id()) + } + + #[test] + fn test_path() { + let msg = MessageFixture::new(); + assert_eq!(msg.message.filename(), msg.maildir_msg.1) + } + + + #[test] + fn test_filenames() { + let msg = MessageFixture::new(); + let mut filenames = msg.message.filenames(); + let filename = filenames.next().unwrap(); + + assert_eq!(filename, msg.message.filename()); + + assert!(filenames.next().is_none()); + let names: Vec = msg.message.filenames().collect(); + + assert_eq!(names, vec![msg.maildir_msg.1]); + } + + #[test] + fn test_header() { + let msg = MessageFixture::new(); + assert_eq!(msg.message.header(&"from").unwrap(), Some("")); + } + + #[test] + fn test_header_not_present() { + let msg = MessageFixture::new(); + assert_eq!(msg.message.header(&"foo").unwrap(), None); + } + + #[test] + fn test_freeze() { + let msg = MessageFixture::new(); + + msg.message.freeze().unwrap(); + msg.message.add_tag(&"foo").unwrap(); + msg.message.add_tag(&"bar").unwrap(); + msg.message.remove_tag(&"foo").unwrap(); + msg.message.thaw().unwrap(); + + assert!(msg.message.tags().all(|x| x != "foo")); + assert!(msg.message.tags().any(|x| x == "bar")); + } + + #[test] + fn test_freeze_context() { + let msg = MessageFixture::new(); + + { + let _frozen = notmuch::FrozenMessage::new(&msg.message).unwrap(); + msg.message.add_tag(&"foo").unwrap(); + msg.message.add_tag(&"bar").unwrap(); + msg.message.remove_tag(&"foo").unwrap(); + + } + assert!(msg.message.tags().all(|x| x != "foo")); + assert!(msg.message.tags().any(|x| x == "bar")); + } + + + #[test] + fn test_freeze_err() { + // not sure if this test is ok? + let msg = MessageFixture::new(); + + msg.message.add_tag(&"foo").unwrap(); + + msg.message.freeze().unwrap(); + assert!(msg.message.remove_all_tags().is_ok()); + + let copy = ::find_message(msg.database.clone(), &msg.message.id()).unwrap().unwrap(); + assert!(copy.tags().any(|x| x == "foo")); + + msg.message.thaw().unwrap(); + + assert!(!msg.message.tags().any(|x| x == "foo")); + + let copy2 = ::find_message(msg.database.clone(), &msg.message.id()).unwrap().unwrap(); + assert!(!copy2.tags().any(|x| x == "foo")); + } + + #[test] + fn test_freeze_context_err() { + // not sure if this test is ok? + let msg = MessageFixture::new(); + msg.message.add_tag(&"foo").unwrap(); + + { + let _frozen = notmuch::FrozenMessage::new(&msg.message).unwrap(); + assert!(msg.message.remove_all_tags().is_ok()); + assert!(!msg.message.tags().any(|x| x == "foo")); + + let copy = ::find_message(msg.database.clone(), &msg.message.id()).unwrap().unwrap(); + assert!(copy.tags().any(|x| x == "foo")); + } + + let copy2 = ::find_message(msg.database.clone(), &msg.message.id()).unwrap().unwrap(); + assert!(!copy2.tags().any(|x| x == "foo")); + assert!(!msg.message.tags().any(|x| x == "foo")); + } + + #[test] + fn test_replies() { + let msg = MessageFixture::new(); + assert_eq!(msg.message.replies().count(), 0); + } + +} + + +// def test_date(self, msg): +// # XXX Someone seems to treat things as local time instead of +// # UTC or the other way around. +// now = int(time.time()) +// assert abs(now - msg.date) < 3600*24 + + +// struct MessagePropertiesFixture { +// // Return a single thread with 2 messages +// pub mailbox: MailBox, +// pub database: Arc, +// pub maildir_msg: (String, PathBuf), +// pub message: notmuch::Message<'static, notmuch::Database>, +// } + +// impl MessagePropertiesFixture { +// pub fn new() -> Self{ +// let mailbox = MailBox::new(); + +// let (msgid, filename) = mailbox.deliver(None, None, None, None, vec![], true, None, false, false, false).unwrap(); + +// let database = Arc::new(notmuch::Database::create(&mailbox.path()).unwrap()); +// let message = ::index_file(database.clone(), &filename, None).unwrap(); +// let properties = ::properties(&message, false); + +// Self { +// mailbox, +// database, +// maildir_msg: (msgid, filename), +// message +// } +// } +// } + + +mod properties { + use super::*; + + #[test] + fn test_add_single() { + let msg = MessageFixture::new(); + msg.message.add_property(&"foo", &"bar").unwrap(); + assert_eq!(msg.message.property(&"foo", true).unwrap(), "bar"); + + msg.message.add_property(&"bar", &"baz").unwrap(); + assert_eq!(msg.message.property(&"bar", true).unwrap(), "baz"); + } + + #[test] + fn test_add_dup() { + let msg = MessageFixture::new(); + msg.message.add_property(&"foo", &"bar").unwrap(); + msg.message.add_property(&"foo", &"baz").unwrap(); + + assert_eq!(msg.message.property(&"foo", true).unwrap(), "bar"); + + let props = msg.message.properties(&"foo", true); + let expect = vec![("foo", "bar"), ("foo", "baz")]; + for (&(ek, ev), (pk, pv)) in expect.iter().zip(props) { + assert_eq!(ek, pk); + assert_eq!(ev, pv); + } + } + + #[test] + fn test_len() { + let msg = MessageFixture::new(); + msg.message.add_property(&"foo", &"a").unwrap(); + msg.message.add_property(&"foo", &"b").unwrap(); + msg.message.add_property(&"bar", &"a").unwrap(); + + let num_props = msg.message.properties(&"", false).count(); + assert_eq!(num_props, 3); + + let mut prop_keys: Vec = msg.message.properties(&"", false).map(|x| x.0).collect(); + prop_keys.sort(); + prop_keys.dedup(); + assert_eq!(prop_keys.len(), 2); + + let mut prop_vals: Vec = msg.message.properties(&"", false).map(|x| x.1).collect(); + prop_vals.sort(); + prop_vals.dedup(); + assert_eq!(prop_vals.len(), 2); + } + + #[test] + fn test_remove() { + let msg = MessageFixture::new(); + msg.message.add_property(&"foo", &"a").unwrap(); + msg.message.add_property(&"foo", &"b").unwrap(); + + msg.message.remove_property(&"foo", &"a").unwrap(); + + assert_eq!(msg.message.property(&"foo", true).unwrap(), "b"); + + } + +} + + + + +// def test_del(self, props): +// props.add('foo', 'a') +// props.add('foo', 'b') +// del props['foo'] +// with pytest.raises(KeyError): +// props['foo'] + +// def test_remove(self, props): +// props.add('foo', 'a') +// props.add('foo', 'b') +// props.remove('foo', 'a') +// assert props['foo'] == 'b' + +// def test_view_abcs(self, props): +// assert isinstance(props.keys(), collections.abc.KeysView) +// assert isinstance(props.values(), collections.abc.ValuesView) +// assert isinstance(props.items(), collections.abc.ItemsView) + +// def test_pop(self, props): +// props.add('foo', 'a') +// props.add('foo', 'b') +// val = props.pop('foo') +// assert val == 'a' + +// def test_pop_default(self, props): +// with pytest.raises(KeyError): +// props.pop('foo') +// assert props.pop('foo', 'default') == 'default' + +// def test_popitem(self, props): +// props.add('foo', 'a') +// assert props.popitem() == ('foo', 'a') +// with pytest.raises(KeyError): +// props.popitem() + +// def test_clear(self, props): +// props.add('foo', 'a') +// props.clear() +// assert len(props) == 0 + +// def test_getall(self, props): +// props.add('foo', 'a') +// assert set(props.getall('foo')) == {('foo', 'a')} + +// def test_getall_prefix(self, props): +// props.add('foo', 'a') +// props.add('foobar', 'b') +// assert set(props.getall('foo')) == {('foo', 'a'), ('foobar', 'b')} + +// def test_getall_exact(self, props): +// props.add('foo', 'a') +// props.add('foobar', 'b') +// assert set(props.getall('foo', exact=True)) == {('foo', 'a')} diff --git a/tests/test_thread.rs b/tests/test_thread.rs new file mode 100644 index 0000000..0909082 --- /dev/null +++ b/tests/test_thread.rs @@ -0,0 +1,108 @@ +use std::sync::Arc; +use fixtures::{NotmuchCommand, MailBox}; + + +struct ThreadFixture { + // Return a single thread with 2 messages + pub mailbox: MailBox, + pub thread: notmuch::Thread<'static, 'static>, +} + +impl ThreadFixture { + pub fn new() -> Self{ + let mailbox = MailBox::new(); + + let (msgid, _) = mailbox.deliver(None, Some("foo".to_string()), None, None, vec![], true, None, false, false, false).unwrap(); + mailbox.deliver(None, Some("bar".to_string()), None, None, vec![("In-Reply-To".to_string(), format!("<{}>", msgid))], true, None, false, false, false).unwrap(); + + let cmd = NotmuchCommand::new(&mailbox.path()); + cmd.run(vec!["new"]).unwrap(); + + let mut threads = { + let database = Arc::new(notmuch::Database::open(&mailbox.path(), notmuch::DatabaseMode::ReadWrite).unwrap()); + + let query = notmuch::Query::create(database.clone(), &"foo".to_string()).unwrap(); + + ::search_threads(query).unwrap() + }; + let thread = threads.next().unwrap(); + + Self { + mailbox, + thread + } + } +} + +#[test] +fn test_threadid() { + let thread = ThreadFixture::new(); + assert!(!thread.thread.id().is_empty()); +} + +#[test] +fn test_len() { + let thread = ThreadFixture::new(); + + assert_eq!(thread.thread.total_messages(), 2); +} + +#[test] +fn test_toplevel() { + let thread = ThreadFixture::new(); + let msgs = thread.thread.toplevel_messages(); + + assert_eq!(msgs.count(), 1); +} + + +#[test] +fn test_toplevel_reply() { + let thread = ThreadFixture::new(); + let msg = thread.thread.toplevel_messages().next().unwrap(); + + assert_eq!(msg.replies().count(), 1); +} + +#[test] +fn test_iter() { + let thread = ThreadFixture::new(); + let msg_count0 = thread.thread.messages().count() as i32; + let msg_count1 = thread.thread.total_messages(); + + assert_eq!(msg_count0, msg_count1); +} + +#[test] +fn test_matched() { + let thread = ThreadFixture::new(); + assert_eq!(thread.thread.matched_messages(), 1); +} + + +#[test] +fn test_authors() { + let thread = ThreadFixture::new(); + + assert_eq!(thread.thread.authors(), vec!["src@example.com".to_string()]); +} + + +#[test] +fn test_subject() { + let thread = ThreadFixture::new(); + + println!("{:?}", thread.thread.subject()); + assert_eq!(thread.thread.subject(), "Test mail"); +} + + + +#[test] +fn test_tags() { + let thread = ThreadFixture::new(); + + let tags: Vec = thread.thread.tags().collect(); + assert!(tags.iter().any(|x| x == "inbox")); +} + \ No newline at end of file -- cgit v1.2.1 From 5d1bb582ae26ba83629bfd6fe0a8d64f816acfee Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 15 Nov 2019 14:05:29 +0100 Subject: more tests for message --- src/ffi.rs | 17 ++++++ src/message.rs | 55 ++++++++++++++----- tests/test_message.rs | 147 +++++++++++++++++++++----------------------------- 3 files changed, 121 insertions(+), 98 deletions(-) diff --git a/src/ffi.rs b/src/ffi.rs index 5dc93aa..285aeba 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -1445,6 +1445,23 @@ extern "C" { key: *const c_char, ) -> notmuch_status_t; + /// Remove all (prefix*,value) pairs from the given message + /// + /// @param[in,out] message message to operate on. + /// @param[in] prefix delete properties with keys that start with prefix. + /// If NULL, delete all properties + /// @returns + /// - NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in + /// read-only mode so message cannot be modified. + /// - NOTMUCH_STATUS_SUCCESS: No error occurred. + /// + /// @since libnotmuch 5.1 (notmuch 0.26) + /// + pub fn notmuch_message_remove_all_properties_with_prefix( + message: *mut notmuch_message_t, + prefix: *const c_char, + ) -> notmuch_status_t; + /// Get the properties for *message*, returning a /// `notmuch_message_properties_t` object which can be used to iterate over /// all properties. diff --git a/src/message.rs b/src/message.rs index 03623a1..8263908 100644 --- a/src/message.rs +++ b/src/message.rs @@ -144,19 +144,47 @@ where unsafe { ffi::notmuch_message_thaw(self.ptr) }.as_result() } - pub fn properties<'m>(&'m self, key: &str, exact: bool) -> MessageProperties<'m, 'o, O> - { + pub fn properties<'m>(&'m self, key: &str, exact: bool) -> MessageProperties<'m, 'o, O> { >::properties(self, key, exact) } - pub fn remove_all_properties(&self, key: &str) -> Result<()> + pub fn remove_all_properties(&self, key: Option<&str>) -> Result<()> { - let key_str = CString::new(key).unwrap(); - unsafe { - ffi::notmuch_message_remove_all_properties(self.ptr, key_str.as_ptr()) - }.as_result() + match key { + Some(k) => { + let key_str = CString::new(k).unwrap(); + unsafe { + ffi::notmuch_message_remove_all_properties(self.ptr, key_str.as_ptr()) + }.as_result() + }, + None => { + let p = ptr::null(); + unsafe { + ffi::notmuch_message_remove_all_properties(self.ptr, p) + }.as_result() + } + } + } + + pub fn remove_all_properties_with_prefix(&self, prefix: Option<&str>) -> Result<()> + { + match prefix { + Some(k) => { + let key_str = CString::new(k).unwrap(); + unsafe { + ffi::notmuch_message_remove_all_properties_with_prefix(self.ptr, key_str.as_ptr()) + }.as_result() + }, + None => { + let p = ptr::null(); + unsafe { + ffi::notmuch_message_remove_all_properties_with_prefix(self.ptr, p) + }.as_result() + } + } } + pub fn count_properties(&self, key: &str) -> Result { let key_str = CString::new(key).unwrap(); @@ -176,10 +204,14 @@ where ffi::notmuch_message_get_property(self.ptr, key_str.as_ptr(), &mut prop) }.as_result()?; - // TODO: the unwrap here is not good - Ok(unsafe{ - CStr::from_ptr(prop) - }.to_str().unwrap().to_string()) + if prop.is_null() { + Err(Error::UnspecifiedError) + } else { + // TODO: the unwrap here is not good + Ok(unsafe{ + CStr::from_ptr(prop) + }.to_str().unwrap().to_string()) + } } pub fn add_property(&self, key: &str, value: &str) -> Result<()> @@ -199,7 +231,6 @@ where ffi::notmuch_message_remove_property(self.ptr, key_str.as_ptr(), value_str.as_ptr()) }.as_result() } - } pub trait MessageExt<'o, O> diff --git a/tests/test_message.rs b/tests/test_message.rs index ce86df0..152f565 100644 --- a/tests/test_message.rs +++ b/tests/test_message.rs @@ -165,35 +165,6 @@ mod message { // now = int(time.time()) // assert abs(now - msg.date) < 3600*24 - -// struct MessagePropertiesFixture { -// // Return a single thread with 2 messages -// pub mailbox: MailBox, -// pub database: Arc, -// pub maildir_msg: (String, PathBuf), -// pub message: notmuch::Message<'static, notmuch::Database>, -// } - -// impl MessagePropertiesFixture { -// pub fn new() -> Self{ -// let mailbox = MailBox::new(); - -// let (msgid, filename) = mailbox.deliver(None, None, None, None, vec![], true, None, false, false, false).unwrap(); - -// let database = Arc::new(notmuch::Database::create(&mailbox.path()).unwrap()); -// let message = ::index_file(database.clone(), &filename, None).unwrap(); -// let properties = ::properties(&message, false); - -// Self { -// mailbox, -// database, -// maildir_msg: (msgid, filename), -// message -// } -// } -// } - - mod properties { use super::*; @@ -244,6 +215,16 @@ mod properties { assert_eq!(prop_vals.len(), 2); } + #[test] + fn test_del() { + let msg = MessageFixture::new(); + msg.message.add_property(&"foo", &"a").unwrap(); + msg.message.add_property(&"foo", &"b").unwrap(); + + msg.message.remove_all_properties(Some(&"foo")).unwrap(); + assert!(msg.message.property(&"foo", true).is_err()); + } + #[test] fn test_remove() { let msg = MessageFixture::new(); @@ -251,66 +232,60 @@ mod properties { msg.message.add_property(&"foo", &"b").unwrap(); msg.message.remove_property(&"foo", &"a").unwrap(); - assert_eq!(msg.message.property(&"foo", true).unwrap(), "b"); + } + + #[test] + fn test_clear() { + let msg = MessageFixture::new(); + msg.message.add_property(&"foo", &"a").unwrap(); + + msg.message.remove_all_properties(None).unwrap(); + assert!(msg.message.property(&"foo", true).is_err()); + } + + #[test] + fn test_getall() { + let msg = MessageFixture::new(); + msg.message.add_property(&"foo", &"a").unwrap(); + + let mut prop_keys: Vec = msg.message.properties(&"foo", false).map(|x| x.0).collect(); + assert_eq!(prop_keys.len(), 1); + assert_eq!(prop_keys, vec!["foo"]); + let mut prop_vals: Vec = msg.message.properties(&"foo", false).map(|x| x.1).collect(); + assert_eq!(prop_vals.len(), 1); + assert_eq!(prop_vals, vec!["a"]); } + #[test] + fn test_getall_prefix() { + let msg = MessageFixture::new(); + msg.message.add_property(&"foo", &"a").unwrap(); + msg.message.add_property(&"foobar", &"b").unwrap(); + + let mut prop_keys: Vec = msg.message.properties(&"foo", false).map(|x| x.0).collect(); + assert_eq!(prop_keys.len(), 2); + assert_eq!(prop_keys, vec!["foo", "foobar"]); + + let mut prop_vals: Vec = msg.message.properties(&"foo", false).map(|x| x.1).collect(); + assert_eq!(prop_vals.len(), 2); + assert_eq!(prop_vals, vec!["a", "b"]); + } + + #[test] + fn test_getall_exact() { + let msg = MessageFixture::new(); + msg.message.add_property(&"foo", &"a").unwrap(); + msg.message.add_property(&"foobar", &"b").unwrap(); + + let mut prop_keys: Vec = msg.message.properties(&"foo", true).map(|x| x.0).collect(); + assert_eq!(prop_keys.len(), 1); + assert_eq!(prop_keys, vec!["foo"]); + + let mut prop_vals: Vec = msg.message.properties(&"foo", true).map(|x| x.1).collect(); + assert_eq!(prop_vals.len(), 1); + assert_eq!(prop_vals, vec!["a"]); + } } - - - -// def test_del(self, props): -// props.add('foo', 'a') -// props.add('foo', 'b') -// del props['foo'] -// with pytest.raises(KeyError): -// props['foo'] - -// def test_remove(self, props): -// props.add('foo', 'a') -// props.add('foo', 'b') -// props.remove('foo', 'a') -// assert props['foo'] == 'b' - -// def test_view_abcs(self, props): -// assert isinstance(props.keys(), collections.abc.KeysView) -// assert isinstance(props.values(), collections.abc.ValuesView) -// assert isinstance(props.items(), collections.abc.ItemsView) - -// def test_pop(self, props): -// props.add('foo', 'a') -// props.add('foo', 'b') -// val = props.pop('foo') -// assert val == 'a' - -// def test_pop_default(self, props): -// with pytest.raises(KeyError): -// props.pop('foo') -// assert props.pop('foo', 'default') == 'default' - -// def test_popitem(self, props): -// props.add('foo', 'a') -// assert props.popitem() == ('foo', 'a') -// with pytest.raises(KeyError): -// props.popitem() - -// def test_clear(self, props): -// props.add('foo', 'a') -// props.clear() -// assert len(props) == 0 - -// def test_getall(self, props): -// props.add('foo', 'a') -// assert set(props.getall('foo')) == {('foo', 'a')} - -// def test_getall_prefix(self, props): -// props.add('foo', 'a') -// props.add('foobar', 'b') -// assert set(props.getall('foo')) == {('foo', 'a'), ('foobar', 'b')} - -// def test_getall_exact(self, props): -// props.add('foo', 'a') -// props.add('foobar', 'b') -// assert set(props.getall('foo', exact=True)) == {('foo', 'a')} -- cgit v1.2.1 From 084675fdfe1329cbd58a48f2306b7c61dec08834 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 15 Nov 2019 20:12:59 +0100 Subject: more tests for tags --- tests/fixtures.rs | 31 ++++++++++-- tests/lib.rs | 1 + tests/test_tags.rs | 144 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+), 3 deletions(-) create mode 100644 tests/test_tags.rs diff --git a/tests/fixtures.rs b/tests/fixtures.rs index c9e04c8..a8166be 100644 --- a/tests/fixtures.rs +++ b/tests/fixtures.rs @@ -147,16 +147,41 @@ impl MailBox { if seen { flags += "S"; } - self.maildir.store_cur_with_flags(&msg.message_to_string().unwrap().as_bytes(), flags.as_str()).unwrap() - }; + println!("flags: {:?}", flags); + let mid = self.maildir.store_cur_with_flags(&msg.message_to_string().unwrap().as_bytes(), flags.as_str()).unwrap(); + // I have no idea what the reasoning for the :2 here is, but ok. + format!("{}:2,{}", mid, flags) + }; + + // let mut flags = String::from(""); + // if flagged { + // flags += "F"; + // } + // if replied { + // flags += "R"; + // } + // if seen { + // flags += "S"; + // } + // println!("flags: {:?}", flags); + // let id = self.maildir.store_cur_with_flags(&msg.message_to_string().unwrap().as_bytes(), flags.as_str()).unwrap(); + + // if is_new { + // let msgpath = format!("{}{}", id, flags); + // std::fs::rename(msgpath, newpath)?; + + // self.maildir.path() + // } + + let mut msgpath = self.path(); msgpath = if is_new { msgpath.join("new") } else { msgpath.join("cur") }; - + msgpath = msgpath.join(&id); Ok((msg_id, msgpath)) diff --git a/tests/lib.rs b/tests/lib.rs index bd3138d..e7ee0bc 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -10,4 +10,5 @@ mod fixtures; mod test_database; mod test_thread; mod test_message; +mod test_tags; diff --git a/tests/test_tags.rs b/tests/test_tags.rs new file mode 100644 index 0000000..5ddabeb --- /dev/null +++ b/tests/test_tags.rs @@ -0,0 +1,144 @@ +use std::sync::Arc; +use std::path::PathBuf; +use fixtures::{MailBox, NotmuchCommand}; + +struct TagSetFixture { + // An non-empty immutable tagset. + // This will have the default new mail tags: inbox, unread. + pub mailbox: MailBox, + pub cmd: NotmuchCommand, + pub database: Arc, + pub message: notmuch::Message<'static, notmuch::Database> +} + +impl TagSetFixture { + pub fn new(mutable: bool, flagged: bool) -> Self{ + let mailbox = MailBox::new(); + let (_msg, filename) = mailbox.deliver(None, None, None, None, vec![], !flagged, None, false, false, flagged).unwrap(); + + let cmd = NotmuchCommand::new(&mailbox.path()); + cmd.run(vec!["new"]).unwrap(); + + let database = Arc::new(notmuch::Database::open(&mailbox.path(), if !mutable {notmuch::DatabaseMode::ReadOnly} else { notmuch::DatabaseMode::ReadWrite }).unwrap()); + let message = ::find_message_by_filename(database.clone(), &filename).unwrap().unwrap(); + + Self { + mailbox, + database, + cmd, + message + } + } +} + +mod immutable { + + use super::*; + + #[test] + fn test_neg(){ + let tagset = TagSetFixture::new(false, false); + + let tags: Vec = tagset.database.all_tags().unwrap().collect(); + tagset.cmd.run(vec!["tag", "+foo", "*"]).unwrap(); + + let database = notmuch::Database::open(&tagset.mailbox.path(), notmuch::DatabaseMode::ReadOnly).unwrap(); + let ntags: Vec = database.all_tags().unwrap().collect(); + + assert_ne!(tags, ntags); + } + + #[test] + fn test_contains(){ + let tagset = TagSetFixture::new(false, false); + let tags: Vec = tagset.database.all_tags().unwrap().collect(); + + assert!(tags.iter().any(|x| x == "unread")); + assert!(!tags.iter().any(|x| x == "foo")); + } + + + #[test] + fn test_len(){ + let tagset = TagSetFixture::new(false, false); + assert_eq!(tagset.database.all_tags().unwrap().count(), 2); + } + +} + +mod mutable { + + use super::*; + + #[test] + fn test_add(){ + let tagset = TagSetFixture::new(true, false); + assert!(!tagset.message.tags().any(|x| x == "foo")); + + tagset.message.add_tag("foo").unwrap(); + assert!(tagset.message.tags().any(|x| x == "foo")); + } + + #[test] + fn test_discard(){ + let tagset = TagSetFixture::new(true, false); + assert!(tagset.message.tags().any(|x| x == "inbox")); + + tagset.message.remove_tag("inbox").unwrap(); + assert!(!tagset.message.tags().any(|x| x == "unbox")); + } + + #[test] + fn test_discard_not_present(){ + let tagset = TagSetFixture::new(true, false); + assert!(!tagset.message.tags().any(|x| x == "foo")); + + tagset.message.remove_tag("foo").unwrap(); + } + + #[test] + fn test_clear(){ + let tagset = TagSetFixture::new(true, false); + assert!(tagset.message.tags().count() > 0); + tagset.message.remove_all_tags().unwrap(); + + assert!(tagset.message.tags().count() == 0); + } + + #[test] + fn test_from_maildir_flags(){ + let tagset = TagSetFixture::new(true, true); + + let msgid = tagset.message.id(); + tagset.message.remove_tag(&"flagged").unwrap(); + tagset.message.maildir_flags_to_tags().unwrap(); + + assert!(tagset.message.tags().any(|x| x == "flagged")); + } + + + #[test] + fn test_to_maildir_flags(){ + + let tagset = TagSetFixture::new(true, true); + + let filename = tagset.message.filename(); + let filestr = filename.to_string_lossy(); + + let file_parts: Vec<&str> = filestr.split(",").collect(); + let flags = file_parts.last().unwrap(); + println!("Flags {:?}", flags); + + assert!(flags.contains("F")); + tagset.message.remove_tag(&"flagged").unwrap(); + tagset.message.tags_to_maildir_flags().unwrap(); + + let filename = tagset.message.filename(); + let filestr = filename.to_string_lossy(); + + let file_parts: Vec<&str> = filestr.split(",").collect(); + let flags = file_parts.last().unwrap(); + assert!(!flags.contains("F")); + } + +} \ No newline at end of file -- cgit v1.2.1 From e16769c9b16223c491766f9c9b2c828ee2253ed4 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 16 Nov 2019 11:14:10 +0100 Subject: less unwraps --- src/config_list.rs | 8 ++++---- src/ffi.rs | 10 +++++++++- src/message.rs | 30 ++++++++++++++++-------------- src/message_properties.rs | 2 +- src/tags.rs | 2 +- src/thread.rs | 13 ++++++------- src/utils.rs | 14 +++++++++++++- tests/test_message.rs | 14 +++++++------- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/config_list.rs b/src/config_list.rs index 632603c..b819418 100644 --- a/src/config_list.rs +++ b/src/config_list.rs @@ -6,7 +6,7 @@ use ffi; use Database; use Filenames; use FilenamesOwner; -use utils::{ScopedSupercow, ScopedPhantomcow}; +use utils::{ToStr, ScopedSupercow, ScopedPhantomcow}; #[derive(Debug)] @@ -46,15 +46,15 @@ impl<'d> Iterator for ConfigList<'d> } let (k, v) = unsafe { - let key = CStr::from_ptr(ffi::notmuch_config_list_key(self.ptr)); - let value = CStr::from_ptr(ffi::notmuch_config_list_value(self.ptr)); + let key = ffi::notmuch_config_list_key(self.ptr); + let value = ffi::notmuch_config_list_value(self.ptr); ffi::notmuch_config_list_move_to_next(self.ptr); (key, value) }; - Some((k.to_str().unwrap().to_string(), v.to_str().unwrap().to_string())) + Some((k.to_string_lossy().to_string(), v.to_string_lossy().to_string())) } } diff --git a/src/ffi.rs b/src/ffi.rs index 285aeba..5c276d8 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -6,7 +6,7 @@ use libc::{c_char, c_double, c_int, c_uint, c_ulong, c_void, time_t}; use error::{Error, Result}; use std::{error, fmt, str}; - +use std::borrow::Cow; use utils::ToStr; notmuch_enum! { @@ -57,6 +57,14 @@ impl ToStr for Status { fn to_str<'a>(&self) -> std::result::Result<&'a str, str::Utf8Error> { unsafe { notmuch_status_to_string((*self).into()) }.to_str() } + + fn to_str_unchecked<'a>(&self) -> &'a str { + unsafe { notmuch_status_to_string((*self).into()) }.to_str_unchecked() + } + + fn to_string_lossy<'a>(&self) -> Cow<'a, str> { + unsafe { notmuch_status_to_string((*self).into()) }.to_string_lossy() + } } impl fmt::Display for Status { diff --git a/src/message.rs b/src/message.rs index 8263908..20ad957 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,7 +1,9 @@ use std::ffi::{CString, CStr}; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::cell::RefCell; +use std::borrow::Cow; use std::ptr; + use supercow::{Supercow}; use error::{Error, Result}; @@ -54,14 +56,14 @@ where } } - pub fn id(self: &Self) -> String { + pub fn id(self: &Self) -> Cow<'_, str> { let mid = unsafe { ffi::notmuch_message_get_message_id(self.ptr) }; - mid.to_str().unwrap().to_string() + mid.to_string_lossy() } - pub fn thread_id(self: &Self) -> String { + pub fn thread_id(self: &Self) -> Cow<'_, str> { let tid = unsafe { ffi::notmuch_message_get_thread_id(self.ptr) }; - tid.to_str().unwrap().to_string() + tid.to_string_lossy() } pub fn replies(self: &Self) -> Messages<'o, O> { @@ -93,16 +95,18 @@ where unsafe { ffi::notmuch_message_get_date(self.ptr) as i64 } } - pub fn header(&self, name: &str) -> Result> { + pub fn header(&self, name: &str) -> Result>> { let name = CString::new(name).unwrap(); let ret = unsafe { ffi::notmuch_message_get_header(self.ptr, name.as_ptr()) }; if ret.is_null() { Err(Error::UnspecifiedError) } else { - Ok(match ret.to_str().unwrap() { - "" => None, - ret => Some(ret), - }) + let ret_str = ret.to_string_lossy(); + if ret_str.is_empty() { + Ok(None) + } else{ + Ok(Some(ret_str)) + } } } @@ -196,7 +200,7 @@ where Ok(cnt) } - pub fn property(&self, key: &str, exact: bool) -> Result + pub fn property(&self, key: &str) -> Result> { let key_str = CString::new(key).unwrap(); let mut prop = ptr::null(); @@ -208,9 +212,7 @@ where Err(Error::UnspecifiedError) } else { // TODO: the unwrap here is not good - Ok(unsafe{ - CStr::from_ptr(prop) - }.to_str().unwrap().to_string()) + Ok(prop.to_string_lossy()) } } diff --git a/src/message_properties.rs b/src/message_properties.rs index 4802383..19ea960 100644 --- a/src/message_properties.rs +++ b/src/message_properties.rs @@ -64,7 +64,7 @@ where (key, value) }; - Some((k.to_str().unwrap().to_string(), v.to_str().unwrap().to_string())) + Some((k.to_string_lossy().to_string(), v.to_string_lossy().to_string())) } } diff --git a/src/tags.rs b/src/tags.rs index 40a45c8..5f3ec60 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -69,7 +69,7 @@ where CStr::from_ptr(t) }; - Some(ctag.to_str().unwrap().to_string()) + Some(ctag.to_string_lossy().to_string()) } } diff --git a/src/thread.rs b/src/thread.rs index 1ebcc24..ffc1f2f 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -1,4 +1,5 @@ use std::ops::Drop; +use std::borrow::Cow; use ffi; use utils::{ToStr, ScopedSupercow, ScopedPhantomcow}; @@ -43,9 +44,9 @@ where } } - pub fn id(self: &Self) -> String { + pub fn id(self: &Self) -> &str { let tid = unsafe { ffi::notmuch_thread_get_thread_id(self.ptr) }; - tid.to_str().unwrap().to_string() + tid.to_str().unwrap() } pub fn total_messages(self: &Self) -> i32 { @@ -75,18 +76,16 @@ where >::tags(self) } - pub fn subject(self: &Self) -> String { + pub fn subject(self: &Self) -> Cow<'_, str> { let sub = unsafe { ffi::notmuch_thread_get_subject(self.ptr) }; - - sub.to_str().unwrap().to_string() + sub.to_string_lossy() } pub fn authors(self: &Self) -> Vec { let athrs = unsafe { ffi::notmuch_thread_get_authors(self.ptr) }; athrs - .to_str() - .unwrap() + .to_string_lossy() .split(',') .map(|s| s.to_string()) .collect() diff --git a/src/utils.rs b/src/utils.rs index 022d508..6030f38 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,17 +1,29 @@ use libc; use std::{ffi, str}; - +use std::borrow::Cow; use supercow::{Supercow, DefaultFeatures/*, NonSyncFeatures*/}; use supercow::ext::{BoxedStorage}; pub trait ToStr { fn to_str<'a>(&self) -> Result<&'a str, str::Utf8Error>; + + fn to_str_unchecked<'a>(&self) -> &'a str; + + fn to_string_lossy<'a>(&self) -> Cow<'a, str>; } 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()) } + + fn to_str_unchecked<'a>(&self) -> &'a str { + unsafe { str::from_utf8_unchecked(ffi::CStr::from_ptr(*self).to_bytes()) } + } + + fn to_string_lossy<'a>(&self) -> Cow<'a, str> { + unsafe { ffi::CStr::from_ptr(*self) }.to_string_lossy() + } } pub trait ToString { diff --git a/tests/test_message.rs b/tests/test_message.rs index 152f565..7a6391d 100644 --- a/tests/test_message.rs +++ b/tests/test_message.rs @@ -70,7 +70,7 @@ mod message { #[test] fn test_header() { let msg = MessageFixture::new(); - assert_eq!(msg.message.header(&"from").unwrap(), Some("")); + assert_eq!(msg.message.header(&"from").unwrap().unwrap().to_string(), ""); } #[test] @@ -172,10 +172,10 @@ mod properties { fn test_add_single() { let msg = MessageFixture::new(); msg.message.add_property(&"foo", &"bar").unwrap(); - assert_eq!(msg.message.property(&"foo", true).unwrap(), "bar"); + assert_eq!(msg.message.property(&"foo").unwrap(), "bar"); msg.message.add_property(&"bar", &"baz").unwrap(); - assert_eq!(msg.message.property(&"bar", true).unwrap(), "baz"); + assert_eq!(msg.message.property(&"bar").unwrap(), "baz"); } #[test] @@ -184,7 +184,7 @@ mod properties { msg.message.add_property(&"foo", &"bar").unwrap(); msg.message.add_property(&"foo", &"baz").unwrap(); - assert_eq!(msg.message.property(&"foo", true).unwrap(), "bar"); + assert_eq!(msg.message.property(&"foo").unwrap(), "bar"); let props = msg.message.properties(&"foo", true); let expect = vec![("foo", "bar"), ("foo", "baz")]; @@ -222,7 +222,7 @@ mod properties { msg.message.add_property(&"foo", &"b").unwrap(); msg.message.remove_all_properties(Some(&"foo")).unwrap(); - assert!(msg.message.property(&"foo", true).is_err()); + assert!(msg.message.property(&"foo").is_err()); } #[test] @@ -232,7 +232,7 @@ mod properties { msg.message.add_property(&"foo", &"b").unwrap(); msg.message.remove_property(&"foo", &"a").unwrap(); - assert_eq!(msg.message.property(&"foo", true).unwrap(), "b"); + assert_eq!(msg.message.property(&"foo").unwrap(), "b"); } #[test] @@ -241,7 +241,7 @@ mod properties { msg.message.add_property(&"foo", &"a").unwrap(); msg.message.remove_all_properties(None).unwrap(); - assert!(msg.message.property(&"foo", true).is_err()); + assert!(msg.message.property(&"foo").is_err()); } #[test] -- cgit v1.2.1 From 3b92173d12659231629c2205138b0857b66942f3 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 16 Nov 2019 21:01:54 +0100 Subject: make clippy happy --- Cargo.toml | 2 +- src/config_list.rs | 6 +- src/error.rs | 2 +- src/index.rs | 7 +-- src/message.rs | 4 +- src/message_properties.rs | 5 +- src/messages.rs | 2 - src/utils.rs | 6 +- tests/commands.rs | 140 ---------------------------------------------- tests/fixtures.rs | 49 ++-------------- tests/test_database.rs | 5 +- tests/test_message.rs | 12 ++-- tests/test_tags.rs | 10 ++-- 13 files changed, 29 insertions(+), 221 deletions(-) delete mode 100644 tests/commands.rs diff --git a/Cargo.toml b/Cargo.toml index f51bda2..48e7415 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "notmuch" -version = "0.5.0" +version = "0.6.0" authors = ["Dirk Van Haerenborgh "] homepage = "https://github.com/vhdirk/notmuch-rs" repository = "https://github.com/vhdirk/notmuch-rs" diff --git a/src/config_list.rs b/src/config_list.rs index b819418..2c1a6a4 100644 --- a/src/config_list.rs +++ b/src/config_list.rs @@ -1,12 +1,8 @@ use std::ops::Drop; -use std::ffi::{CStr, CString}; -use supercow::Supercow; use ffi; use Database; -use Filenames; -use FilenamesOwner; -use utils::{ToStr, ScopedSupercow, ScopedPhantomcow}; +use utils::{ToStr, ScopedPhantomcow}; #[derive(Debug)] diff --git a/src/error.rs b/src/error.rs index 824cc39..64d0716 100644 --- a/src/error.rs +++ b/src/error.rs @@ -27,7 +27,7 @@ impl std::error::Error for Error { } } - fn cause(&self) -> Option<&error::Error> { + fn cause(&self) -> Option<&dyn error::Error> { match *self { Error::IoError(ref e) => Some(e), Error::NotmuchError(ref e) => Some(e), diff --git a/src/index.rs b/src/index.rs index f070020..4db6bc7 100644 --- a/src/index.rs +++ b/src/index.rs @@ -1,13 +1,10 @@ use std::ops::Drop; -use supercow::{Supercow, Phantomcow}; -use error::{Error, Result}; +use error::Result; use ffi; use ffi::DecryptionPolicy; use Database; -use Filenames; -use FilenamesOwner; -use utils::{ScopedSupercow, ScopedPhantomcow}; +use utils::ScopedPhantomcow; #[derive(Debug)] diff --git a/src/message.rs b/src/message.rs index 20ad957..55a544f 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,5 +1,5 @@ -use std::ffi::{CString, CStr}; -use std::path::{Path, PathBuf}; +use std::ffi::CString; +use std::path::PathBuf; use std::cell::RefCell; use std::borrow::Cow; use std::ptr; diff --git a/src/message_properties.rs b/src/message_properties.rs index 19ea960..bd20aa0 100644 --- a/src/message_properties.rs +++ b/src/message_properties.rs @@ -1,11 +1,10 @@ use std::ops::Drop; -use std::ffi::{CStr, CString}; -use supercow::Supercow; +use std::ffi::CStr; use ffi; use Message; use MessageOwner; -use utils::{ScopedSupercow, ScopedPhantomcow}; +use utils::{ScopedPhantomcow}; #[derive(Debug)] diff --git a/src/messages.rs b/src/messages.rs index 60a6f7d..48d30ef 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -1,5 +1,3 @@ -use std::ops::Drop; - use ffi; use utils::ScopedPhantomcow; use MessageOwner; diff --git a/src/utils.rs b/src/utils.rs index 6030f38..57e4004 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -4,6 +4,7 @@ use std::borrow::Cow; use supercow::{Supercow, DefaultFeatures/*, NonSyncFeatures*/}; use supercow::ext::{BoxedStorage}; + pub trait ToStr { fn to_str<'a>(&self) -> Result<&'a str, str::Utf8Error>; @@ -48,8 +49,3 @@ pub type ScopedPhantomcow<'a, OWNED, BORROWED = OWNED, pub type ScopedSupercow<'a, OWNED, BORROWED = OWNED, SHARED = Box + 'a>> = Supercow<'a, OWNED, BORROWED, SHARED, BoxedStorage>; - - - - - diff --git a/tests/commands.rs b/tests/commands.rs deleted file mode 100644 index c9f9d60..0000000 --- a/tests/commands.rs +++ /dev/null @@ -1,140 +0,0 @@ -extern crate dirs; -extern crate notmuch; -extern crate supercow; - -use std::path::Path; -use std::sync::Arc; -use std::result::Result; -use supercow::Supercow; -use notmuch::ScopedSupercow; - -use notmuch::{ - Database, - DatabaseExt, - Query, - QueryExt, - Message, - FrozenMessage, - Error -}; - -#[derive(Debug)] -pub struct AtomicOperation<'d> { - database: ScopedSupercow<'d, Database>, -} - -impl<'d> AtomicOperation<'d> { - pub fn new(db: D) -> Result - where - D: Into>, - { - let database = db.into(); - database.begin_atomic()?; - Ok(AtomicOperation{ - database - }) - } -} - -impl<'d> Drop for AtomicOperation<'d> { - fn drop(&mut self) { - let _ = self.database.end_atomic(); - } -} - -/// Add a single file to the database -pub fn add_file<'d, D, P>(db: D, filename: &P) -> Result, Error> -where - D: Into>, - P: AsRef -{ - let mut database = db.into(); - - let _atomic = AtomicOperation::new(Supercow::share(&mut database)).unwrap(); - - match ::index_file(Supercow::share(&mut database), filename, None) { - Ok(msg) => { - - // scoped version of freezing a message - { - let _fmsg = FrozenMessage::new(&msg); - - - } - Ok(msg) - }, - Err(err) => { - Err(err) - } - } - - -} - - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_add_file() { - - - - } -} - - - -// status = notmuch_database_index_file (notmuch, filename, indexing_cli_choices.opts, &message); -// switch (status) { -// /* Success. */ -// case NOTMUCH_STATUS_SUCCESS: -// state->added_messages++; -// notmuch_message_freeze (message); -// if (state->synchronize_flags) -// notmuch_message_maildir_flags_to_tags (message); - -// for (tag = state->new_tags; *tag != NULL; tag++) { -// if (strcmp ("unread", *tag) != 0 || -// ! notmuch_message_has_maildir_flag (message, 'S')) { -// notmuch_message_add_tag (message, *tag); -// } -// } - -// notmuch_message_thaw (message); -// break; -// /* Non-fatal issues (go on to next file). */ -// case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: -// if (state->synchronize_flags) -// notmuch_message_maildir_flags_to_tags (message); -// break; -// case NOTMUCH_STATUS_FILE_NOT_EMAIL: -// fprintf (stderr, "Note: Ignoring non-mail file: %s\n", filename); -// break; -// case NOTMUCH_STATUS_FILE_ERROR: -// /* Someone renamed/removed the file between scandir and now. */ -// state->vanished_files++; -// fprintf (stderr, "Unexpected error with file %s\n", filename); -// (void) print_status_database ("add_file", notmuch, status); -// break; -// /* Fatal issues. Don't process anymore. */ -// case NOTMUCH_STATUS_READ_ONLY_DATABASE: -// case NOTMUCH_STATUS_XAPIAN_EXCEPTION: -// case NOTMUCH_STATUS_OUT_OF_MEMORY: -// (void) print_status_database ("add_file", notmuch, status); -// goto DONE; -// default: -// INTERNAL_ERROR ("add_message returned unexpected value: %d", status); -// goto DONE; -// } - -// status = notmuch_database_end_atomic (notmuch); - -// DONE: -// if (message) -// notmuch_message_destroy (message); - -// return status; -// } - \ No newline at end of file diff --git a/tests/fixtures.rs b/tests/fixtures.rs index a8166be..7075905 100644 --- a/tests/fixtures.rs +++ b/tests/fixtures.rs @@ -7,25 +7,16 @@ extern crate lettre; extern crate lettre_email; use std::ffi::OsStr; -use std::io::{self, Result, Write}; +use std::io::{Result, Write}; use std::fs::{self, File}; -use std::rc::Rc; -use std::path::{Path, PathBuf}; -use tempfile::{tempdir, tempdir_in, Builder, TempDir}; -use std::net::ToSocketAddrs; +use std::path::PathBuf; +use tempfile::{tempdir, TempDir}; use std::process::Command; -use std::time::{SystemTime, UNIX_EPOCH}; use maildir::Maildir; use lettre_email::{EmailBuilder, Header}; use lettre::SendableEmail; -pub fn timestamp_ms() -> u128 { - let start = SystemTime::now(); - let time_since_epoch = start.duration_since(UNIX_EPOCH).unwrap(); - time_since_epoch.as_millis() -} - // A basic test interface to a valid maildir directory. // // This creates a valid maildir and provides a simple mechanism to @@ -33,7 +24,6 @@ pub fn timestamp_ms() -> u128 { // in the top of the maildir. pub struct MailBox { root_dir: TempDir, - idcount: u32, maildir: Maildir } @@ -73,7 +63,6 @@ impl MailBox { Self { root_dir, - idcount: 0, maildir } } @@ -86,16 +75,10 @@ impl MailBox { // msgid // } - pub fn path(&self) -> PathBuf - { + pub fn path(&self) -> PathBuf { self.root_dir.path().into() } - pub fn hostname(&self) -> String { - let hname = gethostname::gethostname(); - hname.to_string_lossy().into() - } - /// Deliver a new mail message in the mbox. /// This does only adds the message to maildir, does not insert it /// into the notmuch database. @@ -107,7 +90,7 @@ impl MailBox { from: Option, headers: Vec<(String, String)>, is_new: bool, // Move to new dir or cur dir? - keywords: Option>, // List of keywords or labels + _keywords: Option>, // List of keywords or labels seen: bool, // Seen flag (cur dir only) replied: bool, // Replied flag (cur dir only) flagged: bool) // Flagged flag (cur dir only) @@ -154,27 +137,7 @@ impl MailBox { format!("{}:2,{}", mid, flags) }; - // let mut flags = String::from(""); - // if flagged { - // flags += "F"; - // } - // if replied { - // flags += "R"; - // } - // if seen { - // flags += "S"; - // } - // println!("flags: {:?}", flags); - // let id = self.maildir.store_cur_with_flags(&msg.message_to_string().unwrap().as_bytes(), flags.as_str()).unwrap(); - - // if is_new { - // let msgpath = format!("{}{}", id, flags); - // std::fs::rename(msgpath, newpath)?; - - // self.maildir.path() - // } - - + let mut msgpath = self.path(); msgpath = if is_new { msgpath.join("new") diff --git a/tests/test_database.rs b/tests/test_database.rs index 557e0c3..098e271 100644 --- a/tests/test_database.rs +++ b/tests/test_database.rs @@ -85,7 +85,7 @@ mod database { mod atomic { - use super::*; + // use super::*; // TODO: how do I test this?? @@ -107,6 +107,7 @@ mod revision { assert!(rev0 == rev1); assert!(rev0 <= rev1); assert!(rev0 >= rev1); + assert!(!(rev0 < rev1)); assert!(!(rev0 > rev1)); } @@ -176,7 +177,7 @@ mod messages { let db = notmuch::Database::create(&mailbox.path()).unwrap(); let (msgid, filename) = mailbox.deliver(None, None, None, None, vec![], true, None, false, false, false).unwrap(); - let msg = db.index_file(&filename, None).unwrap(); + db.index_file(&filename, None).unwrap(); assert!(db.find_message(&msgid).unwrap().is_some()); db.remove_message(&filename).unwrap(); diff --git a/tests/test_message.rs b/tests/test_message.rs index 7a6391d..7af6f2c 100644 --- a/tests/test_message.rs +++ b/tests/test_message.rs @@ -249,11 +249,11 @@ mod properties { let msg = MessageFixture::new(); msg.message.add_property(&"foo", &"a").unwrap(); - let mut prop_keys: Vec = msg.message.properties(&"foo", false).map(|x| x.0).collect(); + let prop_keys: Vec = msg.message.properties(&"foo", false).map(|x| x.0).collect(); assert_eq!(prop_keys.len(), 1); assert_eq!(prop_keys, vec!["foo"]); - let mut prop_vals: Vec = msg.message.properties(&"foo", false).map(|x| x.1).collect(); + let prop_vals: Vec = msg.message.properties(&"foo", false).map(|x| x.1).collect(); assert_eq!(prop_vals.len(), 1); assert_eq!(prop_vals, vec!["a"]); } @@ -264,11 +264,11 @@ mod properties { msg.message.add_property(&"foo", &"a").unwrap(); msg.message.add_property(&"foobar", &"b").unwrap(); - let mut prop_keys: Vec = msg.message.properties(&"foo", false).map(|x| x.0).collect(); + let prop_keys: Vec = msg.message.properties(&"foo", false).map(|x| x.0).collect(); assert_eq!(prop_keys.len(), 2); assert_eq!(prop_keys, vec!["foo", "foobar"]); - let mut prop_vals: Vec = msg.message.properties(&"foo", false).map(|x| x.1).collect(); + let prop_vals: Vec = msg.message.properties(&"foo", false).map(|x| x.1).collect(); assert_eq!(prop_vals.len(), 2); assert_eq!(prop_vals, vec!["a", "b"]); } @@ -279,11 +279,11 @@ mod properties { msg.message.add_property(&"foo", &"a").unwrap(); msg.message.add_property(&"foobar", &"b").unwrap(); - let mut prop_keys: Vec = msg.message.properties(&"foo", true).map(|x| x.0).collect(); + let prop_keys: Vec = msg.message.properties(&"foo", true).map(|x| x.0).collect(); assert_eq!(prop_keys.len(), 1); assert_eq!(prop_keys, vec!["foo"]); - let mut prop_vals: Vec = msg.message.properties(&"foo", true).map(|x| x.1).collect(); + let prop_vals: Vec = msg.message.properties(&"foo", true).map(|x| x.1).collect(); assert_eq!(prop_vals.len(), 1); assert_eq!(prop_vals, vec!["a"]); } diff --git a/tests/test_tags.rs b/tests/test_tags.rs index 5ddabeb..3d39486 100644 --- a/tests/test_tags.rs +++ b/tests/test_tags.rs @@ -1,5 +1,4 @@ use std::sync::Arc; -use std::path::PathBuf; use fixtures::{MailBox, NotmuchCommand}; struct TagSetFixture { @@ -109,7 +108,6 @@ mod mutable { fn test_from_maildir_flags(){ let tagset = TagSetFixture::new(true, true); - let msgid = tagset.message.id(); tagset.message.remove_tag(&"flagged").unwrap(); tagset.message.maildir_flags_to_tags().unwrap(); @@ -125,20 +123,20 @@ mod mutable { let filename = tagset.message.filename(); let filestr = filename.to_string_lossy(); - let file_parts: Vec<&str> = filestr.split(",").collect(); + let file_parts: Vec<&str> = filestr.split(',').collect(); let flags = file_parts.last().unwrap(); println!("Flags {:?}", flags); - assert!(flags.contains("F")); + assert!(flags.contains('F')); tagset.message.remove_tag(&"flagged").unwrap(); tagset.message.tags_to_maildir_flags().unwrap(); let filename = tagset.message.filename(); let filestr = filename.to_string_lossy(); - let file_parts: Vec<&str> = filestr.split(",").collect(); + let file_parts: Vec<&str> = filestr.split(',').collect(); let flags = file_parts.last().unwrap(); - assert!(!flags.contains("F")); + assert!(!flags.contains('F')); } } \ No newline at end of file -- cgit v1.2.1 From 63635360cd25e95bfa2c52c09592e19e656e3d66 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Fri, 22 Nov 2019 19:29:41 +0100 Subject: allow using with NonSync --- src/utils.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/utils.rs b/src/utils.rs index 57e4004..b5b90f0 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -37,15 +37,25 @@ impl ToString for *const libc::c_char { } } -// pub type ScopedNonSyncSupercow<'a, OWNED, BORROWED = OWNED> = -// Supercow<'a, OWNED, BORROWED, -// Box + 'a>, -// BoxedStorage>; +#[cfg(not(nonsync))] pub type ScopedPhantomcow<'a, OWNED, BORROWED = OWNED, SHARED = Box + 'a>, STORAGE = BoxedStorage> = Supercow<'a, OWNED, BORROWED, SHARED, STORAGE, ()>; +#[cfg(not(nonsync))] pub type ScopedSupercow<'a, OWNED, BORROWED = OWNED, SHARED = Box + 'a>> = Supercow<'a, OWNED, BORROWED, SHARED, BoxedStorage>; + + +#[cfg(nonsync)] +pub type ScopedPhantomcow<'a, OWNED, BORROWED = OWNED, + SHARED = Box + 'a>, + STORAGE = BoxedStorage> = + Supercow<'a, OWNED, BORROWED, SHARED, STORAGE, ()>; + +#[cfg(nonsync)] +pub type ScopedSupercow<'a, OWNED, BORROWED = OWNED, SHARED = Box + 'a>> = + Supercow<'a, OWNED, BORROWED, SHARED, BoxedStorage>; + -- cgit v1.2.1 From 2231a5cf6cdeb90c1cdb75d161a0063d4a385576 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 26 Nov 2019 08:05:49 +0100 Subject: add tests for query --- src/messages.rs | 2 +- tests/lib.rs | 1 + tests/test_query.rs | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/test_thread.rs | 6 ---- 4 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 tests/test_query.rs diff --git a/src/messages.rs b/src/messages.rs index 48d30ef..cfba547 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -116,7 +116,7 @@ mod tests { #[test] #[should_panic] // until test data is filled in - fn recurse() -> () { + fn recurse() { match database::Database::open( &String::new(), database::DatabaseMode::ReadOnly, diff --git a/tests/lib.rs b/tests/lib.rs index e7ee0bc..44ec82f 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -8,6 +8,7 @@ extern crate lettre_email; mod fixtures; mod test_database; +mod test_query; mod test_thread; mod test_message; mod test_tags; diff --git a/tests/test_query.rs b/tests/test_query.rs new file mode 100644 index 0000000..ad8f299 --- /dev/null +++ b/tests/test_query.rs @@ -0,0 +1,97 @@ +use std::sync::Arc; +use fixtures::{NotmuchCommand, MailBox}; + + +struct QueryFixture { + // Return a single thread with 2 messages + pub mailbox: MailBox, + pub query: notmuch::Query<'static>, +} + +impl QueryFixture { + pub fn new() -> Self{ + let mailbox = MailBox::new(); + + let (msgid, _) = mailbox.deliver(None, Some("foo".to_string()), None, None, vec![], true, None, false, false, false).unwrap(); + mailbox.deliver(None, Some("bar".to_string()), None, None, vec![], true, None, false, false, false).unwrap(); + mailbox.deliver(None, Some("baz".to_string()), None, None, vec![("In-Reply-To".to_string(), format!("<{}>", msgid))], true, None, false, false, false).unwrap(); + mailbox.deliver(None, Some("foo qux".to_string()), None, None, vec![], true, None, false, false, false).unwrap(); + mailbox.deliver(None, Some("foo quux".to_string()), None, None, vec![], true, None, false, false, false).unwrap(); + + let cmd = NotmuchCommand::new(&mailbox.path()); + cmd.run(vec!["new"]).unwrap(); + + let query = { + let database = Arc::new(notmuch::Database::open(&mailbox.path(), notmuch::DatabaseMode::ReadWrite).unwrap()); + + notmuch::Query::create(database, &"foo".to_string()).unwrap() + }; + + Self { + mailbox, + query + } + } +} + +#[test] +fn test_iter_threads() { + let q = QueryFixture::new(); + + let threads = q.query.search_threads().unwrap(); + + let mut num = 0; + for _thread in threads { + num += 1; + } + + assert_eq!(num, 3); + +} + +#[test] +fn test_iter_threads_ext() { + let q = QueryFixture::new(); + + let threads = ::search_threads(q.query).unwrap(); + + let mut num = 0; + for _thread in threads { + num += 1; + } + + assert_eq!(num, 3); + +} + + +#[test] +fn test_iter_messages() { + let q = QueryFixture::new(); + + let messages = q.query.search_messages().unwrap(); + + let mut num = 0; + for _message in messages { + num += 1; + } + + assert_eq!(num, 3); + +} + +#[test] +fn test_iter_messages_ext() { + let q = QueryFixture::new(); + + let messages = ::search_messages(q.query).unwrap(); + + let mut num = 0; + for _message in messages { + num += 1; + } + + assert_eq!(num, 3); + +} + diff --git a/tests/test_thread.rs b/tests/test_thread.rs index 0909082..89f1ea0 100644 --- a/tests/test_thread.rs +++ b/tests/test_thread.rs @@ -40,12 +40,6 @@ fn test_threadid() { assert!(!thread.thread.id().is_empty()); } -#[test] -fn test_len() { - let thread = ThreadFixture::new(); - - assert_eq!(thread.thread.total_messages(), 2); -} #[test] fn test_toplevel() { -- cgit v1.2.1