<commit_before>//! Cursor utilities
//!
//! This module contains bindings to the `libwayland-cursor.so` library.
//!
//! These utilities allows you to laod cursor images in order to match
//! your cursors to the ones of the system.
//!
//! First of all, the function `load_theme` will allow you to load a
//! `CursorTheme`, which represents the full cursor theme.
//!
//! From this theme, you can load a specific `Cursor`, which can each
//! contain several images if the cursor is animated. It provides you
//! with the means of knowing which frame of the animation shoudl be
//! displayed at which time, as well as handles to the buffers containing
//! these frames, to attach them to a wayland surface.

use std::ffi::{CString, CStr};
use std::marker::PhantomData;
use std::ops::Deref;
use std::ptr;

use wayland_sys::cursor::*;
use std::os::raw::c_int;

use Proxy;
use protocol::wl_shm::WlShm;
use protocol::wl_buffer::WlBuffer;

/// Checks if the wayland-cursor lib is available and can be used
///
/// Trying to call any function of this module if the lib cannot
/// be used will result in a panic.
pub fn is_available() -> bool {
    is_lib_available()
}

/// Represents a cursor theme loaded from the system.
pub struct CursorTheme {
    theme: *mut wl_cursor_theme
}

/// Attempts to load a cursor theme from given name.
///
/// If no name is given or the requested theme is not found, will
/// load the default theme.
///
/// Other arguments are the requested size for the cursor images (ex: 16)
/// and a handle to the global `WlShm` object.
///
/// Panics:
///
/// - If the `wayland-cursor` lib is not available (see `is_available()` function)
///   in this module.
/// - In case of memory allocation failure.
/// - If the theme name provided as argument contains an interior null
pub fn load_theme(name: Option<&str>, size: u32, shm: &WlShm) -> CursorTheme {
    let ptr = if let Some(theme) = name {
        let cstr = CString::new(theme).expect("Theme name contained an interior null.");
        unsafe {
            ffi_dispatch!(WAYLAND_CURSOR_HANDLE, wl_cursor_theme_load, cstr.as_ptr(), size as c_int, shm.ptr())
        }
    } else {
        unsafe {
            ffi_dispatch!(WAYLAND_CURSOR_HANDLE, wl_cursor_theme_load, ptr::null(), size as c_int, shm.ptr())
        }
    };

    assert!(!ptr.is_null(), "Memory allocation failure while loading a theme.");

    CursorTheme {
        theme: ptr
    }
}

impl CursorTheme {
    /// Retrieve a cursor from the theme.
    ///
    /// Returns `None` if this cursor is not provided by the theme.
    ///
    /// Panics if the name contains an interior null.
    pub fn get_cursor(&self, name: &str) -> Option<Cursor> {
        let cstr = CString::new(name).expect("Cursor name contained an interior null.");
        let ptr = unsafe {
            ffi_dispatch!(WAYLAND_CURSOR_HANDLE, wl_cursor_theme_get_cursor, self.theme, cstr.as_ptr())
        };
        if ptr.is_null() {
            None
        } else {
            Some(Cursor {
                _theme: PhantomData,
                cursor: ptr
            })
        }
    }
}

impl Drop for CursorTheme {
    fn drop(&mut self) {
        unsafe {
            ffi_dispatch!(WAYLAND_CURSOR_HANDLE, wl_cursor_theme_destroy, self.theme);
        }
    }
}

/// A cursor from a theme. Can contain several images if animated.
pub struct Cursor<'a> {
    _theme: PhantomData<&'a CursorTheme>,
    cursor: *mut wl_cursor
}

impl<'a> Cursor<'a> {
    /// Retrieve the name of this cursor.
    pub fn name(&self) -> String {
        let name = unsafe { CStr::from_ptr((*self.cursor).name) };
        name.to_string_lossy().into_owned()
    }

    /// Retrieve the number of images contained in this
    /// animated cursor
    pub fn image_count(&self) -> usize {
        let count = unsafe { (*self.cursor).image_count };
        count as usize
    }

    /// Retrieve the image number of cursor animation.
    ///
    /// Returns the image number of the animation that should be displayed
    /// after a given amount of time since the beginning of the animation,
    /// in milliseconds.
    pub fn frame(&self, duration: u32) -> usize {
        let frame = unsafe {
            ffi_dispatch!(WAYLAND_CURSOR_HANDLE, wl_cursor_frame, self.cursor, duration)
        };
        frame as usize
    }

    /// Retrieve the image number and its duration.
    ///
    /// Same as `frame()`, but also returns the number of milliseconds this
    /// frame should still be displayed.
    pub fn frame_and_duration(&self, duration: u32) -> (usize, u32) {
        let mut out_duration = 0u32;
        let frame = unsafe {
            ffi_dispatch!(WAYLAND_CURSOR_HANDLE, wl_cursor_frame_and_duration,
                self.cursor, duration, &mut out_duration as *mut u32)
        } as usize;
        (frame, out_duration)
    }

    /// Retrieve a `CursorImageBuffer` containing the given image of an animation.
    ///
    /// It can be used to be attached to a surface as a classic `WlBuffer`.
    ///
    /// Returns `None` if the frame is out of bounds.
    ///
    /// Note: destroying this buffer (using the `destroy` method) will corrupt
    /// your theme data, so you might not want to do it.
    pub fn frame_buffer(&self, frame: usize) -> Option<CursorImageBuffer> {
        if frame >= self.image_count() {
            None
        } else {
            unsafe {
                let image = *(*self.cursor).images.offset(frame as isize);
                let ptr = ffi_dispatch!(WAYLAND_CURSOR_HANDLE, wl_cursor_image_get_buffer, image);
                // init the user_data only once
                let data = {
                    use wayland_sys::client::*;
                    ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_user_data, ptr)
                };
                let buffer = if data.is_null() {
                    Proxy::from_ptr_new(ptr)
                } else {
                    Proxy::from_ptr_initialized(ptr)
                };

                Some(CursorImageBuffer {
                    _cursor: PhantomData,
                    buffer: buffer
                })
            }
        }
    }

    /// Retrive the metadate associated with given frame of the animation.
    ///
    /// The tuple contains: `(width, height, hotspot_x, hotspot_y, delay)`
    ///
    /// Returns `None` if the frame is out of bounds.
    pub fn frame_info(&self, frame: usize) -> Option<(u32, u32, u32, u32, u32)> {
        if frame >= self.image_count() {
            None
        } else {
            let image = unsafe { &**(*self.cursor).images.offset(frame as isize) };
            Some((image.width, image.height, image.hotspot_x, image.hotspot_y, image.delay))
        }
    }
}

/// A buffer containing a cursor image.
pub struct CursorImageBuffer<'a> {
    _cursor: PhantomData<&'a Cursor<'a>>,
    buffer: WlBuffer
}

impl<'a> Deref for CursorImageBuffer<'a> {
    type Target = WlBuffer;
    fn deref(&self) -> &WlBuffer {
        &self.buffer
    }
}

<commit_msg>client: cursor API is Send<commit_after>//! Cursor utilities
//!
//! This module contains bindings to the `libwayland-cursor.so` library.
//!
//! These utilities allows you to laod cursor images in order to match
//! your cursors to the ones of the system.
//!
//! First of all, the function `load_theme` will allow you to load a
//! `CursorTheme`, which represents the full cursor theme.
//!
//! From this theme, you can load a specific `Cursor`, which can each
//! contain several images if the cursor is animated. It provides you
//! with the means of knowing which frame of the animation shoudl be
//! displayed at which time, as well as handles to the buffers containing
//! these frames, to attach them to a wayland surface.

use std::ffi::{CString, CStr};
use std::marker::PhantomData;
use std::ops::Deref;
use std::ptr;

use wayland_sys::cursor::*;
use std::os::raw::c_int;

use Proxy;
use protocol::wl_shm::WlShm;
use protocol::wl_buffer::WlBuffer;

/// Checks if the wayland-cursor lib is available and can be used
///
/// Trying to call any function of this module if the lib cannot
/// be used will result in a panic.
pub fn is_available() -> bool {
    is_lib_available()
}

/// Represents a cursor theme loaded from the system.
pub struct CursorTheme {
    theme: *mut wl_cursor_theme
}

unsafe impl Send for CursorTheme { }

/// Attempts to load a cursor theme from given name.
///
/// If no name is given or the requested theme is not found, will
/// load the default theme.
///
/// Other arguments are the requested size for the cursor images (ex: 16)
/// and a handle to the global `WlShm` object.
///
/// Panics:
///
/// - If the `wayland-cursor` lib is not available (see `is_available()` function)
///   in this module.
/// - In case of memory allocation failure.
/// - If the theme name provided as argument contains an interior null
pub fn load_theme(name: Option<&str>, size: u32, shm: &WlShm) -> CursorTheme {
    let ptr = if let Some(theme) = name {
        let cstr = CString::new(theme).expect("Theme name contained an interior null.");
        unsafe {
            ffi_dispatch!(WAYLAND_CURSOR_HANDLE, wl_cursor_theme_load, cstr.as_ptr(), size as c_int, shm.ptr())
        }
    } else {
        unsafe {
            ffi_dispatch!(WAYLAND_CURSOR_HANDLE, wl_cursor_theme_load, ptr::null(), size as c_int, shm.ptr())
        }
    };

    assert!(!ptr.is_null(), "Memory allocation failure while loading a theme.");

    CursorTheme {
        theme: ptr
    }
}

impl CursorTheme {
    /// Retrieve a cursor from the theme.
    ///
    /// Returns `None` if this cursor is not provided by the theme.
    ///
    /// Panics if the name contains an interior null.
    pub fn get_cursor(&self, name: &str) -> Option<Cursor> {
        let cstr = CString::new(name).expect("Cursor name contained an interior null.");
        let ptr = unsafe {
            ffi_dispatch!(WAYLAND_CURSOR_HANDLE, wl_cursor_theme_get_cursor, self.theme, cstr.as_ptr())
        };
        if ptr.is_null() {
            None
        } else {
            Some(Cursor {
                _theme: PhantomData,
                cursor: ptr
            })
        }
    }
}

impl Drop for CursorTheme {
    fn drop(&mut self) {
        unsafe {
            ffi_dispatch!(WAYLAND_CURSOR_HANDLE, wl_cursor_theme_destroy, self.theme);
        }
    }
}

/// A cursor from a theme. Can contain several images if animated.
pub struct Cursor<'a> {
    _theme: PhantomData<&'a CursorTheme>,
    cursor: *mut wl_cursor
}

unsafe impl<'a> Send for Cursor<'a> { }

impl<'a> Cursor<'a> {
    /// Retrieve the name of this cursor.
    pub fn name(&self) -> String {
        let name = unsafe { CStr::from_ptr((*self.cursor).name) };
        name.to_string_lossy().into_owned()
    }

