<commit_before>// Copyright (c) 2015 T. Okubo
// This file is part of vlc-rs.
// Licensed under the MIT license, see the LICENSE file.

use sys;
use ::Instance;
use ::Media;
use ::EventManager;
use ::libc::{c_void, c_uint};
use ::enums::{State, Position};
use std::mem::transmute;

/// A LibVLC media player plays one media (usually in a custom drawable).
pub struct MediaPlayer {
    pub(crate) ptr: *mut sys::libvlc_media_player_t,
}

impl MediaPlayer {
    /// Create an empty Media Player object
    pub fn new(instance: &Instance) -> Option<MediaPlayer> {
        unsafe{
            let p = sys::libvlc_media_player_new(instance.ptr);

            if p.is_null() {
                return None;
            }
            Some(MediaPlayer{ptr: p})
        }
    }

    /// Set the media that will be used by the media_player. If any, previous md will be released.
    pub fn set_media(&self, md: &Media) {
        unsafe{ sys::libvlc_media_player_set_media(self.ptr, md.ptr) };
    }

    /// Get the media used by the media_player.
    pub fn get_media(&self) -> Option<Media> {
        let p = unsafe{ sys::libvlc_media_player_get_media(self.ptr) };
        if p.is_null() {
            None
        }else{
            Some(Media{ptr: p})
        }
    }

    /// Get the Event Manager from which the media player send event.
    pub fn event_manager<'a>(&'a self) -> EventManager<'a> {
        unsafe{
            let p = sys::libvlc_media_player_event_manager(self.ptr);
            assert!(!p.is_null());
            EventManager{ptr: p, _phantomdata: ::std::marker::PhantomData}
        }
    }

    /// is_playing
    pub fn is_playing(&self) -> bool {
        if unsafe{ sys::libvlc_media_player_is_playing(self.ptr) } == 0 {
            false
        }else{
            true
        }
    }

    /// Play
    pub fn play(&self) -> Result<(), ()> {
        if unsafe{ sys::libvlc_media_player_play(self.ptr) } == 0 {
            Ok(())
        }else{
            Err(())
        }
    }

    /// Pause or resume (no effect if there is no media)
    pub fn set_pause(&self, do_pause: bool) {
        unsafe{ sys::libvlc_media_player_set_pause(self.ptr, if do_pause {1} else {0}) };
    }

    /// Toggle pause (no effect if there is no media)
    pub fn pause(&self) {
        unsafe{ sys::libvlc_media_player_pause(self.ptr) };
    }

    /// Stop (no effect if there is no media)
    pub fn stop(&self) {
        unsafe{ sys::libvlc_media_player_stop(self.ptr) };
    }

    pub fn set_callbacks<F>(
        &self,
        play: F,
        pause: Option<Box<dyn Fn(i64) + Send + 'static>>,
        resume: Option<Box<dyn Fn(i64) + Send + 'static>>,
        flush: Option<Box<dyn Fn(i64) + Send + 'static>>,
        drain: Option<Box<dyn Fn() + Send + 'static>>)
        where F: Fn(*const c_void, u32, i64) + Send + 'static,
    {
        let flag_pause = pause.is_some();
        let flag_resume = resume.is_some();
        let flag_flush = flush.is_some();
        let flag_drain = drain.is_some();

        let data = AudioCallbacksData {
            play: Box::new(play), pause: pause, resume: resume,
            flush: flush, drain: drain,
        };
        let data = Box::into_raw(Box::new(data));

        unsafe{
            sys::libvlc_audio_set_callbacks(
                self.ptr,
                Some(audio_cb_play),
                if flag_pause {Some(audio_cb_pause)} else {None},
                if flag_resume {Some(audio_cb_resume)} else {None},
                if flag_flush {Some(audio_cb_flush)} else {None},
                if flag_drain {Some(audio_cb_drain)} else {None},
                data as *mut c_void);
        }
    }

    /// Set the NSView handler where the media player should render its video output.
    pub fn set_nsobject(&self, drawable: *mut c_void) {
        unsafe{ sys::libvlc_media_player_set_nsobject(self.ptr, drawable) };
    }

    /// Get the NSView handler previously set with set_nsobject().
    pub fn get_nsobject(&self) -> Option<*mut c_void> {
        let nso = unsafe{ sys::libvlc_media_player_get_nsobject(self.ptr) };
        if nso.is_null() { None }else{ Some(nso) }
    }

    /// Set an X Window System drawable where the media player should render its video output.
    pub fn set_xwindow(&self, drawable: u32) {
        unsafe{ sys::libvlc_media_player_set_xwindow(self.ptr, drawable) };
    }

    /// Get the X Window System window identifier previously set with set_xwindow().
    pub fn get_xwindow(&self) -> Option<u32> {
        let id = unsafe{ sys::libvlc_media_player_get_xwindow(self.ptr) };
        if id == 0 { None }else{ Some(id) }
    }

    /// Set a Win32/Win64 API window handle (HWND) where the media player should render its video output.
    /// If LibVLC was built without Win32/Win64 API output support, then this has no effects.
    pub fn set_hwnd(&self, drawable: *mut c_void) {
        unsafe{ sys::libvlc_media_player_set_hwnd(self.ptr, drawable) };
    }

    /// Get the Windows API window handle (HWND) previously set with set_hwnd().
    pub fn get_hwnd(&self) -> Option<*mut c_void> {
        let hwnd = unsafe{ sys::libvlc_media_player_get_hwnd(self.ptr) };
        if hwnd.is_null() { None }else{ Some(hwnd) }
    }

    /// Get the current movie time (in ms).
    pub fn get_time(&self) -> Option<i64> {
        unsafe{
            let t = sys::libvlc_media_player_get_time(self.ptr);
            if t == -1 { None }else{ Some(t) }
        }
    }

    /// Set the movie time (in ms).
    /// This has no effect if no media is being played. Not all formats and protocols support this.
    pub fn set_time(&self, time: i64) {
        unsafe{ sys::libvlc_media_player_set_time(self.ptr, time); }
    }

    /// Get movie position as percentage between 0.0 and 1.0.
    pub fn get_position(&self) -> Option<f32> {
        unsafe{
            let pos = sys::libvlc_media_player_get_position(self.ptr);
            if pos == -1f32 { None }else{ Some(pos) }
        }
    }

    /// Set movie position as percentage between 0.0 and 1.0.
    /// This has no effect if playback is not enabled. This might not work depending on the underlying input format and protocol.
    pub fn set_position(&self, pos: f32) {
        unsafe{ sys::libvlc_media_player_set_position(self.ptr, pos); }
    }

    /// Set movie chapter (if applicable).
    pub fn set_chapter(&self, chapter: i32) {
        unsafe{ sys::libvlc_media_player_set_chapter(self.ptr, chapter); }
    }

    /// Get movie chapter.
    pub fn get_chapter(&self) -> Option<i32> {
        unsafe{
            let c = sys::libvlc_media_player_get_chapter(self.ptr);
            if c == -1 { None }else{ Some(c) }
        }
    }

    /// Get movie chapter count.
    pub fn chapter_count(&self) -> Option<i32> {
        unsafe{
            let c = sys::libvlc_media_player_get_chapter_count(self.ptr);
            if c == -1 { None }else{ Some(c) }
        }
    }

    /// Is the player able to play.
    pub fn will_play(&self) -> bool {
        unsafe{
            let b = sys::libvlc_media_player_will_play(self.ptr);
            if b == 0 { false }else{ true }
        }
    }

    /// Get title chapter count.
    pub fn chapter_count_for_title(&self, title: i32) -> Option<i32> {
        unsafe{
            let c = sys::libvlc_media_player_get_chapter_count_for_title(self.ptr, title);
            if c == -1 { None }else{ Some(c) }
        }
    }

    /// Set movie title.
    pub fn set_title(&self, title: i32) {
        unsafe{ sys::libvlc_media_player_set_title(self.ptr, title); }
    }

    /// Get movie title.
    pub fn get_title(&self) -> Option<i32> {
        unsafe{
            let t = sys::libvlc_media_player_get_title(self.ptr);
            if t == -1 { None }else{ Some(t) }
        }
    }

    /// Get movie title count.
    pub fn title_count(&self) -> Option<i32> {
        unsafe{
            let t = sys::libvlc_media_player_get_title_count(self.ptr);
            if t == -1 { Some(t) } else { None }
        }
    }

    /// Set previous chapter (if applicable)
    pub fn previous_chapter(&self) {
        unsafe{ sys::libvlc_media_player_previous_chapter(self.ptr); }
    }

    /// Set next chapter (if applicable)
    pub fn next_chapter(&self) {
        unsafe{ sys::libvlc_media_player_next_chapter(self.ptr); }
    }

    /// Get the requested movie play rate.
    pub fn get_rate(&self) -> f32 {
        unsafe{ sys::libvlc_media_player_get_rate(self.ptr) }
    }

    /// Set movie play rate.
    pub fn set_rate(&self, rate: f32) -> Result<(),()> {
        unsafe{
            if sys::libvlc_media_player_set_rate(self.ptr, rate) == -1 {
                Err(())
            }else{
                Ok(())
            }
        }
    }

    /// Get current movie state.
    pub fn state(&self) -> State {
        unsafe{ sys::libvlc_media_player_get_state(self.ptr) }
    }

    /// How many video outputs does this media player have?
    pub fn has_vout(&self) -> u32 {
        unsafe{ sys::libvlc_media_player_has_vout(self.ptr) }
    }

    /// Is this media player seekable?
    pub fn is_seekable(&self) -> bool {
        unsafe{
            let b = sys::libvlc_media_player_is_seekable(self.ptr);
            if b == 0 { false }else{ true }
        }
    }

    /// Can this media player be paused?
    pub fn can_pause(&self) -> bool {
        unsafe{
            let b = sys::libvlc_media_player_can_pause(self.ptr);
            if b == 0 { false }else{ true }
        }
    }

    /// Check if the current program is scrambled.
    pub fn program_scrambled(&self) -> bool {
        unsafe{
            let b = sys::libvlc_media_player_program_scrambled(self.ptr);
            if b == 0 { false }else{ true }
        }
    }

    /// Display the next frame (if supported)
    pub fn next_frame(&self) {
        unsafe{ sys::libvlc_media_player_next_frame(self.ptr); }
    }

    /// Navigate through DVD Menu.
    pub fn navigate(&self, navigate: u32) {
        unsafe{ sys::libvlc_media_player_navigate(self.ptr, navigate); }
    }

    /// Set if, and how, the video title will be shown when media is played.
    pub fn set_video_title_display(&self, position: Position, timeout: u32) {
        unsafe{ sys::libvlc_media_player_set_video_title_display(self.ptr, position, timeout); }
    }

    /// Returns raw pointer
    pub fn raw(&self) -> *mut sys::libvlc_media_player_t {
        self.ptr
    }
}

