<commit_before>//! Read and write NDArrays as Numpy arrays

use ndarray::prelude::*;
use ndarray as nd;
use std::fs::File;
use std::path::Path;
use std::ptr;
use std::str;
use std::io::{Read, Write};
use regex::bytes::Regex;
use byteorder::{LittleEndian, BigEndian, ReadBytesExt, WriteBytesExt};
use errors::*;
use memmap::{Mmap, Protection};

/// Write an array as a numpy array, fast but only works for native byte order
pub fn write_matrix<S, P>(path: P, arr: &ArrayBase<S, Ix2>) -> Result<()>
    where S: nd::Data<Elem=f64>, P: AsRef<Path> {
    let header_nospace = format!("{{'descr': '<f8', 'fortran_order': False, 'shape': ({},{})}}",
        arr.shape()[0], arr.shape()[1]);
    let virtual_len =
        // Calculating how many bytes we have in the header, so we can get alignment
        header_nospace.len()
        + 6 // The magic string
        + 2 // The version number
        + 2 // An unsigned 2-byte integer for header length
        + 1 ; // Because there will be a \n added
    let padding_needed = (((virtual_len + 15) / 16) * 16) - virtual_len; // to get to the next 16

    // Numpy version 1.0
    let mut writer = File::create(path)?;
    writer.write_all(b"\x93NUMPY\x01\x00")?;
    writer.write_u16::<LittleEndian>((header_nospace.len()
        + padding_needed
        + 1) // newline
        // Magic string, version number and 2 bytes for the header length number not included.
        as u16
        )?;
    write!(writer, "{}{}\n", header_nospace, " ".repeat(padding_needed))?;
    unsafe {
        // O(N) array copy without memory overhead.
        assert!(arr.is_standard_layout(), "To write an array it needs to be in C order (for now).");
        // Treat the incoming data as floating point
        writer.write_all(::std::slice::from_raw_parts(arr.as_ptr() as *const u8, arr.len()*8))?;
    };
    Ok(())
}

/// Read a Numpy matrix into memory. Be careful if it's large. You could run out of memory.
///
/// You need to know the number of dimensions at compile time so for convenience, we assume you
/// need a matrix. Also, this method is fast but only works for native byte order.
pub fn read_matrix<P: AsRef<Path>>(path: P) -> Result<Array2<f64>> {
    let header_match = Regex::new(r"NUMPY\x01\x00(?s:..)\{'descr': ?'<f8', ?'fortran_order': ?False, ?'shape': ?\((\d+), ?(\d+)\)\} *\n").unwrap();
    let mut reader = File::open(path.as_ref())?;
    let mut content = vec![];
    reader.read_to_end(&mut content)?;
    // The skip and the nested context here is so that we can regex parse (with a borrow)
    // and then reuse the buffer as the array. This way there are never two copies in memory.
    let res: Result<(usize, usize, usize)> = {
        let captures = header_match.captures(&content)
            .ok_or(helpful_complaint(path.as_ref(), &content))?;
        Ok((// where the full match ends
            captures.get(0).unwrap().end(),
            // The shape of the array as described in the metadata
            str::from_utf8(&captures[1]).unwrap().parse().unwrap(),
            str::from_utf8(&captures[2]).unwrap().parse().unwrap()
        ))
    };
    let (skip, h, w) = res?;
    let content_f64 = unsafe {
        // O(N) array copy without memory overhead.
        let length = content.len() - skip;
        assert_eq!(length, h*w*8,
            "The numpy file's array is the wrong length for a {}x{} array. \
            It should be {} elements, ({} bytes), but it is actually {} bytes.",
            h, w, h*w, h*w*8, length
        );
        ptr::copy((&content[skip..]).as_ptr(),
                  (&mut content[..length]).as_mut_ptr(),
                  length);
        content.set_len(length);
        // Treat the incoming data as floating point
        let mut out : Vec<f64> = ::std::mem::transmute(content);
        out.set_len(length/8);
        out
    };
    Ok(ArrayBase::from_shape_vec([h, w], content_f64)?)
}

pub struct MatFile(usize, usize, Mmap);

/// Load a Numpy matrix as an mmap. This only consumes address space. (Part 1)
///
/// This is a two-step process because the Mmap needs to outlive the matrix.
pub fn open_matrix_mmap<P: AsRef<Path>>(path: P) -> Result<MatFile> {
    let header_match = Regex::new(r"NUMPY\x01\x00(?s:..)\{'descr': ?'<f8', ?'fortran_order': ?False, ?'shape': ?\((\d+), ?(\d+)\)\} *\n").unwrap();
    let mut reader = File::open(path.as_ref())?;
    let mut content = Vec::with_capacity(65536);
    reader.read_exact(&mut content)?;
    // The skip and the nested context here is so that we can regex parse (with a borrow)
    // and then reuse the buffer as the array. This way there are never two copies in memory.
    let captures = header_match.captures(&content)
        .ok_or(helpful_complaint(path.as_ref(), &content))?;
    // where the full match ends
    let skip = captures.get(0).unwrap().end();
    // The shape of the array as described in the metadata
    let h = str::from_utf8(&captures[1]).unwrap().parse().unwrap();
    let w = str::from_utf8(&captures[2]).unwrap().parse().unwrap();

    Ok(MatFile(h, w, Mmap::open_with_offset(&reader, Protection::Read, skip, h*w*8)?))
}

/// Load a Numpy matrix as an mmap (Part 2)
///
/// You need to know the number of dimensions at compile time so for convenience, we assume you
/// need a matrix. Also, this method is even faster than read_matrix but only works for native byte
/// order.
///
/// This is different than you might expect. The file you read from must outlive the array,
/// because the array is based on an mmap of that file (so that it doesn't read it into memory).
pub fn read_matrix_mmap<'t>(mmap: &'t MatFile) -> Result<ArrayView2<'t, f64>> {
    unsafe {
        let new_slice= ::std::slice::from_raw_parts(mmap.2.ptr() as *const f64, mmap.2.len()/8);
        Ok(ArrayView2::from_shape([mmap.0, mmap.1], new_slice)?)
    }
}

/// Tell the user more info about the file
///
/// It seems verbose but you can see this error often so it save you time.
fn helpful_complaint(p: &Path, header: &[u8]) -> Error {
    let complaint = format!(
        "Expected {} to be an uncompressed numpy (.npy) file, but couldn't \
        parse the header. The first hundred bytes look like: \n\n{}\n\n\
        As bytes, the header is as follows: \n\n{:?}\n\n\
        It should look something like this example, where . are non-printable characters: \
        NUMPY..{{'descr': '<f8', 'fortran_order': False, 'shape': (34, 27)}}\
        Note: Cabarrus only supports 2D big-endian 64-bit float matrices in C order (for \
        simplicity). You may need to change the dtype accordingly.",
        p.display(),
        String::from_utf8_lossy(&header[..100]),
        &header[..100]);
    Error::Other(complaint)
}<commit_msg>Handle super short files<commit_after>//! Read and write NDArrays as Numpy arrays

use ndarray::prelude::*;
use ndarray as nd;
use std::fs::File;
use std::path::Path;
use std::ptr;
use std::str;
use std::io::{Read, Write};
use regex::bytes::Regex;
use byteorder::{LittleEndian, BigEndian, ReadBytesExt, WriteBytesExt};
use errors::*;
use memmap::{Mmap, Protection};

/// Write an array as a numpy array, fast but only works for native byte order
pub fn write_matrix<S, P>(path: P, arr: &ArrayBase<S, Ix2>) -> Result<()>
    where S: nd::Data<Elem=f64>, P: AsRef<Path> {
    let header_nospace = format!("{{'descr': '<f8', 'fortran_order': False, 'shape': ({},{})}}",
        arr.shape()[0], arr.shape()[1]);
    let virtual_len =
        // Calculating how many bytes we have in the header, so we can get alignment
        header_nospace.len()
        + 6 // The magic string
        + 2 // The version number
        + 2 // An unsigned 2-byte integer for header length
        + 1 ; // Because there will be a \n added
    let padding_needed = (((virtual_len + 15) / 16) * 16) - virtual_len; // to get to the next 16

    // Numpy version 1.0
    let mut writer = File::create(path)?;
    writer.write_all(b"\x93NUMPY\x01\x00")?;
    writer.write_u16::<LittleEndian>((header_nospace.len()
        + padding_needed
        + 1) // newline
        // Magic string, version number and 2 bytes for the header length number not included.
        as u16
        )?;
    write!(writer, "{}{}\n", header_nospace, " ".repeat(padding_needed))?;
    unsafe {
        // O(N) array copy without memory overhead.
        assert!(arr.is_standard_layout(), "To write an array it needs to be in C order (for now).");
        // Treat the incoming data as floating point
        writer.write_all(::std::slice::from_raw_parts(arr.as_ptr() as *const u8, arr.len()*8))?;
    };
    Ok(())
}

/// Read a Numpy matrix into memory. Be careful if it's large. You could run out of memory.
///
/// You need to know the number of dimensions at compile time so for convenience, we assume you
/// need a matrix. Also, this method is fast but only works for native byte order.
pub fn read_matrix<P: AsRef<Path>>(path: P) -> Result<Array2<f64>> {
    let header_match = Regex::new(r"NUMPY\x01\x00(?s:..)\{'descr': ?'<f8', ?'fortran_order': ?False, ?'shape': ?\((\d+), ?(\d+)\)\} *\n").unwrap();
    let mut reader = File::open(path.as_ref())?;
    let mut content = vec![];
    reader.read_to_end(&mut content)?;
    // The skip and the nested context here is so that we can regex parse (with a borrow)
    // and then reuse the buffer as the array. This way there are never two copies in memory.
    let res: Result<(usize, usize, usize)> = {
        let captures = header_match.captures(&content)
            .ok_or(helpful_complaint(path.as_ref(), &content))?;
        Ok((// where the full match ends
            captures.get(0).unwrap().end(),
            // The shape of the array as described in the metadata
            str::from_utf8(&captures[1]).unwrap().parse().unwrap(),
            str::from_utf8(&captures[2]).unwrap().parse().unwrap()
        ))
    };
    let (skip, h, w) = res?;
    let content_f64 = unsafe {
        // O(N) array copy without memory overhead.
        let length = content.len() - skip;
        assert_eq!(length, h*w*8,
            "The numpy file's array is the wrong length for a {}x{} array. \
            It should be {} elements, ({} bytes), but it is actually {} bytes.",
            h, w, h*w, h*w*8, length
        );
        ptr::copy((&content[skip..]).as_ptr(),
                  (&mut content[..length]).as_mut_ptr(),
                  length);
        content.set_len(length);
        // Treat the incoming data as floating point
        let mut out : Vec<f64> = ::std::mem::transmute(content);
        out.set_len(length/8);
        out
    };
    Ok(ArrayBase::from_shape_vec([h, w], content_f64)?)
}

pub struct MatFile(usize, usize, Mmap);

