<commit_before>use super::{StringReader, UnmatchedBrace};

use rustc_ast::token::{self, Token};
use rustc_ast::tokenstream::{
    DelimSpan,
    IsJoint::{self, *},
    TokenStream, TokenTree, TreeAndJoint,
};
use rustc_ast_pretty::pprust::token_to_string;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::PResult;
use rustc_span::Span;

impl<'a> StringReader<'a> {
    crate fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec<UnmatchedBrace>) {
        let mut tt_reader = TokenTreesReader {
            string_reader: self,
            token: Token::dummy(),
            joint_to_prev: Joint,
            open_braces: Vec::new(),
            unmatched_braces: Vec::new(),
            matching_delim_spans: Vec::new(),
            last_unclosed_found_span: None,
            last_delim_empty_block_spans: FxHashMap::default(),
        };
        let res = tt_reader.parse_all_token_trees();
        (res, tt_reader.unmatched_braces)
    }
}

struct TokenTreesReader<'a> {
    string_reader: StringReader<'a>,
    token: Token,
    joint_to_prev: IsJoint,
    /// Stack of open delimiters and their spans. Used for error message.
    open_braces: Vec<(token::DelimToken, Span)>,
    unmatched_braces: Vec<UnmatchedBrace>,
    /// The type and spans for all braces
    ///
    /// Used only for error recovery when arriving to EOF with mismatched braces.
    matching_delim_spans: Vec<(token::DelimToken, Span, Span)>,
    last_unclosed_found_span: Option<Span>,
    /// Collect empty block spans that might have been auto-inserted by editors.
    last_delim_empty_block_spans: FxHashMap<token::DelimToken, Span>,
}

impl<'a> TokenTreesReader<'a> {
    // Parse a stream of tokens into a list of `TokenTree`s, up to an `Eof`.
    fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> {
        let mut buf = TokenStreamBuilder::default();

        self.real_token();
        while self.token != token::Eof {
            buf.push(self.parse_token_tree()?);
        }

        Ok(buf.into_token_stream())
    }

    // Parse a stream of tokens into a list of `TokenTree`s, up to a `CloseDelim`.
    fn parse_token_trees_until_close_delim(&mut self) -> TokenStream {
        let mut buf = TokenStreamBuilder::default();
        loop {
            if let token::CloseDelim(..) = self.token.kind {
                return buf.into_token_stream();
            }

            match self.parse_token_tree() {
                Ok(tree) => buf.push(tree),
                Err(mut e) => {
                    e.emit();
                    return buf.into_token_stream();
                }
            }
        }
    }

    fn parse_token_tree(&mut self) -> PResult<'a, TreeAndJoint> {
        let sm = self.string_reader.sess.source_map();
        match self.token.kind {
            token::Eof => {
                let msg = "this file contains an unclosed delimiter";
                let mut err =
                    self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, msg);
                for &(_, sp) in &self.open_braces {
                    err.span_label(sp, "unclosed delimiter");
                    self.unmatched_braces.push(UnmatchedBrace {
                        expected_delim: token::DelimToken::Brace,
                        found_delim: None,
                        found_span: self.token.span,
                        unclosed_span: Some(sp),
                        candidate_span: None,
                    });
                }

                if let Some((delim, _)) = self.open_braces.last() {
                    if let Some((_, open_sp, close_sp)) =
                        self.matching_delim_spans.iter().find(|(d, open_sp, close_sp)| {
                            if let Some(close_padding) = sm.span_to_margin(*close_sp) {
                                if let Some(open_padding) = sm.span_to_margin(*open_sp) {
                                    return delim == d && close_padding != open_padding;
                                }
                            }
                            false
                        })
                    // these are in reverse order as they get inserted on close, but
                    {
                        // we want the last open/first close
                        err.span_label(*open_sp, "this delimiter might not be properly closed...");
                        err.span_label(
                            *close_sp,
                            "...as it matches this but it has different indentation",
                        );
                    }
                }
                Err(err)
            }
            token::OpenDelim(delim) => {
                // The span for beginning of the delimited section
                let pre_span = self.token.span;

                // Parse the open delimiter.
                self.open_braces.push((delim, self.token.span));
                self.real_token();

                // Parse the token trees within the delimiters.
                // We stop at any delimiter so we can try to recover if the user
                // uses an incorrect delimiter.
                let tts = self.parse_token_trees_until_close_delim();

                // Expand to cover the entire delimited token tree
                let delim_span = DelimSpan::from_pair(pre_span, self.token.span);

                match self.token.kind {
                    // Correct delimiter.
                    token::CloseDelim(d) if d == delim => {
                        let (open_brace, open_brace_span) = self.open_braces.pop().unwrap();
                        let close_brace_span = self.token.span;

                        if tts.is_empty() {
                            let empty_block_span = open_brace_span.to(close_brace_span);
                            if !sm.is_multiline(empty_block_span) {
                                // Only track if the block is in the form of `{}`, otherwise it is
                                // likely that it was written on purpose.
                                self.last_delim_empty_block_spans.insert(delim, empty_block_span);
                            }
                        }

                        if self.open_braces.is_empty() {
                            // Clear up these spans to avoid suggesting them as we've found
                            // properly matched delimiters so far for an entire block.
                            self.matching_delim_spans.clear();
                        } else {
                            self.matching_delim_spans.push((
                                open_brace,
                                open_brace_span,
                                close_brace_span,
                            ));
                        }
                        // Parse the closing delimiter.
                        self.real_token();
                    }
                    // Incorrect delimiter.
                    token::CloseDelim(other) => {
                        let mut unclosed_delimiter = None;
                        let mut candidate = None;
                        if self.last_unclosed_found_span != Some(self.token.span) {
                            // do not complain about the same unclosed delimiter multiple times
                            self.last_unclosed_found_span = Some(self.token.span);
                            // This is a conservative error: only report the last unclosed
                            // delimiter. The previous unclosed delimiters could actually be
                            // closed! The parser just hasn't gotten to them yet.
                            if let Some(&(_, sp)) = self.open_braces.last() {
                                unclosed_delimiter = Some(sp);
                            };
                            if let Some(current_padding) = sm.span_to_margin(self.token.span) {
                                for (brace, brace_span) in &self.open_braces {
                                    if let Some(padding) = sm.span_to_margin(*brace_span) {
                                        // high likelihood of these two corresponding
                                        if current_padding == padding && brace == &other {
                                            candidate = Some(*brace_span);
                                        }
                                    }
                                }
                            }
                            let (tok, _) = self.open_braces.pop().unwrap();
                            self.unmatched_braces.push(UnmatchedBrace {
                                expected_delim: tok,
                                found_delim: Some(other),
                                found_span: self.token.span,
                                unclosed_span: unclosed_delimiter,
                                candidate_span: candidate,
                            });
                        } else {
                            self.open_braces.pop();
                        }

                        // If the incorrect delimiter matches an earlier opening
                        // delimiter, then don't consume it (it can be used to
                        // close the earlier one). Otherwise, consume it.
                        // E.g., we try to recover from:
                        // fn foo() {
                        //     bar(baz(
                        // }  // Incorrect delimiter but matches the earlier `{`
                        if !self.open_braces.iter().any(|&(b, _)| b == other) {
                            self.real_token();
                        }
                    }
                    token::Eof => {
                        // Silently recover, the EOF token will be seen again
                        // and an error emitted then. Thus we don't pop from
                        // self.open_braces here.
                    }
                    _ => {}
                }

                Ok(TokenTree::Delimited(delim_span, delim, tts).into())
            }
            token::CloseDelim(delim) => {
                // An unexpected closing delimiter (i.e., there is no
                // matching opening delimiter).
                let token_str = token_to_string(&self.token);
                let msg = format!("unexpected closing delimiter: `{}`", token_str);
                let mut err =
                    self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, &msg);

                if let Some(span) = self.last_delim_empty_block_spans.remove(&delim) {
                    err.span_label(
                        span,
                        "this block is empty, you might have not meant to close it",
                    );
                }
                err.span_label(self.token.span, "unexpected closing delimiter");
                Err(err)
            }
            _ => {
                let tt = TokenTree::Token(self.token.take());
                self.real_token();
                let is_joint = self.joint_to_prev == Joint && self.token.is_op();
                Ok((tt, if is_joint { Joint } else { NonJoint }))
            }
        }
    }

    fn real_token(&mut self) {
        self.joint_to_prev = Joint;
        loop {
            let token = self.string_reader.next_token();
            match token.kind {
                token::Whitespace | token::Comment | token::Shebang(_) | token::Unknown(_) => {
                    self.joint_to_prev = NonJoint;
                }
                _ => {
                    self.token = token;
                    return;
                }
            }
        }
    }
}

#[derive(Default)]
struct TokenStreamBuilder {
    buf: Vec<TreeAndJoint>,
}

impl TokenStreamBuilder {
    fn push(&mut self, (tree, joint): TreeAndJoint) {
        if let Some((TokenTree::Token(prev_token), Joint)) = self.buf.last() {
            if let TokenTree::Token(token) = &tree {
                if let Some(glued) = prev_token.glue(token) {
                    self.buf.pop();
                    self.buf.push((TokenTree::Token(glued), joint));
                    return;
                }
            }
        }
        self.buf.push((tree, joint))
    }

    fn into_token_stream(self) -> TokenStream {
        TokenStream::new(self.buf)
    }
}
<commit_msg>Check if the suggestion's `this block is empty...` span is in the last properly closed block.<commit_after>use super::{StringReader, UnmatchedBrace};

use rustc_ast::token::{self, Token};
use rustc_ast::tokenstream::{
    DelimSpan,
    IsJoint::{self, *},
    TokenStream, TokenTree, TreeAndJoint,
};
use rustc_ast_pretty::pprust::token_to_string;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::PResult;
use rustc_span::Span;

