<commit_before>// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

//! ARM PL031 Real Time Clock
//!
//! This module implements a PL031 Real Time Clock (RTC) that provides to provides long time base counter.
//! This is achieved by generating an interrupt signal after counting for a programmed number of cycles of
//! a real-time clock input.
//!
use std::fmt;
use std::time::Instant;
use std::{io, result};

use crate::BusDevice;
use logger::{warn, IncMetric, METRICS};
use utils::byte_order;
use utils::eventfd::EventFd;
//use bus::Error;

// As you can see in https://static.docs.arm.com/ddi0224/c/real_time_clock_pl031_r1p3_technical_reference_manual_DDI0224C.pdf
// at section 3.2 Summary of RTC registers, the total size occupied by this device is 0x000 -> 0xFFC + 4 = 0x1000.
// From 0x0 to 0x1C we have following registers:
const RTCDR: u64 = 0x0; // Data Register.
const RTCMR: u64 = 0x4; // Match Register.
const RTCLR: u64 = 0x8; // Load Regiser.
const RTCCR: u64 = 0xc; // Control Register.
const RTCIMSC: u64 = 0x10; // Interrupt Mask Set or Clear Register.
const RTCRIS: u64 = 0x14; // Raw Interrupt Status.
const RTCMIS: u64 = 0x18; // Masked Interrupt Status.
const RTCICR: u64 = 0x1c; // Interrupt Clear Register.
                          // From 0x020 to 0xFDC => reserved space.
                          // From 0xFE0 to 0x1000 => Peripheral and PrimeCell Identification Registers which are Read Only registers.
                          // AMBA standard devices have CIDs (Cell IDs) and PIDs (Peripheral IDs). The linux kernel will look for these in order to assert the identity
                          // of these devices (i.e look at the `amba_device_try_add` function).
                          // We are putting the expected values (look at 'Reset value' column from above mentioned document) in an array.
const PL031_ID: [u8; 8] = [0x31, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1];
// We are only interested in the margins.
const AMBA_ID_LOW: u64 = 0xFE0;
const AMBA_ID_HIGH: u64 = 0x1000;

#[derive(Debug)]
pub enum Error {
    BadWriteOffset(u64),
    InterruptFailure(io::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::BadWriteOffset(offset) => write!(f, "Bad Write Offset: {}", offset),
            Error::InterruptFailure(e) => write!(f, "Failed to trigger interrupt: {}", e),
        }
    }
}
type Result<T> = result::Result<T, Error>;

/// A RTC device following the PL031 specification..
pub struct RTC {
    previous_now: Instant,
    tick_offset: i64,
    // This is used for implementing the RTC alarm. However, in Firecracker we do not need it.
    match_value: u32,
    // Writes to this register load an update value into the RTC.
    load: u32,
    imsc: u32,
    ris: u32,
    interrupt_evt: EventFd,
}

impl RTC {
    /// Constructs an AMBA PL031 RTC device.
    pub fn new(interrupt_evt: EventFd) -> RTC {
        RTC {
            // This is used only for duration measuring purposes.
            previous_now: Instant::now(),
            tick_offset: utils::time::get_time_ns(utils::time::ClockType::Real) as i64,
            match_value: 0,
            load: 0,
            imsc: 0,
            ris: 0,
            interrupt_evt,
        }
    }

    fn trigger_interrupt(&mut self) -> Result<()> {
        self.interrupt_evt.write(1).map_err(Error::InterruptFailure)
    }

    fn get_time(&self) -> u32 {
        let ts = (self.tick_offset as i128)
            + (Instant::now().duration_since(self.previous_now).as_nanos() as i128);
        (ts / utils::time::NANOS_PER_SECOND as i128) as u32
    }

    fn handle_write(&mut self, offset: u64, val: u32) -> Result<()> {
        match offset {
            RTCMR => {
                // The MR register is used for implementing the RTC alarm. A real time clock alarm is
                // a feature that can be used to allow a computer to 'wake up' after shut down to execute
                // tasks every day or on a certain day. It can sometimes be found in the 'Power Management'
                // section of a motherboard's BIOS setup. This is functionality that extends beyond
                // Firecracker intended use. However, we increment a metric just in case.
                self.match_value = val;
                METRICS.rtc.missed_write_count.inc();
            }
            RTCLR => {
                self.load = val;
                self.previous_now = Instant::now();
                // If the unwrap fails, then the internal value of the clock has been corrupted and
                // we want to terminate the execution of the process.
                self.tick_offset = utils::time::seconds_to_nanoseconds(i64::from(val))
                    .expect("Time conversion overflow");
            }
            RTCIMSC => {
                self.imsc = val & 1;
                self.trigger_interrupt()?;
            }
            RTCICR => {
                // As per above mentioned doc, the interrupt is cleared by writing any data value to
                // the Interrupt Clear Register.
                self.ris = 0;
                self.trigger_interrupt()?;
            }
            RTCCR => (), // ignore attempts to turn off the timer.
            o => {
                return Err(Error::BadWriteOffset(o));
            }
        }
        Ok(())
    }
    /// Provides a reference to the interrupt event fd.
    pub fn interrupt_evt(&self) -> &EventFd {
        &self.interrupt_evt
    }
}

impl BusDevice for RTC {
    fn read(&mut self, offset: u64, data: &mut [u8]) {
        let v;
        let mut read_ok = true;

        if offset < AMBA_ID_HIGH && offset >= AMBA_ID_LOW {
            let index = ((offset - AMBA_ID_LOW) >> 2) as usize;
            v = u32::from(PL031_ID[index]);
        } else {
            v = match offset {
                RTCDR => self.get_time(),
                RTCMR => {
                    METRICS.rtc.missed_read_count.inc();
                    // Even though we are not implementing RTC alarm we return the last value
                    self.match_value
                }
                RTCLR => self.load,
                RTCCR => 1, // RTC is always enabled.
                RTCIMSC => self.imsc,
                RTCRIS => self.ris,
                RTCMIS => self.ris & self.imsc,
                _ => {
                    read_ok = false;
                    0
                }
            };
        }
        if read_ok && data.len() <= 4 {
            byte_order::write_le_u32(data, v);
        } else {
            warn!(
                "Invalid RTC PL031 read: offset {}, data length {}",
                offset,
                data.len()
            );
            METRICS.rtc.error_count.inc();
        }
    }

    fn write(&mut self, offset: u64, data: &[u8]) {
        if data.len() <= 4 {
            let v = byte_order::read_le_u32(&data[..]);
            if let Err(e) = self.handle_write(offset, v) {
                warn!("Failed to write to RTC PL031 device: {}", e);
                METRICS.rtc.error_count.inc();
            }
        } else {
            warn!(
                "Invalid RTC PL031 write: offset {}, data length {}",
                offset,
                data.len()
            );
            METRICS.rtc.error_count.inc();
        }
    }
}

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

    #[test]
    fn test_rtc_read_write_and_event() {
        let mut rtc = RTC::new(EventFd::new(libc::EFD_NONBLOCK).unwrap());
        let mut data = [0; 4];

        // Read and write to the MR register.
        byte_order::write_le_u32(&mut data, 123);
        rtc.write(RTCMR, &data);
        rtc.read(RTCMR, &mut data);
        let v = byte_order::read_le_u32(&data[..]);
        assert_eq!(v, 123);

        // Read and write to the LR register.
        let v = utils::time::get_time_ns(utils::time::ClockType::Real);
        byte_order::write_le_u32(&mut data, (v / utils::time::NANOS_PER_SECOND) as u32);
        let previous_now_before = rtc.previous_now;
        rtc.write(RTCLR, &data);

        assert!(rtc.previous_now > previous_now_before);

        rtc.read(RTCLR, &mut data);
        let v_read = byte_order::read_le_u32(&data[..]);
        assert_eq!((v / utils::time::NANOS_PER_SECOND) as u32, v_read);

        // Read and write to IMSC register.
        // Test with non zero value.
        let non_zero = 1;
        byte_order::write_le_u32(&mut data, non_zero);
        rtc.write(RTCIMSC, &data);
        // The interrupt line should be on.
        assert!(rtc.interrupt_evt.read().unwrap() == 1);
        rtc.read(RTCIMSC, &mut data);
        let v = byte_order::read_le_u32(&data[..]);
        assert_eq!(non_zero & 1, v);

        // Now test with 0.
        byte_order::write_le_u32(&mut data, 0);
        rtc.write(RTCIMSC, &data);
        rtc.read(RTCIMSC, &mut data);
        let v = byte_order::read_le_u32(&data[..]);
        assert_eq!(0, v);

        // Read and write to the ICR register.
        byte_order::write_le_u32(&mut data, 1);
        rtc.write(RTCICR, &data);
        // The interrupt line should be on.
        assert!(rtc.interrupt_evt.read().unwrap() > 1);
        let v_before = byte_order::read_le_u32(&data[..]);
        let no_errors_before = METRICS.rtc.error_count.count();

        rtc.read(RTCICR, &mut data);
        let no_errors_after = METRICS.rtc.error_count.count();
        let v = byte_order::read_le_u32(&data[..]);
        // ICR is a  write only register. Data received should stay equal to data sent.
        assert_eq!(v, v_before);
        assert_eq!(no_errors_after - no_errors_before, 1);

        // Attempts to turn off the RTC should not go through.
        byte_order::write_le_u32(&mut data, 0);
        rtc.write(RTCCR, &data);
        rtc.read(RTCCR, &mut data);
        let v = byte_order::read_le_u32(&data[..]);
        assert_eq!(v, 1);

        // Attempts to write beyond the writable space. Using here the space used to read
        // the CID and PID from.
        byte_order::write_le_u32(&mut data, 0);
        let no_errors_before = METRICS.rtc.error_count.count();
        rtc.write(AMBA_ID_LOW, &data);
        let no_errors_after = METRICS.rtc.error_count.count();
        assert_eq!(no_errors_after - no_errors_before, 1);
        // However, reading from the AMBA_ID_LOW should succeed upon read.

        let mut data = [0; 4];
        rtc.read(AMBA_ID_LOW, &mut data);
        let index = AMBA_ID_LOW + 3;
        assert_eq!(data[0], PL031_ID[((index - AMBA_ID_LOW) >> 2) as usize]);
    }
}
<commit_msg>aarch64/rtc: update reset value for RTCPeriphID2<commit_after>// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

//! ARM PL031 Real Time Clock
//!
//! This module implements a PL031 Real Time Clock (RTC) that provides to provides long time base counter.
//! This is achieved by generating an interrupt signal after counting for a programmed number of cycles of
//! a real-time clock input.
//!
use std::fmt;
use std::time::Instant;
use std::{io, result};

use crate::BusDevice;
use logger::{warn, IncMetric, METRICS};
use utils::byte_order;
use utils::eventfd::EventFd;
//use bus::Error;

// As you can see in https://static.docs.arm.com/ddi0224/c/real_time_clock_pl031_r1p3_technical_reference_manual_DDI0224C.pdf
// at section 3.2 Summary of RTC registers, the total size occupied by this device is 0x000 -> 0xFFC + 4 = 0x1000.
// From 0x0 to 0x1C we have following registers:
const RTCDR: u64 = 0x0; // Data Register.
const RTCMR: u64 = 0x4; // Match Register.
const RTCLR: u64 = 0x8; // Load Regiser.
const RTCCR: u64 = 0xc; // Control Register.
const RTCIMSC: u64 = 0x10; // Interrupt Mask Set or Clear Register.
const RTCRIS: u64 = 0x14; // Raw Interrupt Status.
const RTCMIS: u64 = 0x18; // Masked Interrupt Status.
const RTCICR: u64 = 0x1c; // Interrupt Clear Register.
                          // From 0x020 to 0xFDC => reserved space.
                          // From 0xFE0 to 0x1000 => Peripheral and PrimeCell Identification Registers which are Read Only registers.
                          // AMBA standard devices have CIDs (Cell IDs) and PIDs (Peripheral IDs). The linux kernel will look for these in order to assert the identity
                          // of these devices (i.e look at the `amba_device_try_add` function).
                          // We are putting the expected values (look at 'Reset value' column from above mentioned document) in an array.
const PL031_ID: [u8; 8] = [0x31, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1];
// We are only interested in the margins.
const AMBA_ID_LOW: u64 = 0xFE0;
const AMBA_ID_HIGH: u64 = 0x1000;

