<commit_before>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! The display subsystem including window management, font rasterization, and
//! GPU drawing.
use std::sync::mpsc;

use parking_lot::{MutexGuard};

use Rgb;
use cli;
use config::Config;
use font::{self, Rasterize};
use meter::Meter;
use renderer::{self, GlyphCache, QuadRenderer};
use selection::Selection;
use term::{Term, SizeInfo};

use window::{self, Size, Pixels, Window, SetInnerSize};

#[derive(Debug)]
pub enum Error {
    /// Error with window management
    Window(window::Error),

    /// Error dealing with fonts
    Font(font::Error),

    /// Error in renderer
    Render(renderer::Error),
}

impl ::std::error::Error for Error {
    fn cause(&self) -> Option<&::std::error::Error> {
        match *self {
            Error::Window(ref err) => Some(err),
            Error::Font(ref err) => Some(err),
            Error::Render(ref err) => Some(err),
        }
    }

    fn description(&self) -> &str {
        match *self {
            Error::Window(ref err) => err.description(),
            Error::Font(ref err) => err.description(),
            Error::Render(ref err) => err.description(),
        }
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            Error::Window(ref err) => err.fmt(f),
            Error::Font(ref err) => err.fmt(f),
            Error::Render(ref err) => err.fmt(f),
        }
    }
}

impl From<window::Error> for Error {
    fn from(val: window::Error) -> Error {
        Error::Window(val)
    }
}

impl From<font::Error> for Error {
    fn from(val: font::Error) -> Error {
        Error::Font(val)
    }
}

impl From<renderer::Error> for Error {
    fn from(val: renderer::Error) -> Error {
        Error::Render(val)
    }
}

/// The display wraps a window, font rasterizer, and GPU renderer
pub struct Display {
    window: Window,
    renderer: QuadRenderer,
    glyph_cache: GlyphCache,
    render_timer: bool,
    rx: mpsc::Receiver<(u32, u32)>,
    tx: mpsc::Sender<(u32, u32)>,
    meter: Meter,
    font_size_modifier: i8,
    size_info: SizeInfo,
    last_background_color: Rgb,
}

/// Can wakeup the render loop from other threads
pub struct Notifier(window::Proxy);

/// Types that are interested in when the display is resized
pub trait OnResize {
    fn on_resize(&mut self, size: &SizeInfo);
}

impl Notifier {
    pub fn notify(&self) {
        self.0.wakeup_event_loop();
    }
}

impl Display {
    pub fn notifier(&self) -> Notifier {
        Notifier(self.window.create_window_proxy())
    }

    pub fn update_config(&mut self, config: &Config) {
        self.render_timer = config.render_timer();
    }

    /// Get size info about the display
    pub fn size(&self) -> &SizeInfo {
        &self.size_info
    }

    pub fn new(
        config: &Config,
        options: &cli::Options,
    ) -> Result<Display, Error> {
        // Extract some properties from config
        let render_timer = config.render_timer();

        // Create the window where Alacritty will be displayed
        let mut window = Window::new(&options.title)?;

        // get window properties for initializing the other subsytems
        let mut viewport_size = window.inner_size_pixels()
            .expect("glutin returns window size");
        let dpr = window.hidpi_factor();

        info!("device_pixel_ratio: {}", dpr);

        // Create renderer
        let mut renderer = QuadRenderer::new(&config, viewport_size)?;

        let (glyph_cache, cell_width, cell_height) =
            Self::new_glyph_cache(&window, &mut renderer, config, 0)?;

        let dimensions = options.dimensions()
            .unwrap_or_else(|| config.dimensions());

        // Resize window to specified dimensions unless one or both dimensions are 0
        if dimensions.columns_u32() > 0 && dimensions.lines_u32() > 0 {
            let width = cell_width as u32 * dimensions.columns_u32();
            let height = cell_height as u32 * dimensions.lines_u32();

            let new_viewport_size = Size {
                width: Pixels(width + 2 * config.padding().x as u32),
                height: Pixels(height + 2 * config.padding().y as u32),
            };

            window.set_inner_size(&new_viewport_size);
            renderer.resize(new_viewport_size.width.0 as _, new_viewport_size.height.0 as _);
            viewport_size = new_viewport_size
        }

        info!("Cell Size: ({} x {})", cell_width, cell_height);

        let size_info = SizeInfo {
            width: viewport_size.width.0 as f32,
            height: viewport_size.height.0 as f32,
            cell_width: cell_width as f32,
            cell_height: cell_height as f32,
            padding_x: config.padding().x.floor(),
            padding_y: config.padding().y.floor(),
        };

        // Channel for resize events
        //
        // macOS has a callback for getting resize events, the channel is used
        // to queue resize events until the next draw call. Unfortunately, it
        // seems that the event loop is blocked until the window is done
        // resizing. If any drawing were to happen during a resize, it would
        // need to be in the callback.
        let (tx, rx) = mpsc::channel();

        // Clear screen
        let background_color = config.colors().primary.background;
        renderer.with_api(config, &size_info, 0. /* visual bell intensity */, |api| {
            api.clear(background_color);
        });

        Ok(Display {
            window: window,
            renderer: renderer,
            glyph_cache: glyph_cache,
            render_timer: render_timer,
            tx: tx,
            rx: rx,
            meter: Meter::new(),
            font_size_modifier: 0,
            size_info: size_info,
            last_background_color: background_color,
        })
    }

    fn new_glyph_cache(window : &Window, renderer : &mut QuadRenderer,
                       config: &Config, font_size_delta: i8)
        -> Result<(GlyphCache, f32, f32), Error>
    {
        let font = config.font().clone().with_size_delta(font_size_delta as f32);
        let dpr = window.hidpi_factor();
        let rasterizer = font::Rasterizer::new(dpr, config.use_thin_strokes())?;

        // Initialize glyph cache
        let glyph_cache = {
            info!("Initializing glyph cache");
            let init_start = ::std::time::Instant::now();

            let cache = renderer.with_loader(|mut api| {
                GlyphCache::new(rasterizer, &font, &mut api)
            })?;

            let stop = init_start.elapsed();
            let stop_f = stop.as_secs() as f64 + stop.subsec_nanos() as f64 / 1_000_000_000f64;
            info!("Finished initializing glyph cache in {}", stop_f);

            cache
        };

        // Need font metrics to resize the window properly. This suggests to me the
        // font metrics should be computed before creating the window in the first
        // place so that a resize is not needed.
        let metrics = glyph_cache.font_metrics();
        let cell_width = (metrics.average_advance + font.offset().x as f64) as u32;
        let cell_height = (metrics.line_height + font.offset().y as f64) as u32;

        return Ok((glyph_cache, cell_width as f32, cell_height as f32));
    }

    pub fn update_glyph_cache(&mut self, config: &Config, font_size_delta: i8) {
        let cache = &mut self.glyph_cache;
        self.renderer.with_loader(|mut api| {
            let _ = cache.update_font_size(config.font(), font_size_delta, &mut api);
        });

        let metrics = cache.font_metrics();
        self.size_info.cell_width = ((metrics.average_advance + config.font().offset().x as f64) as f32).floor();
        self.size_info.cell_height = ((metrics.line_height + config.font().offset().y as f64) as f32).floor();
    }

    #[inline]
    pub fn resize_channel(&self) -> mpsc::Sender<(u32, u32)> {
        self.tx.clone()
    }

    pub fn window(&mut self) -> &mut Window {
        &mut self.window
    }

    /// Process pending resize events
    pub fn handle_resize(
        &mut self,
        terminal: &mut MutexGuard<Term>,
        config: &Config,
        items: &mut [&mut OnResize]
    ) {
        // Resize events new_size and are handled outside the poll_events
        // iterator. This has the effect of coalescing multiple resize
        // events into one.
        let mut new_size = None;

        // Take most recent resize event, if any
        while let Ok(sz) = self.rx.try_recv() {
            new_size = Some(sz);
        }

        if terminal.font_size_modifier != self.font_size_modifier {
            // Font size modification detected

            self.font_size_modifier = terminal.font_size_modifier;
            self.update_glyph_cache(config, terminal.font_size_modifier);

            if new_size == None {
                // Force a resize to refresh things
                new_size = Some((self.size_info.width as u32,
                                 self.size_info.height as u32));
            }
        }

        // Receive any resize events; only call gl::Viewport on last
        // available
        if let Some((w, h)) = new_size.take() {
            self.size_info.width = w as f32;
            self.size_info.height = h as f32;

            let size = &self.size_info;
            terminal.resize(size);

            for item in items {
                item.on_resize(size)
            }

            self.window.resize(w, h);
            self.renderer.resize(w as i32, h as i32);
        }

    }

    /// Draw the screen
    ///
    /// A reference to Term whose state is being drawn must be provided.
    ///
    /// This call may block if vsync is enabled
    pub fn draw(&mut self, mut terminal: MutexGuard<Term>, config: &Config, selection: Option<&Selection>) {
        // Clear dirty flag
        terminal.dirty = !terminal.visual_bell.completed();

        if let Some(title) = terminal.get_next_title() {
            self.window.set_title(&title);
        }

        if let Some(is_urgent) = terminal.next_is_urgent.take() {
            // We don't need to set the urgent flag if we already have the
            // user's attention.
            if !is_urgent || !self.window.is_focused {
                self.window.set_urgent(is_urgent);
            }
        }

        let size_info = *terminal.size_info();
        let visual_bell_intensity = terminal.visual_bell.intensity();

        let background_color = terminal.background_color();
        let background_color_changed = background_color != self.last_background_color;
        self.last_background_color = background_color;

        {
            let glyph_cache = &mut self.glyph_cache;

            // Draw grid
            {
                let _sampler = self.meter.sampler();

                // Make a copy of size_info since the closure passed here
                // borrows terminal mutably
                //
                // TODO I wonder if the renderable cells iter could avoid the
                // mutable borrow
                self.renderer.with_api(config, &size_info, visual_bell_intensity, |mut api| {
                    // Clear screen to update whole background with new color
                    if background_color_changed {
                        api.clear(background_color);
                    }

                    // Draw the grid
                    api.render_cells(terminal.renderable_cells(config, selection), glyph_cache);
                });
            }

            // Draw render timer
            if self.render_timer {
                let timing = format!("{:.3} usec", self.meter.average());
                let color = Rgb { r: 0xd5, g: 0x4e, b: 0x53 };
                self.renderer.with_api(config, &size_info, visual_bell_intensity, |mut api| {
                    api.render_string(&timing[..], glyph_cache, color);
                });
            }
        }

        // Unlock the terminal mutex; following call to swap_buffers() may block
        drop(terminal);
        self.window
            .swap_buffers()
            .expect("swap buffers");

        // Clear after swap_buffers when terminal mutex isn't held. Mesa for
        // some reason takes a long time to call glClear(). The driver descends
        // into xcb_connect_to_fd() which ends up calling __poll_nocancel()
        // which blocks for a while.
        //
        // By keeping this outside of the critical region, the Mesa bug is
        // worked around to some extent. Since this doesn't actually address the
        // issue of glClear being slow, less time is available for input
        // handling and rendering.
        self.renderer.with_api(config, &size_info, visual_bell_intensity, |api| {
            api.clear(background_color);
        });
    }

    pub fn get_window_id(&self) -> Option<usize> {
        self.window.get_window_id()
    }

    /// Adjust the XIM editor position according to the new location of the cursor
    pub fn update_ime_position(&mut self, terminal: &Term) {
        use index::{Point, Line, Column};
        use term::SizeInfo;
        let Point{line: Line(row), col: Column(col)} = terminal.cursor().point;
        let SizeInfo{cell_width: cw,
                    cell_height: ch,
                    padding_x: px,
                    padding_y: py, ..} = *terminal.size_info();
        let nspot_y = (py + (row + 1) as f32 * ch) as i16;
        let nspot_x = (px + col as f32 * cw) as i16;
        self.window().send_xim_spot(nspot_x, nspot_y);
    }
}
<commit_msg>Fix typo and whitespace<commit_after>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! The display subsystem including window management, font rasterization, and
//! GPU drawing.
use std::sync::mpsc;