impl<'a> StringReader<'a> {
    crate fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec<UnmatchedBrace>) {
        let mut tt_reader = TokenTreesReader {
            string_reader: self,
            token: Token::dummy(),
            joint_to_prev: Joint,
            open_braces: Vec::new(),
            unmatched_braces: Vec::new(),
            matching_delim_spans: Vec::new(),
            last_unclosed_found_span: None,
            last_delim_empty_block_spans: FxHashMap::default(),
            matching_block_spans: Vec::new(),
        };
        let res = tt_reader.parse_all_token_trees();
        (res, tt_reader.unmatched_braces)
    }
}

struct TokenTreesReader<'a> {
    string_reader: StringReader<'a>,
    token: Token,
    joint_to_prev: IsJoint,
    /// Stack of open delimiters and their spans. Used for error message.
    open_braces: Vec<(token::DelimToken, Span)>,
    unmatched_braces: Vec<UnmatchedBrace>,
    /// The type and spans for all braces
    ///
    /// Used only for error recovery when arriving to EOF with mismatched braces.
    matching_delim_spans: Vec<(token::DelimToken, Span, Span)>,
    last_unclosed_found_span: Option<Span>,
    /// Collect empty block spans that might have been auto-inserted by editors.
    last_delim_empty_block_spans: FxHashMap<token::DelimToken, Span>,
    /// Collect the spans of braces (Open, Close). Used only
    /// for detecting if blocks are empty
    matching_block_spans: Vec<(Span, Span)>,
}

impl<'a> TokenTreesReader<'a> {
    // Parse a stream of tokens into a list of `TokenTree`s, up to an `Eof`.
    fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> {
        let mut buf = TokenStreamBuilder::default();

        self.real_token();
        while self.token != token::Eof {
            buf.push(self.parse_token_tree()?);
        }

        Ok(buf.into_token_stream())
    }

    // Parse a stream of tokens into a list of `TokenTree`s, up to a `CloseDelim`.
    fn parse_token_trees_until_close_delim(&mut self) -> TokenStream {
        let mut buf = TokenStreamBuilder::default();
        loop {
            if let token::CloseDelim(..) = self.token.kind {
                return buf.into_token_stream();
            }

            match self.parse_token_tree() {
                Ok(tree) => buf.push(tree),
                Err(mut e) => {
                    e.emit();
                    return buf.into_token_stream();
                }
            }
        }
    }

    fn parse_token_tree(&mut self) -> PResult<'a, TreeAndJoint> {
        let sm = self.string_reader.sess.source_map();

        match self.token.kind {
            token::Eof => {
                let msg = "this file contains an unclosed delimiter";
                let mut err =
                    self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, msg);
                for &(_, sp) in &self.open_braces {
                    err.span_label(sp, "unclosed delimiter");
                    self.unmatched_braces.push(UnmatchedBrace {
                        expected_delim: token::DelimToken::Brace,
                        found_delim: None,
                        found_span: self.token.span,
                        unclosed_span: Some(sp),
                        candidate_span: None,
                    });
                }

                if let Some((delim, _)) = self.open_braces.last() {
                    if let Some((_, open_sp, close_sp)) =
                        self.matching_delim_spans.iter().find(|(d, open_sp, close_sp)| {
                            if let Some(close_padding) = sm.span_to_margin(*close_sp) {
                                if let Some(open_padding) = sm.span_to_margin(*open_sp) {
                                    return delim == d && close_padding != open_padding;
                                }
                            }
                            false
                        })
                    // these are in reverse order as they get inserted on close, but
                    {
                        // we want the last open/first close
                        err.span_label(*open_sp, "this delimiter might not be properly closed...");
                        err.span_label(
                            *close_sp,
                            "...as it matches this but it has different indentation",
                        );
                    }
                }
                Err(err)
            }
            token::OpenDelim(delim) => {
                // The span for beginning of the delimited section
                let pre_span = self.token.span;

                // Parse the open delimiter.
                self.open_braces.push((delim, self.token.span));
                self.real_token();

                // Parse the token trees within the delimiters.
                // We stop at any delimiter so we can try to recover if the user
                // uses an incorrect delimiter.
                let tts = self.parse_token_trees_until_close_delim();

                // Expand to cover the entire delimited token tree
                let delim_span = DelimSpan::from_pair(pre_span, self.token.span);

                match self.token.kind {
                    // Correct delimiter.
                    token::CloseDelim(d) if d == delim => {
                        let (open_brace, open_brace_span) = self.open_braces.pop().unwrap();
                        let close_brace_span = self.token.span;

                        if tts.is_empty() {
                            let empty_block_span = open_brace_span.to(close_brace_span);
                            if !sm.is_multiline(empty_block_span) {
                                // Only track if the block is in the form of `{}`, otherwise it is
                                // likely that it was written on purpose.
                                self.last_delim_empty_block_spans.insert(delim, empty_block_span);
                            }
                        }

                        self.matching_block_spans.push((open_brace_span, close_brace_span));

                        if self.open_braces.is_empty() {
                            // Clear up these spans to avoid suggesting them as we've found
                            // properly matched delimiters so far for an entire block.
                            self.matching_delim_spans.clear();
                        } else {
                            self.matching_delim_spans.push((
                                open_brace,
                                open_brace_span,
                                close_brace_span,
                            ));
                        }
                        // Parse the closing delimiter.
                        self.real_token();
                    }
                    // Incorrect delimiter.
                    token::CloseDelim(other) => {
                        let mut unclosed_delimiter = None;
                        let mut candidate = None;

                        if self.last_unclosed_found_span != Some(self.token.span) {
                            // do not complain about the same unclosed delimiter multiple times
                            self.last_unclosed_found_span = Some(self.token.span);
                            // This is a conservative error: only report the last unclosed
                            // delimiter. The previous unclosed delimiters could actually be
                            // closed! The parser just hasn't gotten to them yet.
                            if let Some(&(_, sp)) = self.open_braces.last() {
                                unclosed_delimiter = Some(sp);
                            };
                            if let Some(current_padding) = sm.span_to_margin(self.token.span) {
                                for (brace, brace_span) in &self.open_braces {
                                    if let Some(padding) = sm.span_to_margin(*brace_span) {
                                        // high likelihood of these two corresponding
                                        if current_padding == padding && brace == &other {
                                            candidate = Some(*brace_span);
                                        }
                                    }
                                }
                            }
                            let (tok, _) = self.open_braces.pop().unwrap();
                            self.unmatched_braces.push(UnmatchedBrace {
                                expected_delim: tok,
                                found_delim: Some(other),
                                found_span: self.token.span,
                                unclosed_span: unclosed_delimiter,
                                candidate_span: candidate,
                            });
                        } else {
                            self.open_braces.pop();
                        }

                        // If the incorrect delimiter matches an earlier opening
                        // delimiter, then don't consume it (it can be used to
                        // close the earlier one). Otherwise, consume it.
                        // E.g., we try to recover from:
                        // fn foo() {
                        //     bar(baz(
                        // }  // Incorrect delimiter but matches the earlier `{`
                        if !self.open_braces.iter().any(|&(b, _)| b == other) {
                            self.real_token();
                        }
                    }
                    token::Eof => {
                        // Silently recover, the EOF token will be seen again
                        // and an error emitted then. Thus we don't pop from
                        // self.open_braces here.
                    }
                    _ => {}
                }

                Ok(TokenTree::Delimited(delim_span, delim, tts).into())
            }
            token::CloseDelim(delim) => {
                // An unexpected closing delimiter (i.e., there is no
                // matching opening delimiter).
                let token_str = token_to_string(&self.token);
                let msg = format!("unexpected closing delimiter: `{}`", token_str);
                let mut err =
                    self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, &msg);

                if let Some(span) = self.last_delim_empty_block_spans.remove(&delim) {
                    // Braces are added at the end, so the last element is the biggest block
                    if let Some(parent) = self.matching_block_spans.last() {
                        // Check if the (empty block) is in the last properly closed block
                        if (parent.0.to(parent.1)).contains(span) {
                            err.span_label(
                                span,
                                "this block is empty, you might have not meant to close it",
                            );
                        }
                    }
                }
                err.span_label(self.token.span, "unexpected closing delimiter");
                Err(err)
            }
            _ => {
                let tt = TokenTree::Token(self.token.take());
                self.real_token();
                let is_joint = self.joint_to_prev == Joint && self.token.is_op();
                Ok((tt, if is_joint { Joint } else { NonJoint }))
            }
        }
    }

    fn real_token(&mut self) {
        self.joint_to_prev = Joint;
        loop {
            let token = self.string_reader.next_token();
            match token.kind {
                token::Whitespace | token::Comment | token::Shebang(_) | token::Unknown(_) => {
                    self.joint_to_prev = NonJoint;
                }
                _ => {
                    self.token = token;
                    return;
                }
            }
        }
    }
}

#[derive(Default)]
struct TokenStreamBuilder {
    buf: Vec<TreeAndJoint>,
}

impl TokenStreamBuilder {
    fn push(&mut self, (tree, joint): TreeAndJoint) {
        if let Some((TokenTree::Token(prev_token), Joint)) = self.buf.last() {
            if let TokenTree::Token(token) = &tree {
                if let Some(glued) = prev_token.glue(token) {
                    self.buf.pop();
                    self.buf.push((TokenTree::Token(glued), joint));
                    return;
                }
            }
        }
        self.buf.push((tree, joint))
    }

    fn into_token_stream(self) -> TokenStream {
        TokenStream::new(self.buf)
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::sync::Arc;

use futures::{Future, Task, Poll};
use futures::stream::{Stream, Fuse};
use futures_io::{Ready, ReadTask, WriteTask};

pub trait Parse: Sized + Send + 'static {
    type Parser: Default + Send + 'static;
    type Error: Send + 'static + From<io::Error>;

    fn parse(parser: &mut Self::Parser,
             buf: &Arc<Vec<u8>>,
             offset: usize)
             -> Option<Result<(Self, usize), Self::Error>>;
}

/// A stream for parsing from an underlying reader, using an unbounded internal
/// buffer.
pub struct ParseStream<R, P: Parse> {
    source: R,
    read_ready: bool,
    parser: P::Parser,
    buf: Arc<Vec<u8>>,

