<commit_before>use ffmpeg::format;
use gl;
use gl::types::*;
use ocl::{self, OclPrm};

use super::*;
use capture;
use hooks::hw::FrameCapture;
use manual_free::ManualFree;

pub struct SamplingConverter {
    /// Difference, in video frames, between how much time passed in-game and how much video we
    /// output.
    remainder: f64,

    /// The target time_base.
    time_base: f64,

    /// Data with a destructor.
    private: ManualFree<SamplingConverterPrivate>,
}

struct SamplingConverterPrivate {
    /// Data used for OpenCL operations.
    ///
    /// This is Some(None) if OpenCL is unavailable and None during an engine restart.
    ocl_runtime_data: Option<Option<OclRuntimeData>>,

    /// Pixels from the buffer are stored here when the engine restarts.
    ocl_backup_buffer: Option<Vec<ocl::prm::Float>>,

    /// The video resolution.
    video_resolution: (u32, u32),

    /// The OpenGL sampling buffer.
    gl_sampling_buffer: Vec<f32>,

    /// The OpenGL read buffer.
    gl_read_buffer: Vec<u8>,
}

struct OclRuntimeData {
    /// Buffer images.
    ocl_buffers: [ocl::Image<ocl::prm::Float>; 2],

    /// Output image.
    ocl_output_image: ocl::Image<ocl::prm::Float>,

    /// Index of the last written to OpenCL buffer.
    ocl_current_buffer_index: usize,
}

impl SamplingConverter {
    #[inline]
    pub fn new(engine: &Engine, time_base: f64, video_resolution: (u32, u32)) -> Self {
        assert!(time_base > 0f64);

        Self {
            remainder: 0f64,
            time_base,
            private: ManualFree::new(SamplingConverterPrivate::new(engine, video_resolution)),
        }
    }

    /// This should be called before an engine restart.
    #[inline]
    pub fn backup_and_free_ocl_data(&mut self, engine: &Engine) {
        self.private.backup_and_free_ocl_data(engine);
    }

    #[inline]
    pub fn free(&mut self) {
        self.private.free();
    }
}

impl FPSConverter for SamplingConverter {
    fn time_passed<F>(&mut self, engine: &Engine, frametime: f64, capture: F)
    where
        F: FnOnce(&Engine) -> FrameCapture,
    {
        assert!(frametime >= 0.0f64);

        let frame_capture = capture(engine);

        let old_remainder = self.remainder;
        self.remainder += frametime / self.time_base;

        let exposure = capture::get_capture_parameters(engine).sampling_exposure;

        if self.remainder <= (1f64 - exposure) {
            // Do nothing.
        } else if self.remainder < 1f64 {
            let weight = (self.remainder - old_remainder.max(1f64 - exposure)) * (1f64 / exposure);

            match frame_capture {
                FrameCapture::OpenGL => {
                    let (w, h) = self.private.video_resolution;
                    self.private.gl_read_buffer.resize((w * h * 3) as usize, 0);
                    self.private
                        .gl_sampling_buffer
                        .resize((w * h * 3) as usize, 0f32);

                    unsafe {
                        // Our buffer expects 1-byte alignment.
                        gl::PixelStorei(gl::PACK_ALIGNMENT, 1);

                        // Get the pixels!
                        gl::ReadPixels(0,
                                       0,
                                       w as GLsizei,
                                       h as GLsizei,
                                       gl::RGB,
                                       gl::UNSIGNED_BYTE,
                                       self.private.gl_read_buffer.as_mut_slice().as_mut_ptr() as
                                           _);
                    }

                    let private: &mut SamplingConverterPrivate = &mut self.private;
                    weighted_image_add(&mut private.gl_sampling_buffer,
                                       &private.gl_read_buffer,
                                       weight as f32);
                }

                FrameCapture::OpenCL(ocl_gl_texture) => {
                    let ocl_data = self.private.get_ocl_data(engine).unwrap();

                    ocl_weighted_image_add(engine,
                                           ocl_gl_texture.as_ref(),
                                           ocl_data.src_buffer(),
                                           ocl_data.dst_buffer(),
                                           weight as f32);

                    ocl_data.switch_buffer_index();
                }
            }
        } else {
            let weight = (1f64 - old_remainder.max(1f64 - exposure)) * (1f64 / exposure);

            match frame_capture {
                FrameCapture::OpenGL => {
                    let (w, h) = self.private.video_resolution;
                    self.private.gl_read_buffer.resize((w * h * 3) as usize, 0);
                    self.private
                        .gl_sampling_buffer
                        .resize((w * h * 3) as usize, 0f32);

                    unsafe {
                        // Our buffer expects 1-byte alignment.
                        gl::PixelStorei(gl::PACK_ALIGNMENT, 1);

                        // Get the pixels!
                        gl::ReadPixels(0,
                                       0,
                                       w as GLsizei,
                                       h as GLsizei,
                                       gl::RGB,
                                       gl::UNSIGNED_BYTE,
                                       self.private.gl_read_buffer.as_mut_slice().as_mut_ptr() as
                                           _);
                    }

                    let mut buf = capture::get_buffer(engine, (w, h));
                    buf.set_format(format::Pixel::RGB24);
                    weighted_image_add_to(&self.private.gl_sampling_buffer,
                                          &self.private.gl_read_buffer,
                                          buf.as_mut_slice(),
                                          weight as f32);
                    capture::capture(engine, buf, 1);

                    fill_with_black(&mut self.private.gl_sampling_buffer);

                    self.remainder -= 1f64;

                    // Output it more times if needed.
                    let additional_frames = self.remainder as usize;
                    if additional_frames > 0 {
                        let mut buf = capture::get_buffer(engine, (w, h));
                        buf.set_format(format::Pixel::RGB24);
                        buf.as_mut_slice()
                           .copy_from_slice(&self.private.gl_read_buffer);
                        capture::capture(engine, buf, additional_frames);

                        self.remainder -= additional_frames as f64;
                    }

                    // Add the remaining image into the buffer.
                    if self.remainder > (1f64 - exposure) {
                        let private: &mut SamplingConverterPrivate = &mut self.private;
                        weighted_image_add(&mut private.gl_sampling_buffer,
                                           &private.gl_read_buffer,
                                           (((1f64 - exposure) - self.remainder) *
                                                (1f64 / exposure)) as
                                               f32);
                    }
                }

                FrameCapture::OpenCL(ocl_gl_texture) => {
                    let ocl_data = self.private.get_ocl_data(engine).unwrap();

                    ocl_weighted_image_add(engine,
                                           ocl_gl_texture.as_ref(),
                                           ocl_data.src_buffer(),
                                           ocl_data.output_image(),
                                           weight as f32);

                    ocl_fill_with_black(engine, ocl_data.dst_buffer());

                    ocl_data.switch_buffer_index();

                    // Output the frame.
                    let (w, h) = hw::get_resolution(engine);
                    let mut buf = capture::get_buffer(engine, (w, h));
                    hw::read_ocl_image_into_buf(engine, ocl_data.output_image(), &mut buf);
                    capture::capture(engine, buf, 1);

                    self.remainder -= 1f64;

                    // Output it more times if needed.
                    let additional_frames = self.remainder as usize;
                    if additional_frames > 0 {
                        let mut buf = capture::get_buffer(engine, (w, h));
                        hw::read_ocl_image_into_buf(engine, ocl_gl_texture.as_ref(), &mut buf);
                        capture::capture(engine, buf, additional_frames);

                        self.remainder -= additional_frames as f64;
                    }

                    // Add the remaining image into the buffer.
                    if self.remainder > (1f64 - exposure) {
                        ocl_weighted_image_add(engine,
                                               ocl_gl_texture.as_ref(),
                                               ocl_data.src_buffer(),
                                               ocl_data.dst_buffer(),
                                               (((1f64 - exposure) - self.remainder) *
                                                    (1f64 / exposure)) as
                                                   f32);
                        ocl_data.switch_buffer_index();
                    }
                }
            }
        }
    }
}

impl SamplingConverterPrivate {
    #[inline]
    fn new(engine: &Engine, video_resolution: (u32, u32)) -> Self {
        Self {
            ocl_runtime_data: Some(OclRuntimeData::new(engine, video_resolution)),
            ocl_backup_buffer: None,
            video_resolution,
            gl_sampling_buffer: Vec::new(),
            gl_read_buffer: Vec::new(),
        }
    }

    #[inline]
    fn get_ocl_data(&mut self, engine: &Engine) -> Option<&mut OclRuntimeData> {
        if self.ocl_runtime_data.is_none() {
            self.restore_ocl_data(engine);
        }

        self.ocl_runtime_data.as_mut().unwrap().as_mut()
    }

    /// This should be called before an engine restart.
    fn backup_and_free_ocl_data(&mut self, engine: &Engine) {
        let set_to_none = if let Some(Some(ref ocl_data)) = self.ocl_runtime_data {
            // Copy the src buffer into the output image.
            ocl_weighted_image_add(engine,
                                   ocl_data.dst_buffer(),
                                   ocl_data.src_buffer(),
                                   ocl_data.output_image(),
                                   0f32);

            let image = ocl_data.output_image();

            let mut backup_buffer = Vec::with_capacity(image.element_count());
            backup_buffer.resize(image.element_count(), 0f32.into());

            image.read(&mut backup_buffer).enq().expect("image.read()");

            self.ocl_backup_buffer = Some(backup_buffer);

            true
        } else {
            false
        };

        if set_to_none {
            self.ocl_runtime_data = None;
        }
    }