    /// Retrieve the number of images contained in this
    /// animated cursor
    pub fn image_count(&self) -> usize {
        let count = unsafe { (*self.cursor).image_count };
        count as usize
    }

    /// Retrieve the image number of cursor animation.
    ///
    /// Returns the image number of the animation that should be displayed
    /// after a given amount of time since the beginning of the animation,
    /// in milliseconds.
    pub fn frame(&self, duration: u32) -> usize {
        let frame = unsafe {
            ffi_dispatch!(WAYLAND_CURSOR_HANDLE, wl_cursor_frame, self.cursor, duration)
        };
        frame as usize
    }

    /// Retrieve the image number and its duration.
    ///
    /// Same as `frame()`, but also returns the number of milliseconds this
    /// frame should still be displayed.
    pub fn frame_and_duration(&self, duration: u32) -> (usize, u32) {
        let mut out_duration = 0u32;
        let frame = unsafe {
            ffi_dispatch!(WAYLAND_CURSOR_HANDLE, wl_cursor_frame_and_duration,
                self.cursor, duration, &mut out_duration as *mut u32)
        } as usize;
        (frame, out_duration)
    }

    /// Retrieve a `CursorImageBuffer` containing the given image of an animation.
    ///
    /// It can be used to be attached to a surface as a classic `WlBuffer`.
    ///
    /// Returns `None` if the frame is out of bounds.
    ///
    /// Note: destroying this buffer (using the `destroy` method) will corrupt
    /// your theme data, so you might not want to do it.
    pub fn frame_buffer(&self, frame: usize) -> Option<CursorImageBuffer> {
        if frame >= self.image_count() {
            None
        } else {
            unsafe {
                let image = *(*self.cursor).images.offset(frame as isize);
                let ptr = ffi_dispatch!(WAYLAND_CURSOR_HANDLE, wl_cursor_image_get_buffer, image);
                // init the user_data only once
                let data = {
                    use wayland_sys::client::*;
                    ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_user_data, ptr)
                };
                let buffer = if data.is_null() {
                    Proxy::from_ptr_new(ptr)
                } else {
                    Proxy::from_ptr_initialized(ptr)
                };

                Some(CursorImageBuffer {
                    _cursor: PhantomData,
                    buffer: buffer
                })
            }
        }
    }

    /// Retrive the metadate associated with given frame of the animation.
    ///
    /// The tuple contains: `(width, height, hotspot_x, hotspot_y, delay)`
    ///
    /// Returns `None` if the frame is out of bounds.
    pub fn frame_info(&self, frame: usize) -> Option<(u32, u32, u32, u32, u32)> {
        if frame >= self.image_count() {
            None
        } else {
            let image = unsafe { &**(*self.cursor).images.offset(frame as isize) };
            Some((image.width, image.height, image.hotspot_x, image.hotspot_y, image.delay))
        }
    }
}

/// A buffer containing a cursor image.
pub struct CursorImageBuffer<'a> {
    _cursor: PhantomData<&'a Cursor<'a>>,
    buffer: WlBuffer
}

unsafe impl<'a> Send for CursorImageBuffer<'a> { }

impl<'a> Deref for CursorImageBuffer<'a> {
    type Target = WlBuffer;
    fn deref(&self) -> &WlBuffer {
        &self.buffer
    }
}

<|endoftext|>


<commit_before>// Copyright 2017 CoreOS, Inc.
//
// 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.

//! vagrant/virtualbox metadata fetcher

use std::collections::HashMap;
use std::net::IpAddr;
use std::thread;
use std::time::Duration;

use hostname;
use openssh_keys::PublicKey;
use pnet_datalink;
use slog_scope::{info, warn};

use crate::errors::*;
use crate::network;
use crate::providers::MetadataProvider;

#[derive(Clone, Copy, Debug)]
pub struct VagrantVirtualboxProvider;

impl VagrantVirtualboxProvider {
    pub fn new() -> VagrantVirtualboxProvider {
        VagrantVirtualboxProvider
    }

    fn get_ip() -> Result<String> {
        let max_attempts = 30;
        for _ in 0..max_attempts {
            let iface = VagrantVirtualboxProvider::find_eth1();
            if let Some(iface) = iface {
                for a in iface.ips {
                    if let IpAddr::V4(a) = a.ip() {
                        return Ok(format!("{}", a));
                    }
                }
            }
            info!("eth1 not found or is lacking an ipv4 address; waiting 2 seconds");
            thread::sleep(Duration::from_secs(2));
        }
        Err("eth1 was not found!".into())
    }

    fn find_eth1() -> Option<pnet_datalink::NetworkInterface> {
        let mut ifaces = pnet_datalink::interfaces();
        ifaces.retain(|i| i.name == "eth1");
        if !ifaces.is_empty() {
            Some(ifaces[0].clone())
        } else {
            None
        }
    }
}

impl MetadataProvider for VagrantVirtualboxProvider {
    fn attributes(&self) -> Result<HashMap<String, String>> {
        let mut out = HashMap::with_capacity(2);

        let hostname = hostname::get_hostname().ok_or("unable to get hostname")?;
        let ip = VagrantVirtualboxProvider::get_ip()?;

        out.insert("VAGRANT_VIRTUALBOX_HOSTNAME".to_string(), hostname);
        out.insert("VAGRANT_VIRTUALBOX_PRIVATE_IPV4".to_string(), ip);

        Ok(out)
    }

    fn hostname(&self) -> Result<Option<String>> {
        Ok(hostname::get_hostname())
    }

    fn ssh_keys(&self) -> Result<Vec<PublicKey>> {
        Ok(vec![])
    }

    fn networks(&self) -> Result<Vec<network::Interface>> {
        Ok(vec![])
    }

    fn network_devices(&self) -> Result<Vec<network::Device>> {
        Ok(vec![])
    }

    fn boot_checkin(&self) -> Result<()> {
        warn!("boot check-in requested, but not supported on this platform");
        Ok(())
    }
}
<commit_msg>providers/vagrant: fix deprecated calls<commit_after>// Copyright 2017 CoreOS, Inc.
//
// 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.

//! vagrant/virtualbox metadata fetcher

use std::collections::HashMap;
use std::net::IpAddr;
use std::thread;
use std::time::Duration;

use hostname;
use openssh_keys::PublicKey;
use pnet_datalink;
use slog_scope::{info, warn};

use crate::errors::*;
use crate::network;
use crate::providers::MetadataProvider;

#[derive(Clone, Copy, Debug)]
pub struct VagrantVirtualboxProvider;

impl VagrantVirtualboxProvider {
    pub fn new() -> VagrantVirtualboxProvider {
        VagrantVirtualboxProvider
    }

    fn get_ip() -> Result<String> {
        let max_attempts = 30;
        for _ in 0..max_attempts {
            let iface = VagrantVirtualboxProvider::find_eth1();
            if let Some(iface) = iface {
                for a in iface.ips {
                    if let IpAddr::V4(a) = a.ip() {
                        return Ok(format!("{}", a));
                    }
                }
            }
            info!("eth1 not found or is lacking an ipv4 address; waiting 2 seconds");
            thread::sleep(Duration::from_secs(2));
        }
        Err("eth1 was not found!".into())
    }

    fn find_eth1() -> Option<pnet_datalink::NetworkInterface> {
        let mut ifaces = pnet_datalink::interfaces();
        ifaces.retain(|i| i.name == "eth1");
        if !ifaces.is_empty() {
            Some(ifaces[0].clone())
        } else {
            None
        }
    }
}

impl MetadataProvider for VagrantVirtualboxProvider {
    fn attributes(&self) -> Result<HashMap<String, String>> {
        let mut out = HashMap::with_capacity(2);

        let hostname = hostname::get()
            .chain_err(|| "unable to get hostname")?
            .to_string_lossy()
            .into_owned();
        let ip = VagrantVirtualboxProvider::get_ip()?;

        out.insert("VAGRANT_VIRTUALBOX_HOSTNAME".to_string(), hostname);
        out.insert("VAGRANT_VIRTUALBOX_PRIVATE_IPV4".to_string(), ip);

        Ok(out)
    }

    fn hostname(&self) -> Result<Option<String>> {
        let hostname = hostname::get()
            .chain_err(|| "unable to get hostname")?
            .to_string_lossy()
            .into_owned();
        Ok(Some(hostname))
    }

    fn ssh_keys(&self) -> Result<Vec<PublicKey>> {
        Ok(vec![])
    }

    fn networks(&self) -> Result<Vec<network::Interface>> {
        Ok(vec![])
    }

    fn network_devices(&self) -> Result<Vec<network::Device>> {
        Ok(vec![])
    }

    fn boot_checkin(&self) -> Result<()> {
        warn!("boot check-in requested, but not supported on this platform");
        Ok(())
    }
}
<|endoftext|>


<commit_before>
extern crate rand;
// extern crate time;

// use time::PreciseTime;
use std::net::{Ipv4Addr, SocketAddrV4, UdpSocket};
use file_stream_iter::{FileStreamReader, FileStreamWriter};
use std::io::{ErrorKind, Error};
use tftp_specific::{ErrorCode, PacketType};
use std::str::FromStr;
use std::net::AddrParseError;
use std::error;
use std::str;
use std::path::Path;
use std::time::Duration;
use utils;

pub struct EndPoint {
    local_connection: SocketAddrV4,
    // A server doesn't need a remote_connection
    remote_connection: Option<SocketAddrV4>,
}

