<commit_before>use crate::intrinsics;
use crate::iter::{
    DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator, TrustedRandomAccess,
};
use crate::ops::Try;

/// An iterator that yields `None` forever after the underlying iterator
/// yields `None` once.
///
/// This `struct` is created by the [`fuse`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`fuse`]: trait.Iterator.html#method.fuse
/// [`Iterator`]: trait.Iterator.html
#[derive(Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Fuse<I> {
    // NOTE: for `I: FusedIterator`, this is always assumed `Some`!
    iter: Option<I>,
}
impl<I> Fuse<I> {
    pub(in crate::iter) fn new(iter: I) -> Fuse<I> {
        Fuse { iter: Some(iter) }
    }
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I> FusedIterator for Fuse<I> where I: Iterator {}

/// Fuse the iterator if the expression is `None`.
macro_rules! fuse {
    ($self:ident . iter . $($call:tt)+) => {
        match $self.iter {
            Some(ref mut iter) => match iter.$($call)+ {
                None => {
                    $self.iter = None;
                    None
                }
                item => item,
            },
            None => None,
        }
    };
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> Iterator for Fuse<I>
where
    I: Iterator,
{
    type Item = <I as Iterator>::Item;

    #[inline]
    default fn next(&mut self) -> Option<<I as Iterator>::Item> {
        fuse!(self.iter.next())
    }

    #[inline]
    default fn nth(&mut self, n: usize) -> Option<I::Item> {
        fuse!(self.iter.nth(n))
    }

    #[inline]
    default fn last(self) -> Option<I::Item> {
        match self.iter {
            Some(iter) => iter.last(),
            None => None,
        }
    }

    #[inline]
    default fn count(self) -> usize {
        match self.iter {
            Some(iter) => iter.count(),
            None => 0,
        }
    }

    #[inline]
    default fn size_hint(&self) -> (usize, Option<usize>) {
        match self.iter {
            Some(ref iter) => iter.size_hint(),
            None => (0, Some(0)),
        }
    }

    #[inline]
    default fn try_fold<Acc, Fold, R>(&mut self, mut acc: Acc, fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        if let Some(ref mut iter) = self.iter {
            acc = iter.try_fold(acc, fold)?;
            self.iter = None;
        }
        Try::from_ok(acc)
    }

    #[inline]
    default fn fold<Acc, Fold>(self, mut acc: Acc, fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        if let Some(iter) = self.iter {
            acc = iter.fold(acc, fold);
        }
        acc
    }

    #[inline]
    default fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
    where
        P: FnMut(&Self::Item) -> bool,
    {
        fuse!(self.iter.find(predicate))
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> DoubleEndedIterator for Fuse<I>
where
    I: DoubleEndedIterator,
{
    #[inline]
    default fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
        fuse!(self.iter.next_back())
    }

    #[inline]
    default fn nth_back(&mut self, n: usize) -> Option<<I as Iterator>::Item> {
        fuse!(self.iter.nth_back(n))
    }

    #[inline]
    default fn try_rfold<Acc, Fold, R>(&mut self, mut acc: Acc, fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        if let Some(ref mut iter) = self.iter {
            acc = iter.try_rfold(acc, fold)?;
            self.iter = None;
        }
        Try::from_ok(acc)
    }

    #[inline]
    default fn rfold<Acc, Fold>(self, mut acc: Acc, fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        if let Some(iter) = self.iter {
            acc = iter.rfold(acc, fold);
        }
        acc
    }

    #[inline]
    default fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
    where
        P: FnMut(&Self::Item) -> bool,
    {
        fuse!(self.iter.rfind(predicate))
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> ExactSizeIterator for Fuse<I>
where
    I: ExactSizeIterator,
{
    default fn len(&self) -> usize {
        match self.iter {
            Some(ref iter) => iter.len(),
            None => 0,
        }
    }

    default fn is_empty(&self) -> bool {
        match self.iter {
            Some(ref iter) => iter.is_empty(),
            None => true,
        }
    }
}

// NOTE: for `I: FusedIterator`, we assume that the iterator is always `Some`
impl<I: FusedIterator> Fuse<I> {
    #[inline(always)]
    fn as_inner(&self) -> &I {
        match self.iter {
            Some(ref iter) => iter,
            // SAFETY: the specialized iterator never sets `None`
            None => unsafe { intrinsics::unreachable() },
        }
    }

    #[inline(always)]
    fn as_inner_mut(&mut self) -> &mut I {
        match self.iter {
            Some(ref mut iter) => iter,
            // SAFETY: the specialized iterator never sets `None`
            None => unsafe { intrinsics::unreachable() },
        }
    }

    #[inline(always)]
    fn into_inner(self) -> I {
        match self.iter {
            Some(iter) => iter,
            // SAFETY: the specialized iterator never sets `None`
            None => unsafe { intrinsics::unreachable() },
        }
    }
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I> Iterator for Fuse<I>
where
    I: FusedIterator,
{
    #[inline]
    fn next(&mut self) -> Option<<I as Iterator>::Item> {
        self.as_inner_mut().next()
    }

    #[inline]
    fn nth(&mut self, n: usize) -> Option<I::Item> {
        self.as_inner_mut().nth(n)
    }

    #[inline]
    fn last(self) -> Option<I::Item> {
        self.into_inner().last()
    }

    #[inline]
    fn count(self) -> usize {
        self.into_inner().count()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.as_inner().size_hint()
    }

    #[inline]
    fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        self.as_inner_mut().try_fold(init, fold)
    }

    #[inline]
    fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        self.into_inner().fold(init, fold)
    }

    #[inline]
    fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
    where
        P: FnMut(&Self::Item) -> bool,
    {
        self.as_inner_mut().find(predicate)
    }
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I> DoubleEndedIterator for Fuse<I>
where
    I: DoubleEndedIterator + FusedIterator,
{
    #[inline]
    fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
        self.as_inner_mut().next_back()
    }

    #[inline]
    fn nth_back(&mut self, n: usize) -> Option<<I as Iterator>::Item> {
        self.as_inner_mut().nth_back(n)
    }

    #[inline]
    fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        self.as_inner_mut().try_rfold(init, fold)
    }

    #[inline]
    fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        self.into_inner().rfold(init, fold)
    }

    #[inline]
    fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
    where
        P: FnMut(&Self::Item) -> bool,
    {
        self.as_inner_mut().rfind(predicate)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> ExactSizeIterator for Fuse<I>
where
    I: ExactSizeIterator + FusedIterator,
{
    fn len(&self) -> usize {
        self.as_inner().len()
    }

    fn is_empty(&self) -> bool {
        self.as_inner().is_empty()
    }
}

unsafe impl<I> TrustedRandomAccess for Fuse<I>
where
    I: TrustedRandomAccess,
{
    unsafe fn get_unchecked(&mut self, i: usize) -> I::Item {
        match self.iter {
            Some(ref mut iter) => iter.get_unchecked(i),
            // SAFETY: the caller asserts there is an item at `i`, so we're not exhausted.
            None => intrinsics::unreachable(),
        }
    }

    fn may_have_side_effect() -> bool {
        I::may_have_side_effect()
    }
}
<commit_msg>Use a macro to expand the specialized Fuse<commit_after>use crate::intrinsics;
use crate::iter::{
    DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator, TrustedRandomAccess,
};
use crate::ops::Try;

/// An iterator that yields `None` forever after the underlying iterator
/// yields `None` once.
///
/// This `struct` is created by the [`fuse`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`fuse`]: trait.Iterator.html#method.fuse
/// [`Iterator`]: trait.Iterator.html
#[derive(Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Fuse<I> {
    // NOTE: for `I: FusedIterator`, this is always assumed `Some`!
    iter: Option<I>,
}
impl<I> Fuse<I> {
    pub(in crate::iter) fn new(iter: I) -> Fuse<I> {
        Fuse { iter: Some(iter) }
    }
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I> FusedIterator for Fuse<I> where I: Iterator {}

/// Fuse the iterator if the expression is `None`.
macro_rules! fuse {
    ($self:ident . iter . $($call:tt)+) => {
        match $self.iter {
            Some(ref mut iter) => match iter.$($call)+ {
                None => {
                    $self.iter = None;
                    None
                }
                item => item,
            },
            None => None,
        }
    };
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> Iterator for Fuse<I>
where
    I: Iterator,
{
    type Item = <I as Iterator>::Item;

    #[inline]
    default fn next(&mut self) -> Option<<I as Iterator>::Item> {
        fuse!(self.iter.next())
    }

    #[inline]
    default fn nth(&mut self, n: usize) -> Option<I::Item> {
        fuse!(self.iter.nth(n))
    }

    #[inline]
    default fn last(self) -> Option<I::Item> {
        match self.iter {
            Some(iter) => iter.last(),
            None => None,
        }
    }

    #[inline]
    default fn count(self) -> usize {
        match self.iter {
            Some(iter) => iter.count(),
            None => 0,
        }
    }

    #[inline]
    default fn size_hint(&self) -> (usize, Option<usize>) {
        match self.iter {
            Some(ref iter) => iter.size_hint(),
            None => (0, Some(0)),
        }
    }

    #[inline]
    default fn try_fold<Acc, Fold, R>(&mut self, mut acc: Acc, fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        if let Some(ref mut iter) = self.iter {
            acc = iter.try_fold(acc, fold)?;
            self.iter = None;
        }
        Try::from_ok(acc)
    }

    #[inline]
    default fn fold<Acc, Fold>(self, mut acc: Acc, fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        if let Some(iter) = self.iter {
            acc = iter.fold(acc, fold);
        }
        acc
    }

    #[inline]
    default fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
    where
        P: FnMut(&Self::Item) -> bool,
    {
        fuse!(self.iter.find(predicate))
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> DoubleEndedIterator for Fuse<I>
where
    I: DoubleEndedIterator,
{
    #[inline]
    default fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
        fuse!(self.iter.next_back())
    }

    #[inline]
    default fn nth_back(&mut self, n: usize) -> Option<<I as Iterator>::Item> {
        fuse!(self.iter.nth_back(n))
    }

    #[inline]
    default fn try_rfold<Acc, Fold, R>(&mut self, mut acc: Acc, fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        if let Some(ref mut iter) = self.iter {
            acc = iter.try_rfold(acc, fold)?;
            self.iter = None;
        }
        Try::from_ok(acc)
    }

    #[inline]
    default fn rfold<Acc, Fold>(self, mut acc: Acc, fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        if let Some(iter) = self.iter {
            acc = iter.rfold(acc, fold);
        }
        acc
    }

    #[inline]
    default fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
    where
        P: FnMut(&Self::Item) -> bool,
    {
        fuse!(self.iter.rfind(predicate))
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> ExactSizeIterator for Fuse<I>
where
    I: ExactSizeIterator,
{
    default fn len(&self) -> usize {
        match self.iter {
            Some(ref iter) => iter.len(),
            None => 0,
        }
    }

    default fn is_empty(&self) -> bool {
        match self.iter {
            Some(ref iter) => iter.is_empty(),
            None => true,
        }
    }
}

// NOTE: for `I: FusedIterator`, we assume that the iterator is always `Some`.
// Implementing this as a directly-expanded macro helps codegen performance.
macro_rules! unchecked {
    ($self:ident) => {
        match $self {
            Fuse { iter: Some(iter) } => iter,
            // SAFETY: the specialized iterator never sets `None`
            Fuse { iter: None } => unsafe { intrinsics::unreachable() },
        }
    };
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I> Iterator for Fuse<I>
where
    I: FusedIterator,
{
    #[inline]
    fn next(&mut self) -> Option<<I as Iterator>::Item> {
        unchecked!(self).next()
    }

    #[inline]
    fn nth(&mut self, n: usize) -> Option<I::Item> {
        unchecked!(self).nth(n)
    }

    #[inline]
    fn last(self) -> Option<I::Item> {
        unchecked!(self).last()
    }

    #[inline]
    fn count(self) -> usize {
        unchecked!(self).count()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        unchecked!(self).size_hint()
    }

    #[inline]
    fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        unchecked!(self).try_fold(init, fold)
    }

    #[inline]
    fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        unchecked!(self).fold(init, fold)
    }

    #[inline]
    fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
    where
        P: FnMut(&Self::Item) -> bool,
    {
        unchecked!(self).find(predicate)
    }
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I> DoubleEndedIterator for Fuse<I>
where
    I: DoubleEndedIterator + FusedIterator,
{
    #[inline]
    fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
        unchecked!(self).next_back()
    }

    #[inline]
    fn nth_back(&mut self, n: usize) -> Option<<I as Iterator>::Item> {
        unchecked!(self).nth_back(n)
    }

    #[inline]
    fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        unchecked!(self).try_rfold(init, fold)
    }

    #[inline]
    fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        unchecked!(self).rfold(init, fold)
    }

    #[inline]
    fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
    where
        P: FnMut(&Self::Item) -> bool,
    {
        unchecked!(self).rfind(predicate)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> ExactSizeIterator for Fuse<I>
where
    I: ExactSizeIterator + FusedIterator,
{
    fn len(&self) -> usize {
        unchecked!(self).len()
    }

    fn is_empty(&self) -> bool {
        unchecked!(self).is_empty()
    }
}

unsafe impl<I> TrustedRandomAccess for Fuse<I>
where
    I: TrustedRandomAccess,
{
    unsafe fn get_unchecked(&mut self, i: usize) -> I::Item {
        match self.iter {
            Some(ref mut iter) => iter.get_unchecked(i),
            // SAFETY: the caller asserts there is an item at `i`, so we're not exhausted.
            None => intrinsics::unreachable(),
        }
    }

    fn may_have_side_effect() -> bool {
        I::may_have_side_effect()
    }
}
<|endoftext|>


<commit_before>//! The Connection general header, defined in RFC 2616, Section 14.10.

// TODO: check if the token thing is correct or whether it's any number of tokens. Also, how and
// whether they should be interpreted (I recall its being a header name thing for legacy code,
// perhaps I should normalise header case or some such thing?)

use std::rt::io::{Reader, Writer};
use headers::serialization_utils::normalise_header_name;

/// A value for the Connection header. Note that should it be a ``Token``, the string is in
/// normalised header case (e.g. "Keep-Alive").
#[deriving(Clone, DeepClone, Eq)]
pub enum Connection {
    Token(~str),
    Close,
}
impl ToStr for Connection {
    fn to_str(&self) -> ~str {
        match *self {
            Token(ref s) => s.clone(),
            Close => ~"close",
        }
    }
}

impl super::CommaListHeaderConvertible for Connection {}

impl super::HeaderConvertible for Connection {
    fn from_stream<T: Reader>(reader: &mut super::HeaderValueByteIterator<T>)
            -> Option<Connection> {
        let s = match reader.read_token() {
            Some(s) => normalise_header_name(s),
            None => return None,
        };
        if s.as_slice() == "Close" {
            Some(Close)
        } else {
            Some(Token(s))
        }
    }

    fn to_stream<T: Writer>(&self, writer: &mut T) {
        writer.write(match *self {
            Close => bytes!("close"),
            Token(ref s) => s.as_bytes(),
        });
    }

    fn http_value(&self) -> ~str {
        match *self {
            Close => ~"close",
            Token(ref s) => s.to_owned(),
        }
    }
}

#[test]
fn test_connection() {
    ::headers::test_utils::assert_conversion_correct("close", ~[Close]);
}
#[test]
fn test_connection_2() {
    ::headers::test_utils::assert_conversion_correct("Foo", ~[Token(~"Foo")]);
}
#[test]
fn test_connection_3() {
    ::headers::test_utils::assert_conversion_correct("Foo, Keep-Alive", ~[Token(~"Foo"), Token(~"Keep-Alive")]);
}
#[test]
fn test_connection_4() {
    ::headers::test_utils::assert_conversion_correct("Foo, close", ~[Token(~"Foo"), Close]);
}
#[test]
fn test_connection_5() {
    ::headers::test_utils::assert_conversion_correct("close, Bar", ~[Close, Token(~"Bar")]);
}
#[test]
fn test_connection_6() {
    ::headers::test_utils::assert_interpretation_correct("close", ~[Close]);
}
#[test]
fn test_connection_7() {
    ::headers::test_utils::assert_interpretation_correct("foo", ~[Token(~"Foo")]);
}
#[test]
//#[ignore(reason="lws collapse bug")]
fn test_connection_8() {
    ::headers::test_utils::assert_interpretation_correct("close \r\n , keep-ALIVE", ~[Close, Token(~"Keep-Alive")]);
}
#[test]
fn test_connection_9() {
    ::headers::test_utils::assert_interpretation_correct("foo,close", ~[Token(~"Foo"), Close]);
}
#[test]
fn test_connection_10() {
    ::headers::test_utils::assert_interpretation_correct("close, bar", ~[Close, Token(~"Bar")]);
}
#[test]
fn test_connection_11() {
    ::headers::test_utils::assert_interpretation_correct("CLOSE", Close);
}
#[test]
//#[ignore(reason="lws collapse bug")]
fn test_connection_12() {
    ::headers::test_utils::assert_invalid::<~[Connection]>("foo bar");
}
#[test]
//#[ignore(reason="lws collapse bug")]
fn test_connection_13() {
    ::headers::test_utils::assert_invalid::<~[Connection]>("foo bar");
}
#[test]
#[ignore(reason="lws collapse bug")]
fn test_connection_14() {
    ::headers::test_utils::assert_invalid::<~[Connection]>("foo, bar baz");
}
#[test]
fn test_connection_15() {
    ::headers::test_utils::assert_invalid::<~[Connection]>("foo, , baz");
}
<commit_msg>Enabled test_connection_14.<commit_after>//! The Connection general header, defined in RFC 2616, Section 14.10.

// TODO: check if the token thing is correct or whether it's any number of tokens. Also, how and
// whether they should be interpreted (I recall its being a header name thing for legacy code,
// perhaps I should normalise header case or some such thing?)

use std::rt::io::{Reader, Writer};
use headers::serialization_utils::normalise_header_name;

/// A value for the Connection header. Note that should it be a ``Token``, the string is in
/// normalised header case (e.g. "Keep-Alive").
#[deriving(Clone, DeepClone, Eq)]
pub enum Connection {
    Token(~str),
    Close,
}
impl ToStr for Connection {
    fn to_str(&self) -> ~str {
        match *self {
            Token(ref s) => s.clone(),
            Close => ~"close",
        }
    }
}

impl super::CommaListHeaderConvertible for Connection {}

impl super::HeaderConvertible for Connection {
    fn from_stream<T: Reader>(reader: &mut super::HeaderValueByteIterator<T>)
            -> Option<Connection> {
        let s = match reader.read_token() {
            Some(s) => normalise_header_name(s),
            None => return None,
        };
        if s.as_slice() == "Close" {
            Some(Close)
        } else {
            Some(Token(s))
        }
    }

    fn to_stream<T: Writer>(&self, writer: &mut T) {
        writer.write(match *self {
            Close => bytes!("close"),
            Token(ref s) => s.as_bytes(),
        });
    }

    fn http_value(&self) -> ~str {
        match *self {
            Close => ~"close",
            Token(ref s) => s.to_owned(),
        }
    }
}

#[test]
fn test_connection() {
    ::headers::test_utils::assert_conversion_correct("close", ~[Close]);
}
#[test]
fn test_connection_2() {
    ::headers::test_utils::assert_conversion_correct("Foo", ~[Token(~"Foo")]);
}
#[test]
fn test_connection_3() {
    ::headers::test_utils::assert_conversion_correct("Foo, Keep-Alive", ~[Token(~"Foo"), Token(~"Keep-Alive")]);
}
#[test]
fn test_connection_4() {
    ::headers::test_utils::assert_conversion_correct("Foo, close", ~[Token(~"Foo"), Close]);
}
#[test]
fn test_connection_5() {
    ::headers::test_utils::assert_conversion_correct("close, Bar", ~[Close, Token(~"Bar")]);
}
#[test]
fn test_connection_6() {
    ::headers::test_utils::assert_interpretation_correct("close", ~[Close]);
}
#[test]
fn test_connection_7() {
    ::headers::test_utils::assert_interpretation_correct("foo", ~[Token(~"Foo")]);
}
#[test]
//#[ignore(reason="lws collapse bug")]
fn test_connection_8() {
    ::headers::test_utils::assert_interpretation_correct("close \r\n , keep-ALIVE", ~[Close, Token(~"Keep-Alive")]);
}
#[test]
fn test_connection_9() {
    ::headers::test_utils::assert_interpretation_correct("foo,close", ~[Token(~"Foo"), Close]);
}
#[test]
fn test_connection_10() {
    ::headers::test_utils::assert_interpretation_correct("close, bar", ~[Close, Token(~"Bar")]);
}
#[test]
fn test_connection_11() {
    ::headers::test_utils::assert_interpretation_correct("CLOSE", Close);
}
#[test]
//#[ignore(reason="lws collapse bug")]
fn test_connection_12() {
    ::headers::test_utils::assert_invalid::<~[Connection]>("foo bar");
}
#[test]
//#[ignore(reason="lws collapse bug")]
fn test_connection_13() {
    ::headers::test_utils::assert_invalid::<~[Connection]>("foo bar");
}
#[test]
//#[ignore(reason="lws collapse bug")]
fn test_connection_14() {
    ::headers::test_utils::assert_invalid::<~[Connection]>("foo, bar baz");
}
#[test]
fn test_connection_15() {
    ::headers::test_utils::assert_invalid::<~[Connection]>("foo, , baz");
}
<|endoftext|>


<commit_before>use super::{Parser, PathStyle, TokenType};
use rustc_errors::PResult;
use syntax::ast;
use syntax::print::pprust;
use syntax::token::{self, Nonterminal};
use syntax::util::comments;
use syntax::util::comments;
use syntax_pos::{Span, Symbol};

use log::debug;

#[derive(Debug)]
enum InnerAttributeParsePolicy<'a> {
    Permitted,
    NotPermitted { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option<Span> },
}

const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
                                                     permitted in this context";

impl<'a> Parser<'a> {
    /// Parses attributes that appear before an item.
    pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
        let mut attrs: Vec<ast::Attribute> = Vec::new();
        let mut just_parsed_doc_comment = false;
        loop {
            debug!("parse_outer_attributes: self.token={:?}", self.token);
            match self.token.kind {
                token::Pound => {
                    let inner_error_reason = if just_parsed_doc_comment {
                        "an inner attribute is not permitted following an outer doc comment"
                    } else if !attrs.is_empty() {
                        "an inner attribute is not permitted following an outer attribute"
                    } else {
                        DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
                    };
                    let inner_parse_policy = InnerAttributeParsePolicy::NotPermitted {
                        reason: inner_error_reason,
                        saw_doc_comment: just_parsed_doc_comment,
                        prev_attr_sp: attrs.last().and_then(|a| Some(a.span)),
                    };
                    let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?;
                    attrs.push(attr);
                    just_parsed_doc_comment = false;
                }
                token::DocComment(s) => {
                    let attr = self.mk_doc_comment(s);
                    if attr.style != ast::AttrStyle::Outer {
                        let mut err = self.fatal("expected outer doc comment");
                        err.note(
                            "inner doc comments like this (starting with \
                                  `//!` or `/*!`) can only appear before items",
                        );
                        return Err(err);
                    }
                    attrs.push(attr);
                    self.bump();
                    just_parsed_doc_comment = true;
                }
                _ => break,
            }
        }
        Ok(attrs)
    }

    fn mk_doc_comment(&self, s: Symbol) -> ast::Attribute {
        let style = comments::doc_comment_style(&s.as_str());
        attr::mk_doc_comment(style, s, self.token.span)
    }

    /// Matches `attribute = # ! [ meta_item ]`.
    ///
    /// If `permit_inner` is `true`, then a leading `!` indicates an inner
    /// attribute.
    pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> {
        debug!("parse_attribute: permit_inner={:?} self.token={:?}", permit_inner, self.token);
        let inner_parse_policy = if permit_inner {
            InnerAttributeParsePolicy::Permitted
        } else {
            InnerAttributeParsePolicy::NotPermitted {
                reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG,
                saw_doc_comment: false,
                prev_attr_sp: None,
            }
        };
        self.parse_attribute_with_inner_parse_policy(inner_parse_policy)
    }

    /// The same as `parse_attribute`, except it takes in an `InnerAttributeParsePolicy`
    /// that prescribes how to handle inner attributes.
    fn parse_attribute_with_inner_parse_policy(
        &mut self,
        inner_parse_policy: InnerAttributeParsePolicy<'_>,
    ) -> PResult<'a, ast::Attribute> {
        debug!(
            "parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}",
            inner_parse_policy, self.token
        );
        let (span, item, style) = match self.token.kind {
            token::Pound => {
                let lo = self.token.span;
                self.bump();

                if let InnerAttributeParsePolicy::Permitted = inner_parse_policy {
                    self.expected_tokens.push(TokenType::Token(token::Not));
                }

                let style = if self.token == token::Not {
                    self.bump();
                    ast::AttrStyle::Inner
                } else {
                    ast::AttrStyle::Outer
                };

                self.expect(&token::OpenDelim(token::Bracket))?;
                let item = self.parse_attr_item()?;
                self.expect(&token::CloseDelim(token::Bracket))?;
                let hi = self.prev_span;

                let attr_sp = lo.to(hi);

                // Emit error if inner attribute is encountered and not permitted
                if style == ast::AttrStyle::Inner {
                    if let InnerAttributeParsePolicy::NotPermitted {
                        reason,
                        saw_doc_comment,
                        prev_attr_sp,
                    } = inner_parse_policy
                    {
                        let prev_attr_note = if saw_doc_comment {
                            "previous doc comment"
                        } else {
                            "previous outer attribute"
                        };

                        let mut diagnostic = self.diagnostic().struct_span_err(attr_sp, reason);

                        if let Some(prev_attr_sp) = prev_attr_sp {
                            diagnostic
                                .span_label(attr_sp, "not permitted following an outer attibute")
                                .span_label(prev_attr_sp, prev_attr_note);
                        }

                        diagnostic
                            .note(
                                "inner attributes, like `#![no_std]`, annotate the item \
                                   enclosing them, and are usually found at the beginning of \
                                   source files. Outer attributes, like `#[test]`, annotate the \
                                   item following them.",
                            )
                            .emit()
                    }
                }

                (attr_sp, item, style)
            }
            _ => {
                let token_str = pprust::token_to_string(&self.token);
                return Err(self.fatal(&format!("expected `#`, found `{}`", token_str)));
            }
        };

        Ok(attr::mk_attr_from_item(style, item, span))
    }

    /// Parses an inner part of an attribute (the path and following tokens).
    /// The tokens must be either a delimited token stream, or empty token stream,
    /// or the "legacy" key-value form.
    ///     PATH `(` TOKEN_STREAM `)`
    ///     PATH `[` TOKEN_STREAM `]`
    ///     PATH `{` TOKEN_STREAM `}`
    ///     PATH
    ///     PATH `=` UNSUFFIXED_LIT
    /// The delimiters or `=` are still put into the resulting token stream.
    pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> {
        let item = match self.token.kind {
            token::Interpolated(ref nt) => match **nt {
                Nonterminal::NtMeta(ref item) => Some(item.clone()),
                _ => None,
            },
            _ => None,
        };
        Ok(if let Some(item) = item {
            self.bump();
            item
        } else {
            let path = self.parse_path(PathStyle::Mod)?;
            let args = self.parse_attr_args()?;
            ast::AttrItem { path, args }
        })
    }

    /// Parses attributes that appear after the opening of an item. These should
    /// be preceded by an exclamation mark, but we accept and warn about one
    /// terminated by a semicolon.
    ///
    /// Matches `inner_attrs*`.
    crate fn parse_inner_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
        let mut attrs: Vec<ast::Attribute> = vec![];
        loop {
            match self.token.kind {
                token::Pound => {
                    // Don't even try to parse if it's not an inner attribute.
                    if !self.look_ahead(1, |t| t == &token::Not) {
                        break;
                    }

                    let attr = self.parse_attribute(true)?;
                    assert_eq!(attr.style, ast::AttrStyle::Inner);
                    attrs.push(attr);
                }
                token::DocComment(s) => {
                    // We need to get the position of this token before we bump.
                    let attr = self.mk_doc_comment(s);
                    if attr.style == ast::AttrStyle::Inner {
                        attrs.push(attr);
                        self.bump();
                    } else {
                        break;
                    }
                }
                _ => break,
            }
        }
        Ok(attrs)
    }

    crate fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
        let lit = self.parse_lit()?;
        debug!("checking if {:?} is unusuffixed", lit);

        if !lit.kind.is_unsuffixed() {
            let msg = "suffixed literals are not allowed in attributes";
            self.diagnostic()
                .struct_span_err(lit.span, msg)
                .help(
                    "instead of using a suffixed literal \
                                    (1u8, 1.0f32, etc.), use an unsuffixed version \
                                    (1, 1.0, etc.).",
                )
                .emit()
        }

        Ok(lit)
    }

    /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited.
    pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> {
        let cfg_predicate = self.parse_meta_item()?;
        self.expect(&token::Comma)?;

        // Presumably, the majority of the time there will only be one attr.
        let mut expanded_attrs = Vec::with_capacity(1);
        while self.token.kind != token::Eof {
            let lo = self.token.span;
            let item = self.parse_attr_item()?;
            expanded_attrs.push((item, lo.to(self.prev_span)));
            if !self.eat(&token::Comma) {
                break;
            }
        }

        Ok((cfg_predicate, expanded_attrs))
    }

    /// Matches `COMMASEP(meta_item_inner)`.
    crate fn parse_meta_seq_top(&mut self) -> PResult<'a, Vec<ast::NestedMetaItem>> {
        // Presumably, the majority of the time there will only be one attr.
        let mut nmis = Vec::with_capacity(1);
        while self.token.kind != token::Eof {
            nmis.push(self.parse_meta_item_inner()?);
            if !self.eat(&token::Comma) {
                break;
            }
        }
        Ok(nmis)
    }

    /// Matches the following grammar (per RFC 1559).
    ///
    ///     meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
    ///     meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
    pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
        let nt_meta = match self.token.kind {
            token::Interpolated(ref nt) => match **nt {
                token::NtMeta(ref e) => Some(e.clone()),
                _ => None,
            },
            _ => None,
        };

        if let Some(item) = nt_meta {
            return match item.meta(item.path.span) {
                Some(meta) => {
                    self.bump();
                    Ok(meta)
                }
                None => self.unexpected(),
            };
        }

        let lo = self.token.span;
        let path = self.parse_path(PathStyle::Mod)?;
        let kind = self.parse_meta_item_kind()?;
        let span = lo.to(self.prev_span);
        Ok(ast::MetaItem { path, kind, span })
    }

