<commit_before>//! An IRC implementation of Hamelin.
#![cfg_attr(feature = "irc", feature(env))]
#[cfg(feature = "irc")] extern crate hamelin;
#[cfg(feature = "irc")] extern crate irc;

#[cfg(feature = "irc")] use std::borrow::ToOwned;
#[cfg(feature = "irc")] use std::collections::HashMap;
#[cfg(feature = "irc")] use std::env::args;
#[cfg(feature = "irc")] use std::sync::{Arc, Mutex};
#[cfg(feature = "irc")] use std::thread::spawn;
#[cfg(feature = "irc")] use hamelin::{Hamelin, HamelinGuard};
#[cfg(feature = "irc")] use irc::client::data::Command;
#[cfg(feature = "irc")] use irc::client::data::Command::PRIVMSG;
#[cfg(feature = "irc")] use irc::client::server::{IrcServer, Server};
#[cfg(feature = "irc")] use irc::client::server::utils::Wrapper;

#[cfg(feature = "irc")]
fn main() {
    let args: Vec<_> = args().skip(1).collect();
    if args.len() < 2 {
        println!("Usage: hamelin config command [args]");
        return;
    }
    let hamelin = Arc::new(Hamelin::new(&args[1], if args.len() > 2 {
        Some(&args[2..])
    } else {
        None
    }));
    let cache: Arc<Mutex<HashMap<String, HamelinGuard>>> = Arc::new(Mutex::new(HashMap::new()));
    loop {
        let irc_server = Arc::new(IrcServer::new(&args[0])
                                  .ok().expect("Failed to connect to IRC server."));
        let server_ref = irc_server.clone();
        let cache_ref = cache.clone();
        spawn(move || {
            let server = Wrapper::new(&*server_ref);
            loop {
                for (resp, guard) in cache_ref.lock().unwrap().iter_mut() {
                    if let Ok(line) = guard.read_line() {
                        server.send_privmsg(&resp, &line).unwrap();
                    }
                }
            }
        });
        let server = Wrapper::new(&*irc_server);
        server.identify().unwrap();
        for message in server.iter() {
            match message {
                Ok(message) => {
                    print!("{}", message.into_string());
                    if let Ok(PRIVMSG(chan, msg)) = Command::from_message(&message) {
                        let mut cache = cache.lock().unwrap();
                        let resp = if chan.starts_with("#") {
                            chan
                        } else {
                            message.get_source_nickname().unwrap_or(chan)
                        }.to_owned();
                        if !cache.contains_key(&resp) {
                            let client_str = format!("{}://{}:{}/{}", if server.config().use_ssl() {
                                "ircs" } else { "irc" }, server.config().server(),
                                server.config().port(), resp);
                            let env = vec![
                                ("H-TYPE", "HAMELIN.RS-IRC-0.1"),
                                ("H-CLIENT", &client_str)
                            ];
                            cache.insert(resp.clone(), hamelin.spawn_with_env(&env).unwrap());
                        }
                        let _ = cache[resp].write_line(msg);
                    }
                },
                Err(e) => {
                    println!("Reconnecting because {}", e);
                    break
                }
            }
        }
    }
}

#[cfg(not(feature = "irc"))]
fn main() {
    println!("IRC daemon must be compiled with irc.");
}
<commit_msg>Updated IRC daemon with latest irc updates.<commit_after>//! An IRC implementation of Hamelin.
#[cfg(feature = "irc")] extern crate hamelin;
#[cfg(feature = "irc")] extern crate irc;

#[cfg(feature = "irc")] use std::borrow::ToOwned;
#[cfg(feature = "irc")] use std::collections::HashMap;
#[cfg(feature = "irc")] use std::env::args;
#[cfg(feature = "irc")] use std::sync::{Arc, Mutex};
#[cfg(feature = "irc")] use std::thread::spawn;
#[cfg(feature = "irc")] use hamelin::{Hamelin, HamelinGuard};
#[cfg(feature = "irc")] use irc::client::data::Command::PRIVMSG;
#[cfg(feature = "irc")] use irc::client::prelude::*;

#[cfg(feature = "irc")]
fn main() {
    let args: Vec<_> = args().skip(1).collect();
    if args.len() < 2 {
        println!("Usage: hamelin config command [args]");
        return;
    }
    let hamelin = Arc::new(Hamelin::new(&args[1], if args.len() > 2 {
        Some(&args[2..])
    } else {
        None
    }));
    let cache: Arc<Mutex<HashMap<String, HamelinGuard>>> = Arc::new(Mutex::new(HashMap::new()));
    loop {
        let server = Arc::new(IrcServer::new(&args[0])
                                  .ok().expect("Failed to connect to IRC server."));
        let tserver = server.clone();
        let tcache = cache.clone();
        spawn(move || {
            loop {
                for (resp, guard) in tcache.lock().unwrap().iter_mut() {
                    if let Ok(line) = guard.read_line() {
                        tserver.send_privmsg(&resp, &line).unwrap();
                    }
                }
            }
        });
        server.identify().unwrap();
        for message in server.iter() {
            match message {
                Ok(message) => {
                    print!("{}", message.into_string());
                    if let Ok(PRIVMSG(chan, msg)) = Command::from_message(&message) {
                        let mut cache = cache.lock().unwrap();
                        let resp = if chan.starts_with("#") {
                            &chan[..]
                        } else {
                            message.get_source_nickname().unwrap_or(&chan)
                        }.to_owned();
                        if !cache.contains_key(&resp) {
                            let client_str = format!("{}://{}:{}/{}", if server.config().use_ssl() {
                                "ircs" } else { "irc" }, server.config().server(),
                                server.config().port(), resp);
                            let env = vec![
                                ("H-TYPE", "HAMELIN.RS-IRC-0.1"),
                                ("H-CLIENT", &client_str)
                            ];
                            cache.insert(resp.clone(), hamelin.spawn_with_env(&env).unwrap());
                        }
                        let _ = cache[resp].write_line(&msg);
                    }
                },
                Err(e) => {
                    println!("Reconnecting because {}", e);
                    break
                }
            }
        }
    }
}

#[cfg(not(feature = "irc"))]
fn main() {
    println!("IRC daemon must be compiled with irc.");
}
<|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/. */

//! Communication with the compositor task.

use compositor;
use euclid::{Point2D, Size2D};
use headless;
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use layers::layers::{BufferRequest, LayerBufferSet};
use layers::platform::surface::{NativeDisplay, NativeSurface};
use msg::compositor_msg::{Epoch, EventResult, FrameTreeId, LayerId, LayerProperties};
use msg::compositor_msg::{PaintListener, ScriptToCompositorMsg};
use msg::constellation_msg::{AnimationState, ConstellationChan, PipelineId};
use msg::constellation_msg::{Image, Key, KeyModifiers, KeyState};
use profile_traits::mem;
use profile_traits::time;
use std::fmt::{Debug, Error, Formatter};
use std::rc::Rc;
use std::sync::mpsc::{Receiver, Sender, channel};
use style_traits::viewport::ViewportConstraints;
use url::Url;
use util::cursor::Cursor;
use windowing::{WindowEvent, WindowMethods};
pub use constellation::SendableFrameTree;
pub use windowing;

/// Sends messages to the compositor. This is a trait supplied by the port because the method used
/// to communicate with the compositor may have to kick OS event loops awake, communicate cross-
/// process, and so forth.
pub trait CompositorProxy : 'static + Send {
    /// Sends a message to the compositor.
    fn send(&self, msg: Msg);
    /// Clones the compositor proxy.
    fn clone_compositor_proxy(&self) -> Box<CompositorProxy + 'static + Send>;
}

/// The port that the compositor receives messages on. As above, this is a trait supplied by the
/// Servo port.
pub trait CompositorReceiver : 'static {
    /// Receives the next message inbound for the compositor. This must not block.
    fn try_recv_compositor_msg(&mut self) -> Option<Msg>;
    /// Synchronously waits for, and returns, the next message inbound for the compositor.
    fn recv_compositor_msg(&mut self) -> Msg;
}

/// A convenience implementation of `CompositorReceiver` for a plain old Rust `Receiver`.
impl CompositorReceiver for Receiver<Msg> {
    fn try_recv_compositor_msg(&mut self) -> Option<Msg> {
        match self.try_recv() {
            Ok(msg) => Some(msg),
            Err(_) => None,
        }
    }
    fn recv_compositor_msg(&mut self) -> Msg {
        self.recv().unwrap()
    }
}

pub fn run_script_listener_thread(compositor_proxy: Box<CompositorProxy + 'static + Send>,
                                  receiver: IpcReceiver<ScriptToCompositorMsg>) {
    while let Ok(msg) = receiver.recv() {
        match msg {
            ScriptToCompositorMsg::ScrollFragmentPoint(pipeline_id, layer_id, point, _smooth) => {
                compositor_proxy.send(Msg::ScrollFragmentPoint(pipeline_id,
                                                               layer_id,
                                                               point,
                                                               _smooth));
            }

            ScriptToCompositorMsg::GetClientWindow(send) => {
                compositor_proxy.send(Msg::GetClientWindow(send));
            }

            ScriptToCompositorMsg::MoveTo(point) => {
                compositor_proxy.send(Msg::MoveTo(point));
            }

            ScriptToCompositorMsg::ResizeTo(size) => {
                compositor_proxy.send(Msg::ResizeTo(size));
            }

            ScriptToCompositorMsg::Exit => {
                let (chan, port) = channel();
                compositor_proxy.send(Msg::Exit(chan));
                port.recv().unwrap();
            }

            ScriptToCompositorMsg::SetTitle(pipeline_id, title) => {
                compositor_proxy.send(Msg::ChangePageTitle(pipeline_id, title))
            }

            ScriptToCompositorMsg::SendKeyEvent(key, key_state, key_modifiers) => {
                compositor_proxy.send(Msg::KeyEvent(key, key_state, key_modifiers))
            }

            ScriptToCompositorMsg::TouchEventProcessed(result) => {
                compositor_proxy.send(Msg::TouchEventProcessed(result))
            }
        }
    }
}

/// Implementation of the abstract `PaintListener` interface.
impl PaintListener for Box<CompositorProxy + 'static + Send> {
    fn native_display(&mut self) -> Option<NativeDisplay> {
        let (chan, port) = channel();
        self.send(Msg::GetNativeDisplay(chan));
        // If the compositor is shutting down when a paint task
        // is being created, the compositor won't respond to
        // this message, resulting in an eventual panic. Instead,
        // just return None in this case, since the paint task
        // will exit shortly and never actually be requested
        // to paint buffers by the compositor.
        port.recv().unwrap_or(None)
    }

    fn assign_painted_buffers(&mut self,
                              pipeline_id: PipelineId,
                              epoch: Epoch,
                              replies: Vec<(LayerId, Box<LayerBufferSet>)>,
                              frame_tree_id: FrameTreeId) {
        self.send(Msg::AssignPaintedBuffers(pipeline_id, epoch, replies, frame_tree_id));
    }

    fn ignore_buffer_requests(&mut self, buffer_requests: Vec<BufferRequest>) {
        let mut native_surfaces = Vec::new();
        for request in buffer_requests.into_iter() {
            if let Some(native_surface) = request.native_surface {
                native_surfaces.push(native_surface);
            }
        }
        if !native_surfaces.is_empty() {
            self.send(Msg::ReturnUnusedNativeSurfaces(native_surfaces));
        }
    }

    fn initialize_layers_for_pipeline(&mut self,
                                      pipeline_id: PipelineId,
                                      properties: Vec<LayerProperties>,
                                      epoch: Epoch) {
        // FIXME(#2004, pcwalton): This assumes that the first layer determines the page size, and
        // that all other layers are immediate children of it. This is sufficient to handle
        // `position: fixed` but will not be sufficient to handle `overflow: scroll` or transforms.
        self.send(Msg::InitializeLayersForPipeline(pipeline_id, epoch, properties));
    }

    fn notify_paint_task_exiting(&mut self, pipeline_id: PipelineId) {
        self.send(Msg::PaintTaskExited(pipeline_id))
    }
}