    /// This should be called after an engine restart.
    fn restore_ocl_data(&mut self, engine: &Engine) {
        if self.ocl_runtime_data.is_some() {
            panic!("tried to restore already existing OpenCL data");
        }

        let ocl_data = OclRuntimeData::new(engine, self.video_resolution)
            .expect("changing from fullscreen to windowed is not supported");

        let pro_que = hw::get_pro_que(engine).unwrap();
        let temp_image = hw::build_ocl_image(engine,
                                             &pro_que,
                                             ocl::MemFlags::new().read_only().host_write_only(),
                                             ocl::enums::ImageChannelDataType::Float,
                                             self.video_resolution.into())
                         .expect("building an OpenCL image");

        let backup_buffer = self.ocl_backup_buffer.take().unwrap();
        temp_image.write(&backup_buffer)
                  .enq()
                  .expect("image.write()");

        // Copy the backup buffer into the src buffer.
        ocl_weighted_image_add(engine,
                               ocl_data.dst_buffer(),
                               &temp_image,
                               ocl_data.src_buffer(),
                               0f32);

        self.ocl_runtime_data = Some(Some(ocl_data));
    }
}

impl OclRuntimeData {
    fn new(engine: &Engine, (w, h): (u32, u32)) -> Option<Self> {
        hw::get_pro_que(engine).map(|pro_que| {
            let rv = Self {
                ocl_buffers: [
                    hw::build_ocl_image(engine,
                                        &pro_que,
                                        ocl::MemFlags::new()
                                            .read_write()
                                            .host_no_access(),
                                        ocl::enums::ImageChannelDataType::Float,
                                        (w, h).into())
                    .expect("building an OpenCL image"),
                    hw::build_ocl_image(engine,
                                        &pro_que,
                                        ocl::MemFlags::new()
                                            .read_write()
                                            .host_no_access(),
                                        ocl::enums::ImageChannelDataType::Float,
                                        (w, h).into())
                    .expect("building an OpenCL image"),
                ],
                ocl_output_image: hw::build_ocl_image(engine,
                                                      &pro_que,
                                                      ocl::MemFlags::new()
                                                          .read_write()
                                                          .host_read_only(),
                                                      ocl::enums::ImageChannelDataType::Float,
                                                      (w, h).into())
                                  .expect("building an OpenCL image"),
                ocl_current_buffer_index: 0,
            };

            ocl_fill_with_black(engine, rv.src_buffer());

            rv
        })
    }

    #[inline]
    fn src_buffer(&self) -> &ocl::Image<ocl::prm::Float> {
        &self.ocl_buffers[self.ocl_current_buffer_index]
    }

    #[inline]
    fn dst_buffer(&self) -> &ocl::Image<ocl::prm::Float> {
        &self.ocl_buffers[self.ocl_current_buffer_index ^ 1]
    }

    #[inline]
    fn output_image(&self) -> &ocl::Image<ocl::prm::Float> {
        &self.ocl_output_image
    }

    #[inline]
    fn switch_buffer_index(&mut self) {
        self.ocl_current_buffer_index ^= 1;
    }
}

#[inline]
fn ocl_weighted_image_add<T: OclPrm, U: OclPrm, V: OclPrm>(engine: &Engine,
                                                           src: &ocl::Image<T>,
                                                           buf: &ocl::Image<U>,
                                                           dst: &ocl::Image<V>,
                                                           weight: f32) {
    let pro_que = hw::get_pro_que(engine).unwrap();

    let kernel = pro_que.create_kernel("weighted_image_add")
                        .unwrap()
                        .gws(src.dims())
                        .arg_img(src)
                        .arg_img(buf)
                        .arg_img(dst)
                        .arg_scl(weight);

    kernel.enq().expect("sampling kernel enq()");
}

#[inline]
fn ocl_fill_with_black<T: OclPrm>(engine: &Engine, image: &ocl::Image<T>) {
    let pro_que = hw::get_pro_que(engine).unwrap();

    let kernel = pro_que.create_kernel("fill_with_black")
                        .unwrap()
                        .gws(image.dims())
                        .arg_img(image);

    kernel.enq().expect("sampling kernel enq()");
}

#[inline]
fn weighted_image_add(buf: &mut [f32], image: &[u8], weight: f32) {
    assert!(buf.len() == image.len());

    for i in 0..buf.len() {
        buf[i] += image[i] as f32 * weight;
    }
}

#[inline]
fn weighted_image_add_to(buf: &[f32], image: &[u8], dst: &mut [u8], weight: f32) {
    assert!(buf.len() == image.len());
    assert!(buf.len() == dst.len());

    for i in 0..buf.len() {
        dst[i] = (buf[i] + image[i] as f32 * weight).round() as u8;
    }
}

#[inline]
fn fill_with_black(buf: &mut [f32]) {
    for i in 0..buf.len() {
        buf[i] = 0f32;
    }
}
<commit_msg>Fix reversed subtraction in sampling<commit_after>use ffmpeg::format;
use gl;
use gl::types::*;
use ocl::{self, OclPrm};

use super::*;
use capture;
use hooks::hw::FrameCapture;
use manual_free::ManualFree;

pub struct SamplingConverter {
    /// Difference, in video frames, between how much time passed in-game and how much video we
    /// output.
    remainder: f64,

    /// The target time_base.
    time_base: f64,

    /// Data with a destructor.
    private: ManualFree<SamplingConverterPrivate>,
}

struct SamplingConverterPrivate {
    /// Data used for OpenCL operations.
    ///
    /// This is Some(None) if OpenCL is unavailable and None during an engine restart.
    ocl_runtime_data: Option<Option<OclRuntimeData>>,

    /// Pixels from the buffer are stored here when the engine restarts.
    ocl_backup_buffer: Option<Vec<ocl::prm::Float>>,

    /// The video resolution.
    video_resolution: (u32, u32),

    /// The OpenGL sampling buffer.
    gl_sampling_buffer: Vec<f32>,

    /// The OpenGL read buffer.
    gl_read_buffer: Vec<u8>,
}

struct OclRuntimeData {
    /// Buffer images.
    ocl_buffers: [ocl::Image<ocl::prm::Float>; 2],

    /// Output image.
    ocl_output_image: ocl::Image<ocl::prm::Float>,

    /// Index of the last written to OpenCL buffer.
    ocl_current_buffer_index: usize,
}

impl SamplingConverter {
    #[inline]
    pub fn new(engine: &Engine, time_base: f64, video_resolution: (u32, u32)) -> Self {
        assert!(time_base > 0f64);

        Self {
            remainder: 0f64,
            time_base,
            private: ManualFree::new(SamplingConverterPrivate::new(engine, video_resolution)),
        }
    }

    /// This should be called before an engine restart.
    #[inline]
    pub fn backup_and_free_ocl_data(&mut self, engine: &Engine) {
        self.private.backup_and_free_ocl_data(engine);
    }

    #[inline]
    pub fn free(&mut self) {
        self.private.free();
    }
}