    crate fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {
        Ok(if self.eat(&token::Eq) {
            ast::MetaItemKind::NameValue(self.parse_unsuffixed_lit()?)
        } else if self.check(&token::OpenDelim(token::Paren)) {
            // Matches `meta_seq = ( COMMASEP(meta_item_inner) )`.
            let (list, _) = self.parse_paren_comma_seq(|p| p.parse_meta_item_inner())?;
            ast::MetaItemKind::List(list)
        } else {
            ast::MetaItemKind::Word
        })
    }

    /// Matches `meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;`.
    fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
        match self.parse_unsuffixed_lit() {
            Ok(lit) => return Ok(ast::NestedMetaItem::Literal(lit)),
            Err(ref mut err) => err.cancel(),
        }

        match self.parse_meta_item() {
            Ok(mi) => return Ok(ast::NestedMetaItem::MetaItem(mi)),
            Err(ref mut err) => err.cancel(),
        }

        let found = pprust::token_to_string(&self.token);
        let msg = format!("expected unsuffixed literal or identifier, found `{}`", found);
        Err(self.diagnostic().struct_span_err(self.token.span, &msg))
    }
}
<commit_msg>fix rebase fallout<commit_after>use super::{Parser, PathStyle, TokenType};
use rustc_errors::PResult;
use syntax::ast;
use syntax::attr;
use syntax::print::pprust;
use syntax::token::{self, Nonterminal};
use syntax::util::comments;
use syntax_pos::{Span, Symbol};