/// Messages from the painting task and the constellation task to the compositor task.
pub enum Msg {
    /// Requests that the compositor shut down.
    Exit(Sender<()>),

    /// Informs the compositor that the constellation has completed shutdown.
    /// Required because the constellation can have pending calls to make
    /// (e.g. SetFrameTree) at the time that we send it an ExitMsg.
    ShutdownComplete,

    /// Requests the compositor's graphics metadata. Graphics metadata is what the painter needs
    /// to create surfaces that the compositor can see. On Linux this is the X display; on Mac this
    /// is the pixel format.
    ///
    /// The headless compositor returns `None`.
    GetNativeDisplay(Sender<Option<NativeDisplay>>),

    /// Tells the compositor to create or update the layers for a pipeline if necessary
    /// (i.e. if no layer with that ID exists).
    InitializeLayersForPipeline(PipelineId, Epoch, Vec<LayerProperties>),
    /// Scroll a page in a window
    ScrollFragmentPoint(PipelineId, LayerId, Point2D<f32>, bool),
    /// Requests that the compositor assign the painted buffers to the given layers.
    AssignPaintedBuffers(PipelineId, Epoch, Vec<(LayerId, Box<LayerBufferSet>)>, FrameTreeId),
    /// Alerts the compositor that the current page has changed its title.
    ChangePageTitle(PipelineId, Option<String>),
    /// Alerts the compositor that the current page has changed its URL.
    ChangePageUrl(PipelineId, Url),
    /// Alerts the compositor that the given pipeline has changed whether it is running animations.
    ChangeRunningAnimationsState(PipelineId, AnimationState),
    /// Replaces the current frame tree, typically called during main frame navigation.
    SetFrameTree(SendableFrameTree, Sender<()>, ConstellationChan),
    /// The load of a page has begun: (can go back, can go forward).
    LoadStart(bool, bool),
    /// The load of a page has completed: (can go back, can go forward).
    LoadComplete(bool, bool),
    /// Indicates that the scrolling timeout with the given starting timestamp has happened and a
    /// composite should happen. (See the `scrolling` module.)
    ScrollTimeout(u64),
    RecompositeAfterScroll,
    /// Sends an unconsumed key event back to the compositor.
    KeyEvent(Key, KeyState, KeyModifiers),
    /// Script has handled a touch event, and either prevented or allowed default actions.
    TouchEventProcessed(EventResult),
    /// Changes the cursor.
    SetCursor(Cursor),
    /// Composite to a PNG file and return the Image over a passed channel.
    CreatePng(IpcSender<Option<Image>>),
    /// Informs the compositor that the paint task for the given pipeline has exited.
    PaintTaskExited(PipelineId),
    /// Alerts the compositor that the viewport has been constrained in some manner
    ViewportConstrained(PipelineId, ViewportConstraints),
    /// A reply to the compositor asking if the output image is stable.
    IsReadyToSaveImageReply(bool),
    /// A favicon was detected
    NewFavicon(Url),
    /// <head> tag finished parsing
    HeadParsed,
    /// Signal that the paint task ignored the paint requests that carried
    /// these native surfaces, so that they can be re-added to the surface cache.
    ReturnUnusedNativeSurfaces(Vec<NativeSurface>),
    /// Collect memory reports and send them back to the given mem::ReportsChan.
    CollectMemoryReports(mem::ReportsChan),
    /// A status message to be displayed by the browser chrome.
    Status(Option<String>),
    /// Get Window Informations size and position
    GetClientWindow(IpcSender<(Size2D<u32>, Point2D<i32>)>),
    /// Move the window to a point
    MoveTo(Point2D<i32>),
    /// Resize the window to size
    ResizeTo(Size2D<u32>),
    /// A pipeline was shut down.
    PipelineExited(PipelineId),
}

impl Debug for Msg {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        match *self {
            Msg::Exit(..) => write!(f, "Exit"),
            Msg::ShutdownComplete(..) => write!(f, "ShutdownComplete"),
            Msg::GetNativeDisplay(..) => write!(f, "GetNativeDisplay"),
            Msg::InitializeLayersForPipeline(..) => write!(f, "InitializeLayersForPipeline"),
            Msg::ScrollFragmentPoint(..) => write!(f, "ScrollFragmentPoint"),
            Msg::AssignPaintedBuffers(..) => write!(f, "AssignPaintedBuffers"),
            Msg::ChangeRunningAnimationsState(..) => write!(f, "ChangeRunningAnimationsState"),
            Msg::ChangePageTitle(..) => write!(f, "ChangePageTitle"),
            Msg::ChangePageUrl(..) => write!(f, "ChangePageUrl"),
            Msg::SetFrameTree(..) => write!(f, "SetFrameTree"),
            Msg::LoadComplete(..) => write!(f, "LoadComplete"),
            Msg::LoadStart(..) => write!(f, "LoadStart"),
            Msg::ScrollTimeout(..) => write!(f, "ScrollTimeout"),
            Msg::RecompositeAfterScroll => write!(f, "RecompositeAfterScroll"),
            Msg::KeyEvent(..) => write!(f, "KeyEvent"),
            Msg::TouchEventProcessed(..) => write!(f, "TouchEventProcessed"),
            Msg::SetCursor(..) => write!(f, "SetCursor"),
            Msg::CreatePng(..) => write!(f, "CreatePng"),
            Msg::PaintTaskExited(..) => write!(f, "PaintTaskExited"),
            Msg::ViewportConstrained(..) => write!(f, "ViewportConstrained"),
            Msg::IsReadyToSaveImageReply(..) => write!(f, "IsReadyToSaveImageReply"),
            Msg::NewFavicon(..) => write!(f, "NewFavicon"),
            Msg::HeadParsed => write!(f, "HeadParsed"),
            Msg::ReturnUnusedNativeSurfaces(..) => write!(f, "ReturnUnusedNativeSurfaces"),
            Msg::CollectMemoryReports(..) => write!(f, "CollectMemoryReports"),
            Msg::Status(..) => write!(f, "Status"),
            Msg::GetClientWindow(..) => write!(f, "GetClientWindow"),
            Msg::MoveTo(..) => write!(f, "MoveTo"),
            Msg::ResizeTo(..) => write!(f, "ResizeTo"),
            Msg::PipelineExited(..) => write!(f, "PipelineExited"),
        }
    }
}

pub struct CompositorTask;

impl CompositorTask {
    pub fn create<Window>(window: Option<Rc<Window>>,
                          state: InitialCompositorState)
                          -> Box<CompositorEventListener + 'static>
                          where Window: WindowMethods + 'static {
        match window {
            Some(window) => {
                box compositor::IOCompositor::create(window, state)
                    as Box<CompositorEventListener>
            }
            None => {
                box headless::NullCompositor::create(state)
                    as Box<CompositorEventListener>
            }
        }
    }
}

pub trait CompositorEventListener {
    fn handle_events(&mut self, events: Vec<WindowEvent>) -> bool;
    fn repaint_synchronously(&mut self);
    fn pinch_zoom_level(&self) -> f32;
    /// Requests that the compositor send the title for the main frame as soon as possible.
    fn title_for_main_frame(&self);
}

/// Data used to construct a compositor.
pub struct InitialCompositorState {
    /// A channel to the compositor.
    pub sender: Box<CompositorProxy + Send>,
    /// A port on which messages inbound to the compositor can be received.
    pub receiver: Box<CompositorReceiver>,
    /// A channel to the constellation.
    pub constellation_chan: ConstellationChan,
    /// A channel to the time profiler thread.
    pub time_profiler_chan: time::ProfilerChan,
    /// A channel to the memory profiler thread.
    pub mem_profiler_chan: mem::ProfilerChan,
}
<commit_msg>Auto merge of #8388 - ucarion:ucarion-8386, r=frewsxcv<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/. */

//! Communication with the compositor task.

use compositor;
use euclid::{Point2D, Size2D};
use headless;
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use layers::layers::{BufferRequest, LayerBufferSet};
use layers::platform::surface::{NativeDisplay, NativeSurface};
use msg::compositor_msg::{Epoch, EventResult, FrameTreeId, LayerId, LayerProperties};
use msg::compositor_msg::{PaintListener, ScriptToCompositorMsg};
use msg::constellation_msg::{AnimationState, ConstellationChan, PipelineId};
use msg::constellation_msg::{Image, Key, KeyModifiers, KeyState};
use profile_traits::mem;
use profile_traits::time;
use std::fmt::{Debug, Error, Formatter};
use std::rc::Rc;
use std::sync::mpsc::{Receiver, Sender, channel};
use style_traits::viewport::ViewportConstraints;
use url::Url;
use util::cursor::Cursor;
use windowing::{WindowEvent, WindowMethods};
pub use constellation::SendableFrameTree;
pub use windowing;

/// Sends messages to the compositor. This is a trait supplied by the port because the method used
/// to communicate with the compositor may have to kick OS event loops awake, communicate cross-
/// process, and so forth.
pub trait CompositorProxy : 'static + Send {
    /// Sends a message to the compositor.
    fn send(&self, msg: Msg);
    /// Clones the compositor proxy.
    fn clone_compositor_proxy(&self) -> Box<CompositorProxy + 'static + Send>;
}

/// The port that the compositor receives messages on. As above, this is a trait supplied by the
/// Servo port.
pub trait CompositorReceiver : 'static {
    /// Receives the next message inbound for the compositor. This must not block.
    fn try_recv_compositor_msg(&mut self) -> Option<Msg>;
    /// Synchronously waits for, and returns, the next message inbound for the compositor.
    fn recv_compositor_msg(&mut self) -> Msg;
}

/// A convenience implementation of `CompositorReceiver` for a plain old Rust `Receiver`.
impl CompositorReceiver for Receiver<Msg> {
    fn try_recv_compositor_msg(&mut self) -> Option<Msg> {
        self.try_recv().ok()
    }
    fn recv_compositor_msg(&mut self) -> Msg {
        self.recv().unwrap()
    }
}

pub fn run_script_listener_thread(compositor_proxy: Box<CompositorProxy + 'static + Send>,
                                  receiver: IpcReceiver<ScriptToCompositorMsg>) {
    while let Ok(msg) = receiver.recv() {
        match msg {
            ScriptToCompositorMsg::ScrollFragmentPoint(pipeline_id, layer_id, point, _smooth) => {
                compositor_proxy.send(Msg::ScrollFragmentPoint(pipeline_id,
                                                               layer_id,
                                                               point,
                                                               _smooth));
            }

            ScriptToCompositorMsg::GetClientWindow(send) => {
                compositor_proxy.send(Msg::GetClientWindow(send));
            }

            ScriptToCompositorMsg::MoveTo(point) => {
                compositor_proxy.send(Msg::MoveTo(point));
            }

            ScriptToCompositorMsg::ResizeTo(size) => {
                compositor_proxy.send(Msg::ResizeTo(size));
            }

            ScriptToCompositorMsg::Exit => {
                let (chan, port) = channel();
                compositor_proxy.send(Msg::Exit(chan));
                port.recv().unwrap();
            }

            ScriptToCompositorMsg::SetTitle(pipeline_id, title) => {
                compositor_proxy.send(Msg::ChangePageTitle(pipeline_id, title))
            }

            ScriptToCompositorMsg::SendKeyEvent(key, key_state, key_modifiers) => {
                compositor_proxy.send(Msg::KeyEvent(key, key_state, key_modifiers))
            }

            ScriptToCompositorMsg::TouchEventProcessed(result) => {
                compositor_proxy.send(Msg::TouchEventProcessed(result))
            }
        }
    }
}

