Skip to main content

cidre/ns/
operation.rs

1use crate::{arc, define_cls, define_obj_type, ns, objc};
2
3#[cfg(feature = "dispatch")]
4use crate::dispatch;
5
6#[cfg(feature = "blocks")]
7use crate::blocks;
8
9define_obj_type!(
10    #[doc(alias = "NSOperation")]
11    pub Op(ns::Id)
12);
13
14impl Op {
15    define_cls!(NS_OPERATION);
16
17    #[objc::msg_send(isCancelled)]
18    pub fn is_cancelled(&self) -> bool;
19
20    #[objc::msg_send(cancel)]
21    pub fn cancel(&mut self);
22
23    /// A bool value indicating whether the operation is currently executing.
24    #[objc::msg_send(isExecuting)]
25    pub fn is_executing(&self) -> bool;
26
27    #[objc::msg_send(isFinished)]
28    pub fn is_finished(&self) -> bool;
29
30    #[objc::msg_send(isReady)]
31    pub fn is_ready(&self) -> bool;
32
33    /// Makes the receiver dependent on the completion of the specified operation.
34    ///
35    /// The receiver is not considered ready to execute until all of its dependent operations have finished executing.
36    /// If the receiver is already executing its task, adding dependencies has no practical effect. This method
37    ///  may change the isReady and dependencies properties of the receiver.
38    ///
39    /// It is a programmer error to create any circular dependencies among a set of operations.
40    ///  Doing so can cause a deadlock among the operations and may freeze your program.
41    #[objc::msg_send(addDependency:)]
42    pub fn add_dependency(&mut self, val: &ns::Op);
43
44    /// Removes the receiver’s dependence on the specified operation.
45    #[objc::msg_send(removeDependency:)]
46    pub fn remove_dependency(&mut self, val: &ns::Op);
47
48    /// An array of the operation objects that must finish executing before the current object can begin executing.
49    #[objc::msg_send(dependencies)]
50    pub fn dependencies(&self) -> arc::R<ns::Array<ns::Op>>;
51
52    #[objc::msg_send(name)]
53    pub fn name(&self) -> Option<arc::R<ns::String>>;
54
55    #[objc::msg_send(setName:)]
56    pub fn set_name(&mut self, val: Option<&ns::String>);
57
58    /// Begins the execution of the operation.
59    #[objc::msg_send(start)]
60    pub fn start(&mut self);
61
62    /// Performs the receiver’s non-concurrent task.
63    #[objc::msg_send(main)]
64    pub fn main(&mut self);
65}
66
67define_obj_type!(
68    #[doc(alias = "NSBlockOperation")]
69    pub BlockOp(Op)
70);
71
72impl BlockOp {
73    define_cls!(NS_BLOCK_OPERATION);
74
75    #[cfg(feature = "blocks")]
76    #[objc::msg_send(blockOperationWithBlock:)]
77    pub fn with_block(block: &mut blocks::WorkBlock) -> arc::R<Self>;
78}
79
80impl ns::KvObserverRegistration for Op {}
81impl ns::KvObserverRegistration for BlockOp {}
82
83define_obj_type!(
84    #[doc(alias = "NSOperationQueue")]
85    pub OpQueue(ns::Id), NS_OPERATION_QUEUE
86);
87
88impl ns::KvObserverRegistration for OpQueue {}
89
90impl OpQueue {
91    /// The default maximum number of operations to invoke concurrently in a queue.
92    ///
93    /// The operation queue determines this number dynamically based on current system conditions.
94    #[doc(alias = "NSOperationQueueDefaultMaxConcurrentOperationCount")]
95    pub const DEFAULT_MAX_CONCURRENT_OP_COUNT: isize = -1;
96
97    #[objc::msg_send(name)]
98    pub fn name(&self) -> Option<arc::R<ns::String>>;
99
100    #[objc::msg_send(setName:)]
101    pub fn set_name(&mut self, name: Option<&ns::String>);
102
103    #[objc::msg_send(addOperation:)]
104    pub fn add_op(&mut self, op: &Op);
105
106    #[cfg(feature = "blocks")]
107    #[objc::msg_send(addOperationWithBlock:)]
108    pub fn add_op_with_block(&mut self, block: &mut blocks::WorkBlock);
109
110    #[cfg(feature = "blocks")]
111    #[objc::msg_send(addBarrierBlock:)]
112    pub fn add_barrier_block(&mut self, barrier: &mut blocks::WorkBlock);
113
114    /// The maximum number of queued operations that can run at the same time.
115    ///
116    /// The value in this property affects only the operations that the current queue has executing at the same time.
117    /// Other operation queues can also execute their maximum number of operations in parallel.
118    /// Reducing the number of concurrent operations does not affect any operations that are currently executing.
119    /// Specifying the value NSOperationQueueDefaultMaxConcurrentOperationCount (which is recommended) causes the
120    /// system to set the maximum number of operations based on system conditions.
121    /// The default value of this property is defaultMaxConcurrentOperationCount. You may monitor changes to the value
122    /// of this property using Key-value observing. Configure an observer to monitor the maxConcurrentOperationCount
123    /// key path of the operation queue.
124    #[objc::msg_send(maxConcurrentOperationCount)]
125    pub fn max_concurrent_ops(&self) -> isize;
126
127    #[objc::msg_send(setMaxConcurrentOperationCount:)]
128    pub fn set_max_concurrent_ops(&mut self, val: isize);
129
130    /// A bool value indicating whether the queue is actively scheduling operations for execution.
131    ///
132    /// When the value of this property is false, the queue actively starts operations that are in the queue and ready
133    /// to execute. Setting this property to true prevents the queue from starting any queued operations,
134    /// but already executing operations continue to execute. You may continue to add operations to a queue
135    /// that is suspended but those operations are not scheduled for execution until you change this property to false.
136    ///
137    /// Operations are removed from the queue only when they finish executing. However, in order to finish executing,
138    /// an operation must first be started. Because a suspended queue does not start any new operations, it does not
139    /// remove any operations (including cancelled operations) that are currently queued and not executing.
140    ///
141    /// The default value of this property is false.
142    #[objc::msg_send(isSuspended)]
143    pub fn is_suspended(&self) -> bool;
144
145    #[objc::msg_send(setSuspended:)]
146    pub fn set_suspended(&mut self, val: bool);
147
148    #[objc::msg_send(cancelAllOperations)]
149    pub fn cancel_all_ops(&mut self);
150
151    #[cfg(feature = "dispatch")]
152    #[objc::msg_send(underlyingQueue)]
153    pub fn underlying_queue(&self) -> Option<arc::R<dispatch::Queue>>;
154
155    #[cfg(feature = "dispatch")]
156    #[objc::msg_send(setUnderlyingQueue:)]
157    pub unsafe fn set_underlying_queue_throws(&mut self, val: Option<&dispatch::Queue>);
158
159    #[cfg(feature = "dispatch")]
160    pub fn set_underlying_queue<'ear>(
161        &mut self,
162        val: Option<&dispatch::Queue>,
163    ) -> ns::ExResult<'ear> {
164        ns::try_catch(|| unsafe { self.set_underlying_queue_throws(val) })
165    }
166
167    #[objc::msg_send(currentQueue)]
168    pub fn current() -> Option<arc::R<Self>>;
169
170    #[objc::msg_send(mainQueue)]
171    pub fn main() -> arc::R<Self>;
172}
173
174/// ProgressReporting
175impl OpQueue {
176    #[objc::msg_send(progress)]
177    pub fn progress(&self) -> arc::R<ns::Progress>;
178}
179
180unsafe extern "C" {
181    static NS_OPERATION: &'static objc::Class<Op>;
182    static NS_BLOCK_OPERATION: &'static objc::Class<BlockOp>;
183    static NS_OPERATION_QUEUE: &'static objc::Class<OpQueue>;
184}
185
186#[cfg(test)]
187mod tests {
188    use crate::{dispatch, ns};
189
190    #[test]
191    fn basics() {
192        assert!(ns::OpQueue::current().is_none());
193        let mut queue = ns::OpQueue::new();
194        assert_eq!(
195            ns::OpQueue::DEFAULT_MAX_CONCURRENT_OP_COUNT,
196            queue.max_concurrent_ops()
197        );
198        assert!(queue.underlying_queue().is_none());
199        let dqueue = dispatch::Queue::new();
200        queue.set_underlying_queue(Some(&dqueue)).unwrap();
201        assert_eq!(queue.underlying_queue().as_ref(), Some(&dqueue));
202        assert_eq!(-1, queue.max_concurrent_ops());
203        queue.set_max_concurrent_ops(10);
204        assert_eq!(10, queue.max_concurrent_ops());
205        assert_eq!(queue.underlying_queue().as_ref(), Some(&dqueue));
206
207        let main_op_queue = ns::OpQueue::main();
208        println!("tid {main_op_queue:?}");
209    }
210}