use log::debug;

#[derive(Debug)]
enum InnerAttributeParsePolicy<'a> {
    Permitted,
    NotPermitted { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option<Span> },
}

const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
                                                     permitted in this context";

impl<'a> Parser<'a> {
    /// Parses attributes that appear before an item.
    pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
        let mut attrs: Vec<ast::Attribute> = Vec::new();
        let mut just_parsed_doc_comment = false;
        loop {
            debug!("parse_outer_attributes: self.token={:?}", self.token);
            match self.token.kind {
                token::Pound => {
                    let inner_error_reason = if just_parsed_doc_comment {
                        "an inner attribute is not permitted following an outer doc comment"
                    } else if !attrs.is_empty() {
                        "an inner attribute is not permitted following an outer attribute"
                    } else {
                        DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
                    };
                    let inner_parse_policy = InnerAttributeParsePolicy::NotPermitted {
                        reason: inner_error_reason,
                        saw_doc_comment: just_parsed_doc_comment,
                        prev_attr_sp: attrs.last().and_then(|a| Some(a.span)),
                    };
                    let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?;
                    attrs.push(attr);
                    just_parsed_doc_comment = false;
                }
                token::DocComment(s) => {
                    let attr = self.mk_doc_comment(s);
                    if attr.style != ast::AttrStyle::Outer {
                        let mut err = self.fatal("expected outer doc comment");
                        err.note(
                            "inner doc comments like this (starting with \
                                  `//!` or `/*!`) can only appear before items",
                        );
                        return Err(err);
                    }
                    attrs.push(attr);
                    self.bump();
                    just_parsed_doc_comment = true;
                }
                _ => break,
            }
        }
        Ok(attrs)
    }

    fn mk_doc_comment(&self, s: Symbol) -> ast::Attribute {
        let style = comments::doc_comment_style(&s.as_str());
        attr::mk_doc_comment(style, s, self.token.span)
    }

    /// Matches `attribute = # ! [ meta_item ]`.
    ///
    /// If `permit_inner` is `true`, then a leading `!` indicates an inner
    /// attribute.
    pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> {
        debug!("parse_attribute: permit_inner={:?} self.token={:?}", permit_inner, self.token);
        let inner_parse_policy = if permit_inner {
            InnerAttributeParsePolicy::Permitted
        } else {
            InnerAttributeParsePolicy::NotPermitted {
                reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG,
                saw_doc_comment: false,
                prev_attr_sp: None,
            }
        };
        self.parse_attribute_with_inner_parse_policy(inner_parse_policy)
    }

    /// The same as `parse_attribute`, except it takes in an `InnerAttributeParsePolicy`
    /// that prescribes how to handle inner attributes.
    fn parse_attribute_with_inner_parse_policy(
        &mut self,
        inner_parse_policy: InnerAttributeParsePolicy<'_>,
    ) -> PResult<'a, ast::Attribute> {
        debug!(
            "parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}",
            inner_parse_policy, self.token
        );
        let (span, item, style) = match self.token.kind {
            token::Pound => {
                let lo = self.token.span;
                self.bump();

                if let InnerAttributeParsePolicy::Permitted = inner_parse_policy {
                    self.expected_tokens.push(TokenType::Token(token::Not));
                }

                let style = if self.token == token::Not {
                    self.bump();
                    ast::AttrStyle::Inner
                } else {
                    ast::AttrStyle::Outer
                };

                self.expect(&token::OpenDelim(token::Bracket))?;
                let item = self.parse_attr_item()?;
                self.expect(&token::CloseDelim(token::Bracket))?;
                let hi = self.prev_span;

                let attr_sp = lo.to(hi);

                // Emit error if inner attribute is encountered and not permitted
                if style == ast::AttrStyle::Inner {
                    if let InnerAttributeParsePolicy::NotPermitted {
                        reason,
                        saw_doc_comment,
                        prev_attr_sp,
                    } = inner_parse_policy
                    {
                        let prev_attr_note = if saw_doc_comment {
                            "previous doc comment"
                        } else {
                            "previous outer attribute"
                        };

                        let mut diagnostic = self.diagnostic().struct_span_err(attr_sp, reason);

                        if let Some(prev_attr_sp) = prev_attr_sp {
                            diagnostic
                                .span_label(attr_sp, "not permitted following an outer attibute")
                                .span_label(prev_attr_sp, prev_attr_note);
                        }

                        diagnostic
                            .note(
                                "inner attributes, like `#![no_std]`, annotate the item \
                                   enclosing them, and are usually found at the beginning of \
                                   source files. Outer attributes, like `#[test]`, annotate the \
                                   item following them.",
                            )
                            .emit()
                    }
                }

                (attr_sp, item, style)
            }
            _ => {
                let token_str = pprust::token_to_string(&self.token);
                return Err(self.fatal(&format!("expected `#`, found `{}`", token_str)));
            }
        };

        Ok(attr::mk_attr_from_item(style, item, span))
    }

    /// Parses an inner part of an attribute (the path and following tokens).
    /// The tokens must be either a delimited token stream, or empty token stream,
    /// or the "legacy" key-value form.
    ///     PATH `(` TOKEN_STREAM `)`
    ///     PATH `[` TOKEN_STREAM `]`
    ///     PATH `{` TOKEN_STREAM `}`
    ///     PATH
    ///     PATH `=` UNSUFFIXED_LIT
    /// The delimiters or `=` are still put into the resulting token stream.
    pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> {
        let item = match self.token.kind {
            token::Interpolated(ref nt) => match **nt {
                Nonterminal::NtMeta(ref item) => Some(item.clone()),
                _ => None,
            },
            _ => None,
        };
        Ok(if let Some(item) = item {
            self.bump();
            item
        } else {
            let path = self.parse_path(PathStyle::Mod)?;
            let args = self.parse_attr_args()?;
            ast::AttrItem { path, args }
        })
    }

    /// Parses attributes that appear after the opening of an item. These should
    /// be preceded by an exclamation mark, but we accept and warn about one
    /// terminated by a semicolon.
    ///
    /// Matches `inner_attrs*`.
    crate fn parse_inner_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
        let mut attrs: Vec<ast::Attribute> = vec![];
        loop {
            match self.token.kind {
                token::Pound => {
                    // Don't even try to parse if it's not an inner attribute.
                    if !self.look_ahead(1, |t| t == &token::Not) {
                        break;
                    }

                    let attr = self.parse_attribute(true)?;
                    assert_eq!(attr.style, ast::AttrStyle::Inner);
                    attrs.push(attr);
                }
                token::DocComment(s) => {
                    // We need to get the position of this token before we bump.
                    let attr = self.mk_doc_comment(s);
                    if attr.style == ast::AttrStyle::Inner {
                        attrs.push(attr);
                        self.bump();
                    } else {
                        break;
                    }
                }
                _ => break,
            }
        }
        Ok(attrs)
    }

    crate fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
        let lit = self.parse_lit()?;
        debug!("checking if {:?} is unusuffixed", lit);

        if !lit.kind.is_unsuffixed() {
            let msg = "suffixed literals are not allowed in attributes";
            self.diagnostic()
                .struct_span_err(lit.span, msg)
                .help(
                    "instead of using a suffixed literal \
                                    (1u8, 1.0f32, etc.), use an unsuffixed version \
                                    (1, 1.0, etc.).",
                )
                .emit()
        }

        Ok(lit)
    }

    /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited.
    pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> {
        let cfg_predicate = self.parse_meta_item()?;
        self.expect(&token::Comma)?;

        // Presumably, the majority of the time there will only be one attr.
        let mut expanded_attrs = Vec::with_capacity(1);
        while self.token.kind != token::Eof {
            let lo = self.token.span;
            let item = self.parse_attr_item()?;
            expanded_attrs.push((item, lo.to(self.prev_span)));
            if !self.eat(&token::Comma) {
                break;
            }
        }

        Ok((cfg_predicate, expanded_attrs))
    }

    /// Matches `COMMASEP(meta_item_inner)`.
    crate fn parse_meta_seq_top(&mut self) -> PResult<'a, Vec<ast::NestedMetaItem>> {
        // Presumably, the majority of the time there will only be one attr.
        let mut nmis = Vec::with_capacity(1);
        while self.token.kind != token::Eof {
            nmis.push(self.parse_meta_item_inner()?);
            if !self.eat(&token::Comma) {
                break;
            }
        }
        Ok(nmis)
    }

    /// Matches the following grammar (per RFC 1559).
    ///
    ///     meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
    ///     meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
    pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
        let nt_meta = match self.token.kind {
            token::Interpolated(ref nt) => match **nt {
                token::NtMeta(ref e) => Some(e.clone()),
                _ => None,
            },
            _ => None,
        };

        if let Some(item) = nt_meta {
            return match item.meta(item.path.span) {
                Some(meta) => {
                    self.bump();
                    Ok(meta)
                }
                None => self.unexpected(),
            };
        }

        let lo = self.token.span;
        let path = self.parse_path(PathStyle::Mod)?;
        let kind = self.parse_meta_item_kind()?;
        let span = lo.to(self.prev_span);
        Ok(ast::MetaItem { path, kind, span })
    }

    crate fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {
        Ok(if self.eat(&token::Eq) {
            ast::MetaItemKind::NameValue(self.parse_unsuffixed_lit()?)
        } else if self.check(&token::OpenDelim(token::Paren)) {
            // Matches `meta_seq = ( COMMASEP(meta_item_inner) )`.
            let (list, _) = self.parse_paren_comma_seq(|p| p.parse_meta_item_inner())?;
            ast::MetaItemKind::List(list)
        } else {
            ast::MetaItemKind::Word
        })
    }

    /// Matches `meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;`.
    fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
        match self.parse_unsuffixed_lit() {
            Ok(lit) => return Ok(ast::NestedMetaItem::Literal(lit)),
            Err(ref mut err) => err.cancel(),
        }

        match self.parse_meta_item() {
            Ok(mi) => return Ok(ast::NestedMetaItem::MetaItem(mi)),
            Err(ref mut err) => err.cancel(),
        }

        let found = pprust::token_to_string(&self.token);
        let msg = format!("expected unsuffixed literal or identifier, found `{}`", found);
        Err(self.diagnostic().struct_span_err(self.token.span, &msg))
    }
}
<|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/. */

