<commit_before>//!
//! This module is an attempt to provide a friendly, rust-esque interface to
//! Apple's Audio Unit API.
//!
//! An audio unit can be constructed with the builder pattern.
//!
//! Learn more about the Audio Unit API here:
//! https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40003278-CH1-SW2
//!

use bindings::audio_unit as au;
use error::{Error, AudioUnitError};
use libc;
use self::stream_format::StreamFormat;
use std::mem;

pub mod audio_format;
pub mod stream_format;

/// Represents the input and output scope.
#[derive(Copy, Clone, Debug)]
pub enum Scope {
    Output = 0,
    Input  = 1,
}

/// Represents the input and output elements .
#[derive(Copy, Clone, Debug)]
pub enum Element {
    Output = 0,
    Input  = 1,
}

/// Represents the different types of Audio Units.
#[derive(Copy, Clone, Debug)]
pub enum Type {
    Output          = 1635086197,
    MusicDevice     = 1635085685,
    MusicEffect     = 1635085670,
    FormatConverter = 1635083875,
    Effect          = 1635083896,
    Mixer           = 1635085688,
    Panner          = 1635086446,
    Generator       = 1635084142,
    OfflineEffect   = 1635086188,
    MidiProcessor   = 1635085673,
}

/// Represents the different audio unit sub types.
#[derive(Copy, Clone, Debug)]
pub enum SubType {
    GenericOutput        = 1734700658,
    HalOutput            = 1634230636,
    DefaultOutput        = 1684366880,
    SystemOutput         = 1937339168,
    VoiceProcessingIO    = 1987078511,
    DLSSynth             = 1684828960,
    Sampler              = 1935764848,
    MIDISynth            = 1836284270,
    AUConverter          = 1668247158,
    Varispeed            = 1986097769,
    DeferredRenderer     = 1684366962,
    Splitter             = 1936747636,
    Merger               = 1835364967,
    NewTimePitch         = 1853191280,
    AUiPodTimeOther      = 1768977519,
    RoundTripAAC         = 1918984547,
    PeakLimiter          = 1819112562,
    DynamicsProcessor    = 1684237680,
    LowPassFilter        = 1819304307,
    HighPassFilter       = 1752195443,
    BandPassFilter       = 1651532147,
    HighShelfFilter      = 1752393830,
    LowShelfFilter       = 1819502694,
    ParametricEQ         = 1886217585,
    Distortion           = 1684632436,
    Delay                = 1684368505,
    SampleDelay          = 1935961209,
    GraphicEQ            = 1735550321,
    MultiBandCompressor  = 1835232624,
    MatrixReverb         = 1836213622,
    Pitch                = 1953329268,
    AUFilter             = 1718185076,
    NetSend              = 1853058660,
    RogerBeep            = 1919903602,
    NBandEQ              = 1851942257,
    MultiChannelMixer    = 1835232632,
    MatrixMixer          = 1836608888,
    SpatialMixer         = 862217581,
    StereoMixer          = 1936554098,
    Mixer3D              = 862219640,
    SphericalHeadPanner  = 1936746610,
    VectorPanner         = 1986158963,
    SoundFieldPanner     = 1634558569,
    HRTFPanner           = 1752331366,
    NetReceive           = 1852990326,
    ScheduledSoundPlayer = 1936945260,
    AudioFilePlayer      = 1634103404,
}

/// A rust representation of the au::AudioUnit.
pub struct AudioUnit {
    audio_unit: au::AudioUnit,
}

impl AudioUnit {

    /// Construct a new AudioUnit.
    pub fn new(au_type: Type, sub_type: SubType) -> AudioUnitBuilder {

        // A description of the audio unit we desire.
        let desc = au::AudioComponentDescription {
            componentType         : au_type as libc::c_uint,
            componentSubType      : sub_type as libc::c_uint,
            componentManufacturer : au::kAudioUnitManufacturer_Apple,
            componentFlags        : 0,
            componentFlagsMask    : 0,
        };

        unsafe {
            use std::ptr::null_mut;
            // Find the default audio unit for the description.
            let component_result = match au::AudioComponentFindNext(null_mut(), &desc as *const _) {
                component if component.is_null() => Err(Error::NoMatchingDefaultAudioUnitFound),
                component                        => Ok(component),
            };

            // Get an instance of the default audio unit using the component.
            let mut audio_unit: au::AudioUnit = mem::uninitialized();

            let audio_unit_result = match component_result {
                Ok(component) => {
                    au::AudioComponentInstanceNew(component, &mut audio_unit as *mut au::AudioUnit);
                    Ok(audio_unit)
                },
                Err(err) => Err(err),
            };
            AudioUnitBuilder { audio_unit_result: audio_unit_result }
        }
    }

    /// Return the current Stream Format for the AudioUnit.
    pub fn stream_format(&self) -> StreamFormat {
        unsafe {
            let mut asbd: au::AudioStreamBasicDescription = mem::uninitialized();
            let mut size = ::std::mem::size_of::<au::AudioStreamBasicDescription>() as u32;
            if let Err(err) = Error::from_os_status(au::AudioUnitGetProperty(
                                                        self.audio_unit,
                                                        au::kAudioUnitProperty_StreamFormat,
                                                        Scope::Output as libc::c_uint,
                                                        Element::Output as libc::c_uint,
                                                        &mut asbd as *mut _ as *mut libc::c_void,
                                                        &mut size as *mut au::UInt32)) {
                panic!("{:?}", err);
            }
            StreamFormat::from_asbd(asbd)
        }
    }

    /// Close the audio unit.
    pub fn close(self) {}

}

impl Drop for AudioUnit {
    fn drop(&mut self) {
        unsafe {
            use error;
            use std::error::Error;
            if let Err(err) = error::Error::from_os_status(au::AudioOutputUnitStop(self.audio_unit)) {
                panic!("{:?}", err.description());
            }
            if let Err(err) = error::Error::from_os_status(au::AudioUnitUninitialize(self.audio_unit)) {
                panic!("{:?}", err.description());
            }
        }
    }
}

/// A context on which to build the audio unit.
pub struct AudioUnitBuilder {
    audio_unit_result: Result<au::AudioUnit, Error>,
}

impl AudioUnitBuilder {

    /// Pass a render callback (aka "Input Procedure") to the audio unit.
    /// This will be called every time the AudioUnit requests audio.
    /// f is a boxed FnMut whose arg is [frames[channels]].
    #[inline]
    pub fn render_callback(self, f: Box<FnMut(&mut[&mut[f32]], NumFrames) -> Result<(), String>>) -> AudioUnitBuilder {
        let audio_unit_result = match self.audio_unit_result {
            Err(err) => Err(err),
            Ok(audio_unit) => {
                let size_of_render_callback_struct = mem::size_of::<au::AURenderCallbackStruct>() as u32;

                let callback = Box::new(RenderCallback { f: f });
                unsafe {
                    // Setup render callback.
                    let render_callback = au::AURenderCallbackStruct {
                        inputProc: Some(input_proc), // TODO
                        inputProcRefCon: mem::transmute(callback),
                    };

                    match Error::from_os_status(au::AudioUnitSetProperty(
                                                audio_unit,
                                                au::kAudioUnitProperty_SetRenderCallback,
                                                Scope::Input as libc::c_uint,
                                                Element::Output as libc::c_uint,
                                                &render_callback as *const _ as *const libc::c_void,
                                                size_of_render_callback_struct)) {
                        Ok(()) => Ok(audio_unit),
                        Err(err) => Err(err),
                    }
                }
            },
        };
        AudioUnitBuilder { audio_unit_result: audio_unit_result }
    }

    /// Finish building the audio unit, intialise it and start it.
    pub fn start(self) -> Result<AudioUnit, Error> {
        let audio_unit = try!(self.audio_unit_result);
        unsafe {
            // Initialise the audio unit!
            try!(Error::from_os_status(au::AudioUnitInitialize(audio_unit)));
            try!(Error::from_os_status(au::AudioOutputUnitStart(audio_unit)));
        }
        Ok(AudioUnit { audio_unit: audio_unit })
    }

}

pub type NumFrames = usize;

/// A struct in which we will pass the callback to the AudioUnit's render callback.
pub struct RenderCallback {
    f: Box<FnMut(&mut[&mut[f32]], NumFrames) -> Result<(), String>>,
}

/// Callback procedure that will be called each time our audio_unit requests audio.
extern "C" fn input_proc(in_ref_con: *mut libc::c_void,
                         _io_action_flags: *mut au::AudioUnitRenderActionFlags,
                         _in_time_stamp: *const au::AudioTimeStamp,
                         _in_bus_number: au::UInt32,
                         in_number_frames: au::UInt32,
                         io_data: *mut au::AudioBufferList) -> au::OSStatus {
    let callback: *mut RenderCallback = in_ref_con as *mut _;
    unsafe {
        let num_channels = (*io_data).mNumberBuffers as usize;
        let mut channels: Vec<&mut [f32]> =
            (0..num_channels)
                .map(|i| {
                    let slice_ptr = (*io_data).mBuffers[i].mData as *mut libc::c_float;
                    ::std::slice::from_raw_parts_mut(slice_ptr, in_number_frames as usize)
                })
                .collect();
        match (*(*callback).f)(&mut channels[..], in_number_frames as usize) {
            Ok(()) => 0,
            Err(description) => {
                println!("{:?}", description);
                AudioUnitError::NoConnection as au::OSStatus
            },
        }
    }
}

<commit_msg>Fixed callback memleaks<commit_after>//!
//! This module is an attempt to provide a friendly, rust-esque interface to
//! Apple's Audio Unit API.
//!
//! An audio unit can be constructed with the builder pattern.
//!
//! Learn more about the Audio Unit API here:
//! https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40003278-CH1-SW2
//!

use bindings::audio_unit as au;
use error::{Error, AudioUnitError};
use libc;
use self::stream_format::StreamFormat;
use std::mem;