    // how far into the buffer have we parsed? note: we drain lazily
    pos: usize,

    // is there new data that we need to try to parse?
    need_parse: bool,

    // has `source` yielded an EOF?
    eof: bool,
}

impl<R, P> ParseStream<R, P>
    where R: ReadTask,
          P: Parse
{
    pub fn new(source: R) -> ParseStream<R, P> {
        ParseStream {
            source: source,
            read_ready: false,
            parser: Default::default(),
            buf: Arc::new(Vec::with_capacity(2048)),
            pos: 0,
            need_parse: false,
            eof: false,
        }
    }
}

// TODO: move this into method
fn read(socket: &mut ReadTask<Item=Ready, Error=io::Error>,
        task: &mut Task,
        input: &mut Vec<u8>) -> io::Result<(usize, bool)> {
    loop {
        match try_nb!(socket.read(task, unsafe { slice_to_end(input) })) {
            Some(0) => {
                trace!("socket EOF");
                return Ok((0, true))
            }
            Some(n) => {
                trace!("socket read {} bytes", n);
                unsafe {
                    let len = input.len();
                    input.set_len(len + n);
                }
                return Ok((n, false));
            }
            None => return Ok((0, false)),
        }
    }

    unsafe fn slice_to_end(v: &mut Vec<u8>) -> &mut [u8] {
        use std::slice;
        if v.capacity() == 0 {
            v.reserve(16);
        }
        if v.capacity() == v.len() {
            v.reserve(1);
        }
        slice::from_raw_parts_mut(v.as_mut_ptr().offset(v.len() as isize),
                                  v.capacity() - v.len())
    }
}

impl<R, P> Stream for ParseStream<R, P>
    where R: ReadTask,
          P: Parse
{
    type Item = P;
    type Error = P::Error;

    fn poll(&mut self, task: &mut Task) -> Poll<Option<P>, P::Error> {
        loop {
            if self.need_parse {
                debug!("attempting to parse");
                match P::parse(&mut self.parser, &self.buf, self.pos) {
                    Some(Ok((i, n))) => {
                        self.pos += n;
                        return Poll::Ok(Some(i))
                    }
                    Some(Err(e)) => return Poll::Err(e),
                    None => {
                        self.need_parse = false;
                    }
                }

                // Fast path if we can get mutable access to our own current
                // buffer.
                let mut drained = false;
                if let Some(buf) = Arc::get_mut(&mut self.buf) {
                    buf.drain(..self.pos);
                    drained = true;
                }

                // If we couldn't get access above then we give ourself a new
                // buffer here.
                if !drained {
                    let mut v = Vec::with_capacity(2048);
                    v.extend_from_slice(&self.buf[self.pos..]);
                    self.buf = Arc::new(v);
                }
                self.pos = 0;
            }

            if self.eof {
                return Poll::Ok(None)
            }

            if !self.read_ready {
                match try_poll!(self.source.poll(task)) {
                    Err(e) => return Poll::Err(e.into()),
                    Ok(Some(ref r)) if r.is_read() => self.read_ready = true,
                    Ok(Some(_)) => return Poll::NotReady,
                    Ok(None) => unreachable!(),
                }
            }

            let buf = Arc::get_mut(&mut self.buf).unwrap();
            match read(&mut self.source, task, buf) {
                Ok((n, eof)) => {
                    self.eof = eof;
                    self.need_parse = self.need_parse || n > 0;
                    self.read_ready = n > 0;
                }
                Err(e) => return Poll::Err(e.into()),
            }
        }
    }

    fn schedule(&mut self, task: &mut Task) {
        // TODO: think through this carefully...
        if self.need_parse {
            // No tokens because in a `need_parse` situation, we'll attempt to
            // parse regardless of tokens
            task.notify();
        } else {
            self.source.schedule(task)
        }
    }
}

// TODO: make this a method
fn write(sink: &mut WriteTask<Item=Ready, Error=io::Error>,
         task: &mut Task,
         buf: &mut Vec<u8>) -> io::Result<()> {
    loop {
        match try_nb!(sink.write(task, &buf)) {
            Some(0) => {
                // TODO: copied from mio example, clean up
                return Err(io::Error::new(io::ErrorKind::Other, "early eof2"));
            }
            Some(n) => {
                // TODO: consider draining more lazily, i.e. only just before
                //       returning
                buf.drain(..n);
                if buf.len() == 0 {
                    return Ok(());
                }
            }
            None => return Ok(()),
        }
    }
}

pub trait Serialize: Send + 'static {
    fn serialize(&self, buf: &mut Vec<u8>);
}

/// Serialize a stream of items into a writer, using an unbounded internal
/// buffer.
///
/// Represented as a future which yields () on successfully writing the entire
/// stream (which requires the stream to terminate), or an error if there is any
/// error along the way.
pub struct StreamWriter<W, S> {
    sink: W,
    write_ready: bool,
    items: Fuse<S>,
    buf: Vec<u8>,
}

impl<W, S> StreamWriter<W, S>
    where W: WriteTask,
          S: Stream,
          S::Item: Serialize,
          S::Error: From<io::Error>
{
    pub fn new(sink: W, items: S) -> StreamWriter<W, S> {
        StreamWriter {
            sink: sink,
            write_ready: false,
            items: items.fuse(),
            buf: Vec::with_capacity(2048),
        }
    }
}

impl<W, S> Future for StreamWriter<W, S>
    where W: WriteTask,
          S: Stream,
          S::Item: Serialize,
          S::Error: From<io::Error>
{
    type Item = ();
    type Error = S::Error;

    fn poll(&mut self, task: &mut Task) -> Poll<(), S::Error> {
        // First up, grab any responses we have and serialize them into our
        // local buffer. Make sure to pass down `tokens` only on the *first*
        // poll for items
        //
        // TODO: limit this loop on the size of `self.buf`.
        {
            let mut task = task.scoped();
            loop {
                match self.items.poll(&mut task) {
                    Poll::Err(e) => return Poll::Err(e),
                    Poll::Ok(Some(item)) => {
                        debug!("got an item to serialize!");
                        item.serialize(&mut self.buf);
                        task.ready();
                    }
                    Poll::Ok(None) |
                    Poll::NotReady => break,
                }
            }
        }

        // TODO: optimization for case where we just transitioned from no bytes
        // to write to having bytes to write; in that case, we should try to
        // write regardless of sink_ready.poll, because we haven't asked for a
        // readiness notifcation. Saves a trip around the event loop.

        // Now that we might have some responses to write, try to write them.
        // Note that we always execute at least one iteration of this loop to
        // attempt to pull out write readiness ASAP. If a response is being
        // calculated we can learn that we're ready for a write immediately and
        // write as soon as it's ready when it comes around.
        //
        // If, however, we have no data to write and there are no more responses
        // that will come out, then we don't need to wait for write readiness.
        loop {
            if !self.write_ready && (self.buf.len() > 0 || !self.items.is_done()) {
                match try_poll!(self.sink.poll(task)) {
                    Err(e) => return Poll::Err(e.into()),
                    Ok(Some(ref r)) if r.is_write() => self.write_ready = true,
                    Ok(Some(_)) => return Poll::NotReady,

                    // TODO: this should translate to an error
                    Ok(None) => return Poll::NotReady,
                }
            }

            // If we're here then either
            //
            // (a) write_ready is true
            // (b) the response stream is done
            //
            // If we have an empty fuffer for either of these cases then we have
            // nothing left to do, and are either done with iterating or need to
            // do some more work.
            if self.buf.len() == 0 {
                if self.items.is_done() {
                    return Poll::Ok(())
                } else {
                    return Poll::NotReady
                }
            }

            debug!("trying to write some data");
            let before = self.buf.len();
            if let Err(e) = write(&mut self.sink, task, &mut self.buf) {
                return Poll::Err(e.into())
            }

            // If we didn't fail but we also didn't write anything, then we're
            // no longer ready to write and we may need to poll some more.
            if before == self.buf.len() {
                self.write_ready = false;
            }
        }
    }

    fn schedule(&mut self, task: &mut Task) {
        // wake up on writability only if we have something to write
        if self.buf.len() > 0 {
            self.sink.schedule(task);
        }

        // for now, we are always happy to write more items into our unbounded buffer
        self.items.schedule(task);
    }
}
<commit_msg>Fix compile of minihttp<commit_after>use std::io;
use std::sync::Arc;

use futures::{Future, Task, Poll};
use futures::stream::{Stream, Fuse};
use futures_io::{Ready, ReadTask, WriteTask};

pub trait Parse: Sized + Send + 'static {
    type Parser: Default + Send + 'static;
    type Error: Send + 'static + From<io::Error>;

    fn parse(parser: &mut Self::Parser,
             buf: &Arc<Vec<u8>>,
             offset: usize)
             -> Option<Result<(Self, usize), Self::Error>>;
}

/// A stream for parsing from an underlying reader, using an unbounded internal
/// buffer.
pub struct ParseStream<R, P: Parse> {
    source: R,
    read_ready: bool,
    parser: P::Parser,
    buf: Arc<Vec<u8>>,

    // how far into the buffer have we parsed? note: we drain lazily
    pos: usize,

    // is there new data that we need to try to parse?
    need_parse: bool,

    // has `source` yielded an EOF?
    eof: bool,
}

impl<R, P> ParseStream<R, P>
    where R: ReadTask,
          P: Parse
{
    pub fn new(source: R) -> ParseStream<R, P> {
        ParseStream {
            source: source,
            read_ready: false,
            parser: Default::default(),
            buf: Arc::new(Vec::with_capacity(2048)),
            pos: 0,
            need_parse: false,
            eof: false,
        }
    }
}