//! Module only available when pathfinder is activated

use api::{DeviceIntPoint, DeviceIntSize, DevicePixel, FontRenderMode, FontKey, FontTemplate, NativeFontHandle};
use euclid::{TypedPoint2D, TypedSize2D, TypedVector2D};
use pathfinder_font_renderer;
use pathfinder_partitioner::mesh::Mesh as PathfinderMesh;
use pathfinder_path_utils::cubic_to_quadratic::CubicToQuadraticTransformer;
use render_task::{RenderTask, RenderTaskTree, RenderTaskCache, RenderTaskCacheKey, RenderTaskCacheEntryHandle,
                  RenderTaskCacheKeyKind, RenderTaskId, RenderTaskLocation};
use resource_cache::CacheItem;
use std::ops::Deref;
use std::sync::{Arc, Mutex, MutexGuard};
use tiling::{RenderTargetKind, SpecialRenderPasses};
use glyph_rasterizer::AddFont;
use internal_types::ResourceCacheError;
use glyph_cache::{GlyphCache, GlyphCacheEntry, CachedGlyphInfo};
use std::collections::hash_map::Entry;
use std::f32;
use glyph_rasterizer::{FontInstance, GlyphRasterizer, GlyphFormat, GlyphKey, FontContexts};
use texture_cache::TextureCache;
use gpu_cache::GpuCache;
use profiler::TextureCacheProfileCounters;

