<commit_before>use crate::io::{self, Error, ErrorKind};
use libc::{self, c_int, c_char};
use libc::{RTP_ID};
use crate::sys;
use crate::sys::cvt;
use crate::sys::process::process_common::*;
use crate::sys_common::thread;

////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////

impl Command {
    pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
                 -> io::Result<(Process, StdioPipes)> {
        use crate::sys::{cvt_r};
        const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX";

        if self.saw_nul() {
            return Err(io::Error::new(ErrorKind::InvalidInput,
                                      "nul byte found in provided data"));
        }
        let (ours, theirs) = self.setup_io(default, needs_stdin)?;
        let mut p = Process { pid: 0, status: None };

        unsafe {
            macro_rules! t {
                ($e:expr) => (match $e {
                    Ok(e) => e,
                    Err(e) => return Err(e.into()),
                })
            }

            let mut orig_stdin = libc::STDIN_FILENO;
            let mut orig_stdout = libc::STDOUT_FILENO;
            let mut orig_stderr = libc::STDERR_FILENO;

            if let Some(fd) = theirs.stdin.fd() {
                orig_stdin = t!(cvt_r(|| libc::dup(libc::STDIN_FILENO)));
                t!(cvt_r(|| libc::dup2(fd, libc::STDIN_FILENO)));
            }
            if let Some(fd) = theirs.stdout.fd() {
                orig_stdout = t!(cvt_r(|| libc::dup(libc::STDOUT_FILENO)));
                t!(cvt_r(|| libc::dup2(fd, libc::STDOUT_FILENO)));
            }
            if let Some(fd) = theirs.stderr.fd() {
                orig_stderr = t!(cvt_r(|| libc::dup(libc::STDERR_FILENO)));
                t!(cvt_r(|| libc::dup2(fd, libc::STDERR_FILENO)));
            }

            if let Some(ref cwd) = *self.get_cwd() {
                t!(cvt(libc::chdir(cwd.as_ptr())));
            }

            let ret = libc::rtpSpawn(
                self.get_argv()[0],                   // executing program
                self.get_argv().as_ptr() as *const _, // argv
                *sys::os::environ() as *const *const c_char,
                100 as c_int,                         // initial priority
                thread::min_stack(),                  // initial stack size.
                0,                                    // options
                0                                     // task options
            );

            // Because FileDesc was not used, each duplicated file descriptor
            // needs to be closed manually
            if orig_stdin != libc::STDIN_FILENO {
                t!(cvt_r(|| libc::dup2(orig_stdin, libc::STDIN_FILENO)));
                libc::close(orig_stdin);
            }
            if orig_stdout != libc::STDOUT_FILENO {
                t!(cvt_r(|| libc::dup2(orig_stdout, libc::STDOUT_FILENO)));
                libc::close(orig_stdout);
            }
            if orig_stderr != libc::STDERR_FILENO {
                t!(cvt_r(|| libc::dup2(orig_stderr, libc::STDERR_FILENO)));
                libc::close(orig_stderr);
            }

            if ret != libc::RTP_ID_ERROR {
                p.pid = ret;
                Ok((p, ours))
            } else {
                Err(io::Error::last_os_error())
            }
        }
    }

    pub fn exec(&mut self, default: Stdio) -> io::Error {
        let ret = Command::spawn(self, default, false);
        match ret {
            Ok(t) => unsafe {
                let mut status = 0 as c_int;
                libc::waitpid(t.0.pid, &mut status, 0);
                libc::exit(0);
            },
            Err(e) => e,
        }
    }
}

////////////////////////////////////////////////////////////////////////////////
// Processes
////////////////////////////////////////////////////////////////////////////////

/// The unique id of the process (this should never be negative).
pub struct Process {
    pid: RTP_ID,
    status: Option<ExitStatus>,
}

impl Process {
    pub fn id(&self) -> u32 {
        self.pid as u32
    }

    pub fn kill(&mut self) -> io::Result<()> {
        // If we've already waited on this process then the pid can be recycled
        // and used for another process, and we probably shouldn't be killing
        // random processes, so just return an error.
        if self.status.is_some() {
            Err(Error::new(ErrorKind::InvalidInput,
                           "invalid argument: can't kill an exited process"))
        } else {
            cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(|_| ())
        }
    }

    pub fn wait(&mut self) -> io::Result<ExitStatus> {
        use crate::sys::cvt_r;
        if let Some(status) = self.status {
            return Ok(status)
        }
        let mut status = 0 as c_int;
        cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) })?;
        self.status = Some(ExitStatus::new(status));
        Ok(ExitStatus::new(status))
    }

    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
        if let Some(status) = self.status {
            return Ok(Some(status))
        }
        let mut status = 0 as c_int;
        let pid = cvt(unsafe {
            libc::waitpid(self.pid, &mut status, libc::WNOHANG)
        })?;
        if pid == 0 {
            Ok(None)
        } else {
            self.status = Some(ExitStatus::new(status));
            Ok(Some(ExitStatus::new(status)))
        }
    }
}
<commit_msg>update rtpSpawn's parameters type(It's prototype has been updated in libc)<commit_after>use crate::io::{self, Error, ErrorKind};
use libc::{self, c_int, c_char};
use libc::{RTP_ID};
use crate::sys;
use crate::sys::cvt;
use crate::sys::process::process_common::*;
use crate::sys_common::thread;

////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////

impl Command {
    pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
                 -> io::Result<(Process, StdioPipes)> {
        use crate::sys::{cvt_r};
        const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX";

        if self.saw_nul() {
            return Err(io::Error::new(ErrorKind::InvalidInput,
                                      "nul byte found in provided data"));
        }
        let (ours, theirs) = self.setup_io(default, needs_stdin)?;
        let mut p = Process { pid: 0, status: None };

        unsafe {
            macro_rules! t {
                ($e:expr) => (match $e {
                    Ok(e) => e,
                    Err(e) => return Err(e.into()),
                })
            }

            let mut orig_stdin = libc::STDIN_FILENO;
            let mut orig_stdout = libc::STDOUT_FILENO;
            let mut orig_stderr = libc::STDERR_FILENO;

            if let Some(fd) = theirs.stdin.fd() {
                orig_stdin = t!(cvt_r(|| libc::dup(libc::STDIN_FILENO)));
                t!(cvt_r(|| libc::dup2(fd, libc::STDIN_FILENO)));
            }
            if let Some(fd) = theirs.stdout.fd() {
                orig_stdout = t!(cvt_r(|| libc::dup(libc::STDOUT_FILENO)));
                t!(cvt_r(|| libc::dup2(fd, libc::STDOUT_FILENO)));
            }
            if let Some(fd) = theirs.stderr.fd() {
                orig_stderr = t!(cvt_r(|| libc::dup(libc::STDERR_FILENO)));
                t!(cvt_r(|| libc::dup2(fd, libc::STDERR_FILENO)));
            }

            if let Some(ref cwd) = *self.get_cwd() {
                t!(cvt(libc::chdir(cwd.as_ptr())));
            }

            let ret = libc::rtpSpawn(
                self.get_argv()[0],                   // executing program
                self.get_argv().as_ptr() as *mut *const c_char, // argv
                *sys::os::environ() as *mut *const c_char,
                100 as c_int,                         // initial priority
                thread::min_stack(),                  // initial stack size.
                0,                                    // options
                0                                     // task options
            );

            // Because FileDesc was not used, each duplicated file descriptor
            // needs to be closed manually
            if orig_stdin != libc::STDIN_FILENO {
                t!(cvt_r(|| libc::dup2(orig_stdin, libc::STDIN_FILENO)));
                libc::close(orig_stdin);
            }
            if orig_stdout != libc::STDOUT_FILENO {
                t!(cvt_r(|| libc::dup2(orig_stdout, libc::STDOUT_FILENO)));
                libc::close(orig_stdout);
            }
            if orig_stderr != libc::STDERR_FILENO {
                t!(cvt_r(|| libc::dup2(orig_stderr, libc::STDERR_FILENO)));
                libc::close(orig_stderr);
            }

            if ret != libc::RTP_ID_ERROR {
                p.pid = ret;
                Ok((p, ours))
            } else {
                Err(io::Error::last_os_error())
            }
        }
    }

    pub fn exec(&mut self, default: Stdio) -> io::Error {
        let ret = Command::spawn(self, default, false);
        match ret {
            Ok(t) => unsafe {
                let mut status = 0 as c_int;
                libc::waitpid(t.0.pid, &mut status, 0);
                libc::exit(0);
            },
            Err(e) => e,
        }
    }
}

////////////////////////////////////////////////////////////////////////////////
// Processes
////////////////////////////////////////////////////////////////////////////////

/// The unique id of the process (this should never be negative).
pub struct Process {
    pid: RTP_ID,
    status: Option<ExitStatus>,
}

impl Process {
    pub fn id(&self) -> u32 {
        self.pid as u32
    }

    pub fn kill(&mut self) -> io::Result<()> {
        // If we've already waited on this process then the pid can be recycled
        // and used for another process, and we probably shouldn't be killing
        // random processes, so just return an error.
        if self.status.is_some() {
            Err(Error::new(ErrorKind::InvalidInput,
                           "invalid argument: can't kill an exited process"))
        } else {
            cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(|_| ())
        }
    }

    pub fn wait(&mut self) -> io::Result<ExitStatus> {
        use crate::sys::cvt_r;
        if let Some(status) = self.status {
            return Ok(status)
        }
        let mut status = 0 as c_int;
        cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) })?;
        self.status = Some(ExitStatus::new(status));
        Ok(ExitStatus::new(status))
    }

    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
        if let Some(status) = self.status {
            return Ok(Some(status))
        }
        let mut status = 0 as c_int;
        let pid = cvt(unsafe {
            libc::waitpid(self.pid, &mut status, libc::WNOHANG)
        })?;
        if pid == 0 {
            Ok(None)
        } else {
            self.status = Some(ExitStatus::new(status));
            Ok(Some(ExitStatus::new(status)))
        }
    }
}
<|endoftext|>


<commit_before>//   Copyright 2014 Colin Sherratt
//
//   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.

use std::mem;
use std::ptr;
use std::slice::raw::mut_buf_as_slice;
use sync::Arc;

use opencl::hl::{CommandQueue, Context, Device, Event, EventList};
use opencl::mem::{Buffer, CLBuffer};
use opencl::cl::CL_MEM_READ_WRITE;
use cgmath::Matrix4;
use cgmath::Vector4;
use gl;
use gl::types::{GLuint, GLsizeiptr};
use gl_cl;
use gl_cl::AcquireRelease;

use position::{MatrixManager};
use position::Positions;
use render_data::Renderable;

use Config;

struct GLTextureMatrix<'r> {
    x: &'r mut [Vector4<f32>],
    y: &'r mut [Vector4<f32>],
    z: &'r mut [Vector4<f32>],
    w: &'r mut [Vector4<f32>],
}

impl<'r> MatrixManager for GLTextureMatrix<'r> {
    fn size(&mut self, size: uint) {assert!(self.x.len() > size)}

    fn set(&mut self, idx: uint, mat: Matrix4<f32>) {
        assert!(idx < self.x.len());
        unsafe { *self.x.as_mut_ptr().offset(idx as int) = mat.x; }
        unsafe { *self.y.as_mut_ptr().offset(idx as int) = mat.y; }
        unsafe { *self.z.as_mut_ptr().offset(idx as int) = mat.z; }
        unsafe { *self.w.as_mut_ptr().offset(idx as int) = mat.w; }
    }

    fn get(&self, idx: uint) -> Matrix4<f32> {
        assert!(idx < self.x.len());
        unsafe {
            Matrix4 {
                x: self.x.unsafe_get(idx).clone(),
                y: self.y.unsafe_get(idx).clone(),
                z: self.z.unsafe_get(idx).clone(),
                w: self.w.unsafe_get(idx).clone(),
            }
        }
    }
}

struct GLSSBOMatrix<'r> {
    mat: &'r mut [Matrix4<f32>],
}