pub mod audio_format;
pub mod stream_format;

/// Represents the input and output scope.
#[derive(Copy, Clone, Debug)]
pub enum Scope {
    Output = 0,
    Input  = 1,
}

/// Represents the input and output elements .
#[derive(Copy, Clone, Debug)]
pub enum Element {
    Output = 0,
    Input  = 1,
}

/// Represents the different types of Audio Units.
#[derive(Copy, Clone, Debug)]
pub enum Type {
    Output          = 1635086197,
    MusicDevice     = 1635085685,
    MusicEffect     = 1635085670,
    FormatConverter = 1635083875,
    Effect          = 1635083896,
    Mixer           = 1635085688,
    Panner          = 1635086446,
    Generator       = 1635084142,
    OfflineEffect   = 1635086188,
    MidiProcessor   = 1635085673,
}

/// Represents the different audio unit sub types.
#[derive(Copy, Clone, Debug)]
pub enum SubType {
    GenericOutput        = 1734700658,
    HalOutput            = 1634230636,
    DefaultOutput        = 1684366880,
    SystemOutput         = 1937339168,
    VoiceProcessingIO    = 1987078511,
    DLSSynth             = 1684828960,
    Sampler              = 1935764848,
    MIDISynth            = 1836284270,
    AUConverter          = 1668247158,
    Varispeed            = 1986097769,
    DeferredRenderer     = 1684366962,
    Splitter             = 1936747636,
    Merger               = 1835364967,
    NewTimePitch         = 1853191280,
    AUiPodTimeOther      = 1768977519,
    RoundTripAAC         = 1918984547,
    PeakLimiter          = 1819112562,
    DynamicsProcessor    = 1684237680,
    LowPassFilter        = 1819304307,
    HighPassFilter       = 1752195443,
    BandPassFilter       = 1651532147,
    HighShelfFilter      = 1752393830,
    LowShelfFilter       = 1819502694,
    ParametricEQ         = 1886217585,
    Distortion           = 1684632436,
    Delay                = 1684368505,
    SampleDelay          = 1935961209,
    GraphicEQ            = 1735550321,
    MultiBandCompressor  = 1835232624,
    MatrixReverb         = 1836213622,
    Pitch                = 1953329268,
    AUFilter             = 1718185076,
    NetSend              = 1853058660,
    RogerBeep            = 1919903602,
    NBandEQ              = 1851942257,
    MultiChannelMixer    = 1835232632,
    MatrixMixer          = 1836608888,
    SpatialMixer         = 862217581,
    StereoMixer          = 1936554098,
    Mixer3D              = 862219640,
    SphericalHeadPanner  = 1936746610,
    VectorPanner         = 1986158963,
    SoundFieldPanner     = 1634558569,
    HRTFPanner           = 1752331366,
    NetReceive           = 1852990326,
    ScheduledSoundPlayer = 1936945260,
    AudioFilePlayer      = 1634103404,
}

/// A rust representation of the au::AudioUnit, including a pointer to the current rendering callback.
pub struct AudioUnit {
    audio_unit: au::AudioUnit,
    callback: Option<*mut libc::c_void>
}

impl AudioUnit {

    /// Construct a new AudioUnit.
    pub fn new(au_type: Type, sub_type: SubType) -> AudioUnitBuilder {

        // A description of the audio unit we desire.
        let desc = au::AudioComponentDescription {
            componentType         : au_type as libc::c_uint,
            componentSubType      : sub_type as libc::c_uint,
            componentManufacturer : au::kAudioUnitManufacturer_Apple,
            componentFlags        : 0,
            componentFlagsMask    : 0,
        };

        unsafe {
            use std::ptr::null_mut;
            // Find the default audio unit for the description.
            let component_result = match au::AudioComponentFindNext(null_mut(), &desc as *const _) {
                component if component.is_null() => Err(Error::NoMatchingDefaultAudioUnitFound),
                component                        => Ok(component),
            };

            // Get an instance of the default audio unit using the component.
            let mut audio_unit: au::AudioUnit = mem::uninitialized();

            let audio_unit_result = match component_result {
                Ok(component) => {
                    au::AudioComponentInstanceNew(component, &mut audio_unit as *mut au::AudioUnit);
                    Ok((audio_unit, None))
                },
                Err(err) => Err(err),
            };
            AudioUnitBuilder { audio_unit_result: audio_unit_result }
        }
    }

    /// Return the current Stream Format for the AudioUnit.
    pub fn stream_format(&self) -> StreamFormat {
        unsafe {
            let mut asbd: au::AudioStreamBasicDescription = mem::uninitialized();
            let mut size = ::std::mem::size_of::<au::AudioStreamBasicDescription>() as u32;
            if let Err(err) = Error::from_os_status(au::AudioUnitGetProperty(
                                                        self.audio_unit,
                                                        au::kAudioUnitProperty_StreamFormat,
                                                        Scope::Output as libc::c_uint,
                                                        Element::Output as libc::c_uint,
                                                        &mut asbd as *mut _ as *mut libc::c_void,
                                                        &mut size as *mut au::UInt32)) {
                panic!("{:?}", err);
            }
            StreamFormat::from_asbd(asbd)
        }
    }

    /// Close the audio unit.
    pub fn close(self) {}

}

impl Drop for AudioUnit {
    fn drop(&mut self) {
        unsafe {
            use error;
            use std::error::Error;
            if let Err(err) = error::Error::from_os_status(au::AudioOutputUnitStop(self.audio_unit)) {
                panic!("{:?}", err.description());
            }
            if let Err(err) = error::Error::from_os_status(au::AudioUnitUninitialize(self.audio_unit)) {
                panic!("{:?}", err.description());
            }
            if let Some(callback) = self.callback {
                let _: Box<RenderCallback> = mem::transmute(callback);
            }
        }
    }
}

/// A context on which to build the audio unit.
pub struct AudioUnitBuilder {
    audio_unit_result: Result<(au::AudioUnit, Option<*mut libc::c_void>), Error>,
}

impl AudioUnitBuilder {

    /// Pass a render callback (aka "Input Procedure") to the audio unit.
    /// This will be called every time the AudioUnit requests audio.
    /// f is a boxed FnMut whose arg is [frames[channels]].
    #[inline]
    pub fn render_callback(self, f: Box<FnMut(&mut[&mut[f32]], NumFrames) -> Result<(), String>>) -> AudioUnitBuilder {
        let audio_unit_result = match self.audio_unit_result {
            Err(err) => Err(err),
            Ok((audio_unit, previous_callback)) => {
                unsafe {
                    if let Some(previous_callback_ptr) = previous_callback {
                        let _: Box<RenderCallback> = mem::transmute(previous_callback_ptr);
                    }

                    let size_of_render_callback_struct = mem::size_of::<au::AURenderCallbackStruct>() as u32;

                    // Setup render callback.
                    let callback: *mut libc::c_void = mem::transmute(Box::new(RenderCallback { f: f }));
                    let render_callback = au::AURenderCallbackStruct {
                        inputProc: Some(input_proc), // TODO
                        inputProcRefCon: callback,
                    };

                    match Error::from_os_status(au::AudioUnitSetProperty(
                                                audio_unit,
                                                au::kAudioUnitProperty_SetRenderCallback,
                                                Scope::Input as libc::c_uint,
                                                Element::Output as libc::c_uint,
                                                &render_callback as *const _ as *const libc::c_void,
                                                size_of_render_callback_struct)) {
                        Ok(()) => Ok((audio_unit, Some(callback))),
                        Err(err) => Err(err),
                    }
                }
            },
        };
        AudioUnitBuilder { audio_unit_result: audio_unit_result }
    }

    /// Finish building the audio unit, initialise it and start it.
    pub fn start(self) -> Result<AudioUnit, Error> {
        let (audio_unit, callback) = try!(self.audio_unit_result);
        unsafe {
            // Initialise the audio unit!
            try!(Error::from_os_status(au::AudioUnitInitialize(audio_unit)));
            try!(Error::from_os_status(au::AudioOutputUnitStart(audio_unit)));
        }
        Ok(AudioUnit { audio_unit: audio_unit, callback: callback })
    }

}

pub type NumFrames = usize;

/// A struct in which we will pass the callback to the AudioUnit's render callback.
pub struct RenderCallback {
    f: Box<FnMut(&mut[&mut[f32]], NumFrames) -> Result<(), String>>,
}

/// Callback procedure that will be called each time our audio_unit requests audio.
extern "C" fn input_proc(in_ref_con: *mut libc::c_void,
                         _io_action_flags: *mut au::AudioUnitRenderActionFlags,
                         _in_time_stamp: *const au::AudioTimeStamp,
                         _in_bus_number: au::UInt32,
                         in_number_frames: au::UInt32,
                         io_data: *mut au::AudioBufferList) -> au::OSStatus {
    let callback: *mut RenderCallback = in_ref_con as *mut _;
    unsafe {
        let num_channels = (*io_data).mNumberBuffers as usize;
        let mut channels: Vec<&mut [f32]> =
            (0..num_channels)
                .map(|i| {
                    let slice_ptr = (*io_data).mBuffers[i].mData as *mut libc::c_float;
                    ::std::slice::from_raw_parts_mut(slice_ptr, in_number_frames as usize)
                })
                .collect();
        match (*(*callback).f)(&mut channels[..], in_number_frames as usize) {
            Ok(()) => 0,
            Err(description) => {
                println!("{:?}", description);
                AudioUnitError::NoConnection as au::OSStatus
            },
        }
    }
}
<|endoftext|>


<commit_before>//!
//! This module is an attempt to provide a friendly, rust-esque interface to
//! Apple's Audio Unit API.
//!
//! Learn more about the Audio Unit API here:
//! https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40003278-CH1-SW2
//!

use bindings::audio_unit as au;
use error::{Error, AudioUnitError};
use libc;
use self::stream_format::StreamFormat;
use std::mem;
use std::ptr;

pub mod audio_format;
pub mod stream_format;

