<commit_before>//! Handling of DICOM values with the VR PN (person name) as per PS3.5 sect 6.2.
use std::fmt::{Display, Formatter};

/*#[derive(Debug, Snafu)]
pub enum Error {
    #[snafu(display("Write error: '{source}'"))]
    Write { source: std::fmt::Error },
}
pub type Result<T, E = Error> = std::result::Result<T, E>;
*/
/// Represents a Dicom `PersonName` (PN).
/// Stores family, given, middle name, prefix and suffix as borrowed values.
/// All name components are optional.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct PersonName<'a> {
    prefix: Option<&'a str>,
    family: Option<&'a str>,
    middle: Option<&'a str>,
    given: Option<&'a str>,
    suffix: Option<&'a str>,
}

/// A builder to construct a `PersonName` from it's components.
#[derive(Debug, Copy, Clone)]
pub struct PersonNameBuilder<'a> {
    person_name: PersonName<'a>,
}

impl Display for PersonName<'_> {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        let components: &[Option<&str>] = &[
            self.prefix,
            self.given,
            self.middle,
            self.family,
            self.suffix,
        ];

        let mut c_iter = components.iter().flatten().peekable();

        while let Some(component) = c_iter.next() {
            if c_iter.peek().is_some() {
                write!(f, "{} ", component)?
            } else {
                write!(f, "{}", component)?
            }
        }
        Ok(())
    }
}

impl<'a> PersonName<'a> {
    /// Retrieve PersonName prefix
    pub fn prefix(&self) -> Option<&str> {
        self.prefix
    }
    /// Retrieve PersonName suffix
    pub fn suffix(&self) -> Option<&str> {
        self.suffix
    }
    /// Retrieve family name from PersonName
    pub fn family(&self) -> Option<&str> {
        self.family
    }
    /// Retrieve given name from PersonName
    pub fn given(&self) -> Option<&str> {
        self.given
    }
    /// Retrieve middle name from PersonName
    pub fn middle(&self) -> Option<&str> {
        self.middle
    }
    /// Convert PersonName into a Dicom formatted string.
    /// Name components are interspersed with a '^' separator.
    /// Leading null components produce a separator, while trailing do not.
    pub fn to_dicom_string(&self) -> String {
        let mut name = String::new();

        let components: &[Option<&str>] = &[
            self.family,
            self.given,
            self.middle,
            self.prefix,
            self.suffix,
        ];

        let last_non_empty = components
            .iter()
            .enumerate()
            .rev()
            .find(|(_i, opt)| opt.is_some())
            .map(|(i, _opt)| i + 1)
            .unwrap_or(0);

        let mut it = components.iter().take(last_non_empty).peekable();

        while let Some(option) = it.next() {
            if let Some(component) = option {
                name.push_str(component);
            }
            if it.peek().is_some() {
                name.push('^');
            }
        }

        name
    }
    /// Retrieves a PersonName from a Dicom formatted string slice.
    /// The Dicom string representation is split by '^' separator into its respective components.
    pub fn from_slice(slice: &'a str) -> PersonName<'a> {
        let mut parts = slice.split('^');

        macro_rules! get_component {
            () => {
                parts
                    .next()
                    .and_then(|s| if s.is_empty() { None } else { Some(s) })
            };
        }

        let family = get_component!();
        let given = get_component!();
        let middle = get_component!();
        let prefix = get_component!();
        let suffix = get_component!();

        PersonName {
            prefix,
            given,
            family,
            middle,
            suffix,
        }
    }
    /// Retrieve a builder for a PersonName
    pub fn builder() -> PersonNameBuilder<'a> {
        PersonNameBuilder::new()
    }
}

