<commit_before>#![feature(test)]
extern crate test;

use std::ops::{Mul, Add};

extern crate nalgebra;
use self::nalgebra::{DMat, Transpose};

extern crate rblas;
use rblas::{Gemm};
use rblas::attribute::Transpose as BlasTranspose;

extern crate ndarray;
use ndarray::ArrayBase;
use ndarray::blas::AsBlas;

const NSAMPLES: usize = 6 * 1000;
const NOBSERVED: usize = 10 * 10;
const NHIDDEN: usize = 20;

#[bench]
fn bench_ortho_nmf_weights_dividend_nalgebra(bencher: &mut test::Bencher) {
    let samples = DMat::<f64>::new_ones(NSAMPLES, NOBSERVED);
    let hidden = DMat::<f64>::new_ones(NHIDDEN, NOBSERVED);
    bencher.iter(|| {
        samples.clone().mul(hidden.transpose())
    });
}

#[bench]
fn bench_ortho_nmf_weights_dividend_rblas(bencher: &mut test::Bencher) {
    let mut samples = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NOBSERVED), 1.);
    let mut hidden = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NHIDDEN, NOBSERVED), 1.);
    bencher.iter(|| {
        let mut result = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NHIDDEN), 1.);
        Gemm::gemm(
            &1.,
            BlasTranspose::NoTrans, &samples.blas(),
            BlasTranspose::Trans, &hidden.blas(),
            &0.,
            &mut result.blas());
        result
    });
}

#[bench]
fn bench_ortho_nmf_weights_divisor_nalgebra(bencher: &mut test::Bencher) {
    let weights = DMat::<f64>::new_ones(NSAMPLES, NHIDDEN);
    let hidden = DMat::<f64>::new_ones(NHIDDEN, NOBSERVED);
    bencher.iter(|| {
        weights.clone().mul(&hidden).mul(hidden.transpose())
    });
}

#[bench]
fn bench_ortho_nmf_weights_divisor_rblas(bencher: &mut test::Bencher) {
    let mut weights = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NHIDDEN), 1.);
    let mut hidden = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NHIDDEN, NOBSERVED), 1.);
    let mut reconstruction = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NOBSERVED), 1.);
    bencher.iter(|| {
        let mut result = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NHIDDEN), 1.);
        Gemm::gemm(
            &1.,
            BlasTranspose::NoTrans, &weights.blas(),
            BlasTranspose::NoTrans, &hidden.blas(),
            &0.,
            &mut reconstruction.blas());
        Gemm::gemm(
            &1.,
            BlasTranspose::NoTrans, &reconstruction.blas(),
            BlasTranspose::Trans, &hidden.blas(),
            &0.,
            &mut result.blas());
        result
    });
}

#[bench]
fn bench_ortho_nmf_hidden_dividend_nalgebra(bencher: &mut test::Bencher) {
    let weights = DMat::<f64>::new_ones(NSAMPLES, NHIDDEN);
    let samples = DMat::<f64>::new_ones(NSAMPLES, NOBSERVED);
    bencher.iter(|| {
        weights.transpose().mul(&samples);
    });
}

#[bench]
fn bench_ortho_nmf_hidden_dividend_rblas(bencher: &mut test::Bencher) {
    let mut weights = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NHIDDEN), 1.);
    let mut samples = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NOBSERVED), 1.);
    bencher.iter(|| {
        let mut result = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NHIDDEN, NOBSERVED), 1.);
        Gemm::gemm(
            &1.,
            BlasTranspose::Trans, &weights.blas(),
            BlasTranspose::NoTrans, &samples.blas(),
            &0.,
            &mut result.blas());
        result
    });
}

// TODO why is this so much faster than the other ones
// when it does so much more ?
// is the clone so expensive ?
#[bench]
fn bench_ortho_nmf_hidden_divisor_nalgebra(bencher: &mut test::Bencher) {
    let weights = DMat::<f64>::new_ones(NSAMPLES, NHIDDEN);
    let hidden = DMat::<f64>::new_ones(NHIDDEN, NOBSERVED);
    bencher.iter(|| {
        // TODO this is surprisingly weirdly fast
        let gamma = DMat::<f64>::new_ones(NHIDDEN, NHIDDEN);
        weights.transpose().mul(&weights).mul(&hidden)
            .add(gamma.mul(&hidden))
    });
}

#[bench]
fn bench_ortho_nmf_hidden_divisor_rblas(bencher: &mut test::Bencher) {
    let mut weights = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NHIDDEN), 1.);
    let mut weights_copy = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NHIDDEN), 1.);
    let mut hidden = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NHIDDEN, NOBSERVED), 1.);
    let mut gamma = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NHIDDEN, NHIDDEN), 1.);
    // this is really small
    let mut tmp = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NHIDDEN, NHIDDEN), 1.);
    bencher.iter(|| {
        let mut result = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NHIDDEN, NOBSERVED), 1.);
        // we must make a copy here because we need two mutable
        // references to weights at the same time for .blas()
        // weights_copy.clone_from(&weights);
        let mut weights_copy = weights.clone();
        Gemm::gemm(
            &1.,
            BlasTranspose::Trans, &weights.blas(),
            BlasTranspose::NoTrans, &weights_copy.blas(),
            &0.,
            &mut tmp.blas());
        Gemm::gemm(
            &1.,
            BlasTranspose::NoTrans, &gamma.blas(),
            BlasTranspose::NoTrans, &hidden.blas(),
            &0.,
            &mut result.blas());
        // add to previous result
        Gemm::gemm(
            &1.,
            BlasTranspose::NoTrans, &tmp.blas(),
            BlasTranspose::NoTrans, &hidden.blas(),
            &1.,
            &mut result.blas());
        result
    });
}
<commit_msg>add todo<commit_after>#![feature(test)]
extern crate test;

use std::ops::{Mul, Add};

extern crate nalgebra;
use self::nalgebra::{DMat, Transpose};

extern crate rblas;
use rblas::{Gemm};
use rblas::attribute::Transpose as BlasTranspose;

extern crate ndarray;
use ndarray::ArrayBase;
use ndarray::blas::AsBlas;

const NSAMPLES: usize = 6 * 1000;
const NOBSERVED: usize = 10 * 10;
const NHIDDEN: usize = 20;

// TODO use the functions in OrthogonalNMFBlas here directly

#[bench]
fn bench_ortho_nmf_weights_dividend_nalgebra(bencher: &mut test::Bencher) {
    let samples = DMat::<f64>::new_ones(NSAMPLES, NOBSERVED);
    let hidden = DMat::<f64>::new_ones(NHIDDEN, NOBSERVED);
    bencher.iter(|| {
        samples.clone().mul(hidden.transpose())
    });
}

#[bench]
fn bench_ortho_nmf_weights_dividend_rblas(bencher: &mut test::Bencher) {
    let mut samples = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NOBSERVED), 1.);
    let mut hidden = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NHIDDEN, NOBSERVED), 1.);
    bencher.iter(|| {
        let mut result = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NHIDDEN), 1.);
        Gemm::gemm(
            &1.,
            BlasTranspose::NoTrans, &samples.blas(),
            BlasTranspose::Trans, &hidden.blas(),
            &0.,
            &mut result.blas());
        result
    });
}

#[bench]
fn bench_ortho_nmf_weights_divisor_nalgebra(bencher: &mut test::Bencher) {
    let weights = DMat::<f64>::new_ones(NSAMPLES, NHIDDEN);
    let hidden = DMat::<f64>::new_ones(NHIDDEN, NOBSERVED);
    bencher.iter(|| {
        weights.clone().mul(&hidden).mul(hidden.transpose())
    });
}

#[bench]
fn bench_ortho_nmf_weights_divisor_rblas(bencher: &mut test::Bencher) {
    let mut weights = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NHIDDEN), 1.);
    let mut hidden = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NHIDDEN, NOBSERVED), 1.);
    let mut reconstruction = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NOBSERVED), 1.);
    bencher.iter(|| {
        let mut result = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NHIDDEN), 1.);
        Gemm::gemm(
            &1.,
            BlasTranspose::NoTrans, &weights.blas(),
            BlasTranspose::NoTrans, &hidden.blas(),
            &0.,
            &mut reconstruction.blas());
        Gemm::gemm(
            &1.,
            BlasTranspose::NoTrans, &reconstruction.blas(),
            BlasTranspose::Trans, &hidden.blas(),
            &0.,
            &mut result.blas());
        result
    });
}

#[bench]
fn bench_ortho_nmf_hidden_dividend_nalgebra(bencher: &mut test::Bencher) {
    let weights = DMat::<f64>::new_ones(NSAMPLES, NHIDDEN);
    let samples = DMat::<f64>::new_ones(NSAMPLES, NOBSERVED);
    bencher.iter(|| {
        weights.transpose().mul(&samples);
    });
}

#[bench]
fn bench_ortho_nmf_hidden_dividend_rblas(bencher: &mut test::Bencher) {
    let mut weights = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NHIDDEN), 1.);
    let mut samples = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NOBSERVED), 1.);
    bencher.iter(|| {
        let mut result = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NHIDDEN, NOBSERVED), 1.);
        Gemm::gemm(
            &1.,
            BlasTranspose::Trans, &weights.blas(),
            BlasTranspose::NoTrans, &samples.blas(),
            &0.,
            &mut result.blas());
        result
    });
}

// TODO why is this so much faster than the other ones
// when it does so much more ?
// is the clone so expensive ?
#[bench]
fn bench_ortho_nmf_hidden_divisor_nalgebra(bencher: &mut test::Bencher) {
    let weights = DMat::<f64>::new_ones(NSAMPLES, NHIDDEN);
    let hidden = DMat::<f64>::new_ones(NHIDDEN, NOBSERVED);
    bencher.iter(|| {
        // TODO this is surprisingly weirdly fast
        let gamma = DMat::<f64>::new_ones(NHIDDEN, NHIDDEN);
        weights.transpose().mul(&weights).mul(&hidden)
            .add(gamma.mul(&hidden))
    });
}

