<commit_before>//! Source file support for diagnostic reporting.
//!
//! The main trait defined in this module is the [`Files`] trait, which provides
//! provides the minimum amount of functionality required for printing [`Diagnostics`]
//! with the [`term::emit`] function.
//!
//! Simple implementations of this trait are implemented:
//!
//! - [`SimpleFile`]: For single-file use-cases
//! - [`SimpleFiles`]: For single-file use-cases
//!
//! These data structures provide a pretty minimal API, however,
//! so end-users are encouraged to create their own implementations for their
//! own specific use-cases, such as an implementation that accesses the file
//! system directly (and caches the line start locations), or an implementation
//! using an incremental compilation library like [`salsa`].
//!
//! [`term::emit`]: crate::term::emit
//! [`Diagnostics`]: crate::diagnostic::Diagnostic
//! [`Files`]: Files
//! [`SimpleFile`]: SimpleFile
//! [`SimpleFiles`]: SimpleFiles
//!
//! [`salsa`]: https://crates.io/crates/salsa

use std::ops::Range;

/// A minimal interface for accessing source files when rendering diagnostics.
///
/// A lifetime parameter `'a` is provided to allow any of the returned values to returned by reference.
/// This is to workaround the lack of higher kinded lifetime parameters.
/// This can be ignored if this is not needed, however.
pub trait Files<'a> {
    /// A unique identifier for files in the file provider. This will be used
    /// for rendering `diagnostic::Label`s in the corresponding source files.
    type FileId: 'a + Copy + PartialEq;
    /// The user-facing name of a file, to be displayed in diagnostics.
    type Name: 'a + std::fmt::Display;
    /// The source code of a file.
    type Source: 'a + AsRef<str>;

    /// The user-facing name of a file.
    fn name(&'a self, id: Self::FileId) -> Option<Self::Name>;

    /// The source code of a file.
    fn source(&'a self, id: Self::FileId) -> Option<Self::Source>;

    /// The index of the line at the given byte index.
    ///
    /// # Note for trait implementors
    ///
    /// This can be implemented efficiently by performing a binary search over
    /// a list of line starts that was computed by calling the [`line_starts`]
    /// function that is exported from the [`files`] module. It might be useful
    /// to pre-compute and cache these line starts.
    ///
    /// [`line_starts`]: crate::files::line_starts
    /// [`files`]: crate::files
    fn line_index(&'a self, id: Self::FileId, byte_index: usize) -> Option<usize>;

    /// The user-facing line number at the given line index.
    ///
    /// # Note for trait implementors
    ///
    /// This is usually 1-indexed from the beginning of the file, but
    /// can be useful for implementing something like the
    /// [C preprocessor's `#line` macro][line-macro].
    ///
    /// [line-macro]: https://en.cppreference.com/w/c/preprocessor/line
    #[allow(unused_variables)]
    fn line_number(&'a self, id: Self::FileId, line_index: usize) -> Option<usize> {
        Some(line_index + 1)
    }

    /// The user-facing column number at the given line index and byte index.
    ///
    /// # Note for trait implementors
    ///
    /// This is usually 1-indexed from the the start of the line.
    /// A default implementation is provided, based on the [`column_index`]
    /// function that is exported from the [`files`] module.
    ///
    /// [`files`]: crate::files
    /// [`column_index`]: crate::files::column_index
    fn column_number(
        &'a self,
        id: Self::FileId,
        line_index: usize,
        byte_index: usize,
    ) -> Option<usize> {
        let source = self.source(id)?;
        let line_range = self.line_range(id, line_index)?;
        let column_index = column_index(source.as_ref(), line_range, byte_index);

        Some(column_index + 1)
    }

    /// Convenience method for returning line and column number at the given
    /// byte index in the file.
    fn location(&'a self, id: Self::FileId, byte_index: usize) -> Option<Location> {
        let line_index = self.line_index(id, byte_index)?;

        Some(Location {
            line_number: self.line_number(id, line_index)?,
            column_number: self.column_number(id, line_index, byte_index)?,
        })
    }

    /// The byte range of line in the source of the file.
    fn line_range(&'a self, id: Self::FileId, line_index: usize) -> Option<Range<usize>>;
}

/// A user-facing location in a source file.
///
/// Returned by [`Files::location`].
///
/// [`Files::location`]: Files::location
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Location {
    /// The user-facing line number.
    pub line_number: usize,
    /// The user-facing column number.
    pub column_number: usize,
}

/// The column index at the given byte index in the source file.
/// This is the number of characters to the given byte index.
///
/// If the byte index is smaller than the start of the line, then `0` is returned.
/// If the byte index is past the end of the line, the column index of the last
/// character `+ 1` is returned.
///
/// # Example
///
/// ```rust
/// use codespan_reporting::files;
///
/// let source = "\n\n🗻∈🌏\n\n";
///
/// assert_eq!(files::column_index(source, 0..1, 0), 0);
/// assert_eq!(files::column_index(source, 2..13, 0), 0);
/// assert_eq!(files::column_index(source, 2..13, 2 + 0), 0);
/// assert_eq!(files::column_index(source, 2..13, 2 + 1), 0);
/// assert_eq!(files::column_index(source, 2..13, 2 + 4), 1);
/// assert_eq!(files::column_index(source, 2..13, 2 + 8), 2);
/// assert_eq!(files::column_index(source, 2..13, 2 + 10), 2);
/// assert_eq!(files::column_index(source, 2..13, 2 + 11), 3);
/// assert_eq!(files::column_index(source, 2..13, 2 + 12), 3);
/// ```
pub fn column_index(source: &str, line_range: Range<usize>, byte_index: usize) -> usize {
    let end_index = std::cmp::min(byte_index, std::cmp::min(line_range.end, source.len()));

    (line_range.start..end_index)
        .filter(|byte_index| source.is_char_boundary(byte_index + 1))
        .count()
}

/// Return the starting byte index of each line in the source string.
///
/// This can make it easier to implement [`Files::line_index`] by allowing
/// implementors of [`Files`] to pre-compute the line starts, then search for
/// the corresponding line range, as shown in the example below.
///
/// [`Files`]: Files
/// [`Files::line_index`]: Files::line_index
///
/// # Example
///
/// ```rust
/// use codespan_reporting::files;
///
/// let source = "foo\nbar\r\n\nbaz";
/// let line_starts: Vec<_> = files::line_starts(source).collect();
///
/// assert_eq!(
///     line_starts,
///     [
///         0,  // "foo\n"
///         4,  // "bar\r\n"
///         9,  // ""
///         10, // "baz"
///     ],
/// );
///
/// fn line_index(line_starts: &[usize], byte_index: usize) -> Option<usize> {
///     match line_starts.binary_search(&byte_index) {
///         Ok(line) => Some(line),
///         Err(next_line) => Some(next_line - 1),
///     }
/// }
///
/// assert_eq!(line_index(&line_starts, 5), Some(1));
/// ```
// NOTE: this is copied in `codespan::file::line_starts` and should be kept in sync.
pub fn line_starts<'source>(source: &'source str) -> impl 'source + Iterator<Item = usize> {
    std::iter::once(0).chain(source.match_indices('\n').map(|(i, _)| i + 1))
}

/// A file database that contains a single source file.
///
/// Because there is only single file in this database we use `()` as a [`FileId`].
///
/// This is useful for simple language tests, but it might be worth creating a
/// custom implementation when a language scales beyond a certain size.
///
/// [`FileId`]: Files::FileId
#[derive(Debug, Clone)]
pub struct SimpleFile<Name, Source> {
    /// The name of the file.
    name: Name,
    /// The source code of the file.
    source: Source,
    /// The starting byte indices in the source code.
    line_starts: Vec<usize>,
}

impl<Name, Source> SimpleFile<Name, Source>
where
    Name: std::fmt::Display,
    Source: AsRef<str>,
{
    /// Create a new source file.
    pub fn new(name: Name, source: Source) -> SimpleFile<Name, Source> {
        SimpleFile {
            name,
            line_starts: line_starts(source.as_ref()).collect(),
            source,
        }
    }

    /// Return the name of the file.
    pub fn name(&self) -> &Name {
        &self.name
    }

    /// Return the source of the file.
    pub fn source(&self) -> &Source {
        &self.source
    }

    fn line_start(&self, line_index: usize) -> Option<usize> {
        use std::cmp::Ordering;

        match line_index.cmp(&self.line_starts.len()) {
            Ordering::Less => self.line_starts.get(line_index).cloned(),
            Ordering::Equal => Some(self.source.as_ref().len()),
            Ordering::Greater => None,
        }
    }
}

impl<'a, Name, Source> Files<'a> for SimpleFile<Name, Source>
where
    Name: 'a + std::fmt::Display + Clone,
    Source: 'a + AsRef<str>,
{
    type FileId = ();
    type Name = Name;
    type Source = &'a str;

    fn name(&self, (): ()) -> Option<Name> {
        Some(self.name.clone())
    }

    fn source(&self, (): ()) -> Option<&str> {
        Some(self.source.as_ref())
    }

    fn line_index(&self, (): (), byte_index: usize) -> Option<usize> {
        match self.line_starts.binary_search(&byte_index) {
            Ok(line) => Some(line),
            Err(next_line) => Some(next_line - 1),
        }
    }

    fn line_range(&self, (): (), line_index: usize) -> Option<Range<usize>> {
        let line_start = self.line_start(line_index)?;
        let next_line_start = self.line_start(line_index + 1)?;

        Some(line_start..next_line_start)
    }
}

/// A file database that can store multiple source files.
///
/// This is useful for simple language tests, but it might be worth creating a
/// custom implementation when a language scales beyond a certain size.
#[derive(Debug, Clone)]
pub struct SimpleFiles<Name, Source> {
    files: Vec<SimpleFile<Name, Source>>,
}

impl<Name, Source> SimpleFiles<Name, Source>
where
    Name: std::fmt::Display,
    Source: AsRef<str>,
{
    /// Create a new files database.
    pub fn new() -> SimpleFiles<Name, Source> {
        SimpleFiles { files: Vec::new() }
    }

    /// Add a file to the database, returning the handle that can be used to
    /// refer to it again.
    pub fn add(&mut self, name: Name, source: Source) -> usize {
        let file_id = self.files.len();
        self.files.push(SimpleFile::new(name, source));
        file_id
    }

    /// Get the file corresponding to the given id.
    pub fn get(&self, file_id: usize) -> Option<&SimpleFile<Name, Source>> {
        self.files.get(file_id)
    }
}

impl<'a, Name, Source> Files<'a> for SimpleFiles<Name, Source>
where
    Name: 'a + std::fmt::Display + Clone,
    Source: 'a + AsRef<str>,
{
    type FileId = usize;
    type Name = Name;
    type Source = &'a str;

    fn name(&self, file_id: usize) -> Option<Name> {
        Some(self.get(file_id)?.name().clone())
    }

    fn source(&self, file_id: usize) -> Option<&str> {
        Some(self.get(file_id)?.source().as_ref())
    }

    fn line_index(&self, file_id: usize, byte_index: usize) -> Option<usize> {
        self.get(file_id)?.line_index((), byte_index)
    }

    fn line_range(&self, file_id: usize, line_index: usize) -> Option<Range<usize>> {
        self.get(file_id)?.line_range((), line_index)
    }
}

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

    const TEST_SOURCE: &str = "foo\nbar\r\n\nbaz";

    #[test]
    fn line_starts() {
        let file = SimpleFile::new("test", TEST_SOURCE);

        assert_eq!(
            file.line_starts,
            [
                0,  // "foo\n"
                4,  // "bar\r\n"
                9,  // ""
                10, // "baz"
            ],
        );
    }

    #[test]
    fn line_span_sources() {
        let file = SimpleFile::new("test", TEST_SOURCE);

        let line_sources = (0..4)
            .map(|line| {
                let line_range = file.line_range((), line).unwrap();
                &file.source[line_range]
            })
            .collect::<Vec<_>>();

        assert_eq!(line_sources, ["foo\n", "bar\r\n", "\n", "baz"]);
    }
}
<commit_msg>improve documentation in the files module<commit_after>//! Source file support for diagnostic reporting.
//!
//! The main trait defined in this module is the [`Files`] trait, which provides
//! provides the minimum amount of functionality required for printing [`Diagnostics`]
//! with the [`term::emit`] function.
//!
//! Simple implementations of this trait are implemented:
//!
//! - [`SimpleFile`]: For single-file use-cases
//! - [`SimpleFiles`]: For multi-file use-cases
//!
//! These data structures provide a pretty minimal API, however,
//! so end-users are encouraged to create their own implementations for their
//! own specific use-cases, such as an implementation that accesses the file
//! system directly (and caches the line start locations), or an implementation
//! using an incremental compilation library like [`salsa`].
//!
//! [`term::emit`]: crate::term::emit
//! [`Diagnostics`]: crate::diagnostic::Diagnostic
//! [`Files`]: Files
//! [`SimpleFile`]: SimpleFile
//! [`SimpleFiles`]: SimpleFiles
//!
//! [`salsa`]: https://crates.io/crates/salsa

