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
// Copyright 2017 Lyndon Brown
//
// This file is part of the PulseAudio Rust language binding.
//
// This library is free software; you can redistribute it and/or modify it under the terms of the
// GNU Lesser General Public License as published by the Free Software Foundation; either version
// 2.1 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License along with this library;
// if not, see <http://www.gnu.org/licenses/>.

//! Main loop timer events.
//!
//! # Notes
//!
//! Time events may be created (or reset) with either Unix time values or real-time (monotonic)
//! based values (though if the mainloop does not support monotonic time value, they may be silently
//! converted to unix time).
//!
//! Note that time events created with one form of time value can be freely restarted with the other
//! form of time value.

use std::os::raw::c_void;
use std::rc::Rc;
use libc::timeval;
use super::super::api::{MainloopApi, MainloopInnerType};
use time::{UnixTs, MonotonicTs, Timeval, USEC_INVALID};

pub use capi::pa_time_event as TimeEventInternal;

/// A timer event source
pub struct TimeEvent<T>
    where T: MainloopInnerType
{
    ptr: *mut TimeEventInternal,
    /// Source mainloop
    owner: Rc<T>,
    /// Saved callback closure, for later destruction
    _saved_cb: EventCb,
}

/// A reference to a timer event source, provided to the callback, allowing modification within the
/// callback itself
pub struct TimeEventRef<T: 'static>
    where T: MainloopInnerType
{
    ptr: *mut TimeEventInternal,
    /// Source mainloop
    owner: Rc<T>,
}

pub(crate) type EventCb = ::callbacks::MultiUseCallback<FnMut(*mut TimeEventInternal),
    extern "C" fn(a: *const MainloopApi, e: *mut TimeEventInternal, tv: *const timeval,
    userdata: *mut c_void)>;

impl<T> TimeEvent<T>
    where T: MainloopInnerType
{
    pub(crate) fn from_raw(ptr: *mut TimeEventInternal, mainloop_inner: Rc<T>, callback: EventCb
        ) -> Self
    {
        assert_eq!(false, ptr.is_null());
        Self { ptr: ptr, owner: mainloop_inner, _saved_cb: callback }
    }

    /// Restart this timer event source (whether still running or already expired) with a new Unix
    /// time.
    pub fn restart(&mut self, t: &UnixTs) {
        let fn_ptr = (*self.owner).get_api().time_restart.unwrap();
        fn_ptr(self.ptr, &(t.0).0);
    }

    /// Restart this timer event source (whether still running or already expired) with a new
    /// monotonic time.
    pub fn restart_rt(&mut self, t: MonotonicTs) {
        assert_ne!(t.0, USEC_INVALID);
        let mut tv = Timeval::new_zero();
        tv.set_rt(t.0, (*self.owner).supports_rtclock());

        let fn_ptr = (*self.owner).get_api().time_restart.unwrap();
        fn_ptr(self.ptr, &tv.0);
    }
}

impl<T> TimeEventRef<T>
    where T: MainloopInnerType
{
    pub(crate) fn from_raw(ptr: *mut TimeEventInternal, mainloop_inner: Rc<T>) -> Self {
        assert_eq!(false, ptr.is_null());
        Self { ptr: ptr, owner: mainloop_inner }
    }

    /// Restart this timer event source (whether still running or already expired) with a new Unix
    /// time.
    pub fn restart(&mut self, t: &UnixTs) {
        let fn_ptr = (*self.owner).get_api().time_restart.unwrap();
        fn_ptr(self.ptr, &(t.0).0);
    }

    /// Restart this timer event source (whether still running or already expired) with a new
    /// monotonic time.
    pub fn restart_rt(&mut self, t: MonotonicTs) {
        assert_ne!(t.0, USEC_INVALID);
        let mut tv = Timeval::new_zero();
        tv.set_rt(t.0, (*self.owner).supports_rtclock());

        let fn_ptr = (*self.owner).get_api().time_restart.unwrap();
        fn_ptr(self.ptr, &tv.0);
    }
}

impl<T> Drop for TimeEvent<T>
    where T: MainloopInnerType
{
    fn drop(&mut self) {
        let fn_ptr = (*self.owner).get_api().time_free.unwrap();
        fn_ptr(self.ptr);
    }
}

/// Proxy for the event callback.
/// Warning: This is for multi-use cases! It does **not** destroy the actual closure callback, which
/// must be accomplished separately to avoid a memory leak.
pub(crate)
extern "C"
fn event_cb_proxy(_: *const MainloopApi, e: *mut TimeEventInternal, _: *const timeval,
    userdata: *mut c_void)
{
    let callback = EventCb::get_callback(userdata);
    callback(e);
}