<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// 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.

#![deny(missing_docs)]

//! Graphics device. Not meant for direct use.

use std::{fmt, mem};
use std::hash::Hash;

pub use draw_state::target;
pub use draw_state::state;

pub mod attrib;
pub mod command;
pub mod draw;
pub mod dummy;
pub mod handle;
pub mod mapping;
pub mod shade;
pub mod tex;

mod arc;

/// Draw vertex count.
pub type VertexCount = u32;
/// Draw number of instances
pub type InstanceCount = u32;
/// Index of a uniform block.
pub type UniformBlockIndex = u8;
/// Slot for an attribute.
pub type AttributeSlot = u8;
/// Slot for a uniform buffer object.
pub type UniformBufferSlot = u8;
/// Slot a texture can be bound to.
pub type TextureSlot = u8;

/// Generic error for features that are not supported
/// by the device capabilities.
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct NotSupported;

/// Treat a given slice as `&[u8]` for the given function call
pub fn as_byte_slice<T>(slice: &[T]) -> &[u8] {
    use std::slice;
    let len = mem::size_of::<T>() * slice.len();
    unsafe {
        slice::from_raw_parts(slice.as_ptr() as *const u8, len)
    }
}

/// Features that the device supports.
#[derive(Copy, Clone, Debug)]
#[allow(missing_docs)] // pretty self-explanatory fields!
pub struct Capabilities {
    pub shader_model: shade::ShaderModel,

    pub max_vertex_count: usize,
    pub max_index_count: usize,
    pub max_draw_buffers: usize,
    pub max_texture_size: usize,
    pub max_vertex_attributes: usize,

    /// In GLES it is not allowed to re-bind a buffer to a different
    /// target than the one it was initialized with.
    pub buffer_role_change_allowed: bool,

    pub array_buffer_supported: bool,
    pub fragment_output_supported: bool,
    pub immutable_storage_supported: bool,
    pub instance_base_supported: bool,
    pub instance_call_supported: bool,
    pub instance_rate_supported: bool,
    pub render_targets_supported: bool,
    pub sampler_objects_supported: bool,
    pub srgb_color_supported: bool,
    pub uniform_block_supported: bool,
    pub vertex_base_supported: bool,
}

/// Specifies the access allowed to a buffer mapping.
#[derive(Copy, Clone)]
pub enum MapAccess {
    /// Only allow reads.
    Readable,
    /// Only allow writes.
    Writable,
    /// Allow full access.
    RW
}

/// Describes what geometric primitives are created from vertex data.
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum PrimitiveType {
    /// Each vertex represents a single point.
    Point,
    /// Each pair of vertices represent a single line segment. For example, with `[a, b, c, d,
    /// e]`, `a` and `b` form a line, `c` and `d` form a line, and `e` is discarded.
    Line,
    /// Every two consecutive vertices represent a single line segment. Visually forms a "path" of
    /// lines, as they are all connected. For example, with `[a, b, c]`, `a` and `b` form a line
    /// line, and `b` and `c` form a line.
    LineStrip,
    /// Each triplet of vertices represent a single triangle. For example, with `[a, b, c, d, e]`,
    /// `a`, `b`, and `c` form a triangle, `d` and `e` are discarded.
    TriangleList,
    /// Every three consecutive vertices represent a single triangle. For example, with `[a, b, c,
    /// d]`, `a`, `b`, and `c` form a triangle, and `b`, `c`, and `d` form a triangle.
    TriangleStrip,
    /// The first vertex with the last two are forming a triangle. For example, with `[a, b, c, d
    /// ]`, `a` , `b`, and `c` form a triangle, and `a`, `c`, and `d` form a triangle.
    TriangleFan,
    //Quad,
}

/// A type of each index value in the mesh's index buffer
pub type IndexType = attrib::IntSize;

/// Role of the memory buffer. GLES doesn't chaning bind points for buffers.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
#[repr(u8)]
pub enum BufferRole {
    /// Generic vertex buffer
    Vertex,
    /// Index buffer
    Index,
    /// Uniform block buffer
    Uniform,
}

/// A hint as to how this buffer will be used.
///
/// The nature of these hints make them very implementation specific. Different drivers on
/// different hardware will handle them differently. Only careful profiling will tell which is the
/// best to use for a specific buffer.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
#[repr(u8)]
pub enum BufferUsage {
    /// Once uploaded, this buffer will rarely change, but will be read from often.
    Static,
    /// This buffer will be updated "frequently", and will be read from multiple times between
    /// updates.
    Dynamic,
    /// This buffer always or almost always be updated after each read.
    Stream,
}

/// An information block that is immutable and associated with each buffer
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct BufferInfo {
    /// Role
    pub role: BufferRole,
    /// Usage hint
    pub usage: BufferUsage,
    /// Size in bytes
    pub size: usize,
}

/// An error happening on buffer updates.
#[derive(Clone, PartialEq, Debug)]
pub enum BufferUpdateError {
    /// Trying to change the contents outside of the allocation.
    OutOfBounds,
}

/// Resources pertaining to a specific API.
#[allow(missing_docs)]
pub trait Resources:           Clone + Hash + fmt::Debug + Eq + PartialEq {
    type Buffer:        Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync + 'static;
    type ArrayBuffer:   Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync + 'static;
    type Shader:        Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync + 'static;
    type Program:       Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync + 'static;
    type FrameBuffer:   Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync + 'static;
    type Surface:       Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync + 'static;
    type Texture:       Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync + 'static;
    type Sampler:       Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync + 'static;
    type Fence:         Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync + 'static;
}

#[allow(missing_docs)]
pub trait Factory<R: Resources> {
    /// Associated mapper type
    type Mapper: Clone + mapping::Raw;

    /// Returns the capabilities available to the specific API implementation
    fn get_capabilities<'a>(&'a self) -> &'a Capabilities;

    // resource creation
    fn create_buffer_raw(&mut self, size: usize, BufferRole, BufferUsage) -> handle::RawBuffer<R>;
    fn create_buffer_static_raw(&mut self, data: &[u8], BufferRole) -> handle::RawBuffer<R>;
    fn create_buffer_static<T>(&mut self, data: &[T], role: BufferRole) -> handle::Buffer<R, T> {
        handle::Buffer::from_raw(
            self.create_buffer_static_raw(as_byte_slice(data), role))
    }
    fn create_buffer_dynamic<T>(&mut self, num: usize, role: BufferRole) -> handle::Buffer<R, T> {
        handle::Buffer::from_raw(
            self.create_buffer_raw(num * mem::size_of::<T>(), role, BufferUsage::Stream))
    }

    fn create_array_buffer(&mut self) -> Result<handle::ArrayBuffer<R>, NotSupported>;
    fn create_shader(&mut self, stage: shade::Stage, code: &[u8]) ->
                     Result<handle::Shader<R>, shade::CreateShaderError>;
    fn create_program(&mut self, shaders: &[handle::Shader<R>], targets: Option<&[&str]>)
                      -> Result<handle::Program<R>, shade::CreateProgramError>;
    fn create_frame_buffer(&mut self) -> Result<handle::FrameBuffer<R>, NotSupported>;
    fn create_surface(&mut self, tex::SurfaceInfo) -> Result<handle::Surface<R>, tex::SurfaceError>;
    fn create_texture(&mut self, tex::TextureInfo) -> Result<handle::Texture<R>, tex::TextureError>;
    fn create_sampler(&mut self, tex::SamplerInfo) -> handle::Sampler<R>;

    /// Update the information stored in a specific buffer
    fn update_buffer_raw(&mut self, buf: &handle::RawBuffer<R>, data: &[u8], offset_bytes: usize)
                         -> Result<(), BufferUpdateError>;
    fn update_buffer<T>(&mut self, buf: &handle::Buffer<R, T>, data: &[T], offset_elements: usize)
                        -> Result<(), BufferUpdateError> {
        self.update_buffer_raw(buf.raw(), as_byte_slice(data), mem::size_of::<T>() * offset_elements)
    }
    fn map_buffer_raw(&mut self, &handle::RawBuffer<R>, MapAccess) -> Self::Mapper;
    fn unmap_buffer_raw(&mut self, Self::Mapper);
    fn map_buffer_readable<T: Copy>(&mut self, &handle::Buffer<R, T>) -> mapping::Readable<T, R, Self>;
    fn map_buffer_writable<T: Copy>(&mut self, &handle::Buffer<R, T>) -> mapping::Writable<T, R, Self>;
    fn map_buffer_rw<T: Copy>(&mut self, &handle::Buffer<R, T>) -> mapping::RW<T, R, Self>;

    /// Update the information stored in a texture
    fn update_texture_raw(&mut self, tex: &handle::Texture<R>,
                          img: &tex::ImageInfo, data: &[u8],
                          kind: Option<tex::Kind>) -> Result<(), tex::TextureError>;

    fn update_texture<T>(&mut self, tex: &handle::Texture<R>,
                         img: &tex::ImageInfo, data: &[T],
                         kind: Option<tex::Kind>) -> Result<(), tex::TextureError> {
        self.update_texture_raw(tex, img, as_byte_slice(data), kind)
    }

    fn generate_mipmap(&mut self, &handle::Texture<R>);

    /// Create a new texture with given data
    fn create_texture_static<T>(&mut self, info: tex::TextureInfo, data: &[T])
                             -> Result<handle::Texture<R>, tex::TextureError> {
        let image_info = info.into();
        match self.create_texture(info) {
            Ok(handle) => self.update_texture(&handle, &image_info, data, None)
                              .map(|_| handle),
            Err(e) => Err(e),
        }
    }
}

/// All the data needed simultaneously for submitting a command buffer for
/// execution on a device.
pub type SubmitInfo<'a, D: Device> = (
    &'a D::CommandBuffer,
    &'a draw::DataBuffer,
    &'a handle::Manager<D::Resources>
);

/// An interface for performing draw calls using a specific graphics API
pub trait Device {
    /// Associated resources type.
    type Resources: Resources;
    /// Associated command buffer type.
    type CommandBuffer: draw::CommandBuffer<Self::Resources>;

    /// Returns the capabilities available to the specific API implementation.
    fn get_capabilities<'a>(&'a self) -> &'a Capabilities;

    /// Reset all the states to disabled/default.
    fn reset_state(&mut self);

    /// Submit a command buffer for execution.
    fn submit(&mut self, SubmitInfo<Self>);

    /// Cleanup unused resources, to be called between frames.
    fn cleanup(&mut self);
}

/// Extension to the Device that allows for submitting of commands
/// around a fence
pub trait DeviceFence<R: Resources>: Device<Resources=R> {
    /// Submit a command buffer to the stream creating a fence
    /// the fence is signaled after the GPU has executed all commands
    /// in the buffer
    fn fenced_submit(&mut self, SubmitInfo<Self>, after: Option<handle::Fence<R>>) -> handle::Fence<R>;

    /// Wait on the supplied fence stalling the current thread until
    /// the fence is satisfied
    fn fence_wait(&mut self, fence: &handle::Fence<R>);
}
<commit_msg>Auto merge of #797 - csherratt:lifetime, r=kvark<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// 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.