// TODO: move this into method
fn read(socket: &mut ReadTask<Item=Ready, Error=io::Error>,
        task: &mut Task,
        input: &mut Vec<u8>) -> io::Result<(usize, bool)> {
    loop {
        match try_nb!(socket.read(task, unsafe { slice_to_end(input) })) {
            Some(0) => {
                trace!("socket EOF");
                return Ok((0, true))
            }
            Some(n) => {
                trace!("socket read {} bytes", n);
                unsafe {
                    let len = input.len();
                    input.set_len(len + n);
                }
                return Ok((n, false));
            }
            None => return Ok((0, false)),
        }
    }

    unsafe fn slice_to_end(v: &mut Vec<u8>) -> &mut [u8] {
        use std::slice;
        if v.capacity() == 0 {
            v.reserve(16);
        }
        if v.capacity() == v.len() {
            v.reserve(1);
        }
        slice::from_raw_parts_mut(v.as_mut_ptr().offset(v.len() as isize),
                                  v.capacity() - v.len())
    }
}

impl<R, P> Stream for ParseStream<R, P>
    where R: ReadTask,
          P: Parse
{
    type Item = P;
    type Error = P::Error;

    fn poll(&mut self, task: &mut Task) -> Poll<Option<P>, P::Error> {
        loop {
            if self.need_parse {
                debug!("attempting to parse");
                match P::parse(&mut self.parser, &self.buf, self.pos) {
                    Some(Ok((i, n))) => {
                        self.pos += n;
                        return Poll::Ok(Some(i))
                    }
                    Some(Err(e)) => return Poll::Err(e),
                    None => {
                        self.need_parse = false;
                    }
                }

                // Fast path if we can get mutable access to our own current
                // buffer.
                let mut drained = false;
                if let Some(buf) = Arc::get_mut(&mut self.buf) {
                    buf.drain(..self.pos);
                    drained = true;
                }

                // If we couldn't get access above then we give ourself a new
                // buffer here.
                if !drained {
                    let mut v = Vec::with_capacity(2048);
                    v.extend_from_slice(&self.buf[self.pos..]);
                    self.buf = Arc::new(v);
                }
                self.pos = 0;
            }

            if self.eof {
                return Poll::Ok(None)
            }

            if !self.read_ready {
                match try_poll!(self.source.poll(task)) {
                    Err(e) => return Poll::Err(e.into()),
                    Ok(Some(ref r)) if r.is_read() => self.read_ready = true,
                    Ok(Some(_)) => return Poll::NotReady,
                    Ok(None) => unreachable!(),
                }
            }

            let buf = Arc::get_mut(&mut self.buf).unwrap();
            match read(&mut self.source, task, buf) {
                Ok((n, eof)) => {
                    self.eof = eof;
                    self.need_parse = self.need_parse || n > 0;
                    self.read_ready = n > 0;
                }
                Err(e) => return Poll::Err(e.into()),
            }
        }
    }

    fn schedule(&mut self, task: &mut Task) {
        // TODO: think through this carefully...
        if self.need_parse {
            // No tokens because in a `need_parse` situation, we'll attempt to
            // parse regardless of tokens
            task.notify();
        } else {
            self.source.schedule(task)
        }
    }
}

// TODO: make this a method
fn write(sink: &mut WriteTask<Item=Ready, Error=io::Error>,
         task: &mut Task,
         buf: &mut Vec<u8>) -> io::Result<()> {
    loop {
        match try_nb!(sink.write(task, &buf)) {
            Some(0) => {
                // TODO: copied from mio example, clean up
                return Err(io::Error::new(io::ErrorKind::Other, "early eof2"));
            }
            Some(n) => {
                // TODO: consider draining more lazily, i.e. only just before
                //       returning
                buf.drain(..n);
                if buf.len() == 0 {
                    return Ok(());
                }
            }
            None => return Ok(()),
        }
    }
}

pub trait Serialize: Send + 'static {
    fn serialize(&self, buf: &mut Vec<u8>);
}

/// Serialize a stream of items into a writer, using an unbounded internal
/// buffer.
///
/// Represented as a future which yields () on successfully writing the entire
/// stream (which requires the stream to terminate), or an error if there is any
/// error along the way.
pub struct StreamWriter<W, S> {
    sink: W,
    write_ready: bool,
    items: Fuse<S>,
    buf: Vec<u8>,
}

impl<W, S> StreamWriter<W, S>
    where W: WriteTask,
          S: Stream,
          S::Item: Serialize,
          S::Error: From<io::Error>
{
    pub fn new(sink: W, items: S) -> StreamWriter<W, S> {
        StreamWriter {
            sink: sink,
            write_ready: false,
            items: items.fuse(),
            buf: Vec::with_capacity(2048),
        }
    }
}

impl<W, S> Future for StreamWriter<W, S>
    where W: WriteTask,
          S: Stream,
          S::Item: Serialize,
          S::Error: From<io::Error>
{
    type Item = ();
    type Error = S::Error;

    fn poll(&mut self, task: &mut Task) -> Poll<(), S::Error> {
        // First up, grab any responses we have and serialize them into our
        // local buffer. Make sure to pass down `tokens` only on the *first*
        // poll for items
        //
        // TODO: limit this loop on the size of `self.buf`.
        {
            loop {
                match self.items.poll(task) {
                    Poll::Err(e) => return Poll::Err(e),
                    Poll::Ok(Some(item)) => {
                        debug!("got an item to serialize!");
                        item.serialize(&mut self.buf);
                    }
                    Poll::Ok(None) |
                    Poll::NotReady => break,
                }
            }
        }

        // TODO: optimization for case where we just transitioned from no bytes
        // to write to having bytes to write; in that case, we should try to
        // write regardless of sink_ready.poll, because we haven't asked for a
        // readiness notifcation. Saves a trip around the event loop.

        // Now that we might have some responses to write, try to write them.
        // Note that we always execute at least one iteration of this loop to
        // attempt to pull out write readiness ASAP. If a response is being
        // calculated we can learn that we're ready for a write immediately and
        // write as soon as it's ready when it comes around.
        //
        // If, however, we have no data to write and there are no more responses
        // that will come out, then we don't need to wait for write readiness.
        loop {
            if !self.write_ready && (self.buf.len() > 0 || !self.items.is_done()) {
                match try_poll!(self.sink.poll(task)) {
                    Err(e) => return Poll::Err(e.into()),
                    Ok(Some(ref r)) if r.is_write() => self.write_ready = true,
                    Ok(Some(_)) => return Poll::NotReady,

                    // TODO: this should translate to an error
                    Ok(None) => return Poll::NotReady,
                }
            }

            // If we're here then either
            //
            // (a) write_ready is true
            // (b) the response stream is done
            //
            // If we have an empty fuffer for either of these cases then we have
            // nothing left to do, and are either done with iterating or need to
            // do some more work.
            if self.buf.len() == 0 {
                if self.items.is_done() {
                    return Poll::Ok(())
                } else {
                    return Poll::NotReady
                }
            }

            debug!("trying to write some data");
            let before = self.buf.len();
            if let Err(e) = write(&mut self.sink, task, &mut self.buf) {
                return Poll::Err(e.into())
            }

            // If we didn't fail but we also didn't write anything, then we're
            // no longer ready to write and we may need to poll some more.
            if before == self.buf.len() {
                self.write_ready = false;
            }
        }
    }

    fn schedule(&mut self, task: &mut Task) {
        // wake up on writability only if we have something to write
        if self.buf.len() > 0 {
            self.sink.schedule(task);
        }

        // for now, we are always happy to write more items into our unbounded buffer
        self.items.schedule(task);
    }
}
<|endoftext|>


<commit_before>use super::super::{expand_string, Expander};
use crate::{
    lexers::assignments::{Primitive, TypeError},
    shell::variables::VariableType,
    types,
};
use std::iter::Iterator;

#[derive(PartialEq, Clone, Copy, Debug)]
enum IsArrayHelper {
    Valid(usize),
    RootBracketClosed,
    Invalid,
}

/// Determines if the supplied value is either an array or a string.
///
/// - `[ 1 2 3 ]` = Array
/// - `[ 1 2 3 ][1]` = String
/// - `string` = String
pub(crate) fn is_array(value: &str) -> bool {
    if value.starts_with('[') && value.ends_with(']') {
        !value
            .chars()
            .scan(IsArrayHelper::Valid(0), |state, x| {
                // If previous iteration was RootBracketClosed or Invalid then indicate invalid
                if *state == IsArrayHelper::RootBracketClosed || *state == IsArrayHelper::Invalid {
                    *state = IsArrayHelper::Invalid;
                    return Some(*state);
                }

                if x == '[' {
                    if let IsArrayHelper::Valid(open) = *state {
                        *state = IsArrayHelper::Valid(open + 1);
                    }
                } else if x == ']' {
                    if let IsArrayHelper::Valid(open) = *state {
                        *state = IsArrayHelper::Valid(open - 1);
                    }
                }

                // if true, root bracket was closed
                // => any characters after this one indicate invalid array
                if *state == IsArrayHelper::Valid(0) {
                    *state = IsArrayHelper::RootBracketClosed;
                }

                Some(*state)
            })
            .any(|x| x == IsArrayHelper::Invalid)
    } else {
        false
    }
}

pub(crate) fn is_boolean(value: &str) -> Result<&str, ()> {
    if ["true", "1", "y"].contains(&value) {
        Ok("true")
    } else if ["false", "0", "n"].contains(&value) {
        Ok("false")
    } else {
        Err(())
    }
}

fn is_boolean_string(value: &VariableType) -> Result<&str, ()> {
    if let VariableType::Str(ref value) = *value {
        is_boolean(&value.as_str())
    } else {
        unreachable!()
    }
}

fn is_integer_string(value: VariableType) -> Result<VariableType, ()> {
    let is_ok = if let VariableType::Str(ref num) = value {
        num.parse::<i64>().is_ok()
    } else {
        unreachable!()
    };

    if is_ok {
        Ok(value)
    } else {
        Err(())
    }
}

fn is_float_string(value: VariableType) -> Result<VariableType, ()> {
    let is_ok = if let VariableType::Str(ref num) = value {
        num.parse::<f64>().is_ok()
    } else {
        unreachable!()
    };

    if is_ok {
        Ok(value)
    } else {
        Err(())
    }
}