impl<'r> MatrixManager for GLSSBOMatrix<'r> {
    fn size(&mut self, size: uint) {assert!(self.mat.len() > size)}

    fn set(&mut self, idx: uint, mat: Matrix4<f32>) {
        assert!(idx < self.mat.len());
        unsafe { *self.mat.as_mut_ptr().offset(idx as int) = mat; }
    }

    fn get(&self, idx: uint) -> Matrix4<f32> {
        assert!(idx < self.mat.len());
        unsafe { self.mat.unsafe_get(idx).clone() }
    }
}

pub struct MatrixSSBOBuffer {
    model_matrix: GLuint,
    ptr_model_matrix: *mut Matrix4<f32>,
    size: uint,

    event: Option<Event>,
//    cl: Option<(CalcPositionsCl, Arc<CommandQueue>, [CLBuffer<Matrix4<f32>>, ..1])>,
}

impl MatrixSSBOBuffer {
    pub fn new(cfg: &Config,
               cl: Option<(Arc<Context>, Arc<CommandQueue>, Arc<Device>)>) -> MatrixSSBOBuffer {
        let buffer = &mut [0];

        unsafe {
            gl::GenBuffers(buffer.len() as i32, buffer.unsafe_mut(0));

            gl::BindBuffer(gl::SHADER_STORAGE_BUFFER, buffer[0]);
            gl::BufferData(gl::SHADER_STORAGE_BUFFER,
                           (mem::size_of::<Matrix4<f32>>()*cfg.max_size()) as GLsizeiptr,
                           ptr::null(), gl::DYNAMIC_DRAW);
        }

        /*let clpos = match cl {
            Some((ctx, cq, dev)) => {
                let calc = CalcPositionsCl::new(ctx.deref(), dev.deref());
                let buffers = gl_cl::create_from_gl_buffer(ctx.deref(), buffer[0], CL_MEM_READ_WRITE);

                Some((calc, cq, [buffers]))
            },
            None => None
        };*/

        MatrixSSBOBuffer {
            model_matrix: buffer[0],
            ptr_model_matrix: ptr::null_mut(),
            size: cfg.max_size(),
            //cl: clpos,
            event: None,
        }
    }

    pub fn map(&mut self) {
        //match self.cl {
        //    None => unsafe {
        unsafe {
                gl::BindBuffer(gl::SHADER_STORAGE_BUFFER, self.model_matrix);
                self.ptr_model_matrix = gl::MapBufferRange(gl::SHADER_STORAGE_BUFFER, 0,
                        (mem::size_of::<Matrix4<f32>>()*self.size) as GLsizeiptr,
                        gl::MAP_WRITE_BIT | gl::MAP_INVALIDATE_BUFFER_BIT
                ) as *mut Matrix4<f32>;
        }
        //    },
        //    Some((_, ref cq, ref buf)) => {
        //        cq.acquire_gl_objects(buf.as_slice(), ()).wait()
        //    }
        //}
    }

    pub fn unmap(&mut self) {
        //let event = self.event.take();
        //match (&self.cl, event) {
        //    (&None, None) => unsafe {
        unsafe {
                gl::BindBuffer(gl::SHADER_STORAGE_BUFFER, self.model_matrix);
                gl::UnmapBuffer(gl::SHADER_STORAGE_BUFFER);
                assert!(0 == gl::GetError());
                self.ptr_model_matrix = ptr::null_mut();
        }
        //    },
        //    (&Some((_, ref cq, ref buf)), Some(ref event)) => {
        //        cq.release_gl_objects(buf.as_slice(), event).wait();
        //    }
        //    _ => panic!("expected both an event and a queue")
        //}
    }

    pub fn build<RD: Renderable>(&mut self, db: &RD) {
        //self.event = unsafe {
        //    match self.cl {
        //        None => {
        unsafe {
                    mut_buf_as_slice(self.ptr_model_matrix, self.size, |mat| {
                        let mut mat = GLSSBOMatrix {
                            mat: mat
                        };
                        db.write_positions(&mut mat);
//                        None
                    })
        }
        //        }
        //        Some((ref mut ctx, ref cq, ref buf)) => {
        //            let evt = db.write_positions_cl_mat4(cq.deref(), ctx, buf.as_slice());
        //            Some(evt)
        //        }
        //    }
        //};
    }

    pub fn id(&self) -> GLuint { self.model_matrix }
}

pub struct MatrixTextureBuffer {
    model_matrix: [GLuint, ..4],
    texture_model_matrix: [GLuint, ..4],
    ptr_model_matrix: [*mut Vector4<f32>, ..4],
    size: uint,

    event: Option<Event>,
    //cl: Option<(CalcPositionsCl, Arc<CommandQueue>, [CLBuffer<Vector4<f32>>, ..4])>,
}

impl MatrixTextureBuffer {
    pub fn new(cfg: &Config,
               cl: Option<(Arc<Context>, Arc<CommandQueue>, Arc<Device>)>) -> MatrixTextureBuffer {
        let buffer = &mut [0, 0, 0, 0];
        let texture = &mut [0, 0, 0, 0];

        unsafe {
            gl::GenBuffers(buffer.len() as i32, buffer.unsafe_mut(0));
            gl::GenTextures(texture.len() as i32, texture.unsafe_mut(0));

            for (b, t) in buffer.iter().zip(texture.iter()) {
                gl::BindBuffer(gl::TEXTURE_BUFFER, *b);
                gl::BindTexture(gl::TEXTURE_BUFFER, *t);
                gl::TexBuffer(gl::TEXTURE_BUFFER, gl::RGBA32F, *b);
                gl::BufferData(gl::TEXTURE_BUFFER,
                               (mem::size_of::<Vector4<f32>>()*cfg.max_size()) as GLsizeiptr,
                               ptr::null(), gl::DYNAMIC_DRAW);
            }
        }

        /*let clpos = match cl {
            Some((ctx, cq, dev)) => {
                let calc = CalcPositionsCl::new(ctx.deref(), dev.deref());
                let buffers = [gl_cl::create_from_gl_buffer(ctx.deref(), buffer[0], CL_MEM_READ_WRITE),
                               gl_cl::create_from_gl_buffer(ctx.deref(), buffer[1], CL_MEM_READ_WRITE),
                               gl_cl::create_from_gl_buffer(ctx.deref(), buffer[2], CL_MEM_READ_WRITE),
                               gl_cl::create_from_gl_buffer(ctx.deref(), buffer[3], CL_MEM_READ_WRITE)];

                Some((calc, cq, buffers))
            },
            None => None
        };*/

        MatrixTextureBuffer {
            model_matrix: [buffer[0], buffer[1], buffer[2], buffer[3]],
            texture_model_matrix: [texture[0], texture[1], texture[2], texture[3]],
            ptr_model_matrix: [ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), ptr::null_mut()],
            size: cfg.max_size(),
            //cl: clpos,
            event: None,
        }
    }

    pub fn map(&mut self) {
//        match self.cl {
//            None => {
                for i in range(0u, 4) { unsafe {
                    gl::BindBuffer(gl::TEXTURE_BUFFER, self.model_matrix[i]);
                    self.ptr_model_matrix[i] = gl::MapBufferRange(
                        gl::TEXTURE_BUFFER, 0,
                        (mem::size_of::<Vector4<f32>>()*self.size) as GLsizeiptr,
                        gl::MAP_WRITE_BIT | gl::MAP_INVALIDATE_BUFFER_BIT
                    ) as *mut Vector4<f32>;
                }}
//            }
//            Some((_, ref cq, ref buf)) => {
//                cq.acquire_gl_objects(buf.as_slice(), ()).wait()
//            }
//        }
    }

    pub fn unmap(&mut self) {
//        let event = self.event.take();
//        match (&self.cl, event) {
//            (&None, None) => unsafe {
                for i in range(0u, 4) { unsafe {
                    gl::BindBuffer(gl::TEXTURE_BUFFER, self.model_matrix[i]);
                    gl::UnmapBuffer(gl::TEXTURE_BUFFER);
                    assert!(0 == gl::GetError());
                    self.ptr_model_matrix[i] = ptr::null_mut();
                }}
//            },
//            (&Some((_, ref cq, ref buf)), Some(ref event)) => {
//                cq.release_gl_objects(buf.as_slice(), event).wait();
//            }
//            _ => panic!("expected both an event and a queue")
//        }
    }

    pub fn build<RD: Renderable>(&mut self, db: &RD) {
//        self.event = unsafe {
//            match self.cl {
//                None => {
        unsafe {
                    mut_buf_as_slice(self.ptr_model_matrix[0], self.size, |x| {
                    mut_buf_as_slice(self.ptr_model_matrix[1], self.size, |y| {
                    mut_buf_as_slice(self.ptr_model_matrix[2], self.size, |z| {
                    mut_buf_as_slice(self.ptr_model_matrix[3], self.size, |w| {
                        let mut mat = GLTextureMatrix {
                            x: x, y: y, z: z, w: w
                        };
                        db.write_positions(&mut mat);
                        //None
                    })})})})
        }
//                }
//                Some((ref mut ctx, ref cq, ref buf)) => {
//                    let evt = db.write_positions_cl_vec4x4(cq.deref(), ctx, buf);
//                    Some(evt)
//                }
//            }
//        };
    }

    pub fn ids<'a>(&'a self) -> &'a [GLuint] { self.texture_model_matrix.as_slice() }
}<commit_msg>Readd opencl accelerator to azdo render<commit_after>//   Copyright 2014 Colin Sherratt
//
//   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.

use std::mem;
use std::ptr;
use std::slice::raw::mut_buf_as_slice;
use sync::Arc;

use opencl::hl::{CommandQueue, Context, Device, Event, EventList};
use opencl::mem::{Buffer, CLBuffer};
use opencl::cl::CL_MEM_READ_WRITE;
use cgmath::Matrix4;
use cgmath::Vector4;
use gl;
use gl::types::{GLuint, GLsizeiptr};
use gl_cl;
use gl_cl::AcquireRelease;

use position::{MatrixManager, Positions};
use position::cl::Accelerator;
use render_data::Renderable;

use Config;

struct GLTextureMatrix<'r> {
    x: &'r mut [Vector4<f32>],
    y: &'r mut [Vector4<f32>],
    z: &'r mut [Vector4<f32>],
    w: &'r mut [Vector4<f32>],
}

impl<'r> MatrixManager for GLTextureMatrix<'r> {
    fn size(&mut self, size: uint) {assert!(self.x.len() > size)}

    fn set(&mut self, idx: uint, mat: Matrix4<f32>) {
        assert!(idx < self.x.len());
        unsafe { *self.x.as_mut_ptr().offset(idx as int) = mat.x; }
        unsafe { *self.y.as_mut_ptr().offset(idx as int) = mat.y; }
        unsafe { *self.z.as_mut_ptr().offset(idx as int) = mat.z; }
        unsafe { *self.w.as_mut_ptr().offset(idx as int) = mat.w; }
    }

    fn get(&self, idx: uint) -> Matrix4<f32> {
        assert!(idx < self.x.len());
        unsafe {
            Matrix4 {
                x: self.x.unsafe_get(idx).clone(),
                y: self.y.unsafe_get(idx).clone(),
                z: self.z.unsafe_get(idx).clone(),
                w: self.w.unsafe_get(idx).clone(),
            }
        }
    }
}

struct GLSSBOMatrix<'r> {
    mat: &'r mut [Matrix4<f32>],
}

impl<'r> MatrixManager for GLSSBOMatrix<'r> {
    fn size(&mut self, size: uint) {assert!(self.mat.len() > size)}

    fn set(&mut self, idx: uint, mat: Matrix4<f32>) {
        assert!(idx < self.mat.len());
        unsafe { *self.mat.as_mut_ptr().offset(idx as int) = mat; }
    }

    fn get(&self, idx: uint) -> Matrix4<f32> {
        assert!(idx < self.mat.len());
        unsafe { self.mat.unsafe_get(idx).clone() }
    }
}