use parking_lot::{MutexGuard};

use Rgb;
use cli;
use config::Config;
use font::{self, Rasterize};
use meter::Meter;
use renderer::{self, GlyphCache, QuadRenderer};
use selection::Selection;
use term::{Term, SizeInfo};

use window::{self, Size, Pixels, Window, SetInnerSize};

#[derive(Debug)]
pub enum Error {
    /// Error with window management
    Window(window::Error),

    /// Error dealing with fonts
    Font(font::Error),

    /// Error in renderer
    Render(renderer::Error),
}

impl ::std::error::Error for Error {
    fn cause(&self) -> Option<&::std::error::Error> {
        match *self {
            Error::Window(ref err) => Some(err),
            Error::Font(ref err) => Some(err),
            Error::Render(ref err) => Some(err),
        }
    }

    fn description(&self) -> &str {
        match *self {
            Error::Window(ref err) => err.description(),
            Error::Font(ref err) => err.description(),
            Error::Render(ref err) => err.description(),
        }
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            Error::Window(ref err) => err.fmt(f),
            Error::Font(ref err) => err.fmt(f),
            Error::Render(ref err) => err.fmt(f),
        }
    }
}

impl From<window::Error> for Error {
    fn from(val: window::Error) -> Error {
        Error::Window(val)
    }
}

impl From<font::Error> for Error {
    fn from(val: font::Error) -> Error {
        Error::Font(val)
    }
}

impl From<renderer::Error> for Error {
    fn from(val: renderer::Error) -> Error {
        Error::Render(val)
    }
}

/// The display wraps a window, font rasterizer, and GPU renderer
pub struct Display {
    window: Window,
    renderer: QuadRenderer,
    glyph_cache: GlyphCache,
    render_timer: bool,
    rx: mpsc::Receiver<(u32, u32)>,
    tx: mpsc::Sender<(u32, u32)>,
    meter: Meter,
    font_size_modifier: i8,
    size_info: SizeInfo,
    last_background_color: Rgb,
}

/// Can wakeup the render loop from other threads
pub struct Notifier(window::Proxy);

/// Types that are interested in when the display is resized
pub trait OnResize {
    fn on_resize(&mut self, size: &SizeInfo);
}

impl Notifier {
    pub fn notify(&self) {
        self.0.wakeup_event_loop();
    }
}

impl Display {
    pub fn notifier(&self) -> Notifier {
        Notifier(self.window.create_window_proxy())
    }

    pub fn update_config(&mut self, config: &Config) {
        self.render_timer = config.render_timer();
    }

    /// Get size info about the display
    pub fn size(&self) -> &SizeInfo {
        &self.size_info
    }

    pub fn new(
        config: &Config,
        options: &cli::Options,
    ) -> Result<Display, Error> {
        // Extract some properties from config
        let render_timer = config.render_timer();

        // Create the window where Alacritty will be displayed
        let mut window = Window::new(&options.title)?;

        // get window properties for initializing the other subsystems
        let mut viewport_size = window.inner_size_pixels()
            .expect("glutin returns window size");
        let dpr = window.hidpi_factor();

        info!("device_pixel_ratio: {}", dpr);

        // Create renderer
        let mut renderer = QuadRenderer::new(&config, viewport_size)?;

        let (glyph_cache, cell_width, cell_height) =
            Self::new_glyph_cache(&window, &mut renderer, config, 0)?;

        let dimensions = options.dimensions()
            .unwrap_or_else(|| config.dimensions());

        // Resize window to specified dimensions unless one or both dimensions are 0
        if dimensions.columns_u32() > 0 && dimensions.lines_u32() > 0 {
            let width = cell_width as u32 * dimensions.columns_u32();
            let height = cell_height as u32 * dimensions.lines_u32();

            let new_viewport_size = Size {
                width: Pixels(width + 2 * config.padding().x as u32),
                height: Pixels(height + 2 * config.padding().y as u32),
            };

            window.set_inner_size(&new_viewport_size);
            renderer.resize(new_viewport_size.width.0 as _, new_viewport_size.height.0 as _);
            viewport_size = new_viewport_size
        }

        info!("Cell Size: ({} x {})", cell_width, cell_height);

        let size_info = SizeInfo {
            width: viewport_size.width.0 as f32,
            height: viewport_size.height.0 as f32,
            cell_width: cell_width as f32,
            cell_height: cell_height as f32,
            padding_x: config.padding().x.floor(),
            padding_y: config.padding().y.floor(),
        };

        // Channel for resize events
        //
        // macOS has a callback for getting resize events, the channel is used
        // to queue resize events until the next draw call. Unfortunately, it
        // seems that the event loop is blocked until the window is done
        // resizing. If any drawing were to happen during a resize, it would
        // need to be in the callback.
        let (tx, rx) = mpsc::channel();

        // Clear screen
        let background_color = config.colors().primary.background;
        renderer.with_api(config, &size_info, 0. /* visual bell intensity */, |api| {
            api.clear(background_color);
        });

        Ok(Display {
            window: window,
            renderer: renderer,
            glyph_cache: glyph_cache,
            render_timer: render_timer,
            tx: tx,
            rx: rx,
            meter: Meter::new(),
            font_size_modifier: 0,
            size_info: size_info,
            last_background_color: background_color,
        })
    }

    fn new_glyph_cache(window : &Window, renderer : &mut QuadRenderer,
                       config: &Config, font_size_delta: i8)
        -> Result<(GlyphCache, f32, f32), Error>
    {
        let font = config.font().clone().with_size_delta(font_size_delta as f32);
        let dpr = window.hidpi_factor();
        let rasterizer = font::Rasterizer::new(dpr, config.use_thin_strokes())?;

        // Initialize glyph cache
        let glyph_cache = {
            info!("Initializing glyph cache");
            let init_start = ::std::time::Instant::now();

            let cache = renderer.with_loader(|mut api| {
                GlyphCache::new(rasterizer, &font, &mut api)
            })?;

            let stop = init_start.elapsed();
            let stop_f = stop.as_secs() as f64 + stop.subsec_nanos() as f64 / 1_000_000_000f64;
            info!("Finished initializing glyph cache in {}", stop_f);

            cache
        };

        // Need font metrics to resize the window properly. This suggests to me the
        // font metrics should be computed before creating the window in the first
        // place so that a resize is not needed.
        let metrics = glyph_cache.font_metrics();
        let cell_width = (metrics.average_advance + font.offset().x as f64) as u32;
        let cell_height = (metrics.line_height + font.offset().y as f64) as u32;

        return Ok((glyph_cache, cell_width as f32, cell_height as f32));
    }

    pub fn update_glyph_cache(&mut self, config: &Config, font_size_delta: i8) {
        let cache = &mut self.glyph_cache;
        self.renderer.with_loader(|mut api| {
            let _ = cache.update_font_size(config.font(), font_size_delta, &mut api);
        });

        let metrics = cache.font_metrics();
        self.size_info.cell_width = ((metrics.average_advance + config.font().offset().x as f64) as f32).floor();
        self.size_info.cell_height = ((metrics.line_height + config.font().offset().y as f64) as f32).floor();
    }

    #[inline]
    pub fn resize_channel(&self) -> mpsc::Sender<(u32, u32)> {
        self.tx.clone()
    }

    pub fn window(&mut self) -> &mut Window {
        &mut self.window
    }

    /// Process pending resize events
    pub fn handle_resize(
        &mut self,
        terminal: &mut MutexGuard<Term>,
        config: &Config,
        items: &mut [&mut OnResize]
    ) {
        // Resize events new_size and are handled outside the poll_events
        // iterator. This has the effect of coalescing multiple resize
        // events into one.
        let mut new_size = None;

        // Take most recent resize event, if any
        while let Ok(sz) = self.rx.try_recv() {
            new_size = Some(sz);
        }

        if terminal.font_size_modifier != self.font_size_modifier {
            // Font size modification detected

            self.font_size_modifier = terminal.font_size_modifier;
            self.update_glyph_cache(config, terminal.font_size_modifier);

            if new_size == None {
                // Force a resize to refresh things
                new_size = Some((self.size_info.width as u32,
                                 self.size_info.height as u32));
            }
        }

        // Receive any resize events; only call gl::Viewport on last
        // available
        if let Some((w, h)) = new_size.take() {
            self.size_info.width = w as f32;
            self.size_info.height = h as f32;

            let size = &self.size_info;
            terminal.resize(size);

            for item in items {
                item.on_resize(size)
            }

            self.window.resize(w, h);
            self.renderer.resize(w as i32, h as i32);
        }

    }

    /// Draw the screen
    ///
    /// A reference to Term whose state is being drawn must be provided.
    ///
    /// This call may block if vsync is enabled
    pub fn draw(&mut self, mut terminal: MutexGuard<Term>, config: &Config, selection: Option<&Selection>) {
        // Clear dirty flag
        terminal.dirty = !terminal.visual_bell.completed();

        if let Some(title) = terminal.get_next_title() {
            self.window.set_title(&title);
        }

        if let Some(is_urgent) = terminal.next_is_urgent.take() {
            // We don't need to set the urgent flag if we already have the
            // user's attention.
            if !is_urgent || !self.window.is_focused {
                self.window.set_urgent(is_urgent);
            }
        }

        let size_info = *terminal.size_info();
        let visual_bell_intensity = terminal.visual_bell.intensity();

        let background_color = terminal.background_color();
        let background_color_changed = background_color != self.last_background_color;
        self.last_background_color = background_color;

        {
            let glyph_cache = &mut self.glyph_cache;

            // Draw grid
            {
                let _sampler = self.meter.sampler();

                // Make a copy of size_info since the closure passed here
                // borrows terminal mutably
                //
                // TODO I wonder if the renderable cells iter could avoid the
                // mutable borrow
                self.renderer.with_api(config, &size_info, visual_bell_intensity, |mut api| {
                    // Clear screen to update whole background with new color
                    if background_color_changed {
                        api.clear(background_color);
                    }

                    // Draw the grid
                    api.render_cells(terminal.renderable_cells(config, selection), glyph_cache);
                });
            }

            // Draw render timer
            if self.render_timer {
                let timing = format!("{:.3} usec", self.meter.average());
                let color = Rgb { r: 0xd5, g: 0x4e, b: 0x53 };
                self.renderer.with_api(config, &size_info, visual_bell_intensity, |mut api| {
                    api.render_string(&timing[..], glyph_cache, color);
                });
            }
        }

        // Unlock the terminal mutex; following call to swap_buffers() may block
        drop(terminal);
        self.window
            .swap_buffers()
            .expect("swap buffers");

        // Clear after swap_buffers when terminal mutex isn't held. Mesa for
        // some reason takes a long time to call glClear(). The driver descends
        // into xcb_connect_to_fd() which ends up calling __poll_nocancel()
        // which blocks for a while.
        //
        // By keeping this outside of the critical region, the Mesa bug is
        // worked around to some extent. Since this doesn't actually address the
        // issue of glClear being slow, less time is available for input
        // handling and rendering.
        self.renderer.with_api(config, &size_info, visual_bell_intensity, |api| {
            api.clear(background_color);
        });
    }

    pub fn get_window_id(&self) -> Option<usize> {
        self.window.get_window_id()
    }