fn is_boolean_array(values: &mut VariableType) -> bool {
    if let VariableType::Array(ref mut values) = *values {
        for element in values.iter_mut() {
            let boolean = {
                match is_boolean(&element) {
                    Ok(boolean) => boolean.into(),
                    Err(()) => return false,
                }
            };
            *element = boolean;
        }
        true
    } else {
        unreachable!()
    }
}

fn is_integer_array(value: VariableType) -> Result<VariableType, ()> {
    let is_ok = if let VariableType::Array(ref nums) = value {
        nums.iter().all(|num| num.parse::<i64>().is_ok())
    } else {
        unreachable!()
    };

    if is_ok {
        Ok(value)
    } else {
        Err(())
    }
}

fn is_float_array(value: VariableType) -> Result<VariableType, ()> {
    let is_ok = if let VariableType::Array(ref nums) = value {
        nums.iter().all(|num| num.parse::<f64>().is_ok())
    } else {
        unreachable!()
    };

    if is_ok {
        Ok(value)
    } else {
        Err(())
    }
}

fn get_string<E: Expander>(shell: &E, value: &str) -> VariableType {
    VariableType::Str(types::Str::from(expand_string(value, shell, false).join(" ")))
}

fn get_array<E: Expander>(shell: &E, value: &str) -> VariableType {
    VariableType::Array(expand_string(value, shell, false))
}

fn get_hash_map<E: Expander>(
    shell: &E,
    expression: &str,
    inner_kind: &Primitive,
) -> Result<VariableType, TypeError> {
    let array = expand_string(expression, shell, false);
    let mut hmap = types::HashMap::with_capacity_and_hasher(array.len(), Default::default());

    for string in array {
        if let Some(found) = string.find('=') {
            let key = &string[..found];
            let value = &string[found + 1..];
            match value_check(shell, value, inner_kind) {
                Ok(VariableType::Str(str_)) => {
                    hmap.insert(key.into(), VariableType::Str(str_));
                }
                Ok(VariableType::Array(array)) => {
                    hmap.insert(key.into(), VariableType::Array(array));
                }
                Ok(VariableType::HashMap(map)) => {
                    hmap.insert(key.into(), VariableType::HashMap(map));
                }
                Ok(VariableType::BTreeMap(map)) => {
                    hmap.insert(key.into(), VariableType::BTreeMap(map));
                }
                Err(type_error) => return Err(type_error),
                _ => (),
            }
        } else {
            return Err(TypeError::BadValue(inner_kind.clone()));
        }
    }

    Ok(VariableType::HashMap(hmap))
}

fn get_btree_map<E: Expander>(
    shell: &E,
    expression: &str,
    inner_kind: &Primitive,
) -> Result<VariableType, TypeError> {
    let array = expand_string(expression, shell, false);
    let mut bmap = types::BTreeMap::new();

    for string in array {
        if let Some(found) = string.find('=') {
            let key = &string[..found];
            let value = &string[found + 1..];
            match value_check(shell, value, inner_kind) {
                Ok(VariableType::Str(str_)) => {
                    bmap.insert(key.into(), VariableType::Str(str_));
                }
                Ok(VariableType::Array(array)) => {
                    bmap.insert(key.into(), VariableType::Array(array));
                }
                Ok(VariableType::HashMap(map)) => {
                    bmap.insert(key.into(), VariableType::HashMap(map));
                }
                Ok(VariableType::BTreeMap(map)) => {
                    bmap.insert(key.into(), VariableType::BTreeMap(map));
                }
                Err(type_error) => return Err(type_error),
                _ => (),
            }
        } else {
            return Err(TypeError::BadValue(inner_kind.clone()));
        }
    }

    Ok(VariableType::BTreeMap(bmap))
}

pub(crate) fn value_check<E: Expander>(
    shell: &E,
    value: &str,
    expected: &Primitive,
) -> Result<VariableType, TypeError> {
    macro_rules! get_string {
        () => {
            get_string(shell, value)
        };
    }
    macro_rules! get_array {
        () => {
            get_array(shell, value)
        };
    }
    let is_array = is_array(value);
    match expected {
        Primitive::Any if is_array => Ok(get_array!()),
        Primitive::Any => Ok(get_string!()),
        Primitive::AnyArray if is_array => Ok(get_array!()),
        Primitive::Str if !is_array => Ok(get_string!()),
        Primitive::StrArray if is_array => Ok(get_array!()),
        Primitive::Boolean if !is_array => {
            let value = get_string!();
            let value =
                is_boolean_string(&value).map_err(|_| TypeError::BadValue(expected.clone()))?;
            Ok(VariableType::Str(value.into()))
        }
        Primitive::BooleanArray if is_array => {
            let mut values = get_array!();
            if is_boolean_array(&mut values) {
                Ok(values)
            } else {
                Err(TypeError::BadValue(expected.clone()))
            }
        }
        Primitive::Integer if !is_array => {
            is_integer_string(get_string!()).map_err(|_| TypeError::BadValue(expected.clone()))
        }
        Primitive::IntegerArray if is_array => {
            is_integer_array(get_array!()).map_err(|_| TypeError::BadValue(expected.clone()))
        }
        Primitive::Float if !is_array => {
            is_float_string(get_string!()).map_err(|_| TypeError::BadValue(expected.clone()))
        }
        Primitive::FloatArray if is_array => {
            is_float_array(get_array!()).map_err(|_| TypeError::BadValue(expected.clone()))
        }
        Primitive::HashMap(ref kind) if is_array => get_hash_map(shell, value, kind),
        Primitive::BTreeMap(ref kind) if is_array => get_btree_map(shell, value, kind),
        Primitive::Indexed(_, ref kind) => value_check(shell, value, kind),
        _ => Err(TypeError::BadValue(expected.clone())),
    }
}

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

    #[test]
    fn is_array_() {
        assert!(is_array("[1 2 3]"));
        assert!(!is_array("[1 2 3][0]"));
        assert!(!is_array("string"));
        assert!(is_array("[1  [2 3]  4 [5 6]]"))
    }

    #[test]
    fn is_boolean_() {
        assert_eq!(is_boolean("1"), Ok("true"));
        assert_eq!(is_boolean("y"), Ok("true"));
        assert_eq!(is_boolean("true"), Ok("true"));
        assert_eq!(is_boolean("0"), Ok("false"));
        assert_eq!(is_boolean("n"), Ok("false"));
        assert_eq!(is_boolean("false"), Ok("false"));
        assert_eq!(is_boolean("other"), Err(()));
    }

    #[test]
    fn is_integer_array_() {
        let expected = Ok(VariableType::Array(array!["1", "2", "3"]));
        assert_eq!(is_integer_array(VariableType::Array(array!["1", "2", "3"])), expected);
        assert_eq!(is_integer_array(VariableType::Array(array!["1", "2", "three"])), Err(()));
    }
}
<commit_msg>Reduce lines of code in type checker<commit_after>use super::super::{expand_string, Expander};
use crate::{
    lexers::assignments::{Primitive, TypeError},
    shell::variables::VariableType,
    types,
};
use std::iter::Iterator;

#[derive(PartialEq, Clone, Copy, Debug)]
enum IsArrayHelper {
    Valid(usize),
    RootBracketClosed,
    Invalid,
}

/// Determines if the supplied value is either an array or a string.
///
/// - `[ 1 2 3 ]` = Array
/// - `[ 1 2 3 ][1]` = String
/// - `string` = String
pub(crate) fn is_array(value: &str) -> bool {
    if value.starts_with('[') && value.ends_with(']') {
        !value
            .chars()
            .scan(IsArrayHelper::Valid(0), |state, x| {
                // If previous iteration was RootBracketClosed or Invalid then indicate invalid
                if *state == IsArrayHelper::RootBracketClosed || *state == IsArrayHelper::Invalid {
                    *state = IsArrayHelper::Invalid;
                    return Some(*state);
                }

                if x == '[' {
                    if let IsArrayHelper::Valid(open) = *state {
                        *state = IsArrayHelper::Valid(open + 1);
                    }
                } else if x == ']' {
                    if let IsArrayHelper::Valid(open) = *state {
                        *state = IsArrayHelper::Valid(open - 1);
                    }
                }

                // if true, root bracket was closed
                // => any characters after this one indicate invalid array
                if *state == IsArrayHelper::Valid(0) {
                    *state = IsArrayHelper::RootBracketClosed;
                }

                Some(*state)
            })
            .any(|x| x == IsArrayHelper::Invalid)
    } else {
        false
    }
}

pub(crate) fn is_boolean(primitive_type: Primitive, value: &mut small::String) -> Result<&str, TypeError> {
    if ["true", "1", "y"].contains(&&**value) {
        value.clear();
        value.push_str("true");
        Ok(value.as_str())
    } else if ["false", "0", "n"].contains(&&**value) {
        value.clear();
        value.push_str("false");
        Ok(value.as_str())
    } else {
        Err(TypeError::BadValue(primitive_type))
    }
}

fn is_of(primitive_type: Primitive, value: &mut VariableType) -> Result<(), TypeError> {
    if let VariableType::Array(ref mut items) = value {
        match primitive_type {
            Primitive::BooleanArray => {
                for item in items.iter_mut() {
                    is_boolean(primitive_type.clone(), item)?;
                }
                return Ok(());
            }
            Primitive::IntegerArray => {
                let checks_out = items.iter().all(|num| num.parse::<i64>().is_ok());
                if checks_out {
                    return Ok(());
                }
            }
            Primitive::FloatArray => {
                let checks_out = items.iter().all(|num| num.parse::<f64>().is_ok());
                if checks_out {
                    return Ok(());
                }
            }
            _ => unreachable!(),
        }
    } else if let VariableType::Str(ref mut string) = value {
        match primitive_type {
            Primitive::Boolean => {
                is_boolean(primitive_type, string)?;
                return Ok(())
            }
            Primitive::Integer => if string.parse::<i64>().is_ok() {
                return Ok(());
            }
            Primitive::Float => if string.parse::<f64>().is_ok() {
                return Ok(());
            }
            _ => unreachable!(),
        }
    }
    Err(TypeError::BadValue(primitive_type))
}