impl EndPoint {
    pub fn new(remote: &str, port: &str, is_server: bool) -> Result<EndPoint, AddrParseError> {

        let ipv4 = try!(get_ip_from(remote));
        if is_server {
            Ok(EndPoint {
                local_connection: SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 6900),
                remote_connection: None,
            })
        } else {
            Ok(EndPoint {
                local_connection: SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 9990),
                remote_connection: Some(SocketAddrV4::new(ipv4, 6900)),
            })
        }
    }

    pub fn start_listen(&mut self) -> Result<(), Error> {
        // Bind the socket
        let socket = try!(UdpSocket::bind(self.local_connection));

        // Start servicing requests from a client
        // Read from the socket
        let mut buf = [0u8; 516]; //UDP packet is 516 bytes
        let (amt, src) = try!(socket.recv_from(&mut buf));
        let mut last_blk_id = 0u16;
        match buf[1] {
            1 => {
                // RRQ
                println!("RRQ received");
                // Get filename to be sent from the packet
                let i = utils::get_terminator_position(&buf[2..]);
                let filename = str::from_utf8(&buf[2..i]);
                println!("file requested: {}", filename.unwrap());
                // Send data via the socket
                let mut fs = FileStreamReader::new(String::from(filename.unwrap())).unwrap();
                let (mut buf, num_bytes_read) = fs.next().unwrap();
                let v = self.create_data_packet(last_blk_id, &buf, num_bytes_read);
                let mut time_out = 3; //3 secs
                socket.set_read_timeout(Some(Duration::new(time_out, 0)));
                try!(socket.send_to(v.as_slice(), src));
                // TODO start timer here
                loop {
                    // Get ACK
                    match socket.recv_from(&mut buf){
                        Ok((amt, src)) => {
                            if buf[1] == 4 {
                                println!("ACK received");
                                //TODO verify the ACK received was for the last block id
                                last_blk_id += 1;
                                let (buf, num_bytes_read) = fs.next().unwrap();
                                let v = self.create_data_packet(last_blk_id, &buf, num_bytes_read);
                                try!(socket.send_to(v.as_slice(), src));
                            }
                        },
                        Err(ref e) if e.kind() == ErrorKind::TimedOut => {
                            time_out += 3;
                            socket.set_read_timeout(Some(Duration::new(time_out, 0)));
                        },
                        Err(e) => {

                        }
                    }
                }
            },
            2 => {
                //WRQ
                println!("WRQ received");
                let i = utils::get_terminator_position(&buf[2..]);

                //TODO fix the vec use to copy slice from buf
                let mut v = vec![];
                v.copy_from_slice(&buf[2..i]);
                let filename = str::from_utf8(v.as_slice());
                println!("file requested: {}", filename.unwrap());
                let mut writer = FileStreamWriter::new(String::from(filename.unwrap())).unwrap();
                //send ACK
                let mut block_num = 0u16;
                let mut time_out = 3;
                loop{
                    let low = block_num & 0x00FF;
                    let high = (block_num & 0xFF00) >> 8;

                    println!("Sending ACK");
                    socket.send_to(&[0, PacketType::ACK as u8, high as u8, low as u8], src);

                    Self::clear_buf(&mut buf);
                    match socket.recv_from(&mut buf){
                        Ok((amt, src)) => {
                            writer.append(&mut buf);
                            if amt - 4 < 512{
                                writer.close();
                                break;
                            }
                            block_num += 1;
                        },
                        Err(ref e) if e.kind() == ErrorKind::TimedOut => {
                            time_out += 3;
                            socket.set_read_timeout(Some(Duration::new(time_out, 0)));
                        },
                        Err(e) => {}  // bail out
                    }
                }

            },
            4 => {}
            _ => panic!("unrecognized packet type"),
        }

        Ok(())

    }

    fn create_error_packet(&mut self, error_code: ErrorCode, err_msg : &str)->Vec<u8>{
        let mut v = Vec::with_capacity(2+2+err_msg.len()+1);
        v.push(0);
        v.push(PacketType::ERROR as u8);
        v.push(0);
        v.push(error_code as u8);
        v.extend_from_slice(err_msg.as_bytes());
        v.push('\0' as u8);
        v
    }

    fn clear_buf(buf : &mut[u8]){
        assert!(buf.len() == 516);
        for i in 0..516{
            buf[i] = 0;
        }
    }

    fn create_data_packet(&mut self, blk_id: u16, buf: &[u8], num_bytes: usize) -> Vec<u8> {
        let mut v = Vec::with_capacity(num_bytes + 4);
        v.push(0);
        v.push(PacketType::DATA as u8);
        v.push((blk_id >> 8) as u8);
        v.push((blk_id & 0x00FF) as u8);
        v.extend_from_slice(&buf[0..num_bytes]);
        v
    }

    fn create_rrq_wrq_packet(&self,
                             p_type: PacketType,
                             file_name: &str,
                             mode: &'static str)
                             -> Vec<u8> {
        let mut v = Vec::with_capacity(2 + file_name.len() + 1 + mode.len() + 1);
        v.push(0);
        v.push(p_type as u8);
        v.extend(file_name.as_bytes());
        v.push('\0' as u8);
        v.extend(mode.as_bytes());
        v.push('\0' as u8);//zero terminator
        v
    }

    pub fn get(&mut self, files: &[&str], mode: &'static str) -> Result<(), Error> {
        let socket = try!(UdpSocket::bind(self.local_connection));
        let mut buf = [0; 516];
        for file in files {
            // start with a RRQ
            println!("sending RRQ request");
            let packet = self.create_rrq_wrq_packet(PacketType::RRQ, file, mode);
            try!(socket.send_to(packet.as_slice(), self.remote_connection.unwrap()));
            // TODO remove the hardcoded filename
            let path = Path::new(file);

            println!("Downloading as ./{}", path.file_name().unwrap().to_str().unwrap());
            //TODO fix downloading very file in the current dir
            let mut writer =
                FileStreamWriter::new(format!("./{}", path.file_name().unwrap().to_str().unwrap()))
                    .unwrap();

            loop {
                // get the first block of the requested file
                let (amt, src) = try!(socket.recv_from(&mut buf));
                println!("Received block");
                println!("Total bytes read {}", amt);

                match buf[1] {
                    3 => {
                        let block_size = amt - 4;
                        println!("File block size is {:?}", block_size);
                        if block_size == 0 {
                            println!("Empty block recvd");
                            writer.close();
                            break;
                        }
                        println!("Appending to file");
                        writer.append(&buf[4..4 + block_size]);
                        let block_num: u16 = 0u16 | (buf[2] as u16) << 8 | buf[3] as u16;

                        // send ACK
                        let low = block_num & 0x00FF;
                        let high = (block_num & 0xFF00) >> 8;

                        println!("Sending ACK");
                        socket.send_to(&[0, PacketType::ACK as u8, high as u8, low as u8], src);

                    }
                    _ => {}
                }
                // Flush buf for next read
                // TODO fix this:
                for i in 0..516 {
                    buf[0] = 0;
                }
            }

        }

        Ok(())
    }
}

fn get_ip_from(ip: &str) -> Result<Ipv4Addr, AddrParseError> {
    Ipv4Addr::from_str(ip)
}
<commit_msg>Fix slice to str conversion using the right end range value<commit_after>
extern crate rand;
// extern crate time;

// use time::PreciseTime;
use std::net::{Ipv4Addr, SocketAddrV4, UdpSocket};
use file_stream_iter::{FileStreamReader, FileStreamWriter};
use std::io::{ErrorKind, Error};
use tftp_specific::{ErrorCode, PacketType};
use std::str::FromStr;
use std::net::AddrParseError;
use std::error;
use std::str;
use std::path::Path;
use std::time::Duration;
use utils;

pub struct EndPoint {
    local_connection: SocketAddrV4,
    // A server doesn't need a remote_connection
    remote_connection: Option<SocketAddrV4>,
}

impl EndPoint {
    pub fn new(remote: &str, port: &str, is_server: bool) -> Result<EndPoint, AddrParseError> {

        let ipv4 = try!(get_ip_from(remote));
        if is_server {
            Ok(EndPoint {
                local_connection: SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 6900),
                remote_connection: None,
            })
        } else {
            Ok(EndPoint {
                local_connection: SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 9990),
                remote_connection: Some(SocketAddrV4::new(ipv4, 6900)),
            })
        }
    }

    pub fn start_listen(&mut self) -> Result<(), Error> {
        // Bind the socket
        let socket = try!(UdpSocket::bind(self.local_connection));

        // Start servicing requests from a client
        // Read from the socket
        let mut buf = [0u8; 516]; //UDP packet is 516 bytes
        let (amt, src) = try!(socket.recv_from(&mut buf));
        let mut last_blk_id = 0u16;
        match buf[1] {
            1 => {
                // RRQ
                println!("RRQ received");
                // Get filename to be sent from the packet
                let i = utils::get_terminator_position(&buf[2..amt-2]);
                let filename = str::from_utf8(&buf[2..2+i]);
                println!("file requested: {}", filename.unwrap());
                // Send data via the socket
                let mut fs = FileStreamReader::new(String::from(filename.unwrap())).unwrap();
                let (mut buf, num_bytes_read) = fs.next().unwrap();
                let v = self.create_data_packet(last_blk_id, &buf, num_bytes_read);
                let mut time_out = 3; //3 secs
                socket.set_read_timeout(Some(Duration::new(time_out, 0)));
                try!(socket.send_to(v.as_slice(), src));
                // TODO start timer here
                loop {
                    // Get ACK
                    match socket.recv_from(&mut buf){
                        Ok((amt, src)) => {
                            if buf[1] == 4 {
                                println!("ACK received");
                                //TODO verify the ACK received was for the last block id
                                last_blk_id += 1;
                                let (buf, num_bytes_read) = fs.next().unwrap();
                                let v = self.create_data_packet(last_blk_id, &buf, num_bytes_read);
                                try!(socket.send_to(v.as_slice(), src));
                            }
                        },
                        Err(ref e) if e.kind() == ErrorKind::TimedOut => {
                            time_out += 3;
                            socket.set_read_timeout(Some(Duration::new(time_out, 0)));
                        },
                        Err(e) => {

                        }
                    }
                }
            },
            2 => {
                //WRQ
                println!("WRQ received");
                let i = utils::get_terminator_position(&buf[2..]);

                //TODO fix the vec use to copy slice from buf
                let mut v = vec![];
                v.copy_from_slice(&buf[2..i]);
                let filename = str::from_utf8(v.as_slice());
                println!("file requested: {}", filename.unwrap());
                let mut writer = FileStreamWriter::new(String::from(filename.unwrap())).unwrap();
                //send ACK
                let mut block_num = 0u16;
                let mut time_out = 3;
                loop{
                    let low = block_num & 0x00FF;
                    let high = (block_num & 0xFF00) >> 8;

                    println!("Sending ACK");
                    socket.send_to(&[0, PacketType::ACK as u8, high as u8, low as u8], src);

                    Self::clear_buf(&mut buf);
                    match socket.recv_from(&mut buf){
                        Ok((amt, src)) => {
                            writer.append(&mut buf);
                            if amt - 4 < 512{
                                writer.close();
                                break;
                            }
                            block_num += 1;
                        },
                        Err(ref e) if e.kind() == ErrorKind::TimedOut => {
                            time_out += 3;
                            socket.set_read_timeout(Some(Duration::new(time_out, 0)));
                        },
                        Err(e) => {}  // bail out
                    }
                }

            },
            4 => {}
            _ => panic!("unrecognized packet type"),
        }

        Ok(())

    }

    fn create_error_packet(&mut self, error_code: ErrorCode, err_msg : &str)->Vec<u8>{
        let mut v = Vec::with_capacity(2+2+err_msg.len()+1);
        v.push(0);
        v.push(PacketType::ERROR as u8);
        v.push(0);
        v.push(error_code as u8);
        v.extend_from_slice(err_msg.as_bytes());
        v.push('\0' as u8);
        v
    }

    fn clear_buf(buf : &mut[u8]){
        assert!(buf.len() == 516);
        for i in 0..516{
            buf[i] = 0;
        }
    }

    fn create_data_packet(&mut self, blk_id: u16, buf: &[u8], num_bytes: usize) -> Vec<u8> {
        let mut v = Vec::with_capacity(num_bytes + 4);
        v.push(0);
        v.push(PacketType::DATA as u8);
        v.push((blk_id >> 8) as u8);
        v.push((blk_id & 0x00FF) as u8);
        v.extend_from_slice(&buf[0..num_bytes]);
        v
    }

    fn create_rrq_wrq_packet(&self,
                             p_type: PacketType,
                             file_name: &str,
                             mode: &'static str)
                             -> Vec<u8> {
        let mut v = Vec::with_capacity(2 + file_name.len() + 1 + mode.len() + 1);
        v.push(0);
        v.push(p_type as u8);
        v.extend(file_name.as_bytes());
        v.push('\0' as u8);
        v.extend(mode.as_bytes());
        v.push('\0' as u8);//zero terminator
        v
    }

    pub fn get(&mut self, files: &[&str], mode: &'static str) -> Result<(), Error> {
        let socket = try!(UdpSocket::bind(self.local_connection));
        let mut buf = [0; 516];
        for file in files {
            // start with a RRQ
            println!("sending RRQ request");
            let packet = self.create_rrq_wrq_packet(PacketType::RRQ, file, mode);
            try!(socket.send_to(packet.as_slice(), self.remote_connection.unwrap()));
            // TODO remove the hardcoded filename
            let path = Path::new(file);

            println!("Downloading as ./{}", path.file_name().unwrap().to_str().unwrap());
            //TODO fix downloading very file in the current dir
            let mut writer =
                FileStreamWriter::new(format!("./{}", path.file_name().unwrap().to_str().unwrap()))
                    .unwrap();

            loop {
                // get the first block of the requested file
                let (amt, src) = try!(socket.recv_from(&mut buf));
                println!("Received block");
                println!("Total bytes read {}", amt);

                match buf[1] {
                    3 => {
                        let block_size = amt - 4;
                        println!("File block size is {:?}", block_size);
                        if block_size == 0 {
                            println!("Empty block recvd");
                            writer.close();
                            break;
                        }
                        println!("Appending to file");
                        writer.append(&buf[4..4 + block_size]);
                        let block_num: u16 = 0u16 | (buf[2] as u16) << 8 | buf[3] as u16;

                        // send ACK
                        let low = block_num & 0x00FF;
                        let high = (block_num & 0xFF00) >> 8;

                        println!("Sending ACK");
                        socket.send_to(&[0, PacketType::ACK as u8, high as u8, low as u8], src);

                    }
                    _ => {}
                }
                // Flush buf for next read
                // TODO fix this:
                for i in 0..516 {
                    buf[0] = 0;
                }
            }

        }

        Ok(())
    }
}