#![deny(missing_docs)]

//! Graphics device. Not meant for direct use.

use std::{fmt, mem};
use std::hash::Hash;

pub use draw_state::target;
pub use draw_state::state;

pub mod attrib;
pub mod command;
pub mod draw;
pub mod dummy;
pub mod handle;
pub mod mapping;
pub mod shade;
pub mod tex;

mod arc;

/// Draw vertex count.
pub type VertexCount = u32;
/// Draw number of instances
pub type InstanceCount = u32;
/// Index of a uniform block.
pub type UniformBlockIndex = u8;
/// Slot for an attribute.
pub type AttributeSlot = u8;
/// Slot for a uniform buffer object.
pub type UniformBufferSlot = u8;
/// Slot a texture can be bound to.
pub type TextureSlot = u8;

/// Generic error for features that are not supported
/// by the device capabilities.
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct NotSupported;

/// Treat a given slice as `&[u8]` for the given function call
pub fn as_byte_slice<T>(slice: &[T]) -> &[u8] {
    use std::slice;
    let len = mem::size_of::<T>() * slice.len();
    unsafe {
        slice::from_raw_parts(slice.as_ptr() as *const u8, len)
    }
}

/// Features that the device supports.
#[derive(Copy, Clone, Debug)]
#[allow(missing_docs)] // pretty self-explanatory fields!
pub struct Capabilities {
    pub shader_model: shade::ShaderModel,

    pub max_vertex_count: usize,
    pub max_index_count: usize,
    pub max_draw_buffers: usize,
    pub max_texture_size: usize,
    pub max_vertex_attributes: usize,

    /// In GLES it is not allowed to re-bind a buffer to a different
    /// target than the one it was initialized with.
    pub buffer_role_change_allowed: bool,

    pub array_buffer_supported: bool,
    pub fragment_output_supported: bool,
    pub immutable_storage_supported: bool,
    pub instance_base_supported: bool,
    pub instance_call_supported: bool,
    pub instance_rate_supported: bool,
    pub render_targets_supported: bool,
    pub sampler_objects_supported: bool,
    pub srgb_color_supported: bool,
    pub uniform_block_supported: bool,
    pub vertex_base_supported: bool,
}

/// Specifies the access allowed to a buffer mapping.
#[derive(Copy, Clone)]
pub enum MapAccess {
    /// Only allow reads.
    Readable,
    /// Only allow writes.
    Writable,
    /// Allow full access.
    RW
}

/// Describes what geometric primitives are created from vertex data.
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum PrimitiveType {
    /// Each vertex represents a single point.
    Point,
    /// Each pair of vertices represent a single line segment. For example, with `[a, b, c, d,
    /// e]`, `a` and `b` form a line, `c` and `d` form a line, and `e` is discarded.
    Line,
    /// Every two consecutive vertices represent a single line segment. Visually forms a "path" of
    /// lines, as they are all connected. For example, with `[a, b, c]`, `a` and `b` form a line
    /// line, and `b` and `c` form a line.
    LineStrip,
    /// Each triplet of vertices represent a single triangle. For example, with `[a, b, c, d, e]`,
    /// `a`, `b`, and `c` form a triangle, `d` and `e` are discarded.
    TriangleList,
    /// Every three consecutive vertices represent a single triangle. For example, with `[a, b, c,
    /// d]`, `a`, `b`, and `c` form a triangle, and `b`, `c`, and `d` form a triangle.
    TriangleStrip,
    /// The first vertex with the last two are forming a triangle. For example, with `[a, b, c, d
    /// ]`, `a` , `b`, and `c` form a triangle, and `a`, `c`, and `d` form a triangle.
    TriangleFan,
    //Quad,
}

/// A type of each index value in the mesh's index buffer
pub type IndexType = attrib::IntSize;

/// Role of the memory buffer. GLES doesn't chaning bind points for buffers.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
#[repr(u8)]
pub enum BufferRole {
    /// Generic vertex buffer
    Vertex,
    /// Index buffer
    Index,
    /// Uniform block buffer
    Uniform,
}

/// A hint as to how this buffer will be used.
///
/// The nature of these hints make them very implementation specific. Different drivers on
/// different hardware will handle them differently. Only careful profiling will tell which is the
/// best to use for a specific buffer.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
#[repr(u8)]
pub enum BufferUsage {
    /// Once uploaded, this buffer will rarely change, but will be read from often.
    Static,
    /// This buffer will be updated "frequently", and will be read from multiple times between
    /// updates.
    Dynamic,
    /// This buffer always or almost always be updated after each read.
    Stream,
}

/// An information block that is immutable and associated with each buffer
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct BufferInfo {
    /// Role
    pub role: BufferRole,
    /// Usage hint
    pub usage: BufferUsage,
    /// Size in bytes
    pub size: usize,
}

/// An error happening on buffer updates.
#[derive(Clone, PartialEq, Debug)]
pub enum BufferUpdateError {
    /// Trying to change the contents outside of the allocation.
    OutOfBounds,
}

/// Resources pertaining to a specific API.
#[allow(missing_docs)]
pub trait Resources:           Clone + Hash + fmt::Debug + Eq + PartialEq {
    type Buffer:        Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
    type ArrayBuffer:   Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
    type Shader:        Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
    type Program:       Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
    type FrameBuffer:   Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
    type Surface:       Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
    type Texture:       Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
    type Sampler:       Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
    type Fence:         Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
}

#[allow(missing_docs)]
pub trait Factory<R: Resources> {
    /// Associated mapper type
    type Mapper: Clone + mapping::Raw;

    /// Returns the capabilities available to the specific API implementation
    fn get_capabilities<'a>(&'a self) -> &'a Capabilities;

    // resource creation
    fn create_buffer_raw(&mut self, size: usize, BufferRole, BufferUsage) -> handle::RawBuffer<R>;
    fn create_buffer_static_raw(&mut self, data: &[u8], BufferRole) -> handle::RawBuffer<R>;
    fn create_buffer_static<T>(&mut self, data: &[T], role: BufferRole) -> handle::Buffer<R, T> {
        handle::Buffer::from_raw(
            self.create_buffer_static_raw(as_byte_slice(data), role))
    }
    fn create_buffer_dynamic<T>(&mut self, num: usize, role: BufferRole) -> handle::Buffer<R, T> {
        handle::Buffer::from_raw(
            self.create_buffer_raw(num * mem::size_of::<T>(), role, BufferUsage::Stream))
    }

    fn create_array_buffer(&mut self) -> Result<handle::ArrayBuffer<R>, NotSupported>;
    fn create_shader(&mut self, stage: shade::Stage, code: &[u8]) ->
                     Result<handle::Shader<R>, shade::CreateShaderError>;
    fn create_program(&mut self, shaders: &[handle::Shader<R>], targets: Option<&[&str]>)
                      -> Result<handle::Program<R>, shade::CreateProgramError>;
    fn create_frame_buffer(&mut self) -> Result<handle::FrameBuffer<R>, NotSupported>;
    fn create_surface(&mut self, tex::SurfaceInfo) -> Result<handle::Surface<R>, tex::SurfaceError>;
    fn create_texture(&mut self, tex::TextureInfo) -> Result<handle::Texture<R>, tex::TextureError>;
    fn create_sampler(&mut self, tex::SamplerInfo) -> handle::Sampler<R>;

    /// Update the information stored in a specific buffer
    fn update_buffer_raw(&mut self, buf: &handle::RawBuffer<R>, data: &[u8], offset_bytes: usize)
                         -> Result<(), BufferUpdateError>;
    fn update_buffer<T>(&mut self, buf: &handle::Buffer<R, T>, data: &[T], offset_elements: usize)
                        -> Result<(), BufferUpdateError> {
        self.update_buffer_raw(buf.raw(), as_byte_slice(data), mem::size_of::<T>() * offset_elements)
    }
    fn map_buffer_raw(&mut self, &handle::RawBuffer<R>, MapAccess) -> Self::Mapper;
    fn unmap_buffer_raw(&mut self, Self::Mapper);
    fn map_buffer_readable<T: Copy>(&mut self, &handle::Buffer<R, T>) -> mapping::Readable<T, R, Self>;
    fn map_buffer_writable<T: Copy>(&mut self, &handle::Buffer<R, T>) -> mapping::Writable<T, R, Self>;
    fn map_buffer_rw<T: Copy>(&mut self, &handle::Buffer<R, T>) -> mapping::RW<T, R, Self>;

    /// Update the information stored in a texture
    fn update_texture_raw(&mut self, tex: &handle::Texture<R>,
                          img: &tex::ImageInfo, data: &[u8],
                          kind: Option<tex::Kind>) -> Result<(), tex::TextureError>;

    fn update_texture<T>(&mut self, tex: &handle::Texture<R>,
                         img: &tex::ImageInfo, data: &[T],
                         kind: Option<tex::Kind>) -> Result<(), tex::TextureError> {
        self.update_texture_raw(tex, img, as_byte_slice(data), kind)
    }

    fn generate_mipmap(&mut self, &handle::Texture<R>);

    /// Create a new texture with given data
    fn create_texture_static<T>(&mut self, info: tex::TextureInfo, data: &[T])
                             -> Result<handle::Texture<R>, tex::TextureError> {
        let image_info = info.into();
        match self.create_texture(info) {
            Ok(handle) => self.update_texture(&handle, &image_info, data, None)
                              .map(|_| handle),
            Err(e) => Err(e),
        }
    }
}

/// All the data needed simultaneously for submitting a command buffer for
/// execution on a device.
pub type SubmitInfo<'a, D: Device> = (
    &'a D::CommandBuffer,
    &'a draw::DataBuffer,
    &'a handle::Manager<D::Resources>
);

/// An interface for performing draw calls using a specific graphics API
pub trait Device {
    /// Associated resources type.
    type Resources: Resources;
    /// Associated command buffer type.
    type CommandBuffer: draw::CommandBuffer<Self::Resources>;

    /// Returns the capabilities available to the specific API implementation.
    fn get_capabilities<'a>(&'a self) -> &'a Capabilities;

    /// Reset all the states to disabled/default.
    fn reset_state(&mut self);

    /// Submit a command buffer for execution.
    fn submit(&mut self, SubmitInfo<Self>);

    /// Cleanup unused resources, to be called between frames.
    fn cleanup(&mut self);
}

/// Extension to the Device that allows for submitting of commands
/// around a fence
pub trait DeviceFence<R: Resources>: Device<Resources=R> {
    /// Submit a command buffer to the stream creating a fence
    /// the fence is signaled after the GPU has executed all commands
    /// in the buffer
    fn fenced_submit(&mut self, SubmitInfo<Self>, after: Option<handle::Fence<R>>) -> handle::Fence<R>;

    /// Wait on the supplied fence stalling the current thread until
    /// the fence is satisfied
    fn fence_wait(&mut self, fence: &handle::Fence<R>);
}
<|endoftext|>


<commit_before>extern crate libc;

use x11::xlib;
use x11::xlib::Window;
use super::super::libx;

use super::config::Config;
use super::Container;
use super::Workspaces;
use super::handler;