fn get_string<E: Expander>(shell: &E, value: &str) -> VariableType {
    VariableType::Str(types::Str::from(expand_string(value, shell, false).join(" ")))
}

fn get_array<E: Expander>(shell: &E, value: &str) -> VariableType {
    VariableType::Array(expand_string(value, shell, false))
}

fn get_hash_map<E: Expander>(
    shell: &E,
    expression: &str,
    inner_kind: &Primitive,
) -> Result<VariableType, TypeError> {
    let array = expand_string(expression, shell, false);
    let mut hmap = types::HashMap::with_capacity_and_hasher(array.len(), Default::default());

    for string in array {
        if let Some(found) = string.find('=') {
            let key = &string[..found];
            let value = &string[found + 1..];
            match value_check(shell, value, inner_kind) {
                Ok(VariableType::Str(str_)) => {
                    hmap.insert(key.into(), VariableType::Str(str_));
                }
                Ok(VariableType::Array(array)) => {
                    hmap.insert(key.into(), VariableType::Array(array));
                }
                Ok(VariableType::HashMap(map)) => {
                    hmap.insert(key.into(), VariableType::HashMap(map));
                }
                Ok(VariableType::BTreeMap(map)) => {
                    hmap.insert(key.into(), VariableType::BTreeMap(map));
                }
                Err(type_error) => return Err(type_error),
                _ => (),
            }
        } else {
            return Err(TypeError::BadValue(inner_kind.clone()));
        }
    }

    Ok(VariableType::HashMap(hmap))
}

fn get_btree_map<E: Expander>(
    shell: &E,
    expression: &str,
    inner_kind: &Primitive,
) -> Result<VariableType, TypeError> {
    let array = expand_string(expression, shell, false);
    let mut bmap = types::BTreeMap::new();

    for string in array {
        if let Some(found) = string.find('=') {
            let key = &string[..found];
            let value = &string[found + 1..];
            match value_check(shell, value, inner_kind) {
                Ok(VariableType::Str(str_)) => {
                    bmap.insert(key.into(), VariableType::Str(str_));
                }
                Ok(VariableType::Array(array)) => {
                    bmap.insert(key.into(), VariableType::Array(array));
                }
                Ok(VariableType::HashMap(map)) => {
                    bmap.insert(key.into(), VariableType::HashMap(map));
                }
                Ok(VariableType::BTreeMap(map)) => {
                    bmap.insert(key.into(), VariableType::BTreeMap(map));
                }
                Err(type_error) => return Err(type_error),
                _ => (),
            }
        } else {
            return Err(TypeError::BadValue(inner_kind.clone()));
        }
    }

    Ok(VariableType::BTreeMap(bmap))
}

pub(crate) fn value_check<E: Expander>(
    shell: &E,
    value: &str,
    expected: &Primitive,
) -> Result<VariableType, TypeError> {
    macro_rules! get_string {
        () => {
            get_string(shell, value)
        };
    }
    macro_rules! get_array {
        () => {
            get_array(shell, value)
        };
    }
    let is_array = is_array(value);
    match expected {
        Primitive::Any if is_array => Ok(get_array!()),
        Primitive::Any => Ok(get_string!()),
        Primitive::AnyArray if is_array => Ok(get_array!()),
        Primitive::Str if !is_array => Ok(get_string!()),
        Primitive::StrArray if is_array => Ok(get_array!()),
        Primitive::Boolean | Primitive::Integer | Primitive::Float if !is_array => {
            let mut values = get_string!();
            is_of(expected.clone(), &mut values)?;
            Ok(values)
        }
        Primitive::BooleanArray | Primitive::IntegerArray | Primitive::FloatArray if is_array => {
            let mut values = get_array!();
            is_of(expected.clone(), &mut values)?;
            Ok(values)
        }
        Primitive::HashMap(ref kind) if is_array => get_hash_map(shell, value, kind),
        Primitive::BTreeMap(ref kind) if is_array => get_btree_map(shell, value, kind),
        Primitive::Indexed(_, ref kind) => value_check(shell, value, kind),
        _ => Err(TypeError::BadValue(expected.clone())),
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::types::Array;
    use lexers::TypeError;

    #[test]
    fn is_array_() {
        assert!(is_array("[1 2 3]"));
        assert!(!is_array("[1 2 3][0]"));
        assert!(!is_array("string"));
        assert!(is_array("[1  [2 3]  4 [5 6]]"))
    }

    #[test]
    fn is_boolean_() {
        assert_eq!(is_boolean(Primitive::Boolean, &mut small::String::from("1")),     Ok("true"));
        assert_eq!(is_boolean(Primitive::Boolean, &mut small::String::from("y")),     Ok("true"));
        assert_eq!(is_boolean(Primitive::Boolean, &mut small::String::from("true")),  Ok("true"));
        assert_eq!(is_boolean(Primitive::Boolean, &mut small::String::from("0")),     Ok("false"));
        assert_eq!(is_boolean(Primitive::Boolean, &mut small::String::from("n")),     Ok("false"));
        assert_eq!(is_boolean(Primitive::Boolean, &mut small::String::from("false")), Ok("false"));
        assert_eq!(is_boolean(Primitive::Boolean, &mut small::String::from("other")), Err(TypeError::BadValue(Primitive::Boolean)));
    }

    #[test]
    fn is_integer_array_() {
        assert_eq!(is_of(Primitive::IntegerArray, &mut VariableType::Array(array!["1", "2", "3"])), Ok(()));
        assert_eq!(is_of(Primitive::IntegerArray, &mut VariableType::Array(array!["1", "2", "three"])), Err(TypeError::BadValue(Primitive::IntegerArray)));
    }
}
<|endoftext|>


<commit_before>use crate::llvm;
use crate::llvm::archive_ro::ArchiveRO;
use crate::llvm::{mk_section_iter, False, ObjectFile};
use rustc::middle::cstore::MetadataLoader;
use rustc_target::spec::Target;

use log::debug;
use rustc_codegen_ssa::METADATA_FILENAME;
use rustc_data_structures::owning_ref::OwningRef;
use rustc_data_structures::rustc_erase_owner;

use rustc_fs_util::path_to_c_string;
use std::path::Path;
use std::slice;

pub use rustc_data_structures::sync::MetadataRef;

pub struct LlvmMetadataLoader;

impl MetadataLoader for LlvmMetadataLoader {
    fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<MetadataRef, String> {
        // Use ArchiveRO for speed here, it's backed by LLVM and uses mmap
        // internally to read the file. We also avoid even using a memcpy by
        // just keeping the archive along while the metadata is in use.
        let archive = ArchiveRO::open(filename).map(|ar| OwningRef::new(Box::new(ar))).map_err(|e| {
            debug!("llvm didn't like `{}`: {}", filename.display(), e);
            format!("failed to read rlib metadata in '{}': {}", filename.display(), e)
        })?;
        let buf: OwningRef<_, [u8]> = archive.try_map(|ar| {
            ar.iter()
                .filter_map(|s| s.ok())
                .find(|sect| sect.name() == Some(METADATA_FILENAME))
                .map(|s| s.data())
                .ok_or_else(|| {
                    debug!("didn't find '{}' in the archive", METADATA_FILENAME);
                    format!("failed to read rlib metadata: '{}'", filename.display())
                })
        })?;
        Ok(rustc_erase_owner!(buf))
    }

    fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String> {
        unsafe {
            let buf = path_to_c_string(filename);
            let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr())
                .ok_or_else(|| format!("error reading library: '{}'", filename.display()))?;
            let of = ObjectFile::new(mb).map(|of| OwningRef::new(Box::new(of))).ok_or_else(|| {
                format!("provided path not an object file: '{}'", filename.display())
            })?;
            let buf = of.try_map(|of| search_meta_section(of, target, filename))?;
            Ok(rustc_erase_owner!(buf))
        }
    }
}

fn search_meta_section<'a>(
    of: &'a ObjectFile,
    target: &Target,
    filename: &Path,
) -> Result<&'a [u8], String> {
    unsafe {
        let si = mk_section_iter(of.llof);
        while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
            let mut name_buf = None;
            let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf);
            let name = name_buf.map_or(
                String::new(), // We got a NULL ptr, ignore `name_len`.
                |buf| {
                    String::from_utf8(
                        slice::from_raw_parts(buf.as_ptr() as *const u8, name_len as usize)
                            .to_vec(),
                    )
                    .unwrap()
                },
            );
            debug!("get_metadata_section: name {}", name);
            if read_metadata_section_name(target) == name {
                let cbuf = llvm::LLVMGetSectionContents(si.llsi);
                let csz = llvm::LLVMGetSectionSize(si.llsi) as usize;
                // The buffer is valid while the object file is around
                let buf: &'a [u8] = slice::from_raw_parts(cbuf as *const u8, csz);
                return Ok(buf);
            }
            llvm::LLVMMoveToNextSection(si.llsi);
        }
    }
    Err(format!("metadata not found: '{}'", filename.display()))
}

pub fn metadata_section_name(target: &Target) -> &'static str {
    // Historical note:
    //
    // When using link.exe it was seen that the section name `.note.rustc`
    // was getting shortened to `.note.ru`, and according to the PE and COFF
    // specification:
    //
    // > Executable images do not use a string table and do not support
    // > section names longer than 8 characters
    //
    // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
    //
    // As a result, we choose a slightly shorter name! As to why
    // `.note.rustc` works on MinGW, that's another good question...

    if target.options.is_like_osx { "__DATA,.rustc" } else { ".rustc" }
}

fn read_metadata_section_name(_target: &Target) -> &'static str {
    ".rustc"
}
<commit_msg>Rustfmt<commit_after>use crate::llvm;
use crate::llvm::archive_ro::ArchiveRO;
use crate::llvm::{mk_section_iter, False, ObjectFile};
use rustc::middle::cstore::MetadataLoader;
use rustc_target::spec::Target;

use log::debug;
use rustc_codegen_ssa::METADATA_FILENAME;
use rustc_data_structures::owning_ref::OwningRef;
use rustc_data_structures::rustc_erase_owner;