fn get_ip_from(ip: &str) -> Result<Ipv4Addr, AddrParseError> {
    Ipv4Addr::from_str(ip)
}
<|endoftext|>


<commit_before>//! This module contains a platform specific implementation of the window shell.

use std::{
    cell::{Cell, RefCell},
    char,
    collections::HashMap,
    rc::Rc,
    sync::Mutex,
};

#[cfg(not(target_os = "redox"))]
use minifb;

#[cfg(target_os = "redox")]
use minifb_fix as minifb;

use spin_sleep::LoopHelper;

use crate::{prelude::*, render::*, utils::*};

pub fn initialize() {}

fn key_event_helper(key: &mut KeyHelper, adapter: &mut A, window: &minifb::Window)
where
    A: WindowAdapter,
{
    if !key.0 && window.is_key_pressed(key.1, minifb::KeyRepeat::Yes) {
        adapter.key_event(KeyEvent {
            key: key.2,
            state: ButtonState::Down,
            text: String::new(),
        });

        key.0 = true;
    } else {
        key.0 = false;
    }
}

fn unicode_to_key_event(uni_char: u32) -> Option<KeyEvent> {
    let mut text = String::new();
    let mut key = Key::Unknown;

    if let Some(character) = char::from_u32(uni_char) {
        if !character.is_control() {
            text = character.to_string();
            key = Key::from(character);
        }
    }

    if key == Key::Up || key == Key::Down || key == Key::Left || key == Key::Right || Key::Backspace {
        return None;
    }

    Some(KeyEvent {
        key,
        state: ButtonState::Down,
        text,
    })
}

struct KeyInputCallBack {
    key_events: Rc<RefCell<Vec<KeyEvent>>>,
}

impl minifb::InputCallback for KeyInputCallBack {
    fn add_char(&mut self, uni_char: u32) {
        if let Some(key_event) = unicode_to_key_event(uni_char) {
            self.key_events.borrow_mut().push(key_event);
        }
    }
}

struct KeyHelper(bool, minifb::Key, Key);

/// Concrete implementation of the window shell.
pub struct WindowShell
where
    A: WindowAdapter,
{
    window: minifb::Window,
    render_context_2_d: RenderContext2D,
    adapter: A,
    mouse_pos: (f32, f32),
    button_down: (bool, bool, bool),
    window_size: (usize, usize),
    key_events: Rc<RefCell<Vec<KeyEvent>>>,
    // todo: temp solution
    key_backspace: KeyHelper,
    key_delete: KeyHelper,
    key_left: KeyHelper,
    key_right: KeyHelper,
    key_up: KeyHelper,
    key_down: KeyHelper,
    key_enter: KeyHelper,
    key_control: KeyHelper,
    key_control_right: KeyHelper,
    key_shift_l: KeyHelper,
    key_shift_r: KeyHelper,
    key_alt: KeyHelper,
    key_alt_r: KeyHelper,
    key_escape: KeyHelper,
    key_home: KeyHelper,
}

impl WindowShell
where
    A: WindowAdapter,
{
    /// Creates a new window shell with an adapter.
    pub fn new(
        window: minifb::Window,
        adapter: A,
        key_events: Rc<RefCell<Vec<KeyEvent>>>,
    ) -> WindowShell {
        let size = window.get_size();
        let render_context_2_d = RenderContext2D::new(size.0 as f64, size.1 as f64);

        WindowShell {
            window,
            // window_size: window_size,
            // mouse_buttons: (false, false, false),
            // mouse_position: Point::default(),
            render_context_2_d,
            adapter,
            mouse_pos: (0.0, 0.0),
            window_size: size,
            button_down: (false, false, false),
            key_events,
            key_backspace: KeyHelper(false, minifb::Key::Backspace, Key::Backspace),
            key_left: KeyHelper(false, minifb::Key::Left, Key::Left),
            key_right: KeyHelper(false, minifb::Key::Right, Key::Right),
            key_up: KeyHelper(false, minifb::Key::Up, Key::Up),
            key_down: KeyHelper(false, minifb::Key::Down, Key::Down),
            key_delete: KeyHelper(false, minifb::Key::Delete, Key::Delete),
            key_enter: KeyHelper(false, minifb::Key::Enter, Key::Enter),
            key_control: KeyHelper(false, minifb::Key::LeftCtrl, Key::Control),
            key_control_right: KeyHelper(false, minifb::Key::RightCtrl, Key::Control),
            key_shift_l: KeyHelper(false, minifb::Key::LeftShift, Key::ShiftL),
            key_shift_r: KeyHelper(false, minifb::Key::RightShift, Key::ShiftR),
            key_alt: KeyHelper(false, minifb::Key::LeftAlt, Key::Alt),
            key_alt_r: KeyHelper(false, minifb::Key::RightAlt, Key::Alt),
            key_escape: KeyHelper(false, minifb::Key::Escape, Key::Escape),
            key_home: KeyHelper(false, minifb::Key::Home, Key::Home),
        }
    }

    /// Gets the shell adapter.
    pub fn adapter(&mut self) -> &mut A {
        &mut self.adapter
    }

    /// Gets the render ctx 2D.
    pub fn render_context_2_d(&mut self) -> &mut RenderContext2D {
        &mut self.render_context_2_d
    }

    fn drain_events(&mut self) {
        // mouse move
        if let Some(pos) = self.window.get_mouse_pos(minifb::MouseMode::Discard) {
            if (pos.0.floor(), pos.1.floor()) != self.mouse_pos {
                self.adapter.mouse(pos.0 as f64, pos.1 as f64);
                self.mouse_pos = (pos.0.floor(), pos.1.floor());
            }
        }

        // mouse
        let left_button_down = self.window.get_mouse_down(minifb::MouseButton::Left);
        let middle_button_down = self.window.get_mouse_down(minifb::MouseButton::Middle);
        let right_button_down = self.window.get_mouse_down(minifb::MouseButton::Right);

        if left_button_down != self.button_down.0 {
            if left_button_down {
                self.push_mouse_event(true, MouseButton::Left);
            } else {
                self.push_mouse_event(false, MouseButton::Left);
            }
            self.button_down.0 = left_button_down;
        }

        if middle_button_down != self.button_down.1 {
            if middle_button_down {
                self.push_mouse_event(true, MouseButton::Middle);
            } else {
                self.push_mouse_event(false, MouseButton::Middle);
            }
            self.button_down.1 = middle_button_down;
        }

        if right_button_down != self.button_down.2 {
            if right_button_down {
                self.push_mouse_event(true, MouseButton::Right);
            } else {
                self.push_mouse_event(false, MouseButton::Right);
            }
            self.button_down.2 = right_button_down;
        }

        // scroll
        if let Some(delta) = self.window.get_scroll_wheel() {
            self.adapter.scroll(delta.0 as f64, delta.1 as f64);
        }

        // key
        while let Some(event) = self.key_events.borrow_mut().pop() {
            self.adapter.key_event(event);
        }

        key_event_helper(&mut self.key_backspace, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_delete, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_left, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_right, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_up, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_down, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_enter, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_control, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_control_right, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_shift_l, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_shift_r, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_alt, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_alt_r, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_escape, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_home, &mut self.adapter, &self.window);

        // resize
        if self.window_size != self.window.get_size() {
            self.window_size = self.window.get_size();
            self.render_context_2_d
                .resize(self.window_size.0 as f64, self.window_size.1 as f64);
            self.adapter
                .resize(self.window_size.0 as f64, self.window_size.1 as f64);
        }
    }

    fn push_mouse_event(&mut self, pressed: bool, button: MouseButton) {
        let state = if pressed {
            ButtonState::Down
        } else {
            ButtonState::Up
        };

        self.adapter.mouse_event(MouseEvent {
            x: self.mouse_pos.0 as f64,
            y: self.mouse_pos.1 as f64,
            button,
            state,
        });
    }

    pub fn flip(&mut self) -> bool {
        if let Some(data) = self.render_context_2_d.data() {
            self.window.update_with_buffer(data).unwrap();
            CONSOLE.time_end("render");
            return true;
        }

        false
    }
}

impl Drop for WindowShell
where
    A: WindowAdapter,
{
    fn drop(&mut self) {}
}