pub struct MatrixSSBOBuffer {
    model_matrix: GLuint,
    ptr_model_matrix: *mut Matrix4<f32>,
    size: uint,

    event: Option<Event>,
    cl: Option<(Accelerator, Arc<CommandQueue>, [CLBuffer<Matrix4<f32>>, ..1])>,
}

impl MatrixSSBOBuffer {
    pub fn new(cfg: &Config,
               cl: Option<(Arc<Context>, Arc<CommandQueue>, Arc<Device>)>) -> MatrixSSBOBuffer {
        let buffer = &mut [0];

        unsafe {
            gl::GenBuffers(buffer.len() as i32, buffer.unsafe_mut(0));

            gl::BindBuffer(gl::SHADER_STORAGE_BUFFER, buffer[0]);
            gl::BufferData(gl::SHADER_STORAGE_BUFFER,
                           (mem::size_of::<Matrix4<f32>>()*cfg.max_size()) as GLsizeiptr,
                           ptr::null(), gl::DYNAMIC_DRAW);
        }

        let clpos = match cl {
            Some((ctx, cq, dev)) => {
                let calc = Accelerator::new(ctx.deref(), dev.deref());
                let buffers = gl_cl::create_from_gl_buffer(ctx.deref(), buffer[0], CL_MEM_READ_WRITE);

                Some((calc, cq, [buffers]))
            },
            None => None
        };

        MatrixSSBOBuffer {
            model_matrix: buffer[0],
            ptr_model_matrix: ptr::null_mut(),
            size: cfg.max_size(),
            cl: clpos,
            event: None,
        }
    }

    pub fn map(&mut self) {
        match self.cl {
            None => unsafe {
                gl::BindBuffer(gl::SHADER_STORAGE_BUFFER, self.model_matrix);
                self.ptr_model_matrix = gl::MapBufferRange(gl::SHADER_STORAGE_BUFFER, 0,
                        (mem::size_of::<Matrix4<f32>>()*self.size) as GLsizeiptr,
                        gl::MAP_WRITE_BIT | gl::MAP_INVALIDATE_BUFFER_BIT
                ) as *mut Matrix4<f32>;
            },
            Some((_, ref cq, ref buf)) => {
                cq.acquire_gl_objects(buf.as_slice(), ()).wait()
            }
        }
    }

    pub fn unmap(&mut self) {
        let event = self.event.take();
        match (&self.cl, event) {
            (&None, None) => unsafe {
                gl::BindBuffer(gl::SHADER_STORAGE_BUFFER, self.model_matrix);
                gl::UnmapBuffer(gl::SHADER_STORAGE_BUFFER);
                assert!(0 == gl::GetError());
                self.ptr_model_matrix = ptr::null_mut();
            },
            (&Some((_, ref cq, ref buf)), Some(ref event)) => {
                cq.release_gl_objects(buf.as_slice(), event).wait();
            }
            _ => panic!("expected both an event and a queue")
        }
    }

    pub fn build<RD: Renderable>(&mut self, db: &RD) {
        self.event = unsafe {
            match self.cl {
                None => {
                    mut_buf_as_slice(self.ptr_model_matrix, self.size, |mat| {
                        let mut mat = GLSSBOMatrix {
                            mat: mat
                        };
                        db.write_positions(&mut mat);
                        None
                    })
                }
                Some((ref mut ctx, ref cq, ref buf)) => {
                    let evt = ctx.compute_mat(db, cq.deref(), &buf[0]);
                    Some(evt)
                }
            }
        };
    }

    pub fn id(&self) -> GLuint { self.model_matrix }
}

pub struct MatrixTextureBuffer {
    model_matrix: [GLuint, ..4],
    texture_model_matrix: [GLuint, ..4],
    ptr_model_matrix: [*mut Vector4<f32>, ..4],
    size: uint,

    event: Option<Event>,
    cl: Option<(Accelerator, Arc<CommandQueue>, [CLBuffer<Vector4<f32>>, ..4])>,
}

impl MatrixTextureBuffer {
    pub fn new(cfg: &Config,
               cl: Option<(Arc<Context>, Arc<CommandQueue>, Arc<Device>)>) -> MatrixTextureBuffer {
        let buffer = &mut [0, 0, 0, 0];
        let texture = &mut [0, 0, 0, 0];

        unsafe {
            gl::GenBuffers(buffer.len() as i32, buffer.unsafe_mut(0));
            gl::GenTextures(texture.len() as i32, texture.unsafe_mut(0));

            for (b, t) in buffer.iter().zip(texture.iter()) {
                gl::BindBuffer(gl::TEXTURE_BUFFER, *b);
                gl::BindTexture(gl::TEXTURE_BUFFER, *t);
                gl::TexBuffer(gl::TEXTURE_BUFFER, gl::RGBA32F, *b);
                gl::BufferData(gl::TEXTURE_BUFFER,
                               (mem::size_of::<Vector4<f32>>()*cfg.max_size()) as GLsizeiptr,
                               ptr::null(), gl::DYNAMIC_DRAW);
            }
        }

        let clpos = match cl {
            Some((ctx, cq, dev)) => {
                let calc = Accelerator::new(ctx.deref(), dev.deref());
                let buffers = [gl_cl::create_from_gl_buffer(ctx.deref(), buffer[0], CL_MEM_READ_WRITE),
                               gl_cl::create_from_gl_buffer(ctx.deref(), buffer[1], CL_MEM_READ_WRITE),
                               gl_cl::create_from_gl_buffer(ctx.deref(), buffer[2], CL_MEM_READ_WRITE),
                               gl_cl::create_from_gl_buffer(ctx.deref(), buffer[3], CL_MEM_READ_WRITE)];

                Some((calc, cq, buffers))
            },
            None => None
        };

        MatrixTextureBuffer {
            model_matrix: [buffer[0], buffer[1], buffer[2], buffer[3]],
            texture_model_matrix: [texture[0], texture[1], texture[2], texture[3]],
            ptr_model_matrix: [ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), ptr::null_mut()],
            size: cfg.max_size(),
            cl: clpos,
            event: None,
        }
    }

    pub fn map(&mut self) {
        match self.cl {
            None => {
                for i in range(0u, 4) { unsafe {
                    gl::BindBuffer(gl::TEXTURE_BUFFER, self.model_matrix[i]);
                    self.ptr_model_matrix[i] = gl::MapBufferRange(
                        gl::TEXTURE_BUFFER, 0,
                        (mem::size_of::<Vector4<f32>>()*self.size) as GLsizeiptr,
                        gl::MAP_WRITE_BIT | gl::MAP_INVALIDATE_BUFFER_BIT
                    ) as *mut Vector4<f32>;
                }}
            }
            Some((_, ref cq, ref buf)) => {
                cq.acquire_gl_objects(buf.as_slice(), ()).wait()
            }
        }
    }

    pub fn unmap(&mut self) {
        let event = self.event.take();
        match (&self.cl, event) {
            (&None, None) => unsafe {
                for i in range(0u, 4) {
                    gl::BindBuffer(gl::TEXTURE_BUFFER, self.model_matrix[i]);
                    gl::UnmapBuffer(gl::TEXTURE_BUFFER);
                    assert!(0 == gl::GetError());
                    self.ptr_model_matrix[i] = ptr::null_mut();
                }
            },
            (&Some((_, ref cq, ref buf)), Some(ref event)) => {
                cq.release_gl_objects(buf.as_slice(), event).wait();
            }
            _ => panic!("expected both an event and a queue")
        }
    }

    pub fn build<RD: Renderable>(&mut self, db: &RD) {
        self.event = unsafe {
            match self.cl {
                None => {
                    mut_buf_as_slice(self.ptr_model_matrix[0], self.size, |x| {
                    mut_buf_as_slice(self.ptr_model_matrix[1], self.size, |y| {
                    mut_buf_as_slice(self.ptr_model_matrix[2], self.size, |z| {
                    mut_buf_as_slice(self.ptr_model_matrix[3], self.size, |w| {
                        let mut mat = GLTextureMatrix {
                            x: x, y: y, z: z, w: w
                        };
                        db.write_positions(&mut mat);
                        None
                    })})})})
                }
                Some((ref mut ctx, ref cq, ref buf)) => {
                    let evt = ctx.compute_vec4x4(db, cq.deref(), buf);
                    Some(evt)
                }
            }
        };
    }

    pub fn ids<'a>(&'a self) -> &'a [GLuint] { self.texture_model_matrix.as_slice() }
}<|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/. */

//! Traversals over the DOM and flow trees, running the layout computations.

use construct::FlowConstructor;
use context::{LayoutContext, SharedLayoutContext};
use display_list_builder::DisplayListBuildState;
use flow::{CAN_BE_FRAGMENTED, Flow, ImmutableFlowUtils, PostorderFlowTraversal};
use flow::{PreorderFlowTraversal, self};
use gfx::display_list::OpaqueNode;
use script_layout_interface::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RestyleDamage};
use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode};
use std::mem;
use style::context::StyleContext;
use style::matching::MatchMethods;
use style::traversal::{DomTraversalContext, STYLE_BLOOM};
use style::traversal::{put_thread_local_bloom_filter, recalc_style_at};
use util::opts;
use util::tid::tid;
use wrapper::{LayoutNodeLayoutData, ServoLayoutNode, ThreadSafeLayoutNodeHelpers};

pub struct RecalcStyleAndConstructFlows<'lc> {
    context: LayoutContext<'lc>,
    root: OpaqueNode,
}

impl<'lc, 'ln> DomTraversalContext<ServoLayoutNode<'ln>> for RecalcStyleAndConstructFlows<'lc> {
    type SharedContext = SharedLayoutContext;
    #[allow(unsafe_code)]
    fn new<'a>(shared: &'a Self::SharedContext, root: OpaqueNode) -> Self {
        // FIXME(bholley): This transmutation from &'a to &'lc is very unfortunate, but I haven't
        // found a way to avoid it despite spending several days on it (and consulting Manishearth,
        // brson, and nmatsakis).
        //
        // The crux of the problem is that parameterizing DomTraversalContext on the lifetime of
        // the SharedContext doesn't work for a variety of reasons [1]. However, the code in
        // parallel.rs needs to be able to use the DomTraversalContext trait (or something similar)
        // to stack-allocate a struct (a generalized LayoutContext<'a>) that holds a borrowed
        // SharedContext, which means that the struct needs to be parameterized on a lifetime.
        // Given the aforementioned constraint, the only way to accomplish this is to avoid
        // propagating the borrow lifetime from the struct to the trait, but that means that the
        // new() method on the trait cannot require the lifetime of its argument to match the
        // lifetime of the Self object it creates.
        //
        // This could be solved with an associated type with an unbound lifetime parameter, but
        // that would require higher-kinded types, which don't exist yet and probably aren't coming
        // for a while.
        //
        // So we transmute. :-( This is safe because the DomTravesalContext is stack-allocated on
        // the worker thread while processing a WorkUnit, whereas the borrowed SharedContext is
        // live for the entire duration of the restyle. This really could _almost_ compile: all
        // we'd need to do is change the signature to to |new<'a: 'lc>|, and everything would
        // work great. But we can't do that, because that would cause a mismatch with the signature
        // in the trait we're implementing, and we can't mention 'lc in that trait at all for the
        // reasons described above.
        //
        // [1] For example, the WorkQueue type needs to be parameterized on the concrete type of
        // DomTraversalContext::SharedContext, and the WorkQueue lifetime is similar to that of the
        // LayoutThread, generally much longer than that of a given SharedLayoutContext borrow.
        let shared_lc: &'lc SharedLayoutContext = unsafe { mem::transmute(shared) };
        RecalcStyleAndConstructFlows {
            context: LayoutContext::new(shared_lc),
            root: root,
        }
    }

    fn process_preorder(&self, node: ServoLayoutNode<'ln>) {
        // FIXME(pcwalton): Stop allocating here. Ideally this should just be done by the HTML
        // parser.
        node.initialize_data();

        recalc_style_at(&self.context, self.root, node);
    }

    fn process_postorder(&self, node: ServoLayoutNode<'ln>) { construct_flows_at(&self.context, self.root, node); }
}