/// Load a Numpy matrix as an mmap. This only consumes address space. (Part 1)
///
/// This is a two-step process because the Mmap needs to outlive the matrix.
pub fn open_matrix_mmap<P: AsRef<Path>>(path: P) -> Result<MatFile> {
    let header_match = Regex::new(r"NUMPY\x01\x00(?s:..)\{'descr': ?'<f8', ?'fortran_order': ?False, ?'shape': ?\((\d+), ?(\d+)\)\} *\n").unwrap();
    let mut reader = File::open(path.as_ref())?;
    let mut content = Vec::with_capacity(65536);
    reader.read_exact(&mut content)?;
    // The skip and the nested context here is so that we can regex parse (with a borrow)
    // and then reuse the buffer as the array. This way there are never two copies in memory.
    let captures = header_match.captures(&content)
        .ok_or(helpful_complaint(path.as_ref(), &content))?;
    // where the full match ends
    let skip = captures.get(0).unwrap().end();
    // The shape of the array as described in the metadata
    let h = str::from_utf8(&captures[1]).unwrap().parse().unwrap();
    let w = str::from_utf8(&captures[2]).unwrap().parse().unwrap();

    Ok(MatFile(h, w, Mmap::open_with_offset(&reader, Protection::Read, skip, h*w*8)?))
}

/// Load a Numpy matrix as an mmap (Part 2)
///
/// You need to know the number of dimensions at compile time so for convenience, we assume you
/// need a matrix. Also, this method is even faster than read_matrix but only works for native byte
/// order.
///
/// This is different than you might expect. The file you read from must outlive the array,
/// because the array is based on an mmap of that file (so that it doesn't read it into memory).
pub fn read_matrix_mmap<'t>(mmap: &'t MatFile) -> Result<ArrayView2<'t, f64>> {
    unsafe {
        let new_slice= ::std::slice::from_raw_parts(mmap.2.ptr() as *const f64, mmap.2.len()/8);
        Ok(ArrayView2::from_shape([mmap.0, mmap.1], new_slice)?)
    }
}

/// Tell the user more info about the file
///
/// It seems verbose but you can see this error often so it save you time.
fn helpful_complaint(p: &Path, header: &[u8]) -> Error {
    let cap = ::std::cmp::min(header.len(), 100);
    let complaint = format!(
        "Expected {} to be an uncompressed numpy (.npy) file, but couldn't \
        parse the header. The first hundred bytes look like: \n\n{}\n\n\
        As bytes, the header is as follows: \n\n{:?}\n\n\
        It should look something like this example, where . are non-printable characters: \
        NUMPY..{{'descr': '<f8', 'fortran_order': False, 'shape': (34, 27)}}\
        Note: Cabarrus only supports 2D big-endian 64-bit float matrices in C order (for \
        simplicity). You may need to change the dtype accordingly.",
        p.display(),
        String::from_utf8_lossy(&header[..cap]),
        &header[..cap]);
    Error::Other(complaint)
}<|endoftext|>


<commit_before>//! Emit diagnostics using the `annotate-snippets` library
//!
//! This is the equivalent of `./emitter.rs` but making use of the
//! [`annotate-snippets`][annotate_snippets] library instead of building the output ourselves.
//!
//! [annotate_snippets]: https://docs.rs/crate/annotate-snippets/

use crate::emitter::FileWithAnnotatedLines;
use crate::snippet::Line;
use crate::{CodeSuggestion, Diagnostic, DiagnosticId, Emitter, Level, SubDiagnostic};
use annotate_snippets::display_list::{DisplayList, FormatOptions};
use annotate_snippets::snippet::*;
use rustc_data_structures::sync::Lrc;
use rustc_span::source_map::SourceMap;
use rustc_span::{MultiSpan, SourceFile};

/// Generates diagnostics using annotate-snippet
pub struct AnnotateSnippetEmitterWriter {
    source_map: Option<Lrc<SourceMap>>,
    /// If true, hides the longer explanation text
    short_message: bool,
    /// If true, will normalize line numbers with `LL` to prevent noise in UI test diffs.
    ui_testing: bool,

    macro_backtrace: bool,
}

impl Emitter for AnnotateSnippetEmitterWriter {
    /// The entry point for the diagnostics generation
    fn emit_diagnostic(&mut self, diag: &Diagnostic) {
        let mut children = diag.children.clone();
        let (mut primary_span, suggestions) = self.primary_span_formatted(&diag);

        self.fix_multispans_in_extern_macros_and_render_macro_backtrace(
            &self.source_map,
            &mut primary_span,
            &mut children,
            &diag.level,
            self.macro_backtrace,
        );

        self.emit_messages_default(
            &diag.level,
            diag.message(),
            &diag.code,
            &primary_span,
            &children,
            &suggestions,
        );
    }

    fn source_map(&self) -> Option<&Lrc<SourceMap>> {
        self.source_map.as_ref()
    }

    fn should_show_explain(&self) -> bool {
        !self.short_message
    }
}

/// Provides the source string for the given `line` of `file`
fn source_string(file: Lrc<SourceFile>, line: &Line) -> String {
    file.get_line(line.line_index - 1).map(|a| a.to_string()).unwrap_or_default()
}

/// Maps `Diagnostic::Level` to `snippet::AnnotationType`
fn annotation_type_for_level(level: Level) -> AnnotationType {
    match level {
        Level::Bug | Level::Fatal | Level::Error => AnnotationType::Error,
        Level::Warning => AnnotationType::Warning,
        Level::Note => AnnotationType::Note,
        Level::Help => AnnotationType::Help,
        // FIXME(#59346): Not sure how to map these two levels
        Level::Cancelled | Level::FailureNote => AnnotationType::Error,
    }
}

impl AnnotateSnippetEmitterWriter {
    pub fn new(
        source_map: Option<Lrc<SourceMap>>,
        short_message: bool,
        macro_backtrace: bool,
    ) -> Self {
        Self { source_map, short_message, ui_testing: false, macro_backtrace }
    }

    /// Allows to modify `Self` to enable or disable the `ui_testing` flag.
    ///
    /// If this is set to true, line numbers will be normalized as `LL` in the output.
    pub fn ui_testing(mut self, ui_testing: bool) -> Self {
        self.ui_testing = ui_testing;
        self
    }

    fn emit_messages_default(
        &mut self,
        level: &Level,
        message: String,
        code: &Option<DiagnosticId>,
        msp: &MultiSpan,
        _children: &[SubDiagnostic],
        _suggestions: &[CodeSuggestion],
    ) {
        if let Some(source_map) = &self.source_map {
            // Make sure our primary file comes first
            let primary_lo = if let Some(ref primary_span) = msp.primary_span().as_ref() {
                source_map.lookup_char_pos(primary_span.lo())
            } else {
                // FIXME(#59346): Not sure when this is the case and what
                // should be done if it happens
                return;
            };
            let annotated_files =
                FileWithAnnotatedLines::collect_annotations(msp, &self.source_map);
            // owned: line source, line index, annotations
            type Owned = (String, usize, Vec<crate::snippet::Annotation>);
            let origin = primary_lo.file.name.to_string();
            let annotated_files: Vec<Owned> = annotated_files
                .into_iter()
                .flat_map(|annotated_file| {
                    let file = annotated_file.file;
                    annotated_file
                        .lines
                        .into_iter()
                        .map(|line| {
                            (source_string(file.clone(), &line), line.line_index, line.annotations)
                        })
                        .collect::<Vec<Owned>>()
                })
                .collect();
            let snippet = Snippet {
                title: Some(Annotation {
                    label: Some(&message),
                    id: code.as_ref().map(|c| match c {
                        DiagnosticId::Error(val) | DiagnosticId::Lint(val) => val.as_str(),
                    }),
                    annotation_type: annotation_type_for_level(*level),
                }),
                footer: vec![],
                opt: FormatOptions { color: true, anonymized_line_numbers: self.ui_testing },
                slices: annotated_files
                    .iter()
                    .map(|(source, line_index, annotations)| {
                        Slice {
                            source,
                            line_start: *line_index,
                            origin: Some(&origin),
                            // FIXME(#59346): Not really sure when `fold` should be true or false
                            fold: false,
                            annotations: annotations
                                .into_iter()
                                .map(|annotation| SourceAnnotation {
                                    range: (annotation.start_col, annotation.end_col),
                                    label: annotation
                                        .label
                                        .as_ref()
                                        .map(|s| s.as_str())
                                        .unwrap_or_default(),
                                    annotation_type: annotation_type_for_level(*level),
                                })
                                .collect(),
                        }
                    })
                    .collect(),
            };
            // FIXME(#59346): Figure out if we can _always_ print to stderr or not.
            // `emitter.rs` has the `Destination` enum that lists various possible output
            // destinations.
            eprintln!("{}", DisplayList::from(snippet))
        }
        // FIXME(#59346): Is it ok to return None if there's no source_map?
    }
}
<commit_msg>Fix make sure out primary file comes first<commit_after>//! Emit diagnostics using the `annotate-snippets` library
//!
//! This is the equivalent of `./emitter.rs` but making use of the
//! [`annotate-snippets`][annotate_snippets] library instead of building the output ourselves.
//!
//! [annotate_snippets]: https://docs.rs/crate/annotate-snippets/

use crate::emitter::FileWithAnnotatedLines;
use crate::snippet::Line;
use crate::{CodeSuggestion, Diagnostic, DiagnosticId, Emitter, Level, SubDiagnostic};
use annotate_snippets::display_list::{DisplayList, FormatOptions};
use annotate_snippets::snippet::*;
use rustc_data_structures::sync::Lrc;
use rustc_span::source_map::SourceMap;
use rustc_span::{MultiSpan, SourceFile};

/// Generates diagnostics using annotate-snippet
pub struct AnnotateSnippetEmitterWriter {
    source_map: Option<Lrc<SourceMap>>,
    /// If true, hides the longer explanation text
    short_message: bool,
    /// If true, will normalize line numbers with `LL` to prevent noise in UI test diffs.
    ui_testing: bool,

    macro_backtrace: bool,
}

impl Emitter for AnnotateSnippetEmitterWriter {
    /// The entry point for the diagnostics generation
    fn emit_diagnostic(&mut self, diag: &Diagnostic) {
        let mut children = diag.children.clone();
        let (mut primary_span, suggestions) = self.primary_span_formatted(&diag);

        self.fix_multispans_in_extern_macros_and_render_macro_backtrace(
            &self.source_map,
            &mut primary_span,
            &mut children,
            &diag.level,
            self.macro_backtrace,
        );

        self.emit_messages_default(
            &diag.level,
            diag.message(),
            &diag.code,
            &primary_span,
            &children,
            &suggestions,
        );
    }

    fn source_map(&self) -> Option<&Lrc<SourceMap>> {
        self.source_map.as_ref()
    }

    fn should_show_explain(&self) -> bool {
        !self.short_message
    }
}

/// Provides the source string for the given `line` of `file`
fn source_string(file: Lrc<SourceFile>, line: &Line) -> String {
    file.get_line(line.line_index - 1).map(|a| a.to_string()).unwrap_or_default()
}

/// Maps `Diagnostic::Level` to `snippet::AnnotationType`
fn annotation_type_for_level(level: Level) -> AnnotationType {
    match level {
        Level::Bug | Level::Fatal | Level::Error => AnnotationType::Error,
        Level::Warning => AnnotationType::Warning,
        Level::Note => AnnotationType::Note,
        Level::Help => AnnotationType::Help,
        // FIXME(#59346): Not sure how to map these two levels
        Level::Cancelled | Level::FailureNote => AnnotationType::Error,
    }
}

impl AnnotateSnippetEmitterWriter {
    pub fn new(
        source_map: Option<Lrc<SourceMap>>,
        short_message: bool,
        macro_backtrace: bool,
    ) -> Self {
        Self { source_map, short_message, ui_testing: false, macro_backtrace }
    }