impl<'a> PersonNameBuilder<'a> {
    pub fn new() -> PersonNameBuilder<'a> {
        PersonNameBuilder {
            person_name: PersonName {
                prefix: None,
                family: None,
                middle: None,
                given: None,
                suffix: None,
            },
        }
    }
    /// Insert family name component
    pub fn with_family(mut self, family_name: &'a str) -> PersonNameBuilder<'a> {
        self.person_name.family = Some(family_name);
        self
    }
    pub fn with_middle(mut self, middle_name: &'a str) -> PersonNameBuilder<'a> {
        self.person_name.middle = Some(middle_name);
        self
    }
    pub fn with_given(mut self, given_name: &'a str) -> PersonNameBuilder<'a> {
        self.person_name.given = Some(given_name);
        self
    }
    pub fn with_prefix(mut self, name_prefix: &'a str) -> PersonNameBuilder<'a> {
        self.person_name.prefix = Some(name_prefix);
        self
    }
    pub fn with_suffix(mut self, name_suffix: &'a str) -> PersonNameBuilder<'a> {
        self.person_name.suffix = Some(name_suffix);
        self
    }
    /// Builds a PersonName
    pub fn build(&self) -> PersonName<'a> {
        self.person_name
    }
}

impl<'a> Default for PersonNameBuilder<'a> {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_person_name_to_dicom_string() {
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: None,
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "Adams^John".to_string());

        let p = PersonName {
            prefix: Some("Rev."),
            given: None,
            middle: None,
            family: None,
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "^^^Rev.".to_string());
        let p = PersonName {
            prefix: None,
            given: None,
            middle: None,
            family: None,
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(p.to_dicom_string(), "^^^^B.A. M.Div.".to_string());
        let p = PersonName {
            prefix: Some("Rev."),
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(
            p.to_dicom_string(),
            "Adams^John^Robert^Rev.^B.A. M.Div.".to_string()
        );
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(
            p.to_dicom_string(),
            "Adams^John^Robert^^B.A. M.Div.".to_string()
        );
        let p = PersonName {
            prefix: Some("Rev."),
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "Adams^John^Robert^Rev.".to_string());
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "Adams^John^Robert".to_string());
        let p = PersonName {
            prefix: None,
            given: None,
            middle: Some("Robert"),
            family: None,
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "^^Robert".to_string());
    }
    #[test]
    fn test_person_name_to_string() {
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: None,
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_string(), "John Adams".to_string());

        let p = PersonName {
            prefix: Some("Rev."),
            given: None,
            middle: None,
            family: None,
            suffix: None,
        };
        assert_eq!(p.to_string(), "Rev.".to_string());

        let p = PersonName {
            prefix: None,
            given: None,
            middle: None,
            family: None,
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(p.to_string(), "B.A. M.Div.".to_string());
        let p = PersonName {
            prefix: Some("Rev."),
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(
            p.to_string(),
            "Rev. John Robert Adams B.A. M.Div.".to_string()
        );
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(p.to_string(), "John Robert Adams B.A. M.Div.".to_string());
        let p = PersonName {
            prefix: Some("Rev."),
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_string(), "Rev. John Robert Adams".to_string());
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_string(), "John Robert Adams".to_string());
        let p = PersonName {
            prefix: None,
            given: None,
            middle: Some("Robert"),
            family: None,
            suffix: None,
        };
        assert_eq!(p.to_string(), "Robert".to_string());
    }
    #[test]
    fn person_name_from_slice() {
        assert_eq!(
            PersonName::from_slice("^^Robert"),
            PersonName {
                prefix: None,
                given: None,
                middle: Some("Robert"),
                family: None,
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("^^^Rev."),
            PersonName {
                prefix: Some("Rev."),
                given: None,
                middle: None,
                family: None,
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("^^^^B.A. M.Div."),
            PersonName {
                prefix: None,
                given: None,
                middle: None,
                family: None,
                suffix: Some("B.A. M.Div."),
            }
        );
        assert_eq!(
            PersonName::from_slice("^^Robert"),
            PersonName {
                prefix: None,
                given: None,
                middle: Some("Robert"),
                family: None,
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("^John"),
            PersonName {
                prefix: None,
                given: Some("John"),
                middle: None,
                family: None,
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("Adams"),
            PersonName {
                prefix: None,
                given: None,
                middle: None,
                family: Some("Adams"),
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("Adams^^^^B.A. M.Div."),
            PersonName {
                prefix: None,
                given: None,
                middle: None,
                family: Some("Adams"),
                suffix: Some("B.A. M.Div."),
            }
        );
        assert_eq!(
            PersonName::from_slice("Adams^^Robert^^B.A. M.Div."),
            PersonName {
                prefix: None,
                given: None,
                middle: Some("Robert"),
                family: Some("Adams"),
                suffix: Some("B.A. M.Div."),
            }
        );
        assert_eq!(
            PersonName::from_slice("Adams^John^Robert^Rev.^B.A. M.Div."),
            PersonName {
                prefix: Some("Rev."),
                given: Some("John"),
                middle: Some("Robert"),
                family: Some("Adams"),
                suffix: Some("B.A. M.Div."),
            }
        );
    }
}
<commit_msg> - simplify to_dicom_string<commit_after>//! Handling of DICOM values with the VR PN (person name) as per PS3.5 sect 6.2.
use std::fmt::{Display, Formatter};

/*#[derive(Debug, Snafu)]
pub enum Error {
    #[snafu(display("Write error: '{source}'"))]
    Write { source: std::fmt::Error },
}
pub type Result<T, E = Error> = std::result::Result<T, E>;
*/
/// Represents a Dicom `PersonName` (PN).
/// Stores family, given, middle name, prefix and suffix as borrowed values.
/// All name components are optional.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct PersonName<'a> {
    prefix: Option<&'a str>,
    family: Option<&'a str>,
    middle: Option<&'a str>,
    given: Option<&'a str>,
    suffix: Option<&'a str>,
}

/// A builder to construct a `PersonName` from it's components.
#[derive(Debug, Copy, Clone)]
pub struct PersonNameBuilder<'a> {
    person_name: PersonName<'a>,
}

impl Display for PersonName<'_> {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        let components: &[Option<&str>] = &[
            self.prefix,
            self.given,
            self.middle,
            self.family,
            self.suffix,
        ];

        let mut c_iter = components.iter().flatten().peekable();

        while let Some(component) = c_iter.next() {
            if c_iter.peek().is_some() {
                write!(f, "{} ", component)?
            } else {
                write!(f, "{}", component)?
            }
        }
        Ok(())
    }
}

impl<'a> PersonName<'a> {
    /// Retrieve PersonName prefix
    pub fn prefix(&self) -> Option<&str> {
        self.prefix
    }
    /// Retrieve PersonName suffix
    pub fn suffix(&self) -> Option<&str> {
        self.suffix
    }
    /// Retrieve family name from PersonName
    pub fn family(&self) -> Option<&str> {
        self.family
    }
    /// Retrieve given name from PersonName
    pub fn given(&self) -> Option<&str> {
        self.given
    }
    /// Retrieve middle name from PersonName
    pub fn middle(&self) -> Option<&str> {
        self.middle
    }
    /// Convert PersonName into a Dicom formatted string.
    /// Name components are interspersed with a '^' separator.
    /// Leading null components produce a separator, while trailing do not.
    pub fn to_dicom_string(&self) -> String {
        let mut name = String::new();

        let components: &[Option<&str>] = &[
            self.family,
            self.given,
            self.middle,
            self.prefix,
            self.suffix,
        ];

        let mut it  = components.iter().rev().peekable();
        // remove trailing None (null) components
        while it.next_if(|component| component.is_none()).is_some(){}

        let mut it = it.rev().peekable();
        while let Some(option) = it.next() {
            if let Some(component) = option {
                name.push_str(component);
            }
            if it.peek().is_some() {
                name.push('^');
            }
        }

        name
    }
    /// Retrieves a PersonName from a Dicom formatted string slice.
    /// The Dicom string representation is split by '^' separator into its respective components.
    pub fn from_slice(slice: &'a str) -> PersonName<'a> {
        let mut parts = slice.split('^');

        macro_rules! get_component {
            () => {
                parts
                    .next()
                    .and_then(|s| if s.is_empty() { None } else { Some(s) })
            };
        }

        let family = get_component!();
        let given = get_component!();
        let middle = get_component!();
        let prefix = get_component!();
        let suffix = get_component!();

        PersonName {
            prefix,
            given,
            family,
            middle,
            suffix,
        }
    }
    /// Retrieve a builder for a PersonName
    pub fn builder() -> PersonNameBuilder<'a> {
        PersonNameBuilder::new()
    }
}

impl<'a> PersonNameBuilder<'a> {
    pub fn new() -> PersonNameBuilder<'a> {
        PersonNameBuilder {
            person_name: PersonName {
                prefix: None,
                family: None,
                middle: None,
                given: None,
                suffix: None,
            },
        }
    }
    /// Insert family name component
    pub fn with_family(mut self, family_name: &'a str) -> PersonNameBuilder<'a> {
        self.person_name.family = Some(family_name);
        self
    }
    pub fn with_middle(mut self, middle_name: &'a str) -> PersonNameBuilder<'a> {
        self.person_name.middle = Some(middle_name);
        self
    }
    pub fn with_given(mut self, given_name: &'a str) -> PersonNameBuilder<'a> {
        self.person_name.given = Some(given_name);
        self
    }
    pub fn with_prefix(mut self, name_prefix: &'a str) -> PersonNameBuilder<'a> {
        self.person_name.prefix = Some(name_prefix);
        self
    }
    pub fn with_suffix(mut self, name_suffix: &'a str) -> PersonNameBuilder<'a> {
        self.person_name.suffix = Some(name_suffix);
        self
    }
    /// Builds a PersonName
    pub fn build(&self) -> PersonName<'a> {
        self.person_name
    }
}

impl<'a> Default for PersonNameBuilder<'a> {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_person_name_to_dicom_string() {
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: None,
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "Adams^John".to_string());

        let p = PersonName {
            prefix: Some("Rev."),
            given: None,
            middle: None,
            family: None,
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "^^^Rev.".to_string());
        let p = PersonName {
            prefix: None,
            given: None,
            middle: None,
            family: None,
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(p.to_dicom_string(), "^^^^B.A. M.Div.".to_string());
        let p = PersonName {
            prefix: Some("Rev."),
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(
            p.to_dicom_string(),
            "Adams^John^Robert^Rev.^B.A. M.Div.".to_string()
        );
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(
            p.to_dicom_string(),
            "Adams^John^Robert^^B.A. M.Div.".to_string()
        );
        let p = PersonName {
            prefix: Some("Rev."),
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "Adams^John^Robert^Rev.".to_string());
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "Adams^John^Robert".to_string());
        let p = PersonName {
            prefix: None,
            given: None,
            middle: Some("Robert"),
            family: None,
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "^^Robert".to_string());
    }
    #[test]
    fn test_person_name_to_string() {
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: None,
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_string(), "John Adams".to_string());

        let p = PersonName {
            prefix: Some("Rev."),
            given: None,
            middle: None,
            family: None,
            suffix: None,
        };
        assert_eq!(p.to_string(), "Rev.".to_string());

        let p = PersonName {
            prefix: None,
            given: None,
            middle: None,
            family: None,
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(p.to_string(), "B.A. M.Div.".to_string());
        let p = PersonName {
            prefix: Some("Rev."),
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(
            p.to_string(),
            "Rev. John Robert Adams B.A. M.Div.".to_string()
        );
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(p.to_string(), "John Robert Adams B.A. M.Div.".to_string());
        let p = PersonName {
            prefix: Some("Rev."),
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_string(), "Rev. John Robert Adams".to_string());
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_string(), "John Robert Adams".to_string());
        let p = PersonName {
            prefix: None,
            given: None,
            middle: Some("Robert"),
            family: None,
            suffix: None,
        };
        assert_eq!(p.to_string(), "Robert".to_string());
    }
    #[test]
    fn person_name_from_slice() {
        assert_eq!(
            PersonName::from_slice("^^Robert"),
            PersonName {
                prefix: None,
                given: None,
                middle: Some("Robert"),
                family: None,
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("^^^Rev."),
            PersonName {
                prefix: Some("Rev."),
                given: None,
                middle: None,
                family: None,
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("^^^^B.A. M.Div."),
            PersonName {
                prefix: None,
                given: None,
                middle: None,
                family: None,
                suffix: Some("B.A. M.Div."),
            }
        );
        assert_eq!(
            PersonName::from_slice("^^Robert"),
            PersonName {
                prefix: None,
                given: None,
                middle: Some("Robert"),
                family: None,
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("^John"),
            PersonName {
                prefix: None,
                given: Some("John"),
                middle: None,
                family: None,
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("Adams"),
            PersonName {
                prefix: None,
                given: None,
                middle: None,
                family: Some("Adams"),
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("Adams^^^^B.A. M.Div."),
            PersonName {
                prefix: None,
                given: None,
                middle: None,
                family: Some("Adams"),
                suffix: Some("B.A. M.Div."),
            }
        );
        assert_eq!(
            PersonName::from_slice("Adams^^Robert^^B.A. M.Div."),
            PersonName {
                prefix: None,
                given: None,
                middle: Some("Robert"),
                family: Some("Adams"),
                suffix: Some("B.A. M.Div."),
            }
        );
        assert_eq!(
            PersonName::from_slice("Adams^John^Robert^Rev.^B.A. M.Div."),
            PersonName {
                prefix: Some("Rev."),
                given: Some("John"),
                middle: Some("Robert"),
                family: Some("Adams"),
                suffix: Some("B.A. M.Div."),
            }
        );
    }
}
<|endoftext|>


<commit_before>//! Types which are documented locally in the Tokio crate, but does not actually
//! live here.
//!
//! **Note** this module is only visible on docs.rs, you cannot use it directly
//! in your own code.

/// The name of a type which is not defined here.
///
/// This is typically used as an alias for another type, like so:
///
/// ```rust,ignore
/// /// See [some::other::location](https://example.com).
/// type DEFINED_ELSEWHERE = crate::doc::NotDefinedHere;
/// ```
///
/// This type is uninhabitable like the [`never` type] to ensure that no one
/// will ever accidentally use it.
///
/// [`never` type]: https://doc.rust-lang.org/std/primitive.never.html
pub enum NotDefinedHere {}

pub mod os;
pub mod winapi;
<commit_msg>chore: add Debug to NotDefinedHere (#4092)<commit_after>//! Types which are documented locally in the Tokio crate, but does not actually
//! live here.
//!
//! **Note** this module is only visible on docs.rs, you cannot use it directly
//! in your own code.

/// The name of a type which is not defined here.
///
/// This is typically used as an alias for another type, like so:
///
/// ```rust,ignore
/// /// See [some::other::location](https://example.com).
/// type DEFINED_ELSEWHERE = crate::doc::NotDefinedHere;
/// ```
///
/// This type is uninhabitable like the [`never` type] to ensure that no one
/// will ever accidentally use it.
///
/// [`never` type]: https://doc.rust-lang.org/std/primitive.never.html
#[derive(Debug)]
pub enum NotDefinedHere {}

pub mod os;
pub mod winapi;
<|endoftext|>


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

use geom::length::Length;
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use geom::num::Zero;

use std::default::Default;
use std::i32;
use std::fmt;
use std::ops::{Add, Sub, Neg, Mul, Div, Rem};

use rustc_serialize::{Encoder, Encodable};

// Units for use with geom::length and geom::scale_factor.

/// A normalized "pixel" at the default resolution for the display.
///
/// Like the CSS "px" unit, the exact physical size of this unit may vary between devices, but it
/// should approximate a device-independent reference length.  This unit corresponds to Android's
/// "density-independent pixel" (dip), Mac OS X's "point", and Windows "device-independent pixel."
///
/// The relationship between DevicePixel and ScreenPx is defined by the OS.  On most low-dpi
/// screens, one ScreenPx is equal to one DevicePixel.  But on high-density screens it can be
/// some larger number.  For example, by default on Apple "retina" displays, one ScreenPx equals
/// two DevicePixels.  On Android "MDPI" displays, one ScreenPx equals 1.5 device pixels.
///
/// The ratio between ScreenPx and DevicePixel for a given display be found by calling
/// `servo::windowing::WindowMethods::hidpi_factor`.
#[derive(Debug, Copy, Clone)]
pub enum ScreenPx {}

/// One CSS "px" in the coordinate system of the "initial viewport":
/// http://www.w3.org/TR/css-device-adapt/#initial-viewport
///
/// ViewportPx is equal to ScreenPx times a "page zoom" factor controlled by the user.  This is
/// the desktop-style "full page" zoom that enlarges content but then reflows the layout viewport
/// so it still exactly fits the visible area.
///
/// At the default zoom level of 100%, one PagePx is equal to one ScreenPx.  However, if the
/// document is zoomed in or out then this scale may be larger or smaller.
#[derive(RustcEncodable, Debug, Copy, Clone)]
pub enum ViewportPx {}

/// One CSS "px" in the root coordinate system for the content document.
///
/// PagePx is equal to ViewportPx multiplied by a "viewport zoom" factor controlled by the user.
/// This is the mobile-style "pinch zoom" that enlarges content without reflowing it.  When the
/// viewport zoom is not equal to 1.0, then the layout viewport is no longer the same physical size
/// as the viewable area.
#[derive(RustcEncodable, Debug, Copy, Clone)]
pub enum PagePx {}

// In summary, the hierarchy of pixel units and the factors to convert from one to the next:
//
// DevicePixel
//   / hidpi_ratio => ScreenPx
//     / desktop_zoom => ViewportPx
//       / pinch_zoom => PagePx

// An Au is an "App Unit" and represents 1/60th of a CSS pixel.  It was
// originally proposed in 2002 as a standard unit of measure in Gecko.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=177805 for more info.
//
// FIXME: Implement Au using Length and ScaleFactor instead of a custom type.
#[derive(Clone, Copy, Hash, PartialEq, PartialOrd, Eq, Ord)]
pub struct Au(pub i32);

impl Default for Au {
    #[inline]
    fn default() -> Au {
        Au(0)
    }
}

impl Zero for Au {
    #[inline]
    fn zero() -> Au {
        Au(0)
    }
}

pub static ZERO_POINT: Point2D<Au> = Point2D {
    x: Au(0),
    y: Au(0),
};

pub static ZERO_RECT: Rect<Au> = Rect {
    origin: Point2D {
        x: Au(0),
        y: Au(0),
    },
    size: Size2D {
        width: Au(0),
        height: Au(0),
    }
};

pub static MAX_RECT: Rect<Au> = Rect {
    origin: Point2D {
        x: Au(i32::MIN / 2),
        y: Au(i32::MIN / 2),
    },
    size: Size2D {
        width: MAX_AU,
        height: MAX_AU,
    }
};

pub const MIN_AU: Au = Au(i32::MIN);
pub const MAX_AU: Au = Au(i32::MAX);

impl Encodable for Au {
    fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
        e.emit_f64(self.to_f64_px())
    }
}

impl fmt::Debug for Au {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}px", self.to_f64_px())
    }}

impl Add for Au {
    type Output = Au;

    #[inline]
    fn add(self, other: Au) -> Au {
        Au(self.0.wrapping_add(other.0))
    }
}

impl Sub for Au {
    type Output = Au;

    #[inline]
    fn sub(self, other: Au) -> Au {
        Au(self.0.wrapping_sub(other.0))
    }

}

impl Mul<i32> for Au {
    type Output = Au;

    #[inline]
    fn mul(self, other: i32) -> Au {
        Au(self.0.wrapping_mul(other))
    }
}

impl Div<i32> for Au {
    type Output = Au;

    #[inline]
    fn div(self, other: i32) -> Au {
        Au(self.0 / other)
    }
}

impl Rem<i32> for Au {
    type Output = Au;

    #[inline]
    fn rem(self, other: i32) -> Au {
        Au(self.0 % other)
    }
}

impl Neg for Au {
    type Output = Au;

    #[inline]
    fn neg(self) -> Au {
        Au(-self.0)
    }
}

impl Au {
    /// FIXME(pcwalton): Workaround for lack of cross crate inlining of newtype structs!
    #[inline]
    pub fn new(value: i32) -> Au {
        Au(value)
    }

    #[inline]
    pub fn scale_by(self, factor: f32) -> Au {
        Au(((self.0 as f32) * factor) as i32)
    }

    #[inline]
    pub fn from_px(px: i32) -> Au {
        Au((px * 60) as i32)
    }

    #[inline]
    pub fn from_page_px(px: Length<PagePx, f32>) -> Au {
        Au((px.get() * 60f32) as i32)
    }

    /// Rounds this app unit down to the pixel towards zero and returns it.
    #[inline]
    pub fn to_px(&self) -> i32 {
        self.0 / 60
    }

    /// Rounds this app unit down to the previous (left or top) pixel and returns it.
    #[inline]
    pub fn to_prev_px(&self) -> i32 {
        ((self.0 as f64) / 60f64).floor() as i32
    }

    /// Rounds this app unit up to the next (right or bottom) pixel and returns it.
    #[inline]
    pub fn to_next_px(&self) -> i32 {
        ((self.0 as f64) / 60f64).ceil() as i32
    }

    #[inline]
    pub fn to_nearest_px(&self) -> i32 {
        ((self.0 as f64) / 60f64).round() as i32
    }

    #[inline]
    pub fn to_f32_px(&self) -> f32 {
        (self.0 as f32) / 60f32
    }

    #[inline]
    pub fn to_f64_px(&self) -> f64 {
        (self.0 as f64) / 60f64
    }

    #[inline]
    pub fn to_snapped(&self) -> Au {
        let res = self.0 % 60i32;
        return if res >= 30i32 { return Au(self.0 - res + 60i32) }
                       else { return Au(self.0 - res) };
    }

    #[inline]
    pub fn from_f32_px(px: f32) -> Au {
        Au((px * 60f32) as i32)
    }

    #[inline]
    pub fn from_pt(pt: f64) -> Au {
        Au::from_f64_px(pt_to_px(pt))
    }

    #[inline]
    pub fn from_f64_px(px: f64) -> Au {
        Au((px * 60.) as i32)
    }
}

// assumes 72 points per inch, and 96 px per inch
pub fn pt_to_px(pt: f64) -> f64 {
    pt / 72. * 96.
}

// assumes 72 points per inch, and 96 px per inch
pub fn px_to_pt(px: f64) -> f64 {
    px / 96. * 72.
}

/// Returns true if the rect contains the given point. Points on the top or left sides of the rect
/// are considered inside the rectangle, while points on the right or bottom sides of the rect are
/// not considered inside the rectangle.
pub fn rect_contains_point<T:PartialOrd + Add<T, Output=T>>(rect: Rect<T>, point: Point2D<T>) -> bool {
    point.x >= rect.origin.x && point.x < rect.origin.x + rect.size.width &&
        point.y >= rect.origin.y && point.y < rect.origin.y + rect.size.height
}

/// A helper function to convert a rect of `f32` pixels to a rect of app units.
pub fn f32_rect_to_au_rect(rect: Rect<f32>) -> Rect<Au> {
    Rect(Point2D(Au::from_f32_px(rect.origin.x), Au::from_f32_px(rect.origin.y)),
         Size2D(Au::from_f32_px(rect.size.width), Au::from_f32_px(rect.size.height)))
}

<commit_msg>Make most Au methods take self by value. (It’s a i32 wrapper.)<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use geom::length::Length;
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use geom::num::Zero;

use std::default::Default;
use std::i32;
use std::fmt;
use std::ops::{Add, Sub, Neg, Mul, Div, Rem};

use rustc_serialize::{Encoder, Encodable};

// Units for use with geom::length and geom::scale_factor.

/// A normalized "pixel" at the default resolution for the display.
///
/// Like the CSS "px" unit, the exact physical size of this unit may vary between devices, but it
/// should approximate a device-independent reference length.  This unit corresponds to Android's
/// "density-independent pixel" (dip), Mac OS X's "point", and Windows "device-independent pixel."
///
/// The relationship between DevicePixel and ScreenPx is defined by the OS.  On most low-dpi
/// screens, one ScreenPx is equal to one DevicePixel.  But on high-density screens it can be
/// some larger number.  For example, by default on Apple "retina" displays, one ScreenPx equals
/// two DevicePixels.  On Android "MDPI" displays, one ScreenPx equals 1.5 device pixels.
///
/// The ratio between ScreenPx and DevicePixel for a given display be found by calling
/// `servo::windowing::WindowMethods::hidpi_factor`.
#[derive(Debug, Copy, Clone)]
pub enum ScreenPx {}

/// One CSS "px" in the coordinate system of the "initial viewport":
/// http://www.w3.org/TR/css-device-adapt/#initial-viewport
///
/// ViewportPx is equal to ScreenPx times a "page zoom" factor controlled by the user.  This is
/// the desktop-style "full page" zoom that enlarges content but then reflows the layout viewport
/// so it still exactly fits the visible area.
///
/// At the default zoom level of 100%, one PagePx is equal to one ScreenPx.  However, if the
/// document is zoomed in or out then this scale may be larger or smaller.
#[derive(RustcEncodable, Debug, Copy, Clone)]
pub enum ViewportPx {}

/// One CSS "px" in the root coordinate system for the content document.
///
/// PagePx is equal to ViewportPx multiplied by a "viewport zoom" factor controlled by the user.
/// This is the mobile-style "pinch zoom" that enlarges content without reflowing it.  When the
/// viewport zoom is not equal to 1.0, then the layout viewport is no longer the same physical size
/// as the viewable area.
#[derive(RustcEncodable, Debug, Copy, Clone)]
pub enum PagePx {}

// In summary, the hierarchy of pixel units and the factors to convert from one to the next:
//
// DevicePixel
//   / hidpi_ratio => ScreenPx
//     / desktop_zoom => ViewportPx
//       / pinch_zoom => PagePx

// An Au is an "App Unit" and represents 1/60th of a CSS pixel.  It was
// originally proposed in 2002 as a standard unit of measure in Gecko.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=177805 for more info.
//
// FIXME: Implement Au using Length and ScaleFactor instead of a custom type.
#[derive(Clone, Copy, Hash, PartialEq, PartialOrd, Eq, Ord)]
pub struct Au(pub i32);

impl Default for Au {
    #[inline]
    fn default() -> Au {
        Au(0)
    }
}

impl Zero for Au {
    #[inline]
    fn zero() -> Au {
        Au(0)
    }
}

pub static ZERO_POINT: Point2D<Au> = Point2D {
    x: Au(0),
    y: Au(0),
};

pub static ZERO_RECT: Rect<Au> = Rect {
    origin: Point2D {
        x: Au(0),
        y: Au(0),
    },
    size: Size2D {
        width: Au(0),
        height: Au(0),
    }
};

pub static MAX_RECT: Rect<Au> = Rect {
    origin: Point2D {
        x: Au(i32::MIN / 2),
        y: Au(i32::MIN / 2),
    },
    size: Size2D {
        width: MAX_AU,
        height: MAX_AU,
    }
};

pub const MIN_AU: Au = Au(i32::MIN);
pub const MAX_AU: Au = Au(i32::MAX);

impl Encodable for Au {
    fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
        e.emit_f64(self.to_f64_px())
    }
}

impl fmt::Debug for Au {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}px", self.to_f64_px())
    }}

impl Add for Au {
    type Output = Au;

    #[inline]
    fn add(self, other: Au) -> Au {
        Au(self.0.wrapping_add(other.0))
    }
}

impl Sub for Au {
    type Output = Au;

    #[inline]
    fn sub(self, other: Au) -> Au {
        Au(self.0.wrapping_sub(other.0))
    }

}

impl Mul<i32> for Au {
    type Output = Au;

    #[inline]
    fn mul(self, other: i32) -> Au {
        Au(self.0.wrapping_mul(other))
    }
}

impl Div<i32> for Au {
    type Output = Au;

    #[inline]
    fn div(self, other: i32) -> Au {
        Au(self.0 / other)
    }
}

impl Rem<i32> for Au {
    type Output = Au;

    #[inline]
    fn rem(self, other: i32) -> Au {
        Au(self.0 % other)
    }
}

impl Neg for Au {
    type Output = Au;

    #[inline]
    fn neg(self) -> Au {
        Au(-self.0)
    }
}

impl Au {
    /// FIXME(pcwalton): Workaround for lack of cross crate inlining of newtype structs!
    #[inline]
    pub fn new(value: i32) -> Au {
        Au(value)
    }

    #[inline]
    pub fn scale_by(self, factor: f32) -> Au {
        Au(((self.0 as f32) * factor) as i32)
    }

    #[inline]
    pub fn from_px(px: i32) -> Au {
        Au((px * 60) as i32)
    }

    #[inline]
    pub fn from_page_px(px: Length<PagePx, f32>) -> Au {
        Au((px.get() * 60f32) as i32)
    }

    /// Rounds this app unit down to the pixel towards zero and returns it.
    #[inline]
    pub fn to_px(self) -> i32 {
        self.0 / 60
    }

    /// Rounds this app unit down to the previous (left or top) pixel and returns it.
    #[inline]
    pub fn to_prev_px(self) -> i32 {
        ((self.0 as f64) / 60f64).floor() as i32
    }

    /// Rounds this app unit up to the next (right or bottom) pixel and returns it.
    #[inline]
    pub fn to_next_px(self) -> i32 {
        ((self.0 as f64) / 60f64).ceil() as i32
    }

    #[inline]
    pub fn to_nearest_px(self) -> i32 {
        ((self.0 as f64) / 60f64).round() as i32
    }

    #[inline]
    pub fn to_f32_px(self) -> f32 {
        (self.0 as f32) / 60f32
    }

    #[inline]
    pub fn to_f64_px(self) -> f64 {
        (self.0 as f64) / 60f64
    }

    #[inline]
    pub fn to_snapped(self) -> Au {
        let res = self.0 % 60i32;
        return if res >= 30i32 { return Au(self.0 - res + 60i32) }
                       else { return Au(self.0 - res) };
    }

    #[inline]
    pub fn from_f32_px(px: f32) -> Au {
        Au((px * 60f32) as i32)
    }

    #[inline]
    pub fn from_pt(pt: f64) -> Au {
        Au::from_f64_px(pt_to_px(pt))
    }

    #[inline]
    pub fn from_f64_px(px: f64) -> Au {
        Au((px * 60.) as i32)
    }
}

// assumes 72 points per inch, and 96 px per inch
pub fn pt_to_px(pt: f64) -> f64 {
    pt / 72. * 96.
}

// assumes 72 points per inch, and 96 px per inch
pub fn px_to_pt(px: f64) -> f64 {
    px / 96. * 72.
}

/// Returns true if the rect contains the given point. Points on the top or left sides of the rect
/// are considered inside the rectangle, while points on the right or bottom sides of the rect are
/// not considered inside the rectangle.
pub fn rect_contains_point<T:PartialOrd + Add<T, Output=T>>(rect: Rect<T>, point: Point2D<T>) -> bool {
    point.x >= rect.origin.x && point.x < rect.origin.x + rect.size.width &&
        point.y >= rect.origin.y && point.y < rect.origin.y + rect.size.height
}

/// A helper function to convert a rect of `f32` pixels to a rect of app units.
pub fn f32_rect_to_au_rect(rect: Rect<f32>) -> Rect<Au> {
    Rect(Point2D(Au::from_f32_px(rect.origin.x), Au::from_f32_px(rect.origin.y)),
         Size2D(Au::from_f32_px(rect.size.width), Au::from_f32_px(rect.size.height)))
}

<|endoftext|>


<commit_before>//! Streaming SIMD Extensions 3 (SSE3)

use simd_llvm::{simd_shuffle2, simd_shuffle4};
use v128::*;
use x86::*;

#[cfg(test)]
use stdsimd_test::assert_instr;

/// Alternatively add and subtract packed single-precision (32-bit)
/// floating-point elements in `a` to/from packed elements in `b`.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(addsubps))]
pub unsafe fn _mm_addsub_ps(a: f32x4, b: f32x4) -> f32x4 {
    addsubps(a, b)
}

/// Alternatively add and subtract packed double-precision (64-bit)
/// floating-point elements in `a` to/from packed elements in `b`.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(addsubpd))]
pub unsafe fn _mm_addsub_pd(a: f64x2, b: f64x2) -> f64x2 {
    addsubpd(a, b)
}

/// Horizontally add adjacent pairs of double-precision (64-bit)
/// floating-point elements in `a` and `b`, and pack the results.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(haddpd))]
pub unsafe fn _mm_hadd_pd(a: f64x2, b: f64x2) -> f64x2 {
    haddpd(a, b)
}

/// Horizontally add adjacent pairs of single-precision (32-bit)
/// floating-point elements in `a` and `b`, and pack the results.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(haddps))]
pub unsafe fn _mm_hadd_ps(a: f32x4, b: f32x4) -> f32x4 {
    haddps(a, b)
}

/// Horizontally subtract adjacent pairs of double-precision (64-bit)
/// floating-point elements in `a` and `b`, and pack the results.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(hsubpd))]
pub unsafe fn _mm_hsub_pd(a: f64x2, b: f64x2) -> f64x2 {
    hsubpd(a, b)
}

/// Horizontally add adjacent pairs of single-precision (32-bit)
/// floating-point elements in `a` and `b`, and pack the results.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(hsubps))]
pub unsafe fn _mm_hsub_ps(a: f32x4, b: f32x4) -> f32x4 {
    hsubps(a, b)
}

/// Load 128-bits of integer data from unaligned memory.
/// This intrinsic may perform better than `_mm_loadu_si128`
/// when the data crosses a cache line boundary.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(lddqu))]
pub unsafe fn _mm_lddqu_si128(mem_addr: *const __m128i) -> __m128i {
    __m128i::from(lddqu(mem_addr as *const _))
}

/// Duplicate the low double-precision (64-bit) floating-point element
/// from `a`.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(movddup))]
pub unsafe fn _mm_movedup_pd(a: f64x2) -> f64x2 {
    simd_shuffle2(a, a, [0, 0])
}

/// Load a double-precision (64-bit) floating-point element from memory
/// into both elements of return vector.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(movddup))]
pub unsafe fn _mm_loaddup_pd(mem_addr: *const f64) -> __m128d {
    _mm_load1_pd(mem_addr)
}

/// Duplicate odd-indexed single-precision (32-bit) floating-point elements
/// from `a`.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(movshdup))]
pub unsafe fn _mm_movehdup_ps(a: f32x4) -> f32x4 {
    simd_shuffle4(a, a, [1, 1, 3, 3])
}

/// Duplicate even-indexed single-precision (32-bit) floating-point elements
/// from `a`.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(movsldup))]
pub unsafe fn _mm_moveldup_ps(a: f32x4) -> f32x4 {
    simd_shuffle4(a, a, [0, 0, 2, 2])
}

#[allow(improper_ctypes)]
extern "C" {
    #[link_name = "llvm.x86.sse3.addsub.ps"]
    fn addsubps(a: f32x4, b: f32x4) -> f32x4;
    #[link_name = "llvm.x86.sse3.addsub.pd"]
    fn addsubpd(a: f64x2, b: f64x2) -> f64x2;
    #[link_name = "llvm.x86.sse3.hadd.pd"]
    fn haddpd(a: f64x2, b: f64x2) -> f64x2;
    #[link_name = "llvm.x86.sse3.hadd.ps"]
    fn haddps(a: f32x4, b: f32x4) -> f32x4;
    #[link_name = "llvm.x86.sse3.hsub.pd"]
    fn hsubpd(a: f64x2, b: f64x2) -> f64x2;
    #[link_name = "llvm.x86.sse3.hsub.ps"]
    fn hsubps(a: f32x4, b: f32x4) -> f32x4;
    #[link_name = "llvm.x86.sse3.ldu.dq"]
    fn lddqu(mem_addr: *const i8) -> i8x16;
}

#[cfg(test)]
mod tests {
    use stdsimd_test::simd_test;

    use v128::*;
    use x86::i586::sse3;
    use x86::*;

    #[simd_test = "sse3"]
    unsafe fn test_mm_addsub_ps() {
        let a = f32x4::new(-1.0, 5.0, 0.0, -10.0);
        let b = f32x4::new(-100.0, 20.0, 0.0, -5.0);
        let r = sse3::_mm_addsub_ps(a, b);
        assert_eq!(r, f32x4::new(99.0, 25.0, 0.0, -15.0));
    }

    #[simd_test = "sse3"]
    unsafe fn test_mm_addsub_pd() {
        let a = f64x2::new(-1.0, 5.0);
        let b = f64x2::new(-100.0, 20.0);
        let r = sse3::_mm_addsub_pd(a, b);
        assert_eq!(r, f64x2::new(99.0, 25.0));
    }

    #[simd_test = "sse3"]
    unsafe fn test_mm_hadd_pd() {
        let a = f64x2::new(-1.0, 5.0);
        let b = f64x2::new(-100.0, 20.0);
        let r = sse3::_mm_hadd_pd(a, b);
        assert_eq!(r, f64x2::new(4.0, -80.0));
    }

    #[simd_test = "sse3"]
    unsafe fn test_mm_hadd_ps() {
        let a = f32x4::new(-1.0, 5.0, 0.0, -10.0);
        let b = f32x4::new(-100.0, 20.0, 0.0, -5.0);
        let r = sse3::_mm_hadd_ps(a, b);
        assert_eq!(r, f32x4::new(4.0, -10.0, -80.0, -5.0));
    }

    #[simd_test = "sse3"]
    unsafe fn test_mm_hsub_pd() {
        let a = f64x2::new(-1.0, 5.0);
        let b = f64x2::new(-100.0, 20.0);
        let r = sse3::_mm_hsub_pd(a, b);
        assert_eq!(r, f64x2::new(-6.0, -120.0));
    }

    #[simd_test = "sse3"]
    unsafe fn test_mm_hsub_ps() {
        let a = f32x4::new(-1.0, 5.0, 0.0, -10.0);
        let b = f32x4::new(-100.0, 20.0, 0.0, -5.0);
        let r = sse3::_mm_hsub_ps(a, b);
        assert_eq!(r, f32x4::new(-6.0, 10.0, -120.0, 5.0));
    }

    #[simd_test = "sse3"]
    unsafe fn test_mm_lddqu_si128() {
        #[cfg_attr(rustfmt, rustfmt_skip)]
        let a = __m128i::from(i8x16::new(
            1, 2, 3, 4,
            5, 6, 7, 8,
            9, 10, 11, 12,
            13, 14, 15, 16,
        ));
        let r = sse3::_mm_lddqu_si128(&a);
        assert_eq!(a, r);
    }

    #[simd_test = "sse3"]
    unsafe fn test_mm_movedup_pd() {
        let a = f64x2::new(-1.0, 5.0);
        let r = sse3::_mm_movedup_pd(a);
        assert_eq!(r, f64x2::new(-1.0, -1.0));
    }

    #[simd_test = "sse3"]
    unsafe fn test_mm_movehdup_ps() {
        let a = f32x4::new(-1.0, 5.0, 0.0, -10.0);
        let r = sse3::_mm_movehdup_ps(a);
        assert_eq!(r, f32x4::new(5.0, 5.0, -10.0, -10.0));
    }

    #[simd_test = "sse3"]
    unsafe fn test_mm_moveldup_ps() {
        let a = f32x4::new(-1.0, 5.0, 0.0, -10.0);
        let r = sse3::_mm_moveldup_ps(a);
        assert_eq!(r, f32x4::new(-1.0, -1.0, 0.0, 0.0));
    }

    #[simd_test = "sse3"]
    unsafe fn test_mm_loaddup_pd() {
        let d = -5.0;
        let r = _mm_loaddup_pd(&d);
        assert_eq_m128d(r, _mm_setr_pd(d, d));
    }
}
<commit_msg>Migrate i586::sse3 to vendor types (#274)<commit_after>//! Streaming SIMD Extensions 3 (SSE3)

use simd_llvm::{simd_shuffle2, simd_shuffle4};
use v128::*;
use x86::*;

#[cfg(test)]
use stdsimd_test::assert_instr;

/// Alternatively add and subtract packed single-precision (32-bit)
/// floating-point elements in `a` to/from packed elements in `b`.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(addsubps))]
pub unsafe fn _mm_addsub_ps(a: __m128, b: __m128) -> __m128 {
    addsubps(a, b)
}

/// Alternatively add and subtract packed double-precision (64-bit)
/// floating-point elements in `a` to/from packed elements in `b`.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(addsubpd))]
pub unsafe fn _mm_addsub_pd(a: __m128d, b: __m128d) -> __m128d {
    addsubpd(a, b)
}

/// Horizontally add adjacent pairs of double-precision (64-bit)
/// floating-point elements in `a` and `b`, and pack the results.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(haddpd))]
pub unsafe fn _mm_hadd_pd(a: __m128d, b: __m128d) -> __m128d {
    haddpd(a, b)
}

/// Horizontally add adjacent pairs of single-precision (32-bit)
/// floating-point elements in `a` and `b`, and pack the results.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(haddps))]
pub unsafe fn _mm_hadd_ps(a: __m128, b: __m128) -> __m128 {
    haddps(a, b)
}

/// Horizontally subtract adjacent pairs of double-precision (64-bit)
/// floating-point elements in `a` and `b`, and pack the results.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(hsubpd))]
pub unsafe fn _mm_hsub_pd(a: __m128d, b: __m128d) -> __m128d {
    hsubpd(a, b)
}

/// Horizontally add adjacent pairs of single-precision (32-bit)
/// floating-point elements in `a` and `b`, and pack the results.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(hsubps))]
pub unsafe fn _mm_hsub_ps(a: __m128, b: __m128) -> __m128 {
    hsubps(a, b)
}

/// Load 128-bits of integer data from unaligned memory.
/// This intrinsic may perform better than `_mm_loadu_si128`
/// when the data crosses a cache line boundary.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(lddqu))]
pub unsafe fn _mm_lddqu_si128(mem_addr: *const __m128i) -> __m128i {
    __m128i::from(lddqu(mem_addr as *const _))
}

/// Duplicate the low double-precision (64-bit) floating-point element
/// from `a`.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(movddup))]
pub unsafe fn _mm_movedup_pd(a: __m128d) -> __m128d {
    simd_shuffle2(a, a, [0, 0])
}

/// Load a double-precision (64-bit) floating-point element from memory
/// into both elements of return vector.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(movddup))]
pub unsafe fn _mm_loaddup_pd(mem_addr: *const f64) -> __m128d {
    _mm_load1_pd(mem_addr)
}

/// Duplicate odd-indexed single-precision (32-bit) floating-point elements
/// from `a`.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(movshdup))]
pub unsafe fn _mm_movehdup_ps(a: __m128) -> __m128 {
    simd_shuffle4(a, a, [1, 1, 3, 3])
}

/// Duplicate even-indexed single-precision (32-bit) floating-point elements
/// from `a`.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(movsldup))]
pub unsafe fn _mm_moveldup_ps(a: __m128) -> __m128 {
    simd_shuffle4(a, a, [0, 0, 2, 2])
}

#[allow(improper_ctypes)]
extern "C" {
    #[link_name = "llvm.x86.sse3.addsub.ps"]
    fn addsubps(a: __m128, b: __m128) -> __m128;
    #[link_name = "llvm.x86.sse3.addsub.pd"]
    fn addsubpd(a: __m128d, b: __m128d) -> __m128d;
    #[link_name = "llvm.x86.sse3.hadd.pd"]
    fn haddpd(a: __m128d, b: __m128d) -> __m128d;
    #[link_name = "llvm.x86.sse3.hadd.ps"]
    fn haddps(a: __m128, b: __m128) -> __m128;
    #[link_name = "llvm.x86.sse3.hsub.pd"]
    fn hsubpd(a: __m128d, b: __m128d) -> __m128d;
    #[link_name = "llvm.x86.sse3.hsub.ps"]
    fn hsubps(a: __m128, b: __m128) -> __m128;
    #[link_name = "llvm.x86.sse3.ldu.dq"]
    fn lddqu(mem_addr: *const i8) -> i8x16;
}

#[cfg(test)]
mod tests {
    use stdsimd_test::simd_test;

    use x86::*;

    #[simd_test = "sse3"]
    unsafe fn test_mm_addsub_ps() {
        let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0);
        let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0);
        let r = _mm_addsub_ps(a, b);
        assert_eq_m128(r, _mm_setr_ps(99.0, 25.0, 0.0, -15.0));
    }

    #[simd_test = "sse3"]
    unsafe fn test_mm_addsub_pd() {
        let a = _mm_setr_pd(-1.0, 5.0);
        let b = _mm_setr_pd(-100.0, 20.0);
        let r = _mm_addsub_pd(a, b);
        assert_eq_m128d(r, _mm_setr_pd(99.0, 25.0));
    }

    #[simd_test = "sse3"]
    unsafe fn test_mm_hadd_pd() {
        let a = _mm_setr_pd(-1.0, 5.0);
        let b = _mm_setr_pd(-100.0, 20.0);
        let r = _mm_hadd_pd(a, b);
        assert_eq_m128d(r, _mm_setr_pd(4.0, -80.0));
    }

    #[simd_test = "sse3"]
    unsafe fn test_mm_hadd_ps() {
        let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0);
        let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0);
        let r = _mm_hadd_ps(a, b);
        assert_eq_m128(r, _mm_setr_ps(4.0, -10.0, -80.0, -5.0));
    }

    #[simd_test = "sse3"]
    unsafe fn test_mm_hsub_pd() {
        let a = _mm_setr_pd(-1.0, 5.0);
        let b = _mm_setr_pd(-100.0, 20.0);
        let r = _mm_hsub_pd(a, b);
        assert_eq_m128d(r, _mm_setr_pd(-6.0, -120.0));
    }

    #[simd_test = "sse3"]
    unsafe fn test_mm_hsub_ps() {
        let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0);
        let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0);
        let r = _mm_hsub_ps(a, b);
        assert_eq_m128(r, _mm_setr_ps(-6.0, 10.0, -120.0, 5.0));
    }

    #[simd_test = "sse3"]
    unsafe fn test_mm_lddqu_si128() {
        #[cfg_attr(rustfmt, rustfmt_skip)]
        let a = _mm_setr_epi8(
            1, 2, 3, 4,
            5, 6, 7, 8,
            9, 10, 11, 12,
            13, 14, 15, 16,
        );
        let r = _mm_lddqu_si128(&a);
        assert_eq!(a, r);
    }

    #[simd_test = "sse3"]
    unsafe fn test_mm_movedup_pd() {
        let a = _mm_setr_pd(-1.0, 5.0);
        let r = _mm_movedup_pd(a);
        assert_eq_m128d(r, _mm_setr_pd(-1.0, -1.0));
    }

    #[simd_test = "sse3"]
    unsafe fn test_mm_movehdup_ps() {
        let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0);
        let r = _mm_movehdup_ps(a);
        assert_eq_m128(r, _mm_setr_ps(5.0, 5.0, -10.0, -10.0));
    }

    #[simd_test = "sse3"]
    unsafe fn test_mm_moveldup_ps() {
        let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0);
        let r = _mm_moveldup_ps(a);
        assert_eq_m128(r, _mm_setr_ps(-1.0, -1.0, 0.0, 0.0));
    }

    #[simd_test = "sse3"]
    unsafe fn test_mm_loaddup_pd() {
        let d = -5.0;
        let r = _mm_loaddup_pd(&d);
        assert_eq_m128d(r, _mm_setr_pd(d, d));
    }
}
<|endoftext|>


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