/// A bottom-up, parallelizable traversal.
pub trait PostorderNodeMutTraversal<ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> {
    /// The operation to perform. Return true to continue or false to stop.
    fn process(&mut self, node: &ConcreteThreadSafeLayoutNode);
}

/// The flow construction traversal, which builds flows for styled nodes.
#[inline]
#[allow(unsafe_code)]
fn construct_flows_at<'a, N: LayoutNode>(context: &'a LayoutContext<'a>, root: OpaqueNode, node: N) {
    // Construct flows for this node.
    {
        let tnode = node.to_threadsafe();

        // Always reconstruct if incremental layout is turned off.
        let nonincremental_layout = opts::get().nonincremental_layout;
        if nonincremental_layout || node.has_dirty_descendants() {
            let mut flow_constructor = FlowConstructor::new(context);
            if nonincremental_layout || !flow_constructor.repair_if_possible(&tnode) {
                flow_constructor.process(&tnode);
                debug!("Constructed flow for {:x}: {:x}",
                       tnode.debug_id(),
                       tnode.flow_debug_id());
            }
        }

        // Reset the layout damage in this node. It's been propagated to the
        // flow by the flow constructor.
        tnode.set_restyle_damage(RestyleDamage::empty());
    }

    unsafe {
        node.set_changed(false);
        node.set_dirty(false);
        node.set_dirty_descendants(false);
    }

    let unsafe_layout_node = node.to_unsafe();

    let (mut bf, old_node, old_generation) =
        STYLE_BLOOM.with(|style_bloom| {
            mem::replace(&mut *style_bloom.borrow_mut(), None)
            .expect("The bloom filter should have been set by style recalc.")
        });

    assert_eq!(old_node, unsafe_layout_node);
    assert_eq!(old_generation, context.shared_context().generation);

    match node.layout_parent_node(root) {
        None => {
            debug!("[{}] - {:X}, and deleting BF.", tid(), unsafe_layout_node.0);
            // If this is the reflow root, eat the thread-local bloom filter.
        }
        Some(parent) => {
            // Otherwise, put it back, but remove this node.
            node.remove_from_bloom_filter(&mut *bf);
            let unsafe_parent = parent.to_unsafe();
            put_thread_local_bloom_filter(bf, &unsafe_parent, &context.shared_context());
        },
    };
}

/// The bubble-inline-sizes traversal, the first part of layout computation. This computes
/// preferred and intrinsic inline-sizes and bubbles them up the tree.
pub struct BubbleISizes<'a> {
    pub layout_context: &'a LayoutContext<'a>,
}

impl<'a> PostorderFlowTraversal for BubbleISizes<'a> {
    #[inline]
    fn process(&self, flow: &mut Flow) {
        flow.bubble_inline_sizes();
        flow::mut_base(flow).restyle_damage.remove(BUBBLE_ISIZES);
    }

    #[inline]
    fn should_process(&self, flow: &mut Flow) -> bool {
        flow::base(flow).restyle_damage.contains(BUBBLE_ISIZES)
    }
}

/// The assign-inline-sizes traversal. In Gecko this corresponds to `Reflow`.
#[derive(Copy, Clone)]
pub struct AssignISizes<'a> {
    pub layout_context: &'a LayoutContext<'a>,
}

impl<'a> PreorderFlowTraversal for AssignISizes<'a> {
    #[inline]
    fn process(&self, flow: &mut Flow) {
        flow.assign_inline_sizes(self.layout_context);
    }

    #[inline]
    fn should_process(&self, flow: &mut Flow) -> bool {
        flow::base(flow).restyle_damage.intersects(REFLOW_OUT_OF_FLOW | REFLOW)
    }
}

/// The assign-block-sizes-and-store-overflow traversal, the last (and most expensive) part of
/// layout computation. Determines the final block-sizes for all layout objects and computes
/// positions. In Gecko this corresponds to `Reflow`.
#[derive(Copy, Clone)]
pub struct AssignBSizes<'a> {
    pub layout_context: &'a LayoutContext<'a>,
}

impl<'a> PostorderFlowTraversal for AssignBSizes<'a> {
    #[inline]
    fn process(&self, flow: &mut Flow) {
        // Can't do anything with anything that floats might flow through until we reach their
        // inorder parent.
        //
        // NB: We must return without resetting the restyle bits for these, as we haven't actually
        // reflowed anything!
        if flow.floats_might_flow_through() {
            return
        }

        flow.assign_block_size(self.layout_context);
    }

    #[inline]
    fn should_process(&self, flow: &mut Flow) -> bool {
        let base = flow::base(flow);
        base.restyle_damage.intersects(REFLOW_OUT_OF_FLOW | REFLOW) &&
        // The fragmentation countainer is responsible for calling Flow::fragment recursively
        !base.flags.contains(CAN_BE_FRAGMENTED)
    }
}

#[derive(Copy, Clone)]
pub struct ComputeAbsolutePositions<'a> {
    pub layout_context: &'a LayoutContext<'a>,
}

impl<'a> PreorderFlowTraversal for ComputeAbsolutePositions<'a> {
    #[inline]
    fn process(&self, flow: &mut Flow) {
        flow.compute_absolute_position(self.layout_context);
    }
}

pub struct BuildDisplayList<'a> {
    pub state: DisplayListBuildState<'a>,
}

impl<'a> BuildDisplayList<'a> {
    #[inline]
    pub fn traverse(&mut self, flow: &mut Flow) {
        if self.should_process() {
            self.state.push_stacking_context_id(flow::base(flow).stacking_context_id);
            flow.build_display_list(&mut self.state);
            flow::mut_base(flow).restyle_damage.remove(REPAINT);
            self.state.pop_stacking_context_id();
        }

        for kid in flow::child_iter_mut(flow) {
            self.traverse(kid);
        }
    }

    #[inline]
    fn should_process(&self) -> bool {
        true
    }
}
<commit_msg>Make RecalcStyleAndConstructFlows generic over the LayoutNode implementation.<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/. */

//! Traversals over the DOM and flow trees, running the layout computations.

use construct::FlowConstructor;
use context::{LayoutContext, SharedLayoutContext};
use display_list_builder::DisplayListBuildState;
use flow::{CAN_BE_FRAGMENTED, Flow, ImmutableFlowUtils, PostorderFlowTraversal};
use flow::{PreorderFlowTraversal, self};
use gfx::display_list::OpaqueNode;
use script_layout_interface::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RestyleDamage};
use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode};
use std::mem;
use style::context::StyleContext;
use style::dom::TNode;
use style::matching::MatchMethods;
use style::properties::ServoComputedValues;
use style::selector_impl::ServoSelectorImpl;
use style::traversal::{DomTraversalContext, STYLE_BLOOM};
use style::traversal::{put_thread_local_bloom_filter, recalc_style_at};
use util::opts;
use util::tid::tid;
use wrapper::{LayoutNodeLayoutData, ThreadSafeLayoutNodeHelpers};

pub struct RecalcStyleAndConstructFlows<'lc> {
    context: LayoutContext<'lc>,
    root: OpaqueNode,
}

impl<'lc, N> DomTraversalContext<N> for RecalcStyleAndConstructFlows<'lc>
    where N: LayoutNode + TNode<ConcreteComputedValues=ServoComputedValues>,
          N::ConcreteElement: ::selectors::Element<Impl=ServoSelectorImpl>

{
    type SharedContext = SharedLayoutContext;
    #[allow(unsafe_code)]
    fn new<'a>(shared: &'a Self::SharedContext, root: OpaqueNode) -> Self {
        // FIXME(bholley): This transmutation from &'a to &'lc is very unfortunate, but I haven't
        // found a way to avoid it despite spending several days on it (and consulting Manishearth,
        // brson, and nmatsakis).
        //
        // The crux of the problem is that parameterizing DomTraversalContext on the lifetime of
        // the SharedContext doesn't work for a variety of reasons [1]. However, the code in
        // parallel.rs needs to be able to use the DomTraversalContext trait (or something similar)
        // to stack-allocate a struct (a generalized LayoutContext<'a>) that holds a borrowed
        // SharedContext, which means that the struct needs to be parameterized on a lifetime.
        // Given the aforementioned constraint, the only way to accomplish this is to avoid
        // propagating the borrow lifetime from the struct to the trait, but that means that the
        // new() method on the trait cannot require the lifetime of its argument to match the
        // lifetime of the Self object it creates.
        //
        // This could be solved with an associated type with an unbound lifetime parameter, but
        // that would require higher-kinded types, which don't exist yet and probably aren't coming
        // for a while.
        //
        // So we transmute. :-( This is safe because the DomTravesalContext is stack-allocated on
        // the worker thread while processing a WorkUnit, whereas the borrowed SharedContext is
        // live for the entire duration of the restyle. This really could _almost_ compile: all
        // we'd need to do is change the signature to to |new<'a: 'lc>|, and everything would
        // work great. But we can't do that, because that would cause a mismatch with the signature
        // in the trait we're implementing, and we can't mention 'lc in that trait at all for the
        // reasons described above.
        //
        // [1] For example, the WorkQueue type needs to be parameterized on the concrete type of
        // DomTraversalContext::SharedContext, and the WorkQueue lifetime is similar to that of the
        // LayoutThread, generally much longer than that of a given SharedLayoutContext borrow.
        let shared_lc: &'lc SharedLayoutContext = unsafe { mem::transmute(shared) };
        RecalcStyleAndConstructFlows {
            context: LayoutContext::new(shared_lc),
            root: root,
        }
    }

    fn process_preorder(&self, node: N) {
        // FIXME(pcwalton): Stop allocating here. Ideally this should just be done by the HTML
        // parser.
        node.initialize_data();

        recalc_style_at(&self.context, self.root, node);
    }

    fn process_postorder(&self, node: N) { construct_flows_at(&self.context, self.root, node); }
}

/// A bottom-up, parallelizable traversal.
pub trait PostorderNodeMutTraversal<ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> {
    /// The operation to perform. Return true to continue or false to stop.
    fn process(&mut self, node: &ConcreteThreadSafeLayoutNode);
}

/// The flow construction traversal, which builds flows for styled nodes.
#[inline]
#[allow(unsafe_code)]
fn construct_flows_at<'a, N: LayoutNode>(context: &'a LayoutContext<'a>, root: OpaqueNode, node: N) {
    // Construct flows for this node.
    {
        let tnode = node.to_threadsafe();

        // Always reconstruct if incremental layout is turned off.
        let nonincremental_layout = opts::get().nonincremental_layout;
        if nonincremental_layout || node.has_dirty_descendants() {
            let mut flow_constructor = FlowConstructor::new(context);
            if nonincremental_layout || !flow_constructor.repair_if_possible(&tnode) {
                flow_constructor.process(&tnode);
                debug!("Constructed flow for {:x}: {:x}",
                       tnode.debug_id(),
                       tnode.flow_debug_id());
            }
        }

        // Reset the layout damage in this node. It's been propagated to the
        // flow by the flow constructor.
        tnode.set_restyle_damage(RestyleDamage::empty());
    }

    unsafe {
        node.set_changed(false);
        node.set_dirty(false);
        node.set_dirty_descendants(false);
    }

    let unsafe_layout_node = node.to_unsafe();

    let (mut bf, old_node, old_generation) =
        STYLE_BLOOM.with(|style_bloom| {
            mem::replace(&mut *style_bloom.borrow_mut(), None)
            .expect("The bloom filter should have been set by style recalc.")
        });

    assert_eq!(old_node, unsafe_layout_node);
    assert_eq!(old_generation, context.shared_context().generation);

    match node.layout_parent_node(root) {
        None => {
            debug!("[{}] - {:X}, and deleting BF.", tid(), unsafe_layout_node.0);
            // If this is the reflow root, eat the thread-local bloom filter.
        }
        Some(parent) => {
            // Otherwise, put it back, but remove this node.
            node.remove_from_bloom_filter(&mut *bf);
            let unsafe_parent = parent.to_unsafe();
            put_thread_local_bloom_filter(bf, &unsafe_parent, &context.shared_context());
        },
    };
}