#[derive(Debug)]
pub enum Error {
    BadWriteOffset(u64),
    InterruptFailure(io::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::BadWriteOffset(offset) => write!(f, "Bad Write Offset: {}", offset),
            Error::InterruptFailure(e) => write!(f, "Failed to trigger interrupt: {}", e),
        }
    }
}
type Result<T> = result::Result<T, Error>;

/// A RTC device following the PL031 specification..
pub struct RTC {
    previous_now: Instant,
    tick_offset: i64,
    // This is used for implementing the RTC alarm. However, in Firecracker we do not need it.
    match_value: u32,
    // Writes to this register load an update value into the RTC.
    load: u32,
    imsc: u32,
    ris: u32,
    interrupt_evt: EventFd,
}

impl RTC {
    /// Constructs an AMBA PL031 RTC device.
    pub fn new(interrupt_evt: EventFd) -> RTC {
        RTC {
            // This is used only for duration measuring purposes.
            previous_now: Instant::now(),
            tick_offset: utils::time::get_time_ns(utils::time::ClockType::Real) as i64,
            match_value: 0,
            load: 0,
            imsc: 0,
            ris: 0,
            interrupt_evt,
        }
    }

    fn trigger_interrupt(&mut self) -> Result<()> {
        self.interrupt_evt.write(1).map_err(Error::InterruptFailure)
    }

    fn get_time(&self) -> u32 {
        let ts = (self.tick_offset as i128)
            + (Instant::now().duration_since(self.previous_now).as_nanos() as i128);
        (ts / utils::time::NANOS_PER_SECOND as i128) as u32
    }

    fn handle_write(&mut self, offset: u64, val: u32) -> Result<()> {
        match offset {
            RTCMR => {
                // The MR register is used for implementing the RTC alarm. A real time clock alarm is
                // a feature that can be used to allow a computer to 'wake up' after shut down to execute
                // tasks every day or on a certain day. It can sometimes be found in the 'Power Management'
                // section of a motherboard's BIOS setup. This is functionality that extends beyond
                // Firecracker intended use. However, we increment a metric just in case.
                self.match_value = val;
                METRICS.rtc.missed_write_count.inc();
            }
            RTCLR => {
                self.load = val;
                self.previous_now = Instant::now();
                // If the unwrap fails, then the internal value of the clock has been corrupted and
                // we want to terminate the execution of the process.
                self.tick_offset = utils::time::seconds_to_nanoseconds(i64::from(val))
                    .expect("Time conversion overflow");
            }
            RTCIMSC => {
                self.imsc = val & 1;
                self.trigger_interrupt()?;
            }
            RTCICR => {
                // As per above mentioned doc, the interrupt is cleared by writing any data value to
                // the Interrupt Clear Register.
                self.ris = 0;
                self.trigger_interrupt()?;
            }
            RTCCR => (), // ignore attempts to turn off the timer.
            o => {
                return Err(Error::BadWriteOffset(o));
            }
        }
        Ok(())
    }
    /// Provides a reference to the interrupt event fd.
    pub fn interrupt_evt(&self) -> &EventFd {
        &self.interrupt_evt
    }
}

impl BusDevice for RTC {
    fn read(&mut self, offset: u64, data: &mut [u8]) {
        let v;
        let mut read_ok = true;

        if offset < AMBA_ID_HIGH && offset >= AMBA_ID_LOW {
            let index = ((offset - AMBA_ID_LOW) >> 2) as usize;
            v = u32::from(PL031_ID[index]);
        } else {
            v = match offset {
                RTCDR => self.get_time(),
                RTCMR => {
                    METRICS.rtc.missed_read_count.inc();
                    // Even though we are not implementing RTC alarm we return the last value
                    self.match_value
                }
                RTCLR => self.load,
                RTCCR => 1, // RTC is always enabled.
                RTCIMSC => self.imsc,
                RTCRIS => self.ris,
                RTCMIS => self.ris & self.imsc,
                _ => {
                    read_ok = false;
                    0
                }
            };
        }
        if read_ok && data.len() <= 4 {
            byte_order::write_le_u32(data, v);
        } else {
            warn!(
                "Invalid RTC PL031 read: offset {}, data length {}",
                offset,
                data.len()
            );
            METRICS.rtc.error_count.inc();
        }
    }

    fn write(&mut self, offset: u64, data: &[u8]) {
        if data.len() <= 4 {
            let v = byte_order::read_le_u32(&data[..]);
            if let Err(e) = self.handle_write(offset, v) {
                warn!("Failed to write to RTC PL031 device: {}", e);
                METRICS.rtc.error_count.inc();
            }
        } else {
            warn!(
                "Invalid RTC PL031 write: offset {}, data length {}",
                offset,
                data.len()
            );
            METRICS.rtc.error_count.inc();
        }
    }
}

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

    #[test]
    fn test_rtc_read_write_and_event() {
        let mut rtc = RTC::new(EventFd::new(libc::EFD_NONBLOCK).unwrap());
        let mut data = [0; 4];

        // Read and write to the MR register.
        byte_order::write_le_u32(&mut data, 123);
        rtc.write(RTCMR, &data);
        rtc.read(RTCMR, &mut data);
        let v = byte_order::read_le_u32(&data[..]);
        assert_eq!(v, 123);

        // Read and write to the LR register.
        let v = utils::time::get_time_ns(utils::time::ClockType::Real);
        byte_order::write_le_u32(&mut data, (v / utils::time::NANOS_PER_SECOND) as u32);
        let previous_now_before = rtc.previous_now;
        rtc.write(RTCLR, &data);

        assert!(rtc.previous_now > previous_now_before);

        rtc.read(RTCLR, &mut data);
        let v_read = byte_order::read_le_u32(&data[..]);
        assert_eq!((v / utils::time::NANOS_PER_SECOND) as u32, v_read);

        // Read and write to IMSC register.
        // Test with non zero value.
        let non_zero = 1;
        byte_order::write_le_u32(&mut data, non_zero);
        rtc.write(RTCIMSC, &data);
        // The interrupt line should be on.
        assert!(rtc.interrupt_evt.read().unwrap() == 1);
        rtc.read(RTCIMSC, &mut data);
        let v = byte_order::read_le_u32(&data[..]);
        assert_eq!(non_zero & 1, v);

        // Now test with 0.
        byte_order::write_le_u32(&mut data, 0);
        rtc.write(RTCIMSC, &data);
        rtc.read(RTCIMSC, &mut data);
        let v = byte_order::read_le_u32(&data[..]);
        assert_eq!(0, v);

        // Read and write to the ICR register.
        byte_order::write_le_u32(&mut data, 1);
        rtc.write(RTCICR, &data);
        // The interrupt line should be on.
        assert!(rtc.interrupt_evt.read().unwrap() > 1);
        let v_before = byte_order::read_le_u32(&data[..]);
        let no_errors_before = METRICS.rtc.error_count.count();

        rtc.read(RTCICR, &mut data);
        let no_errors_after = METRICS.rtc.error_count.count();
        let v = byte_order::read_le_u32(&data[..]);
        // ICR is a  write only register. Data received should stay equal to data sent.
        assert_eq!(v, v_before);
        assert_eq!(no_errors_after - no_errors_before, 1);

        // Attempts to turn off the RTC should not go through.
        byte_order::write_le_u32(&mut data, 0);
        rtc.write(RTCCR, &data);
        rtc.read(RTCCR, &mut data);
        let v = byte_order::read_le_u32(&data[..]);
        assert_eq!(v, 1);

        // Attempts to write beyond the writable space. Using here the space used to read
        // the CID and PID from.
        byte_order::write_le_u32(&mut data, 0);
        let no_errors_before = METRICS.rtc.error_count.count();
        rtc.write(AMBA_ID_LOW, &data);
        let no_errors_after = METRICS.rtc.error_count.count();
        assert_eq!(no_errors_after - no_errors_before, 1);
        // However, reading from the AMBA_ID_LOW should succeed upon read.

        let mut data = [0; 4];
        rtc.read(AMBA_ID_LOW, &mut data);
        let index = AMBA_ID_LOW + 3;
        assert_eq!(data[0], PL031_ID[((index - AMBA_ID_LOW) >> 2) as usize]);
    }
}
<|endoftext|>


<commit_before>use cgmath;
use cgmath::{Vector, Point, Matrix};
use gl;
use std;
use std::collections::HashMap;
use std::f32;
use yaglw;
use yaglw::gl_context::GLContext;

use common::entity_id;

use terrain_mesh;
use vertex;

#[cfg(test)]
use std::mem;

// VRAM bytes
pub const BYTE_BUDGET: usize = 64_000_000;
pub const TUFT_COST: usize = 64;
pub const TUFT_BUDGET: usize = BYTE_BUDGET / TUFT_COST;

/// Struct for loading/unloading/maintaining terrain data in VRAM.
pub struct T<'a> {
  id_to_index: HashMap<entity_id::T, usize>,
  index_to_id: Vec<entity_id::T>,

  gl_array: yaglw::vertex_buffer::ArrayHandle<'a>,
  _instance_vertices: yaglw::vertex_buffer::GLBuffer<'a, vertex::TextureVertex>,
  per_tuft: yaglw::vertex_buffer::GLBuffer<'a, terrain_mesh::Grass>,
}

#[allow(missing_docs)]
pub fn new<'a, 'b:'a>(
  gl: &'a mut GLContext,
  shader: &yaglw::shader::Shader<'a>,
) -> T<'b>
{
  use yaglw::vertex_buffer;

  let gl_array = vertex_buffer::ArrayHandle::new(gl);
  let mut instance_vertices = vertex_buffer::GLBuffer::new(gl, 18);
  let per_tuft = vertex_buffer::GLBuffer::new(gl, TUFT_BUDGET);

  let mut vertices = Vec::new();
  {
    let tangent = cgmath::Vector3::new(0.0, 0.0, 0.5);
    let normal = cgmath::Vector3::new(0.0, 1.0, 0.0);
    let mut quad = |v: &cgmath::Vector3<f32>| {
      let mut tri = |p0, t0, p1, t1, p2, t2| {
        let vert = |p, t| {
          vertex::TextureVertex {
            world_position: p,
            texture_position: t,
          }
        };
        vertices.push(vert(p0, t0));
        vertices.push(vert(p1, t1));
        vertices.push(vert(p2, t2));
      };

      tri(
        Point::from_vec(&-v.div_s(2.0))                , cgmath::Vector2::new(0.0 , 0.0) ,
        Point::from_vec(&v.div_s(2.0))                 , cgmath::Vector2::new(1.0 , 0.0) ,
        Point::from_vec(&v.div_s(2.0).add_v(&normal))  , cgmath::Vector2::new(1.0 , 1.0) ,
      );
      tri(
        Point::from_vec(&-v.div_s(2.0))                , cgmath::Vector2::new(0.0 , 0.0) ,
        Point::from_vec(&v.div_s(2.0).add_v(&normal))  , cgmath::Vector2::new(1.0 , 1.0) ,
        Point::from_vec(&-v.div_s(2.0).add_v(&normal)) , cgmath::Vector2::new(0.0 , 1.0) ,
      );
    };

    quad(&tangent);
    quad(&cgmath::Matrix3::from_axis_angle(&normal, cgmath::rad(f32::consts::FRAC_PI_3)).mul_v(&tangent));
    quad(&cgmath::Matrix3::from_axis_angle(&normal, cgmath::rad(2.0 * f32::consts::FRAC_PI_3)).mul_v(&tangent));
  }

  unsafe {
    gl::BindVertexArray(gl_array.gl_id);
  }
  shader.use_shader(gl);
  instance_vertices.byte_buffer.bind(gl);
  instance_vertices.push(gl, &vertices);
  let attrib_span =
    vertex_buffer::VertexAttribData::apply(
      &[
        vertex_buffer::VertexAttribData {
          name: "vertex_position",
          size: 3,
          unit: vertex_buffer::GLType::Float,
          divisor: 0,
        },
        vertex_buffer::VertexAttribData {
          name: "texture_position",
          size: 2,
          unit: vertex_buffer::GLType::Float,
          divisor: 0,
        },
      ],
      gl,
      shader,
    );
  assert!(attrib_span == std::mem::size_of::<vertex::TextureVertex>() as u32);

  per_tuft.byte_buffer.bind(gl);
  let attrib_span =
    vertex_buffer::VertexAttribData::apply(
      &[
        vertex_buffer::VertexAttribData {
          name: "root",
          size: 3,
          unit: vertex_buffer::GLType::Float,
          divisor: 1,
        },
        vertex_buffer::VertexAttribData {
          name: "normal",
          size: 3,
          unit: vertex_buffer::GLType::Float,
          divisor: 1,
        },
        vertex_buffer::VertexAttribData {
          name: "tex_id",
          size: 3,
          unit: vertex_buffer::GLType::UInt,
          divisor: 1,
        },
      ],
      gl,
      shader,
    );
  assert!(attrib_span == std::mem::size_of::<terrain_mesh::Grass>() as u32);

  T {
    id_to_index: HashMap::new(),
    index_to_id: Vec::new(),

    gl_array: gl_array,
    _instance_vertices: instance_vertices,
    per_tuft: per_tuft,
  }
}