use phf_shared::{self, FmtConst};
use serde_json::{self, Value};
use std::env;
use std::fmt;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::process::Command;
use std::time::Instant;

fn main() {
    let start = Instant::now();

    let style_out_dir = PathBuf::from(env::var_os("DEP_SERVO_STYLE_CRATE_OUT_DIR").unwrap());
    let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());

    let status = Command::new(find_python())
        .arg("dom/bindings/codegen/run.py")
        .arg(style_out_dir.join("css-properties.json"))
        .arg(&out_dir)
        .status()
        .unwrap();
    if !status.success() {
        std::process::exit(1)
    }

    println!("Binding generation completed in {:?}", start.elapsed());

    let json = out_dir.join("InterfaceObjectMapData.json");
    let json: Value = serde_json::from_reader(File::open(&json).unwrap()).unwrap();
    let mut map = phf_codegen::Map::new();
    for (key, value) in json.as_object().unwrap() {
        map.entry(Bytes(key), value.as_str().unwrap());
    }
    let phf = PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("InterfaceObjectMapPhf.rs");
    let mut phf = File::create(&phf).unwrap();
    write!(
        &mut phf,
        "pub static MAP: phf::Map<&'static [u8], fn(JSContext, HandleObject)> = {};\n",
        map.build(),
    )
    .unwrap();
}