#[bench]
fn bench_ortho_nmf_hidden_divisor_rblas(bencher: &mut test::Bencher) {
    let mut weights = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NHIDDEN), 1.);
    let mut weights_copy = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NHIDDEN), 1.);
    let mut hidden = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NHIDDEN, NOBSERVED), 1.);
    let mut gamma = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NHIDDEN, NHIDDEN), 1.);
    // this is really small
    let mut tmp = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NHIDDEN, NHIDDEN), 1.);
    bencher.iter(|| {
        let mut result = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NHIDDEN, NOBSERVED), 1.);
        // we must make a copy here because we need two mutable
        // references to weights at the same time for .blas()
        // weights_copy.clone_from(&weights);
        let mut weights_copy = weights.clone();
        Gemm::gemm(
            &1.,
            BlasTranspose::Trans, &weights.blas(),
            BlasTranspose::NoTrans, &weights_copy.blas(),
            &0.,
            &mut tmp.blas());
        Gemm::gemm(
            &1.,
            BlasTranspose::NoTrans, &gamma.blas(),
            BlasTranspose::NoTrans, &hidden.blas(),
            &0.,
            &mut result.blas());
        // add to previous result
        Gemm::gemm(
            &1.,
            BlasTranspose::NoTrans, &tmp.blas(),
            BlasTranspose::NoTrans, &hidden.blas(),
            &1.,
            &mut result.blas());
        result
    });
}
<|endoftext|>


<commit_before>//! Parser for an Accept-Language HTTP header.

use language_tags::{LanguageTag, ParseError};
use locale_config::{LanguageRange, Locale};

use std::error;
use std::fmt;
use std::str::FromStr;

/// Used to set the language for rendering.
///
/// SVG documents can use the `<switch>` element, whose children have a `systemLanguage`
/// attribute; only the first child which has a `systemLanguage` that matches the
/// preferred languages will be rendered.
///
/// This enum, used with `CairoRenderer::with_language`, configures how to obtain the
/// user's prefererred languages.
pub enum Language {
    /// Use the Unix environment variables `LANGUAGE`, `LC_ALL`, `LC_MESSAGES` and `LANG` to obtain the
    /// user's language.  This uses [`g_get_language_names()`][ggln] underneath.
    ///
    /// [ggln]: https://docs.gtk.org/glib/func.get_language_names.html
    FromEnvironment,
    AcceptLanguage(AcceptLanguage),
}

/// `Language` but with the environment's locale converted to something we can use.
#[derive(Clone)]
pub enum UserLanguage {
    LanguageTags(LanguageTags),
    AcceptLanguage(AcceptLanguage),
}

#[derive(Clone, Debug, PartialEq)]
struct Weight(Option<f32>);

impl Weight {
    fn numeric(&self) -> f32 {
        self.0.unwrap_or(1.0)
    }
}

#[derive(Clone, Debug, PartialEq)]
struct Item {
    tag: LanguageTag,
    weight: Weight,
}

/// Stores a parsed version of an HTTP Accept-Language header.
///
/// RFC 7231: <https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.5>
#[derive(Clone, Debug, PartialEq)]
pub struct AcceptLanguage(Box<[Item]>);

/// Errors when parsing an `AcceptLanguage`.
#[derive(Debug, PartialEq)]
pub enum AcceptLanguageError {
    NoElements,
    InvalidCharacters,
    InvalidLanguageTag(ParseError),
    InvalidWeight,
}

impl error::Error for AcceptLanguageError {}

impl fmt::Display for AcceptLanguageError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::NoElements => write!(f, "no language tags in list"),
            Self::InvalidCharacters => write!(f, "invalid characters in language list"),
            Self::InvalidLanguageTag(e) => write!(f, "invalid language tag: {}", e),
            Self::InvalidWeight => write!(f, "invalid q= weight"),
        }
    }
}

/// Optional whitespace, Space or Tab, per RFC 7230.
///
/// RFC 7230: <https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.3>
const OWS: [char; 2] = ['\x20', '\x09'];

impl AcceptLanguage {
    pub fn parse(s: &str) -> Result<AcceptLanguage, AcceptLanguageError> {
        if !s.is_ascii() {
            return Err(AcceptLanguageError::InvalidCharacters);
        }

        let mut items = Vec::new();

        for val in s.split(',') {
            let trimmed = val.trim_matches(&OWS[..]);
            if trimmed.is_empty() {
                continue;
            }

            items.push(Item::parse(trimmed)?);
        }

        if items.is_empty() {
            Err(AcceptLanguageError::NoElements)
        } else {
            Ok(AcceptLanguage(items.into_boxed_slice()))
        }
    }

    pub fn iter(&self) -> impl Iterator<Item = (&LanguageTag, f32)> {
        self.0.iter().map(|item| (&item.tag, item.weight.numeric()))
    }

    fn any_matches(&self, tag: &LanguageTag) -> bool {
        self.iter().any(|(self_tag, _weight)| tag.matches(self_tag))
    }
}

impl Item {
    fn parse(s: &str) -> Result<Item, AcceptLanguageError> {
        let semicolon_pos = s.find(';');

        let (before_semicolon, after_semicolon) = if let Some(semi) = semicolon_pos {
            (&s[..semi], Some(&s[semi + 1..]))
        } else {
            (s, None)
        };

        let tag = LanguageTag::parse(before_semicolon)
            .map_err(AcceptLanguageError::InvalidLanguageTag)?;

        let weight = if let Some(quality) = after_semicolon {
            let quality = quality.trim_start_matches(&OWS[..]);

            let number = if let Some(qvalue) = quality.strip_prefix("q=") {
                if qvalue.starts_with(&['0', '1'][..]) {
                    let first_digit = qvalue.chars().next().unwrap();

                    if let Some(decimals) = qvalue[1..].strip_prefix('.') {
                        if (first_digit == '0'
                            && decimals.len() <= 3
                            && decimals.chars().all(|c| c.is_digit(10)))
                            || (first_digit == '1'
                                && decimals.len() <= 3
                                && decimals.chars().all(|c| c == '0'))
                        {
                            qvalue
                        } else {
                            return Err(AcceptLanguageError::InvalidWeight);
                        }
                    } else {
                        qvalue
                    }
                } else {
                    return Err(AcceptLanguageError::InvalidWeight);
                }
            } else {
                return Err(AcceptLanguageError::InvalidWeight);
            };

            Weight(Some(
                f32::from_str(number).map_err(|_| AcceptLanguageError::InvalidWeight)?,
            ))
        } else {
            Weight(None)
        };

        Ok(Item { tag, weight })
    }
}

/// A list of BCP47 language tags.
///
/// RFC 5664: <https://www.rfc-editor.org/info/rfc5664>
#[derive(Debug, Clone, PartialEq)]
pub struct LanguageTags(Vec<LanguageTag>);

impl LanguageTags {
    pub fn empty() -> Self {
        LanguageTags(Vec::new())
    }

    /// Converts a `Locale` to a set of language tags.
    pub fn from_locale(locale: &Locale) -> Result<LanguageTags, String> {
        let mut tags = Vec::new();

        for locale_range in locale.tags_for("messages") {
            if locale_range == LanguageRange::invariant() {
                continue;
            }

            let str_locale_range = locale_range.as_ref();

            let locale_tag = LanguageTag::from_str(str_locale_range).map_err(|e| {
                format!(
                    "invalid language tag \"{}\" in locale: {}",
                    str_locale_range, e
                )
            })?;

            if !locale_tag.is_language_range() {
                return Err(format!(
                    "language tag \"{}\" is not a language range",
                    locale_tag
                ));
            }

            tags.push(locale_tag);
        }

        Ok(LanguageTags(tags))
    }

    pub fn from(tags: Vec<LanguageTag>) -> LanguageTags {
        LanguageTags(tags)
    }

    pub fn iter(&self) -> impl Iterator<Item = &LanguageTag> {
        self.0.iter()
    }

    pub fn any_matches(&self, language_tag: &LanguageTag) -> bool {
        self.0.iter().any(|tag| tag.matches(language_tag))
    }
}