impl FPSConverter for SamplingConverter {
    fn time_passed<F>(&mut self, engine: &Engine, frametime: f64, capture: F)
    where
        F: FnOnce(&Engine) -> FrameCapture,
    {
        assert!(frametime >= 0.0f64);

        let frame_capture = capture(engine);

        let old_remainder = self.remainder;
        self.remainder += frametime / self.time_base;

        let exposure = capture::get_capture_parameters(engine).sampling_exposure;

        if self.remainder <= (1f64 - exposure) {
            // Do nothing.
        } else if self.remainder < 1f64 {
            let weight = (self.remainder - old_remainder.max(1f64 - exposure)) * (1f64 / exposure);

            match frame_capture {
                FrameCapture::OpenGL => {
                    let (w, h) = self.private.video_resolution;
                    self.private.gl_read_buffer.resize((w * h * 3) as usize, 0);
                    self.private
                        .gl_sampling_buffer
                        .resize((w * h * 3) as usize, 0f32);

                    unsafe {
                        // Our buffer expects 1-byte alignment.
                        gl::PixelStorei(gl::PACK_ALIGNMENT, 1);

                        // Get the pixels!
                        gl::ReadPixels(0,
                                       0,
                                       w as GLsizei,
                                       h as GLsizei,
                                       gl::RGB,
                                       gl::UNSIGNED_BYTE,
                                       self.private.gl_read_buffer.as_mut_slice().as_mut_ptr() as
                                           _);
                    }

                    let private: &mut SamplingConverterPrivate = &mut self.private;
                    weighted_image_add(&mut private.gl_sampling_buffer,
                                       &private.gl_read_buffer,
                                       weight as f32);
                }

                FrameCapture::OpenCL(ocl_gl_texture) => {
                    let ocl_data = self.private.get_ocl_data(engine).unwrap();

                    ocl_weighted_image_add(engine,
                                           ocl_gl_texture.as_ref(),
                                           ocl_data.src_buffer(),
                                           ocl_data.dst_buffer(),
                                           weight as f32);

                    ocl_data.switch_buffer_index();
                }
            }
        } else {
            let weight = (1f64 - old_remainder.max(1f64 - exposure)) * (1f64 / exposure);

            match frame_capture {
                FrameCapture::OpenGL => {
                    let (w, h) = self.private.video_resolution;
                    self.private.gl_read_buffer.resize((w * h * 3) as usize, 0);
                    self.private
                        .gl_sampling_buffer
                        .resize((w * h * 3) as usize, 0f32);

                    unsafe {
                        // Our buffer expects 1-byte alignment.
                        gl::PixelStorei(gl::PACK_ALIGNMENT, 1);

                        // Get the pixels!
                        gl::ReadPixels(0,
                                       0,
                                       w as GLsizei,
                                       h as GLsizei,
                                       gl::RGB,
                                       gl::UNSIGNED_BYTE,
                                       self.private.gl_read_buffer.as_mut_slice().as_mut_ptr() as
                                           _);
                    }

                    let mut buf = capture::get_buffer(engine, (w, h));
                    buf.set_format(format::Pixel::RGB24);
                    weighted_image_add_to(&self.private.gl_sampling_buffer,
                                          &self.private.gl_read_buffer,
                                          buf.as_mut_slice(),
                                          weight as f32);
                    capture::capture(engine, buf, 1);

                    fill_with_black(&mut self.private.gl_sampling_buffer);

                    self.remainder -= 1f64;

                    // Output it more times if needed.
                    let additional_frames = self.remainder as usize;
                    if additional_frames > 0 {
                        let mut buf = capture::get_buffer(engine, (w, h));
                        buf.set_format(format::Pixel::RGB24);
                        buf.as_mut_slice()
                           .copy_from_slice(&self.private.gl_read_buffer);
                        capture::capture(engine, buf, additional_frames);

                        self.remainder -= additional_frames as f64;
                    }

                    // Add the remaining image into the buffer.
                    if self.remainder > (1f64 - exposure) {
                        let private: &mut SamplingConverterPrivate = &mut self.private;
                        weighted_image_add(&mut private.gl_sampling_buffer,
                                           &private.gl_read_buffer,
                                           ((self.remainder - (1f64 - exposure)) *
                                                (1f64 / exposure)) as
                                               f32);
                    }
                }

                FrameCapture::OpenCL(ocl_gl_texture) => {
                    let ocl_data = self.private.get_ocl_data(engine).unwrap();

                    ocl_weighted_image_add(engine,
                                           ocl_gl_texture.as_ref(),
                                           ocl_data.src_buffer(),
                                           ocl_data.output_image(),
                                           weight as f32);

                    ocl_fill_with_black(engine, ocl_data.dst_buffer());

                    ocl_data.switch_buffer_index();

                    // Output the frame.
                    let (w, h) = hw::get_resolution(engine);
                    let mut buf = capture::get_buffer(engine, (w, h));
                    hw::read_ocl_image_into_buf(engine, ocl_data.output_image(), &mut buf);
                    capture::capture(engine, buf, 1);

                    self.remainder -= 1f64;

                    // Output it more times if needed.
                    let additional_frames = self.remainder as usize;
                    if additional_frames > 0 {
                        let mut buf = capture::get_buffer(engine, (w, h));
                        hw::read_ocl_image_into_buf(engine, ocl_gl_texture.as_ref(), &mut buf);
                        capture::capture(engine, buf, additional_frames);

                        self.remainder -= additional_frames as f64;
                    }

                    // Add the remaining image into the buffer.
                    if self.remainder > (1f64 - exposure) {
                        ocl_weighted_image_add(engine,
                                               ocl_gl_texture.as_ref(),
                                               ocl_data.src_buffer(),
                                               ocl_data.dst_buffer(),
                                               ((self.remainder - (1f64 - exposure)) *
                                                    (1f64 / exposure)) as
                                                   f32);
                        ocl_data.switch_buffer_index();
                    }
                }
            }
        }
    }
}

impl SamplingConverterPrivate {
    #[inline]
    fn new(engine: &Engine, video_resolution: (u32, u32)) -> Self {
        Self {
            ocl_runtime_data: Some(OclRuntimeData::new(engine, video_resolution)),
            ocl_backup_buffer: None,
            video_resolution,
            gl_sampling_buffer: Vec::new(),
            gl_read_buffer: Vec::new(),
        }
    }

    #[inline]
    fn get_ocl_data(&mut self, engine: &Engine) -> Option<&mut OclRuntimeData> {
        if self.ocl_runtime_data.is_none() {
            self.restore_ocl_data(engine);
        }

        self.ocl_runtime_data.as_mut().unwrap().as_mut()
    }

    /// This should be called before an engine restart.
    fn backup_and_free_ocl_data(&mut self, engine: &Engine) {
        let set_to_none = if let Some(Some(ref ocl_data)) = self.ocl_runtime_data {
            // Copy the src buffer into the output image.
            ocl_weighted_image_add(engine,
                                   ocl_data.dst_buffer(),
                                   ocl_data.src_buffer(),
                                   ocl_data.output_image(),
                                   0f32);

            let image = ocl_data.output_image();

            let mut backup_buffer = Vec::with_capacity(image.element_count());
            backup_buffer.resize(image.element_count(), 0f32.into());

            image.read(&mut backup_buffer).enq().expect("image.read()");

            self.ocl_backup_buffer = Some(backup_buffer);

            true
        } else {
            false
        };

        if set_to_none {
            self.ocl_runtime_data = None;
        }
    }

    /// This should be called after an engine restart.
    fn restore_ocl_data(&mut self, engine: &Engine) {
        if self.ocl_runtime_data.is_some() {
            panic!("tried to restore already existing OpenCL data");
        }

        let ocl_data = OclRuntimeData::new(engine, self.video_resolution)
            .expect("changing from fullscreen to windowed is not supported");

        let pro_que = hw::get_pro_que(engine).unwrap();
        let temp_image = hw::build_ocl_image(engine,
                                             &pro_que,
                                             ocl::MemFlags::new().read_only().host_write_only(),
                                             ocl::enums::ImageChannelDataType::Float,
                                             self.video_resolution.into())
                         .expect("building an OpenCL image");

        let backup_buffer = self.ocl_backup_buffer.take().unwrap();
        temp_image.write(&backup_buffer)
                  .enq()
                  .expect("image.write()");

        // Copy the backup buffer into the src buffer.
        ocl_weighted_image_add(engine,
                               ocl_data.dst_buffer(),
                               &temp_image,
                               ocl_data.src_buffer(),
                               0f32);

        self.ocl_runtime_data = Some(Some(ocl_data));
    }
}

impl OclRuntimeData {
    fn new(engine: &Engine, (w, h): (u32, u32)) -> Option<Self> {
        hw::get_pro_que(engine).map(|pro_que| {
            let rv = Self {
                ocl_buffers: [
                    hw::build_ocl_image(engine,
                                        &pro_que,
                                        ocl::MemFlags::new()
                                            .read_write()
                                            .host_no_access(),
                                        ocl::enums::ImageChannelDataType::Float,
                                        (w, h).into())
                    .expect("building an OpenCL image"),
                    hw::build_ocl_image(engine,
                                        &pro_que,
                                        ocl::MemFlags::new()
                                            .read_write()
                                            .host_no_access(),
                                        ocl::enums::ImageChannelDataType::Float,
                                        (w, h).into())
                    .expect("building an OpenCL image"),
                ],
                ocl_output_image: hw::build_ocl_image(engine,
                                                      &pro_que,
                                                      ocl::MemFlags::new()
                                                          .read_write()
                                                          .host_read_only(),
                                                      ocl::enums::ImageChannelDataType::Float,
                                                      (w, h).into())
                                  .expect("building an OpenCL image"),
                ocl_current_buffer_index: 0,
            };

            ocl_fill_with_black(engine, rv.src_buffer());

            rv
        })
    }

    #[inline]
    fn src_buffer(&self) -> &ocl::Image<ocl::prm::Float> {
        &self.ocl_buffers[self.ocl_current_buffer_index]
    }

    #[inline]
    fn dst_buffer(&self) -> &ocl::Image<ocl::prm::Float> {
        &self.ocl_buffers[self.ocl_current_buffer_index ^ 1]
    }

    #[inline]
    fn output_image(&self) -> &ocl::Image<ocl::prm::Float> {
        &self.ocl_output_image
    }

    #[inline]
    fn switch_buffer_index(&mut self) {
        self.ocl_current_buffer_index ^= 1;
    }
}

#[inline]
fn ocl_weighted_image_add<T: OclPrm, U: OclPrm, V: OclPrm>(engine: &Engine,
                                                           src: &ocl::Image<T>,
                                                           buf: &ocl::Image<U>,
                                                           dst: &ocl::Image<V>,
                                                           weight: f32) {
    let pro_que = hw::get_pro_que(engine).unwrap();

    let kernel = pro_que.create_kernel("weighted_image_add")
                        .unwrap()
                        .gws(src.dims())
                        .arg_img(src)
                        .arg_img(buf)
                        .arg_img(dst)
                        .arg_scl(weight);

    kernel.enq().expect("sampling kernel enq()");
}

#[inline]
fn ocl_fill_with_black<T: OclPrm>(engine: &Engine, image: &ocl::Image<T>) {
    let pro_que = hw::get_pro_que(engine).unwrap();

    let kernel = pro_que.create_kernel("fill_with_black")
                        .unwrap()
                        .gws(image.dims())
                        .arg_img(image);

    kernel.enq().expect("sampling kernel enq()");
}

#[inline]
fn weighted_image_add(buf: &mut [f32], image: &[u8], weight: f32) {
    assert!(buf.len() == image.len());

    for i in 0..buf.len() {
        buf[i] += image[i] as f32 * weight;
    }
}

#[inline]
fn weighted_image_add_to(buf: &[f32], image: &[u8], dst: &mut [u8], weight: f32) {
    assert!(buf.len() == image.len());
    assert!(buf.len() == dst.len());

    for i in 0..buf.len() {
        dst[i] = (buf[i] + image[i] as f32 * weight).round() as u8;
    }
}