impl<'a> T<'a> {
  /// Add a series of entites into VRAM.
  pub fn push(
    &mut self,
    gl: &mut GLContext,
    grass: &[terrain_mesh::Grass],
    grass_ids: &[entity_id::T],
  ) {
    self.per_tuft.byte_buffer.bind(gl);
    let success: bool = self.per_tuft.push(gl, grass);
    if !success {
      panic!("Ran out of VRAM for grass");
    }

    for id in grass_ids {
      self.id_to_index.insert(*id, self.index_to_id.len());
      self.index_to_id.push(*id);
    }
  }

  // TODO: Make this take many ids as a parameter, to reduce `bind`s.
  // Note: `id` must be present in the buffers.
  /// Remove some entity from VRAM.
  pub fn swap_remove(&mut self, gl: &mut GLContext, id: entity_id::T) {
    let idx = *self.id_to_index.get(&id).unwrap();
    let swapped_id = self.index_to_id[self.index_to_id.len() - 1];
    self.index_to_id.swap_remove(idx);
    self.id_to_index.remove(&id);

    if id != swapped_id {
      self.id_to_index.insert(swapped_id, idx);
    }

    self.per_tuft.byte_buffer.bind(gl);
    self.per_tuft.swap_remove(gl, idx, 1);
  }

  pub fn draw(&self, _gl: &mut GLContext) {
    unsafe {
      gl::BindVertexArray(self.gl_array.gl_id);
      gl::DrawArraysInstanced(gl::TRIANGLES, 0, 18, self.index_to_id.len() as i32);
    }
  }
}
<commit_msg>fix build?<commit_after>use cgmath;
use cgmath::{Vector, Point, Matrix};
use gl;
use std;
use std::collections::HashMap;
use std::f32;
use yaglw;
use yaglw::gl_context::GLContext;

use common::entity_id;

use terrain_mesh;
use vertex;

// VRAM bytes
pub const BYTE_BUDGET: usize = 64_000_000;
pub const TUFT_COST: usize = 64;
pub const TUFT_BUDGET: usize = BYTE_BUDGET / TUFT_COST;

/// Struct for loading/unloading/maintaining terrain data in VRAM.
pub struct T<'a> {
  id_to_index: HashMap<entity_id::T, usize>,
  index_to_id: Vec<entity_id::T>,

  gl_array: yaglw::vertex_buffer::ArrayHandle<'a>,
  _instance_vertices: yaglw::vertex_buffer::GLBuffer<'a, vertex::TextureVertex>,
  per_tuft: yaglw::vertex_buffer::GLBuffer<'a, terrain_mesh::Grass>,
}

#[allow(missing_docs)]
pub fn new<'a, 'b:'a>(
  gl: &'a mut GLContext,
  shader: &yaglw::shader::Shader<'a>,
) -> T<'b>
{
  use yaglw::vertex_buffer;

  let gl_array = vertex_buffer::ArrayHandle::new(gl);
  let mut instance_vertices = vertex_buffer::GLBuffer::new(gl, 18);
  let per_tuft = vertex_buffer::GLBuffer::new(gl, TUFT_BUDGET);

  let mut vertices = Vec::new();
  {
    let tangent = cgmath::Vector3::new(0.0, 0.0, 0.5);
    let normal = cgmath::Vector3::new(0.0, 1.0, 0.0);
    let mut quad = |v: &cgmath::Vector3<f32>| {
      let mut tri = |p0, t0, p1, t1, p2, t2| {
        let vert = |p, t| {
          vertex::TextureVertex {
            world_position: p,
            texture_position: t,
          }
        };
        vertices.push(vert(p0, t0));
        vertices.push(vert(p1, t1));
        vertices.push(vert(p2, t2));
      };

      tri(
        Point::from_vec(&-v.div_s(2.0))                , cgmath::Vector2::new(0.0 , 0.0) ,
        Point::from_vec(&v.div_s(2.0))                 , cgmath::Vector2::new(1.0 , 0.0) ,
        Point::from_vec(&v.div_s(2.0).add_v(&normal))  , cgmath::Vector2::new(1.0 , 1.0) ,
      );
      tri(
        Point::from_vec(&-v.div_s(2.0))                , cgmath::Vector2::new(0.0 , 0.0) ,
        Point::from_vec(&v.div_s(2.0).add_v(&normal))  , cgmath::Vector2::new(1.0 , 1.0) ,
        Point::from_vec(&-v.div_s(2.0).add_v(&normal)) , cgmath::Vector2::new(0.0 , 1.0) ,
      );
    };

    quad(&tangent);
    quad(&cgmath::Matrix3::from_axis_angle(&normal, cgmath::rad(f32::consts::FRAC_PI_3)).mul_v(&tangent));
    quad(&cgmath::Matrix3::from_axis_angle(&normal, cgmath::rad(2.0 * f32::consts::FRAC_PI_3)).mul_v(&tangent));
  }

  unsafe {
    gl::BindVertexArray(gl_array.gl_id);
  }
  shader.use_shader(gl);
  instance_vertices.byte_buffer.bind(gl);
  instance_vertices.push(gl, &vertices);
  let attrib_span =
    vertex_buffer::VertexAttribData::apply(
      &[
        vertex_buffer::VertexAttribData {
          name: "vertex_position",
          size: 3,
          unit: vertex_buffer::GLType::Float,
          divisor: 0,
        },
        vertex_buffer::VertexAttribData {
          name: "texture_position",
          size: 2,
          unit: vertex_buffer::GLType::Float,
          divisor: 0,
        },
      ],
      gl,
      shader,
    );
  assert!(attrib_span == std::mem::size_of::<vertex::TextureVertex>() as u32);

  per_tuft.byte_buffer.bind(gl);
  let attrib_span =
    vertex_buffer::VertexAttribData::apply(
      &[
        vertex_buffer::VertexAttribData {
          name: "root",
          size: 3,
          unit: vertex_buffer::GLType::Float,
          divisor: 1,
        },
        vertex_buffer::VertexAttribData {
          name: "normal",
          size: 3,
          unit: vertex_buffer::GLType::Float,
          divisor: 1,
        },
        vertex_buffer::VertexAttribData {
          name: "tex_id",
          size: 3,
          unit: vertex_buffer::GLType::UInt,
          divisor: 1,
        },
      ],
      gl,
      shader,
    );
  assert!(attrib_span == std::mem::size_of::<terrain_mesh::Grass>() as u32);

  T {
    id_to_index: HashMap::new(),
    index_to_id: Vec::new(),

    gl_array: gl_array,
    _instance_vertices: instance_vertices,
    per_tuft: per_tuft,
  }
}

impl<'a> T<'a> {
  /// Add a series of entites into VRAM.
  pub fn push(
    &mut self,
    gl: &mut GLContext,
    grass: &[terrain_mesh::Grass],
    grass_ids: &[entity_id::T],
  ) {
    self.per_tuft.byte_buffer.bind(gl);
    let success: bool = self.per_tuft.push(gl, grass);
    if !success {
      panic!("Ran out of VRAM for grass");
    }

    for id in grass_ids {
      self.id_to_index.insert(*id, self.index_to_id.len());
      self.index_to_id.push(*id);
    }
  }

  // TODO: Make this take many ids as a parameter, to reduce `bind`s.
  // Note: `id` must be present in the buffers.
  /// Remove some entity from VRAM.
  pub fn swap_remove(&mut self, gl: &mut GLContext, id: entity_id::T) {
    let idx = *self.id_to_index.get(&id).unwrap();
    let swapped_id = self.index_to_id[self.index_to_id.len() - 1];
    self.index_to_id.swap_remove(idx);
    self.id_to_index.remove(&id);

    if id != swapped_id {
      self.id_to_index.insert(swapped_id, idx);
    }

    self.per_tuft.byte_buffer.bind(gl);
    self.per_tuft.swap_remove(gl, idx, 1);
  }

  pub fn draw(&self, _gl: &mut GLContext) {
    unsafe {
      gl::BindVertexArray(self.gl_array.gl_id);
      gl::DrawArraysInstanced(gl::TRIANGLES, 0, 18, self.index_to_id.len() as i32);
    }
  }
}
<|endoftext|>


<commit_before>use parking_lot::RwLock;
use std::any::Any;
use std::rc::Rc;

use super::Mode;

use crate::core::codepointinfo::CodepointInfo;
use crate::core::codepointinfo::TextStyle;

use crate::core::editor::InputStageActionMap;
use crate::core::modes::core_mode::split_with_direction;
use crate::core::Editor;
use crate::core::EditorEnv;

use crate::core::view::ContentFilter;

use crate::core::view::FilterIo;
use crate::core::view::LayoutDirection;
use crate::core::view::LayoutEnv;
use crate::core::view::LayoutOperation;

use crate::core::view::View;

use crate::core::document::DocumentBuilder;

pub struct BasicEditorMode {
    // add common fields
}
pub struct BasicEditorModeContext {
    // add per view fields
}

impl<'a> Mode for BasicEditorMode {
    fn name(&self) -> &'static str {
        &"basic-editor"
    }

    fn build_action_map(&self) -> InputStageActionMap<'static> {
        let mut map = InputStageActionMap::new();
        Self::register_input_stage_actions(&mut map);
        map
    }

    fn alloc_ctx(&self) -> Box<dyn Any> {
        dbg_println!("alloc BasicEditorMode-mode ctx");
        let ctx = BasicEditorModeContext {};
        Box::new(ctx)
    }

    fn configure_view(
        &mut self,
        mut editor: &mut Editor<'static>,
        mut env: &mut EditorEnv<'static>,
        mut view: &mut View<'static>,
    ) {
        let doc = view.document();

        let status_doc = DocumentBuilder::new()
            .document_name("")
            .internal(true)
            //           .use_buffer_log(false)
            .finalize();

        let status_doc = status_doc;

        // hsplit

        // children_layout_and_modes
        let ops_modes = vec![
            (
                LayoutOperation::Fixed {
                    size: 1 + 0, /* nano-like */
                },
                doc.clone(),
                vec![], // TODO(ceg): title-mode
            ),
            (
                LayoutOperation::RemainMinus { minus: 2 },
                doc.clone(),
                vec!["simple-view".to_owned()],
            ),
            (
                LayoutOperation::Fixed { size: 1 },
                None,
                vec!["hsplit-mode".to_owned()],
            ),
            (
                LayoutOperation::RemainPercent { p: 100.0 },
                status_doc,
                vec!["status-mode".to_owned()],
            ),
        ];

        view.layout_ops = ops_modes.iter().map(|e| e.0.clone()).collect();
        let docs = ops_modes.iter().map(|e| e.1.clone()).collect();
        let modes = ops_modes.iter().map(|e| e.2.clone()).collect();

        let (width, height) = view.dimension();
        dbg_println!("width {}  height {}", width, height);

        split_with_direction(
            &mut editor,
            &mut env,
            &mut view,
            width,
            height,
            LayoutDirection::Vertical,
            &docs,
            &modes,
        );

        // mark children as non destroyable
        for i in 0..view.children.len() {
            let vid = view.children[i];
            let v = editor.view_map.get(&vid).unwrap();
            v.write().destroyable = false;
        }

        // TODO(ceg): put some kind of label/name? on
        // like view.label = 'text-view'
        // like view.label = 'status-line'
        // view.children_by_label<String, (vid, index)>

        // set focus on text view : TODO(ceg): title mode + configure
        let title_vid = view.children[0];
        let v = editor.view_map.get(&title_vid).unwrap();
        v.write()
            .compose_content_filters
            .borrow_mut()
            .push(Box::new(BasicEditorTitle::new()));

        // set focus on text view (simple-view mode)
        view.main_child = Some(1); // index in children
        view.focus_to = Some(view.children[1]); // TODO(ceg):
        env.focus_changed_to = Some(view.children[1]); // TODO(ceg):

        // TODO(ceg): status mode + configure
        // setup status view
        let status_vid = view.children[view.children.len() - 1];
        // set status_vid
        view.status_view_id = Some(status_vid);
        env.status_view_id = Some(status_vid);
    }
}