use std::ops::Range;

/// A minimal interface for accessing source files when rendering diagnostics.
///
/// A lifetime parameter `'a` is provided to allow any of the returned values to returned by reference.
/// This is to workaround the lack of higher kinded lifetime parameters.
/// This can be ignored if this is not needed, however.
pub trait Files<'a> {
    /// A unique identifier for files in the file provider. This will be used
    /// for rendering `diagnostic::Label`s in the corresponding source files.
    type FileId: 'a + Copy + PartialEq;
    /// The user-facing name of a file, to be displayed in diagnostics.
    type Name: 'a + std::fmt::Display;
    /// The source code of a file.
    type Source: 'a + AsRef<str>;

    /// The user-facing name of a file.
    fn name(&'a self, id: Self::FileId) -> Option<Self::Name>;

    /// The source code of a file.
    fn source(&'a self, id: Self::FileId) -> Option<Self::Source>;

    /// The index of the line at the given byte index.
    /// If the byte index is past the end of the file, returns the maximum line index in the file.
    /// This means that this function only fails if the file is not present.
    ///
    /// # Note for trait implementors
    ///
    /// This can be implemented efficiently by performing a binary search over
    /// a list of line starts that was computed by calling the [`line_starts`]
    /// function that is exported from the [`files`] module. It might be useful
    /// to pre-compute and cache these line starts.
    ///
    /// [`line_starts`]: crate::files::line_starts
    /// [`files`]: crate::files
    fn line_index(&'a self, id: Self::FileId, byte_index: usize) -> Option<usize>;

    /// The user-facing line number at the given line index.
    /// It is not necessarily checked that the specified line index
    /// is actually in the file.
    ///
    /// # Note for trait implementors
    ///
    /// This is usually 1-indexed from the beginning of the file, but
    /// can be useful for implementing something like the
    /// [C preprocessor's `#line` macro][line-macro].
    ///
    /// [line-macro]: https://en.cppreference.com/w/c/preprocessor/line
    #[allow(unused_variables)]
    fn line_number(&'a self, id: Self::FileId, line_index: usize) -> Option<usize> {
        Some(line_index + 1)
    }

    /// The user-facing column number at the given line index and byte index.
    ///
    /// # Note for trait implementors
    ///
    /// This is usually 1-indexed from the the start of the line.
    /// A default implementation is provided, based on the [`column_index`]
    /// function that is exported from the [`files`] module.
    ///
    /// [`files`]: crate::files
    /// [`column_index`]: crate::files::column_index
    fn column_number(
        &'a self,
        id: Self::FileId,
        line_index: usize,
        byte_index: usize,
    ) -> Option<usize> {
        let source = self.source(id)?;
        let line_range = self.line_range(id, line_index)?;
        let column_index = column_index(source.as_ref(), line_range, byte_index);

        Some(column_index + 1)
    }

    /// Convenience method for returning line and column number at the given
    /// byte index in the file.
    fn location(&'a self, id: Self::FileId, byte_index: usize) -> Option<Location> {
        let line_index = self.line_index(id, byte_index)?;

        Some(Location {
            line_number: self.line_number(id, line_index)?,
            column_number: self.column_number(id, line_index, byte_index)?,
        })
    }

    /// The byte range of line in the source of the file.
    fn line_range(&'a self, id: Self::FileId, line_index: usize) -> Option<Range<usize>>;
}

/// A user-facing location in a source file.
///
/// Returned by [`Files::location`].
///
/// [`Files::location`]: Files::location
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Location {
    /// The user-facing line number.
    pub line_number: usize,
    /// The user-facing column number.
    pub column_number: usize,
}

/// The column index at the given byte index in the source file.
/// This is the number of characters to the given byte index.
///
/// If the byte index is smaller than the start of the line, then `0` is returned.
/// If the byte index is past the end of the line, the column index of the last
/// character `+ 1` is returned.
///
/// # Example
///
/// ```rust
/// use codespan_reporting::files;
///
/// let source = "\n\n🗻∈🌏\n\n";
///
/// assert_eq!(files::column_index(source, 0..1, 0), 0);
/// assert_eq!(files::column_index(source, 2..13, 0), 0);
/// assert_eq!(files::column_index(source, 2..13, 2 + 0), 0);
/// assert_eq!(files::column_index(source, 2..13, 2 + 1), 0);
/// assert_eq!(files::column_index(source, 2..13, 2 + 4), 1);
/// assert_eq!(files::column_index(source, 2..13, 2 + 8), 2);
/// assert_eq!(files::column_index(source, 2..13, 2 + 10), 2);
/// assert_eq!(files::column_index(source, 2..13, 2 + 11), 3);
/// assert_eq!(files::column_index(source, 2..13, 2 + 12), 3);
/// ```
pub fn column_index(source: &str, line_range: Range<usize>, byte_index: usize) -> usize {
    let end_index = std::cmp::min(byte_index, std::cmp::min(line_range.end, source.len()));

    (line_range.start..end_index)
        .filter(|byte_index| source.is_char_boundary(byte_index + 1))
        .count()
}

/// Return the starting byte index of each line in the source string.
///
/// This can make it easier to implement [`Files::line_index`] by allowing
/// implementors of [`Files`] to pre-compute the line starts, then search for
/// the corresponding line range, as shown in the example below.
///
/// [`Files`]: Files
/// [`Files::line_index`]: Files::line_index
///
/// # Example
///
/// ```rust
/// use codespan_reporting::files;
///
/// let source = "foo\nbar\r\n\nbaz";
/// let line_starts: Vec<_> = files::line_starts(source).collect();
///
/// assert_eq!(
///     line_starts,
///     [
///         0,  // "foo\n"
///         4,  // "bar\r\n"
///         9,  // ""
///         10, // "baz"
///     ],
/// );
///
/// fn line_index(line_starts: &[usize], byte_index: usize) -> Option<usize> {
///     match line_starts.binary_search(&byte_index) {
///         Ok(line) => Some(line),
///         Err(next_line) => Some(next_line - 1),
///     }
/// }
///
/// assert_eq!(line_index(&line_starts, 5), Some(1));
/// ```
// NOTE: this is copied in `codespan::file::line_starts` and should be kept in sync.
pub fn line_starts<'source>(source: &'source str) -> impl 'source + Iterator<Item = usize> {
    std::iter::once(0).chain(source.match_indices('\n').map(|(i, _)| i + 1))
}

/// A file database that contains a single source file.
///
/// Because there is only single file in this database we use `()` as a [`FileId`].
///
/// This is useful for simple language tests, but it might be worth creating a
/// custom implementation when a language scales beyond a certain size.
///
/// [`FileId`]: Files::FileId
#[derive(Debug, Clone)]
pub struct SimpleFile<Name, Source> {
    /// The name of the file.
    name: Name,
    /// The source code of the file.
    source: Source,
    /// The starting byte indices in the source code.
    line_starts: Vec<usize>,
}

impl<Name, Source> SimpleFile<Name, Source>
where
    Name: std::fmt::Display,
    Source: AsRef<str>,
{
    /// Create a new source file.
    pub fn new(name: Name, source: Source) -> SimpleFile<Name, Source> {
        SimpleFile {
            name,
            line_starts: line_starts(source.as_ref()).collect(),
            source,
        }
    }

    /// Return the name of the file.
    pub fn name(&self) -> &Name {
        &self.name
    }

    /// Return the source of the file.
    pub fn source(&self) -> &Source {
        &self.source
    }

    fn line_start(&self, line_index: usize) -> Option<usize> {
        use std::cmp::Ordering;

        match line_index.cmp(&self.line_starts.len()) {
            Ordering::Less => self.line_starts.get(line_index).cloned(),
            Ordering::Equal => Some(self.source.as_ref().len()),
            Ordering::Greater => None,
        }
    }
}

impl<'a, Name, Source> Files<'a> for SimpleFile<Name, Source>
where
    Name: 'a + std::fmt::Display + Clone,
    Source: 'a + AsRef<str>,
{
    type FileId = ();
    type Name = Name;
    type Source = &'a str;

    fn name(&self, (): ()) -> Option<Name> {
        Some(self.name.clone())
    }

    fn source(&self, (): ()) -> Option<&str> {
        Some(self.source.as_ref())
    }

    fn line_index(&self, (): (), byte_index: usize) -> Option<usize> {
        match self.line_starts.binary_search(&byte_index) {
            Ok(line) => Some(line),
            Err(next_line) => Some(next_line - 1),
        }
    }

    fn line_range(&self, (): (), line_index: usize) -> Option<Range<usize>> {
        let line_start = self.line_start(line_index)?;
        let next_line_start = self.line_start(line_index + 1)?;

        Some(line_start..next_line_start)
    }
}

/// A file database that can store multiple source files.
///
/// This is useful for simple language tests, but it might be worth creating a
/// custom implementation when a language scales beyond a certain size.
/// It is a glorified `Vec<SimpleFile>` that implements the `Files` trait.
#[derive(Debug, Clone)]
pub struct SimpleFiles<Name, Source> {
    files: Vec<SimpleFile<Name, Source>>,
}

impl<Name, Source> SimpleFiles<Name, Source>
where
    Name: std::fmt::Display,
    Source: AsRef<str>,
{
    /// Create a new files database.
    pub fn new() -> SimpleFiles<Name, Source> {
        SimpleFiles { files: Vec::new() }
    }

    /// Add a file to the database, returning the handle that can be used to
    /// refer to it again.
    pub fn add(&mut self, name: Name, source: Source) -> usize {
        let file_id = self.files.len();
        self.files.push(SimpleFile::new(name, source));
        file_id
    }

    /// Get the file corresponding to the given id.
    pub fn get(&self, file_id: usize) -> Option<&SimpleFile<Name, Source>> {
        self.files.get(file_id)
    }
}

impl<'a, Name, Source> Files<'a> for SimpleFiles<Name, Source>
where
    Name: 'a + std::fmt::Display + Clone,
    Source: 'a + AsRef<str>,
{
    type FileId = usize;
    type Name = Name;
    type Source = &'a str;

    fn name(&self, file_id: usize) -> Option<Name> {
        Some(self.get(file_id)?.name().clone())
    }

    fn source(&self, file_id: usize) -> Option<&str> {
        Some(self.get(file_id)?.source().as_ref())
    }

    fn line_index(&self, file_id: usize, byte_index: usize) -> Option<usize> {
        self.get(file_id)?.line_index((), byte_index)
    }

    fn line_range(&self, file_id: usize, line_index: usize) -> Option<Range<usize>> {
        self.get(file_id)?.line_range((), line_index)
    }
}

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

    const TEST_SOURCE: &str = "foo\nbar\r\n\nbaz";

    #[test]
    fn line_starts() {
        let file = SimpleFile::new("test", TEST_SOURCE);

        assert_eq!(
            file.line_starts,
            [
                0,  // "foo\n"
                4,  // "bar\r\n"
                9,  // ""
                10, // "baz"
            ],
        );
    }

    #[test]
    fn line_span_sources() {
        let file = SimpleFile::new("test", TEST_SOURCE);

        let line_sources = (0..4)
            .map(|line| {
                let line_range = file.line_range((), line).unwrap();
                &file.source[line_range]
            })
            .collect::<Vec<_>>();

        assert_eq!(line_sources, ["foo\n", "bar\r\n", "\n", "baz"]);
    }
}
<|endoftext|>


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