#[inline]
fn fill_with_black(buf: &mut [f32]) {
    for i in 0..buf.len() {
        buf[i] = 0f32;
    }
}
<|endoftext|>


<commit_before>extern crate rav1e;
extern crate y4m;

use rav1e::*;

fn main() {
    let mut files = EncoderFiles::from_cli();
    let mut y4m_dec = y4m::decode(&mut files.input_file).unwrap();
    let width = y4m_dec.get_width();
    let height = y4m_dec.get_height();
    let mut y4m_enc = y4m::encode(width,height,y4m::Ratio::new(30,1)).write_header(&mut files.rec_file).unwrap();
    let fi = FrameInvariants::new(width, height);
    let sequence = Sequence::new();
    write_ivf_header(&mut files.output_file, fi.sb_width*64, fi.sb_height*64);

    let mut frame_number = 0;
    loop {
        process_frame(frame_number, &sequence, &fi,
                      &mut files.output_file, &mut y4m_dec, &mut y4m_enc);
        frame_number += 1;
    }
}
<commit_msg>Make sure rav1e binary terminates.<commit_after>extern crate rav1e;
extern crate y4m;

use rav1e::*;

fn main() {
    let mut files = EncoderFiles::from_cli();
    let mut y4m_dec = y4m::decode(&mut files.input_file).unwrap();
    let width = y4m_dec.get_width();
    let height = y4m_dec.get_height();
    let mut y4m_enc = y4m::encode(width,height,y4m::Ratio::new(30,1)).write_header(&mut files.rec_file).unwrap();
    let fi = FrameInvariants::new(width, height);
    let sequence = Sequence::new();
    write_ivf_header(&mut files.output_file, fi.sb_width*64, fi.sb_height*64);

    let mut frame_number = 0;
    loop {
        if !process_frame(frame_number, &sequence, &fi,
                          &mut files.output_file, &mut y4m_dec, &mut y4m_enc) {
            break;
        }
        frame_number += 1;
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
use rand::Rand;

use rand::Rng;

#[inline]
fn sbx_beta(u: f32, eta: f32) -> f32 {
    debug_assert!(u >= 0.0 && u < 1.0);

    if u <= 0.5 {
        2.0 * u
    } else {
        1.0 / (2.0 * (1.0 - u))
    }
    .powf(1.0 / (eta + 1.0))
}

/// Modifies ind1 and ind2 in-place.
/// Reference: http://www.iitk.ac.in/kangal/papers/k2011017.pdf
pub fn simulated_binary_crossover<R: Rng>(rng: &mut R,
                                          ind1: &mut [f32],
                                          ind2: &mut [f32],
                                          eta: f32) {
    assert!(ind1.len() == ind2.len());

    let mut iter = ind1.iter_mut().zip(ind2.iter_mut());
    for (x1, x2) in iter {
        let (p1, p2) = (*x1, *x2);

        let u = rng.gen::<f32>();
        let beta = sbx_beta(u, eta);

        let c1 = 0.5 * (((1.0 + beta) * p1) + ((1.0 - beta) * p2));
        let c2 = 0.5 * (((1.0 - beta) * p1) + ((1.0 + beta) * p2));

        *x1 = c1;
        *x2 = c2;
    }
}

#[test]
fn test_sbx() {
    let mut rng = ::rand::isaac::Isaac64Rng::new_unseeded();

    let parent1 = vec![1.0, 2.0];
    let parent2 = vec![100.0, 1.0];

    let mut child1 = parent1.clone();
    let mut child2 = parent2.clone();

    simulated_binary_crossover(&mut rng, &mut child1[..], &mut child2[..], 2.0);

    let beta: Vec<_> = (0..2)
                           .map(|i| (child2[i] - child1[i]) / (parent2[i] - parent1[i]))
                           .collect();

    println!("({:?}, {:?}) => ({:?}, {:?})",
             parent1,
             parent2,
             child1,
             child2);
    println!("beta: {:?}", beta);
}
<commit_msg>Factor out more common code.<commit_after>#[cfg(test)]
use rand::Rand;

use rand::Rng;

#[inline]
fn sbx_beta(u: f32, eta: f32) -> f32 {
    debug_assert!(u >= 0.0 && u < 1.0);

    if u <= 0.5 {
        2.0 * u
    } else {
        1.0 / (2.0 * (1.0 - u))
    }
    .powf(1.0 / (eta + 1.0))
}

#[inline]
fn sbx_single_var<R: Rng>(rng: &mut R, p: (f32, f32), eta: f32) -> (f32, f32) {
    let u = rng.gen::<f32>();
    let beta = sbx_beta(u, eta);

    (0.5 * (((1.0 + beta) * p.0) + ((1.0 - beta) * p.1)),
     0.5 * (((1.0 - beta) * p.0) + ((1.0 + beta) * p.1)))
}

/// Modifies ind1 and ind2 in-place.
/// Reference: http://www.iitk.ac.in/kangal/papers/k2011017.pdf
pub fn simulated_binary_crossover<R: Rng>(rng: &mut R,
                                          ind1: &mut [f32],
                                          ind2: &mut [f32],
                                          eta: f32) {
    assert!(ind1.len() == ind2.len());

    let mut iter = ind1.iter_mut().zip(ind2.iter_mut());
    for (x1, x2) in iter {
        let (c1, c2) = sbx_single_var(rng, (*x1, *x2), eta);
        *x1 = c1;
        *x2 = c2;
    }
}

#[test]
fn test_sbx() {
    let mut rng = ::rand::isaac::Isaac64Rng::new_unseeded();

    let parent1 = vec![1.0, 2.0];
    let parent2 = vec![100.0, 1.0];

    let mut child1 = parent1.clone();
    let mut child2 = parent2.clone();

    simulated_binary_crossover(&mut rng, &mut child1[..], &mut child2[..], 2.0);

    let beta: Vec<_> = (0..2)
                           .map(|i| (child2[i] - child1[i]) / (parent2[i] - parent1[i]))
                           .collect();

    println!("({:?}, {:?}) => ({:?}, {:?})",
             parent1,
             parent2,
             child1,
             child2);
    println!("beta: {:?}", beta);
}
<|endoftext|>


<commit_before>use self::Msg::*;
use class::ClassId;
use ctxt::Context;
use interner::Name;
use lexer::position::Position;
use ty::BuiltinType;

#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Msg {
    Unimplemented,
    UnknownType(String),
    UnknownIdentifier(String),
    UnknownFunction(String),
    UnknownProp(String, BuiltinType),
    UnknownMethod(BuiltinType, Name, Vec<BuiltinType>),
    IdentifierExists(String),
    ShadowFunction(String),
    ShadowParam(String),
    ShadowType(String),
    ShadowProp(String),
    VarNeedsTypeInfo(String),
    ParamTypesIncompatible(String, Vec<BuiltinType>, Vec<BuiltinType>),
    WhileCondType(BuiltinType),
    IfCondType(BuiltinType),
    ReturnType(BuiltinType, BuiltinType),
    LvalueExpected,
    AssignType(String, BuiltinType, BuiltinType),
    AssignProp(Name, ClassId, BuiltinType, BuiltinType),
    UnOpType(String, BuiltinType),
    BinOpType(String, BuiltinType, BuiltinType),
    OutsideLoop,
    NoReturnValue,
    MainNotFound,
    WrongMainDefinition,
    ThisInFunction
}

impl Msg {
    pub fn message(&self, ctxt: &Context) -> String {
        match *self {
            Unimplemented => format!("feature not implemented yet."),
            UnknownType(ref name) => format!("no type with name `{}` known.", name),
            UnknownIdentifier(ref name) => format!("unknown identifier `{}`.", name),
            UnknownFunction(ref name) => format!("unknown function `{}`", name),
            UnknownMethod(cls, name, ref args) => {
                let name = ctxt.interner.str(name).to_string();
                let cls = cls.name(ctxt);
                let args = args.iter().map(|a| a.name(ctxt)).collect::<Vec<String>>().connect(", ");

                format!("no method with definition `{}({})` in class `{}`.", name, args, cls)
            }
            UnknownProp(ref prop, ref ty) =>
                format!("unknown property `{}` for type `{}`", prop, ty.name(ctxt)),
            IdentifierExists(ref name) => format!("can not redefine identifier `{}`.", name),
            ShadowFunction(ref name) => format!("can not shadow function `{}`.", name),
            ShadowParam(ref name) => format!("can not shadow param `{}`.", name),
            ShadowType(ref name) => format!("can not shadow type `{}`.", name),
            ShadowProp(ref name) => format!("property with name `{}` already exists.", name),
            VarNeedsTypeInfo(ref name) =>
                format!("variable `{}` needs either type declaration or expression.", name),
            ParamTypesIncompatible(ref name, ref def, ref expr) =>
                format!("function types incompatible"),
            WhileCondType(ref ty) =>
                format!("while expects condition of type `bool` but got `{}`.", ty.name(ctxt)),
            IfCondType(ref ty) =>
                format!("if expects condition of type `bool` but got `{}`.", ty.name(ctxt)),
            ReturnType(ref def, ref expr) =>
                format!("return expects value of type `{}` but got `{}`.",
                    def.name(ctxt), expr.name(ctxt)),
            LvalueExpected => format!("lvalue expected for assignment"),
            AssignType(ref name, ref def, ref expr) =>
                format!("cannot assign `{}` to variable `{}` of type `{}`.",
                        &expr.name(ctxt), name, &def.name(ctxt)),
            AssignProp(name, clsid, ref def, ref expr) => {
                let cls = ctxt.cls_by_id(clsid);
                let cls_name = ctxt.interner.str(cls.name).to_string();
                let prop_name = ctxt.interner.str(name).to_string();

                format!("cannot assign `{}` to property `{}`.`{}` of type `{}`.",
                        &expr.name(ctxt), cls_name, prop_name, &def.name(ctxt))
            },
            UnOpType(ref op, ref expr) =>
                format!("unary operator `{}` can not handle value of type `{} {}`.", op, op,
                    &expr.name(ctxt)),
            BinOpType(ref op, ref lhs, ref rhs) =>
                format!("binary operator `{}` can not handle expression of type `{} {} {}`",
                    op, &lhs.name(ctxt), op, &rhs.name(ctxt)),
            OutsideLoop => "statement only allowed inside loops".into(),
            NoReturnValue => "function does not return a value in all code paths".into(),
            MainNotFound => "no main function found in the program".into(),
            WrongMainDefinition => "main function has wrong definition".into(),
            ThisInFunction => "`this` can only be used in methods not functions".into(),
        }
    }
}

#[derive(Clone, Debug)]
pub struct MsgWithPos {
    pub msg: Msg,
    pub pos: Position,
}

impl MsgWithPos {
    pub fn new(pos: Position, msg: Msg) -> MsgWithPos {
        MsgWithPos {
            pos: pos,
            msg: msg
        }
    }

    pub fn message(&self, ctxt: &Context) -> String {
        format!("error at {}: {}", self.pos, self.msg.message(ctxt))
    }
}
<commit_msg>changed some error messages<commit_after>use self::Msg::*;
use class::ClassId;
use ctxt::Context;
use interner::Name;
use lexer::position::Position;
use ty::BuiltinType;

#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Msg {
    Unimplemented,
    UnknownType(String),
    UnknownIdentifier(String),
    UnknownFunction(String),
    UnknownProp(String, BuiltinType),
    UnknownMethod(BuiltinType, Name, Vec<BuiltinType>),
    IdentifierExists(String),
    ShadowFunction(String),
    ShadowParam(String),
    ShadowType(String),
    ShadowProp(String),
    VarNeedsTypeInfo(String),
    ParamTypesIncompatible(String, Vec<BuiltinType>, Vec<BuiltinType>),
    WhileCondType(BuiltinType),
    IfCondType(BuiltinType),
    ReturnType(BuiltinType, BuiltinType),
    LvalueExpected,
    AssignType(String, BuiltinType, BuiltinType),
    AssignProp(Name, ClassId, BuiltinType, BuiltinType),
    UnOpType(String, BuiltinType),
    BinOpType(String, BuiltinType, BuiltinType),
    OutsideLoop,
    NoReturnValue,
    MainNotFound,
    WrongMainDefinition,
    ThisInFunction
}