    /// Adjust the XIM editor position according to the new location of the cursor
    pub fn update_ime_position(&mut self, terminal: &Term) {
        use index::{Point, Line, Column};
        use term::SizeInfo;
        let Point{line: Line(row), col: Column(col)} = terminal.cursor().point;
        let SizeInfo{cell_width: cw,
                    cell_height: ch,
                    padding_x: px,
                    padding_y: py, ..} = *terminal.size_info();
        let nspot_y = (py + (row + 1) as f32 * ch) as i16;
        let nspot_x = (px + col as f32 * cw) as i16;
        self.window().send_xim_spot(nspot_x, nspot_y);
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Read;
use std::io::Seek;
use std::io::SeekFrom::Start;
use std::io;
use std::fmt;
use std::slice;

#[repr(C)]
#[derive(Clone, PartialEq)]
pub struct Sym {
    pub st_name: u32, // Symbol name (string tbl index)
    pub st_info: u8, // Symbol type and binding
    pub st_other: u8, // Symbol visibility
    pub st_shndx: u16, // Section index
    pub st_value: u64, // Symbol value
    pub st_size: u64, // Symbol size
}

pub const SIZEOF_SYM: usize = 4 + 1 + 1 + 2 + 8 + 8;

#[inline(always)]
pub fn st_bind(info: u8) -> u8 {
    info >> 4
}

#[inline(always)]
pub fn st_type(info: u8) -> u8 {
    info & 0xf
}

#[inline(always)]
pub fn is_import(sym: &Sym) -> bool {
    let binding = st_bind(sym.st_info);
    binding == STB_GLOBAL && sym.st_value == 0
}

// sym bindings
pub const STB_LOCAL: u8 = 0; // Local symbol
pub const STB_GLOBAL: u8 = 1; // Global symbol
pub const STB_WEAK: u8 = 2; // Weak symbol
pub const STB_NUM: u8 = 3; // Number of defined types.
pub const STB_LOOS: u8 = 10; // Start of OS-specific
pub const STB_GNU_UNIQUE: u8 = 10; // Unique symbol.
pub const STB_HIOS: u8 = 12; // End of OS-specific
pub const STB_LOPROC: u8 = 13; // Start of processor-specific
pub const STB_HIPROC: u8 = 15; // End of processor-specific

#[inline]
pub fn bind_to_str(typ: u8) -> &'static str {
    match typ {
        STB_LOCAL => "LOCAL",
        STB_GLOBAL => "GLOBAL",
        STB_WEAK => "WEAK",
        STB_NUM => "NUM",
        STB_GNU_UNIQUE => "GNU_UNIQUE",
        _ => "UNKNOWN_STB",
    }
}

// sym types
pub const STT_NOTYPE: u8 = 0; // Symbol type is unspecified
pub const STT_OBJECT: u8 = 1; // Symbol is a data object
pub const STT_FUNC: u8 = 2; // Symbol is a code object
pub const STT_SECTION: u8 = 3; // Symbol associated with a section
pub const STT_FILE: u8 = 4; // Symbol's name is file name
pub const STT_COMMON: u8 = 5; // Symbol is a common data object
pub const STT_TLS: u8 = 6; // Symbol is thread-local data object
pub const STT_NUM: u8 = 7; // Number of defined types
pub const STT_LOOS: u8 = 10; // Start of OS-specific
pub const STT_GNU_IFUNC: u8 = 10; // Symbol is indirect code object
pub const STT_HIOS: u8 = 12; // End of OS-specific
pub const STT_LOPROC: u8 = 13; // Start of processor-specific
pub const STT_HIPROC: u8 = 15; // End of processor-specific

#[inline]
pub fn type_to_str(typ: u8) -> &'static str {
    match typ {
        STT_NOTYPE => "NOTYPE",
        STT_OBJECT => "OBJECT",
        STT_FUNC => "FUNC",
        STT_SECTION => "SECTION",
        STT_FILE => "FILE",
        STT_COMMON => "COMMON",
        STT_TLS => "TLS",
        STT_NUM => "NUM",
        STT_GNU_IFUNC => "GNU_IFUNC",
        _ => "UNKNOWN_STT",

    }
}

impl fmt::Debug for Sym {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let bind = st_bind(self.st_info);
        let typ = st_type(self.st_info);
        write!(f,
               "st_name: {} {} {} st_other: {} st_shndx: {} st_value: {:x} st_size: {}",
               self.st_name,
               bind_to_str(bind),
               type_to_str(typ),
               self.st_other,
               self.st_shndx,
               self.st_value,
               self.st_size)
    }
}

pub unsafe fn from_raw<'a>(symp: *const Sym, count: usize) -> &'a [Sym] {
    slice::from_raw_parts(symp, count)
}

pub fn from_fd<'a>(fd: &mut File, offset: usize, count: usize) -> io::Result<Vec<Sym>> {
    let mut bytes = vec![0u8; count * SIZEOF_SYM]; // afaik this shouldn't work, since i pass in a byte size...
    try!(fd.seek(Start(offset as u64)));
    try!(fd.read(&mut bytes));
    let bytes = unsafe { slice::from_raw_parts(bytes.as_ptr() as *mut Sym, count) };
    let mut syms = Vec::with_capacity(count);
    syms.extend_from_slice(bytes);
    syms.dedup();
    Ok(syms)
}
<commit_msg>elf.sym: add Copy derived trait<commit_after>use std::fs::File;
use std::io::Read;
use std::io::Seek;
use std::io::SeekFrom::Start;
use std::io;
use std::fmt;
use std::slice;

#[repr(C)]
#[derive(Clone, Copy, PartialEq)]
pub struct Sym {
    pub st_name: u32, // Symbol name (string tbl index)
    pub st_info: u8, // Symbol type and binding
    pub st_other: u8, // Symbol visibility
    pub st_shndx: u16, // Section index
    pub st_value: u64, // Symbol value
    pub st_size: u64, // Symbol size
}

pub const SIZEOF_SYM: usize = 4 + 1 + 1 + 2 + 8 + 8;

#[inline(always)]
pub fn st_bind(info: u8) -> u8 {
    info >> 4
}

#[inline(always)]
pub fn st_type(info: u8) -> u8 {
    info & 0xf
}

#[inline(always)]
pub fn is_import(sym: &Sym) -> bool {
    let binding = st_bind(sym.st_info);
    binding == STB_GLOBAL && sym.st_value == 0
}

// sym bindings
pub const STB_LOCAL: u8 = 0; // Local symbol
pub const STB_GLOBAL: u8 = 1; // Global symbol
pub const STB_WEAK: u8 = 2; // Weak symbol
pub const STB_NUM: u8 = 3; // Number of defined types.
pub const STB_LOOS: u8 = 10; // Start of OS-specific
pub const STB_GNU_UNIQUE: u8 = 10; // Unique symbol.
pub const STB_HIOS: u8 = 12; // End of OS-specific
pub const STB_LOPROC: u8 = 13; // Start of processor-specific
pub const STB_HIPROC: u8 = 15; // End of processor-specific

#[inline]
pub fn bind_to_str(typ: u8) -> &'static str {
    match typ {
        STB_LOCAL => "LOCAL",
        STB_GLOBAL => "GLOBAL",
        STB_WEAK => "WEAK",
        STB_NUM => "NUM",
        STB_GNU_UNIQUE => "GNU_UNIQUE",
        _ => "UNKNOWN_STB",
    }
}

// sym types
pub const STT_NOTYPE: u8 = 0; // Symbol type is unspecified
pub const STT_OBJECT: u8 = 1; // Symbol is a data object
pub const STT_FUNC: u8 = 2; // Symbol is a code object
pub const STT_SECTION: u8 = 3; // Symbol associated with a section
pub const STT_FILE: u8 = 4; // Symbol's name is file name
pub const STT_COMMON: u8 = 5; // Symbol is a common data object
pub const STT_TLS: u8 = 6; // Symbol is thread-local data object
pub const STT_NUM: u8 = 7; // Number of defined types
pub const STT_LOOS: u8 = 10; // Start of OS-specific
pub const STT_GNU_IFUNC: u8 = 10; // Symbol is indirect code object
pub const STT_HIOS: u8 = 12; // End of OS-specific
pub const STT_LOPROC: u8 = 13; // Start of processor-specific
pub const STT_HIPROC: u8 = 15; // End of processor-specific

#[inline]
pub fn type_to_str(typ: u8) -> &'static str {
    match typ {
        STT_NOTYPE => "NOTYPE",
        STT_OBJECT => "OBJECT",
        STT_FUNC => "FUNC",
        STT_SECTION => "SECTION",
        STT_FILE => "FILE",
        STT_COMMON => "COMMON",
        STT_TLS => "TLS",
        STT_NUM => "NUM",
        STT_GNU_IFUNC => "GNU_IFUNC",
        _ => "UNKNOWN_STT",

    }
}

impl fmt::Debug for Sym {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let bind = st_bind(self.st_info);
        let typ = st_type(self.st_info);
        write!(f,
               "st_name: {} {} {} st_other: {} st_shndx: {} st_value: {:x} st_size: {}",
               self.st_name,
               bind_to_str(bind),
               type_to_str(typ),
               self.st_other,
               self.st_shndx,
               self.st_value,
               self.st_size)
    }
}

pub unsafe fn from_raw<'a>(symp: *const Sym, count: usize) -> &'a [Sym] {
    slice::from_raw_parts(symp, count)
}

pub fn from_fd<'a>(fd: &mut File, offset: usize, count: usize) -> io::Result<Vec<Sym>> {
    let mut bytes = vec![0u8; count * SIZEOF_SYM]; // afaik this shouldn't work, since i pass in a byte size...
    try!(fd.seek(Start(offset as u64)));
    try!(fd.read(&mut bytes));
    let bytes = unsafe { slice::from_raw_parts(bytes.as_ptr() as *mut Sym, count) };
    let mut syms = Vec::with_capacity(count);
    syms.extend_from_slice(bytes);
    syms.dedup();
    Ok(syms)
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fmt;
use std::io::IoError as StdIoError;
use std::iter::repeat;
use serialize;

use super::{Data, StrVal, Bool, VecVal, Map};
pub use self::Error::*;

pub struct Encoder<'a> {
    pub data: Vec<Data<'a>>,
}

impl<'a> Encoder<'a> {
    pub fn new() -> Encoder<'a> {
        Encoder { data: Vec::new() }
    }
}

#[derive(PartialEq)]
pub enum Error {
    UnsupportedType,
    InvalidStr,
    MissingElements,
    KeyIsNotString,
    IoError(StdIoError),
}

impl fmt::Show for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            UnsupportedType => "unsupported type".fmt(f),
            InvalidStr => "invalid str".fmt(f),
            MissingElements => "no elements in value".fmt(f),
            KeyIsNotString => "key is not a string".fmt(f),
            IoError(ref err) => err.fmt(f),
        }
    }
}

pub type EncoderResult = Result<(), Error>;

impl<'a> serialize::Encoder for Encoder<'a> {
    type Error = Error;

    fn emit_nil(&mut self) -> EncoderResult { Err(UnsupportedType) }

    fn emit_int(&mut self, v: isize) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_uint(&mut self, v: usize) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_u64(&mut self, v: u64) -> EncoderResult   { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_u32(&mut self, v: u32) -> EncoderResult   { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_u16(&mut self, v: u16) -> EncoderResult   { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_u8(&mut self, v: u8) -> EncoderResult     { self.data.push(StrVal(v.to_string())); Ok(()) }

    fn emit_i64(&mut self, v: i64) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_i32(&mut self, v: i32) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_i16(&mut self, v: i16) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_i8(&mut self, v: i8) -> EncoderResult   { self.data.push(StrVal(v.to_string())); Ok(()) }

    fn emit_bool(&mut self, v: bool) -> EncoderResult { self.data.push(Bool(v)); Ok(()) }

    fn emit_f64(&mut self, v: f64) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_f32(&mut self, v: f32) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }

    fn emit_char(&mut self, v: char) -> EncoderResult {
        self.data.push(StrVal(repeat(v).take(1).collect::<String>()));
        Ok(())
    }
    fn emit_str(&mut self, v: &str) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }

    fn emit_enum< F >(&mut self, _name: &str, _f: F ) -> EncoderResult
    where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        Err(UnsupportedType)
    }