/// Should match macOS 10.13 High Sierra.
///
/// We multiply by sqrt(2) to compensate for the fact that dilation amounts are relative to the
/// pixel square on macOS and relative to the vertex normal in Pathfinder.
const STEM_DARKENING_FACTOR_X: f32 = 0.0121 * f32::consts::SQRT_2;
const STEM_DARKENING_FACTOR_Y: f32 = 0.0121 * 1.25 * f32::consts::SQRT_2;

/// Likewise, should match macOS 10.13 High Sierra.
const MAX_STEM_DARKENING_AMOUNT: f32 = 0.3 * f32::consts::SQRT_2;

const CUBIC_TO_QUADRATIC_APPROX_TOLERANCE: f32 = 0.01;

type PathfinderFontContext = pathfinder_font_renderer::FontContext<FontKey>;

impl AddFont for PathfinderFontContext {
    fn add_font(&mut self, font_key: &FontKey, template: &FontTemplate) {
        match *template {
            FontTemplate::Raw(ref bytes, index) => {
                drop(self.add_font_from_memory(&font_key, bytes.clone(), index))
            }
            FontTemplate::Native(ref native_font_handle) => {
                drop(self.add_native_font(&font_key, NativeFontHandleWrapper(native_font_handle)))
            }
        }
    }
}

pub(in super) fn create_pathfinder_font_context()
-> Result<Box<ThreadSafePathfinderFontContext>, ResourceCacheError>
{
    match PathfinderFontContext::new() {
        Ok(context) => Ok(Box::new(ThreadSafePathfinderFontContext(Mutex::new(context)))),
        Err(_) => {
            let msg = "Failed to create the Pathfinder font context!".to_owned();
            Err(ResourceCacheError::new(msg))
        }
    }
}

pub struct ThreadSafePathfinderFontContext(Mutex<PathfinderFontContext>);

impl Deref for ThreadSafePathfinderFontContext {
    type Target = Mutex<PathfinderFontContext>;

    fn deref(&self) -> &Mutex<PathfinderFontContext> {
        &self.0
    }
}

/// PathfinderFontContext can contain a *mut IDWriteFactory.
/// However, since we know that it is wrapped in a Mutex, it is safe
/// to assume that this struct is thread-safe
unsafe impl Send for ThreadSafePathfinderFontContext {}
unsafe impl Sync for ThreadSafePathfinderFontContext { }

impl GlyphRasterizer {

    pub(in super) fn add_font_to_pathfinder(&mut self, font_key: &FontKey, template: &FontTemplate) {
        let font_contexts = Arc::clone(&self.font_contexts);
        debug!("add_font_to_pathfinder({:?})", font_key);
        font_contexts.lock_pathfinder_context().add_font(&font_key, &template);
    }

    pub fn get_cache_item_for_glyph(
        &self,
        glyph_key: &GlyphKey,
        font: &FontInstance,
        glyph_cache: &GlyphCache,
        texture_cache: &TextureCache,
        render_task_cache: &RenderTaskCache)
    -> Option<(CacheItem, GlyphFormat)>
    {
        let glyph_key_cache = glyph_cache.get_glyph_key_cache_for_font(font);
        let render_task_cache_key = match *glyph_key_cache.get(glyph_key) {
            GlyphCacheEntry::Cached(ref cached_glyph) => {
                (*cached_glyph).render_task_cache_key.clone()
            }
            GlyphCacheEntry::Blank => return None,
            GlyphCacheEntry::Pending => {
                panic!("GlyphRasterizer::get_cache_item_for_glyph(): Glyph should have been \
                        cached by now!")
            }
        };
        let cache_item = render_task_cache.get_cache_item_for_render_task(texture_cache,
                                                                          &render_task_cache_key);
        Some((cache_item, font.get_glyph_format()))
    }

    pub(in super) fn request_glyph_from_pathfinder_if_necessary(
        &mut self,
        glyph_key: &GlyphKey,
        font: &FontInstance,
        cached_glyph_info: CachedGlyphInfo,
        texture_cache: &mut TextureCache,
        gpu_cache: &mut GpuCache,
        render_task_cache: &mut RenderTaskCache,
        render_task_tree: &mut RenderTaskTree,
        render_passes: &mut SpecialRenderPasses)
    -> Result<(RenderTaskCacheEntryHandle,GlyphFormat), ()>
    {
        let mut pathfinder_font_context = self.font_contexts.lock_pathfinder_context();
        let render_task_cache_key = cached_glyph_info.render_task_cache_key;
        let (glyph_origin, glyph_size) = (cached_glyph_info.origin, render_task_cache_key.size);
        let user_data = [glyph_origin.x as f32, (glyph_origin.y - glyph_size.height) as f32, 1.0];
        let handle = try!(render_task_cache.request_render_task(render_task_cache_key,
                                                                texture_cache,
                                                                gpu_cache,
                                                                render_task_tree,
                                                                Some(user_data),
                                                                false,
                                                                |render_tasks| {
            // TODO(pcwalton): Non-subpixel font render mode.
            request_render_task_from_pathfinder(glyph_key,
                                                font,
                                                &glyph_origin,
                                                &glyph_size,
                                                &mut *pathfinder_font_context,
                                                font.render_mode,
                                                render_tasks,
                                                render_passes)
        }));
        Ok((handle, font.get_glyph_format()))
    }

    pub fn request_glyphs(
        &mut self,
        glyph_cache: &mut GlyphCache,
        font: FontInstance,
        glyph_keys: &[GlyphKey],
        texture_cache: &mut TextureCache,
        gpu_cache: &mut GpuCache,
        render_task_cache: &mut RenderTaskCache,
        render_task_tree: &mut RenderTaskTree,
        render_passes: &mut SpecialRenderPasses,
    ) {
        debug_assert!(self.font_contexts.lock_shared_context().has_font(&font.font_key));

        let glyph_key_cache = glyph_cache.get_glyph_key_cache_for_font_mut(font.clone());

        // select glyphs that have not been requested yet.
        for glyph_key in glyph_keys {
            let mut cached_glyph_info = None;
            match glyph_key_cache.entry(glyph_key.clone()) {
                Entry::Occupied(mut entry) => {
                    let value = entry.into_mut();
                    match *value {
                        GlyphCacheEntry::Cached(ref glyph_info) => {
                            cached_glyph_info = Some(glyph_info.clone())
                        }
                        GlyphCacheEntry::Blank | GlyphCacheEntry::Pending => {}
                    }
                }
                Entry::Vacant(_) => {}
            }

            let cached_glyph_info = match cached_glyph_info {
                Some(cached_glyph_info) => cached_glyph_info,
                None => {
                    let mut pathfinder_font_context = self.font_contexts.lock_pathfinder_context();

                    let pathfinder_font_instance = pathfinder_font_renderer::FontInstance {
                        font_key: font.font_key.clone(),
                        size: font.size,
                    };

                    // TODO: pathfinder will need to support 2D subpixel offset
                    let pathfinder_subpixel_offset =
                        pathfinder_font_renderer::SubpixelOffset(glyph_key.subpixel_offset.0 as u8);
                    let pathfinder_glyph_key =
                        pathfinder_font_renderer::GlyphKey::new(glyph_key.index,
                                                                pathfinder_subpixel_offset);
                    let glyph_dimensions =
                        match pathfinder_font_context.glyph_dimensions(&pathfinder_font_instance,
                                                                       &pathfinder_glyph_key,
                                                                       false) {
                            Ok(glyph_dimensions) => glyph_dimensions,
                            Err(_) => continue,
                        };

                    let cached_glyph_info = CachedGlyphInfo {
                        render_task_cache_key: RenderTaskCacheKey {
                            size: TypedSize2D::from_untyped(&glyph_dimensions.size.to_i32()),
                            kind: RenderTaskCacheKeyKind::Glyph(self.next_gpu_glyph_cache_key),
                        },
                        format: font.get_glyph_format(),
                        origin: DeviceIntPoint::new(glyph_dimensions.origin.x as i32,
                                                    -glyph_dimensions.origin.y as i32),
                    };
                    self.next_gpu_glyph_cache_key.0 += 1;
                    cached_glyph_info
                }
            };

            let handle =
                match self.request_glyph_from_pathfinder_if_necessary(glyph_key,
                                                                      &font,
                                                                      cached_glyph_info.clone(),
                                                                      texture_cache,
                                                                      gpu_cache,
                                                                      render_task_cache,
                                                                      render_task_tree,
                                                                      render_passes) {
                    Ok(_) => GlyphCacheEntry::Cached(cached_glyph_info),
                    Err(_) => GlyphCacheEntry::Blank,
                };

            glyph_key_cache.insert(glyph_key.clone(), handle);
        }
    }