use rustc_fs_util::path_to_c_string;
use std::path::Path;
use std::slice;

pub use rustc_data_structures::sync::MetadataRef;

pub struct LlvmMetadataLoader;

impl MetadataLoader for LlvmMetadataLoader {
    fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<MetadataRef, String> {
        // Use ArchiveRO for speed here, it's backed by LLVM and uses mmap
        // internally to read the file. We also avoid even using a memcpy by
        // just keeping the archive along while the metadata is in use.
        let archive =
            ArchiveRO::open(filename).map(|ar| OwningRef::new(Box::new(ar))).map_err(|e| {
                debug!("llvm didn't like `{}`: {}", filename.display(), e);
                format!("failed to read rlib metadata in '{}': {}", filename.display(), e)
            })?;
        let buf: OwningRef<_, [u8]> = archive.try_map(|ar| {
            ar.iter()
                .filter_map(|s| s.ok())
                .find(|sect| sect.name() == Some(METADATA_FILENAME))
                .map(|s| s.data())
                .ok_or_else(|| {
                    debug!("didn't find '{}' in the archive", METADATA_FILENAME);
                    format!("failed to read rlib metadata: '{}'", filename.display())
                })
        })?;
        Ok(rustc_erase_owner!(buf))
    }

    fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String> {
        unsafe {
            let buf = path_to_c_string(filename);
            let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr())
                .ok_or_else(|| format!("error reading library: '{}'", filename.display()))?;
            let of =
                ObjectFile::new(mb).map(|of| OwningRef::new(Box::new(of))).ok_or_else(|| {
                    format!("provided path not an object file: '{}'", filename.display())
                })?;
            let buf = of.try_map(|of| search_meta_section(of, target, filename))?;
            Ok(rustc_erase_owner!(buf))
        }
    }
}

fn search_meta_section<'a>(
    of: &'a ObjectFile,
    target: &Target,
    filename: &Path,
) -> Result<&'a [u8], String> {
    unsafe {
        let si = mk_section_iter(of.llof);
        while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
            let mut name_buf = None;
            let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf);
            let name = name_buf.map_or(
                String::new(), // We got a NULL ptr, ignore `name_len`.
                |buf| {
                    String::from_utf8(
                        slice::from_raw_parts(buf.as_ptr() as *const u8, name_len as usize)
                            .to_vec(),
                    )
                    .unwrap()
                },
            );
            debug!("get_metadata_section: name {}", name);
            if read_metadata_section_name(target) == name {
                let cbuf = llvm::LLVMGetSectionContents(si.llsi);
                let csz = llvm::LLVMGetSectionSize(si.llsi) as usize;
                // The buffer is valid while the object file is around
                let buf: &'a [u8] = slice::from_raw_parts(cbuf as *const u8, csz);
                return Ok(buf);
            }
            llvm::LLVMMoveToNextSection(si.llsi);
        }
    }
    Err(format!("metadata not found: '{}'", filename.display()))
}

pub fn metadata_section_name(target: &Target) -> &'static str {
    // Historical note:
    //
    // When using link.exe it was seen that the section name `.note.rustc`
    // was getting shortened to `.note.ru`, and according to the PE and COFF
    // specification:
    //
    // > Executable images do not use a string table and do not support
    // > section names longer than 8 characters
    //
    // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
    //
    // As a result, we choose a slightly shorter name! As to why
    // `.note.rustc` works on MinGW, that's another good question...

    if target.options.is_like_osx { "__DATA,.rustc" } else { ".rustc" }
}

fn read_metadata_section_name(_target: &Target) -> &'static str {
    ".rustc"
}
<|endoftext|>


<commit_before>use crate::fmt;
use crate::ops::Try;

use super::super::{Iterator, DoubleEndedIterator, FusedIterator};
use super::Map;

/// An iterator that maps each element to an iterator, and yields the elements
/// of the produced iterators.
///
/// This `struct` is created by the [`flat_map`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`flat_map`]: trait.Iterator.html#method.flat_map
/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct FlatMap<I, U: IntoIterator, F> {
    inner: FlattenCompat<Map<I, F>, <U as IntoIterator>::IntoIter>
}
impl<I: Iterator, U: IntoIterator, F: FnMut(I::Item) -> U> FlatMap<I, U, F> {
    pub(in super::super) fn new(iter: I, f: F) -> FlatMap<I, U, F> {
        FlatMap { inner: FlattenCompat::new(iter.map(f)) }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Clone, U, F: Clone> Clone for FlatMap<I, U, F>
where
    U: Clone + IntoIterator<IntoIter: Clone>,
{
    fn clone(&self) -> Self { FlatMap { inner: self.inner.clone() } }
}

#[stable(feature = "core_impl_debug", since = "1.9.0")]
impl<I: fmt::Debug, U, F> fmt::Debug for FlatMap<I, U, F>
where
    U: IntoIterator<IntoIter: fmt::Debug>,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("FlatMap").field("inner", &self.inner).finish()
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator, U: IntoIterator, F> Iterator for FlatMap<I, U, F>
    where F: FnMut(I::Item) -> U,
{
    type Item = U::Item;

    #[inline]
    fn next(&mut self) -> Option<U::Item> { self.inner.next() }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) { self.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.inner.try_fold(init, fold)
    }

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

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: DoubleEndedIterator, U, F> DoubleEndedIterator for FlatMap<I, U, F>
where
    F: FnMut(I::Item) -> U,
    U: IntoIterator,
    U::IntoIter: DoubleEndedIterator,
{
    #[inline]
    fn next_back(&mut self) -> Option<U::Item> { self.inner.next_back() }

    #[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.inner.try_rfold(init, fold)
    }

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

#[stable(feature = "fused", since = "1.26.0")]
impl<I, U, F> FusedIterator for FlatMap<I, U, F>
    where I: FusedIterator, U: IntoIterator, F: FnMut(I::Item) -> U {}

/// An iterator that flattens one level of nesting in an iterator of things
/// that can be turned into iterators.
///
/// This `struct` is created by the [`flatten`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`flatten`]: trait.Iterator.html#method.flatten
/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "iterator_flatten", since = "1.29.0")]
pub struct Flatten<I: Iterator>
where
    I::Item: IntoIterator,
{
    inner: FlattenCompat<I, <I::Item as IntoIterator>::IntoIter>,
}

impl<I: Iterator<Item: IntoIterator>> Flatten<I> {
    pub(in super::super) fn new(iter: I) -> Flatten<I> {
        Flatten { inner: FlattenCompat::new(iter) }
    }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> fmt::Debug for Flatten<I>
where
    I: fmt::Debug + Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: fmt::Debug + Iterator,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Flatten").field("inner", &self.inner).finish()
    }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> Clone for Flatten<I>
where
    I: Clone + Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: Clone + Iterator,
{
    fn clone(&self) -> Self { Flatten { inner: self.inner.clone() } }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> Iterator for Flatten<I>
where
    I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: Iterator,
{
    type Item = U::Item;

    #[inline]
    fn next(&mut self) -> Option<U::Item> { self.inner.next() }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) { self.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.inner.try_fold(init, fold)
    }

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

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> DoubleEndedIterator for Flatten<I>
where
    I: DoubleEndedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: DoubleEndedIterator,
{
    #[inline]
    fn next_back(&mut self) -> Option<U::Item> { self.inner.next_back() }

    #[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.inner.try_rfold(init, fold)
    }

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

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> FusedIterator for Flatten<I>
where
    I: FusedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: Iterator,
{}

/// Real logic of both `Flatten` and `FlatMap` which simply delegate to
/// this type.
#[derive(Clone, Debug)]
struct FlattenCompat<I, U> {
    iter: I,
    frontiter: Option<U>,
    backiter: Option<U>,
}
impl<I, U> FlattenCompat<I, U> {
    /// Adapts an iterator by flattening it, for use in `flatten()` and `flat_map()`.
    fn new(iter: I) -> FlattenCompat<I, U> {
        FlattenCompat { iter, frontiter: None, backiter: None }
    }
}

impl<I, U> Iterator for FlattenCompat<I, U>
where
    I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: Iterator,
{
    type Item = U::Item;

    #[inline]
    fn next(&mut self) -> Option<U::Item> {
        loop {
            if let Some(ref mut inner) = self.frontiter {
                if let elt@Some(_) = inner.next() { return elt }
            }
            match self.iter.next() {
                None => return self.backiter.as_mut().and_then(|it| it.next()),
                Some(inner) => self.frontiter = Some(inner.into_iter()),
            }
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let (flo, fhi) = self.frontiter.as_ref().map_or((0, Some(0)), |it| it.size_hint());
        let (blo, bhi) = self.backiter.as_ref().map_or((0, Some(0)), |it| it.size_hint());
        let lo = flo.saturating_add(blo);
        match (self.iter.size_hint(), fhi, bhi) {
            ((0, Some(0)), Some(a), Some(b)) => (lo, a.checked_add(b)),
            _ => (lo, None)
        }
    }

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

        {
            let frontiter = &mut self.frontiter;
            init = self.iter.try_fold(init, |acc, x| {
                let mut mid = x.into_iter();
                let r = mid.try_fold(acc, &mut fold);
                *frontiter = Some(mid);
                r
            })?;
        }
        self.frontiter = None;

        if let Some(ref mut back) = self.backiter {
            init = back.try_fold(init, &mut fold)?;
        }
        self.backiter = None;

        Try::from_ok(init)
    }

    #[inline]
    fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
        where Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        self.frontiter.into_iter()
            .chain(self.iter.map(IntoIterator::into_iter))
            .chain(self.backiter)
            .fold(init, |acc, iter| iter.fold(acc, &mut fold))
    }
}

