1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
use std::ops::Drop;
use std::borrow::Cow;

use ffi;
use utils::{ToStr, ScopedSupercow, ScopedPhantomcow};
use Messages;
use MessageOwner;
use Tags;
use TagsOwner;
use Query;

#[derive(Debug)]
pub struct Thread<'d, 'q>
where
    'd: 'q
{
    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 {}

impl<'d, 'q> Thread<'d, 'q>
where
    'd: 'q
{
    pub(crate) fn from_ptr<P>(ptr: *mut ffi::notmuch_thread_t, owner: P) -> Thread<'d, 'q>
    where
        P: Into<ScopedPhantomcow<'q, Query<'d>>>,
    {
        Thread {
            ptr,
            marker: owner.into(),
        }
    }

    pub fn id(self: &Self) -> &str {
        let tid = unsafe { ffi::notmuch_thread_get_thread_id(self.ptr) };
        tid.to_str().unwrap()
    }

    pub fn total_messages(self: &Self) -> i32 {
        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.ptr) }
    }

    pub fn toplevel_messages(self: &Self) -> Messages<'_, Self> {
        <Self as ThreadExt<'d, 'q>>::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> {
        <Self as ThreadExt<'d, 'q>>::messages(self)
    }

    pub fn tags(&self) -> Tags<'_, Self> {
        <Self as ThreadExt<'d, 'q>>::tags(self)
    }

    pub fn subject(self: &Self) -> Cow<'_, str> {
        let sub = unsafe { ffi::notmuch_thread_get_subject(self.ptr) };
        sub.to_string_lossy()
    }

    pub fn authors(self: &Self) -> Vec<String> {
        let athrs = unsafe { ffi::notmuch_thread_get_authors(self.ptr) };

        athrs
            .to_string_lossy()
            .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.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.ptr) as i64 }
    }
}

pub trait ThreadExt<'d, 'q>
where
    'd: 'q
{
    fn tags<'s, S>(thread: S) -> Tags<'s, Thread<'d, 'q>>
    where
        S: Into<ScopedSupercow<'s, Thread<'d, 'q>>>,
    {
        let threadref = thread.into();
        Tags::from_ptr(
            unsafe { ffi::notmuch_thread_get_tags(threadref.ptr) },
            ScopedSupercow::phantom(threadref),
        )
    }

    fn toplevel_messages<'s, S>(thread: S) -> Messages<'s, Thread<'d, 'q>>
    where
        S: Into<ScopedSupercow<'s, Thread<'d, 'q>>>,
    {
        let threadref = thread.into();
        Messages::from_ptr(
            unsafe { ffi::notmuch_thread_get_toplevel_messages(threadref.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<ScopedSupercow<'s, Thread<'d, 'q>>>,
    {
        let threadref = thread.into();
        Messages::from_ptr(
            unsafe { ffi::notmuch_thread_get_messages(threadref.ptr) },
            ScopedSupercow::phantom(threadref),
        )
    }
}

impl<'d, 'q> ThreadExt<'d, 'q> for Thread<'d, 'q> where 'd: 'q {}

unsafe impl<'d, 'q> Send for Thread<'d, 'q> where 'd: 'q {}
unsafe impl<'d, 'q> Sync for Thread<'d, 'q> where 'd: 'q {}