#[derive(Eq, Hash, PartialEq)]
struct Bytes<'a>(&'a str);

impl<'a> FmtConst for Bytes<'a> {
    fn fmt_const(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        // https://github.com/rust-lang/rust/issues/55223
        // should technically be just `write!(formatter, "b\"{}\"", self.0)
        // but the referenced issue breaks promotion in the surrounding code
        write!(formatter, "{{ const FOO: &[u8] = b\"{}\"; FOO }}", self.0)
    }
}

impl<'a> phf_shared::PhfHash for Bytes<'a> {
    fn phf_hash<H: std::hash::Hasher>(&self, hasher: &mut H) {
        self.0.as_bytes().phf_hash(hasher)
    }
}

fn find_python() -> String {
    env::var("PYTHON").ok().unwrap_or_else(|| {
        let candidates = if cfg!(windows) {
            ["python2.7.exe", "python27.exe", "python.exe"]
        } else {
            ["python2.7", "python2", "python"]
        };
        for &name in &candidates {
            if Command::new(name)
                .arg("--version")
                .output()
                .ok()
                .map_or(false, |out| out.status.success())
            {
                return name.to_owned();
            }
        }
        panic!(
            "Can't find python (tried {})! Try fixing PATH or setting the PYTHON env var",
            candidates.join(", ")
        )
    })
}
<commit_msg>Auto merge of #26413 - servo:jdm-patch-41, r=asajeffrey<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use phf_shared::{self, FmtConst};
use serde_json::{self, Value};
use std::env;
use std::fmt;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::process::Command;
use std::time::Instant;