impl Drop for MediaPlayer {
    fn drop(&mut self) {
        unsafe{ sys::libvlc_media_player_release(self.ptr) };
    }
}

// For audio_set_callbacks
struct AudioCallbacksData {
    play: Box<dyn Fn(*const c_void, u32, i64) + Send + 'static>,
    pause: Option<Box<dyn Fn(i64) + Send + 'static>>,
    resume: Option<Box<dyn Fn(i64) + Send + 'static>>,
    flush: Option<Box<dyn Fn(i64) + Send + 'static>>,
    drain: Option<Box<dyn Fn() + Send + 'static>>,
}

unsafe extern "C" fn audio_cb_play(
    data: *mut c_void, samples: *const c_void, count: c_uint, pts: i64) {
    let data: &AudioCallbacksData = transmute(data as *mut AudioCallbacksData);
    (data.play)(samples, count, pts);

}

unsafe extern "C" fn audio_cb_pause(data: *mut c_void, pts: i64) {
    let data: &AudioCallbacksData = transmute(data as *mut AudioCallbacksData);
    (data.pause.as_ref().unwrap())(pts);
}

unsafe extern "C" fn audio_cb_resume(data: *mut c_void, pts: i64) {
    let data: &AudioCallbacksData = transmute(data as *mut AudioCallbacksData);
    (data.resume.as_ref().unwrap())(pts);
}

unsafe extern "C" fn audio_cb_flush(data: *mut c_void, pts: i64) {
    let data: &AudioCallbacksData = transmute(data as *mut AudioCallbacksData);
    (data.flush.as_ref().unwrap())(pts);
}

unsafe extern "C" fn audio_cb_drain(data: *mut c_void) {
    let data: &AudioCallbacksData = transmute(data as *mut AudioCallbacksData);
    (data.drain.as_ref().unwrap())();
}

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct TrackDescription {
    pub id: i32,
    pub name: Option<String>,
}

<commit_msg>media_player: fix crate path<commit_after>// Copyright (c) 2015 T. Okubo
// This file is part of vlc-rs.
// Licensed under the MIT license, see the LICENSE file.

use crate::sys;
use crate::Instance;
use crate::Media;
use crate::EventManager;
use libc::{c_void, c_uint};
use crate::enums::{State, Position};
use std::mem::transmute;

/// A LibVLC media player plays one media (usually in a custom drawable).
pub struct MediaPlayer {
    pub(crate) ptr: *mut sys::libvlc_media_player_t,
}

impl MediaPlayer {
    /// Create an empty Media Player object
    pub fn new(instance: &Instance) -> Option<MediaPlayer> {
        unsafe{
            let p = sys::libvlc_media_player_new(instance.ptr);

            if p.is_null() {
                return None;
            }
            Some(MediaPlayer{ptr: p})
        }
    }

    /// Set the media that will be used by the media_player. If any, previous md will be released.
    pub fn set_media(&self, md: &Media) {
        unsafe{ sys::libvlc_media_player_set_media(self.ptr, md.ptr) };
    }

    /// Get the media used by the media_player.
    pub fn get_media(&self) -> Option<Media> {
        let p = unsafe{ sys::libvlc_media_player_get_media(self.ptr) };
        if p.is_null() {
            None
        }else{
            Some(Media{ptr: p})
        }
    }

    /// Get the Event Manager from which the media player send event.
    pub fn event_manager<'a>(&'a self) -> EventManager<'a> {
        unsafe{
            let p = sys::libvlc_media_player_event_manager(self.ptr);
            assert!(!p.is_null());
            EventManager{ptr: p, _phantomdata: ::std::marker::PhantomData}
        }
    }

    /// is_playing
    pub fn is_playing(&self) -> bool {
        if unsafe{ sys::libvlc_media_player_is_playing(self.ptr) } == 0 {
            false
        }else{
            true
        }
    }

    /// Play
    pub fn play(&self) -> Result<(), ()> {
        if unsafe{ sys::libvlc_media_player_play(self.ptr) } == 0 {
            Ok(())
        }else{
            Err(())
        }
    }

    /// Pause or resume (no effect if there is no media)
    pub fn set_pause(&self, do_pause: bool) {
        unsafe{ sys::libvlc_media_player_set_pause(self.ptr, if do_pause {1} else {0}) };
    }

    /// Toggle pause (no effect if there is no media)
    pub fn pause(&self) {
        unsafe{ sys::libvlc_media_player_pause(self.ptr) };
    }

    /// Stop (no effect if there is no media)
    pub fn stop(&self) {
        unsafe{ sys::libvlc_media_player_stop(self.ptr) };
    }

    pub fn set_callbacks<F>(
        &self,
        play: F,
        pause: Option<Box<dyn Fn(i64) + Send + 'static>>,
        resume: Option<Box<dyn Fn(i64) + Send + 'static>>,
        flush: Option<Box<dyn Fn(i64) + Send + 'static>>,
        drain: Option<Box<dyn Fn() + Send + 'static>>)
        where F: Fn(*const c_void, u32, i64) + Send + 'static,
    {
        let flag_pause = pause.is_some();
        let flag_resume = resume.is_some();
        let flag_flush = flush.is_some();
        let flag_drain = drain.is_some();

        let data = AudioCallbacksData {
            play: Box::new(play), pause: pause, resume: resume,
            flush: flush, drain: drain,
        };
        let data = Box::into_raw(Box::new(data));

        unsafe{
            sys::libvlc_audio_set_callbacks(
                self.ptr,
                Some(audio_cb_play),
                if flag_pause {Some(audio_cb_pause)} else {None},
                if flag_resume {Some(audio_cb_resume)} else {None},
                if flag_flush {Some(audio_cb_flush)} else {None},
                if flag_drain {Some(audio_cb_drain)} else {None},
                data as *mut c_void);
        }
    }

    /// Set the NSView handler where the media player should render its video output.
    pub fn set_nsobject(&self, drawable: *mut c_void) {
        unsafe{ sys::libvlc_media_player_set_nsobject(self.ptr, drawable) };
    }

    /// Get the NSView handler previously set with set_nsobject().
    pub fn get_nsobject(&self) -> Option<*mut c_void> {
        let nso = unsafe{ sys::libvlc_media_player_get_nsobject(self.ptr) };
        if nso.is_null() { None }else{ Some(nso) }
    }

    /// Set an X Window System drawable where the media player should render its video output.
    pub fn set_xwindow(&self, drawable: u32) {
        unsafe{ sys::libvlc_media_player_set_xwindow(self.ptr, drawable) };
    }

    /// Get the X Window System window identifier previously set with set_xwindow().
    pub fn get_xwindow(&self) -> Option<u32> {
        let id = unsafe{ sys::libvlc_media_player_get_xwindow(self.ptr) };
        if id == 0 { None }else{ Some(id) }
    }

    /// Set a Win32/Win64 API window handle (HWND) where the media player should render its video output.
    /// If LibVLC was built without Win32/Win64 API output support, then this has no effects.
    pub fn set_hwnd(&self, drawable: *mut c_void) {
        unsafe{ sys::libvlc_media_player_set_hwnd(self.ptr, drawable) };
    }

    /// Get the Windows API window handle (HWND) previously set with set_hwnd().
    pub fn get_hwnd(&self) -> Option<*mut c_void> {
        let hwnd = unsafe{ sys::libvlc_media_player_get_hwnd(self.ptr) };
        if hwnd.is_null() { None }else{ Some(hwnd) }
    }

    /// Get the current movie time (in ms).
    pub fn get_time(&self) -> Option<i64> {
        unsafe{
            let t = sys::libvlc_media_player_get_time(self.ptr);
            if t == -1 { None }else{ Some(t) }
        }
    }

    /// Set the movie time (in ms).
    /// This has no effect if no media is being played. Not all formats and protocols support this.
    pub fn set_time(&self, time: i64) {
        unsafe{ sys::libvlc_media_player_set_time(self.ptr, time); }
    }

    /// Get movie position as percentage between 0.0 and 1.0.
    pub fn get_position(&self) -> Option<f32> {
        unsafe{
            let pos = sys::libvlc_media_player_get_position(self.ptr);
            if pos == -1f32 { None }else{ Some(pos) }
        }
    }

    /// Set movie position as percentage between 0.0 and 1.0.
    /// This has no effect if playback is not enabled. This might not work depending on the underlying input format and protocol.
    pub fn set_position(&self, pos: f32) {
        unsafe{ sys::libvlc_media_player_set_position(self.ptr, pos); }
    }

    /// Set movie chapter (if applicable).
    pub fn set_chapter(&self, chapter: i32) {
        unsafe{ sys::libvlc_media_player_set_chapter(self.ptr, chapter); }
    }

    /// Get movie chapter.
    pub fn get_chapter(&self) -> Option<i32> {
        unsafe{
            let c = sys::libvlc_media_player_get_chapter(self.ptr);
            if c == -1 { None }else{ Some(c) }
        }
    }

    /// Get movie chapter count.
    pub fn chapter_count(&self) -> Option<i32> {
        unsafe{
            let c = sys::libvlc_media_player_get_chapter_count(self.ptr);
            if c == -1 { None }else{ Some(c) }
        }
    }

    /// Is the player able to play.
    pub fn will_play(&self) -> bool {
        unsafe{
            let b = sys::libvlc_media_player_will_play(self.ptr);
            if b == 0 { false }else{ true }
        }
    }

    /// Get title chapter count.
    pub fn chapter_count_for_title(&self, title: i32) -> Option<i32> {
        unsafe{
            let c = sys::libvlc_media_player_get_chapter_count_for_title(self.ptr, title);
            if c == -1 { None }else{ Some(c) }
        }
    }

    /// Set movie title.
    pub fn set_title(&self, title: i32) {
        unsafe{ sys::libvlc_media_player_set_title(self.ptr, title); }
    }

    /// Get movie title.
    pub fn get_title(&self) -> Option<i32> {
        unsafe{
            let t = sys::libvlc_media_player_get_title(self.ptr);
            if t == -1 { None }else{ Some(t) }
        }
    }

    /// Get movie title count.
    pub fn title_count(&self) -> Option<i32> {
        unsafe{
            let t = sys::libvlc_media_player_get_title_count(self.ptr);
            if t == -1 { Some(t) } else { None }
        }
    }

    /// Set previous chapter (if applicable)
    pub fn previous_chapter(&self) {
        unsafe{ sys::libvlc_media_player_previous_chapter(self.ptr); }
    }

    /// Set next chapter (if applicable)
    pub fn next_chapter(&self) {
        unsafe{ sys::libvlc_media_player_next_chapter(self.ptr); }
    }

    /// Get the requested movie play rate.
    pub fn get_rate(&self) -> f32 {
        unsafe{ sys::libvlc_media_player_get_rate(self.ptr) }
    }

    /// Set movie play rate.
    pub fn set_rate(&self, rate: f32) -> Result<(),()> {
        unsafe{
            if sys::libvlc_media_player_set_rate(self.ptr, rate) == -1 {
                Err(())
            }else{
                Ok(())
            }
        }
    }

    /// Get current movie state.
    pub fn state(&self) -> State {
        unsafe{ sys::libvlc_media_player_get_state(self.ptr) }
    }

    /// How many video outputs does this media player have?
    pub fn has_vout(&self) -> u32 {
        unsafe{ sys::libvlc_media_player_has_vout(self.ptr) }
    }

    /// Is this media player seekable?
    pub fn is_seekable(&self) -> bool {
        unsafe{
            let b = sys::libvlc_media_player_is_seekable(self.ptr);
            if b == 0 { false }else{ true }
        }
    }

    /// Can this media player be paused?
    pub fn can_pause(&self) -> bool {
        unsafe{
            let b = sys::libvlc_media_player_can_pause(self.ptr);
            if b == 0 { false }else{ true }
        }
    }

    /// Check if the current program is scrambled.
    pub fn program_scrambled(&self) -> bool {
        unsafe{
            let b = sys::libvlc_media_player_program_scrambled(self.ptr);
            if b == 0 { false }else{ true }
        }
    }

    /// Display the next frame (if supported)
    pub fn next_frame(&self) {
        unsafe{ sys::libvlc_media_player_next_frame(self.ptr); }
    }

    /// Navigate through DVD Menu.
    pub fn navigate(&self, navigate: u32) {
        unsafe{ sys::libvlc_media_player_navigate(self.ptr, navigate); }
    }

    /// Set if, and how, the video title will be shown when media is played.
    pub fn set_video_title_display(&self, position: Position, timeout: u32) {
        unsafe{ sys::libvlc_media_player_set_video_title_display(self.ptr, position, timeout); }
    }

    /// Returns raw pointer
    pub fn raw(&self) -> *mut sys::libvlc_media_player_t {
        self.ptr
    }
}