impl UserLanguage {
    pub fn any_matches(&self, tags: &LanguageTags) -> bool {
        match *self {
            UserLanguage::LanguageTags(ref language_tags) => {
                tags.iter().any(|tag| language_tags.any_matches(tag))
            }
            UserLanguage::AcceptLanguage(ref accept_language) => {
                tags.iter().any(|tag| accept_language.any_matches(tag))
            }
        }
    }
}

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

    #[test]
    fn parses_accept_language() {
        // plain tag
        assert_eq!(
            AcceptLanguage::parse("es-MX").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(None)
                }]
                .into_boxed_slice()
            )
        );

        // with quality
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // with quality
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=0").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(0.0))
                }]
                .into_boxed_slice()
            )
        );

        // zero decimals are allowed
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=0.").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(0.0))
                }]
                .into_boxed_slice()
            )
        );

        // zero decimals are allowed
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1.").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // one decimal
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1.0").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // two decimals
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1.00").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // three decimals
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1.000").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // multiple elements
        assert_eq!(
            AcceptLanguage::parse("es-MX, en; q=0.5").unwrap(),
            AcceptLanguage(
                vec![
                    Item {
                        tag: LanguageTag::parse("es-MX").unwrap(),
                        weight: Weight(None)
                    },
                    Item {
                        tag: LanguageTag::parse("en").unwrap(),
                        weight: Weight(Some(0.5))
                    },
                ]
                .into_boxed_slice()
            )
        );

        // superfluous whitespace
        assert_eq!(
            AcceptLanguage::parse(",es-MX;q=1.000  , en; q=0.125  ,  ,").unwrap(),
            AcceptLanguage(
                vec![
                    Item {
                        tag: LanguageTag::parse("es-MX").unwrap(),
                        weight: Weight(Some(1.0))
                    },
                    Item {
                        tag: LanguageTag::parse("en").unwrap(),
                        weight: Weight(Some(0.125))
                    },
                ]
                .into_boxed_slice()
            )
        );
    }

    #[test]
    fn empty_lists() {
        assert!(matches!(
            AcceptLanguage::parse(""),
            Err(AcceptLanguageError::NoElements)
        ));

        assert!(matches!(
            AcceptLanguage::parse(","),
            Err(AcceptLanguageError::NoElements)
        ));

        assert!(matches!(
            AcceptLanguage::parse(", , ,,,"),
            Err(AcceptLanguageError::NoElements)
        ));
    }

    #[test]
    fn ascii_only() {
        assert!(matches!(
            AcceptLanguage::parse("ës"),
            Err(AcceptLanguageError::InvalidCharacters)
        ));
    }

    #[test]
    fn invalid_tag() {
        assert!(matches!(
            AcceptLanguage::parse("no_underscores"),
            Err(AcceptLanguageError::InvalidLanguageTag(_))
        ));
    }

    #[test]
    fn invalid_weight() {
        assert!(matches!(
            AcceptLanguage::parse("es;"),
            Err(AcceptLanguageError::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q"),
            Err(AcceptLanguageError::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q="),
            Err(AcceptLanguageError::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q=2"),
            Err(AcceptLanguageError::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q=1.1"),
            Err(AcceptLanguageError::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q=1.12"),
            Err(AcceptLanguageError::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q=1.123"),
            Err(AcceptLanguageError::InvalidWeight)
        ));

        // Up to three decimals allowed per RFC 7231
        assert!(matches!(
            AcceptLanguage::parse("es;q=0.1234"),
            Err(AcceptLanguageError::InvalidWeight)
        ));
    }

    #[test]
    fn iter() {
        let accept_language = AcceptLanguage::parse("es-MX, en; q=0.5").unwrap();
        let mut iter = accept_language.iter();

        let (tag, weight) = iter.next().unwrap();
        assert_eq!(*tag, LanguageTag::parse("es-MX").unwrap());
        assert_eq!(weight, 1.0);

        let (tag, weight) = iter.next().unwrap();
        assert_eq!(*tag, LanguageTag::parse("en").unwrap());
        assert_eq!(weight, 0.5);

        assert!(iter.next().is_none());
    }
}
<commit_msg>clippy: is_ascii_digit() instead of is_digit(10)<commit_after>//! Parser for an Accept-Language HTTP header.

use language_tags::{LanguageTag, ParseError};
use locale_config::{LanguageRange, Locale};

use std::error;
use std::fmt;
use std::str::FromStr;

/// Used to set the language for rendering.
///
/// SVG documents can use the `<switch>` element, whose children have a `systemLanguage`
/// attribute; only the first child which has a `systemLanguage` that matches the
/// preferred languages will be rendered.
///
/// This enum, used with `CairoRenderer::with_language`, configures how to obtain the
/// user's prefererred languages.
pub enum Language {
    /// Use the Unix environment variables `LANGUAGE`, `LC_ALL`, `LC_MESSAGES` and `LANG` to obtain the
    /// user's language.  This uses [`g_get_language_names()`][ggln] underneath.
    ///
    /// [ggln]: https://docs.gtk.org/glib/func.get_language_names.html
    FromEnvironment,
    AcceptLanguage(AcceptLanguage),
}

/// `Language` but with the environment's locale converted to something we can use.
#[derive(Clone)]
pub enum UserLanguage {
    LanguageTags(LanguageTags),
    AcceptLanguage(AcceptLanguage),
}

#[derive(Clone, Debug, PartialEq)]
struct Weight(Option<f32>);

impl Weight {
    fn numeric(&self) -> f32 {
        self.0.unwrap_or(1.0)
    }
}

#[derive(Clone, Debug, PartialEq)]
struct Item {
    tag: LanguageTag,
    weight: Weight,
}

/// Stores a parsed version of an HTTP Accept-Language header.
///
/// RFC 7231: <https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.5>
#[derive(Clone, Debug, PartialEq)]
pub struct AcceptLanguage(Box<[Item]>);

/// Errors when parsing an `AcceptLanguage`.
#[derive(Debug, PartialEq)]
pub enum AcceptLanguageError {
    NoElements,
    InvalidCharacters,
    InvalidLanguageTag(ParseError),
    InvalidWeight,
}

impl error::Error for AcceptLanguageError {}

impl fmt::Display for AcceptLanguageError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::NoElements => write!(f, "no language tags in list"),
            Self::InvalidCharacters => write!(f, "invalid characters in language list"),
            Self::InvalidLanguageTag(e) => write!(f, "invalid language tag: {}", e),
            Self::InvalidWeight => write!(f, "invalid q= weight"),
        }
    }
}

/// Optional whitespace, Space or Tab, per RFC 7230.
///
/// RFC 7230: <https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.3>
const OWS: [char; 2] = ['\x20', '\x09'];

impl AcceptLanguage {
    pub fn parse(s: &str) -> Result<AcceptLanguage, AcceptLanguageError> {
        if !s.is_ascii() {
            return Err(AcceptLanguageError::InvalidCharacters);
        }

        let mut items = Vec::new();

        for val in s.split(',') {
            let trimmed = val.trim_matches(&OWS[..]);
            if trimmed.is_empty() {
                continue;
            }

            items.push(Item::parse(trimmed)?);
        }

        if items.is_empty() {
            Err(AcceptLanguageError::NoElements)
        } else {
            Ok(AcceptLanguage(items.into_boxed_slice()))
        }
    }

    pub fn iter(&self) -> impl Iterator<Item = (&LanguageTag, f32)> {
        self.0.iter().map(|item| (&item.tag, item.weight.numeric()))
    }

    fn any_matches(&self, tag: &LanguageTag) -> bool {
        self.iter().any(|(self_tag, _weight)| tag.matches(self_tag))
    }
}

impl Item {
    fn parse(s: &str) -> Result<Item, AcceptLanguageError> {
        let semicolon_pos = s.find(';');

        let (before_semicolon, after_semicolon) = if let Some(semi) = semicolon_pos {
            (&s[..semi], Some(&s[semi + 1..]))
        } else {
            (s, None)
        };

        let tag = LanguageTag::parse(before_semicolon)
            .map_err(AcceptLanguageError::InvalidLanguageTag)?;

        let weight = if let Some(quality) = after_semicolon {
            let quality = quality.trim_start_matches(&OWS[..]);

            let number = if let Some(qvalue) = quality.strip_prefix("q=") {
                if qvalue.starts_with(&['0', '1'][..]) {
                    let first_digit = qvalue.chars().next().unwrap();

                    if let Some(decimals) = qvalue[1..].strip_prefix('.') {
                        if (first_digit == '0'
                            && decimals.len() <= 3
                            && decimals.chars().all(|c| c.is_ascii_digit()))
                            || (first_digit == '1'
                                && decimals.len() <= 3
                                && decimals.chars().all(|c| c == '0'))
                        {
                            qvalue
                        } else {
                            return Err(AcceptLanguageError::InvalidWeight);
                        }
                    } else {
                        qvalue
                    }
                } else {
                    return Err(AcceptLanguageError::InvalidWeight);
                }
            } else {
                return Err(AcceptLanguageError::InvalidWeight);
            };

            Weight(Some(
                f32::from_str(number).map_err(|_| AcceptLanguageError::InvalidWeight)?,
            ))
        } else {
            Weight(None)
        };

        Ok(Item { tag, weight })
    }
}

/// A list of BCP47 language tags.
///
/// RFC 5664: <https://www.rfc-editor.org/info/rfc5664>
#[derive(Debug, Clone, PartialEq)]
pub struct LanguageTags(Vec<LanguageTag>);

impl LanguageTags {
    pub fn empty() -> Self {
        LanguageTags(Vec::new())
    }

    /// Converts a `Locale` to a set of language tags.
    pub fn from_locale(locale: &Locale) -> Result<LanguageTags, String> {
        let mut tags = Vec::new();

        for locale_range in locale.tags_for("messages") {
            if locale_range == LanguageRange::invariant() {
                continue;
            }

            let str_locale_range = locale_range.as_ref();

            let locale_tag = LanguageTag::from_str(str_locale_range).map_err(|e| {
                format!(
                    "invalid language tag \"{}\" in locale: {}",
                    str_locale_range, e
                )
            })?;

            if !locale_tag.is_language_range() {
                return Err(format!(
                    "language tag \"{}\" is not a language range",
                    locale_tag
                ));
            }

            tags.push(locale_tag);
        }

        Ok(LanguageTags(tags))
    }

    pub fn from(tags: Vec<LanguageTag>) -> LanguageTags {
        LanguageTags(tags)
    }

    pub fn iter(&self) -> impl Iterator<Item = &LanguageTag> {
        self.0.iter()
    }

    pub fn any_matches(&self, language_tag: &LanguageTag) -> bool {
        self.0.iter().any(|tag| tag.matches(language_tag))
    }
}

impl UserLanguage {
    pub fn any_matches(&self, tags: &LanguageTags) -> bool {
        match *self {
            UserLanguage::LanguageTags(ref language_tags) => {
                tags.iter().any(|tag| language_tags.any_matches(tag))
            }
            UserLanguage::AcceptLanguage(ref accept_language) => {
                tags.iter().any(|tag| accept_language.any_matches(tag))
            }
        }
    }
}

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

    #[test]
    fn parses_accept_language() {
        // plain tag
        assert_eq!(
            AcceptLanguage::parse("es-MX").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(None)
                }]
                .into_boxed_slice()
            )
        );

        // with quality
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // with quality
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=0").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(0.0))
                }]
                .into_boxed_slice()
            )
        );

        // zero decimals are allowed
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=0.").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(0.0))
                }]
                .into_boxed_slice()
            )
        );

        // zero decimals are allowed
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1.").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // one decimal
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1.0").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // two decimals
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1.00").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // three decimals
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1.000").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // multiple elements
        assert_eq!(
            AcceptLanguage::parse("es-MX, en; q=0.5").unwrap(),
            AcceptLanguage(
                vec![
                    Item {
                        tag: LanguageTag::parse("es-MX").unwrap(),
                        weight: Weight(None)
                    },
                    Item {
                        tag: LanguageTag::parse("en").unwrap(),
                        weight: Weight(Some(0.5))
                    },
                ]
                .into_boxed_slice()
            )
        );

        // superfluous whitespace
        assert_eq!(
            AcceptLanguage::parse(",es-MX;q=1.000  , en; q=0.125  ,  ,").unwrap(),
            AcceptLanguage(
                vec![
                    Item {
                        tag: LanguageTag::parse("es-MX").unwrap(),
                        weight: Weight(Some(1.0))
                    },
                    Item {
                        tag: LanguageTag::parse("en").unwrap(),
                        weight: Weight(Some(0.125))
                    },
                ]
                .into_boxed_slice()
            )
        );
    }

    #[test]
    fn empty_lists() {
        assert!(matches!(
            AcceptLanguage::parse(""),
            Err(AcceptLanguageError::NoElements)
        ));

        assert!(matches!(
            AcceptLanguage::parse(","),
            Err(AcceptLanguageError::NoElements)
        ));

        assert!(matches!(
            AcceptLanguage::parse(", , ,,,"),
            Err(AcceptLanguageError::NoElements)
        ));
    }

    #[test]
    fn ascii_only() {
        assert!(matches!(
            AcceptLanguage::parse("ës"),
            Err(AcceptLanguageError::InvalidCharacters)
        ));
    }

    #[test]
    fn invalid_tag() {
        assert!(matches!(
            AcceptLanguage::parse("no_underscores"),
            Err(AcceptLanguageError::InvalidLanguageTag(_))
        ));
    }

    #[test]
    fn invalid_weight() {
        assert!(matches!(
            AcceptLanguage::parse("es;"),
            Err(AcceptLanguageError::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q"),
            Err(AcceptLanguageError::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q="),
            Err(AcceptLanguageError::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q=2"),
            Err(AcceptLanguageError::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q=1.1"),
            Err(AcceptLanguageError::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q=1.12"),
            Err(AcceptLanguageError::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q=1.123"),
            Err(AcceptLanguageError::InvalidWeight)
        ));

        // Up to three decimals allowed per RFC 7231
        assert!(matches!(
            AcceptLanguage::parse("es;q=0.1234"),
            Err(AcceptLanguageError::InvalidWeight)
        ));
    }

    #[test]
    fn iter() {
        let accept_language = AcceptLanguage::parse("es-MX, en; q=0.5").unwrap();
        let mut iter = accept_language.iter();

        let (tag, weight) = iter.next().unwrap();
        assert_eq!(*tag, LanguageTag::parse("es-MX").unwrap());
        assert_eq!(weight, 1.0);

        let (tag, weight) = iter.next().unwrap();
        assert_eq!(*tag, LanguageTag::parse("en").unwrap());
        assert_eq!(weight, 0.5);

        assert!(iter.next().is_none());
    }
}
<|endoftext|>


<commit_before>
// silence warnings while still a WIP
#![allow(unused_variables)]
#![allow(dead_code)]
#![allow(unused_assignments)]
#![allow(unused_imports)]

use autograd::{Variable, Function, FuncId, FuncIntf, RootKind};
use tensor::{Tensor, TensorKind, TensorKindList};
use std::collections::{HashSet, HashMap, VecDeque};
use itertools;

pub struct ExecutionEngine {}

type FnRefs = HashMap<Function, u32>;
type FnDependencies = HashMap<Function, FnRefs>;

impl ExecutionEngine {
    fn _compute_dependencies(function: &Function) -> FnDependencies {
        unimplemented!()
    }
    fn _free_backward_dependency(dependencies: &FnDependencies,
                                 prev_func: &Function,
                                 func: &Function,
                                 arg_id: i32)
                                 -> usize {
        unimplemented!();
    }
    fn _is_ready_for_backward(dependencies: &FnDependencies, function: &Function) -> bool {
        unimplemented!()
    }
    fn _add_grad(need_copy: &mut HashSet<TensorKind>,
                 prev_grad: &Vec<Option<TensorKind>>,
                 output_nr: usize,
                 d_prev_grad: &TensorKind) {
        unimplemented!()
    }
    pub fn run_backward<T: Copy>(var: &mut Variable<T>, grad: TensorKind, retain_variables: bool) {
        let grad_fn;
        match var.grad_fn() {
            Some(v) => grad_fn = v,
            None => {
                let grad_tensor = Tensor::<T>::from(grad);
                var._do_backward(&grad_tensor);
                return;
            }
        }
        let mut ready = VecDeque::new();
        ready.push_back((grad_fn.clone(), vec![grad]));
        let mut need_copy: HashSet<TensorKind> = HashSet::new();
        let mut not_ready: HashMap<FuncId, Vec<Option<TensorKind>>> = HashMap::new();

        let dependencies = Self::_compute_dependencies(&grad_fn);
        while !ready.is_empty() {
            let (mut func, grad) = ready.pop_front().unwrap();
            let grad_input = func._do_backward(&grad, retain_variables);
            for (&(ref prev_func_, ref arg_id), ref d_prev_func) in
                itertools::zip(func.previous_functions(), grad_input) {
                if !prev_func_.requires_grad() {
                    continue;
                }
                let prev_func = match prev_func_ {
                    &RootKind::RootVar(ref v) => {
                        v.clone()._do_backward(&d_prev_func);
                        return;
                    }
                    &RootKind::RootFunc(ref f) => f,
                };
                let output_nr =
                    Self::_free_backward_dependency(&dependencies, prev_func, &func, *arg_id);
                let is_ready = Self::_is_ready_for_backward(&dependencies, prev_func);
                if is_ready {
                    let prev_grad = if not_ready.contains_key(&prev_func.id) {
                        let prev_grad = not_ready[&prev_func.id].clone();
                        Self::_add_grad(&mut need_copy, &prev_grad, output_nr, &d_prev_func);
                        prev_grad
                            .iter()
                            .map(|sv| if let &Some(ref v) = sv {
                                     v.clone()
                                 } else {
                                     panic!("found None")
                                 })
                            .collect()
                    } else {
                        vec![d_prev_func.clone()]
                    };
                    ready.push_front((prev_func.clone(), prev_grad))
                } else {
                    let prev_grad = if not_ready.contains_key(&prev_func.id) {
                        not_ready[&prev_func.id].clone()
                    } else {
                        prev_func.output_ids().iter().map(|_| None).collect()
                    };
                    Self::_add_grad(&mut need_copy, &prev_grad, output_nr, &d_prev_func);
                    not_ready.insert(prev_func.id, prev_grad.clone());
                }
            }
        }
    }
}
<commit_msg>implement _is_ready_for_backward<commit_after>
// silence warnings while still a WIP
#![allow(unused_variables)]
#![allow(dead_code)]
#![allow(unused_assignments)]
#![allow(unused_imports)]

use autograd::{Variable, Function, FuncId, FuncIntf, RootKind};
use tensor::{Tensor, TensorKind, TensorKindList};
use std::collections::{HashSet, HashMap, VecDeque};
use itertools;

pub struct ExecutionEngine {}

type FnRefs = HashMap<FuncId, u32>;
type FnDependencies = HashMap<FuncId, FnRefs>;

impl ExecutionEngine {
    fn _compute_dependencies(function: &Function) -> FnDependencies {
        unimplemented!()
    }
    fn _free_backward_dependency(dependencies: &FnDependencies,
                                 prev_func: &Function,
                                 func: &Function,
                                 arg_id: i32)
                                 -> usize {
        unimplemented!();
    }
    fn _is_ready_for_backward(dependencies: &FnDependencies, function: &Function) -> bool {
        for ref deps in dependencies[&function.id].iter() {
            if deps.1 > &0 {
                return false;
            }
        }
        return true;
    }
    fn _add_grad(need_copy: &mut HashSet<TensorKind>,
                 prev_grad: &Vec<Option<TensorKind>>,
                 output_nr: usize,
                 d_prev_grad: &TensorKind) {
        unimplemented!()
    }
    pub fn run_backward<T: Copy>(var: &mut Variable<T>, grad: TensorKind, retain_variables: bool) {
        let grad_fn;
        match var.grad_fn() {
            Some(v) => grad_fn = v,
            None => {
                let grad_tensor = Tensor::<T>::from(grad);
                var._do_backward(&grad_tensor);
                return;
            }
        }
        let mut ready = VecDeque::new();
        ready.push_back((grad_fn.clone(), vec![grad]));
        let mut need_copy: HashSet<TensorKind> = HashSet::new();
        let mut not_ready: HashMap<FuncId, Vec<Option<TensorKind>>> = HashMap::new();

        let dependencies = Self::_compute_dependencies(&grad_fn);
        while !ready.is_empty() {
            let (mut func, grad) = ready.pop_front().unwrap();
            let grad_input = func._do_backward(&grad, retain_variables);
            for (&(ref prev_func_, ref arg_id), ref d_prev_func) in
                itertools::zip(func.previous_functions(), grad_input) {
                if !prev_func_.requires_grad() {
                    continue;
                }
                let prev_func = match prev_func_ {
                    &RootKind::RootVar(ref v) => {
                        v.clone()._do_backward(&d_prev_func);
                        return;
                    }
                    &RootKind::RootFunc(ref f) => f,
                };
                let output_nr =
                    Self::_free_backward_dependency(&dependencies, prev_func, &func, *arg_id);
                let is_ready = Self::_is_ready_for_backward(&dependencies, prev_func);
                if is_ready {
                    let prev_grad = if not_ready.contains_key(&prev_func.id) {
                        let prev_grad = not_ready[&prev_func.id].clone();
                        Self::_add_grad(&mut need_copy, &prev_grad, output_nr, &d_prev_func);
                        prev_grad
                            .iter()
                            .map(|sv| if let &Some(ref v) = sv {
                                     v.clone()
                                 } else {
                                     panic!("found None")
                                 })
                            .collect()
                    } else {
                        vec![d_prev_func.clone()]
                    };
                    ready.push_front((prev_func.clone(), prev_grad))
                } else {
                    let prev_grad = if not_ready.contains_key(&prev_func.id) {
                        not_ready[&prev_func.id].clone()
                    } else {
                        prev_func.output_ids().iter().map(|_| None).collect()
                    };
                    Self::_add_grad(&mut need_copy, &prev_grad, output_nr, &d_prev_func);
                    not_ready.insert(prev_func.id, prev_grad.clone());
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use if_chain::if_chain;
use rustc::hir::def::{CtorKind, Def};
use rustc::hir::intravisit::{walk_item, walk_path, walk_ty, NestedVisitorMap, Visitor};
use rustc::hir::*;
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use rustc::ty;
use rustc::{declare_tool_lint, lint_array};
use rustc_errors::Applicability;
use syntax_pos::symbol::keywords::SelfUpper;

use crate::utils::span_lint_and_sugg;

declare_clippy_lint! {
    /// **What it does:** Checks for unnecessary repetition of structure name when a
    /// replacement with `Self` is applicable.
    ///
    /// **Why is this bad?** Unnecessary repetition. Mixed use of `Self` and struct
    /// name
    /// feels inconsistent.
    ///
    /// **Known problems:**
    /// - False positive when using associated types (#2843)
    /// - False positives in some situations when using generics (#3410)
    ///
    /// **Example:**
    /// ```rust
    /// struct Foo {}
    /// impl Foo {
    ///     fn new() -> Foo {
    ///         Foo {}
    ///     }
    /// }
    /// ```
    /// could be
    /// ```rust
    /// struct Foo {}
    /// impl Foo {
    ///     fn new() -> Self {
    ///         Self {}
    ///     }
    /// }
    /// ```
    pub USE_SELF,
    pedantic,
    "Unnecessary structure name repetition whereas `Self` is applicable"
}

#[derive(Copy, Clone, Default)]
pub struct UseSelf;

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

    fn name(&self) -> &'static str {
        "UseSelf"
    }
}

const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element";

fn span_use_self_lint(cx: &LateContext<'_, '_>, path: &Path) {
    // Path segments only include actual path, no methods or fields.
    let last_path_span = path.segments.last().expect(SEGMENTS_MSG).ident.span;
    // Only take path up to the end of last_path_span.
    let span = path.span.with_hi(last_path_span.hi());

    span_lint_and_sugg(
        cx,
        USE_SELF,
        span,
        "unnecessary structure name repetition",
        "use the applicable keyword",
        "Self".to_owned(),
        Applicability::MachineApplicable,
    );
}

struct TraitImplTyVisitor<'a, 'tcx: 'a> {
    item_type: ty::Ty<'tcx>,
    cx: &'a LateContext<'a, 'tcx>,
    trait_type_walker: ty::walk::TypeWalker<'tcx>,
    impl_type_walker: ty::walk::TypeWalker<'tcx>,
}

impl<'a, 'tcx> Visitor<'tcx> for TraitImplTyVisitor<'a, 'tcx> {
    fn visit_ty(&mut self, t: &'tcx Ty) {
        let trait_ty = self.trait_type_walker.next();
        let impl_ty = self.impl_type_walker.next();

        if let TyKind::Path(QPath::Resolved(_, path)) = &t.node {
            // The implementation and trait types don't match which means that
            // the concrete type was specified by the implementation
            if impl_ty != trait_ty {
                if let Some(impl_ty) = impl_ty {
                    if self.item_type == impl_ty {
                        let is_self_ty = if let def::Def::SelfTy(..) = path.def {
                            true
                        } else {
                            false
                        };

                        if !is_self_ty {
                            span_use_self_lint(self.cx, path);
                        }
                    }
                }
            }
        }

        walk_ty(self, t)
    }

    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::None
    }
}

fn check_trait_method_impl_decl<'a, 'tcx: 'a>(
    cx: &'a LateContext<'a, 'tcx>,
    item_type: ty::Ty<'tcx>,
    impl_item: &ImplItem,
    impl_decl: &'tcx FnDecl,
    impl_trait_ref: &ty::TraitRef<'_>,
) {
    let trait_method = cx
        .tcx
        .associated_items(impl_trait_ref.def_id)
        .find(|assoc_item| {
            assoc_item.kind == ty::AssociatedKind::Method
                && cx
                    .tcx
                    .hygienic_eq(impl_item.ident, assoc_item.ident, impl_trait_ref.def_id)
        })
        .expect("impl method matches a trait method");

    let trait_method_sig = cx.tcx.fn_sig(trait_method.def_id);
    let trait_method_sig = cx.tcx.erase_late_bound_regions(&trait_method_sig);

    let impl_method_def_id = cx.tcx.hir().local_def_id_from_hir_id(impl_item.hir_id);
    let impl_method_sig = cx.tcx.fn_sig(impl_method_def_id);
    let impl_method_sig = cx.tcx.erase_late_bound_regions(&impl_method_sig);

    let output_ty = if let FunctionRetTy::Return(ty) = &impl_decl.output {
        Some(&**ty)
    } else {
        None
    };

    // `impl_decl_ty` (of type `hir::Ty`) represents the type declared in the signature.
    // `impl_ty` (of type `ty:TyS`) is the concrete type that the compiler has determined for
    // that declaration. We use `impl_decl_ty` to see if the type was declared as `Self`
    // and use `impl_ty` to check its concrete type.
    for (impl_decl_ty, (impl_ty, trait_ty)) in impl_decl.inputs.iter().chain(output_ty).zip(
        impl_method_sig
            .inputs_and_output
            .iter()
            .zip(trait_method_sig.inputs_and_output),
    ) {
        let mut visitor = TraitImplTyVisitor {
            cx,
            item_type,
            trait_type_walker: trait_ty.walk(),
            impl_type_walker: impl_ty.walk(),
        };

        visitor.visit_ty(&impl_decl_ty);
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UseSelf {
    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
        if in_external_macro(cx.sess(), item.span) {
            return;
        }
        if_chain! {
            if let ItemKind::Impl(.., ref item_type, ref refs) = item.node;
            if let TyKind::Path(QPath::Resolved(_, ref item_path)) = item_type.node;
            then {
                let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args;
                let should_check = if let Some(ref params) = *parameters {
                    !params.parenthesized && !params.args.iter().any(|arg| match arg {
                        GenericArg::Lifetime(_) => true,
                        _ => false,
                    })
                } else {
                    true
                };

                if should_check {
                    let visitor = &mut UseSelfVisitor {
                        item_path,
                        cx,
                    };
                    let impl_def_id = cx.tcx.hir().local_def_id_from_hir_id(item.hir_id);
                    let impl_trait_ref = cx.tcx.impl_trait_ref(impl_def_id);

                    if let Some(impl_trait_ref) = impl_trait_ref {
                        for impl_item_ref in refs {
                            let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
                            if let ImplItemKind::Method(MethodSig{ decl: impl_decl, .. }, impl_body_id)
                                    = &impl_item.node {
                                let item_type = cx.tcx.type_of(impl_def_id);
                                check_trait_method_impl_decl(cx, item_type, impl_item, impl_decl, &impl_trait_ref);

                                let body = cx.tcx.hir().body(*impl_body_id);
                                visitor.visit_body(body);
                            } else {
                                visitor.visit_impl_item(impl_item);
                            }
                        }
                    } else {
                        for impl_item_ref in refs {
                            let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
                            visitor.visit_impl_item(impl_item);
                        }
                    }
                }
            }
        }
    }
}

struct UseSelfVisitor<'a, 'tcx: 'a> {
    item_path: &'a Path,
    cx: &'a LateContext<'a, 'tcx>,
}

impl<'a, 'tcx> Visitor<'tcx> for UseSelfVisitor<'a, 'tcx> {
    fn visit_path(&mut self, path: &'tcx Path, _id: HirId) {
        if path.segments.last().expect(SEGMENTS_MSG).ident.name != SelfUpper.name() {
            if self.item_path.def == path.def {
                span_use_self_lint(self.cx, path);
            } else if let Def::StructCtor(ctor_did, CtorKind::Fn) = path.def {
                if self.item_path.def.opt_def_id() == self.cx.tcx.parent_def_id(ctor_did) {
                    span_use_self_lint(self.cx, path);
                }
            }
        }
        walk_path(self, path);
    }

    fn visit_item(&mut self, item: &'tcx Item) {
        match item.node {
            ItemKind::Use(..)
            | ItemKind::Static(..)
            | ItemKind::Enum(..)
            | ItemKind::Struct(..)
            | ItemKind::Union(..)
            | ItemKind::Impl(..)
            | ItemKind::Fn(..) => {
                // Don't check statements that shadow `Self` or where `Self` can't be used
            },
            _ => walk_item(self, item),
        }
    }

    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::All(&self.cx.tcx.hir())
    }
}
<commit_msg>parent_def_id -> parent<commit_after>use if_chain::if_chain;
use rustc::hir::def::{CtorKind, Def};
use rustc::hir::intravisit::{walk_item, walk_path, walk_ty, NestedVisitorMap, Visitor};
use rustc::hir::*;
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use rustc::ty;
use rustc::{declare_tool_lint, lint_array};
use rustc::ty::DefIdTree;
use rustc_errors::Applicability;
use syntax_pos::symbol::keywords::SelfUpper;

use crate::utils::span_lint_and_sugg;

declare_clippy_lint! {
    /// **What it does:** Checks for unnecessary repetition of structure name when a
    /// replacement with `Self` is applicable.
    ///
    /// **Why is this bad?** Unnecessary repetition. Mixed use of `Self` and struct
    /// name
    /// feels inconsistent.
    ///
    /// **Known problems:**
    /// - False positive when using associated types (#2843)
    /// - False positives in some situations when using generics (#3410)
    ///
    /// **Example:**
    /// ```rust
    /// struct Foo {}
    /// impl Foo {
    ///     fn new() -> Foo {
    ///         Foo {}
    ///     }
    /// }
    /// ```
    /// could be
    /// ```rust
    /// struct Foo {}
    /// impl Foo {
    ///     fn new() -> Self {
    ///         Self {}
    ///     }
    /// }
    /// ```
    pub USE_SELF,
    pedantic,
    "Unnecessary structure name repetition whereas `Self` is applicable"
}

#[derive(Copy, Clone, Default)]
pub struct UseSelf;

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

    fn name(&self) -> &'static str {
        "UseSelf"
    }
}