    /// Allows to modify `Self` to enable or disable the `ui_testing` flag.
    ///
    /// If this is set to true, line numbers will be normalized as `LL` in the output.
    pub fn ui_testing(mut self, ui_testing: bool) -> Self {
        self.ui_testing = ui_testing;
        self
    }

    fn emit_messages_default(
        &mut self,
        level: &Level,
        message: String,
        code: &Option<DiagnosticId>,
        msp: &MultiSpan,
        _children: &[SubDiagnostic],
        _suggestions: &[CodeSuggestion],
    ) {
        if let Some(source_map) = &self.source_map {
            // Make sure our primary file comes first
            let primary_lo = if let Some(ref primary_span) = msp.primary_span().as_ref() {
                if primary_span.is_dummy() {
                    // FIXME(#59346): Not sure when this is the case and what
                    // should be done if it happens
                    return;
                } else {
                    source_map.lookup_char_pos(primary_span.lo())
                }
            } else {
                // FIXME(#59346): Not sure when this is the case and what
                // should be done if it happens
                return;
            };
            let mut annotated_files =
                FileWithAnnotatedLines::collect_annotations(msp, &self.source_map);
            if let Ok(pos) =
                annotated_files.binary_search_by(|x| x.file.name.cmp(&primary_lo.file.name))
            {
                annotated_files.swap(0, pos);
            }
            // owned: line source, line index, annotations
            type Owned = (String, usize, Vec<crate::snippet::Annotation>);
            let origin = primary_lo.file.name.to_string();
            let annotated_files: Vec<Owned> = annotated_files
                .into_iter()
                .flat_map(|annotated_file| {
                    let file = annotated_file.file;
                    annotated_file
                        .lines
                        .into_iter()
                        .map(|line| {
                            (source_string(file.clone(), &line), line.line_index, line.annotations)
                        })
                        .collect::<Vec<Owned>>()
                })
                .collect();
            let snippet = Snippet {
                title: Some(Annotation {
                    label: Some(&message),
                    id: code.as_ref().map(|c| match c {
                        DiagnosticId::Error(val) | DiagnosticId::Lint(val) => val.as_str(),
                    }),
                    annotation_type: annotation_type_for_level(*level),
                }),
                footer: vec![],
                opt: FormatOptions { color: true, anonymized_line_numbers: self.ui_testing },
                slices: annotated_files
                    .iter()
                    .map(|(source, line_index, annotations)| {
                        Slice {
                            source,
                            line_start: *line_index,
                            origin: Some(&origin),
                            // FIXME(#59346): Not really sure when `fold` should be true or false
                            fold: false,
                            annotations: annotations
                                .into_iter()
                                .map(|annotation| SourceAnnotation {
                                    range: (annotation.start_col, annotation.end_col),
                                    label: annotation
                                        .label
                                        .as_ref()
                                        .map(|s| s.as_str())
                                        .unwrap_or_default(),
                                    annotation_type: annotation_type_for_level(*level),
                                })
                                .collect(),
                        }
                    })
                    .collect(),
            };
            // FIXME(#59346): Figure out if we can _always_ print to stderr or not.
            // `emitter.rs` has the `Destination` enum that lists various possible output
            // destinations.
            eprintln!("{}", DisplayList::from(snippet))
        }
        // FIXME(#59346): Is it ok to return None if there's no source_map?
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::mem;
use std::ptr;
use std::ops::Deref;
use std::ops::DerefMut;
use std::os::raw::c_void;
use std::sync::Arc;

use instance::MemoryType;
use device::Device;
use memory::Content;
use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Represents memory that has been allocated.
pub struct DeviceMemory {
    device: Arc<Device>,
    memory: vk::DeviceMemory,
    size: usize,
    memory_type_index: u32,
}

impl DeviceMemory {
    /// Allocates a chunk of memory from the device.
    ///
    /// Some platforms may have a limit on the maximum size of a single allocation. For example,
    /// certain systems may fail to create allocations with a size greater than or equal to 4GB.
    ///
    /// # Panic
    ///
    /// - Panicks if `size` is 0.
    /// - Panicks if `memory_type` doesn't belong to the same physical device as `device`.
    ///
    // TODO: VK_ERROR_TOO_MANY_OBJECTS error
    #[inline]
    pub fn alloc(device: &Arc<Device>, memory_type: &MemoryType, size: usize)
                 -> Result<DeviceMemory, OomError>
    {
        assert!(size >= 1);
        assert_eq!(device.physical_device().internal_object(),
                   memory_type.physical_device().internal_object());

        if size > memory_type.heap().size() {
            return Err(OomError::OutOfDeviceMemory);
        }

        let vk = device.pointers();

        let memory = unsafe {
            let infos = vk::MemoryAllocateInfo {
                sType: vk::STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
                pNext: ptr::null(),
                allocationSize: size as u64,
                memoryTypeIndex: memory_type.id(),
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.AllocateMemory(device.internal_object(), &infos,
                                                ptr::null(), &mut output)));
            output
        };

        Ok(DeviceMemory {
            device: device.clone(),
            memory: memory,
            size: size,
            memory_type_index: memory_type.id(),
        })
    }

    /// Allocates a chunk of memory and maps it.
    ///
    /// # Panic
    ///
    /// - Panicks if `memory_type` doesn't belong to the same physical device as `device`.
    /// - Panicks if the memory type is not host-visible.
    ///
    pub fn alloc_and_map(device: &Arc<Device>, memory_type: &MemoryType, size: usize)
                         -> Result<MappedDeviceMemory, OomError>
    {
        let vk = device.pointers();

        assert!(memory_type.is_host_visible());
        let mem = try!(DeviceMemory::alloc(device, memory_type, size));

        let coherent = memory_type.is_host_coherent();

        let ptr = unsafe {
            let mut output = mem::uninitialized();
            try!(check_errors(vk.MapMemory(device.internal_object(), mem.memory, 0,
                                           mem.size as vk::DeviceSize, 0 /* reserved flags */,
                                           &mut output)));
            output
        };

        Ok(MappedDeviceMemory {
            memory: mem,
            pointer: ptr,
            coherent: coherent,
        })
    }

    /// Returns the memory type this chunk was allocated on.
    #[inline]
    pub fn memory_type(&self) -> MemoryType {
        self.device.physical_device().memory_type_by_id(self.memory_type_index).unwrap()
    }

    /// Returns the size in bytes of that memory chunk.
    #[inline]
    pub fn size(&self) -> usize {
        self.size
    }

    /// Returns the device associated with this allocation.
    #[inline]
    pub fn device(&self) -> &Arc<Device> {
        &self.device
    }
}

unsafe impl VulkanObject for DeviceMemory {
    type Object = vk::DeviceMemory;

    #[inline]
    fn internal_object(&self) -> vk::DeviceMemory {
        self.memory
    }
}

impl Drop for DeviceMemory {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.FreeMemory(self.device.internal_object(), self.memory, ptr::null());
        }
    }
}

/// Represents memory that has been allocated and mapped in CPU accessible space.
pub struct MappedDeviceMemory {
    memory: DeviceMemory,
    pointer: *mut c_void,
    coherent: bool,
}

impl MappedDeviceMemory {
    /// Returns the underlying `DeviceMemory`.
    // TODO: impl AsRef instead
    #[inline]
    pub fn memory(&self) -> &DeviceMemory {
        &self.memory
    }

    // TODO: remove
    #[inline]
    #[doc(hidden)]
    pub fn mapping_pointer(&self) -> *mut c_void {
        self.pointer
    }

    /// Gives access to the content of the memory.
    ///
    /// # Safety
    ///
    /// - Type safety is not checked. You must ensure that `T` corresponds to the content of the
    ///   buffer.
    /// - Accesses are not synchronized. Synchronization must be handled outside of
    ///   the `MappedDeviceMemory`.
    ///
    #[inline]
    pub unsafe fn read_write<T: ?Sized>(&self) -> CpuAccess<T> where T: Content + 'static {
        let vk = self.memory.device().pointers();
        let pointer = T::ref_from_ptr(self.pointer, self.memory.size()).unwrap();       // TODO: error

        if !self.coherent {
            let range = vk::MappedMemoryRange {
                sType: vk::STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
                pNext: ptr::null(),
                memory: self.memory.internal_object(),
                offset: 0,
                size: vk::WHOLE_SIZE,
            };

            // TODO: check result?
            vk.InvalidateMappedMemoryRanges(self.memory.device().internal_object(), 1, &range);
        }

        CpuAccess {
            mem: self,
            coherent: self.coherent,
            pointer: pointer,
        }
    }
}

impl Drop for MappedDeviceMemory {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.memory.device.pointers();
            vk.UnmapMemory(self.memory.device.internal_object(), self.memory.memory);
        }
    }
}

/// Object that can be used to read or write the content of a `MappedDeviceMemory`.
pub struct CpuAccess<'a, T: ?Sized + 'a> {
    pointer: *mut T,
    mem: &'a MappedDeviceMemory,
    coherent: bool,
}

impl<'a, T: ?Sized + 'a> Deref for CpuAccess<'a, T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &T {
        unsafe { &*self.pointer }
    }
}

impl<'a, T: ?Sized + 'a> DerefMut for CpuAccess<'a, T> {
    #[inline]
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.pointer }
    }
}