impl Msg {
    pub fn message(&self, ctxt: &Context) -> String {
        match *self {
            Unimplemented => format!("feature not implemented yet."),
            UnknownType(ref name) => format!("no type with name `{}` known.", name),
            UnknownIdentifier(ref name) => format!("unknown identifier `{}`.", name),
            UnknownFunction(ref name) => format!("unknown function `{}`", name),
            UnknownMethod(cls, name, ref args) => {
                let name = ctxt.interner.str(name).to_string();
                let cls = cls.name(ctxt);
                let args = args.iter().map(|a| a.name(ctxt)).collect::<Vec<String>>().connect(", ");

                format!("no method with definition `{}({})` in class `{}`.", name, args, cls)
            }
            UnknownProp(ref prop, ref ty) =>
                format!("unknown property `{}` for type `{}`", prop, ty.name(ctxt)),
            IdentifierExists(ref name) => format!("can not redefine identifier `{}`.", name),
            ShadowFunction(ref name) => format!("can not shadow function `{}`.", name),
            ShadowParam(ref name) => format!("can not shadow param `{}`.", name),
            ShadowType(ref name) => format!("can not shadow type `{}`.", name),
            ShadowProp(ref name) => format!("property with name `{}` already exists.", name),
            VarNeedsTypeInfo(ref name) =>
                format!("variable `{}` needs either type declaration or expression.", name),
            ParamTypesIncompatible(ref name, ref def, ref expr) =>
                format!("function types incompatible"),
            WhileCondType(ref ty) =>
                format!("`while` expects condition of type `bool` but got `{}`.", ty.name(ctxt)),
            IfCondType(ref ty) =>
                format!("`if` expects condition of type `bool` but got `{}`.", ty.name(ctxt)),
            ReturnType(ref def, ref expr) =>
                format!("`return` expects value of type `{}` but got `{}`.",
                    def.name(ctxt), expr.name(ctxt)),
            LvalueExpected => format!("lvalue expected for assignment"),
            AssignType(ref name, ref def, ref expr) =>
                format!("cannot assign `{}` to variable `{}` of type `{}`.",
                        &expr.name(ctxt), name, &def.name(ctxt)),
            AssignProp(name, clsid, ref def, ref expr) => {
                let cls = ctxt.cls_by_id(clsid);
                let cls_name = ctxt.interner.str(cls.name).to_string();
                let prop_name = ctxt.interner.str(name).to_string();

                format!("cannot assign `{}` to property `{}`.`{}` of type `{}`.",
                        &expr.name(ctxt), cls_name, prop_name, &def.name(ctxt))
            },
            UnOpType(ref op, ref expr) =>
                format!("unary operator `{}` can not handle value of type `{} {}`.", op, op,
                    &expr.name(ctxt)),
            BinOpType(ref op, ref lhs, ref rhs) =>
                format!("binary operator `{}` can not handle expression of type `{} {} {}`",
                    op, &lhs.name(ctxt), op, &rhs.name(ctxt)),
            OutsideLoop => "statement only allowed inside loops".into(),
            NoReturnValue => "function does not return a value in all code paths".into(),
            MainNotFound => "no `main` function found in the program".into(),
            WrongMainDefinition => "`main` function has wrong definition".into(),
            ThisInFunction => "`this` can only be used in methods not functions".into(),
        }
    }
}

#[derive(Clone, Debug)]
pub struct MsgWithPos {
    pub msg: Msg,
    pub pos: Position,
}

impl MsgWithPos {
    pub fn new(pos: Position, msg: Msg) -> MsgWithPos {
        MsgWithPos {
            pos: pos,
            msg: msg
        }
    }

    pub fn message(&self, ctxt: &Context) -> String {
        format!("error at {}: {}", self.pos, self.msg.message(ctxt))
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 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.

//! Unix-specific extensions to primitives in the `std::fs` module.

#![stable(feature = "rust1", since = "1.0.0")]

use fs::{self, Permissions, OpenOptions};
use io;
use libc;
use path::Path;
use sys;
use sys_common::{FromInner, AsInner, AsInnerMut};
use sys::platform::fs::MetadataExt as UnixMetadataExt;

/// Unix-specific extensions to `Permissions`
#[stable(feature = "fs_ext", since = "1.1.0")]
pub trait PermissionsExt {
    /// Returns the underlying raw `mode_t` bits that are the standard Unix
    /// permissions for this file.
    #[stable(feature = "fs_ext", since = "1.1.0")]
    fn mode(&self) -> u32;

    /// Sets the underlying raw bits for this set of permissions.
    #[stable(feature = "fs_ext", since = "1.1.0")]
    fn set_mode(&mut self, mode: u32);

    /// Creates a new instance of `Permissions` from the given set of Unix
    /// permission bits.
    #[stable(feature = "fs_ext", since = "1.1.0")]
    fn from_mode(mode: u32) -> Self;
}

#[stable(feature = "fs_ext", since = "1.1.0")]
impl PermissionsExt for Permissions {
    fn mode(&self) -> u32 {
        self.as_inner().mode()
    }

    fn set_mode(&mut self, mode: u32) {
        *self = Permissions::from_inner(FromInner::from_inner(mode));
    }

    fn from_mode(mode: u32) -> Permissions {
        Permissions::from_inner(FromInner::from_inner(mode))
    }
}

/// Unix-specific extensions to `OpenOptions`
#[stable(feature = "fs_ext", since = "1.1.0")]
pub trait OpenOptionsExt {
    /// Sets the mode bits that a new file will be created with.
    ///
    /// If a new file is created as part of a `File::open_opts` call then this
    /// specified `mode` will be used as the permission bits for the new file.
    /// If no `mode` is set, the default of `0o666` will be used.
    /// The operating system masks out bits with the systems `umask`, to produce
    /// the final permissions.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// extern crate libc;
    /// use std::fs::OpenOptions;
    /// use std::os::unix::fs::OpenOptionsExt;
    ///
    /// let mut options = OpenOptions::new();
    /// options.mode(0o644); // Give read/write for owner and read for others.
    /// let file = options.open("foo.txt");
    /// ```
    #[stable(feature = "fs_ext", since = "1.1.0")]
    fn mode(&mut self, mode: u32) -> &mut Self;

    /// Pass custom flags to the `flags` agument of `open`.
    ///
    /// The bits that define the access mode are masked out with `O_ACCMODE`, to
    /// ensure they do not interfere with the access mode set by Rusts options.
    ///
    /// Custom flags can only set flags, not remove flags set by Rusts options.
    /// This options overwrites any previously set custom flags.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// extern crate libc;
    /// use std::fs::OpenOptions;
    /// use std::os::unix::fs::OpenOptionsExt;
    ///
    /// let mut options = OpenOptions::new();
    /// options.write(true);
    /// if cfg!(unix) {
    ///     options.custom_flags(libc::O_NOFOLLOW);
    /// }
    /// let file = options.open("foo.txt");
    /// ```
    #[stable(feature = "open_options_ext", since = "1.10.0")]
    fn custom_flags(&mut self, flags: i32) -> &mut Self;
}

#[stable(feature = "fs_ext", since = "1.1.0")]
impl OpenOptionsExt for OpenOptions {
    fn mode(&mut self, mode: u32) -> &mut OpenOptions {
        self.as_inner_mut().mode(mode); self
    }

    fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
        self.as_inner_mut().custom_flags(flags); self
    }
}

// Hm, why are there casts here to the returned type, shouldn't the types always
// be the same? Right you are! Turns out, however, on android at least the types
// in the raw `stat` structure are not the same as the types being returned. Who
// knew!
//
// As a result to make sure this compiles for all platforms we do the manual
// casts and rely on manual lowering to `stat` if the raw type is desired.
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn dev(&self) -> u64;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn ino(&self) -> u64;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn mode(&self) -> u32;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn nlink(&self) -> u64;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn uid(&self) -> u32;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn gid(&self) -> u32;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn rdev(&self) -> u64;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn size(&self) -> u64;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn atime(&self) -> i64;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn atime_nsec(&self) -> i64;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn mtime(&self) -> i64;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn mtime_nsec(&self) -> i64;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn ctime(&self) -> i64;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn ctime_nsec(&self) -> i64;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn blksize(&self) -> u64;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn blocks(&self) -> u64;
}

