<commit_before>//! Convert sdf files to other formats.

use std::iter::repeat;
use std::path::Path;

use peakbag::{PeakDetector, Peak};
use sdc;

use Result;
use error::Error;
use file::{Block, Channel, File, FileInfo, Record};

const HIGH_WIDTH: usize = 2;
const HIGH_FLOOR: u16 = 15;
const HIGH_CEILING: u16 = 255;
const LOW_WIDTHS: (usize, usize) = (3, 2);
const LOW_FLOOR: u16 = 15;
const LOW_CEILINGS: (u16, u16) = (250, 255); // heh
const MIN_HEIGHT_ABOVE_BACKGROUND: f64 = 5.0;
const MAX_KURTOSIS: f64 = 0.04;

/// Turns a single sdf record into zero or more `Point`s.
///
/// At this point, we assume that the timestamps are absolute. TODO make this smarter to handle the
/// case when the user has called `File::set_sosbl_mode(SosblMode::Relative)`.
///
/// # Panics
///
/// Panics if there are zero or more than one reference blocks in the record.
///
/// # Examples
///
/// ```
/// use sdf::convert::discretize;
/// use sdf::file::File;
/// let mut file = File::open("data/110630_174316.sdf").unwrap();
/// let ref file_info = file.info().unwrap();
/// file.reindex().unwrap();
/// let ref record = file.read().unwrap();
/// let points = discretize(record, file_info).unwrap();
/// ```
pub fn discretize(record: &Record, file_info: &FileInfo) -> Result<Vec<Point>> {
    let mut high_blocks = Vec::new();
    let mut low_blocks = Vec::new();
    let mut reference_block = None;
    for block in &record.blocks {
        match block.channel {
            Channel::High => high_blocks.push(block),
            Channel::Low => low_blocks.push(block),
            Channel::Reference => {
                if reference_block.is_some() {
                    panic!("More than one reference block in this record");
                } else {
                    reference_block = Some(block);
                }
            }
            _ => {}
        }
    }
    let reference_block = reference_block.unwrap();
    let high_detector = PeakDetector::new(HIGH_WIDTH, HIGH_FLOOR, HIGH_CEILING)
                            .min_height_above_background(MIN_HEIGHT_ABOVE_BACKGROUND)
                            .max_kurtosis(MAX_KURTOSIS);
    let (low_width, low_ceiling) = match high_blocks.len() {
        0 => (LOW_WIDTHS.0, LOW_CEILINGS.0),
        _ => (LOW_WIDTHS.1, LOW_CEILINGS.1),
    };
    let low_detector = PeakDetector::new(low_width, LOW_FLOOR, low_ceiling)
                           .min_height_above_background(MIN_HEIGHT_ABOVE_BACKGROUND)
                           .max_kurtosis(MAX_KURTOSIS)
                           .saturation(LOW_CEILINGS.1);
    let reference_detector = high_detector;

    let reference_peaks = reference_detector.detect_peaks(&reference_block.samples[..]);
    if reference_peaks.len() != 1 {
        debug!("Could not get a single reference peak out of: {:?}",
               reference_block.samples);
        return Err(Error::NeedSingleReferencePeak(reference_peaks.len()));
    }
    let ref reference_peak = reference_peaks[0];

    let timestamp = |peak: &Peak<_>, block: &Block| {
        block.time_sosbl + peak.index as f64 * file_info.sampling_time
    };

    let t_ref = timestamp(reference_peak, &reference_block);

    let mut points = Vec::new();
    for (block, detector) in low_blocks.iter()
                                       .zip(repeat(low_detector))
                                       .chain(high_blocks.iter().zip(repeat(high_detector))) {
        let peaks = detector.detect_peaks(&block.samples[..]);
        let num_target = peaks.len();
        for (i, peak) in peaks.into_iter().enumerate() {
            let time = timestamp(&peak, block);
            let range = file_info.v_group / 2.0 * (time - t_ref);
            // x is straight out of the scanner, and the mirror pans it along the
            // z axis.
            let theta = (record.direction[2] / record.direction[0])
                            .atan()
                            .to_degrees();
            let point = Point {
                time: time,
                range: range as f32,
                theta: theta as f32,
                x: (record.origin[0] + record.direction[0] * range) as f32,
                y: (record.origin[1] + record.direction[1] * range) as f32,
                z: (record.origin[2] + record.direction[2] * range) as f32,
                target: (i + 1) as u8,
                num_target: num_target as u8,
                facet: record.facet,
                peak: peak,
                high_channel: block.channel == Channel::High,
            };
            points.push(point);
        }
    }

    Ok(points)
}

/// A 3D point in the scanner's own coordiante frame.
#[derive(Clone, Copy, Debug)]
pub struct Point {
    /// The time that this point was collected. Its reference frame depends on the time settings
    /// provided to the sdf library, which at this point are poorly defined.
    pub time: f64,
    /// The raw range to the point, which is different than the cartesian xyz distance.
    pub range: f32,
    /// The mirror scan angle in degrees.
    pub theta: f32,
    /// The x coordinate of the point in the scanner's own coordinate system.
    pub x: f32,
    /// The y coordinate of the point in the scanner's own coordinate system.
    pub y: f32,
    /// The z coordinate of the point in the scanner's own coordinate system.
    pub z: f32,
    /// The target number (1-indexed).
    pub target: u8,
    /// The total number of targets in this pulse.
    pub num_target: u8,
    /// The mirror facet used to reflect the laser energy.
    pub facet: u16,
    /// The raw peak information returned from `peakbag`.
    pub peak: Peak<u16>,
    /// Was this point collected on the high channel?
    pub high_channel: bool,
}

impl File {
    /// Writes all points from an .sdf file to an .sdc file.
    ///
    /// # Example
    ///
    /// ```no_run
    /// use sdf::file::File;
    /// File::convert("110630_174316.sdf", "110630_174316.sdc").unwrap();
    /// ```
    pub fn convert<T: Into<Vec<u8>>, P: AsRef<Path>>(sdf_path: T, sdc_path: P) -> Result<()> {
        let mut sdf_file = try!(File::open(sdf_path));
        let ref file_info = try!(sdf_file.info());
        let mut sdc_file = try!(sdc::Writer::from_path(sdc_path));
        for (i, record) in sdf_file.into_iter().enumerate() {
            let points = match discretize(&record, file_info) {
                Ok(points) => points,
                Err(Error::NeedSingleReferencePeak(_)) => {
                    warn!("No reference peak detected for pulse {}, skipping", i);
                    continue;
                }
                Err(err) => return Err(err),
            };
            for p in points {
                let ref point = sdc::Point {
                    time: p.time,
                    range: p.range,
                    theta: p.theta,
                    x: p.x,
                    y: p.y,
                    z: p.z,
                    amplitude: p.peak.amplitude,
                    // FIXME actually calculate this value
                    width: 1,
                    target_type: sdc::TargetType::Peak,
                    // Riegl one-indexes its target counts. Bah.
                    target: p.target,
                    num_target: p.num_target,
                    // FIXME I have no idea what this means
                    rg_index: 1,
                    facet_number: p.facet as u8,
                    high_channel: p.high_channel,
                    class_id: None,
                    rho: None,
                    reflectance: None,
                };
                try!(sdc_file.write_point(point));
            }
        }
        Ok(())
    }
}

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

    use file::File;

    #[test]
    fn first_point() {
        let mut file = File::open("data/110630_174316.sdf").unwrap();
        file.reindex().unwrap();
        let ref file_info = file.info().unwrap();
        let ref record = file.read().unwrap();
        let points = discretize(record, file_info).unwrap();
        assert_eq!(4, points.len());
    }
}
<commit_msg>Set the point's time to global<commit_after>//! Convert sdf files to other formats.

use std::iter::repeat;
use std::path::Path;

use peakbag::{PeakDetector, Peak};
use sdc;

use Result;
use error::Error;
use file::{Block, Channel, File, FileInfo, Record};

const HIGH_WIDTH: usize = 2;
const HIGH_FLOOR: u16 = 15;
const HIGH_CEILING: u16 = 255;
const LOW_WIDTHS: (usize, usize) = (3, 2);
const LOW_FLOOR: u16 = 15;
const LOW_CEILINGS: (u16, u16) = (250, 255); // heh
const MIN_HEIGHT_ABOVE_BACKGROUND: f64 = 5.0;
const MAX_KURTOSIS: f64 = 0.04;

/// Turns a single sdf record into zero or more `Point`s.
///
/// At this point, we assume that the timestamps are absolute. TODO make this smarter to handle the
/// case when the user has called `File::set_sosbl_mode(SosblMode::Relative)`.
///
/// # Panics
///
/// Panics if there are zero or more than one reference blocks in the record.
///
/// # Examples
///
/// ```
/// use sdf::convert::discretize;
/// use sdf::file::File;
/// let mut file = File::open("data/110630_174316.sdf").unwrap();
/// let ref file_info = file.info().unwrap();
/// file.reindex().unwrap();
/// let ref record = file.read().unwrap();
/// let points = discretize(record, file_info).unwrap();
/// ```
pub fn discretize(record: &Record, file_info: &FileInfo) -> Result<Vec<Point>> {
    let mut high_blocks = Vec::new();
    let mut low_blocks = Vec::new();
    let mut reference_block = None;
    for block in &record.blocks {
        match block.channel {
            Channel::High => high_blocks.push(block),
            Channel::Low => low_blocks.push(block),
            Channel::Reference => {
                if reference_block.is_some() {
                    panic!("More than one reference block in this record");
                } else {
                    reference_block = Some(block);
                }
            }
            _ => {}
        }
    }
    let reference_block = reference_block.unwrap();
    let high_detector = PeakDetector::new(HIGH_WIDTH, HIGH_FLOOR, HIGH_CEILING)
                            .min_height_above_background(MIN_HEIGHT_ABOVE_BACKGROUND)
                            .max_kurtosis(MAX_KURTOSIS);
    let (low_width, low_ceiling) = match high_blocks.len() {
        0 => (LOW_WIDTHS.0, LOW_CEILINGS.0),
        _ => (LOW_WIDTHS.1, LOW_CEILINGS.1),
    };
    let low_detector = PeakDetector::new(low_width, LOW_FLOOR, low_ceiling)
                           .min_height_above_background(MIN_HEIGHT_ABOVE_BACKGROUND)
                           .max_kurtosis(MAX_KURTOSIS)
                           .saturation(LOW_CEILINGS.1);
    let reference_detector = high_detector;

    let reference_peaks = reference_detector.detect_peaks(&reference_block.samples[..]);
    if reference_peaks.len() != 1 {
        debug!("Could not get a single reference peak out of: {:?}",
               reference_block.samples);
        return Err(Error::NeedSingleReferencePeak(reference_peaks.len()));
    }
    let ref reference_peak = reference_peaks[0];

    let timestamp = |peak: &Peak<_>, block: &Block| {
        block.time_sosbl + peak.index as f64 * file_info.sampling_time
    };

    let t_ref = timestamp(reference_peak, &reference_block);

    let mut points = Vec::new();
    for (block, detector) in low_blocks.iter()
                                       .zip(repeat(low_detector))
                                       .chain(high_blocks.iter().zip(repeat(high_detector))) {
        let peaks = detector.detect_peaks(&block.samples[..]);
        let num_target = peaks.len();
        for (i, peak) in peaks.into_iter().enumerate() {
            let time = timestamp(&peak, block);
            let range = file_info.v_group / 2.0 * (time - t_ref);
            // x is straight out of the scanner, and the mirror pans it along the
            // z axis.
            let theta = (record.direction[2] / record.direction[0])
                            .atan()
                            .to_degrees();
            let point = Point {
                time: time - record.time_sorg + record.time_external,
                range: range as f32,
                theta: theta as f32,
                x: (record.origin[0] + record.direction[0] * range) as f32,
                y: (record.origin[1] + record.direction[1] * range) as f32,
                z: (record.origin[2] + record.direction[2] * range) as f32,
                target: (i + 1) as u8,
                num_target: num_target as u8,
                facet: record.facet,
                peak: peak,
                high_channel: block.channel == Channel::High,
            };
            points.push(point);
        }
    }

    Ok(points)
}