    pub fn resolve_glyphs(
        &mut self,
        _: &mut GlyphCache,
        _: &mut TextureCache,
        _: &mut GpuCache,
        _: &mut RenderTaskCache,
        _: &mut RenderTaskTree,
        _: &mut TextureCacheProfileCounters,
    ) {
        self.remove_dead_fonts();
    }
}

impl FontContexts {
    pub fn lock_pathfinder_context(&self) -> MutexGuard<PathfinderFontContext> {
        self.pathfinder_context.lock().unwrap()
    }
}

fn compute_embolden_amount(ppem: f32) -> TypedVector2D<f32, DevicePixel> {
    TypedVector2D::new(f32::min(ppem * STEM_DARKENING_FACTOR_X, MAX_STEM_DARKENING_AMOUNT),
                       f32::min(ppem * STEM_DARKENING_FACTOR_Y, MAX_STEM_DARKENING_AMOUNT))
}

fn request_render_task_from_pathfinder(glyph_key: &GlyphKey,
                                       font: &FontInstance,
                                       glyph_origin: &DeviceIntPoint,
                                       glyph_size: &DeviceIntSize,
                                       font_context: &mut PathfinderFontContext,
                                       render_mode: FontRenderMode,
                                       render_tasks: &mut RenderTaskTree,
                                       render_passes: &mut SpecialRenderPasses)
                                       -> Result<RenderTaskId, ()> {
    let pathfinder_font_instance = pathfinder_font_renderer::FontInstance {
        font_key: font.font_key.clone(),
        size: font.size,
    };

    // TODO: pathfinder will need to support 2D subpixel offset
    let pathfinder_subpixel_offset =
        pathfinder_font_renderer::SubpixelOffset(glyph_key.subpixel_offset.0 as u8);
    let glyph_subpixel_offset: f64 = glyph_key.subpixel_offset.0.into();
    let pathfinder_glyph_key = pathfinder_font_renderer::GlyphKey::new(glyph_key.index,
                                                                       pathfinder_subpixel_offset);

    // TODO(pcwalton): Fall back to CPU rendering if Pathfinder fails to collect the outline.
    let mut mesh = PathfinderMesh::new();
    let outline = try!(font_context.glyph_outline(&pathfinder_font_instance,
                                                  &pathfinder_glyph_key));
    let tolerance = CUBIC_TO_QUADRATIC_APPROX_TOLERANCE;
    mesh.push_stencil_segments(CubicToQuadraticTransformer::new(outline.iter(), tolerance));
    mesh.push_stencil_normals(CubicToQuadraticTransformer::new(outline.iter(), tolerance));

    // FIXME(pcwalton): Support vertical subpixel offsets.
    // FIXME(pcwalton): Embolden amount should be 0 on macOS if "Use LCD font
    // smoothing" is unchecked in System Preferences.

    let subpixel_offset = TypedPoint2D::new(glyph_subpixel_offset as f32, 0.0);
    let embolden_amount = compute_embolden_amount(font.size.to_f32_px());

    let location = RenderTaskLocation::Dynamic(None, Some(*glyph_size));
    let glyph_render_task = RenderTask::new_glyph(location,
                                                  mesh,
                                                  &glyph_origin,
                                                  &subpixel_offset,
                                                  font.render_mode,
                                                  &embolden_amount);

    let root_task_id = render_tasks.add(glyph_render_task);
    let render_pass = match render_mode {
        FontRenderMode::Mono | FontRenderMode::Alpha => &mut render_passes.alpha_glyph_pass,
        FontRenderMode::Subpixel => &mut render_passes.color_glyph_pass,
    };
    render_pass.add_render_task(root_task_id, *glyph_size, RenderTargetKind::Color);

    Ok(root_task_id)
}

pub struct NativeFontHandleWrapper<'a>(pub &'a NativeFontHandle);
<commit_msg>Write `Blank` into the glyph key cache if glyph dimensions can't be fetched from the font.<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/. */

//! Module only available when pathfinder is activated

use api::{DeviceIntPoint, DeviceIntSize, DevicePixel, FontRenderMode, FontKey, FontTemplate, NativeFontHandle};
use euclid::{TypedPoint2D, TypedSize2D, TypedVector2D};
use pathfinder_font_renderer;
use pathfinder_partitioner::mesh::Mesh as PathfinderMesh;
use pathfinder_path_utils::cubic_to_quadratic::CubicToQuadraticTransformer;
use render_task::{RenderTask, RenderTaskTree, RenderTaskCache, RenderTaskCacheKey, RenderTaskCacheEntryHandle,
                  RenderTaskCacheKeyKind, RenderTaskId, RenderTaskLocation};
use resource_cache::CacheItem;
use std::ops::Deref;
use std::sync::{Arc, Mutex, MutexGuard};
use tiling::{RenderTargetKind, SpecialRenderPasses};
use glyph_rasterizer::AddFont;
use internal_types::ResourceCacheError;
use glyph_cache::{GlyphCache, GlyphCacheEntry, CachedGlyphInfo};
use std::collections::hash_map::Entry;
use std::f32;
use glyph_rasterizer::{FontInstance, GlyphRasterizer, GlyphFormat, GlyphKey, FontContexts};
use texture_cache::TextureCache;
use gpu_cache::GpuCache;
use profiler::TextureCacheProfileCounters;

/// Should match macOS 10.13 High Sierra.
///
/// We multiply by sqrt(2) to compensate for the fact that dilation amounts are relative to the
/// pixel square on macOS and relative to the vertex normal in Pathfinder.
const STEM_DARKENING_FACTOR_X: f32 = 0.0121 * f32::consts::SQRT_2;
const STEM_DARKENING_FACTOR_Y: f32 = 0.0121 * 1.25 * f32::consts::SQRT_2;

/// Likewise, should match macOS 10.13 High Sierra.
const MAX_STEM_DARKENING_AMOUNT: f32 = 0.3 * f32::consts::SQRT_2;

const CUBIC_TO_QUADRATIC_APPROX_TOLERANCE: f32 = 0.01;

type PathfinderFontContext = pathfinder_font_renderer::FontContext<FontKey>;

impl AddFont for PathfinderFontContext {
    fn add_font(&mut self, font_key: &FontKey, template: &FontTemplate) {
        match *template {
            FontTemplate::Raw(ref bytes, index) => {
                drop(self.add_font_from_memory(&font_key, bytes.clone(), index))
            }
            FontTemplate::Native(ref native_font_handle) => {
                drop(self.add_native_font(&font_key, NativeFontHandleWrapper(native_font_handle)))
            }
        }
    }
}

pub(in super) fn create_pathfinder_font_context()
-> Result<Box<ThreadSafePathfinderFontContext>, ResourceCacheError>
{
    match PathfinderFontContext::new() {
        Ok(context) => Ok(Box::new(ThreadSafePathfinderFontContext(Mutex::new(context)))),
        Err(_) => {
            let msg = "Failed to create the Pathfinder font context!".to_owned();
            Err(ResourceCacheError::new(msg))
        }
    }
}

pub struct ThreadSafePathfinderFontContext(Mutex<PathfinderFontContext>);

impl Deref for ThreadSafePathfinderFontContext {
    type Target = Mutex<PathfinderFontContext>;

    fn deref(&self) -> &Mutex<PathfinderFontContext> {
        &self.0
    }
}

/// PathfinderFontContext can contain a *mut IDWriteFactory.
/// However, since we know that it is wrapped in a Mutex, it is safe
/// to assume that this struct is thread-safe
unsafe impl Send for ThreadSafePathfinderFontContext {}
unsafe impl Sync for ThreadSafePathfinderFontContext { }

impl GlyphRasterizer {
    pub(in super) fn add_font_to_pathfinder(&mut self, font_key: &FontKey, template: &FontTemplate) {
        let font_contexts = Arc::clone(&self.font_contexts);
        debug!("add_font_to_pathfinder({:?})", font_key);
        font_contexts.lock_pathfinder_context().add_font(&font_key, &template);
    }

    pub fn get_cache_item_for_glyph(
        &self,
        glyph_key: &GlyphKey,
        font: &FontInstance,
        glyph_cache: &GlyphCache,
        texture_cache: &TextureCache,
        render_task_cache: &RenderTaskCache)
    -> Option<(CacheItem, GlyphFormat)>
    {
        let glyph_key_cache = glyph_cache.get_glyph_key_cache_for_font(font);
        let render_task_cache_key = match *glyph_key_cache.get(glyph_key) {
            GlyphCacheEntry::Cached(ref cached_glyph) => {
                (*cached_glyph).render_task_cache_key.clone()
            }
            GlyphCacheEntry::Blank => return None,
            GlyphCacheEntry::Pending => {
                panic!("GlyphRasterizer::get_cache_item_for_glyph(): Glyph should have been \
                        cached by now!")
            }
        };
        let cache_item = render_task_cache.get_cache_item_for_render_task(texture_cache,
                                                                          &render_task_cache_key);
        Some((cache_item, font.get_glyph_format()))
    }

    pub(in super) fn request_glyph_from_pathfinder_if_necessary(
        &mut self,
        glyph_key: &GlyphKey,
        font: &FontInstance,
        cached_glyph_info: CachedGlyphInfo,
        texture_cache: &mut TextureCache,
        gpu_cache: &mut GpuCache,
        render_task_cache: &mut RenderTaskCache,
        render_task_tree: &mut RenderTaskTree,
        render_passes: &mut SpecialRenderPasses)
    -> Result<(RenderTaskCacheEntryHandle,GlyphFormat), ()>
    {
        let mut pathfinder_font_context = self.font_contexts.lock_pathfinder_context();
        let render_task_cache_key = cached_glyph_info.render_task_cache_key;
        let (glyph_origin, glyph_size) = (cached_glyph_info.origin, render_task_cache_key.size);
        let user_data = [glyph_origin.x as f32, (glyph_origin.y - glyph_size.height) as f32, 1.0];
        let handle = try!(render_task_cache.request_render_task(render_task_cache_key,
                                                                texture_cache,
                                                                gpu_cache,
                                                                render_task_tree,
                                                                Some(user_data),
                                                                false,
                                                                |render_tasks| {
            // TODO(pcwalton): Non-subpixel font render mode.
            request_render_task_from_pathfinder(glyph_key,
                                                font,
                                                &glyph_origin,
                                                &glyph_size,
                                                &mut *pathfinder_font_context,
                                                font.render_mode,
                                                render_tasks,
                                                render_passes)
        }));
        Ok((handle, font.get_glyph_format()))
    }

