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
#![cfg_attr(feature = "backtrace", feature(error_generic_member_access))]

#[cfg(feature = "backtrace")]
use std::backtrace::Backtrace;

#[derive(thiserror::Error, Debug)]
#[error("channellib receive error")]
pub struct RecvError {
    #[from]
    source: crossbeam_channel::RecvError,
    #[cfg(feature = "backtrace")]
    pub backtrace: Backtrace,
}

#[derive(thiserror::Error, Debug)]
#[error("channellib receive timeout error")]
pub struct RecvTimeoutError {
    #[from]
    source: crossbeam_channel::RecvTimeoutError,
    #[cfg(feature = "backtrace")]
    pub backtrace: Backtrace,
}

impl RecvTimeoutError {
    #[inline(always)]
    pub fn is_timeout(&self) -> bool {
        self.source.is_timeout()
    }
}

#[derive(thiserror::Error, Debug)]
#[error("channellib try receive error")]
pub struct TryRecvError {
    #[from]
    source: crossbeam_channel::TryRecvError,
    #[cfg(feature = "backtrace")]
    pub backtrace: Backtrace,
}

impl TryRecvError {
    pub fn inner(self) -> crossbeam_channel::TryRecvError {
        self.source
    }

    pub fn is_empty(&self) -> bool {
        matches!(self.source, crossbeam_channel::TryRecvError::Empty)
    }

    pub fn is_disconnected(&self) -> bool {
        matches!(self.source, crossbeam_channel::TryRecvError::Disconnected)
    }
}

#[derive(thiserror::Error)]
#[error("channellib send error")]
pub struct SendError<T> {
    inner: crossbeam_channel::SendError<T>,
    #[cfg(feature = "backtrace")]
    pub backtrace: Backtrace,
}

impl<T> std::fmt::Debug for SendError<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
        write!(f, "channellib::SendError")
    }
}

// ------

pub struct Receiver<T>(crossbeam_channel::Receiver<T>);

impl<T> Receiver<T> {
    pub fn into_inner(self) -> crossbeam_channel::Receiver<T> {
        self.0
    }

    #[inline(always)]
    pub fn recv(&self) -> Result<T, RecvError> {
        self.0.recv().map_err(Into::into)
    }

    #[inline(always)]
    pub fn try_recv(&self) -> Result<T, TryRecvError> {
        self.0.try_recv().map_err(Into::into)
    }

    #[inline(always)]
    pub fn recv_timeout(&self, dur: std::time::Duration) -> Result<T, RecvTimeoutError> {
        self.0.recv_timeout(dur).map_err(Into::into)
    }
}

pub struct Sender<T>(crossbeam_channel::Sender<T>);

impl<T> Sender<T> {
    pub fn into_inner(self) -> crossbeam_channel::Sender<T> {
        self.0
    }

    #[inline(always)]
    pub fn send(&self, msg: T) -> Result<(), SendError<T>> {
        self.0.send(msg).map_err(|e| SendError {
            inner: e,
            #[cfg(feature = "backtrace")]
            backtrace: Backtrace::capture(),
        })
    }

    #[inline(always)]
    pub fn is_full(&self) -> bool {
        self.0.is_full()
    }
}

impl<T> Clone for Sender<T> {
    #[inline(always)]
    fn clone(&self) -> Sender<T> {
        Sender(self.0.clone())
    }
}

#[inline(always)]
pub fn bounded<T>(cap: usize) -> (Sender<T>, Receiver<T>) {
    let (tx, rx) = crossbeam_channel::bounded(cap);
    (Sender(tx), Receiver(rx))
}

#[inline(always)]
pub fn unbounded<T>() -> (Sender<T>, Receiver<T>) {
    let (tx, rx) = crossbeam_channel::unbounded();
    (Sender(tx), Receiver(rx))
}