impl<'a, T: ?Sized + 'a> Drop for CpuAccess<'a, T> {
    #[inline]
    fn drop(&mut self) {
        // If the memory doesn't have the `coherent` flag, we need to flush the data.
        if !self.coherent {
            let vk = self.mem.memory().device().pointers();

            let range = vk::MappedMemoryRange {
                sType: vk::STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
                pNext: ptr::null(),
                memory: self.mem.memory().internal_object(),
                offset: 0,
                size: vk::WHOLE_SIZE,
            };

            // TODO: check result?
            unsafe {
                vk.FlushMappedMemoryRanges(self.mem.memory().device().internal_object(),
                                           1, &range);
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use OomError;
    use memory::DeviceMemory;

    #[test]
    fn create() {
        let (device, _) = gfx_dev_and_queue!();
        let mem_ty = device.physical_device().memory_types().next().unwrap();
        let _ = DeviceMemory::alloc(&device, &mem_ty, 256).unwrap();
    }

    #[test]
    #[should_panic]
    fn zero_size() {
        let (device, _) = gfx_dev_and_queue!();
        let mem_ty = device.physical_device().memory_types().next().unwrap();
        let _ = DeviceMemory::alloc(&device, &mem_ty, 0);
    }

    #[test]
    #[cfg(target_pointer_width = "64")]
    fn oom_single() {
        let (device, _) = gfx_dev_and_queue!();
        let mem_ty = device.physical_device().memory_types().filter(|m| !m.is_lazily_allocated())
                           .next().unwrap();

        match DeviceMemory::alloc(&device, &mem_ty, 0xffffffffffffffff) {
            Err(OomError::OutOfDeviceMemory) => (),
            _ => panic!()
        }
    }

    #[test]
    #[ignore]       // TODO: fails on AMD + Windows
    fn oom_multi() {
        let (device, _) = gfx_dev_and_queue!();
        let mem_ty = device.physical_device().memory_types().filter(|m| !m.is_lazily_allocated())
                           .next().unwrap();
        let heap_size = mem_ty.heap().size();

        for _ in 0 .. 4 {
            match DeviceMemory::alloc(&device, &mem_ty, heap_size / 3) {
                Err(OomError::OutOfDeviceMemory) => return,     // test succeeded
                _ => ()
            }
        }

        panic!()
    }
}
<commit_msg>Remove MappedDeviceMemory::mapping_pointer<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::mem;
use std::ptr;
use std::ops::Deref;
use std::ops::DerefMut;
use std::os::raw::c_void;
use std::sync::Arc;

use instance::MemoryType;
use device::Device;
use memory::Content;
use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Represents memory that has been allocated.
pub struct DeviceMemory {
    device: Arc<Device>,
    memory: vk::DeviceMemory,
    size: usize,
    memory_type_index: u32,
}

impl DeviceMemory {
    /// Allocates a chunk of memory from the device.
    ///
    /// Some platforms may have a limit on the maximum size of a single allocation. For example,
    /// certain systems may fail to create allocations with a size greater than or equal to 4GB.
    ///
    /// # Panic
    ///
    /// - Panicks if `size` is 0.
    /// - Panicks if `memory_type` doesn't belong to the same physical device as `device`.
    ///
    // TODO: VK_ERROR_TOO_MANY_OBJECTS error
    #[inline]
    pub fn alloc(device: &Arc<Device>, memory_type: &MemoryType, size: usize)
                 -> Result<DeviceMemory, OomError>
    {
        assert!(size >= 1);
        assert_eq!(device.physical_device().internal_object(),
                   memory_type.physical_device().internal_object());

        if size > memory_type.heap().size() {
            return Err(OomError::OutOfDeviceMemory);
        }

        let vk = device.pointers();

        let memory = unsafe {
            let infos = vk::MemoryAllocateInfo {
                sType: vk::STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
                pNext: ptr::null(),
                allocationSize: size as u64,
                memoryTypeIndex: memory_type.id(),
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.AllocateMemory(device.internal_object(), &infos,
                                                ptr::null(), &mut output)));
            output
        };

        Ok(DeviceMemory {
            device: device.clone(),
            memory: memory,
            size: size,
            memory_type_index: memory_type.id(),
        })
    }

    /// Allocates a chunk of memory and maps it.
    ///
    /// # Panic
    ///
    /// - Panicks if `memory_type` doesn't belong to the same physical device as `device`.
    /// - Panicks if the memory type is not host-visible.
    ///
    pub fn alloc_and_map(device: &Arc<Device>, memory_type: &MemoryType, size: usize)
                         -> Result<MappedDeviceMemory, OomError>
    {
        let vk = device.pointers();

        assert!(memory_type.is_host_visible());
        let mem = try!(DeviceMemory::alloc(device, memory_type, size));

        let coherent = memory_type.is_host_coherent();

        let ptr = unsafe {
            let mut output = mem::uninitialized();
            try!(check_errors(vk.MapMemory(device.internal_object(), mem.memory, 0,
                                           mem.size as vk::DeviceSize, 0 /* reserved flags */,
                                           &mut output)));
            output
        };

        Ok(MappedDeviceMemory {
            memory: mem,
            pointer: ptr,
            coherent: coherent,
        })
    }

    /// Returns the memory type this chunk was allocated on.
    #[inline]
    pub fn memory_type(&self) -> MemoryType {
        self.device.physical_device().memory_type_by_id(self.memory_type_index).unwrap()
    }

    /// Returns the size in bytes of that memory chunk.
    #[inline]
    pub fn size(&self) -> usize {
        self.size
    }

    /// Returns the device associated with this allocation.
    #[inline]
    pub fn device(&self) -> &Arc<Device> {
        &self.device
    }
}

unsafe impl VulkanObject for DeviceMemory {
    type Object = vk::DeviceMemory;

    #[inline]
    fn internal_object(&self) -> vk::DeviceMemory {
        self.memory
    }
}

impl Drop for DeviceMemory {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.FreeMemory(self.device.internal_object(), self.memory, ptr::null());
        }
    }
}

/// Represents memory that has been allocated and mapped in CPU accessible space.
pub struct MappedDeviceMemory {
    memory: DeviceMemory,
    pointer: *mut c_void,
    coherent: bool,
}

impl MappedDeviceMemory {
    /// Returns the underlying `DeviceMemory`.
    // TODO: impl AsRef instead
    #[inline]
    pub fn memory(&self) -> &DeviceMemory {
        &self.memory
    }

    /// Gives access to the content of the memory.
    ///
    /// # Safety
    ///
    /// - Type safety is not checked. You must ensure that `T` corresponds to the content of the
    ///   buffer.
    /// - Accesses are not synchronized. Synchronization must be handled outside of
    ///   the `MappedDeviceMemory`.
    ///
    #[inline]
    pub unsafe fn read_write<T: ?Sized>(&self) -> CpuAccess<T> where T: Content + 'static {
        let vk = self.memory.device().pointers();
        let pointer = T::ref_from_ptr(self.pointer, self.memory.size()).unwrap();       // TODO: error

        if !self.coherent {
            let range = vk::MappedMemoryRange {
                sType: vk::STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
                pNext: ptr::null(),
                memory: self.memory.internal_object(),
                offset: 0,
                size: vk::WHOLE_SIZE,
            };

            // TODO: check result?
            vk.InvalidateMappedMemoryRanges(self.memory.device().internal_object(), 1, &range);
        }

        CpuAccess {
            mem: self,
            coherent: self.coherent,
            pointer: pointer,
        }
    }
}

impl Drop for MappedDeviceMemory {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.memory.device.pointers();
            vk.UnmapMemory(self.memory.device.internal_object(), self.memory.memory);
        }
    }
}

/// Object that can be used to read or write the content of a `MappedDeviceMemory`.
pub struct CpuAccess<'a, T: ?Sized + 'a> {
    pointer: *mut T,
    mem: &'a MappedDeviceMemory,
    coherent: bool,
}

impl<'a, T: ?Sized + 'a> Deref for CpuAccess<'a, T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &T {
        unsafe { &*self.pointer }
    }
}

impl<'a, T: ?Sized + 'a> DerefMut for CpuAccess<'a, T> {
    #[inline]
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.pointer }
    }
}

impl<'a, T: ?Sized + 'a> Drop for CpuAccess<'a, T> {
    #[inline]
    fn drop(&mut self) {
        // If the memory doesn't have the `coherent` flag, we need to flush the data.
        if !self.coherent {
            let vk = self.mem.memory().device().pointers();

            let range = vk::MappedMemoryRange {
                sType: vk::STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
                pNext: ptr::null(),
                memory: self.mem.memory().internal_object(),
                offset: 0,
                size: vk::WHOLE_SIZE,
            };

            // TODO: check result?
            unsafe {
                vk.FlushMappedMemoryRanges(self.mem.memory().device().internal_object(),
                                           1, &range);
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use OomError;
    use memory::DeviceMemory;

    #[test]
    fn create() {
        let (device, _) = gfx_dev_and_queue!();
        let mem_ty = device.physical_device().memory_types().next().unwrap();
        let _ = DeviceMemory::alloc(&device, &mem_ty, 256).unwrap();
    }

    #[test]
    #[should_panic]
    fn zero_size() {
        let (device, _) = gfx_dev_and_queue!();
        let mem_ty = device.physical_device().memory_types().next().unwrap();
        let _ = DeviceMemory::alloc(&device, &mem_ty, 0);
    }

    #[test]
    #[cfg(target_pointer_width = "64")]
    fn oom_single() {
        let (device, _) = gfx_dev_and_queue!();
        let mem_ty = device.physical_device().memory_types().filter(|m| !m.is_lazily_allocated())
                           .next().unwrap();

        match DeviceMemory::alloc(&device, &mem_ty, 0xffffffffffffffff) {
            Err(OomError::OutOfDeviceMemory) => (),
            _ => panic!()
        }
    }

    #[test]
    #[ignore]       // TODO: fails on AMD + Windows
    fn oom_multi() {
        let (device, _) = gfx_dev_and_queue!();
        let mem_ty = device.physical_device().memory_types().filter(|m| !m.is_lazily_allocated())
                           .next().unwrap();
        let heap_size = mem_ty.heap().size();

        for _ in 0 .. 4 {
            match DeviceMemory::alloc(&device, &mem_ty, heap_size / 3) {
                Err(OomError::OutOfDeviceMemory) => return,     // test succeeded
                _ => ()
            }
        }

        panic!()
    }
}
<|endoftext|>


<commit_before>use slack_hook::{Attachment, AttachmentBuilder, Field, PayloadBuilder, Slack, SlackText, SlackLink};
use slack_hook::SlackTextContent::{Text, Link};

use taste::{BenchmarkResult, TastingResult};

pub struct SlackNotifier {
    conn: Slack,
    channel: String,
    github_repo: String,
}

impl SlackNotifier {
    pub fn new(hook_url: &str, channel: &str, repo_url: &str) -> SlackNotifier {
        SlackNotifier {
            conn: Slack::new(hook_url).unwrap(),
            channel: String::from(channel),
            github_repo: String::from(repo_url),
        }
    }

    pub fn notify(&self, res: &TastingResult) -> Result<(), String> {
        println!("{:#?}", res);
        let payload = PayloadBuilder::new()
            .text(vec![Text("I've tasted commit _".into()),
                       Text(format!("\"{}\"_ -- ", res.commit_msg.lines().next().unwrap())
                           .into()),
                       Link(SlackLink::new(&format!("{}/commit/{}",
                                                    self.github_repo,
                                                    res.commit_id),
                                           &res.commit_id[0..6]))]
                .as_slice())
            .attachments(result_to_attachments(&res))
            .channel(self.channel.clone())
            .username("taster")
            .icon_emoji(":tea:")
            .build()
            .unwrap();

        match self.conn.send(&payload) {
            Ok(_) => Ok(()),
            Err(e) => Err(format!("{:?}", e)),
        }
    }
}

fn result_to_attachments(res: &TastingResult) -> Vec<Attachment> {
    let color = if !res.build || !res.bench {
        "danger"
    } else {
        "good"
    };

    let title = if !res.build {
        "Build failure!"
    } else if !res.bench {
        "Benchmark failure!"
    } else {
        "Performance results:"
    };

    let taste = if !res.build || !res.bench {
        "was inedible"
    } else {
        "tasted nice"
    };

    let mut attachments = Vec::new();
    let build_att = AttachmentBuilder::new("")
        .title(format!("It {}.", taste))
        .fields(vec![Field {
                         title: "Build".into(),
                         value: SlackText::new(if res.build { "success" } else { "failed" }),
                         short: Some(true),
                     },
                     Field {
                         title: "Benchmark".into(),
                         value: SlackText::new(if res.benchmark { "success" } else { "failed" }),
                         short: Some(true),
                     }])
        .color(color)
        .build()
        .unwrap();
    attachments.push(build_att);

    match res.results {
        None => (),
        Some(ref r) => {
            for res in r {
                let mut nv = res.iter()
                    .map(|(k, v)| {
                        let val = match v {
                            &BenchmarkResult::Neutral(ref s, _) => s,
                            _ => unimplemented!(),
                        };
                        Field {
                            title: k.clone(),
                            value: SlackText::new(val.clone()),
                            short: Some(true),
                        }
                    })
                    .collect::<Vec<_>>();
                nv.sort_by(|a, b| b.title.cmp(&a.title));
                let att = AttachmentBuilder::new(format!("It {}.", taste))
                    .color(color)
                    .title(title)
                    .fields(nv)
                    .build()
                    .unwrap();
                attachments.push(att);
            }
        }
    }
    attachments
}
<commit_msg>Don't typo field name.<commit_after>use slack_hook::{Attachment, AttachmentBuilder, Field, PayloadBuilder, Slack, SlackText, SlackLink};
use slack_hook::SlackTextContent::{Text, Link};

use taste::{BenchmarkResult, TastingResult};

pub struct SlackNotifier {
    conn: Slack,
    channel: String,
    github_repo: String,
}

impl SlackNotifier {
    pub fn new(hook_url: &str, channel: &str, repo_url: &str) -> SlackNotifier {
        SlackNotifier {
            conn: Slack::new(hook_url).unwrap(),
            channel: String::from(channel),
            github_repo: String::from(repo_url),
        }
    }

    pub fn notify(&self, res: &TastingResult) -> Result<(), String> {
        println!("{:#?}", res);
        let payload = PayloadBuilder::new()
            .text(vec![Text("I've tasted commit _".into()),
                       Text(format!("\"{}\"_ -- ", res.commit_msg.lines().next().unwrap())
                           .into()),
                       Link(SlackLink::new(&format!("{}/commit/{}",
                                                    self.github_repo,
                                                    res.commit_id),
                                           &res.commit_id[0..6]))]
                .as_slice())
            .attachments(result_to_attachments(&res))
            .channel(self.channel.clone())
            .username("taster")
            .icon_emoji(":tea:")
            .build()
            .unwrap();

        match self.conn.send(&payload) {
            Ok(_) => Ok(()),
            Err(e) => Err(format!("{:?}", e)),
        }
    }
}

fn result_to_attachments(res: &TastingResult) -> Vec<Attachment> {
    let color = if !res.build || !res.bench {
        "danger"
    } else {
        "good"
    };

    let title = if !res.build {
        "Build failure!"
    } else if !res.bench {
        "Benchmark failure!"
    } else {
        "Performance results:"
    };

    let taste = if !res.build || !res.bench {
        "was inedible"
    } else {
        "tasted nice"
    };

    let mut attachments = Vec::new();
    let build_att = AttachmentBuilder::new("")
        .title(format!("It {}.", taste))
        .fields(vec![Field {
                         title: "Build".into(),
                         value: SlackText::new(if res.build { "success" } else { "failed" }),
                         short: Some(true),
                     },
                     Field {
                         title: "Benchmark".into(),
                         value: SlackText::new(if res.bench { "success" } else { "failed" }),
                         short: Some(true),
                     }])
        .color(color)
        .build()
        .unwrap();
    attachments.push(build_att);

    match res.results {
        None => (),
        Some(ref r) => {
            for res in r {
                let mut nv = res.iter()
                    .map(|(k, v)| {
                        let val = match v {
                            &BenchmarkResult::Neutral(ref s, _) => s,
                            _ => unimplemented!(),
                        };
                        Field {
                            title: k.clone(),
                            value: SlackText::new(val.clone()),
                            short: Some(true),
                        }
                    })
                    .collect::<Vec<_>>();
                nv.sort_by(|a, b| b.title.cmp(&a.title));
                let att = AttachmentBuilder::new(format!("It {}.", taste))
                    .color(color)
                    .title(title)
                    .fields(nv)
                    .build()
                    .unwrap();
                attachments.push(att);
            }
        }
    }
    attachments
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::io::Result as IoResult;
use std::io::Error as IoError;
use std::io::ErrorKind as IoErrorKind;
use {MemReader, ReadsMemory};

pub struct MemorySlice<'a> {
  pub start: usize,
  pub end: usize,
  reader: &'a MemReader,
  mark: Option<usize>
}

impl<'a> MemorySlice<'a> {
  pub fn new(reader: &'a MemReader, start: usize, end: usize) -> Self {
    MemorySlice {
      start: start,
      end: end,
      reader: reader,
      mark: None
    }
  }
}

impl<'a> Read for MemorySlice<'a> {
  fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
    let start = match self.mark {
      Some(m) => m,
      None => self.start
    };
    let buf_len = buf.len();
    if start + buf_len > self.end {
      return Ok(0);
    }
    let bytes = self.reader.read_bytes(start, buf_len).map_err(|e| IoError::new(IoErrorKind::Other, e))?;
    self.mark = Some(start + buf_len);
    for (i, byte) in bytes.iter().enumerate() {
      buf[i] = *byte;
    }
    Ok(bytes.len())
  }
}
<commit_msg>refactor: use into_iter and don't dereference<commit_after>use std::io::Read;
use std::io::Result as IoResult;
use std::io::Error as IoError;
use std::io::ErrorKind as IoErrorKind;
use {MemReader, ReadsMemory};

pub struct MemorySlice<'a> {
  pub start: usize,
  pub end: usize,
  reader: &'a MemReader,
  mark: Option<usize>
}