unsafe extern fn error_handler(display: *mut xlib::Display, event: *mut xlib::XErrorEvent) -> libc::c_int {
    // match event.error_code {
    //     xlib::BadAtom => {
    //         println!("bad atom");
    //     }
    //     _ => {}
    // }
    1
}

fn load_resource(mut context: &mut libx::Context) {
    use std::mem;
    use std::ffi;
    let screen = context.screen_num;
    let root = context.root;
    let display = context.display;
    let mut values: xlib::XGCValues = unsafe{ mem::zeroed() };
    // let gc = libx::create_gc(self.context, self.id, 0, values);
    let gc = libx::default_gc(*context, screen);

    unsafe {
        let black = xlib::XBlackPixel(display, screen);
        let white = xlib::XWhitePixel(display, screen);

        xlib::XSetLineAttributes(display, gc, 5, 0, 0, 0);

        let cmap = xlib::XDefaultColormap(display, screen);
        let mut color: xlib::XColor = mem::zeroed();
        let name = ffi::CString::new("blue").unwrap().as_ptr();
        let r = xlib::XParseColor(display, cmap, name, &mut color);
        xlib::XAllocColor(display, cmap, &mut color);

        context.gc = gc;
        context.focus_bg = black;
        context.focus_fg = color.pixel;
        context.unfocus_bg = black;
        context.unfocus_fg = black;
    }
}

pub struct WindowManager {
    pub context: libx::Context,
    pub workspaces: Workspaces,
    config: Config
}

impl WindowManager {
    pub fn new() -> WindowManager {
	let res = libx::open_display(None);
        let mut context = match res {
            Some(c) => {
                c
            }
            None => {
                panic!("can't open display")
            }
        };

	context.screen_num  = libx::default_screen(context);
	context.root = libx::root_window(context, context.screen_num);
        load_resource(&mut context);

	let mut wm = WindowManager {
            context: context,
            config: Config::load(),
            workspaces: Workspaces::new(context)
        };
        wm
    }

    pub fn clean(&mut self) {
        libx::close_display(self.context);
    }

    pub fn handle_create(&mut self, event: &xlib::XCreateWindowEvent) {
        if event.override_redirect != 0 {
            return;
        }

        let attrs = libx::get_window_attributes(self.context, event.window);
        println!("{} attr {} {}", event.window, attrs.width, attrs.height);
        // get window property
        let n = libx::get_text_property(self.context, event.window, xlib::XA_WM_NAME);
        match n {
            Some(s) => {debug!("create window {} for {}", event.window, s);}
            None => {}
        }

        // let atoms = libx::get_wm_protocols(self.context, event.window);
        // for a in atoms.iter() {
        //     println!("atom {}", a);
        //     let name = libx::get_atom_name(self.context, *a);
        //     match name {
        //         Some(n) => println!("name {}", n),
        //         None => println!("name {}", a),
        //     };
        // }
    }

    pub fn handle_destroy(&mut self, event: &xlib::XDestroyWindowEvent) {
        self.workspaces.remove_window(event.window);
        if self.workspaces.get_focus().is_none() {
            self.workspaces.set_focus(self.context.root);
        }
    }

    pub fn handle_map_request(&mut self, event: &xlib::XMapRequestEvent) {

        // add app top-level window to workspace
        // let window = Window::new(self.context, event.window);
        let manage = Workspaces::can_manage(self.context, event.window);

        if manage {
            debug!("top level window");
            let mut container = Container::from_id(self.context, event.window);
            container.map();
            // container.focus();
            // change attributes before display
            let mask = 0x420010;
            let mask = xlib::EnterWindowMask | xlib::PropertyChangeMask;
            libx::select_input(self.context, container.id, mask);

            if self.config.titlebar_height > 0 {
                container.titlebar_height = self.config.titlebar_height as usize;
            }
            self.workspaces.insert_window(container);
        }
        else {
            libx::map_window(self.context, event.window);
        }
    }

    pub fn handle_client_message(&mut self, event: &xlib::XClientMessageEvent) {
        println!("message type {}", event.message_type);
        let s = libx::get_atom_name(self.context, event.message_type);
        match s {
            Some(v) => println!("{}", &v),
            None => {}
        }

        match event.format {
            8 => {
                for i in 0..20 {
                    println!("{}", event.data.get_byte(i));
                }
            }
            16 => {
                for i in 0..10 {
                    println!("{}", event.data.get_short(i))
                }
            }
            32 => {
                for i in 0..5 {
                    let a = event.data.get_long(i);
                    if a != 0{
                        let s = libx::get_atom_name(self.context, a as xlib::Atom);
                        match s {
                            Some(v) => println!("{}", v),
                            None => {}
                        }
                    }
                }
            }
            _ => {}
        }
    }

    pub fn handle_button_motion(&mut self, event: &xlib::XMotionEvent) {
        let (window, _) = libx::get_input_focus(self.context);
        if window != event.window {
            self.workspaces.set_focus(event.window);
        }
    }

    pub fn handle_button_press(&mut self, event: &xlib::XButtonEvent) {
        let id = match self.workspaces.get_container(event.window) {
            Some((_,c)) => {
                let client = c.query_point(event.x, event.y);
                match client {
                    Some(c) => {
                        c.id
                    }
                    None => { return }
                }
            }
            None => { return }
        };
        self.workspaces.set_focus(id);
    }
    pub fn handle_key_release(&mut self, event: &xlib::XKeyEvent) {
        if event.state > 0 {
            let sym = libx::lookup_keysym(*event, 0);
            let b = handler::KeyBind {
                key: sym,
                mask: event.state,
            };
            debug!("key {} {}", event.state, sym);

            match self.config.bindsyms.get_mut(&b) {
                Some(handler) => {
                    handler.handle(&mut self.workspaces, self.context);
                }
                None => {
                    println!("no bind");
                }
            }
        }
    }

    pub fn handle_property(&mut self, event: &xlib::XPropertyEvent) {
        let usertime = libx::get_atom(self.context, "_NET_WM_USER_TIME");
        match event.atom {
            usertime => {
                debug!("_NET_WM_USER_TIME");
                // let window = Window::new(self.context, event.window);
                self.workspaces.set_focus(event.window);
            }
        }
    }

    pub fn handle_configure_request(&mut self, event: &xlib::XConfigureRequestEvent) {
        let mut change = xlib::XWindowChanges {
            x: event.x,
            y: event.y,
            width: event.width,
            height: event.height,
            border_width: event.border_width,
            sibling: event.above,
            stack_mode: event.detail
        };
        debug!("config x: {}, y: {}, width: {}, height: {}",
               change.x, change.y, change.width, change.height);
        libx::configure_window(self.context, event.window, event.value_mask as u32, change);
    }

    pub fn handle_focus_in(&mut self, event: &xlib::XFocusChangeEvent) {
        self.workspaces.set_focus(event.window);
      }

    pub fn handle_enter(&mut self, event: &xlib::XCrossingEvent){
        if event.focus == 0 {
            self.workspaces.set_focus(event.window);
        }
    }

    pub fn handle(&mut self, e: xlib::XEvent) {
        let t = e.get_type();
        match t {
            xlib::CreateNotify => {
                let event: xlib::XCreateWindowEvent = From::from(e);
                debug!("create notify {}", event.window);
                self.handle_create(&event);
            }
            xlib::DestroyNotify => {
                let event: xlib::XDestroyWindowEvent = From::from(e);
                debug!("destroy notify {}", event.window);
                self.handle_destroy(&event);
            }
            xlib::MapNotify => {
                let event: xlib::XMapEvent = From::from(e);
                debug!("map notify {}", event.window);
            }
            xlib::UnmapNotify => {
                let event: xlib::XUnmapEvent = From::from(e);
                debug!("unmap notify {}", event.window);
            }
            xlib::MapRequest => {
                let event: xlib::XMapRequestEvent = From::from(e);
                debug!("map request {}", event.window);
                self.handle_map_request(&event);
            }
            xlib::ClientMessage => {
                debug!("client message");
                // let event = cast_event::<xlib::XClientMessageEvent>(&e);
                let event: xlib::XClientMessageEvent = From::from(e);
                self.handle_client_message(&event);
            }
            xlib::KeyRelease => {
                debug!("key release");
                let mut event: xlib::XKeyEvent = From::from(e);
                self.handle_key_release(&mut event);
            }
            xlib::MotionNotify => {
                let mut event: xlib::XMotionEvent = From::from(e);
                debug!("button motion {}", event.window);
                self.handle_button_motion(&event);
            }
            xlib::ButtonRelease => {
                let mut event: xlib::XButtonEvent = From::from(e);
                debug!("button release {}", event.window);
            }
            xlib::ButtonPress => {
                let mut event: xlib::XButtonEvent = From::from(e);
                debug!("button press {}", event.window);
                self.handle_button_press(&event);
            }
            xlib::ConfigureNotify => {
                debug!("configure notify");
            }
            xlib::ConfigureRequest =>{
                let mut event: xlib::XConfigureRequestEvent = From::from(e);
                debug!("configure request {}", event.window);
                self.handle_configure_request(&event);
            }
            xlib::FocusIn => {
                let mut event: xlib::XFocusChangeEvent = From::from(e);
                debug!("focus in {}", event.window);
                self.handle_focus_in(&event);

            }
            xlib::FocusOut => {
                let mut event: xlib::XFocusChangeEvent = From::from(e);
                debug!("focus out {}", event.window);
            }
            xlib::EnterNotify => {
                let mut event: xlib::XCrossingEvent = From::from(e);
                debug!("enter window {}", event.window);
                self.handle_enter(&event);
            }
            xlib::PropertyNotify => {
                let mut event: xlib::XPropertyEvent = From::from(e);
                debug!("property notify {}", event.window);
                self.handle_property(&event);
            }
            _ => {
                debug!("unhandled event {}", t);
            }
        }
    }
    pub fn run(&mut self) {
        loop {
            //handle events here
            let mut e = libx::next_event(self.context);
            self.handle(e);
        }
    }

    pub fn init(&mut self) {
        let mask = 0x1A0034;
        let mask = xlib::SubstructureRedirectMask | xlib::SubstructureNotifyMask | xlib::ButtonPressMask;

        unsafe{
            // xlib::XSetErrorHandler(Some(error_handler));
        }
        let left_ptr: u32 = 68;
        libx::define_cursor(self.context, self.context.root, left_ptr);

        libx::ungrab_button(self.context, 0, 0x8000, self.context.root);
        libx::select_input(self.context, self.context.root,
                           mask);

        for bind in self.config.bindsyms.keys() {
            let code = libx::keysym_to_keycode(self.context, bind.key);
            libx::grab_key(self.context, code, bind.mask, self.context.root);
        }
        libx::sync(self.context, 0);

        self.init_workspaces();
    }

    fn init_workspaces(&mut self) {
        self.workspaces.switch_workspace('1', self.context);
    }
}
<commit_msg>focus on client or self<commit_after>extern crate libc;

use x11::xlib;
use x11::xlib::Window;
use super::super::libx;

use super::config::Config;
use super::Container;
use super::Workspaces;
use super::handler;