    pub fn request_glyphs(
        &mut self,
        glyph_cache: &mut GlyphCache,
        font: FontInstance,
        glyph_keys: &[GlyphKey],
        texture_cache: &mut TextureCache,
        gpu_cache: &mut GpuCache,
        render_task_cache: &mut RenderTaskCache,
        render_task_tree: &mut RenderTaskTree,
        render_passes: &mut SpecialRenderPasses,
    ) {
        debug_assert!(self.font_contexts.lock_shared_context().has_font(&font.font_key));

        let glyph_key_cache = glyph_cache.get_glyph_key_cache_for_font_mut(font.clone());

        // select glyphs that have not been requested yet.
        for glyph_key in glyph_keys {
            let mut cached_glyph_info = None;
            match glyph_key_cache.entry(glyph_key.clone()) {
                Entry::Occupied(mut entry) => {
                    let value = entry.into_mut();
                    match *value {
                        GlyphCacheEntry::Cached(ref glyph_info) => {
                            cached_glyph_info = Some(glyph_info.clone())
                        }
                        GlyphCacheEntry::Blank | GlyphCacheEntry::Pending => {}
                    }
                }
                Entry::Vacant(_) => {}
            }

            if cached_glyph_info.is_none() {
                let mut pathfinder_font_context = self.font_contexts.lock_pathfinder_context();

                let pathfinder_font_instance = pathfinder_font_renderer::FontInstance {
                    font_key: font.font_key.clone(),
                    size: font.size,
                };

                // TODO: pathfinder will need to support 2D subpixel offset
                let pathfinder_subpixel_offset =
                    pathfinder_font_renderer::SubpixelOffset(glyph_key.subpixel_offset.0 as u8);
                let pathfinder_glyph_key =
                    pathfinder_font_renderer::GlyphKey::new(glyph_key.index,
                                                            pathfinder_subpixel_offset);

                if let Ok(glyph_dimensions) =
                        pathfinder_font_context.glyph_dimensions(&pathfinder_font_instance,
                                                                 &pathfinder_glyph_key,
                                                                 false) {
                    let render_task_cache_key = RenderTaskCacheKey {
                        size: TypedSize2D::from_untyped(&glyph_dimensions.size.to_i32()),
                        kind: RenderTaskCacheKeyKind::Glyph(self.next_gpu_glyph_cache_key),
                    };
                    cached_glyph_info = Some(CachedGlyphInfo {
                        render_task_cache_key,
                        format: font.get_glyph_format(),
                        origin: DeviceIntPoint::new(glyph_dimensions.origin.x as i32,
                                                    -glyph_dimensions.origin.y as i32),
                    });
                    self.next_gpu_glyph_cache_key.0 += 1;
                }
            }

            let handle = match cached_glyph_info {
                Some(glyph_info) => {
                    match self.request_glyph_from_pathfinder_if_necessary(glyph_key,
                                                                          &font,
                                                                          glyph_info.clone(),
                                                                          texture_cache,
                                                                          gpu_cache,
                                                                          render_task_cache,
                                                                          render_task_tree,
                                                                          render_passes) {
                        Ok(_) => GlyphCacheEntry::Cached(glyph_info),
                        Err(_) => GlyphCacheEntry::Blank,
                    }
                }
                None => GlyphCacheEntry::Blank,
            };

            glyph_key_cache.insert(glyph_key.clone(), handle);
        }
    }

    pub fn resolve_glyphs(
        &mut self,
        _: &mut GlyphCache,
        _: &mut TextureCache,
        _: &mut GpuCache,
        _: &mut RenderTaskCache,
        _: &mut RenderTaskTree,
        _: &mut TextureCacheProfileCounters,
    ) {
        self.remove_dead_fonts();
    }
}

impl FontContexts {
    pub fn lock_pathfinder_context(&self) -> MutexGuard<PathfinderFontContext> {
        self.pathfinder_context.lock().unwrap()
    }
}

fn compute_embolden_amount(ppem: f32) -> TypedVector2D<f32, DevicePixel> {
    TypedVector2D::new(f32::min(ppem * STEM_DARKENING_FACTOR_X, MAX_STEM_DARKENING_AMOUNT),
                       f32::min(ppem * STEM_DARKENING_FACTOR_Y, MAX_STEM_DARKENING_AMOUNT))
}

fn request_render_task_from_pathfinder(glyph_key: &GlyphKey,
                                       font: &FontInstance,
                                       glyph_origin: &DeviceIntPoint,
                                       glyph_size: &DeviceIntSize,
                                       font_context: &mut PathfinderFontContext,
                                       render_mode: FontRenderMode,
                                       render_tasks: &mut RenderTaskTree,
                                       render_passes: &mut SpecialRenderPasses)
                                       -> Result<RenderTaskId, ()> {
    let pathfinder_font_instance = pathfinder_font_renderer::FontInstance {
        font_key: font.font_key.clone(),
        size: font.size,
    };

    // TODO: pathfinder will need to support 2D subpixel offset
    let pathfinder_subpixel_offset =
        pathfinder_font_renderer::SubpixelOffset(glyph_key.subpixel_offset.0 as u8);
    let glyph_subpixel_offset: f64 = glyph_key.subpixel_offset.0.into();
    let pathfinder_glyph_key = pathfinder_font_renderer::GlyphKey::new(glyph_key.index,
                                                                       pathfinder_subpixel_offset);

    // TODO(pcwalton): Fall back to CPU rendering if Pathfinder fails to collect the outline.
    let mut mesh = PathfinderMesh::new();
    let outline = try!(font_context.glyph_outline(&pathfinder_font_instance,
                                                  &pathfinder_glyph_key));
    let tolerance = CUBIC_TO_QUADRATIC_APPROX_TOLERANCE;
    mesh.push_stencil_segments(CubicToQuadraticTransformer::new(outline.iter(), tolerance));
    mesh.push_stencil_normals(CubicToQuadraticTransformer::new(outline.iter(), tolerance));

    // FIXME(pcwalton): Support vertical subpixel offsets.
    // FIXME(pcwalton): Embolden amount should be 0 on macOS if "Use LCD font
    // smoothing" is unchecked in System Preferences.

    let subpixel_offset = TypedPoint2D::new(glyph_subpixel_offset as f32, 0.0);
    let embolden_amount = compute_embolden_amount(font.size.to_f32_px());

    let location = RenderTaskLocation::Dynamic(None, Some(*glyph_size));
    let glyph_render_task = RenderTask::new_glyph(location,
                                                  mesh,
                                                  &glyph_origin,
                                                  &subpixel_offset,
                                                  font.render_mode,
                                                  &embolden_amount);

    let root_task_id = render_tasks.add(glyph_render_task);
    let render_pass = match render_mode {
        FontRenderMode::Mono | FontRenderMode::Alpha => &mut render_passes.alpha_glyph_pass,
        FontRenderMode::Subpixel => &mut render_passes.color_glyph_pass,
    };
    render_pass.add_render_task(root_task_id, *glyph_size, RenderTargetKind::Color);

    Ok(root_task_id)
}

pub struct NativeFontHandleWrapper<'a>(pub &'a NativeFontHandle);
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

#[macro_use]
extern crate criterion;
use criterion::Criterion;

use rand::Rng;

extern crate arrow;

use arrow::compute::take;
use arrow::datatypes::*;
use arrow::util::test_util::seedable_rng;
use arrow::{array::*, util::bench_util::*};

fn create_random_index(size: usize, null_density: f32) -> UInt32Array {
    let mut rng = seedable_rng();
    let mut builder = UInt32Builder::new(size);
    for _ in 0..size {
        if rng.gen::<f32>() < null_density {
            let value = rng.gen_range::<u32, _, _>(0u32, size as u32);
            builder.append_value(value).unwrap();
        } else {
            builder.append_null().unwrap()
        }
    }
    builder.finish()
}

fn bench_take(values: &dyn Array, indices: &UInt32Array) {
    criterion::black_box(take(values, &indices, None).unwrap());
}

fn add_benchmark(c: &mut Criterion) {
    let values = create_primitive_array::<Int32Type>(512, 0.0);
    let indices = create_random_index(512, 0.0);
    c.bench_function("take i32 512", |b| b.iter(|| bench_take(&values, &indices)));
    let values = create_primitive_array::<Int32Type>(1024, 0.0);
    let indices = create_random_index(1024, 0.0);
    c.bench_function("take i32 1024", |b| {
        b.iter(|| bench_take(&values, &indices))
    });

    let indices = create_random_index(512, 0.5);
    c.bench_function("take i32 nulls 512", |b| {
        b.iter(|| bench_take(&values, &indices))
    });
    let values = create_primitive_array::<Int32Type>(1024, 0.0);
    let indices = create_random_index(1024, 0.5);
    c.bench_function("take i32 nulls 1024", |b| {
        b.iter(|| bench_take(&values, &indices))
    });

    let values = create_boolean_array(512, 0.0, 0.5);
    let indices = create_random_index(512, 0.0);
    c.bench_function("take bool 512", |b| {
        b.iter(|| bench_take(&values, &indices))
    });
    let values = create_boolean_array(1024, 0.0, 0.5);
    let indices = create_random_index(1024, 0.0);
    c.bench_function("take bool 1024", |b| {
        b.iter(|| bench_take(&values, &indices))
    });

    let values = create_boolean_array(512, 0.0, 0.5);
    let indices = create_random_index(512, 0.5);
    c.bench_function("take bool nulls 512", |b| {
        b.iter(|| bench_take(&values, &indices))
    });
    let values = create_boolean_array(1024, 0.0, 0.5);
    let indices = create_random_index(1024, 0.5);
    c.bench_function("take bool nulls 1024", |b| {
        b.iter(|| bench_take(&values, &indices))
    });

    let values = create_string_array(512, 0.0);
    let indices = create_random_index(512, 0.0);
    c.bench_function("take str 512", |b| b.iter(|| bench_take(&values, &indices)));

    let values = create_string_array(1024, 0.0);
    let indices = create_random_index(1024, 0.0);
    c.bench_function("take str 1024", |b| {
        b.iter(|| bench_take(&values, &indices))
    });

    let values = create_string_array(512, 0.0);
    let indices = create_random_index(512, 0.5);
    c.bench_function("take str null indices 512", |b| {
        b.iter(|| bench_take(&values, &indices))
    });

    let values = create_string_array(1024, 0.0);
    let indices = create_random_index(1024, 0.5);
    c.bench_function("take str null indices 1024", |b| {
        b.iter(|| bench_take(&values, &indices))
    });

    let values = create_string_array(1024, 0.5);

    let indices = create_random_index(1024, 0.0);
    c.bench_function("take str null values 1024", |b| {
        b.iter(|| bench_take(&values, &indices))
    });

    let values = create_string_array(1024, 0.5);
    let indices = create_random_index(1024, 0.5);
    c.bench_function("take str null values null indices 1024", |b| {
        b.iter(|| bench_take(&values, &indices))
    });
}