const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element";

fn span_use_self_lint(cx: &LateContext<'_, '_>, path: &Path) {
    // Path segments only include actual path, no methods or fields.
    let last_path_span = path.segments.last().expect(SEGMENTS_MSG).ident.span;
    // Only take path up to the end of last_path_span.
    let span = path.span.with_hi(last_path_span.hi());

    span_lint_and_sugg(
        cx,
        USE_SELF,
        span,
        "unnecessary structure name repetition",
        "use the applicable keyword",
        "Self".to_owned(),
        Applicability::MachineApplicable,
    );
}

struct TraitImplTyVisitor<'a, 'tcx: 'a> {
    item_type: ty::Ty<'tcx>,
    cx: &'a LateContext<'a, 'tcx>,
    trait_type_walker: ty::walk::TypeWalker<'tcx>,
    impl_type_walker: ty::walk::TypeWalker<'tcx>,
}

impl<'a, 'tcx> Visitor<'tcx> for TraitImplTyVisitor<'a, 'tcx> {
    fn visit_ty(&mut self, t: &'tcx Ty) {
        let trait_ty = self.trait_type_walker.next();
        let impl_ty = self.impl_type_walker.next();

        if let TyKind::Path(QPath::Resolved(_, path)) = &t.node {
            // The implementation and trait types don't match which means that
            // the concrete type was specified by the implementation
            if impl_ty != trait_ty {
                if let Some(impl_ty) = impl_ty {
                    if self.item_type == impl_ty {
                        let is_self_ty = if let def::Def::SelfTy(..) = path.def {
                            true
                        } else {
                            false
                        };

                        if !is_self_ty {
                            span_use_self_lint(self.cx, path);
                        }
                    }
                }
            }
        }

        walk_ty(self, t)
    }

    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::None
    }
}