//! Input / output.

/// A producer of bytes.
pub trait InputStream {
    /// Reads at least `min_bytes` into `buf` unless EOF is encountered first. Returns the
    /// number of bytes read.
    fn try_read(&mut self, buf : &mut [u8], min_bytes : usize) -> ::std::io::Result<usize>;

    /// Reads at least `min_bytes` into `buf`, returning the number of bytes read. If EOF is
    /// encountered first, returns an error.
    fn read(&mut self, buf : &mut [u8], min_bytes : usize) -> ::std::io::Result<usize> {
        let n = try!(self.try_read(buf, min_bytes));
        if n < min_bytes {
            Err(::std::io::Error::new(::std::io::ErrorKind::Other, "Premature EOF", None))
        } else {
            Ok(n)
        }
    }

    /// Reads into `buf` until it is full. Returns an error if EOF is encountered first.
    fn read_exact(&mut self, buf : &mut [u8]) -> ::std::io::Result<()> {
        let min_bytes = buf.len();
        try!(self.read(buf, min_bytes));
        Ok(())
    }
}

impl <R> InputStream for R where R : ::std::io::Read {
    fn try_read(&mut self, buf : &mut [u8], min_bytes : usize) -> ::std::io::Result<usize> {
        let mut pos = 0;
        while pos < min_bytes {
            let buf1 = &mut buf[pos ..];
            let n = try!(self.read(buf1));
            pos += n;
            if n == 0 { return Ok(pos); }
        }
        return Ok(pos);
    }
}

pub trait BufferedInputStream : InputStream {
    fn skip(&mut self, bytes : usize) -> ::std::io::Result<()>;
    unsafe fn get_read_buffer(&mut self) -> ::std::io::Result<(*const u8, *const u8)>;
}

pub struct BufferedInputStreamWrapper<R> {
    inner : R,
    buf : Vec<u8>,
    pos : usize,
    cap : usize
}

impl <R> BufferedInputStreamWrapper<R> {
    pub fn new(r : R) -> BufferedInputStreamWrapper<R> {
        let mut result = BufferedInputStreamWrapper {
            inner : r,
            buf : Vec::with_capacity(8192),
            pos : 0,
            cap : 0
        };
        unsafe {
            result.buf.set_len(8192)
        }
        return result;
    }
}

impl<R: InputStream> BufferedInputStream for BufferedInputStreamWrapper<R> {

   fn skip(&mut self, mut bytes : usize) -> ::std::io::Result<()> {
        let available = self.cap - self.pos;
        if bytes <= available {
            self.pos += bytes;
        } else {
            bytes -= available;
            if bytes <= self.buf.len() {
                //# Read the next buffer-full.
                let n = try!(self.inner.try_read(self.buf.as_mut_slice(), bytes));
                self.pos = bytes;
                self.cap = n;
            } else {
                //# Forward large skip to the underlying stream.
                panic!("TODO")
            }
        }
        Ok(())
    }

    unsafe fn get_read_buffer(&mut self) -> ::std::io::Result<(*const u8, *const u8)> {
        if self.cap - self.pos == 0 {
            let n = try!(self.inner.try_read(self.buf.as_mut_slice(), 1));
            self.cap = n;
            self.pos = 0;
        }
        Ok((self.buf.get_unchecked(self.pos) as *const u8,
            self.buf.get_unchecked(self.cap) as *const u8))
    }
}

impl<R: InputStream> InputStream for BufferedInputStreamWrapper<R> {
    fn try_read(&mut self, mut dst: &mut [u8], mut min_bytes : usize) -> ::std::io::Result<usize> {
        if min_bytes <= self.cap - self.pos {
            // Serve from the current buffer.
            let n = ::std::cmp::min(self.cap - self.pos, dst.len());
            ::std::slice::bytes::copy_memory(dst,
                                             &self.buf[self.pos .. self.pos + n]);
            self.pos += n;
            return Ok(n);
        } else {
            // Copy current available into destination.
            ::std::slice::bytes::copy_memory(dst,
                                             &self.buf[self.pos .. self.cap]);
            let from_first_buffer = self.cap - self.pos;

            let dst = &mut dst[from_first_buffer ..];
            min_bytes -= from_first_buffer;

            if dst.len() <= self.buf.len() {
                // Read the next buffer-full.
                let n = try!(self.inner.try_read(self.buf.as_mut_slice(), min_bytes));
                let from_second_buffer = ::std::cmp::min(n, dst.len());
                ::std::slice::bytes::copy_memory(dst,
                                                 &self.buf[0 .. from_second_buffer]);
                self.cap = n;
                self.pos = from_second_buffer;
                return Ok(from_first_buffer + from_second_buffer);
            } else {
                // Forward large read to the underlying stream.
                self.pos = 0;
                self.cap = 0;
                return Ok(from_first_buffer + try!(self.inner.try_read(dst, min_bytes)));
            }
        }
    }
}

pub struct ArrayInputStream<'a> {
    array : &'a [u8]
}

impl <'a> ArrayInputStream<'a> {
    pub fn new<'b>(array : &'b [u8]) -> ArrayInputStream<'b> {
        ArrayInputStream { array : array }
    }
}

impl <'a> InputStream for ArrayInputStream<'a> {
    fn try_read(&mut self, dst: &mut [u8], _min_bytes : usize) -> ::std::io::Result<usize> {
        let n = ::std::cmp::min(dst.len(), self.array.len());
        ::std::slice::bytes::copy_memory(dst, &self.array[0 .. n]);
        self.array = &self.array[n ..];
        Ok(n)
    }
}

impl <'a> BufferedInputStream for ArrayInputStream<'a> {
    fn skip(&mut self, bytes : usize) -> ::std::io::Result<()> {
        assert!(self.array.len() >= bytes,
                "ArrayInputStream ended prematurely.");
        self.array = &self.array[bytes ..];
        Ok(())
    }
    unsafe fn get_read_buffer(&mut self) -> ::std::io::Result<(*const u8, *const u8)> {
        let len = self.array.len();
        Ok((self.array.as_ptr() as *const u8,
           self.array.get_unchecked(len) as *const u8))
    }
}

/// A consumer of bytes.
pub trait OutputStream {
    /// Writes all of `buf`.
    fn write(&mut self, buf : &[u8]) -> ::std::io::Result<()>;
    fn flush(&mut self) -> ::std::io::Result<()> { Ok(()) }
}

impl <W> OutputStream for W where W : ::std::io::Write {
    fn write(&mut self, buf : &[u8]) -> ::std::io::Result<()> {
        self.write_all(buf)
    }
    fn flush(&mut self) -> ::std::io::Result<()> {
        self.flush()
    }
}

pub trait BufferedOutputStream : OutputStream {
    unsafe fn get_write_buffer(&mut self) -> (*mut u8, *mut u8);
    unsafe fn write_ptr(&mut self, ptr: *mut u8, size: usize) -> ::std::io::Result<()>;
}

pub struct BufferedOutputStreamWrapper<'a, W:'a> {
    inner: &'a mut W,
    buf: Vec<u8>,
    pos: usize
}

impl <'a, W> BufferedOutputStreamWrapper<'a, W> {
    pub fn new<'b> (w : &'b mut W) -> BufferedOutputStreamWrapper<W> {
        let mut result = BufferedOutputStreamWrapper {
            inner: w,
            buf : Vec::with_capacity(8192),
            pos : 0
        };
        unsafe {
            result.buf.set_len(8192);
        }
        return result;
    }
}

impl<'a, W: OutputStream> BufferedOutputStream for BufferedOutputStreamWrapper<'a, W> {
    #[inline]
    unsafe fn get_write_buffer(&mut self) -> (*mut u8, *mut u8) {
        let len = self.buf.len();
        (self.buf.get_unchecked_mut(self.pos) as *mut u8,
         self.buf.get_unchecked_mut(len) as *mut u8)
    }

    #[inline]
    unsafe fn write_ptr(&mut self, ptr: *mut u8, size: usize) -> ::std::io::Result<()> {
        let easy_case = ptr == self.buf.get_unchecked_mut(self.pos) as *mut u8;
        if easy_case {
            self.pos += size;
            Ok(())
        } else {
            let buf = ::std::slice::from_raw_parts_mut::<u8>(ptr, size);
            self.write(buf)
        }
    }

}

impl<'a, W: OutputStream> OutputStream for BufferedOutputStreamWrapper<'a, W> {
    fn write(&mut self, buf: &[u8]) -> ::std::io::Result<()> {
        let available = self.buf.len() - self.pos;
        let mut size = buf.len();
        if size <= available {
            let dst = &mut self.buf.as_mut_slice()[self.pos ..];
            ::std::slice::bytes::copy_memory(dst, buf);
            self.pos += size;
        } else if size <= self.buf.len() {
            // Too much for this buffer, but not a full buffer's
            // worth, so we'll go ahead and copy.
            {
                let dst = &mut self.buf.as_mut_slice()[self.pos ..];
                ::std::slice::bytes::copy_memory(dst, &buf[0 .. available]);
            }
            try!(self.inner.write(self.buf.as_mut_slice()));

            size -= available;
            let src = &buf[available ..];
            let dst = &mut self.buf.as_mut_slice()[0 ..];
            ::std::slice::bytes::copy_memory(dst, src);
            self.pos = size;
        } else {
            // Writing so much data that we might as well write
            // directly to avoid a copy.
            try!(self.inner.write(&self.buf[0 .. self.pos]));
            self.pos = 0;
            try!(self.inner.write(buf));
        }
        return Ok(());
    }

    fn flush(&mut self) -> ::std::io::Result<()> {
        if self.pos > 0 {
            try!(self.inner.write(&self.buf[0 .. self.pos]));
            self.pos = 0;
        }
        self.inner.flush()
    }
}

pub struct ArrayOutputStream<'a> {
    array : &'a mut [u8],
    fill_pos : usize,
}

impl <'a> ArrayOutputStream<'a> {
    pub fn new<'b>(array : &'b mut [u8]) -> ArrayOutputStream<'b> {
        ArrayOutputStream {
            array : array,
            fill_pos : 0
        }
    }
}

impl <'a> OutputStream for ArrayOutputStream<'a> {
    fn write(&mut self, buf: &[u8]) -> ::std::io::Result<()> {
        assert!(buf.len() <= self.array.len() - self.fill_pos,
                "ArrayOutputStream's backing array was not large enough for the data written.");
        ::std::slice::bytes::copy_memory(&mut self.array[self.fill_pos ..], buf);
        self.fill_pos += buf.len();
        Ok(())
    }
}

impl <'a> BufferedOutputStream for ArrayOutputStream<'a> {
    unsafe fn get_write_buffer(&mut self) -> (*mut u8, *mut u8) {
        let len = self.array.len();
        (self.array.get_unchecked_mut(self.fill_pos) as *mut u8,
         self.array.get_unchecked_mut(len) as *mut u8)
    }
    unsafe fn write_ptr(&mut self, ptr: *mut u8, size: usize) -> ::std::io::Result<()> {
        let easy_case = ptr == self.array.get_unchecked_mut(self.fill_pos) as *mut u8;
        if easy_case {
            self.fill_pos += size;
            Ok(())
        } else {
            let buf = ::std::slice::from_raw_parts_mut::<u8>(ptr, size);
            self.write(buf)
        }
    }
}
<commit_msg>Retry if errno is EINTR.<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Input / output.