#[stable(feature = "metadata_ext", since = "1.1.0")]
impl MetadataExt for fs::Metadata {
    fn dev(&self) -> u64 { self.st_dev() }
    fn ino(&self) -> u64 { self.st_ino() }
    fn mode(&self) -> u32 { self.st_mode() }
    fn nlink(&self) -> u64 { self.st_nlink() }
    fn uid(&self) -> u32 { self.st_uid() }
    fn gid(&self) -> u32 { self.st_gid() }
    fn rdev(&self) -> u64 { self.st_rdev() }
    fn size(&self) -> u64 { self.st_size() }
    fn atime(&self) -> i64 { self.st_atime() }
    fn atime_nsec(&self) -> i64 { self.st_atime_nsec() }
    fn mtime(&self) -> i64 { self.st_mtime() }
    fn mtime_nsec(&self) -> i64 { self.st_mtime_nsec() }
    fn ctime(&self) -> i64 { self.st_ctime() }
    fn ctime_nsec(&self) -> i64 { self.st_ctime_nsec() }
    fn blksize(&self) -> u64 { self.st_blksize() }
    fn blocks(&self) -> u64 { self.st_blocks() }
}

/// Add special unix types (block/char device, fifo and socket)
#[stable(feature = "file_type_ext", since = "1.5.0")]
pub trait FileTypeExt {
    /// Returns whether this file type is a block device.
    #[stable(feature = "file_type_ext", since = "1.5.0")]
    fn is_block_device(&self) -> bool;
    /// Returns whether this file type is a char device.
    #[stable(feature = "file_type_ext", since = "1.5.0")]
    fn is_char_device(&self) -> bool;
    /// Returns whether this file type is a fifo.
    #[stable(feature = "file_type_ext", since = "1.5.0")]
    fn is_fifo(&self) -> bool;
    /// Returns whether this file type is a socket.
    #[stable(feature = "file_type_ext", since = "1.5.0")]
    fn is_socket(&self) -> bool;
}

#[stable(feature = "file_type_ext", since = "1.5.0")]
impl FileTypeExt for fs::FileType {
    fn is_block_device(&self) -> bool { self.as_inner().is(libc::S_IFBLK) }
    fn is_char_device(&self) -> bool { self.as_inner().is(libc::S_IFCHR) }
    fn is_fifo(&self) -> bool { self.as_inner().is(libc::S_IFIFO) }
    fn is_socket(&self) -> bool { self.as_inner().is(libc::S_IFSOCK) }
}

/// Unix-specific extension methods for `fs::DirEntry`
#[stable(feature = "dir_entry_ext", since = "1.1.0")]
pub trait DirEntryExt {
    /// Returns the underlying `d_ino` field in the contained `dirent`
    /// structure.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs;
    /// use std::os::unix::fs::DirEntryExt;
    ///
    /// if let Ok(entries) = fs::read_dir(".") {
    ///     for entry in entries {
    ///         if let Ok(entry) = entry {
    ///             // Here, `entry` is a `DirEntry`.
    ///             println!("{:?}: {}", entry.file_name(), entry.ino());
    ///         }
    ///     }
    /// }
    /// ```
    #[stable(feature = "dir_entry_ext", since = "1.1.0")]
    fn ino(&self) -> u64;
}

#[stable(feature = "dir_entry_ext", since = "1.1.0")]
impl DirEntryExt for fs::DirEntry {
    fn ino(&self) -> u64 { self.as_inner().ino() }
}

/// Creates a new symbolic link on the filesystem.
///
/// The `dst` path will be a symbolic link pointing to the `src` path.
///
/// # Note
///
/// On Windows, you must specify whether a symbolic link points to a file
/// or directory.  Use `os::windows::fs::symlink_file` to create a
/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a
/// symbolic link to a directory.  Additionally, the process must have
/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a
/// symbolic link.
///
/// # Examples
///
/// ```
/// use std::os::unix::fs;
///
/// # fn foo() -> std::io::Result<()> {
/// try!(fs::symlink("a.txt", "b.txt"));
/// # Ok(())
/// # }
/// ```
#[stable(feature = "symlink", since = "1.1.0")]
pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
{
    sys::fs::symlink(src.as_ref(), dst.as_ref())
}

#[stable(feature = "dir_builder", since = "1.6.0")]
/// An extension trait for `fs::DirBuilder` for unix-specific options.
pub trait DirBuilderExt {
    /// Sets the mode to create new directories with. This option defaults to
    /// 0o777.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::fs::DirBuilder;
    /// use std::os::unix::fs::DirBuilderExt;
    ///
    /// let mut builder = DirBuilder::new();
    /// builder.mode(0o755);
    /// ```
    #[stable(feature = "dir_builder", since = "1.6.0")]
    fn mode(&mut self, mode: u32) -> &mut Self;
}

#[stable(feature = "dir_builder", since = "1.6.0")]
impl DirBuilderExt for fs::DirBuilder {
    fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder {
        self.as_inner_mut().set_mode(mode);
        self
    }
}
<commit_msg>Add OpenOptionsExt doc examples<commit_after>// Copyright 2015 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.

//! Unix-specific extensions to primitives in the `std::fs` module.

#![stable(feature = "rust1", since = "1.0.0")]

use fs::{self, Permissions, OpenOptions};
use io;
use libc;
use path::Path;
use sys;
use sys_common::{FromInner, AsInner, AsInnerMut};
use sys::platform::fs::MetadataExt as UnixMetadataExt;

/// Unix-specific extensions to `Permissions`
#[stable(feature = "fs_ext", since = "1.1.0")]
pub trait PermissionsExt {
    /// Returns the underlying raw `mode_t` bits that are the standard Unix
    /// permissions for this file.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// use std::fs::File;
    /// use std::os::unix::fs::PermissionsExt;
    ///
    /// let f = try!(File::create("foo.txt"));
    /// let metadata = try!(f.metadata());
    /// let permissions = metadata.permissions();
    ///
    /// println!("permissions: {}", permissions.mode());
    /// ```
    #[stable(feature = "fs_ext", since = "1.1.0")]
    fn mode(&self) -> u32;

    /// Sets the underlying raw bits for this set of permissions.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// use std::fs::File;
    /// use std::os::unix::fs::PermissionsExt;
    ///
    /// let f = try!(File::create("foo.txt"));
    /// let metadata = try!(f.metadata());
    /// let mut permissions = metadata.permissions();
    ///
    /// permissions.set_mode(0o644); // Read/write for owner and read for others.
    /// assert_eq!(permissions.mode(), 0o644);
    /// ```
    #[stable(feature = "fs_ext", since = "1.1.0")]
    fn set_mode(&mut self, mode: u32);

    /// Creates a new instance of `Permissions` from the given set of Unix
    /// permission bits.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// use std::fs::Permissions;
    /// use std::os::unix::fs::PermissionsExt;
    ///
    /// // Read/write for owner and read for others.
    /// let permissions = Permissions::from_mode(0o644);
    /// assert_eq!(permissions.mode(), 0o644);
    /// ```
    #[stable(feature = "fs_ext", since = "1.1.0")]
    fn from_mode(mode: u32) -> Self;
}

#[stable(feature = "fs_ext", since = "1.1.0")]
impl PermissionsExt for Permissions {
    fn mode(&self) -> u32 {
        self.as_inner().mode()
    }

    fn set_mode(&mut self, mode: u32) {
        *self = Permissions::from_inner(FromInner::from_inner(mode));
    }

    fn from_mode(mode: u32) -> Permissions {
        Permissions::from_inner(FromInner::from_inner(mode))
    }
}