/// Implementation of the abstract `PaintListener` interface.
impl PaintListener for Box<CompositorProxy + 'static + Send> {
    fn native_display(&mut self) -> Option<NativeDisplay> {
        let (chan, port) = channel();
        self.send(Msg::GetNativeDisplay(chan));
        // If the compositor is shutting down when a paint task
        // is being created, the compositor won't respond to
        // this message, resulting in an eventual panic. Instead,
        // just return None in this case, since the paint task
        // will exit shortly and never actually be requested
        // to paint buffers by the compositor.
        port.recv().unwrap_or(None)
    }

    fn assign_painted_buffers(&mut self,
                              pipeline_id: PipelineId,
                              epoch: Epoch,
                              replies: Vec<(LayerId, Box<LayerBufferSet>)>,
                              frame_tree_id: FrameTreeId) {
        self.send(Msg::AssignPaintedBuffers(pipeline_id, epoch, replies, frame_tree_id));
    }

    fn ignore_buffer_requests(&mut self, buffer_requests: Vec<BufferRequest>) {
        let mut native_surfaces = Vec::new();
        for request in buffer_requests.into_iter() {
            if let Some(native_surface) = request.native_surface {
                native_surfaces.push(native_surface);
            }
        }
        if !native_surfaces.is_empty() {
            self.send(Msg::ReturnUnusedNativeSurfaces(native_surfaces));
        }
    }

    fn initialize_layers_for_pipeline(&mut self,
                                      pipeline_id: PipelineId,
                                      properties: Vec<LayerProperties>,
                                      epoch: Epoch) {
        // FIXME(#2004, pcwalton): This assumes that the first layer determines the page size, and
        // that all other layers are immediate children of it. This is sufficient to handle
        // `position: fixed` but will not be sufficient to handle `overflow: scroll` or transforms.
        self.send(Msg::InitializeLayersForPipeline(pipeline_id, epoch, properties));
    }

    fn notify_paint_task_exiting(&mut self, pipeline_id: PipelineId) {
        self.send(Msg::PaintTaskExited(pipeline_id))
    }
}

/// Messages from the painting task and the constellation task to the compositor task.
pub enum Msg {
    /// Requests that the compositor shut down.
    Exit(Sender<()>),

    /// Informs the compositor that the constellation has completed shutdown.
    /// Required because the constellation can have pending calls to make
    /// (e.g. SetFrameTree) at the time that we send it an ExitMsg.
    ShutdownComplete,

    /// Requests the compositor's graphics metadata. Graphics metadata is what the painter needs
    /// to create surfaces that the compositor can see. On Linux this is the X display; on Mac this
    /// is the pixel format.
    ///
    /// The headless compositor returns `None`.
    GetNativeDisplay(Sender<Option<NativeDisplay>>),

    /// Tells the compositor to create or update the layers for a pipeline if necessary
    /// (i.e. if no layer with that ID exists).
    InitializeLayersForPipeline(PipelineId, Epoch, Vec<LayerProperties>),
    /// Scroll a page in a window
    ScrollFragmentPoint(PipelineId, LayerId, Point2D<f32>, bool),
    /// Requests that the compositor assign the painted buffers to the given layers.
    AssignPaintedBuffers(PipelineId, Epoch, Vec<(LayerId, Box<LayerBufferSet>)>, FrameTreeId),
    /// Alerts the compositor that the current page has changed its title.
    ChangePageTitle(PipelineId, Option<String>),
    /// Alerts the compositor that the current page has changed its URL.
    ChangePageUrl(PipelineId, Url),
    /// Alerts the compositor that the given pipeline has changed whether it is running animations.
    ChangeRunningAnimationsState(PipelineId, AnimationState),
    /// Replaces the current frame tree, typically called during main frame navigation.
    SetFrameTree(SendableFrameTree, Sender<()>, ConstellationChan),
    /// The load of a page has begun: (can go back, can go forward).
    LoadStart(bool, bool),
    /// The load of a page has completed: (can go back, can go forward).
    LoadComplete(bool, bool),
    /// Indicates that the scrolling timeout with the given starting timestamp has happened and a
    /// composite should happen. (See the `scrolling` module.)
    ScrollTimeout(u64),
    RecompositeAfterScroll,
    /// Sends an unconsumed key event back to the compositor.
    KeyEvent(Key, KeyState, KeyModifiers),
    /// Script has handled a touch event, and either prevented or allowed default actions.
    TouchEventProcessed(EventResult),
    /// Changes the cursor.
    SetCursor(Cursor),
    /// Composite to a PNG file and return the Image over a passed channel.
    CreatePng(IpcSender<Option<Image>>),
    /// Informs the compositor that the paint task for the given pipeline has exited.
    PaintTaskExited(PipelineId),
    /// Alerts the compositor that the viewport has been constrained in some manner
    ViewportConstrained(PipelineId, ViewportConstraints),
    /// A reply to the compositor asking if the output image is stable.
    IsReadyToSaveImageReply(bool),
    /// A favicon was detected
    NewFavicon(Url),
    /// <head> tag finished parsing
    HeadParsed,
    /// Signal that the paint task ignored the paint requests that carried
    /// these native surfaces, so that they can be re-added to the surface cache.
    ReturnUnusedNativeSurfaces(Vec<NativeSurface>),
    /// Collect memory reports and send them back to the given mem::ReportsChan.
    CollectMemoryReports(mem::ReportsChan),
    /// A status message to be displayed by the browser chrome.
    Status(Option<String>),
    /// Get Window Informations size and position
    GetClientWindow(IpcSender<(Size2D<u32>, Point2D<i32>)>),
    /// Move the window to a point
    MoveTo(Point2D<i32>),
    /// Resize the window to size
    ResizeTo(Size2D<u32>),
    /// A pipeline was shut down.
    PipelineExited(PipelineId),
}

impl Debug for Msg {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        match *self {
            Msg::Exit(..) => write!(f, "Exit"),
            Msg::ShutdownComplete(..) => write!(f, "ShutdownComplete"),
            Msg::GetNativeDisplay(..) => write!(f, "GetNativeDisplay"),
            Msg::InitializeLayersForPipeline(..) => write!(f, "InitializeLayersForPipeline"),
            Msg::ScrollFragmentPoint(..) => write!(f, "ScrollFragmentPoint"),
            Msg::AssignPaintedBuffers(..) => write!(f, "AssignPaintedBuffers"),
            Msg::ChangeRunningAnimationsState(..) => write!(f, "ChangeRunningAnimationsState"),
            Msg::ChangePageTitle(..) => write!(f, "ChangePageTitle"),
            Msg::ChangePageUrl(..) => write!(f, "ChangePageUrl"),
            Msg::SetFrameTree(..) => write!(f, "SetFrameTree"),
            Msg::LoadComplete(..) => write!(f, "LoadComplete"),
            Msg::LoadStart(..) => write!(f, "LoadStart"),
            Msg::ScrollTimeout(..) => write!(f, "ScrollTimeout"),
            Msg::RecompositeAfterScroll => write!(f, "RecompositeAfterScroll"),
            Msg::KeyEvent(..) => write!(f, "KeyEvent"),
            Msg::TouchEventProcessed(..) => write!(f, "TouchEventProcessed"),
            Msg::SetCursor(..) => write!(f, "SetCursor"),
            Msg::CreatePng(..) => write!(f, "CreatePng"),
            Msg::PaintTaskExited(..) => write!(f, "PaintTaskExited"),
            Msg::ViewportConstrained(..) => write!(f, "ViewportConstrained"),
            Msg::IsReadyToSaveImageReply(..) => write!(f, "IsReadyToSaveImageReply"),
            Msg::NewFavicon(..) => write!(f, "NewFavicon"),
            Msg::HeadParsed => write!(f, "HeadParsed"),
            Msg::ReturnUnusedNativeSurfaces(..) => write!(f, "ReturnUnusedNativeSurfaces"),
            Msg::CollectMemoryReports(..) => write!(f, "CollectMemoryReports"),
            Msg::Status(..) => write!(f, "Status"),
            Msg::GetClientWindow(..) => write!(f, "GetClientWindow"),
            Msg::MoveTo(..) => write!(f, "MoveTo"),
            Msg::ResizeTo(..) => write!(f, "ResizeTo"),
            Msg::PipelineExited(..) => write!(f, "PipelineExited"),
        }
    }
}

pub struct CompositorTask;

impl CompositorTask {
    pub fn create<Window>(window: Option<Rc<Window>>,
                          state: InitialCompositorState)
                          -> Box<CompositorEventListener + 'static>
                          where Window: WindowMethods + 'static {
        match window {
            Some(window) => {
                box compositor::IOCompositor::create(window, state)
                    as Box<CompositorEventListener>
            }
            None => {
                box headless::NullCompositor::create(state)
                    as Box<CompositorEventListener>
            }
        }
    }
}

pub trait CompositorEventListener {
    fn handle_events(&mut self, events: Vec<WindowEvent>) -> bool;
    fn repaint_synchronously(&mut self);
    fn pinch_zoom_level(&self) -> f32;
    /// Requests that the compositor send the title for the main frame as soon as possible.
    fn title_for_main_frame(&self);
}

/// Data used to construct a compositor.
pub struct InitialCompositorState {
    /// A channel to the compositor.
    pub sender: Box<CompositorProxy + Send>,
    /// A port on which messages inbound to the compositor can be received.
    pub receiver: Box<CompositorReceiver>,
    /// A channel to the constellation.
    pub constellation_chan: ConstellationChan,
    /// A channel to the time profiler thread.
    pub time_profiler_chan: time::ProfilerChan,
    /// A channel to the memory profiler thread.
    pub mem_profiler_chan: mem::ProfilerChan,
}
<|endoftext|>


<commit_before>use error::*;

#[cfg(feature = "unstable")]
use std::fs;
#[cfg(feature = "unstable")]
use std::os::unix::fs::PermissionsExt;
#[cfg(feature = "unstable")]
use std::path::Path;

/// Check that the value set for ```$XDG_RUNTIME_DIR``` is a valid path, has the correct owner and
/// permissions.
///
/// Returns Ok(()) if path is valid, owner is current uid and has permissions 0o700, or propogates any errors
/// that occurred.
///
/// >$XDG_RUNTIME_DIR defines the base directory relative to which user-specific non-essential runtime files and
/// other file objects (such as sockets, named pipes, ...) should be stored. The directory MUST be owned by the
/// user, and he MUST be the only one having read and write access to it. Its Unix access mode MUST be 0700.
/// >
/// >The lifetime of the directory MUST be bound to the user being logged in. It MUST be created when the user
/// first logs in and if the user fully logs out the directory MUST be removed. If the user logs in more than
/// once he should get pointed to the same directory, and it is mandatory that the directory continues to exist
/// from his first login to his last logout on the system, and not removed in between. Files in the directory
/// MUST not survive reboot or a full logout/login cycle.
/// >
/// >The directory MUST be on a local file system and not shared with any other system. The directory MUST by
/// fully-featured by the standards of the operating system. More specifically, on Unix-like operating systems
/// AF_UNIX sockets, symbolic links, hard links, proper permissions, file locking, sparse files, memory mapping,
/// file change notifications, a reliable hard link count must be supported, and no restrictions on the file name
/// character set should be imposed. Files in this directory MAY be subjected to periodic clean-up. To ensure that
/// your files are not removed, they should have their access time timestamp modified at least once every 6 hours
/// of monotonic time or the 'sticky' bit should be set on the file.
#[cfg(feature = "unstable")]
pub fn test_runtime_dir<P: AsRef<Path>>(path: P) -> Result<()> {
    fs::metadata(&path)
        .or_else(|e| Err(Error::from(e)))
        .map(|attr| (attr.permissions().mode()))
        .and_then(inner::check_permissions)
        .and(inner::test_dir_uid_is_current_user(path.as_ref()))
}

#[cfg(feature = "unstable")]
mod inner {
    use super::*;
    use error::*;