/// Implementation of the OrbClient based shell runner.
pub struct ShellRunner
where
    A: WindowAdapter,
{
    pub window_shell: Rc<RefCell<WindowShell>>,
    pub update: Rc<Cell<bool>>,
    pub running: Rc<Cell<bool>>,
    pub updater: Box<dyn Updater>,
}

impl ShellRunner
where
    A: WindowAdapter,
{
    pub fn run(&mut self) {
        let mut loop_helper = LoopHelper::builder()
            .report_interval_s(0.5)
            .build_with_target_rate(60.0);

        let mut _current_fps = None;

        loop {
            if !self.running.get() || !self.window_shell.borrow().window.is_open() {
                break;
            }

            let _delta = loop_helper.loop_start();

            if let Some(fps) = loop_helper.report_rate() {
                _current_fps = Some(fps);
                // println!("fps: {}", fps);
            }

            // CONSOLE.time("complete run");

            self.updater.update();

            if self.update.get() {
                self.update.set(false);
            }

            if !self.window_shell.borrow_mut().flip() {
                self.window_shell.borrow_mut().window.update();
            }

            self.window_shell.borrow_mut().drain_events();

            loop_helper.loop_sleep();
            // CONSOLE.time_end("complete run");
        }
    }
}

/// Constructs the window shell
pub struct WindowBuilder
where
    A: WindowAdapter,
{
    title: String,

    resizeable: bool,

    bounds: Rectangle,

    adapter: A,
}

impl WindowBuilder
where
    A: WindowAdapter,
{
    /// Create a new window builder with the given adapter.
    pub fn new(adapter: A) -> Self {
        WindowBuilder {
            adapter,
            title: String::default(),
            resizeable: false,
            bounds: Rectangle::default(),
        }
    }

    /// Sets the title.
    pub fn title(mut self, title: impl Into<String>) -> Self {
        self.title = title.into();
        self
    }

    /// Sets resizeable.
    pub fn resizeable(mut self, resizeable: bool) -> Self {
        self.resizeable = resizeable;
        self
    }

    /// Sets the bounds.
    pub fn bounds(mut self, bounds: impl Into<Rectangle>) -> Self {
        self.bounds = bounds.into();
        self
    }

    /// Builds the window shell.
    pub fn build(self) -> WindowShell {
        let window_options = minifb::WindowOptions {
            resize: self.resizeable,
            ..Default::default()
        };

        let mut window = minifb::Window::new(
            self.title.as_str(),
            self.bounds.width as usize,
            self.bounds.height as usize,
            window_options,
        )
        .unwrap_or_else(|e| {
            panic!("{}", e);
        });

        let key_events = Rc::new(RefCell::new(vec![]));

        window.set_input_callback(Box::new(KeyInputCallBack {
            key_events: key_events.clone(),
        }));

        window.set_position(self.bounds.x as isize, self.bounds.y as isize);

        WindowShell::new(window, self.adapter, key_events)
    }
}

use std::time::Instant;

lazy_static! {
    pub static ref CONSOLE: Console = Console {
        instants: Mutex::new(HashMap::new())
    };
}

pub struct Console {
    instants: Mutex<HashMap<String, Instant>>,
}

impl Console {
    pub fn time(&self, name: impl Into<String>) {
        self.instants
            .lock()
            .unwrap()
            .insert(name.into(), Instant::now());
    }

    pub fn time_end(&self, name: impl Into<String>) {
        if let Some((k, v)) = self.instants.lock().unwrap().remove_entry(&name.into()) {
            println!("{} {}ms - timer ended", k, v.elapsed().as_millis());
        }
    }

    pub fn log(&self, message: impl Into<String>) {
        println!("{}", message.into());
    }
}
<commit_msg>Adds backspace filter to unicode_to_key_event and Key::from branch for backspace<commit_after>//! This module contains a platform specific implementation of the window shell.

use std::{
    cell::{Cell, RefCell},
    char,
    collections::HashMap,
    rc::Rc,
    sync::Mutex,
};

#[cfg(not(target_os = "redox"))]
use minifb;

#[cfg(target_os = "redox")]
use minifb_fix as minifb;

use spin_sleep::LoopHelper;

use crate::{prelude::*, render::*, utils::*};

pub fn initialize() {}

fn key_event_helper(key: &mut KeyHelper, adapter: &mut A, window: &minifb::Window)
where
    A: WindowAdapter,
{
    if !key.0 && window.is_key_pressed(key.1, minifb::KeyRepeat::Yes) {
        adapter.key_event(KeyEvent {
            key: key.2,
            state: ButtonState::Down,
            text: String::new(),
        });

        key.0 = true;
    } else {
        key.0 = false;
    }
}

fn unicode_to_key_event(uni_char: u32) -> Option<KeyEvent> {
    let mut text = String::new();

    let key = if let Some(character) = char::from_u32(uni_char) {
        text = character.to_string();
        Key::from(character)
    } else {
        Key::Unknown
    };

    if key == Key::Up || key == Key::Down || key == Key::Left || key == Key::Right || key == Key::Backspace {
        return None;
    }

    Some(KeyEvent {
        key,
        state: ButtonState::Down,
        text,
    })
}

struct KeyInputCallBack {
    key_events: Rc<RefCell<Vec<KeyEvent>>>,
}

impl minifb::InputCallback for KeyInputCallBack {
    fn add_char(&mut self, uni_char: u32) {
        if let Some(key_event) = unicode_to_key_event(uni_char) {
            self.key_events.borrow_mut().push(key_event);
        }
    }
}

struct KeyHelper(bool, minifb::Key, Key);

/// Concrete implementation of the window shell.
pub struct WindowShell
where
    A: WindowAdapter,
{
    window: minifb::Window,
    render_context_2_d: RenderContext2D,
    adapter: A,
    mouse_pos: (f32, f32),
    button_down: (bool, bool, bool),
    window_size: (usize, usize),
    key_events: Rc<RefCell<Vec<KeyEvent>>>,
    // todo: temp solution
    key_backspace: KeyHelper,
    key_delete: KeyHelper,
    key_left: KeyHelper,
    key_right: KeyHelper,
    key_up: KeyHelper,
    key_down: KeyHelper,
    key_enter: KeyHelper,
    key_control: KeyHelper,
    key_control_right: KeyHelper,
    key_shift_l: KeyHelper,
    key_shift_r: KeyHelper,
    key_alt: KeyHelper,
    key_alt_r: KeyHelper,
    key_escape: KeyHelper,
    key_home: KeyHelper,
}

impl WindowShell
where
    A: WindowAdapter,
{
    /// Creates a new window shell with an adapter.
    pub fn new(
        window: minifb::Window,
        adapter: A,
        key_events: Rc<RefCell<Vec<KeyEvent>>>,
    ) -> WindowShell {
        let size = window.get_size();
        let render_context_2_d = RenderContext2D::new(size.0 as f64, size.1 as f64);

        WindowShell {
            window,
            // window_size: window_size,
            // mouse_buttons: (false, false, false),
            // mouse_position: Point::default(),
            render_context_2_d,
            adapter,
            mouse_pos: (0.0, 0.0),
            window_size: size,
            button_down: (false, false, false),
            key_events,
            key_backspace: KeyHelper(false, minifb::Key::Backspace, Key::Backspace),
            key_left: KeyHelper(false, minifb::Key::Left, Key::Left),
            key_right: KeyHelper(false, minifb::Key::Right, Key::Right),
            key_up: KeyHelper(false, minifb::Key::Up, Key::Up),
            key_down: KeyHelper(false, minifb::Key::Down, Key::Down),
            key_delete: KeyHelper(false, minifb::Key::Delete, Key::Delete),
            key_enter: KeyHelper(false, minifb::Key::Enter, Key::Enter),
            key_control: KeyHelper(false, minifb::Key::LeftCtrl, Key::Control),
            key_control_right: KeyHelper(false, minifb::Key::RightCtrl, Key::Control),
            key_shift_l: KeyHelper(false, minifb::Key::LeftShift, Key::ShiftL),
            key_shift_r: KeyHelper(false, minifb::Key::RightShift, Key::ShiftR),
            key_alt: KeyHelper(false, minifb::Key::LeftAlt, Key::Alt),
            key_alt_r: KeyHelper(false, minifb::Key::RightAlt, Key::Alt),
            key_escape: KeyHelper(false, minifb::Key::Escape, Key::Escape),
            key_home: KeyHelper(false, minifb::Key::Home, Key::Home),
        }
    }

    /// Gets the shell adapter.
    pub fn adapter(&mut self) -> &mut A {
        &mut self.adapter
    }

    /// Gets the render ctx 2D.
    pub fn render_context_2_d(&mut self) -> &mut RenderContext2D {
        &mut self.render_context_2_d
    }

    fn drain_events(&mut self) {
        // mouse move
        if let Some(pos) = self.window.get_mouse_pos(minifb::MouseMode::Discard) {
            if (pos.0.floor(), pos.1.floor()) != self.mouse_pos {
                self.adapter.mouse(pos.0 as f64, pos.1 as f64);
                self.mouse_pos = (pos.0.floor(), pos.1.floor());
            }
        }

        // mouse
        let left_button_down = self.window.get_mouse_down(minifb::MouseButton::Left);
        let middle_button_down = self.window.get_mouse_down(minifb::MouseButton::Middle);
        let right_button_down = self.window.get_mouse_down(minifb::MouseButton::Right);

        if left_button_down != self.button_down.0 {
            if left_button_down {
                self.push_mouse_event(true, MouseButton::Left);
            } else {
                self.push_mouse_event(false, MouseButton::Left);
            }
            self.button_down.0 = left_button_down;
        }

        if middle_button_down != self.button_down.1 {
            if middle_button_down {
                self.push_mouse_event(true, MouseButton::Middle);
            } else {
                self.push_mouse_event(false, MouseButton::Middle);
            }
            self.button_down.1 = middle_button_down;
        }

        if right_button_down != self.button_down.2 {
            if right_button_down {
                self.push_mouse_event(true, MouseButton::Right);
            } else {
                self.push_mouse_event(false, MouseButton::Right);
            }
            self.button_down.2 = right_button_down;
        }

        // scroll
        if let Some(delta) = self.window.get_scroll_wheel() {
            self.adapter.scroll(delta.0 as f64, delta.1 as f64);
        }

        // key
        while let Some(event) = self.key_events.borrow_mut().pop() {
            self.adapter.key_event(event);
        }

        key_event_helper(&mut self.key_backspace, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_delete, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_left, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_right, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_up, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_down, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_enter, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_control, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_control_right, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_shift_l, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_shift_r, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_alt, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_alt_r, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_escape, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_home, &mut self.adapter, &self.window);

        // resize
        if self.window_size != self.window.get_size() {
            self.window_size = self.window.get_size();
            self.render_context_2_d
                .resize(self.window_size.0 as f64, self.window_size.1 as f64);
            self.adapter
                .resize(self.window_size.0 as f64, self.window_size.1 as f64);
        }
    }

    fn push_mouse_event(&mut self, pressed: bool, button: MouseButton) {
        let state = if pressed {
            ButtonState::Down
        } else {
            ButtonState::Up
        };

        self.adapter.mouse_event(MouseEvent {
            x: self.mouse_pos.0 as f64,
            y: self.mouse_pos.1 as f64,
            button,
            state,
        });
    }

    pub fn flip(&mut self) -> bool {
        if let Some(data) = self.render_context_2_d.data() {
            self.window.update_with_buffer(data).unwrap();
            CONSOLE.time_end("render");
            return true;
        }

        false
    }
}