/// Unix-specific extensions to `OpenOptions`
#[stable(feature = "fs_ext", since = "1.1.0")]
pub trait OpenOptionsExt {
    /// Sets the mode bits that a new file will be created with.
    ///
    /// If a new file is created as part of a `File::open_opts` call then this
    /// specified `mode` will be used as the permission bits for the new file.
    /// If no `mode` is set, the default of `0o666` will be used.
    /// The operating system masks out bits with the systems `umask`, to produce
    /// the final permissions.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// extern crate libc;
    /// use std::fs::OpenOptions;
    /// use std::os::unix::fs::OpenOptionsExt;
    ///
    /// let mut options = OpenOptions::new();
    /// options.mode(0o644); // Give read/write for owner and read for others.
    /// let file = options.open("foo.txt");
    /// ```
    #[stable(feature = "fs_ext", since = "1.1.0")]
    fn mode(&mut self, mode: u32) -> &mut Self;

    /// Pass custom flags to the `flags` agument of `open`.
    ///
    /// The bits that define the access mode are masked out with `O_ACCMODE`, to
    /// ensure they do not interfere with the access mode set by Rusts options.
    ///
    /// Custom flags can only set flags, not remove flags set by Rusts options.
    /// This options overwrites any previously set custom flags.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// extern crate libc;
    /// use std::fs::OpenOptions;
    /// use std::os::unix::fs::OpenOptionsExt;
    ///
    /// let mut options = OpenOptions::new();
    /// options.write(true);
    /// if cfg!(unix) {
    ///     options.custom_flags(libc::O_NOFOLLOW);
    /// }
    /// let file = options.open("foo.txt");
    /// ```
    #[stable(feature = "open_options_ext", since = "1.10.0")]
    fn custom_flags(&mut self, flags: i32) -> &mut Self;
}

#[stable(feature = "fs_ext", since = "1.1.0")]
impl OpenOptionsExt for OpenOptions {
    fn mode(&mut self, mode: u32) -> &mut OpenOptions {
        self.as_inner_mut().mode(mode); self
    }

    fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
        self.as_inner_mut().custom_flags(flags); self
    }
}

// Hm, why are there casts here to the returned type, shouldn't the types always
// be the same? Right you are! Turns out, however, on android at least the types
// in the raw `stat` structure are not the same as the types being returned. Who
// knew!
//
// As a result to make sure this compiles for all platforms we do the manual
// casts and rely on manual lowering to `stat` if the raw type is desired.
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn dev(&self) -> u64;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn ino(&self) -> u64;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn mode(&self) -> u32;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn nlink(&self) -> u64;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn uid(&self) -> u32;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn gid(&self) -> u32;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn rdev(&self) -> u64;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn size(&self) -> u64;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn atime(&self) -> i64;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn atime_nsec(&self) -> i64;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn mtime(&self) -> i64;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn mtime_nsec(&self) -> i64;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn ctime(&self) -> i64;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn ctime_nsec(&self) -> i64;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn blksize(&self) -> u64;
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    fn blocks(&self) -> u64;
}

#[stable(feature = "metadata_ext", since = "1.1.0")]
impl MetadataExt for fs::Metadata {
    fn dev(&self) -> u64 { self.st_dev() }
    fn ino(&self) -> u64 { self.st_ino() }
    fn mode(&self) -> u32 { self.st_mode() }
    fn nlink(&self) -> u64 { self.st_nlink() }
    fn uid(&self) -> u32 { self.st_uid() }
    fn gid(&self) -> u32 { self.st_gid() }
    fn rdev(&self) -> u64 { self.st_rdev() }
    fn size(&self) -> u64 { self.st_size() }
    fn atime(&self) -> i64 { self.st_atime() }
    fn atime_nsec(&self) -> i64 { self.st_atime_nsec() }
    fn mtime(&self) -> i64 { self.st_mtime() }
    fn mtime_nsec(&self) -> i64 { self.st_mtime_nsec() }
    fn ctime(&self) -> i64 { self.st_ctime() }
    fn ctime_nsec(&self) -> i64 { self.st_ctime_nsec() }
    fn blksize(&self) -> u64 { self.st_blksize() }
    fn blocks(&self) -> u64 { self.st_blocks() }
}

/// Add special unix types (block/char device, fifo and socket)
#[stable(feature = "file_type_ext", since = "1.5.0")]
pub trait FileTypeExt {
    /// Returns whether this file type is a block device.
    #[stable(feature = "file_type_ext", since = "1.5.0")]
    fn is_block_device(&self) -> bool;
    /// Returns whether this file type is a char device.
    #[stable(feature = "file_type_ext", since = "1.5.0")]
    fn is_char_device(&self) -> bool;
    /// Returns whether this file type is a fifo.
    #[stable(feature = "file_type_ext", since = "1.5.0")]
    fn is_fifo(&self) -> bool;
    /// Returns whether this file type is a socket.
    #[stable(feature = "file_type_ext", since = "1.5.0")]
    fn is_socket(&self) -> bool;
}

#[stable(feature = "file_type_ext", since = "1.5.0")]
impl FileTypeExt for fs::FileType {
    fn is_block_device(&self) -> bool { self.as_inner().is(libc::S_IFBLK) }
    fn is_char_device(&self) -> bool { self.as_inner().is(libc::S_IFCHR) }
    fn is_fifo(&self) -> bool { self.as_inner().is(libc::S_IFIFO) }
    fn is_socket(&self) -> bool { self.as_inner().is(libc::S_IFSOCK) }
}

/// Unix-specific extension methods for `fs::DirEntry`
#[stable(feature = "dir_entry_ext", since = "1.1.0")]
pub trait DirEntryExt {
    /// Returns the underlying `d_ino` field in the contained `dirent`
    /// structure.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs;
    /// use std::os::unix::fs::DirEntryExt;
    ///
    /// if let Ok(entries) = fs::read_dir(".") {
    ///     for entry in entries {
    ///         if let Ok(entry) = entry {
    ///             // Here, `entry` is a `DirEntry`.
    ///             println!("{:?}: {}", entry.file_name(), entry.ino());
    ///         }
    ///     }
    /// }
    /// ```
    #[stable(feature = "dir_entry_ext", since = "1.1.0")]
    fn ino(&self) -> u64;
}

#[stable(feature = "dir_entry_ext", since = "1.1.0")]
impl DirEntryExt for fs::DirEntry {
    fn ino(&self) -> u64 { self.as_inner().ino() }
}

/// Creates a new symbolic link on the filesystem.
///
/// The `dst` path will be a symbolic link pointing to the `src` path.
///
/// # Note
///
/// On Windows, you must specify whether a symbolic link points to a file
/// or directory.  Use `os::windows::fs::symlink_file` to create a
/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a
/// symbolic link to a directory.  Additionally, the process must have
/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a
/// symbolic link.
///
/// # Examples
///
/// ```
/// use std::os::unix::fs;
///
/// # fn foo() -> std::io::Result<()> {
/// try!(fs::symlink("a.txt", "b.txt"));
/// # Ok(())
/// # }
/// ```
#[stable(feature = "symlink", since = "1.1.0")]
pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
{
    sys::fs::symlink(src.as_ref(), dst.as_ref())
}

#[stable(feature = "dir_builder", since = "1.6.0")]
/// An extension trait for `fs::DirBuilder` for unix-specific options.
pub trait DirBuilderExt {
    /// Sets the mode to create new directories with. This option defaults to
    /// 0o777.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::fs::DirBuilder;
    /// use std::os::unix::fs::DirBuilderExt;
    ///
    /// let mut builder = DirBuilder::new();
    /// builder.mode(0o755);
    /// ```
    #[stable(feature = "dir_builder", since = "1.6.0")]
    fn mode(&mut self, mode: u32) -> &mut Self;
}

#[stable(feature = "dir_builder", since = "1.6.0")]
impl DirBuilderExt for fs::DirBuilder {
    fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder {
        self.as_inner_mut().set_mode(mode);
        self
    }
}
<|endoftext|>


<commit_before>use crate::{schema::*, types::Node};

pub struct Transform {
    from_kind: &'static str,
    to_kind: &'static str,
    transform: fn(&Node) -> Node,
}

pub static TRANSFORMS: &[Transform] = &[Transform {
    from_kind: RUST_PRIMITIVE_TYPE_STR,
    to_kind: RUST_ARRAY_TYPE,
    transform: |node| {
        let mut node = node.clone();
        node.kind = RUST_ARRAY_TYPE.to_string();
        node
    },
}];
<commit_msg>Add todo<commit_after>use crate::{schema::*, types::Node};

pub struct Transform {
    from_kind: &'static str,
    to_kind: &'static str,
    transform: fn(&Node) -> Node,
}

// TODO: could field additions be modelled as a transform?

pub static TRANSFORMS: &[Transform] = &[Transform {
    from_kind: RUST_PRIMITIVE_TYPE_STR,
    to_kind: RUST_ARRAY_TYPE,
    transform: |node| {
        let mut node = node.clone();
        node.kind = RUST_ARRAY_TYPE.to_string();
        node
    },
}];
<|endoftext|>


<commit_before>mod analysis_stats;
mod analysis_bench;
mod help;

use std::{error::Error, fmt::Write, io::Read};

use flexi_logger::Logger;
use pico_args::Arguments;
use ra_ide_api::{file_structure, Analysis};
use ra_prof::profile;
use ra_syntax::{AstNode, SourceFile};

type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>;