impl<'a> MemorySlice<'a> {
  pub fn new(reader: &'a MemReader, start: usize, end: usize) -> Self {
    MemorySlice {
      start: start,
      end: end,
      reader: reader,
      mark: None
    }
  }
}

impl<'a> Read for MemorySlice<'a> {
  fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
    let start = match self.mark {
      Some(m) => m,
      None => self.start
    };
    let buf_len = buf.len();
    if start + buf_len > self.end {
      return Ok(0);
    }
    let bytes = self.reader.read_bytes(start, buf_len).map_err(|e| IoError::new(IoErrorKind::Other, e))?;
    let bytes_len = bytes.len();
    self.mark = Some(start + buf_len);
    for (i, byte) in bytes.into_iter().enumerate() {
      buf[i] = byte;
    }
    Ok(bytes_len)
  }
}
<|endoftext|>


<commit_before>//! Defines complex queries over Ardite driver data structures.

use std::collections::BTreeMap;
use value::*;

/// Specifies a complex driver query. The query is structured like a tree
/// except each node is unaware of its name (or if it even has a name).
pub enum Query {
  /// The most basic query node.
  Node {
    /// Child queries. If `None` then the entire value is returned.
    children: Option<BTreeMap<Key, Query>>
  },
  /// Directly query a collection.
  Collection {
    /// The range of records to query.
    range: Range,
    /// A set of conditions which are joined by “and” which specifies the
    /// values to be filtered out be the query.
    filter: Vec<Condition>,
    /// Child queries. If `None` then the entire value is returned.
    children: Option<BTreeMap<Key, Query>>
  }
}

/// Specifies a positive numeric range of data.
#[derive(Default)]
pub struct Range {
  /// The inclusive lower bound of the range. If `None`, the range is unbounded
  /// on the bottom and thus goes to 0.
  from: Option<u64>,
  /// The exclusive upper bound of the range. If `None`, the range is unbounded
  /// on the top and thus goes to infinity.
  to: Option<u64>
}

/// A condition which will resolve to a boolean value after comparing a certain
/// value with a set rule.
// TODO: Add more conditions.
pub enum Condition {
  /// The condition always passes.
  True,
  /// The condition always fails.
  False,
  /// If the compared value is exactly equal to this one, the condition passes.
  Equal(Value)
}
<commit_msg>refactor: refactor query and add conditions<commit_after>//! Defines complex queries over Ardite driver data structures.

use value::*;

/// Specifies a complex driver query. The query is structured like a tree
/// except each node is unaware of its name (or if it even has a name). It
/// cannot be expected that a `Query` tree will map 1 to 1 with a `Value` tree.
pub enum Query {
  /// Basic query of a value with some specified children.
  Item {
    /// Name of
    name: String,
    /// Child queries.
    children: Vec<Query>
  },
  /// Query all values of a single record. If an object it returns *all* of the
  /// properties. Works like a star select in SQL. Some properties may be
  /// hidden and therefore not included in the return value. This is up to the
  /// disgression of the driver.
  Value {
    /// The name of the value to return.
    name: String
  },
  /// Directly query a collection. When thinking of the `Query` type as a tree
  /// which maps to a `Value` object, this query “skips” a level. For example,
  /// another query might have
  /// `Query::Item(users) -> Query::Item(1) -> Query::Item(name)` which maps to
  /// the expect JSON pointer `/users/1/name`. Whereas with a collection, the
  /// query may look like `Query::Collection(users) -> Query::Item(name)`. Note
  /// that there was no “middle” query item for the record.
  Collection {
    /// The name of the collection we will be querying.
    name: String,
    /// The range of records to query.
    range: Range,
    /// A set of conditions which are joined by “and” which specifies the
    /// values to be filtered out be the query.
    filter: Condition,
    /// Child queries.
    children: Vec<Query>
  }
}

/// Specifies a positive numeric range of data.
#[derive(Default)]
pub struct Range {
  /// The inclusive lower bound of the range. If `None`, the range is unbounded
  /// on the bottom and thus goes to 0.
  from: Option<u64>,
  /// The exclusive upper bound of the range. If `None`, the range is unbounded
  /// on the top and thus goes to infinity.
  to: Option<u64>
}

/// A condition which will resolve to a boolean value after comparing a certain
/// value with a set rule.
// TODO: Add more conditions.
pub enum Condition {
  /// The condition always passes.
  True,
  /// The condition always fails.
  False,
  /// Inverts a condition.
  Not(Box<Condition>),
  /// Composes many conditions. They all must be true for the condition to be
  /// true.
  And(Vec<Condition>),
  /// Composes many conditions. Only one must be true for the condition to be
  /// true.
  Or(Vec<Condition>),
  /// If the compared value is exactly equal to this one, the condition passes.
  Equal(Value)
}
<|endoftext|>


<commit_before>pub struct Node<T> {
    val: T,
    next: Option<Box<Node<T>>>,
}

pub struct Stack<T> {
    s: Option<Box<Node<T>>>
}

impl<T> Stack<T> {
    pub fn new() -> Stack<T> {
        Stack { s: None }
    }

    pub fn push(&mut self, val: T) {
        let next = self.s.take();
        self.s = Some(Box::new(Node { val: val, next: next }))
    }

    pub fn pop(&mut self) -> Option<T> {
        let mut top = self.s.take();
        self.s = top.as_mut().map(|t| t.next.take()).unwrap_or(None);
        top.map(|n| n.val)
    }

    pub fn len(&self) -> usize {
        let mut sz = 0;
        let mut p = self.s.as_ref();
        while p.is_some() {
            p = p.map(|n| n.next.as_ref()).unwrap_or(None);
            sz += 1;
        }
        sz
    }

    pub fn peek(&self) -> Option<&T> {
        self.s.as_ref().map(|n| &n.val)
    }

    pub fn peek_mut(&mut self) -> Option<&mut T> {
        self.s.as_mut().map(|n| &mut n.val)
    }
}

pub struct IntoIter<T> {
    stack: Stack<T>
}

impl<T> Iterator for IntoIter<T> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        self.stack.pop()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.stack.len();
        (len, Some(len))
    }
}

impl<T> ExactSizeIterator for IntoIter<T> {
    fn len(&self) -> usize {
        self.stack.len()
    }
}

impl<T> IntoIterator for Stack<T> {
    type Item = T;
    type IntoIter = IntoIter<T>;

    fn into_iter(self) -> Self::IntoIter {
        IntoIter { stack: self }
    }
}