/// Represents the input and output scope.
#[derive(Copy, Clone, Debug)]
pub enum Scope {
    Output = 0,
    Input  = 1,
}

/// Represents the input and output elements .
#[derive(Copy, Clone, Debug)]
pub enum Element {
    Output = 0,
    Input  = 1,
}

/// Represents the different types of Audio Units.
#[derive(Copy, Clone, Debug)]
pub enum Type {
    Output          = 1635086197,
    MusicDevice     = 1635085685,
    MusicEffect     = 1635085670,
    FormatConverter = 1635083875,
    Effect          = 1635083896,
    Mixer           = 1635085688,
    Panner          = 1635086446,
    Generator       = 1635084142,
    OfflineEffect   = 1635086188,
    MidiProcessor   = 1635085673,
}

/// Represents the different audio unit sub types.
#[derive(Copy, Clone, Debug)]
pub enum SubType {
    GenericOutput        = 1734700658,
    HalOutput            = 1634230636,
    DefaultOutput        = 1684366880,
    SystemOutput         = 1937339168,
    VoiceProcessingIO    = 1987078511,
    DLSSynth             = 1684828960,
    Sampler              = 1935764848,
    MIDISynth            = 1836284270,
    AUConverter          = 1668247158,
    Varispeed            = 1986097769,
    DeferredRenderer     = 1684366962,
    Splitter             = 1936747636,
    Merger               = 1835364967,
    NewTimePitch         = 1853191280,
    AUiPodTimeOther      = 1768977519,
    RoundTripAAC         = 1918984547,
    PeakLimiter          = 1819112562,
    DynamicsProcessor    = 1684237680,
    LowPassFilter        = 1819304307,
    HighPassFilter       = 1752195443,
    BandPassFilter       = 1651532147,
    HighShelfFilter      = 1752393830,
    LowShelfFilter       = 1819502694,
    ParametricEQ         = 1886217585,
    Distortion           = 1684632436,
    Delay                = 1684368505,
    SampleDelay          = 1935961209,
    GraphicEQ            = 1735550321,
    MultiBandCompressor  = 1835232624,
    MatrixReverb         = 1836213622,
    Pitch                = 1953329268,
    AUFilter             = 1718185076,
    NetSend              = 1853058660,
    RogerBeep            = 1919903602,
    NBandEQ              = 1851942257,
    MultiChannelMixer    = 1835232632,
    MatrixMixer          = 1836608888,
    SpatialMixer         = 862217581,
    StereoMixer          = 1936554098,
    Mixer3D              = 862219640,
    SphericalHeadPanner  = 1936746610,
    VectorPanner         = 1986158963,
    SoundFieldPanner     = 1634558569,
    HRTFPanner           = 1752331366,
    NetReceive           = 1852990326,
    ScheduledSoundPlayer = 1936945260,
    AudioFilePlayer      = 1634103404,
}

pub type NumFrames = usize;

/// A type representing a render callback (aka "Input Procedure")
/// If set on an AudioUnit, this will be called every time the AudioUnit requests audio.
/// The first arg is [frames[channels]]; the second is the number of frames to render.
pub type RenderCallback = FnMut(&mut[&mut[f32]], NumFrames) -> Result<(), String>;

/// A rust representation of the au::AudioUnit, including a pointer to the current rendering callback.
pub struct AudioUnit {
    instance: au::AudioUnit,
    callback: Option<*mut libc::c_void>
}

macro_rules! try_os_status {
    ($expr:expr) => (try!(Error::from_os_status($expr)))
}

impl AudioUnit {

    /// Construct a new AudioUnit.
    pub fn new(au_type: Type, sub_type: SubType) -> Result<AudioUnit, Error> {

        // A description of the audio unit we desire.
        let desc = au::AudioComponentDescription {
            componentType         : au_type as libc::c_uint,
            componentSubType      : sub_type as libc::c_uint,
            componentManufacturer : au::kAudioUnitManufacturer_Apple,
            componentFlags        : 0,
            componentFlagsMask    : 0,
        };

        unsafe {
            // Find the default audio unit for the description.
            let component = match au::AudioComponentFindNext(ptr::null_mut(), &desc as *const _) {
                component if component.is_null() => return Err(Error::NoMatchingDefaultAudioUnitFound),
                component                        => component,
            };

            // Get an instance of the default audio unit using the component.
            let mut instance: au::AudioUnit = mem::uninitialized();

            try_os_status!(au::AudioComponentInstanceNew(component, &mut instance as *mut au::AudioUnit));
            // Initialise the audio unit!
            try_os_status!(au::AudioUnitInitialize(instance));
            Ok(AudioUnit {
                instance: instance,
                callback: None
            })
        }
    }

    fn free_render_callback(&self) {
        if let Some(callback) = self.callback {
            // Here, we transfer ownership of the callback back to the current scope so that it
            // is dropped and cleaned up. Without this line, we would leak the Boxed callback.
            let _: Box<Box<RenderCallback>> = unsafe { mem::transmute(callback) };
        }
    }

    /// Pass a render callback (aka "Input Procedure") to the audio unit.
    pub fn render_callback(&mut self, f: Option<Box<RenderCallback>>) -> Result<(), Error>
    {
        unsafe {
            // Setup render callback. Notice that we relinquish ownership of the Callback
            // here so that it can be used as the C render callback via a void pointer.
            // We do however store the *mut so that we can transmute back to a
            // Box<Box<RenderCallback>> within our AudioUnit's Drop implementation
            // (otherwise it would leak). The double-boxing is due to incompleteness with
            // Rust's FnMut implemetation and is necessary to be able to transmute to the
            // correct pointer size.
            let callback_ptr: *mut libc::c_void = match f {
                Some(x) => mem::transmute(Box::new(x)),
                _ => ptr::null_mut()
            };
            let render_callback = au::AURenderCallbackStruct {
                inputProc: Some(input_proc),
                inputProcRefCon: callback_ptr
            };

            try_os_status!(au::AudioUnitSetProperty(
                self.instance,
                au::kAudioUnitProperty_SetRenderCallback,
                Scope::Input as libc::c_uint,
                Element::Output as libc::c_uint,
                &render_callback as *const _ as *const libc::c_void,
                mem::size_of::<au::AURenderCallbackStruct>() as u32));

            self.free_render_callback();
            self.callback = if !callback_ptr.is_null() { Some(callback_ptr) } else { None };
            Ok(())
        }
    }

    /// Start the audio unit.
    pub fn start(&self) -> Result<(), Error> {
        unsafe { try_os_status!(au::AudioOutputUnitStart(self.instance)); }
        Ok(())
    }

    /// Stop the audio unit.
    pub fn stop(&self) -> Result<(), Error> {
        unsafe { try_os_status!(au::AudioOutputUnitStop(self.instance)); }
        Ok(())
    }

    /// Set the audio unit's sample rate.
    pub fn set_sample_rate(&self, sample_rate: f64) -> Result<(), Error> {
        unsafe {
            try_os_status!(au::AudioUnitSetProperty(
                self.instance,
                au::kAudioUnitProperty_SampleRate,
                au::kAudioUnitScope_Input,
                0,
                &sample_rate as *const _ as *const libc::c_void,
                mem::size_of::<f64>() as u32));
            Ok(())
        }
    }

    /// Get the audio unit's sample rate.
    pub fn sample_rate(&self) -> Result<f64, Error> {
        unsafe {
            let mut sample_rate: f64 = 0.0;
            let mut size: u32 = mem::size_of::<f64>() as u32;
            try_os_status!(au::AudioUnitGetProperty(
                self.instance,
                au::kAudioUnitProperty_SampleRate,
                au::kAudioUnitScope_Input,
                0,
                &mut sample_rate as *mut _ as *mut libc::c_void,
                &mut size as *mut _));
            Ok(sample_rate)
        }
    }

    /// Sets the current Stream Format for the AudioUnit.
    pub fn set_stream_format(&self, stream_format: StreamFormat) -> Result<(), Error> {
        unsafe {
            let mut asbd = stream_format.to_asbd();
            try_os_status!(au::AudioUnitSetProperty(
                self.instance,
                au::kAudioUnitProperty_StreamFormat,
                au::kAudioUnitScope_Input,
                0,
                &mut asbd as *mut _ as *mut libc::c_void,
                mem::size_of::<au::AudioStreamBasicDescription>() as u32));
            Ok(())
        }
    }

    /// Return the current Stream Format for the AudioUnit.
    pub fn stream_format(&self) -> Result<StreamFormat, Error> {
        unsafe {
            let mut asbd: au::AudioStreamBasicDescription = mem::uninitialized();
            let mut size = ::std::mem::size_of::<au::AudioStreamBasicDescription>() as u32;
            try_os_status!(au::AudioUnitGetProperty(
                self.instance,
                au::kAudioUnitProperty_StreamFormat,
                Scope::Output as libc::c_uint,
                Element::Output as libc::c_uint,
                &mut asbd as *mut _ as *mut libc::c_void,
                &mut size as *mut au::UInt32));
            Ok(StreamFormat::from_asbd(asbd))
        }
    }

}

impl Drop for AudioUnit {
    fn drop(&mut self) {
        unsafe {
            use error;
            use std::error::Error;
            if let Err(err) = self.stop() {
                panic!("{:?}", err.description());
            }
            if let Err(err) = error::Error::from_os_status(au::AudioUnitUninitialize(self.instance)) {
                panic!("{:?}", err.description());
            }
            self.free_render_callback();
        }
    }
}