    fn emit_enum_variant< F >(&mut self,
                         _name: &str,
                         _id: usize,
                         _len: usize,
                         _f: F) -> EncoderResult
                         where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        Err(UnsupportedType)
    }

    fn emit_enum_variant_arg< F >(&mut self,
                             _a_idx: usize,
                             _f: F) -> EncoderResult
                             where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        Err(UnsupportedType)
    }

    fn emit_enum_struct_variant< F >(&mut self,
                                _v_name: &str,
                                _v_id: usize,
                                _len: usize,
                                _f: F) -> EncoderResult
                                where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        Err(UnsupportedType)
    }

    fn emit_enum_struct_variant_field< F >(&mut self,
                                      _f_name: &str,
                                      _f_idx: usize,
                                      _f: F) -> EncoderResult
                                      where F : FnOnce(&mut Encoder<'a>) -> EncoderResult  {
        Err(UnsupportedType)
    }

    fn emit_struct< F >(&mut self,
                   _name: &str,
                   _len: usize,
                   f: F) -> EncoderResult
                   where F : FnOnce(&mut Encoder<'a>) -> EncoderResult  {
        self.data.push(Map(HashMap::new()));
        f(self)
    }

    fn emit_struct_field< F >(&mut self,
                         name: &str,
                         _idx: usize,
                         f: F) -> EncoderResult
                         where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        let mut m = match self.data.pop() {
            Some(Map(m)) => m,
            _ => { return Err(UnsupportedType); }
        };
        try!(f(self));
        let data = match self.data.pop() {
            Some(d) => d,
            _ => { return Err(UnsupportedType); }
        };
        m.insert(name.to_string(), data);
        self.data.push(Map(m));
        Ok(())
    }

    fn emit_tuple< F >(&mut self,
                  len: usize,
                  f: F) -> EncoderResult
                  where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        self.emit_seq(len, f)
    }

    fn emit_tuple_arg< F >(&mut self, idx: usize, f: F) -> EncoderResult
    where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        self.emit_seq_elt(idx, f)
    }

    fn emit_tuple_struct< F >(&mut self,
                         _name: &str,
                         len: usize,
                         f: F) -> EncoderResult
                         where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        self.emit_seq(len, f)
    }

    fn emit_tuple_struct_arg< F >(&mut self, idx: usize, f: F) -> EncoderResult
    where F : FnOnce(&mut Encoder<'a>) -> EncoderResult  {
        self.emit_seq_elt(idx, f)
    }

    // Specialized types:
    fn emit_option< F >(&mut self, _f: F) -> EncoderResult
    where F : FnOnce(&mut Encoder<'a>) -> EncoderResult  {
        Err(UnsupportedType)
    }

    fn emit_option_none(&mut self) -> EncoderResult {
        Err(UnsupportedType)
    }

    fn emit_option_some< F >(&mut self, _f: F) -> EncoderResult
  where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        Err(UnsupportedType)
    }

    fn emit_seq< F >(&mut self, _len: usize, f: F) -> EncoderResult
  where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        self.data.push(VecVal(Vec::new()));
        f(self)
    }

    fn emit_seq_elt< F >(&mut self, _idx: usize, f: F) -> EncoderResult
  where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        let mut v = match self.data.pop() {
            Some(VecVal(v)) => v,
            _ => { return Err(UnsupportedType); }
        };
        try!(f(self));
        let data = match self.data.pop() {
            Some(d) => d,
            _ => { return Err(UnsupportedType); }
        };
        v.push(data);
        self.data.push(VecVal(v));
        Ok(())
    }

    fn emit_map< F >(&mut self, _len: usize, f: F) -> EncoderResult
  where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        self.data.push(Map(HashMap::new()));
        f(self)
    }

    fn emit_map_elt_key< F >(&mut self, _idx: usize, mut f: F) -> EncoderResult
  where F : FnMut(&mut Encoder<'a>) -> EncoderResult {
        try!(f(self));
        let last = match self.data.last() {
            Some(d) => d,
            None => { return Err(MissingElements); }
        };
        match *last {
            StrVal(_) => Ok(()),
            _ => Err(KeyIsNotString),
        }
    }

    fn emit_map_elt_val< F >(&mut self, _idx: usize, f: F) -> EncoderResult
  where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        let k = match self.data.pop() {
            Some(StrVal(s)) => s,
            _ => { return Err(KeyIsNotString); }
        };
        let mut m = match self.data.pop() {
            Some(Map(m)) => m,
            _ => panic!("Expected a map"),
        };
        try!(f(self));
        let popped = match self.data.pop() {
            Some(p) => p,
            None => panic!("Error: Nothing to pop!"),
        };
        m.insert(k, popped);
        self.data.push(Map(m));
        Ok(())
    }
}

pub fn encode<'a, T: serialize::Encodable>(data: &T) -> Result<Data<'a>, Error> {
    let mut encoder = Encoder::new();
    try!(data.encode(&mut encoder));
    assert_eq!(encoder.data.len(), 1);
    match encoder.data.pop() {
        Some(data) => Ok(data),
        None => panic!("Error: Nothing to pop!"),
    }
}
<commit_msg>Update for latest nightly.<commit_after>use std::collections::HashMap;
use std::fmt;
use std::io::IoError as StdIoError;
use std::iter::repeat;
use serialize;

use super::{Data, StrVal, Bool, VecVal, Map};
pub use self::Error::*;

pub struct Encoder<'a> {
    pub data: Vec<Data<'a>>,
}

impl<'a> Encoder<'a> {
    pub fn new() -> Encoder<'a> {
        Encoder { data: Vec::new() }
    }
}

#[derive(PartialEq)]
pub enum Error {
    UnsupportedType,
    InvalidStr,
    MissingElements,
    KeyIsNotString,
    IoError(StdIoError),
}

impl fmt::Show for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            UnsupportedType => "unsupported type".fmt(f),
            InvalidStr => "invalid str".fmt(f),
            MissingElements => "no elements in value".fmt(f),
            KeyIsNotString => "key is not a string".fmt(f),
            IoError(ref err) => err.fmt(f),
        }
    }
}

pub type EncoderResult = Result<(), Error>;

impl<'a> serialize::Encoder for Encoder<'a> {
    type Error = Error;

    fn emit_nil(&mut self) -> EncoderResult { Err(UnsupportedType) }

    fn emit_int(&mut self, v: isize) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_uint(&mut self, v: usize) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_u64(&mut self, v: u64) -> EncoderResult   { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_u32(&mut self, v: u32) -> EncoderResult   { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_u16(&mut self, v: u16) -> EncoderResult   { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_u8(&mut self, v: u8) -> EncoderResult     { self.data.push(StrVal(v.to_string())); Ok(()) }

    fn emit_i64(&mut self, v: i64) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_i32(&mut self, v: i32) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_i16(&mut self, v: i16) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_i8(&mut self, v: i8) -> EncoderResult   { self.data.push(StrVal(v.to_string())); Ok(()) }

    fn emit_bool(&mut self, v: bool) -> EncoderResult { self.data.push(Bool(v)); Ok(()) }

    fn emit_f64(&mut self, v: f64) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_f32(&mut self, v: f32) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }

    fn emit_char(&mut self, v: char) -> EncoderResult {
        self.data.push(StrVal(repeat(v).take(1).collect::<String>()));
        Ok(())
    }
    fn emit_str(&mut self, v: &str) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }

    fn emit_enum< F >(&mut self, _name: &str, _f: F ) -> EncoderResult
    where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        Err(UnsupportedType)
    }

    fn emit_enum_variant< F >(&mut self,
                         _name: &str,
                         _id: usize,
                         _len: usize,
                         _f: F) -> EncoderResult
                         where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        Err(UnsupportedType)
    }

    fn emit_enum_variant_arg< F >(&mut self,
                             _a_idx: usize,
                             _f: F) -> EncoderResult
                             where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        Err(UnsupportedType)
    }

    fn emit_enum_struct_variant< F >(&mut self,
                                _v_name: &str,
                                _v_id: usize,
                                _len: usize,
                                _f: F) -> EncoderResult
                                where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        Err(UnsupportedType)
    }

    fn emit_enum_struct_variant_field< F >(&mut self,
                                      _f_name: &str,
                                      _f_idx: usize,
                                      _f: F) -> EncoderResult
                                      where F : FnOnce(&mut Encoder<'a>) -> EncoderResult  {
        Err(UnsupportedType)
    }

    fn emit_struct< F >(&mut self,
                   _name: &str,
                   _len: usize,
                   f: F) -> EncoderResult
                   where F : FnOnce(&mut Encoder<'a>) -> EncoderResult  {
        self.data.push(Map(HashMap::new()));
        f(self)
    }

    fn emit_struct_field< F >(&mut self,
                         name: &str,
                         _idx: usize,
                         f: F) -> EncoderResult
                         where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        let mut m = match self.data.pop() {
            Some(Map(m)) => m,
            _ => { return Err(UnsupportedType); }
        };
        try!(f(self));
        let data = match self.data.pop() {
            Some(d) => d,
            _ => { return Err(UnsupportedType); }
        };
        m.insert(name.to_string(), data);
        self.data.push(Map(m));
        Ok(())
    }

    fn emit_tuple< F >(&mut self,
                  len: usize,
                  f: F) -> EncoderResult
                  where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        self.emit_seq(len, f)
    }

    fn emit_tuple_arg< F >(&mut self, idx: usize, f: F) -> EncoderResult
    where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        self.emit_seq_elt(idx, f)
    }

    fn emit_tuple_struct< F >(&mut self,
                         _name: &str,
                         len: usize,
                         f: F) -> EncoderResult
                         where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        self.emit_seq(len, f)
    }

    fn emit_tuple_struct_arg< F >(&mut self, idx: usize, f: F) -> EncoderResult
    where F : FnOnce(&mut Encoder<'a>) -> EncoderResult  {
        self.emit_seq_elt(idx, f)
    }

    // Specialized types:
    fn emit_option< F >(&mut self, _f: F) -> EncoderResult
    where F : FnOnce(&mut Encoder<'a>) -> EncoderResult  {
        Err(UnsupportedType)
    }

    fn emit_option_none(&mut self) -> EncoderResult {
        Err(UnsupportedType)
    }

    fn emit_option_some< F >(&mut self, _f: F) -> EncoderResult
  where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        Err(UnsupportedType)
    }

    fn emit_seq< F >(&mut self, _len: usize, f: F) -> EncoderResult
  where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        self.data.push(VecVal(Vec::new()));
        f(self)
    }

    fn emit_seq_elt< F >(&mut self, _idx: usize, f: F) -> EncoderResult
  where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        let mut v = match self.data.pop() {
            Some(VecVal(v)) => v,
            _ => { return Err(UnsupportedType); }
        };
        try!(f(self));
        let data = match self.data.pop() {
            Some(d) => d,
            _ => { return Err(UnsupportedType); }
        };
        v.push(data);
        self.data.push(VecVal(v));
        Ok(())
    }

    fn emit_map< F >(&mut self, _len: usize, f: F) -> EncoderResult
  where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        self.data.push(Map(HashMap::new()));
        f(self)
    }

    fn emit_map_elt_key< F >(&mut self, _idx: usize, f: F) -> EncoderResult
  where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        try!(f(self));
        let last = match self.data.last() {
            Some(d) => d,
            None => { return Err(MissingElements); }
        };
        match *last {
            StrVal(_) => Ok(()),
            _ => Err(KeyIsNotString),
        }
    }

    fn emit_map_elt_val< F >(&mut self, _idx: usize, f: F) -> EncoderResult
  where F : FnOnce(&mut Encoder<'a>) -> EncoderResult {
        let k = match self.data.pop() {
            Some(StrVal(s)) => s,
            _ => { return Err(KeyIsNotString); }
        };
        let mut m = match self.data.pop() {
            Some(Map(m)) => m,
            _ => panic!("Expected a map"),
        };
        try!(f(self));
        let popped = match self.data.pop() {
            Some(p) => p,
            None => panic!("Error: Nothing to pop!"),
        };
        m.insert(k, popped);
        self.data.push(Map(m));
        Ok(())
    }
}

pub fn encode<'a, T: serialize::Encodable>(data: &T) -> Result<Data<'a>, Error> {
    let mut encoder = Encoder::new();
    try!(data.encode(&mut encoder));
    assert_eq!(encoder.data.len(), 1);
    match encoder.data.pop() {
        Some(data) => Ok(data),
        None => panic!("Error: Nothing to pop!"),
    }
}
<|endoftext|>


<commit_before>use rustc_serialize::{Encoder,Encodable};
use types::{Value,BasicValue,Struct,Signature};

pub struct DBusEncoder {
    val: Vec<Value>,
    signature: String,
    handling_key: bool
}