impl<I, U> DoubleEndedIterator for FlattenCompat<I, U>
where
    I: DoubleEndedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: DoubleEndedIterator,
{
    #[inline]
    fn next_back(&mut self) -> Option<U::Item> {
        loop {
            if let Some(ref mut inner) = self.backiter {
                if let elt@Some(_) = inner.next_back() { return elt }
            }
            match self.iter.next_back() {
                None => return self.frontiter.as_mut().and_then(|it| it.next_back()),
                next => self.backiter = next.map(IntoIterator::into_iter),
            }
        }
    }

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

        {
            let backiter = &mut self.backiter;
            init = self.iter.try_rfold(init, |acc, x| {
                let mut mid = x.into_iter();
                let r = mid.try_rfold(acc, &mut fold);
                *backiter = Some(mid);
                r
            })?;
        }
        self.backiter = None;

        if let Some(ref mut front) = self.frontiter {
            init = front.try_rfold(init, &mut fold)?;
        }
        self.frontiter = None;

        Try::from_ok(init)
    }

    #[inline]
    fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
        where Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        self.frontiter.into_iter()
            .chain(self.iter.map(IntoIterator::into_iter))
            .chain(self.backiter)
            .rfold(init, |acc, iter| iter.rfold(acc, &mut fold))
    }
}
<commit_msg>Reduce genericity in FlattenCompat<commit_after>use crate::fmt;
use crate::ops::Try;

use super::super::{Iterator, DoubleEndedIterator, FusedIterator};
use super::Map;

/// An iterator that maps each element to an iterator, and yields the elements
/// of the produced iterators.
///
/// This `struct` is created by the [`flat_map`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`flat_map`]: trait.Iterator.html#method.flat_map
/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct FlatMap<I, U: IntoIterator, F> {
    inner: FlattenCompat<Map<I, F>, <U as IntoIterator>::IntoIter>
}
impl<I: Iterator, U: IntoIterator, F: FnMut(I::Item) -> U> FlatMap<I, U, F> {
    pub(in super::super) fn new(iter: I, f: F) -> FlatMap<I, U, F> {
        FlatMap { inner: FlattenCompat::new(iter.map(f)) }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Clone, U, F: Clone> Clone for FlatMap<I, U, F>
where
    U: Clone + IntoIterator<IntoIter: Clone>,
{
    fn clone(&self) -> Self { FlatMap { inner: self.inner.clone() } }
}

#[stable(feature = "core_impl_debug", since = "1.9.0")]
impl<I: fmt::Debug, U, F> fmt::Debug for FlatMap<I, U, F>
where
    U: IntoIterator<IntoIter: fmt::Debug>,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("FlatMap").field("inner", &self.inner).finish()
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator, U: IntoIterator, F> Iterator for FlatMap<I, U, F>
    where F: FnMut(I::Item) -> U,
{
    type Item = U::Item;

    #[inline]
    fn next(&mut self) -> Option<U::Item> { self.inner.next() }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) { self.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.inner.try_fold(init, fold)
    }

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

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: DoubleEndedIterator, U, F> DoubleEndedIterator for FlatMap<I, U, F>
where
    F: FnMut(I::Item) -> U,
    U: IntoIterator,
    U::IntoIter: DoubleEndedIterator,
{
    #[inline]
    fn next_back(&mut self) -> Option<U::Item> { self.inner.next_back() }

    #[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.inner.try_rfold(init, fold)
    }

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

#[stable(feature = "fused", since = "1.26.0")]
impl<I, U, F> FusedIterator for FlatMap<I, U, F>
    where I: FusedIterator, U: IntoIterator, F: FnMut(I::Item) -> U {}

/// An iterator that flattens one level of nesting in an iterator of things
/// that can be turned into iterators.
///
/// This `struct` is created by the [`flatten`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`flatten`]: trait.Iterator.html#method.flatten
/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "iterator_flatten", since = "1.29.0")]
pub struct Flatten<I: Iterator>
where
    I::Item: IntoIterator,
{
    inner: FlattenCompat<I, <I::Item as IntoIterator>::IntoIter>,
}

impl<I: Iterator<Item: IntoIterator>> Flatten<I> {
    pub(in super::super) fn new(iter: I) -> Flatten<I> {
        Flatten { inner: FlattenCompat::new(iter) }
    }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> fmt::Debug for Flatten<I>
where
    I: fmt::Debug + Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: fmt::Debug + Iterator,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Flatten").field("inner", &self.inner).finish()
    }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> Clone for Flatten<I>
where
    I: Clone + Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: Clone + Iterator,
{
    fn clone(&self) -> Self { Flatten { inner: self.inner.clone() } }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> Iterator for Flatten<I>
where
    I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: Iterator,
{
    type Item = U::Item;

    #[inline]
    fn next(&mut self) -> Option<U::Item> { self.inner.next() }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) { self.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.inner.try_fold(init, fold)
    }

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

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> DoubleEndedIterator for Flatten<I>
where
    I: DoubleEndedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: DoubleEndedIterator,
{
    #[inline]
    fn next_back(&mut self) -> Option<U::Item> { self.inner.next_back() }

    #[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.inner.try_rfold(init, fold)
    }

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

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> FusedIterator for Flatten<I>
where
    I: FusedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: Iterator,
{}

/// Real logic of both `Flatten` and `FlatMap` which simply delegate to
/// this type.
#[derive(Clone, Debug)]
struct FlattenCompat<I, U> {
    iter: I,
    frontiter: Option<U>,
    backiter: Option<U>,
}
impl<I, U> FlattenCompat<I, U> {
    /// Adapts an iterator by flattening it, for use in `flatten()` and `flat_map()`.
    fn new(iter: I) -> FlattenCompat<I, U> {
        FlattenCompat { iter, frontiter: None, backiter: None }
    }
}

impl<I, U> Iterator for FlattenCompat<I, U>
where
    I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: Iterator,
{
    type Item = U::Item;

    #[inline]
    fn next(&mut self) -> Option<U::Item> {
        loop {
            if let Some(ref mut inner) = self.frontiter {
                if let elt@Some(_) = inner.next() { return elt }
            }
            match self.iter.next() {
                None => return self.backiter.as_mut()?.next(),
                Some(inner) => self.frontiter = Some(inner.into_iter()),
            }
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let (flo, fhi) = self.frontiter.as_ref().map_or((0, Some(0)), U::size_hint);
        let (blo, bhi) = self.backiter.as_ref().map_or((0, Some(0)), U::size_hint);
        let lo = flo.saturating_add(blo);
        match (self.iter.size_hint(), fhi, bhi) {
            ((0, Some(0)), Some(a), Some(b)) => (lo, a.checked_add(b)),
            _ => (lo, None)
        }
    }

    #[inline]
    fn try_fold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R where
        Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
    {
        #[inline]
        fn flatten<'a, T: IntoIterator, Acc, R: Try<Ok = Acc>>(
            frontiter: &'a mut Option<T::IntoIter>,
            fold: &'a mut impl FnMut(Acc, T::Item) -> R,
        ) -> impl FnMut(Acc, T) -> R + 'a {
            move |acc, x| {
                let mut mid = x.into_iter();
                let r = mid.try_fold(acc, &mut *fold);
                *frontiter = Some(mid);
                r
            }
        }

        if let Some(ref mut front) = self.frontiter {
            init = front.try_fold(init, &mut fold)?;
        }
        self.frontiter = None;

        init = self.iter.try_fold(init, flatten(&mut self.frontiter, &mut fold))?;
        self.frontiter = None;

        if let Some(ref mut back) = self.backiter {
            init = back.try_fold(init, &mut fold)?;
        }
        self.backiter = None;

        Try::from_ok(init)
    }

    #[inline]
    fn fold<Acc, Fold>(self, init: Acc, ref mut fold: Fold) -> Acc
        where Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        #[inline]
        fn flatten<U: Iterator, Acc>(
            fold: &mut impl FnMut(Acc, U::Item) -> Acc,
        ) -> impl FnMut(Acc, U) -> Acc + '_ {
            move |acc, iter| iter.fold(acc, &mut *fold)
        }

        self.frontiter.into_iter()
            .chain(self.iter.map(IntoIterator::into_iter))
            .chain(self.backiter)
            .fold(init, flatten(fold))
    }
}

impl<I, U> DoubleEndedIterator for FlattenCompat<I, U>
where
    I: DoubleEndedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: DoubleEndedIterator,
{
    #[inline]
    fn next_back(&mut self) -> Option<U::Item> {
        loop {
            if let Some(ref mut inner) = self.backiter {
                if let elt@Some(_) = inner.next_back() { return elt }
            }
            match self.iter.next_back() {
                None => return self.frontiter.as_mut()?.next_back(),
                next => self.backiter = next.map(IntoIterator::into_iter),
            }
        }
    }

    #[inline]
    fn try_rfold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R where
        Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
    {
        #[inline]
        fn flatten<'a, T: IntoIterator, Acc, R: Try<Ok = Acc>>(
            backiter: &'a mut Option<T::IntoIter>,
            fold: &'a mut impl FnMut(Acc, T::Item) -> R,
        ) -> impl FnMut(Acc, T) -> R + 'a where
            T::IntoIter: DoubleEndedIterator,
        {
            move |acc, x| {
                let mut mid = x.into_iter();
                let r = mid.try_rfold(acc, &mut *fold);
                *backiter = Some(mid);
                r
            }
        }

        if let Some(ref mut back) = self.backiter {
            init = back.try_rfold(init, &mut fold)?;
        }
        self.backiter = None;

        init = self.iter.try_rfold(init, flatten(&mut self.backiter, &mut fold))?;
        self.backiter = None;

        if let Some(ref mut front) = self.frontiter {
            init = front.try_rfold(init, &mut fold)?;
        }
        self.frontiter = None;

        Try::from_ok(init)
    }

    #[inline]
    fn rfold<Acc, Fold>(self, init: Acc, ref mut fold: Fold) -> Acc
        where Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        #[inline]
        fn flatten<U: DoubleEndedIterator, Acc>(
            fold: &mut impl FnMut(Acc, U::Item) -> Acc,
        ) -> impl FnMut(Acc, U) -> Acc + '_ {
            move |acc, iter| iter.rfold(acc, &mut *fold)
        }

        self.frontiter.into_iter()
            .chain(self.iter.map(IntoIterator::into_iter))
            .chain(self.backiter)
            .rfold(init, flatten(fold))
    }
}
<|endoftext|>