fn check_trait_method_impl_decl<'a, 'tcx: 'a>(
    cx: &'a LateContext<'a, 'tcx>,
    item_type: ty::Ty<'tcx>,
    impl_item: &ImplItem,
    impl_decl: &'tcx FnDecl,
    impl_trait_ref: &ty::TraitRef<'_>,
) {
    let trait_method = cx
        .tcx
        .associated_items(impl_trait_ref.def_id)
        .find(|assoc_item| {
            assoc_item.kind == ty::AssociatedKind::Method
                && cx
                    .tcx
                    .hygienic_eq(impl_item.ident, assoc_item.ident, impl_trait_ref.def_id)
        })
        .expect("impl method matches a trait method");

    let trait_method_sig = cx.tcx.fn_sig(trait_method.def_id);
    let trait_method_sig = cx.tcx.erase_late_bound_regions(&trait_method_sig);

    let impl_method_def_id = cx.tcx.hir().local_def_id_from_hir_id(impl_item.hir_id);
    let impl_method_sig = cx.tcx.fn_sig(impl_method_def_id);
    let impl_method_sig = cx.tcx.erase_late_bound_regions(&impl_method_sig);

    let output_ty = if let FunctionRetTy::Return(ty) = &impl_decl.output {
        Some(&**ty)
    } else {
        None
    };

    // `impl_decl_ty` (of type `hir::Ty`) represents the type declared in the signature.
    // `impl_ty` (of type `ty:TyS`) is the concrete type that the compiler has determined for
    // that declaration. We use `impl_decl_ty` to see if the type was declared as `Self`
    // and use `impl_ty` to check its concrete type.
    for (impl_decl_ty, (impl_ty, trait_ty)) in impl_decl.inputs.iter().chain(output_ty).zip(
        impl_method_sig
            .inputs_and_output
            .iter()
            .zip(trait_method_sig.inputs_and_output),
    ) {
        let mut visitor = TraitImplTyVisitor {
            cx,
            item_type,
            trait_type_walker: trait_ty.walk(),
            impl_type_walker: impl_ty.walk(),
        };

        visitor.visit_ty(&impl_decl_ty);
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UseSelf {
    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
        if in_external_macro(cx.sess(), item.span) {
            return;
        }
        if_chain! {
            if let ItemKind::Impl(.., ref item_type, ref refs) = item.node;
            if let TyKind::Path(QPath::Resolved(_, ref item_path)) = item_type.node;
            then {
                let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args;
                let should_check = if let Some(ref params) = *parameters {
                    !params.parenthesized && !params.args.iter().any(|arg| match arg {
                        GenericArg::Lifetime(_) => true,
                        _ => false,
                    })
                } else {
                    true
                };

                if should_check {
                    let visitor = &mut UseSelfVisitor {
                        item_path,
                        cx,
                    };
                    let impl_def_id = cx.tcx.hir().local_def_id_from_hir_id(item.hir_id);
                    let impl_trait_ref = cx.tcx.impl_trait_ref(impl_def_id);

                    if let Some(impl_trait_ref) = impl_trait_ref {
                        for impl_item_ref in refs {
                            let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
                            if let ImplItemKind::Method(MethodSig{ decl: impl_decl, .. }, impl_body_id)
                                    = &impl_item.node {
                                let item_type = cx.tcx.type_of(impl_def_id);
                                check_trait_method_impl_decl(cx, item_type, impl_item, impl_decl, &impl_trait_ref);

                                let body = cx.tcx.hir().body(*impl_body_id);
                                visitor.visit_body(body);
                            } else {
                                visitor.visit_impl_item(impl_item);
                            }
                        }
                    } else {
                        for impl_item_ref in refs {
                            let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
                            visitor.visit_impl_item(impl_item);
                        }
                    }
                }
            }
        }
    }
}

struct UseSelfVisitor<'a, 'tcx: 'a> {
    item_path: &'a Path,
    cx: &'a LateContext<'a, 'tcx>,
}