/// Callback procedure that will be called each time our audio_unit requests audio.
extern "C" fn input_proc(in_ref_con: *mut libc::c_void,
                         _io_action_flags: *mut au::AudioUnitRenderActionFlags,
                         _in_time_stamp: *const au::AudioTimeStamp,
                         _in_bus_number: au::UInt32,
                         in_number_frames: au::UInt32,
                         io_data: *mut au::AudioBufferList) -> au::OSStatus {
    let callback: *mut Box<RenderCallback> = in_ref_con as *mut _;
    unsafe {
        let num_channels = (*io_data).mNumberBuffers as usize;

        // FIXME: We shouldn't need a Vec for this, it should probably be something like
        // `&[&mut [f32]]` instead.
        let mut channels: Vec<&mut [f32]> =
            (0..num_channels)
                .map(|i| {
                    let slice_ptr = (*io_data).mBuffers[i].mData as *mut libc::c_float;
                    ::std::slice::from_raw_parts_mut(slice_ptr, in_number_frames as usize)
                })
                .collect();

        match (*callback)(&mut channels[..], in_number_frames as usize) {
            Ok(()) => 0 as au::OSStatus,
            Err(description) => {
                use std::io::Write;
                writeln!(::std::io::stderr(), "{:?}", description).unwrap();
                AudioUnitError::NoConnection as au::OSStatus
            },
        }
    }
}
<commit_msg>Added TODO about incorrect render buffer size<commit_after>//!
//! This module is an attempt to provide a friendly, rust-esque interface to
//! Apple's Audio Unit API.
//!
//! Learn more about the Audio Unit API here:
//! https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40003278-CH1-SW2
//!

use bindings::audio_unit as au;
use error::{Error, AudioUnitError};
use libc;
use self::stream_format::StreamFormat;
use std::mem;
use std::ptr;

pub mod audio_format;
pub mod stream_format;

/// Represents the input and output scope.
#[derive(Copy, Clone, Debug)]
pub enum Scope {
    Output = 0,
    Input  = 1,
}

/// Represents the input and output elements .
#[derive(Copy, Clone, Debug)]
pub enum Element {
    Output = 0,
    Input  = 1,
}

/// Represents the different types of Audio Units.
#[derive(Copy, Clone, Debug)]
pub enum Type {
    Output          = 1635086197,
    MusicDevice     = 1635085685,
    MusicEffect     = 1635085670,
    FormatConverter = 1635083875,
    Effect          = 1635083896,
    Mixer           = 1635085688,
    Panner          = 1635086446,
    Generator       = 1635084142,
    OfflineEffect   = 1635086188,
    MidiProcessor   = 1635085673,
}

/// Represents the different audio unit sub types.
#[derive(Copy, Clone, Debug)]
pub enum SubType {
    GenericOutput        = 1734700658,
    HalOutput            = 1634230636,
    DefaultOutput        = 1684366880,
    SystemOutput         = 1937339168,
    VoiceProcessingIO    = 1987078511,
    DLSSynth             = 1684828960,
    Sampler              = 1935764848,
    MIDISynth            = 1836284270,
    AUConverter          = 1668247158,
    Varispeed            = 1986097769,
    DeferredRenderer     = 1684366962,
    Splitter             = 1936747636,
    Merger               = 1835364967,
    NewTimePitch         = 1853191280,
    AUiPodTimeOther      = 1768977519,
    RoundTripAAC         = 1918984547,
    PeakLimiter          = 1819112562,
    DynamicsProcessor    = 1684237680,
    LowPassFilter        = 1819304307,
    HighPassFilter       = 1752195443,
    BandPassFilter       = 1651532147,
    HighShelfFilter      = 1752393830,
    LowShelfFilter       = 1819502694,
    ParametricEQ         = 1886217585,
    Distortion           = 1684632436,
    Delay                = 1684368505,
    SampleDelay          = 1935961209,
    GraphicEQ            = 1735550321,
    MultiBandCompressor  = 1835232624,
    MatrixReverb         = 1836213622,
    Pitch                = 1953329268,
    AUFilter             = 1718185076,
    NetSend              = 1853058660,
    RogerBeep            = 1919903602,
    NBandEQ              = 1851942257,
    MultiChannelMixer    = 1835232632,
    MatrixMixer          = 1836608888,
    SpatialMixer         = 862217581,
    StereoMixer          = 1936554098,
    Mixer3D              = 862219640,
    SphericalHeadPanner  = 1936746610,
    VectorPanner         = 1986158963,
    SoundFieldPanner     = 1634558569,
    HRTFPanner           = 1752331366,
    NetReceive           = 1852990326,
    ScheduledSoundPlayer = 1936945260,
    AudioFilePlayer      = 1634103404,
}

pub type NumFrames = usize;

/// A type representing a render callback (aka "Input Procedure")
/// If set on an AudioUnit, this will be called every time the AudioUnit requests audio.
/// The first arg is [frames[channels]]; the second is the number of frames to render.
pub type RenderCallback = FnMut(&mut[&mut[f32]], NumFrames) -> Result<(), String>;

/// A rust representation of the au::AudioUnit, including a pointer to the current rendering callback.
pub struct AudioUnit {
    instance: au::AudioUnit,
    callback: Option<*mut libc::c_void>
}

macro_rules! try_os_status {
    ($expr:expr) => (try!(Error::from_os_status($expr)))
}

impl AudioUnit {

    /// Construct a new AudioUnit.
    pub fn new(au_type: Type, sub_type: SubType) -> Result<AudioUnit, Error> {

        // A description of the audio unit we desire.
        let desc = au::AudioComponentDescription {
            componentType         : au_type as libc::c_uint,
            componentSubType      : sub_type as libc::c_uint,
            componentManufacturer : au::kAudioUnitManufacturer_Apple,
            componentFlags        : 0,
            componentFlagsMask    : 0,
        };

        unsafe {
            // Find the default audio unit for the description.
            let component = match au::AudioComponentFindNext(ptr::null_mut(), &desc as *const _) {
                component if component.is_null() => return Err(Error::NoMatchingDefaultAudioUnitFound),
                component                        => component,
            };

            // Get an instance of the default audio unit using the component.
            let mut instance: au::AudioUnit = mem::uninitialized();

            try_os_status!(au::AudioComponentInstanceNew(component, &mut instance as *mut au::AudioUnit));
            // Initialise the audio unit!
            try_os_status!(au::AudioUnitInitialize(instance));
            Ok(AudioUnit {
                instance: instance,
                callback: None
            })
        }
    }

    fn free_render_callback(&self) {
        if let Some(callback) = self.callback {
            // Here, we transfer ownership of the callback back to the current scope so that it
            // is dropped and cleaned up. Without this line, we would leak the Boxed callback.
            let _: Box<Box<RenderCallback>> = unsafe { mem::transmute(callback) };
        }
    }

    /// Pass a render callback (aka "Input Procedure") to the audio unit.
    pub fn render_callback(&mut self, f: Option<Box<RenderCallback>>) -> Result<(), Error>
    {
        unsafe {
            // Setup render callback. Notice that we relinquish ownership of the Callback
            // here so that it can be used as the C render callback via a void pointer.
            // We do however store the *mut so that we can transmute back to a
            // Box<Box<RenderCallback>> within our AudioUnit's Drop implementation
            // (otherwise it would leak). The double-boxing is due to incompleteness with
            // Rust's FnMut implemetation and is necessary to be able to transmute to the
            // correct pointer size.
            let callback_ptr: *mut libc::c_void = match f {
                Some(x) => mem::transmute(Box::new(x)),
                _ => ptr::null_mut()
            };
            let render_callback = au::AURenderCallbackStruct {
                inputProc: Some(input_proc),
                inputProcRefCon: callback_ptr
            };

            try_os_status!(au::AudioUnitSetProperty(
                self.instance,
                au::kAudioUnitProperty_SetRenderCallback,
                Scope::Input as libc::c_uint,
                Element::Output as libc::c_uint,
                &render_callback as *const _ as *const libc::c_void,
                mem::size_of::<au::AURenderCallbackStruct>() as u32));

            self.free_render_callback();
            self.callback = if !callback_ptr.is_null() { Some(callback_ptr) } else { None };
            Ok(())
        }
    }

    /// Start the audio unit.
    pub fn start(&self) -> Result<(), Error> {
        unsafe { try_os_status!(au::AudioOutputUnitStart(self.instance)); }
        Ok(())
    }

    /// Stop the audio unit.
    pub fn stop(&self) -> Result<(), Error> {
        unsafe { try_os_status!(au::AudioOutputUnitStop(self.instance)); }
        Ok(())
    }

    /// Set the audio unit's sample rate.
    pub fn set_sample_rate(&self, sample_rate: f64) -> Result<(), Error> {
        unsafe {
            try_os_status!(au::AudioUnitSetProperty(
                self.instance,
                au::kAudioUnitProperty_SampleRate,
                au::kAudioUnitScope_Input,
                0,
                &sample_rate as *const _ as *const libc::c_void,
                mem::size_of::<f64>() as u32));
            Ok(())
        }
    }

    /// Get the audio unit's sample rate.
    pub fn sample_rate(&self) -> Result<f64, Error> {
        unsafe {
            let mut sample_rate: f64 = 0.0;
            let mut size: u32 = mem::size_of::<f64>() as u32;
            try_os_status!(au::AudioUnitGetProperty(
                self.instance,
                au::kAudioUnitProperty_SampleRate,
                au::kAudioUnitScope_Input,
                0,
                &mut sample_rate as *mut _ as *mut libc::c_void,
                &mut size as *mut _));
            Ok(sample_rate)
        }
    }

    /// Sets the current Stream Format for the AudioUnit.
    pub fn set_stream_format(&self, stream_format: StreamFormat) -> Result<(), Error> {
        unsafe {
            let mut asbd = stream_format.to_asbd();
            try_os_status!(au::AudioUnitSetProperty(
                self.instance,
                au::kAudioUnitProperty_StreamFormat,
                au::kAudioUnitScope_Input,
                0,
                &mut asbd as *mut _ as *mut libc::c_void,
                mem::size_of::<au::AudioStreamBasicDescription>() as u32));
            Ok(())
        }
    }