    use libc::funcs::posix88::stat_::stat;
    use libc::funcs::posix88::unistd::getuid;
    use libc::types::os::arch::posix01::stat as Stat;
    use std::ffi::CString;
    use std::mem;
    use std::path::Path;

    pub fn test_dir_uid_is_current_user(path: &Path) -> Result<()> {
        let p = try!(cstr(path));
        unsafe {
            let mut s: Stat = mem::zeroed();
            stat(p.as_ptr(), &mut s);

            let uid = getuid();

            match uid == s.st_uid {
                true => Ok(()),
                false => Result::from(XdgError::IncorrectOwner)
            }
        }
    }

    pub fn check_permissions(permissions: u32) -> Result<()> {
        match permissions == 0o700 {
            true => Ok(()),
            false => Result::from(XdgError::IncorrectPermissions)
        }
    }

    fn cstr(path: &Path) -> Result<CString> {
        path.as_os_str().to_cstring()
            .ok_or(Error::from(XdgError::InvalidPath))
    }
}

<commit_msg>clean up unnecessary cfg attrs in unstable module<commit_after>use error::*;

use libc::funcs::posix88::stat_::stat;
use libc::funcs::posix88::unistd::getuid;
use libc::types::os::arch::posix01::stat as Stat;

use std::ffi::CString;
use std::fs;
use std::mem;
use std::os::unix::fs::PermissionsExt;
use std::path::Path;

/// Check that the value set for ```$XDG_RUNTIME_DIR``` is a valid path, has the correct owner and
/// permissions.
///
/// Returns Ok(()) if path is valid, owner is current uid and has permissions 0o700, or propogates any errors
/// that occurred.
///
/// >$XDG_RUNTIME_DIR defines the base directory relative to which user-specific non-essential runtime files and
/// other file objects (such as sockets, named pipes, ...) should be stored. The directory MUST be owned by the
/// user, and he MUST be the only one having read and write access to it. Its Unix access mode MUST be 0700.
/// >
/// >The lifetime of the directory MUST be bound to the user being logged in. It MUST be created when the user
/// first logs in and if the user fully logs out the directory MUST be removed. If the user logs in more than
/// once he should get pointed to the same directory, and it is mandatory that the directory continues to exist
/// from his first login to his last logout on the system, and not removed in between. Files in the directory
/// MUST not survive reboot or a full logout/login cycle.
/// >
/// >The directory MUST be on a local file system and not shared with any other system. The directory MUST by
/// fully-featured by the standards of the operating system. More specifically, on Unix-like operating systems
/// AF_UNIX sockets, symbolic links, hard links, proper permissions, file locking, sparse files, memory mapping,
/// file change notifications, a reliable hard link count must be supported, and no restrictions on the file name
/// character set should be imposed. Files in this directory MAY be subjected to periodic clean-up. To ensure that
/// your files are not removed, they should have their access time timestamp modified at least once every 6 hours
/// of monotonic time or the 'sticky' bit should be set on the file.
pub fn test_runtime_dir<P: AsRef<Path>>(path: P) -> Result<()> {
    fs::metadata(&path)
        .or_else(|e| Err(Error::from(e)))
        .map(|attr| (attr.permissions().mode()))
        .and_then(check_permissions)
        .and(test_dir_uid_is_current_user(path.as_ref()))
}

fn test_dir_uid_is_current_user(path: &Path) -> Result<()> {
    let p = try!(cstr(path));
    unsafe {
        let mut s: Stat = mem::zeroed();
        stat(p.as_ptr(), &mut s);

        let uid = getuid();

        match uid == s.st_uid {
            true => Ok(()),
            false => Result::from(XdgError::IncorrectOwner)
        }
    }
}

fn check_permissions(permissions: u32) -> Result<()> {
    match permissions == 0o700 {
        true => Ok(()),
        false => Result::from(XdgError::IncorrectPermissions)
    }
}

fn cstr(path: &Path) -> Result<CString> {
    path.as_os_str().to_cstring()
        .ok_or(Error::from(XdgError::InvalidPath))
}
<|endoftext|>


<commit_before>//! Numeric Rust provides a foundation for doing scientific computing with Rust. It aims to be for
//! Rust what Numpy is for Python.
//!
//! OpenBLAS/LAPACK is used to make things like matrix muliplications and solving linear equations
//! fast.
extern crate blas;
extern crate lapack;
extern crate num;
extern crate rand;
extern crate hdf5_sys;
extern crate libc;

pub mod traits;
pub mod tensor;
pub mod math;
pub mod random;
pub mod linalg;
pub mod io;

/// Many of the things in tensor is lifted into numeric since they are so common.
pub use tensor::{Tensor, AxisIndex, Ellipsis, StridedSlice, Index, Full, NewAxis};
pub use tensor::{SingleTensor, DoubleTensor};

/// Many of the functions in math are lifted into numeric since they are so common.
pub use math::{log, ln, log10, log2, sin, cos, tan, asin, acos, atan, exp_m1, exp, exp2,
               ln_1p, sinh, cosh, tanh, asinh, acosh, atanh, atan2, sqrt,
               floor, ceil, round, trunc, fract, abs, signum, powf, powi,
               is_nan, is_finite, is_infinite, is_normal,
               is_sign_positive, is_sign_negative};

pub use random::RandomState;
<commit_msg>Re-export more functions into global namespace<commit_after>//! Numeric Rust provides a foundation for doing scientific computing with Rust. It aims to be for
//! Rust what Numpy is for Python.
//!
//! OpenBLAS/LAPACK is used to make things like matrix muliplications and solving linear equations
//! fast.
extern crate blas;
extern crate lapack;
extern crate num;
extern crate rand;
extern crate hdf5_sys;
extern crate libc;

pub mod traits;
pub mod tensor;
pub mod math;
pub mod random;
pub mod linalg;
pub mod io;

// Lift commonly used functions into the numeric namespace
pub use tensor::{Tensor, AxisIndex, Ellipsis, StridedSlice, Index, Full, NewAxis};
pub use tensor::{SingleTensor, DoubleTensor};

pub use math::{log, ln, log10, log2, sin, cos, tan, asin, acos, atan, exp_m1, exp, exp2,
               ln_1p, sinh, cosh, tanh, asinh, acosh, atanh, atan2, sqrt,
               floor, ceil, round, trunc, fract, abs, signum, powf, powi,
               is_nan, is_finite, is_infinite, is_normal,
               is_sign_positive, is_sign_negative};

pub use random::RandomState;

pub use linalg::diag;
<|endoftext|>


<commit_before>/*!
example of using mel to build up a filter matrix that can then
be used to
repeatedly and very efficiently ([blas](https://en.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms))
used to
transform a power spectrum vector to a mel filtered vector of lower dimension:

```
extern crate mel;

extern crate ndarray;
use ndarray::ArrayBase;
use ndarray::blas::AsBlas;

extern crate rblas;
use rblas::{Gemv, Matrix, Vector};
use rblas::attribute::Transpose;

fn main() {
    let sample_rate = 44100;
    let window_size = 4096;
    let power_spectrum_size = window_size / 2;
    let filter_count = 100;

    // build up the mel filter matrix
    let mut mel_filter_matrix: ArrayBase<Vec<f64>, (usize, usize)> =
        ArrayBase::zeros((filter_count, power_spectrum_size));
    for (row, col, coefficient) in mel::enumerate_mel_scaling_matrix(
        sample_rate,
        window_size,
        power_spectrum_size,
        filter_count,
    ) {
        mel_filter_matrix[(row, col)] = coefficient;
    }

    let mut power_spectrum_vector: ArrayBase<Vec<f64>, usize> =
        ArrayBase::from_elem(power_spectrum_size, 1.);

    let mut mel_vector: ArrayBase<Vec<f64>, usize> =
        ArrayBase::zeros(filter_count);

    // mel_vector <- mel_filter_matrix * power_spectrum_vector
    Gemv::gemv(
        Transpose::NoTrans,
        &1.,
        &mel_filter_matrix.blas(),
        &power_spectrum_vector.blas(),
        &0.,
        &mut mel_vector.blas());
}
```
*/

extern crate ndarray;
use ndarray::ArrayBase;

#[macro_use]
extern crate nalgebra;
use nalgebra::ApproxEq;

extern crate num;
use num::{Float, FromPrimitive};

extern crate hertz;
extern crate apodize;

extern crate itertools;
use itertools::linspace;

macro_rules! f64_from_usize {
    ($val:expr) => {
        <f64>::from_usize($val)
            .expect("type `f64` can't represent a specific value of type `usize` on this architecture.");
    }
}

macro_rules! usize_from_f64 {
    ($val:expr) => {
        <usize>::from_f64($val)
            .expect("type `usize` can't represent a specific value of type `f64` on this architecture.");
    }
}

#[inline]
pub fn hertz_from_mel(mel: f64) -> f64 {
    700. * ((10.).powf(mel / 2595.) - 1.)
}

#[inline]
pub fn mel_from_hertz(hertz: f64) -> f64 {
    2595. * (1. + hertz / 700.).log10()
}

#[test]
fn test_mel() {
    assert_approx_eq_eps!(
        549.64, mel_from_hertz(440.), 0.01);
    assert_approx_eq_eps!(
        440., hertz_from_mel(549.64), 0.01);

    let mel = 0.;
    assert_approx_eq!(mel, mel_from_hertz(hertz_from_mel(mel)));
    let mel = 100.;
    assert_approx_eq_eps!(
        mel, mel_from_hertz(hertz_from_mel(mel)), 0.0001);
    let mel = 3000.;
    assert_approx_eq_eps!(
        mel, mel_from_hertz(hertz_from_mel(mel)), 0.0001);

    let hertz = 0.;
    assert_approx_eq!(hertz, hertz_from_mel(mel_from_hertz(hertz)));
    let hertz = 1000.;
    assert_approx_eq!(hertz, hertz_from_mel(mel_from_hertz(hertz)));
    let hertz = 44100. / 2.;
    assert_approx_eq!(hertz, hertz_from_mel(mel_from_hertz(hertz)));
}

/// col index changes fastest
pub struct MelScalingMatrixEnumerator<WindowIter> {
    // parameters

    /// equivalent to col count
    input_size: usize,
    /// equivalent to row count
    output_size: usize,

    mel_from_hertz: fn(f64) -> f64,
    hertz_from_mel: fn(f64) -> f64,

    max_hertz: f64,

    window_function: fn(usize) -> WindowIter,

    // state

    row_index: usize,
    col_index: usize,

    start_mels_iter: itertools::Linspace<f64>,
    end_mels_iter: itertools::Linspace<f64>,

    // this gets set anew for every row
    window_start: usize,
    window_size: usize,
    window_iter: WindowIter
}

impl<WindowIter> MelScalingMatrixEnumerator<WindowIter>
    where WindowIter: Iterator<Item=f64>
{
    #[inline]
    pub fn is_done(&self) -> bool {
        self.is_after_last_row() && self.is_after_last_col()
    }

    #[inline]
    pub fn is_after_last_row(&self) -> bool {
        self.output_size <= self.row_index
    }

    #[inline]
    pub fn is_after_last_col(&self) -> bool {
        self.input_size <= self.col_index
    }

    #[inline]
    pub fn index(&self) -> usize {
        self.row_index * self.input_size + self.col_index
    }

    #[inline]
    pub fn remaining(&self) -> usize {
        // TODO is this off by one ?
        self.len() - self.index()
    }
}