impl<'a, 'tcx> Visitor<'tcx> for UseSelfVisitor<'a, 'tcx> {
    fn visit_path(&mut self, path: &'tcx Path, _id: HirId) {
        if path.segments.last().expect(SEGMENTS_MSG).ident.name != SelfUpper.name() {
            if self.item_path.def == path.def {
                span_use_self_lint(self.cx, path);
            } else if let Def::StructCtor(ctor_did, CtorKind::Fn) = path.def {
                if self.item_path.def.opt_def_id() == self.cx.tcx.parent(ctor_did) {
                    span_use_self_lint(self.cx, path);
                }
            }
        }
        walk_path(self, path);
    }

    fn visit_item(&mut self, item: &'tcx Item) {
        match item.node {
            ItemKind::Use(..)
            | ItemKind::Static(..)
            | ItemKind::Enum(..)
            | ItemKind::Struct(..)
            | ItemKind::Union(..)
            | ItemKind::Impl(..)
            | ItemKind::Fn(..) => {
                // Don't check statements that shadow `Self` or where `Self` can't be used
            },
            _ => walk_item(self, item),
        }
    }

    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::All(&self.cx.tcx.hir())
    }
}
<|endoftext|>


<commit_before>// Based on smallpt, http://www.kevinbeason.com/smallpt/ which is also licensed under
// the MIT license.
extern crate argparse;
extern crate image;
extern crate num_cpus;
extern crate rand;
extern crate threadpool;

use argparse::{ArgumentParser, Store, StoreTrue};
use rand::{XorShiftRng, SeedableRng};
use threadpool::ThreadPool;

use std::fs::File;
use std::io::{self, BufWriter};
use std::io::prelude::*;
use std::sync::Arc;
use std::sync::mpsc::channel;

extern crate path_tracer;
use path_tracer::*;

fn main() {
    let mut samps = 1;
    let mut width = 1024;
    let mut height = 768;
    let mut output_filename = "".to_string();
    let mut num_threads = num_cpus::get();
    let mut seed = 0x193a6754;
    let mut partial = false;
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Render a simple image");
        ap.refer(&mut samps).add_option(&["-s", "--samples"], Store, "Number of samples");
        ap.refer(&mut height).add_option(&["-h", "--height"], Store, "Height");
        ap.refer(&mut width).add_option(&["-w", "--width"], Store, "Width");
        ap.refer(&mut output_filename).add_option(&["-o", "--output"], Store,
                                                  "Filename to output to");
        ap.refer(&mut num_threads).add_option(&["--num-threads"], Store,
                                              "Number of threads to use");
        ap.refer(&mut seed).add_option(&["--seed"], Store, "Random seed");
        ap.refer(&mut partial).add_option(&["--partial"], StoreTrue,
                                          "Output a partial render");
        ap.parse_args_or_exit();
    }
    samps = samps / 4;
    if samps < 1 { samps = 1; }
    if output_filename == "" {
        output_filename = if partial { "image.part" } else { "image.png" }.to_string();
    }
    const BLACK : Vec3d = Vec3d { x: 0.0, y: 0.0, z: 0.0 };
    const RED : Vec3d = Vec3d { x: 0.75, y: 0.25, z: 0.25 };
    const BLUE : Vec3d = Vec3d { x: 0.25, y: 0.25, z: 0.75 };
    const GREY : Vec3d = Vec3d { x: 0.75, y: 0.75, z: 0.75 };
    const WHITE : Vec3d = Vec3d { x: 0.999, y: 0.999, z: 0.999 };
    let mut scene = Scene::new();
    scene.add(Box::new(Sphere::new(Material::Diffuse, 1e5,
                                   Vec3d::new(1e5+1.0, 40.8, 81.6),
                                   BLACK, RED)));
    scene.add(Box::new(Sphere::new(Material::Diffuse, 1e5,
                                   Vec3d::new(-1e5+99.0, 40.8, 81.6),
                                   BLACK, BLUE)));
    scene.add(Box::new(Sphere::new(Material::Diffuse, 1e5,
                                   Vec3d::new(50.0, 40.8, 1e5),
                                   BLACK, GREY)));
    scene.add(Box::new(Sphere::new(Material::Diffuse, 1e5,
                                   Vec3d::new(50.0, 40.8, -1e5 + 170.0),
                                   BLACK, BLACK)));
    scene.add(Box::new(Sphere::new(Material::Diffuse, 1e5,
                                   Vec3d::new(50.0, 1e5, 81.6),
                                   BLACK, GREY)));
    scene.add(Box::new(Sphere::new(Material::Diffuse, 1e5,
                                   Vec3d::new(50.0, -1e5 + 81.6, 81.6),
                                   BLACK, GREY)));
    scene.add(Box::new(Sphere::new(Material::Specular, 16.5,
                                   Vec3d::new(27.0, 16.5, 47.0),
                                   BLACK, WHITE)));
    scene.add(Box::new(Sphere::new(Material::Refractive, 16.5,
                                   Vec3d::new(73.0, 16.5, 78.0),
                                   BLACK, WHITE)));
    scene.add(Box::new(Sphere::new(Material::Diffuse, 600.0,
                                   Vec3d::new(50.0, 681.6 - 0.27, 81.6),
                                   Vec3d::new(12.0, 12.0, 12.0), BLACK)));
    let scene = Arc::new(scene);

    let camera_pos = Vec3d::new(50.0, 52.0, 295.6);
    let camera_dir = Vec3d::new(0.0, -0.042612, -1.0).normalized();
    let camera_x = Vec3d::new(width as f64 * 0.5135 / height as f64, 0.0, 0.0);
    let camera_y = camera_x.cross(camera_dir).normalized() * 0.5135;

    println!("Using {} threads", num_threads);
    let pool = ThreadPool::new(num_threads);
    let (tx, rx) = channel();

    for y in 0..height {
        let tx = tx.clone();
        let scene = scene.clone();
        pool.execute(move || {
            let mut line = Vec::with_capacity(width);
            let mut rng = XorShiftRng::from_seed([1 + (y * y) as u32, seed, 0x15aac60d, 0xb017f00d]);
            for x in 0..width {
                let mut sum = Vec3d::zero();
                for sx in 0..2 {
                    for sy in 0..2 {
                        let mut r = Vec3d::zero();
                        for _samp in 0..samps {
                            let dx = random_samp(&mut rng);
                            let dy = random_samp(&mut rng);
                            let sub_x = (sx as f64 + 0.5 + dx) / 2.0;
                            let dir_x = (sub_x + x as f64) / width as f64 - 0.5;
                            let sub_y = (sy as f64 + 0.5 + dy) / 2.0;
                            let dir_y = (sub_y + (height -y - 1) as f64) / height as f64 - 0.5;
                            let dir = (camera_x * dir_x + camera_y * dir_y + camera_dir).normalized();
                            let jittered_ray = Ray::new(camera_pos + dir * 140.0, dir);
                            let sample = radiance(&scene, &jittered_ray, 0, &mut rng);
                            r = r + (sample / (samps as f64));
                        }
                        sum = sum + (r.clamp() * 0.25);
                    }
                }
                line.push(sum);
            }
            tx.send((y, line)).unwrap();
        });
    }
    let mut left = height;
    let mut screen : Vec<Vec<Vec3d>> = Vec::new();
    for _y in 0..height {
        screen.push(Vec::new());
    }
    while left > 0 {
        print!("Rendering ({} spp) {:.4}%...\r", samps * 4, 100.0 * (height - left) as f64 / height as f64);
        io::stdout().flush().ok().expect("Could not flush stdout");
        let (y, line) = rx.recv().unwrap();
        screen[y] = line;
        left -= 1;
    }
    if !partial {
        println!("\nWriting output to '{}'", output_filename);
        let mut image = image::ImageBuffer::new(width as u32, height as u32);
        for y in 0..height {
            for x in 0..width {
                let sum = screen[y][x];
                image.put_pixel(x as u32, y as u32, image::Rgb([to_int(sum.x), to_int(sum.y), to_int(sum.z)]));
            }
        }
        let mut output_file = File::create(output_filename).unwrap();
        image::ImageRgb8(image).save(&mut output_file, image::PNG).unwrap();
    } else {
        println!("\nWriting partial output to '{}'", output_filename);
        let mut writer = BufWriter::new(File::create(output_filename).unwrap());
        write!(&mut writer, "{} {} {}\n", width, height, samps).unwrap();
        for y in 0..height {
            for x in 0..width {
                let sum = screen[y][x];
                if x != 0 { write!(&mut writer, " ").unwrap(); }
                write!(&mut writer, "{} {} {}", sum.x, sum.y, sum.z).unwrap();
            }
            write!(&mut writer, "\n").unwrap();
        }
    }
}
<commit_msg>Minor formatting tweaks<commit_after>// Based on smallpt, http://www.kevinbeason.com/smallpt/ which is also licensed under
// the MIT license.
extern crate argparse;
extern crate image;
extern crate num_cpus;
extern crate rand;
extern crate threadpool;