fn main() {
    let start = Instant::now();

    let style_out_dir = PathBuf::from(env::var_os("DEP_SERVO_STYLE_CRATE_OUT_DIR").unwrap());
    let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());

    let status = Command::new(find_python())
        .arg("dom/bindings/codegen/run.py")
        .arg(style_out_dir.join("css-properties.json"))
        .arg(&out_dir)
        .status()
        .unwrap();
    if !status.success() {
        std::process::exit(1)
    }

    println!("Binding generation completed in {:?}", start.elapsed());

    let json = out_dir.join("InterfaceObjectMapData.json");
    let json: Value = serde_json::from_reader(File::open(&json).unwrap()).unwrap();
    let mut map = phf_codegen::Map::new();
    for (key, value) in json.as_object().unwrap() {
        map.entry(Bytes(key), value.as_str().unwrap());
    }
    let phf = PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("InterfaceObjectMapPhf.rs");
    let mut phf = File::create(&phf).unwrap();
    write!(
        &mut phf,
        "pub static MAP: phf::Map<&'static [u8], fn(JSContext, HandleObject)> = {};\n",
        map.build(),
    )
    .unwrap();
}

#[derive(Eq, Hash, PartialEq)]
struct Bytes<'a>(&'a str);

impl<'a> FmtConst for Bytes<'a> {
    fn fmt_const(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        // https://github.com/rust-lang/rust/issues/55223
        // should technically be just `write!(formatter, "b\"{}\"", self.0)
        // but the referenced issue breaks promotion in the surrounding code
        write!(formatter, "{{ const FOO: &[u8] = b\"{}\"; FOO }}", self.0)
    }
}

impl<'a> phf_shared::PhfHash for Bytes<'a> {
    fn phf_hash<H: std::hash::Hasher>(&self, hasher: &mut H) {
        self.0.as_bytes().phf_hash(hasher)
    }
}

fn find_python() -> String {
    env::var("PYTHON2").ok().unwrap_or_else(|| {
        let candidates = if cfg!(windows) {
            ["python2.7.exe", "python27.exe", "python.exe"]
        } else {
            ["python2.7", "python2", "python"]
        };
        for &name in &candidates {
            if Command::new(name)
                .arg("--version")
                .output()
                .ok()
                .map_or(false, |out| out.status.success())
            {
                return name.to_owned();
            }
        }
        panic!(
            "Can't find python (tried {})! Try fixing PATH or setting the PYTHON2 env var",
            candidates.join(", ")
        )
    })
}
<|endoftext|>


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

use dom::characterdata::CharacterData;
use dom::element::Element;
use dom::eventtarget::EventTarget;
use dom::htmldivelement::HTMLDivElement;
use dom::htmlelement::HTMLElement;
use dom::htmlspanelement::HTMLSpanElement;
use dom::node::Node;
use dom::text::Text;

use std::mem::size_of;