/// A producer of bytes.
pub trait InputStream {
    /// Reads at least `min_bytes` into `buf` unless EOF is encountered first. Returns the
    /// number of bytes read.
    fn try_read(&mut self, buf : &mut [u8], min_bytes : usize) -> ::std::io::Result<usize>;

    /// Reads at least `min_bytes` into `buf`, returning the number of bytes read. If EOF is
    /// encountered first, returns an error.
    fn read(&mut self, buf : &mut [u8], min_bytes : usize) -> ::std::io::Result<usize> {
        let n = try!(self.try_read(buf, min_bytes));
        if n < min_bytes {
            Err(::std::io::Error::new(::std::io::ErrorKind::Other, "Premature EOF", None))
        } else {
            Ok(n)
        }
    }

    /// Reads into `buf` until it is full. Returns an error if EOF is encountered first.
    fn read_exact(&mut self, buf : &mut [u8]) -> ::std::io::Result<()> {
        let min_bytes = buf.len();
        try!(self.read(buf, min_bytes));
        Ok(())
    }
}

impl <R> InputStream for R where R : ::std::io::Read {
    fn try_read(&mut self, buf : &mut [u8], min_bytes : usize) -> ::std::io::Result<usize> {
        let mut pos = 0;
        while pos < min_bytes {
            let buf1 = &mut buf[pos ..];
            match self.read(buf1) {
                Ok(n) => {
                    pos += n;
                    if n == 0 { return Ok(pos); }
                }
                Err(e) => {
                    if e.kind() != ::std::io::ErrorKind::Interrupted {
                        return Err(e);
                    }
                    // Retry if we were interrupted.
                }
            }
        }
        return Ok(pos);
    }
}

pub trait BufferedInputStream : InputStream {
    fn skip(&mut self, bytes : usize) -> ::std::io::Result<()>;
    unsafe fn get_read_buffer(&mut self) -> ::std::io::Result<(*const u8, *const u8)>;
}

pub struct BufferedInputStreamWrapper<R> {
    inner : R,
    buf : Vec<u8>,
    pos : usize,
    cap : usize
}

impl <R> BufferedInputStreamWrapper<R> {
    pub fn new(r : R) -> BufferedInputStreamWrapper<R> {
        let mut result = BufferedInputStreamWrapper {
            inner : r,
            buf : Vec::with_capacity(8192),
            pos : 0,
            cap : 0
        };
        unsafe {
            result.buf.set_len(8192)
        }
        return result;
    }
}

impl<R: InputStream> BufferedInputStream for BufferedInputStreamWrapper<R> {

   fn skip(&mut self, mut bytes : usize) -> ::std::io::Result<()> {
        let available = self.cap - self.pos;
        if bytes <= available {
            self.pos += bytes;
        } else {
            bytes -= available;
            if bytes <= self.buf.len() {
                //# Read the next buffer-full.
                let n = try!(self.inner.try_read(self.buf.as_mut_slice(), bytes));
                self.pos = bytes;
                self.cap = n;
            } else {
                //# Forward large skip to the underlying stream.
                panic!("TODO")
            }
        }
        Ok(())
    }

    unsafe fn get_read_buffer(&mut self) -> ::std::io::Result<(*const u8, *const u8)> {
        if self.cap - self.pos == 0 {
            let n = try!(self.inner.try_read(self.buf.as_mut_slice(), 1));
            self.cap = n;
            self.pos = 0;
        }
        Ok((self.buf.get_unchecked(self.pos) as *const u8,
            self.buf.get_unchecked(self.cap) as *const u8))
    }
}

impl<R: InputStream> InputStream for BufferedInputStreamWrapper<R> {
    fn try_read(&mut self, mut dst: &mut [u8], mut min_bytes : usize) -> ::std::io::Result<usize> {
        if min_bytes <= self.cap - self.pos {
            // Serve from the current buffer.
            let n = ::std::cmp::min(self.cap - self.pos, dst.len());
            ::std::slice::bytes::copy_memory(dst,
                                             &self.buf[self.pos .. self.pos + n]);
            self.pos += n;
            return Ok(n);
        } else {
            // Copy current available into destination.
            ::std::slice::bytes::copy_memory(dst,
                                             &self.buf[self.pos .. self.cap]);
            let from_first_buffer = self.cap - self.pos;

            let dst = &mut dst[from_first_buffer ..];
            min_bytes -= from_first_buffer;

            if dst.len() <= self.buf.len() {
                // Read the next buffer-full.
                let n = try!(self.inner.try_read(self.buf.as_mut_slice(), min_bytes));
                let from_second_buffer = ::std::cmp::min(n, dst.len());
                ::std::slice::bytes::copy_memory(dst,
                                                 &self.buf[0 .. from_second_buffer]);
                self.cap = n;
                self.pos = from_second_buffer;
                return Ok(from_first_buffer + from_second_buffer);
            } else {
                // Forward large read to the underlying stream.
                self.pos = 0;
                self.cap = 0;
                return Ok(from_first_buffer + try!(self.inner.try_read(dst, min_bytes)));
            }
        }
    }
}

pub struct ArrayInputStream<'a> {
    array : &'a [u8]
}

impl <'a> ArrayInputStream<'a> {
    pub fn new<'b>(array : &'b [u8]) -> ArrayInputStream<'b> {
        ArrayInputStream { array : array }
    }
}

impl <'a> InputStream for ArrayInputStream<'a> {
    fn try_read(&mut self, dst: &mut [u8], _min_bytes : usize) -> ::std::io::Result<usize> {
        let n = ::std::cmp::min(dst.len(), self.array.len());
        ::std::slice::bytes::copy_memory(dst, &self.array[0 .. n]);
        self.array = &self.array[n ..];
        Ok(n)
    }
}

impl <'a> BufferedInputStream for ArrayInputStream<'a> {
    fn skip(&mut self, bytes : usize) -> ::std::io::Result<()> {
        assert!(self.array.len() >= bytes,
                "ArrayInputStream ended prematurely.");
        self.array = &self.array[bytes ..];
        Ok(())
    }
    unsafe fn get_read_buffer(&mut self) -> ::std::io::Result<(*const u8, *const u8)> {
        let len = self.array.len();
        Ok((self.array.as_ptr() as *const u8,
           self.array.get_unchecked(len) as *const u8))
    }
}

/// A consumer of bytes.
pub trait OutputStream {
    /// Writes all of `buf`.
    fn write(&mut self, buf : &[u8]) -> ::std::io::Result<()>;
    fn flush(&mut self) -> ::std::io::Result<()> { Ok(()) }
}

impl <W> OutputStream for W where W : ::std::io::Write {
    fn write(&mut self, buf : &[u8]) -> ::std::io::Result<()> {
        self.write_all(buf)
    }
    fn flush(&mut self) -> ::std::io::Result<()> {
        self.flush()
    }
}

pub trait BufferedOutputStream : OutputStream {
    unsafe fn get_write_buffer(&mut self) -> (*mut u8, *mut u8);
    unsafe fn write_ptr(&mut self, ptr: *mut u8, size: usize) -> ::std::io::Result<()>;
}

pub struct BufferedOutputStreamWrapper<'a, W:'a> {
    inner: &'a mut W,
    buf: Vec<u8>,
    pos: usize
}

impl <'a, W> BufferedOutputStreamWrapper<'a, W> {
    pub fn new<'b> (w : &'b mut W) -> BufferedOutputStreamWrapper<W> {
        let mut result = BufferedOutputStreamWrapper {
            inner: w,
            buf : Vec::with_capacity(8192),
            pos : 0
        };
        unsafe {
            result.buf.set_len(8192);
        }
        return result;
    }
}

impl<'a, W: OutputStream> BufferedOutputStream for BufferedOutputStreamWrapper<'a, W> {
    #[inline]
    unsafe fn get_write_buffer(&mut self) -> (*mut u8, *mut u8) {
        let len = self.buf.len();
        (self.buf.get_unchecked_mut(self.pos) as *mut u8,
         self.buf.get_unchecked_mut(len) as *mut u8)
    }

    #[inline]
    unsafe fn write_ptr(&mut self, ptr: *mut u8, size: usize) -> ::std::io::Result<()> {
        let easy_case = ptr == self.buf.get_unchecked_mut(self.pos) as *mut u8;
        if easy_case {
            self.pos += size;
            Ok(())
        } else {
            let buf = ::std::slice::from_raw_parts_mut::<u8>(ptr, size);
            self.write(buf)
        }
    }

}

impl<'a, W: OutputStream> OutputStream for BufferedOutputStreamWrapper<'a, W> {
    fn write(&mut self, buf: &[u8]) -> ::std::io::Result<()> {
        let available = self.buf.len() - self.pos;
        let mut size = buf.len();
        if size <= available {
            let dst = &mut self.buf.as_mut_slice()[self.pos ..];
            ::std::slice::bytes::copy_memory(dst, buf);
            self.pos += size;
        } else if size <= self.buf.len() {
            // Too much for this buffer, but not a full buffer's
            // worth, so we'll go ahead and copy.
            {
                let dst = &mut self.buf.as_mut_slice()[self.pos ..];
                ::std::slice::bytes::copy_memory(dst, &buf[0 .. available]);
            }
            try!(self.inner.write(self.buf.as_mut_slice()));

            size -= available;
            let src = &buf[available ..];
            let dst = &mut self.buf.as_mut_slice()[0 ..];
            ::std::slice::bytes::copy_memory(dst, src);
            self.pos = size;
        } else {
            // Writing so much data that we might as well write
            // directly to avoid a copy.
            try!(self.inner.write(&self.buf[0 .. self.pos]));
            self.pos = 0;
            try!(self.inner.write(buf));
        }
        return Ok(());
    }

    fn flush(&mut self) -> ::std::io::Result<()> {
        if self.pos > 0 {
            try!(self.inner.write(&self.buf[0 .. self.pos]));
            self.pos = 0;
        }
        self.inner.flush()
    }
}

pub struct ArrayOutputStream<'a> {
    array : &'a mut [u8],
    fill_pos : usize,
}

impl <'a> ArrayOutputStream<'a> {
    pub fn new<'b>(array : &'b mut [u8]) -> ArrayOutputStream<'b> {
        ArrayOutputStream {
            array : array,
            fill_pos : 0
        }
    }
}

impl <'a> OutputStream for ArrayOutputStream<'a> {
    fn write(&mut self, buf: &[u8]) -> ::std::io::Result<()> {
        assert!(buf.len() <= self.array.len() - self.fill_pos,
                "ArrayOutputStream's backing array was not large enough for the data written.");
        ::std::slice::bytes::copy_memory(&mut self.array[self.fill_pos ..], buf);
        self.fill_pos += buf.len();
        Ok(())
    }
}

impl <'a> BufferedOutputStream for ArrayOutputStream<'a> {
    unsafe fn get_write_buffer(&mut self) -> (*mut u8, *mut u8) {
        let len = self.array.len();
        (self.array.get_unchecked_mut(self.fill_pos) as *mut u8,
         self.array.get_unchecked_mut(len) as *mut u8)
    }
    unsafe fn write_ptr(&mut self, ptr: *mut u8, size: usize) -> ::std::io::Result<()> {
        let easy_case = ptr == self.array.get_unchecked_mut(self.fill_pos) as *mut u8;
        if easy_case {
            self.fill_pos += size;
            Ok(())
        } else {
            let buf = ::std::slice::from_raw_parts_mut::<u8>(ptr, size);
            self.write(buf)
        }
    }
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate std;
use self::std::prelude::v1::*;
use self::std::env;
use self::std::io::Error as IoError;
use self::libc::{c_void, size_t};
use core::ptr;
use stack;
use valgrind;

#[allow(raw_pointer_derive)]
#[derive(Debug)]
pub struct Stack {
  ptr: *mut u8,
  len: usize,
  valgrind_id: valgrind::stack_id_t
}

pub struct StackSource;

impl stack::StackSource for StackSource {
  type Output = Stack;
  fn get_stack(size: usize) -> Stack {
    Stack::new(size)
  }
}

impl stack::Stack for Stack {
  fn top(&mut self) -> *mut u8 {
    unsafe {
      self.ptr.offset(self.len as isize)
    }
  }