#[derive(Debug,PartialEq)]
pub enum EncoderError {
    BadKeyType,
    Unsupported,
    EmptyArray
}

impl DBusEncoder {
    fn handle_struct (&self) -> Result<(),EncoderError> {
        let objs = Vec::new();
        for i in self.val.into_iter() {
            objs.push(i);
        }
        let s = Struct {
            objects: objs,
            signature: Signature(self.signature.to_string())
        };
        self.signature = "".to_string();
        self.val.push(Value::Struct(s));
        Ok(())
    }

    pub fn new() -> DBusEncoder {
        DBusEncoder {
            val: Vec::new(),
            signature: "".to_string(),
            handling_key: false
        }
    }

    pub fn encode<T: Encodable>(obj: &T) -> Result<Value,EncoderError> {
        let mut encoder = DBusEncoder::new();
        try!(obj.encode(&mut encoder));
        Ok(encoder.val.take().unwrap())
    }
}

impl Encoder for DBusEncoder {
    type Error = EncoderError;

    fn emit_nil(&mut self) -> Result<(), Self::Error> {
        Err(EncoderError::Unsupported)
    }
    fn emit_usize(&mut self, v: usize) -> Result<(), Self::Error> {
        self.val.push(Value::BasicValue(BasicValue::Uint64(v as u64)));
        self.signature.push_str("n");
        Ok(())
    }
    fn emit_u64(&mut self, v: u64) -> Result<(), Self::Error> {
        self.val.push(Value::BasicValue(BasicValue::Uint64(v)));
        self.signature.push_str("n");
        Ok(())
    }
    fn emit_u32(&mut self, v: u32) -> Result<(), Self::Error> {
        self.val.push(Value::BasicValue(BasicValue::Uint32(v)));
        self.signature.push_str("u");
        Ok(())
    }
    fn emit_u16(&mut self, v: u16) -> Result<(), Self::Error> {
        self.val.push(Value::BasicValue(BasicValue::Uint16(v)));
        self.signature.push_str("q");
        Ok(())
    }
    fn emit_u8(&mut self, v: u8) -> Result<(), Self::Error> {
        self.val.push(Value::BasicValue(BasicValue::Byte(v)));
        self.signature.push_str("y");
        Ok(())
    }
    fn emit_isize(&mut self, v: isize) -> Result<(), Self::Error> {
        self.val.push(Value::BasicValue(BasicValue::Int64(v as i64)));
        self.signature.push_str("x");
        Ok(())
    }
    fn emit_i64(&mut self, v: i64) -> Result<(), Self::Error> {
        self.val.push(Value::BasicValue(BasicValue::Int64(v)));
        self.signature.push_str("x");
        Ok(())
    }
    fn emit_i32(&mut self, v: i32) -> Result<(), Self::Error> {
        self.val.push(Value::BasicValue(BasicValue::Int32(v)));
        self.signature.push_str("i");
        Ok(())
    }
    fn emit_i16(&mut self, v: i16) -> Result<(), Self::Error> {
        self.val.push(Value::BasicValue(BasicValue::Int16(v)));
        self.signature.push_str("n");
        Ok(())
    }
    fn emit_i8(&mut self, _v: i8) -> Result<(), Self::Error> {
        Err(EncoderError::Unsupported)
    }
    fn emit_bool(&mut self, v: bool) -> Result<(), Self::Error> {
        self.val.push(Value::BasicValue(BasicValue::Boolean(v)));
        self.signature.push_str("b");
        Ok(())
    }
    fn emit_f64(&mut self, v: f64) -> Result<(), Self::Error> {
        self.val.push(Value::Double(v));
        self.signature.push_str("d");
        Ok(())
    }
    fn emit_f32(&mut self, v: f32) -> Result<(), Self::Error> {
        self.val.push(Value::Double(v as f64));
        self.signature.push_str("d");
        Ok(())
    }
    fn emit_char(&mut self, v: char) -> Result<(), Self::Error> {
        self.val.push(Value::BasicValue(BasicValue::Byte(v as u8)));
        self.signature.push_str("y");
        Ok(())
    }
    fn emit_str(&mut self, v: &str) -> Result<(), Self::Error> {
        self.val.push(Value::BasicValue(BasicValue::String(v.to_string())));
        self.signature.push_str("s");
        Ok(())
    }

    fn emit_struct<F>(&mut self, _name: &str, _len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        try!(f(self));
        self.handle_struct()
    }
    fn emit_struct_field<F>(&mut self, _f_name: &str, _f_idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        f(self)
    }
    fn emit_tuple<F>(&mut self, _len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        try!(f(self));
        self.handle_struct()
    }
    fn emit_tuple_arg<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        f(self)
    }
    fn emit_tuple_struct<F>(&mut self, _name: &str, _len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        try!(f(self));
        self.handle_struct()
    }
    fn emit_tuple_struct_arg<F>(&mut self, _f_idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        f(self)
    }

    fn emit_seq<F>(&mut self, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        if len == 0 {
            return Err(EncoderError::EmptyArray);
        }
        self.handle_dbus_array(f)
    }
    fn emit_seq_elt<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        let val = f(self);
        val
    }

    fn emit_map<F>(&mut self, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        if len == 0 {
            return Err(EncoderError::EmptyArray);
        }
        self.handle_dbus_array(f)
    }
    fn emit_map_elt_key<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        self.add_to_sig("{");
        self.handling_key = true;
        let val = try!(f(self));
        self.handling_key = false;
        Ok(val)
    }
    fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        let val = try!(f(self));
        self.add_to_sig("}");
        Ok(val)
    }

    fn emit_option<F>(&mut self, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(EncoderError::Unsupported)
    }
    fn emit_option_none(&mut self) -> Result<(), Self::Error> {
        Err(EncoderError::Unsupported)
    }
    fn emit_option_some<F>(&mut self, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(EncoderError::Unsupported)
    }
    fn emit_enum<F>(&mut self, _name: &str, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(EncoderError::Unsupported)
    }
    fn emit_enum_variant<F>(&mut self, _v_name: &str, _v_id: usize, _len: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(EncoderError::Unsupported)
    }
    fn emit_enum_variant_arg<F>(&mut self, _a_idx: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(EncoderError::Unsupported)
    }
    fn emit_enum_struct_variant<F>(&mut self, _v_name: &str, _v_id: usize, _len: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(EncoderError::Unsupported)
    }
    fn emit_enum_struct_variant_field<F>(&mut self, _f_name: &str, _f_idx: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(EncoderError::Unsupported)
    }
}

<commit_msg>encoder.rs: implement map support<commit_after>use std::collections::HashMap;

use rustc_serialize::{Encoder,Encodable};

use types::{Value,BasicValue,Struct,Signature,Dictionary};

pub struct DBusEncoder {
    val: Vec<Value>,
    signature: String,
    key: Option<BasicValue>
}

#[derive(Debug,PartialEq)]
pub enum EncoderError {
    BadKeyType,
    Unsupported,
    EmptyArray
}

impl DBusEncoder {
    fn handle_struct (&mut self) -> Result<(),EncoderError> {
        let mut objs = Vec::new();
        {
            let val = &self.val;
            for i in val {
                objs.push(i.clone());
            }
        }
        let s = Struct {
            objects: objs,
            signature: Signature("(".to_string() + &self.signature + ")")
        };
        self.signature = "".to_string();
        self.val.push(Value::Struct(s));
        Ok(())
    }

    fn handle_array (&mut self) -> Result<(),EncoderError> {
        let mut objs = Vec::new();
        for i in 0..self.val.len() {
            self.val.push(Value::BasicValue(BasicValue::Byte(0)));
            objs.push(self.val.swap_remove(i));
        }
        self.val.clear();
        self.val.push(Value::Array(objs));
        Ok(())
    }

    pub fn new() -> DBusEncoder {
        DBusEncoder {
            val: Vec::new(),
            signature: "".to_string(),
            key: None
        }
    }

    pub fn encode<T: Encodable>(obj: &T) -> Result<Value,EncoderError> {
        let mut encoder = DBusEncoder::new();
        try!(obj.encode(&mut encoder));
        Ok(encoder.val.remove(0))
    }
}

impl Encoder for DBusEncoder {
    type Error = EncoderError;

    fn emit_nil(&mut self) -> Result<(), Self::Error> {
        Err(EncoderError::Unsupported)
    }
    fn emit_usize(&mut self, v: usize) -> Result<(), Self::Error> {
        self.val.push(Value::BasicValue(BasicValue::Uint64(v as u64)));
        self.signature.push_str("n");
        Ok(())
    }
    fn emit_u64(&mut self, v: u64) -> Result<(), Self::Error> {
        self.val.push(Value::BasicValue(BasicValue::Uint64(v)));
        self.signature.push_str("n");
        Ok(())
    }
    fn emit_u32(&mut self, v: u32) -> Result<(), Self::Error> {
        self.val.push(Value::BasicValue(BasicValue::Uint32(v)));
        self.signature.push_str("u");
        Ok(())
    }
    fn emit_u16(&mut self, v: u16) -> Result<(), Self::Error> {
        self.val.push(Value::BasicValue(BasicValue::Uint16(v)));
        self.signature.push_str("q");
        Ok(())
    }
    fn emit_u8(&mut self, v: u8) -> Result<(), Self::Error> {
        self.val.push(Value::BasicValue(BasicValue::Byte(v)));
        self.signature.push_str("y");
        Ok(())
    }
    fn emit_isize(&mut self, v: isize) -> Result<(), Self::Error> {
        self.val.push(Value::BasicValue(BasicValue::Int64(v as i64)));
        self.signature.push_str("x");
        Ok(())
    }
    fn emit_i64(&mut self, v: i64) -> Result<(), Self::Error> {
        self.val.push(Value::BasicValue(BasicValue::Int64(v)));
        self.signature.push_str("x");
        Ok(())
    }
    fn emit_i32(&mut self, v: i32) -> Result<(), Self::Error> {
        self.val.push(Value::BasicValue(BasicValue::Int32(v)));
        self.signature.push_str("i");
        Ok(())
    }
    fn emit_i16(&mut self, v: i16) -> Result<(), Self::Error> {
        self.val.push(Value::BasicValue(BasicValue::Int16(v)));
        self.signature.push_str("n");
        Ok(())
    }
    fn emit_i8(&mut self, _v: i8) -> Result<(), Self::Error> {
        Err(EncoderError::Unsupported)
    }
    fn emit_bool(&mut self, v: bool) -> Result<(), Self::Error> {
        self.val.push(Value::BasicValue(BasicValue::Boolean(v)));
        self.signature.push_str("b");
        Ok(())
    }
    fn emit_f64(&mut self, v: f64) -> Result<(), Self::Error> {
        self.val.push(Value::Double(v));
        self.signature.push_str("d");
        Ok(())
    }
    fn emit_f32(&mut self, v: f32) -> Result<(), Self::Error> {
        self.val.push(Value::Double(v as f64));
        self.signature.push_str("d");
        Ok(())
    }
    fn emit_char(&mut self, v: char) -> Result<(), Self::Error> {
        self.val.push(Value::BasicValue(BasicValue::Byte(v as u8)));
        self.signature.push_str("y");
        Ok(())
    }
    fn emit_str(&mut self, v: &str) -> Result<(), Self::Error> {
        self.val.push(Value::BasicValue(BasicValue::String(v.to_string())));
        self.signature.push_str("s");
        Ok(())
    }