/// The bubble-inline-sizes traversal, the first part of layout computation. This computes
/// preferred and intrinsic inline-sizes and bubbles them up the tree.
pub struct BubbleISizes<'a> {
    pub layout_context: &'a LayoutContext<'a>,
}

impl<'a> PostorderFlowTraversal for BubbleISizes<'a> {
    #[inline]
    fn process(&self, flow: &mut Flow) {
        flow.bubble_inline_sizes();
        flow::mut_base(flow).restyle_damage.remove(BUBBLE_ISIZES);
    }

    #[inline]
    fn should_process(&self, flow: &mut Flow) -> bool {
        flow::base(flow).restyle_damage.contains(BUBBLE_ISIZES)
    }
}

/// The assign-inline-sizes traversal. In Gecko this corresponds to `Reflow`.
#[derive(Copy, Clone)]
pub struct AssignISizes<'a> {
    pub layout_context: &'a LayoutContext<'a>,
}

impl<'a> PreorderFlowTraversal for AssignISizes<'a> {
    #[inline]
    fn process(&self, flow: &mut Flow) {
        flow.assign_inline_sizes(self.layout_context);
    }

    #[inline]
    fn should_process(&self, flow: &mut Flow) -> bool {
        flow::base(flow).restyle_damage.intersects(REFLOW_OUT_OF_FLOW | REFLOW)
    }
}

/// The assign-block-sizes-and-store-overflow traversal, the last (and most expensive) part of
/// layout computation. Determines the final block-sizes for all layout objects and computes
/// positions. In Gecko this corresponds to `Reflow`.
#[derive(Copy, Clone)]
pub struct AssignBSizes<'a> {
    pub layout_context: &'a LayoutContext<'a>,
}

impl<'a> PostorderFlowTraversal for AssignBSizes<'a> {
    #[inline]
    fn process(&self, flow: &mut Flow) {
        // Can't do anything with anything that floats might flow through until we reach their
        // inorder parent.
        //
        // NB: We must return without resetting the restyle bits for these, as we haven't actually
        // reflowed anything!
        if flow.floats_might_flow_through() {
            return
        }

        flow.assign_block_size(self.layout_context);
    }

    #[inline]
    fn should_process(&self, flow: &mut Flow) -> bool {
        let base = flow::base(flow);
        base.restyle_damage.intersects(REFLOW_OUT_OF_FLOW | REFLOW) &&
        // The fragmentation countainer is responsible for calling Flow::fragment recursively
        !base.flags.contains(CAN_BE_FRAGMENTED)
    }
}

#[derive(Copy, Clone)]
pub struct ComputeAbsolutePositions<'a> {
    pub layout_context: &'a LayoutContext<'a>,
}

impl<'a> PreorderFlowTraversal for ComputeAbsolutePositions<'a> {
    #[inline]
    fn process(&self, flow: &mut Flow) {
        flow.compute_absolute_position(self.layout_context);
    }
}

pub struct BuildDisplayList<'a> {
    pub state: DisplayListBuildState<'a>,
}

impl<'a> BuildDisplayList<'a> {
    #[inline]
    pub fn traverse(&mut self, flow: &mut Flow) {
        if self.should_process() {
            self.state.push_stacking_context_id(flow::base(flow).stacking_context_id);
            flow.build_display_list(&mut self.state);
            flow::mut_base(flow).restyle_damage.remove(REPAINT);
            self.state.pop_stacking_context_id();
        }

        for kid in flow::child_iter_mut(flow) {
            self.traverse(kid);
        }
    }

    #[inline]
    fn should_process(&self) -> bool {
        true
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// The MIT License (MIT)

// Copyright (c) 2015 Rustcc Developers

//  Permission is hereby granted, free of charge, to any person obtaining a
//  copy of this software and associated documentation files (the "Software"),
//  to deal in the Software without restriction, including without limitation
//  the rights to use, copy, modify, merge, publish, distribute, sublicense,
//  and/or sell copies of the Software, and to permit persons to whom the
//  Software is furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
//  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
//  DEALINGS IN THE SOFTWARE.

use std::ptr;
use std::fmt;

use libc;

use mmap::{MemoryMap, MapOption};

/// A task's stack. The name "Stack" is a vestige of segmented stacks.
pub struct Stack {
    buf: Option<MemoryMap>,
    min_size: usize,
}

impl fmt::Debug for Stack {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "Stack {} buf: ", "{"));
        match self.buf {
            Some(ref map) => try!(write!(f, "Some({:#x}), ", map.data() as libc::uintptr_t)),
            None => try!(write!(f, "None, ")),
        }
        write!(f, "min_size: {:?} {}", self.min_size, "}")
    }
}

// Try to use MAP_STACK on platforms that support it (it's what we're doing
// anyway), but some platforms don't support it at all. For example, it appears
// that there's a bug in freebsd that MAP_STACK implies MAP_FIXED (so it always
// fails): http://lists.freebsd.org/pipermail/freebsd-bugs/2011-July/044840.html
//
// DragonFly BSD also seems to suffer from the same problem. When MAP_STACK is
// used, it returns the same `ptr` multiple times.
#[cfg(all(not(windows), not(target_os = "freebsd"), not(target_os = "dragonfly")))]
static STACK_FLAGS: libc::c_int = libc::MAP_STACK | libc::MAP_PRIVATE | libc::MAP_ANON;
#[cfg(any(target_os = "freebsd",
          target_os = "dragonfly"))]
static STACK_FLAGS: libc::c_int = libc::MAP_PRIVATE | libc::MAP_ANON;
#[cfg(windows)]
static STACK_FLAGS: libc::c_int = 0;

impl Stack {
    /// Allocate a new stack of `size`. If size = 0, this will fail. Use
    /// `dummy_stack` if you want a zero-sized stack.
    pub fn new(size: usize) -> Stack {
        // Map in a stack. Eventually we might be able to handle stack
        // allocation failure, which would fail to spawn the task. But there's
        // not many sensible things to do on OOM.  Failure seems fine (and is
        // what the old stack allocation did).
        let stack = match MemoryMap::new(size, &[MapOption::MapReadable,
                                                 MapOption::MapWritable,
                                                 MapOption::MapNonStandardFlags(STACK_FLAGS)]) {
            Ok(map) => map,
            Err(e) => panic!("mmap for stack of size {} failed: {}", size, e)
        };

        // Change the last page to be inaccessible. This is to provide safety;
        // when an FFI function overflows it will (hopefully) hit this guard
        // page. It isn't guaranteed, but that's why FFI is unsafe. buf.data is
        // guaranteed to be aligned properly.
        if !protect_last_page(&stack) {
            panic!("Could not memory-protect guard page. stack={:?}",
                  stack.data());
        }

        Stack {
            buf: Some(stack),
            min_size: size,
        }
    }

    /// Create a 0-length stack which starts (and ends) at 0.
    #[allow(dead_code)]
    pub unsafe fn dummy_stack() -> Stack {
        Stack {
            buf: None,
            min_size: 0,
        }
    }

    #[allow(dead_code)]
    pub fn guard(&self) -> *const usize {
        (self.start() as usize + page_size()) as *const usize
    }

    /// Point to the low end of the allocated stack
    pub fn start(&self) -> *const usize {
        self.buf.as_ref()
            .map(|m| m.data() as *const usize)
            .unwrap_or(ptr::null())
    }

    /// Point one usize beyond the high end of the allocated stack
    pub fn end(&self) -> *const usize {
        self.buf
            .as_ref()
            .map(|buf| unsafe {
                buf.data().offset(buf.len() as isize) as *const usize
            })
            .unwrap_or(ptr::null())
    }

    /// Minimun size of this stack
    #[inline(always)]
    pub fn min_size(&self) -> usize {
        self.min_size
    }
}

#[cfg(unix)]
fn protect_last_page(stack: &MemoryMap) -> bool {
    unsafe {
        // This may seem backwards: the start of the segment is the last page?
        // Yes! The stack grows from higher addresses (the end of the allocated
        // block) to lower addresses (the start of the allocated block).
        let last_page = stack.data() as *mut libc::c_void;
        libc::mprotect(last_page, page_size() as libc::size_t,
                       libc::PROT_NONE) != -1
    }
}

#[cfg(windows)]
fn protect_last_page(stack: &MemoryMap) -> bool {
    unsafe {
        // see above
        let last_page = stack.data() as *mut libc::c_void;
        let mut old_prot: libc::DWORD = 0;
        libc::VirtualProtect(last_page, page_size() as libc::SIZE_T,
                             libc::PAGE_NOACCESS,
                             &mut old_prot as libc::LPDWORD) != 0
    }
}

#[cfg(unix)]
fn page_size() -> usize {
    unsafe {
        libc::sysconf(libc::_SC_PAGESIZE) as usize
    }
}

#[cfg(windows)]
fn page_size() -> usize {
    unsafe {
        let mut info = mem::zeroed();
        libc::GetSystemInfo(&mut info);
        info.dwPageSize as usize
    }
}
<commit_msg>Bugfix with std::mem (modern Rust)<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// The MIT License (MIT)

// Copyright (c) 2015 Rustcc Developers

//  Permission is hereby granted, free of charge, to any person obtaining a
//  copy of this software and associated documentation files (the "Software"),
//  to deal in the Software without restriction, including without limitation
//  the rights to use, copy, modify, merge, publish, distribute, sublicense,
//  and/or sell copies of the Software, and to permit persons to whom the
//  Software is furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
//  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
//  DEALINGS IN THE SOFTWARE.

use std::ptr;
use std::fmt;
use std::mem;

use libc;

use mmap::{MemoryMap, MapOption};

/// A task's stack. The name "Stack" is a vestige of segmented stacks.
pub struct Stack {
    buf: Option<MemoryMap>,
    min_size: usize,
}

impl fmt::Debug for Stack {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "Stack {} buf: ", "{"));
        match self.buf {
            Some(ref map) => try!(write!(f, "Some({:#x}), ", map.data() as libc::uintptr_t)),
            None => try!(write!(f, "None, ")),
        }
        write!(f, "min_size: {:?} {}", self.min_size, "}")
    }
}

// Try to use MAP_STACK on platforms that support it (it's what we're doing
// anyway), but some platforms don't support it at all. For example, it appears
// that there's a bug in freebsd that MAP_STACK implies MAP_FIXED (so it always
// fails): http://lists.freebsd.org/pipermail/freebsd-bugs/2011-July/044840.html
//
// DragonFly BSD also seems to suffer from the same problem. When MAP_STACK is
// used, it returns the same `ptr` multiple times.
#[cfg(all(not(windows), not(target_os = "freebsd"), not(target_os = "dragonfly")))]
static STACK_FLAGS: libc::c_int = libc::MAP_STACK | libc::MAP_PRIVATE | libc::MAP_ANON;
#[cfg(any(target_os = "freebsd",
          target_os = "dragonfly"))]
static STACK_FLAGS: libc::c_int = libc::MAP_PRIVATE | libc::MAP_ANON;
#[cfg(windows)]
static STACK_FLAGS: libc::c_int = 0;

impl Stack {
    /// Allocate a new stack of `size`. If size = 0, this will fail. Use
    /// `dummy_stack` if you want a zero-sized stack.
    pub fn new(size: usize) -> Stack {
        // Map in a stack. Eventually we might be able to handle stack
        // allocation failure, which would fail to spawn the task. But there's
        // not many sensible things to do on OOM.  Failure seems fine (and is
        // what the old stack allocation did).
        let stack = match MemoryMap::new(size, &[MapOption::MapReadable,
                                                 MapOption::MapWritable,
                                                 MapOption::MapNonStandardFlags(STACK_FLAGS)]) {
            Ok(map) => map,
            Err(e) => panic!("mmap for stack of size {} failed: {}", size, e)
        };

        // Change the last page to be inaccessible. This is to provide safety;
        // when an FFI function overflows it will (hopefully) hit this guard
        // page. It isn't guaranteed, but that's why FFI is unsafe. buf.data is
        // guaranteed to be aligned properly.
        if !protect_last_page(&stack) {
            panic!("Could not memory-protect guard page. stack={:?}",
                  stack.data());
        }

        Stack {
            buf: Some(stack),
            min_size: size,
        }
    }