impl Drop for WindowShell
where
    A: WindowAdapter,
{
    fn drop(&mut self) {}
}

/// Implementation of the OrbClient based shell runner.
pub struct ShellRunner
where
    A: WindowAdapter,
{
    pub window_shell: Rc<RefCell<WindowShell>>,
    pub update: Rc<Cell<bool>>,
    pub running: Rc<Cell<bool>>,
    pub updater: Box<dyn Updater>,
}

impl ShellRunner
where
    A: WindowAdapter,
{
    pub fn run(&mut self) {
        let mut loop_helper = LoopHelper::builder()
            .report_interval_s(0.5)
            .build_with_target_rate(60.0);

        let mut _current_fps = None;

        loop {
            if !self.running.get() || !self.window_shell.borrow().window.is_open() {
                break;
            }

            let _delta = loop_helper.loop_start();

            if let Some(fps) = loop_helper.report_rate() {
                _current_fps = Some(fps);
                // println!("fps: {}", fps);
            }

            // CONSOLE.time("complete run");

            self.updater.update();

            if self.update.get() {
                self.update.set(false);
            }

            if !self.window_shell.borrow_mut().flip() {
                self.window_shell.borrow_mut().window.update();
            }

            self.window_shell.borrow_mut().drain_events();

            loop_helper.loop_sleep();
            // CONSOLE.time_end("complete run");
        }
    }
}

/// Constructs the window shell
pub struct WindowBuilder
where
    A: WindowAdapter,
{
    title: String,

    resizeable: bool,

    bounds: Rectangle,

    adapter: A,
}

impl WindowBuilder
where
    A: WindowAdapter,
{
    /// Create a new window builder with the given adapter.
    pub fn new(adapter: A) -> Self {
        WindowBuilder {
            adapter,
            title: String::default(),
            resizeable: false,
            bounds: Rectangle::default(),
        }
    }

    /// Sets the title.
    pub fn title(mut self, title: impl Into<String>) -> Self {
        self.title = title.into();
        self
    }

    /// Sets resizeable.
    pub fn resizeable(mut self, resizeable: bool) -> Self {
        self.resizeable = resizeable;
        self
    }

    /// Sets the bounds.
    pub fn bounds(mut self, bounds: impl Into<Rectangle>) -> Self {
        self.bounds = bounds.into();
        self
    }

    /// Builds the window shell.
    pub fn build(self) -> WindowShell {
        let window_options = minifb::WindowOptions {
            resize: self.resizeable,
            ..Default::default()
        };

        let mut window = minifb::Window::new(
            self.title.as_str(),
            self.bounds.width as usize,
            self.bounds.height as usize,
            window_options,
        )
        .unwrap_or_else(|e| {
            panic!("{}", e);
        });

        let key_events = Rc::new(RefCell::new(vec![]));

        window.set_input_callback(Box::new(KeyInputCallBack {
            key_events: key_events.clone(),
        }));

        window.set_position(self.bounds.x as isize, self.bounds.y as isize);

        WindowShell::new(window, self.adapter, key_events)
    }
}

use std::time::Instant;

lazy_static! {
    pub static ref CONSOLE: Console = Console {
        instants: Mutex::new(HashMap::new())
    };
}

pub struct Console {
    instants: Mutex<HashMap<String, Instant>>,
}

impl Console {
    pub fn time(&self, name: impl Into<String>) {
        self.instants
            .lock()
            .unwrap()
            .insert(name.into(), Instant::now());
    }

    pub fn time_end(&self, name: impl Into<String>) {
        if let Some((k, v)) = self.instants.lock().unwrap().remove_entry(&name.into()) {
            println!("{} {}ms - timer ended", k, v.elapsed().as_millis());
        }
    }

    pub fn log(&self, message: impl Into<String>) {
        println!("{}", message.into());
    }
}
<|endoftext|>


<commit_before>//! Runtime support needed for testing the stdarch crate.
//!
//! This basically just disassembles the current executable and then parses the
//! output once globally and then provides the `assert` function which makes
//! assertions about the disassembly of a function.
#![feature(const_str_as_bytes)]
#![feature(const_transmute)]
#![feature(vec_leak)]
#![allow(clippy::missing_docs_in_private_items, clippy::print_stdout)]

extern crate assert_instr_macro;
extern crate cc;
#[macro_use]
extern crate lazy_static;
extern crate rustc_demangle;
extern crate simd_test_macro;
#[macro_use]
extern crate cfg_if;

pub use assert_instr_macro::*;
pub use simd_test_macro::*;
use std::{cmp, collections::HashSet, env, hash, str, sync::atomic::AtomicPtr};

// `println!` doesn't work on wasm32 right now, so shadow the compiler's `println!`
// macro with our own shim that redirects to `console.log`.
#[allow(unused)]
#[cfg(target_arch = "wasm32")]
#[macro_export]
macro_rules! println {
    ($($args:tt)*) => (crate::wasm::js_console_log(&format!($($args)*)))
}

cfg_if! {
    if #[cfg(target_arch = "wasm32")] {
        extern crate wasm_bindgen;
        extern crate console_error_panic_hook;
        pub mod wasm;
        use wasm::disassemble_myself;
    } else {
        mod disassembly;
        use disassembly::disassemble_myself;
    }
}

lazy_static! {
    static ref DISASSEMBLY: HashSet<Function> = disassemble_myself();
}

#[derive(Debug)]
struct Function {
    name: String,
    instrs: Vec<String>,
}
impl Function {
    fn new(n: &str) -> Self {
        Self {
            name: n.to_string(),
            instrs: Vec::new(),
        }
    }
}

impl cmp::PartialEq for Function {
    fn eq(&self, other: &Self) -> bool {
        self.name == other.name
    }
}
impl cmp::Eq for Function {}

impl hash::Hash for Function {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.name.hash(state)
    }
}

/// Main entry point for this crate, called by the `#[assert_instr]` macro.
///
/// This asserts that the function at `fnptr` contains the instruction
/// `expected` provided.
pub fn assert(_fnptr: usize, fnname: &str, expected: &str) {
    //eprintln!("shim name: {}", fnname);
    let function = &DISASSEMBLY
        .get(&Function::new(fnname))
        .unwrap_or_else(|| panic!("function \"{}\" not found in the disassembly", fnname));
    //eprintln!("  function: {:?}", function);

    let mut instrs = &function.instrs[..];
    while instrs.last().map_or(false, |s| s == "nop") {
        instrs = &instrs[..instrs.len() - 1];
    }

    // Look for `expected` as the first part of any instruction in this
    // function, e.g., tzcntl in tzcntl %rax,%rax.
    let found = instrs.iter().any(|s| s.contains(expected));

    // Look for `call` instructions in the disassembly to detect whether
    // inlining failed: all intrinsics are `#[inline(always)]`, so
    // calling one intrinsic from another should not generate `call`
    // instructions.
    let inlining_failed = instrs.windows(2).any(|s| {
        // On 32-bit x86 position independent code will call itself and be
        // immediately followed by a `pop` to learn about the current address.
        // Let's not take that into account when considering whether a function
        // failed inlining something.
        s[0].contains("call") && (!cfg!(target_arch = "x86") || s[1].contains("pop"))
    });

    let instruction_limit = std::env::var("STDARCH_ASSERT_INSTR_LIMIT")
        .ok()
        .map_or_else(
            || match expected {
                // `cpuid` returns a pretty big aggregate structure, so exempt
                // it from the slightly more restrictive 22 instructions below.
                "cpuid" => 30,

                // Apparently, on Windows, LLVM generates a bunch of
                // saves/restores of xmm registers around these intstructions,
                // which exceeds the limit of 20 below. As it seems dictated by
                // Windows's ABI (I believe?), we probably can't do much
                // about it.
                "vzeroall" | "vzeroupper" if cfg!(windows) => 30,

                // Intrinsics using `cvtpi2ps` are typically "composites" and
                // in some cases exceed the limit.
                "cvtpi2ps" => 25,

                // core_arch/src/acle/simd32
                "usad8" => 27,
                "qadd8" | "qsub8" | "sadd8" | "sel" | "shadd8" | "shsub8" | "usub8" | "ssub8" => 29,

                // Original limit was 20 instructions, but ARM DSP Intrinsics
                // are exactly 20 instructions long. So, bump the limit to 22
                // instead of adding here a long list of exceptions.
                _ => 22,
            },
            |v| v.parse().unwrap(),
        );
    let probably_only_one_instruction = instrs.len() < instruction_limit;

    if found && probably_only_one_instruction && !inlining_failed {
        return;
    }

    // Help debug by printing out the found disassembly, and then panic as we
    // didn't find the instruction.
    println!("disassembly for {}: ", fnname,);
    for (i, instr) in instrs.iter().enumerate() {
        println!("\t{:2}: {}", i, instr);
    }

    if !found {
        panic!(
            "failed to find instruction `{}` in the disassembly",
            expected
        );
    } else if !probably_only_one_instruction {
        panic!(
            "instruction found, but the disassembly contains too many \
             instructions: #instructions = {} >= {} (limit)",
            instrs.len(),
            instruction_limit
        );
    } else if inlining_failed {
        panic!(
            "instruction found, but the disassembly contains `call` \
             instructions, which hint that inlining failed"
        );
    }
}

pub fn assert_skip_test_ok(name: &str) {
    if env::var("STDARCH_TEST_EVERYTHING").is_err() {
        return;
    }
    panic!("skipped test `{}` when it shouldn't be skipped", name);
}

// See comment in `assert-instr-macro` crate for why this exists
pub static _DONT_DEDUP: AtomicPtr<u8> = AtomicPtr::new(b"".as_ptr() as *mut _);
<commit_msg>Remove const_str_as_bytes feature gate<commit_after>//! Runtime support needed for testing the stdarch crate.
//!
//! This basically just disassembles the current executable and then parses the
//! output once globally and then provides the `assert` function which makes
//! assertions about the disassembly of a function.
#![feature(const_transmute)]
#![feature(vec_leak)]
#![allow(clippy::missing_docs_in_private_items, clippy::print_stdout)]

extern crate assert_instr_macro;
extern crate cc;
#[macro_use]
extern crate lazy_static;
extern crate rustc_demangle;
extern crate simd_test_macro;
#[macro_use]
extern crate cfg_if;