criterion_group!(benches, add_benchmark);
criterion_main!(benches);
<commit_msg>ARROW-11494: [Rust] fix take bench<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

#[macro_use]
extern crate criterion;
use criterion::Criterion;

use rand::Rng;

extern crate arrow;

use arrow::compute::take;
use arrow::datatypes::*;
use arrow::util::test_util::seedable_rng;
use arrow::{array::*, util::bench_util::*};

fn create_random_index(size: usize, null_density: f32) -> UInt32Array {
    let mut rng = seedable_rng();
    let mut builder = UInt32Builder::new(size);
    for _ in 0..size {
        if rng.gen::<f32>() < null_density {
            builder.append_null().unwrap()
        } else {
            let value = rng.gen_range::<u32, _, _>(0u32, size as u32);
            builder.append_value(value).unwrap();
        }
    }
    builder.finish()
}

fn bench_take(values: &dyn Array, indices: &UInt32Array) {
    criterion::black_box(take(values, &indices, None).unwrap());
}

fn add_benchmark(c: &mut Criterion) {
    let values = create_primitive_array::<Int32Type>(512, 0.0);
    let indices = create_random_index(512, 0.0);
    c.bench_function("take i32 512", |b| b.iter(|| bench_take(&values, &indices)));
    let values = create_primitive_array::<Int32Type>(1024, 0.0);
    let indices = create_random_index(1024, 0.0);
    c.bench_function("take i32 1024", |b| {
        b.iter(|| bench_take(&values, &indices))
    });

    let indices = create_random_index(512, 0.5);
    c.bench_function("take i32 nulls 512", |b| {
        b.iter(|| bench_take(&values, &indices))
    });
    let values = create_primitive_array::<Int32Type>(1024, 0.0);
    let indices = create_random_index(1024, 0.5);
    c.bench_function("take i32 nulls 1024", |b| {
        b.iter(|| bench_take(&values, &indices))
    });

    let values = create_boolean_array(512, 0.0, 0.5);
    let indices = create_random_index(512, 0.0);
    c.bench_function("take bool 512", |b| {
        b.iter(|| bench_take(&values, &indices))
    });
    let values = create_boolean_array(1024, 0.0, 0.5);
    let indices = create_random_index(1024, 0.0);
    c.bench_function("take bool 1024", |b| {
        b.iter(|| bench_take(&values, &indices))
    });

    let values = create_boolean_array(512, 0.0, 0.5);
    let indices = create_random_index(512, 0.5);
    c.bench_function("take bool nulls 512", |b| {
        b.iter(|| bench_take(&values, &indices))
    });
    let values = create_boolean_array(1024, 0.0, 0.5);
    let indices = create_random_index(1024, 0.5);
    c.bench_function("take bool nulls 1024", |b| {
        b.iter(|| bench_take(&values, &indices))
    });

    let values = create_string_array(512, 0.0);
    let indices = create_random_index(512, 0.0);
    c.bench_function("take str 512", |b| b.iter(|| bench_take(&values, &indices)));

    let values = create_string_array(1024, 0.0);
    let indices = create_random_index(1024, 0.0);
    c.bench_function("take str 1024", |b| {
        b.iter(|| bench_take(&values, &indices))
    });

    let values = create_string_array(512, 0.0);
    let indices = create_random_index(512, 0.5);
    c.bench_function("take str null indices 512", |b| {
        b.iter(|| bench_take(&values, &indices))
    });

    let values = create_string_array(1024, 0.0);
    let indices = create_random_index(1024, 0.5);
    c.bench_function("take str null indices 1024", |b| {
        b.iter(|| bench_take(&values, &indices))
    });

    let values = create_string_array(1024, 0.5);

    let indices = create_random_index(1024, 0.0);
    c.bench_function("take str null values 1024", |b| {
        b.iter(|| bench_take(&values, &indices))
    });

    let values = create_string_array(1024, 0.5);
    let indices = create_random_index(1024, 0.5);
    c.bench_function("take str null values null indices 1024", |b| {
        b.iter(|| bench_take(&values, &indices))
    });
}

criterion_group!(benches, add_benchmark);
criterion_main!(benches);
<|endoftext|>


<commit_before>//! The forwarder module shall act as wrapper for the ffi mangled lib.rs
//! calls, which shall be very thin and spare there, but extensive here
//! to prepare clean calls to adbfflutter.
use crate::{
    common::paths::SearchPath,
    ctrl::{ForwardNetMsg, UiUpdateMsg},
    data::{collection::Collection, ipc::IPC},
    net::subs::peer_representation,
    shared,
};
use async_std::task;
use crossbeam::{sync::WaitGroup, unbounded};
use std::{
    sync::{mpsc::channel, Arc, Mutex},
    thread,
};

/// just return the number of audio files found for now
pub fn ffi_file_count_good(input_path: Vec<String>) -> u32 {
    // prepare data
    let cleaned_paths = SearchPath::new(&input_path);
    let search_path = Arc::new(Mutex::new(cleaned_paths));

    let (tx, _rx) = channel::<UiUpdateMsg>();
    let synced_to_ui_messages = Arc::new(Mutex::new(tx.clone()));
    let has_ui = false;

    // set up data
    let collection_protected = Arc::new(Mutex::new(Collection::new()));
    let output_data_return_handle = shared::collection_search(
        collection_protected,
        search_path,
        synced_to_ui_messages,
        has_ui,
    );

    // scope and block trickery for lifetime and mutability
    output_data_return_handle.nr_found_songs
}

/// return the peer hash for testing yet
pub async fn ffi_new_peer() -> u64 {
    //
    let dummy_wait_net_thread = WaitGroup::new();
    let (ui_sender, reactor) = channel::<UiUpdateMsg>();
    let (_, dummy_ipc_receive) = unbounded::<IPC>();

    // todo: make it a lazy static as RUNTIME, to also hold the same IP, otherwise it will
    //       always change it's ip!
    // initiate a thread (which will be ... (todo: lazy_static maybe later, and keep it running)
    // which handles net communication
    let single_shot_net_thread = thread::Builder::new()
        .name("app_net".into())
        .spawn(move || {
            task::block_on(async move {
                let _ =
                    shared::net_search(dummy_wait_net_thread, Some(ui_sender), dummy_ipc_receive)
                        .await;
            });
        })
        .unwrap();

    // very interesting, the compiler is awesome!!
    let out;

    // loop over fixme: (very cheap version here, that could be done more elegantly)
    loop {
        if let Ok(reaction) = reactor.try_recv() {
            match reaction {
                UiUpdateMsg::CollectionUpdate(_, _) => {}
                UiUpdateMsg::NetUpdate(net_message) => {
                    match net_message {
                        ForwardNetMsg::Add(peer) => {
                            // yet only id is interesting
                            out = peer_representation::peer_to_hash(&peer.id);
                            break;
                        }
                        ForwardNetMsg::Delete(_peer_id) => {}
                        ForwardNetMsg::Stats(_) => {}
                    }
                }
                UiUpdateMsg::PeerSearchFinished(_peer_id, _data) => {}
                UiUpdateMsg::StopUI => {}
            }
        }
    }
    // kill this big thread / fixme: very inefficent yet
    drop(single_shot_net_thread);
    out
}
<commit_msg>[fix] documentation and try Release keyword build with github<commit_after>//! The forwarder module shall act as wrapper for the ffi mangled lib.rs
//! calls, which shall be very thin and spare there, but extensive here
//! to prepare clean calls to adbfflutter.
use crate::{
    common::paths::SearchPath,
    ctrl::{ForwardNetMsg, UiUpdateMsg},
    data::{collection::Collection, ipc::IPC},
    net::subs::peer_representation,
    shared,
};
use async_std::task;
use crossbeam::{sync::WaitGroup, unbounded};
use std::{
    sync::{mpsc::channel, Arc, Mutex},
    thread,
};

/// just return the number of audio files found for now
pub fn ffi_file_count_good(input_path: Vec<String>) -> u32 {
    // prepare data
    let cleaned_paths = SearchPath::new(&input_path);
    let search_path = Arc::new(Mutex::new(cleaned_paths));

    let (tx, _rx) = channel::<UiUpdateMsg>();
    let synced_to_ui_messages = Arc::new(Mutex::new(tx.clone()));
    let has_ui = false;

    // set up data
    let collection_protected = Arc::new(Mutex::new(Collection::new()));
    let output_data_return_handle = shared::collection_search(
        collection_protected,
        search_path,
        synced_to_ui_messages,
        has_ui,
    );

    // scope and block trickery for lifetime and mutability
    output_data_return_handle.nr_found_songs
}

/// return the peer hash for testing yet
pub async fn ffi_new_peer() -> u64 {
    //
    let dummy_wait_net_thread = WaitGroup::new();
    let (ui_sender, reactor) = channel::<UiUpdateMsg>();
    let (_, dummy_ipc_receive) = unbounded::<IPC>();

    // todo: make it a lazy static as RUNTIME, to also hold the same IP, otherwise it will
    //       always change its IP!
    // initiate a thread (which will be ... (todo: lazy_static maybe later, and keep it running)
    // which handles net communication
    let single_shot_net_thread = thread::Builder::new()
        .name("app_net".into())
        .spawn(move || {
            task::block_on(async move {
                let _ =
                    shared::net_search(dummy_wait_net_thread, Some(ui_sender), dummy_ipc_receive)
                        .await;
            });
        })
        .unwrap();

    // very interesting, the compiler is awesome!!
    let out;

    // loop over fixme: (very cheap version here, that could be done more elegantly)
    loop {
        if let Ok(reaction) = reactor.try_recv() {
            match reaction {
                UiUpdateMsg::CollectionUpdate(_, _) => {}
                UiUpdateMsg::NetUpdate(net_message) => {
                    match net_message {
                        ForwardNetMsg::Add(peer) => {
                            // yet only id is interesting
                            out = peer_representation::peer_to_hash(&peer.id);
                            break;
                        }
                        ForwardNetMsg::Delete(_peer_id) => {}
                        ForwardNetMsg::Stats(_) => {}
                    }
                }
                UiUpdateMsg::PeerSearchFinished(_peer_id, _data) => {}
                UiUpdateMsg::StopUI => {}
            }
        }
    }
    // kill this big thread / fixme: very inefficent yet
    drop(single_shot_net_thread);
    out
}
<|endoftext|>