    /// Create a 0-length stack which starts (and ends) at 0.
    #[allow(dead_code)]
    pub unsafe fn dummy_stack() -> Stack {
        Stack {
            buf: None,
            min_size: 0,
        }
    }

    #[allow(dead_code)]
    pub fn guard(&self) -> *const usize {
        (self.start() as usize + page_size()) as *const usize
    }

    /// Point to the low end of the allocated stack
    pub fn start(&self) -> *const usize {
        self.buf.as_ref()
            .map(|m| m.data() as *const usize)
            .unwrap_or(ptr::null())
    }

    /// Point one usize beyond the high end of the allocated stack
    pub fn end(&self) -> *const usize {
        self.buf
            .as_ref()
            .map(|buf| unsafe {
                buf.data().offset(buf.len() as isize) as *const usize
            })
            .unwrap_or(ptr::null())
    }

    /// Minimun size of this stack
    #[inline(always)]
    pub fn min_size(&self) -> usize {
        self.min_size
    }
}

#[cfg(unix)]
fn protect_last_page(stack: &MemoryMap) -> bool {
    unsafe {
        // This may seem backwards: the start of the segment is the last page?
        // Yes! The stack grows from higher addresses (the end of the allocated
        // block) to lower addresses (the start of the allocated block).
        let last_page = stack.data() as *mut libc::c_void;
        libc::mprotect(last_page, page_size() as libc::size_t,
                       libc::PROT_NONE) != -1
    }
}

#[cfg(windows)]
fn protect_last_page(stack: &MemoryMap) -> bool {
    unsafe {
        // see above
        let last_page = stack.data() as *mut libc::c_void;
        let mut old_prot: libc::DWORD = 0;
        libc::VirtualProtect(last_page, page_size() as libc::SIZE_T,
                             libc::PAGE_NOACCESS,
                             &mut old_prot as libc::LPDWORD) != 0
    }
}

#[cfg(unix)]
fn page_size() -> usize {
    unsafe {
        libc::sysconf(libc::_SC_PAGESIZE) as usize
    }
}

#[cfg(windows)]
fn page_size() -> usize {
    unsafe {
        let mut info = mem::zeroed();
        libc::GetSystemInfo(&mut info);
        info.dwPageSize as usize
    }
}
<|endoftext|>


<commit_before>// min-version: 1.33.0

// === GDB TESTS ===================================================================================

// gdb-command:run

// gdb-command: print btree_set
// gdbg-check:$1 = size=15 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}

// gdb-command: print btree_map
// gdbg-check:$2 = size=15 = {[0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 5, [6] = 6, [7] = 7, [8] = 8, [9] = 9, [10] = 10, [11] = 11, [12] = 12, [13] = 13, [14] = 14}

use std::collections::{BTreeMap, BTreeSet};

fn main() {
    let mut btree_set = BTreeSet::new();
    for i in 0..15 {
        btree_set.insert(i);
    }

    let mut btree_map = BTreeMap::new();
    for i in 0..15 {
        btree_map.insert(i, i);
    }
    print!(""); // #break
}
<commit_msg>T: disable btree tests for 1.44<commit_after>// min-version: 1.33.0
// max-version: 1.43.0

// === GDB TESTS ===================================================================================

// gdb-command:run

// gdb-command: print btree_set
// gdbg-check:$1 = size=15 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}

// gdb-command: print btree_map
// gdbg-check:$2 = size=15 = {[0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 5, [6] = 6, [7] = 7, [8] = 8, [9] = 9, [10] = 10, [11] = 11, [12] = 12, [13] = 13, [14] = 14}

use std::collections::{BTreeMap, BTreeSet};

fn main() {
    let mut btree_set = BTreeSet::new();
    for i in 0..15 {
        btree_set.insert(i);
    }

    let mut btree_map = BTreeMap::new();
    for i in 0..15 {
        btree_map.insert(i, i);
    }
    print!(""); // #break
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::io::buffered::BufferedWriter;

struct DummyWriter;
impl Writer for DummyWriter {
    fn write(&mut self, _: &[u8]) {}
}

static ITER: int = 50;
static LIMIT: f64 = 2.0;

fn main() {
    let args = std::os::args();
    let (w, mut out) = if args.len() < 2 {
        println("Test mode: do not dump the image.");
        (1000, ~DummyWriter as ~Writer)
    } else {
        (from_str(args[1]).unwrap(),
         ~BufferedWriter::new(std::io::stdout()) as ~Writer)
    };
    let h = w;
    let mut byte_acc = 0i8;
    let mut bit_num = 0;

    writeln!(out, "P4\n{} {}", w, h);

    for y in range(0, h) {
        let y = y as f64;
        for x in range(0, w) {
            let mut z_r = 0f64;
            let mut z_i = 0f64;
            let mut t_r = 0f64;
            let mut t_i = 0f64;
            let c_r = 2.0 * (x as f64) / (w as f64) - 1.5;
            let c_i = 2.0 * (y as f64) / (h as f64) - 1.0;

            for _ in range(0, ITER) {
                if t_r + t_i > LIMIT * LIMIT {
                    break;
                }

                z_i = 2.0 * z_r * z_i + c_i;
                z_r = t_r - t_i + c_r;
                t_r = z_r * z_r;
                t_i = z_i * z_i;
            }

            byte_acc <<= 1;
            if t_r + t_i <= LIMIT * LIMIT {
                byte_acc |= 1;
            }

            bit_num += 1;

            if bit_num == 8 {
                out.write_i8(byte_acc);
                byte_acc = 0;
                bit_num = 0;
            } else if x == w - 1 {
                byte_acc <<= 8 - w % 8;
                out.write_i8(byte_acc);
                byte_acc = 0;
                bit_num = 0;
            }
        }
    }

    out.flush();
}
<commit_msg>Clarrify the message for test mode and use u8 instead of i8 for storing bits<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::io::buffered::BufferedWriter;

struct DummyWriter;
impl Writer for DummyWriter {
    fn write(&mut self, _: &[u8]) {}
}

static ITER: int = 50;
static LIMIT: f64 = 2.0;

fn main() {
    let args = std::os::args();
    let (w, mut out) = if args.len() < 2 {
        println("Test mode: do not dump the image because it's not utf8,"
                + " which interferes with the test runner.");
        (1000, ~DummyWriter as ~Writer)
    } else {
        (from_str(args[1]).unwrap(),
         ~BufferedWriter::new(std::io::stdout()) as ~Writer)
    };
    let h = w;
    let mut byte_acc = 0u8;
    let mut bit_num = 0;

    writeln!(out, "P4\n{} {}", w, h);

    for y in range(0, h) {
        let y = y as f64;
        for x in range(0, w) {
            let mut z_r = 0f64;
            let mut z_i = 0f64;
            let mut t_r = 0f64;
            let mut t_i = 0f64;
            let c_r = 2.0 * (x as f64) / (w as f64) - 1.5;
            let c_i = 2.0 * (y as f64) / (h as f64) - 1.0;

            for _ in range(0, ITER) {
                if t_r + t_i > LIMIT * LIMIT {
                    break;
                }

                z_i = 2.0 * z_r * z_i + c_i;
                z_r = t_r - t_i + c_r;
                t_r = z_r * z_r;
                t_i = z_i * z_i;
            }

            byte_acc <<= 1;
            if t_r + t_i <= LIMIT * LIMIT {
                byte_acc |= 1;
            }

            bit_num += 1;

            if bit_num == 8 {
                out.write_u8(byte_acc);
                byte_acc = 0;
                bit_num = 0;
            } else if x == w - 1 {
                byte_acc <<= 8 - w % 8;
                out.write_u8(byte_acc);
                byte_acc = 0;
                bit_num = 0;
            }
        }
    }

    out.flush();
}
<|endoftext|>


<commit_before>pub type door_attr_t = ::c_uint;
pub type door_id_t = ::c_ulonglong;

s! {
    pub struct shmid_ds {
        pub shm_perm: ::ipc_perm,
        pub shm_segsz: ::size_t,
        pub shm_flags: ::uintptr_t,
        pub shm_lkcnt: ::c_ushort,
        pub shm_lpid: ::pid_t,
        pub shm_cpid: ::pid_t,
        pub shm_nattch: ::shmatt_t,
        pub shm_cnattch: ::c_ulong,
        pub shm_atime: ::time_t,
        pub shm_dtime: ::time_t,
        pub shm_ctime: ::time_t,
        pub shm_amp: *mut ::c_void,
        pub shm_gransize: u64,
        pub shm_allocated: u64,
        pub shm_pad4: [i64; 1],
    }

    pub struct door_desc_t__d_data__d_desc {
        pub d_descriptor: ::c_int,
        pub d_id: ::door_id_t
    }
}

pub const PORT_SOURCE_POSTWAIT: ::c_int = 8;
pub const PORT_SOURCE_SIGNAL: ::c_int = 9;

pub const AF_LOCAL: ::c_int = 0;
pub const AF_FILE: ::c_int = 0;

pub const TCP_KEEPIDLE: ::c_int = 0x1d;
pub const TCP_KEEPCNT: ::c_int = 0x1e;
pub const TCP_KEEPINTVL: ::c_int = 0x1f;

extern "C" {
    pub fn fexecve(
        fd: ::c_int,
        argv: *const *const ::c_char,
        envp: *const *const ::c_char,
    ) -> ::c_int;

    pub fn mincore(addr: *const ::c_void, len: ::size_t, vec: *mut ::c_char) -> ::c_int;

    pub fn door_call(d: ::c_int, params: *const door_arg_t) -> ::c_int;
    pub fn door_return(
        data_ptr: *const ::c_char,
        data_size: ::size_t,
        desc_ptr: *const door_desc_t,
        num_desc: ::c_uint,
    );
    pub fn door_create(
        server_procedure: extern "C" fn(
            cookie: *const ::c_void,
            argp: *const ::c_char,
            arg_size: ::size_t,
            dp: *const door_desc_t,
            n_desc: ::c_uint,
        ),
        cookie: *const ::c_void,
        attributes: door_attr_t,
    ) -> ::c_int;

    pub fn fattach(fildes: ::c_int, path: *const ::c_char) -> ::c_int;

    pub fn pthread_getattr_np(thread: ::pthread_t, attr: *mut ::pthread_attr_t) -> ::c_int;
}

s_no_extra_traits! {
    #[cfg_attr(feature = "extra_traits", allow(missing_debug_implementations))]
    pub union door_desc_t__d_data {
        pub d_desc: door_desc_t__d_data__d_desc,
        d_resv: [::c_int; 5], /* Check out /usr/include/sys/door.h */
    }

    #[cfg_attr(feature = "extra_traits", allow(missing_debug_implementations))]
    pub struct door_desc_t {
        pub d_attributes: door_attr_t,
        pub d_data: door_desc_t__d_data,
    }

    #[cfg_attr(feature = "extra_traits", allow(missing_debug_implementations))]
    pub struct door_arg_t {
        pub data_ptr: *const ::c_char,
        pub data_size: ::size_t,
        pub desc_ptr: *const door_desc_t,
        pub dec_num: ::c_uint,
        pub rbuf: *const ::c_char,
        pub rsize: ::size_t,
    }
}
<commit_msg>Solaris TCP_KEEPINTVL and TCP_KEEPCNT have wrong values<commit_after>pub type door_attr_t = ::c_uint;
pub type door_id_t = ::c_ulonglong;

s! {
    pub struct shmid_ds {
        pub shm_perm: ::ipc_perm,
        pub shm_segsz: ::size_t,
        pub shm_flags: ::uintptr_t,
        pub shm_lkcnt: ::c_ushort,
        pub shm_lpid: ::pid_t,
        pub shm_cpid: ::pid_t,
        pub shm_nattch: ::shmatt_t,
        pub shm_cnattch: ::c_ulong,
        pub shm_atime: ::time_t,
        pub shm_dtime: ::time_t,
        pub shm_ctime: ::time_t,
        pub shm_amp: *mut ::c_void,
        pub shm_gransize: u64,
        pub shm_allocated: u64,
        pub shm_pad4: [i64; 1],
    }

    pub struct door_desc_t__d_data__d_desc {
        pub d_descriptor: ::c_int,
        pub d_id: ::door_id_t
    }
}

pub const PORT_SOURCE_POSTWAIT: ::c_int = 8;
pub const PORT_SOURCE_SIGNAL: ::c_int = 9;

pub const AF_LOCAL: ::c_int = 0;
pub const AF_FILE: ::c_int = 0;

pub const TCP_KEEPIDLE: ::c_int = 0x1d;
pub const TCP_KEEPINTVL: ::c_int = 0x1e;
pub const TCP_KEEPCNT: ::c_int = 0x1f;

extern "C" {
    pub fn fexecve(
        fd: ::c_int,
        argv: *const *const ::c_char,
        envp: *const *const ::c_char,
    ) -> ::c_int;

    pub fn mincore(addr: *const ::c_void, len: ::size_t, vec: *mut ::c_char) -> ::c_int;

    pub fn door_call(d: ::c_int, params: *const door_arg_t) -> ::c_int;
    pub fn door_return(
        data_ptr: *const ::c_char,
        data_size: ::size_t,
        desc_ptr: *const door_desc_t,
        num_desc: ::c_uint,
    );
    pub fn door_create(
        server_procedure: extern "C" fn(
            cookie: *const ::c_void,
            argp: *const ::c_char,
            arg_size: ::size_t,
            dp: *const door_desc_t,
            n_desc: ::c_uint,
        ),
        cookie: *const ::c_void,
        attributes: door_attr_t,
    ) -> ::c_int;

    pub fn fattach(fildes: ::c_int, path: *const ::c_char) -> ::c_int;

    pub fn pthread_getattr_np(thread: ::pthread_t, attr: *mut ::pthread_attr_t) -> ::c_int;
}

s_no_extra_traits! {
    #[cfg_attr(feature = "extra_traits", allow(missing_debug_implementations))]
    pub union door_desc_t__d_data {
        pub d_desc: door_desc_t__d_data__d_desc,
        d_resv: [::c_int; 5], /* Check out /usr/include/sys/door.h */
    }

    #[cfg_attr(feature = "extra_traits", allow(missing_debug_implementations))]
    pub struct door_desc_t {
        pub d_attributes: door_attr_t,
        pub d_data: door_desc_t__d_data,
    }

    #[cfg_attr(feature = "extra_traits", allow(missing_debug_implementations))]
    pub struct door_arg_t {
        pub data_ptr: *const ::c_char,
        pub data_size: ::size_t,
        pub desc_ptr: *const door_desc_t,
        pub dec_num: ::c_uint,
        pub rbuf: *const ::c_char,
        pub rsize: ::size_t,
    }
}
<|endoftext|>


<commit_before>#![no_main]
#[macro_use]
extern crate libfuzzer_sys;
extern crate alloc;
extern crate cbor;

use alloc::vec::Vec;

fuzz_target!(|data: &[u8]| {
    let encoded = cbor::read(data);
    if let Ok(value) = encoded {
	let mut decoded = Vec::new();
	let result = cbor::write(value, &mut decoded);
	assert!(result);
	assert_eq!(decoded, data);
    };
});

<commit_msg>Refactoring<commit_after>#![no_main]
#[macro_use]
extern crate libfuzzer_sys;
extern crate alloc;
extern crate cbor;

use alloc::vec::Vec;

fuzz_target!(|data: &[u8]| {
    if let Ok(value) = cbor::read(data) {
        let mut result = Vec::new();
        assert!(cbor::write(value, &mut result));
        assert_eq!(result, data);
    };
});
<|endoftext|>


<commit_before>#![cfg(feature = "bytes")]

use std::fmt;
use std::ops::Deref;
use std::str;

use bytes::Bytes;

use crate::clear::Clear;

/// Thin wrapper around `Bytes` which guarantees that bytes are valid UTF-8 string.
/// Should be API-compatible to `String`.
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Chars(Bytes);

impl Chars {
    /// New empty object.
    pub fn new() -> Chars {
        Chars(Bytes::new())
    }

    /// Try convert from `Bytes`
    pub fn from_bytes(bytes: Bytes) -> Result<Chars, str::Utf8Error> {
        str::from_utf8(&bytes)?;

        Ok(Chars(bytes))
    }

    /// Len in bytes.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Self-explanatory
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }
}

