coremidi 0.9.0

CoreMIDI library for Rust
use std::ops::Deref;

use coremidi_sys::{
    ItemCount, MIDIEndpointDispose, MIDIEndpointRef, MIDIGetDestination,
    MIDIGetNumberOfDestinations,
};

use crate::endpoints::endpoint::Endpoint;
use crate::Object;

/// A [MIDI destination](https://developer.apple.com/documentation/coremidi/midiendpointref) owned by an entity.
///
/// A destination can be created from an index like this:
///
/// ```rust,no_run
/// let destination = coremidi::Destination::from_index(0).unwrap();
/// println!("The destination at index 0 has display name '{}'", destination.display_name().unwrap());
/// ```
///
#[derive(Debug, Hash, Eq, PartialEq)]
pub struct Destination {
    pub(crate) endpoint: Endpoint,
}

impl Destination {
    pub(crate) fn new(endpoint_ref: MIDIEndpointRef) -> Self {
        Self {
            endpoint: Endpoint::new(endpoint_ref),
        }
    }

    /// Create a destination endpoint from its index.
    /// See [MIDIGetDestination](https://developer.apple.com/documentation/coremidi/1495108-midigetdestination)
    ///
    pub fn from_index(index: usize) -> Option<Destination> {
        let endpoint_ref = unsafe { MIDIGetDestination(index as ItemCount) };
        match endpoint_ref {
            0 => None,
            _ => Some(Self::new(endpoint_ref)),
        }
    }
}

impl Clone for Destination {
    fn clone(&self) -> Self {
        Self::new(self.endpoint.object.0)
    }
}

impl AsRef<Object> for Destination {
    fn as_ref(&self) -> &Object {
        &self.endpoint.object
    }
}

impl AsRef<Endpoint> for Destination {
    fn as_ref(&self) -> &Endpoint {
        &self.endpoint
    }
}

impl Deref for Destination {
    type Target = Endpoint;

    fn deref(&self) -> &Endpoint {
        &self.endpoint
    }
}

/// Destination endpoints available in the system.
///
/// The number of destinations available in the system can be retrieved with:
///
/// ```
/// let number_of_destinations = coremidi::Destinations::count();
/// ```
///
/// The destinations in the system can be iterated as:
///
/// ```rust,no_run
/// for destination in coremidi::Destinations {
///   println!("{}", destination.display_name().unwrap());
/// }
/// ```
///
pub struct Destinations;

impl Destinations {
    /// Get the number of destinations available in the system for sending MIDI messages.
    /// See [MIDIGetNumberOfDestinations](https://developer.apple.com/documentation/coremidi/1495309-midigetnumberofdestinations).
    ///
    pub fn count() -> usize {
        unsafe { MIDIGetNumberOfDestinations() as usize }
    }
}

impl IntoIterator for Destinations {
    type Item = Destination;
    type IntoIter = DestinationsIterator;

    fn into_iter(self) -> Self::IntoIter {
        DestinationsIterator {
            index: 0,
            count: Self::count(),
        }
    }
}

pub struct DestinationsIterator {
    index: usize,
    count: usize,
}

impl Iterator for DestinationsIterator {
    type Item = Destination;

    fn next(&mut self) -> Option<Destination> {
        if self.index < self.count {
            let destination = Destination::from_index(self.index);
            self.index += 1;
            destination
        } else {
            None
        }
    }
}

/// A [MIDI virtual destination](https://developer.apple.com/documentation/coremidi/3566476-mididestinationcreatewithprotoco) owned by a client.
///
/// A virtual destination can be created like:
///
/// ```rust,no_run
/// use coremidi::Protocol;
/// let client = coremidi::Client::new("example-client").unwrap();
/// client.virtual_destination_with_protocol("example-destination", Protocol::Midi10, |event_list| println!("{:?}", event_list)).unwrap();
/// ```
///
#[derive(Debug, Hash, Eq, PartialEq)]
pub struct VirtualDestination {
    pub(crate) endpoint: Endpoint,
}

impl VirtualDestination {
    pub(crate) fn new(endpoint_ref: MIDIEndpointRef) -> Self {
        Self {
            endpoint: Endpoint::new(endpoint_ref),
        }
    }
}

impl Deref for VirtualDestination {
    type Target = Endpoint;

    fn deref(&self) -> &Endpoint {
        &self.endpoint
    }
}

impl From<Object> for VirtualDestination {
    fn from(object: Object) -> Self {
        Self::new(object.0)
    }
}

impl Drop for VirtualDestination {
    fn drop(&mut self) {
        unsafe { MIDIEndpointDispose(self.endpoint.object.0) };
    }
}