use argparse::{ArgumentParser, Store, StoreTrue};
use rand::{XorShiftRng, SeedableRng};
use threadpool::ThreadPool;

use std::fs::File;
use std::io::{self, BufWriter};
use std::io::prelude::*;
use std::sync::Arc;
use std::sync::mpsc::channel;

extern crate path_tracer;
use path_tracer::*;

fn main() {
    let mut samps = 1;
    let mut width = 1024;
    let mut height = 768;
    let mut output_filename = "".to_string();
    let mut num_threads = num_cpus::get();
    let mut seed = 0x193a6754;
    let mut partial = false;
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Render a simple image");
        ap.refer(&mut samps).add_option(&["-s", "--samples"], Store, "Number of samples");
        ap.refer(&mut height).add_option(&["-h", "--height"], Store, "Height");
        ap.refer(&mut width).add_option(&["-w", "--width"], Store, "Width");
        ap.refer(&mut output_filename).add_option(&["-o", "--output"], Store,
                                                  "Filename to output to");
        ap.refer(&mut num_threads).add_option(&["--num-threads"], Store,
                                              "Number of threads to use");
        ap.refer(&mut seed).add_option(&["--seed"], Store, "Random seed");
        ap.refer(&mut partial).add_option(&["--partial"], StoreTrue,
                                          "Output a partial render");
        ap.parse_args_or_exit();
    }
    samps = samps / 4;
    if samps < 1 { samps = 1; }
    if output_filename == "" {
        output_filename = if partial { "image.part" } else { "image.png" }.to_string();
    }
    const BLACK : Vec3d = Vec3d { x: 0.0, y: 0.0, z: 0.0 };
    const RED : Vec3d = Vec3d { x: 0.75, y: 0.25, z: 0.25 };
    const BLUE : Vec3d = Vec3d { x: 0.25, y: 0.25, z: 0.75 };
    const GREY : Vec3d = Vec3d { x: 0.75, y: 0.75, z: 0.75 };
    const WHITE : Vec3d = Vec3d { x: 0.999, y: 0.999, z: 0.999 };
    let mut scene = Scene::new();
    scene.add(Box::new(Sphere::new(Material::Diffuse, 1e5,
                                   Vec3d::new(1e5+1.0, 40.8, 81.6),
                                   BLACK, RED)));
    scene.add(Box::new(Sphere::new(Material::Diffuse, 1e5,
                                   Vec3d::new(-1e5+99.0, 40.8, 81.6),
                                   BLACK, BLUE)));
    scene.add(Box::new(Sphere::new(Material::Diffuse, 1e5,
                                   Vec3d::new(50.0, 40.8, 1e5),
                                   BLACK, GREY)));
    scene.add(Box::new(Sphere::new(Material::Diffuse, 1e5,
                                   Vec3d::new(50.0, 40.8, -1e5 + 170.0),
                                   BLACK, BLACK)));
    scene.add(Box::new(Sphere::new(Material::Diffuse, 1e5,
                                   Vec3d::new(50.0, 1e5, 81.6),
                                   BLACK, GREY)));
    scene.add(Box::new(Sphere::new(Material::Diffuse, 1e5,
                                   Vec3d::new(50.0, -1e5 + 81.6, 81.6),
                                   BLACK, GREY)));
    scene.add(Box::new(Sphere::new(Material::Specular, 16.5,
                                   Vec3d::new(27.0, 16.5, 47.0),
                                   BLACK, WHITE)));
    scene.add(Box::new(Sphere::new(Material::Refractive, 16.5,
                                   Vec3d::new(73.0, 16.5, 78.0),
                                   BLACK, WHITE)));
    scene.add(Box::new(Sphere::new(Material::Diffuse, 600.0,
                                   Vec3d::new(50.0, 681.6 - 0.27, 81.6),
                                   Vec3d::new(12.0, 12.0, 12.0), BLACK)));
    let scene = Arc::new(scene);

    let camera_pos = Vec3d::new(50.0, 52.0, 295.6);
    let camera_dir = Vec3d::new(0.0, -0.042612, -1.0).normalized();
    let camera_x = Vec3d::new(width as f64 * 0.5135 / height as f64, 0.0, 0.0);
    let camera_y = camera_x.cross(camera_dir).normalized() * 0.5135;

    println!("Using {} threads", num_threads);
    let pool = ThreadPool::new(num_threads);
    let (tx, rx) = channel();

    for y in 0..height {
        let tx = tx.clone();
        let scene = scene.clone();
        pool.execute(move || {
            let mut line = Vec::with_capacity(width);
            let mut rng = XorShiftRng::from_seed([1 + (y * y) as u32, seed, 0x15aac60d, 0xb017f00d]);
            for x in 0..width {
                let mut sum = Vec3d::zero();
                for sx in 0..2 {
                    for sy in 0..2 {
                        let mut r = Vec3d::zero();
                        for _samp in 0..samps {
                            let dx = random_samp(&mut rng);
                            let dy = random_samp(&mut rng);
                            let sub_x = (sx as f64 + 0.5 + dx) / 2.0;
                            let dir_x = (sub_x + x as f64) / width as f64 - 0.5;
                            let sub_y = (sy as f64 + 0.5 + dy) / 2.0;
                            let dir_y = (sub_y + (height - y - 1) as f64) / height as f64 - 0.5;
                            let dir = (camera_x * dir_x + camera_y * dir_y + camera_dir).normalized();
                            let jittered_ray = Ray::new(camera_pos + dir * 140.0, dir);
                            let sample = radiance(&scene, &jittered_ray, 0, &mut rng);
                            r = r + (sample / samps as f64);
                        }
                        sum = sum + r.clamp() * 0.25;
                    }
                }
                line.push(sum);
            }
            tx.send((y, line)).unwrap();
        });
    }
    let mut left = height;
    let mut screen : Vec<Vec<Vec3d>> = Vec::new();
    for _y in 0..height {
        screen.push(Vec::new());
    }
    while left > 0 {
        print!("Rendering ({} spp) {:.4}%...\r", samps * 4, 100.0 * (height - left) as f64 / height as f64);
        io::stdout().flush().ok().expect("Could not flush stdout");
        let (y, line) = rx.recv().unwrap();
        screen[y] = line;
        left -= 1;
    }
    if !partial {
        println!("\nWriting output to '{}'", output_filename);
        let mut image = image::ImageBuffer::new(width as u32, height as u32);
        for y in 0..height {
            for x in 0..width {
                let sum = screen[y][x];
                image.put_pixel(x as u32, y as u32, image::Rgb([to_int(sum.x), to_int(sum.y), to_int(sum.z)]));
            }
        }
        let mut output_file = File::create(output_filename).unwrap();
        image::ImageRgb8(image).save(&mut output_file, image::PNG).unwrap();
    } else {
        println!("\nWriting partial output to '{}'", output_filename);
        let mut writer = BufWriter::new(File::create(output_filename).unwrap());
        write!(&mut writer, "{} {} {}\n", width, height, samps).unwrap();
        for y in 0..height {
            for x in 0..width {
                let sum = screen[y][x];
                if x != 0 { write!(&mut writer, " ").unwrap(); }
                write!(&mut writer, "{} {} {}", sum.x, sum.y, sum.z).unwrap();
            }
            write!(&mut writer, "\n").unwrap();
        }
    }
}
<|endoftext|>


<commit_before>// (C)opyleft 2013 Frank Denis