unsafe extern fn error_handler(display: *mut xlib::Display, event: *mut xlib::XErrorEvent) -> libc::c_int {
    // match event.error_code {
    //     xlib::BadAtom => {
    //         println!("bad atom");
    //     }
    //     _ => {}
    // }
    1
}

fn load_resource(mut context: &mut libx::Context) {
    use std::mem;
    use std::ffi;
    let screen = context.screen_num;
    let root = context.root;
    let display = context.display;
    let mut values: xlib::XGCValues = unsafe{ mem::zeroed() };
    // let gc = libx::create_gc(self.context, self.id, 0, values);
    let gc = libx::default_gc(*context, screen);

    unsafe {
        let black = xlib::XBlackPixel(display, screen);
        let white = xlib::XWhitePixel(display, screen);

        xlib::XSetLineAttributes(display, gc, 5, 0, 0, 0);

        let cmap = xlib::XDefaultColormap(display, screen);
        let mut color: xlib::XColor = mem::zeroed();
        let name = ffi::CString::new("blue").unwrap().as_ptr();
        let r = xlib::XParseColor(display, cmap, name, &mut color);
        xlib::XAllocColor(display, cmap, &mut color);

        context.gc = gc;
        context.focus_bg = black;
        context.focus_fg = color.pixel;
        context.unfocus_bg = black;
        context.unfocus_fg = black;
    }
}

pub struct WindowManager {
    pub context: libx::Context,
    pub workspaces: Workspaces,
    config: Config
}

impl WindowManager {
    pub fn new() -> WindowManager {
	let res = libx::open_display(None);
        let mut context = match res {
            Some(c) => {
                c
            }
            None => {
                panic!("can't open display")
            }
        };

	context.screen_num  = libx::default_screen(context);
	context.root = libx::root_window(context, context.screen_num);
        load_resource(&mut context);

	let mut wm = WindowManager {
            context: context,
            config: Config::load(),
            workspaces: Workspaces::new(context)
        };
        wm
    }

    pub fn clean(&mut self) {
        libx::close_display(self.context);
    }

    pub fn handle_create(&mut self, event: &xlib::XCreateWindowEvent) {
        if event.override_redirect != 0 {
            return;
        }

        let attrs = libx::get_window_attributes(self.context, event.window);
        println!("{} attr {} {}", event.window, attrs.width, attrs.height);
        // get window property
        let n = libx::get_text_property(self.context, event.window, xlib::XA_WM_NAME);
        match n {
            Some(s) => {debug!("create window {} for {}", event.window, s);}
            None => {}
        }

        // let atoms = libx::get_wm_protocols(self.context, event.window);
        // for a in atoms.iter() {
        //     println!("atom {}", a);
        //     let name = libx::get_atom_name(self.context, *a);
        //     match name {
        //         Some(n) => println!("name {}", n),
        //         None => println!("name {}", a),
        //     };
        // }
    }

    pub fn handle_destroy(&mut self, event: &xlib::XDestroyWindowEvent) {
        self.workspaces.remove_window(event.window);
        if self.workspaces.get_focus().is_none() {
            self.workspaces.set_focus(self.context.root);
        }
    }

    pub fn handle_map_request(&mut self, event: &xlib::XMapRequestEvent) {

        // add app top-level window to workspace
        // let window = Window::new(self.context, event.window);
        let manage = Workspaces::can_manage(self.context, event.window);

        if manage {
            debug!("top level window");
            let mut container = Container::from_id(self.context, event.window);
            container.map();
            // container.focus();
            // change attributes before display
            let mask = 0x420010;
            let mask = xlib::EnterWindowMask | xlib::PropertyChangeMask;
            libx::select_input(self.context, container.id, mask);

            if self.config.titlebar_height > 0 {
                container.titlebar_height = self.config.titlebar_height as usize;
            }
            self.workspaces.insert_window(container);
        }
        else {
            libx::map_window(self.context, event.window);
        }
    }

    pub fn handle_client_message(&mut self, event: &xlib::XClientMessageEvent) {
        println!("message type {}", event.message_type);
        let s = libx::get_atom_name(self.context, event.message_type);
        match s {
            Some(v) => println!("{}", &v),
            None => {}
        }

        match event.format {
            8 => {
                for i in 0..20 {
                    println!("{}", event.data.get_byte(i));
                }
            }
            16 => {
                for i in 0..10 {
                    println!("{}", event.data.get_short(i))
                }
            }
            32 => {
                for i in 0..5 {
                    let a = event.data.get_long(i);
                    if a != 0{
                        let s = libx::get_atom_name(self.context, a as xlib::Atom);
                        match s {
                            Some(v) => println!("{}", v),
                            None => {}
                        }
                    }
                }
            }
            _ => {}
        }
    }

    pub fn handle_button_motion(&mut self, event: &xlib::XMotionEvent) {
        let (window, _) = libx::get_input_focus(self.context);
        if window != event.window {
            self.workspaces.set_focus(event.window);
        }
    }

    pub fn handle_button_press(&mut self, event: &xlib::XButtonEvent) {
        let id = match self.workspaces.get_container(event.window) {
            Some((_,container)) => {
                let client = container.query_point(event.x, event.y);
                match client {
                    Some(c) => {
                        c.id
                    }
                    None => { container.id }
                }
            }
            None => { return }
        };
        self.workspaces.set_focus(id);
    }
    pub fn handle_key_release(&mut self, event: &xlib::XKeyEvent) {
        if event.state > 0 {
            let sym = libx::lookup_keysym(*event, 0);
            let b = handler::KeyBind {
                key: sym,
                mask: event.state,
            };
            debug!("key {} {}", event.state, sym);

            match self.config.bindsyms.get_mut(&b) {
                Some(handler) => {
                    handler.handle(&mut self.workspaces, self.context);
                }
                None => {
                    println!("no bind");
                }
            }
        }
    }

    pub fn handle_property(&mut self, event: &xlib::XPropertyEvent) {
        let usertime = libx::get_atom(self.context, "_NET_WM_USER_TIME");
        match event.atom {
            usertime => {
                debug!("_NET_WM_USER_TIME");
                // let window = Window::new(self.context, event.window);
                self.workspaces.set_focus(event.window);
            }
        }
    }

    pub fn handle_configure_request(&mut self, event: &xlib::XConfigureRequestEvent) {
        let mut change = xlib::XWindowChanges {
            x: event.x,
            y: event.y,
            width: event.width,
            height: event.height,
            border_width: event.border_width,
            sibling: event.above,
            stack_mode: event.detail
        };
        debug!("config x: {}, y: {}, width: {}, height: {}",
               change.x, change.y, change.width, change.height);
        libx::configure_window(self.context, event.window, event.value_mask as u32, change);
    }

    pub fn handle_focus_in(&mut self, event: &xlib::XFocusChangeEvent) {
        self.workspaces.set_focus(event.window);
      }

    pub fn handle_enter(&mut self, event: &xlib::XCrossingEvent){
        if event.focus == 0 {
            self.workspaces.set_focus(event.window);
        }
    }

    pub fn handle(&mut self, e: xlib::XEvent) {
        let t = e.get_type();
        match t {
            xlib::CreateNotify => {
                let event: xlib::XCreateWindowEvent = From::from(e);
                debug!("create notify {}", event.window);
                self.handle_create(&event);
            }
            xlib::DestroyNotify => {
                let event: xlib::XDestroyWindowEvent = From::from(e);
                debug!("destroy notify {}", event.window);
                self.handle_destroy(&event);
            }
            xlib::MapNotify => {
                let event: xlib::XMapEvent = From::from(e);
                debug!("map notify {}", event.window);
            }
            xlib::UnmapNotify => {
                let event: xlib::XUnmapEvent = From::from(e);
                debug!("unmap notify {}", event.window);
            }
            xlib::MapRequest => {
                let event: xlib::XMapRequestEvent = From::from(e);
                debug!("map request {}", event.window);
                self.handle_map_request(&event);
            }
            xlib::ClientMessage => {
                debug!("client message");
                // let event = cast_event::<xlib::XClientMessageEvent>(&e);
                let event: xlib::XClientMessageEvent = From::from(e);
                self.handle_client_message(&event);
            }
            xlib::KeyRelease => {
                debug!("key release");
                let mut event: xlib::XKeyEvent = From::from(e);
                self.handle_key_release(&mut event);
            }
            xlib::MotionNotify => {
                let mut event: xlib::XMotionEvent = From::from(e);
                debug!("button motion {}", event.window);
                self.handle_button_motion(&event);
            }
            xlib::ButtonRelease => {
                let mut event: xlib::XButtonEvent = From::from(e);
                debug!("button release {}", event.window);
            }
            xlib::ButtonPress => {
                let mut event: xlib::XButtonEvent = From::from(e);
                debug!("button press {}", event.window);
                self.handle_button_press(&event);
            }
            xlib::ConfigureNotify => {
                debug!("configure notify");
            }
            xlib::ConfigureRequest =>{
                let mut event: xlib::XConfigureRequestEvent = From::from(e);
                debug!("configure request {}", event.window);
                self.handle_configure_request(&event);
            }
            xlib::FocusIn => {
                let mut event: xlib::XFocusChangeEvent = From::from(e);
                debug!("focus in {}", event.window);
                self.handle_focus_in(&event);

            }
            xlib::FocusOut => {
                let mut event: xlib::XFocusChangeEvent = From::from(e);
                debug!("focus out {}", event.window);
            }
            xlib::EnterNotify => {
                let mut event: xlib::XCrossingEvent = From::from(e);
                debug!("enter window {}", event.window);
                self.handle_enter(&event);
            }
            xlib::PropertyNotify => {
                let mut event: xlib::XPropertyEvent = From::from(e);
                debug!("property notify {}", event.window);
                self.handle_property(&event);
            }
            _ => {
                debug!("unhandled event {}", t);
            }
        }
    }
    pub fn run(&mut self) {
        loop {
            //handle events here
            let mut e = libx::next_event(self.context);
            self.handle(e);
        }
    }

    pub fn init(&mut self) {
        let mask = 0x1A0034;
        let mask = xlib::SubstructureRedirectMask | xlib::SubstructureNotifyMask | xlib::ButtonPressMask;

        unsafe{
            // xlib::XSetErrorHandler(Some(error_handler));
        }
        let left_ptr: u32 = 68;
        libx::define_cursor(self.context, self.context.root, left_ptr);

        libx::ungrab_button(self.context, 0, 0x8000, self.context.root);
        libx::select_input(self.context, self.context.root,
                           mask);

        for bind in self.config.bindsyms.keys() {
            let code = libx::keysym_to_keycode(self.context, bind.key);
            libx::grab_key(self.context, code, bind.mask, self.context.root);
        }
        libx::sync(self.context, 0);

        self.init_workspaces();
    }

    fn init_workspaces(&mut self) {
        self.workspaces.switch_workspace('1', self.context);
    }
}
<|endoftext|>


<commit_before>use std::ops::Range;
use std::sync::Arc;

use super::ast::{self, Assignment, Ast, AstKind, Identifier, Int, Struct, Symbol, Text};
use super::cst::{self, CstDb};
use super::cst_to_ast::CstToAst;
use super::error::CompilerError;
use super::hir::{self, Body, Expression, Lambda};
use crate::builtin_functions;
use crate::input::Input;
use im::HashMap;