/// A 3D point in the scanner's own coordiante frame.
#[derive(Clone, Copy, Debug)]
pub struct Point {
    /// The time that this point was collected. Its reference frame depends on the time settings
    /// provided to the sdf library, which at this point are poorly defined.
    pub time: f64,
    /// The raw range to the point, which is different than the cartesian xyz distance.
    pub range: f32,
    /// The mirror scan angle in degrees.
    pub theta: f32,
    /// The x coordinate of the point in the scanner's own coordinate system.
    pub x: f32,
    /// The y coordinate of the point in the scanner's own coordinate system.
    pub y: f32,
    /// The z coordinate of the point in the scanner's own coordinate system.
    pub z: f32,
    /// The target number (1-indexed).
    pub target: u8,
    /// The total number of targets in this pulse.
    pub num_target: u8,
    /// The mirror facet used to reflect the laser energy.
    pub facet: u16,
    /// The raw peak information returned from `peakbag`.
    pub peak: Peak<u16>,
    /// Was this point collected on the high channel?
    pub high_channel: bool,
}

impl File {
    /// Writes all points from an .sdf file to an .sdc file.
    ///
    /// # Example
    ///
    /// ```no_run
    /// use sdf::file::File;
    /// File::convert("110630_174316.sdf", "110630_174316.sdc").unwrap();
    /// ```
    pub fn convert<T: Into<Vec<u8>>, P: AsRef<Path>>(sdf_path: T, sdc_path: P) -> Result<()> {
        let mut sdf_file = try!(File::open(sdf_path));
        let ref file_info = try!(sdf_file.info());
        let mut sdc_file = try!(sdc::Writer::from_path(sdc_path));
        for (i, record) in sdf_file.into_iter().enumerate() {
            let points = match discretize(&record, file_info) {
                Ok(points) => points,
                Err(Error::NeedSingleReferencePeak(_)) => {
                    warn!("No reference peak detected for pulse {}, skipping", i);
                    continue;
                }
                Err(err) => return Err(err),
            };
            for p in points {
                let ref point = sdc::Point {
                    time: p.time,
                    range: p.range,
                    theta: p.theta,
                    x: p.x,
                    y: p.y,
                    z: p.z,
                    amplitude: p.peak.amplitude,
                    // FIXME actually calculate this value
                    width: 1,
                    target_type: sdc::TargetType::Peak,
                    // Riegl one-indexes its target counts. Bah.
                    target: p.target,
                    num_target: p.num_target,
                    // FIXME I have no idea what this means
                    rg_index: 1,
                    facet_number: p.facet as u8,
                    high_channel: p.high_channel,
                    class_id: None,
                    rho: None,
                    reflectance: None,
                };
                try!(sdc_file.write_point(point));
            }
        }
        Ok(())
    }
}

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

    use file::File;

    #[test]
    fn first_point() {
        let mut file = File::open("data/110630_174316.sdf").unwrap();
        file.reindex().unwrap();
        let ref file_info = file.info().unwrap();
        let ref record = file.read().unwrap();
        let points = discretize(record, file_info).unwrap();
        assert_eq!(4, points.len());
        assert_eq!(409397.90336020273, points[0].time);
    }
}
<|endoftext|>


<commit_before>
/*
Effective Address (Dolphin OS)

   80000000  24MB  Main Memory (RAM), write-back cached
   C0000000  24MB  Main Memory (RAM), write-through cached
   C8000000   2MB  Embedded Framebuffer (EFB)
   CC000000        Command Processor (CP)
   CC001000        Pixel Engine (PE)
   CC002000        Video Interface (VI)
   CC003000        Peripheral Interface (PI)
   CC004000        Memory Interface (MI)
   CC005000        DSP and DMA Audio Interface (AID)
   CC006000        DVD Interface (DI)
   CC006400        Serial Interface (SI)
   CC006800        External Interface (EXI)
   CC006C00        Audio Streaming Interface (AIS)
   CC008000        PI FIFO (GX)
   FFF00000   1MB  Boot ROM (first megabyte), used during BS only.

Physical Address (Flipper memory interface)
   00000000  24MB  Main Memory (RAM)
   08000000   2MB  Embedded Framebuffer (EFB)
   0C000000        Command Processor (CP)
   0C001000        Pixel Engine (PE)
   0C002000        Video Interface (VI)
   0C003000        Peripheral Interface (PI)
   0C004000        Memory Interface (MI)
   0C005000        DSP and DMA Audio Interface (AID)
   0C006000        DVD Interface (DI)
   0C006400        Serial Interface (SI)
   0C006800        External Interface (EXI)
   0C006C00        Audio Streaming Interface (AIS)
   0C008000        PI FIFO (GX)
   FFF00000   1MB  Boot ROM (first megabyte)
*/

use super::machine_status::MachineStatus;

const IBAT0U: usize = 528;
const IBAT0L: usize = 529;
const IBAT1U: usize = 530;
const IBAT1L: usize = 531;
const IBAT2U: usize = 532;
const IBAT2L: usize = 533;
const IBAT3U: usize = 534;
const IBAT3L: usize = 535;
const DBAT0U: usize = 536;
const DBAT0L: usize = 537;
const DBAT1U: usize = 538;
const DBAT1L: usize = 539;
const DBAT2U: usize = 540;
const DBAT2L: usize = 541;
const DBAT3U: usize = 542;
const DBAT3L: usize = 543;

#[derive(Default, Clone, Copy, Debug)]
struct Bat {
   bepi: u16,
   bl: u16,
   vs: bool,
   vp: bool,
   brpn: u16,
   wimg: u8,
   pp: u8
}

#[derive(Debug)]
pub struct Mmu {
   dbat: [Bat; 4],
   ibat: [Bat; 4],
}

impl Mmu {

   pub fn new() -> Mmu {
      Mmu {
         dbat: [Bat::default(); 4],
         ibat: [Bat::default(); 4]
      }
   }

   // generic write to ibat and dbat registries
   pub fn write_bat_reg(&mut self, register: usize, value: u32) {
      match register {
         IBAT0U => self.write_ibat_upper(0, value),
         IBAT1U => self.write_ibat_upper(1, value),
         IBAT2U => self.write_ibat_upper(2, value),
         IBAT3U => self.write_ibat_upper(3, value),
         DBAT0U => self.write_dbat_upper(0, value),
         DBAT1U => self.write_dbat_upper(1, value),
         DBAT2U => self.write_dbat_upper(2, value),
         DBAT3U => self.write_dbat_upper(3, value),
         IBAT0L => self.write_ibat_lower(0, value),
         IBAT1L => self.write_ibat_lower(1, value),
         IBAT2L => self.write_ibat_lower(2, value),
         IBAT3L => self.write_ibat_lower(3, value),
         DBAT0L => self.write_dbat_lower(0, value),
         DBAT1L => self.write_dbat_lower(1, value),
         DBAT2L => self.write_dbat_lower(2, value),
         DBAT3L => self.write_dbat_lower(3, value),
         _ => panic!("Invalid bat register")
      }
   }

   fn write_ibat_upper(&mut self, index: usize, value: u32) {
      let bat = &mut self.ibat[index];

      // FixMe: validate BAT value

      bat.bepi = (value >> 17 & 0b111_1111_1111_1111) as u16;
      bat.bl   = (value >> 2 & 0b111_1111_1111) as u16;
      bat.vs   = (value >> 1 & 0b1) != 0;
      bat.vp   = (value & 0b1) != 0;
   }

   fn write_ibat_lower(&mut self, index: usize, value:u32) {
      let bat = &mut self.ibat[index];

      // FixMe: validate BAT value

      bat.brpn = (value >> 17 & 0b111_1111_1111_1111) as u16;
      bat.wimg = (value >> 3 & 0b1_1111) as u8;
      bat.pp   = (value & 0b11) as u8;
   }

   fn write_dbat_upper(&mut self, index: usize, value: u32) {
      let bat = &mut self.dbat[index];

      // FixMe: validate BAT value

      bat.bepi = (value >> 17 & 0b111_1111_1111_1111) as u16;
      bat.bl   = (value >> 2 & 0b111_1111_1111) as u16;
      bat.vs   = (value >> 1 & 0b1) != 0;
      bat.vp   = (value & 0b1) != 0;
   }

   fn write_dbat_lower(&mut self, index: usize, value:u32) {
      let bat = &mut self.dbat[index];

      // FixMe: validate BAT value

      bat.brpn = (value >> 17 & 0b111_1111_1111_1111) as u16;
      bat.wimg = (value >> 3 & 0b1_1111) as u8;
      bat.pp   = (value & 0b11) as u8;
   }

   // FIXME: the EA ranges are wrong, supposed to be EA[0:19] and EA[20:31]

   // instruction address access
   pub fn instr_address_translate(&mut self, msr: &MachineStatus, ea: u32) -> u32 {
      if msr.instr_address_translation { // bloack address translation mode (BAT)

         for x in 0..self.ibat.len() {
            let bat = &self.ibat[x];

            if ((ea >> 17) as u16) & (!bat.bl) == bat.bepi { // FixMe: this is wrong

               if (!msr.privilege_level && bat.vs) || (msr.privilege_level && bat.vp) {

                  return ((bat.brpn as u32) << 17) ^ (ea & 0b1_1111_1111_1111_1111)
               }

            }

         }

         panic!("FixMe: perform address translation with Segment Register");

      } else { // read address translation mode
         ea
      }
   }

   // data address access
   pub fn data_address_translate(&mut self, msr: &MachineStatus, ea: u32) -> u32 {
      if msr.data_address_translation { // block address translation mode (BAT)

         for x in 0..self.dbat.len() {
            let bat = &self.dbat[x];

            if ((ea >> 17) as u16) & (!bat.bl) == bat.bepi { // FixMe: this is wrong

               if (!msr.privilege_level && bat.vs) || (msr.privilege_level && bat.vp) {

                  return ((bat.brpn as u32) << 17) ^ (ea & 0b1_1111_1111_1111_1111)
               }

            }
         }

         panic!("FixMe: perform address translation with Segment Register");

      } else { // read address translation mode
         ea
      }
   }
}
<commit_msg>fix spelling<commit_after>
/*
Effective Address (Dolphin OS)

   80000000  24MB  Main Memory (RAM), write-back cached
   C0000000  24MB  Main Memory (RAM), write-through cached
   C8000000   2MB  Embedded Framebuffer (EFB)
   CC000000        Command Processor (CP)
   CC001000        Pixel Engine (PE)
   CC002000        Video Interface (VI)
   CC003000        Peripheral Interface (PI)
   CC004000        Memory Interface (MI)
   CC005000        DSP and DMA Audio Interface (AID)
   CC006000        DVD Interface (DI)
   CC006400        Serial Interface (SI)
   CC006800        External Interface (EXI)
   CC006C00        Audio Streaming Interface (AIS)
   CC008000        PI FIFO (GX)
   FFF00000   1MB  Boot ROM (first megabyte), used during BS only.

Physical Address (Flipper memory interface)
   00000000  24MB  Main Memory (RAM)
   08000000   2MB  Embedded Framebuffer (EFB)
   0C000000        Command Processor (CP)
   0C001000        Pixel Engine (PE)
   0C002000        Video Interface (VI)
   0C003000        Peripheral Interface (PI)
   0C004000        Memory Interface (MI)
   0C005000        DSP and DMA Audio Interface (AID)
   0C006000        DVD Interface (DI)
   0C006400        Serial Interface (SI)
   0C006800        External Interface (EXI)
   0C006C00        Audio Streaming Interface (AIS)
   0C008000        PI FIFO (GX)
   FFF00000   1MB  Boot ROM (first megabyte)
*/

use super::machine_status::MachineStatus;

const IBAT0U: usize = 528;
const IBAT0L: usize = 529;
const IBAT1U: usize = 530;
const IBAT1L: usize = 531;
const IBAT2U: usize = 532;
const IBAT2L: usize = 533;
const IBAT3U: usize = 534;
const IBAT3L: usize = 535;
const DBAT0U: usize = 536;
const DBAT0L: usize = 537;
const DBAT1U: usize = 538;
const DBAT1L: usize = 539;
const DBAT2U: usize = 540;
const DBAT2L: usize = 541;
const DBAT3U: usize = 542;
const DBAT3L: usize = 543;