impl<'a> From<&'a str> for Chars {
    fn from(src: &'a str) -> Chars {
        Chars(Bytes::copy_from_slice(src.as_bytes()))
    }
}

impl From<String> for Chars {
    fn from(src: String) -> Chars {
        Chars(Bytes::from(src))
    }
}

impl Into<String> for Chars {
    fn into(self) -> String {
        unsafe { String::from_utf8_unchecked(self.0.into()) }
    }
}

impl Default for Chars {
    fn default() -> Self {
        Chars::new()
    }
}

impl Deref for Chars {
    type Target = str;

    fn deref(&self) -> &str {
        unsafe { str::from_utf8_unchecked(&self.0) }
    }
}

impl Clear for Chars {
    fn clear(&mut self) {
        self.0.clear();
    }
}

impl fmt::Display for Chars {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&**self, f)
    }
}

impl fmt::Debug for Chars {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&**self, f)
    }
}

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

    #[test]
    fn test_display_and_debug() {
        let s = "test";
        let string: String = s.into();
        let chars: Chars = s.into();

        assert_eq!(format!("{}", string), format!("{}", chars));
        assert_eq!(format!("{:?}", string), format!("{:?}", chars));
    }
}
<commit_msg>Explatin while unsafe is safe in chars<commit_after>#![cfg(feature = "bytes")]

use std::fmt;
use std::ops::Deref;
use std::str;

use bytes::Bytes;

use crate::clear::Clear;

/// Thin wrapper around `Bytes` which guarantees that bytes are valid UTF-8 string.
/// Should be API-compatible to `String`.
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Chars(Bytes);

impl Chars {
    /// New empty object.
    pub fn new() -> Chars {
        Chars(Bytes::new())
    }

    /// Try convert from `Bytes`
    pub fn from_bytes(bytes: Bytes) -> Result<Chars, str::Utf8Error> {
        str::from_utf8(&bytes)?;

        Ok(Chars(bytes))
    }

    /// Len in bytes.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Self-explanatory
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }
}

impl<'a> From<&'a str> for Chars {
    fn from(src: &'a str) -> Chars {
        Chars(Bytes::copy_from_slice(src.as_bytes()))
    }
}

impl From<String> for Chars {
    fn from(src: String) -> Chars {
        Chars(Bytes::from(src))
    }
}

impl Into<String> for Chars {
    fn into(self) -> String {
        // This is safe because `Chars` is guaranteed to store a valid UTF-8 string
        unsafe { String::from_utf8_unchecked(self.0.into()) }
    }
}

impl Default for Chars {
    fn default() -> Self {
        Chars::new()
    }
}

impl Deref for Chars {
    type Target = str;

    fn deref(&self) -> &str {
        // This is safe because `Chars` is guaranteed to store a valid UTF-8 string
        unsafe { str::from_utf8_unchecked(&self.0) }
    }
}

impl Clear for Chars {
    fn clear(&mut self) {
        self.0.clear();
    }
}

impl fmt::Display for Chars {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&**self, f)
    }
}

impl fmt::Debug for Chars {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&**self, f)
    }
}

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

    #[test]
    fn test_display_and_debug() {
        let s = "test";
        let string: String = s.into();
        let chars: Chars = s.into();

        assert_eq!(format!("{}", string), format!("{}", chars));
        assert_eq!(format!("{:?}", string), format!("{:?}", chars));
    }
}
<|endoftext|>


<commit_before>#![crate_name = "jit_macros"]
#![comment = "Macros for LibJIT Bindings"]
#![crate_type = "dylib"]
#![allow(raw_pointer_deriving, dead_code, non_camel_case_types)]
#![deny(unnecessary_parens, unrecognized_lint, unreachable_code, unnecessary_allocation, unnecessary_typecast, unnecessary_allocation, uppercase_variables, unused_must_use)]
#![feature(globs, plugin_registrar, quote)]
#![experimental]
//! This crate provides some macros for better LibJIT interop
//! For example, here's a quick example of automatic struct compilation to a LibJIT value:
//!
//! ```rust
//! extern crate jit;
//! #[phase(syntax)]
//! extern crate jit_macros;
//! use jit::{C_DECL, Context, Function, Type, Types, get_type};
//!
//! #[jit_compile]
//! struct Pos {
//!     x: f64,
//!     y: f64,
//!     z: f64
//! }
//! fn main() {
//!     let cx = Context::new();
//!     cx.build(|| {
//!         // build the IR
//!         let sig = get_type(fn() -> Pos);
//!         let func = Function::new(cx, sig);
//!         let result = Pos {
//!             x: -10,
//!             y: 0,
//!             z: 10
//!         }.compile();
//!         func.insn_return(&result);
//!         /// run the IR
//!         func.compile();
//!         let rfunc:fn() -> Pos = func.closure0();
//!         assert_eq(rfunc().x, -10)
//!     });
//! }
//! ```
extern crate rustc;
extern crate syntax;

use rustc::plugin::Registry;
use std::gc::{Gc, GC};
use syntax::ast::*;
use syntax::codemap::*;
use syntax::ext::base::*;
use syntax::ext::build::*;
use syntax::ext::quote::rt::*;
use syntax::parse::token::*;
use syntax::owned_slice::OwnedSlice;