    /// Return the current Stream Format for the AudioUnit.
    pub fn stream_format(&self) -> Result<StreamFormat, Error> {
        unsafe {
            let mut asbd: au::AudioStreamBasicDescription = mem::uninitialized();
            let mut size = ::std::mem::size_of::<au::AudioStreamBasicDescription>() as u32;
            try_os_status!(au::AudioUnitGetProperty(
                self.instance,
                au::kAudioUnitProperty_StreamFormat,
                Scope::Output as libc::c_uint,
                Element::Output as libc::c_uint,
                &mut asbd as *mut _ as *mut libc::c_void,
                &mut size as *mut au::UInt32));
            Ok(StreamFormat::from_asbd(asbd))
        }
    }

}

impl Drop for AudioUnit {
    fn drop(&mut self) {
        unsafe {
            use error;
            use std::error::Error;
            if let Err(err) = self.stop() {
                panic!("{:?}", err.description());
            }
            if let Err(err) = error::Error::from_os_status(au::AudioUnitUninitialize(self.instance)) {
                panic!("{:?}", err.description());
            }
            self.free_render_callback();
        }
    }
}

/// Callback procedure that will be called each time our audio_unit requests audio.
extern "C" fn input_proc(in_ref_con: *mut libc::c_void,
                         _io_action_flags: *mut au::AudioUnitRenderActionFlags,
                         _in_time_stamp: *const au::AudioTimeStamp,
                         _in_bus_number: au::UInt32,
                         in_number_frames: au::UInt32,
                         io_data: *mut au::AudioBufferList) -> au::OSStatus {
    let callback: *mut Box<RenderCallback> = in_ref_con as *mut _;
    unsafe {
        let num_channels = (*io_data).mNumberBuffers as usize;

        // FIXME: We shouldn't need a Vec for this, it should probably be something like
        // `&[&mut [f32]]` instead.
        let mut channels: Vec<&mut [f32]> =
            (0..num_channels)
                .map(|i| {
                    let slice_ptr = (*io_data).mBuffers[i].mData as *mut libc::c_float;
                    // TODO: the size of this buffer needs to be calculated properly based on the stream format.
                    // Currently this won't be correct in at least this case:
                    /*
                    stream_format::StreamFormat {
                        sample_rate: 44100.0,
                        audio_format: audio_format::AudioFormat::LinearPCM(Some(audio_format::LinearPCMFlag::IsFloat)),
                        bytes_per_packet: 2 * 4,
                        frames_per_packet: 1,
                        bytes_per_frame: 2 * 4,
                        channels_per_frame: 2,
                        bits_per_channel: 32
                    }
                     */
                    ::std::slice::from_raw_parts_mut(slice_ptr, in_number_frames as usize)
                })
                .collect();

        match (*callback)(&mut channels[..], in_number_frames as usize) {
            Ok(()) => 0 as au::OSStatus,
            Err(description) => {
                use std::io::Write;
                writeln!(::std::io::stderr(), "{:?}", description).unwrap();
                AudioUnitError::NoConnection as au::OSStatus
            },
        }
    }
}
<|endoftext|>


<commit_before>// NOTE need to store the drawable in lua, because it's a reference to a drawable a lua object

use std::default::Default;
use std::fmt::{self, Display, Formatter};
use std::rc::Rc;
use rustwlc::{Geometry, Point, Size};
use rlua::{self, Table, Lua, UserData, ToLua, Value};
use super::drawable::Drawable;
use super::property::Property;

use super::class::{self, Class, ClassBuilder};
use super::object::{Object, Objectable, ObjectBuilder};

#[derive(Clone, Debug)]
pub struct DrawinState {
    // Note that the drawable is stored in Lua.
    // TODO WINDOW_OBJECT_HEADER??
    ontop: bool,
    visible: bool,
    cursor: String,
    geometry: Geometry,
    geometry_dirty: bool
}

#[derive(Clone, Debug)]
pub struct Drawin<'lua>(Table<'lua>);

impl UserData for DrawinState {}

impl Default for DrawinState {
    fn default() -> Self {
        DrawinState {
            ontop: false,
            visible: false,
            cursor: String::default(),
            geometry: Geometry::zero(),
            geometry_dirty: false
        }
    }
}

impl Display for DrawinState {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Drawin: {:p}", self)
    }
}

impl <'lua> Drawin<'lua> {
    fn new(lua: &Lua) -> rlua::Result<Object> {
        let class = class::class_setup(lua, "drawin")?;
        Ok(object_setup(lua, Drawin::allocate(lua, class)?)?.build())
    }

    fn update_drawing(&mut self) -> rlua::Result<()> {
        let state = self.state()?;
        let table = &self.0;
        let mut drawable = Drawable::cast(table.get::<_, Table>("drawable")?.into())?;
        drawable.set_geometry(state.geometry)?;
        table.raw_set::<_, Table>("drawable", drawable.get_table())?;
        Ok(())
    }

    fn get_visible(&mut self) -> rlua::Result<bool> {
        let drawin = self.state()?;
        Ok(drawin.visible)
    }

    fn set_visible(&mut self, val: bool) -> rlua::Result<()> {
        let mut drawin = self.state()?;
        drawin.visible = val;
        self.map()?;
        self.set_state(drawin)
    }

    fn map(&mut self) -> rlua::Result<()> {
        // TODO other things
        self.update_drawing()
    }

    fn get_geometry(&self) -> rlua::Result<Geometry> {
        Ok(self.state()?.geometry)
    }

    fn resize(&mut self, geometry: Geometry) -> rlua::Result<()> {
        let mut state = self.state()?;
        let old_geometry = state.geometry;
        state.geometry = geometry;
        if state.geometry.size.w <= 0 {
            state.geometry.size.w = old_geometry.size.w;
        }
        if state.geometry.size.h <= 0 {
            state.geometry.size.h = old_geometry.size.h
        }
        state.geometry_dirty = true;
        self.update_drawing()?;
        // TODO emit signals
        // TODO update screen workareas like in awesome? Might not be necessary
        self.set_state(state)
    }
}

impl <'lua> ToLua<'lua> for Drawin<'lua> {
    fn to_lua(self, lua: &'lua Lua) -> rlua::Result<Value<'lua>> {
        self.0.to_lua(lua)
    }
}

impl_objectable!(Drawin, DrawinState);

pub fn init(lua: &Lua) -> rlua::Result<Class> {
    property_setup(lua, method_setup(lua, Class::builder(lua, Some(Rc::new(Drawin::new)), None, None)?)?)?
        .save_class("drawin")?
        .build()
}

fn method_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    // TODO Do properly
    use super::dummy;
    builder.method("connect_signal".into(), lua.create_function(dummy))?
            // TODO This should be adding properties, e.g like luaA_class_new
           .method("__call".into(), lua.create_function(|lua, _: Value| Drawin::new(lua)))
}

fn property_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    builder
        .property(Property::new("visible".into(),
                                Some(lua.create_function(set_visible)),
                                Some(lua.create_function(get_visible)),
                                Some(lua.create_function(set_visible))))
}

fn object_setup<'lua>(lua: &'lua Lua, builder: ObjectBuilder<'lua>) -> rlua::Result<ObjectBuilder<'lua>> {
    // TODO Do properly
    let table = lua.create_table();
    let drawable_table = Drawable::new(lua)?.to_lua(lua)?;
    table.set("drawable", drawable_table)?;
    table.set("geometry", lua.create_function(drawin_geometry))?;
    builder.add_to_meta(table)
}

fn set_visible<'lua>(_: &'lua Lua, (table, visible): (Table<'lua>, bool))
                     -> rlua::Result<()> {
    let mut drawin = Drawin::cast(table.into())?;
    drawin.set_visible(visible)
    // TODO signal
}

fn get_visible<'lua>(_: &'lua Lua, table: Table<'lua>) -> rlua::Result<bool> {
    let mut drawin = Drawin::cast(table.into())?;
    drawin.get_visible()
    // TODO signal
}

fn drawin_geometry<'lua>(lua: &'lua Lua, (drawin, geometry): (Table<'lua>, Table<'lua>)) -> rlua::Result<Table<'lua>> {
    let mut drawin = Drawin::cast(drawin.into())?;
    let w = geometry.get::<_, i32>("width")?;
    let h = geometry.get::<_, i32>("height")?;
    let x = geometry.get::<_, i32>("x")?;
    let y = geometry.get::<_, i32>("y")?;
    if x > 0 && y > 0 {
        let geo = Geometry {
            origin: Point { x, y },
            size: Size { w: w as u32, h: h as u32 }
        };
        drawin.resize(geo)?;
    }
    let new_geo = drawin.get_geometry()?;
    let Size { w, h } = new_geo.size;
    let Point { x, y } = new_geo.origin;
    let res = lua.create_table();
    res.set("x", x)?;
    res.set("y", y)?;
    res.set("height", h)?;
    res.set("width", w)?;
    Ok(res)
}
<commit_msg>drawin: Implement x, y, width, height<commit_after>// NOTE need to store the drawable in lua, because it's a reference to a drawable a lua object

use std::default::Default;
use std::fmt::{self, Display, Formatter};
use std::rc::Rc;
use rustwlc::{Geometry, Point, Size};
use rlua::{self, Table, Lua, UserData, ToLua, Value};
use rlua::prelude::LuaInteger;
use super::drawable::Drawable;
use super::property::Property;

use super::class::{self, Class, ClassBuilder};
use super::object::{Object, Objectable, ObjectBuilder};

#[derive(Clone, Debug)]
pub struct DrawinState {
    // Note that the drawable is stored in Lua.
    // TODO WINDOW_OBJECT_HEADER??
    ontop: bool,
    visible: bool,
    cursor: String,
    geometry: Geometry,
    geometry_dirty: bool
}

#[derive(Clone, Debug)]
pub struct Drawin<'lua>(Table<'lua>);

impl UserData for DrawinState {}

impl Default for DrawinState {
    fn default() -> Self {
        DrawinState {
            ontop: false,
            visible: false,
            cursor: String::default(),
            geometry: Geometry::zero(),
            geometry_dirty: false
        }
    }
}