#[test]
fn test_stack() {
    let mut s = Stack::new();
    assert_eq!(s.len(), 0);
    s.push(1000);
    assert_eq!(s.len(), 1);
    s.push(2000);
    assert_eq!(s.len(), 2);
    assert_eq!(s.peek(), Some(&2000));
    assert_eq!(s.pop(), Some(2000));
    assert_eq!(s.len(), 1);
    assert_eq!(s.pop(), Some(1000));
    assert_eq!(s.len(), 0);
    assert_eq!(s.pop(), None);
    assert_eq!(s.len(), 0);

    s.push(250);
    s.peek_mut().map(|val| *val = 100);
    assert_eq!(s.pop(), Some(100));
}

#[test]
fn test_stack_into_iter() {
    let mut s = Stack::new();
    s.push(100);
    s.push(200);
    s.push(300);

    let mut result = vec![300, 200, 100].into_iter();
    for i in s {
        assert_eq!(i, result.next().unwrap());
    }
}
<commit_msg>implement Clone for Stack; implement iter()<commit_after>pub struct Node<T> {
    val: T,
    next: Option<Box<Node<T>>>,
}

impl<T: Clone> Clone for Node<T> {
    fn clone(&self) -> Self {
        Node {
            val: self.val.clone(),
            next: self.next.clone()
        }
    }
}

pub struct Stack<T> {
    s: Option<Box<Node<T>>>
}

impl<T: Clone> Clone for Stack<T> {
    fn clone(&self) -> Self {
        Stack { s: self.s.clone() }
    }
}

impl<T> Stack<T> {
    pub fn new() -> Stack<T> {
        Stack { s: None }
    }

    pub fn push(&mut self, val: T) {
        let next = self.s.take();
        self.s = Some(Box::new(Node { val: val, next: next }))
    }

    pub fn pop(&mut self) -> Option<T> {
        let mut top = self.s.take();
        self.s = top.as_mut().map(|t| t.next.take()).unwrap_or(None);
        top.map(|n| n.val)
    }

    pub fn len(&self) -> usize {
        let mut sz = 0;
        let mut p = self.s.as_ref();
        while p.is_some() {
            p = p.map(|n| n.next.as_ref()).unwrap_or(None);
            sz += 1;
        }
        sz
    }

    pub fn peek(&self) -> Option<&T> {
        self.s.as_ref().map(|n| &n.val)
    }

    pub fn peek_mut(&mut self) -> Option<&mut T> {
        self.s.as_mut().map(|n| &mut n.val)
    }
}

pub struct IntoIter<T> {
    stack: Stack<T>
}

impl<T> Iterator for IntoIter<T> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        self.stack.pop()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.stack.len();
        (len, Some(len))
    }
}

impl<T> ExactSizeIterator for IntoIter<T> {
    fn len(&self) -> usize {
        self.stack.len()
    }
}

impl<T> IntoIterator for Stack<T> {
    type Item = T;
    type IntoIter = IntoIter<T>;

    fn into_iter(self) -> Self::IntoIter {
        IntoIter { stack: self }
    }
}

pub struct Iter<'a, T> where T: 'a {
    node: Option<&'a Box<Node<T>>>
}

impl<'a, T> Iterator for Iter<'a, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<&'a T> {
        let ret = self.node.map(|n| &n.val);
        self.node = self.node.map(|n| n.next.as_ref()).unwrap_or(None);
        ret
    }

    // Bad
    fn size_hint(&self) -> (usize, Option<usize>) {
        let mut sz = 0;
        let mut p = self.node;
        while p.is_some() {
            p = p.map(|n| n.next.as_ref()).unwrap_or(None);
            sz += 1;
        }
        (sz, Some(sz))
    }
}

impl<'a, T> ExactSizeIterator for Iter<'a, T> {
    fn len(&self) -> usize {
        self.size_hint().0
    }
}

impl<T> Stack<T> {
    pub fn iter<'a>(&'a self) -> Iter<'a, T> {
        Iter {
            node: self.s.as_ref()
        }
    }
}

#[test]
fn test_stack() {
    let mut s = Stack::new();
    assert_eq!(s.len(), 0);
    s.push(1000);
    assert_eq!(s.len(), 1);
    s.push(2000);
    assert_eq!(s.len(), 2);
    assert_eq!(s.peek(), Some(&2000));
    assert_eq!(s.pop(), Some(2000));
    assert_eq!(s.len(), 1);
    assert_eq!(s.pop(), Some(1000));
    assert_eq!(s.len(), 0);
    assert_eq!(s.pop(), None);
    assert_eq!(s.len(), 0);

    s.push(250);
    s.peek_mut().map(|val| *val = 100);
    assert_eq!(s.pop(), Some(100));
}

#[test]
fn test_stack_into_iter() {
    let mut s = Stack::new();
    s.push(100);
    s.push(200);
    s.push(300);

    let mut result = vec![300, 200, 100].into_iter();
    for i in s {
        assert_eq!(i, result.next().unwrap());
    }
}

#[test]
fn test_stack_iter() {
    let mut s = Stack::new();
    s.push(100);
    s.push(200);
    s.push(300);

    let mut result = vec![300, 200, 100].into_iter();
    for i in s.iter() {
        assert_eq!(*i, result.next().unwrap());
    }

    assert_eq!(s.len(), 3);
}

#[test]
fn test_stack_clone() {
    let mut s = Stack::new();
    s.push(100);
    s.push(200);
    s.push(300);

    let t = s.clone();

    s.pop();
    assert_eq!(s.len(), 2);
    assert_eq!(t.len(), 3);
}
<|endoftext|>


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

//! Fixed-function hardware state.
//!
//! Configures the primitive assembly (PA), rasterizer, and output merger (OM) blocks.

use std::default::Default;
use std::fmt;

use target;

/// The front face winding order of a set of vertices.
#[derive(Eq, Ord, PartialEq, PartialOrd, Hash, Copy, Clone, Debug)]
pub enum FrontFace {
    /// Clockwise winding order.
    Clockwise,
    /// Counter-clockwise winding order.
    CounterClockwise,
}

/// Width of a line.
/// Could be f32 if not for Hash deriving issues.
pub type LineWidth = i32;
/// Slope depth offset factor
/// Could be f32 if not for Hash deriving issues.
pub type OffsetSlope = i32;
/// Number of units to offset, where
/// the unit is the minimal difference in the depth value
/// dictated by the precision of the depth buffer.
pub type OffsetUnits = i32;

/// How to offset vertices in screen space, if at all.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd)]
pub struct Offset(pub OffsetSlope, pub OffsetUnits);

/// Which face, if any, to cull.
#[allow(missing_docs)]
#[derive(Copy, Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub enum CullFace {
    Nothing,
    Front,
    Back,
}

/// How to rasterize a primitive.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd)]
pub enum RasterMethod {
    /// Rasterize as a point.
    Point,
    /// Rasterize as a line with the given width.
    Line(LineWidth),
    /// Rasterize as a face with a given cull face mode.
    Fill(CullFace),
}

/// Primitive rasterization state. Note that GL allows different raster
/// method to be used for front and back, while this abstraction does not.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd)]
pub struct Primitive {
    /// Which vertex winding is considered to be the front face for culling.
    pub front_face: FrontFace,
    /// How to rasterize this primitive.
    pub method: RasterMethod,
    /// Any polygon offset to apply.
    pub offset: Option<Offset>,
}

impl Primitive {
    /// Get the cull face, if any, for this primitive state.
    pub fn get_cull_face(&self) -> CullFace {
        match self.method {
            RasterMethod::Fill(mode) => mode,
            _ => CullFace::Nothing,
        }
    }
}

impl Default for Primitive {
    fn default() -> Primitive {
        Primitive {
            front_face: FrontFace::CounterClockwise,
            method: RasterMethod::Fill(CullFace::Nothing),
            offset: None,
        }
    }
}

/// Multi-sampling rasterization mode
#[derive(Copy, Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub struct MultiSample;
    //sample_mask: u16,
    //alpha_to_coverage: bool,

/// A pixel-wise comparison function.
#[derive(Copy, Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub enum Comparison {
    /// `false`
    Never,
    /// `x < y`
    Less,
    /// `x <= y`
    LessEqual,
    /// `x == y`
    Equal,
    /// `x >= y`
    GreaterEqual,
    /// `x > y`
    Greater,
    /// `x != y`
    NotEqual,
    /// `true`
    Always,
}

/// Stencil mask operation.
#[allow(missing_docs)]
#[derive(Copy, Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub enum StencilOp {
    /// Keep the current value in the stencil buffer (no change).
    Keep,
    /// Set the value in the stencil buffer to zero.
    Zero,
    /// Set the stencil buffer value to `value` from `StencilSide`
    Replace,
    /// Increment the stencil buffer value, clamping to its maximum value.
    IncrementClamp,
    /// Increment the stencil buffer value, wrapping around to 0 on overflow.
    IncrementWrap,
    /// Decrement the stencil buffer value, clamping to its minimum value.
    DecrementClamp,
    /// Decrement the stencil buffer value, wrapping around to the maximum value on overflow.
    DecrementWrap,
    /// Bitwise invert the current value in the stencil buffer.
    Invert,
}

/// Complete stencil state for a given side of a face.
#[derive(Copy, Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub struct StencilSide {
    /// Comparison function to use to determine if the stencil test passes.
    pub fun: Comparison,
    /// A mask that is ANDd with both the stencil buffer value and the reference value when they
    /// are read before doing the stencil test.
    pub mask_read: target::Stencil,
    /// A mask that is ANDd with the stencil value before writing to the stencil buffer.
    pub mask_write: target::Stencil,
    /// What operation to do if the stencil test fails.
    pub op_fail: StencilOp,
    /// What operation to do if the stenil test passes but the depth test fails.
    pub op_depth_fail: StencilOp,
    /// What operation to do if both the depth and stencil test pass.
    pub op_pass: StencilOp,
}

impl Default for StencilSide {
    fn default() -> StencilSide {
        StencilSide {
            fun: Comparison::Always,
            mask_read: target::Stencil::max_value(),
            mask_write: target::Stencil::max_value(),
            op_fail: StencilOp::Keep,
            op_depth_fail: StencilOp::Keep,
            op_pass: StencilOp::Keep,
        }
    }
}

/// Complete stencil state, specifying how to handle the front and back side of a face.
#[allow(missing_docs)]
#[derive(Copy, Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub struct Stencil {
    pub front: StencilSide,
    pub back: StencilSide,
    pub front_ref: target::Stencil,
    pub back_ref: target::Stencil,
}

impl Default for Stencil {
    fn default() -> Stencil {
        Stencil {
            front: Default::default(),
            back: Default::default(),
            front_ref: 0,
            back_ref: 0,
        }
    }
}

/// Depth test state.
#[derive(Copy, Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub struct Depth {
    /// Comparison function to use.
    pub fun: Comparison,
    /// Specify whether to write to the depth buffer or not.
    pub write: bool,
}

impl Default for Depth {
    fn default() -> Depth {
        Depth {
            fun: Comparison::Always,
            write: false,
        }
    }
}

#[allow(missing_docs)]
#[derive(Copy, Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub enum Equation {
    /// Adds source and destination.
    /// Source and destination are multiplied by blending parameters before addition.
    Add,
    /// Subtracts destination from source.
    /// Source and destination are multiplied by blending parameters before subtraction.
    Sub,
    /// Subtracts source from destination.
    /// Source and destination are multiplied by blending parameters before subtraction.
    RevSub,
    /// Component-wise minimum value of source and destination.
    /// Blending parameters are ignored.
    Min,
    /// Component-wise maximum value of source and destination.
    /// Blending parameters are ignored.
    Max,
}