impl Drop for MediaPlayer {
    fn drop(&mut self) {
        unsafe{ sys::libvlc_media_player_release(self.ptr) };
    }
}

// For audio_set_callbacks
struct AudioCallbacksData {
    play: Box<dyn Fn(*const c_void, u32, i64) + Send + 'static>,
    pause: Option<Box<dyn Fn(i64) + Send + 'static>>,
    resume: Option<Box<dyn Fn(i64) + Send + 'static>>,
    flush: Option<Box<dyn Fn(i64) + Send + 'static>>,
    drain: Option<Box<dyn Fn() + Send + 'static>>,
}

unsafe extern "C" fn audio_cb_play(
    data: *mut c_void, samples: *const c_void, count: c_uint, pts: i64) {
    let data: &AudioCallbacksData = transmute(data as *mut AudioCallbacksData);
    (data.play)(samples, count, pts);

}

unsafe extern "C" fn audio_cb_pause(data: *mut c_void, pts: i64) {
    let data: &AudioCallbacksData = transmute(data as *mut AudioCallbacksData);
    (data.pause.as_ref().unwrap())(pts);
}

unsafe extern "C" fn audio_cb_resume(data: *mut c_void, pts: i64) {
    let data: &AudioCallbacksData = transmute(data as *mut AudioCallbacksData);
    (data.resume.as_ref().unwrap())(pts);
}

unsafe extern "C" fn audio_cb_flush(data: *mut c_void, pts: i64) {
    let data: &AudioCallbacksData = transmute(data as *mut AudioCallbacksData);
    (data.flush.as_ref().unwrap())(pts);
}

unsafe extern "C" fn audio_cb_drain(data: *mut c_void) {
    let data: &AudioCallbacksData = transmute(data as *mut AudioCallbacksData);
    (data.drain.as_ref().unwrap())();
}

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct TrackDescription {
    pub id: i32,
    pub name: Option<String>,
}

<|endoftext|>


<commit_before>use std::fmt;

use crate::node::{Node, Value};

/// A comment node.
#[derive(Clone, Debug)]
pub struct Comment {
    content: String,
}

impl Comment {
    /// Create a node.
    #[inline]
    pub fn new<T>(content: T) -> Self
    where
        T: Into<String>,
    {
        Self {
            content: content.into(),
        }
    }
}

impl fmt::Display for Comment {
    #[inline]
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "<!-- {} -->", self.content)
    }
}

impl Node for Comment {
    #[inline]
    fn append<T>(&mut self, _: T)
    where
        T: Node,
    {
    }

    #[inline]
    fn assign<T, U>(&mut self, _: T, _: U)
    where
        T: Into<String>,
        U: Into<Value>,
    {
    }
}

#[cfg(test)]
mod tests {
    use super::Comment;

    #[test]
    fn comment() {
        let comment = Comment::new("a comment.");
        assert_eq!(comment.to_string(), "<!-- a comment. -->");
    }
}
<commit_msg>Extend the comment test<commit_after>use std::fmt;

use crate::node::{Node, Value};

/// A comment node.
#[derive(Clone, Debug)]
pub struct Comment {
    content: String,
}

impl Comment {
    /// Create a node.
    #[inline]
    pub fn new<T>(content: T) -> Self
    where
        T: Into<String>,
    {
        Self {
            content: content.into(),
        }
    }
}

impl fmt::Display for Comment {
    #[inline]
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "<!-- {} -->", self.content)
    }
}

impl Node for Comment {
    #[inline]
    fn append<T>(&mut self, _: T)
    where
        T: Node,
    {
    }

    #[inline]
    fn assign<T, U>(&mut self, _: T, _: U)
    where
        T: Into<String>,
        U: Into<Value>,
    {
    }
}

#[cfg(test)]
mod tests {
    use super::Comment;

    #[test]
    fn comment_display() {
        let comment = Comment::new("valid");
        assert_eq!(comment.to_string(), "<!-- valid -->");

        let comment = Comment::new("invalid -->");
        assert_eq!(comment.to_string(), "<!-- invalid --> -->");
    }
}
<|endoftext|>


<commit_before>// from <https://github.com/diesel-rs/diesel/blob/8bebe479cb05388220719b8b385fffb727d40588/diesel/src/macros/parse.rs>
// Copyright (C) 2016 Sean Griffin, licensed under MIT/Apache-2.0

#[macro_export]
#[doc(hidden)]
macro_rules! __parse_struct_body {
    // Entry point for named structs
    (
        $headers:tt,
        callback = $callback:ident,
        body = {$($body:tt)*},
    ) => {
        __parse_struct_body! {
            $headers,
            callback = $callback,
            fields = [],
            body = ($($body)*,),
        }
    };

    // Entry point for tuple structs
    (
        $headers:tt,
        callback = $callback:ident,
        body = ($($body:tt)*),
    ) => {
        __parse_struct_body! {
            $headers,
            callback = $callback,
            fields = [],
            body = ($($body)*,),
        }
    };

    // silently skip meta-tokens (e.g. doc-comments)
    (
        $headers:tt,
        callback = $callback:ident,
        fields = $fields:tt,
        body = (
            #$meta:tt
            $($tail:tt)*),
    ) => {
        __parse_struct_body! {
            $headers,
            callback = $callback,
            fields = $fields,
            body = ($($tail)*),
        }
    };

    // silently skip visibility specifier
    (
        $headers:tt,
        callback = $callback:ident,
        fields = $fields:tt,
        body = (
            pub
            $($tail:tt)*),
    ) => {
        __parse_struct_body! {
            $headers,
            callback = $callback,
            fields = $fields,
            body = ($($tail)*),
        }
    };

    // Since we blindly add a comma to the end of the body, we might have a
    // double trailing comma.  If it's the only token left, that's what
    // happened. Strip it.
    (
        $headers:tt,
        callback = $callback:ident,
        fields = $fields:tt,
        body = (,),
    ) => {
        __parse_struct_body! {
            $headers,
            callback = $callback,
            fields = $fields,
            body = (),
        }
    };

    // handle the named struct field and its type
    (
        $headers:tt,
        callback = $callback:ident,
        fields = [$($fields:tt)*],
        body = ($field_name:ident : $field_ty:ty, $($tail:tt)*),
    ) => {
        __parse_struct_body! {
            $headers,
            callback = $callback,
            fields = [$($fields)* {
                field_name: $field_name,
                field_ty: $field_ty,
            }],
            body = ($($tail)*),
        }
    };

    // At this point we've parsed the entire body. We create the pattern
    // for destructuring, and pass all the information back to the main macro
    // to generate the final impl
    (
        $headers:tt,
        callback = $callback:ident,
        fields = $fields:tt,
        body = (),
    ) => {
        $callback! {
            $headers,
            fields = $fields,
        }
    };
}

/// Hack to tell the compiler that something is in fact an item. This is needed
/// when `tt` fragments are used in specific positions.
#[doc(hidden)]
#[macro_export]
macro_rules!  __parse_as_item {
    ($i:item) => { $i }
}
<commit_msg>parse_struct: change order<commit_after>// from <https://github.com/diesel-rs/diesel/blob/8bebe479cb05388220719b8b385fffb727d40588/diesel/src/macros/parse.rs>
// Copyright (C) 2016 Sean Griffin, licensed under MIT/Apache-2.0

#[macro_export]
#[doc(hidden)]
macro_rules! __parse_struct_body {
    // Entry point for named structs
    (
        $headers:tt,
        callback = $callback:ident,
        body = {$($body:tt)*},
    ) => {
        __parse_struct_body! {
            $headers,
            callback = $callback,
            body = ($($body)*,),
            fields = [],
        }
    };

    // Entry point for tuple structs
    (
        $headers:tt,
        callback = $callback:ident,
        body = ($($body:tt)*),
    ) => {
        __parse_struct_body! {
            $headers,
            callback = $callback,
            body = ($($body)*,),
            fields = [],
        }
    };

    // silently skip meta-tokens (e.g. doc-comments)
    (
        $headers:tt,
        callback = $callback:ident,
        body = (
            #$meta:tt
            $($tail:tt)*),
        fields = $fields:tt,
    ) => {
        __parse_struct_body! {
            $headers,
            callback = $callback,
            body = ($($tail)*),
            fields = $fields,
        }
    };

    // silently skip visibility specifier
    (
        $headers:tt,
        callback = $callback:ident,
        body = (
            pub
            $($tail:tt)*),
        fields = $fields:tt,
    ) => {
        __parse_struct_body! {
            $headers,
            callback = $callback,
            body = ($($tail)*),
            fields = $fields,
        }
    };

    // Since we blindly add a comma to the end of the body, we might have a
    // double trailing comma.  If it's the only token left, that's what
    // happened. Strip it.
    (
        $headers:tt,
        callback = $callback:ident,
        body = (,),
        fields = $fields:tt,
    ) => {
        __parse_struct_body! {
            $headers,
            callback = $callback,
            body = (),
            fields = $fields,
        }
    };

    // handle struct field and its type
    (
        $headers:tt,
        callback = $callback:ident,
        body = ($field_name:ident : $field_ty:ty, $($tail:tt)*),
        fields = [$($fields:tt)*],
    ) => {
        __parse_struct_body! {
            $headers,
            callback = $callback,
            body = ($($tail)*),
            fields = [$($fields)* {
                field_name: $field_name,
                field_ty: $field_ty,
            }],
        }
    };

    // At this point we've parsed the entire body. We create the pattern
    // for destructuring, and pass all the information back to the main macro
    // to generate the final impl
    (
        $headers:tt,
        callback = $callback:ident,
        body = (),
        fields = $fields:tt,
    ) => {
        $callback! {
            $headers,
            fields = $fields,
        }
    };
}