#[derive(Default, Clone, Copy, Debug)]
struct Bat {
   bepi: u16,
   bl: u16,
   vs: bool,
   vp: bool,
   brpn: u16,
   wimg: u8,
   pp: u8
}

#[derive(Debug)]
pub struct Mmu {
   dbat: [Bat; 4],
   ibat: [Bat; 4],
}

impl Mmu {

   pub fn new() -> Mmu {
      Mmu {
         dbat: [Bat::default(); 4],
         ibat: [Bat::default(); 4]
      }
   }

   // generic write to ibat and dbat registries
   pub fn write_bat_reg(&mut self, register: usize, value: u32) {
      match register {
         IBAT0U => self.write_ibat_upper(0, value),
         IBAT1U => self.write_ibat_upper(1, value),
         IBAT2U => self.write_ibat_upper(2, value),
         IBAT3U => self.write_ibat_upper(3, value),
         DBAT0U => self.write_dbat_upper(0, value),
         DBAT1U => self.write_dbat_upper(1, value),
         DBAT2U => self.write_dbat_upper(2, value),
         DBAT3U => self.write_dbat_upper(3, value),
         IBAT0L => self.write_ibat_lower(0, value),
         IBAT1L => self.write_ibat_lower(1, value),
         IBAT2L => self.write_ibat_lower(2, value),
         IBAT3L => self.write_ibat_lower(3, value),
         DBAT0L => self.write_dbat_lower(0, value),
         DBAT1L => self.write_dbat_lower(1, value),
         DBAT2L => self.write_dbat_lower(2, value),
         DBAT3L => self.write_dbat_lower(3, value),
         _ => panic!("Invalid bat register")
      }
   }

   fn write_ibat_upper(&mut self, index: usize, value: u32) {
      let bat = &mut self.ibat[index];

      // FixMe: validate BAT value

      bat.bepi = (value >> 17 & 0b111_1111_1111_1111) as u16;
      bat.bl   = (value >> 2 & 0b111_1111_1111) as u16;
      bat.vs   = (value >> 1 & 0b1) != 0;
      bat.vp   = (value & 0b1) != 0;
   }

   fn write_ibat_lower(&mut self, index: usize, value:u32) {
      let bat = &mut self.ibat[index];

      // FixMe: validate BAT value

      bat.brpn = (value >> 17 & 0b111_1111_1111_1111) as u16;
      bat.wimg = (value >> 3 & 0b1_1111) as u8;
      bat.pp   = (value & 0b11) as u8;
   }

   fn write_dbat_upper(&mut self, index: usize, value: u32) {
      let bat = &mut self.dbat[index];

      // FixMe: validate BAT value

      bat.bepi = (value >> 17 & 0b111_1111_1111_1111) as u16;
      bat.bl   = (value >> 2 & 0b111_1111_1111) as u16;
      bat.vs   = (value >> 1 & 0b1) != 0;
      bat.vp   = (value & 0b1) != 0;
   }

   fn write_dbat_lower(&mut self, index: usize, value:u32) {
      let bat = &mut self.dbat[index];

      // FixMe: validate BAT value

      bat.brpn = (value >> 17 & 0b111_1111_1111_1111) as u16;
      bat.wimg = (value >> 3 & 0b1_1111) as u8;
      bat.pp   = (value & 0b11) as u8;
   }

   // FIXME: the EA ranges are wrong, supposed to be EA[0:19] and EA[20:31]

   // instruction address access
   pub fn instr_address_translate(&mut self, msr: &MachineStatus, ea: u32) -> u32 {
      if msr.instr_address_translation { // block address translation mode (BAT)

         for x in 0..self.ibat.len() {
            let bat = &self.ibat[x];

            if ((ea >> 17) as u16) & (!bat.bl) == bat.bepi { // FixMe: this is wrong

               if (!msr.privilege_level && bat.vs) || (msr.privilege_level && bat.vp) {

                  return ((bat.brpn as u32) << 17) ^ (ea & 0b1_1111_1111_1111_1111)
               }

            }

         }

         panic!("FixMe: perform address translation with Segment Register");

      } else { // read address translation mode
         ea
      }
   }

   // data address access
   pub fn data_address_translate(&mut self, msr: &MachineStatus, ea: u32) -> u32 {
      if msr.data_address_translation { // block address translation mode (BAT)

         for x in 0..self.dbat.len() {
            let bat = &self.dbat[x];

            if ((ea >> 17) as u16) & (!bat.bl) == bat.bepi { // FixMe: this is wrong

               if (!msr.privilege_level && bat.vs) || (msr.privilege_level && bat.vp) {

                  return ((bat.brpn as u32) << 17) ^ (ea & 0b1_1111_1111_1111_1111)
               }

            }
         }

         panic!("FixMe: perform address translation with Segment Register");

      } else { // read address translation mode
         ea
      }
   }
}
<|endoftext|>


<commit_before>use crate::errors::OscError;
use crate::types::{OscArray, OscBundle, OscColor, OscMessage, OscMidiMessage, OscPacket, OscTime, OscType};
use crate::alloc::{string::{String, ToString}, vec::Vec};

use nom::Offset;
use nom::sequence::terminated;
use nom::bytes::complete::{take, take_till};
use nom::combinator::{map, map_parser};
use nom::multi::many0;
use nom::number::complete::{be_f32, be_f64, be_i32, be_i64, be_u32};
use nom::{IResult,combinator::map_res,sequence::tuple,Err};
use OscError::BadPacket;

/// Common MTU size for ethernet
pub const MTU: usize = 1536;

/// Takes a bytes slice representing a UDP packet and returns the OSC packet as well as a slice of
/// any bytes remaining after the OSC packet.
pub fn decode_udp<'a>(msg: &'a [u8]) -> Result<(&'a [u8], OscPacket), OscError> {
    match decode_packet(msg, msg) {
        Ok((remainder, osc_packet)) => Ok((remainder, osc_packet)),
        Err(e) => match e {
            Err::Incomplete(_) => Err(BadPacket("Incomplete data")),
            Err::Error(e) => Err(e),
            Err::Failure(e) => Err(e)
        }
    }
}

/// Takes a bytes slice from a TCP stream (or any stream-based protocol) and returns the first OSC
/// packet as well as a slice of the bytes remaining after the packet.
pub fn decode_tcp<'a>(msg: &'a [u8]) -> Result<(&'a [u8], Option<OscPacket>), OscError> {
    let (input, osc_packet_length) = match be_u32(msg) {
        Ok((i, o)) => (i, o),
        Err(e) => match e {
            Err::Incomplete(_) => return Err(BadPacket("Incomplete data")),
            Err::Error(e) => return Err(e),
            Err::Failure(e) => return Err(e)
        }
    };

    if osc_packet_length as usize > msg.len() {
        return Ok((msg, None));
    }

    match decode_packet(input, msg).map(|(remainder, osc_packet)| {
        (remainder, Some(osc_packet))
    }) {
        Ok((remainder, osc_packet)) => Ok((remainder, osc_packet)),
        Err(e) => match e {
            Err::Incomplete(_) => Err(BadPacket("Incomplete data")),
            Err::Error(e) => Err(e),
            Err::Failure(e) => Err(e)
        }
    }
}

/// Takes a bytes slice from a TCP stream (or any stream-based protocol) and returns a vec of all
/// OSC packets in the slice as well as a slice of the bytes remaining after the last packet.
pub fn decode_tcp_vec<'a>(msg: &'a [u8]) -> Result<(&'a [u8], Vec<OscPacket>), OscError> {
    let mut input = msg;
    let mut osc_packets = vec![];

    while let (remainder, Some(osc_packet)) = decode_tcp(input)? {
        input = remainder;
        osc_packets.push(osc_packet);

        if remainder.len() == 0 {
            break;
        }
    };

    Ok((input, osc_packets))
}

fn decode_packet<'a>(
    input: &'a [u8],
    original_input: &'a[u8],
) -> IResult<&'a [u8], OscPacket, OscError> {
    if input.is_empty() {
        return Err(nom::Err::Error(OscError::BadPacket("Empty packet.")));
    }

    let (input, addr) = read_osc_string(input, original_input)?;

    match addr.chars().next() {
        Some('/') => {
            decode_message(addr, input, original_input)
        }
        Some('#') if &addr == "#bundle" => {
            decode_bundle(input, original_input)
        }
        _ => Err(nom::Err::Error(OscError::BadPacket(
            "Invalid message address or bundle tag"
        ))),
    }
}

fn decode_message<'a>(
    addr: String,
    input: &'a [u8],
    original_input: &'a[u8],
) -> IResult<&'a [u8], OscPacket, OscError> {
    let (input, type_tags) = read_osc_string(input, original_input)?;

    if type_tags.len() > 1 {
        let (input, args) = read_osc_args(
            input,
            original_input,
            type_tags,
        )?;
        Ok((input, OscPacket::Message(OscMessage { addr, args })))
    } else {
        Ok((input, OscPacket::Message(OscMessage { addr, args: vec![] })))
    }
}

fn decode_bundle<'a>(
    input: &'a [u8],
    original_input: &'a[u8],
) -> IResult<&'a [u8], OscPacket, OscError> {
    let (input, (timetag, content)) = tuple((
        read_time_tag,
        many0(|input| read_bundle_element(input, original_input)),
    ))(input)?;

    Ok((
        input,
        OscPacket::Bundle(OscBundle {
            timetag,
            content,
        }),
    ))
}

fn read_bundle_element<'a>(input: &'a [u8], original_input: &'a[u8]) -> IResult<&'a [u8], OscPacket, OscError> {
    let (input, elem_size) = be_u32(input)?;

    let result = map_parser(
        |input| {
            take(elem_size)(input).map_err(|_: nom::Err<OscError>| {
                nom::Err::Error(OscError::BadBundle(
                    "Bundle shorter than expected!".to_string(),
                ))
            })
        },
        |input| decode_packet(input, original_input),
    )(input);
    drop(elem_size);
    result
}

fn read_osc_string<'a>(input: &'a [u8], original_input: &'a[u8]) -> IResult<&'a [u8], String, OscError> {
    map_res(
        terminated(
            take_till(|c| c == 0u8),
            pad_to_32_bit_boundary(original_input),
        ),
        |str_buf: &'a[u8]| {
            String::from_utf8(str_buf.into())
                .map_err(OscError::StringError)
                .map(|s| s.trim_matches(0u8 as char).to_string())
        },
    )(input)
}

fn read_osc_args<'a>(
    mut input: &'a[u8],
    original_input: &'a[u8],
    raw_type_tags: String,
) ->  IResult<&'a [u8], Vec<OscType>, OscError> {
    let type_tags: Vec<char> = raw_type_tags.chars().skip(1).collect();

    let mut args: Vec<OscType> = Vec::with_capacity(type_tags.len());
    let mut stack: Vec<Vec<OscType>> = Vec::new();
    for tag in type_tags {
        if tag == '[' {
            // array start: save current frame and start a new frame
            // for the array's content
            stack.push(args);
            args = Vec::new();
        } else if tag == ']' {
            // found the end of the current array:
            // create array object from current frame and step one level up
            let array = OscType::Array(OscArray { content: args });
            match stack.pop() {
                Some(stashed) => args = stashed,
                None => return Err(nom::Err::Error(OscError::BadMessage(
                    "Encountered ] outside array"
                ))),
            }
            args.push(array);
        } else {
            let input_and_arg = read_osc_arg(input, original_input, tag)?;
            input = input_and_arg.0;
            args.push(input_and_arg.1);
        }
    }
    Ok((input, args))
}

fn read_osc_arg<'a>(input: &'a[u8], original_input: &'a[u8], tag: char) -> IResult<&'a[u8], OscType, OscError> {
    match tag {
        'f' => map(be_f32, OscType::Float)(input),
        'd' => map(be_f64, OscType::Double)(input),
        'i' => map(be_i32, OscType::Int)(input),
        'h' => map(be_i64, OscType::Long)(input),
        's' => {
            read_osc_string(input, original_input)
                .map(|(remainder, string)| (remainder, OscType::String(string)))
        }
        't' => read_time_tag(input).map(|(remainder, time)| {
            (remainder, OscType::Time(time))
        }),
        'b' => read_blob(input, original_input),
        'r' => read_osc_color(input),
        'T' => Ok((input, true.into())),
        'F' => Ok((input, false.into())),
        'N' => Ok((input, OscType::Nil)),
        'I' => Ok((input, OscType::Inf)),
        'c' => read_char(input),
        'm' => read_midi_message(input),
        _ => Err(nom::Err::Error(OscError::BadArg(format!(
            "Type tag \"{}\" is not implemented!",
            tag
        )))),
    }
}