#[allow(missing_docs)]
#[derive(Copy, Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub enum BlendValue {
    SourceColor,
    SourceAlpha,
    DestColor,
    DestAlpha,
    ConstColor,
    ConstAlpha,
}

#[allow(missing_docs)]
#[derive(Copy, Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub enum Factor {
    Zero,
    One,
    SourceAlphaSaturated,
    ZeroPlus(BlendValue),
    OneMinus(BlendValue),
}

#[allow(missing_docs)]
#[derive(Eq, Ord, PartialEq, PartialOrd, Hash, Copy, Clone, Debug)]
pub struct BlendChannel {
    pub equation: Equation,
    pub source: Factor,
    pub destination: Factor,
}

impl Default for BlendChannel {
    fn default() -> BlendChannel {
        BlendChannel {
            equation: Equation::Add,
            source: Factor::One,
            destination: Factor::One,
        }
    }
}

#[allow(missing_docs)]
#[derive(Copy, Clone, Hash, PartialOrd, PartialEq, Eq)]
pub struct Blend {
    pub color: BlendChannel,
    pub alpha: BlendChannel,
    /// Color mask to use. Each flag indicates that the given color channel can be written to, and
    /// they can be OR'd together.
    pub mask: ColorMask,
}

impl Default for Blend {
    fn default() -> Blend {
        Blend {
            color: Default::default(),
            alpha: Default::default(),
            mask: MASK_ALL,
        }
    }
}

impl fmt::Debug for Blend {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Blend {{ color: {:?}, alpha: {:?}, mask: {:?} }}",
               self.color, self.alpha, self.mask)
    }
}

bitflags!(
    #[allow(missing_docs)]
    flags ColorMask: u8 {
        #[allow(missing_docs)]
        const RED     = 0x1,
        #[allow(missing_docs)]
        const GREEN   = 0x2,
        #[allow(missing_docs)]
        const BLUE    = 0x4,
        #[allow(missing_docs)]
        const ALPHA   = 0x8,
        #[allow(missing_docs)]
        const MASK_ALL = 0xF,
        #[allow(missing_docs)]
        const MASK_NONE = 0x0
    }
);
<commit_msg>Moved get_cull_face from Primitive into RasterMethod<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Fixed-function hardware state.
//!
//! Configures the primitive assembly (PA), rasterizer, and output merger (OM) blocks.

use std::default::Default;
use std::fmt;

use target;

/// The front face winding order of a set of vertices.
#[derive(Eq, Ord, PartialEq, PartialOrd, Hash, Copy, Clone, Debug)]
pub enum FrontFace {
    /// Clockwise winding order.
    Clockwise,
    /// Counter-clockwise winding order.
    CounterClockwise,
}

/// Width of a line.
/// Could be f32 if not for Hash deriving issues.
pub type LineWidth = i32;
/// Slope depth offset factor
/// Could be f32 if not for Hash deriving issues.
pub type OffsetSlope = i32;
/// Number of units to offset, where
/// the unit is the minimal difference in the depth value
/// dictated by the precision of the depth buffer.
pub type OffsetUnits = i32;

/// How to offset vertices in screen space, if at all.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd)]
pub struct Offset(pub OffsetSlope, pub OffsetUnits);

/// Which face, if any, to cull.
#[allow(missing_docs)]
#[derive(Copy, Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub enum CullFace {
    Nothing,
    Front,
    Back,
}

/// How to rasterize a primitive.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd)]
pub enum RasterMethod {
    /// Rasterize as a point.
    Point,
    /// Rasterize as a line with the given width.
    Line(LineWidth),
    /// Rasterize as a face with a given cull face mode.
    Fill(CullFace),
}

impl RasterMethod {
    /// Get the cull face, if any, for this primitive state.
    pub fn get_cull_face(&self) -> CullFace {
        match self {
            &RasterMethod::Fill(mode) => mode,
            _ => CullFace::Nothing,
        }
    }
}

/// Primitive rasterization state. Note that GL allows different raster
/// method to be used for front and back, while this abstraction does not.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd)]
pub struct Primitive {
    /// Which vertex winding is considered to be the front face for culling.
    pub front_face: FrontFace,
    /// How to rasterize this primitive.
    pub method: RasterMethod,
    /// Any polygon offset to apply.
    pub offset: Option<Offset>,
}

impl Default for Primitive {
    fn default() -> Primitive {
        Primitive {
            front_face: FrontFace::CounterClockwise,
            method: RasterMethod::Fill(CullFace::Nothing),
            offset: None,
        }
    }
}

/// Multi-sampling rasterization mode
#[derive(Copy, Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub struct MultiSample;
    //sample_mask: u16,
    //alpha_to_coverage: bool,

/// A pixel-wise comparison function.
#[derive(Copy, Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub enum Comparison {
    /// `false`
    Never,
    /// `x < y`
    Less,
    /// `x <= y`
    LessEqual,
    /// `x == y`
    Equal,
    /// `x >= y`
    GreaterEqual,
    /// `x > y`
    Greater,
    /// `x != y`
    NotEqual,
    /// `true`
    Always,
}

/// Stencil mask operation.
#[allow(missing_docs)]
#[derive(Copy, Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub enum StencilOp {
    /// Keep the current value in the stencil buffer (no change).
    Keep,
    /// Set the value in the stencil buffer to zero.
    Zero,
    /// Set the stencil buffer value to `value` from `StencilSide`
    Replace,
    /// Increment the stencil buffer value, clamping to its maximum value.
    IncrementClamp,
    /// Increment the stencil buffer value, wrapping around to 0 on overflow.
    IncrementWrap,
    /// Decrement the stencil buffer value, clamping to its minimum value.
    DecrementClamp,
    /// Decrement the stencil buffer value, wrapping around to the maximum value on overflow.
    DecrementWrap,
    /// Bitwise invert the current value in the stencil buffer.
    Invert,
}

/// Complete stencil state for a given side of a face.
#[derive(Copy, Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub struct StencilSide {
    /// Comparison function to use to determine if the stencil test passes.
    pub fun: Comparison,
    /// A mask that is ANDd with both the stencil buffer value and the reference value when they
    /// are read before doing the stencil test.
    pub mask_read: target::Stencil,
    /// A mask that is ANDd with the stencil value before writing to the stencil buffer.
    pub mask_write: target::Stencil,
    /// What operation to do if the stencil test fails.
    pub op_fail: StencilOp,
    /// What operation to do if the stenil test passes but the depth test fails.
    pub op_depth_fail: StencilOp,
    /// What operation to do if both the depth and stencil test pass.
    pub op_pass: StencilOp,
}

impl Default for StencilSide {
    fn default() -> StencilSide {
        StencilSide {
            fun: Comparison::Always,
            mask_read: target::Stencil::max_value(),
            mask_write: target::Stencil::max_value(),
            op_fail: StencilOp::Keep,
            op_depth_fail: StencilOp::Keep,
            op_pass: StencilOp::Keep,
        }
    }
}

/// Complete stencil state, specifying how to handle the front and back side of a face.
#[allow(missing_docs)]
#[derive(Copy, Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub struct Stencil {
    pub front: StencilSide,
    pub back: StencilSide,
    pub front_ref: target::Stencil,
    pub back_ref: target::Stencil,
}

impl Default for Stencil {
    fn default() -> Stencil {
        Stencil {
            front: Default::default(),
            back: Default::default(),
            front_ref: 0,
            back_ref: 0,
        }
    }
}

/// Depth test state.
#[derive(Copy, Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub struct Depth {
    /// Comparison function to use.
    pub fun: Comparison,
    /// Specify whether to write to the depth buffer or not.
    pub write: bool,
}

impl Default for Depth {
    fn default() -> Depth {
        Depth {
            fun: Comparison::Always,
            write: false,
        }
    }
}

#[allow(missing_docs)]
#[derive(Copy, Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub enum Equation {
    /// Adds source and destination.
    /// Source and destination are multiplied by blending parameters before addition.
    Add,
    /// Subtracts destination from source.
    /// Source and destination are multiplied by blending parameters before subtraction.
    Sub,
    /// Subtracts source from destination.
    /// Source and destination are multiplied by blending parameters before subtraction.
    RevSub,
    /// Component-wise minimum value of source and destination.
    /// Blending parameters are ignored.
    Min,
    /// Component-wise maximum value of source and destination.
    /// Blending parameters are ignored.
    Max,
}

#[allow(missing_docs)]
#[derive(Copy, Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub enum BlendValue {
    SourceColor,
    SourceAlpha,
    DestColor,
    DestAlpha,
    ConstColor,
    ConstAlpha,
}

#[allow(missing_docs)]
#[derive(Copy, Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub enum Factor {
    Zero,
    One,
    SourceAlphaSaturated,
    ZeroPlus(BlendValue),
    OneMinus(BlendValue),
}

#[allow(missing_docs)]
#[derive(Eq, Ord, PartialEq, PartialOrd, Hash, Copy, Clone, Debug)]
pub struct BlendChannel {
    pub equation: Equation,
    pub source: Factor,
    pub destination: Factor,
}

impl Default for BlendChannel {
    fn default() -> BlendChannel {
        BlendChannel {
            equation: Equation::Add,
            source: Factor::One,
            destination: Factor::One,
        }
    }
}

#[allow(missing_docs)]
#[derive(Copy, Clone, Hash, PartialOrd, PartialEq, Eq)]
pub struct Blend {
    pub color: BlendChannel,
    pub alpha: BlendChannel,
    /// Color mask to use. Each flag indicates that the given color channel can be written to, and
    /// they can be OR'd together.
    pub mask: ColorMask,
}

impl Default for Blend {
    fn default() -> Blend {
        Blend {
            color: Default::default(),
            alpha: Default::default(),
            mask: MASK_ALL,
        }
    }
}

impl fmt::Debug for Blend {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Blend {{ color: {:?}, alpha: {:?}, mask: {:?} }}",
               self.color, self.alpha, self.mask)
    }
}

bitflags!(
    #[allow(missing_docs)]
    flags ColorMask: u8 {
        #[allow(missing_docs)]
        const RED     = 0x1,
        #[allow(missing_docs)]
        const GREEN   = 0x2,
        #[allow(missing_docs)]
        const BLUE    = 0x4,
        #[allow(missing_docs)]
        const ALPHA   = 0x8,
        #[allow(missing_docs)]
        const MASK_ALL = 0xF,
        #[allow(missing_docs)]
        const MASK_NONE = 0x0
    }
);
<|endoftext|>


<commit_before>//! Provides components which retry multiple times to read or write on the kebit store without blocking.s
use crate::api::Encodable;
use crate::api::Reader;
use crate::api::WriteError;
use crate::api::Writer;
use crate::core::ReadResult;
use crate::core::TryIter;
use crossbeam_utils::Backoff;
use parking_lot::Mutex;
use std::iter::FusedIterator;
use std::iter::Iterator;
use std::sync::Arc;

/// A nonblocking iterator over messages in the channel which tries multiple times to read
/// a message from a channel.
#[repr(transparent)]
pub struct RetryIter<'a, R: Reader> {
    inner: TryIter<'a, R>,
}

impl<'a, R: Reader> From<TryIter<'a, R>> for RetryIter<'a, R> {
    fn from(try_iter: TryIter<'a, R>) -> RetryIter<'a, R> {
        RetryIter { inner: try_iter }
    }
}