impl Display for DrawinState {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Drawin: {:p}", self)
    }
}

impl <'lua> Drawin<'lua> {
    fn new(lua: &Lua) -> rlua::Result<Object> {
        let class = class::class_setup(lua, "drawin")?;
        Ok(object_setup(lua, Drawin::allocate(lua, class)?)?.build())
    }

    fn update_drawing(&mut self) -> rlua::Result<()> {
        let state = self.state()?;
        let table = &self.0;
        let mut drawable = Drawable::cast(table.get::<_, Table>("drawable")?.into())?;
        drawable.set_geometry(state.geometry)?;
        table.raw_set::<_, Table>("drawable", drawable.get_table())?;
        Ok(())
    }

    fn get_visible(&mut self) -> rlua::Result<bool> {
        let drawin = self.state()?;
        Ok(drawin.visible)
    }

    fn set_visible(&mut self, val: bool) -> rlua::Result<()> {
        let mut drawin = self.state()?;
        drawin.visible = val;
        self.map()?;
        self.set_state(drawin)
    }

    fn map(&mut self) -> rlua::Result<()> {
        // TODO other things
        self.update_drawing()
    }

    fn get_geometry(&self) -> rlua::Result<Geometry> {
        Ok(self.state()?.geometry)
    }

    fn resize(&mut self, geometry: Geometry) -> rlua::Result<()> {
        let mut state = self.state()?;
        let old_geometry = state.geometry;
        state.geometry = geometry;
        if state.geometry.size.w <= 0 {
            state.geometry.size.w = old_geometry.size.w;
        }
        if state.geometry.size.h <= 0 {
            state.geometry.size.h = old_geometry.size.h
        }
        state.geometry_dirty = true;
        self.update_drawing()?;
        // TODO emit signals
        // TODO update screen workareas like in awesome? Might not be necessary
        self.set_state(state)
    }
}

impl <'lua> ToLua<'lua> for Drawin<'lua> {
    fn to_lua(self, lua: &'lua Lua) -> rlua::Result<Value<'lua>> {
        self.0.to_lua(lua)
    }
}

impl_objectable!(Drawin, DrawinState);

pub fn init(lua: &Lua) -> rlua::Result<Class> {
    property_setup(lua, method_setup(lua, Class::builder(lua, Some(Rc::new(Drawin::new)), None, None)?)?)?
        .save_class("drawin")?
        .build()
}

fn method_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    // TODO Do properly
    use super::dummy;
    builder.method("connect_signal".into(), lua.create_function(dummy))?
            // TODO This should be adding properties, e.g like luaA_class_new
           .method("__call".into(), lua.create_function(|lua, _: Value| Drawin::new(lua)))
}

fn property_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    builder
        .property(Property::new("x".into(),
                                Some(lua.create_function(set_x)),
                                Some(lua.create_function(get_x)),
                                Some(lua.create_function(set_x))))?
        .property(Property::new("y".into(),
                                Some(lua.create_function(set_y)),
                                Some(lua.create_function(get_y)),
                                Some(lua.create_function(set_y))))?
        .property(Property::new("width".into(),
                                Some(lua.create_function(set_width)),
                                Some(lua.create_function(get_width)),
                                Some(lua.create_function(set_width))))?
        .property(Property::new("height".into(),
                                Some(lua.create_function(set_height)),
                                Some(lua.create_function(get_height)),
                                Some(lua.create_function(set_height))))?
        .property(Property::new("visible".into(),
                                Some(lua.create_function(set_visible)),
                                Some(lua.create_function(get_visible)),
                                Some(lua.create_function(set_visible))))
}

fn object_setup<'lua>(lua: &'lua Lua, builder: ObjectBuilder<'lua>) -> rlua::Result<ObjectBuilder<'lua>> {
    // TODO Do properly
    let table = lua.create_table();
    let drawable_table = Drawable::new(lua)?.to_lua(lua)?;
    table.set("drawable", drawable_table)?;
    table.set("geometry", lua.create_function(drawin_geometry))?;
    builder.add_to_meta(table)
}

fn set_visible<'lua>(_: &'lua Lua, (table, visible): (Table<'lua>, bool))
                     -> rlua::Result<()> {
    let mut drawin = Drawin::cast(table.into())?;
    drawin.set_visible(visible)
    // TODO signal
}

fn get_visible<'lua>(_: &'lua Lua, table: Table<'lua>) -> rlua::Result<bool> {
    let mut drawin = Drawin::cast(table.into())?;
    drawin.get_visible()
    // TODO signal
}

fn drawin_geometry<'lua>(lua: &'lua Lua, (drawin, geometry): (Table<'lua>, Table<'lua>)) -> rlua::Result<Table<'lua>> {
    let mut drawin = Drawin::cast(drawin.into())?;
    let w = geometry.get::<_, i32>("width")?;
    let h = geometry.get::<_, i32>("height")?;
    let x = geometry.get::<_, i32>("x")?;
    let y = geometry.get::<_, i32>("y")?;
    if x > 0 && y > 0 {
        let geo = Geometry {
            origin: Point { x, y },
            size: Size { w: w as u32, h: h as u32 }
        };
        drawin.resize(geo)?;
    }
    let new_geo = drawin.get_geometry()?;
    let Size { w, h } = new_geo.size;
    let Point { x, y } = new_geo.origin;
    let res = lua.create_table();
    res.set("x", x)?;
    res.set("y", y)?;
    res.set("height", h)?;
    res.set("width", w)?;
    Ok(res)
}

fn get_x<'lua>(_: &'lua Lua, drawin: Table<'lua>) -> rlua::Result<LuaInteger> {
    let drawin = Drawin::cast(drawin.into())?;
    let Point { x, .. } = drawin.get_geometry()?.origin;
    Ok(x as LuaInteger)
}

fn set_x<'lua>(_: &'lua Lua, (drawin, x): (Table<'lua>, LuaInteger)) -> rlua::Result<()> {
    let mut drawin = Drawin::cast(drawin.into())?;
    let mut geo = drawin.get_geometry()?;
    geo.origin.x = x as i32;
    drawin.resize(geo)?;
    Ok(())
}

fn get_y<'lua>(_: &'lua Lua, drawin: Table<'lua>) -> rlua::Result<LuaInteger> {
    let drawin = Drawin::cast(drawin.into())?;
    let Point { y, .. } = drawin.get_geometry()?.origin;
    Ok(y as LuaInteger)
}

fn set_y<'lua>(_: &'lua Lua, (drawin, y): (Table<'lua>, LuaInteger)) -> rlua::Result<()> {
    let mut drawin = Drawin::cast(drawin.into())?;
    let mut geo = drawin.get_geometry()?;
    geo.origin.y = y as i32;
    drawin.resize(geo)?;
    Ok(())
}

fn get_width<'lua>(_: &'lua Lua, drawin: Table<'lua>) -> rlua::Result<LuaInteger> {
    let drawin = Drawin::cast(drawin.into())?;
    let Size { w, .. } = drawin.get_geometry()?.size;
    Ok(w as LuaInteger)
}

fn set_width<'lua>(_: &'lua Lua, (drawin, width): (Table<'lua>, LuaInteger)) -> rlua::Result<()> {
    let mut drawin = Drawin::cast(drawin.into())?;
    let mut geo = drawin.get_geometry()?;
    if width > 0 {
        geo.size.w = width as u32;
        drawin.resize(geo)?;
    }
    Ok(())
}

fn get_height<'lua>(_: &'lua Lua, drawin: Table<'lua>) -> rlua::Result<LuaInteger> {
    let drawin = Drawin::cast(drawin.into())?;
    let Size { h, .. } = drawin.get_geometry()?.size;
    Ok(h as LuaInteger)
}

fn set_height<'lua>(_: &'lua Lua, (drawin, height): (Table<'lua>, LuaInteger)) -> rlua::Result<()> {
    let mut drawin = Drawin::cast(drawin.into())?;
    let mut geo = drawin.get_geometry()?;
    if height > 0 {
        geo.size.h = height as u32;
        drawin.resize(geo)?;
    }
    Ok(())
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::fmt;
use std::io::Write;

use syn;

use crate::bindgen::cargo::cargo_metadata::Dependency;
use crate::bindgen::config::Config;
use crate::bindgen::writer::SourceWriter;

#[derive(PartialEq, Eq)]
enum DefineKey<'a> {
    Boolean(&'a str),
    Named(&'a str, &'a str),
}

impl<'a> DefineKey<'a> {
    fn load(key: &str) -> DefineKey {
        // TODO: dirty parser
        if !key.contains('=') {
            return DefineKey::Boolean(key);
        }

        let mut splits = key.trim().split('=');

        let name = match splits.next() {
            Some(n) => n.trim(),
            None => return DefineKey::Boolean(key),
        };

        let value = match splits.next() {
            Some(v) => v.trim(),
            None => return DefineKey::Boolean(key),
        };

        if splits.next().is_some() {
            return DefineKey::Boolean(key);
        }

        DefineKey::Named(name, value)
    }
}

#[derive(Debug, Clone)]
pub enum Cfg {
    Boolean(String),
    Named(String, String),
    Any(Vec<Cfg>),
    All(Vec<Cfg>),
    Not(Box<Cfg>),
}

impl fmt::Display for Cfg {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Cfg::Boolean(key) => write!(f, "{}", key),
            Cfg::Named(key, value) => write!(f, "{} = {:?}", key, value),
            Cfg::Any(cfgs) => {
                write!(f, "any(")?;
                for (index, cfg) in cfgs.iter().enumerate() {
                    if index > 0 {
                        write!(f, ", ")?;
                    }
                    write!(f, "{}", cfg)?;
                }
                write!(f, ")")
            }
            Cfg::All(cfgs) => {
                write!(f, "all(")?;
                for (index, cfg) in cfgs.iter().enumerate() {
                    if index > 0 {
                        write!(f, ", ")?;
                    }
                    write!(f, "{}", cfg)?;
                }
                write!(f, ")")
            }
            Cfg::Not(cfg) => write!(f, "not({})", cfg),
        }
    }
}