impl BasicEditorMode {
    pub fn new() -> Self {
        dbg_println!("BasicEditorMode");
        BasicEditorMode {}
    }

    pub fn register_input_stage_actions<'a>(_map: &'a mut InputStageActionMap<'a>) {}
}

///////////////////////////////////////////////////////////////////////////////////////////////////

struct BasicEditorTitle {
    title: String,
    width: usize,
    height: usize,
}

impl BasicEditorTitle {
    pub fn new() -> Self {
        BasicEditorTitle {
            title: String::new(),
            width: 0,
            height: 0,
        }
    }
}

use crate::core::VERSION;

impl ContentFilter<'_> for BasicEditorTitle {
    fn name(&self) -> &'static str {
        &"editor-title"
    }

    fn setup(
        &mut self,
        editor: &Editor,
        env: &mut LayoutEnv,
        view: &Rc<RwLock<View>>,
        parent_view: Option<&View<'static>>,
    ) {
        self.width = env.screen.width();
        self.height = env.screen.height();

        let mut w = self.width;
        self.title = format!("unlimitED {} ", VERSION);
        w = w.saturating_sub(self.title.len());

        let view = view.read();
        let d = view.document().unwrap();
        let d = d.read();
        let mut doc_info = format!("{}", d.name);
        let dlen = doc_info.len();
        if w > dlen {
            let margin = 1; // w / 2 - dlen / 2;
            let margin = (0..margin).map(|_| " ").collect::<String>();
            self.title.push_str(&margin);
        }

        if d.changed {
            doc_info.push_str("* ");
        } else {
            doc_info.push_str("  ");
        }
        if d.is_syncing {
            doc_info.push_str(" (sync) ");
        }

        if true {
            let mut have_offset = false;
            let mut view_start_offset = 0;
            let mut view_end_offset = 0;

            if let Some(parent) = parent_view {
                if let Some(focus) = parent.focus_to {
                    if let Some(v) = editor.view_map.get(&focus) {
                        let v = &v.read();
                        view_start_offset = v.start_offset;
                        view_end_offset = v.end_offset;

                        have_offset = true;
                    }
                }
            }

            if have_offset {
                doc_info.push_str(&format!(
                    " {}-{}/{}",
                    view_start_offset,
                    view_end_offset,
                    d.size()
                ));
            } else {
                doc_info.push_str(&format!(" size {:<12}", d.size()));
                doc_info.push_str(&format!(" unknown @offset"));
            }
        }

        {
            let p_input = crate::core::event::pending_input_event_count();
            let p_rdr = crate::core::event::pending_render_event_count();
            doc_info.push_str(&format!(" pending input:{} rdr:{}", p_input, p_rdr));
        }

        self.title.push_str(&doc_info);
    }

    fn run(
        &mut self,
        _view: &View,
        env: &mut LayoutEnv,
        _filter_in: &Vec<FilterIo>,
        _filter_out: &mut Vec<FilterIo>,
    ) {
        let _bg_color = (113, 114, 123);

        let len = self.title.len();
        for c in self.title.chars() {
            let mut cpi = CodepointInfo::new();
            cpi.displayed_cp = c;
            cpi.style.color = TextStyle::default_bg_color();
            cpi.style.bg_color = TextStyle::default_color();
            let (b, _) = env.screen.push(cpi.clone());
            if !b {
                break;
            }
        }

        if len >= self.width {
            env.quit = true;
            return;
        }
        let remain = self.width - len;

        let _fill = ' ' as char;
        for _i in 0..remain {
            let mut cpi = CodepointInfo::new();
            cpi.style.color = TextStyle::default_bg_color(); // remove ?
            cpi.style.bg_color = TextStyle::default_color(); // remove ?

            let (b, _) = env.screen.push(cpi.clone());
            if !b {
                env.quit = true;
                return;
            }
        }

        env.quit = true;
    }

    fn finish(&mut self, _view: &View, _env: &mut LayoutEnv) {}
}
<commit_msg>basic editor update title bar<commit_after>use parking_lot::RwLock;
use std::any::Any;
use std::rc::Rc;

use super::Mode;

use crate::core::codepointinfo::CodepointInfo;
use crate::core::codepointinfo::TextStyle;

use crate::core::editor::InputStageActionMap;
use crate::core::modes::core_mode::split_with_direction;
use crate::core::Editor;
use crate::core::EditorEnv;

use crate::core::view::ContentFilter;

use crate::core::view::FilterIo;
use crate::core::view::LayoutDirection;
use crate::core::view::LayoutEnv;
use crate::core::view::LayoutOperation;

use crate::core::view::View;

use crate::core::document::DocumentBuilder;

pub struct BasicEditorMode {
    // add common fields
}
pub struct BasicEditorModeContext {
    // add per view fields
}

impl<'a> Mode for BasicEditorMode {
    fn name(&self) -> &'static str {
        &"basic-editor"
    }

    fn build_action_map(&self) -> InputStageActionMap<'static> {
        let mut map = InputStageActionMap::new();
        Self::register_input_stage_actions(&mut map);
        map
    }

    fn alloc_ctx(&self) -> Box<dyn Any> {
        dbg_println!("alloc BasicEditorMode-mode ctx");
        let ctx = BasicEditorModeContext {};
        Box::new(ctx)
    }

    fn configure_view(
        &mut self,
        mut editor: &mut Editor<'static>,
        mut env: &mut EditorEnv<'static>,
        mut view: &mut View<'static>,
    ) {
        let doc = view.document();

        let status_doc = DocumentBuilder::new()
            .document_name("")
            .internal(true)
            //           .use_buffer_log(false)
            .finalize();

        let status_doc = status_doc;

        // hsplit

        // children_layout_and_modes
        let ops_modes = vec![
            (
                LayoutOperation::Fixed {
                    size: 1 + 0, /* nano-like */
                },
                doc.clone(),
                vec![], // TODO(ceg): title-mode
            ),
            (
                LayoutOperation::RemainMinus { minus: 2 },
                doc.clone(),
                vec!["simple-view".to_owned()],
            ),
            (
                LayoutOperation::Fixed { size: 1 },
                None,
                vec!["hsplit-mode".to_owned()],
            ),
            (
                LayoutOperation::RemainPercent { p: 100.0 },
                status_doc,
                vec!["status-mode".to_owned()],
            ),
        ];

        view.layout_ops = ops_modes.iter().map(|e| e.0.clone()).collect();
        let docs = ops_modes.iter().map(|e| e.1.clone()).collect();
        let modes = ops_modes.iter().map(|e| e.2.clone()).collect();

        let (width, height) = view.dimension();
        dbg_println!("width {}  height {}", width, height);

        split_with_direction(
            &mut editor,
            &mut env,
            &mut view,
            width,
            height,
            LayoutDirection::Vertical,
            &docs,
            &modes,
        );

        // mark children as non destroyable
        for i in 0..view.children.len() {
            let vid = view.children[i];
            let v = editor.view_map.get(&vid).unwrap();
            v.write().destroyable = false;
        }

        // TODO(ceg): put some kind of label/name? on
        // like view.label = 'text-view'
        // like view.label = 'status-line'
        // view.children_by_label<String, (vid, index)>

        // set focus on text view : TODO(ceg): title mode + configure
        let title_vid = view.children[0];
        let v = editor.view_map.get(&title_vid).unwrap();
        v.write()
            .compose_content_filters
            .borrow_mut()
            .push(Box::new(BasicEditorTitle::new()));

        // set focus on text view (simple-view mode)
        view.main_child = Some(1); // index in children
        view.focus_to = Some(view.children[1]); // TODO(ceg):
        env.focus_changed_to = Some(view.children[1]); // TODO(ceg):

        // TODO(ceg): status mode + configure
        // setup status view
        let status_vid = view.children[view.children.len() - 1];
        // set status_vid
        view.status_view_id = Some(status_vid);
        env.status_view_id = Some(status_vid);
    }
}

impl BasicEditorMode {
    pub fn new() -> Self {
        dbg_println!("BasicEditorMode");
        BasicEditorMode {}
    }

    pub fn register_input_stage_actions<'a>(_map: &'a mut InputStageActionMap<'a>) {}
}

///////////////////////////////////////////////////////////////////////////////////////////////////

struct BasicEditorTitle {
    title: String,
    width: usize,
    height: usize,
}

impl BasicEditorTitle {
    pub fn new() -> Self {
        BasicEditorTitle {
            title: String::new(),
            width: 0,
            height: 0,
        }
    }
}

use crate::core::VERSION;

impl ContentFilter<'_> for BasicEditorTitle {
    fn name(&self) -> &'static str {
        &"editor-title"
    }

    fn setup(
        &mut self,
        editor: &Editor,
        env: &mut LayoutEnv,
        view: &Rc<RwLock<View>>,
        parent_view: Option<&View<'static>>,
    ) {
        self.width = env.screen.width();
        self.height = env.screen.height();

        let mut w = self.width;
        self.title = format!("unlimitED {} ", VERSION);
        w = w.saturating_sub(self.title.len());

        let view = view.read();
        let d = view.document().unwrap();
        let d = d.read();
        let mut doc_info = format!("{}", d.name);
        let dlen = doc_info.len();
        if w > dlen {
            let margin = 1; // w / 2 - dlen / 2;
            let margin = (0..margin).map(|_| " ").collect::<String>();
            self.title.push_str(&margin);
        }

        if d.changed {
            doc_info.push_str("* ");
        } else {
            doc_info.push_str("  ");
        }
        if d.is_syncing {
            doc_info.push_str("(sync)");
        }

        doc_info.push_str(&format!(" size {:<12}", d.size()));

        self.title.push_str(&doc_info);
    }

    fn run(
        &mut self,
        _view: &View,
        env: &mut LayoutEnv,
        _filter_in: &Vec<FilterIo>,
        _filter_out: &mut Vec<FilterIo>,
    ) {
        let _bg_color = (113, 114, 123);

        let len = self.title.len();
        for c in self.title.chars() {
            let mut cpi = CodepointInfo::new();
            cpi.displayed_cp = c;
            cpi.style.color = TextStyle::default_bg_color();
            cpi.style.bg_color = TextStyle::default_color();
            let (b, _) = env.screen.push(cpi.clone());
            if !b {
                break;
            }
        }

        if len >= self.width {
            env.quit = true;
            return;
        }
        let remain = self.width - len;

        let _fill = ' ' as char;
        for _i in 0..remain {
            let mut cpi = CodepointInfo::new();
            cpi.style.color = TextStyle::default_bg_color(); // remove ?
            cpi.style.bg_color = TextStyle::default_color(); // remove ?

            let (b, _) = env.screen.push(cpi.clone());
            if !b {
                env.quit = true;
                return;
            }
        }

        env.quit = true;
    }

    fn finish(&mut self, _view: &View, _env: &mut LayoutEnv) {}
}
<|endoftext|>


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

#![deny(missing_docs, missing_copy_implementations)]

//! Memory mapping

use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use super::{Resources, Factory};

/// Unsafe operations for a buffer mapping
pub trait Raw {
    /// Set the element at `index` to `val`. Not bounds-checked.
    unsafe fn set<T>(&self, index: usize, val: T);
    /// Returns a slice of the specified length.
    unsafe fn to_slice<T>(&self, len: usize) -> &[T];
    /// Returns a mutable slice of the specified length.
    unsafe fn to_mut_slice<T>(&self, len: usize) -> &mut [T];
}

/// A handle to a readable map, which can be sliced.
pub struct Readable<'a, T: Copy, R: 'a + Resources, F: 'a + Factory<R>> where
    F::Mapper: 'a
{
    raw: F::Mapper,
    len: usize,
    factory: &'a mut F,
    phantom_t: PhantomData<T>
}

impl<'a, T: Copy, R: Resources, F: Factory<R>> Deref for Readable<'a, T, R, F> where
    F::Mapper: 'a,
{
    type Target = [T];

    fn deref(&self) -> &[T] {
        unsafe { self.raw.to_slice(self.len) }
    }
}