impl<'a, R: Reader> Iterator for RetryIter<'a, R> {
    type Item = ReadResult<'a>;
    /// Tries multiple times to read a message from channel.
    ///
    /// # Errors
    ///
    /// If the ReadResult is a Failure all subsequent call will return None.
    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        let backoff = Backoff::new();
        loop {
            let res = self.inner.next();
            match res {
                Some(ReadResult::Nothing) => {
                    if backoff.is_completed() {
                        return res;
                    } else {
                        backoff.snooze();
                    }
                }
                Some(_) => return res,
                None => return None,
            }
        }
    }
    ///Returns (0, None) if records may be still available in the channel or (0, Some(0)) if
    ///the channel is exhausted.
    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.inner.size_hint()
    }
}

impl<'a, R: Reader> FusedIterator for RetryIter<'a, R> {}

/// Writer which decorates another writer in order to make it available to multiple threads.
/// This writer is non-blocking but will try multiple times before it give up.
#[repr(transparent)]
pub struct RetryWriter<W: Writer> {
    mx_writer: Arc<Mutex<W>>,
}

impl<W: Writer> RetryWriter<W> {
    #[inline]
    pub fn new(mx_writer: Arc<Mutex<W>>) -> RetryWriter<W> {
        RetryWriter { mx_writer }
    }
}

impl<W: Writer> Writer for RetryWriter<W> {
    ///Tries to acquire the inner writer than writes the given message into channel.
    ///
    /// # Errors
    ///
    /// Any error returned by the decorated writer will be passed on.
    /// WriteError::Wait will be returned if the inner writer cannot be acquired.
    #[inline]
    fn write<E: Encodable>(&mut self, data: &E) -> Result<u32, WriteError> {
        let backoff = Backoff::new();
        loop {
            let try_write = self.mx_writer.try_lock();
            match try_write {
                Some(mut writer) => {
                    return writer.write(data);
                }
                None => {
                    if backoff.is_completed() {
                        return Err(WriteError::Wait);
                    } else {
                        backoff.snooze();
                    }
                }
            }
        }
    }
}
#[cfg(test)]
mod test {
    use super::*;
    use crate::api::*;
    use crate::core::*;
    use assert_matches::*;
    use tempdir::TempDir;
    #[test]
    fn retry_iter() {
        let metadata = Metadata::new(100, 1000, 10000, 1000, 1000, TickUnit::Millis);
        let test_tmp_dir = TempDir::new("kektest").unwrap();
        let txt = "There are 10 kinds of people";
        let mut msgs = txt.split_whitespace();
        let mut writer = shm_writer(&test_tmp_dir.path(), &metadata, EncoderHandler::default()).unwrap();
        let mut reader = shm_reader(&test_tmp_dir.path(), 1000).unwrap();
        let mut retry_iter: RetryIter<ShmReader> = reader.try_iter().into();
        assert_matches!(retry_iter.size_hint(), (0, None));
        assert_matches!(retry_iter.next(), Some(ReadResult::Nothing));
        for _i in 0..3 {
            let to_wr = msgs.next().unwrap().as_bytes();
            writer.write(&to_wr).unwrap();
        }
        for _i in 0..3 {
            assert_matches!(retry_iter.next(), Some(ReadResult::Record(_)));
        }
        assert_matches!(retry_iter.next(), Some(ReadResult::Nothing));
        std::mem::drop(writer);
        assert_matches!(retry_iter.next(), Some(ReadResult::Failed(ReadError::Closed)));
        assert_matches!(retry_iter.next(), None);
        assert_matches!(retry_iter.size_hint(), (0, Some(0)));
    }

    #[test]
    fn retry_write() {
        let metadata = Metadata::new(100, 1000, 10000, 1000, 1000, TickUnit::Millis);
        let test_tmp_dir = TempDir::new("kektest").unwrap();
        let writer = shm_writer(&test_tmp_dir.path(), &metadata, EncoderHandler::default()).unwrap();
        let arc_mx = Arc::new(Mutex::new(writer));
        let handles: Vec<std::thread::JoinHandle<()>> = (0..5)
            .map(|i| (i, arc_mx.clone()))
            .map(|(i, arc_mx)| {
                std::thread::spawn(move || {
                    let to_wr = format!("Hello {}", &i);
                    let mut retry_w = RetryWriter::new(arc_mx);
                    for _i in 0..3 {
                        loop {
                            match retry_w.write(&to_wr) {
                                Ok(_) => break,
                                Err(WriteError::Wait) => (),
                                Err(_) => panic!("Write failure"),
                            };
                        }
                    }
                })
            })
            .collect();
        for handle in handles {
            handle.join().unwrap();
        }
        let mut read_results = std::collections::HashMap::<&str, i32>::new();
        let mut shm_reader = shm_reader(&test_tmp_dir.path(), 1000).unwrap();
        let reader_iter = shm_reader.try_iter();
        for msg in reader_iter {
            match msg {
                ReadResult::Record(data) => {
                    *read_results.entry(std::str::from_utf8(data).unwrap()).or_default() += 1;
                }
                _ => break,
            }
        }
        assert_eq!(read_results.len(), 5);
        for (key, value) in read_results {
            dbg!(key, value);
            assert_eq!(value, 3);
        }
    }
}
<commit_msg>Fix assert_matches uses to they compile with nightly<commit_after>//! Provides components which retry multiple times to read or write on the kebit store without blocking.s
use crate::api::Encodable;
use crate::api::Reader;
use crate::api::WriteError;
use crate::api::Writer;
use crate::core::ReadResult;
use crate::core::TryIter;
use crossbeam_utils::Backoff;
use parking_lot::Mutex;
use std::iter::FusedIterator;
use std::iter::Iterator;
use std::sync::Arc;

/// A nonblocking iterator over messages in the channel which tries multiple times to read
/// a message from a channel.
#[repr(transparent)]
pub struct RetryIter<'a, R: Reader> {
    inner: TryIter<'a, R>,
}

impl<'a, R: Reader> From<TryIter<'a, R>> for RetryIter<'a, R> {
    fn from(try_iter: TryIter<'a, R>) -> RetryIter<'a, R> {
        RetryIter { inner: try_iter }
    }
}

impl<'a, R: Reader> Iterator for RetryIter<'a, R> {
    type Item = ReadResult<'a>;
    /// Tries multiple times to read a message from channel.
    ///
    /// # Errors
    ///
    /// If the ReadResult is a Failure all subsequent call will return None.
    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        let backoff = Backoff::new();
        loop {
            let res = self.inner.next();
            match res {
                Some(ReadResult::Nothing) => {
                    if backoff.is_completed() {
                        return res;
                    } else {
                        backoff.snooze();
                    }
                }
                Some(_) => return res,
                None => return None,
            }
        }
    }
    ///Returns (0, None) if records may be still available in the channel or (0, Some(0)) if
    ///the channel is exhausted.
    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.inner.size_hint()
    }
}

impl<'a, R: Reader> FusedIterator for RetryIter<'a, R> {}

/// Writer which decorates another writer in order to make it available to multiple threads.
/// This writer is non-blocking but will try multiple times before it give up.
#[repr(transparent)]
pub struct RetryWriter<W: Writer> {
    mx_writer: Arc<Mutex<W>>,
}

impl<W: Writer> RetryWriter<W> {
    #[inline]
    pub fn new(mx_writer: Arc<Mutex<W>>) -> RetryWriter<W> {
        RetryWriter { mx_writer }
    }
}

impl<W: Writer> Writer for RetryWriter<W> {
    ///Tries to acquire the inner writer than writes the given message into channel.
    ///
    /// # Errors
    ///
    /// Any error returned by the decorated writer will be passed on.
    /// WriteError::Wait will be returned if the inner writer cannot be acquired.
    #[inline]
    fn write<E: Encodable>(&mut self, data: &E) -> Result<u32, WriteError> {
        let backoff = Backoff::new();
        loop {
            let try_write = self.mx_writer.try_lock();
            match try_write {
                Some(mut writer) => {
                    return writer.write(data);
                }
                None => {
                    if backoff.is_completed() {
                        return Err(WriteError::Wait);
                    } else {
                        backoff.snooze();
                    }
                }
            }
        }
    }
}
#[cfg(test)]
mod test {
    use super::*;
    use crate::api::*;
    use crate::core::*;
    use assert_matches::assert_matches as match_assert;
    use tempdir::TempDir;
    #[test]
    fn retry_iter() {
        let metadata = Metadata::new(100, 1000, 10000, 1000, 1000, TickUnit::Millis);
        let test_tmp_dir = TempDir::new("kektest").unwrap();
        let txt = "There are 10 kinds of people";
        let mut msgs = txt.split_whitespace();
        let mut writer = shm_writer(&test_tmp_dir.path(), &metadata, EncoderHandler::default()).unwrap();
        let mut reader = shm_reader(&test_tmp_dir.path(), 1000).unwrap();
        let mut retry_iter: RetryIter<ShmReader> = reader.try_iter().into();
        match_assert!(retry_iter.size_hint(), (0, None));
        match_assert!(retry_iter.next(), Some(ReadResult::Nothing));
        for _i in 0..3 {
            let to_wr = msgs.next().unwrap().as_bytes();
            writer.write(&to_wr).unwrap();
        }
        for _i in 0..3 {
            match_assert!(retry_iter.next(), Some(ReadResult::Record(_)));
        }
        match_assert!(retry_iter.next(), Some(ReadResult::Nothing));
        std::mem::drop(writer);
        match_assert!(retry_iter.next(), Some(ReadResult::Failed(ReadError::Closed)));
        match_assert!(retry_iter.next(), None);
        match_assert!(retry_iter.size_hint(), (0, Some(0)));
    }

    #[test]
    fn retry_write() {
        let metadata = Metadata::new(100, 1000, 10000, 1000, 1000, TickUnit::Millis);
        let test_tmp_dir = TempDir::new("kektest").unwrap();
        let writer = shm_writer(&test_tmp_dir.path(), &metadata, EncoderHandler::default()).unwrap();
        let arc_mx = Arc::new(Mutex::new(writer));
        let handles: Vec<std::thread::JoinHandle<()>> = (0..5)
            .map(|i| (i, arc_mx.clone()))
            .map(|(i, arc_mx)| {
                std::thread::spawn(move || {
                    let to_wr = format!("Hello {}", &i);
                    let mut retry_w = RetryWriter::new(arc_mx);
                    for _i in 0..3 {
                        loop {
                            match retry_w.write(&to_wr) {
                                Ok(_) => break,
                                Err(WriteError::Wait) => (),
                                Err(_) => panic!("Write failure"),
                            };
                        }
                    }
                })
            })
            .collect();
        for handle in handles {
            handle.join().unwrap();
        }
        let mut read_results = std::collections::HashMap::<&str, i32>::new();
        let mut shm_reader = shm_reader(&test_tmp_dir.path(), 1000).unwrap();
        let reader_iter = shm_reader.try_iter();
        for msg in reader_iter {
            match msg {
                ReadResult::Record(data) => {
                    *read_results.entry(std::str::from_utf8(data).unwrap()).or_default() += 1;
                }
                _ => break,
            }
        }
        assert_eq!(read_results.len(), 5);
        for (key, value) in read_results {
            dbg!(key, value);
            assert_eq!(value, 3);
        }
    }
}
<|endoftext|>