// Macro so that we can stringify type names
// I'd really prefer the tests themselves to be run at plugin time,
// however rustc::middle doesn't have access to the full type data
macro_rules! sizeof_checker (
    ($testname: ident, $t:ty, $known_size:expr) => (
        #[test]
        fn $testname() {
            let new = size_of::<$t>();
            let old = $known_size;
            if new < old {
                panic!("Your changes have decreased the stack size of commonly used DOM struct {} from {} to {}. \
                        Good work! Please update the size in script/tests.rs",
                        stringify!($t), old, new)
            } else if new > old {
                panic!("Your changes have increased the stack size of commonly used DOM struct {} from {} to {}. \
                        These structs are present in large quantities in the DOM, and increasing the size \
                        may dramatically affect our memory footprint. Please consider choosing a design which \
                        avoids this increase. If you feel that the increase is necessary, \
                        update to the new size in script/tests.rs.",
                        stringify!($t), old, new)
        }
    });
)

// Update the sizes here
sizeof_checker!(size_event_target, EventTarget, 56)
sizeof_checker!(size_node, Node, 304)
sizeof_checker!(size_element, Element, 448)
sizeof_checker!(size_htmlelement, HTMLElement, 464)
sizeof_checker!(size_div, HTMLDivElement, 464)
sizeof_checker!(size_span, HTMLSpanElement, 464)
sizeof_checker!(size_text, Text, 336)
sizeof_checker!(size_characterdata, CharacterData, 336)
<commit_msg>Update HTML{Div,Span,}Element stack size<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::characterdata::CharacterData;
use dom::element::Element;
use dom::eventtarget::EventTarget;
use dom::htmldivelement::HTMLDivElement;
use dom::htmlelement::HTMLElement;
use dom::htmlspanelement::HTMLSpanElement;
use dom::node::Node;
use dom::text::Text;

use std::mem::size_of;

// Macro so that we can stringify type names
// I'd really prefer the tests themselves to be run at plugin time,
// however rustc::middle doesn't have access to the full type data
macro_rules! sizeof_checker (
    ($testname: ident, $t:ty, $known_size:expr) => (
        #[test]
        fn $testname() {
            let new = size_of::<$t>();
            let old = $known_size;
            if new < old {
                panic!("Your changes have decreased the stack size of commonly used DOM struct {} from {} to {}. \
                        Good work! Please update the size in script/tests.rs",
                        stringify!($t), old, new)
            } else if new > old {
                panic!("Your changes have increased the stack size of commonly used DOM struct {} from {} to {}. \
                        These structs are present in large quantities in the DOM, and increasing the size \
                        may dramatically affect our memory footprint. Please consider choosing a design which \
                        avoids this increase. If you feel that the increase is necessary, \
                        update to the new size in script/tests.rs.",
                        stringify!($t), old, new)
        }
    });
)

// Update the sizes here
sizeof_checker!(size_event_target, EventTarget, 56)
sizeof_checker!(size_node, Node, 304)
sizeof_checker!(size_element, Element, 448)
sizeof_checker!(size_htmlelement, HTMLElement, 480)
sizeof_checker!(size_div, HTMLDivElement, 480)
sizeof_checker!(size_span, HTMLSpanElement, 480)
sizeof_checker!(size_text, Text, 336)
sizeof_checker!(size_characterdata, CharacterData, 336)
<|endoftext|>


<commit_before>//! FIXME: write short doc here

use rustc_hash::{FxHashMap, FxHashSet};

use hir::{InFile, Name};
use ra_db::SourceDatabase;
use ra_prof::profile;
use ra_syntax::{ast, AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxKind::*, TextRange, T};

use crate::{
    db::RootDatabase,
    references::{
        classify_name, classify_name_ref,
        NameKind::{self, *},
    },
    FileId,
};

#[derive(Debug)]
pub struct HighlightedRange {
    pub range: TextRange,
    pub tag: &'static str,
    pub binding_hash: Option<u64>,
}

fn is_control_keyword(kind: SyntaxKind) -> bool {
    match kind {
        T![for]
        | T![loop]
        | T![while]
        | T![continue]
        | T![break]
        | T![if]
        | T![else]
        | T![match]
        | T![return] => true,
        _ => false,
    }
}

pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> {
    let _p = profile("highlight");
    let parse = db.parse(file_id);
    let root = parse.tree().syntax().clone();

    fn calc_binding_hash(file_id: FileId, name: &Name, shadow_count: u32) -> u64 {
        fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 {
            use std::{collections::hash_map::DefaultHasher, hash::Hasher};

            let mut hasher = DefaultHasher::new();
            x.hash(&mut hasher);
            hasher.finish()
        }

        hash((file_id, name, shadow_count))
    }

    // Visited nodes to handle highlighting priorities
    // FIXME: retain only ranges here
    let mut highlighted: FxHashSet<SyntaxElement> = FxHashSet::default();
    let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default();

    let mut res = Vec::new();
    for node in root.descendants_with_tokens() {
        if highlighted.contains(&node) {
            continue;
        }
        let mut binding_hash = None;
        let tag = match node.kind() {
            FN_DEF => {
                bindings_shadow_count.clear();
                continue;
            }
            COMMENT => "comment",
            STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => "string",
            ATTR => "attribute",
            NAME_REF => {
                if node.ancestors().any(|it| it.kind() == ATTR) {
                    continue;
                }

                let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap();
                let name_kind =
                    classify_name_ref(db, InFile::new(file_id.into(), &name_ref)).map(|d| d.kind);

                if let Some(Local(local)) = &name_kind {
                    if let Some(name) = local.name(db) {
                        let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
                        binding_hash = Some(calc_binding_hash(file_id, &name, *shadow_count))
                    }
                };

                name_kind.map_or("text", |it| highlight_name(db, it))
            }
            NAME => {
                let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap();
                let name_kind =
                    classify_name(db, InFile::new(file_id.into(), &name)).map(|d| d.kind);

                if let Some(Local(local)) = &name_kind {
                    if let Some(name) = local.name(db) {
                        let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
                        *shadow_count += 1;
                        binding_hash = Some(calc_binding_hash(file_id, &name, *shadow_count))
                    }
                };

                match name_kind {
                    Some(name_kind) => highlight_name(db, name_kind),
                    None => name.syntax().parent().map_or("function", |x| match x.kind() {
                        STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => "type",
                        TYPE_PARAM => "type.param",
                        RECORD_FIELD_DEF => "field",
                        _ => "function",
                    }),
                }
            }
            INT_NUMBER | FLOAT_NUMBER => "literal.numeric",
            BYTE => "literal.byte",
            CHAR => "literal.char",
            LIFETIME => "type.lifetime",
            T![unsafe] => "keyword.unsafe",
            k if is_control_keyword(k) => "keyword.control",
            k if k.is_keyword() => "keyword",
            _ => {
                if let Some(macro_call) = node.as_node().cloned().and_then(ast::MacroCall::cast) {
                    if let Some(path) = macro_call.path() {
                        if let Some(segment) = path.segment() {
                            if let Some(name_ref) = segment.name_ref() {
                                highlighted.insert(name_ref.syntax().clone().into());
                                let range_start = name_ref.syntax().text_range().start();
                                let mut range_end = name_ref.syntax().text_range().end();
                                for sibling in path.syntax().siblings_with_tokens(Direction::Next) {
                                    match sibling.kind() {
                                        T![!] | IDENT => range_end = sibling.text_range().end(),
                                        _ => (),
                                    }
                                }
                                res.push(HighlightedRange {
                                    range: TextRange::from_to(range_start, range_end),
                                    tag: "macro",
                                    binding_hash: None,
                                })
                            }
                        }
                    }
                }
                continue;
            }
        };
        res.push(HighlightedRange { range: node.text_range(), tag, binding_hash })
    }
    res
}

pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: bool) -> String {
    let parse = db.parse(file_id);

    fn rainbowify(seed: u64) -> String {
        use rand::prelude::*;
        let mut rng = SmallRng::seed_from_u64(seed);
        format!(
            "hsl({h},{s}%,{l}%)",
            h = rng.gen_range::<u16, _, _>(0, 361),
            s = rng.gen_range::<u16, _, _>(42, 99),
            l = rng.gen_range::<u16, _, _>(40, 91),
        )
    }

    let mut ranges = highlight(db, file_id);
    ranges.sort_by_key(|it| it.range.start());
    // quick non-optimal heuristic to intersect token ranges and highlighted ranges
    let mut frontier = 0;
    let mut could_intersect: Vec<&HighlightedRange> = Vec::new();

    let mut buf = String::new();
    buf.push_str(&STYLE);
    buf.push_str("
");
    let tokens = parse.tree().syntax().descendants_with_tokens().filter_map(|it| it.into_token());
    for token in tokens {
        could_intersect.retain(|it| token.text_range().start() <= it.range.end());
        while let Some(r) = ranges.get(frontier) {
            if r.range.start() <= token.text_range().end() {
                could_intersect.push(r);
                frontier += 1;
            } else {
                break;
            }
        }
        let text = html_escape(&token.text());
        let ranges = could_intersect
            .iter()
            .filter(|it| token.text_range().is_subrange(&it.range))
            .collect::<Vec<_>>();
        if ranges.is_empty() {
            buf.push_str(&text);
        } else {
            let classes = ranges.iter().map(|x| x.tag).collect::<Vec<_>>().join(" ");
            let binding_hash = ranges.first().and_then(|x| x.binding_hash);
            let color = match (rainbow, binding_hash) {
                (true, Some(hash)) => format!(
                    " data-binding-hash=\"{}\" style=\"color: {};\"",
                    hash,
                    rainbowify(hash)
                ),
                _ => "".into(),
            };
            buf.push_str(&format!("{}", classes, color, text));
        }
    }
    buf.push_str("
");
    buf
}

fn highlight_name(db: &RootDatabase, name_kind: NameKind) -> &'static str {
    match name_kind {
        Macro(_) => "macro",
        Field(_) => "field",
        AssocItem(hir::AssocItem::Function(_)) => "function",
        AssocItem(hir::AssocItem::Const(_)) => "constant",
        AssocItem(hir::AssocItem::TypeAlias(_)) => "type",
        Def(hir::ModuleDef::Module(_)) => "module",
        Def(hir::ModuleDef::Function(_)) => "function",
        Def(hir::ModuleDef::Adt(_)) => "type",
        Def(hir::ModuleDef::EnumVariant(_)) => "constant",
        Def(hir::ModuleDef::Const(_)) => "constant",
        Def(hir::ModuleDef::Static(_)) => "constant",
        Def(hir::ModuleDef::Trait(_)) => "type",
        Def(hir::ModuleDef::TypeAlias(_)) => "type",
        Def(hir::ModuleDef::BuiltinType(_)) => "type.builtin",
        SelfType(_) => "type.self",
        TypeParam(_) => "type.param",
        Local(local) => {
            if local.is_mut(db) {
                "variable.mut"
            } else if local.ty(db).is_mutable_reference() {
                "variable.mut"
            } else {
                "variable"
            }
        }
    }
}

//FIXME: like, real html escaping
fn html_escape(text: &str) -> String {
    text.replace("<", "<").replace(">", ">")
}

const STYLE: &str = "

";

#[cfg(test)]
mod tests {
    use crate::mock_analysis::single_file;
    use test_utils::{assert_eq_text, project_dir, read_text};

    #[test]
    fn test_highlighting() {
        let (analysis, file_id) = single_file(
            r#"
#[derive(Clone, Debug)]
struct Foo {
    pub x: i32,
    pub y: i32,
}

fn foo<T>() -> T {
    unimplemented!();
    foo::<i32>();
}

// comment
fn main() {
    println!("Hello, {}!", 92);

    let mut vec = Vec::new();
    if true {
        vec.push(Foo { x: 0, y: 1 });
    }
    unsafe { vec.set_len(0); }

    let mut x = 42;
    let y = &mut x;
    let z = &y;

    y;
}

enum E<X> {
    V(X)
}

impl<X> E<X> {
    fn new<T>() -> E<T> {}
}
"#
            .trim(),
        );
        let dst_file = project_dir().join("crates/ra_ide/src/snapshots/highlighting.html");
        let actual_html = &analysis.highlight_as_html(file_id, false).unwrap();
        let expected_html = &read_text(&dst_file);
        std::fs::write(dst_file, &actual_html).unwrap();
        assert_eq_text!(expected_html, actual_html);
    }

    #[test]
    fn test_rainbow_highlighting() {
        let (analysis, file_id) = single_file(
            r#"
fn main() {
    let hello = "hello";
    let x = hello.to_string();
    let y = hello.to_string();

    let x = "other color please!";
    let y = x.to_string();
}

fn bar() {
    let mut hello = "hello";
}
"#
            .trim(),
        );
        let dst_file = project_dir().join("crates/ra_ide/src/snapshots/rainbow_highlighting.html");
        let actual_html = &analysis.highlight_as_html(file_id, true).unwrap();
        let expected_html = &read_text(&dst_file);
        std::fs::write(dst_file, &actual_html).unwrap();
        assert_eq_text!(expected_html, actual_html);
    }
}
<commit_msg>introduce named constants for highlighting tag names.<commit_after>//! FIXME: write short doc here

use rustc_hash::{FxHashMap, FxHashSet};

use hir::{InFile, Name};
use ra_db::SourceDatabase;
use ra_prof::profile;
use ra_syntax::{ast, AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxKind::*, TextRange, T};

use crate::{
    db::RootDatabase,
    references::{
        classify_name, classify_name_ref,
        NameKind::{self, *},
    },
    FileId,
};

const HIGHLIGHT_TAG_FIELD: &'static str = "field";
const HIGHLIGHT_TAG_FUNCTION: &'static str = "function";
const HIGHLIGHT_TAG_MODULE: &'static str = "module";
const HIGHLIGHT_TAG_TYPE: &'static str = "type";
const HIGHLIGHT_TAG_CONSTANT: &'static str = "constant";
const HIGHLIGHT_TAG_MACRO: &'static str = "macro";
const HIGHLIGHT_TAG_VARIABLE: &'static str = "variable";
const HIGHLIGHT_TAG_VARIABLE_MUT: &'static str = "variable.mut";
const HIGHLIGHT_TAG_TEXT: &'static str = "text";

const HIGHLIGHT_TAG_TYPE_BUILTIN: &'static str = "type.builtin";
const HIGHLIGHT_TAG_TYPE_SELF: &'static str = "type.self";
const HIGHLIGHT_TAG_TYPE_PARAM: &'static str = "type.param";
const HIGHLIGHT_TAG_TYPE_LIFETIME: &'static str = "type.lifetime";

const HIGHLIGHT_TAG_LITERAL_BYTE: &'static str = "literal.byte";
const HIGHLIGHT_TAG_LITERAL_NUMERIC: &'static str = "literal.numeric";
const HIGHLIGHT_TAG_LITERAL_CHAR: &'static str = "literal.char";
const HIGHLIGHT_TAG_LITERAL_COMMENT: &'static str = "comment";
const HIGHLIGHT_TAG_LITERAL_STRING: &'static str = "string";
const HIGHLIGHT_TAG_LITERAL_ATTRIBUTE: &'static str = "attribute";

const HIGHLIGHT_TAG_KEYWORD_UNSAFE: &'static str = "keyword.unsafe";
const HIGHLIGHT_TAG_KEYWORD_CONTROL: &'static str = "keyword.control";
const HIGHLIGHT_TAG_KEYWORD: &'static str = "keyword";

#[derive(Debug)]
pub struct HighlightedRange {
    pub range: TextRange,
    pub tag: &'static str,
    pub binding_hash: Option<u64>,
}

fn is_control_keyword(kind: SyntaxKind) -> bool {
    match kind {
        T![for]
        | T![loop]
        | T![while]
        | T![continue]
        | T![break]
        | T![if]
        | T![else]
        | T![match]
        | T![return] => true,
        _ => false,
    }
}

pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> {
    let _p = profile("highlight");
    let parse = db.parse(file_id);
    let root = parse.tree().syntax().clone();

    fn calc_binding_hash(file_id: FileId, name: &Name, shadow_count: u32) -> u64 {
        fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 {
            use std::{collections::hash_map::DefaultHasher, hash::Hasher};

            let mut hasher = DefaultHasher::new();
            x.hash(&mut hasher);
            hasher.finish()
        }

        hash((file_id, name, shadow_count))
    }

    // Visited nodes to handle highlighting priorities
    // FIXME: retain only ranges here
    let mut highlighted: FxHashSet<SyntaxElement> = FxHashSet::default();
    let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default();

    let mut res = Vec::new();
    for node in root.descendants_with_tokens() {
        if highlighted.contains(&node) {
            continue;
        }
        let mut binding_hash = None;
        let tag = match node.kind() {
            FN_DEF => {
                bindings_shadow_count.clear();
                continue;
            }
            COMMENT => HIGHLIGHT_TAG_LITERAL_COMMENT,
            STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => HIGHLIGHT_TAG_LITERAL_STRING,
            ATTR => HIGHLIGHT_TAG_LITERAL_ATTRIBUTE,
            NAME_REF => {
                if node.ancestors().any(|it| it.kind() == ATTR) {
                    continue;
                }

                let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap();
                let name_kind =
                    classify_name_ref(db, InFile::new(file_id.into(), &name_ref)).map(|d| d.kind);

                if let Some(Local(local)) = &name_kind {
                    if let Some(name) = local.name(db) {
                        let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
                        binding_hash = Some(calc_binding_hash(file_id, &name, *shadow_count))
                    }
                };

                name_kind.map_or(HIGHLIGHT_TAG_TEXT, |it| highlight_name(db, it))
            }
            NAME => {
                let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap();
                let name_kind =
                    classify_name(db, InFile::new(file_id.into(), &name)).map(|d| d.kind);

                if let Some(Local(local)) = &name_kind {
                    if let Some(name) = local.name(db) {
                        let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
                        *shadow_count += 1;
                        binding_hash = Some(calc_binding_hash(file_id, &name, *shadow_count))
                    }
                };

                match name_kind {
                    Some(name_kind) => highlight_name(db, name_kind),
                    None => {
                        name.syntax().parent().map_or(HIGHLIGHT_TAG_FUNCTION, |x| match x.kind() {
                            STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => {
                                HIGHLIGHT_TAG_TYPE
                            }
                            TYPE_PARAM => HIGHLIGHT_TAG_TYPE_PARAM,
                            RECORD_FIELD_DEF => HIGHLIGHT_TAG_FIELD,
                            _ => HIGHLIGHT_TAG_FUNCTION,
                        })
                    }
                }
            }
            INT_NUMBER | FLOAT_NUMBER => HIGHLIGHT_TAG_LITERAL_NUMERIC,
            BYTE => HIGHLIGHT_TAG_LITERAL_BYTE,
            CHAR => HIGHLIGHT_TAG_LITERAL_CHAR,
            LIFETIME => HIGHLIGHT_TAG_TYPE_LIFETIME,
            T![unsafe] => HIGHLIGHT_TAG_KEYWORD_UNSAFE,
            k if is_control_keyword(k) => HIGHLIGHT_TAG_KEYWORD_CONTROL,
            k if k.is_keyword() => HIGHLIGHT_TAG_KEYWORD,
            _ => {
                if let Some(macro_call) = node.as_node().cloned().and_then(ast::MacroCall::cast) {
                    if let Some(path) = macro_call.path() {
                        if let Some(segment) = path.segment() {
                            if let Some(name_ref) = segment.name_ref() {
                                highlighted.insert(name_ref.syntax().clone().into());
                                let range_start = name_ref.syntax().text_range().start();
                                let mut range_end = name_ref.syntax().text_range().end();
                                for sibling in path.syntax().siblings_with_tokens(Direction::Next) {
                                    match sibling.kind() {
                                        T![!] | IDENT => range_end = sibling.text_range().end(),
                                        _ => (),
                                    }
                                }
                                res.push(HighlightedRange {
                                    range: TextRange::from_to(range_start, range_end),
                                    tag: HIGHLIGHT_TAG_MACRO,
                                    binding_hash: None,
                                })
                            }
                        }
                    }
                }
                continue;
            }
        };
        res.push(HighlightedRange { range: node.text_range(), tag, binding_hash })
    }
    res
}

pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: bool) -> String {
    let parse = db.parse(file_id);

    fn rainbowify(seed: u64) -> String {
        use rand::prelude::*;
        let mut rng = SmallRng::seed_from_u64(seed);
        format!(
            "hsl({h},{s}%,{l}%)",
            h = rng.gen_range::<u16, _, _>(0, 361),
            s = rng.gen_range::<u16, _, _>(42, 99),
            l = rng.gen_range::<u16, _, _>(40, 91),
        )
    }

    let mut ranges = highlight(db, file_id);
    ranges.sort_by_key(|it| it.range.start());
    // quick non-optimal heuristic to intersect token ranges and highlighted ranges
    let mut frontier = 0;
    let mut could_intersect: Vec<&HighlightedRange> = Vec::new();

    let mut buf = String::new();
    buf.push_str(&STYLE);
    buf.push_str("
");
    let tokens = parse.tree().syntax().descendants_with_tokens().filter_map(|it| it.into_token());
    for token in tokens {
        could_intersect.retain(|it| token.text_range().start() <= it.range.end());
        while let Some(r) = ranges.get(frontier) {
            if r.range.start() <= token.text_range().end() {
                could_intersect.push(r);
                frontier += 1;
            } else {
                break;
            }
        }
        let text = html_escape(&token.text());
        let ranges = could_intersect
            .iter()
            .filter(|it| token.text_range().is_subrange(&it.range))
            .collect::<Vec<_>>();
        if ranges.is_empty() {
            buf.push_str(&text);
        } else {
            let classes = ranges.iter().map(|x| x.tag).collect::<Vec<_>>().join(" ");
            let binding_hash = ranges.first().and_then(|x| x.binding_hash);
            let color = match (rainbow, binding_hash) {
                (true, Some(hash)) => format!(
                    " data-binding-hash=\"{}\" style=\"color: {};\"",
                    hash,
                    rainbowify(hash)
                ),
                _ => "".into(),
            };
            buf.push_str(&format!("{}", classes, color, text));
        }
    }
    buf.push_str("
");
    buf
}

fn highlight_name(db: &RootDatabase, name_kind: NameKind) -> &'static str {
    match name_kind {
        Macro(_) => HIGHLIGHT_TAG_MACRO,
        Field(_) => HIGHLIGHT_TAG_FIELD,
        AssocItem(hir::AssocItem::Function(_)) => HIGHLIGHT_TAG_FUNCTION,
        AssocItem(hir::AssocItem::Const(_)) => HIGHLIGHT_TAG_CONSTANT,
        AssocItem(hir::AssocItem::TypeAlias(_)) => HIGHLIGHT_TAG_TYPE,
        Def(hir::ModuleDef::Module(_)) => HIGHLIGHT_TAG_MODULE,
        Def(hir::ModuleDef::Function(_)) => HIGHLIGHT_TAG_FUNCTION,
        Def(hir::ModuleDef::Adt(_)) => HIGHLIGHT_TAG_TYPE,
        Def(hir::ModuleDef::EnumVariant(_)) => HIGHLIGHT_TAG_CONSTANT,
        Def(hir::ModuleDef::Const(_)) => HIGHLIGHT_TAG_CONSTANT,
        Def(hir::ModuleDef::Static(_)) => HIGHLIGHT_TAG_CONSTANT,
        Def(hir::ModuleDef::Trait(_)) => HIGHLIGHT_TAG_TYPE,
        Def(hir::ModuleDef::TypeAlias(_)) => HIGHLIGHT_TAG_TYPE,
        Def(hir::ModuleDef::BuiltinType(_)) => HIGHLIGHT_TAG_TYPE_BUILTIN,
        SelfType(_) => HIGHLIGHT_TAG_TYPE_SELF,
        TypeParam(_) => HIGHLIGHT_TAG_TYPE_PARAM,
        Local(local) => {
            if local.is_mut(db) {
                HIGHLIGHT_TAG_VARIABLE_MUT
            } else if local.ty(db).is_mutable_reference() {
                HIGHLIGHT_TAG_VARIABLE_MUT
            } else {
                HIGHLIGHT_TAG_VARIABLE
            }
        }
    }
}

//FIXME: like, real html escaping
fn html_escape(text: &str) -> String {
    text.replace("<", "<").replace(">", ">")
}

const STYLE: &str = "

";

#[cfg(test)]
mod tests {
    use crate::mock_analysis::single_file;
    use test_utils::{assert_eq_text, project_dir, read_text};

    #[test]
    fn test_highlighting() {
        let (analysis, file_id) = single_file(
            r#"
#[derive(Clone, Debug)]
struct Foo {
    pub x: i32,
    pub y: i32,
}

fn foo<T>() -> T {
    unimplemented!();
    foo::<i32>();
}

// comment
fn main() {
    println!("Hello, {}!", 92);

    let mut vec = Vec::new();
    if true {
        vec.push(Foo { x: 0, y: 1 });
    }
    unsafe { vec.set_len(0); }

    let mut x = 42;
    let y = &mut x;
    let z = &y;

    y;
}

enum E<X> {
    V(X)
}

impl<X> E<X> {
    fn new<T>() -> E<T> {}
}
"#
            .trim(),
        );
        let dst_file = project_dir().join("crates/ra_ide/src/snapshots/highlighting.html");
        let actual_html = &analysis.highlight_as_html(file_id, false).unwrap();
        let expected_html = &read_text(&dst_file);
        std::fs::write(dst_file, &actual_html).unwrap();
        assert_eq_text!(expected_html, actual_html);
    }

    #[test]
    fn test_rainbow_highlighting() {
        let (analysis, file_id) = single_file(
            r#"
fn main() {
    let hello = "hello";
    let x = hello.to_string();
    let y = hello.to_string();

    let x = "other color please!";
    let y = x.to_string();
}

fn bar() {
    let mut hello = "hello";
}
"#
            .trim(),
        );
        let dst_file = project_dir().join("crates/ra_ide/src/snapshots/rainbow_highlighting.html");
        let actual_html = &analysis.highlight_as_html(file_id, true).unwrap();
        let expected_html = &read_text(&dst_file);
        std::fs::write(dst_file, &actual_html).unwrap();
        assert_eq_text!(expected_html, actual_html);
    }
}
<|endoftext|>


<commit_before>use std::os;
use std::io::{BufferedStream, File, IoResult};

struct CrontabIterator<'i> {
    lines: &'i mut Iterator<IoResult<String>>,
}