#[salsa::query_group(AstToHirStorage)]
pub trait AstToHir: CstDb + CstToAst {
    fn hir_to_ast_id(&self, input: Input, id: hir::Id) -> Option<ast::Id>;
    fn hir_to_cst_id(&self, input: Input, id: hir::Id) -> Option<cst::Id>;
    fn hir_id_to_span(&self, input: Input, id: hir::Id) -> Option<Range<usize>>;
    fn hir_id_to_display_span(&self, input: Input, id: hir::Id) -> Option<Range<usize>>;

    fn ast_to_hir_id(&self, input: Input, id: ast::Id) -> Option<hir::Id>;
    fn cst_to_hir_id(&self, input: Input, id: cst::Id) -> Option<hir::Id>;

    fn hir(&self, input: Input) -> Option<(Arc<Body>, HashMap<hir::Id, ast::Id>)>;
    fn hir_raw(
        &self,
        input: Input,
    ) -> Option<(Arc<Body>, HashMap<hir::Id, ast::Id>, Vec<CompilerError>)>;
}

fn hir_to_ast_id(db: &dyn AstToHir, input: Input, id: hir::Id) -> Option<ast::Id> {
    let (_, hir_to_ast_id_mapping) = db.hir(input).unwrap();
    hir_to_ast_id_mapping.get(&id).cloned()
}
fn hir_to_cst_id(db: &dyn AstToHir, input: Input, id: hir::Id) -> Option<cst::Id> {
    let id = db.hir_to_ast_id(input.clone(), id)?;
    db.ast_to_cst_id(input, id)
}
fn hir_id_to_span(db: &dyn AstToHir, input: Input, id: hir::Id) -> Option<Range<usize>> {
    let id = db.hir_to_ast_id(input.clone(), id)?;
    db.ast_id_to_span(input, id)
}
fn hir_id_to_display_span(db: &dyn AstToHir, input: Input, id: hir::Id) -> Option<Range<usize>> {
    let id = db.hir_to_cst_id(input.clone(), id)?;
    Some(db.find_cst(input, id).display_span())
}

fn ast_to_hir_id(db: &dyn AstToHir, input: Input, id: ast::Id) -> Option<hir::Id> {
    let (_, hir_to_ast_id_mapping) = db.hir(input).unwrap();
    hir_to_ast_id_mapping
        .iter()
        .find_map(|(key, &value)| if value == id { Some(key) } else { None })
        .cloned()
}
fn cst_to_hir_id(db: &dyn AstToHir, input: Input, id: cst::Id) -> Option<hir::Id> {
    let id = db.cst_to_ast_id(input.clone(), id)?;
    db.ast_to_hir_id(input, id)
}

fn hir(db: &dyn AstToHir, input: Input) -> Option<(Arc<Body>, HashMap<hir::Id, ast::Id>)> {
    db.hir_raw(input)
        .map(|(hir, id_mapping, _)| (hir, id_mapping))
}
fn hir_raw(
    db: &dyn AstToHir,
    input: Input,
) -> Option<(Arc<Body>, HashMap<hir::Id, ast::Id>, Vec<CompilerError>)> {
    let (ast, _) = db.ast(input.clone())?;

    let mut context = Context {
        db,
        input: input.clone(),
    };
    let mut compiler = Compiler::new(&mut context);
    compiler.compile(&ast);
    Some((
        Arc::new(compiler.body),
        compiler.output.id_mapping,
        compiler.output.errors,
    ))
}

struct Context<'c> {
    db: &'c dyn AstToHir,
    input: Input,
}

#[derive(Clone)]
struct Output {
    id_mapping: HashMap<hir::Id, ast::Id>,
    errors: Vec<CompilerError>,
}

struct Compiler<'c> {
    context: &'c Context<'c>,
    output: Output,
    body: Body,
    parent_ids: Vec<usize>,
    next_id: usize,
    identifiers: HashMap<String, hir::Id>,
}
impl<'c> Compiler<'c> {
    fn new(context: &'c Context<'c>) -> Self {
        let builtin_identifiers = builtin_functions::VALUES
            .iter()
            .enumerate()
            .map(|(index, builtin_function)| {
                let string = format!("builtin{:?}", builtin_function);
                (string, hir::Id(vec![index]))
            })
            .collect::<HashMap<_, _>>();

        Compiler {
            context,
            output: Output {
                id_mapping: HashMap::new(),
                errors: vec![],
            },
            parent_ids: vec![],
            next_id: builtin_identifiers.len(),
            body: Body::new(),
            identifiers: builtin_identifiers,
        }
    }

    fn compile(&mut self, asts: &[Ast]) {
        if asts.is_empty() {
            self.body.out = Some(self.push_without_ast_mapping(Expression::nothing()));
        } else {
            for ast in asts.into_iter() {
                self.body.out = Some(self.compile_single(ast));
            }
        }
    }
    fn compile_single(&mut self, ast: &Ast) -> hir::Id {
        match &ast.kind {
            AstKind::Int(Int(int)) => self.push(ast.id, Expression::Int(int.to_owned()), None),
            AstKind::Text(Text(string)) => {
                self.push(ast.id, Expression::Text(string.value.to_owned()), None)
            }
            AstKind::Identifier(Identifier(symbol)) => {
                let reference = match self.identifiers.get(&symbol.value) {
                    Some(reference) => reference.to_owned(),
                    None => {
                        self.output.errors.push(CompilerError {
                            message: format!("Unknown reference: {}", symbol.value),
                            span: self
                                .context
                                .db
                                .ast_id_to_span(self.context.input.clone(), symbol.id)
                                .unwrap(),
                        });
                        return self.push(symbol.id, Expression::Error, None);
                    }
                };
                self.push(ast.id, Expression::Reference(reference.to_owned()), None)
            }
            AstKind::Symbol(Symbol(symbol)) => {
                self.push(ast.id, Expression::Symbol(symbol.value.to_owned()), None)
            }
            AstKind::Struct(Struct { entries }) => {
                let entries = entries
                    .iter()
                    .map(|(key, value)| (self.compile_single(key), self.compile_single(value)))
                    .collect();
                self.push(ast.id, Expression::Struct(entries), None)
            }
            AstKind::Lambda(ast::Lambda {
                parameters,
                body: body_asts,
            }) => {
                let mut body = Body::new();
                let lambda_id = add_ids(&self.parent_ids, self.next_id);
                let mut identifiers = self.identifiers.clone();

                for (parameter_index, parameter) in parameters.iter().enumerate() {
                    let id = hir::Id(add_ids(&lambda_id, parameter_index));
                    body.identifiers
                        .insert(id.to_owned(), parameter.value.to_owned());
                    identifiers.insert(parameter.value.to_owned(), id);
                }
                let mut inner = Compiler::<'c> {
                    context: &mut self.context,
                    output: self.output.clone(),
                    body,
                    parent_ids: lambda_id.to_owned(),
                    next_id: parameters.len(),
                    identifiers,
                };

                inner.compile(&body_asts);
                self.output = inner.output;
                self.push(
                    ast.id,
                    Expression::Lambda(Lambda {
                        first_id: hir::Id(add_ids(&lambda_id[..], 0)),
                        parameters: parameters.iter().map(|it| it.value.to_owned()).collect(),
                        body: inner.body,
                    }),
                    None,
                )
            }
            AstKind::Call(ast::Call { name, arguments }) => {
                let arguments = arguments
                    .iter()
                    .map(|argument| self.compile_single(argument))
                    .collect();

                let function = match self.identifiers.get(&name.value) {
                    Some(function) => function.to_owned(),
                    None => {
                        self.output.errors.push(CompilerError {
                            message: format!("Unknown function: {}", name.value),
                            span: self
                                .context
                                .db
                                .ast_id_to_span(self.context.input.clone(), name.id)
                                .unwrap(),
                        });
                        return self.push(name.id, Expression::Error, None);
                    }
                };
                self.push(
                    ast.id,
                    Expression::Call {
                        function,
                        arguments,
                    },
                    None,
                )
            }
            AstKind::Assignment(Assignment { name, body }) => {
                let mut inner = Compiler::<'c> {
                    context: &mut self.context,
                    output: self.output.clone(),
                    body: Body::new(),
                    parent_ids: add_ids(&self.parent_ids, self.next_id),
                    next_id: 0,
                    identifiers: self.identifiers.clone(),
                };
                inner.compile(&body);
                self.output = inner.output;
                self.push(
                    ast.id,
                    Expression::Body(inner.body),
                    Some(name.value.to_owned()),
                )
            }
            AstKind::Error => self.push(ast.id, Expression::Error, None),
        }
    }

    fn push(
        &mut self,
        ast_id: ast::Id,
        expression: Expression,
        identifier: Option<String>,
    ) -> hir::Id {
        let id = self.create_next_id(ast_id);
        self.body.push(id.clone(), expression, identifier.clone());
        self.output.id_mapping.insert(id.clone(), ast_id);
        if let Some(identifier) = identifier {
            self.identifiers.insert(identifier, id.clone());
        }
        id
    }
    fn push_without_ast_mapping(&mut self, expression: Expression) -> hir::Id {
        let id = self.create_next_id_without_ast_mapping();
        self.body.push(id.to_owned(), expression, None);
        id
    }

    fn create_next_id(&mut self, ast_id: ast::Id) -> hir::Id {
        let id = self.create_next_id_without_ast_mapping();
        assert!(matches!(
            self.output.id_mapping.insert(id.to_owned(), ast_id),
            None
        ));
        id
    }
    fn create_next_id_without_ast_mapping(&mut self) -> hir::Id {
        let id = hir::Id(add_ids(&self.parent_ids, self.next_id));
        self.next_id += 1;
        id
    }
}

fn add_ids(parents: &[usize], id: usize) -> Vec<usize> {
    parents.iter().map(|it| *it).chain(vec![id]).collect()
}
<commit_msg>fix(compiler): store HIR → AST ID mapping for parameters<commit_after>use std::ops::Range;
use std::sync::Arc;

use super::ast::{self, Assignment, Ast, AstKind, Identifier, Int, Struct, Symbol, Text};
use super::cst::{self, CstDb};
use super::cst_to_ast::CstToAst;
use super::error::CompilerError;
use super::hir::{self, Body, Expression, Lambda};
use crate::builtin_functions;
use crate::input::Input;
use im::HashMap;

#[salsa::query_group(AstToHirStorage)]
pub trait AstToHir: CstDb + CstToAst {
    fn hir_to_ast_id(&self, input: Input, id: hir::Id) -> Option<ast::Id>;
    fn hir_to_cst_id(&self, input: Input, id: hir::Id) -> Option<cst::Id>;
    fn hir_id_to_span(&self, input: Input, id: hir::Id) -> Option<Range<usize>>;
    fn hir_id_to_display_span(&self, input: Input, id: hir::Id) -> Option<Range<usize>>;