/// Hack to tell the compiler that something is in fact an item. This is needed
/// when `tt` fragments are used in specific positions.
#[doc(hidden)]
#[macro_export]
macro_rules!  __parse_as_item {
    ($i:item) => { $i }
}
<|endoftext|>


<commit_before>// these imports (of, eg, 'literal') are only used within macros. It appears
// Rust will incorrectly warn that they are unused, hence this attribute.
#[allow(unused_imports)]
use parsers::*;

#[derive(Show, Eq, PartialEq, Clone)]
enum Input {
  A,
  B,
  C,
  D,
}

//need more tests :/

#[test]
fn test_seq() {
  let input = [Input::A, Input::B, Input::C, Input::D];
  let parser = seq!(literal(Input::A), literal(Input::B), literal(Input::C));
  assert_eq!( parser.parse(input.as_slice()) , Ok(((Input::A, (Input::B, Input::C)), input.slice_from(3))));
}

#[test]
fn test_seq_map() {
  let input = [Input::A, Input::B];
  let parser = seq!(literal(Input::A), literal(Input::B) to |&: (a, b)| 5);
  let expected = Ok( (5, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_rep() {
  let input = [Input::A, Input::B, Input::A, Input::B, Input::A, Input::C];
  let parser = rep!(seq!(literal(Input::A), literal(Input::B)));
  let expected = Ok((
    vec![(Input::A, Input::B), (Input::A, Input::B)],
    input.slice_from(4)
  ));
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_or() {
  let input = [Input::A, Input::B, Input::A, Input::C];
  let parser = rep!(or!(literal(Input::A), literal(Input::B)));
  let expected = Ok((
    vec![Input::A, Input::B, Input::A],
    input.slice_from(3)
  ));
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_multi_or() {
  let input = [Input::A];
  let parser = or!(literal(Input::A), literal(Input::B), literal(Input::C));
  let expected = Ok( (Input::A, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_or_map() {
  let input = [Input::B];
  let parser = or!(literal(Input::A), literal(Input::B) to |&: x| 5);
  let expected = Ok( (5, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_map() {
  let input = [Input::A];
  let parser = map!(literal(Input::A), |&: a| 5);
  let expected = Ok( (5, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_recursive_or() {
  let input = [Input::A, Input::A, Input::C];
  fn a_seq<'a>() -> Box<Parser<'a, &'a [Input], usize> + 'a> {
    Box::new(or!(
      map!(literal(Input::C), |&: _| 2),
      map!(seq!(literal(Input::A), lazy!(a_seq())), |&: (a, seq)| 1 + seq)
    ))
  }
  let parser = a_seq();
  let expected = Ok( (4, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_repsep() {
  let input = [Input::A, Input::B, Input::C, Input::B, Input::A, Input::A];
  let parser = repsep!(or!(literal(Input::A), literal(Input::C)) , literal(Input::B));
  let expected = Ok((vec![Input::A, Input::C, Input::A], input.slice_from(5)));
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_opt() {
  let input = [Input::A, Input::A, Input::B];
  let parser = rep!(seq!(literal(Input::A), opt!(literal(Input::B))));
  let expected = Ok((vec![(Input::A, None), (Input::A, Some(Input::B))], input.slice_from(3)));
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_matcher() {
  let input = [Input::A, Input::B, Input::C];
  let parser = rep!(matcher!(Input : Input::A => 4, Input::B => 5));
  let expected = Ok( (vec![4, 5], input.slice_from(2)) );
  assert_eq!( parser.parse(input.as_slice()), expected );

}

<commit_msg>Don't bind values unnecessarily<commit_after>// these imports (of, eg, 'literal') are only used within macros. It appears
// Rust will incorrectly warn that they are unused, hence this attribute.
#[allow(unused_imports)]
use parsers::*;

#[derive(Show, Eq, PartialEq, Clone)]
enum Input {
  A,
  B,
  C,
  D,
}

//need more tests :/

#[test]
fn test_seq() {
  let input = [Input::A, Input::B, Input::C, Input::D];
  let parser = seq!(literal(Input::A), literal(Input::B), literal(Input::C));
  assert_eq!( parser.parse(input.as_slice()) , Ok(((Input::A, (Input::B, Input::C)), input.slice_from(3))));
}

#[test]
fn test_seq_map() {
  let input = [Input::A, Input::B];
  let parser = seq!(literal(Input::A), literal(Input::B) to |&: _| 5);
  let expected = Ok( (5, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_rep() {
  let input = [Input::A, Input::B, Input::A, Input::B, Input::A, Input::C];
  let parser = rep!(seq!(literal(Input::A), literal(Input::B)));
  let expected = Ok((
    vec![(Input::A, Input::B), (Input::A, Input::B)],
    input.slice_from(4)
  ));
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_or() {
  let input = [Input::A, Input::B, Input::A, Input::C];
  let parser = rep!(or!(literal(Input::A), literal(Input::B)));
  let expected = Ok((
    vec![Input::A, Input::B, Input::A],
    input.slice_from(3)
  ));
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_multi_or() {
  let input = [Input::A];
  let parser = or!(literal(Input::A), literal(Input::B), literal(Input::C));
  let expected = Ok( (Input::A, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_or_map() {
  let input = [Input::B];
  let parser = or!(literal(Input::A), literal(Input::B) to |&: _| 5);
  let expected = Ok( (5, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_map() {
  let input = [Input::A];
  let parser = map!(literal(Input::A), |&: _| 5);
  let expected = Ok( (5, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_recursive_or() {
  let input = [Input::A, Input::A, Input::C];
  fn a_seq<'a>() -> Box<Parser<'a, &'a [Input], usize> + 'a> {
    Box::new(or!(
      map!(literal(Input::C), |&: _| 2),
      map!(seq!(literal(Input::A), lazy!(a_seq())), |&: (_, seq)| 1 + seq)
    ))
  }
  let parser = a_seq();
  let expected = Ok( (4, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_repsep() {
  let input = [Input::A, Input::B, Input::C, Input::B, Input::A, Input::A];
  let parser = repsep!(or!(literal(Input::A), literal(Input::C)) , literal(Input::B));
  let expected = Ok((vec![Input::A, Input::C, Input::A], input.slice_from(5)));
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_opt() {
  let input = [Input::A, Input::A, Input::B];
  let parser = rep!(seq!(literal(Input::A), opt!(literal(Input::B))));
  let expected = Ok((vec![(Input::A, None), (Input::A, Some(Input::B))], input.slice_from(3)));
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_matcher() {
  let input = [Input::A, Input::B, Input::C];
  let parser = rep!(matcher!(Input : Input::A => 4, Input::B => 5));
  let expected = Ok( (vec![4, 5], input.slice_from(2)) );
  assert_eq!( parser.parse(input.as_slice()), expected );

}

<|endoftext|>


<commit_before>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// This is a script to deploy and execute a binary on an x86-64 iOS simulator.
// The primary use of this is to be able to run unit tests on the simulator and retrieve the results.
//
// To do this through Cargo instead, use Dinghy (https://github.com/snipsco/dinghy):
// cargo dinghy install, then cargo dinghy test.

use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::process;
use std::process::Command;

// Step one: Wrap as an app
fn package_as_simulator_app(crate_name: &str, test_binary_path: &Path) {
    println!("Packaging simulator app");
    Command::new("rm").arg("-rf").arg("ios_simulator_app").status().unwrap();
    Command::new("mkdir").arg("ios_simulator_app").check_status();
    Command::new("cp").arg(test_binary_path).arg(["ios_simulator_app/", crate_name].join("")).check_status();
    let mut f = File::create("ios_simulator_app/Info.plist").unwrap();
    f.write_all(&[
        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
        "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">",
        "<plist version=\"1.0\">",
        "    <dict>",
        "        <key>CFBundleExecutable</key>",
      &["        <string>", crate_name, "</string>"].join(""),
        "        <key>CFBundleIdentifier</key>",
        "        <string>com.rust.unittests</string>",
        "        <key>UIRequiredDeviceCapabilities</key>",
        "        <array>",
        "            <string>x86_64</string>",
        "        </array>",
        "    </dict>",
        "</plist>"].join("\n").into_bytes()).unwrap();
}

// Step two: Start the iOS simulator
fn start_simulator() {
    println!("Looking for iOS simulator");
    let output = Command::new("xcrun").arg("simctl").arg("list").output().unwrap();
    let mut simulator_exists = false;
    let mut simulator_booted = false;
    let mut found_rust_sim = false;
    let stdout = String::from_utf8(output.stdout).unwrap();
    for line in stdout.lines() {
        if line.contains("rust_ios") {
            if found_rust_sim {
                panic!("Duplicate rust_ios simulators found. Please double-check xcrun simctl list.");
            }
            simulator_exists = true;
            simulator_booted = line.contains("(Booted)");
            found_rust_sim = true;
        }
    }

    if simulator_exists == false {
        println!("Creating iOS simulator");
        Command::new("xcrun").arg("simctl").arg("create").arg("rust_ios")
            .arg("com.apple.CoreSimulator.SimDeviceType.iPhone-SE").arg("com.apple.CoreSimulator.SimRuntime.iOS-10-2").check_status();
    } else if simulator_booted == true {
        println!("Shutting down already-booted simulator");
        Command::new("xcrun").arg("simctl").arg("shutdown").arg("rust_ios").check_status();
    }

    println!("Starting iOS simulator");
    // We can't uninstall the app (if present) as that will hang if the simulator isn't completely booted;just erase the simulator instead.
    Command::new("xcrun").arg("simctl").arg("erase").arg("rust_ios").check_status();
    Command::new("xcrun").arg("simctl").arg("boot").arg("rust_ios").check_status();
}

// Step three: Install the app
fn install_app_to_simulator() {
    println!("Installing app to simulator");
    Command::new("xcrun").arg("simctl").arg("install").arg("booted").arg("ios_simulator_app/").check_status();
}

// Step four: Run the app
fn run_app_on_simulator() {
    println!("Running app");
    let output = Command::new("xcrun").arg("simctl").arg("launch").arg("--console").arg("booted").arg("com.rust.unittests").output().unwrap();
    let mut test_run_passed = false;
    let stdout = String::from_utf8(output.stdout).unwrap();
    for line in stdout.lines() {
        println!("{}", line);

        if test_run_passed == false {
            // Based on all.rs test output
            test_run_passed = line.contains("PASSED") && line.contains("tests");
        }
    }

    println!("Shutting down simulator");
    Command::new("xcrun").arg("simctl").arg("shutdown").arg("rust_ios").check_status();
    assert!(test_run_passed);
}

trait CheckStatus {
    fn check_status(&mut self);
}

impl CheckStatus for Command {
    fn check_status(&mut self) {
        assert!(self.status().unwrap().success());
    }
}

pub fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() != 2 {
        println!("Usage: {:?} executable", Path::new(&args[0]).file_name().unwrap());
        process::exit(-1);
    }

    let test_binary_path = Path::new(&args[1]);
    let crate_name = test_binary_path.file_name().unwrap();

    package_as_simulator_app(crate_name.to_str().unwrap(), test_binary_path);
    start_simulator();
    install_app_to_simulator();
    run_app_on_simulator();
}<commit_msg>Removed non-mandatory UIRequiredDeviceCapabilities<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// This is a script to deploy and execute a binary on an iOS simulator.
// The primary use of this is to be able to run unit tests on the simulator and retrieve the results.
//
// To do this through Cargo instead, use Dinghy (https://github.com/snipsco/dinghy):
// cargo dinghy install, then cargo dinghy test.

use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::process;
use std::process::Command;

// Step one: Wrap as an app
fn package_as_simulator_app(crate_name: &str, test_binary_path: &Path) {
    println!("Packaging simulator app");
    Command::new("rm").arg("-rf").arg("ios_simulator_app").status().unwrap();
    Command::new("mkdir").arg("ios_simulator_app").check_status();
    Command::new("cp").arg(test_binary_path).arg(["ios_simulator_app/", crate_name].join("")).check_status();
    let mut f = File::create("ios_simulator_app/Info.plist").unwrap();
    f.write_all(&[
        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
        "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">",
        "<plist version=\"1.0\">",
        "    <dict>",
        "        <key>CFBundleExecutable</key>",
      &["        <string>", crate_name, "</string>"].join(""),
        "        <key>CFBundleIdentifier</key>",
        "        <string>com.rust.unittests</string>",
        "    </dict>",
        "</plist>"].join("\n").into_bytes()).unwrap();
}

// Step two: Start the iOS simulator
fn start_simulator() {
    println!("Looking for iOS simulator");
    let output = Command::new("xcrun").arg("simctl").arg("list").output().unwrap();
    let mut simulator_exists = false;
    let mut simulator_booted = false;
    let mut found_rust_sim = false;
    let stdout = String::from_utf8(output.stdout).unwrap();
    for line in stdout.lines() {
        if line.contains("rust_ios") {
            if found_rust_sim {
                panic!("Duplicate rust_ios simulators found. Please double-check xcrun simctl list.");
            }
            simulator_exists = true;
            simulator_booted = line.contains("(Booted)");
            found_rust_sim = true;
        }
    }

    if simulator_exists == false {
        println!("Creating iOS simulator");
        Command::new("xcrun").arg("simctl").arg("create").arg("rust_ios")
            .arg("com.apple.CoreSimulator.SimDeviceType.iPhone-SE").arg("com.apple.CoreSimulator.SimRuntime.iOS-10-2").check_status();
    } else if simulator_booted == true {
        println!("Shutting down already-booted simulator");
        Command::new("xcrun").arg("simctl").arg("shutdown").arg("rust_ios").check_status();
    }

    println!("Starting iOS simulator");
    // We can't uninstall the app (if present) as that will hang if the simulator isn't completely booted;just erase the simulator instead.
    Command::new("xcrun").arg("simctl").arg("erase").arg("rust_ios").check_status();
    Command::new("xcrun").arg("simctl").arg("boot").arg("rust_ios").check_status();
}

// Step three: Install the app
fn install_app_to_simulator() {
    println!("Installing app to simulator");
    Command::new("xcrun").arg("simctl").arg("install").arg("booted").arg("ios_simulator_app/").check_status();
}

// Step four: Run the app
fn run_app_on_simulator() {
    println!("Running app");
    let output = Command::new("xcrun").arg("simctl").arg("launch").arg("--console").arg("booted").arg("com.rust.unittests").output().unwrap();
    let mut test_run_passed = false;
    let stdout = String::from_utf8(output.stdout).unwrap();
    for line in stdout.lines() {
        println!("{}", line);

        if test_run_passed == false {
            // Based on all.rs test output
            test_run_passed = line.contains("PASSED") && line.contains("tests");
        }
    }

    println!("Shutting down simulator");
    Command::new("xcrun").arg("simctl").arg("shutdown").arg("rust_ios").check_status();
    assert!(test_run_passed);
}

trait CheckStatus {
    fn check_status(&mut self);
}

impl CheckStatus for Command {
    fn check_status(&mut self) {
        assert!(self.status().unwrap().success());
    }
}

pub fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() != 2 {
        println!("Usage: {:?} executable", Path::new(&args[0]).file_name().unwrap());
        process::exit(-1);
    }

    let test_binary_path = Path::new(&args[1]);
    let crate_name = test_binary_path.file_name().unwrap();

    package_as_simulator_app(crate_name.to_str().unwrap(), test_binary_path);
    start_simulator();
    install_app_to_simulator();
    run_app_on_simulator();
}<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::process::Command;
use std::env;

fn main() {
    let target = env::var("TARGET").expect("Environnement variable TARGET not set");
    // let out_dir = env::var("OUT_DIR").expect("Failed to get output directory");
    let current_dir = env::current_dir().expect("Failed to get current directory");

    // println!("target:      {:?}", target);
    // println!("out_dir:     {:?}", out_dir);
    // println!("current_dir: {:?}", current_dir);

    let libqmlbind_dir = current_dir.join("libqmlbind");
    let libqmlbind_build_dir = libqmlbind_dir.join("build");

    let qt_dir = env::var("QT_DIR").map(|p| PathBuf::from(p)).unwrap_or({
        println!("Environnement variable 'QT_DIR' not set!");
        println!("Defaulting to ${{HOME}}/Qt/${{QT_VER}}/${{QT_COMP}} where:");
        let home_dir = env::home_dir().map(|p| PathBuf::from(p)).unwrap();
        let default_qt_ver = "5.7".to_string();
        let default_qt_comp = if target.contains("linux") {
            "gcc_64".to_string()
        } else if target.contains("darwin") {
            "clang_64".to_string()
        } else {
            panic!("Unsuported platform in gallery's build.rs!")
        };
        println!("    QT_VER:  {}", default_qt_ver);
        println!("    QT_COMP: {}", default_qt_comp);
        let qt_dir_default = home_dir.join("Qt")
                                  .join(env::var("QT_VER").unwrap_or(default_qt_ver))
                                  .join(env::var("QT_COMP").unwrap_or(default_qt_comp));
        qt_dir_default
    });
    println!("Using Qt directory: {:?}", qt_dir);
    println!("Use QT_DIR environment variable to overwrite.");

    let qt_lib_dir = qt_dir.join("lib");
    let qt_bin_dir = qt_dir.join("bin");

    // Initialize git submodule
    if !libqmlbind_dir.join(".git").exists() {
        let _ = Command::new("git").args(&["submodule", "update", "--init"])
                                   .status()
                                   .unwrap_or_else(|e| panic!("Failed to initialize git submodule: {}", e));
    }

    std::fs::create_dir_all(&libqmlbind_build_dir).unwrap_or_else(|e| panic!("Failed to create libqmlbind build directory: {}", e));

    let output = Command::new(qt_bin_dir.join("qmake")).arg("../qmlbind")
                                      .current_dir(&libqmlbind_build_dir)
                                      .output()
                                      .unwrap_or_else(|e| panic!("Failed execute qmake: {}", e));
    println!("output.status: {}", output.status);
    println!("output.stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("output.stderr: {}", String::from_utf8_lossy(&output.stderr));
    assert!(output.status.success(), "failed to execute qmake process");

    let output = Command::new("make")
                                .current_dir(&libqmlbind_build_dir)
                                .output()
                                .unwrap_or_else(|e| panic!("Failed execute make : {}", e));
    println!("output.status: {}", output.status);
    println!("output.stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("output.stderr: {}", String::from_utf8_lossy(&output.stderr));
    assert!(output.status.success(), "failed to execute make process");

    let output = Command::new("make").arg("staticlib")
                                     .current_dir(&libqmlbind_build_dir)
                                     .output()
                                     .unwrap_or_else(|e| panic!("Failed execute 'make staticlib': {}", e));
    println!("output.status: {}", output.status);
    println!("output.stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("output.stderr: {}", String::from_utf8_lossy(&output.stderr));
    assert!(output.status.success(), "failed to execute 'make staticlib' process");

    println!("cargo:rustc-link-search={}", libqmlbind_build_dir.to_str().unwrap());
    println!("cargo:rustc-link-lib=static=qmlbind");

    let osx_framework = if target.contains("darwin") { "=framework" }
                        else  { "" };
    // On Linux, libraries are name "Qt5Core", not "QtCore" as on OSX
    let linux_qt_lib_ver = if target.contains("linux") { "5" }
                           else  { "" };

    println!("cargo:rustc-link-search{}={}", osx_framework, qt_lib_dir.to_str().unwrap());

    println!("cargo:rustc-link-lib{}=Qt{}Core", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Network", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Gui", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Qml", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Widgets", osx_framework, linux_qt_lib_ver);

    // On Linux, Qt needs icui18n, icuuc and icudata
    if target.contains("linux") {
        println!("cargo:rustc-link-lib=icui18n");
        println!("cargo:rustc-link-lib=icuuc");
        println!("cargo:rustc-link-lib=icudata");
    }

    println!("cargo:rustc-flags=-l stdc++");
}
<commit_msg>libqmlbind-sys: Output variables in build script<commit_after>use std::path::PathBuf;
use std::process::Command;
use std::env;

fn main() {
    let target = env::var("TARGET").expect("Environnement variable TARGET not set");
    // let out_dir = env::var("OUT_DIR").expect("Failed to get output directory");
    let current_dir = env::current_dir().expect("Failed to get current directory");

    // println!("target:      {:?}", target);
    // println!("out_dir:     {:?}", out_dir);
    // println!("current_dir: {:?}", current_dir);

    let libqmlbind_dir = current_dir.join("libqmlbind");
    let libqmlbind_build_dir = libqmlbind_dir.join("build");

    let qt_dir = env::var("QT_DIR").map(|p| PathBuf::from(p)).unwrap_or({
        println!("Environnement variable 'QT_DIR' not set!");
        println!("Defaulting to ${{HOME}}/Qt/${{QT_VER}}/${{QT_COMP}} where:");
        let home_dir = env::home_dir().map(|p| PathBuf::from(p)).unwrap();
        let default_qt_ver = "5.7".to_string();
        let default_qt_comp = if target.contains("linux") {
            "gcc_64".to_string()
        } else if target.contains("darwin") {
            "clang_64".to_string()
        } else {
            panic!("Unsuported platform in gallery's build.rs!")
        };
        println!("    QT_VER:  {}", default_qt_ver);
        println!("    QT_COMP: {}", default_qt_comp);
        let qt_dir_default = home_dir.join("Qt")
                                  .join(env::var("QT_VER").unwrap_or(default_qt_ver))
                                  .join(env::var("QT_COMP").unwrap_or(default_qt_comp));
        qt_dir_default
    });
    println!("Using Qt directory: {:?}", qt_dir);
    println!("Use QT_DIR environment variable to overwrite.");

    let qt_lib_dir = qt_dir.join("lib");
    let qt_bin_dir = qt_dir.join("bin");

    // Initialize git submodule
    if !libqmlbind_dir.join(".git").exists() {
        let _ = Command::new("git").args(&["submodule", "update", "--init"])
                                   .status()
                                   .unwrap_or_else(|e| panic!("Failed to initialize git submodule: {}", e));
    }

    std::fs::create_dir_all(&libqmlbind_build_dir).unwrap_or_else(|e| panic!("Failed to create libqmlbind build directory: {}", e));

    println!("current_dir: {:?}", current_dir);
    println!("libqmlbind_dir: {:?}", libqmlbind_dir);
    println!("libqmlbind_build_dir: {:?}", libqmlbind_build_dir);
    println!("qt_lib_dir: {:?}", qt_lib_dir);
    println!("qt_bin_dir: {:?}", qt_bin_dir);

    let output = Command::new(qt_bin_dir.join("qmake")).arg("../qmlbind")
                                      .current_dir(&libqmlbind_build_dir)
                                      .output()
                                      .unwrap_or_else(|e| panic!("Failed execute qmake: {}", e));
    println!("output.status: {}", output.status);
    println!("output.stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("output.stderr: {}", String::from_utf8_lossy(&output.stderr));
    assert!(output.status.success(), "failed to execute qmake process");

    let output = Command::new("make")
                                .current_dir(&libqmlbind_build_dir)
                                .output()
                                .unwrap_or_else(|e| panic!("Failed execute make : {}", e));
    println!("output.status: {}", output.status);
    println!("output.stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("output.stderr: {}", String::from_utf8_lossy(&output.stderr));
    assert!(output.status.success(), "failed to execute make process");

    let output = Command::new("make").arg("staticlib")
                                     .current_dir(&libqmlbind_build_dir)
                                     .output()
                                     .unwrap_or_else(|e| panic!("Failed execute 'make staticlib': {}", e));
    println!("output.status: {}", output.status);
    println!("output.stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("output.stderr: {}", String::from_utf8_lossy(&output.stderr));
    assert!(output.status.success(), "failed to execute 'make staticlib' process");

    println!("cargo:rustc-link-search={}", libqmlbind_build_dir.to_str().unwrap());
    println!("cargo:rustc-link-lib=static=qmlbind");

    let osx_framework = if target.contains("darwin") { "=framework" }
                        else  { "" };
    // On Linux, libraries are name "Qt5Core", not "QtCore" as on OSX
    let linux_qt_lib_ver = if target.contains("linux") { "5" }
                           else  { "" };

    println!("cargo:rustc-link-search{}={}", osx_framework, qt_lib_dir.to_str().unwrap());

    println!("cargo:rustc-link-lib{}=Qt{}Core", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Network", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Gui", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Qml", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Widgets", osx_framework, linux_qt_lib_ver);

    // On Linux, Qt needs icui18n, icuuc and icudata
    if target.contains("linux") {
        println!("cargo:rustc-link-lib=icui18n");
        println!("cargo:rustc-link-lib=icuuc");
        println!("cargo:rustc-link-lib=icudata");
    }

    println!("cargo:rustc-flags=-l stdc++");
}
<|endoftext|>


<commit_before>//! way-cooler registry.

use std::ops::Deref;
use std::collections::hash_map::{HashMap, Entry};
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};

use rustc_serialize::Decodable;
use rustc_serialize::json::{Json, ToJson, Decoder, DecoderError};

mod types;
pub use self::types::*; // Export constants too

#[cfg(test)]
mod tests;

pub type RegMap = HashMap<String, RegistryField>;

lazy_static! {
    /// Registry variable for the registry
    static ref REGISTRY: RwLock<RegMap> = RwLock::new(HashMap::new());
}

/// Error types that can happen
#[derive(Debug, PartialEq)]
pub enum RegistryError {
    /// The registry key was not found
    KeyNotFound,
    /// Attempting to set a readonly value
    InvalidOperation,
}

/// Result type of gets/sets to the registry
pub type RegistryResult<T> = Result<T, RegistryError>;

/// Initialize the registry (register default API)
pub fn init() {
}

/// Acquires a read lock on the registry.
pub fn read_lock<'a>() -> RwLockReadGuard<'a, RegMap> {
    REGISTRY.read().expect("Unable to read from registry!")
}

/// Acquires a write lock on the registry.
pub fn write_lock<'a>() -> RwLockWriteGuard<'a, RegMap> {
    REGISTRY.write().expect("Unable to write to registry!")
}

/// Gets a RegistryField enum with the specified name
pub fn get_field(name: &str) -> Option<RegistryField> {
    // clone() will either clone an Arc or an Arc+AccessFlags
    let result = read_lock().get(name).map(|v| v.clone());
    trace!("get: {} => {:?}", name, &result);
    return result;
}

/// Gets a data type from the registry, returning a reference to the property
/// method if the field is a property.
pub fn get_data(name: &str) -> RegistryResult<RegistryGetData> {
    get_field(name).ok_or(RegistryError::KeyNotFound)
        .and_then(|val| match val {
            RegistryField::Object { flags, data } =>
                Ok(RegistryGetData::Object(flags, data)),
            RegistryField::Property { get: maybe_get, set: maybe_set } =>
                match maybe_get {
                    Some(get) => {
                        let mut flags = AccessFlags::READ();
                        if maybe_set.is_some() {
                            flags.insert(AccessFlags::WRITE());
                        }
                        Ok(RegistryGetData::Property(flags, get))
                    }
                    None => Err(RegistryError::InvalidOperation)
                },
        })
}

/// Get a Rust structure from the registry
#[allow(dead_code)]
pub fn get_struct<T>(name: &str)
                     -> RegistryResult<(AccessFlags, Result<T, DecoderError>)>
where T: Decodable {
    get_data(name).map(|data| data.resolve())
        .map(|(flags, json)|
             (flags, T::decode(&mut Decoder::new(json.deref().clone()))))
}

/// Set a value to the given registry field.
pub fn insert_field(key: String, value: RegistryField) -> Option<RegistryField> {
    let mut reg = write_lock();
    reg.insert(key, value)
}

/// Add the json object to the registry
pub fn insert_json(key: String, flags: AccessFlags, value: Json)
                   -> Option<RegistryField> {
    write_lock().insert(key,
                        RegistryField::Object {
                            flags: flags,
                            data: Arc::new(value)
                        })
}

/// Set a value to the given JSON value.
pub fn set_json(key: String, json: Json) -> RegistryResult<RegistrySetData> {
    let mut reg = write_lock();
    match reg.entry(key) {
        Entry::Vacant(_vacancy) => {
            return Err(RegistryError::KeyNotFound)
        },
        Entry::Occupied(mut entry) => {
            let first_type = entry.get().get_type();
            let flags = entry.get().get_flags();
            if first_type == FieldType::Object {
                return Ok(RegistrySetData::Displaced(
                    entry.insert(RegistryField::Object {
                        flags: flags, data: Arc::new(json)
                    }).as_object()
                        .expect("Just created object").1));
            }
            else if first_type == FieldType::Property {
                match entry.get().clone().as_property_set() {
                    Some(func) =>
                        return Ok(RegistrySetData::Property(flags, func)),
                    None => return Err(RegistryError::InvalidOperation)
                }
            }
            else {
                return Err(RegistryError::InvalidOperation);
            }
        }
    }
}

/// Set an object/property in the registry to a value using a ToJson.
#[allow(dead_code)]
pub fn insert_struct<T: ToJson>(key: String, flags: AccessFlags, value: T)
                             -> Option<RegistryField> {
    insert_field(key, RegistryField::Object {
        flags: flags,
        data: Arc::new(value.to_json()) })
}

/// Binds properties to a field of the registry
pub fn insert_property(key: String, get_fn: Option<GetFn>, set_fn: Option<SetFn>)
                          -> Option<RegistryField> {
    insert_field(key, RegistryField::Property { get: get_fn, set: set_fn })
}

/// Gets access flags and field type of the given key.
///
/// Returns `None` if the key does not exist.
#[allow(dead_code)]
pub fn key_info(key: &str) -> Option<(FieldType, AccessFlags)> {
    trace!("key_info: {}", key);
    let read_reg = read_lock();
    read_reg.get(key).map(|field| (field.get_type(), field.get_flags()))
}
<commit_msg>Remove dead_code on used registry methods<commit_after>//! way-cooler registry.

use std::ops::Deref;
use std::collections::hash_map::{HashMap, Entry};
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};

use rustc_serialize::Decodable;
use rustc_serialize::json::{Json, ToJson, Decoder, DecoderError};

mod types;
pub use self::types::*; // Export constants too

#[cfg(test)]
mod tests;

pub type RegMap = HashMap<String, RegistryField>;

lazy_static! {
    /// Registry variable for the registry
    static ref REGISTRY: RwLock<RegMap> = RwLock::new(HashMap::new());
}

/// Error types that can happen
#[derive(Debug, PartialEq)]
pub enum RegistryError {
    /// The registry key was not found
    KeyNotFound,
    /// Attempting to set a readonly value
    InvalidOperation,
}

/// Result type of gets/sets to the registry
pub type RegistryResult<T> = Result<T, RegistryError>;

/// Initialize the registry (register default API)
pub fn init() {
}

/// Acquires a read lock on the registry.
pub fn read_lock<'a>() -> RwLockReadGuard<'a, RegMap> {
    REGISTRY.read().expect("Unable to read from registry!")
}

/// Acquires a write lock on the registry.
pub fn write_lock<'a>() -> RwLockWriteGuard<'a, RegMap> {
    REGISTRY.write().expect("Unable to write to registry!")
}

/// Gets a RegistryField enum with the specified name
pub fn get_field(name: &str) -> Option<RegistryField> {
    // clone() will either clone an Arc or an Arc+AccessFlags
    let result = read_lock().get(name).map(|v| v.clone());
    trace!("get: {} => {:?}", name, &result);
    return result;
}

/// Gets a data type from the registry, returning a reference to the property
/// method if the field is a property.
pub fn get_data(name: &str) -> RegistryResult<RegistryGetData> {
    get_field(name).ok_or(RegistryError::KeyNotFound)
        .and_then(|val| match val {
            RegistryField::Object { flags, data } =>
                Ok(RegistryGetData::Object(flags, data)),
            RegistryField::Property { get: maybe_get, set: maybe_set } =>
                match maybe_get {
                    Some(get) => {
                        let mut flags = AccessFlags::READ();
                        if maybe_set.is_some() {
                            flags.insert(AccessFlags::WRITE());
                        }
                        Ok(RegistryGetData::Property(flags, get))
                    }
                    None => Err(RegistryError::InvalidOperation)
                },
        })
}

/// Get a Rust structure from the registry
#[allow(dead_code)]
pub fn get_struct<T>(name: &str)
                     -> RegistryResult<(AccessFlags, Result<T, DecoderError>)>
where T: Decodable {
    get_data(name).map(|data| data.resolve())
        .map(|(flags, json)|
             (flags, T::decode(&mut Decoder::new(json.deref().clone()))))
}

/// Set a value to the given registry field.
pub fn insert_field(key: String, value: RegistryField) -> Option<RegistryField> {
    let mut reg = write_lock();
    reg.insert(key, value)
}

/// Add the json object to the registry
pub fn insert_json(key: String, flags: AccessFlags, value: Json)
                   -> Option<RegistryField> {
    write_lock().insert(key,
                        RegistryField::Object {
                            flags: flags,
                            data: Arc::new(value)
                        })
}

/// Set a value to the given JSON value.
pub fn set_json(key: String, json: Json) -> RegistryResult<RegistrySetData> {
    let mut reg = write_lock();
    match reg.entry(key) {
        Entry::Vacant(_vacancy) => {
            return Err(RegistryError::KeyNotFound)
        },
        Entry::Occupied(mut entry) => {
            let first_type = entry.get().get_type();
            let flags = entry.get().get_flags();
            if first_type == FieldType::Object {
                return Ok(RegistrySetData::Displaced(
                    entry.insert(RegistryField::Object {
                        flags: flags, data: Arc::new(json)
                    }).as_object()
                        .expect("Just created object").1));
            }
            else if first_type == FieldType::Property {
                match entry.get().clone().as_property_set() {
                    Some(func) =>
                        return Ok(RegistrySetData::Property(flags, func)),
                    None => return Err(RegistryError::InvalidOperation)
                }
            }
            else {
                return Err(RegistryError::InvalidOperation);
            }
        }
    }
}

/// Set an object/property in the registry to a value using a ToJson.
#[allow(dead_code)]
pub fn insert_struct<T: ToJson>(key: String, flags: AccessFlags, value: T)
                             -> Option<RegistryField> {
    insert_field(key, RegistryField::Object {
        flags: flags,
        data: Arc::new(value.to_json()) })
}

/// Binds properties to a field of the registry
pub fn insert_property(key: String, get_fn: Option<GetFn>, set_fn: Option<SetFn>)
                          -> Option<RegistryField> {
    insert_field(key, RegistryField::Property { get: get_fn, set: set_fn })
}

/// Gets access flags and field type of the given key.
///
/// Returns `None` if the key does not exist.
pub fn key_info(key: &str) -> Option<(FieldType, AccessFlags)> {
    trace!("key_info: {}", key);
    let read_reg = read_lock();
    read_reg.get(key).map(|field| (field.get_type(), field.get_flags()))
}
<|endoftext|>


<commit_before>use std::ffi::CString;
use std::mem::size_of;
use std::ptr;

use gl;
use cgmath;

use euclid::{Rect, Size2D, Point2D};

use gl::types::*;

use cgmath::Matrix;

use text::RasterizedGlyph;

static TEXT_SHADER_V: &'static str = include_str!("../../res/text.v.glsl");
static TEXT_SHADER_F: &'static str = include_str!("../../res/text.f.glsl");

pub struct QuadRenderer {
    program: ShaderProgram,
    vao: GLuint,
    vbo: GLuint,
    ebo: GLuint,
}

#[allow(dead_code)]
#[derive(Debug)]
pub struct PackedVertex {
    x: f32,
    y: f32,
    u: f32,
    v: f32,
}

impl QuadRenderer {
    // TODO should probably hand this a transform instead of width/height
    pub fn new(width: u32, height: u32) -> QuadRenderer {
        let program = ShaderProgram::new(width, height);

        let mut vao: GLuint = 0;
        let mut vbo: GLuint = 0;
        let mut ebo: GLuint = 0;

        unsafe {
            gl::GenVertexArrays(1, &mut vao);
            gl::GenBuffers(1, &mut vbo);
            gl::GenBuffers(1, &mut ebo);
            gl::BindVertexArray(vao);

            gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
            gl::BufferData(
                gl::ARRAY_BUFFER,
                (size_of::<PackedVertex>() * 4) as GLsizeiptr,
                ptr::null(),
                gl::DYNAMIC_DRAW
            );

            let indices: [u32; 6] = [0, 1, 3,
                                     1, 2, 3];

            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ebo);
            gl::BufferData(gl::ELEMENT_ARRAY_BUFFER,
                           6 * size_of::<u32>() as isize,
                           indices.as_ptr() as *const _,
                           gl::STATIC_DRAW);

            gl::EnableVertexAttribArray(0);
            gl::EnableVertexAttribArray(1);

            // positions
            gl::VertexAttribPointer(0, 2,
                                    gl::FLOAT, gl::FALSE,
                                    size_of::<PackedVertex>() as i32,
                                    ptr::null());

            // uv mapping
            gl::VertexAttribPointer(1, 2,
                                    gl::FLOAT, gl::FALSE,
                                    size_of::<PackedVertex>() as i32,
                                    (2 * size_of::<f32>()) as *const _);

            gl::BindVertexArray(0);
            gl::BindBuffer(gl::ARRAY_BUFFER, 0);
            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0);
        }

        QuadRenderer {
            program: program,
            vao: vao,
            vbo: vbo,
            ebo: ebo,
        }
    }

    pub fn render(&self, glyph: &Glyph, x: f32, y: f32) {
        self.program.activate();
        unsafe {
            // set color
            gl::Uniform3f(self.program.u_color, 1., 1., 0.5);
        }

        let rect = get_rect(glyph, x, y);

        // Top right, Bottom right, Bottom left, Top left
        let packed = [PackedVertex {
            x: rect.max_x(),
            y: rect.max_y(),
            u: 1.0,
            v: 0.0,
        }, PackedVertex {
            x: rect.max_x(),
            y: rect.min_y(),
            u: 1.0,
            v: 1.0,
        }, PackedVertex {
            x: rect.min_x(),
            y: rect.min_y(),
            u: 0.0,
            v: 1.0,
        }, PackedVertex {
            x: rect.min_x(),
            y: rect.max_y(),
            u: 0.0,
            v: 0.0,
        }];

        unsafe {
            bind_mask_texture(glyph.tex_id);
            gl::BindVertexArray(self.vao);

            gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
            gl::BufferSubData(
                gl::ARRAY_BUFFER,
                0,
                (packed.len() * size_of::<PackedVertex>()) as isize,
                packed.as_ptr() as *const _
            );
            gl::BindBuffer(gl::ARRAY_BUFFER, 0);
            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.ebo);

            gl::DrawElements(gl::TRIANGLES, 6, gl::UNSIGNED_INT, ptr::null());
            gl::BindVertexArray(0);
            gl::BindTexture(gl::TEXTURE_2D, 0);
        }

        self.program.deactivate();
    }
}

fn get_rect(glyph: &Glyph, x: f32, y: f32) -> Rect<f32> {
    Rect::new(
        Point2D::new(x, y),
        Size2D::new(glyph.width as f32, glyph.height as f32)
    )
}

fn bind_mask_texture(id: u32) {
    unsafe {
        gl::ActiveTexture(gl::TEXTURE0);
        gl::BindTexture(gl::TEXTURE_2D, id);
    }
}

pub struct ShaderProgram {
    id: GLuint,
    /// projection matrix uniform
    u_projection: GLint,
    /// color uniform
    u_color: GLint,
}

impl ShaderProgram {
    pub fn activate(&self) {
        unsafe {
            gl::UseProgram(self.id);
        }
    }

    pub fn deactivate(&self) {
        unsafe {
            gl::UseProgram(0);
        }
    }

    pub fn new(width: u32, height: u32) -> ShaderProgram {
        let vertex_shader = ShaderProgram::create_vertex_shader();
        let fragment_shader = ShaderProgram::create_fragment_shader();
        let program = ShaderProgram::create_program(vertex_shader, fragment_shader);

        unsafe {
            gl::DeleteShader(vertex_shader);
            gl::DeleteShader(fragment_shader);
        }

        // get uniform locations
        let projection_str = CString::new("projection").unwrap();
        let color_str = CString::new("textColor").unwrap();

        let (projection, color) = unsafe {
            (
                gl::GetUniformLocation(program, projection_str.as_ptr()),
                gl::GetUniformLocation(program, color_str.as_ptr())
            )
        };

        assert!(projection != gl::INVALID_VALUE as i32);
        assert!(projection != gl::INVALID_OPERATION as i32);
        assert!(color != gl::INVALID_VALUE as i32);
        assert!(color != gl::INVALID_OPERATION as i32);

        let shader = ShaderProgram {
            id: program,
            u_projection: projection,
            u_color: color,
        };

        // set projection uniform
        let ortho = cgmath::ortho(0., width as f32, 0., height as f32, -1., 1.);
        let projection: [[f32; 4]; 4] = ortho.into();

        println!("width: {}, height: {}", width, height);

        shader.activate();
        unsafe {
            gl::UniformMatrix4fv(shader.u_projection,
                                 1, gl::FALSE, projection.as_ptr() as *const _);
        }
        shader.deactivate();

        shader
    }

    fn create_program(vertex: GLuint, fragment: GLuint) -> GLuint {

        unsafe {
            let program = gl::CreateProgram();
            gl::AttachShader(program, vertex);
            gl::AttachShader(program, fragment);
            gl::LinkProgram(program);

            let mut success: GLint = 0;
            gl::GetProgramiv(program, gl::LINK_STATUS, &mut success);

            if success != (gl::TRUE as GLint) {
                panic!("failed to link shader program");
            }
            program
        }
    }

    fn create_fragment_shader() -> GLuint {
        unsafe {
            let fragment_shader = gl::CreateShader(gl::FRAGMENT_SHADER);
            let fragment_source = CString::new(TEXT_SHADER_F).unwrap();
            gl::ShaderSource(fragment_shader, 1, &fragment_source.as_ptr(), ptr::null());
            gl::CompileShader(fragment_shader);

            let mut success: GLint = 0;
            gl::GetShaderiv(fragment_shader, gl::COMPILE_STATUS, &mut success);

            if success != (gl::TRUE as GLint) {
                panic!("failed to compiler fragment shader");
            }
            fragment_shader
        }
    }

    fn create_vertex_shader() -> GLuint {
        unsafe {
            let vertex_shader = gl::CreateShader(gl::VERTEX_SHADER);
            let vertex_source = CString::new(TEXT_SHADER_V).unwrap();
            gl::ShaderSource(vertex_shader, 1, &vertex_source.as_ptr(), ptr::null());
            gl::CompileShader(vertex_shader);

            let mut success: GLint = 0;
            gl::GetShaderiv(vertex_shader, gl::COMPILE_STATUS, &mut success);

            if success != (gl::TRUE as GLint) {
                panic!("failed to compiler vertex shader");
            }
            vertex_shader
        }
    }
}

#[allow(dead_code)]
pub struct Glyph {
    tex_id: GLuint,
    top: i32,
    left: i32,
    width: i32,
    height: i32,
}

impl Glyph {
    pub fn new(rasterized: &RasterizedGlyph) -> Glyph {
        let mut id: GLuint = 0;
        unsafe {
            gl::PixelStorei(gl::UNPACK_ALIGNMENT, 1);
            gl::GenTextures(1, &mut id);
            gl::BindTexture(gl::TEXTURE_2D, id);
            gl::TexImage2D(
                gl::TEXTURE_2D,
                0,
                gl::RED as i32,
                rasterized.width as i32,
                rasterized.height as i32,
                0,
                gl::RED,
                gl::UNSIGNED_BYTE,
                rasterized.buf.as_ptr() as *const _
            );

            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32);
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32);
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32);
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);

            gl::BindTexture(gl::TEXTURE_2D, 0);
        }

        Glyph {
            tex_id: id,
            top: rasterized.top as i32,
            width: rasterized.width as i32,
            height: rasterized.height as i32,
            left: rasterized.left as i32,
        }
    }
}
<commit_msg>Cleanup PackedVertex initialization<commit_after>use std::ffi::CString;
use std::mem::size_of;
use std::ptr;

use gl;
use cgmath;

use euclid::{Rect, Size2D, Point2D};

use gl::types::*;

use cgmath::Matrix;

use text::RasterizedGlyph;

static TEXT_SHADER_V: &'static str = include_str!("../../res/text.v.glsl");
static TEXT_SHADER_F: &'static str = include_str!("../../res/text.f.glsl");

pub struct QuadRenderer {
    program: ShaderProgram,
    vao: GLuint,
    vbo: GLuint,
    ebo: GLuint,
}

#[allow(dead_code)]
#[derive(Debug)]
pub struct PackedVertex {
    x: f32,
    y: f32,
    u: f32,
    v: f32,
}

impl QuadRenderer {
    // TODO should probably hand this a transform instead of width/height
    pub fn new(width: u32, height: u32) -> QuadRenderer {
        let program = ShaderProgram::new(width, height);

        let mut vao: GLuint = 0;
        let mut vbo: GLuint = 0;
        let mut ebo: GLuint = 0;

        unsafe {
            gl::GenVertexArrays(1, &mut vao);
            gl::GenBuffers(1, &mut vbo);
            gl::GenBuffers(1, &mut ebo);
            gl::BindVertexArray(vao);

            gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
            gl::BufferData(
                gl::ARRAY_BUFFER,
                (size_of::<PackedVertex>() * 4) as GLsizeiptr,
                ptr::null(),
                gl::DYNAMIC_DRAW
            );

            let indices: [u32; 6] = [0, 1, 3,
                                     1, 2, 3];

            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ebo);
            gl::BufferData(gl::ELEMENT_ARRAY_BUFFER,
                           6 * size_of::<u32>() as isize,
                           indices.as_ptr() as *const _,
                           gl::STATIC_DRAW);

            gl::EnableVertexAttribArray(0);
            gl::EnableVertexAttribArray(1);

            // positions
            gl::VertexAttribPointer(0, 2,
                                    gl::FLOAT, gl::FALSE,
                                    size_of::<PackedVertex>() as i32,
                                    ptr::null());

            // uv mapping
            gl::VertexAttribPointer(1, 2,
                                    gl::FLOAT, gl::FALSE,
                                    size_of::<PackedVertex>() as i32,
                                    (2 * size_of::<f32>()) as *const _);

            gl::BindVertexArray(0);
            gl::BindBuffer(gl::ARRAY_BUFFER, 0);
            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0);
        }

        QuadRenderer {
            program: program,
            vao: vao,
            vbo: vbo,
            ebo: ebo,
        }
    }

    pub fn render(&self, glyph: &Glyph, x: f32, y: f32) {
        self.program.activate();
        unsafe {
            // set color
            gl::Uniform3f(self.program.u_color, 1., 1., 0.5);
        }

        let rect = get_rect(glyph, x, y);

        // Top right, Bottom right, Bottom left, Top left
        let packed = [
            PackedVertex { x: rect.max_x(), y: rect.max_y(), u: 1.0, v: 0.0, },
            PackedVertex { x: rect.max_x(), y: rect.min_y(), u: 1.0, v: 1.0, },
            PackedVertex { x: rect.min_x(), y: rect.min_y(), u: 0.0, v: 1.0, },
            PackedVertex { x: rect.min_x(), y: rect.max_y(), u: 0.0, v: 0.0, },
        ];

        unsafe {
            bind_mask_texture(glyph.tex_id);
            gl::BindVertexArray(self.vao);

            gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
            gl::BufferSubData(
                gl::ARRAY_BUFFER,
                0,
                (packed.len() * size_of::<PackedVertex>()) as isize,
                packed.as_ptr() as *const _
            );
            gl::BindBuffer(gl::ARRAY_BUFFER, 0);
            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.ebo);

            gl::DrawElements(gl::TRIANGLES, 6, gl::UNSIGNED_INT, ptr::null());
            gl::BindVertexArray(0);
            gl::BindTexture(gl::TEXTURE_2D, 0);
        }

        self.program.deactivate();
    }
}

fn get_rect(glyph: &Glyph, x: f32, y: f32) -> Rect<f32> {
    Rect::new(
        Point2D::new(x, y),
        Size2D::new(glyph.width as f32, glyph.height as f32)
    )
}

fn bind_mask_texture(id: u32) {
    unsafe {
        gl::ActiveTexture(gl::TEXTURE0);
        gl::BindTexture(gl::TEXTURE_2D, id);
    }
}

pub struct ShaderProgram {
    id: GLuint,
    /// projection matrix uniform
    u_projection: GLint,
    /// color uniform
    u_color: GLint,
}

impl ShaderProgram {
    pub fn activate(&self) {
        unsafe {
            gl::UseProgram(self.id);
        }
    }

    pub fn deactivate(&self) {
        unsafe {
            gl::UseProgram(0);
        }
    }

    pub fn new(width: u32, height: u32) -> ShaderProgram {
        let vertex_shader = ShaderProgram::create_vertex_shader();
        let fragment_shader = ShaderProgram::create_fragment_shader();
        let program = ShaderProgram::create_program(vertex_shader, fragment_shader);

        unsafe {
            gl::DeleteShader(vertex_shader);
            gl::DeleteShader(fragment_shader);
        }

        // get uniform locations
        let projection_str = CString::new("projection").unwrap();
        let color_str = CString::new("textColor").unwrap();

        let (projection, color) = unsafe {
            (
                gl::GetUniformLocation(program, projection_str.as_ptr()),
                gl::GetUniformLocation(program, color_str.as_ptr())
            )
        };

        assert!(projection != gl::INVALID_VALUE as i32);
        assert!(projection != gl::INVALID_OPERATION as i32);
        assert!(color != gl::INVALID_VALUE as i32);
        assert!(color != gl::INVALID_OPERATION as i32);

        let shader = ShaderProgram {
            id: program,
            u_projection: projection,
            u_color: color,
        };

        // set projection uniform
        let ortho = cgmath::ortho(0., width as f32, 0., height as f32, -1., 1.);
        let projection: [[f32; 4]; 4] = ortho.into();

        println!("width: {}, height: {}", width, height);

        shader.activate();
        unsafe {
            gl::UniformMatrix4fv(shader.u_projection,
                                 1, gl::FALSE, projection.as_ptr() as *const _);
        }
        shader.deactivate();

        shader
    }

    fn create_program(vertex: GLuint, fragment: GLuint) -> GLuint {

        unsafe {
            let program = gl::CreateProgram();
            gl::AttachShader(program, vertex);
            gl::AttachShader(program, fragment);
            gl::LinkProgram(program);

            let mut success: GLint = 0;
            gl::GetProgramiv(program, gl::LINK_STATUS, &mut success);

            if success != (gl::TRUE as GLint) {
                panic!("failed to link shader program");
            }
            program
        }
    }

    fn create_fragment_shader() -> GLuint {
        unsafe {
            let fragment_shader = gl::CreateShader(gl::FRAGMENT_SHADER);
            let fragment_source = CString::new(TEXT_SHADER_F).unwrap();
            gl::ShaderSource(fragment_shader, 1, &fragment_source.as_ptr(), ptr::null());
            gl::CompileShader(fragment_shader);

            let mut success: GLint = 0;
            gl::GetShaderiv(fragment_shader, gl::COMPILE_STATUS, &mut success);

            if success != (gl::TRUE as GLint) {
                panic!("failed to compiler fragment shader");
            }
            fragment_shader
        }
    }

    fn create_vertex_shader() -> GLuint {
        unsafe {
            let vertex_shader = gl::CreateShader(gl::VERTEX_SHADER);
            let vertex_source = CString::new(TEXT_SHADER_V).unwrap();
            gl::ShaderSource(vertex_shader, 1, &vertex_source.as_ptr(), ptr::null());
            gl::CompileShader(vertex_shader);

            let mut success: GLint = 0;
            gl::GetShaderiv(vertex_shader, gl::COMPILE_STATUS, &mut success);

            if success != (gl::TRUE as GLint) {
                panic!("failed to compiler vertex shader");
            }
            vertex_shader
        }
    }
}

#[allow(dead_code)]
pub struct Glyph {
    tex_id: GLuint,
    top: i32,
    left: i32,
    width: i32,
    height: i32,
}

impl Glyph {
    pub fn new(rasterized: &RasterizedGlyph) -> Glyph {
        let mut id: GLuint = 0;
        unsafe {
            gl::PixelStorei(gl::UNPACK_ALIGNMENT, 1);
            gl::GenTextures(1, &mut id);
            gl::BindTexture(gl::TEXTURE_2D, id);
            gl::TexImage2D(
                gl::TEXTURE_2D,
                0,
                gl::RED as i32,
                rasterized.width as i32,
                rasterized.height as i32,
                0,
                gl::RED,
                gl::UNSIGNED_BYTE,
                rasterized.buf.as_ptr() as *const _
            );

            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32);
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32);
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32);
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);

            gl::BindTexture(gl::TEXTURE_2D, 0);
        }

        Glyph {
            tex_id: id,
            top: rasterized.top as i32,
            width: rasterized.width as i32,
            height: rasterized.height as i32,
            left: rasterized.left as i32,
        }
    }
}
<|endoftext|>