impl<'a, T: Copy, R: Resources, F: Factory<R>> Drop for Readable<'a, T, R, F> where
    F::Mapper: 'a,
{
    fn drop(&mut self) {
        self.factory.unmap_buffer_raw(self.raw.clone())
    }
}

/// A handle to a writable map, which only allows setting elements.
pub struct Writable<'a, T: Copy, R: 'a + Resources, F: 'a + Factory<R>> where
    F::Mapper: 'a
{
    raw: F::Mapper,
    len: usize,
    factory: &'a mut F,
    phantom_t: PhantomData<T>
}

impl<'a, T: Copy, R: Resources, F: Factory<R>> Writable<'a, T, R, F> where
    F::Mapper: 'a
{
    /// Set a value in the buffer
    pub fn set(&mut self, idx: usize, val: T) {
        if idx >= self.len {
            panic!("Tried to write out of bounds to a WritableMapping!")
        }
        unsafe { self.raw.set(idx, val); }
    }
}

impl<'a, T: Copy, R: Resources, F: Factory<R>> Drop for Writable<'a, T, R, F> where
    F::Mapper: 'a,
{
    fn drop(&mut self) {
        self.factory.unmap_buffer_raw(self.raw.clone())
    }
}

/// A handle to a complete readable/writable map, which can be sliced both ways.
pub struct RW<'a, T: Copy, R: 'a + Resources, F: 'a + Factory<R>> where
    F::Mapper: 'a
{
    raw: F::Mapper,
    len: usize,
    factory: &'a mut F,
    phantom_t: PhantomData<T>
}

impl<'a, T: Copy, R: Resources, F: Factory<R>> Deref for RW<'a, T, R, F> where
    F::Mapper: 'a
{
    type Target = [T];

    fn deref(&self) -> &[T] {
        unsafe { self.raw.to_slice(self.len) }
    }
}

impl<'a, T: Copy, R: Resources, F: Factory<R>> DerefMut for RW<'a, T, R, F> where
    F::Mapper: 'a
{
    fn deref_mut(&mut self) -> &mut [T] {
        unsafe { self.raw.to_mut_slice(self.len) }
    }
}

impl<'a, T: Copy, R: Resources, F: Factory<R>> Drop for RW<'a, T, R, F> where
    F::Mapper: 'a
{
    fn drop(&mut self) {
        self.factory.unmap_buffer_raw(self.raw.clone())
    }
}