  fn limit(&self) -> *const u8 {
    unsafe {
      self.ptr.offset(env::page_size() as isize)
    }
  }
}

impl Stack {
  fn new(size: usize) -> Stack {
    let page_size = env::page_size();

    // round the page size up,
    // using the fact that it is a power of two
    let len = (size + page_size - 1) & !(page_size - 1);

    const STACK_PROT: libc::c_int = libc::PROT_READ | libc::PROT_WRITE;
    const STACK_FLAGS: libc::c_int = libc::MAP_STACK
                                   | libc::MAP_PRIVATE
                                   | libc::MAP_ANON;

    let stack = unsafe {
      let ptr = libc::mmap(ptr::null_mut(), len as size_t,
                           STACK_PROT, STACK_FLAGS, -1, 0);

      if ptr == libc::MAP_FAILED {
        panic!("mmap for stack of size {} failed: {:?}",
               len, IoError::last_os_error())
      }

      let valgrind_id =
        valgrind::stack_register(ptr.offset(len as isize) as *const _,
                                 ptr as *const _);

      Stack { ptr: ptr as *mut u8, len: len, valgrind_id: valgrind_id }
    };

    stack.protect();

    stack
  }

  fn protect(&self) {
    unsafe {
      if libc::mprotect(self.ptr as *mut c_void,
                        env::page_size() as libc::size_t,
                        libc::PROT_NONE) != 0 {
        panic!("mprotect for guard page of stack {:p} failed: {:?}",
               self.ptr, IoError::last_os_error());
      }
    }
  }
}

impl Drop for Stack {
  fn drop(&mut self) {
    unsafe {
      valgrind::stack_deregister(self.valgrind_id);
      if libc::munmap(self.ptr as *mut c_void, self.len as size_t) != 0 {
        panic!("munmap for stack {:p} of size {} failed: {:?}",
               self.ptr, self.len, IoError::last_os_error())
      }
    }
  }
}
<commit_msg>pass os::Stack addresses to Valgrind in the right order<commit_after>extern crate libc;
extern crate std;
use self::std::prelude::v1::*;
use self::std::env;
use self::std::io::Error as IoError;
use self::libc::{c_void, size_t};
use core::ptr;
use stack;
use valgrind;

#[allow(raw_pointer_derive)]
#[derive(Debug)]
pub struct Stack {
  ptr: *mut u8,
  len: usize,
  valgrind_id: valgrind::stack_id_t
}

pub struct StackSource;

impl stack::StackSource for StackSource {
  type Output = Stack;
  fn get_stack(size: usize) -> Stack {
    Stack::new(size)
  }
}

impl stack::Stack for Stack {
  fn top(&mut self) -> *mut u8 {
    unsafe {
      self.ptr.offset(self.len as isize)
    }
  }

  fn limit(&self) -> *const u8 {
    unsafe {
      self.ptr.offset(env::page_size() as isize)
    }
  }
}

impl Stack {
  fn new(size: usize) -> Stack {
    let page_size = env::page_size();

    // round the page size up,
    // using the fact that it is a power of two
    let len = (size + page_size - 1) & !(page_size - 1);

    const STACK_PROT: libc::c_int = libc::PROT_READ | libc::PROT_WRITE;
    const STACK_FLAGS: libc::c_int = libc::MAP_STACK
                                   | libc::MAP_PRIVATE
                                   | libc::MAP_ANON;

    let stack = unsafe {
      let ptr = libc::mmap(ptr::null_mut(), len as size_t,
                           STACK_PROT, STACK_FLAGS, -1, 0);

      if ptr == libc::MAP_FAILED {
        panic!("mmap for stack of size {} failed: {:?}",
               len, IoError::last_os_error())
      }

      let valgrind_id =
        valgrind::stack_register(ptr as *const _,
                                 ptr.offset(len as isize) as *const _);

      Stack { ptr: ptr as *mut u8, len: len, valgrind_id: valgrind_id }
    };

    stack.protect();

    stack
  }

  fn protect(&self) {
    unsafe {
      if libc::mprotect(self.ptr as *mut c_void,
                        env::page_size() as libc::size_t,
                        libc::PROT_NONE) != 0 {
        panic!("mprotect for guard page of stack {:p} failed: {:?}",
               self.ptr, IoError::last_os_error());
      }
    }
  }
}

impl Drop for Stack {
  fn drop(&mut self) {
    unsafe {
      valgrind::stack_deregister(self.valgrind_id);
      if libc::munmap(self.ptr as *mut c_void, self.len as size_t) != 0 {
        panic!("munmap for stack {:p} of size {} failed: {:?}",
               self.ptr, self.len, IoError::last_os_error())
      }
    }
  }
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use mirai_annotations::debug_checked_precondition;
use serde::{Serialize, Serializer};
use static_assertions::const_assert;
use std::{fmt, str};
use thiserror::Error;

/// An efficient container for formatting a byte slice as a hex-formatted string,
/// stored on the stack.
///
/// Using `ShortHexStr` instead of `hex::encode` is about 3-4x faster on a recent
/// MBP 2019 (~48 ns/iter vs ~170 ns/iter) in an artifical micro benchmark.
#[derive(Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)]
pub struct ShortHexStr([u8; ShortHexStr::LENGTH]);

#[derive(Error, Debug)]
#[error("Input bytes are too short")]
pub struct InputTooShortError;

impl ShortHexStr {
    pub const SOURCE_LENGTH: usize = 4;
    pub const LENGTH: usize = 2 * ShortHexStr::SOURCE_LENGTH;

    /// Format a new `ShortHexStr` from a byte slice.
    ///
    /// Returns `Err(InputTooShortError)` if the input byte slice length is less
    /// than `SOURCE_LENGTH` bytes.
    pub fn try_from_bytes(src_bytes: &[u8]) -> Result<ShortHexStr, InputTooShortError> {
        if src_bytes.len() >= ShortHexStr::SOURCE_LENGTH {
            let src_short_bytes = &src_bytes[0..ShortHexStr::SOURCE_LENGTH];
            let mut dest_bytes = [0u8; ShortHexStr::LENGTH];

            // We include a tiny hex encode here instead of using the `hex` crate's
            // `encode_to_slice`, since the compiler seems unable to inline across
            // the crate boundary.
            hex_encode(&src_short_bytes, &mut dest_bytes);
            Ok(Self(dest_bytes))
        } else {
            Err(InputTooShortError)
        }
    }

    pub fn as_str(&self) -> &str {
        // We could also do str::from_utf8_unchecked here to avoid the unnecessary
        // runtime check. Shaves ~6-7 ns/iter in a micro bench but the unsafe is
        // probably not worth the hassle.
        str::from_utf8(&self.0).expect(
            "This can never fail since &self.0 will only ever contain the \
             following characters: '0123456789abcdef', which are all valid \
             ASCII characters and therefore all valid UTF-8",
        )
    }
}

impl fmt::Debug for ShortHexStr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.as_str())
    }
}

impl fmt::Display for ShortHexStr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.as_str())
    }
}

impl Serialize for ShortHexStr {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(self.as_str())
    }
}

/// Maps a nibble to its corresponding hex-formatted ASCII character.
const HEX_CHARS_LOWER: &[u8; 16] = b"0123456789abcdef";

/// Format a byte as hex. Returns a tuple containing the first character and then
/// the second character as ASCII bytes.
#[inline(always)]
fn byte2hex(byte: u8) -> (u8, u8) {
    let hi = HEX_CHARS_LOWER[((byte >> 4) & 0x0f) as usize];
    let lo = HEX_CHARS_LOWER[(byte & 0x0f) as usize];
    (hi, lo)
}

/// Hex encode a byte slice into the destination byte slice.
#[inline(always)]
fn hex_encode(src: &[u8], dst: &mut [u8]) {
    debug_checked_precondition!(dst.len() == 2 * src.len());

    for (byte, out) in src.iter().zip(dst.chunks_mut(2)) {
        let (hi, lo) = byte2hex(*byte);
        out[0] = hi;
        out[1] = lo;
    }
}

pub trait AsShortHexStr {
    fn short_str(&self) -> ShortHexStr;
}

impl AsShortHexStr for [u8; 16] {
    fn short_str(&self) -> ShortHexStr {
        const_assert!(16 >= ShortHexStr::SOURCE_LENGTH);
        ShortHexStr::try_from_bytes(self)
            .expect("This can never fail since 16 >= ShortHexStr::SOURCE_LENGTH")
    }
}

impl AsShortHexStr for [u8; 32] {
    fn short_str(&self) -> ShortHexStr {
        const_assert!(32 >= ShortHexStr::SOURCE_LENGTH);
        ShortHexStr::try_from_bytes(self)
            .expect("This can never fail since 32 >= ShortHexStr::SOURCE_LENGTH")
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use proptest::prelude::*;
    use std::{str, u8};

    #[test]
    fn test_hex_encode() {
        let src = [0x12_u8, 0x34, 0xfe, 0xba];
        let mut actual = [0u8; 8];
        hex_encode(&src, &mut actual);
        let expected = b"1234feba";
        assert_eq!(&actual, expected);
    }

    #[test]
    fn test_byte2hex_equivalence() {
        for byte in 0..=u8::MAX {
            let (hi, lo) = byte2hex(byte);
            let formatted_bytes = [hi, lo];
            let actual = str::from_utf8(&formatted_bytes[..]).unwrap();
            let expected = hex::encode(&[byte][..]);
            assert_eq!(actual, expected.as_str());
        }
    }

    proptest! {
        #[test]
        fn test_address_short_str_equivalence(addr in any::<[u8; 16]>()) {
            let short_str_old = hex::encode(&addr[0..ShortHexStr::SOURCE_LENGTH]);
            let short_str_new = ShortHexStr::try_from_bytes(&addr).unwrap();
            prop_assert_eq!(short_str_old.as_str(), short_str_new.as_str());
        }
    }
}
<commit_msg>[short-hex-str] Disable clippy arithmetic overflow lints with comments<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use mirai_annotations::debug_checked_precondition;
use serde::{Serialize, Serializer};
use static_assertions::const_assert;
use std::{fmt, str};
use thiserror::Error;

/// An efficient container for formatting a byte slice as a hex-formatted string,
/// stored on the stack.
///
/// Using `ShortHexStr` instead of `hex::encode` is about 3-4x faster on a recent
/// MBP 2019 (~48 ns/iter vs ~170 ns/iter) in an artifical micro benchmark.
#[derive(Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)]
pub struct ShortHexStr([u8; ShortHexStr::LENGTH]);

#[derive(Error, Debug)]
#[error("Input bytes are too short")]
pub struct InputTooShortError;

impl ShortHexStr {
    pub const SOURCE_LENGTH: usize = 4;
    pub const LENGTH: usize = 2 * ShortHexStr::SOURCE_LENGTH;