fn read_char(input: &[u8]) -> IResult<&[u8], OscType, OscError> {
    map_res(
        be_u32,
        |b| {
            let opt_char = char::from_u32(b);
            match opt_char {
                Some(c) => Ok(OscType::Char(c)),
                None => Err(OscError::BadArg(
                    "Argument is not a char!".to_string(),
                )),
            }
        },
    )(input)
}

fn read_blob<'a>(input: &'a[u8], original_input: &'a[u8]) -> IResult<&'a[u8], OscType, OscError> {
    let (input, size) = be_u32(input)?;

    map(
        terminated(
            take(size),
            pad_to_32_bit_boundary(original_input),
        ),
        |blob| OscType::Blob(blob.into()),
    )(input)
}

fn read_time_tag<'a>(input: &'a[u8]) -> IResult<&'a[u8], OscTime, OscError> {
    map(
        tuple((be_u32, be_u32)),
        |(seconds, fractional)| OscTime {
            seconds,
            fractional,
        },
    )(input)
}

fn read_midi_message<'a>(input: &'a[u8]) -> IResult<&'a[u8], OscType, OscError> {
    map(take(4usize), |buf: &[u8]| {
        OscType::Midi(OscMidiMessage {
            port: buf[0],
            status: buf[1],
            data1: buf[2],
            data2: buf[3],
        })
    })(input)
}

fn read_osc_color<'a>(input: &'a[u8]) -> IResult<&'a[u8], OscType, OscError> {
    map(take(4usize), |buf: &[u8]| {
        OscType::Color(OscColor {
            red: buf[0],
            green: buf[1],
            blue: buf[2],
            alpha: buf[3],
        })
    })(input)
}

fn pad_to_32_bit_boundary<'a>(
    original_input: &'a[u8]
) -> impl Fn(&'a[u8]) -> IResult<&'a[u8], (), OscError> {
    move |input| {
        let offset = 4 - original_input.offset(input) % 4;
        let (input, _) = take(offset)(input)?;
        Ok((input, ()))
    }
}
<commit_msg>Qualify errors for consistency<commit_after>use crate::errors::OscError;
use crate::types::{OscArray, OscBundle, OscColor, OscMessage, OscMidiMessage, OscPacket, OscTime, OscType};
use crate::alloc::{string::{String, ToString}, vec::Vec};

use nom::Offset;
use nom::sequence::terminated;
use nom::bytes::complete::{take, take_till};
use nom::combinator::{map, map_parser};
use nom::multi::many0;
use nom::number::complete::{be_f32, be_f64, be_i32, be_i64, be_u32};
use nom::{IResult,combinator::map_res,sequence::tuple,Err};

/// Common MTU size for ethernet
pub const MTU: usize = 1536;

/// Takes a bytes slice representing a UDP packet and returns the OSC packet as well as a slice of
/// any bytes remaining after the OSC packet.
pub fn decode_udp<'a>(msg: &'a [u8]) -> Result<(&'a [u8], OscPacket), OscError> {
    match decode_packet(msg, msg) {
        Ok((remainder, osc_packet)) => Ok((remainder, osc_packet)),
        Err(e) => match e {
            Err::Incomplete(_) => Err(OscError::BadPacket("Incomplete data")),
            Err::Error(e) => Err(e),
            Err::Failure(e) => Err(e)
        }
    }
}

/// Takes a bytes slice from a TCP stream (or any stream-based protocol) and returns the first OSC
/// packet as well as a slice of the bytes remaining after the packet.
pub fn decode_tcp<'a>(msg: &'a [u8]) -> Result<(&'a [u8], Option<OscPacket>), OscError> {
    let (input, osc_packet_length) = match be_u32(msg) {
        Ok((i, o)) => (i, o),
        Err(e) => match e {
            Err::Incomplete(_) => return Err(OscError::BadPacket("Incomplete data")),
            Err::Error(e) => return Err(e),
            Err::Failure(e) => return Err(e)
        }
    };

    if osc_packet_length as usize > msg.len() {
        return Ok((msg, None));
    }

    match decode_packet(input, msg).map(|(remainder, osc_packet)| {
        (remainder, Some(osc_packet))
    }) {
        Ok((remainder, osc_packet)) => Ok((remainder, osc_packet)),
        Err(e) => match e {
            Err::Incomplete(_) => Err(OscError::BadPacket("Incomplete data")),
            Err::Error(e) => Err(e),
            Err::Failure(e) => Err(e)
        }
    }
}

/// Takes a bytes slice from a TCP stream (or any stream-based protocol) and returns a vec of all
/// OSC packets in the slice as well as a slice of the bytes remaining after the last packet.
pub fn decode_tcp_vec<'a>(msg: &'a [u8]) -> Result<(&'a [u8], Vec<OscPacket>), OscError> {
    let mut input = msg;
    let mut osc_packets = vec![];

    while let (remainder, Some(osc_packet)) = decode_tcp(input)? {
        input = remainder;
        osc_packets.push(osc_packet);

        if remainder.len() == 0 {
            break;
        }
    };

    Ok((input, osc_packets))
}

fn decode_packet<'a>(
    input: &'a [u8],
    original_input: &'a[u8],
) -> IResult<&'a [u8], OscPacket, OscError> {
    if input.is_empty() {
        return Err(nom::Err::Error(OscError::BadPacket("Empty packet.")));
    }

    let (input, addr) = read_osc_string(input, original_input)?;

    match addr.chars().next() {
        Some('/') => {
            decode_message(addr, input, original_input)
        }
        Some('#') if &addr == "#bundle" => {
            decode_bundle(input, original_input)
        }
        _ => Err(nom::Err::Error(OscError::BadPacket(
            "Invalid message address or bundle tag"
        ))),
    }
}

fn decode_message<'a>(
    addr: String,
    input: &'a [u8],
    original_input: &'a[u8],
) -> IResult<&'a [u8], OscPacket, OscError> {
    let (input, type_tags) = read_osc_string(input, original_input)?;

    if type_tags.len() > 1 {
        let (input, args) = read_osc_args(
            input,
            original_input,
            type_tags,
        )?;
        Ok((input, OscPacket::Message(OscMessage { addr, args })))
    } else {
        Ok((input, OscPacket::Message(OscMessage { addr, args: vec![] })))
    }
}

fn decode_bundle<'a>(
    input: &'a [u8],
    original_input: &'a[u8],
) -> IResult<&'a [u8], OscPacket, OscError> {
    let (input, (timetag, content)) = tuple((
        read_time_tag,
        many0(|input| read_bundle_element(input, original_input)),
    ))(input)?;

    Ok((
        input,
        OscPacket::Bundle(OscBundle {
            timetag,
            content,
        }),
    ))
}

fn read_bundle_element<'a>(input: &'a [u8], original_input: &'a[u8]) -> IResult<&'a [u8], OscPacket, OscError> {
    let (input, elem_size) = be_u32(input)?;

    let result = map_parser(
        |input| {
            take(elem_size)(input).map_err(|_: nom::Err<OscError>| {
                nom::Err::Error(OscError::BadBundle(
                    "Bundle shorter than expected!".to_string(),
                ))
            })
        },
        |input| decode_packet(input, original_input),
    )(input);
    drop(elem_size);
    result
}

fn read_osc_string<'a>(input: &'a [u8], original_input: &'a[u8]) -> IResult<&'a [u8], String, OscError> {
    map_res(
        terminated(
            take_till(|c| c == 0u8),
            pad_to_32_bit_boundary(original_input),
        ),
        |str_buf: &'a[u8]| {
            String::from_utf8(str_buf.into())
                .map_err(OscError::StringError)
                .map(|s| s.trim_matches(0u8 as char).to_string())
        },
    )(input)
}

fn read_osc_args<'a>(
    mut input: &'a[u8],
    original_input: &'a[u8],
    raw_type_tags: String,
) ->  IResult<&'a [u8], Vec<OscType>, OscError> {
    let type_tags: Vec<char> = raw_type_tags.chars().skip(1).collect();

    let mut args: Vec<OscType> = Vec::with_capacity(type_tags.len());
    let mut stack: Vec<Vec<OscType>> = Vec::new();
    for tag in type_tags {
        if tag == '[' {
            // array start: save current frame and start a new frame
            // for the array's content
            stack.push(args);
            args = Vec::new();
        } else if tag == ']' {
            // found the end of the current array:
            // create array object from current frame and step one level up
            let array = OscType::Array(OscArray { content: args });
            match stack.pop() {
                Some(stashed) => args = stashed,
                None => return Err(nom::Err::Error(OscError::BadMessage(
                    "Encountered ] outside array"
                ))),
            }
            args.push(array);
        } else {
            let input_and_arg = read_osc_arg(input, original_input, tag)?;
            input = input_and_arg.0;
            args.push(input_and_arg.1);
        }
    }
    Ok((input, args))
}

fn read_osc_arg<'a>(input: &'a[u8], original_input: &'a[u8], tag: char) -> IResult<&'a[u8], OscType, OscError> {
    match tag {
        'f' => map(be_f32, OscType::Float)(input),
        'd' => map(be_f64, OscType::Double)(input),
        'i' => map(be_i32, OscType::Int)(input),
        'h' => map(be_i64, OscType::Long)(input),
        's' => {
            read_osc_string(input, original_input)
                .map(|(remainder, string)| (remainder, OscType::String(string)))
        }
        't' => read_time_tag(input).map(|(remainder, time)| {
            (remainder, OscType::Time(time))
        }),
        'b' => read_blob(input, original_input),
        'r' => read_osc_color(input),
        'T' => Ok((input, true.into())),
        'F' => Ok((input, false.into())),
        'N' => Ok((input, OscType::Nil)),
        'I' => Ok((input, OscType::Inf)),
        'c' => read_char(input),
        'm' => read_midi_message(input),
        _ => Err(nom::Err::Error(OscError::BadArg(format!(
            "Type tag \"{}\" is not implemented!",
            tag
        )))),
    }
}

fn read_char(input: &[u8]) -> IResult<&[u8], OscType, OscError> {
    map_res(
        be_u32,
        |b| {
            let opt_char = char::from_u32(b);
            match opt_char {
                Some(c) => Ok(OscType::Char(c)),
                None => Err(OscError::BadArg(
                    "Argument is not a char!".to_string(),
                )),
            }
        },
    )(input)
}

fn read_blob<'a>(input: &'a[u8], original_input: &'a[u8]) -> IResult<&'a[u8], OscType, OscError> {
    let (input, size) = be_u32(input)?;

    map(
        terminated(
            take(size),
            pad_to_32_bit_boundary(original_input),
        ),
        |blob| OscType::Blob(blob.into()),
    )(input)
}

fn read_time_tag<'a>(input: &'a[u8]) -> IResult<&'a[u8], OscTime, OscError> {
    map(
        tuple((be_u32, be_u32)),
        |(seconds, fractional)| OscTime {
            seconds,
            fractional,
        },
    )(input)
}

fn read_midi_message<'a>(input: &'a[u8]) -> IResult<&'a[u8], OscType, OscError> {
    map(take(4usize), |buf: &[u8]| {
        OscType::Midi(OscMidiMessage {
            port: buf[0],
            status: buf[1],
            data1: buf[2],
            data2: buf[3],
        })
    })(input)
}

fn read_osc_color<'a>(input: &'a[u8]) -> IResult<&'a[u8], OscType, OscError> {
    map(take(4usize), |buf: &[u8]| {
        OscType::Color(OscColor {
            red: buf[0],
            green: buf[1],
            blue: buf[2],
            alpha: buf[3],
        })
    })(input)
}