/*!
 * Bloom filter for Rust
 *
 * This is a simple but fast Bloom filter implementation, that requires only
 * 2 hash functions, generated with SipHash-2-4 using randomized keys.
 */

#[desc = "A fast Bloom filter implementation."];
#[license = "BSD"];
#[link(name = "bloomfilter", vers = "0.1")];
#[crate_type = "lib"];
#[warn(non_camel_case_types, non_uppercase_statics, non_uppercase_statics, unnecessary_qualification, managed_heap_memory)]

extern mod extra;

use std::hash;
use std::num;
use std::rand;
use std::rand::Rng;
use extra::bitv;

struct SipHashKey {
    k1: u64,
    k2: u64
}

impl SipHashKey {
    fn new(k1: u64, k2: u64) -> SipHashKey {
        SipHashKey {
            k1: k1,
            k2: k2
        }
    }

    fn new_random() -> SipHashKey {
        let mut rng = rand::task_rng();
        SipHashKey {
            k1: rand::Rand::rand(& mut rng),
            k2: rand::Rand::rand(& mut rng)
        }
    }
}

/// Bloom filter structure
pub struct Bloom {
    priv bitmap: bitv::Bitv,
    priv bitmap_bits: u64,
    priv k_num: uint,
    priv skeys: [SipHashKey, ..2]
}

impl Bloom {

/// Create a new bloom filter structure.
/// bitmap_size is the size in bytes (not bits) that will be allocated in memory
/// items_count is an estimation of the maximum number of items to store.
    pub fn new(bitmap_size: uint, items_count: uint) -> Bloom {
        assert!(bitmap_size > 0u && items_count > 0u);
        let bitmap_bits = (bitmap_size as u64) * 8u64;
        let k_num = Bloom::optimal_k_num(bitmap_bits, items_count);
        let bitmap = bitv::Bitv::new(bitmap_bits as uint, false);
        let skeys = [ SipHashKey::new_random(), SipHashKey::new_random() ];
        Bloom {
            bitmap: bitmap,
            bitmap_bits: bitmap_bits,
            k_num: k_num,
            skeys: skeys
        }
    }

/// Create a new bloom filter structure.
/// items_count is an estimation of the maximum number of items to store.
/// fp_p is the wanted rate of false positives, in ]0.0, 1.0[
    pub fn new_for_fp_rate(items_count: uint, fp_p: f64) -> Bloom {
        let bitmap_size = Bloom::compute_bitmap_size(items_count, fp_p);
        Bloom::new(bitmap_size, items_count)
    }

/// Compute a recommended bitmap size for items_count items
/// and a fp_p rate of false positives.
/// fp_p obviously has to be within the ]0.0, 1.0[ range.
    pub fn compute_bitmap_size(items_count: uint, fp_p: f64) -> uint {
        assert!(items_count > 0u);
        assert!(fp_p > 0.0 && fp_p < 1.0);
        let log2 = num::ln(2.0f64);
        let log2_2 = log2 * log2;
        ((items_count as f64) * num::ln(fp_p) / (-8.0 * log2_2)).ceil() as uint
    }

/// Record the presence of an item.
    pub fn set<T: hash::Hash>(& mut self, item: T) {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            self.bitmap.set(bit_offset, true);
        }
    }

/// Check if an item is present in the set.
/// There can be false positives, but no false negatives.
    pub fn check<T: hash::Hash>(&self, item: T) -> bool {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            if self.bitmap.get(bit_offset) == false {
                return false;
            }
        }
        true
    }

/// Record the presence of an item in the set,
/// and return the previous state of this item.
    pub fn check_and_set<T: hash::Hash>(&mut self, item: T) -> bool {
        let mut hashes = [ 0u64, 0u64 ];
        let mut found = true;
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            if self.bitmap.get(bit_offset) == false {
                found = false;
                self.bitmap.set(bit_offset, true);
            }
        }
        found
    }

    fn optimal_k_num(bitmap_bits: u64, items_count: uint) -> uint {
        let m = bitmap_bits as f64;
        let n = items_count as f64;
        let k_num = (m / n * num::ln(2.0f64).ceil()) as uint;
        num::max(k_num, 1)
    }

    fn bloom_hash<T: hash::Hash>(&self, hashes: & mut [u64, ..2],
                  item: &T, k_i: uint) -> u64 {
        if k_i < 2 {
            let skey = self.skeys[k_i];
            let hash = (*item).hash_keyed(skey.k1, skey.k2);
            hashes[k_i] = hash;
            hash
        } else {
            hashes[0] + (((k_i as u64) * hashes[1]) % 0xffffffffffffffc5)
        }
    }
}

#[test]
fn bloom_test_set() {
    let mut bloom = Bloom::new(10, 80);
    let key = &rand::task_rng().gen_ascii_str(16u);
    assert!(bloom.check(key) == false);
    bloom.set(&key);
    assert!(bloom.check(key.clone()) == true);
}

#[test]
fn bloom_test_check_and_set() {
    let mut bloom = Bloom::new(10, 80);
    let key = &rand::task_rng().gen_ascii_str(16u);
    assert!(bloom.check_and_set(key) == false);
    assert!(bloom.check_and_set(key.clone()) == true);
}
<commit_msg>Add missing ; after lint settings<commit_after>// (C)opyleft 2013 Frank Denis

/*!
 * Bloom filter for Rust
 *
 * This is a simple but fast Bloom filter implementation, that requires only
 * 2 hash functions, generated with SipHash-2-4 using randomized keys.
 */

#[desc = "A fast Bloom filter implementation."];
#[license = "BSD"];
#[link(name = "bloomfilter", vers = "0.1")];
#[crate_type = "lib"];
#[warn(non_camel_case_types, non_uppercase_statics, non_uppercase_statics, unnecessary_qualification, managed_heap_memory)];

extern mod extra;

use std::hash;
use std::num;
use std::rand;
use std::rand::Rng;
use extra::bitv;

struct SipHashKey {
    k1: u64,
    k2: u64
}

impl SipHashKey {
    fn new(k1: u64, k2: u64) -> SipHashKey {
        SipHashKey {
            k1: k1,
            k2: k2
        }
    }

    fn new_random() -> SipHashKey {
        let mut rng = rand::task_rng();
        SipHashKey {
            k1: rand::Rand::rand(& mut rng),
            k2: rand::Rand::rand(& mut rng)
        }
    }
}

/// Bloom filter structure
pub struct Bloom {
    priv bitmap: bitv::Bitv,
    priv bitmap_bits: u64,
    priv k_num: uint,
    priv skeys: [SipHashKey, ..2]
}

impl Bloom {

/// Create a new bloom filter structure.
/// bitmap_size is the size in bytes (not bits) that will be allocated in memory
/// items_count is an estimation of the maximum number of items to store.
    pub fn new(bitmap_size: uint, items_count: uint) -> Bloom {
        assert!(bitmap_size > 0u && items_count > 0u);
        let bitmap_bits = (bitmap_size as u64) * 8u64;
        let k_num = Bloom::optimal_k_num(bitmap_bits, items_count);
        let bitmap = bitv::Bitv::new(bitmap_bits as uint, false);
        let skeys = [ SipHashKey::new_random(), SipHashKey::new_random() ];
        Bloom {
            bitmap: bitmap,
            bitmap_bits: bitmap_bits,
            k_num: k_num,
            skeys: skeys
        }
    }

/// Create a new bloom filter structure.
/// items_count is an estimation of the maximum number of items to store.
/// fp_p is the wanted rate of false positives, in ]0.0, 1.0[
    pub fn new_for_fp_rate(items_count: uint, fp_p: f64) -> Bloom {
        let bitmap_size = Bloom::compute_bitmap_size(items_count, fp_p);
        Bloom::new(bitmap_size, items_count)
    }

/// Compute a recommended bitmap size for items_count items
/// and a fp_p rate of false positives.
/// fp_p obviously has to be within the ]0.0, 1.0[ range.
    pub fn compute_bitmap_size(items_count: uint, fp_p: f64) -> uint {
        assert!(items_count > 0u);
        assert!(fp_p > 0.0 && fp_p < 1.0);
        let log2 = num::ln(2.0f64);
        let log2_2 = log2 * log2;
        ((items_count as f64) * num::ln(fp_p) / (-8.0 * log2_2)).ceil() as uint
    }

/// Record the presence of an item.
    pub fn set<T: hash::Hash>(& mut self, item: T) {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            self.bitmap.set(bit_offset, true);
        }
    }

/// Check if an item is present in the set.
/// There can be false positives, but no false negatives.
    pub fn check<T: hash::Hash>(&self, item: T) -> bool {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            if self.bitmap.get(bit_offset) == false {
                return false;
            }
        }
        true
    }

/// Record the presence of an item in the set,
/// and return the previous state of this item.
    pub fn check_and_set<T: hash::Hash>(&mut self, item: T) -> bool {
        let mut hashes = [ 0u64, 0u64 ];
        let mut found = true;
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            if self.bitmap.get(bit_offset) == false {
                found = false;
                self.bitmap.set(bit_offset, true);
            }
        }
        found
    }

    fn optimal_k_num(bitmap_bits: u64, items_count: uint) -> uint {
        let m = bitmap_bits as f64;
        let n = items_count as f64;
        let k_num = (m / n * num::ln(2.0f64).ceil()) as uint;
        num::max(k_num, 1)
    }

    fn bloom_hash<T: hash::Hash>(&self, hashes: & mut [u64, ..2],
                  item: &T, k_i: uint) -> u64 {
        if k_i < 2 {
            let skey = self.skeys[k_i];
            let hash = (*item).hash_keyed(skey.k1, skey.k2);
            hashes[k_i] = hash;
            hash
        } else {
            hashes[0] + (((k_i as u64) * hashes[1]) % 0xffffffffffffffc5)
        }
    }
}

#[test]
fn bloom_test_set() {
    let mut bloom = Bloom::new(10, 80);
    let key = &rand::task_rng().gen_ascii_str(16u);
    assert!(bloom.check(key) == false);
    bloom.set(&key);
    assert!(bloom.check(key.clone()) == true);
}

#[test]
fn bloom_test_check_and_set() {
    let mut bloom = Bloom::new(10, 80);
    let key = &rand::task_rng().gen_ascii_str(16u);
    assert!(bloom.check_and_set(key) == false);
    assert!(bloom.check_and_set(key.clone()) == true);
}
<|endoftext|>