    /// Format a new `ShortHexStr` from a byte slice.
    ///
    /// Returns `Err(InputTooShortError)` if the input byte slice length is less
    /// than `SOURCE_LENGTH` bytes.
    pub fn try_from_bytes(src_bytes: &[u8]) -> Result<ShortHexStr, InputTooShortError> {
        if src_bytes.len() >= ShortHexStr::SOURCE_LENGTH {
            let src_short_bytes = &src_bytes[0..ShortHexStr::SOURCE_LENGTH];
            let mut dest_bytes = [0u8; ShortHexStr::LENGTH];

            // We include a tiny hex encode here instead of using the `hex` crate's
            // `encode_to_slice`, since the compiler seems unable to inline across
            // the crate boundary.
            hex_encode(&src_short_bytes, &mut dest_bytes);
            Ok(Self(dest_bytes))
        } else {
            Err(InputTooShortError)
        }
    }

    pub fn as_str(&self) -> &str {
        // We could also do str::from_utf8_unchecked here to avoid the unnecessary
        // runtime check. Shaves ~6-7 ns/iter in a micro bench but the unsafe is
        // probably not worth the hassle.
        str::from_utf8(&self.0).expect(
            "This can never fail since &self.0 will only ever contain the \
             following characters: '0123456789abcdef', which are all valid \
             ASCII characters and therefore all valid UTF-8",
        )
    }
}

impl fmt::Debug for ShortHexStr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.as_str())
    }
}

impl fmt::Display for ShortHexStr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.as_str())
    }
}

impl Serialize for ShortHexStr {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(self.as_str())
    }
}

/// Maps a nibble to its corresponding hex-formatted ASCII character.
const HEX_CHARS_LOWER: &[u8; 16] = b"0123456789abcdef";

/// Format a byte as hex. Returns a tuple containing the first character and then
/// the second character as ASCII bytes.
#[inline(always)]
fn byte2hex(byte: u8) -> (u8, u8) {
    #[allow(clippy::integer_arithmetic)] // X >> 4 is valid for all bytes
    let hi = HEX_CHARS_LOWER[((byte >> 4) & 0x0f) as usize];
    let lo = HEX_CHARS_LOWER[(byte & 0x0f) as usize];
    (hi, lo)
}

/// Hex encode a byte slice into the destination byte slice.
#[inline(always)]
#[allow(clippy::integer_arithmetic)] // debug only assertion
fn hex_encode(src: &[u8], dst: &mut [u8]) {
    debug_checked_precondition!(dst.len() == 2 * src.len());

    for (byte, out) in src.iter().zip(dst.chunks_mut(2)) {
        let (hi, lo) = byte2hex(*byte);
        out[0] = hi;
        out[1] = lo;
    }
}

pub trait AsShortHexStr {
    fn short_str(&self) -> ShortHexStr;
}

impl AsShortHexStr for [u8; 16] {
    fn short_str(&self) -> ShortHexStr {
        const_assert!(16 >= ShortHexStr::SOURCE_LENGTH);
        ShortHexStr::try_from_bytes(self)
            .expect("This can never fail since 16 >= ShortHexStr::SOURCE_LENGTH")
    }
}

impl AsShortHexStr for [u8; 32] {
    fn short_str(&self) -> ShortHexStr {
        const_assert!(32 >= ShortHexStr::SOURCE_LENGTH);
        ShortHexStr::try_from_bytes(self)
            .expect("This can never fail since 32 >= ShortHexStr::SOURCE_LENGTH")
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use proptest::prelude::*;
    use std::{str, u8};

    #[test]
    fn test_hex_encode() {
        let src = [0x12_u8, 0x34, 0xfe, 0xba];
        let mut actual = [0u8; 8];
        hex_encode(&src, &mut actual);
        let expected = b"1234feba";
        assert_eq!(&actual, expected);
    }

    #[test]
    fn test_byte2hex_equivalence() {
        for byte in 0..=u8::MAX {
            let (hi, lo) = byte2hex(byte);
            let formatted_bytes = [hi, lo];
            let actual = str::from_utf8(&formatted_bytes[..]).unwrap();
            let expected = hex::encode(&[byte][..]);
            assert_eq!(actual, expected.as_str());
        }
    }

    proptest! {
        #[test]
        fn test_address_short_str_equivalence(addr in any::<[u8; 16]>()) {
            let short_str_old = hex::encode(&addr[0..ShortHexStr::SOURCE_LENGTH]);
            let short_str_new = ShortHexStr::try_from_bytes(&addr).unwrap();
            prop_assert_eq!(short_str_old.as_str(), short_str_new.as_str());
        }
    }
}
<|endoftext|>


<commit_before>use crate::airport_data::{Airport, AirportType, Position, Runway};
use rand::seq::SliceRandom;
use rocket::State;
use rocket_contrib::json::{Json, JsonValue};
use serde_derive::{Deserialize, Serialize};
use std::fmt;
use std::ptr;

const MAX_AIRPORTS_TO_GET: usize = 2000;
const MAX_AIRPORTS_TO_RETURN: usize = 100;

#[post("/search_routes", format = "json", data = "<filters>")]
pub fn search_routes<'a>(filters: Json<Filters>, airports: State<'a, Vec<Airport>>) -> JsonValue {
    let departures = filters
        .departure
        .as_ref()
        .map(|filters| filters.matching_airports(&airports))
        .unwrap_or_else(|| random_airport_set(&airports));

    let arrivals = filters
        .arrival
        .as_ref()
        .map(|filters| filters.matching_airports(&airports))
        .unwrap_or_else(|| random_airport_set(&airports));

    let mut routes = Vec::with_capacity(MAX_AIRPORTS_TO_RETURN / 2);

    for departure in departures {
        for arrival in &arrivals {
            if ptr::eq(departure, *arrival) {
                continue;
            }

            let route = Route::new(departure, arrival, filters.speed);

            match &filters.time_or_dist {
                Some(TimeOrDistance::Time(time_range)) => {
                    if !time_range.within(&route.time) {
                        continue;
                    }
                }
                Some(TimeOrDistance::Distance(dist_range)) => {
                    if !dist_range.within(&route.distance) {
                        continue;
                    }
                }
                None => (),
            }

            routes.push(route);
        }
    }

    let mut routes = routes.as_mut_slice();

    if routes.len() > 1 {
        let (shuffled, _) = routes.partial_shuffle(&mut rand::thread_rng(), MAX_AIRPORTS_TO_RETURN);
        routes = shuffled;
    }

    json!({ "routes": routes })
}

#[inline(always)]
fn random_airport_set(airports: &[Airport]) -> Vec<&Airport> {
    airports
        .choose_multiple(&mut rand::thread_rng(), MAX_AIRPORTS_TO_GET)
        .collect()
}

#[derive(Debug, Serialize)]
struct Route<'a> {
    from: &'a Airport,
    to: &'a Airport,
    distance: f32,
    time: Time,
}

impl<'a> Route<'a> {
    #[inline(always)]
    fn new(from: &'a Airport, to: &'a Airport, speed: Speed) -> Self {
        let distance = Self::calculate_distance(from.position, to.position);
        let time = Time::from_distance(distance, speed);

        Self {
            from,
            to,
            distance,
            time,
        }
    }

    /// Get the distance in nautical miles between two longitude and latitude points
    /// using the Haversine formula.
    fn calculate_distance(from: Position, to: Position) -> f32 {
        // Radius of Earth in nautical miles
        const RADIUS_NM: f32 = 3440.0;

        let from_lat = from.latitude_deg.to_radians();
        let to_lat = to.latitude_deg.to_radians();
        let lat = to_lat - from_lat;

        let lon = (to.longitude_deg - from.longitude_deg).to_radians();

        let a =
            (lat / 2.0).sin().powi(2) + from_lat.cos() * to_lat.cos() * (lon / 2.0).sin().powi(2);
        let c = 2.0 * a.sqrt().atan2((1.0 - a).sqrt());

        RADIUS_NM * c
    }
}

#[derive(Copy, Clone, Debug, Default, Deserialize, Serialize, PartialEq, PartialOrd)]
pub struct Time {
    pub hour: u8,
    pub minutes: u8,
}

impl Time {
    fn from_distance(distance: f32, speed: Speed) -> Self {
        let total_hours = distance / speed.as_knots();

        let hour = total_hours.floor().min(99.0);
        let minutes = ((total_hours - hour) * 60.0).floor().min(59.0);

        Self {
            hour: hour as u8,
            minutes: minutes as u8,
        }
    }
}

#[derive(Copy, Clone, Debug, Deserialize)]
#[serde(rename_all = "lowercase")]
#[serde(tag = "type", content = "value")]
pub enum Speed {
    Mach(f32),
    Knots(f32),
}

impl Speed {
    #[inline(always)]
    fn as_knots(self) -> f32 {
        const KNOTS_PER_MACH: f32 = 666.739;

        match self {
            Self::Mach(mach) => mach * KNOTS_PER_MACH,
            Self::Knots(knots) => knots,
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct Filters {
    pub speed: Speed,
    pub departure: Option<AirportFilters>,
    pub arrival: Option<AirportFilters>,
    #[serde(rename = "timeDist", default)]
    pub time_or_dist: Option<TimeOrDistance>,
}

#[derive(Debug, Deserialize)]
pub struct AirportFilters {
    pub icao: Option<String>,
    #[serde(rename = "airportType", default)]
    pub airport_type: AirportType,
    #[serde(rename = "runwayLength")]
    pub runway_length: Option<RunwayLength>,
    #[serde(default)]
    pub countries: Vec<String>,
}

impl AirportFilters {
    pub fn matching_airports<'a>(&self, airports: &'a [Airport]) -> Vec<&'a Airport> {
        if let Some(icao) = &self.icao {
            let index = airports
                .binary_search_by(|arpt| arpt.icao.as_str().cmp(icao.as_str()))
                .ok();

            let index = match index {
                Some(index) => index,
                None => return Vec::new(),
            };

            return vec![&airports[index]];
        }

        type MatchClosure<'a> = Box<dyn Fn(&Airport) -> bool + 'a>;

        let type_matches: MatchClosure = match self.airport_type {
            AirportType::Unknown => Box::new(|_| true),
            kind => Box::new(move |arpt| arpt.class == kind),
        };

        let runway_len_matches: MatchClosure = match self.runway_length {
            Some(len) => Box::new(move |arpt| len.fits_any(&arpt.runways)),
            None => Box::new(|_| true),
        };

        let country_matches: MatchClosure = match self.countries.as_slice() {
            [] => Box::new(|_| true),
            countries => Box::new(move |arpt| Self::list_has_any(&arpt.country_name, countries)),
        };

        Self::airport_matches(
            |arpt| type_matches(arpt) && runway_len_matches(arpt) && country_matches(arpt),
            airports,
        )
    }

    fn airport_matches<F>(matcher: F, airports: &[Airport]) -> Vec<&Airport>
    where
        F: Fn(&Airport) -> bool,
    {
        let mut results = Vec::new();

        for airport in airports {
            if !matcher(airport) {
                continue;
            }

            results.push(airport);

            if results.len() >= MAX_AIRPORTS_TO_GET {
                break;
            }
        }

        results
    }

    #[inline(always)]
    fn list_has_any(name: &str, list: &[String]) -> bool {
        list.iter().any(|x| x.eq_ignore_ascii_case(name))
    }
}

#[derive(Copy, Clone, Debug, Deserialize)]
#[serde(tag = "selector", content = "length")]
pub enum RunwayLength {
    #[serde(rename = "eq")]
    Equal(u32),
    #[serde(rename = "gt")]
    GreaterThan(u32),
    #[serde(rename = "lt")]
    LessThan(u32),
}

impl RunwayLength {
    #[inline(always)]
    pub fn fits(self, length: u32) -> bool {
        match self {
            Self::Equal(len) => len == length,
            Self::GreaterThan(len) => length > len,
            Self::LessThan(len) => length < len,
        }
    }