    fn ast_to_hir_id(&self, input: Input, id: ast::Id) -> Option<hir::Id>;
    fn cst_to_hir_id(&self, input: Input, id: cst::Id) -> Option<hir::Id>;

    fn hir(&self, input: Input) -> Option<(Arc<Body>, HashMap<hir::Id, ast::Id>)>;
    fn hir_raw(
        &self,
        input: Input,
    ) -> Option<(Arc<Body>, HashMap<hir::Id, ast::Id>, Vec<CompilerError>)>;
}

fn hir_to_ast_id(db: &dyn AstToHir, input: Input, id: hir::Id) -> Option<ast::Id> {
    let (_, hir_to_ast_id_mapping) = db.hir(input).unwrap();
    hir_to_ast_id_mapping.get(&id).cloned()
}
fn hir_to_cst_id(db: &dyn AstToHir, input: Input, id: hir::Id) -> Option<cst::Id> {
    let id = db.hir_to_ast_id(input.clone(), id)?;
    db.ast_to_cst_id(input, id)
}
fn hir_id_to_span(db: &dyn AstToHir, input: Input, id: hir::Id) -> Option<Range<usize>> {
    let id = db.hir_to_ast_id(input.clone(), id)?;
    db.ast_id_to_span(input, id)
}
fn hir_id_to_display_span(db: &dyn AstToHir, input: Input, id: hir::Id) -> Option<Range<usize>> {
    let id = db.hir_to_cst_id(input.clone(), id)?;
    Some(db.find_cst(input, id).display_span())
}

fn ast_to_hir_id(db: &dyn AstToHir, input: Input, id: ast::Id) -> Option<hir::Id> {
    let (_, hir_to_ast_id_mapping) = db.hir(input).unwrap();
    hir_to_ast_id_mapping
        .iter()
        .find_map(|(key, &value)| if value == id { Some(key) } else { None })
        .cloned()
}
fn cst_to_hir_id(db: &dyn AstToHir, input: Input, id: cst::Id) -> Option<hir::Id> {
    let id = db.cst_to_ast_id(input.clone(), id)?;
    db.ast_to_hir_id(input, id)
}

fn hir(db: &dyn AstToHir, input: Input) -> Option<(Arc<Body>, HashMap<hir::Id, ast::Id>)> {
    db.hir_raw(input)
        .map(|(hir, id_mapping, _)| (hir, id_mapping))
}
fn hir_raw(
    db: &dyn AstToHir,
    input: Input,
) -> Option<(Arc<Body>, HashMap<hir::Id, ast::Id>, Vec<CompilerError>)> {
    let (ast, _) = db.ast(input.clone())?;

    let mut context = Context {
        db,
        input: input.clone(),
    };
    let mut compiler = Compiler::new(&mut context);
    compiler.compile(&ast);
    Some((
        Arc::new(compiler.body),
        compiler.output.id_mapping,
        compiler.output.errors,
    ))
}

struct Context<'c> {
    db: &'c dyn AstToHir,
    input: Input,
}

#[derive(Clone)]
struct Output {
    id_mapping: HashMap<hir::Id, ast::Id>,
    errors: Vec<CompilerError>,
}

struct Compiler<'c> {
    context: &'c Context<'c>,
    output: Output,
    body: Body,
    parent_ids: Vec<usize>,
    next_id: usize,
    identifiers: HashMap<String, hir::Id>,
}
impl<'c> Compiler<'c> {
    fn new(context: &'c Context<'c>) -> Self {
        let builtin_identifiers = builtin_functions::VALUES
            .iter()
            .enumerate()
            .map(|(index, builtin_function)| {
                let string = format!("builtin{:?}", builtin_function);
                (string, hir::Id(vec![index]))
            })
            .collect::<HashMap<_, _>>();

        Compiler {
            context,
            output: Output {
                id_mapping: HashMap::new(),
                errors: vec![],
            },
            parent_ids: vec![],
            next_id: builtin_identifiers.len(),
            body: Body::new(),
            identifiers: builtin_identifiers,
        }
    }

    fn compile(&mut self, asts: &[Ast]) {
        if asts.is_empty() {
            self.body.out = Some(self.push_without_ast_mapping(Expression::nothing()));
        } else {
            for ast in asts.into_iter() {
                self.body.out = Some(self.compile_single(ast));
            }
        }
    }
    fn compile_single(&mut self, ast: &Ast) -> hir::Id {
        match &ast.kind {
            AstKind::Int(Int(int)) => self.push(ast.id, Expression::Int(int.to_owned()), None),
            AstKind::Text(Text(string)) => {
                self.push(ast.id, Expression::Text(string.value.to_owned()), None)
            }
            AstKind::Identifier(Identifier(symbol)) => {
                let reference = match self.identifiers.get(&symbol.value) {
                    Some(reference) => reference.to_owned(),
                    None => {
                        self.output.errors.push(CompilerError {
                            message: format!("Unknown reference: {}", symbol.value),
                            span: self
                                .context
                                .db
                                .ast_id_to_span(self.context.input.clone(), symbol.id)
                                .unwrap(),
                        });
                        return self.push(symbol.id, Expression::Error, None);
                    }
                };
                self.push(ast.id, Expression::Reference(reference.to_owned()), None)
            }
            AstKind::Symbol(Symbol(symbol)) => {
                self.push(ast.id, Expression::Symbol(symbol.value.to_owned()), None)
            }
            AstKind::Struct(Struct { entries }) => {
                let entries = entries
                    .iter()
                    .map(|(key, value)| (self.compile_single(key), self.compile_single(value)))
                    .collect();
                self.push(ast.id, Expression::Struct(entries), None)
            }
            AstKind::Lambda(ast::Lambda {
                parameters,
                body: body_asts,
            }) => {
                let mut body = Body::new();
                let lambda_id = add_ids(&self.parent_ids, self.next_id);
                let mut identifiers = self.identifiers.clone();

                for (parameter_index, parameter) in parameters.iter().enumerate() {
                    let id = hir::Id(add_ids(&lambda_id, parameter_index));
                    self.output.id_mapping.insert(id.clone(), parameter.id);
                    body.identifiers
                        .insert(id.to_owned(), parameter.value.to_owned());
                    identifiers.insert(parameter.value.to_owned(), id);
                }
                let mut inner = Compiler::<'c> {
                    context: &mut self.context,
                    output: self.output.clone(),
                    body,
                    parent_ids: lambda_id.to_owned(),
                    next_id: parameters.len(),
                    identifiers,
                };

                inner.compile(&body_asts);
                self.output = inner.output;
                self.push(
                    ast.id,
                    Expression::Lambda(Lambda {
                        first_id: hir::Id(add_ids(&lambda_id[..], 0)),
                        parameters: parameters.iter().map(|it| it.value.to_owned()).collect(),
                        body: inner.body,
                    }),
                    None,
                )
            }
            AstKind::Call(ast::Call { name, arguments }) => {
                let arguments = arguments
                    .iter()
                    .map(|argument| self.compile_single(argument))
                    .collect();

                let function = match self.identifiers.get(&name.value) {
                    Some(function) => function.to_owned(),
                    None => {
                        self.output.errors.push(CompilerError {
                            message: format!("Unknown function: {}", name.value),
                            span: self
                                .context
                                .db
                                .ast_id_to_span(self.context.input.clone(), name.id)
                                .unwrap(),
                        });
                        return self.push(name.id, Expression::Error, None);
                    }
                };
                self.push(
                    ast.id,
                    Expression::Call {
                        function,
                        arguments,
                    },
                    None,
                )
            }
            AstKind::Assignment(Assignment { name, body }) => {
                let mut inner = Compiler::<'c> {
                    context: &mut self.context,
                    output: self.output.clone(),
                    body: Body::new(),
                    parent_ids: add_ids(&self.parent_ids, self.next_id),
                    next_id: 0,
                    identifiers: self.identifiers.clone(),
                };
                inner.compile(&body);
                self.output = inner.output;
                self.push(
                    ast.id,
                    Expression::Body(inner.body),
                    Some(name.value.to_owned()),
                )
            }
            AstKind::Error => self.push(ast.id, Expression::Error, None),
        }
    }

    fn push(
        &mut self,
        ast_id: ast::Id,
        expression: Expression,
        identifier: Option<String>,
    ) -> hir::Id {
        let id = self.create_next_id(ast_id);
        self.body.push(id.clone(), expression, identifier.clone());
        self.output.id_mapping.insert(id.clone(), ast_id);
        if let Some(identifier) = identifier {
            self.identifiers.insert(identifier, id.clone());
        }
        id
    }
    fn push_without_ast_mapping(&mut self, expression: Expression) -> hir::Id {
        let id = self.create_next_id_without_ast_mapping();
        self.body.push(id.to_owned(), expression, None);
        id
    }

    fn create_next_id(&mut self, ast_id: ast::Id) -> hir::Id {
        let id = self.create_next_id_without_ast_mapping();
        assert!(matches!(
            self.output.id_mapping.insert(id.to_owned(), ast_id),
            None
        ));
        id
    }
    fn create_next_id_without_ast_mapping(&mut self) -> hir::Id {
        let id = hir::Id(add_ids(&self.parent_ids, self.next_id));
        self.next_id += 1;
        id
    }
}

fn add_ids(parents: &[usize], id: usize) -> Vec<usize> {
    parents.iter().map(|it| *it).chain(vec![id]).collect()
}
<|endoftext|>


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

use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::WebSocketBinding;
use dom::bindings::codegen::Bindings::WebSocketBinding::WebSocketMethods;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::InheritTypes::EventTargetCast;
use dom::bindings::codegen::InheritTypes::EventCast;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::error::Error::{InvalidAccess, Syntax};
use dom::bindings::global::{GlobalField, GlobalRef};
use dom::bindings::js::Root;
use dom::bindings::refcounted::Trusted;
use dom::bindings::str::USVString;
use dom::bindings::trace::JSTraceable;
use dom::bindings::utils::reflect_dom_object;
use dom::closeevent::CloseEvent;
use dom::event::{Event, EventBubbles, EventCancelable, EventHelpers};
use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId};
use script_task::Runnable;
use script_task::ScriptMsg;
use std::cell::{Cell, RefCell};
use std::borrow::ToOwned;
use util::str::DOMString;

use hyper::header::Host;
use websocket::Message;
use websocket::ws::sender::Sender as Sender_Object;
use websocket::client::sender::Sender;
use websocket::client::receiver::Receiver;
use websocket::stream::WebSocketStream;
use websocket::client::request::Url;
use websocket::Client;
use websocket::header::Origin;
use websocket::result::WebSocketResult;
use websocket::ws::util::url::parse_url;

#[derive(JSTraceable, PartialEq, Copy, Clone)]
enum WebSocketRequestState {
    Connecting = 0,
    Open = 1,
    Closing = 2,
    Closed = 3,
}

no_jsmanaged_fields!(Sender<WebSocketStream>);