impl<'i> CrontabIterator<'i> {
    fn new(iter: &'i mut Iterator<IoResult<String>>) -> CrontabIterator<'i> {
        CrontabIterator {
            lines: iter
        }
    }
}

impl<'i> Iterator<String> for CrontabIterator<'i> {
    fn next(&mut self) -> Option<String> {
        match self.lines.next() {
            None => None,
            Some(Err(_)) => None,
            Some(Ok(line)) => Some(line),
        }
    }
}

fn main() {
    let args: Vec<String> = os::args();

    let file = File::open(&Path::new("/var/spool/cron/kstep")).unwrap();
    let mut buffer = BufferedStream::new(file);
    let mut lines = buffer.lines();
    let mut crontab = CrontabIterator::new(&mut lines);

    println!("target dir: {}", args.get(1));

    for line in crontab {
        println!("line: {}", line);
    }
}
<commit_msg>WIP: rust step 2<commit_after>#![feature(phase)]

#[phase(plugin)]
extern crate regex_macros;
extern crate regex;

use std::os;
use std::io::{BufferedStream, File, IoResult};
use regex::Regex;

static SPACES: Regex = regex!("[ \t]+");

#[deriving(Show)]
enum Month {
    January = 1,
    February = 2,
    March = 3,
    April = 4,
    May = 5,
    June = 6,
    July = 7,
    August = 8,
    September = 9,
    October = 10,
    November = 11,
    December = 12,
}

#[deriving(Show)]
enum DayOfWeek {
    Sunday = 0,
    Monday = 1,
    Tuesday = 2,
    Wednesday = 3,
    Thursday = 4,
    Friday = 5,
    Saturday = 6,
}

#[deriving(Show)]
struct Minute(uint);

#[deriving(Show)]
struct Hour(uint);

#[deriving(Show)]
struct Day(uint);

#[deriving(Show)]
enum CrontabEntry {
    Periodic(Vec<Minute>, Vec<Hour>, Vec<Day>, Vec<Month>, Vec<DayOfWeek>, String),
    Monotonic(String, String),
}

impl CrontabEntry {
    fn new(parts: Vec<String>) -> CrontabEntry {
        Periodic(
            vec![Minute(0)],
            vec![Hour(0)],
            vec![Day(0)],
            vec![January],
            vec![Sunday],
            "command".into_string(),
        )
    }
}

struct CrontabIterator<'i> {
    lines: &'i mut Iterator<IoResult<String>>,
}

impl<'i> CrontabIterator<'i> {
    fn new(iter: &'i mut Iterator<IoResult<String>>) -> CrontabIterator<'i> {
        CrontabIterator {
            lines: iter
        }
    }
}

impl<'i> Iterator<CrontabEntry> for CrontabIterator<'i> {
    fn next(&mut self) -> Option<CrontabEntry> {
        loop {
            match self.lines.next() {
                None => return None,
                Some(Err(_)) => return None,

                Some(Ok(line)) => {
                    let line = line.as_slice().trim();

                    if line.starts_with("#") {
                        continue;
                    }

                    let parts = SPACES.splitn(line, 6).map(|p| p.into_string()).collect();

                    return Some(CrontabEntry::new(parts));
                }
            }
        }
    }
}

fn main() {
    let args: Vec<String> = os::args();

    let file = File::open(&Path::new("/var/spool/cron/kstep")).unwrap();
    let mut buffer = BufferedStream::new(file);
    let mut lines = buffer.lines();
    let mut crontab = CrontabIterator::new(&mut lines);

    println!("target dir: {}", args.get(1));

    for line in crontab {
        println!("line: {}", line);
    }
}
<|endoftext|>


<commit_before>use super::number::NumberOps;
use super::point::Point;
use super::ring::Ring;

#[inline]
pub fn h_multi_intersect(p1: Point, p2: Point, step: i64, inters: &mut Ring<i64>)  {
   let start = 1 + p1.y / step;
   let end = 1 + (p2.y - 1) / step;

   for i in start..end {
      let x = h_intersect(p1, p2, i * step);
      inters.push(x);
   }
}

#[inline]
pub fn h_multi_intersect_fast(p1: Point, p2: Point, step: i64, inters: &mut Ring<i64>)  {
   let start = 1 + p1.y / step;
   let end = 1 + (p2.y - 1) / step;

   let dy = p2.y - p1.y;
   let dx = p2.x - p1.x;

   let step_x = dx * step / dy;

   let mut x = p1.x + (dx * (start * step - p1.y)).rounding_div(dy);
   inters.push(x);

   for i in start+1..end {
      x += step_x;
      inters.push(x);
   }
}

#[inline]
fn h_intersect(p1: Point, p2: Point, y: i64) -> i64 {
   p1.x + ((p2.x - p1.x) * (y - p1.y)).rounding_div(p2.y - p1.y)
}

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

   use super::super::point::Point;
   use super::super::ring::Ring;

   use super::*;

   #[bench]
   fn bench_lineinter_1(b: &mut Bencher) {
      let mut inters = Ring::new(10_000);
      let p1 = Point::new(2135, 2476);
      let p2 = Point::new(16753, 72398);

      b.iter(|| {
         for _ in 0..1000 {
            inters.rewind(100);
            h_multi_intersect(p1, p2, 1000, &mut inters);
            inters.consume();
         }
      });
   }

   #[bench]
   fn bench_lineinter_2(b: &mut Bencher) {
      let mut inters = Ring::new(10_000);
      let p1 = Point::new(2135, 2476);
      let p2 = Point::new(16753, 72398);

      b.iter(|| {
         for _ in 0..1000 {
            inters.rewind(100);
            h_multi_intersect_fast(p1, p2, 1000, &mut inters);
            inters.consume();
         }
      });
   }
}
<commit_msg>Slight improvement for the benchmark of the intersection example<commit_after>use super::number::NumberOps;
use super::point::Point;
use super::ring::Ring;

#[inline]
pub fn h_multi_intersect(p1: Point, p2: Point, step: i64, inters: &mut Ring<i64>) {
   let start = 1 + p1.y / step;
   let end = 1 + (p2.y - 1) / step;

   for i in start..end {
      let x = h_intersect(p1, p2, i * step);
      inters.push(x);
   }
}

#[inline]
pub fn h_multi_intersect_fast(p1: Point, p2: Point, step: i64, inters: &mut Ring<i64>) {
   let start = 1 + p1.y / step;
   let end = 1 + (p2.y - 1) / step;

   let dy = p2.y - p1.y;
   let dx = p2.x - p1.x;

   let step_x = dx * step / dy;

   let mut x = p1.x + (dx * (start * step - p1.y)).rounding_div(dy);
   inters.push(x);

   for i in start+1..end {
      x += step_x;
      inters.push(x);
   }
}

#[inline]
fn h_intersect(p1: Point, p2: Point, y: i64) -> i64 {
   p1.x + ((p2.x - p1.x) * (y - p1.y)).rounding_div(p2.y - p1.y)
}

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

   use super::super::point::Point;
   use super::super::ring::Ring;

   use super::*;

   #[bench]
   fn bench_lineinter_1(b: &mut Bencher) {
      let mut inters = Ring::new(100_000);
      let p1 = Point::new(2135, 2476);
      let p2 = Point::new(16753, 1_534_398);

      b.iter(|| {
         for _ in 0..1000 {
            inters.clear();
            h_multi_intersect(p1, p2, 1000, &mut inters);
         }
      });
   }

   #[bench]
   fn bench_lineinter_2(b: &mut Bencher) {
      let mut inters = Ring::new(100_000);
      let p1 = Point::new(2135, 2476);
      let p2 = Point::new(16753, 1_534_398);

      b.iter(|| {
         for _ in 0..1000 {
            inters.clear();
            h_multi_intersect_fast(p1, p2, 1000, &mut inters);
         }
      });
   }
}
<|endoftext|>