    #[inline(always)]
    pub fn fits_any(self, runways: &[Runway]) -> bool {
        runways.iter().any(|runway| match runway.length_ft {
            Some(len) => self.fits(len),
            None => false,
        })
    }
}

#[derive(Debug, Default, Deserialize)]
pub struct Range<T>
where
    T: fmt::Debug + Default + PartialOrd,
{
    pub min: Option<T>,
    pub max: Option<T>,
}

impl<T> Range<T>
where
    T: fmt::Debug + Default + PartialOrd,
{
    fn within(&self, value: &T) -> bool {
        if let Some(true) = self.min.as_ref().map(|min| value < min) {
            return false;
        }

        if let Some(true) = self.max.as_ref().map(|max| value > max) {
            return false;
        }

        true
    }
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "lowercase")]
#[serde(tag = "type", content = "value")]
pub enum TimeOrDistance {
    #[serde(rename = "time")]
    Time(Range<Time>),
    #[serde(rename = "dist")]
    Distance(Range<f32>),
}

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

    #[test]
    fn range_within() {
        macro_rules! within {
            ($min:expr => $max:expr, $value:expr) => {
                Range::within(
                    &Range {
                        min: $min,
                        max: $max,
                    },
                    &$value,
                )
            };
        }

        assert_eq!(within!(Some(1) => Some(3), 2), true);
        assert_eq!(within!(Some(2) => Some(3), 2), true);
        assert_eq!(within!(Some(2) => Some(3), 3), true);

        assert_eq!(within!(Some(1) => Some(5), 10), false);
        assert_eq!(within!(Some(10) => Some(100), 9), false);
    }

    #[test]
    fn runway_length_fits() {
        assert_eq!(RunwayLength::Equal(12345).fits(12345), true);
        assert_eq!(RunwayLength::Equal(12345).fits(12346), false);

        assert_eq!(RunwayLength::GreaterThan(1000).fits(1001), true);
        assert_eq!(RunwayLength::GreaterThan(1000).fits(1000), false);

        assert_eq!(RunwayLength::LessThan(1000).fits(999), true);
        assert_eq!(RunwayLength::LessThan(1000).fits(1000), false);
    }
}
<commit_msg>backend: Remove unnecessary pub modifiers<commit_after>use crate::airport_data::{Airport, AirportType, Position, Runway};
use rand::seq::SliceRandom;
use rocket::State;
use rocket_contrib::json::{Json, JsonValue};
use serde_derive::{Deserialize, Serialize};
use std::fmt;
use std::ptr;

const MAX_AIRPORTS_TO_GET: usize = 2000;
const MAX_AIRPORTS_TO_RETURN: usize = 100;

#[post("/search_routes", format = "json", data = "<filters>")]
pub fn search_routes<'a>(filters: Json<Filters>, airports: State<'a, Vec<Airport>>) -> JsonValue {
    let departures = filters
        .departure
        .as_ref()
        .map(|filters| filters.matching_airports(&airports))
        .unwrap_or_else(|| random_airport_set(&airports));

    let arrivals = filters
        .arrival
        .as_ref()
        .map(|filters| filters.matching_airports(&airports))
        .unwrap_or_else(|| random_airport_set(&airports));

    let mut routes = Vec::with_capacity(MAX_AIRPORTS_TO_RETURN / 2);

    for departure in departures {
        for arrival in &arrivals {
            if ptr::eq(departure, *arrival) {
                continue;
            }

            let route = Route::new(departure, arrival, filters.speed);

            match &filters.time_or_dist {
                Some(TimeOrDistance::Time(time_range)) => {
                    if !time_range.within(&route.time) {
                        continue;
                    }
                }
                Some(TimeOrDistance::Distance(dist_range)) => {
                    if !dist_range.within(&route.distance) {
                        continue;
                    }
                }
                None => (),
            }

            routes.push(route);
        }
    }

    let mut routes = routes.as_mut_slice();

    if routes.len() > 1 {
        let (shuffled, _) = routes.partial_shuffle(&mut rand::thread_rng(), MAX_AIRPORTS_TO_RETURN);
        routes = shuffled;
    }

    json!({ "routes": routes })
}

#[inline(always)]
fn random_airport_set(airports: &[Airport]) -> Vec<&Airport> {
    airports
        .choose_multiple(&mut rand::thread_rng(), MAX_AIRPORTS_TO_GET)
        .collect()
}

#[derive(Debug, Serialize)]
struct Route<'a> {
    from: &'a Airport,
    to: &'a Airport,
    distance: f32,
    time: Time,
}

impl<'a> Route<'a> {
    #[inline(always)]
    fn new(from: &'a Airport, to: &'a Airport, speed: Speed) -> Self {
        let distance = Self::calculate_distance(from.position, to.position);
        let time = Time::from_distance(distance, speed);

        Self {
            from,
            to,
            distance,
            time,
        }
    }

    /// Get the distance in nautical miles between two longitude and latitude points
    /// using the Haversine formula.
    fn calculate_distance(from: Position, to: Position) -> f32 {
        // Radius of Earth in nautical miles
        const RADIUS_NM: f32 = 3440.0;

        let from_lat = from.latitude_deg.to_radians();
        let to_lat = to.latitude_deg.to_radians();
        let lat = to_lat - from_lat;

        let lon = (to.longitude_deg - from.longitude_deg).to_radians();

        let a =
            (lat / 2.0).sin().powi(2) + from_lat.cos() * to_lat.cos() * (lon / 2.0).sin().powi(2);
        let c = 2.0 * a.sqrt().atan2((1.0 - a).sqrt());

        RADIUS_NM * c
    }
}

#[derive(Copy, Clone, Debug, Default, Deserialize, Serialize, PartialEq, PartialOrd)]
struct Time {
    hour: u8,
    minutes: u8,
}

impl Time {
    fn from_distance(distance: f32, speed: Speed) -> Self {
        let total_hours = distance / speed.as_knots();

        let hour = total_hours.floor().min(99.0);
        let minutes = ((total_hours - hour) * 60.0).floor().min(59.0);

        Self {
            hour: hour as u8,
            minutes: minutes as u8,
        }
    }
}

#[derive(Copy, Clone, Debug, Deserialize)]
#[serde(rename_all = "lowercase")]
#[serde(tag = "type", content = "value")]
pub enum Speed {
    Mach(f32),
    Knots(f32),
}

impl Speed {
    #[inline(always)]
    fn as_knots(self) -> f32 {
        const KNOTS_PER_MACH: f32 = 666.739;

        match self {
            Self::Mach(mach) => mach * KNOTS_PER_MACH,
            Self::Knots(knots) => knots,
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct Filters {
    speed: Speed,
    departure: Option<AirportFilters>,
    arrival: Option<AirportFilters>,
    #[serde(rename = "timeDist", default)]
    time_or_dist: Option<TimeOrDistance>,
}

#[derive(Debug, Deserialize)]
struct AirportFilters {
    icao: Option<String>,
    #[serde(rename = "airportType", default)]
    airport_type: AirportType,
    #[serde(rename = "runwayLength")]
    runway_length: Option<RunwayLength>,
    #[serde(default)]
    countries: Vec<String>,
}

impl AirportFilters {
    fn matching_airports<'a>(&self, airports: &'a [Airport]) -> Vec<&'a Airport> {
        if let Some(icao) = &self.icao {
            let index = airports
                .binary_search_by(|arpt| arpt.icao.as_str().cmp(icao.as_str()))
                .ok();

            let index = match index {
                Some(index) => index,
                None => return Vec::new(),
            };

            return vec![&airports[index]];
        }

        type MatchClosure<'a> = Box<dyn Fn(&Airport) -> bool + 'a>;

        let type_matches: MatchClosure = match self.airport_type {
            AirportType::Unknown => Box::new(|_| true),
            kind => Box::new(move |arpt| arpt.class == kind),
        };

        let runway_len_matches: MatchClosure = match self.runway_length {
            Some(len) => Box::new(move |arpt| len.fits_any(&arpt.runways)),
            None => Box::new(|_| true),
        };

        let country_matches: MatchClosure = match self.countries.as_slice() {
            [] => Box::new(|_| true),
            countries => Box::new(move |arpt| Self::list_has_any(&arpt.country_name, countries)),
        };

        Self::airport_matches(
            |arpt| type_matches(arpt) && runway_len_matches(arpt) && country_matches(arpt),
            airports,
        )
    }

    fn airport_matches<F>(matcher: F, airports: &[Airport]) -> Vec<&Airport>
    where
        F: Fn(&Airport) -> bool,
    {
        let mut results = Vec::new();

        for airport in airports {
            if !matcher(airport) {
                continue;
            }

            results.push(airport);

            if results.len() >= MAX_AIRPORTS_TO_GET {
                break;
            }
        }

        results
    }

    #[inline(always)]
    fn list_has_any(name: &str, list: &[String]) -> bool {
        list.iter().any(|x| x.eq_ignore_ascii_case(name))
    }
}

#[derive(Copy, Clone, Debug, Deserialize)]
#[serde(tag = "selector", content = "length")]
pub enum RunwayLength {
    #[serde(rename = "eq")]
    Equal(u32),
    #[serde(rename = "gt")]
    GreaterThan(u32),
    #[serde(rename = "lt")]
    LessThan(u32),
}

impl RunwayLength {
    #[inline(always)]
    pub fn fits(self, length: u32) -> bool {
        match self {
            Self::Equal(len) => len == length,
            Self::GreaterThan(len) => length > len,
            Self::LessThan(len) => length < len,
        }
    }

    #[inline(always)]
    pub fn fits_any(self, runways: &[Runway]) -> bool {
        runways.iter().any(|runway| match runway.length_ft {
            Some(len) => self.fits(len),
            None => false,
        })
    }
}

#[derive(Debug, Default, Deserialize)]
pub struct Range<T>
where
    T: fmt::Debug + Default + PartialOrd,
{
    pub min: Option<T>,
    pub max: Option<T>,
}

impl<T> Range<T>
where
    T: fmt::Debug + Default + PartialOrd,
{
    fn within(&self, value: &T) -> bool {
        if let Some(true) = self.min.as_ref().map(|min| value < min) {
            return false;
        }

        if let Some(true) = self.max.as_ref().map(|max| value > max) {
            return false;
        }

        true
    }
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "lowercase")]
#[serde(tag = "type", content = "value")]
enum TimeOrDistance {
    #[serde(rename = "time")]
    Time(Range<Time>),
    #[serde(rename = "dist")]
    Distance(Range<f32>),
}

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

    #[test]
    fn range_within() {
        macro_rules! within {
            ($min:expr => $max:expr, $value:expr) => {
                Range::within(
                    &Range {
                        min: $min,
                        max: $max,
                    },
                    &$value,
                )
            };
        }

        assert_eq!(within!(Some(1) => Some(3), 2), true);
        assert_eq!(within!(Some(2) => Some(3), 2), true);
        assert_eq!(within!(Some(2) => Some(3), 3), true);

        assert_eq!(within!(Some(1) => Some(5), 10), false);
        assert_eq!(within!(Some(10) => Some(100), 9), false);
    }

    #[test]
    fn runway_length_fits() {
        assert_eq!(RunwayLength::Equal(12345).fits(12345), true);
        assert_eq!(RunwayLength::Equal(12345).fits(12346), false);

        assert_eq!(RunwayLength::GreaterThan(1000).fits(1001), true);
        assert_eq!(RunwayLength::GreaterThan(1000).fits(1000), false);

        assert_eq!(RunwayLength::LessThan(1000).fits(999), true);
        assert_eq!(RunwayLength::LessThan(1000).fits(1000), false);
    }
}
<|endoftext|>


<commit_before>extern crate proc_macro;

use proc_macro::*;
use std::process::Command;
use std::sync::Once;