    fn emit_struct<F>(&mut self, _name: &str, _len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        try!(f(self));
        self.handle_struct()
    }
    fn emit_struct_field<F>(&mut self, _f_name: &str, _f_idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        f(self)
    }
    fn emit_tuple<F>(&mut self, _len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        try!(f(self));
        self.handle_struct()
    }
    fn emit_tuple_arg<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        f(self)
    }
    fn emit_tuple_struct<F>(&mut self, _name: &str, _len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        try!(f(self));
        self.handle_struct()
    }
    fn emit_tuple_struct_arg<F>(&mut self, _f_idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        f(self)
    }

    fn emit_seq<F>(&mut self, _len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        try!(f(self));
        self.handle_array()
    }
    fn emit_seq_elt<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        f(self)
    }

    fn emit_map<F>(&mut self, _len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        let map : Dictionary = HashMap::new();
        self.val.push(Value::Dictionary(map));
        f(self)
    }
    fn emit_map_elt_key<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        try!(f(self));
        self.key = match self.val.pop().unwrap() {
            Value::BasicValue(x) => Some(x),
            _ => return Err(EncoderError::BadKeyType)
        };
        Ok(())
    }
    fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        let key : BasicValue = self.key.take().unwrap();
        try!(f(self));
        let val : Value = self.val.pop().unwrap();
        let mut map = self.val.pop().unwrap();
        match map {
            Value::Dictionary(ref mut x) => x.insert(key, val),
            _ => panic!("No dictionary on stack")
        };
        self.val.push(map);
        Ok(())
    }

    fn emit_option<F>(&mut self, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(EncoderError::Unsupported)
    }
    fn emit_option_none(&mut self) -> Result<(), Self::Error> {
        Err(EncoderError::Unsupported)
    }
    fn emit_option_some<F>(&mut self, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(EncoderError::Unsupported)
    }
    fn emit_enum<F>(&mut self, _name: &str, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(EncoderError::Unsupported)
    }
    fn emit_enum_variant<F>(&mut self, _v_name: &str, _v_id: usize, _len: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(EncoderError::Unsupported)
    }
    fn emit_enum_variant_arg<F>(&mut self, _a_idx: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(EncoderError::Unsupported)
    }
    fn emit_enum_struct_variant<F>(&mut self, _v_name: &str, _v_id: usize, _len: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(EncoderError::Unsupported)
    }
    fn emit_enum_struct_variant_field<F>(&mut self, _f_name: &str, _f_idx: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(EncoderError::Unsupported)
    }
}

#[test]
fn test_array() {
    let array : Vec<u32> = vec![1,2,3];
    let v = DBusEncoder::encode(&array).ok().unwrap();
    let a2 = vec![
        Value::BasicValue(BasicValue::Uint32(1)),
        Value::BasicValue(BasicValue::Uint32(2)),
        Value::BasicValue(BasicValue::Uint32(3)),
    ];
    assert_eq!(v, Value::Array(a2));
}
<|endoftext|>


<commit_before>// const _GRAMMAR: &'static str = include_str!("grammar.pest");

#[derive(Parser)]
#[grammar = "grammar.pest"]
pub struct HandlebarsParser;

#[cfg(test)]
use pest::Parser;

#[cfg(test)]
macro_rules! assert_rule {
    ($rule:expr, $in:expr) => {
        assert_eq!(
            HandlebarsParser::parse($rule, $in)
                .unwrap()
                .last()
                .unwrap()
                .as_span()
                .end(),
            $in.len()
        );
    };
}

#[cfg(test)]
macro_rules! assert_not_rule {
    ($rule:expr, $in:expr) => {
        assert!(
            HandlebarsParser::parse($rule, $in).is_err()
                || HandlebarsParser::parse($rule, $in)
                    .unwrap()
                    .last()
                    .unwrap()
                    .as_span()
                    .end()
                    != $in.len()
        );
    };
}

#[cfg(test)]
macro_rules! assert_rule_match {
    ($rule:expr, $in:expr) => {
        assert!(HandlebarsParser::parse($rule, $in).is_ok());
    };
}

#[test]
fn test_raw_text() {
    let s = vec![
        "
 helloworld
    ",
        r"hello\{{world}}",
        r"hello\{{#if world}}nice\{{/if}}",
        r"hello \{{{{raw}}}}hello\{{{{/raw}}}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::raw_text, i);
    }

    let s_not_escape = vec![r"\\{{hello}}"];
    for i in s_not_escape.iter() {
        assert_not_rule!(Rule::raw_text, i);
    }
}

#[test]
fn test_raw_block_text() {
    let s = "
 {{hello}}
";
    assert_rule!(Rule::raw_block_text, s);
}

#[test]
fn test_reference() {
    let s = vec![
        "a",
        "abc",
        "../a",
        "a.b",
        "@abc",
        "a.[abc]",
        "aBc.[abc]",
        "abc.[0].[nice]",
        "some-name",
        "this.[0].ok",
    ];
    for i in s.iter() {
        assert_rule!(Rule::reference, i);
    }
}

#[test]
fn test_name() {
    let s = vec!["if", "(abc)"];
    for i in s.iter() {
        assert_rule!(Rule::name, i);
    }
}

#[test]
fn test_param() {
    let s = vec!["hello", "\"json literal\""];
    for i in s.iter() {
        assert_rule!(Rule::param, i);
    }
}

#[test]
fn test_hash() {
    let s = vec![
        "hello=world",
        "hello=\"world\"",
        "hello=(world)",
        "hello=(world 0)",
    ];
    for i in s.iter() {
        assert_rule!(Rule::hash, i);
    }
}

#[test]
fn test_json_literal() {
    let s = vec![
        "\"json string\"",
        "\"quot: \\\"\"",
        "'json string'",
        "'quot: \\''",
        "[]",
        "[\"hello\"]",
        "[1,2,3,4,true]",
        "{\"hello\": \"world\"}",
        "{}",
        "{\"a\":1, \"b\":2 }",
    ];
    for i in s.iter() {
        assert_rule!(Rule::literal, i);
    }
}

#[test]
fn test_comment() {
    let s = vec!["{{!-- <hello {{ a-b c-d}} {{d-c}} ok --}}",
                 "{{!--

{{this.title}}

                --}}"];
    for i in s.iter() {
        assert_rule!(Rule::hbs_comment, i);
    }
    let s2 = vec!["{{! hello }}", "{{! test me }}"];
    for i in s2.iter() {
        assert_rule!(Rule::hbs_comment_compact, i);
    }
}

#[test]
fn test_subexpression() {
    let s = vec!["(sub)", "(sub 0)", "(sub a=1)"];
    for i in s.iter() {
        assert_rule!(Rule::subexpression, i);
    }
}

#[test]
fn test_expression() {
    let s = vec![
        "{{exp}}",
        "{{(exp)}}",
        "{{../exp}}",
        "{{exp 1}}",
        "{{exp \"literal\"}}",
        "{{exp ref}}",
        "{{exp (sub)}}",
        "{{exp (sub 123)}}",
        "{{exp []}}",
        "{{exp {}}}",
        "{{exp key=1}}",
        "{{exp key=ref}}",
        "{{exp key=(sub)}}",
        "{{exp key=(sub 0)}}",
        "{{exp key=(sub 0 key=1)}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::expression, i);
    }
}

#[test]
fn test_identifier_with_dash() {
    let s = vec!["{{exp-foo}}"];
    for i in s.iter() {
        assert_rule!(Rule::expression, i);
    }
}

#[test]
fn test_html_expression() {
    let s = vec!["{{{html}}}", "{{{(html)}}}", "{{{(html)}}}"];
    for i in s.iter() {
        assert_rule!(Rule::html_expression, i);
    }
}

#[test]
fn test_helper_start() {
    let s = vec![
        "{{#if hello}}",
        "{{#if (hello)}}",
        "{{#if hello=world}}",
        "{{#if hello hello=world}}",
        "{{#if []}}",
        "{{#if {}}}",
        "{{#if}}",
        "{{~#if hello~}}",
        "{{#each people as |person|}}",
        "{{#each-obj obj as |val key|}}",
        "{{#each assets}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::helper_block_start, i);
    }
}

#[test]
fn test_helper_end() {
    let s = vec!["{{/if}}", "{{~/if}}", "{{~/if ~}}", "{{/if   ~}}"];
    for i in s.iter() {
        assert_rule!(Rule::helper_block_end, i);
    }
}

#[test]
fn test_helper_block() {
    let s = vec![
        "{{#if hello}}hello{{/if}}",
        "{{#if true}}hello{{/if}}",
        "{{#if nice ok=1}}hello{{/if}}",
        "{{#if}}hello{{else}}world{{/if}}",
        "{{#if}}hello{{^}}world{{/if}}",
        "{{#if}}{{#if}}hello{{/if}}{{/if}}",
        "{{#if}}hello{{~else}}world{{/if}}",
        "{{#if}}hello{{else~}}world{{/if}}",
        "{{#if}}hello{{~^~}}world{{/if}}",
        "{{#if}}{{/if}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::helper_block, i);
    }
}

#[test]
fn test_raw_block() {
    let s = vec![
        "{{{{if hello}}}}good {{hello}}{{{{/if}}}}",
        "{{{{if hello}}}}{{#if nice}}{{/if}}{{{{/if}}}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::raw_block, i);
    }
}

#[test]
fn test_block_param() {
    let s = vec!["as |person|", "as |val key|"];
    for i in s.iter() {
        assert_rule!(Rule::block_param, i);
    }
}

#[test]
fn test_path() {
    let s = vec![
        "a",
        "a.b.c.d",
        "a.[0].[1].[2]",
        "a.[abc]",
        "a/v/c.d.s",
        "a.[0]/b/c/../d",
        "a.[bb c]/b/c/../d",
        "a.[0].[#hello]",
        "../a/b.[0].[1]",
        "./this.[0]/[1]/this/../a",
        "./this_name",
        "./goo/[/bar]",
        "a.[你好]",
        "a.[10].[#comment]",
        "a.[]", // empty key
        "././[/foo]",
        "[foo]",
        "@root/a/b",
    ];
    for i in s.iter() {
        assert_rule_match!(Rule::path, i);
    }
}

#[test]
fn test_directive_expression() {
    let s = vec!["{{* ssh}}", "{{~* ssh}}"];
    for i in s.iter() {
        assert_rule!(Rule::directive_expression, i);
    }
}

#[test]
fn test_directive_block() {
    let s = vec![
        "{{#* inline}}something{{/inline}}",
        "{{~#* inline}}hello{{/inline}}",
        "{{#* inline \"partialname\"}}something{{/inline}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::directive_block, i);
    }
}

#[test]
fn test_partial_expression() {
    let s = vec![
        "{{> hello}}",
        "{{> (hello)}}",
        "{{~> hello a}}",
        "{{> hello a=1}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::partial_expression, i);
    }
}

#[test]
fn test_partial_block() {
    let s = vec!["{{#> hello}}nice{{/hello}}"];
    for i in s.iter() {
        assert_rule!(Rule::partial_block, i);
    }
}
<commit_msg>(test) fix test for path test<commit_after>// const _GRAMMAR: &'static str = include_str!("grammar.pest");

#[derive(Parser)]
#[grammar = "grammar.pest"]
pub struct HandlebarsParser;

#[cfg(test)]
use pest::Parser;

#[cfg(test)]
macro_rules! assert_rule {
    ($rule:expr, $in:expr) => {
        assert_eq!(
            HandlebarsParser::parse($rule, $in)
                .unwrap()
                .last()
                .unwrap()
                .as_span()
                .end(),
            $in.len()
        );
    };
}

#[cfg(test)]
macro_rules! assert_not_rule {
    ($rule:expr, $in:expr) => {
        assert!(
            HandlebarsParser::parse($rule, $in).is_err()
                || HandlebarsParser::parse($rule, $in)
                    .unwrap()
                    .last()
                    .unwrap()
                    .as_span()
                    .end()
                    != $in.len()
        );
    };
}

#[cfg(test)]
macro_rules! assert_rule_match {
    ($rule:expr, $in:expr) => {
        assert!(HandlebarsParser::parse($rule, $in).is_ok());
    };
}

#[test]
fn test_raw_text() {
    let s = vec![
        "
 helloworld
    ",
        r"hello\{{world}}",
        r"hello\{{#if world}}nice\{{/if}}",
        r"hello \{{{{raw}}}}hello\{{{{/raw}}}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::raw_text, i);
    }

    let s_not_escape = vec![r"\\{{hello}}"];
    for i in s_not_escape.iter() {
        assert_not_rule!(Rule::raw_text, i);
    }
}

#[test]
fn test_raw_block_text() {
    let s = "
 {{hello}}
";
    assert_rule!(Rule::raw_block_text, s);
}