impl<WindowIter> Iterator for MelScalingMatrixEnumerator<WindowIter>
    where WindowIter: Iterator<Item=f64>
{
    type Item = (usize, usize, f64);

    #[inline]
    fn next(&mut self) -> Option<(usize, usize, f64)> {
        if self.is_done() {
            return None;
        }

        // start a new row/filter
        if self.is_after_last_col() {
            self.col_index = 0;
            self.row_index += 1;
            if self.is_after_last_row() {
                return None;
            }

            let start_mel = self.start_mels_iter.next()
                .expect("self.start_mels_iter.next()");
            let end_mel = self.end_mels_iter.next()
                .expect("self.end_mels_iter.next()");

            let hertz_from_mel = self.hertz_from_mel;
            let start_hertz = hertz_from_mel(start_mel);
            let end_hertz = hertz_from_mel(end_mel);

            // TODO maybe round or floor or ceil here
            self.window_start = usize_from_f64!((
                start_hertz /
                self.max_hertz *
                f64_from_usize!(self.input_size)).floor());

            let window_end = usize_from_f64!((
                end_hertz /
                self.max_hertz *
                f64_from_usize!(self.input_size)).floor());

            self.window_size = std::cmp::max(
                window_end - self.window_start, 1);

            println!("window_start = {}, window_end = {}, window_size = {}", self.window_start, window_end, self.window_size);

            let window_function = self.window_function;
            self.window_iter = window_function(self.window_size);
        }

        let col = self.col_index;

        let value = if col < self.window_start {
            0.
        } else {
            match self.window_iter.next() {
                Some(value) => {
                    value / f64_from_usize!(self.window_size)
                },
                None => 0.
            }
        };

        self.col_index += 1;
        Some((self.row_index, col, value))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let remaining = self.remaining();
        (remaining, Some(remaining))
    }
}

impl<WindowIter> ExactSizeIterator for MelScalingMatrixEnumerator<WindowIter>
    where WindowIter: Iterator<Item=f64>
{
    #[inline]
    fn len(&self) -> usize {
        self.input_size * self.output_size
    }
}

/// (or many vectors at once in form of a matrix)
/// to transform that vector into mel space.
/// efficiently
/// rows are mel
/// cols are freq
/// TODO get frequency index pair for nth mel
/// TODO enumerate scaling vector
/// TODO which dimension first
pub fn enumerate_mel_scaling_matrix_base<WindowIter>(
    // TODO more descriptive argument names
    min_hertz: f64,
    max_hertz: f64,
    // TODO shape
    input_size: usize,
    output_size: usize,
    mel_from_hertz: fn(f64) -> f64,
    hertz_from_mel: fn(f64) -> f64,
    window_function: fn(usize) -> WindowIter
) -> MelScalingMatrixEnumerator<WindowIter>
    where WindowIter: Iterator<Item=f64>
{
    assert!(min_hertz < max_hertz);
    assert!(output_size < input_size);
    assert!(0 < output_size);
    assert!(0 < input_size);

    let min_mel = mel_from_hertz(min_hertz);
    let max_mel = mel_from_hertz(max_hertz);

    // initially start_mels_iter == end_mels_iter
    let mut start_mels_iter = linspace(min_mel, max_mel, output_size + 1);
    let mut end_mels_iter = linspace(min_mel, max_mel, output_size + 1);
    end_mels_iter.next();

    let start_mel = start_mels_iter.next().unwrap();
    let end_mel = end_mels_iter.next().unwrap();

    let start_hertz = hertz_from_mel(start_mel);
    let end_hertz = hertz_from_mel(end_mel);

    // TODO maybe round or floor or ceil here
    let start_index = usize_from_f64!((
        start_hertz / max_hertz * f64_from_usize!(input_size)).floor());

    let end_index = usize_from_f64!((
        end_hertz / max_hertz * f64_from_usize!(input_size)).floor());

    let window_size = std::cmp::max(end_index - start_index, 1);

    println!("window_start = {}, window_end = {}, window_size = {}", start_index, end_index, window_size);

    let window_iter = window_function(window_size);

    MelScalingMatrixEnumerator::<WindowIter> {
        // parameters
        input_size: input_size,
        output_size: output_size,
        window_function: window_function,
        hertz_from_mel: hertz_from_mel,
        mel_from_hertz: mel_from_hertz,
        max_hertz: max_hertz,

        // state
        row_index: 0,
        col_index: 0,

        start_mels_iter: start_mels_iter,
        end_mels_iter: end_mels_iter,

        window_start: start_index,
        window_size: window_size,
        window_iter: window_iter,
    }
}

/// one filter per row
pub fn enumerate_mel_scaling_matrix(
    sample_rate: usize,
    window_size: usize,
    input_size: usize,
    output_size: usize,
) -> MelScalingMatrixEnumerator<apodize::TriangularWindowIter>
{
    enumerate_mel_scaling_matrix_base(
        hertz::rayleigh(
            f64_from_usize!(sample_rate),
            f64_from_usize!(window_size)),
        hertz::nyquist(f64_from_usize!(sample_rate)),
        input_size,
        output_size,
        mel_from_hertz,
        hertz_from_mel,
        apodize::triangular_iter
    )
}

#[test]
fn test_enumerate_mel_scaling_matrix() {
    let sample_rate = 44100;
    let window_size = 100;
    let power_spectrum_size = window_size / 2;
    let filter_count = 10;

    let mut data: ArrayBase<Vec<f64>, (usize, usize)> =
        ArrayBase::zeros((filter_count, power_spectrum_size));

    for (row, col, coefficient) in enumerate_mel_scaling_matrix(
        sample_rate,
        window_size,
        power_spectrum_size,
        filter_count,
    ) {
        data[(row, col)] = coefficient;
    }
    println!("{:?}", data);
}

// TODO test that identity matrix with
// output_size = input_size
// and conversion functions = identity

// TODO test in a small scale that scaling matrixes are correct
// then test it in emir directly and check correctness visually
<commit_msg>make mel warped correspond to center of triangular windows<commit_after>/*!
example of using mel to build up a filter matrix that can then
be used to
repeatedly and very efficiently ([blas](https://en.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms))
used to
transform a power spectrum vector to a mel filtered vector of lower dimension:

```
extern crate mel;

extern crate ndarray;
use ndarray::ArrayBase;
use ndarray::blas::AsBlas;

extern crate rblas;
use rblas::{Gemv, Matrix, Vector};
use rblas::attribute::Transpose;

fn main() {
    let sample_rate = 44100;
    let window_size = 4096;
    let power_spectrum_size = window_size / 2;
    let filter_count = 100;

    // build up the mel filter matrix
    let mut mel_filter_matrix: ArrayBase<Vec<f64>, (usize, usize)> =
        ArrayBase::zeros((filter_count, power_spectrum_size));
    for (row, col, coefficient) in mel::enumerate_mel_scaling_matrix(
        sample_rate,
        window_size,
        power_spectrum_size,
        filter_count,
    ) {
        mel_filter_matrix[(row, col)] = coefficient;
    }

    let mut power_spectrum_vector: ArrayBase<Vec<f64>, usize> =
        ArrayBase::from_elem(power_spectrum_size, 1.);

    let mut mel_vector: ArrayBase<Vec<f64>, usize> =
        ArrayBase::zeros(filter_count);

    // mel_vector <- mel_filter_matrix * power_spectrum_vector
    Gemv::gemv(
        Transpose::NoTrans,
        &1.,
        &mel_filter_matrix.blas(),
        &power_spectrum_vector.blas(),
        &0.,
        &mut mel_vector.blas());
}
```
*/

extern crate ndarray;
use ndarray::ArrayBase;

#[macro_use]
extern crate nalgebra;
use nalgebra::ApproxEq;

extern crate num;
use num::{Float, FromPrimitive};

extern crate hertz;
extern crate apodize;

extern crate itertools;
use itertools::linspace;

macro_rules! f64_from_usize {
    ($val:expr) => {
        <f64>::from_usize($val)
            .expect("type `f64` can't represent a specific value of type `usize` on this architecture.");
    }
}

macro_rules! usize_from_f64 {
    ($val:expr) => {
        <usize>::from_f64($val)
            .expect("type `usize` can't represent a specific value of type `f64` on this architecture.");
    }
}

#[inline]
pub fn hertz_from_mel(mel: f64) -> f64 {
    700. * ((10.).powf(mel / 2595.) - 1.)
}

#[inline]
pub fn mel_from_hertz(hertz: f64) -> f64 {
    2595. * (1. + hertz / 700.).log10()
}

#[test]
fn test_mel() {
    assert_approx_eq_eps!(
        549.64, mel_from_hertz(440.), 0.01);
    assert_approx_eq_eps!(
        440., hertz_from_mel(549.64), 0.01);

    let mel = 0.;
    assert_approx_eq!(mel, mel_from_hertz(hertz_from_mel(mel)));
    let mel = 100.;
    assert_approx_eq_eps!(
        mel, mel_from_hertz(hertz_from_mel(mel)), 0.0001);
    let mel = 3000.;
    assert_approx_eq_eps!(
        mel, mel_from_hertz(hertz_from_mel(mel)), 0.0001);

    let hertz = 0.;
    assert_approx_eq!(hertz, hertz_from_mel(mel_from_hertz(hertz)));
    let hertz = 1000.;
    assert_approx_eq!(hertz, hertz_from_mel(mel_from_hertz(hertz)));
    let hertz = 44100. / 2.;
    assert_approx_eq!(hertz, hertz_from_mel(mel_from_hertz(hertz)));
}

/// col index changes fastest
pub struct MelScalingMatrixEnumerator<WindowIter> {
    // parameters

    /// equivalent to col count
    input_size: usize,
    /// equivalent to row count
    output_size: usize,

    mel_from_hertz: fn(f64) -> f64,
    hertz_from_mel: fn(f64) -> f64,

    max_hertz: f64,

    window_function: fn(usize) -> WindowIter,

    // state

    row_index: usize,
    col_index: usize,

    start_mels_iter: itertools::Linspace<f64>,
    end_mels_iter: itertools::Linspace<f64>,

    // this gets set anew for every row
    window_start: usize,
    window_size: usize,
    window_iter: WindowIter
}

impl<WindowIter> MelScalingMatrixEnumerator<WindowIter>
    where WindowIter: Iterator<Item=f64>
{
    #[inline]
    pub fn is_done(&self) -> bool {
        self.is_after_last_row() && self.is_after_last_col()
    }

    #[inline]
    pub fn is_after_last_row(&self) -> bool {
        self.output_size <= self.row_index
    }

    #[inline]
    pub fn is_after_last_col(&self) -> bool {
        self.input_size <= self.col_index
    }

    #[inline]
    pub fn index(&self) -> usize {
        self.row_index * self.input_size + self.col_index
    }

    #[inline]
    pub fn remaining(&self) -> usize {
        // TODO is this off by one ?
        self.len() - self.index()
    }
}

impl<WindowIter> Iterator for MelScalingMatrixEnumerator<WindowIter>
    where WindowIter: Iterator<Item=f64>
{
    type Item = (usize, usize, f64);

    #[inline]
    fn next(&mut self) -> Option<(usize, usize, f64)> {
        if self.is_done() {
            return None;
        }

        // start a new row/filter
        if self.is_after_last_col() {
            self.col_index = 0;
            self.row_index += 1;
            if self.is_after_last_row() {
                return None;
            }

            let start_mel = self.start_mels_iter.next()
                .expect("self.start_mels_iter.next()");
            let end_mel = self.end_mels_iter.next()
                .expect("self.end_mels_iter.next()");

            let hertz_from_mel = self.hertz_from_mel;
            let start_hertz = hertz_from_mel(start_mel);
            let end_hertz = hertz_from_mel(end_mel);

            // TODO maybe round or floor or ceil here
            self.window_start = usize_from_f64!((
                start_hertz /
                self.max_hertz *
                f64_from_usize!(self.input_size)).floor());

            let window_end = usize_from_f64!((
                end_hertz /
                self.max_hertz *
                f64_from_usize!(self.input_size)).floor());

            self.window_size = std::cmp::max(
                window_end - self.window_start, 1);

            println!("window_start = {}, window_end = {}, window_size = {}", self.window_start, window_end, self.window_size);

            let window_function = self.window_function;
            self.window_iter = window_function(self.window_size);
        }

        let col = self.col_index;

        let value = if col < self.window_start {
            0.
        } else {
            match self.window_iter.next() {
                Some(value) => {
                    value / f64_from_usize!(self.window_size)
                },
                None => 0.
            }
        };

        self.col_index += 1;
        Some((self.row_index, col, value))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let remaining = self.remaining();
        (remaining, Some(remaining))
    }
}