#[proc_macro_attribute]
pub fn cargo_test(attr: TokenStream, item: TokenStream) -> TokenStream {
    // Ideally these options would be embedded in the test itself. However, I
    // find it very helpful to have the test clearly state whether or not it
    // is ignored. It would be nice to have some kind of runtime ignore
    // support (such as
    // https://internals.rust-lang.org/t/pre-rfc-skippable-tests/14611).
    //
    // Unfortunately a big drawback here is that if the environment changes
    // (such as the existence of the `git` CLI), this will not trigger a
    // rebuild and the test will still be ignored. In theory, something like
    // `tracked_env` or `tracked_path`
    // (https://github.com/rust-lang/rust/issues/99515) could help with this,
    // but they don't really handle the absence of files well.
    let mut ignore = false;
    let mut requires_reason = false;
    let mut found_reason = false;
    let is_not_nightly = || !version().1;
    for rule in split_rules(attr) {
        match rule.as_str() {
            "build_std_real" => {
                // Only run the "real" build-std tests on nightly and with an
                // explicit opt-in (these generally only work on linux, and
                // have some extra requirements, and are slow, and can pollute
                // the environment since it downloads dependencies).
                ignore |= is_not_nightly();
                ignore |= option_env!("CARGO_RUN_BUILD_STD_TESTS").is_none();
            }
            "build_std_mock" => {
                // Only run the "mock" build-std tests on nightly and disable
                // for windows-gnu which is missing object files (see
                // https://github.com/rust-lang/wg-cargo-std-aware/issues/46).
                ignore |= is_not_nightly();
                ignore |= cfg!(all(target_os = "windows", target_env = "gnu"));
            }
            "nightly" => {
                requires_reason = true;
                ignore |= is_not_nightly();
            }
            s if s.starts_with("requires_") => {
                let command = &s[9..];
                ignore |= !has_command(command);
            }
            s if s.starts_with(">=1.") => {
                requires_reason = true;
                let min_minor = s[4..].parse().unwrap();
                ignore |= version().0 < min_minor;
            }
            s if s.starts_with("reason=") => {
                found_reason = true;
            }
            _ => panic!("unknown rule {:?}", rule),
        }
    }
    if requires_reason && !found_reason {
        panic!(
            "#[cargo_test] with a rule also requires a reason, \
            such as #[cargo_test(nightly, reason = \"needs -Z unstable-thing\")]"
        );
    }

    let span = Span::call_site();
    let mut ret = TokenStream::new();
    let add_attr = |ret: &mut TokenStream, attr_name| {
        ret.extend(Some(TokenTree::from(Punct::new('#', Spacing::Alone))));
        let attr = TokenTree::from(Ident::new(attr_name, span));
        ret.extend(Some(TokenTree::from(Group::new(
            Delimiter::Bracket,
            attr.into(),
        ))));
    };
    add_attr(&mut ret, "test");
    if ignore {
        add_attr(&mut ret, "ignore");
    }

    for token in item {
        let group = match token {
            TokenTree::Group(g) => {
                if g.delimiter() == Delimiter::Brace {
                    g
                } else {
                    ret.extend(Some(TokenTree::Group(g)));
                    continue;
                }
            }
            other => {
                ret.extend(Some(other));
                continue;
            }
        };

        let mut new_body = to_token_stream(
            r#"let _test_guard = {
                let tmp_dir = option_env!("CARGO_TARGET_TMPDIR");
                cargo_test_support::paths::init_root(tmp_dir)
            };"#,
        );

        new_body.extend(group.stream());
        ret.extend(Some(TokenTree::from(Group::new(
            group.delimiter(),
            new_body,
        ))));
    }

    ret
}

fn split_rules(t: TokenStream) -> Vec<String> {
    let tts: Vec<_> = t.into_iter().collect();
    tts.split(|tt| match tt {
        TokenTree::Punct(p) => p.as_char() == ',',
        _ => false,
    })
    .filter(|parts| !parts.is_empty())
    .map(|parts| {
        parts
            .into_iter()
            .map(|part| part.to_string())
            .collect::<String>()
    })
    .collect()
}

fn to_token_stream(code: &str) -> TokenStream {
    code.parse().unwrap()
}

static mut VERSION: (u32, bool) = (0, false);

fn version() -> &'static (u32, bool) {
    static INIT: Once = Once::new();
    INIT.call_once(|| {
        let output = Command::new("rustc")
            .arg("-V")
            .output()
            .expect("rustc should run");
        let stdout = std::str::from_utf8(&output.stdout).expect("utf8");
        let vers = stdout.split_whitespace().skip(1).next().unwrap();
        let is_nightly = option_env!("CARGO_TEST_DISABLE_NIGHTLY").is_none()
            && (vers.contains("-nightly") || vers.contains("-dev"));
        let minor = vers.split('.').skip(1).next().unwrap().parse().unwrap();
        unsafe { VERSION = (minor, is_nightly) }
    });
    unsafe { &VERSION }
}

fn has_command(command: &str) -> bool {
    let output = match Command::new(command).arg("--version").output() {
        Ok(output) => output,
        Err(e) => {
            // hg is not installed on GitHub macos.
            // Consider installing it if Cargo gains more hg support, but
            // otherwise it isn't critical.
            if is_ci() && !(cfg!(target_os = "macos") && command == "hg") {
                panic!(
                    "expected command `{}` to be somewhere in PATH: {}",
                    command, e
                );
            }
            return false;
        }
    };
    if !output.status.success() {
        panic!(
            "expected command `{}` to be runnable, got error {}:\n\
            stderr:{}\n\
            stdout:{}\n",
            command,
            output.status,
            String::from_utf8_lossy(&output.stderr),
            String::from_utf8_lossy(&output.stdout)
        );
    }
    true
}

/// Whether or not this running in a Continuous Integration environment.
fn is_ci() -> bool {
    // Consider using `tracked_env` instead of option_env! when it is stabilized.
    // `tracked_env` will handle changes, but not require rebuilding the macro
    // itself like option_env does.
    option_env!("CI").is_some() || option_env!("TF_BUILD").is_some()
}
<commit_msg>Remove needless is_not_nightly closure.<commit_after>extern crate proc_macro;

use proc_macro::*;
use std::process::Command;
use std::sync::Once;

#[proc_macro_attribute]
pub fn cargo_test(attr: TokenStream, item: TokenStream) -> TokenStream {
    // Ideally these options would be embedded in the test itself. However, I
    // find it very helpful to have the test clearly state whether or not it
    // is ignored. It would be nice to have some kind of runtime ignore
    // support (such as
    // https://internals.rust-lang.org/t/pre-rfc-skippable-tests/14611).
    //
    // Unfortunately a big drawback here is that if the environment changes
    // (such as the existence of the `git` CLI), this will not trigger a
    // rebuild and the test will still be ignored. In theory, something like
    // `tracked_env` or `tracked_path`
    // (https://github.com/rust-lang/rust/issues/99515) could help with this,
    // but they don't really handle the absence of files well.
    let mut ignore = false;
    let mut requires_reason = false;
    let mut found_reason = false;
    let is_not_nightly = !version().1;
    for rule in split_rules(attr) {
        match rule.as_str() {
            "build_std_real" => {
                // Only run the "real" build-std tests on nightly and with an
                // explicit opt-in (these generally only work on linux, and
                // have some extra requirements, and are slow, and can pollute
                // the environment since it downloads dependencies).
                ignore |= is_not_nightly;
                ignore |= option_env!("CARGO_RUN_BUILD_STD_TESTS").is_none();
            }
            "build_std_mock" => {
                // Only run the "mock" build-std tests on nightly and disable
                // for windows-gnu which is missing object files (see
                // https://github.com/rust-lang/wg-cargo-std-aware/issues/46).
                ignore |= is_not_nightly;
                ignore |= cfg!(all(target_os = "windows", target_env = "gnu"));
            }
            "nightly" => {
                requires_reason = true;
                ignore |= is_not_nightly;
            }
            s if s.starts_with("requires_") => {
                let command = &s[9..];
                ignore |= !has_command(command);
            }
            s if s.starts_with(">=1.") => {
                requires_reason = true;
                let min_minor = s[4..].parse().unwrap();
                ignore |= version().0 < min_minor;
            }
            s if s.starts_with("reason=") => {
                found_reason = true;
            }
            _ => panic!("unknown rule {:?}", rule),
        }
    }
    if requires_reason && !found_reason {
        panic!(
            "#[cargo_test] with a rule also requires a reason, \
            such as #[cargo_test(nightly, reason = \"needs -Z unstable-thing\")]"
        );
    }

    let span = Span::call_site();
    let mut ret = TokenStream::new();
    let add_attr = |ret: &mut TokenStream, attr_name| {
        ret.extend(Some(TokenTree::from(Punct::new('#', Spacing::Alone))));
        let attr = TokenTree::from(Ident::new(attr_name, span));
        ret.extend(Some(TokenTree::from(Group::new(
            Delimiter::Bracket,
            attr.into(),
        ))));
    };
    add_attr(&mut ret, "test");
    if ignore {
        add_attr(&mut ret, "ignore");
    }

    for token in item {
        let group = match token {
            TokenTree::Group(g) => {
                if g.delimiter() == Delimiter::Brace {
                    g
                } else {
                    ret.extend(Some(TokenTree::Group(g)));
                    continue;
                }
            }
            other => {
                ret.extend(Some(other));
                continue;
            }
        };

        let mut new_body = to_token_stream(
            r#"let _test_guard = {
                let tmp_dir = option_env!("CARGO_TARGET_TMPDIR");
                cargo_test_support::paths::init_root(tmp_dir)
            };"#,
        );

        new_body.extend(group.stream());
        ret.extend(Some(TokenTree::from(Group::new(
            group.delimiter(),
            new_body,
        ))));
    }

    ret
}

fn split_rules(t: TokenStream) -> Vec<String> {
    let tts: Vec<_> = t.into_iter().collect();
    tts.split(|tt| match tt {
        TokenTree::Punct(p) => p.as_char() == ',',
        _ => false,
    })
    .filter(|parts| !parts.is_empty())
    .map(|parts| {
        parts
            .into_iter()
            .map(|part| part.to_string())
            .collect::<String>()
    })
    .collect()
}

fn to_token_stream(code: &str) -> TokenStream {
    code.parse().unwrap()
}

static mut VERSION: (u32, bool) = (0, false);

fn version() -> &'static (u32, bool) {
    static INIT: Once = Once::new();
    INIT.call_once(|| {
        let output = Command::new("rustc")
            .arg("-V")
            .output()
            .expect("rustc should run");
        let stdout = std::str::from_utf8(&output.stdout).expect("utf8");
        let vers = stdout.split_whitespace().skip(1).next().unwrap();
        let is_nightly = option_env!("CARGO_TEST_DISABLE_NIGHTLY").is_none()
            && (vers.contains("-nightly") || vers.contains("-dev"));
        let minor = vers.split('.').skip(1).next().unwrap().parse().unwrap();
        unsafe { VERSION = (minor, is_nightly) }
    });
    unsafe { &VERSION }
}

fn has_command(command: &str) -> bool {
    let output = match Command::new(command).arg("--version").output() {
        Ok(output) => output,
        Err(e) => {
            // hg is not installed on GitHub macos.
            // Consider installing it if Cargo gains more hg support, but
            // otherwise it isn't critical.
            if is_ci() && !(cfg!(target_os = "macos") && command == "hg") {
                panic!(
                    "expected command `{}` to be somewhere in PATH: {}",
                    command, e
                );
            }
            return false;
        }
    };
    if !output.status.success() {
        panic!(
            "expected command `{}` to be runnable, got error {}:\n\
            stderr:{}\n\
            stdout:{}\n",
            command,
            output.status,
            String::from_utf8_lossy(&output.stderr),
            String::from_utf8_lossy(&output.stdout)
        );
    }
    true
}

/// Whether or not this running in a Continuous Integration environment.
fn is_ci() -> bool {
    // Consider using `tracked_env` instead of option_env! when it is stabilized.
    // `tracked_env` will handle changes, but not require rebuilding the macro
    // itself like option_env does.
    option_env!("CI").is_some() || option_env!("TF_BUILD").is_some()
}
<|endoftext|>