fn main() -> Result<()> {
    Logger::with_env().start()?;

    let subcommand = match std::env::args_os().nth(1) {
        None => {
            eprintln!("{}", help::GLOBAL_HELP);
            return Ok(());
        }
        Some(s) => s,
    };
    let mut matches = Arguments::from_vec(std::env::args_os().skip(2).collect());

    match &*subcommand.to_string_lossy() {
        "parse" => {
            if matches.contains(["-h", "--help"]) {
                eprintln!("{}", help::PARSE_HELP);
                return Ok(());
            }
            let no_dump = matches.contains("--no-dump");
            matches.finish().or_else(handle_extra_flags)?;

            let _p = profile("parsing");
            let file = file()?;
            if !no_dump {
                println!("{:#?}", file.syntax());
            }
            std::mem::forget(file);
        }
        "symbols" => {
            if matches.contains(["-h", "--help"]) {
                eprintln!("{}", help::SYMBOLS_HELP);
                return Ok(());
            }
            matches.finish().or_else(handle_extra_flags)?;
            let file = file()?;
            for s in file_structure(&file) {
                println!("{:?}", s);
            }
        }
        "highlight" => {
            if matches.contains(["-h", "--help"]) {
                eprintln!("{}", help::HIGHLIGHT_HELP);
                return Ok(());
            }
            let rainbow_opt = matches.contains(["-r", "--rainbow"]);
            matches.finish().or_else(handle_extra_flags)?;
            let (analysis, file_id) = Analysis::from_single_file(read_stdin()?);
            let html = analysis.highlight_as_html(file_id, rainbow_opt).unwrap();
            println!("{}", html);
        }
        "analysis-stats" => {
            if matches.contains(["-h", "--help"]) {
                eprintln!("{}", help::ANALYSIS_STATS_HELP);
                return Ok(());
            }
            let verbose = matches.contains(["-v", "--verbose"]);
            let memory_usage = matches.contains("--memory-usage");
            let path: String = matches.value_from_str("--path")?.unwrap_or_default();
            let only = matches.value_from_str(["-o", "--only"])?.map(|v: String| v.to_owned());
            matches.finish().or_else(handle_extra_flags)?;
            analysis_stats::run(
                verbose,
                memory_usage,
                path.as_ref(),
                only.as_ref().map(String::as_ref),
            )?;
        }
        "analysis-bench" => {
            if matches.contains(["-h", "--help"]) {
                eprintln!("{}", help::ANALYSIS_BENCH_HELP);
                return Ok(());
            }
            let verbose = matches.contains(["-v", "--verbose"]);
            let path: String = matches.value_from_str("--path")?.unwrap_or_default();
            let highlight_path = matches.value_from_str("--highlight")?;
            let complete_path = matches.value_from_str("--complete")?;
            if highlight_path.is_some() && complete_path.is_some() {
                panic!("either --highlight or --complete must be set, not both")
            }
            let op = if let Some(path) = highlight_path {
                let path: String = path;
                analysis_bench::Op::Highlight { path: path.into() }
            } else if let Some(path_line_col) = complete_path {
                let path_line_col: String = path_line_col;
                let (path_line, column) = rsplit_at_char(path_line_col.as_str(), ':')?;
                let (path, line) = rsplit_at_char(path_line, ':')?;
                analysis_bench::Op::Complete {
                    path: path.into(),
                    line: line.parse()?,
                    column: column.parse()?,
                }
            } else {
                panic!("either --highlight or --complete must be set")
            };
            matches.finish().or_else(handle_extra_flags)?;
            analysis_bench::run(verbose, path.as_ref(), op)?;
        }
        _ => eprintln!("{}", help::GLOBAL_HELP),
    }
    Ok(())
}

fn handle_extra_flags(e: pico_args::Error) -> Result<()> {
    if let pico_args::Error::UnusedArgsLeft(flags) = e {
        let mut invalid_flags = String::new();
        for flag in flags {
            write!(&mut invalid_flags, "{}, ", flag)?;
        }
        let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2);
        Err(format!("Invalid flags: {}", invalid_flags).into())
    } else {
        Err(e.to_string().into())
    }
}

fn file() -> Result<SourceFile> {
    let text = read_stdin()?;
    Ok(SourceFile::parse(&text).tree())
}

fn read_stdin() -> Result<String> {
    let mut buff = String::new();
    std::io::stdin().read_to_string(&mut buff)?;
    Ok(buff)
}

fn rsplit_at_char(s: &str, c: char) -> Result<(&str, &str)> {
    let idx = s.rfind(':').ok_or_else(|| format!("no `{}` in {}", c, s))?;
    Ok((&s[..idx], &s[idx + 1..]))
}
<commit_msg>analysis stats uses positional arg again<commit_after>mod analysis_stats;
mod analysis_bench;
mod help;

use std::{error::Error, fmt::Write, io::Read};

use flexi_logger::Logger;
use pico_args::Arguments;
use ra_ide_api::{file_structure, Analysis};
use ra_prof::profile;
use ra_syntax::{AstNode, SourceFile};

type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>;

fn main() -> Result<()> {
    Logger::with_env().start()?;

    let subcommand = match std::env::args_os().nth(1) {
        None => {
            eprintln!("{}", help::GLOBAL_HELP);
            return Ok(());
        }
        Some(s) => s,
    };
    let mut matches = Arguments::from_vec(std::env::args_os().skip(2).collect());

    match &*subcommand.to_string_lossy() {
        "parse" => {
            if matches.contains(["-h", "--help"]) {
                eprintln!("{}", help::PARSE_HELP);
                return Ok(());
            }
            let no_dump = matches.contains("--no-dump");
            matches.finish().or_else(handle_extra_flags)?;

            let _p = profile("parsing");
            let file = file()?;
            if !no_dump {
                println!("{:#?}", file.syntax());
            }
            std::mem::forget(file);
        }
        "symbols" => {
            if matches.contains(["-h", "--help"]) {
                eprintln!("{}", help::SYMBOLS_HELP);
                return Ok(());
            }
            matches.finish().or_else(handle_extra_flags)?;
            let file = file()?;
            for s in file_structure(&file) {
                println!("{:?}", s);
            }
        }
        "highlight" => {
            if matches.contains(["-h", "--help"]) {
                eprintln!("{}", help::HIGHLIGHT_HELP);
                return Ok(());
            }
            let rainbow_opt = matches.contains(["-r", "--rainbow"]);
            matches.finish().or_else(handle_extra_flags)?;
            let (analysis, file_id) = Analysis::from_single_file(read_stdin()?);
            let html = analysis.highlight_as_html(file_id, rainbow_opt).unwrap();
            println!("{}", html);
        }
        "analysis-stats" => {
            if matches.contains(["-h", "--help"]) {
                eprintln!("{}", help::ANALYSIS_STATS_HELP);
                return Ok(());
            }
            let verbose = matches.contains(["-v", "--verbose"]);
            let memory_usage = matches.contains("--memory-usage");
            let only = matches.value_from_str(["-o", "--only"])?.map(|v: String| v.to_owned());
            let path = {
                let mut trailing = matches.free()?;
                if trailing.len() != 1 {
                    eprintln!("{}", help::ANALYSIS_STATS_HELP);
                    Err("Invalid flags")?;
                }
                trailing.pop().unwrap()
            };
            analysis_stats::run(
                verbose,
                memory_usage,
                path.as_ref(),
                only.as_ref().map(String::as_ref),
            )?;
        }
        "analysis-bench" => {
            if matches.contains(["-h", "--help"]) {
                eprintln!("{}", help::ANALYSIS_BENCH_HELP);
                return Ok(());
            }
            let verbose = matches.contains(["-v", "--verbose"]);
            let path: String = matches.value_from_str("--path")?.unwrap_or_default();
            let highlight_path = matches.value_from_str("--highlight")?;
            let complete_path = matches.value_from_str("--complete")?;
            if highlight_path.is_some() && complete_path.is_some() {
                panic!("either --highlight or --complete must be set, not both")
            }
            let op = if let Some(path) = highlight_path {
                let path: String = path;
                analysis_bench::Op::Highlight { path: path.into() }
            } else if let Some(path_line_col) = complete_path {
                let path_line_col: String = path_line_col;
                let (path_line, column) = rsplit_at_char(path_line_col.as_str(), ':')?;
                let (path, line) = rsplit_at_char(path_line, ':')?;
                analysis_bench::Op::Complete {
                    path: path.into(),
                    line: line.parse()?,
                    column: column.parse()?,
                }
            } else {
                panic!("either --highlight or --complete must be set")
            };
            matches.finish().or_else(handle_extra_flags)?;
            analysis_bench::run(verbose, path.as_ref(), op)?;
        }
        _ => eprintln!("{}", help::GLOBAL_HELP),
    }
    Ok(())
}

fn handle_extra_flags(e: pico_args::Error) -> Result<()> {
    if let pico_args::Error::UnusedArgsLeft(flags) = e {
        let mut invalid_flags = String::new();
        for flag in flags {
            write!(&mut invalid_flags, "{}, ", flag)?;
        }
        let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2);
        Err(format!("Invalid flags: {}", invalid_flags).into())
    } else {
        Err(e.to_string().into())
    }
}

fn file() -> Result<SourceFile> {
    let text = read_stdin()?;
    Ok(SourceFile::parse(&text).tree())
}

fn read_stdin() -> Result<String> {
    let mut buff = String::new();
    std::io::stdin().read_to_string(&mut buff)?;
    Ok(buff)
}

fn rsplit_at_char(s: &str, c: char) -> Result<(&str, &str)> {
    let idx = s.rfind(':').ok_or_else(|| format!("no `{}` in {}", c, s))?;
    Ok((&s[..idx], &s[idx + 1..]))
}
<|endoftext|>