pub use assert_instr_macro::*;
pub use simd_test_macro::*;
use std::{cmp, collections::HashSet, env, hash, str, sync::atomic::AtomicPtr};

// `println!` doesn't work on wasm32 right now, so shadow the compiler's `println!`
// macro with our own shim that redirects to `console.log`.
#[allow(unused)]
#[cfg(target_arch = "wasm32")]
#[macro_export]
macro_rules! println {
    ($($args:tt)*) => (crate::wasm::js_console_log(&format!($($args)*)))
}

cfg_if! {
    if #[cfg(target_arch = "wasm32")] {
        extern crate wasm_bindgen;
        extern crate console_error_panic_hook;
        pub mod wasm;
        use wasm::disassemble_myself;
    } else {
        mod disassembly;
        use disassembly::disassemble_myself;
    }
}

lazy_static! {
    static ref DISASSEMBLY: HashSet<Function> = disassemble_myself();
}

#[derive(Debug)]
struct Function {
    name: String,
    instrs: Vec<String>,
}
impl Function {
    fn new(n: &str) -> Self {
        Self {
            name: n.to_string(),
            instrs: Vec::new(),
        }
    }
}

impl cmp::PartialEq for Function {
    fn eq(&self, other: &Self) -> bool {
        self.name == other.name
    }
}
impl cmp::Eq for Function {}

impl hash::Hash for Function {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.name.hash(state)
    }
}

/// Main entry point for this crate, called by the `#[assert_instr]` macro.
///
/// This asserts that the function at `fnptr` contains the instruction
/// `expected` provided.
pub fn assert(_fnptr: usize, fnname: &str, expected: &str) {
    //eprintln!("shim name: {}", fnname);
    let function = &DISASSEMBLY
        .get(&Function::new(fnname))
        .unwrap_or_else(|| panic!("function \"{}\" not found in the disassembly", fnname));
    //eprintln!("  function: {:?}", function);

    let mut instrs = &function.instrs[..];
    while instrs.last().map_or(false, |s| s == "nop") {
        instrs = &instrs[..instrs.len() - 1];
    }

    // Look for `expected` as the first part of any instruction in this
    // function, e.g., tzcntl in tzcntl %rax,%rax.
    let found = instrs.iter().any(|s| s.contains(expected));

    // Look for `call` instructions in the disassembly to detect whether
    // inlining failed: all intrinsics are `#[inline(always)]`, so
    // calling one intrinsic from another should not generate `call`
    // instructions.
    let inlining_failed = instrs.windows(2).any(|s| {
        // On 32-bit x86 position independent code will call itself and be
        // immediately followed by a `pop` to learn about the current address.
        // Let's not take that into account when considering whether a function
        // failed inlining something.
        s[0].contains("call") && (!cfg!(target_arch = "x86") || s[1].contains("pop"))
    });

    let instruction_limit = std::env::var("STDARCH_ASSERT_INSTR_LIMIT")
        .ok()
        .map_or_else(
            || match expected {
                // `cpuid` returns a pretty big aggregate structure, so exempt
                // it from the slightly more restrictive 22 instructions below.
                "cpuid" => 30,

                // Apparently, on Windows, LLVM generates a bunch of
                // saves/restores of xmm registers around these intstructions,
                // which exceeds the limit of 20 below. As it seems dictated by
                // Windows's ABI (I believe?), we probably can't do much
                // about it.
                "vzeroall" | "vzeroupper" if cfg!(windows) => 30,

                // Intrinsics using `cvtpi2ps` are typically "composites" and
                // in some cases exceed the limit.
                "cvtpi2ps" => 25,

                // core_arch/src/acle/simd32
                "usad8" => 27,
                "qadd8" | "qsub8" | "sadd8" | "sel" | "shadd8" | "shsub8" | "usub8" | "ssub8" => 29,

                // Original limit was 20 instructions, but ARM DSP Intrinsics
                // are exactly 20 instructions long. So, bump the limit to 22
                // instead of adding here a long list of exceptions.
                _ => 22,
            },
            |v| v.parse().unwrap(),
        );
    let probably_only_one_instruction = instrs.len() < instruction_limit;

    if found && probably_only_one_instruction && !inlining_failed {
        return;
    }

    // Help debug by printing out the found disassembly, and then panic as we
    // didn't find the instruction.
    println!("disassembly for {}: ", fnname,);
    for (i, instr) in instrs.iter().enumerate() {
        println!("\t{:2}: {}", i, instr);
    }

    if !found {
        panic!(
            "failed to find instruction `{}` in the disassembly",
            expected
        );
    } else if !probably_only_one_instruction {
        panic!(
            "instruction found, but the disassembly contains too many \
             instructions: #instructions = {} >= {} (limit)",
            instrs.len(),
            instruction_limit
        );
    } else if inlining_failed {
        panic!(
            "instruction found, but the disassembly contains `call` \
             instructions, which hint that inlining failed"
        );
    }
}

pub fn assert_skip_test_ok(name: &str) {
    if env::var("STDARCH_TEST_EVERYTHING").is_err() {
        return;
    }
    panic!("skipped test `{}` when it shouldn't be skipped", name);
}

// See comment in `assert-instr-macro` crate for why this exists
pub static _DONT_DEDUP: AtomicPtr<u8> = AtomicPtr::new(b"".as_ptr() as *mut _);
<|endoftext|>


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

//! The style bloom filter is used as an optimization when matching deep
//! descendant selectors.

#![deny(missing_docs)]

use dom::{SendElement, TElement};
use selectors::bloom::BloomFilter;

/// A struct that allows us to fast-reject deep descendant selectors avoiding
/// selector-matching.
///
/// This is implemented using a counting bloom filter, and it's a standard
/// optimization. See Gecko's `AncestorFilter`, and Blink's and WebKit's
/// `SelectorFilter`.
///
/// The constraints for Servo's style system are a bit different compared to
/// traditional style systems given Servo does a parallel breadth-first
/// traversal instead of a sequential depth-first traversal.
///
/// This implies that we need to track a bit more state than other browsers to
/// ensure we're doing the correct thing during the traversal, and being able to
/// apply this optimization effectively.
///
/// Concretely, we have a bloom filter instance per worker thread, and we track
/// the current DOM depth in order to find a common ancestor when it doesn't
/// match the previous element we've styled.
///
/// This is usually a pretty fast operation (we use to be one level deeper than
/// the previous one), but in the case of work-stealing, we may needed to push
/// and pop multiple elements.
///
/// See the `insert_parents_recovering`, where most of the magic happens.
///
/// Regarding thread-safety, this struct is safe because:
///
///  * We clear this after a restyle.
///  * The DOM shape and attributes (and every other thing we access here) are
///    immutable during a restyle.
///
pub struct StyleBloom<E: TElement> {
    /// The bloom filter per se.
    filter: Box<BloomFilter>,

    /// The stack of elements that this bloom filter contains.
    elements: Vec<SendElement<E>>,
}

fn each_relevant_element_hash<E, F>(element: E, mut f: F)
    where E: TElement,
          F: FnMut(u32),
{
    f(element.get_local_name().get_hash());
    f(element.get_namespace().get_hash());

    if let Some(id) = element.get_id() {
        f(id.get_hash());
    }

    // TODO: case-sensitivity depends on the document type and quirks mode.
    //
    // TODO(emilio): It's not clear whether that's relevant here though?
    // Classes and ids should be normalized already I think.
    element.each_class(|class| {
        f(class.get_hash())
    });
}

impl<E: TElement> StyleBloom<E> {
    /// Create an empty `StyleBloom`.
    pub fn new() -> Self {
        StyleBloom {
            filter: Box::new(BloomFilter::new()),
            elements: vec![],
        }
    }

    /// Return the bloom filter used properly by the `selectors` crate.
    pub fn filter(&self) -> &BloomFilter {
        &*self.filter
    }

    /// Push an element to the bloom filter, knowing that it's a child of the
    /// last element parent.
    pub fn push(&mut self, element: E) {
        if cfg!(debug_assertions) {
            if self.elements.is_empty() {
                assert!(element.parent_element().is_none());
            }
        }
        self.push_internal(element);
    }

    /// Same as `push`, but without asserting, in order to use it from
    /// `rebuild`.
    fn push_internal(&mut self, element: E) {
        each_relevant_element_hash(element, |hash| {
            self.filter.insert_hash(hash);
        });
        self.elements.push(unsafe { SendElement::new(element) });
    }

    /// Pop the last element in the bloom filter and return it.
    fn pop(&mut self) -> Option<E> {
        let popped = self.elements.pop().map(|el| *el);

        if let Some(popped) = popped {
            each_relevant_element_hash(popped, |hash| {
                self.filter.remove_hash(hash);
            })
        }

        popped
    }

    /// Returns true if the bloom filter is empty.
    pub fn is_empty(&self) -> bool {
        self.elements.is_empty()
    }

    /// Clears the bloom filter.
    pub fn clear(&mut self) {
        self.filter.clear();
        self.elements.clear();
    }

    /// Rebuilds the bloom filter up to the parent of the given element.
    pub fn rebuild(&mut self, mut element: E) {
        self.clear();

        while let Some(parent) = element.parent_element() {
            self.push_internal(parent);
            element = parent;
        }

        // Put them in the order we expect, from root to `element`'s parent.
        self.elements.reverse();
    }

    /// In debug builds, asserts that all the parents of `element` are in the
    /// bloom filter.
    ///
    /// Goes away in release builds.
    pub fn assert_complete(&self, mut element: E) {
        if cfg!(debug_assertions) {
            let mut checked = 0;
            while let Some(parent) = element.parent_element() {
                assert_eq!(parent, *self.elements[self.elements.len() - 1 - checked]);
                element = parent;
                checked += 1;
            }
            assert_eq!(checked, self.elements.len());
        }
    }