impl<WindowIter> ExactSizeIterator for MelScalingMatrixEnumerator<WindowIter>
    where WindowIter: Iterator<Item=f64>
{
    #[inline]
    fn len(&self) -> usize {
        self.input_size * self.output_size
    }
}

/// (or many vectors at once in form of a matrix)
/// to transform that vector into mel space.
/// efficiently
/// rows are mel
/// cols are freq
/// TODO get frequency index pair for nth mel
/// TODO enumerate scaling vector
/// TODO which dimension first
pub fn enumerate_mel_scaling_matrix_base<WindowIter>(
    // TODO more descriptive argument names
    min_hertz: f64,
    max_hertz: f64,
    // TODO shape
    input_size: usize,
    output_size: usize,
    mel_from_hertz: fn(f64) -> f64,
    hertz_from_mel: fn(f64) -> f64,
    window_function: fn(usize) -> WindowIter
) -> MelScalingMatrixEnumerator<WindowIter>
    where WindowIter: Iterator<Item=f64>
{
    assert!(min_hertz < max_hertz);
    assert!(output_size < input_size);
    assert!(0 < output_size);
    assert!(0 < input_size);

    let min_mel = mel_from_hertz(min_hertz);
    let max_mel = mel_from_hertz(max_hertz);

    // initially start_mels_iter == end_mels_iter
    let mut start_mels_iter = linspace(min_mel, max_mel, output_size + 2);
    let mut end_mels_iter = linspace(min_mel, max_mel, output_size + 2);
    end_mels_iter.next();
    end_mels_iter.next();

    let start_mel = start_mels_iter.next().unwrap();
    let end_mel = end_mels_iter.next().unwrap();

    let start_hertz = hertz_from_mel(start_mel);
    let end_hertz = hertz_from_mel(end_mel);

    // TODO maybe round or floor or ceil here
    let start_index = usize_from_f64!((
        start_hertz / max_hertz * f64_from_usize!(input_size)).floor());

    let end_index = usize_from_f64!((
        end_hertz / max_hertz * f64_from_usize!(input_size)).floor());

    let window_size = std::cmp::max(end_index - start_index, 1);

    println!("window_start = {}, window_end = {}, window_size = {}", start_index, end_index, window_size);

    let window_iter = window_function(window_size);

    MelScalingMatrixEnumerator::<WindowIter> {
        // parameters
        input_size: input_size,
        output_size: output_size,
        window_function: window_function,
        hertz_from_mel: hertz_from_mel,
        mel_from_hertz: mel_from_hertz,
        max_hertz: max_hertz,

        // state
        row_index: 0,
        col_index: 0,

        start_mels_iter: start_mels_iter,
        end_mels_iter: end_mels_iter,

        window_start: start_index,
        window_size: window_size,
        window_iter: window_iter,
    }
}

/// one filter per row
pub fn enumerate_mel_scaling_matrix(
    sample_rate: usize,
    window_size: usize,
    input_size: usize,
    output_size: usize,
) -> MelScalingMatrixEnumerator<apodize::TriangularWindowIter>
{
    enumerate_mel_scaling_matrix_base(
        hertz::rayleigh(
            f64_from_usize!(sample_rate),
            f64_from_usize!(window_size)),
        hertz::nyquist(f64_from_usize!(sample_rate)),
        input_size,
        output_size,
        mel_from_hertz,
        hertz_from_mel,
        apodize::triangular_iter
    )
}

#[test]
fn test_enumerate_mel_scaling_matrix() {
    let sample_rate = 44100;
    let window_size = 100;
    let power_spectrum_size = window_size / 2;
    let filter_count = 10;

    let mut data: ArrayBase<Vec<f64>, (usize, usize)> =
        ArrayBase::zeros((filter_count, power_spectrum_size));

    for (row, col, coefficient) in enumerate_mel_scaling_matrix(
        sample_rate,
        window_size,
        power_spectrum_size,
        filter_count,
    ) {
        data[(row, col)] = coefficient;
    }
    println!("{:?}", data);
}

// TODO test that identity matrix with
// output_size = input_size
// and conversion functions = identity

// TODO test in a small scale that scaling matrixes are correct
// then test it in emir directly and check correctness visually
<|endoftext|>


<commit_before>extern crate ndarray;
extern crate rand;

#[macro_use]
extern crate slog;
extern crate slog_async;
extern crate slog_term;

extern crate blas;
extern crate openblas_src;

extern crate serde;
#[macro_use]
extern crate serde_derive;

mod consts;
mod macros;
pub mod utils;

pub extern crate spaces as geometry;
pub use self::geometry::{Matrix, Vector};

mod parameter;
pub use self::parameter::Parameter;

pub mod agents;
pub mod domains;
pub mod fa;
pub mod logging;
pub mod policies;

mod experiment;
pub use self::experiment::*;
<commit_msg>fix: import macros from ndarray crate for use in tests<commit_after>#[allow(unused_imports)]
#[macro_use]
extern crate ndarray;
extern crate rand;

#[macro_use]
extern crate slog;
extern crate slog_async;
extern crate slog_term;

extern crate blas;
extern crate openblas_src;

extern crate serde;
#[macro_use]
extern crate serde_derive;

mod consts;
mod macros;
pub mod utils;

pub extern crate spaces as geometry;
pub use self::geometry::{Matrix, Vector};

mod parameter;
pub use self::parameter::Parameter;

pub mod agents;
pub mod domains;
pub mod fa;
pub mod logging;
pub mod policies;

mod experiment;
pub use self::experiment::*;
<|endoftext|>


<commit_before>#![crate_name = "bindgen"]
#![crate_type = "dylib"]

#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

#![warn(missing_docs)]

extern crate clang_sys;
extern crate syntex_syntax as syntax;
extern crate libc;
#[macro_use]
extern crate log;

use std::collections::HashSet;
use std::default::Default;
use std::io::{self, Write};
use std::fs::OpenOptions;
use std::path::Path;

use syntax::ast;
use syntax::codemap::{DUMMY_SP, Span};
use syntax::print::pprust;
use syntax::print::pp::eof;
use syntax::ptr::P;

use types::Global;

use clang_sys::support::Clang;

mod types;
mod clang;
mod gen;
mod parser;

#[derive(Debug, Clone)]
pub struct Builder<'a> {
    options: BindgenOptions,
    logger: Option<&'a Logger>,
}

pub fn builder<'a>() -> Builder<'a> {
    Default::default()
}

impl<'a> Builder<'a> {
    /// Add a C header to parse.
    pub fn header<T: Into<String>>(&mut self, header: T) -> &mut Self {
        self.clang_arg(header)
    }

    pub fn match_pat<T: Into<String>>(&mut self, arg: T) -> &mut Self {
        self.options.match_pat.push(arg.into());
        self
    }

    /// Add a clang CLI argument.
    pub fn clang_arg<T: Into<String>>(&mut self, arg: T) -> &mut Self {
        self.options.clang_args.push(arg.into());
        self
    }

    /// Add a library to link.
    pub fn link<T: Into<String>>(&mut self, library: T, link_type: LinkType) -> &mut Self {
        self.options.links.push((library.into(), link_type));
        self
    }

    /// Force bindgen to exit if a type is not recognized.
    pub fn forbid_unknown_types(&mut self) -> &mut Self {
        self.options.fail_on_unknown_type = true;
        self
    }

    pub fn builtins(&mut self) -> &mut Self {
        self.options.builtins = true;
        self
    }

    /// Control if the generated structs will derive Debug.
    pub fn derive_debug(&mut self, derive_debug: bool) -> &mut Self {
        self.options.derive_debug = derive_debug;
        self
    }

    /// Control if bindgen should convert the C enums to rust enums or rust constants.
    pub fn rust_enums(&mut self, value: bool) -> &mut Self {
        self.options.rust_enums = value;
        self
    }

    /// Set the logger to use.
    pub fn log(&mut self, logger: &'a Logger) -> &mut Self {
        self.logger = Some(logger);
        self
    }

    pub fn override_enum_ty<T: Into<String>>(&mut self, ty: T) -> &mut Self {
        self.options.override_enum_ty = ty.into();
        self
    }

    /// Controls if bindgen should also print the parsed AST (for debug).
    pub fn emit_ast(&mut self, value: bool) -> &mut Self {
        self.options.emit_ast = value;
        self
    }

    /// Sets the prefix to use for c_void and others.
    pub fn ctypes_prefix<T: Into<Vec<String>>>(&mut self, prefix: T) -> &mut Self {
        self.options.ctypes_prefix = prefix.into();
        self
    }

    /// Generate the binding using the options previously set.
    pub fn generate(&self) -> Result<Bindings, ()> {
        Bindings::generate(&self.options, self.logger, None)
    }
}

impl<'a> Default for Builder<'a> {
    fn default() -> Builder<'a> {
        Builder {
            logger: None,
            options: Default::default(),
        }
    }
}

#[derive(Debug, Clone)]
/// Deprecated - use a `Builder` instead
#[doc(hidden)]
pub struct BindgenOptions {
    pub match_pat: Vec<String>,
    pub builtins: bool,
    pub rust_enums: bool,
    pub links: Vec<(String, LinkType)>,
    pub emit_ast: bool,
    pub fail_on_unknown_type: bool,
    pub override_enum_ty: String,
    pub clang_args: Vec<String>,
    pub derive_debug: bool,
    /// The prefix to use for the c types like c_void.
    ///
    /// Default: ["std", "os", "raw"]
    pub ctypes_prefix: Vec<String>,
}