fn pad_to_32_bit_boundary<'a>(
    original_input: &'a[u8]
) -> impl Fn(&'a[u8]) -> IResult<&'a[u8], (), OscError> {
    move |input| {
        let offset = 4 - original_input.offset(input) % 4;
        let (input, _) = take(offset)(input)?;
        Ok((input, ()))
    }
}
<|endoftext|>


<commit_before>extern crate rspgod;
extern crate postgres;
extern crate rustc_serialize;

use postgres::{Connection, SslMode};
use rspgod::types::{Change};
use rustc_serialize::json;

#[derive(Debug)]
struct TestRecord {
    id:   i32,
    name: String,
}

#[derive(Debug)]
struct LDUpdate {
    data: String,
}

#[test]
fn sanity_test() {
    with_clean_database(|c| {
        let records = vec![
            TestRecord { id: 1, name: "Michael Baker".to_string() },
            TestRecord { id: 2, name: "Josh Cheek".to_string(),   },
        ];

        for record in records.iter() {
            create_record(c, &record);
        }

        fetch_records(c);
    });
}

#[test]
fn basic_insert() {
    with_slot(|c| {
        let record = TestRecord {id: 1, name: "Michael Baker".to_string(), };
        create_record(c, &record);
        let updates = fetch_updates(c);
        assert_eq!(updates.len(), 1);
        let change:Change = json::decode(&updates[0].data[..]).unwrap();
        assert!(match change {
            Change::Insert {..} => { true },
            _                   => { false },
        });
    });
}

//
// [TODO] I want to move a lot of these into a utility module when I can figure out how to do that
//

fn fetch_updates(c: &Connection) -> Vec<LDUpdate> {
    let stmt = c.prepare("SELECT * FROM pg_logical_slot_peek_changes('slot', NULL, NULL)").unwrap();
    let mut result = vec![];
    for r in stmt.query(&[]).unwrap() {
        result.push(LDUpdate { data: r.get(2) });
    }
    result
}

fn create_slot(c: &Connection) {
    let stmt = c.prepare("select * from pg_create_logical_replication_slot('slot', 'thingy')").unwrap();
    stmt.execute(&[]).unwrap();
}

fn drop_slot(c: &Connection) {
    let stmt = c.prepare("select pg_drop_replication_slot('slot')").unwrap();
    match stmt.execute(&[]) {
        _ => {},
    }
}

fn with_slot<F>(f: F) where F:Fn(&Connection) -> () {
    with_clean_database(|c| {
        drop_slot(c);
        create_slot(c);
        f(c);
        drop_slot(c);
    });
}

fn with_clean_database<F>(f: F) where F:Fn(&Connection) -> () {
    let c = connection();
    reset_database(&c);
    f(&c);
    drop_database(&c);
}

fn reset_database(c: &Connection) {
    drop_database(&c);
    create_database(&c);
}

fn create_database(c: &Connection) {
    let stmt = c.prepare("create table test_table (id int primary key, name text)").unwrap();
    stmt.execute(&[]).unwrap();
}

fn fetch_records(c: &Connection) -> Vec<TestRecord> {
    let stmt = c.prepare("select id, name from test_table").unwrap();
    let results = stmt.query(&[]).unwrap();
    results.iter().map(|r| {
        TestRecord {
            id:   r.get(0),
            name: r.get(1),
        }
    }).collect()
}

fn create_record(c: &Connection, r: &TestRecord) {
    let stmt = c.prepare("insert into test_table (id, name) values ($1, $2)").unwrap();
    stmt.execute(&[
        &r.id,
        &r.name,
    ]).unwrap();
}

fn drop_database(c: &Connection) {
    let stmt = c.prepare("drop table if exists test_table").unwrap();
    stmt.execute(&[]).unwrap();
}

fn connection_string() -> String {
    match std::env::var("POSTGRES_URL") {
        Ok(val) => val,
        Err(e)  => panic!(format!("You must set the POSTGRES_URL environment variable to point to a running Postgres test database when running automated tests: {}", e)),
    }
}

fn connection() -> Connection {
    match Connection::connect(&connection_string()[..], &SslMode::None) {
        Ok(c)  => c,
        Err(e) => panic!(format!("Could not connect to the test database: {}", e)),
    }
}
<commit_msg>Removes an unecessary data structure from the tests<commit_after>extern crate rspgod;
extern crate postgres;
extern crate rustc_serialize;

use postgres::{Connection, SslMode};
use rspgod::types::{Change};
use rustc_serialize::json;

#[derive(Debug)]
struct TestRecord {
    id:   i32,
    name: String,
}

#[test]
fn sanity_test() {
    with_clean_database(|c| {
        let records = vec![
            TestRecord { id: 1, name: "Michael Baker".to_string() },
            TestRecord { id: 2, name: "Josh Cheek".to_string(),   },
        ];

        for record in records.iter() {
            create_record(c, &record);
        }

        fetch_records(c);
    });
}

#[test]
fn basic_insert() {
    with_slot(|c| {
        let record = TestRecord {id: 1, name: "Michael Baker".to_string(), };
        create_record(c, &record);
        let updates = fetch_updates(c);
        assert_eq!(updates.len(), 1);
        let change:Change = json::decode(&updates[0][..]).unwrap();
        assert!(match change {
            Change::Insert {..} => { true },
            _                   => { false },
        });
    });
}

//
// [TODO] I want to move a lot of these into a utility module when I can figure out how to do that
//

fn fetch_updates(c: &Connection) -> Vec<String> {
    let stmt = c.prepare("SELECT * FROM pg_logical_slot_peek_changes('slot', NULL, NULL)").unwrap();
    let mut result = vec![];
    for r in stmt.query(&[]).unwrap() {
        result.push(r.get(2));
    }
    result
}

fn create_slot(c: &Connection) {
    let stmt = c.prepare("select * from pg_create_logical_replication_slot('slot', 'thingy')").unwrap();
    stmt.execute(&[]).unwrap();
}

fn drop_slot(c: &Connection) {
    let stmt = c.prepare("select pg_drop_replication_slot('slot')").unwrap();
    match stmt.execute(&[]) {
        _ => {},
    }
}

fn with_slot<F>(f: F) where F:Fn(&Connection) -> () {
    with_clean_database(|c| {
        drop_slot(c);
        create_slot(c);
        f(c);
        drop_slot(c);
    });
}

fn with_clean_database<F>(f: F) where F:Fn(&Connection) -> () {
    let c = connection();
    reset_database(&c);
    f(&c);
    drop_database(&c);
}

fn reset_database(c: &Connection) {
    drop_database(&c);
    create_database(&c);
}

fn create_database(c: &Connection) {
    let stmt = c.prepare("create table test_table (id int primary key, name text)").unwrap();
    stmt.execute(&[]).unwrap();
}

fn fetch_records(c: &Connection) -> Vec<TestRecord> {
    let stmt = c.prepare("select id, name from test_table").unwrap();
    let results = stmt.query(&[]).unwrap();
    results.iter().map(|r| {
        TestRecord {
            id:   r.get(0),
            name: r.get(1),
        }
    }).collect()
}

fn create_record(c: &Connection, r: &TestRecord) {
    let stmt = c.prepare("insert into test_table (id, name) values ($1, $2)").unwrap();
    stmt.execute(&[
        &r.id,
        &r.name,
    ]).unwrap();
}

fn drop_database(c: &Connection) {
    let stmt = c.prepare("drop table if exists test_table").unwrap();
    stmt.execute(&[]).unwrap();
}

fn connection_string() -> String {
    match std::env::var("POSTGRES_URL") {
        Ok(val) => val,
        Err(e)  => panic!(format!("You must set the POSTGRES_URL environment variable to point to a running Postgres test database when running automated tests: {}", e)),
    }
}

fn connection() -> Connection {
    match Connection::connect(&connection_string()[..], &SslMode::None) {
        Ok(c)  => c,
        Err(e) => panic!(format!("Could not connect to the test database: {}", e)),
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::process::{Command, Stdio};
use std::path::PathBuf;
use std::io::Write;

fn get_bin_dir() -> PathBuf {
    env::current_exe()
        .expect("test bin's directory")
        .parent()
        .expect("test bin's parent directory")
        .parent()
        .expect("executable's directory")
        .to_path_buf()
}

fn cmd_aux2bib() -> Command {
    let path;
    if cfg!(not(windows)) {
        path = get_bin_dir().join("aux2bib");
    } else {
        path = get_bin_dir().join("aux2bib.exe");
    }
    if !path.is_file() {
        panic!("aux2bib binary {:?} was not found", path);
    }
    println!("{:?}", path);
    let mut cmd = Command::new(path);
    cmd.env_clear().stderr(Stdio::piped()).stdout(
        Stdio::piped(),
    );

    cmd
}

fn cmd_blg2bib() -> Command {
    let path;
    if cfg!(not(windows)) {
        path = get_bin_dir().join("blg2bib");
    } else {
        path = get_bin_dir().join("blg2bib.exe");
    }
    if !path.is_file() {
        panic!("blg2bib binary {:?} was not found", path);
    }
    let mut cmd = Command::new(path);
    cmd.env_clear().stderr(Stdio::piped()).stdout(
        Stdio::piped(),
    );

    cmd
}

#[cfg(not(windows))]
#[test]
fn aux2bib_runs() {
    let mut cmd = cmd_aux2bib().arg("--help").spawn().expect(
        "Failed to execute aux2bib",
    );

    let error_code = cmd.wait().expect("Failed to wait on aux2bib");

    assert!(error_code.success());
}

#[cfg(not(windows))]
#[test]
fn blg2bib_runs() {
    let mut cmd = cmd_blg2bib().arg("--help").spawn().expect(
        "Failed to execute blg2bib",
    );

    let error_code = cmd.wait().expect("Failed to wait on blg2bib");

    assert!(error_code.success());
}

#[cfg(not(windows))]
#[test]
fn aux2bib_stdin_empty() {
    let mut child = cmd_aux2bib().stdin(Stdio::piped()).spawn().expect(
        "Failed to execute aux2bib",
    );

    {
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(b"").expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert!(output.status.success());
    assert_eq!(output.stdout, []);
}

#[cfg(not(windows))]
#[test]
fn blg2bib_stdin_empty() {
    let mut child = cmd_blg2bib().stdin(Stdio::piped()).spawn().expect(
        "Failed to execute blg2bib",
    );

    {
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(b"").expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert!(output.status.success());
    assert_eq!(output.stdout, []);
}
<commit_msg>test: Add test of aux2bib with actual input<commit_after>use std::env;
use std::process::{Command, Stdio};
use std::path::PathBuf;
use std::io::Write;

fn get_bin_dir() -> PathBuf {
    env::current_exe()
        .expect("test bin's directory")
        .parent()
        .expect("test bin's parent directory")
        .parent()
        .expect("executable's directory")
        .to_path_buf()
}

fn cmd_aux2bib() -> Command {
    let path;
    if cfg!(not(windows)) {
        path = get_bin_dir().join("aux2bib");
    } else {
        path = get_bin_dir().join("aux2bib.exe");
    }
    if !path.is_file() {
        panic!("aux2bib binary {:?} was not found", path);
    }
    println!("{:?}", path);
    let mut cmd = Command::new(path);
    cmd.env_clear().stderr(Stdio::piped()).stdout(
        Stdio::piped(),
    );

    cmd
}

fn cmd_blg2bib() -> Command {
    let path;
    if cfg!(not(windows)) {
        path = get_bin_dir().join("blg2bib");
    } else {
        path = get_bin_dir().join("blg2bib.exe");
    }
    if !path.is_file() {
        panic!("blg2bib binary {:?} was not found", path);
    }
    let mut cmd = Command::new(path);
    cmd.env_clear().stderr(Stdio::piped()).stdout(
        Stdio::piped(),
    );

    cmd
}

#[cfg(not(windows))]
#[test]
fn aux2bib_runs() {
    let mut cmd = cmd_aux2bib().arg("--help").spawn().expect(
        "Failed to execute aux2bib",
    );

    let error_code = cmd.wait().expect("Failed to wait on aux2bib");

    assert!(error_code.success());
}

#[cfg(not(windows))]
#[test]
fn blg2bib_runs() {
    let mut cmd = cmd_blg2bib().arg("--help").spawn().expect(
        "Failed to execute blg2bib",
    );

    let error_code = cmd.wait().expect("Failed to wait on blg2bib");

    assert!(error_code.success());
}

#[cfg(not(windows))]
#[test]
fn aux2bib_stdin_empty() {
    let mut child = cmd_aux2bib().stdin(Stdio::piped()).spawn().expect(
        "Failed to execute aux2bib",
    );

    {
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(b"").expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert!(output.status.success());
    assert_eq!(output.stdout, []);
}

#[cfg(not(windows))]
#[test]
fn blg2bib_stdin_empty() {
    let mut child = cmd_blg2bib().stdin(Stdio::piped()).spawn().expect(
        "Failed to execute blg2bib",
    );

    {
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(b"").expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert!(output.status.success());
    assert_eq!(output.stdout, []);
}

#[cfg(not(windows))]
#[test]
fn aux2bib_stdin_bibtex() {
    let mut child = cmd_aux2bib().stdin(Stdio::piped()).spawn().expect(
        "Failed to execute aux2bib",
    );

    {
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin
            .write_all(
                b"\
\\relax
\\citation{Higgs:2014aqa}
\\citation{Higgs:2015mei}
\\bibstyle{unsrt}
\\bibdata{test_bibtex}
        ",
            )
            .expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert!(output.status.success());
    // Output could conceivably change in future, so just check that some things are there
    assert!(
        std::str::from_utf8(&output.stdout).unwrap().contains(
            "@article{Higgs:2014aqa,",
        ) &&
            std::str::from_utf8(&output.stdout).unwrap().contains(
                "Higgs, Peter W.",
            ) &&
            std::str::from_utf8(&output.stdout).unwrap().contains(
                "Nobel Lecture: Evading the Goldstone theorem",
            ) &&
            std::str::from_utf8(&output.stdout).unwrap().contains(
                "2014",
            )
    );
    assert!(
        std::str::from_utf8(&output.stdout).unwrap().contains(
            "@article{Higgs:2015mei,",
        ) &&
            std::str::from_utf8(&output.stdout).unwrap().contains(
                "Higgs, P. W.",
            ) &&
            std::str::from_utf8(&output.stdout).unwrap().contains(
                "Evading the Goldstone theorem",
            ) &&
            std::str::from_utf8(&output.stdout).unwrap().contains(
                "2015",
            )
    );
}
<|endoftext|>


<commit_before>use rustc::hir::*;
use rustc::lint::*;

use crate::utils;

const ORD: [&str; 3] = ["core", "cmp", "Ord"];
const PARTIAL_ORD: [&str; 3] = ["core", "cmp", "PartialOrd"];

/// **What it does:**
/// Checks for the usage of negated comparision operators on types which only implement
/// `PartialOrd` (e.g. `f64`).
///
/// **Why is this bad?**
/// These operators make it easy to forget that the underlying types actually allow not only three
/// potential Orderings (Less, Equal, Greater) but also a forth one (Uncomparable). Escpeccially if
/// the operator based comparision result is negated it is easy to miss that fact.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// use core::cmp::Ordering;
///
/// // Bad
/// let a = 1.0;
/// let b = std::f64::NAN;
///
/// let _not_less_or_equal = !(a <= b);
///
/// // Good
/// let a = 1.0;
/// let b = std::f64::NAN;
///
/// let _not_less_or_equal = match a.partial_cmp(&b) {
///     None | Some(Ordering::Greater) => true,
///     _ => false,
/// };
/// ```
declare_lint! {
    pub NEG_CMP_OP_ON_PARTIAL_ORD, Warn,
    "The use of negated comparision operators on partially orded types may produce confusing code."
}

pub struct NoNegCompOpForPartialOrd;

impl LintPass for NoNegCompOpForPartialOrd {
    fn get_lints(&self) -> LintArray {
        lint_array!(NEG_CMP_OP_ON_PARTIAL_ORD)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NoNegCompOpForPartialOrd {

    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        if_chain! {

            if let Expr_::ExprUnary(UnOp::UnNot, ref inner) = expr.node;
            if let Expr_::ExprBinary(ref op, ref left, _) = inner.node;
            if let BinOp_::BiLe | BinOp_::BiGe | BinOp_::BiLt | BinOp_::BiGt = op.node;

            then {

                let ty = cx.tables.expr_ty(left);

                let implements_ord = {
                    if let Some(id) = utils::get_trait_def_id(cx, &ORD) {
                        utils::implements_trait(cx, ty, id, &[])
                    } else {
                        return;
                    }
                };

                let implements_partial_ord = {
                    if let Some(id) = utils::get_trait_def_id(cx, &PARTIAL_ORD) {
                        utils::implements_trait(cx, ty, id, &[])
                    } else {
                        return;
                    }
                };

                if implements_partial_ord && !implements_ord {
                    cx.span_lint(
                        NEG_CMP_OP_ON_PARTIAL_ORD,
                        expr.span,
                        "The use of negated comparision operators on partially orded\
                        types produces code that is hard to read and refactor. Please\
                        consider to use the partial_cmp() instead, to make it clear\
                        that the two values could be incomparable."
                    )
                }
            }
        }
    }
}
<commit_msg>Use declare_clippy_lint instead of declare_lint.<commit_after>use rustc::hir::*;
use rustc::lint::*;

use crate::utils;

const ORD: [&str; 3] = ["core", "cmp", "Ord"];
const PARTIAL_ORD: [&str; 3] = ["core", "cmp", "PartialOrd"];

/// **What it does:**
/// Checks for the usage of negated comparision operators on types which only implement
/// `PartialOrd` (e.g. `f64`).
///
/// **Why is this bad?**
/// These operators make it easy to forget that the underlying types actually allow not only three
/// potential Orderings (Less, Equal, Greater) but also a forth one (Uncomparable). Escpeccially if
/// the operator based comparision result is negated it is easy to miss that fact.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// use core::cmp::Ordering;
///
/// // Bad
/// let a = 1.0;
/// let b = std::f64::NAN;
///
/// let _not_less_or_equal = !(a <= b);
///
/// // Good
/// let a = 1.0;
/// let b = std::f64::NAN;
///
/// let _not_less_or_equal = match a.partial_cmp(&b) {
///     None | Some(Ordering::Greater) => true,
///     _ => false,
/// };
/// ```
declare_clippy_lint! {
    pub NEG_CMP_OP_ON_PARTIAL_ORD,
    complexity,
    "The use of negated comparision operators on partially orded types may produce confusing code."
}

pub struct NoNegCompOpForPartialOrd;

impl LintPass for NoNegCompOpForPartialOrd {
    fn get_lints(&self) -> LintArray {
        lint_array!(NEG_CMP_OP_ON_PARTIAL_ORD)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NoNegCompOpForPartialOrd {

    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        if_chain! {

            if let Expr_::ExprUnary(UnOp::UnNot, ref inner) = expr.node;
            if let Expr_::ExprBinary(ref op, ref left, _) = inner.node;
            if let BinOp_::BiLe | BinOp_::BiGe | BinOp_::BiLt | BinOp_::BiGt = op.node;

            then {

                let ty = cx.tables.expr_ty(left);

                let implements_ord = {
                    if let Some(id) = utils::get_trait_def_id(cx, &ORD) {
                        utils::implements_trait(cx, ty, id, &[])
                    } else {
                        return;
                    }
                };

                let implements_partial_ord = {
                    if let Some(id) = utils::get_trait_def_id(cx, &PARTIAL_ORD) {
                        utils::implements_trait(cx, ty, id, &[])
                    } else {
                        return;
                    }
                };

                if implements_partial_ord && !implements_ord {
                    cx.span_lint(
                        NEG_CMP_OP_ON_PARTIAL_ORD,
                        expr.span,
                        "The use of negated comparision operators on partially orded\
                        types produces code that is hard to read and refactor. Please\
                        consider to use the partial_cmp() instead, to make it clear\
                        that the two values could be incomparable."
                    )
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;
use std::collections::HashMap;
use std::collections::HashSet;

pub fn main() {
    println!("Pipe the puzzle input to stdin");
    let mut edges = HashMap::<char, HashSet<char>>::new();
    let stdin = io::stdin();
    for line in stdin.lock().lines() {
        let line = line.unwrap();
        let numbers = line.chars().collect::<Vec<_>>();
        {
            let set = edges.entry(numbers[0]).or_insert(HashSet::<char>::new());
            set.insert(numbers[1]);
            set.insert(numbers[2]);
        }
        let set = edges.entry(numbers[1]).or_insert(HashSet::<char>::new());
        set.insert(numbers[2]);
    }
    let mut vec: Vec<_> = edges.iter().collect();
    vec.sort_by_key(|&(_, set)| set.len());
    let mut ans = vec.iter().rev().map(|&(&n, _)| n).collect::<String>();
    let (_, last) = vec[0];
    for &c in last {
        ans.push(c);
    }
    println!("{}", ans);
}
<commit_msg>use proper Entry API with a function as a parameter<commit_after>use std::io;
use std::io::prelude::*;
use std::collections::HashMap;
use std::collections::HashSet;

pub fn main() {
    println!("Pipe the puzzle input to stdin");
    let mut edges = HashMap::<char, HashSet<char>>::new();
    let stdin = io::stdin();
    for line in stdin.lock().lines() {
        let line = line.unwrap();
        let numbers = line.chars().collect::<Vec<_>>();
        {
            let set = edges.entry(numbers[0]).or_insert_with(HashSet::<char>::new);
            set.insert(numbers[1]);
            set.insert(numbers[2]);
        }
        let set = edges.entry(numbers[1]).or_insert_with(HashSet::<char>::new);
        set.insert(numbers[2]);
    }
    let mut vec: Vec<_> = edges.iter().collect();
    vec.sort_by_key(|&(_, set)| set.len());
    let mut ans = vec.iter().rev().map(|&(&n, _)| n).collect::<String>();
    let (_, last) = vec[0];
    for &c in last {
        ans.push(c);
    }
    println!("{}", ans);
}
<|endoftext|>


<commit_before>//! Interval-based annotation features.

use bio::utils::{Interval, IntervalError};

pub trait NamedInterval: Sized {

    /// Underlying interval struct.
    fn interval(&self) -> &Interval<u64>;  // TODO: Generalize over interval types.

    /// Name of the interval.
    fn name(&self) -> Option<&str>;

    /// Name setter that returns the implementor itself.
    ///
    /// This function is expected to mutate the implementing type.
    fn with_name<T: Into<String>>(self, name: T) -> Self;

    /// Coordinate setter that returns the implementor itself.
    ///
    /// This function is expected to mutate the implementing type.
    fn with_coords(self, start: u64, end: u64) -> Result<Self, IntervalError>;

    /// Start coordinate of the interval.
    fn start(&self) -> u64 {
        self.interval().start
    }

    /// End coordinate of the interval.
    fn end(&self) -> u64 {
        self.interval().end
    }

    /// The number of bases covered by the interval.
    fn span(&self) -> u64 {
        self.end() - self.start()
    }

    /// Whether two intervals have an overlap or not.
    fn overlaps(&self, other: &Self) -> bool {
        self.start() < other.end() && other.start() < self.end()
    }

    /// Whether one interval completely contains the other.
    fn envelops(&self, other: &Self) -> bool {
        self.start() <= other.start() && self.end() >= other.end()
    }

    /// Whether two intervals cover a contiguous region without any overlaps.
    fn adjacent(&self, other: &Self) -> bool {
        self.end() == other.start() || self.start() == other.end()
    }
}

/// Macro for default function implementations of interval types.
macro_rules! impl_ninterval {
    ($struct_ty:ty) => (

        impl NamedInterval for $struct_ty {

            /// Name of the interval.
            fn name(&self) -> Option<&str> {
                self.name.as_ref().map(|n| n.as_str())
            }

            fn with_name<T>(mut self, name: T) -> $struct_ty
                where T: Into<String>
            {
                self.name = Some(name.into());
                self
            }

            fn interval(&self) -> &Interval<u64> {
                &self.interval
            }

            fn with_coords(mut self, start: u64, end: u64) -> Result<$struct_ty, IntervalError> {
                Interval::new(start..end)
                    .map(|iv| {
                        self.interval = iv;
                        self
                    })
            }
        }

    );
}

/// Default implementation of the `Interval` trait.
///
/// This struct also provides static methods for creating exons, transcripts, and genes.
#[derive(Debug)]
pub struct Feature {
    interval: Interval<u64>,
    name: Option<String>,
}

impl Default for Feature {

    fn default() -> Feature {
        Feature { interval: Interval::new(0..0).unwrap(), name: None }
    }
}

impl_ninterval!(Feature);

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

    #[test]
    fn default() {
        let fx = Feature::default();
        assert_eq!(fx.start(), 0);
        assert_eq!(fx.end(), 0);
        assert_eq!(fx.name(), None);
    }

    #[test]
    fn with_name() {
        let fx1 = Feature::default()
            .with_name("fx1");
        assert_eq!(fx1.start(), 0);
        assert_eq!(fx1.end(), 0);
        assert_eq!(fx1.name(), Some("fx1"));

        let fx2 = Feature::default()
            .with_name("fx2".to_owned());
        assert_eq!(fx2.start(), 0);
        assert_eq!(fx2.end(), 0);
        assert_eq!(fx2.name(), Some("fx2"));
    }

    #[test]
    fn with_coords() {
        let fxm = Feature::default()
            .with_coords(1, 3);
        assert!(fxm.is_ok());
        let fx = fxm.unwrap();
        assert_eq!(fx.start(), 1);
        assert_eq!(fx.end(), 3);
        assert_eq!(fx.name(), None);
    }

    #[test]
    fn with_coords_err() {
        let fxm = Feature::default()
            .with_coords(3, 1);
        assert!(fxm.is_err());
    }

    #[test]
    fn with_multiples() {
        let fxm = Feature::default()
            .with_coords(20, 30)
            .map(|f| f.with_name("fx"));
        assert!(fxm.is_ok());
        let fx = fxm.unwrap();
        assert_eq!(fx.start(), 20);
        assert_eq!(fx.end(), 30);
        assert_eq!(fx.name(), Some("fx"));
    }

    #[test]
    fn span() {
        let fx = Feature::default().with_coords(0, 15).unwrap();
        assert_eq!(fx.span(), 15);
    }

    #[test]
    fn overlaps() {
        let fx1 = Feature::default().with_coords(100, 115).unwrap();

        let fx2 = Feature::default().with_coords(110, 120).unwrap();
        assert!(fx1.overlaps(&fx2));
        assert!(fx1.overlaps(&fx2));

        let fx3 = Feature::default().with_coords(115, 120).unwrap();
        assert!(!fx1.overlaps(&fx3));
        assert!(!fx3.overlaps(&fx1));

        let fx4 = Feature::default().with_coords(90, 100).unwrap();
        assert!(!fx1.overlaps(&fx4));
        assert!(!fx4.overlaps(&fx1));

        let fx5 = Feature::default().with_coords(200, 300).unwrap();
        assert!(!fx1.overlaps(&fx5));
        assert!(!fx5.overlaps(&fx1));
    }
}
<commit_msg>Make test helper function<commit_after>//! Interval-based annotation features.

use bio::utils::{Interval, IntervalError};

pub trait NamedInterval: Sized {

    /// Underlying interval struct.
    fn interval(&self) -> &Interval<u64>;  // TODO: Generalize over interval types.

    /// Name of the interval.
    fn name(&self) -> Option<&str>;

    /// Name setter that returns the implementor itself.
    ///
    /// This function is expected to mutate the implementing type.
    fn with_name<T: Into<String>>(self, name: T) -> Self;

    /// Coordinate setter that returns the implementor itself.
    ///
    /// This function is expected to mutate the implementing type.
    fn with_coords(self, start: u64, end: u64) -> Result<Self, IntervalError>;

    /// Start coordinate of the interval.
    fn start(&self) -> u64 {
        self.interval().start
    }

    /// End coordinate of the interval.
    fn end(&self) -> u64 {
        self.interval().end
    }

    /// The number of bases covered by the interval.
    fn span(&self) -> u64 {
        self.end() - self.start()
    }

    /// Whether two intervals have an overlap or not.
    fn overlaps(&self, other: &Self) -> bool {
        self.start() < other.end() && other.start() < self.end()
    }

    /// Whether one interval completely contains the other.
    fn envelops(&self, other: &Self) -> bool {
        self.start() <= other.start() && self.end() >= other.end()
    }

    /// Whether two intervals cover a contiguous region without any overlaps.
    fn adjacent(&self, other: &Self) -> bool {
        self.end() == other.start() || self.start() == other.end()
    }
}

/// Macro for default function implementations of interval types.
macro_rules! impl_ninterval {
    ($struct_ty:ty) => (

        impl NamedInterval for $struct_ty {

            /// Name of the interval.
            fn name(&self) -> Option<&str> {
                self.name.as_ref().map(|n| n.as_str())
            }

            fn with_name<T>(mut self, name: T) -> $struct_ty
                where T: Into<String>
            {
                self.name = Some(name.into());
                self
            }

            fn interval(&self) -> &Interval<u64> {
                &self.interval
            }

            fn with_coords(mut self, start: u64, end: u64) -> Result<$struct_ty, IntervalError> {
                Interval::new(start..end)
                    .map(|iv| {
                        self.interval = iv;
                        self
                    })
            }
        }

    );
}

/// Default implementation of the `Interval` trait.
///
/// This struct also provides static methods for creating exons, transcripts, and genes.
#[derive(Debug)]
pub struct Feature {
    interval: Interval<u64>,
    name: Option<String>,
}

impl Default for Feature {

    fn default() -> Feature {
        Feature { interval: Interval::new(0..0).unwrap(), name: None }
    }
}

impl_ninterval!(Feature);

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

    #[test]
    fn default() {
        let fx = Feature::default();
        assert_eq!(fx.start(), 0);
        assert_eq!(fx.end(), 0);
        assert_eq!(fx.name(), None);
    }

    #[test]
    fn with_name() {
        let fx1 = Feature::default()
            .with_name("fx1");
        assert_eq!(fx1.start(), 0);
        assert_eq!(fx1.end(), 0);
        assert_eq!(fx1.name(), Some("fx1"));

        let fx2 = Feature::default()
            .with_name("fx2".to_owned());
        assert_eq!(fx2.start(), 0);
        assert_eq!(fx2.end(), 0);
        assert_eq!(fx2.name(), Some("fx2"));
    }

    #[test]
    fn with_coords() {
        let fxm = Feature::default()
            .with_coords(1, 3);
        assert!(fxm.is_ok());
        let fx = fxm.unwrap();
        assert_eq!(fx.start(), 1);
        assert_eq!(fx.end(), 3);
        assert_eq!(fx.name(), None);
    }

    #[test]
    fn with_coords_err() {
        let fxm = Feature::default()
            .with_coords(3, 1);
        assert!(fxm.is_err());
    }

    #[test]
    fn with_multiples() {
        let fxm = Feature::default()
            .with_coords(20, 30)
            .map(|f| f.with_name("fx"));
        assert!(fxm.is_ok());
        let fx = fxm.unwrap();
        assert_eq!(fx.start(), 20);
        assert_eq!(fx.end(), 30);
        assert_eq!(fx.name(), Some("fx"));
    }

    fn make_feature(start: u64, end: u64) -> Feature {
        Feature::default().with_coords(start, end).unwrap()
    }

    #[test]
    fn span() {
        let fx = make_feature(0, 15);
        assert_eq!(fx.span(), 15);
    }

    #[test]
    fn overlaps() {
        let fx1 = make_feature(100, 115);

        let fx2 = make_feature(110, 120);
        assert!(fx1.overlaps(&fx2));
        assert!(fx1.overlaps(&fx2));

        let fx3 = make_feature(115, 120);
        assert!(!fx1.overlaps(&fx3));
        assert!(!fx3.overlaps(&fx1));

        let fx4 = make_feature(90, 100);
        assert!(!fx1.overlaps(&fx4));
        assert!(!fx4.overlaps(&fx1));

        let fx5 = make_feature(200, 300);
        assert!(!fx1.overlaps(&fx5));
        assert!(!fx5.overlaps(&fx1));
    }
}
<|endoftext|>


<commit_before>
include!(concat!(env!("OUT_DIR"), "/exceptional-grammar.rs"));

#[cfg(test)]
mod test_helpers {
    use super::*;
    use ast::*;
    use num::rational::{Ratio};
    use num::{BigInt};

    pub fn l_string(name: &str) -> Literal {
        Literal::CharString(
           name.to_owned()
        )
    }

    pub fn l_number(num: i64, denom: i64) -> Literal {
        Literal::Number(
            Ratio::new(
                BigInt::from(num),
                BigInt::from(denom)
            )
        )
    }

    pub fn l_bool(b: bool) -> Literal {
        match b {
            true => Literal::Boolean(true),
            false => Literal::Boolean(false)
        }
    }

    pub fn l_function(args: Vec<String>, statements: Vec<Statement>) -> Literal {
        Literal::Fn(Box::new((args, statements)))
    }

    pub fn s_assign(name: &str, literal: Literal) -> Statement {
        Statement::Assign(
            true,
            name.to_owned(),
            Box::new(
                e_literal(
                    literal
                )
            )
        )
    }

    pub fn s_call(name: &str, args: Vec<Expression>) -> Statement {
        Statement::Call(name.to_owned(), args)
    }

    pub fn e_literal(literal: Literal) -> Expression {
        Expression::Literal(literal)
    }

    pub fn parse_expression(input: &str) -> Expression {
        expression(input).unwrap()
    }

    pub fn parse_statements(input: &str) -> Vec<Statement> {
        statements(input).unwrap()
    }

    pub fn parse_literal(input: &str) -> Literal {
        literal(input).unwrap()
    }
}

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

    #[test]
    fn parses_number() {
        assert_eq!(
            parse_literal(&"1234"),
            l_number(1234, 1)
        );

        assert_eq!(
            parse_literal(&"0011"),
            l_number(11, 1)
        );
    }

    #[test]
    fn parses_strings() {
        assert_eq!(
            parse_literal(&"\"\""),
            l_string(&"")
        );

        assert_eq!(
            parse_literal(&"\"string with more words\""),
            l_string(&"string with more words")
        );
    }

    #[test]
    fn parses_booleans() {
        assert_eq!(
            parse_literal(&"true"),
            l_bool(true)
        );

        assert_eq!(
            parse_literal(&"false"),
            l_bool(false)
        );
    }
}

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

    #[test]
    fn parses_simple_literal_expressions() {
        assert_eq!(
            parse_expression(&"1"),
            e_literal(l_number(1, 1))
        );

        assert_eq!(
            parse_expression(&"\"\""),
            e_literal(l_string(&""))
        )
    }

    #[test]
    fn parses_simple_functions() {
        assert_eq!(
            parse_expression(&"def() do end"),
            e_literal(
                l_function(vec![], vec![])
            )
        )
    }

    #[test]
    fn parses_functions_with_args() {
        assert_eq!(
            parse_expression(&"def(a, b) do end"),
            e_literal(
                l_function(vec!["a".to_owned(), "b".to_owned()], vec![])
            )
        )
    }

    #[test]
    fn prases_functions_with_bodies() {
        assert_eq!(
            parse_expression(&"def(a, b) do\nlet c = 1\nend"),
            e_literal(
                l_function(
                    vec!["a".to_owned(), "b".to_owned()],
                    vec![s_assign(&"c", l_number(1, 1))]
                )
            )
        )
    }
}

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

    #[test]
    fn parses_assigns() {
        assert_eq!(
            parse_statements(&"let a = 1"),
            [s_assign(&"a", l_number(1, 1))]
        )
    }

    #[test]
    fn parses_calls() {
        assert_eq!(
            parse_statements("a()"),
            [s_call(&"a", vec![])]
        )
    }

    #[test]
    fn parses_calls_with_simple_args() {
        assert_eq!(
            parse_statements("a(1)"),
            [s_call(&"a", vec![e_literal(v_ratio(1, 1))])]
        )
    }
}
<commit_msg>Add expression and math tests<commit_after>
include!(concat!(env!("OUT_DIR"), "/exceptional-grammar.rs"));

#[cfg(test)]
mod test_helpers {
    use super::*;
    use ast::*;
    use num::rational::{Ratio};
    use num::{BigInt};

    pub fn l_string(name: &str) -> Literal {
        Literal::CharString(
           name.to_owned()
        )
    }

    pub fn l_number(num: i64, denom: i64) -> Literal {
        Literal::Number(
            Ratio::new(
                BigInt::from(num),
                BigInt::from(denom)
            )
        )
    }

    pub fn l_bool(b: bool) -> Literal {
        match b {
            true => Literal::Boolean(true),
            false => Literal::Boolean(false)
        }
    }

    pub fn l_function(args: Vec<String>, statements: Vec<Statement>) -> Literal {
        Literal::Fn(Box::new((args, statements)))
    }

    pub fn s_assign(name: &str, literal: Literal) -> Statement {
        Statement::Assign(
            true,
            name.to_owned(),
            Box::new(
                e_literal(
                    literal
                )
            )
        )
    }

    pub fn s_call(name: &str, args: Vec<Expression>) -> Statement {
        Statement::Call(name.to_owned(), args)
    }

    pub fn e_literal(literal: Literal) -> Expression {
        Expression::Literal(literal)
    }

    pub fn e_binop(op: &str, left: Expression, right: Expression) -> Expression {
        Expression::BinOp(op.to_owned(), Box::new(left), Box::new(right))
    }

    pub fn parse_expression(input: &str) -> Expression {
        expression(input).unwrap()
    }

    pub fn parse_statements(input: &str) -> Vec<Statement> {
        statements(input).unwrap()
    }

    pub fn parse_literal(input: &str) -> Literal {
        literal(input).unwrap()
    }
}

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

    #[test]
    fn parses_number() {
        assert_eq!(
            parse_literal(&"1234"),
            l_number(1234, 1)
        );

        assert_eq!(
            parse_literal(&"0011"),
            l_number(11, 1)
        );
    }

    #[test]
    fn parses_strings() {
        assert_eq!(
            parse_literal(&"\"\""),
            l_string(&"")
        );

        assert_eq!(
            parse_literal(&"\"string with more words\""),
            l_string(&"string with more words")
        );
    }

    #[test]
    fn parses_booleans() {
        assert_eq!(
            parse_literal(&"true"),
            l_bool(true)
        );

        assert_eq!(
            parse_literal(&"false"),
            l_bool(false)
        );
    }
}

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

    #[test]
    fn parses_simple_literal_expressions() {
        assert_eq!(
            parse_expression(&"1"),
            e_literal(l_number(1, 1))
        );

        assert_eq!(
            parse_expression(&"\"\""),
            e_literal(l_string(&""))
        )
    }

    #[test]
    fn parses_math() {
        assert_eq!(
            parse_expression(&"1 + 2 * 3 / 5 - 4"),
            e_binop(
                "+",
                e_literal(l_number(1, 1)),
                e_binop(
                    "-",
                    e_binop(
                        "*",
                        e_literal(l_number(2, 1)),
                        e_binop("/", e_literal(l_number(3, 1)), e_literal(l_number(5, 1)))
                    ),
                    e_literal(l_number(4, 1)),
                )
            )
        );
    }

    #[test]
    fn parses_simple_functions() {
        assert_eq!(
            parse_expression(&"def() do end"),
            e_literal(
                l_function(vec![], vec![])
            )
        )
    }

    #[test]
    fn parses_functions_with_args() {
        assert_eq!(
            parse_expression(&"def(a, b) do end"),
            e_literal(
                l_function(vec!["a".to_owned(), "b".to_owned()], vec![])
            )
        )
    }

    #[test]
    fn prases_functions_with_bodies() {
        assert_eq!(
            parse_expression(&"def(a, b) do\nlet c = 1\nend"),
            e_literal(
                l_function(
                    vec!["a".to_owned(), "b".to_owned()],
                    vec![s_assign(&"c", l_number(1, 1))]
                )
            )
        )
    }
}

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

    #[test]
    fn parses_assigns() {
        assert_eq!(
            parse_statements(&"let a = 1"),
            [s_assign(&"a", l_number(1, 1))]
        )
    }

    #[test]
    fn parses_calls() {
        assert_eq!(
            parse_statements("a()"),
            [s_call(&"a", vec![])]
        )
    }

    #[test]
    fn parses_calls_with_simple_args() {
        assert_eq!(
            parse_statements("a(1)"),
            [s_call(&"a", vec![e_literal(l_number(1, 1))])]
        )
    }

    #[test]
    fn parses_calls_with_expressive_args() {
        let args = vec![
            e_binop(
                "+",
                e_literal(l_number(1, 1)),
                e_literal(l_number(2, 1)),
            ),
            e_literal(l_function(vec!["x".to_owned()], vec![]))
        ];
        assert_eq!(
            parse_statements("a(1 + 2, def(x) do end)"),
            [s_call(&"a", args)]
        )
    }
}
<|endoftext|>


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

use ipc_channel::ipc::IpcSender;
use opts;
use serde::Serialize;
use std::any::Any;
use std::borrow::ToOwned;
use std::io::{Write, stderr};
use std::panic::{PanicInfo, take_hook, set_hook};
use std::sync::mpsc::Sender;
use std::thread;
use std::thread::Builder;
use thread_state;

pub type PanicReason = Option<String>;

pub fn spawn_named<F>(name: String, f: F)
    where F: FnOnce() + Send + 'static
{
    let builder = thread::Builder::new().name(name);

    if opts::get().full_backtraces {
        builder.spawn(f).unwrap();
        return;
    }

    let f_with_hook = move || {
        let hook = take_hook();

        let new_hook = move |info: &PanicInfo| {
            let payload = info.payload();
            if let Some(s) = payload.downcast_ref::<String>() {
                if s.contains("SendError") {
                    let err = stderr();
                    let _ = write!(err.lock(), "Thread \"{}\" panicked with an unwrap of \
                                                `SendError` (backtrace skipped)\n",
                           thread::current().name().unwrap_or("<unknown thread>"));
                    return;
                } else if s.contains("RecvError")  {
                    let err = stderr();
                    let _ = write!(err.lock(), "Thread \"{}\" panicked with an unwrap of \
                                                `RecvError` (backtrace skipped)\n",
                           thread::current().name().unwrap_or("<unknown thread>"));
                    return;
                }
            }
            hook(&info);
        };
        set_hook(Box::new(new_hook));
        f();
    };

    builder.spawn(f_with_hook).unwrap();
}

pub trait AddFailureDetails {
    fn add_panic_message(&mut self, message: String);
    fn add_panic_object(&mut self, object: Box<Any>) {
        if let Some(message) = object.downcast_ref::<String>() {
            self.add_panic_message(message.to_owned());
        } else if let Some(&message) = object.downcast_ref::<&'static str>() {
            self.add_panic_message(message.to_owned());
        }
    }
}

/// An abstraction over `Sender<T>` and `IpcSender<T>`, for use in
/// `spawn_named_with_send_on_failure`.
pub trait SendOnFailure {
    type Value;
    fn send_on_failure(&mut self, value: Self::Value);
}

impl<T> SendOnFailure for Sender<T> where T: Send + 'static {
    type Value = T;
    fn send_on_failure(&mut self, value: T) {
        // Discard any errors to avoid double-panic
        let _ = self.send(value);
    }
}

impl<T> SendOnFailure for IpcSender<T> where T: Send + Serialize + 'static {
    type Value = T;
    fn send_on_failure(&mut self, value: T) {
        // Discard any errors to avoid double-panic
        let _ = self.send(value);
    }
}

/// Arrange to send a particular message to a channel if the thread fails.
pub fn spawn_named_with_send_on_failure<F, T, S>(name: String,
                                                 state: thread_state::ThreadState,
                                                 f: F,
                                                 mut msg: T,
                                                 mut dest: S)
    where F: FnOnce() + Send + 'static,
          T: Send + AddFailureDetails + 'static,
          S: Send + SendOnFailure + 'static,
          S::Value: From<T>,
{
    let future_handle = thread::Builder::new().name(name.to_owned()).spawn(move || {
        thread_state::initialize(state);
        f()
    }).unwrap();

    let watcher_name = format!("{}Watcher", name);
    Builder::new().name(watcher_name).spawn(move || {
        match future_handle.join() {
            Ok(()) => (),
            Err(err) => {
                debug!("{} failed, notifying constellation", name);
                msg.add_panic_object(err);
                dest.send_on_failure(S::Value::from(msg));
            }
        }
    }).unwrap();
}
<commit_msg>Make add_panic_object in thread.rs borrow rather than own the object.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use ipc_channel::ipc::IpcSender;
use opts;
use serde::Serialize;
use std::any::Any;
use std::borrow::ToOwned;
use std::io::{Write, stderr};
use std::panic::{PanicInfo, take_hook, set_hook};
use std::sync::mpsc::Sender;
use std::thread;
use std::thread::Builder;
use thread_state;

pub type PanicReason = Option<String>;

pub fn spawn_named<F>(name: String, f: F)
    where F: FnOnce() + Send + 'static
{
    let builder = thread::Builder::new().name(name);

    if opts::get().full_backtraces {
        builder.spawn(f).unwrap();
        return;
    }

    let f_with_hook = move || {
        let hook = take_hook();

        let new_hook = move |info: &PanicInfo| {
            let payload = info.payload();
            if let Some(s) = payload.downcast_ref::<String>() {
                if s.contains("SendError") {
                    let err = stderr();
                    let _ = write!(err.lock(), "Thread \"{}\" panicked with an unwrap of \
                                                `SendError` (backtrace skipped)\n",
                           thread::current().name().unwrap_or("<unknown thread>"));
                    return;
                } else if s.contains("RecvError")  {
                    let err = stderr();
                    let _ = write!(err.lock(), "Thread \"{}\" panicked with an unwrap of \
                                                `RecvError` (backtrace skipped)\n",
                           thread::current().name().unwrap_or("<unknown thread>"));
                    return;
                }
            }
            hook(&info);
        };
        set_hook(Box::new(new_hook));
        f();
    };

    builder.spawn(f_with_hook).unwrap();
}

pub trait AddFailureDetails {
    fn add_panic_message(&mut self, message: String);
    fn add_panic_object(&mut self, object: &Any) {
        if let Some(message) = object.downcast_ref::<String>() {
            self.add_panic_message(message.to_owned());
        } else if let Some(&message) = object.downcast_ref::<&'static str>() {
            self.add_panic_message(message.to_owned());
        }
    }
}

/// An abstraction over `Sender<T>` and `IpcSender<T>`, for use in
/// `spawn_named_with_send_on_failure`.
pub trait SendOnFailure {
    type Value;
    fn send_on_failure(&mut self, value: Self::Value);
}

impl<T> SendOnFailure for Sender<T> where T: Send + 'static {
    type Value = T;
    fn send_on_failure(&mut self, value: T) {
        // Discard any errors to avoid double-panic
        let _ = self.send(value);
    }
}

impl<T> SendOnFailure for IpcSender<T> where T: Send + Serialize + 'static {
    type Value = T;
    fn send_on_failure(&mut self, value: T) {
        // Discard any errors to avoid double-panic
        let _ = self.send(value);
    }
}

/// Arrange to send a particular message to a channel if the thread fails.
pub fn spawn_named_with_send_on_failure<F, T, S>(name: String,
                                                 state: thread_state::ThreadState,
                                                 f: F,
                                                 mut msg: T,
                                                 mut dest: S)
    where F: FnOnce() + Send + 'static,
          T: Send + AddFailureDetails + 'static,
          S: Send + SendOnFailure + 'static,
          S::Value: From<T>,
{
    let future_handle = thread::Builder::new().name(name.to_owned()).spawn(move || {
        thread_state::initialize(state);
        f()
    }).unwrap();

    let watcher_name = format!("{}Watcher", name);
    Builder::new().name(watcher_name).spawn(move || {
        match future_handle.join() {
            Ok(()) => (),
            Err(err) => {
                debug!("{} failed, notifying constellation", name);
                msg.add_panic_object(&*err);
                dest.send_on_failure(S::Value::from(msg));
            }
        }
    }).unwrap();
}
<|endoftext|>