    /// Insert the parents of an element in the bloom filter, trying to recover
    /// the filter if the last element inserted doesn't match.
    ///
    /// Gets the element depth in the dom, to make it efficient, or if not
    /// provided always rebuilds the filter from scratch.
    ///
    /// Returns the new bloom filter depth, that the traversal code is
    /// responsible to keep around if it wants to get an effective filter.
    pub fn insert_parents_recovering(&mut self,
                                     element: E,
                                     element_depth: usize)
    {
        // Easy case, we're in a different restyle, or we're empty.
        if self.elements.is_empty() {
            self.rebuild(element);
            return;
        }

        let parent_element = match element.parent_element() {
            Some(parent) => parent,
            None => {
                // Yay, another easy case.
                self.clear();
                return;
            }
        };

        if self.elements.last().map(|el| **el) == Some(parent_element) {
            // Ta da, cache hit, we're all done.
            return;
        }

        if element_depth == 0 {
            self.clear();
            return;
        }

        // We should've early exited above.
        debug_assert!(element_depth != 0,
                      "We should have already cleared the bloom filter");
        debug_assert!(!self.elements.is_empty(),
                      "How! We should've just rebuilt!");

        // Now the fun begins: We have the depth of the dom and the depth of the
        // last element inserted in the filter, let's try to find a common
        // parent.
        //
        // The current depth, that is, the depth of the last element inserted in
        // the bloom filter, is the number of elements _minus one_, that is: if
        // there's one element, it must be the root -> depth zero.
        let mut current_depth = self.elements.len() - 1;

        // If the filter represents an element too deep in the dom, we need to
        // pop ancestors.
        while current_depth > element_depth - 1 {
            self.pop().expect("Emilio is bad at math");
            current_depth -= 1;
        }

        // Now let's try to find a common parent in the bloom filter chain,
        // starting with parent_element.
        let mut common_parent = parent_element;
        let mut common_parent_depth = element_depth - 1;

        // Let's collect the parents we are going to need to insert once we've
        // found the common one.
        let mut parents_to_insert = vec![];

        // If the bloom filter still doesn't have enough elements, the common
        // parent is up in the dom.
        while common_parent_depth > current_depth {
            // TODO(emilio): Seems like we could insert parents here, then
            // reverse the slice.
            parents_to_insert.push(common_parent);
            common_parent =
                common_parent.parent_element().expect("We were lied");
            common_parent_depth -= 1;
        }

        // Now the two depths are the same.
        debug_assert_eq!(common_parent_depth, current_depth);

        // Happy case: The parents match, we only need to push the ancestors
        // we've collected and we'll never enter in this loop.
        //
        // Not-so-happy case: Parent's don't match, so we need to keep going up
        // until we find a common ancestor.
        //
        // Gecko currently models native anonymous content that conceptually hangs
        // off the document (such as scrollbars) as a separate subtree from the
        // document root.  Thus it's possible with Gecko that we do not find any
        // common ancestor.
        while **self.elements.last().unwrap() != common_parent {
            parents_to_insert.push(common_parent);
            self.pop().unwrap();
            common_parent = match common_parent.parent_element() {
                Some(parent) => parent,
                None => {
                    debug_assert!(self.elements.is_empty());
                    if cfg!(feature = "gecko") {
                        break;
                    } else {
                        panic!("should have found a common ancestor");
                    }
                }
            }
        }

        // Now the parents match, so insert the stack of elements we have been
        // collecting so far.
        for parent in parents_to_insert.into_iter().rev() {
            self.push(parent);
        }

        debug_assert_eq!(self.elements.len(), element_depth);

        // We're done! Easy.
    }
}
<commit_msg>style: Use a SmallVec for common ancestors in the bloom filter.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! The style bloom filter is used as an optimization when matching deep
//! descendant selectors.

#![deny(missing_docs)]

use dom::{SendElement, TElement};
use selectors::bloom::BloomFilter;
use smallvec::SmallVec;

/// A struct that allows us to fast-reject deep descendant selectors avoiding
/// selector-matching.
///
/// This is implemented using a counting bloom filter, and it's a standard
/// optimization. See Gecko's `AncestorFilter`, and Blink's and WebKit's
/// `SelectorFilter`.
///
/// The constraints for Servo's style system are a bit different compared to
/// traditional style systems given Servo does a parallel breadth-first
/// traversal instead of a sequential depth-first traversal.
///
/// This implies that we need to track a bit more state than other browsers to
/// ensure we're doing the correct thing during the traversal, and being able to
/// apply this optimization effectively.
///
/// Concretely, we have a bloom filter instance per worker thread, and we track
/// the current DOM depth in order to find a common ancestor when it doesn't
/// match the previous element we've styled.
///
/// This is usually a pretty fast operation (we use to be one level deeper than
/// the previous one), but in the case of work-stealing, we may needed to push
/// and pop multiple elements.
///
/// See the `insert_parents_recovering`, where most of the magic happens.
///
/// Regarding thread-safety, this struct is safe because:
///
///  * We clear this after a restyle.
///  * The DOM shape and attributes (and every other thing we access here) are
///    immutable during a restyle.
///
pub struct StyleBloom<E: TElement> {
    /// The bloom filter per se.
    filter: Box<BloomFilter>,

    /// The stack of elements that this bloom filter contains.
    elements: Vec<SendElement<E>>,
}

fn each_relevant_element_hash<E, F>(element: E, mut f: F)
    where E: TElement,
          F: FnMut(u32),
{
    f(element.get_local_name().get_hash());
    f(element.get_namespace().get_hash());

    if let Some(id) = element.get_id() {
        f(id.get_hash());
    }

    // TODO: case-sensitivity depends on the document type and quirks mode.
    //
    // TODO(emilio): It's not clear whether that's relevant here though?
    // Classes and ids should be normalized already I think.
    element.each_class(|class| {
        f(class.get_hash())
    });
}

impl<E: TElement> StyleBloom<E> {
    /// Create an empty `StyleBloom`.
    pub fn new() -> Self {
        StyleBloom {
            filter: Box::new(BloomFilter::new()),
            elements: vec![],
        }
    }

    /// Return the bloom filter used properly by the `selectors` crate.
    pub fn filter(&self) -> &BloomFilter {
        &*self.filter
    }

    /// Push an element to the bloom filter, knowing that it's a child of the
    /// last element parent.
    pub fn push(&mut self, element: E) {
        if cfg!(debug_assertions) {
            if self.elements.is_empty() {
                assert!(element.parent_element().is_none());
            }
        }
        self.push_internal(element);
    }

    /// Same as `push`, but without asserting, in order to use it from
    /// `rebuild`.
    fn push_internal(&mut self, element: E) {
        each_relevant_element_hash(element, |hash| {
            self.filter.insert_hash(hash);
        });
        self.elements.push(unsafe { SendElement::new(element) });
    }

    /// Pop the last element in the bloom filter and return it.
    fn pop(&mut self) -> Option<E> {
        let popped = self.elements.pop().map(|el| *el);

        if let Some(popped) = popped {
            each_relevant_element_hash(popped, |hash| {
                self.filter.remove_hash(hash);
            })
        }

        popped
    }

    /// Returns true if the bloom filter is empty.
    pub fn is_empty(&self) -> bool {
        self.elements.is_empty()
    }

    /// Clears the bloom filter.
    pub fn clear(&mut self) {
        self.filter.clear();
        self.elements.clear();
    }

    /// Rebuilds the bloom filter up to the parent of the given element.
    pub fn rebuild(&mut self, mut element: E) {
        self.clear();

        while let Some(parent) = element.parent_element() {
            self.push_internal(parent);
            element = parent;
        }

        // Put them in the order we expect, from root to `element`'s parent.
        self.elements.reverse();
    }

    /// In debug builds, asserts that all the parents of `element` are in the
    /// bloom filter.
    ///
    /// Goes away in release builds.
    pub fn assert_complete(&self, mut element: E) {
        if cfg!(debug_assertions) {
            let mut checked = 0;
            while let Some(parent) = element.parent_element() {
                assert_eq!(parent, *self.elements[self.elements.len() - 1 - checked]);
                element = parent;
                checked += 1;
            }
            assert_eq!(checked, self.elements.len());
        }
    }

    /// Insert the parents of an element in the bloom filter, trying to recover
    /// the filter if the last element inserted doesn't match.
    ///
    /// Gets the element depth in the dom, to make it efficient, or if not
    /// provided always rebuilds the filter from scratch.
    ///
    /// Returns the new bloom filter depth, that the traversal code is
    /// responsible to keep around if it wants to get an effective filter.
    pub fn insert_parents_recovering(&mut self,
                                     element: E,
                                     element_depth: usize)
    {
        // Easy case, we're in a different restyle, or we're empty.
        if self.elements.is_empty() {
            self.rebuild(element);
            return;
        }

        let parent_element = match element.parent_element() {
            Some(parent) => parent,
            None => {
                // Yay, another easy case.
                self.clear();
                return;
            }
        };

        if self.elements.last().map(|el| **el) == Some(parent_element) {
            // Ta da, cache hit, we're all done.
            return;
        }

        if element_depth == 0 {
            self.clear();
            return;
        }

        // We should've early exited above.
        debug_assert!(element_depth != 0,
                      "We should have already cleared the bloom filter");
        debug_assert!(!self.elements.is_empty(),
                      "How! We should've just rebuilt!");

        // Now the fun begins: We have the depth of the dom and the depth of the
        // last element inserted in the filter, let's try to find a common
        // parent.
        //
        // The current depth, that is, the depth of the last element inserted in
        // the bloom filter, is the number of elements _minus one_, that is: if
        // there's one element, it must be the root -> depth zero.
        let mut current_depth = self.elements.len() - 1;

        // If the filter represents an element too deep in the dom, we need to
        // pop ancestors.
        while current_depth > element_depth - 1 {
            self.pop().expect("Emilio is bad at math");
            current_depth -= 1;
        }

        // Now let's try to find a common parent in the bloom filter chain,
        // starting with parent_element.
        let mut common_parent = parent_element;
        let mut common_parent_depth = element_depth - 1;

        // Let's collect the parents we are going to need to insert once we've
        // found the common one.
        let mut parents_to_insert = SmallVec::<[E; 8]>::new();

        // If the bloom filter still doesn't have enough elements, the common
        // parent is up in the dom.
        while common_parent_depth > current_depth {
            // TODO(emilio): Seems like we could insert parents here, then
            // reverse the slice.
            parents_to_insert.push(common_parent);
            common_parent =
                common_parent.parent_element().expect("We were lied");
            common_parent_depth -= 1;
        }

        // Now the two depths are the same.
        debug_assert_eq!(common_parent_depth, current_depth);

        // Happy case: The parents match, we only need to push the ancestors
        // we've collected and we'll never enter in this loop.
        //
        // Not-so-happy case: Parent's don't match, so we need to keep going up
        // until we find a common ancestor.
        //
        // Gecko currently models native anonymous content that conceptually
        // hangs off the document (such as scrollbars) as a separate subtree
        // from the document root.
        //
        // Thus it's possible with Gecko that we do not find any common
        // ancestor.
        while **self.elements.last().unwrap() != common_parent {
            parents_to_insert.push(common_parent);
            self.pop().unwrap();
            common_parent = match common_parent.parent_element() {
                Some(parent) => parent,
                None => {
                    debug_assert!(self.elements.is_empty());
                    if cfg!(feature = "gecko") {
                        break;
                    } else {
                        panic!("should have found a common ancestor");
                    }
                }
            }
        }

        // Now the parents match, so insert the stack of elements we have been
        // collecting so far.
        for parent in parents_to_insert.into_iter().rev() {
            self.push(parent);
        }

        debug_assert_eq!(self.elements.len(), element_depth);

        // We're done! Easy.
    }
}
<|endoftext|>