impl Default for BindgenOptions {
    fn default() -> BindgenOptions {
        let clang = Clang::find(None).expect("No clang found, is it installed?");
        let mut args = Vec::new();
        for dir in clang.c_search_paths {
            args.push("-idirafter".to_owned());
            args.push(dir.to_str().unwrap().to_owned());
        }
        BindgenOptions {
            match_pat: Vec::new(),
            builtins: false,
            rust_enums: true,
            links: Vec::new(),
            emit_ast: false,
            fail_on_unknown_type: true,
            override_enum_ty: "".to_owned(),
            clang_args: args,
            derive_debug: true,
            ctypes_prefix: vec!["std".into(), "os".into(), "raw".into()],
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum LinkType {
    Static,
    Dynamic,
    Framework,
}

pub trait Logger: std::fmt::Debug {
    fn error(&self, msg: &str);
    fn warn(&self, msg: &str);
}

#[derive(Clone)]
pub struct Bindings {
    module: ast::Mod,
    attributes: Vec<ast::Attribute>,
}

impl Bindings {
    /// Deprecated - use a `Builder` instead
    #[doc(hidden)]
    pub fn generate(options: &BindgenOptions,
                    logger: Option<&Logger>,
                    span: Option<Span>)
                    -> Result<Bindings, ()> {
        let l = DummyLogger;
        let logger = match logger {
            Some(l) => l,
            None => &l as &Logger,
        };

        let span = match span {
            Some(s) => s,
            None => DUMMY_SP,
        };

        let globals = try!(parse_headers(options, logger));

        let (m, attrs) = gen::gen_mod(options, globals, span);
        let module = ast::Mod {
            inner: span,
            items: m,
        };

        Ok(Bindings {
            module: module,
            attributes: attrs,
        })
    }

    pub fn into_ast(self) -> Vec<P<ast::Item>> {
        self.module.items
    }

    pub fn to_string(&self) -> String {
        let mut mod_str = Vec::new();
        {
            let ref_writer = Box::new(mod_str.by_ref()) as Box<Write>;
            self.write(ref_writer).expect("Could not write bindings to string");
        }
        String::from_utf8(mod_str).unwrap()
    }

    pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
        let file = try!(OpenOptions::new().write(true).truncate(true).create(true).open(path));
        self.write(Box::new(file))
    }

    // https://github.com/Manishearth/rust-clippy/issues/740
    #[cfg_attr(feature = "clippy", allow(needless_lifetimes))]
    pub fn write<'a>(&self, mut writer: Box<Write + 'a>) -> io::Result<()> {
        try!(writer.write("/* automatically generated by rust-bindgen */\n\n".as_bytes()));
        let mut ps = pprust::rust_printer(writer);
        try!(ps.print_mod(&self.module, &self.attributes));
        try!(ps.print_remaining_comments());
        try!(eof(&mut ps.s));
        ps.s.out.flush()
    }
}

#[derive(Debug)]
struct DummyLogger;

impl Logger for DummyLogger {
    fn error(&self, _msg: &str) {}
    fn warn(&self, _msg: &str) {}
}

fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result<Vec<Global>, ()> {
    fn str_to_ikind(s: &str) -> Option<types::IKind> {
        match s {
            "uchar" => Some(types::IUChar),
            "schar" => Some(types::ISChar),
            "ushort" => Some(types::IUShort),
            "sshort" => Some(types::IShort),
            "uint" => Some(types::IUInt),
            "sint" => Some(types::IInt),
            "ulong" => Some(types::IULong),
            "slong" => Some(types::ILong),
            "ulonglong" => Some(types::IULongLong),
            "slonglong" => Some(types::ILongLong),
            _ => None,
        }
    }

    let clang_opts = parser::ClangParserOptions {
        builtin_names: builtin_names(),
        builtins: options.builtins,
        match_pat: options.match_pat.clone(),
        emit_ast: options.emit_ast,
        fail_on_unknown_type: options.fail_on_unknown_type,
        override_enum_ty: str_to_ikind(&options.override_enum_ty[..]),
        clang_args: options.clang_args.clone(),
    };

    parser::parse(clang_opts, logger)
}

fn builtin_names() -> HashSet<String> {
    let mut names = HashSet::new();
    let keys = ["__va_list_tag", "__va_list", "__builtin_va_list"];

    for s in &keys {
        names.insert((*s).to_owned());
    }

    names
}

#[test]
fn builder_state() {
    let logger = DummyLogger;
    let mut build = builder();
    {
        build.header("example.h");
        build.link("m", LinkType::Static);
        build.log(&logger);
    }
    assert!(build.logger.is_some());
    assert!(build.options.clang_args.binary_search(&"example.h".to_owned()).is_ok());
    assert!(build.options.links.binary_search(&("m".to_owned(), LinkType::Static)).is_ok());
}
<commit_msg>Add some doc + lint warning.<commit_after>#![crate_name = "bindgen"]
#![crate_type = "dylib"]

#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

#![warn(missing_docs)]

//! TODO: add some doc

extern crate clang_sys;
extern crate syntex_syntax as syntax;
extern crate libc;
#[macro_use]
extern crate log;

use std::collections::HashSet;
use std::default::Default;
use std::io::{self, Write};
use std::fs::OpenOptions;
use std::path::Path;

use syntax::ast;
use syntax::codemap::{DUMMY_SP, Span};
use syntax::print::pprust;
use syntax::print::pp::eof;
use syntax::ptr::P;

use types::Global;

use clang_sys::support::Clang;

mod types;
mod clang;
mod gen;
mod parser;

/// A builder to generate bindings.
#[derive(Debug, Clone)]
pub struct Builder<'a> {
    options: BindgenOptions,
    logger: Option<&'a Logger>,
}

/// Returns a new builder for Bindgen.
pub fn builder<'a>() -> Builder<'a> {
    Default::default()
}

impl<'a> Builder<'a> {
    /// Add a C header to parse.
    pub fn header<T: Into<String>>(&mut self, header: T) -> &mut Self {
        self.clang_arg(header)
    }

    /// Add a pattern to filter which file to generate a binding for.
    pub fn match_pat<T: Into<String>>(&mut self, arg: T) -> &mut Self {
        self.options.match_pat.push(arg.into());
        self
    }

    /// Add a clang CLI argument.
    pub fn clang_arg<T: Into<String>>(&mut self, arg: T) -> &mut Self {
        self.options.clang_args.push(arg.into());
        self
    }

    /// Add a library to link.
    pub fn link<T: Into<String>>(&mut self, library: T, link_type: LinkType) -> &mut Self {
        self.options.links.push((library.into(), link_type));
        self
    }

    /// Force bindgen to exit if a type is not recognized.
    pub fn forbid_unknown_types(&mut self) -> &mut Self {
        self.options.fail_on_unknown_type = true;
        self
    }

    /// Control if we should use the c builtins like `__va_list`.
    pub fn builtins(&mut self) -> &mut Self {
        self.options.builtins = true;
        self
    }

    /// Control if the generated structs will derive Debug.
    pub fn derive_debug(&mut self, derive_debug: bool) -> &mut Self {
        self.options.derive_debug = derive_debug;
        self
    }

    /// Control if bindgen should convert the C enums to rust enums or rust constants.
    pub fn rust_enums(&mut self, value: bool) -> &mut Self {
        self.options.rust_enums = value;
        self
    }

    /// Set the logger to use.
    pub fn log(&mut self, logger: &'a Logger) -> &mut Self {
        self.logger = Some(logger);
        self
    }

    /// Overrides the type used to represent a C enum.
    pub fn override_enum_ty<T: Into<String>>(&mut self, ty: T) -> &mut Self {
        self.options.override_enum_ty = ty.into();
        self
    }

    /// Controls if bindgen should also print the parsed AST (for debug).
    pub fn emit_ast(&mut self, value: bool) -> &mut Self {
        self.options.emit_ast = value;
        self
    }

    /// Sets the prefix to use for c_void and others.
    pub fn ctypes_prefix<T: Into<Vec<String>>>(&mut self, prefix: T) -> &mut Self {
        self.options.ctypes_prefix = prefix.into();
        self
    }

    /// Generate the binding using the options previously set.
    pub fn generate(&self) -> Result<Bindings, ()> {
        Bindings::generate(&self.options, self.logger, None)
    }
}

impl<'a> Default for Builder<'a> {
    fn default() -> Builder<'a> {
        Builder {
            logger: None,
            options: Default::default(),
        }
    }
}

#[derive(Debug, Clone)]
/// Deprecated - use a `Builder` instead
#[doc(hidden)]
pub struct BindgenOptions {
    pub match_pat: Vec<String>,
    pub builtins: bool,
    pub rust_enums: bool,
    pub links: Vec<(String, LinkType)>,
    pub emit_ast: bool,
    pub fail_on_unknown_type: bool,
    pub override_enum_ty: String,
    pub clang_args: Vec<String>,
    pub derive_debug: bool,
    /// The prefix to use for the c types like c_void.
    ///
    /// Default: ["std", "os", "raw"]
    pub ctypes_prefix: Vec<String>,
}

impl Default for BindgenOptions {
    fn default() -> BindgenOptions {
        let clang = Clang::find(None).expect("No clang found, is it installed?");
        let mut args = Vec::new();
        for dir in clang.c_search_paths {
            args.push("-idirafter".to_owned());
            args.push(dir.to_str().unwrap().to_owned());
        }
        BindgenOptions {
            match_pat: Vec::new(),
            builtins: false,
            rust_enums: true,
            links: Vec::new(),
            emit_ast: false,
            fail_on_unknown_type: true,
            override_enum_ty: "".to_owned(),
            clang_args: args,
            derive_debug: true,
            ctypes_prefix: vec!["std".into(), "os".into(), "raw".into()],
        }
    }
}

/// Type of the link to the library which binding is generating.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum LinkType {
    /// Do a static link to the library.
    Static,
    /// Do a dynamic link to the library.
    Dynamic,
    /// Link to a MacOS Framework.
    Framework,
}

/// Trait used internaly to log things with context like the C file line number.
pub trait Logger: std::fmt::Debug {
    /// Like `error!()`.
    fn error(&self, msg: &str);
    /// Like `warn!()`.
    fn warn(&self, msg: &str);
}

/// Contains the generated code.
#[derive(Clone)]
pub struct Bindings {
    module: ast::Mod,
    attributes: Vec<ast::Attribute>,
}

impl Bindings {
    /// Deprecated - use a `Builder` instead
    #[doc(hidden)]
    pub fn generate(options: &BindgenOptions,
                    logger: Option<&Logger>,
                    span: Option<Span>)
                    -> Result<Bindings, ()> {
        let l = DummyLogger;
        let logger = match logger {
            Some(l) => l,
            None => &l as &Logger,
        };

        let span = match span {
            Some(s) => s,
            None => DUMMY_SP,
        };

        let globals = try!(parse_headers(options, logger));

        let (m, attrs) = gen::gen_mod(options, globals, span);
        let module = ast::Mod {
            inner: span,
            items: m,
        };

        Ok(Bindings {
            module: module,
            attributes: attrs,
        })
    }

    /// Get the generated code AST.
    pub fn into_ast(self) -> Vec<P<ast::Item>> {
        self.module.items
    }

    /// Get the generated code in a String.
    pub fn to_string(&self) -> String {
        let mut mod_str = Vec::new();
        {
            let ref_writer = Box::new(mod_str.by_ref()) as Box<Write>;
            self.write(ref_writer).expect("Could not write bindings to string");
        }
        String::from_utf8(mod_str).unwrap()
    }

    /// Write the generated code in a file.
    pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
        let file = try!(OpenOptions::new().write(true).truncate(true).create(true).open(path));
        self.write(Box::new(file))
    }

    // https://github.com/Manishearth/rust-clippy/issues/740
    #[cfg_attr(feature = "clippy", allow(needless_lifetimes))]
    /// Write the generated code in the provided `Write` object.
    pub fn write<'a>(&self, mut writer: Box<Write + 'a>) -> io::Result<()> {
        try!(writer.write("/* automatically generated by rust-bindgen */\n\n".as_bytes()));
        let mut ps = pprust::rust_printer(writer);
        try!(ps.print_mod(&self.module, &self.attributes));
        try!(ps.print_remaining_comments());
        try!(eof(&mut ps.s));
        ps.s.out.flush()
    }
}

#[derive(Debug)]
struct DummyLogger;

impl Logger for DummyLogger {
    fn error(&self, _msg: &str) {}
    fn warn(&self, _msg: &str) {}
}

fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result<Vec<Global>, ()> {
    fn str_to_ikind(s: &str) -> Option<types::IKind> {
        match s {
            "uchar" => Some(types::IUChar),
            "schar" => Some(types::ISChar),
            "ushort" => Some(types::IUShort),
            "sshort" => Some(types::IShort),
            "uint" => Some(types::IUInt),
            "sint" => Some(types::IInt),
            "ulong" => Some(types::IULong),
            "slong" => Some(types::ILong),
            "ulonglong" => Some(types::IULongLong),
            "slonglong" => Some(types::ILongLong),
            _ => None,
        }
    }

    let clang_opts = parser::ClangParserOptions {
        builtin_names: builtin_names(),
        builtins: options.builtins,
        match_pat: options.match_pat.clone(),
        emit_ast: options.emit_ast,
        fail_on_unknown_type: options.fail_on_unknown_type,
        override_enum_ty: str_to_ikind(&options.override_enum_ty[..]),
        clang_args: options.clang_args.clone(),
    };

    parser::parse(clang_opts, logger)
}

fn builtin_names() -> HashSet<String> {
    let mut names = HashSet::new();
    let keys = ["__va_list_tag", "__va_list", "__builtin_va_list"];

    for s in &keys {
        names.insert((*s).to_owned());
    }

    names
}

