1 use coremidi_sys::{
2     ItemCount, MIDIEndpointDispose, MIDIGetDestination, MIDIGetNumberOfDestinations,
3 };
4 
5 use std::ops::Deref;
6 
7 use crate::{callback::BoxedCallback, object::Object, packets::PacketList};
8 
9 use super::Endpoint;
10 
11 /// A [MIDI source](https://developer.apple.com/reference/coremidi/midiendpointref) owned by an entity.
12 ///
13 /// A source can be created from an index like this:
14 ///
15 /// ```rust,no_run
16 /// let source = coremidi::Destination::from_index(0).unwrap();
17 /// println!("The source at index 0 has display name '{}'", source.display_name().unwrap());
18 /// ```
19 ///
20 #[derive(Debug)]
21 pub struct Destination {
22     pub(crate) endpoint: Endpoint,
23 }
24 
25 impl Destination {
26     /// Create a destination endpoint from its index.
27     /// See [MIDIGetDestination](https://developer.apple.com/reference/coremidi/1495108-midigetdestination)
28     ///
from_index(index: usize) -> Option<Destination>29     pub fn from_index(index: usize) -> Option<Destination> {
30         let endpoint_ref = unsafe { MIDIGetDestination(index as ItemCount) };
31         match endpoint_ref {
32             0 => None,
33             _ => Some(Destination {
34                 endpoint: Endpoint {
35                     object: Object(endpoint_ref),
36                 },
37             }),
38         }
39     }
40 }
41 
42 impl Deref for Destination {
43     type Target = Endpoint;
44 
deref(&self) -> &Endpoint45     fn deref(&self) -> &Endpoint {
46         &self.endpoint
47     }
48 }
49 
50 /// Destination endpoints available in the system.
51 ///
52 /// The number of destinations available in the system can be retrieved with:
53 ///
54 /// ```
55 /// let number_of_destinations = coremidi::Destinations::count();
56 /// ```
57 ///
58 /// The destinations in the system can be iterated as:
59 ///
60 /// ```rust,no_run
61 /// for destination in coremidi::Destinations {
62 ///   println!("{}", destination.display_name().unwrap());
63 /// }
64 /// ```
65 ///
66 pub struct Destinations;
67 
68 impl Destinations {
69     /// Get the number of destinations available in the system for sending MIDI messages.
70     /// See [MIDIGetNumberOfDestinations](https://developer.apple.com/reference/coremidi/1495309-midigetnumberofdestinations).
71     ///
count() -> usize72     pub fn count() -> usize {
73         unsafe { MIDIGetNumberOfDestinations() as usize }
74     }
75 }
76 
77 impl IntoIterator for Destinations {
78     type Item = Destination;
79     type IntoIter = DestinationsIterator;
80 
into_iter(self) -> Self::IntoIter81     fn into_iter(self) -> Self::IntoIter {
82         DestinationsIterator {
83             index: 0,
84             count: Self::count(),
85         }
86     }
87 }
88 
89 pub struct DestinationsIterator {
90     index: usize,
91     count: usize,
92 }
93 
94 impl Iterator for DestinationsIterator {
95     type Item = Destination;
96 
next(&mut self) -> Option<Destination>97     fn next(&mut self) -> Option<Destination> {
98         if self.index < self.count {
99             let destination = Destination::from_index(self.index);
100             self.index += 1;
101             destination
102         } else {
103             None
104         }
105     }
106 }
107 
108 /// A [MIDI virtual destination](https://developer.apple.com/reference/coremidi/1495347-mididestinationcreate) owned by a client.
109 ///
110 /// A virtual destination can be created like:
111 ///
112 /// ```rust,no_run
113 /// let client = coremidi::Client::new("example-client").unwrap();
114 /// client.virtual_destination("example-destination", |packet_list| println!("{}", packet_list)).unwrap();
115 /// ```
116 ///
117 #[derive(Debug)]
118 pub struct VirtualDestination {
119     // Note: the order is important here, endpoint needs to be dropped first
120     pub(crate) endpoint: Endpoint,
121     pub(crate) callback: BoxedCallback<PacketList>,
122 }
123 
124 impl VirtualDestination {}
125 
126 impl Deref for VirtualDestination {
127     type Target = Endpoint;
128 
deref(&self) -> &Endpoint129     fn deref(&self) -> &Endpoint {
130         &self.endpoint
131     }
132 }
133 
134 impl Drop for VirtualDestination {
drop(&mut self)135     fn drop(&mut self) {
136         unsafe { MIDIEndpointDispose(self.endpoint.object.0) };
137     }
138 }
139