#[dom_struct]
pub struct WebSocket {
    eventtarget: EventTarget,
    url: Url,
    global: GlobalField,
    ready_state: Cell<WebSocketRequestState>,
    sender: RefCell<Option<Sender<WebSocketStream>>>,
    failed: Cell<bool>, //Flag to tell if websocket was closed due to failure
    full: Cell<bool>, //Flag to tell if websocket queue is full
    clean_close: Cell<bool>, //Flag to tell if the websocket closed cleanly (not due to full or fail)
    code: Cell<u16>, //Closing code
    reason: DOMRefCell<DOMString>, //Closing reason
    data: DOMRefCell<DOMString>, //Data from send - TODO: Remove after buffer is added.
}

/// *Establish a WebSocket Connection* as defined in RFC 6455.
fn establish_a_websocket_connection(url: (Host, String, bool), origin: String)
    -> WebSocketResult<(Sender<WebSocketStream>, Receiver<WebSocketStream>)> {
    let mut request = try!(Client::connect(url));
    request.headers.set(Origin(origin));

    let response = try!(request.send());
    try!(response.validate());

    Ok(response.begin().split())
}

impl WebSocket {
    pub fn new_inherited(global: GlobalRef, url: Url) -> WebSocket {
        WebSocket {
            eventtarget: EventTarget::new_inherited(EventTargetTypeId::WebSocket),
            url: url,
            global: GlobalField::from_rooted(&global),
            ready_state: Cell::new(WebSocketRequestState::Connecting),
            failed: Cell::new(false),
            sender: RefCell::new(None),
            full: Cell::new(false),
            clean_close: Cell::new(true),
            code: Cell::new(0),
            reason: DOMRefCell::new("".to_owned()),
            data: DOMRefCell::new("".to_owned()),
        }

    }

    pub fn new(global: GlobalRef,
               url: DOMString,
               protocols: Option<DOMString>)
               -> Fallible<Root<WebSocket>> {
        // Step 1.
        let parsed_url = try!(Url::parse(&url).map_err(|_| Error::Syntax));
        let url = try!(parse_url(&parsed_url).map_err(|_| Error::Syntax));

        // Step 4.
        let protocols = protocols.as_slice();

        // Step 5.
        for (i, protocol) in protocols.iter().enumerate() {
            // https://tools.ietf.org/html/rfc6455#section-4.1
            // Handshake requirements, step 10
            if protocol.is_empty() {
                return Err(Syntax);
            }

            if protocols[i+1..].iter().any(|p| p == protocol) {
                return Err(Syntax);
            }

            if protocol.chars().any(|c| c < '\u{0021}' || c > '\u{007E}') {
                return Err(Syntax);
            }
        }

        /*TODO: This constructor is only a prototype, it does not accomplish the specs
          defined here:
          http://html.spec.whatwg.org
          The remaining 8 items must be satisfied.
          TODO: This constructor should be responsible for spawning a thread for the
          receive loop after ws.r().Open() - See comment
        */
        let ws = reflect_dom_object(box WebSocket::new_inherited(global, parsed_url),
                                    global,
                                    WebSocketBinding::Wrap);

        let channel = establish_a_websocket_connection(url, global.get_url().serialize());
        let (temp_sender, _temp_receiver) = match channel {
            Ok(channel) => channel,
            Err(e) => {
                debug!("Failed to establish a WebSocket connection: {:?}", e);
                let global_root = ws.r().global.root();
                let address = Trusted::new(global_root.r().get_cx(), ws.r(), global_root.r().script_chan().clone());
                let task = box CloseTask {
                    addr: address,
                };
                global_root.r().script_chan().send(ScriptMsg::RunnableMsg(task)).unwrap();
                return Ok(ws);
            }
        };

        *ws.r().sender.borrow_mut() = Some(temp_sender);

        //Create everything necessary for starting the open asynchronous task, then begin the task.
        let global_root = ws.r().global.root();
        let addr: Trusted<WebSocket> =
            Trusted::new(global_root.r().get_cx(), ws.r(), global_root.r().script_chan().clone());
        let open_task = box ConnectionEstablishedTask {
            addr: addr,
        };
        global_root.r().script_chan().send(ScriptMsg::RunnableMsg(open_task)).unwrap();
        //TODO: Spawn thread here for receive loop
        /*TODO: Add receive loop here and make new thread run this
          Receive is an infinite loop "similiar" the one shown here:
          https://github.com/cyderize/rust-websocket/blob/master/examples/client.rs#L64
          TODO: The receive loop however does need to follow the spec. These are outlined here
          under "WebSocket message has been received" items 1-5:
          https://github.com/cyderize/rust-websocket/blob/master/examples/client.rs#L64
          TODO: The receive loop also needs to dispatch an asynchronous event as stated here:
          https://github.com/cyderize/rust-websocket/blob/master/examples/client.rs#L64
          TODO: When the receive loop receives a close message from the server,
          it confirms the websocket is now closed. This requires the close event
          to be fired (dispatch_close fires the close event - see implementation below)
        */
        Ok(ws)
    }

    pub fn Constructor(global: GlobalRef,
                       url: DOMString,
                       protocols: Option<DOMString>)
                       -> Fallible<Root<WebSocket>> {
        WebSocket::new(global, url, protocols)
    }
}

impl<'a> WebSocketMethods for &'a WebSocket {
    event_handler!(open, GetOnopen, SetOnopen);
    event_handler!(close, GetOnclose, SetOnclose);
    event_handler!(error, GetOnerror, SetOnerror);

    fn Url(self) -> DOMString {
        self.url.serialize()
    }

    fn ReadyState(self) -> u16 {
        self.ready_state.get() as u16
    }

    fn Send(self, data: Option<USVString>) -> Fallible<()> {
        match self.ready_state.get() {
            WebSocketRequestState::Connecting => {
                return Err(Error::InvalidState);
            },
            WebSocketRequestState::Open => (),
            WebSocketRequestState::Closing | WebSocketRequestState::Closed => {
                // TODO: Update bufferedAmount.
                return Ok(());
            }
        }

        /*TODO: This is not up to spec see http://html.spec.whatwg.org/multipage/comms.html search for
                "If argument is a string"
          TODO: Need to buffer data
          TODO: bufferedAmount attribute returns the size of the buffer in bytes -
                this is a required attribute defined in the websocket.webidl file
          TODO: The send function needs to flag when full by using the following
          self.full.set(true). This needs to be done when the buffer is full
        */
        let mut other_sender = self.sender.borrow_mut();
        let my_sender = other_sender.as_mut().unwrap();
        let _ = my_sender.send_message(Message::Text(data.unwrap().0));
        return Ok(())
    }

    fn Close(self, code: Option<u16>, reason: Option<USVString>) -> Fallible<()>{
        fn send_close(this: &WebSocket) {
            this.ready_state.set(WebSocketRequestState::Closing);

            let mut sender = this.sender.borrow_mut();
            //TODO: Also check if the buffer is full
            if let Some(sender) = sender.as_mut() {
                let _ = sender.send_message(Message::Close(None));
            }
        }

        if let Some(code) = code {
            //Check code is NOT 1000 NOR in the range of 3000-4999 (inclusive)
            if  code != 1000 && (code < 3000 || code > 4999) {
                return Err(Error::InvalidAccess);
            }
        }
        if let Some(ref reason) = reason {
            if reason.0.as_bytes().len() > 123 { //reason cannot be larger than 123 bytes
                return Err(Error::Syntax);
            }
        }

        match self.ready_state.get() {
            WebSocketRequestState::Closing | WebSocketRequestState::Closed  => {} //Do nothing
            WebSocketRequestState::Connecting => { //Connection is not yet established
                /*By setting the state to closing, the open function
                  will abort connecting the websocket*/
                self.failed.set(true);
                send_close(self);
                //Note: After sending the close message, the receive loop confirms a close message from the server and
                //      must fire a close event
            }
            WebSocketRequestState::Open => {
                //Closing handshake not started - still in open
                //Start the closing by setting the code and reason if they exist
                if let Some(code) = code {
                    self.code.set(code);
                }
                if let Some(reason) = reason {
                    *self.reason.borrow_mut() = reason.0;
                }
                send_close(self);
                //Note: After sending the close message, the receive loop confirms a close message from the server and
                //      must fire a close event
            }
        }
        Ok(()) //Return Ok
    }
}

/// Task queued when *the WebSocket connection is established*.
struct ConnectionEstablishedTask {
    addr: Trusted<WebSocket>,
}

impl Runnable for ConnectionEstablishedTask {
    fn handler(self: Box<Self>) {
        let ws = self.addr.root();

        // Step 1: Protocols.

        // Step 2.
        ws.ready_state.set(WebSocketRequestState::Open);

        // Step 3: Extensions.
        // Step 4: Protocols.
        // Step 5: Cookies.

        // Step 6.
        let global = ws.global.root();
        let event = Event::new(global.r(), "open".to_owned(),
                               EventBubbles::DoesNotBubble,
                               EventCancelable::NotCancelable);
        event.fire(EventTargetCast::from_ref(ws.r()));
    }
}

struct CloseTask {
    addr: Trusted<WebSocket>,
}

impl Runnable for CloseTask {
    fn handler(self: Box<Self>) {
        let ws = self.addr.root();
        let ws = ws.r();
        let global = ws.global.root();
        ws.ready_state.set(WebSocketRequestState::Closed);
        //If failed or full, fire error event
        if ws.failed.get() || ws.full.get() {
            ws.failed.set(false);
            ws.full.set(false);
            //A Bad close
            ws.clean_close.set(false);
            let event = Event::new(global.r(),
                                   "error".to_owned(),
                                   EventBubbles::DoesNotBubble,
                                   EventCancelable::Cancelable);
            let target = EventTargetCast::from_ref(ws);
            event.r().fire(target);
        }
        let rsn = ws.reason.borrow();
        let rsn_clone = rsn.clone();
        /*In addition, we also have to fire a close even if error event fired
         https://html.spec.whatwg.org/multipage/#closeWebSocket
        */
        let close_event = CloseEvent::new(global.r(),
                                          "close".to_owned(),
                                          EventBubbles::DoesNotBubble,
                                          EventCancelable::NotCancelable,
                                          ws.clean_close.get(),
                                          ws.code.get(),
                                          rsn_clone);
        let target = EventTargetCast::from_ref(ws);
        let event = EventCast::from_ref(close_event.r());
        event.fire(target);
    }
}
<commit_msg>Set the WebSocket's Sender from the ConnectionEstablishedTask.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::WebSocketBinding;
use dom::bindings::codegen::Bindings::WebSocketBinding::WebSocketMethods;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::InheritTypes::EventTargetCast;
use dom::bindings::codegen::InheritTypes::EventCast;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::error::Error::{InvalidAccess, Syntax};
use dom::bindings::global::{GlobalField, GlobalRef};
use dom::bindings::js::Root;
use dom::bindings::refcounted::Trusted;
use dom::bindings::str::USVString;
use dom::bindings::trace::JSTraceable;
use dom::bindings::utils::reflect_dom_object;
use dom::closeevent::CloseEvent;
use dom::event::{Event, EventBubbles, EventCancelable, EventHelpers};
use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId};
use script_task::Runnable;
use script_task::ScriptMsg;
use std::cell::{Cell, RefCell};
use std::borrow::ToOwned;
use util::str::DOMString;