#[deriving(Copy)]
struct MacroContext<'a, 'b> {
    pub cx: &'a ExtCtxt<'b>,
    pub pos: Span,
    pub item: Gc<Item>
}
impl<'a, 'b> MacroContext<'a, 'b> {
    pub fn new(cx:&'a ExtCtxt<'b>, pos:Span, item:Gc<Item>) -> MacroContext<'a, 'b> {
        MacroContext {
            cx: cx,
            pos: pos,
            item: item
        }
    }
    #[inline(always)]
    pub fn get_curr(&self) -> P<Ty> {
        self.cx.ty_ident(self.pos, self.item.ident)
    }
}
fn gen_compile(cx:&mut ExtCtxt, pos:Span, _:Gc<MetaItem>, item:Gc<Item>, cb:|Gc<Item>|) {
    let context = MacroContext::new(cx, pos, item);
    let ref cx = context.cx;
    let methods = vec!(
        box(GC) gen_type_meth(context),
        box(GC) gen_compile_meth(context)
    );
    let node = ItemImpl(
        Generics {
            lifetimes: vec!(),
            ty_params: OwnedSlice::empty()
        },
        Some(cx.trait_ref(cx.path_global(pos, vec!(cx.ident_of("jit"), cx.ident_of("Compile"))))),
        cx.ty_path(cx.path_ident(pos, item.ident), None),
        methods
    );
    cb(cx.item(pos, cx.ident_of("Compile"), vec!(), node));
}
fn gen_type_meth(context: MacroContext) -> Method {
    let MacroContext {cx: ref cx, pos: pos, item: item} = context;
    let jit_type_t = cx.ty_path(cx.path_global(pos, vec!(cx.ident_of("jit"), cx.ident_of("Type"))), None);
    let create_struct = cx.expr_path(cx.path_global(pos, vec!(cx.ident_of("jit"), cx.ident_of("Type"), cx.ident_of("create_struct"))));
    let fields:Vec<(Option<String>, P<Expr>)> = match item.node {
        ItemStruct(def, _) if def.is_virtual => {
            cx.span_err(pos, "Virtual structs cannot be JIT compiled");
            fail!("...")
        },
        ItemStruct(def, _) => {
            def.fields.iter().map(|field| {
                let name:Option<String> = match field.node.kind {
                    NamedField(id, _) => Some(id.to_source()),
                    UnnamedField(_) => None
                };
                let ty = field.node.ty;
                let ty_expr = quote_expr!(&**cx, &::jit::get_type::<$ty>());
                (name, ty_expr)
            }).collect()
        },
        _ => {
            cx.span_err(pos, "Compile can only be automatically implemented for structs");
            fail!("...")
        }
    };
    let jit_type_body = cx.block(pos, vec!(
        cx.stmt_let(pos, false, cx.ident_of("ty"), {
            let mut fields = cx.expr_vec(pos, fields.iter().map(|&(_, ex)| ex).collect());
            fields = cx.expr_method_call(pos, fields, cx.ident_of("as_mut_slice"), vec!());
            cx.expr_call(pos, create_struct, vec!(fields))
        }),
    ), Some(cx.expr_ident(pos, cx.ident_of("ty"))));
    Method {
        ident: cx.ident_of("jit_type"),
        attrs: vec!(
            cx.attribute(pos, cx.meta_word(pos, InternedString::new("inline")))
        ),
        generics: Generics {
            lifetimes: vec!(),
            ty_params: OwnedSlice::empty()
        },
        explicit_self: Spanned {
            node: SelfStatic,
            span: pos
        },
        fn_style: NormalFn,
        decl: cx.fn_decl(
            vec!(
                cx.arg(pos, cx.ident_of("_"), cx.ty_option(context.get_curr()))
            ),
            jit_type_t
        ),
        body: jit_type_body,
        span: pos,
        id: item.id,
        vis: Inherited
    }
}
fn gen_compile_meth(context: MacroContext) -> Method {
    let MacroContext {cx: ref cx, pos: pos, item: item} = context;
    let lifetime = cx.lifetime(pos, cx.ident_of("'a").name);
    let jit_func_t = cx.ty_path(cx.path_all(pos, true, vec!(cx.ident_of("jit"), cx.ident_of("Function")), vec!(lifetime.clone()), vec!()), None);
    let jit_val_t = cx.ty_path(cx.path_all(pos, true, vec!(cx.ident_of("jit"), cx.ident_of("Value")), vec!(lifetime.clone()), vec!()), None);
    let curr_item = context.get_curr();
    let compile_body = cx.block(pos, vec!(
        cx.stmt_let(pos, false, cx.ident_of("ty"), cx.expr_call(pos, quote_expr!(&**cx, ::jit::get_type::<$curr_item>), vec!())),
        cx.stmt_let(pos, false, cx.ident_of("val"), cx.expr_call(pos, quote_expr!(&**cx, ::jit::Value::new), vec!(
            cx.expr_ident(pos, cx.ident_of("func")),
            cx.expr_addr_of(pos, cx.expr_ident(pos, cx.ident_of("ty")))
        )))
    ), Some(cx.expr_ident(pos, cx.ident_of("val"))));
    Method {
        ident: cx.ident_of("compile"),
        attrs: vec!(
            cx.attribute(pos, cx.meta_word(pos, InternedString::new("inline")))
        ),
        generics: Generics {
            lifetimes: vec!(
                lifetime.clone()
            ),
            ty_params: OwnedSlice::empty()
        },
        explicit_self: Spanned {
            node: SelfRegion(None, MutImmutable, cx.ident_of("self")),
            span: pos
        },
        fn_style: NormalFn,
        decl: cx.fn_decl(
            vec!(
                Arg::new_self(pos, MutImmutable, cx.ident_of("func")),
                cx.arg(pos, cx.ident_of("func"), cx.ty_rptr(pos, jit_func_t, None, MutImmutable))
            ),
            jit_val_t
        ),
        body: compile_body,
        span: pos,
        id: item.id,
        vis: Inherited
    }
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(intern("jit_compile"), ItemDecorator(gen_compile));
}<commit_msg>Remove all uses of `Gc` in favour of `P` in case the backend changes<commit_after>#![crate_name = "jit_macros"]
#![comment = "Macros for LibJIT Bindings"]
#![crate_type = "dylib"]
#![allow(raw_pointer_deriving, dead_code, non_camel_case_types)]
#![deny(unnecessary_parens, unrecognized_lint, unreachable_code, unnecessary_allocation, unnecessary_typecast, unnecessary_allocation, uppercase_variables, unused_must_use)]
#![feature(globs, plugin_registrar, quote)]
#![experimental]
//! This crate provides some macros for better LibJIT interop
//! For example, here's a quick example of automatic struct compilation to a LibJIT value:
//!
//! ```rust
//! extern crate jit;
//! #[phase(syntax)]
//! extern crate jit_macros;
//! use jit::{C_DECL, Context, Function, Type, Types, get_type};
//!
//! #[jit_compile]
//! struct Pos {
//!     x: f64,
//!     y: f64,
//!     z: f64
//! }
//! fn main() {
//!     let cx = Context::new();
//!     cx.build(|| {
//!         // build the IR
//!         let sig = get_type(fn() -> Pos);
//!         let func = Function::new(cx, sig);
//!         let result = Pos {
//!             x: -10,
//!             y: 0,
//!             z: 10
//!         }.compile();
//!         func.insn_return(&result);
//!         /// run the IR
//!         func.compile();
//!         let rfunc:fn() -> Pos = func.closure0();
//!         assert_eq(rfunc().x, -10)
//!     });
//! }
//! ```
extern crate rustc;
extern crate syntax;

use rustc::plugin::Registry;
use std::gc::GC;
use syntax::ast::*;
use syntax::codemap::*;
use syntax::ext::base::*;
use syntax::ext::build::*;
use syntax::ext::quote::rt::*;
use syntax::parse::token::*;
use syntax::owned_slice::OwnedSlice;

#[deriving(Copy)]
struct MacroContext<'a, 'b> {
    pub cx: &'a ExtCtxt<'b>,
    pub pos: Span,
    pub item: P<Item>
}
impl<'a, 'b> MacroContext<'a, 'b> {
    pub fn new(cx:&'a ExtCtxt<'b>, pos:Span, item:P<Item>) -> MacroContext<'a, 'b> {
        MacroContext {
            cx: cx,
            pos: pos,
            item: item
        }
    }
    #[inline(always)]
    pub fn get_curr(&self) -> P<Ty> {
        self.cx.ty_ident(self.pos, self.item.ident)
    }
}
fn gen_compile(cx:&mut ExtCtxt, pos:Span, _:P<MetaItem>, item:P<Item>, cb:|P<Item>|) {
    let context = MacroContext::new(cx, pos, item);
    let ref cx = context.cx;
    let methods = vec!(
        box(GC) gen_type_meth(context),
        box(GC) gen_compile_meth(context)
    );
    let node = ItemImpl(
        Generics {
            lifetimes: vec!(),
            ty_params: OwnedSlice::empty()
        },
        Some(cx.trait_ref(cx.path_global(pos, vec!(cx.ident_of("jit"), cx.ident_of("Compile"))))),
        cx.ty_path(cx.path_ident(pos, item.ident), None),
        methods
    );
    cb(cx.item(pos, cx.ident_of("Compile"), vec!(), node));
}
fn gen_type_meth(context: MacroContext) -> Method {
    let MacroContext {cx: ref cx, pos: pos, item: item} = context;
    let jit_type_t = cx.ty_path(cx.path_global(pos, vec!(cx.ident_of("jit"), cx.ident_of("Type"))), None);
    let create_struct = cx.expr_path(cx.path_global(pos, vec!(cx.ident_of("jit"), cx.ident_of("Type"), cx.ident_of("create_struct"))));
    let fields:Vec<(Option<String>, P<Expr>)> = match item.node {
        ItemStruct(def, _) if def.is_virtual => {
            cx.span_err(pos, "Virtual structs cannot be JIT compiled");
            fail!("...")
        },
        ItemStruct(def, _) => {
            def.fields.iter().map(|field| {
                let name:Option<String> = match field.node.kind {
                    NamedField(id, _) => Some(id.to_source()),
                    UnnamedField(_) => None
                };
                let ty = field.node.ty;
                let ty_expr = quote_expr!(&**cx, &::jit::get_type::<$ty>());
                (name, ty_expr)
            }).collect()
        },
        _ => {
            cx.span_err(pos, "Compile can only be automatically implemented for structs");
            fail!("...")
        }
    };
    let jit_type_body = cx.block(pos, vec!(
        cx.stmt_let(pos, false, cx.ident_of("ty"), {
            let mut fields = cx.expr_vec(pos, fields.iter().map(|&(_, ex)| ex).collect());
            fields = cx.expr_method_call(pos, fields, cx.ident_of("as_mut_slice"), vec!());
            cx.expr_call(pos, create_struct, vec!(fields))
        }),
    ), Some(cx.expr_ident(pos, cx.ident_of("ty"))));
    Method {
        ident: cx.ident_of("jit_type"),
        attrs: vec!(
            cx.attribute(pos, cx.meta_word(pos, InternedString::new("inline")))
        ),
        generics: Generics {
            lifetimes: vec!(),
            ty_params: OwnedSlice::empty()
        },
        explicit_self: Spanned {
            node: SelfStatic,
            span: pos
        },
        fn_style: NormalFn,
        decl: cx.fn_decl(
            vec!(
                cx.arg(pos, cx.ident_of("_"), cx.ty_option(context.get_curr()))
            ),
            jit_type_t
        ),
        body: jit_type_body,
        span: pos,
        id: item.id,
        vis: Inherited
    }
}
fn gen_compile_meth(context: MacroContext) -> Method {
    let MacroContext {cx: ref cx, pos: pos, item: item} = context;
    let lifetime = cx.lifetime(pos, cx.ident_of("'a").name);
    let jit_func_t = cx.ty_path(cx.path_all(pos, true, vec!(cx.ident_of("jit"), cx.ident_of("Function")), vec!(lifetime.clone()), vec!()), None);
    let jit_val_t = cx.ty_path(cx.path_all(pos, true, vec!(cx.ident_of("jit"), cx.ident_of("Value")), vec!(lifetime.clone()), vec!()), None);
    let curr_item = context.get_curr();
    let compile_body = cx.block(pos, vec!(
        cx.stmt_let(pos, false, cx.ident_of("ty"), cx.expr_call(pos, quote_expr!(&**cx, ::jit::get_type::<$curr_item>), vec!())),
        cx.stmt_let(pos, false, cx.ident_of("val"), cx.expr_call(pos, quote_expr!(&**cx, ::jit::Value::new), vec!(
            cx.expr_ident(pos, cx.ident_of("func")),
            cx.expr_addr_of(pos, cx.expr_ident(pos, cx.ident_of("ty")))
        )))
    ), Some(cx.expr_ident(pos, cx.ident_of("val"))));
    Method {
        ident: cx.ident_of("compile"),
        attrs: vec!(
            cx.attribute(pos, cx.meta_word(pos, InternedString::new("inline")))
        ),
        generics: Generics {
            lifetimes: vec!(
                lifetime.clone()
            ),
            ty_params: OwnedSlice::empty()
        },
        explicit_self: Spanned {
            node: SelfRegion(None, MutImmutable, cx.ident_of("self")),
            span: pos
        },
        fn_style: NormalFn,
        decl: cx.fn_decl(
            vec!(
                Arg::new_self(pos, MutImmutable, cx.ident_of("func")),
                cx.arg(pos, cx.ident_of("func"), cx.ty_rptr(pos, jit_func_t, None, MutImmutable))
            ),
            jit_val_t
        ),
        body: compile_body,
        span: pos,
        id: item.id,
        vis: Inherited
    }
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(intern("jit_compile"), ItemDecorator(gen_compile));
}<|endoftext|>