#[test]
fn builder_state() {
    let logger = DummyLogger;
    let mut build = builder();
    {
        build.header("example.h");
        build.link("m", LinkType::Static);
        build.log(&logger);
    }
    assert!(build.logger.is_some());
    assert!(build.options.clang_args.binary_search(&"example.h".to_owned()).is_ok());
    assert!(build.options.links.binary_search(&("m".to_owned(), LinkType::Static)).is_ok());
}
<|endoftext|>


<commit_before>#![feature(slice_splits)]
#![cfg_attr(test, feature(test))]
extern crate itertools;
extern crate rand;

use itertools::partition;

#[derive(Debug, Clone)]
pub struct LazySort<T> {
    greater: Vec<T>,
    less: Option<Box<LazySort<T>>>,
}

impl<T: Ord> LazySort<T> {
    fn split_greater(&mut self) -> Option<T> {
        match self.greater.len() {
            0 => None,
            1 => self.greater.pop(),
            _ => {
                let pivot_idx = self.greater.len() - 1;
                let split_idx = {
                    let mid_idx = self.greater.len() / 2;
                    // I've chosen the element in the middle of the vec as the pivot.
                    // However, we first swap the pivot with the last element so that there is
                    // a contiguous space in memory to be partitioned.
                    self.greater.swap(pivot_idx, mid_idx);
                    let (pivot, rest) = self.greater.split_last_mut().unwrap();
                    // partition all but the last element, which is the pivot. This makes the vec
                    // look like [greater, greater, ..., greater, less, less, ..., less, pivot]
                    partition(rest, |el| el > pivot)
                };
                // Swapping the pivot with the first less element allows us to split off
                // vec[split_idx + 1..] to create a new vec with all the elements less than pivot.
                self.greater.swap(pivot_idx, split_idx);
                let split_off_idx = split_idx + 1;
                if split_off_idx < self.greater.len() {
                    let mut less = Box::new(LazySort {
                        greater: self.greater.split_off(split_off_idx),
                        less: None,
                    });
                    // Recursively compute the next element from the LazySort struct containing
                    // the elements less than the pivot.
                    let next = less.next();
                    self.less = Some(less);
                    next
                } else {
                    // If there were no elements less than the pivot, then return the pivot.
                    self.greater.pop()
                }
            }
        }
    }
}

impl<T: Ord> Iterator for LazySort<T> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        let next = if let Some(ref mut less) = self.less {
            less.next()
        } else {
            return self.split_greater();
        };
        if next.is_some() {
            next
        } else {
            self.less = None;
            // The pivot is always the last element in the vec, and it's the first element
            // to be returned once all of the elements less than it have been returned.
            self.greater.pop()
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        match self.less {
            None => (self.greater.len(), Some(self.greater.len())),
            Some(ref less) => {
                let (lower, upper) = less.size_hint();
                (lower + self.greater.len(),
                 upper.map(|upper| upper + self.greater.len()))
            }
        }
    }

}

pub trait LazySortIterator: Iterator
    where Self: Sized
{
    fn lazy_sort(self) -> LazySort<Self::Item> {
        LazySort {
            greater: self.collect(),
            less: None,
        }
    }
}

impl<T> LazySortIterator for T where T: Iterator { }

#[test]
fn test_sort() {
    let mut v = vec![2, 4, 2, 5, 8, 4, 3, 4, 6];
    let v2: Vec<_> = v.iter().cloned().lazy_sort().collect();
    v.sort();
    assert_eq!(v, v2);
}

#[test]
fn test_empty() {
    let v: Vec<u64> = vec![];
    let v2: Vec<_> = v.iter().cloned().lazy_sort().collect();
    assert_eq!(v, v2);
}

#[test]
fn test_size_hint() {
    let v = vec![2, 4, 2, 5, 8, 4, 3, 4, 6];
    let mut sort_iter = v.iter().cloned().lazy_sort();
    for i in 0..v.len() {
        let (lower, upper) = sort_iter.size_hint();
        assert_eq!(v.len() - i, lower);
        assert_eq!(Some(v.len() - i), upper);
        sort_iter.next();
    }
}

#[cfg(test)]
mod bench {
    extern crate test;

    use self::test::Bencher;
    use rand::{thread_rng, Rng};
    use super::LazySortIterator;

    #[bench]
    fn take_1000_lazy(b: &mut Bencher) {
        let mut rng = thread_rng();
        let v: Vec<u32> = rng.gen_iter().take(50_000).collect();
        b.iter(|| v.iter().cloned().lazy_sort().take(1000).collect::<Vec<_>>());
    }

    #[bench]
    fn take_1000_eager(b: &mut Bencher) {
        let mut rng = thread_rng();
        let v: Vec<u32> = rng.gen_iter().take(50_000).collect();
        b.iter(|| {
            let mut v = v.clone();
            v.sort();
            v.iter().cloned().take(1000).collect::<Vec<_>>();
        });
    }

    #[bench]
    fn take_10_000_lazy(b: &mut Bencher) {
        let mut rng = thread_rng();
        let v: Vec<u32> = rng.gen_iter().take(50_000).collect();
        b.iter(|| v.iter().cloned().lazy_sort().take(10_000).collect::<Vec<_>>());
    }

    #[bench]
    fn take_10_000_eager(b: &mut Bencher) {
        let mut rng = thread_rng();
        let v: Vec<u32> = rng.gen_iter().take(50_000).collect();
        b.iter(|| {
            let mut v = v.clone();
            v.sort();
            v.iter().cloned().take(10_000).collect::<Vec<_>>();
        });
    }

    #[bench]
    fn take_50_000_lazy(b: &mut Bencher) {
        let mut rng = thread_rng();
        let v: Vec<u32> = rng.gen_iter().take(50_000).collect();
        b.iter(|| v.iter().cloned().lazy_sort().take(50_000).collect::<Vec<_>>());
    }

    #[bench]
    fn take_50_000_eager(b: &mut Bencher) {
        let mut rng = thread_rng();
        let v: Vec<u32> = rng.gen_iter().take(50_000).collect();
        b.iter(|| {
            let mut v = v.clone();
            v.sort();
            v.iter().cloned().take(50_000).collect::<Vec<_>>();
        });
    }
}
<commit_msg>rustfmt<commit_after>#![feature(slice_splits)]
#![cfg_attr(test, feature(test))]
extern crate itertools;
extern crate rand;

use itertools::partition;

#[derive(Debug, Clone)]
pub struct LazySort<T> {
    greater: Vec<T>,
    less: Option<Box<LazySort<T>>>,
}

impl<T: Ord> LazySort<T> {
    fn split_greater(&mut self) -> Option<T> {
        match self.greater.len() {
            0 => None,
            1 => self.greater.pop(),
            _ => {
                let pivot_idx = self.greater.len() - 1;
                let split_idx = {
                    let mid_idx = self.greater.len() / 2;
                    // I've chosen the element in the middle of the vec as the pivot.
                    // However, we first swap the pivot with the last element so that there is
                    // a contiguous space in memory to be partitioned.
                    self.greater.swap(pivot_idx, mid_idx);
                    let (pivot, rest) = self.greater.split_last_mut().unwrap();
                    // partition all but the last element, which is the pivot. This makes the vec
                    // look like [greater, greater, ..., greater, less, less, ..., less, pivot]
                    partition(rest, |el| el > pivot)
                };
                // Swapping the pivot with the first less element allows us to split off
                // vec[split_idx + 1..] to create a new vec with all the elements less than pivot.
                self.greater.swap(pivot_idx, split_idx);
                let split_off_idx = split_idx + 1;
                if split_off_idx < self.greater.len() {
                    let mut less = Box::new(LazySort {
                        greater: self.greater.split_off(split_off_idx),
                        less: None,
                    });
                    // Recursively compute the next element from the LazySort struct containing
                    // the elements less than the pivot.
                    let next = less.next();
                    self.less = Some(less);
                    next
                } else {
                    // If there were no elements less than the pivot, then return the pivot.
                    self.greater.pop()
                }
            }
        }
    }
}

impl<T: Ord> Iterator for LazySort<T> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        let next = if let Some(ref mut less) = self.less {
            less.next()
        } else {
            return self.split_greater();
        };
        if next.is_some() {
            next
        } else {
            self.less = None;
            // The pivot is always the last element in the vec, and it's the first element
            // to be returned once all of the elements less than it have been returned.
            self.greater.pop()
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        match self.less {
            None => (self.greater.len(), Some(self.greater.len())),
            Some(ref less) => {
                let (lower, upper) = less.size_hint();
                (lower + self.greater.len(),
                 upper.map(|upper| upper + self.greater.len()))
            }
        }
    }
}

pub trait LazySortIterator: Iterator
    where Self: Sized
{
    fn lazy_sort(self) -> LazySort<Self::Item> {
        LazySort {
            greater: self.collect(),
            less: None,
        }
    }
}

impl<T> LazySortIterator for T where T: Iterator { }

#[test]
fn test_sort() {
    let mut v = vec![2, 4, 2, 5, 8, 4, 3, 4, 6];
    let v2: Vec<_> = v.iter().cloned().lazy_sort().collect();
    v.sort();
    assert_eq!(v, v2);
}

#[test]
fn test_empty() {
    let v: Vec<u64> = vec![];
    let v2: Vec<_> = v.iter().cloned().lazy_sort().collect();
    assert_eq!(v, v2);
}

#[test]
fn test_size_hint() {
    let v = vec![2, 4, 2, 5, 8, 4, 3, 4, 6];
    let mut sort_iter = v.iter().cloned().lazy_sort();
    for i in 0..v.len() {
        let (lower, upper) = sort_iter.size_hint();
        assert_eq!(v.len() - i, lower);
        assert_eq!(Some(v.len() - i), upper);
        sort_iter.next();
    }
}

#[cfg(test)]
mod bench {
    extern crate test;

    use self::test::Bencher;
    use rand::{thread_rng, Rng};
    use super::LazySortIterator;

    #[bench]
    fn take_1000_lazy(b: &mut Bencher) {
        let mut rng = thread_rng();
        let v: Vec<u32> = rng.gen_iter().take(50_000).collect();
        b.iter(|| v.iter().cloned().lazy_sort().take(1000).collect::<Vec<_>>());
    }

    #[bench]
    fn take_1000_eager(b: &mut Bencher) {
        let mut rng = thread_rng();
        let v: Vec<u32> = rng.gen_iter().take(50_000).collect();
        b.iter(|| {
            let mut v = v.clone();
            v.sort();
            v.iter().cloned().take(1000).collect::<Vec<_>>();
        });
    }

    #[bench]
    fn take_10_000_lazy(b: &mut Bencher) {
        let mut rng = thread_rng();
        let v: Vec<u32> = rng.gen_iter().take(50_000).collect();
        b.iter(|| v.iter().cloned().lazy_sort().take(10_000).collect::<Vec<_>>());
    }

    #[bench]
    fn take_10_000_eager(b: &mut Bencher) {
        let mut rng = thread_rng();
        let v: Vec<u32> = rng.gen_iter().take(50_000).collect();
        b.iter(|| {
            let mut v = v.clone();
            v.sort();
            v.iter().cloned().take(10_000).collect::<Vec<_>>();
        });
    }

    #[bench]
    fn take_50_000_lazy(b: &mut Bencher) {
        let mut rng = thread_rng();
        let v: Vec<u32> = rng.gen_iter().take(50_000).collect();
        b.iter(|| v.iter().cloned().lazy_sort().take(50_000).collect::<Vec<_>>());
    }

    #[bench]
    fn take_50_000_eager(b: &mut Bencher) {
        let mut rng = thread_rng();
        let v: Vec<u32> = rng.gen_iter().take(50_000).collect();
        b.iter(|| {
            let mut v = v.clone();
            v.sort();
            v.iter().cloned().take(50_000).collect::<Vec<_>>();
        });
    }
}
<|endoftext|>