#[test]
fn test_reference() {
    let s = vec![
        "a",
        "abc",
        "../a",
        "a.b",
        "@abc",
        "a.[abc]",
        "aBc.[abc]",
        "abc.[0].[nice]",
        "some-name",
        "this.[0].ok",
    ];
    for i in s.iter() {
        assert_rule!(Rule::reference, i);
    }
}

#[test]
fn test_name() {
    let s = vec!["if", "(abc)"];
    for i in s.iter() {
        assert_rule!(Rule::name, i);
    }
}

#[test]
fn test_param() {
    let s = vec!["hello", "\"json literal\""];
    for i in s.iter() {
        assert_rule!(Rule::param, i);
    }
}

#[test]
fn test_hash() {
    let s = vec![
        "hello=world",
        "hello=\"world\"",
        "hello=(world)",
        "hello=(world 0)",
    ];
    for i in s.iter() {
        assert_rule!(Rule::hash, i);
    }
}

#[test]
fn test_json_literal() {
    let s = vec![
        "\"json string\"",
        "\"quot: \\\"\"",
        "'json string'",
        "'quot: \\''",
        "[]",
        "[\"hello\"]",
        "[1,2,3,4,true]",
        "{\"hello\": \"world\"}",
        "{}",
        "{\"a\":1, \"b\":2 }",
    ];
    for i in s.iter() {
        assert_rule!(Rule::literal, i);
    }
}

#[test]
fn test_comment() {
    let s = vec!["{{!-- <hello {{ a-b c-d}} {{d-c}} ok --}}",
                 "{{!--

{{this.title}}

                --}}"];
    for i in s.iter() {
        assert_rule!(Rule::hbs_comment, i);
    }
    let s2 = vec!["{{! hello }}", "{{! test me }}"];
    for i in s2.iter() {
        assert_rule!(Rule::hbs_comment_compact, i);
    }
}

#[test]
fn test_subexpression() {
    let s = vec!["(sub)", "(sub 0)", "(sub a=1)"];
    for i in s.iter() {
        assert_rule!(Rule::subexpression, i);
    }
}

#[test]
fn test_expression() {
    let s = vec![
        "{{exp}}",
        "{{(exp)}}",
        "{{../exp}}",
        "{{exp 1}}",
        "{{exp \"literal\"}}",
        "{{exp ref}}",
        "{{exp (sub)}}",
        "{{exp (sub 123)}}",
        "{{exp []}}",
        "{{exp {}}}",
        "{{exp key=1}}",
        "{{exp key=ref}}",
        "{{exp key=(sub)}}",
        "{{exp key=(sub 0)}}",
        "{{exp key=(sub 0 key=1)}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::expression, i);
    }
}

#[test]
fn test_identifier_with_dash() {
    let s = vec!["{{exp-foo}}"];
    for i in s.iter() {
        assert_rule!(Rule::expression, i);
    }
}

#[test]
fn test_html_expression() {
    let s = vec!["{{{html}}}", "{{{(html)}}}", "{{{(html)}}}"];
    for i in s.iter() {
        assert_rule!(Rule::html_expression, i);
    }
}

#[test]
fn test_helper_start() {
    let s = vec![
        "{{#if hello}}",
        "{{#if (hello)}}",
        "{{#if hello=world}}",
        "{{#if hello hello=world}}",
        "{{#if []}}",
        "{{#if {}}}",
        "{{#if}}",
        "{{~#if hello~}}",
        "{{#each people as |person|}}",
        "{{#each-obj obj as |val key|}}",
        "{{#each assets}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::helper_block_start, i);
    }
}

#[test]
fn test_helper_end() {
    let s = vec!["{{/if}}", "{{~/if}}", "{{~/if ~}}", "{{/if   ~}}"];
    for i in s.iter() {
        assert_rule!(Rule::helper_block_end, i);
    }
}

#[test]
fn test_helper_block() {
    let s = vec![
        "{{#if hello}}hello{{/if}}",
        "{{#if true}}hello{{/if}}",
        "{{#if nice ok=1}}hello{{/if}}",
        "{{#if}}hello{{else}}world{{/if}}",
        "{{#if}}hello{{^}}world{{/if}}",
        "{{#if}}{{#if}}hello{{/if}}{{/if}}",
        "{{#if}}hello{{~else}}world{{/if}}",
        "{{#if}}hello{{else~}}world{{/if}}",
        "{{#if}}hello{{~^~}}world{{/if}}",
        "{{#if}}{{/if}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::helper_block, i);
    }
}

#[test]
fn test_raw_block() {
    let s = vec![
        "{{{{if hello}}}}good {{hello}}{{{{/if}}}}",
        "{{{{if hello}}}}{{#if nice}}{{/if}}{{{{/if}}}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::raw_block, i);
    }
}

#[test]
fn test_block_param() {
    let s = vec!["as |person|", "as |val key|"];
    for i in s.iter() {
        assert_rule!(Rule::block_param, i);
    }
}

#[test]
fn test_path() {
    let s = vec![
        "a",
        "a.b.c.d",
        "a.[0].[1].[2]",
        "a.[abc]",
        "a/v/c.d.s",
        "a.[0]/b/c/d",
        "a.[bb c]/b/c/d",
        "a.[0].[#hello]",
        "../a/b.[0].[1]",
        "./this.[0]/[1]/this/a",
        "./this_name",
        "./goo/[/bar]",
        "a.[你好]",
        "a.[10].[#comment]",
        "a.[]", // empty key
        "././[/foo]",
        "[foo]",
        "@root/a/b",
    ];
    for i in s.iter() {
        assert_rule_match!(Rule::path, i);
    }
}

#[test]
fn test_directive_expression() {
    let s = vec!["{{* ssh}}", "{{~* ssh}}"];
    for i in s.iter() {
        assert_rule!(Rule::directive_expression, i);
    }
}

#[test]
fn test_directive_block() {
    let s = vec![
        "{{#* inline}}something{{/inline}}",
        "{{~#* inline}}hello{{/inline}}",
        "{{#* inline \"partialname\"}}something{{/inline}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::directive_block, i);
    }
}

#[test]
fn test_partial_expression() {
    let s = vec![
        "{{> hello}}",
        "{{> (hello)}}",
        "{{~> hello a}}",
        "{{> hello a=1}}",
    ];
    for i in s.iter() {
        assert_rule!(Rule::partial_expression, i);
    }
}

#[test]
fn test_partial_block() {
    let s = vec!["{{#> hello}}nice{{/hello}}"];
    for i in s.iter() {
        assert_rule!(Rule::partial_block, i);
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

use bootstrap::{Action, EventHandler, EventSig, MouseButton};
use color::ColorAlpha;
use overlay::{Disc, Quad, Renderer, RenderInput, Text, Texture2D, Triangle, Vert};
use scene::Scene;

type Time = f32;

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Viewport {
  pub x: f32,
  pub y: f32,
  pub w: f32,
  pub h: f32
}

pub struct GUI<'a> {
  // common
  renderer: Renderer,

  widgets: HashMap<String, Box<Widget<'a> + 'a>>,

  // event stuff
  last_cursor: Option<[f64; 2]>,
  last_mouse_left_down: Option<[f64; 2]>,
  last_mouse_left_up: Option<[f64; 2]>,
  focused_widgets: HashMap<Focus, String>
}

impl<'a> GUI<'a> {
  pub fn new(viewport: Viewport, scene: &mut Scene) -> Self {
    GUI {
      renderer: Renderer::new(viewport.w.ceil() as u32, viewport.h.ceil() as u32, 1024, 1024, 1024, scene),
      widgets: HashMap::new(),
      last_cursor: None,
      last_mouse_left_down: None,
      last_mouse_left_up: None,
      focused_widgets: HashMap::new(),
    }
  }

  pub fn add_widget<W>(&mut self, id: &str, widget: &W) where W: 'a + Clone + Widget<'a> {
    self.widgets.insert(id.to_owned(), Box::new(widget.clone()));
  }

  pub fn remove_widget(&mut self, id: &str) {
    self.widgets.remove(id);
  }

  pub fn render(&self) -> &Texture2D {
    let mut tris = Vec::new();
    let mut quads = Vec::new();
    let mut discs = Vec::new();
    let mut texts = Vec::new();

    for widget in self.widgets.values() {
      for prim in widget.unwidget() {
        match prim {
          WidgetPrim::Triangle(ref tri) => tris.push(*tri),
          WidgetPrim::Quad(ref quad) => quads.push(*quad),
          WidgetPrim::Disc(ref disc) => discs.push(*disc),
          WidgetPrim::Text(ref text) => texts.push(*text)
        }
      }
    }

    let render_input = RenderInput::new()
      .triangles(&tris)
      .quads(&quads)
      .discs(&discs)
      .texts(&texts, 1.);

    self.renderer.render(render_input)
  }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
enum Focus {
  MouseButton(MouseButton, Action),
  Drag
}

impl<'a> EventHandler for GUI<'a> {
  fn on_mouse_button(&mut self, button: MouseButton, action: Action) -> EventSig {
    if let MouseButton::Button1 = button {
      let last_cursor = self.last_cursor.unwrap();

      match action {
        Action::Press => {
          self.last_mouse_left_down = Some(last_cursor);
          self.last_mouse_left_up = None;

          for (key, widget) in &mut self.widgets {
            if widget.on_mouse_button(button, action) == EventSig::Focused {
              self.focused_widgets.insert(Focus::MouseButton(button, action), key.clone());
              break;
            }
          }
        },
        Action::Release => {
          // check whether it’s a click
          if px_dist(self.last_mouse_left_down.unwrap(), last_cursor) <= 5. {
            // it’s a click
            for widget in self.widgets.values() {
              widget.on_click(last_cursor);
            }
          }

          self.last_mouse_left_down = None;
          self.last_mouse_left_up = Some(last_cursor);

          self.focused_widgets.remove(&Focus::MouseButton(button, Action::Press));
          self.focused_widgets.remove(&Focus::Drag);
        },
        _ => ()
      }
    }

    EventSig::Handled
  }

  // TODO: change the implementation to take into account widget focus
  fn on_cursor_move(&mut self, cursor: [f64; 2]) -> EventSig {
    self.last_cursor = Some(cursor);

    if let Some(key) = self.focused_widgets.get(&Focus::Drag).cloned() {
      let focused = self.widgets.get(&key).unwrap();
      let down_cursor = self.last_mouse_left_down.unwrap();
      focused.on_drag(cursor, down_cursor);
    } else if let Some(key) = self.focused_widgets.get(&Focus::MouseButton(MouseButton::Button1, Action::Press)).cloned() {
      let focused = self.widgets.get(&key).unwrap();
      let down_cursor = self.last_mouse_left_down.unwrap();

      if px_dist(down_cursor, cursor) > 5. {
        self.focused_widgets.insert(Focus::Drag, key);
        focused.on_drag(cursor, down_cursor);
      }
    }

    EventSig::Handled
  }
}

/// Widget primitives.
///
/// A widget primitive is used as primary a tool to build up widgets. A widget is basically just a
/// sum of widget primitives used to represent it.
pub enum WidgetPrim<'a> {
  Triangle(Triangle),
  Quad(Quad),
  Disc(Disc),
  Text(Text<'a>)
}

pub trait Widget<'a>: EventHandler {
  fn unwidget(&self) -> Vec<WidgetPrim<'a>>;
  fn on_click(&self, _: [f64; 2]) {}
  fn on_drag(&self, _: [f64; 2], _: [f64; 2]) {}
}

pub struct ProgressBar {
  w: f32,
  progress_quad: Quad,
  inactive_quad: Quad,
  recip_dur_sec: f32,
  listeners: HashMap<String, Rc<RefCell<ProgressBarListener>>>
}

pub enum ProgressBarEvent {
  Set(Time),
  Toggle
}

pub trait ProgressBarListener {
  fn on(&mut self, e: ProgressBarEvent) -> bool;
}

impl ProgressBar {
  pub fn new(w: f32, h: f32, progress_color: ColorAlpha, inactive_color: ColorAlpha, dur_sec: f32) -> Rc<RefCell<Self>> {
    let pcol = *progress_color.as_ref();
    let icol = *inactive_color.as_ref();

    let progress_quad = Quad(
      Vert::new([0., 0., 0.], pcol),
      Vert::new([0., h, 0.], pcol),
      Vert::new([0., 0., 0.], pcol),
      Vert::new([0., h, 0.], pcol)
    );

    let inactive_quad = Quad(
      Vert::new([w, 0., 0.], icol),
      Vert::new([w, h, 0.], icol),
      Vert::new([0., 0., 0.], icol),
      Vert::new([0., h, 0.], icol)
    );

    Rc::new(RefCell::new(ProgressBar {
      w: w,
      progress_quad: progress_quad,
      inactive_quad: inactive_quad,
      recip_dur_sec: 1. / dur_sec,
      listeners: HashMap::new()
    }))
  }

  /// Add a listener.
  pub fn add_listener(&mut self, key: &str, listener: &Rc<RefCell<ProgressBarListener>>) {
    self.listeners.insert(key.to_owned(), listener.clone());
  }

  /// Remove a listener.
  pub fn remove_listener(&mut self, key: &str) {
    self.listeners.remove(key);
  }

  /// Set the cursor (seconds).
  pub fn set(&mut self, cursor: f32) {
    let c = cursor * self.recip_dur_sec * self.w;

    // update the quads
    self.progress_quad.0.pos[0] = c;
    self.progress_quad.1.pos[0] = c;
    self.inactive_quad.2.pos[0] = c;
    self.inactive_quad.3.pos[0] = c;

    for l in self.listeners.values() {
      l.borrow_mut().on(ProgressBarEvent::Set(cursor));
    }
  }

  pub fn toggle(&mut self) {
    for l in self.listeners.values() {
      l.borrow_mut().on(ProgressBarEvent::Toggle);
    }
  }

  pub fn on_cursor_change(&mut self, cursor: [f64; 2]) {
    let c = cursor[0] as f32;

    // update the quads
    self.progress_quad.0.pos[0] = c;
    self.progress_quad.1.pos[0] = c;
    self.inactive_quad.2.pos[0] = c;
    self.inactive_quad.3.pos[0] = c;

    for l in self.listeners.values() {
      l.borrow_mut().on(ProgressBarEvent::Set(c / (self.recip_dur_sec * self.w)));
    }
  }
}

impl EventHandler for Rc<RefCell<ProgressBar>> {
  fn on_mouse_button(&mut self, _: MouseButton, action: Action) -> EventSig {
    if action == Action::Press {
      EventSig::Focused
    } else {
      EventSig::Ignored
    }
  }
}

impl<'a> Widget<'a> for Rc<RefCell<ProgressBar>> {
  fn unwidget(&self) -> Vec<WidgetPrim<'a>> {
    let bar = &self.borrow();
    vec![WidgetPrim::Quad(bar.progress_quad), WidgetPrim::Quad(bar.inactive_quad)]
  }

  fn on_click(&self, cursor: [f64; 2]) {
    self.borrow_mut().on_cursor_change(cursor);
  }

  fn on_drag(&self, cursor: [f64; 2], down_cursor: [f64; 2]) {
    self.borrow_mut().on_cursor_change([cursor[0], down_cursor[1]]);
  }
}