impl Cfg {
    pub fn join(cfgs: &[Cfg]) -> Option<Cfg> {
        if cfgs.is_empty() {
            None
        } else {
            Some(Cfg::All(cfgs.to_owned()))
        }
    }

    pub fn append(parent: Option<&Cfg>, child: Option<Cfg>) -> Option<Cfg> {
        match (parent, child) {
            (None, None) => None,
            (None, Some(child)) => Some(child),
            (Some(parent), None) => Some(parent.clone()),
            (Some(parent), Some(child)) => Some(Cfg::All(vec![parent.clone(), child])),
        }
    }

    pub fn load(attrs: &[syn::Attribute]) -> Option<Cfg> {
        let mut configs = Vec::new();

        for attr in attrs {
            if let Ok(syn::Meta::List(syn::MetaList { path, nested, .. })) = attr.parse_meta() {
                if !path.is_ident("cfg") || nested.len() != 1 {
                    continue;
                }

                if let Some(config) = Cfg::load_single(nested.first().unwrap()) {
                    configs.push(config);
                }
            }
        }

        match configs.len() {
            0 => None,
            1 => Some(configs.pop().unwrap()),
            _ => Some(Cfg::All(configs)),
        }
    }

    pub fn load_metadata(dependency: &Dependency) -> Option<Cfg> {
        dependency
            .target
            .as_ref()
            .map(|target| {
                syn::parse_str::<syn::Meta>(target)
                    .expect("error parsing dependency's target metadata")
            })
            .and_then(|target| {
                if let syn::Meta::List(syn::MetaList { path, nested, .. }) = target {
                    if !path.is_ident("cfg") || nested.len() != 1 {
                        return None;
                    }
                    Cfg::load_single(nested.first().unwrap())
                } else {
                    None
                }
            })
    }

    fn load_single(item: &syn::NestedMeta) -> Option<Cfg> {
        match *item {
            syn::NestedMeta::Meta(syn::Meta::Path(ref path)) => Some(Cfg::Boolean(format!(
                "{}",
                path.segments.first().unwrap().ident
            ))),
            syn::NestedMeta::Meta(syn::Meta::NameValue(syn::MetaNameValue {
                ref path,
                ref lit,
                ..
            })) => match lit {
                &syn::Lit::Str(ref value) => Some(Cfg::Named(
                    format!("{}", path.segments.first().unwrap().ident),
                    value.value(),
                )),
                _ => None,
            },
            syn::NestedMeta::Meta(syn::Meta::List(syn::MetaList {
                ref path,
                ref nested,
                ..
            })) => {
                if path.is_ident("any") {
                    if let Some(configs) = Cfg::load_list(nested.iter()) {
                        Some(Cfg::Any(configs))
                    } else {
                        None
                    }
                } else if path.is_ident("all") {
                    if let Some(configs) = Cfg::load_list(nested.iter()) {
                        Some(Cfg::All(configs))
                    } else {
                        None
                    }
                } else if path.is_ident("not") {
                    if nested.len() != 1 {
                        return None;
                    }

                    if let Some(config) = Cfg::load_single(&nested[0]) {
                        Some(Cfg::Not(Box::new(config)))
                    } else {
                        None
                    }
                } else {
                    None
                }
            }
            _ => None,
        }
    }

    fn load_list<'a, I: Iterator<Item = &'a syn::NestedMeta>>(attrs: I) -> Option<Vec<Cfg>> {
        let mut configs = Vec::new();

        for attr in attrs {
            if let Some(config) = Cfg::load_single(attr) {
                configs.push(config);
            } else {
                return None;
            }
        }

        if configs.is_empty() {
            None
        } else {
            Some(configs)
        }
    }
}

pub trait ToCondition: Sized {
    fn to_condition(&self, config: &Config) -> Option<Condition>;
}

impl<'a> ToCondition for Option<Cfg> {
    fn to_condition(&self, config: &Config) -> Option<Condition> {
        self.as_ref()?.to_condition(config)
    }
}

impl<'a> ToCondition for Cfg {
    fn to_condition(&self, config: &Config) -> Option<Condition> {
        match *self {
            Cfg::Boolean(ref cfg_name) => {
                let define = config
                    .defines
                    .iter()
                    .find(|(key, ..)| DefineKey::Boolean(&cfg_name) == DefineKey::load(key));
                if let Some((_, define)) = define {
                    Some(Condition::Define(define.to_owned()))
                } else {
                    warn!(
                        "Missing `[defines]` entry for `{}` in cbindgen config.",
                        self,
                    );
                    None
                }
            }
            Cfg::Named(ref cfg_name, ref cfg_value) => {
                let define = config.defines.iter().find(|(key, ..)| {
                    DefineKey::Named(&cfg_name, &cfg_value) == DefineKey::load(key)
                });
                if let Some((_, define)) = define {
                    Some(Condition::Define(define.to_owned()))
                } else {
                    warn!(
                        "Missing `[defines]` entry for `{}` in cbindgen config.",
                        self,
                    );
                    None
                }
            }
            Cfg::Any(ref children) => {
                let conditions: Vec<_> = children
                    .iter()
                    .filter_map(|x| x.to_condition(config))
                    .collect();
                match conditions.len() {
                    0 => None,
                    1 => conditions.into_iter().next(),
                    _ => Some(Condition::Any(conditions)),
                }
            }
            Cfg::All(ref children) => {
                let cfgs: Vec<_> = children
                    .iter()
                    .filter_map(|x| x.to_condition(config))
                    .collect();
                match cfgs.len() {
                    0 => None,
                    1 => cfgs.into_iter().next(),
                    _ => Some(Condition::All(cfgs)),
                }
            }
            Cfg::Not(ref child) => child
                .to_condition(config)
                .map(|cfg| Condition::Not(Box::new(cfg))),
        }
    }
}

#[derive(Debug, Clone)]
pub enum Condition {
    Define(String),
    Any(Vec<Condition>),
    All(Vec<Condition>),
    Not(Box<Condition>),
}

impl Condition {
    fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
        match *self {
            Condition::Define(ref define) => {
                out.write("defined(");
                write!(out, "{}", define);
                out.write(")");
            }
            Condition::Any(ref conditions) => {
                out.write("(");
                for (i, condition) in conditions.iter().enumerate() {
                    if i != 0 {
                        out.write(" || ");
                    }
                    condition.write(config, out);
                }
                out.write(")");
            }
            Condition::All(ref conditions) => {
                out.write("(");
                for (i, condition) in conditions.iter().enumerate() {
                    if i != 0 {
                        out.write(" && ");
                    }
                    condition.write(config, out);
                }
                out.write(")");
            }
            Condition::Not(ref condition) => {
                out.write("!");
                condition.write(config, out);
            }
        }
    }
}

pub trait ConditionWrite {
    fn write_before<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>);
    fn write_after<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>);
}

impl ConditionWrite for Option<Condition> {
    fn write_before<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
        if let Some(ref cfg) = *self {
            out.push_set_spaces(0);
            out.write("#if ");
            cfg.write(config, out);
            out.pop_set_spaces();
            out.new_line();
        }
    }

    fn write_after<F: Write>(&self, _config: &Config, out: &mut SourceWriter<F>) {
        if self.is_some() {
            out.new_line();
            out.push_set_spaces(0);
            out.write("#endif");
            out.pop_set_spaces();
        }
    }
}
<commit_msg>ir: cfg: Cleanup the cfg code a bit more.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::fmt;
use std::io::Write;

use syn;

use crate::bindgen::cargo::cargo_metadata::Dependency;
use crate::bindgen::config::Config;
use crate::bindgen::writer::SourceWriter;

#[derive(PartialEq, Eq)]
enum DefineKey<'a> {
    Boolean(&'a str),
    Named(&'a str, &'a str),
}

impl<'a> DefineKey<'a> {
    fn load(key: &str) -> DefineKey {
        // TODO: dirty parser
        if !key.contains('=') {
            return DefineKey::Boolean(key);
        }

        let mut splits = key.trim().split('=');

        let name = match splits.next() {
            Some(n) => n.trim(),
            None => return DefineKey::Boolean(key),
        };

        let value = match splits.next() {
            Some(v) => v.trim(),
            None => return DefineKey::Boolean(key),
        };

        if splits.next().is_some() {
            return DefineKey::Boolean(key);
        }

        DefineKey::Named(name, value)
    }
}

#[derive(Debug, Clone)]
pub enum Cfg {
    Boolean(String),
    Named(String, String),
    Any(Vec<Cfg>),
    All(Vec<Cfg>),
    Not(Box<Cfg>),
}

impl fmt::Display for Cfg {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Cfg::Boolean(key) => write!(f, "{}", key),
            Cfg::Named(key, value) => write!(f, "{} = {:?}", key, value),
            Cfg::Any(cfgs) => {
                write!(f, "any(")?;
                for (index, cfg) in cfgs.iter().enumerate() {
                    if index > 0 {
                        write!(f, ", ")?;
                    }
                    write!(f, "{}", cfg)?;
                }
                write!(f, ")")
            }
            Cfg::All(cfgs) => {
                write!(f, "all(")?;
                for (index, cfg) in cfgs.iter().enumerate() {
                    if index > 0 {
                        write!(f, ", ")?;
                    }
                    write!(f, "{}", cfg)?;
                }
                write!(f, ")")
            }
            Cfg::Not(cfg) => write!(f, "not({})", cfg),
        }
    }
}

impl Cfg {
    pub fn join(cfgs: &[Cfg]) -> Option<Cfg> {
        if cfgs.is_empty() {
            None
        } else {
            Some(Cfg::All(cfgs.to_owned()))
        }
    }