use hyper::header::Host;
use websocket::Message;
use websocket::ws::sender::Sender as Sender_Object;
use websocket::client::sender::Sender;
use websocket::client::receiver::Receiver;
use websocket::stream::WebSocketStream;
use websocket::client::request::Url;
use websocket::Client;
use websocket::header::Origin;
use websocket::result::WebSocketResult;
use websocket::ws::util::url::parse_url;

#[derive(JSTraceable, PartialEq, Copy, Clone)]
enum WebSocketRequestState {
    Connecting = 0,
    Open = 1,
    Closing = 2,
    Closed = 3,
}

no_jsmanaged_fields!(Sender<WebSocketStream>);

#[dom_struct]
pub struct WebSocket {
    eventtarget: EventTarget,
    url: Url,
    global: GlobalField,
    ready_state: Cell<WebSocketRequestState>,
    sender: RefCell<Option<Sender<WebSocketStream>>>,
    failed: Cell<bool>, //Flag to tell if websocket was closed due to failure
    full: Cell<bool>, //Flag to tell if websocket queue is full
    clean_close: Cell<bool>, //Flag to tell if the websocket closed cleanly (not due to full or fail)
    code: Cell<u16>, //Closing code
    reason: DOMRefCell<DOMString>, //Closing reason
    data: DOMRefCell<DOMString>, //Data from send - TODO: Remove after buffer is added.
}

/// *Establish a WebSocket Connection* as defined in RFC 6455.
fn establish_a_websocket_connection(url: (Host, String, bool), origin: String)
    -> WebSocketResult<(Sender<WebSocketStream>, Receiver<WebSocketStream>)> {
    let mut request = try!(Client::connect(url));
    request.headers.set(Origin(origin));

    let response = try!(request.send());
    try!(response.validate());

    Ok(response.begin().split())
}

impl WebSocket {
    pub fn new_inherited(global: GlobalRef, url: Url) -> WebSocket {
        WebSocket {
            eventtarget: EventTarget::new_inherited(EventTargetTypeId::WebSocket),
            url: url,
            global: GlobalField::from_rooted(&global),
            ready_state: Cell::new(WebSocketRequestState::Connecting),
            failed: Cell::new(false),
            sender: RefCell::new(None),
            full: Cell::new(false),
            clean_close: Cell::new(true),
            code: Cell::new(0),
            reason: DOMRefCell::new("".to_owned()),
            data: DOMRefCell::new("".to_owned()),
        }

    }

    pub fn new(global: GlobalRef,
               url: DOMString,
               protocols: Option<DOMString>)
               -> Fallible<Root<WebSocket>> {
        // Step 1.
        let parsed_url = try!(Url::parse(&url).map_err(|_| Error::Syntax));
        let url = try!(parse_url(&parsed_url).map_err(|_| Error::Syntax));

        // Step 4.
        let protocols = protocols.as_slice();

        // Step 5.
        for (i, protocol) in protocols.iter().enumerate() {
            // https://tools.ietf.org/html/rfc6455#section-4.1
            // Handshake requirements, step 10
            if protocol.is_empty() {
                return Err(Syntax);
            }

            if protocols[i+1..].iter().any(|p| p == protocol) {
                return Err(Syntax);
            }

            if protocol.chars().any(|c| c < '\u{0021}' || c > '\u{007E}') {
                return Err(Syntax);
            }
        }

        /*TODO: This constructor is only a prototype, it does not accomplish the specs
          defined here:
          http://html.spec.whatwg.org
          The remaining 8 items must be satisfied.
          TODO: This constructor should be responsible for spawning a thread for the
          receive loop after ws.r().Open() - See comment
        */
        let ws = reflect_dom_object(box WebSocket::new_inherited(global, parsed_url),
                                    global,
                                    WebSocketBinding::Wrap);

        let channel = establish_a_websocket_connection(url, global.get_url().serialize());
        let (temp_sender, _temp_receiver) = match channel {
            Ok(channel) => channel,
            Err(e) => {
                debug!("Failed to establish a WebSocket connection: {:?}", e);
                let global_root = ws.r().global.root();
                let address = Trusted::new(global_root.r().get_cx(), ws.r(), global_root.r().script_chan().clone());
                let task = box CloseTask {
                    addr: address,
                };
                global_root.r().script_chan().send(ScriptMsg::RunnableMsg(task)).unwrap();
                return Ok(ws);
            }
        };

        //Create everything necessary for starting the open asynchronous task, then begin the task.
        let global_root = ws.r().global.root();
        let addr: Trusted<WebSocket> =
            Trusted::new(global_root.r().get_cx(), ws.r(), global_root.r().script_chan().clone());
        let open_task = box ConnectionEstablishedTask {
            addr: addr,
            sender: temp_sender,
        };
        global_root.r().script_chan().send(ScriptMsg::RunnableMsg(open_task)).unwrap();
        //TODO: Spawn thread here for receive loop
        /*TODO: Add receive loop here and make new thread run this
          Receive is an infinite loop "similiar" the one shown here:
          https://github.com/cyderize/rust-websocket/blob/master/examples/client.rs#L64
          TODO: The receive loop however does need to follow the spec. These are outlined here
          under "WebSocket message has been received" items 1-5:
          https://github.com/cyderize/rust-websocket/blob/master/examples/client.rs#L64
          TODO: The receive loop also needs to dispatch an asynchronous event as stated here:
          https://github.com/cyderize/rust-websocket/blob/master/examples/client.rs#L64
          TODO: When the receive loop receives a close message from the server,
          it confirms the websocket is now closed. This requires the close event
          to be fired (dispatch_close fires the close event - see implementation below)
        */
        Ok(ws)
    }

    pub fn Constructor(global: GlobalRef,
                       url: DOMString,
                       protocols: Option<DOMString>)
                       -> Fallible<Root<WebSocket>> {
        WebSocket::new(global, url, protocols)
    }
}

impl<'a> WebSocketMethods for &'a WebSocket {
    event_handler!(open, GetOnopen, SetOnopen);
    event_handler!(close, GetOnclose, SetOnclose);
    event_handler!(error, GetOnerror, SetOnerror);

    fn Url(self) -> DOMString {
        self.url.serialize()
    }

    fn ReadyState(self) -> u16 {
        self.ready_state.get() as u16
    }

    fn Send(self, data: Option<USVString>) -> Fallible<()> {
        match self.ready_state.get() {
            WebSocketRequestState::Connecting => {
                return Err(Error::InvalidState);
            },
            WebSocketRequestState::Open => (),
            WebSocketRequestState::Closing | WebSocketRequestState::Closed => {
                // TODO: Update bufferedAmount.
                return Ok(());
            }
        }

        /*TODO: This is not up to spec see http://html.spec.whatwg.org/multipage/comms.html search for
                "If argument is a string"
          TODO: Need to buffer data
          TODO: bufferedAmount attribute returns the size of the buffer in bytes -
                this is a required attribute defined in the websocket.webidl file
          TODO: The send function needs to flag when full by using the following
          self.full.set(true). This needs to be done when the buffer is full
        */
        let mut other_sender = self.sender.borrow_mut();
        let my_sender = other_sender.as_mut().unwrap();
        let _ = my_sender.send_message(Message::Text(data.unwrap().0));
        return Ok(())
    }

    fn Close(self, code: Option<u16>, reason: Option<USVString>) -> Fallible<()>{
        fn send_close(this: &WebSocket) {
            this.ready_state.set(WebSocketRequestState::Closing);

            let mut sender = this.sender.borrow_mut();
            //TODO: Also check if the buffer is full
            if let Some(sender) = sender.as_mut() {
                let _ = sender.send_message(Message::Close(None));
            }
        }

        if let Some(code) = code {
            //Check code is NOT 1000 NOR in the range of 3000-4999 (inclusive)
            if  code != 1000 && (code < 3000 || code > 4999) {
                return Err(Error::InvalidAccess);
            }
        }
        if let Some(ref reason) = reason {
            if reason.0.as_bytes().len() > 123 { //reason cannot be larger than 123 bytes
                return Err(Error::Syntax);
            }
        }

        match self.ready_state.get() {
            WebSocketRequestState::Closing | WebSocketRequestState::Closed  => {} //Do nothing
            WebSocketRequestState::Connecting => { //Connection is not yet established
                /*By setting the state to closing, the open function
                  will abort connecting the websocket*/
                self.failed.set(true);
                send_close(self);
                //Note: After sending the close message, the receive loop confirms a close message from the server and
                //      must fire a close event
            }
            WebSocketRequestState::Open => {
                //Closing handshake not started - still in open
                //Start the closing by setting the code and reason if they exist
                if let Some(code) = code {
                    self.code.set(code);
                }
                if let Some(reason) = reason {
                    *self.reason.borrow_mut() = reason.0;
                }
                send_close(self);
                //Note: After sending the close message, the receive loop confirms a close message from the server and
                //      must fire a close event
            }
        }
        Ok(()) //Return Ok
    }
}

/// Task queued when *the WebSocket connection is established*.
struct ConnectionEstablishedTask {
    addr: Trusted<WebSocket>,
    sender: Sender<WebSocketStream>,
}

impl Runnable for ConnectionEstablishedTask {
    fn handler(self: Box<Self>) {
        let ws = self.addr.root();

        *ws.r().sender.borrow_mut() = Some(self.sender);

        // Step 1: Protocols.

        // Step 2.
        ws.ready_state.set(WebSocketRequestState::Open);

        // Step 3: Extensions.
        // Step 4: Protocols.
        // Step 5: Cookies.

        // Step 6.
        let global = ws.global.root();
        let event = Event::new(global.r(), "open".to_owned(),
                               EventBubbles::DoesNotBubble,
                               EventCancelable::NotCancelable);
        event.fire(EventTargetCast::from_ref(ws.r()));
    }
}

struct CloseTask {
    addr: Trusted<WebSocket>,
}

impl Runnable for CloseTask {
    fn handler(self: Box<Self>) {
        let ws = self.addr.root();
        let ws = ws.r();
        let global = ws.global.root();
        ws.ready_state.set(WebSocketRequestState::Closed);
        //If failed or full, fire error event
        if ws.failed.get() || ws.full.get() {
            ws.failed.set(false);
            ws.full.set(false);
            //A Bad close
            ws.clean_close.set(false);
            let event = Event::new(global.r(),
                                   "error".to_owned(),
                                   EventBubbles::DoesNotBubble,
                                   EventCancelable::Cancelable);
            let target = EventTargetCast::from_ref(ws);
            event.r().fire(target);
        }
        let rsn = ws.reason.borrow();
        let rsn_clone = rsn.clone();
        /*In addition, we also have to fire a close even if error event fired
         https://html.spec.whatwg.org/multipage/#closeWebSocket
        */
        let close_event = CloseEvent::new(global.r(),
                                          "close".to_owned(),
                                          EventBubbles::DoesNotBubble,
                                          EventCancelable::NotCancelable,
                                          ws.clean_close.get(),
                                          ws.code.get(),
                                          rsn_clone);
        let target = EventTargetCast::from_ref(ws);
        let event = EventCast::from_ref(close_event.r());
        event.fire(target);
    }
}
<|endoftext|>