/// Pixel distance between two points.
fn px_dist(a: [f64; 2], b: [f64; 2]) -> f64 {
  let x = b[0] - a[0];
  let y = b[1] - a[1];

  f64::sqrt(x*x + y*y)
}
<commit_msg>Removed useless ProgressBarEvent.<commit_after>use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

use bootstrap::{Action, EventHandler, EventSig, MouseButton};
use color::ColorAlpha;
use overlay::{Disc, Quad, Renderer, RenderInput, Text, Texture2D, Triangle, Vert};
use scene::Scene;

type Time = f32;

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Viewport {
  pub x: f32,
  pub y: f32,
  pub w: f32,
  pub h: f32
}

pub struct GUI<'a> {
  // common
  renderer: Renderer,

  widgets: HashMap<String, Box<Widget<'a> + 'a>>,

  // event stuff
  last_cursor: Option<[f64; 2]>,
  last_mouse_left_down: Option<[f64; 2]>,
  last_mouse_left_up: Option<[f64; 2]>,
  focused_widgets: HashMap<Focus, String>
}

impl<'a> GUI<'a> {
  pub fn new(viewport: Viewport, scene: &mut Scene) -> Self {
    GUI {
      renderer: Renderer::new(viewport.w.ceil() as u32, viewport.h.ceil() as u32, 1024, 1024, 1024, scene),
      widgets: HashMap::new(),
      last_cursor: None,
      last_mouse_left_down: None,
      last_mouse_left_up: None,
      focused_widgets: HashMap::new(),
    }
  }

  pub fn add_widget<W>(&mut self, id: &str, widget: &W) where W: 'a + Clone + Widget<'a> {
    self.widgets.insert(id.to_owned(), Box::new(widget.clone()));
  }

  pub fn remove_widget(&mut self, id: &str) {
    self.widgets.remove(id);
  }

  pub fn render(&self) -> &Texture2D {
    let mut tris = Vec::new();
    let mut quads = Vec::new();
    let mut discs = Vec::new();
    let mut texts = Vec::new();

    for widget in self.widgets.values() {
      for prim in widget.unwidget() {
        match prim {
          WidgetPrim::Triangle(ref tri) => tris.push(*tri),
          WidgetPrim::Quad(ref quad) => quads.push(*quad),
          WidgetPrim::Disc(ref disc) => discs.push(*disc),
          WidgetPrim::Text(ref text) => texts.push(*text)
        }
      }
    }

    let render_input = RenderInput::new()
      .triangles(&tris)
      .quads(&quads)
      .discs(&discs)
      .texts(&texts, 1.);

    self.renderer.render(render_input)
  }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
enum Focus {
  MouseButton(MouseButton, Action),
  Drag
}

impl<'a> EventHandler for GUI<'a> {
  fn on_mouse_button(&mut self, button: MouseButton, action: Action) -> EventSig {
    if let MouseButton::Button1 = button {
      let last_cursor = self.last_cursor.unwrap();

      match action {
        Action::Press => {
          self.last_mouse_left_down = Some(last_cursor);
          self.last_mouse_left_up = None;

          for (key, widget) in &mut self.widgets {
            if widget.on_mouse_button(button, action) == EventSig::Focused {
              self.focused_widgets.insert(Focus::MouseButton(button, action), key.clone());
              break;
            }
          }
        },
        Action::Release => {
          // check whether it’s a click
          if px_dist(self.last_mouse_left_down.unwrap(), last_cursor) <= 5. {
            // it’s a click
            for widget in self.widgets.values() {
              widget.on_click(last_cursor);
            }
          }

          self.last_mouse_left_down = None;
          self.last_mouse_left_up = Some(last_cursor);

          self.focused_widgets.remove(&Focus::MouseButton(button, Action::Press));
          self.focused_widgets.remove(&Focus::Drag);
        },
        _ => ()
      }
    }

    EventSig::Handled
  }

  // TODO: change the implementation to take into account widget focus
  fn on_cursor_move(&mut self, cursor: [f64; 2]) -> EventSig {
    self.last_cursor = Some(cursor);

    if let Some(key) = self.focused_widgets.get(&Focus::Drag).cloned() {
      let focused = self.widgets.get(&key).unwrap();
      let down_cursor = self.last_mouse_left_down.unwrap();
      focused.on_drag(cursor, down_cursor);
    } else if let Some(key) = self.focused_widgets.get(&Focus::MouseButton(MouseButton::Button1, Action::Press)).cloned() {
      let focused = self.widgets.get(&key).unwrap();
      let down_cursor = self.last_mouse_left_down.unwrap();

      if px_dist(down_cursor, cursor) > 5. {
        self.focused_widgets.insert(Focus::Drag, key);
        focused.on_drag(cursor, down_cursor);
      }
    }

    EventSig::Handled
  }
}

/// Widget primitives.
///
/// A widget primitive is used as primary a tool to build up widgets. A widget is basically just a
/// sum of widget primitives used to represent it.
pub enum WidgetPrim<'a> {
  Triangle(Triangle),
  Quad(Quad),
  Disc(Disc),
  Text(Text<'a>)
}

pub trait Widget<'a>: EventHandler {
  fn unwidget(&self) -> Vec<WidgetPrim<'a>>;
  fn on_click(&self, _: [f64; 2]) {}
  fn on_drag(&self, _: [f64; 2], _: [f64; 2]) {}
}

pub struct ProgressBar {
  w: f32,
  progress_quad: Quad,
  inactive_quad: Quad,
  recip_dur_sec: f32,
  listeners: HashMap<String, Rc<RefCell<ProgressBarListener>>>
}

pub trait ProgressBarListener {
  fn on_set(&mut self, t: Time) -> bool;
}

impl ProgressBar {
  pub fn new(w: f32, h: f32, progress_color: ColorAlpha, inactive_color: ColorAlpha, dur_sec: f32) -> Rc<RefCell<Self>> {
    let pcol = *progress_color.as_ref();
    let icol = *inactive_color.as_ref();

    let progress_quad = Quad(
      Vert::new([0., 0., 0.], pcol),
      Vert::new([0., h, 0.], pcol),
      Vert::new([0., 0., 0.], pcol),
      Vert::new([0., h, 0.], pcol)
    );

    let inactive_quad = Quad(
      Vert::new([w, 0., 0.], icol),
      Vert::new([w, h, 0.], icol),
      Vert::new([0., 0., 0.], icol),
      Vert::new([0., h, 0.], icol)
    );

    Rc::new(RefCell::new(ProgressBar {
      w: w,
      progress_quad: progress_quad,
      inactive_quad: inactive_quad,
      recip_dur_sec: 1. / dur_sec,
      listeners: HashMap::new()
    }))
  }

  /// Add a listener.
  pub fn add_listener(&mut self, key: &str, listener: &Rc<RefCell<ProgressBarListener>>) {
    self.listeners.insert(key.to_owned(), listener.clone());
  }

  /// Remove a listener.
  pub fn remove_listener(&mut self, key: &str) {
    self.listeners.remove(key);
  }

  /// Set the cursor (seconds).
  pub fn set(&mut self, cursor: f32) {
    let c = cursor * self.recip_dur_sec * self.w;

    // update the quads
    self.progress_quad.0.pos[0] = c;
    self.progress_quad.1.pos[0] = c;
    self.inactive_quad.2.pos[0] = c;
    self.inactive_quad.3.pos[0] = c;

    for l in self.listeners.values() {
      l.borrow_mut().on_set(cursor);
    }
  }

  pub fn on_cursor_change(&mut self, cursor: [f64; 2]) {
    let c = cursor[0] as f32;

    // update the quads
    self.progress_quad.0.pos[0] = c;
    self.progress_quad.1.pos[0] = c;
    self.inactive_quad.2.pos[0] = c;
    self.inactive_quad.3.pos[0] = c;

    for l in self.listeners.values() {
      l.borrow_mut().on_set(c / (self.recip_dur_sec * self.w));
    }
  }
}

impl EventHandler for Rc<RefCell<ProgressBar>> {
  fn on_mouse_button(&mut self, _: MouseButton, action: Action) -> EventSig {
    if action == Action::Press {
      EventSig::Focused
    } else {
      EventSig::Ignored
    }
  }
}

impl<'a> Widget<'a> for Rc<RefCell<ProgressBar>> {
  fn unwidget(&self) -> Vec<WidgetPrim<'a>> {
    let bar = &self.borrow();
    vec![WidgetPrim::Quad(bar.progress_quad), WidgetPrim::Quad(bar.inactive_quad)]
  }

  fn on_click(&self, cursor: [f64; 2]) {
    self.borrow_mut().on_cursor_change(cursor);
  }

  fn on_drag(&self, cursor: [f64; 2], down_cursor: [f64; 2]) {
    self.borrow_mut().on_cursor_change([cursor[0], down_cursor[1]]);
  }
}

/// Pixel distance between two points.
fn px_dist(a: [f64; 2], b: [f64; 2]) -> f64 {
  let x = b[0] - a[0];
  let y = b[1] - a[1];

  f64::sqrt(x*x + y*y)
}
<|endoftext|>