    pub fn append(parent: Option<&Cfg>, child: Option<Cfg>) -> Option<Cfg> {
        match (parent, child) {
            (None, None) => None,
            (None, Some(child)) => Some(child),
            (Some(parent), None) => Some(parent.clone()),
            (Some(parent), Some(child)) => Some(Cfg::All(vec![parent.clone(), child])),
        }
    }

    pub fn load(attrs: &[syn::Attribute]) -> Option<Cfg> {
        let mut configs = Vec::new();

        for attr in attrs {
            if let Ok(syn::Meta::List(syn::MetaList { path, nested, .. })) = attr.parse_meta() {
                if !path.is_ident("cfg") || nested.len() != 1 {
                    continue;
                }

                if let Some(config) = Cfg::load_single(nested.first().unwrap()) {
                    configs.push(config);
                }
            }
        }

        match configs.len() {
            0 => None,
            1 => Some(configs.pop().unwrap()),
            _ => Some(Cfg::All(configs)),
        }
    }

    pub fn load_metadata(dependency: &Dependency) -> Option<Cfg> {
        dependency
            .target
            .as_ref()
            .map(|target| {
                syn::parse_str::<syn::Meta>(target)
                    .expect("error parsing dependency's target metadata")
            })
            .and_then(|target| {
                if let syn::Meta::List(syn::MetaList { path, nested, .. }) = target {
                    if !path.is_ident("cfg") || nested.len() != 1 {
                        return None;
                    }
                    Cfg::load_single(nested.first().unwrap())
                } else {
                    None
                }
            })
    }

    fn load_single(item: &syn::NestedMeta) -> Option<Cfg> {
        Some(match *item {
            syn::NestedMeta::Meta(syn::Meta::Path(ref path)) => {
                Cfg::Boolean(format!("{}", path.segments.first().unwrap().ident))
            }
            syn::NestedMeta::Meta(syn::Meta::NameValue(syn::MetaNameValue {
                ref path,
                ref lit,
                ..
            })) => match *lit {
                syn::Lit::Str(ref value) => Cfg::Named(
                    format!("{}", path.segments.first().unwrap().ident),
                    value.value(),
                ),
                _ => return None,
            },
            syn::NestedMeta::Meta(syn::Meta::List(syn::MetaList {
                ref path,
                ref nested,
                ..
            })) => {
                if path.is_ident("any") {
                    Cfg::Any(Cfg::load_list(nested.iter())?)
                } else if path.is_ident("all") {
                    Cfg::All(Cfg::load_list(nested.iter())?)
                } else if path.is_ident("not") {
                    if nested.len() != 1 {
                        return None;
                    }

                    Cfg::Not(Box::new(Cfg::load_single(&nested[0])?))
                } else {
                    return None;
                }
            }
            _ => return None,
        })
    }

    fn load_list<'a, I: Iterator<Item = &'a syn::NestedMeta>>(attrs: I) -> Option<Vec<Cfg>> {
        let mut configs = Vec::new();

        for attr in attrs {
            configs.push(Cfg::load_single(attr)?);
        }

        if configs.is_empty() {
            None
        } else {
            Some(configs)
        }
    }
}

pub trait ToCondition: Sized {
    fn to_condition(&self, config: &Config) -> Option<Condition>;
}

impl<'a> ToCondition for Option<Cfg> {
    fn to_condition(&self, config: &Config) -> Option<Condition> {
        self.as_ref()?.to_condition(config)
    }
}

impl<'a> ToCondition for Cfg {
    fn to_condition(&self, config: &Config) -> Option<Condition> {
        match *self {
            Cfg::Boolean(ref cfg_name) => {
                let define = config
                    .defines
                    .iter()
                    .find(|(key, ..)| DefineKey::Boolean(&cfg_name) == DefineKey::load(key));
                if let Some((_, define)) = define {
                    Some(Condition::Define(define.to_owned()))
                } else {
                    warn!(
                        "Missing `[defines]` entry for `{}` in cbindgen config.",
                        self,
                    );
                    None
                }
            }
            Cfg::Named(ref cfg_name, ref cfg_value) => {
                let define = config.defines.iter().find(|(key, ..)| {
                    DefineKey::Named(&cfg_name, &cfg_value) == DefineKey::load(key)
                });
                if let Some((_, define)) = define {
                    Some(Condition::Define(define.to_owned()))
                } else {
                    warn!(
                        "Missing `[defines]` entry for `{}` in cbindgen config.",
                        self,
                    );
                    None
                }
            }
            Cfg::Any(ref children) => {
                let conditions: Vec<_> = children
                    .iter()
                    .filter_map(|x| x.to_condition(config))
                    .collect();
                match conditions.len() {
                    0 => None,
                    1 => conditions.into_iter().next(),
                    _ => Some(Condition::Any(conditions)),
                }
            }
            Cfg::All(ref children) => {
                let cfgs: Vec<_> = children
                    .iter()
                    .filter_map(|x| x.to_condition(config))
                    .collect();
                match cfgs.len() {
                    0 => None,
                    1 => cfgs.into_iter().next(),
                    _ => Some(Condition::All(cfgs)),
                }
            }
            Cfg::Not(ref child) => child
                .to_condition(config)
                .map(|cfg| Condition::Not(Box::new(cfg))),
        }
    }
}

#[derive(Debug, Clone)]
pub enum Condition {
    Define(String),
    Any(Vec<Condition>),
    All(Vec<Condition>),
    Not(Box<Condition>),
}

impl Condition {
    fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
        match *self {
            Condition::Define(ref define) => {
                out.write("defined(");
                write!(out, "{}", define);
                out.write(")");
            }
            Condition::Any(ref conditions) => {
                out.write("(");
                for (i, condition) in conditions.iter().enumerate() {
                    if i != 0 {
                        out.write(" || ");
                    }
                    condition.write(config, out);
                }
                out.write(")");
            }
            Condition::All(ref conditions) => {
                out.write("(");
                for (i, condition) in conditions.iter().enumerate() {
                    if i != 0 {
                        out.write(" && ");
                    }
                    condition.write(config, out);
                }
                out.write(")");
            }
            Condition::Not(ref condition) => {
                out.write("!");
                condition.write(config, out);
            }
        }
    }
}

pub trait ConditionWrite {
    fn write_before<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>);
    fn write_after<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>);
}

impl ConditionWrite for Option<Condition> {
    fn write_before<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
        if let Some(ref cfg) = *self {
            out.push_set_spaces(0);
            out.write("#if ");
            cfg.write(config, out);
            out.pop_set_spaces();
            out.new_line();
        }
    }

    fn write_after<F: Write>(&self, _config: &Config, out: &mut SourceWriter<F>) {
        if self.is_some() {
            out.new_line();
            out.push_set_spaces(0);
            out.write("#endif");
            out.pop_set_spaces();
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use bindgen::items::*;

pub fn mangle_path(name: &str, generic_values: &Vec<Type>) -> String {
    assert!(!name.contains("_"));

    let mut out = String::from(name);
    out.push_str("_");
    for (i, ty) in generic_values.iter().enumerate() {
        if i != 0 {
            out.push_str("__"); // ,
        }
        append_type(ty, &mut out);
    }
    out
}

fn append_type(ty: &Type, out: &mut String) {
    match ty {
        &Type::Path(ref path, ref generic_values) => {
            out.push_str(path);
            if generic_values.len() != 0 {
                out.push_str("_"); // <
                for (i, generic) in generic_values.iter().enumerate() {
                    if i != 0 {
                        out.push_str("__"); // ,
                    }
                    append_type(generic, out);
                }
                out.push_str("___"); // >
            }
        }
        &Type::Primitive(ref primitive) => {
            out.push_str(primitive.to_repr_rust());
        }
        &Type::ConstPtr(..) => {
            unimplemented!();
        }
        &Type::Ptr(..) => {
            unimplemented!();
        }
        &Type::Array(..) => {
            unimplemented!();
        }
        &Type::FuncPtr(..) => {
            unimplemented!();
        }
    }
}

#[test]
fn mangle_test() {
    assert_eq!(mangle_path("Foo",
                           &vec![Type::Primitive(PrimitiveType::Float)]),
               "Foo_float");

    assert_eq!(mangle_path("Foo",
                           &vec![Type::Path("Bar".to_owned(),
                                            vec![Type::Primitive(PrimitiveType::Float)])
                           ]),
               "Foo_Bar_float___");
}
<commit_msg>Update mangle.rs test expectations<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use bindgen::items::*;

pub fn mangle_path(name: &str, generic_values: &Vec<Type>) -> String {
    assert!(!name.contains("_"));

    let mut out = String::from(name);
    out.push_str("_");
    for (i, ty) in generic_values.iter().enumerate() {
        if i != 0 {
            out.push_str("__"); // ,
        }
        append_type(ty, &mut out);
    }
    out
}

fn append_type(ty: &Type, out: &mut String) {
    match ty {
        &Type::Path(ref path, ref generic_values) => {
            out.push_str(path);
            if generic_values.len() != 0 {
                out.push_str("_"); // <
                for (i, generic) in generic_values.iter().enumerate() {
                    if i != 0 {
                        out.push_str("__"); // ,
                    }
                    append_type(generic, out);
                }
                out.push_str("___"); // >
            }
        }
        &Type::Primitive(ref primitive) => {
            out.push_str(primitive.to_repr_rust());
        }
        &Type::ConstPtr(..) => {
            unimplemented!();
        }
        &Type::Ptr(..) => {
            unimplemented!();
        }
        &Type::Array(..) => {
            unimplemented!();
        }
        &Type::FuncPtr(..) => {
            unimplemented!();
        }
    }
}

#[test]
fn mangle_test() {
    assert_eq!(mangle_path("Foo",
                           &vec![Type::Primitive(PrimitiveType::Float)]),
               "Foo_f32");

    assert_eq!(mangle_path("Foo",
                           &vec![Type::Path("Bar".to_owned(),
                                            vec![Type::Primitive(PrimitiveType::Float)])
                           ]),
               "Foo_Bar_f32___");
}
<|endoftext|>