/// A service trait with methods for mapping already implemented.
/// To be used by device back ends.
#[allow(missing_docs)]
pub trait Builder<'a, R: Resources> {
    type RawMapping: Raw;

    fn map_readable<T: Copy>(&'a mut self, Self::RawMapping, usize) -> Readable<T, R, Self> where
        Self: Sized + Factory<R>;
    fn map_writable<T: Copy>(&'a mut self, Self::RawMapping, usize) -> Writable<T, R, Self> where
        Self: Sized + Factory<R>;
    fn map_read_write<T: Copy>(&'a mut self, Self::RawMapping, usize) -> RW<T, R, Self> where
        Self: Sized + Factory<R>;
}

impl<'a, R: Resources, F: Factory<R>> Builder<'a, R> for F where
    F::Mapper: 'a
{
    type RawMapping = F::Mapper;

    fn map_readable<T: Copy>(&'a mut self, map: F::Mapper,
                    length: usize) -> Readable<T, R, Self> {
        Readable {
            raw: map,
            len: length,
            factory: self,
            phantom_t: PhantomData,
        }
    }

    fn map_writable<T: Copy>(&'a mut self, map: F::Mapper,
                    length: usize) -> Writable<T, R, Self> {
        Writable {
            raw: map,
            len: length,
            factory: self,
            phantom_t: PhantomData,
        }
    }

    fn map_read_write<T: Copy>(&'a mut self, map: F::Mapper,
                      length: usize) -> RW<T, R, Self> {
        RW {
            raw: map,
            len: length,
            factory: self,
            phantom_t: PhantomData,
        }
    }
}
<commit_msg>Fix code which caused E0309 warnings Remove some trailing spaces from the end of trait bounds lists on fns<commit_after>// Copyright 2015 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![deny(missing_docs, missing_copy_implementations)]

//! Memory mapping

use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use super::{Resources, Factory};

/// Unsafe operations for a buffer mapping
pub trait Raw {
    /// Set the element at `index` to `val`. Not bounds-checked.
    unsafe fn set<T>(&self, index: usize, val: T);
    /// Returns a slice of the specified length.
    unsafe fn to_slice<T>(&self, len: usize) -> &[T];
    /// Returns a mutable slice of the specified length.
    unsafe fn to_mut_slice<T>(&self, len: usize) -> &mut [T];
}

/// A handle to a readable map, which can be sliced.
pub struct Readable<'a, T: Copy + 'a, R: 'a + Resources, F: 'a + Factory<R>> where
    F::Mapper: 'a
{
    raw: F::Mapper,
    len: usize,
    factory: &'a mut F,
    phantom_t: PhantomData<T>
}

impl<'a, T: Copy, R: Resources, F: Factory<R>> Deref for Readable<'a, T, R, F> where
    F::Mapper: 'a
{
    type Target = [T];

    fn deref(&self) -> &[T] {
        unsafe { self.raw.to_slice(self.len) }
    }
}

impl<'a, T: Copy, R: Resources, F: Factory<R>> Drop for Readable<'a, T, R, F> where
    F::Mapper: 'a
{
    fn drop(&mut self) {
        self.factory.unmap_buffer_raw(self.raw.clone())
    }
}

/// A handle to a writable map, which only allows setting elements.
pub struct Writable<'a, T: Copy, R: 'a + Resources, F: 'a + Factory<R>> where
    F::Mapper: 'a
{
    raw: F::Mapper,
    len: usize,
    factory: &'a mut F,
    phantom_t: PhantomData<T>
}

impl<'a, T: Copy, R: Resources, F: Factory<R>> Writable<'a, T, R, F> where
    F::Mapper: 'a
{
    /// Set a value in the buffer
    pub fn set(&mut self, idx: usize, val: T) {
        if idx >= self.len {
            panic!("Tried to write out of bounds to a WritableMapping!")
        }
        unsafe { self.raw.set(idx, val); }
    }
}

impl<'a, T: Copy, R: Resources, F: Factory<R>> Drop for Writable<'a, T, R, F> where
    F::Mapper: 'a
{
    fn drop(&mut self) {
        self.factory.unmap_buffer_raw(self.raw.clone())
    }
}

/// A handle to a complete readable/writable map, which can be sliced both ways.
pub struct RW<'a, T: Copy + 'a, R: 'a + Resources, F: 'a + Factory<R>> where
    F::Mapper: 'a
{
    raw: F::Mapper,
    len: usize,
    factory: &'a mut F,
    phantom_t: PhantomData<T>
}

impl<'a, T: Copy + 'a, R: Resources, F: Factory<R>> Deref for RW<'a, T, R, F> where
    F::Mapper: 'a
{
    type Target = [T];

    fn deref(&self) -> &[T] {
        unsafe { self.raw.to_slice(self.len) }
    }
}

impl<'a, T: Copy + 'a, R: Resources, F: Factory<R>> DerefMut for RW<'a, T, R, F> where
    F::Mapper: 'a
{
    fn deref_mut(&mut self) -> &mut [T] {
        unsafe { self.raw.to_mut_slice(self.len) }
    }
}

impl<'a, T: Copy, R: Resources, F: Factory<R>> Drop for RW<'a, T, R, F> where
    F::Mapper: 'a
{
    fn drop(&mut self) {
        self.factory.unmap_buffer_raw(self.raw.clone())
    }
}

/// A service trait with methods for mapping already implemented.
/// To be used by device back ends.
#[allow(missing_docs)]
pub trait Builder<'a, R: Resources> {
    type RawMapping: Raw;

    fn map_readable<T: Copy>(&'a mut self, Self::RawMapping, usize) -> Readable<T, R, Self> where
        Self: Sized + Factory<R>;
    fn map_writable<T: Copy>(&'a mut self, Self::RawMapping, usize) -> Writable<T, R, Self> where
        Self: Sized + Factory<R>;
    fn map_read_write<T: Copy>(&'a mut self, Self::RawMapping, usize) -> RW<T, R, Self> where
        Self: Sized + Factory<R>;
}

impl<'a, R: Resources, F: Factory<R>> Builder<'a, R> for F where
    F::Mapper: 'a
{
    type RawMapping = F::Mapper;

    fn map_readable<T: Copy>(&'a mut self, map: F::Mapper,
                    length: usize) -> Readable<T, R, Self> {
        Readable {
            raw: map,
            len: length,
            factory: self,
            phantom_t: PhantomData,
        }
    }

    fn map_writable<T: Copy>(&'a mut self, map: F::Mapper,
                    length: usize) -> Writable<T, R, Self> {
        Writable {
            raw: map,
            len: length,
            factory: self,
            phantom_t: PhantomData,
        }
    }

    fn map_read_write<T: Copy>(&'a mut self, map: F::Mapper,
                      length: usize) -> RW<T, R, Self> {
        RW {
            raw: map,
            len: length,
            factory: self,
            phantom_t: PhantomData,
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::process::Command;
use std::time::{Duration, Instant};

fn main() {
    let mut args = env::args_os().skip(1).collect::<Vec<_>>();
    let rustc = env::var_os("RUSTC_REAL").unwrap();

    if let Some(count) = env::var("RUSTC_THREAD_COUNT")
        .ok()
        .and_then(|v| v.parse::<u32>().ok())
    {
        args.push(std::ffi::OsString::from(format!("-Zthreads={}", count)));
    }

    args.push(std::ffi::OsString::from("-Adeprecated"));

    if let Some(pos) = args.iter().position(|arg| arg == "--wrap-rustc-with") {
        // Strip out the flag and its argument, and run rustc under the wrapper
        // program named by the argument.
        args.remove(pos);
        let wrapper = args.remove(pos);
        let wrapper = wrapper.to_str().unwrap();

        raise_priority();

        match wrapper {
            "perf-stat" | "perf-stat-self-profile" => {
                let mut cmd = Command::new("perf");
                let has_perf = cmd.output().is_ok();
                assert!(has_perf);
                cmd.arg("stat")
                    .arg("-x;")
                    .arg("-e")
                    .arg("instructions:u,cycles:u,task-clock,cpu-clock,faults")
                    .arg("--log-fd")
                    .arg("1")
                    .arg(&rustc)
                    .args(&args);

                let prof_out_dir = std::env::current_dir().unwrap().join("self-profile-output");
                if wrapper == "perf-stat-self-profile" {
                    cmd.arg(&format!(
                        "-Zself-profile={}",
                        prof_out_dir.to_str().unwrap()
                    ));
                    let _ = std::fs::remove_dir_all(&prof_out_dir);
                    let _ = std::fs::create_dir_all(&prof_out_dir);
                }

                let start = Instant::now();
                let status = cmd.status().expect("failed to spawn");
                let dur = start.elapsed();
                assert!(status.success());
                print_memory();
                print_time(dur);
                if wrapper == "perf-stat-self-profile" {
                    let crate_name = args
                        .windows(2)
                        .find(|args| args[0] == "--crate-name")
                        .and_then(|args| args[1].to_str())
                        .expect("rustc to be invoked with crate name");
                    let mut prefix = None;
                    // We don't know the pid of rustc, and can't easily get it -- we only know the
                    // `perf` pid. So just blindly look in the directory to hopefully find it.
                    for entry in std::fs::read_dir(&prof_out_dir).unwrap() {
                        let entry = entry.unwrap();
                        if entry
                            .file_name()
                            .to_str()
                            .map_or(false, |s| s.starts_with(crate_name))
                        {
                            let file = entry.file_name().to_str().unwrap().to_owned();
                            let new_prefix = Some(file[..file.find('.').unwrap()].to_owned());
                            assert!(
                                prefix.is_none() || prefix == new_prefix,
                                "prefix={:?}, new_prefix={:?}",
                                prefix,
                                new_prefix
                            );
                            prefix = new_prefix;
                        }
                    }
                    let prefix = prefix.expect(&format!("found prefix {:?}", prof_out_dir));
                    // FIXME: it'd be great to have a less generic name for this;
                    // we should think about renaming the binary in measureme to measureme, such
                    // that the command is `measureme summarize ...`.
                    let mut cmd = Command::new("summarize");
                    cmd.current_dir(&prof_out_dir);
                    cmd.arg("summarize").arg("--json");
                    cmd.arg(&prefix);
                    let status = cmd.status().expect(&format!(
                        "summarize spawned successfully in {:?}",
                        prof_out_dir
                    ));
                    assert!(
                        status.success(),
                        "summarize failed in {:?}; prefix is {:?}",
                        prof_out_dir,
                        prefix
                    );
                    let json =
                        std::fs::read_to_string(prof_out_dir.join(&format!("{}.json", prefix)))
                            .expect("able to read JSON output");
                    println!("!self-profile-output:{}", json);
                }
            }

            "time-passes" => {
                let mut cmd = Command::new(&rustc);
                cmd.arg("-Ztime-passes").args(&args);

                assert!(cmd.status().expect("failed to spawn").success());
            }

            "perf-record" => {
                let mut cmd = Command::new("perf");
                let has_perf = cmd.output().is_ok();
                assert!(has_perf);
                cmd.arg("record")
                    .arg("--call-graph=dwarf")
                    .arg("--output=perf")
                    .arg("--freq=99")
                    .arg(&rustc)
                    .args(&args);

                assert!(cmd.status().expect("failed to spawn").success());
            }

            "oprofile" => {
                let mut cmd = Command::new("operf");
                let has_oprofile = cmd.output().is_ok();
                assert!(has_oprofile);
                // Other possibly useful args: --callgraph, --separate-thread
                cmd.arg("operf").arg(&rustc).args(&args);

                assert!(cmd.status().expect("failed to spawn").success());
            }

            "cachegrind" => {
                let mut cmd = Command::new("valgrind");
                let has_valgrind = cmd.output().is_ok();
                assert!(has_valgrind);

                // With --cache-sim=no and --branch-sim=no, Cachegrind just
                // collects instruction counts.
                cmd.arg("--tool=cachegrind")
                    .arg("--cache-sim=no")
                    .arg("--branch-sim=no")
                    .arg("--cachegrind-out-file=cgout")
                    .arg(&rustc)
                    .args(&args);

                assert!(cmd.status().expect("failed to spawn").success());
            }

            "callgrind" => {
                let mut cmd = Command::new("valgrind");
                let has_valgrind = cmd.output().is_ok();
                assert!(has_valgrind);

                // With --cache-sim=no and --branch-sim=no, Callgrind just
                // collects instruction counts.
                cmd.arg("--tool=callgrind")
                    .arg("--cache-sim=no")
                    .arg("--branch-sim=no")
                    .arg("--callgrind-out-file=clgout")
                    .arg(&rustc)
                    .args(&args);

                assert!(cmd.status().expect("failed to spawn").success());
            }

            "exp-dhat" => {
                let mut cmd = Command::new("valgrind");
                let has_valgrind = cmd.output().is_ok();
                assert!(has_valgrind);
                cmd.arg("--tool=exp-dhat")
                    .arg("--show-top-n=500")
                    .arg("--num-callers=4")
                    .arg("--sort-by=tot-blocks-allocd")
                    .arg(&rustc)
                    .args(&args);

                assert!(cmd.status().expect("failed to spawn").success());
            }

            "dhat" => {
                let mut cmd = Command::new("valgrind");
                let has_valgrind = cmd.output().is_ok();
                assert!(has_valgrind);
                cmd.arg("--tool=dhat")
                    .arg("--num-callers=4")
                    .arg("--dhat-out-file=dhout")
                    .arg(&rustc)
                    .args(&args);

                assert!(cmd.status().expect("failed to spawn").success());
            }

            "massif" => {
                let mut cmd = Command::new("valgrind");
                let has_valgrind = cmd.output().is_ok();
                assert!(has_valgrind);
                cmd.arg("--tool=massif")
                    .arg("--heap-admin=0")
                    .arg("--depth=15")
                    .arg("--threshold=0.2")
                    .arg("--massif-out-file=msout")
                    .arg("--alloc-fn=__rdl_alloc")
                    .arg(&rustc)
                    .args(&args);

                assert!(cmd.status().expect("failed to spawn").success());
            }

            "eprintln" => {
                let mut cmd = Command::new(&rustc);
                cmd.args(&args);

                assert!(cmd.status().expect("failed to spawn").success());
            }

            _ => {
                panic!("unknown wrapper: {}", wrapper);
            }
        }
    } else {
        let mut cmd = Command::new(&rustc);
        cmd.args(&args);
        exec(&mut cmd);
    }
}

#[cfg(unix)]
fn exec(cmd: &mut Command) -> ! {
    use std::os::unix::prelude::*;
    let error = cmd.exec();
    panic!("failed to exec: {}", error);
}

#[cfg(unix)]
fn raise_priority() {
    unsafe {
        // Try to reduce jitter in wall time by increasing our priority to the
        // maximum
        for i in (1..21).rev() {
            let r = libc::setpriority(libc::PRIO_PROCESS as _, libc::getpid() as libc::id_t, -i);
            if r == 0 {
                break;
            }
        }
    }
}

#[cfg(unix)]
fn print_memory() {
    use std::mem;

    unsafe {
        let mut usage = mem::zeroed();
        let r = libc::getrusage(libc::RUSAGE_CHILDREN, &mut usage);
        if r == 0 {
            // for explanation of all the semicolons, see `print_time` below
            println!("{};;max-rss;3;100.00", usage.ru_maxrss);
        }
    }
}

fn print_time(dur: Duration) {
    // Format output the same as `perf stat` in CSV mode, explained at
    // http://man7.org/linux/man-pages/man1/perf-stat.1.html#CSV_FORMAT
    //
    // tl;dr; it's:
    //
    //      $value ; $unit ; $name ; $runtime ; $pct
    println!(
        "{}.{:09};;wall-time;4;100.00",
        dur.as_secs(),
        dur.subsec_nanos()
    );
}

#[cfg(windows)]
fn raise_priority() {}

#[cfg(windows)]
fn print_memory() {}
<commit_msg>Print out failed command in rustc-fake<commit_after>use std::env;
use std::process::Command;
use std::time::{Duration, Instant};

fn main() {
    let mut args = env::args_os().skip(1).collect::<Vec<_>>();
    let rustc = env::var_os("RUSTC_REAL").unwrap();

    if let Some(count) = env::var("RUSTC_THREAD_COUNT")
        .ok()
        .and_then(|v| v.parse::<u32>().ok())
    {
        args.push(std::ffi::OsString::from(format!("-Zthreads={}", count)));
    }

    args.push(std::ffi::OsString::from("-Adeprecated"));

    if let Some(pos) = args.iter().position(|arg| arg == "--wrap-rustc-with") {
        // Strip out the flag and its argument, and run rustc under the wrapper
        // program named by the argument.
        args.remove(pos);
        let wrapper = args.remove(pos);
        let wrapper = wrapper.to_str().unwrap();

        raise_priority();

        match wrapper {
            "perf-stat" | "perf-stat-self-profile" => {
                let mut cmd = Command::new("perf");
                let has_perf = cmd.output().is_ok();
                assert!(has_perf);
                cmd.arg("stat")
                    .arg("-x;")
                    .arg("-e")
                    .arg("instructions:u,cycles:u,task-clock,cpu-clock,faults")
                    .arg("--log-fd")
                    .arg("1")
                    .arg(&rustc)
                    .args(&args);

                let prof_out_dir = std::env::current_dir().unwrap().join("self-profile-output");
                if wrapper == "perf-stat-self-profile" {
                    cmd.arg(&format!(
                        "-Zself-profile={}",
                        prof_out_dir.to_str().unwrap()
                    ));
                    let _ = std::fs::remove_dir_all(&prof_out_dir);
                    let _ = std::fs::create_dir_all(&prof_out_dir);
                }

                let start = Instant::now();
                let status = cmd.status().expect("failed to spawn");
                let dur = start.elapsed();
                assert!(status.success());
                print_memory();
                print_time(dur);
                if wrapper == "perf-stat-self-profile" {
                    let crate_name = args
                        .windows(2)
                        .find(|args| args[0] == "--crate-name")
                        .and_then(|args| args[1].to_str())
                        .expect("rustc to be invoked with crate name");
                    let mut prefix = None;
                    // We don't know the pid of rustc, and can't easily get it -- we only know the
                    // `perf` pid. So just blindly look in the directory to hopefully find it.
                    for entry in std::fs::read_dir(&prof_out_dir).unwrap() {
                        let entry = entry.unwrap();
                        if entry
                            .file_name()
                            .to_str()
                            .map_or(false, |s| s.starts_with(crate_name))
                        {
                            let file = entry.file_name().to_str().unwrap().to_owned();
                            let new_prefix = Some(file[..file.find('.').unwrap()].to_owned());
                            assert!(
                                prefix.is_none() || prefix == new_prefix,
                                "prefix={:?}, new_prefix={:?}",
                                prefix,
                                new_prefix
                            );
                            prefix = new_prefix;
                        }
                    }
                    let prefix = prefix.expect(&format!("found prefix {:?}", prof_out_dir));
                    // FIXME: it'd be great to have a less generic name for this;
                    // we should think about renaming the binary in measureme to measureme, such
                    // that the command is `measureme summarize ...`.
                    let mut cmd = Command::new("summarize");
                    cmd.current_dir(&prof_out_dir);
                    cmd.arg("summarize").arg("--json");
                    cmd.arg(&prefix);
                    let status = cmd.status().expect(&format!(
                        "summarize spawned successfully in {:?}",
                        prof_out_dir
                    ));
                    assert!(
                        status.success(),
                        "summarize failed in {:?}; prefix is {:?}",
                        prof_out_dir,
                        prefix
                    );
                    let json =
                        std::fs::read_to_string(prof_out_dir.join(&format!("{}.json", prefix)))
                            .expect("able to read JSON output");
                    println!("!self-profile-output:{}", json);
                }
            }

            "time-passes" => {
                let mut cmd = Command::new(&rustc);
                cmd.arg("-Ztime-passes").args(&args);

                assert!(cmd.status().expect("failed to spawn").success());
            }

            "perf-record" => {
                let mut cmd = Command::new("perf");
                let has_perf = cmd.output().is_ok();
                assert!(has_perf);
                cmd.arg("record")
                    .arg("--call-graph=dwarf")
                    .arg("--output=perf")
                    .arg("--freq=99")
                    .arg(&rustc)
                    .args(&args);

                assert!(cmd.status().expect("failed to spawn").success());
            }

            "oprofile" => {
                let mut cmd = Command::new("operf");
                let has_oprofile = cmd.output().is_ok();
                assert!(has_oprofile);
                // Other possibly useful args: --callgraph, --separate-thread
                cmd.arg("operf").arg(&rustc).args(&args);

                assert!(cmd.status().expect("failed to spawn").success());
            }

            "cachegrind" => {
                let mut cmd = Command::new("valgrind");
                let has_valgrind = cmd.output().is_ok();
                assert!(has_valgrind);

                // With --cache-sim=no and --branch-sim=no, Cachegrind just
                // collects instruction counts.
                cmd.arg("--tool=cachegrind")
                    .arg("--cache-sim=no")
                    .arg("--branch-sim=no")
                    .arg("--cachegrind-out-file=cgout")
                    .arg(&rustc)
                    .args(&args);

                assert!(cmd.status().expect("failed to spawn").success());
            }

            "callgrind" => {
                let mut cmd = Command::new("valgrind");
                let has_valgrind = cmd.output().is_ok();
                assert!(has_valgrind);

                // With --cache-sim=no and --branch-sim=no, Callgrind just
                // collects instruction counts.
                cmd.arg("--tool=callgrind")
                    .arg("--cache-sim=no")
                    .arg("--branch-sim=no")
                    .arg("--callgrind-out-file=clgout")
                    .arg(&rustc)
                    .args(&args);

                assert!(cmd.status().expect("failed to spawn").success());
            }

            "exp-dhat" => {
                let mut cmd = Command::new("valgrind");
                let has_valgrind = cmd.output().is_ok();
                assert!(has_valgrind);
                cmd.arg("--tool=exp-dhat")
                    .arg("--show-top-n=500")
                    .arg("--num-callers=4")
                    .arg("--sort-by=tot-blocks-allocd")
                    .arg(&rustc)
                    .args(&args);

                assert!(cmd.status().expect("failed to spawn").success());
            }

            "dhat" => {
                let mut cmd = Command::new("valgrind");
                let has_valgrind = cmd.output().is_ok();
                assert!(has_valgrind);
                cmd.arg("--tool=dhat")
                    .arg("--num-callers=4")
                    .arg("--dhat-out-file=dhout")
                    .arg(&rustc)
                    .args(&args);

                assert!(cmd.status().expect("failed to spawn").success());
            }

            "massif" => {
                let mut cmd = Command::new("valgrind");
                let has_valgrind = cmd.output().is_ok();
                assert!(has_valgrind);
                cmd.arg("--tool=massif")
                    .arg("--heap-admin=0")
                    .arg("--depth=15")
                    .arg("--threshold=0.2")
                    .arg("--massif-out-file=msout")
                    .arg("--alloc-fn=__rdl_alloc")
                    .arg(&rustc)
                    .args(&args);

                assert!(cmd.status().expect("failed to spawn").success());
            }

            "eprintln" => {
                let mut cmd = Command::new(&rustc);
                cmd.args(&args);

                assert!(cmd.status().expect("failed to spawn").success());
            }

            _ => {
                panic!("unknown wrapper: {}", wrapper);
            }
        }
    } else {
        let mut cmd = Command::new(&rustc);
        cmd.args(&args);
        exec(&mut cmd);
    }
}

#[cfg(unix)]
fn exec(cmd: &mut Command) -> ! {
    use std::os::unix::prelude::*;
    let cmd_d = format!("{:?}", cmd);
    let error = cmd.exec();
    panic!("failed to exec `{}`: {}", cmd_d, error);
}

#[cfg(unix)]
fn raise_priority() {
    unsafe {
        // Try to reduce jitter in wall time by increasing our priority to the
        // maximum
        for i in (1..21).rev() {
            let r = libc::setpriority(libc::PRIO_PROCESS as _, libc::getpid() as libc::id_t, -i);
            if r == 0 {
                break;
            }
        }
    }
}

#[cfg(unix)]
fn print_memory() {
    use std::mem;

    unsafe {
        let mut usage = mem::zeroed();
        let r = libc::getrusage(libc::RUSAGE_CHILDREN, &mut usage);
        if r == 0 {
            // for explanation of all the semicolons, see `print_time` below
            println!("{};;max-rss;3;100.00", usage.ru_maxrss);
        }
    }
}

fn print_time(dur: Duration) {
    // Format output the same as `perf stat` in CSV mode, explained at
    // http://man7.org/linux/man-pages/man1/perf-stat.1.html#CSV_FORMAT
    //
    // tl;dr; it's:
    //
    //      $value ; $unit ; $name ; $runtime ; $pct
    println!(
        "{}.{:09};;wall-time;4;100.00",
        dur.as_secs(),
        dur.subsec_nanos()
    );
}

#[cfg(windows)]
fn raise_priority() {}

#[cfg(windows)]
fn print_memory() {}
<|endoftext|>


<commit_before>extern crate algebra;

use std::mem::swap;
use std::fmt::{Display, Formatter, Error};

use algebra::ops::{Additive, Multiplicative, Inverse, inv};
use algebra::cmp::ApproxEq;
use algebra::structure::*;
use algebra::wrapper::Wrapper as W;
use algebra::wrapper::id as wrap_id;
use algebra::ident::{Identity, id};

#[derive(PartialEq, Clone)]
struct Vec2<Scalar: FieldApprox> {
    x: Scalar,
    y: Scalar,
}

impl<Scalar: FieldApprox> Vec2<Scalar> {
    fn new(x: Scalar, y: Scalar) -> Vec2<Scalar> {
        Vec2 {
            x: x,
            y: y,
        }
    }
}

impl<Scalar: FieldApprox + Display> Display for Vec2<Scalar> {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        fmt.write_fmt(format_args!("({}, {})", self.x, self.y))
    }
}

impl<Scalar: FieldApprox> ApproxEq for Vec2<Scalar> {
    type Eps = Scalar::Eps;

    fn default_epsilon() -> Self::Eps {
        Scalar::default_epsilon()
    }

    fn approx_eq_eps(&self, b: &Self, epsilon: &Self::Eps) -> bool {
        self.x.approx_eq_eps(&b.x, epsilon) &&
        self.y.approx_eq_eps(&b.y, epsilon)
    }
}

impl<Scalar: FieldApprox> MagmaApprox<Additive> for Vec2<Scalar> {
    fn approx(mut self, lhs: Self) -> Self {
        self.x = self.x.ap(Additive, lhs.x);
        self.y = self.y.ap(Additive, lhs.y);
        self
    }
}

impl<Scalar: FieldApprox> Inverse<Additive> for Vec2<Scalar> {
    fn inv(mut self) -> Self {
        self.x = inv(Additive, self.x);
        self.y = inv(Additive, self.y);
        self
    }
}

impl<Scalar: FieldApprox> Identity<Additive> for Vec2<Scalar> {
    fn id() -> Self {
        Vec2 {
            x: id(Additive),
            y: id(Additive),
        }
    }
}

impl<Scalar: FieldApprox> QuasigroupApprox<Additive> for Vec2<Scalar> {}
impl<Scalar: FieldApprox> LoopApprox<Additive> for Vec2<Scalar> {}

impl<Scalar: FieldApprox> SemigroupApprox<Additive> for Vec2<Scalar> {}
impl<Scalar: FieldApprox> MonoidApprox<Additive> for Vec2<Scalar> {}

impl<Scalar: FieldApprox> GroupApprox<Additive> for Vec2<Scalar> {}
impl<Scalar: FieldApprox> GroupAbelianApprox<Additive> for Vec2<Scalar> {}

impl<Scalar: FieldApprox> ModuleApprox<Scalar> for Vec2<Scalar> {}
impl<Scalar: FieldApprox> VectorApprox<Scalar> for Vec2<Scalar> {}

impl<Scalar: FieldApprox> MagmaApprox<Multiplicative> for Vec2<Scalar> {
    fn approx(mut self, lhs: Self) -> Self {
        self.x = self.x.ap(Multiplicative, lhs.x);
        self.y = self.y.ap(Multiplicative, lhs.y);
        self
    }
}

impl<Scalar: FieldApprox> Identity<Multiplicative> for Vec2<Scalar> {
    fn id() -> Self {
        Vec2 {
            x: id(Multiplicative),
            y: id(Multiplicative),
        }
    }
}

fn gcd<T: RingCommutativeApprox + PartialOrd>(a: T, b: T) -> T {
    let (mut a, mut b) = (W(a), W(b));
    if a < wrap_id(Additive) {
        a = -a;
    }
    if b < wrap_id(Multiplicative) {
        b = -b;
    }
    while a != b {
        if a > b {
            a = a - b.clone();
        } else {
            b = b - a.clone();
        }
    }
    a.0
}

#[test]
fn gcd_works() {
    assert_eq!(2, gcd(8, 6));
    assert_eq!(2, gcd(6, 8));
    assert_eq!(3, gcd(15, 6));
    assert_eq!(3, gcd(6, 15));
    assert_eq!(1, gcd(17, 12345));
    assert_eq!(1, gcd(42312, 17));
    println!("1");
    assert_eq!(5, gcd(15, -35));
    println!("2");
    assert_eq!(5, gcd(-15, 35));
    println!("3");
    assert_eq!(5, gcd(-15, -35));
    println!("4");
}

#[derive(Clone)]
struct Rational {
    a: i64,
    b: i64,
}

impl Rational {
    fn new(a: i64, b: i64) -> Self {
        assert!(b != 0);
        Rational {
            a: a,
            b: b,
        }
    }

    fn whole(n: i64) -> Self {
        Rational {
            a: n,
            b: 1,
        }
    }
}

impl Display for Rational {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        if self.b == 1 {
            fmt.write_fmt(format_args!("{}", self.a))
        } else {
            fmt.write_fmt(format_args!("{}⁄{}", self.a, self.b))
        }
    }
}

impl PartialEq for Rational {
    fn eq(&self, lhs: &Self) -> bool {
        self.a * lhs.b == lhs.a * self.b
    }
}

impl ApproxEq for Rational {
    type Eps = f64;

    fn default_epsilon() -> Self::Eps {
        0.
    }

    fn approx_eq_eps(&self, b: &Self, epsilon: &Self::Eps) -> bool {
        let us = self.a as f64 / self.b as f64;
        let them = b.a as f64 / b.b as f64;
        (us - them).abs() <= *epsilon
    }
}

impl MagmaApprox<Additive> for Rational {
    fn approx(mut self, lhs: Self) -> Self {
        self.a = self.a * lhs.b + lhs.a * self.b;
        self.b *= lhs.b;
        let gcd = gcd(self.a, self.b);
        self.a /= gcd;
        self.b /= gcd;
        self
    }
}

impl Inverse<Additive> for Rational {
    fn inv(mut self) -> Self {
        self.a = -self.a;
        self.b = self.b;
        self
    }
}

impl Identity<Additive> for Rational {
    fn id() -> Self {
        Rational {
            a: 0,
            b: 1,
        }
    }
}

impl QuasigroupApprox<Additive> for Rational {}
impl LoopApprox<Additive> for Rational {}

impl SemigroupApprox<Additive> for Rational {}
impl MonoidApprox<Additive> for Rational {}

impl GroupApprox<Additive> for Rational {}
impl GroupAbelianApprox<Additive> for Rational {}

impl MagmaApprox<Multiplicative> for Rational {
    fn approx(mut self, lhs: Self) -> Self {
        self.a *= lhs.a;
        self.b *= lhs.b;
        let gcd = gcd(self.a, self.b);
        self.a /= gcd;
        self.b /= gcd;
        self
    }
}

impl Inverse<Multiplicative> for Rational {
    fn inv(mut self) -> Self {
        swap(&mut self.a, &mut self.b);
        self
    }
}

impl Identity<Multiplicative> for Rational {
    fn id() -> Self {
        Rational {
            a: 1,
            b: 1,
        }
    }
}

impl QuasigroupApprox<Multiplicative> for Rational {}
impl LoopApprox<Multiplicative> for Rational {}

impl SemigroupApprox<Multiplicative> for Rational {}
impl MonoidApprox<Multiplicative> for Rational {}

impl GroupApprox<Multiplicative> for Rational {}
impl GroupAbelianApprox<Multiplicative> for Rational {}

impl RingApprox for Rational {}
impl RingCommutativeApprox for Rational {}
impl FieldApprox for Rational {}

fn main() {
    let vec = || W(Vec2::new(Rational::new(1, 2), Rational::whole(3)));
    let vec2 = || W(Vec2::new(Rational::whole(5), Rational::new(11, 7)));
    let vec3 = || W(Vec2::new(Rational::new(7, 11), Rational::whole(17)));

    let vec4 = (vec() * vec2()) + (vec() * vec3());
    let vec5 = vec() * (vec2() + vec3());
    if vec4.approx_eq(&vec5) {
        println!("{} == {}", vec4, vec5);
    } else {
        println!("{} != {}", vec4, vec5);
    }
}
<commit_msg>Fixed example. Removed leftover debug prints from example.<commit_after>extern crate algebra;

use std::mem::swap;
use std::fmt::{Display, Formatter, Error};

use algebra::ops::{Additive, Multiplicative, Inverse, inv};
use algebra::cmp::ApproxEq;
use algebra::structure::*;
use algebra::wrapper::Wrapper as W;
use algebra::wrapper::id as wrap_id;
use algebra::ident::{Identity, id};

#[derive(PartialEq, Clone)]
struct Vec2<Scalar: FieldApprox> {
    x: Scalar,
    y: Scalar,
}

impl<Scalar: FieldApprox> Vec2<Scalar> {
    fn new(x: Scalar, y: Scalar) -> Vec2<Scalar> {
        Vec2 {
            x: x,
            y: y,
        }
    }
}

impl<Scalar: FieldApprox + Display> Display for Vec2<Scalar> {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        fmt.write_fmt(format_args!("({}, {})", self.x, self.y))
    }
}

impl<Scalar: FieldApprox> ApproxEq for Vec2<Scalar> {
    type Eps = Scalar::Eps;

    fn default_epsilon() -> Self::Eps {
        Scalar::default_epsilon()
    }

    fn approx_eq_eps(&self, b: &Self, epsilon: &Self::Eps) -> bool {
        self.x.approx_eq_eps(&b.x, epsilon) &&
        self.y.approx_eq_eps(&b.y, epsilon)
    }
}

impl<Scalar: FieldApprox> MagmaApprox<Additive> for Vec2<Scalar> {
    fn approx(mut self, lhs: Self) -> Self {
        self.x = self.x.ap(Additive, lhs.x);
        self.y = self.y.ap(Additive, lhs.y);
        self
    }
}

impl<Scalar: FieldApprox> Inverse<Additive> for Vec2<Scalar> {
    fn inv(mut self) -> Self {
        self.x = inv(Additive, self.x);
        self.y = inv(Additive, self.y);
        self
    }
}

impl<Scalar: FieldApprox> Identity<Additive> for Vec2<Scalar> {
    fn id() -> Self {
        Vec2 {
            x: id(Additive),
            y: id(Additive),
        }
    }
}

impl<Scalar: FieldApprox> QuasigroupApprox<Additive> for Vec2<Scalar> {}
impl<Scalar: FieldApprox> LoopApprox<Additive> for Vec2<Scalar> {}

impl<Scalar: FieldApprox> SemigroupApprox<Additive> for Vec2<Scalar> {}
impl<Scalar: FieldApprox> MonoidApprox<Additive> for Vec2<Scalar> {}

impl<Scalar: FieldApprox> GroupApprox<Additive> for Vec2<Scalar> {}
impl<Scalar: FieldApprox> GroupAbelianApprox<Additive> for Vec2<Scalar> {}

impl<Scalar: FieldApprox> ModuleApprox<Scalar> for Vec2<Scalar> {}
impl<Scalar: FieldApprox> VectorSpaceApprox<Scalar> for Vec2<Scalar> {}

impl<Scalar: FieldApprox> MagmaApprox<Multiplicative> for Vec2<Scalar> {
    fn approx(mut self, lhs: Self) -> Self {
        self.x = self.x.ap(Multiplicative, lhs.x);
        self.y = self.y.ap(Multiplicative, lhs.y);
        self
    }
}

impl<Scalar: FieldApprox> Identity<Multiplicative> for Vec2<Scalar> {
    fn id() -> Self {
        Vec2 {
            x: id(Multiplicative),
            y: id(Multiplicative),
        }
    }
}

fn gcd<T: RingCommutativeApprox + PartialOrd>(a: T, b: T) -> T {
    let (mut a, mut b) = (W(a), W(b));
    if a < wrap_id(Additive) {
        a = -a;
    }
    if b < wrap_id(Multiplicative) {
        b = -b;
    }
    while a != b {
        if a > b {
            a = a - b.clone();
        } else {
            b = b - a.clone();
        }
    }
    a.0
}

#[test]
fn gcd_works() {
    assert_eq!(2, gcd(8, 6));
    assert_eq!(2, gcd(6, 8));
    assert_eq!(3, gcd(15, 6));
    assert_eq!(3, gcd(6, 15));
    assert_eq!(1, gcd(17, 12345));
    assert_eq!(1, gcd(42312, 17));
    assert_eq!(5, gcd(15, -35));
    assert_eq!(5, gcd(-15, 35));
    assert_eq!(5, gcd(-15, -35));
}

#[derive(Clone)]
struct Rational {
    a: i64,
    b: i64,
}

impl Rational {
    fn new(a: i64, b: i64) -> Self {
        assert!(b != 0);
        Rational {
            a: a,
            b: b,
        }
    }

    fn whole(n: i64) -> Self {
        Rational {
            a: n,
            b: 1,
        }
    }
}

impl Display for Rational {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        if self.b == 1 {
            fmt.write_fmt(format_args!("{}", self.a))
        } else {
            fmt.write_fmt(format_args!("{}⁄{}", self.a, self.b))
        }
    }
}

impl PartialEq for Rational {
    fn eq(&self, lhs: &Self) -> bool {
        self.a * lhs.b == lhs.a * self.b
    }
}

impl ApproxEq for Rational {
    type Eps = f64;

    fn default_epsilon() -> Self::Eps {
        0.
    }

    fn approx_eq_eps(&self, b: &Self, epsilon: &Self::Eps) -> bool {
        let us = self.a as f64 / self.b as f64;
        let them = b.a as f64 / b.b as f64;
        (us - them).abs() <= *epsilon
    }
}

impl MagmaApprox<Additive> for Rational {
    fn approx(mut self, lhs: Self) -> Self {
        self.a = self.a * lhs.b + lhs.a * self.b;
        self.b *= lhs.b;
        let gcd = gcd(self.a, self.b);
        self.a /= gcd;
        self.b /= gcd;
        self
    }
}

impl Inverse<Additive> for Rational {
    fn inv(mut self) -> Self {
        self.a = -self.a;
        self.b = self.b;
        self
    }
}

impl Identity<Additive> for Rational {
    fn id() -> Self {
        Rational {
            a: 0,
            b: 1,
        }
    }
}

impl QuasigroupApprox<Additive> for Rational {}
impl LoopApprox<Additive> for Rational {}

impl SemigroupApprox<Additive> for Rational {}
impl MonoidApprox<Additive> for Rational {}

impl GroupApprox<Additive> for Rational {}
impl GroupAbelianApprox<Additive> for Rational {}

impl MagmaApprox<Multiplicative> for Rational {
    fn approx(mut self, lhs: Self) -> Self {
        self.a *= lhs.a;
        self.b *= lhs.b;
        let gcd = gcd(self.a, self.b);
        self.a /= gcd;
        self.b /= gcd;
        self
    }
}

impl Inverse<Multiplicative> for Rational {
    fn inv(mut self) -> Self {
        swap(&mut self.a, &mut self.b);
        self
    }
}

impl Identity<Multiplicative> for Rational {
    fn id() -> Self {
        Rational {
            a: 1,
            b: 1,
        }
    }
}

impl QuasigroupApprox<Multiplicative> for Rational {}
impl LoopApprox<Multiplicative> for Rational {}

impl SemigroupApprox<Multiplicative> for Rational {}
impl MonoidApprox<Multiplicative> for Rational {}

impl GroupApprox<Multiplicative> for Rational {}
impl GroupAbelianApprox<Multiplicative> for Rational {}

impl RingApprox for Rational {}
impl RingCommutativeApprox for Rational {}
impl FieldApprox for Rational {}

fn main() {
    let vec = || W(Vec2::new(Rational::new(1, 2), Rational::whole(3)));
    let vec2 = || W(Vec2::new(Rational::whole(5), Rational::new(11, 7)));
    let vec3 = || W(Vec2::new(Rational::new(7, 11), Rational::whole(17)));

    let vec4 = (vec() * vec2()) + (vec() * vec3());
    let vec5 = vec() * (vec2() + vec3());
    if vec4.approx_eq(&vec5) {
        println!("{} == {}", vec4, vec5);
    } else {
        println!("{} != {}", vec4, vec5);
    }
}
<|endoftext|>


<commit_before>use std::slice;

use crate::stash::Stash;
use crate::batched_vec::BatchedVecRef;

macro_rules! per_cache_line {
    ($t:ty) => {{ ::std::cmp::max(64 / ::std::mem::size_of::<$t>(), 4) }}
}

pub struct SWCBuffer<T> {
    staged: Vec<T>,
    counts: [u8; 256],
}

impl<T> SWCBuffer<T> {

    pub fn new() -> Self {
        let staged = Vec::with_capacity(256 * per_cache_line!(T));
        let addr: usize = unsafe { ::std::mem::transmute(staged.as_ptr()) };

        // looks like this is often cache-line aligned; yay!
        assert_eq!(addr % 64, 0);

        SWCBuffer {
            staged: staged,
            counts: [0u8; 256],
        }
    }

    #[inline]
    pub fn slice(&self, byte: usize) -> &[T] {
        unsafe {
            slice::from_raw_parts(
                self.staged.as_ptr().offset(per_cache_line!(T) as isize * byte as isize),
                *self.counts.get_unchecked(byte) as usize
            )
        }
    }

    #[inline]
    pub fn full(&self, byte: usize) -> bool {
        unsafe { (*self.counts.get_unchecked(byte) as usize) == per_cache_line!(T) }
    }

    #[inline]
    pub fn count(&self, byte: usize) -> usize {
        unsafe { *self.counts.get_unchecked(byte) as usize }
    }

    #[inline]
    pub fn push(&mut self, element: T, byte: usize) {
        unsafe {
            let offset = per_cache_line!(T) as isize * byte as isize + *self.counts.get_unchecked(byte as usize) as isize;
            ::std::ptr::write(self.staged.as_mut_ptr().offset(offset), element);
            *self.counts.get_unchecked_mut(byte) += 1;
        }
    }

    #[inline]
    pub fn drain_into<'a>(&mut self, byte: usize, batch: &mut BatchedVecRef<'a, T>, stash: &mut Stash<T>) where T: 'a {
        unsafe {
            if *self.counts.get_unchecked(byte) > 0 {
                batch.push_all(self.slice(byte), stash);
                *self.counts.get_unchecked_mut(byte) = 0;
            }
        }
    }

    #[inline]
    pub fn drain_into_vec(&mut self, byte: usize, batch: &mut Vec<T>, _stash: &mut Stash<T>) {
        unsafe {
            for i in 0 .. *self.counts.get_unchecked(byte) {
                batch.push(::std::ptr::read(self.staged.as_mut_ptr().offset(per_cache_line!(T) as isize * byte as isize + i as isize)));
            }
            *self.counts.get_unchecked_mut(byte) = 0;
        }
    }
}
<commit_msg>sort: guarantee rather than assume cache aligned allocations<commit_after>use std::slice;

use crate::stash::Stash;
use crate::batched_vec::BatchedVecRef;

macro_rules! per_cache_line {
    ($t:ty) => {{ ::std::cmp::max(64 / ::std::mem::size_of::<$t>(), 4) }}
}

#[repr(align(64))]
pub struct CacheLine([u8; 64]);

pub struct SWCBuffer<T> {
    counts: [u8; 256],
    staged: Vec<CacheLine>,
    phantom: std::marker::PhantomData<T>,
}

impl<T> SWCBuffer<T> {

    pub fn new() -> Self {
        let nlines = (256 * per_cache_line!(T) * std::mem::size_of::<T>()) / 64;
        let staged = Vec::<CacheLine>::with_capacity(nlines);

        // verify cache alignment
        let addr = staged.as_ptr() as usize;
        assert_eq!(addr % 64, 0);

        SWCBuffer {
            staged: staged,
            counts: [0u8; 256],
            phantom: std::marker::PhantomData,
        }
    }

    fn staged_ptr(&self) -> *const T {
        self.staged.as_ptr() as _
    }

    fn staged_mut_ptr(&mut self) -> *mut T {
        self.staged.as_mut_ptr() as _
    }

    #[inline]
    pub fn slice(&self, byte: usize) -> &[T] {
        unsafe {
            slice::from_raw_parts(
                self.staged_ptr().offset(per_cache_line!(T) as isize * byte as isize),
                *self.counts.get_unchecked(byte) as usize
            )
        }
    }

    #[inline]
    pub fn full(&self, byte: usize) -> bool {
        unsafe { (*self.counts.get_unchecked(byte) as usize) == per_cache_line!(T) }
    }

    #[inline]
    pub fn count(&self, byte: usize) -> usize {
        unsafe { *self.counts.get_unchecked(byte) as usize }
    }

    #[inline]
    pub fn push(&mut self, element: T, byte: usize) {
        unsafe {
            let offset = per_cache_line!(T) as isize * byte as isize + *self.counts.get_unchecked(byte as usize) as isize;
            ::std::ptr::write(self.staged_mut_ptr().offset(offset), element);
            *self.counts.get_unchecked_mut(byte) += 1;
        }
    }

    #[inline]
    pub fn drain_into<'a>(&mut self, byte: usize, batch: &mut BatchedVecRef<'a, T>, stash: &mut Stash<T>) where T: 'a {
        unsafe {
            if *self.counts.get_unchecked(byte) > 0 {
                batch.push_all(self.slice(byte), stash);
                *self.counts.get_unchecked_mut(byte) = 0;
            }
        }
    }

    #[inline]
    pub fn drain_into_vec(&mut self, byte: usize, batch: &mut Vec<T>, _stash: &mut Stash<T>) {
        unsafe {
            for i in 0 .. *self.counts.get_unchecked(byte) {
                batch.push(::std::ptr::read(self.staged_mut_ptr().offset(per_cache_line!(T) as isize * byte as isize + i as isize)));
            }
            *self.counts.get_unchecked_mut(byte) = 0;
        }
    }
}
<|endoftext|>