<commit_before>use std::io::Write;

use crate::error;
use itertools::Itertools;
use lazy_static::lazy_static;
use liquid_core::error::ResultLiquidReplaceExt;
use liquid_core::parser::TryMatchToken;
use liquid_core::Language;
use liquid_core::TagBlock;
use liquid_core::TagTokenIter;
use liquid_core::ValueView;
use liquid_core::{Renderable, Runtime};
use pulldown_cmark as cmark;
use pulldown_cmark::Event::{self, End, Html, Start, Text};

#[cfg(not(feature = "syntax-highlight"))]
use engarde::Raw as Highlight;
#[cfg(feature = "syntax-highlight")]
use engarde::Syntax as Highlight;

lazy_static! {
    static ref HIGHLIGHT: Highlight = Highlight::new();
}

#[cfg(feature = "syntax-highlight")]
pub fn has_syntax_theme(name: &str) -> error::Result<bool> {
    Ok(HIGHLIGHT.has_theme(name))
}

#[cfg(not(feature = "syntax-highlight"))]
pub fn has_syntax_theme(name: &str) -> error::Result<bool> {
    failure::bail!("Themes are unsupported in this build.");
}

pub fn verify_theme(theme: Option<&str>) -> error::Result<()> {
    if let Some(theme) = &theme {
        match has_syntax_theme(theme) {
            Ok(true) => {}
            Ok(false) => failure::bail!("Syntax theme '{}' is unsupported", theme),
            Err(err) => {
                log::warn!("Syntax theme named '{}' ignored. Reason: {}", theme, err);
            }
        };
    }
    Ok(())
}

pub fn list_syntax_themes() -> Vec<String> {
    HIGHLIGHT.themes().collect()
}

pub fn list_syntaxes() -> Vec<String> {
    HIGHLIGHT.syntaxes().collect()
}

#[derive(Clone, Debug)]
struct CodeBlock {
    lang: Option<liquid::model::KString>,
    code: String,
    theme: Option<liquid::model::KString>,
}

impl Renderable for CodeBlock {
    fn render_to(
        &self,
        writer: &mut dyn Write,
        _context: &dyn Runtime,
    ) -> Result<(), liquid_core::Error> {
        write!(
            writer,
            "{}",
            HIGHLIGHT.format(&self.code, self.lang.as_deref(), self.theme.as_deref())
        )
        .replace("Failed to render")?;

        Ok(())
    }
}

#[derive(Clone, Debug)]
pub struct CodeBlockParser {
    syntax_theme: Option<liquid::model::KString>,
}

impl CodeBlockParser {
    pub fn new(theme: Option<liquid::model::KString>) -> error::Result<Self> {
        verify_theme(theme.as_deref())?;
        Ok(Self {
            syntax_theme: theme,
        })
    }
}

impl liquid_core::BlockReflection for CodeBlockParser {
    fn start_tag(&self) -> &'static str {
        "highlight"
    }

    fn end_tag(&self) -> &'static str {
        "endhighlight"
    }

    fn description(&self) -> &'static str {
        "Syntax highlight code using HTML"
    }
}

impl liquid_core::ParseBlock for CodeBlockParser {
    fn reflection(&self) -> &dyn liquid_core::BlockReflection {
        self
    }

    fn parse(
        &self,
        mut arguments: TagTokenIter<'_>,
        mut tokens: TagBlock<'_, '_>,
        _options: &Language,
    ) -> Result<Box<dyn Renderable>, liquid_core::Error> {
        let lang = arguments
            .expect_next("Identifier or literal expected.")
            .ok()
            .map(|lang| {
                // This may accept strange inputs such as `{% include 0 %}` or `{% include filterchain | filter:0 %}`.
                // Those inputs would fail anyway by there being not a path with those langs so they are not a big concern.
                match lang.expect_literal() {
                    // Using `to_str()` on literals ensures `Strings` will have their quotes trimmed.
                    TryMatchToken::Matches(lang) => lang.to_kstr().into_owned(),
                    TryMatchToken::Fails(lang) => liquid::model::KString::from_ref(lang.as_str()),
                }
            });
        // no more arguments should be supplied, trying to supply them is an error
        arguments.expect_nothing()?;

        let mut content = String::new();
        while let Some(element) = tokens.next()? {
            content.push_str(element.as_str());
        }
        tokens.assert_empty();

        Ok(Box::new(CodeBlock {
            code: content,
            lang,
            theme: self.syntax_theme.clone(),
        }))
    }
}

pub struct DecoratedParser<'a> {
    parser: cmark::Parser<'a, 'a>,
    theme: Option<&'a str>,
    lang: Option<String>,
    code: Option<Vec<pulldown_cmark::CowStr<'a>>>,
}

impl<'a> DecoratedParser<'a> {
    pub fn new(parser: cmark::Parser<'a, 'a>, theme: Option<&'a str>) -> error::Result<Self> {
        verify_theme(theme)?;
        Ok(DecoratedParser {
            parser,
            theme,
            lang: None,
            code: None,
        })
    }
}

impl<'a> Iterator for DecoratedParser<'a> {
    type Item = Event<'a>;

    fn next(&mut self) -> Option<Event<'a>> {
        match self.parser.next() {
            Some(Text(text)) => {
                if let Some(ref mut code) = self.code {
                    code.push(text);
                    Some(Text(pulldown_cmark::CowStr::Borrowed("")))
                } else {
                    Some(Text(text))
                }
            }
            Some(Start(cmark::Tag::CodeBlock(info))) => {
                let tag = match info {
                    pulldown_cmark::CodeBlockKind::Indented => "",
                    pulldown_cmark::CodeBlockKind::Fenced(ref tag) => tag.as_ref(),
                };
                self.lang = tag.split(' ').map(|s| s.to_owned()).next();
                self.code = Some(vec![]);
                Some(Text(pulldown_cmark::CowStr::Borrowed("")))
            }
            Some(End(cmark::Tag::CodeBlock(_))) => {
                let html = if let Some(code) = self.code.as_deref() {
                    let code = code.iter().join("\n");
                    HIGHLIGHT.format(&code, self.lang.as_deref(), self.theme)
                } else {
                    HIGHLIGHT.format("", self.lang.as_deref(), self.theme)
                };
                // reset highlighter
                self.lang = None;
                self.code = None;
                // close the code block
                Some(Html(pulldown_cmark::CowStr::Boxed(html.into_boxed_str())))
            }
            item => item,
        }
    }
}

pub fn decorate_markdown<'a>(
    parser: cmark::Parser<'a, 'a>,
    theme_name: Option<&'a str>,
) -> error::Result<DecoratedParser<'a>> {
    DecoratedParser::new(parser, theme_name)
}

#[cfg(test)]
#[cfg(feature = "syntax-highlight")]
mod test_syntsx {
    use super::*;

    const CODE_BLOCK: &str = "mod test {
        fn hello(arg: int) -> bool {
            \
                                      true
        }
    }
    ";

    const CODEBLOCK_RENDERED: &str =
        "
\n\
         mod \
         test {\n\
                 \
         fn \
         hello(\
         arg: int) -> \
         bool {\n\
                     \
         true\n\
                 }\n\
             }\n\

\n";

    #[test]
    fn highlight_block_renders_rust() {
        let highlight: Box<dyn liquid_core::ParseBlock> =
            Box::new(CodeBlockParser::new(Some("base16-ocean.dark".into())).unwrap());
        let parser = liquid::ParserBuilder::new()
            .block(highlight)
            .build()
            .unwrap();
        let template = parser
            .parse(&format!(
                "{{% highlight rust %}}{}{{% endhighlight %}}",
                CODE_BLOCK
            ))
            .unwrap();
        let output = template.render(&liquid::Object::new());
        snapbox::assert_eq(CODEBLOCK_RENDERED, &output.unwrap());
    }

    const MARKDOWN_RENDERED: &str =
        "
\n\
         mod \
         test {\n\
                 \
         fn \
         hello(\
         arg: int) -> \
         bool {\n\
                     \
         true\n\
                 }\n\
             }\n\
             \n\

\n";

    #[test]
    fn markdown_renders_rust() {
        let html = format!(
            "```rust
{}
```",
            CODE_BLOCK
        );

        let mut buf = String::new();
        let parser = cmark::Parser::new(&html);
        cmark::html::push_html(
            &mut buf,
            decorate_markdown(parser, Some("base16-ocean.dark")).unwrap(),
        );
        snapbox::assert_eq(MARKDOWN_RENDERED, &buf);
    }
}

#[cfg(test)]
#[cfg(not(feature = "syntax-highlight"))]
mod test_raw {
    use super::*;

    const CODE_BLOCK: &str = "mod test {
        fn hello(arg: int) -> bool {
            \
                                      true
        }
    }
";

    const CODEBLOCK_RENDERED: &str = r#"
mod test {
        fn hello(arg: int) -> bool {
            true
        }
    }

"#;

    #[test]
    fn codeblock_renders_rust() {
        let highlight: Box<dyn liquid_core::ParseBlock> =
            Box::new(CodeBlockParser::new("base16-ocean.dark".into()));
        let parser = liquid::ParserBuilder::new()
            .block(highlight)
            .build()
            .unwrap();
        let template = parser
            .parse(&format!(
                "{{% highlight rust %}}{}{{% endhighlight %}}",
                CODE_BLOCK
            ))
            .unwrap();
        let output = template.render(&liquid::Object::new());
        assert_eq!(output.unwrap(), CODEBLOCK_RENDERED.to_string());
    }

    const MARKDOWN_RENDERED: &str = r#"
mod test {
        fn hello(arg: int) -> bool {
            true
        }
    }

"#;

    #[test]
    fn decorate_markdown_renders_rust() {
        let html = format!(
            "```rust
{}
```",
            CODE_BLOCK
        );

        let mut buf = String::new();
        let parser = cmark::Parser::new(&html);
        cmark::html::push_html(
            &mut buf,
            decorate_markdown(parser, Some("base16-ocean.dark")),
        );
        assert_eq!(buf, MARKDOWN_RENDERED);
    }
}
<commit_msg>refactor: Reduce visibility of highlight functions<commit_after>use std::io::Write;

use crate::error;
use itertools::Itertools;
use lazy_static::lazy_static;
use liquid_core::error::ResultLiquidReplaceExt;
use liquid_core::parser::TryMatchToken;
use liquid_core::Language;
use liquid_core::TagBlock;
use liquid_core::TagTokenIter;
use liquid_core::ValueView;
use liquid_core::{Renderable, Runtime};
use pulldown_cmark as cmark;
use pulldown_cmark::Event::{self, End, Html, Start, Text};

#[cfg(not(feature = "syntax-highlight"))]
use engarde::Raw as Highlight;
#[cfg(feature = "syntax-highlight")]
use engarde::Syntax as Highlight;

lazy_static! {
    static ref HIGHLIGHT: Highlight = Highlight::new();
}

#[cfg(feature = "syntax-highlight")]
fn has_syntax_theme(name: &str) -> error::Result<bool> {
    Ok(HIGHLIGHT.has_theme(name))
}

#[cfg(not(feature = "syntax-highlight"))]
fn has_syntax_theme(name: &str) -> error::Result<bool> {
    failure::bail!("Themes are unsupported in this build.");
}

fn verify_theme(theme: Option<&str>) -> error::Result<()> {
    if let Some(theme) = &theme {
        match has_syntax_theme(theme) {
            Ok(true) => {}
            Ok(false) => failure::bail!("Syntax theme '{}' is unsupported", theme),
            Err(err) => {
                log::warn!("Syntax theme named '{}' ignored. Reason: {}", theme, err);
            }
        };
    }
    Ok(())
}

pub fn list_syntax_themes() -> Vec<String> {
    HIGHLIGHT.themes().collect()
}

pub fn list_syntaxes() -> Vec<String> {
    HIGHLIGHT.syntaxes().collect()
}

#[derive(Clone, Debug)]
struct CodeBlock {
    lang: Option<liquid::model::KString>,
    code: String,
    theme: Option<liquid::model::KString>,
}

impl Renderable for CodeBlock {
    fn render_to(
        &self,
        writer: &mut dyn Write,
        _context: &dyn Runtime,
    ) -> Result<(), liquid_core::Error> {
        write!(
            writer,
            "{}",
            HIGHLIGHT.format(&self.code, self.lang.as_deref(), self.theme.as_deref())
        )
        .replace("Failed to render")?;

        Ok(())
    }
}

#[derive(Clone, Debug)]
pub struct CodeBlockParser {
    syntax_theme: Option<liquid::model::KString>,
}

impl CodeBlockParser {
    pub fn new(theme: Option<liquid::model::KString>) -> error::Result<Self> {
        verify_theme(theme.as_deref())?;
        Ok(Self {
            syntax_theme: theme,
        })
    }
}

impl liquid_core::BlockReflection for CodeBlockParser {
    fn start_tag(&self) -> &'static str {
        "highlight"
    }

    fn end_tag(&self) -> &'static str {
        "endhighlight"
    }

    fn description(&self) -> &'static str {
        "Syntax highlight code using HTML"
    }
}

impl liquid_core::ParseBlock for CodeBlockParser {
    fn reflection(&self) -> &dyn liquid_core::BlockReflection {
        self
    }

    fn parse(
        &self,
        mut arguments: TagTokenIter<'_>,
        mut tokens: TagBlock<'_, '_>,
        _options: &Language,
    ) -> Result<Box<dyn Renderable>, liquid_core::Error> {
        let lang = arguments
            .expect_next("Identifier or literal expected.")
            .ok()
            .map(|lang| {
                // This may accept strange inputs such as `{% include 0 %}` or `{% include filterchain | filter:0 %}`.
                // Those inputs would fail anyway by there being not a path with those langs so they are not a big concern.
                match lang.expect_literal() {
                    // Using `to_str()` on literals ensures `Strings` will have their quotes trimmed.
                    TryMatchToken::Matches(lang) => lang.to_kstr().into_owned(),
                    TryMatchToken::Fails(lang) => liquid::model::KString::from_ref(lang.as_str()),
                }
            });
        // no more arguments should be supplied, trying to supply them is an error
        arguments.expect_nothing()?;

        let mut content = String::new();
        while let Some(element) = tokens.next()? {
            content.push_str(element.as_str());
        }
        tokens.assert_empty();

        Ok(Box::new(CodeBlock {
            code: content,
            lang,
            theme: self.syntax_theme.clone(),
        }))
    }
}

pub struct DecoratedParser<'a> {
    parser: cmark::Parser<'a, 'a>,
    theme: Option<&'a str>,
    lang: Option<String>,
    code: Option<Vec<pulldown_cmark::CowStr<'a>>>,
}

impl<'a> DecoratedParser<'a> {
    pub fn new(parser: cmark::Parser<'a, 'a>, theme: Option<&'a str>) -> error::Result<Self> {
        verify_theme(theme)?;
        Ok(DecoratedParser {
            parser,
            theme,
            lang: None,
            code: None,
        })
    }
}

impl<'a> Iterator for DecoratedParser<'a> {
    type Item = Event<'a>;

    fn next(&mut self) -> Option<Event<'a>> {
        match self.parser.next() {
            Some(Text(text)) => {
                if let Some(ref mut code) = self.code {
                    code.push(text);
                    Some(Text(pulldown_cmark::CowStr::Borrowed("")))
                } else {
                    Some(Text(text))
                }
            }
            Some(Start(cmark::Tag::CodeBlock(info))) => {
                let tag = match info {
                    pulldown_cmark::CodeBlockKind::Indented => "",
                    pulldown_cmark::CodeBlockKind::Fenced(ref tag) => tag.as_ref(),
                };
                self.lang = tag.split(' ').map(|s| s.to_owned()).next();
                self.code = Some(vec![]);
                Some(Text(pulldown_cmark::CowStr::Borrowed("")))
            }
            Some(End(cmark::Tag::CodeBlock(_))) => {
                let html = if let Some(code) = self.code.as_deref() {
                    let code = code.iter().join("\n");
                    HIGHLIGHT.format(&code, self.lang.as_deref(), self.theme)
                } else {
                    HIGHLIGHT.format("", self.lang.as_deref(), self.theme)
                };
                // reset highlighter
                self.lang = None;
                self.code = None;
                // close the code block
                Some(Html(pulldown_cmark::CowStr::Boxed(html.into_boxed_str())))
            }
            item => item,
        }
    }
}

pub fn decorate_markdown<'a>(
    parser: cmark::Parser<'a, 'a>,
    theme_name: Option<&'a str>,
) -> error::Result<DecoratedParser<'a>> {
    DecoratedParser::new(parser, theme_name)
}

#[cfg(test)]
#[cfg(feature = "syntax-highlight")]
mod test_syntsx {
    use super::*;

    const CODE_BLOCK: &str = "mod test {
        fn hello(arg: int) -> bool {
            \
                                      true
        }
    }
    ";

    const CODEBLOCK_RENDERED: &str =
        "
\n\
         mod \
         test {\n\
                 \
         fn \
         hello(\
         arg: int) -> \
         bool {\n\
                     \
         true\n\
                 }\n\
             }\n\

\n";

    #[test]
    fn highlight_block_renders_rust() {
        let highlight: Box<dyn liquid_core::ParseBlock> =
            Box::new(CodeBlockParser::new(Some("base16-ocean.dark".into())).unwrap());
        let parser = liquid::ParserBuilder::new()
            .block(highlight)
            .build()
            .unwrap();
        let template = parser
            .parse(&format!(
                "{{% highlight rust %}}{}{{% endhighlight %}}",
                CODE_BLOCK
            ))
            .unwrap();
        let output = template.render(&liquid::Object::new());
        snapbox::assert_eq(CODEBLOCK_RENDERED, &output.unwrap());
    }

    const MARKDOWN_RENDERED: &str =
        "
\n\
         mod \
         test {\n\
                 \
         fn \
         hello(\
         arg: int) -> \
         bool {\n\
                     \
         true\n\
                 }\n\
             }\n\
             \n\

\n";

    #[test]
    fn markdown_renders_rust() {
        let html = format!(
            "```rust
{}
```",
            CODE_BLOCK
        );

        let mut buf = String::new();
        let parser = cmark::Parser::new(&html);
        cmark::html::push_html(
            &mut buf,
            decorate_markdown(parser, Some("base16-ocean.dark")).unwrap(),
        );
        snapbox::assert_eq(MARKDOWN_RENDERED, &buf);
    }
}

#[cfg(test)]
#[cfg(not(feature = "syntax-highlight"))]
mod test_raw {
    use super::*;

    const CODE_BLOCK: &str = "mod test {
        fn hello(arg: int) -> bool {
            \
                                      true
        }
    }
";

    const CODEBLOCK_RENDERED: &str = r#"
mod test {
        fn hello(arg: int) -> bool {
            true
        }
    }

"#;

    #[test]
    fn codeblock_renders_rust() {
        let highlight: Box<dyn liquid_core::ParseBlock> =
            Box::new(CodeBlockParser::new("base16-ocean.dark".into()));
        let parser = liquid::ParserBuilder::new()
            .block(highlight)
            .build()
            .unwrap();
        let template = parser
            .parse(&format!(
                "{{% highlight rust %}}{}{{% endhighlight %}}",
                CODE_BLOCK
            ))
            .unwrap();
        let output = template.render(&liquid::Object::new());
        assert_eq!(output.unwrap(), CODEBLOCK_RENDERED.to_string());
    }

    const MARKDOWN_RENDERED: &str = r#"
mod test {
        fn hello(arg: int) -> bool {
            true
        }
    }

"#;

    #[test]
    fn decorate_markdown_renders_rust() {
        let html = format!(
            "```rust
{}
```",
            CODE_BLOCK
        );

        let mut buf = String::new();
        let parser = cmark::Parser::new(&html);
        cmark::html::push_html(
            &mut buf,
            decorate_markdown(parser, Some("base16-ocean.dark")),
        );
        assert_eq!(buf, MARKDOWN_RENDERED);
    }
}
<|endoftext|>


<commit_before>//! Implements iterative deepening, aspiration windows, multi-PV.
//!
//! Iterative deepening works as follows: the program starts with a
//! one ply search, then increments the search depth and does another
//! search. This process is repeated until the time allocated for the
//! search is exhausted. In case of an unfinished search, the program
//! always has the option to fall back to the move selected in the
//! last iteration of the search.
//!
//! Aspiration windows are a way to reduce the search space in the
//! search. The way it works is that we get the value from the last
//! search iteration, calculate a window around it, and use this as
//! alpha-beta bounds for the next search. Because the window is
//! narrower, more beta cutoffs are achieved, and the search takes a
//! shorter time. The drawback is that if the true score is outside
//! this window, then a costly re-search must be made. But then most
//! probably the re-search will be much faster, because many positions
//! will be remembered from the transposition table.
//!
//! In multi-PV mode the engine calculates and sends to the GUI
//! several principal variations (PV), each one starting with a
//! different first move.

use std::cmp::{min, max};
use std::mem;
use std::thread;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver, TryRecvError};
use basetypes::*;
use moves::*;
use tt::*;
use position::Position;
use search::MAX_DEPTH;
use search::threading::{Command, Report, serve_simple, serve_deepening};

/// The half-with of the initial aspiration window.
const INITIAL_ASPIRATION_WINDOW: Value = 17; // 16;

/// The `SearchExecutor` trait is used to execute consecutive searches
/// in different starting positions.
pub trait SearchExecutor {
    /// Creates a new instance.
    fn new(tt: Arc<Tt>) -> Self;

    /// Starts a new search.
    ///
    /// * `search_id`: a number identifying the new search;
    ///
    /// * `position`: the root position;
    ///
    /// * `depth`: the requested search depth;
    ///
    /// * `lower_bound`: the lower bound for the new search;
    ///
    /// * `upper_bound`: the upper bound for the new search;
    ///
    /// * `value`: the evaluation of the root position so far, or
    ///   `VALUE_UNKNOWN` if not available.
    ///
    /// * `searchmoves`: restricts the analysis to the supplied list
    ///   of moves only (no restrictions if the suppied list is
    ///   empty);
    ///
    /// * `variation_count`: specifies how many best lines of play to
    ///   calculate (the first move in each line will be different).
    ///
    /// After calling `start_search`, `try_recv_report` must be called
    /// periodically until the returned report indicates that the
    /// search is done. A new search must not be started until the
    /// previous search is done.
    fn start_search(&mut self,
                    search_id: usize,
                    position: Position,
                    depth: u8,
                    lower_bound: Value,
                    upper_bound: Value,
                    value: Value,
                    searchmoves: Vec<Move>,
                    variation_count: usize);

    /// Attempts to return a search report without blocking.
    fn try_recv_report(&mut self) -> Result<Report, TryRecvError>;

    /// Requests the termination of the current search.
    ///
    /// After calling `terminate`, `try_recv_report` must continue to
    /// be called periodically until the returned report indicates
    /// that the search is done.
    fn terminate_search(&mut self);
}

/// Executes bare alpha-beta searches to a fixed depth.
pub struct SimpleSearcher {
    thread: Option<thread::JoinHandle<()>>,
    thread_commands: Sender<Command>,
    thread_reports: Receiver<Report>,
}

impl SearchExecutor for SimpleSearcher {
    fn new(tt: Arc<Tt>) -> SimpleSearcher {
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        SimpleSearcher {
            thread: Some(thread::spawn(move || {
                serve_simple(tt, commands_rx, reports_tx);
            })),
            thread_commands: commands_tx,
            thread_reports: reports_rx,
        }
    }

    #[allow(unused_variables)]
    fn start_search(&mut self,
                    search_id: usize,
                    position: Position,
                    depth: u8,
                    lower_bound: Value,
                    upper_bound: Value,
                    value: Value,
                    searchmoves: Vec<Move>,
                    variation_count: usize) {
        debug_assert!(depth <= MAX_DEPTH);
        debug_assert!(lower_bound < upper_bound);
        debug_assert!(lower_bound != VALUE_UNKNOWN);
        debug_assert!(searchmoves.is_empty());
        self.thread_commands
            .send(Command::Search {
                search_id: search_id,
                position: position,
                depth: depth,
                lower_bound: lower_bound,
                upper_bound: upper_bound,
            })
            .unwrap();
    }

    fn try_recv_report(&mut self) -> Result<Report, TryRecvError> {
        self.thread_reports.try_recv()
    }

    fn terminate_search(&mut self) {
        self.thread_commands.send(Command::Stop).unwrap();
    }
}

impl Drop for SimpleSearcher {
    fn drop(&mut self) {
        self.thread_commands.send(Command::Exit).unwrap();
        self.thread.take().unwrap().join().unwrap();
    }
}

/// Executes multi-PV searches to a fixed depth.
pub struct MultipvSearcher;

/// Executes multi-PV searches to a fixed depth with aspiration.
pub struct AspirationSearcher {
    search_id: usize,
    position: Position,
    depth: u8,
    lower_bound: Value,
    upper_bound: Value,
    value: Value,
    searchmoves: Vec<Move>,
    variation_count: usize,

    /// `true` if the current search has been terminated.
    search_is_terminated: bool,

    /// The number of positions analyzed during previous (failed) searches.
    previously_searched_nodes: NodeCount,

    /// The aspiration window will be widened by this value if the
    /// search fails. (We use `isize` to avoid overflows.)
    delta: isize,

    /// The lower bound of the aspiration window.
    alpha: Value,

    /// The upper bound of the aspiration window.
    beta: Value,

    /// The real work will be handed over to `SimpleSearcher`.
    searcher: SimpleSearcher,
}

impl AspirationSearcher {
    /// A helper method. It tells `self.searcher` to run a new search.
    fn start_aspirated_search(&mut self) {
        self.searcher.start_search(0,
                                   self.position.clone(),
                                   self.depth,
                                   self.alpha,
                                   self.beta,
                                   self.value,
                                   self.searchmoves.clone(),
                                   self.variation_count);
    }

    /// A helper method. It multiplies `self.delta` by a constant.
    fn increase_delta(&mut self) {
        self.delta += 3 * self.delta / 8;
        if self.delta > 1500 {
            self.delta = 1_000_000;
        }
    }

    /// A helper method. It widens the aspiration window if necessary.
    fn widen_aspiration_window(&mut self) -> bool {
        let v = self.value as isize;
        if self.value <= self.alpha && self.lower_bound < self.alpha {
            // Set smaller `self.alpha`.
            self.alpha = max(v - self.delta, self.lower_bound as isize) as Value;
            self.increase_delta();
            return true;
        } else if self.value >= self.beta && self.upper_bound > self.beta {
            // Set bigger `self.beta`.
            self.beta = min(v + self.delta, self.upper_bound as isize) as Value;
            self.increase_delta();
            return true;
        }
        false
    }
}

impl SearchExecutor for AspirationSearcher {
    fn new(tt: Arc<Tt>) -> AspirationSearcher {
        let mut this: AspirationSearcher = unsafe { mem::uninitialized() };
        this.searcher = SimpleSearcher::new(tt);
        this
    }

    fn start_search(&mut self,
                    search_id: usize,
                    position: Position,
                    depth: u8,
                    lower_bound: Value,
                    upper_bound: Value,
                    value: Value,
                    searchmoves: Vec<Move>,
                    variation_count: usize) {
        debug_assert!(depth <= MAX_DEPTH);
        debug_assert!(lower_bound < upper_bound);
        debug_assert!(lower_bound != VALUE_UNKNOWN);
        self.search_id = search_id;
        self.position = position;
        self.depth = depth;
        self.lower_bound = lower_bound;
        self.upper_bound = upper_bound;
        self.value = value;
        self.searchmoves = searchmoves;
        self.variation_count = variation_count;
        self.search_is_terminated = false;
        self.previously_searched_nodes = 0;
        self.delta = INITIAL_ASPIRATION_WINDOW as isize;

        // Set the initial aspiration window (`self.alpha`, `self.beta`).
        let (a, b) = if value == VALUE_UNKNOWN || value < lower_bound || value > upper_bound {
            (lower_bound, upper_bound)
        } else {
            let v = value as isize;
            (max(v - self.delta, lower_bound as isize) as Value,
             min(v + self.delta, upper_bound as isize) as Value)
        };
        self.alpha = a;
        self.beta = b;

        self.start_aspirated_search();
    }

    fn try_recv_report(&mut self) -> Result<Report, TryRecvError> {
        let Report { searched_nodes, depth, value, best_moves, done, .. } =
            try!(self.searcher.try_recv_report());
        let searched_nodes = self.previously_searched_nodes + searched_nodes;
        let depth = if done && !self.search_is_terminated {
            self.previously_searched_nodes = searched_nodes;
            self.value = value;
            if self.widen_aspiration_window() {
                // Start a re-search.
                self.start_aspirated_search();
                return Err(TryRecvError::Empty);
            }
            depth
        } else {
            0
        };

        return Ok(Report {
            search_id: self.search_id,
            searched_nodes: searched_nodes,
            depth: depth,
            value: self.value,
            best_moves: best_moves,
            done: done,
        });
    }

    fn terminate_search(&mut self) {
        self.search_is_terminated = true;
        self.searcher.terminate_search();
    }
}

/// Executes deepeing multi-PV searches with aspiration.
pub struct DeepeningSearcher {
    thread: Option<thread::JoinHandle<()>>,
    thread_commands: Sender<Command>,
    thread_reports: Receiver<Report>,
}

impl SearchExecutor for DeepeningSearcher {
    fn new(tt: Arc<Tt>) -> DeepeningSearcher {
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        DeepeningSearcher {
            thread: Some(thread::spawn(move || {
                serve_deepening(tt, commands_rx, reports_tx);
            })),
            thread_commands: commands_tx,
            thread_reports: reports_rx,
        }
    }

    #[allow(unused_variables)]
    fn start_search(&mut self,
                    search_id: usize,
                    position: Position,
                    depth: u8,
                    lower_bound: Value,
                    upper_bound: Value,
                    value: Value,
                    searchmoves: Vec<Move>,
                    variation_count: usize) {
        debug_assert!(depth <= MAX_DEPTH);
        debug_assert!(lower_bound < upper_bound);
        debug_assert!(lower_bound != VALUE_UNKNOWN);
        self.thread_commands
            .send(Command::Search {
                search_id: search_id,
                position: position,
                depth: depth,
                lower_bound: lower_bound,
                upper_bound: upper_bound,
            })
            .unwrap();
    }

    fn try_recv_report(&mut self) -> Result<Report, TryRecvError> {
        self.thread_reports.try_recv()
    }

    fn terminate_search(&mut self) {
        self.thread_commands.send(Command::Stop).unwrap();
    }
}

impl Drop for DeepeningSearcher {
    fn drop(&mut self) {
        self.thread_commands.send(Command::Exit).unwrap();
        self.thread.take().unwrap().join().unwrap();
    }
}
<commit_msg>rename a constant<commit_after>//! Implements iterative deepening, aspiration windows, multi-PV.
//!
//! Iterative deepening works as follows: the program starts with a
//! one ply search, then increments the search depth and does another
//! search. This process is repeated until the time allocated for the
//! search is exhausted. In case of an unfinished search, the program
//! always has the option to fall back to the move selected in the
//! last iteration of the search.
//!
//! Aspiration windows are a way to reduce the search space in the
//! search. The way it works is that we get the value from the last
//! search iteration, calculate a window around it, and use this as
//! alpha-beta bounds for the next search. Because the window is
//! narrower, more beta cutoffs are achieved, and the search takes a
//! shorter time. The drawback is that if the true score is outside
//! this window, then a costly re-search must be made. But then most
//! probably the re-search will be much faster, because many positions
//! will be remembered from the transposition table.
//!
//! In multi-PV mode the engine calculates and sends to the GUI
//! several principal variations (PV), each one starting with a
//! different first move.

use std::cmp::{min, max};
use std::mem;
use std::thread;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver, TryRecvError};
use basetypes::*;
use moves::*;
use tt::*;
use position::Position;
use search::MAX_DEPTH;
use search::threading::{Command, Report, serve_simple, serve_deepening};

/// The half-width of the initial aspiration window.
const INITIAL_ASPIRATION_HALFWIDTH: Value = 17; // 16;

/// The `SearchExecutor` trait is used to execute consecutive searches
/// in different starting positions.
pub trait SearchExecutor {
    /// Creates a new instance.
    fn new(tt: Arc<Tt>) -> Self;

    /// Starts a new search.
    ///
    /// * `search_id`: a number identifying the new search;
    ///
    /// * `position`: the root position;
    ///
    /// * `depth`: the requested search depth;
    ///
    /// * `lower_bound`: the lower bound for the new search;
    ///
    /// * `upper_bound`: the upper bound for the new search;
    ///
    /// * `value`: the evaluation of the root position so far, or
    ///   `VALUE_UNKNOWN` if not available.
    ///
    /// * `searchmoves`: restricts the analysis to the supplied list
    ///   of moves only (no restrictions if the suppied list is
    ///   empty);
    ///
    /// * `variation_count`: specifies how many best lines of play to
    ///   calculate (the first move in each line will be different).
    ///
    /// After calling `start_search`, `try_recv_report` must be called
    /// periodically until the returned report indicates that the
    /// search is done. A new search must not be started until the
    /// previous search is done.
    fn start_search(&mut self,
                    search_id: usize,
                    position: Position,
                    depth: u8,
                    lower_bound: Value,
                    upper_bound: Value,
                    value: Value,
                    searchmoves: Vec<Move>,
                    variation_count: usize);

    /// Attempts to return a search report without blocking.
    fn try_recv_report(&mut self) -> Result<Report, TryRecvError>;

    /// Requests the termination of the current search.
    ///
    /// After calling `terminate`, `try_recv_report` must continue to
    /// be called periodically until the returned report indicates
    /// that the search is done.
    fn terminate_search(&mut self);
}

/// Executes bare alpha-beta searches to a fixed depth.
pub struct SimpleSearcher {
    thread: Option<thread::JoinHandle<()>>,
    thread_commands: Sender<Command>,
    thread_reports: Receiver<Report>,
}

impl SearchExecutor for SimpleSearcher {
    fn new(tt: Arc<Tt>) -> SimpleSearcher {
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        SimpleSearcher {
            thread: Some(thread::spawn(move || {
                serve_simple(tt, commands_rx, reports_tx);
            })),
            thread_commands: commands_tx,
            thread_reports: reports_rx,
        }
    }

    #[allow(unused_variables)]
    fn start_search(&mut self,
                    search_id: usize,
                    position: Position,
                    depth: u8,
                    lower_bound: Value,
                    upper_bound: Value,
                    value: Value,
                    searchmoves: Vec<Move>,
                    variation_count: usize) {
        debug_assert!(depth <= MAX_DEPTH);
        debug_assert!(lower_bound < upper_bound);
        debug_assert!(lower_bound != VALUE_UNKNOWN);
        debug_assert!(searchmoves.is_empty());
        self.thread_commands
            .send(Command::Search {
                search_id: search_id,
                position: position,
                depth: depth,
                lower_bound: lower_bound,
                upper_bound: upper_bound,
            })
            .unwrap();
    }

    fn try_recv_report(&mut self) -> Result<Report, TryRecvError> {
        self.thread_reports.try_recv()
    }

    fn terminate_search(&mut self) {
        self.thread_commands.send(Command::Stop).unwrap();
    }
}

impl Drop for SimpleSearcher {
    fn drop(&mut self) {
        self.thread_commands.send(Command::Exit).unwrap();
        self.thread.take().unwrap().join().unwrap();
    }
}

/// Executes multi-PV searches to a fixed depth.
pub struct MultipvSearcher;

/// Executes multi-PV searches to a fixed depth with aspiration.
pub struct AspirationSearcher {
    search_id: usize,
    position: Position,
    depth: u8,
    lower_bound: Value,
    upper_bound: Value,
    value: Value,
    searchmoves: Vec<Move>,
    variation_count: usize,

    /// `true` if the current search has been terminated.
    search_is_terminated: bool,

    /// The number of positions analyzed during previous (failed) searches.
    previously_searched_nodes: NodeCount,

    /// The aspiration window will be widened by this value if the
    /// search fails. (We use `isize` to avoid overflows.)
    delta: isize,

    /// The lower bound of the aspiration window.
    alpha: Value,

    /// The upper bound of the aspiration window.
    beta: Value,

    /// The real work will be handed over to `SimpleSearcher`.
    searcher: SimpleSearcher,
}

impl AspirationSearcher {
    /// A helper method. It tells `self.searcher` to run a new search.
    fn start_aspirated_search(&mut self) {
        self.searcher.start_search(0,
                                   self.position.clone(),
                                   self.depth,
                                   self.alpha,
                                   self.beta,
                                   self.value,
                                   self.searchmoves.clone(),
                                   self.variation_count);
    }

    /// A helper method. It multiplies `self.delta` by a constant.
    fn increase_delta(&mut self) {
        self.delta += 3 * self.delta / 8;
        if self.delta > 1500 {
            self.delta = 1_000_000;
        }
    }

    /// A helper method. It widens the aspiration window if necessary.
    fn widen_aspiration_window(&mut self) -> bool {
        let v = self.value as isize;
        if self.value <= self.alpha && self.lower_bound < self.alpha {
            // Set smaller `self.alpha`.
            self.alpha = max(v - self.delta, self.lower_bound as isize) as Value;
            self.increase_delta();
            return true;
        } else if self.value >= self.beta && self.upper_bound > self.beta {
            // Set bigger `self.beta`.
            self.beta = min(v + self.delta, self.upper_bound as isize) as Value;
            self.increase_delta();
            return true;
        }
        false
    }
}

impl SearchExecutor for AspirationSearcher {
    fn new(tt: Arc<Tt>) -> AspirationSearcher {
        let mut this: AspirationSearcher = unsafe { mem::uninitialized() };
        this.searcher = SimpleSearcher::new(tt);
        this
    }

    fn start_search(&mut self,
                    search_id: usize,
                    position: Position,
                    depth: u8,
                    lower_bound: Value,
                    upper_bound: Value,
                    value: Value,
                    searchmoves: Vec<Move>,
                    variation_count: usize) {
        debug_assert!(depth <= MAX_DEPTH);
        debug_assert!(lower_bound < upper_bound);
        debug_assert!(lower_bound != VALUE_UNKNOWN);
        self.search_id = search_id;
        self.position = position;
        self.depth = depth;
        self.lower_bound = lower_bound;
        self.upper_bound = upper_bound;
        self.value = value;
        self.searchmoves = searchmoves;
        self.variation_count = variation_count;
        self.search_is_terminated = false;
        self.previously_searched_nodes = 0;
        self.delta = INITIAL_ASPIRATION_HALFWIDTH as isize;

        // Set the initial aspiration window (`self.alpha`, `self.beta`).
        let (a, b) = if value == VALUE_UNKNOWN || value < lower_bound || value > upper_bound {
            (lower_bound, upper_bound)
        } else {
            let v = value as isize;
            (max(v - self.delta, lower_bound as isize) as Value,
             min(v + self.delta, upper_bound as isize) as Value)
        };
        self.alpha = a;
        self.beta = b;

        self.start_aspirated_search();
    }

    fn try_recv_report(&mut self) -> Result<Report, TryRecvError> {
        let Report { searched_nodes, depth, value, best_moves, done, .. } =
            try!(self.searcher.try_recv_report());
        let searched_nodes = self.previously_searched_nodes + searched_nodes;
        let depth = if done && !self.search_is_terminated {
            self.previously_searched_nodes = searched_nodes;
            self.value = value;
            if self.widen_aspiration_window() {
                // Start a re-search.
                self.start_aspirated_search();
                return Err(TryRecvError::Empty);
            }
            depth
        } else {
            0
        };

        return Ok(Report {
            search_id: self.search_id,
            searched_nodes: searched_nodes,
            depth: depth,
            value: self.value,
            best_moves: best_moves,
            done: done,
        });
    }

    fn terminate_search(&mut self) {
        self.search_is_terminated = true;
        self.searcher.terminate_search();
    }
}

/// Executes deepeing multi-PV searches with aspiration.
pub struct DeepeningSearcher {
    thread: Option<thread::JoinHandle<()>>,
    thread_commands: Sender<Command>,
    thread_reports: Receiver<Report>,
}

impl SearchExecutor for DeepeningSearcher {
    fn new(tt: Arc<Tt>) -> DeepeningSearcher {
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        DeepeningSearcher {
            thread: Some(thread::spawn(move || {
                serve_deepening(tt, commands_rx, reports_tx);
            })),
            thread_commands: commands_tx,
            thread_reports: reports_rx,
        }
    }

    #[allow(unused_variables)]
    fn start_search(&mut self,
                    search_id: usize,
                    position: Position,
                    depth: u8,
                    lower_bound: Value,
                    upper_bound: Value,
                    value: Value,
                    searchmoves: Vec<Move>,
                    variation_count: usize) {
        debug_assert!(depth <= MAX_DEPTH);
        debug_assert!(lower_bound < upper_bound);
        debug_assert!(lower_bound != VALUE_UNKNOWN);
        self.thread_commands
            .send(Command::Search {
                search_id: search_id,
                position: position,
                depth: depth,
                lower_bound: lower_bound,
                upper_bound: upper_bound,
            })
            .unwrap();
    }

    fn try_recv_report(&mut self) -> Result<Report, TryRecvError> {
        self.thread_reports.try_recv()
    }

    fn terminate_search(&mut self) {
        self.thread_commands.send(Command::Stop).unwrap();
    }
}

impl Drop for DeepeningSearcher {
    fn drop(&mut self) {
        self.thread_commands.send(Command::Exit).unwrap();
        self.thread.take().unwrap().join().unwrap();
    }
}
<|endoftext|>


<commit_before>#![cfg(not(syn_disable_nightly_tests))]
#![cfg(not(miri))]
#![recursion_limit = "1024"]
#![feature(rustc_private)]
#![allow(
    clippy::explicit_deref_methods,
    clippy::manual_assert,
    clippy::match_wildcard_for_single_variants,
    clippy::too_many_lines
)]

//! The tests in this module do the following:
//!
//! 1. Parse a given expression in both `syn` and `librustc`.
//! 2. Fold over the expression adding brackets around each subexpression (with
//!    some complications - see the `syn_brackets` and `librustc_brackets`
//!    methods).
//! 3. Serialize the `syn` expression back into a string, and re-parse it with
//!    `librustc`.
//! 4. Respan all of the expressions, replacing the spans with the default
//!    spans.
//! 5. Compare the expressions with one another, if they are not equal fail.

extern crate rustc_ast;
extern crate rustc_data_structures;
extern crate rustc_span;

use crate::common::eq::SpanlessEq;
use crate::common::parse;
use quote::quote;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use regex::Regex;
use rustc_ast::ast;
use rustc_ast::ptr::P;
use rustc_span::edition::Edition;
use std::fs;
use std::process;
use std::sync::atomic::{AtomicUsize, Ordering};
use walkdir::{DirEntry, WalkDir};

#[macro_use]
mod macros;

#[allow(dead_code)]
mod common;

mod repo;

/// Test some pre-set expressions chosen by us.
#[test]
fn test_simple_precedence() {
    const EXPRS: &[&str] = &[
        "1 + 2 * 3 + 4",
        "1 + 2 * ( 3 + 4 )",
        "{ for i in r { } *some_ptr += 1; }",
        "{ loop { break 5; } }",
        "{ if true { () }.mthd() }",
        "{ for i in unsafe { 20 } { } }",
    ];

    let mut failed = 0;

    for input in EXPRS {
        let expr = if let Some(expr) = parse::syn_expr(input) {
            expr
        } else {
            failed += 1;
            continue;
        };

        let pf = match test_expressions(Edition::Edition2018, vec![expr]) {
            (1, 0) => "passed",
            (0, 1) => {
                failed += 1;
                "failed"
            }
            _ => unreachable!(),
        };
        errorf!("=== {}: {}\n", input, pf);
    }

    if failed > 0 {
        panic!("Failed {} tests", failed);
    }
}

/// Test expressions from rustc, like in `test_round_trip`.
#[test]
fn test_rustc_precedence() {
    common::rayon_init();
    repo::clone_rust();
    let abort_after = common::abort_after();
    if abort_after == 0 {
        panic!("Skipping all precedence tests");
    }

    let passed = AtomicUsize::new(0);
    let failed = AtomicUsize::new(0);

    // 2018 edition is hard
    let edition_regex = Regex::new(r"\b(async|try)[!(]").unwrap();

    WalkDir::new("tests/rust")
        .sort_by(|a, b| a.file_name().cmp(b.file_name()))
        .into_iter()
        .filter_entry(repo::base_dir_filter)
        .collect::<Result<Vec<DirEntry>, walkdir::Error>>()
        .unwrap()
        .into_par_iter()
        .for_each(|entry| {
            let path = entry.path();
            if path.is_dir() {
                return;
            }

            let content = fs::read_to_string(path).unwrap();
            let content = edition_regex.replace_all(&content, "_$0");

            let (l_passed, l_failed) = match syn::parse_file(&content) {
                Ok(file) => {
                    let edition = repo::edition(path).parse().unwrap();
                    let exprs = collect_exprs(file);
                    test_expressions(edition, exprs)
                }
                Err(msg) => {
                    errorf!("syn failed to parse\n{:?}\n", msg);
                    (0, 1)
                }
            };

            errorf!(
                "=== {}: {} passed | {} failed\n",
                path.display(),
                l_passed,
                l_failed
            );

            passed.fetch_add(l_passed, Ordering::Relaxed);
            let prev_failed = failed.fetch_add(l_failed, Ordering::Relaxed);

            if prev_failed + l_failed >= abort_after {
                process::exit(1);
            }
        });

    let passed = passed.load(Ordering::Relaxed);
    let failed = failed.load(Ordering::Relaxed);

    errorf!("\n===== Precedence Test Results =====\n");
    errorf!("{} passed | {} failed\n", passed, failed);

    if failed > 0 {
        panic!("{} failures", failed);
    }
}

fn test_expressions(edition: Edition, exprs: Vec<syn::Expr>) -> (usize, usize) {
    let mut passed = 0;
    let mut failed = 0;

    rustc_span::create_session_if_not_set_then(edition, |_| {
        for expr in exprs {
            let raw = quote!(#expr).to_string();

            let librustc_ast = if let Some(e) = librustc_parse_and_rewrite(&raw) {
                e
            } else {
                failed += 1;
                errorf!("\nFAIL - librustc failed to parse raw\n");
                continue;
            };

            let syn_expr = syn_brackets(expr);
            let syn_ast = if let Some(e) = parse::librustc_expr(&quote!(#syn_expr).to_string()) {
                e
            } else {
                failed += 1;
                errorf!("\nFAIL - librustc failed to parse bracketed\n");
                continue;
            };

            if SpanlessEq::eq(&syn_ast, &librustc_ast) {
                passed += 1;
            } else {
                failed += 1;
                errorf!("\nFAIL\n{:?}\n!=\n{:?}\n", syn_ast, librustc_ast);
            }
        }
    });

    (passed, failed)
}

fn librustc_parse_and_rewrite(input: &str) -> Option<P<ast::Expr>> {
    parse::librustc_expr(input).and_then(librustc_brackets)
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precedence of the parsed expressions, and produce a stringified
/// form of the resulting expression.
///
/// This method operates on librustc objects.
fn librustc_brackets(mut librustc_expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
    use rustc_ast::ast::{
        Attribute, Block, BorrowKind, Expr, ExprField, ExprKind, GenericArg, Local, LocalKind, Pat,
        Stmt, StmtKind, StructExpr, StructRest, Ty,
    };
    use rustc_ast::mut_visit::{noop_visit_generic_arg, noop_visit_local, MutVisitor};
    use rustc_data_structures::map_in_place::MapInPlace;
    use rustc_data_structures::thin_vec::ThinVec;
    use rustc_span::DUMMY_SP;
    use std::mem;
    use std::ops::DerefMut;

    struct BracketsVisitor {
        failed: bool,
    }

    fn flat_map_field<T: MutVisitor>(mut f: ExprField, vis: &mut T) -> Vec<ExprField> {
        if f.is_shorthand {
            noop_visit_expr(&mut f.expr, vis);
        } else {
            vis.visit_expr(&mut f.expr);
        }
        vec![f]
    }

    fn flat_map_stmt<T: MutVisitor>(stmt: Stmt, vis: &mut T) -> Vec<Stmt> {
        let kind = match stmt.kind {
            // Don't wrap toplevel expressions in statements.
            StmtKind::Expr(mut e) => {
                noop_visit_expr(&mut e, vis);
                StmtKind::Expr(e)
            }
            StmtKind::Semi(mut e) => {
                noop_visit_expr(&mut e, vis);
                StmtKind::Semi(e)
            }
            s => s,
        };

        vec![Stmt { kind, ..stmt }]
    }

    fn noop_visit_expr<T: MutVisitor>(e: &mut Expr, vis: &mut T) {
        use rustc_ast::mut_visit::{noop_visit_expr, visit_thin_attrs};
        match &mut e.kind {
            ExprKind::AddrOf(BorrowKind::Raw, ..) => {}
            ExprKind::Struct(expr) => {
                let StructExpr {
                    qself,
                    path,
                    fields,
                    rest,
                } = expr.deref_mut();
                vis.visit_qself(qself);
                vis.visit_path(path);
                fields.flat_map_in_place(|field| flat_map_field(field, vis));
                if let StructRest::Base(rest) = rest {
                    vis.visit_expr(rest);
                }
                vis.visit_id(&mut e.id);
                vis.visit_span(&mut e.span);
                visit_thin_attrs(&mut e.attrs, vis);
            }
            _ => noop_visit_expr(e, vis),
        }
    }

    impl MutVisitor for BracketsVisitor {
        fn visit_expr(&mut self, e: &mut P<Expr>) {
            match e.kind {
                ExprKind::ConstBlock(..) => {}
                _ => noop_visit_expr(e, self),
            }
            match e.kind {
                ExprKind::If(..) | ExprKind::Block(..) | ExprKind::Let(..) => {}
                _ => {
                    let inner = mem::replace(
                        e,
                        P(Expr {
                            id: ast::DUMMY_NODE_ID,
                            kind: ExprKind::Err,
                            span: DUMMY_SP,
                            attrs: ThinVec::new(),
                            tokens: None,
                        }),
                    );
                    e.kind = ExprKind::Paren(inner);
                }
            }
        }

        fn visit_generic_arg(&mut self, arg: &mut GenericArg) {
            match arg {
                // Don't wrap unbraced const generic arg as that's invalid syntax.
                GenericArg::Const(anon_const) => {
                    if let ExprKind::Block(..) = &mut anon_const.value.kind {
                        noop_visit_expr(&mut anon_const.value, self);
                    }
                }
                _ => noop_visit_generic_arg(arg, self),
            }
        }

        fn visit_block(&mut self, block: &mut P<Block>) {
            self.visit_id(&mut block.id);
            block
                .stmts
                .flat_map_in_place(|stmt| flat_map_stmt(stmt, self));
            self.visit_span(&mut block.span);
        }

        fn visit_local(&mut self, local: &mut P<Local>) {
            match local.kind {
                LocalKind::InitElse(..) => {}
                _ => noop_visit_local(local, self),
            }
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn visit_pat(&mut self, pat: &mut P<Pat>) {
            let _ = pat;
        }

        fn visit_ty(&mut self, ty: &mut P<Ty>) {
            let _ = ty;
        }

        fn visit_attribute(&mut self, attr: &mut Attribute) {
            let _ = attr;
        }
    }

    let mut folder = BracketsVisitor { failed: false };
    folder.visit_expr(&mut librustc_expr);
    if folder.failed {
        None
    } else {
        Some(librustc_expr)
    }
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precedence of the parsed expressions, and produce a stringified
/// form of the resulting expression.
fn syn_brackets(syn_expr: syn::Expr) -> syn::Expr {
    use syn::fold::{fold_expr, fold_generic_argument, fold_generic_method_argument, Fold};
    use syn::{token, Expr, ExprParen, GenericArgument, GenericMethodArgument, Pat, Stmt, Type};

    struct ParenthesizeEveryExpr;
    impl Fold for ParenthesizeEveryExpr {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            match expr {
                Expr::Group(_) => unreachable!(),
                Expr::If(..) | Expr::Unsafe(..) | Expr::Block(..) | Expr::Let(..) => {
                    fold_expr(self, expr)
                }
                _ => Expr::Paren(ExprParen {
                    attrs: Vec::new(),
                    expr: Box::new(fold_expr(self, expr)),
                    paren_token: token::Paren::default(),
                }),
            }
        }

        fn fold_generic_argument(&mut self, arg: GenericArgument) -> GenericArgument {
            match arg {
                GenericArgument::Const(arg) => GenericArgument::Const(match arg {
                    Expr::Block(_) => fold_expr(self, arg),
                    // Don't wrap unbraced const generic arg as that's invalid syntax.
                    _ => arg,
                }),
                _ => fold_generic_argument(self, arg),
            }
        }

        fn fold_generic_method_argument(
            &mut self,
            arg: GenericMethodArgument,
        ) -> GenericMethodArgument {
            match arg {
                GenericMethodArgument::Const(arg) => GenericMethodArgument::Const(match arg {
                    Expr::Block(_) => fold_expr(self, arg),
                    // Don't wrap unbraced const generic arg as that's invalid syntax.
                    _ => arg,
                }),
                _ => fold_generic_method_argument(self, arg),
            }
        }

        fn fold_stmt(&mut self, stmt: Stmt) -> Stmt {
            match stmt {
                // Don't wrap toplevel expressions in statements.
                Stmt::Expr(e) => Stmt::Expr(fold_expr(self, e)),
                Stmt::Semi(e, semi) => {
                    if let Expr::Verbatim(_) = e {
                        Stmt::Semi(e, semi)
                    } else {
                        Stmt::Semi(fold_expr(self, e), semi)
                    }
                }
                s => s,
            }
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn fold_pat(&mut self, pat: Pat) -> Pat {
            pat
        }

        fn fold_type(&mut self, ty: Type) -> Type {
            ty
        }
    }

    let mut folder = ParenthesizeEveryExpr;
    folder.fold_expr(syn_expr)
}

/// Walk through a crate collecting all expressions we can find in it.
fn collect_exprs(file: syn::File) -> Vec<syn::Expr> {
    use syn::fold::Fold;
    use syn::punctuated::Punctuated;
    use syn::{token, Expr, ExprTuple, Path};

    struct CollectExprs(Vec<Expr>);
    impl Fold for CollectExprs {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            match expr {
                Expr::Verbatim(_) => {}
                _ => self.0.push(expr),
            }

            Expr::Tuple(ExprTuple {
                attrs: vec![],
                elems: Punctuated::new(),
                paren_token: token::Paren::default(),
            })
        }

        fn fold_path(&mut self, path: Path) -> Path {
            // Skip traversing into const generic path arguments
            path
        }
    }

    let mut folder = CollectExprs(vec![]);
    folder.fold_file(file);
    folder.0
}
<commit_msg>Update test suite to nightly-2022-08-23<commit_after>#![cfg(not(syn_disable_nightly_tests))]
#![cfg(not(miri))]
#![recursion_limit = "1024"]
#![feature(rustc_private)]
#![allow(
    clippy::explicit_deref_methods,
    clippy::manual_assert,
    clippy::match_wildcard_for_single_variants,
    clippy::too_many_lines
)]

//! The tests in this module do the following:
//!
//! 1. Parse a given expression in both `syn` and `librustc`.
//! 2. Fold over the expression adding brackets around each subexpression (with
//!    some complications - see the `syn_brackets` and `librustc_brackets`
//!    methods).
//! 3. Serialize the `syn` expression back into a string, and re-parse it with
//!    `librustc`.
//! 4. Respan all of the expressions, replacing the spans with the default
//!    spans.
//! 5. Compare the expressions with one another, if they are not equal fail.

extern crate rustc_ast;
extern crate rustc_data_structures;
extern crate rustc_span;

use crate::common::eq::SpanlessEq;
use crate::common::parse;
use quote::quote;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use regex::Regex;
use rustc_ast::ast;
use rustc_ast::ptr::P;
use rustc_span::edition::Edition;
use std::fs;
use std::process;
use std::sync::atomic::{AtomicUsize, Ordering};
use walkdir::{DirEntry, WalkDir};

#[macro_use]
mod macros;

#[allow(dead_code)]
mod common;

mod repo;

/// Test some pre-set expressions chosen by us.
#[test]
fn test_simple_precedence() {
    const EXPRS: &[&str] = &[
        "1 + 2 * 3 + 4",
        "1 + 2 * ( 3 + 4 )",
        "{ for i in r { } *some_ptr += 1; }",
        "{ loop { break 5; } }",
        "{ if true { () }.mthd() }",
        "{ for i in unsafe { 20 } { } }",
    ];

    let mut failed = 0;

    for input in EXPRS {
        let expr = if let Some(expr) = parse::syn_expr(input) {
            expr
        } else {
            failed += 1;
            continue;
        };

        let pf = match test_expressions(Edition::Edition2018, vec![expr]) {
            (1, 0) => "passed",
            (0, 1) => {
                failed += 1;
                "failed"
            }
            _ => unreachable!(),
        };
        errorf!("=== {}: {}\n", input, pf);
    }

    if failed > 0 {
        panic!("Failed {} tests", failed);
    }
}

/// Test expressions from rustc, like in `test_round_trip`.
#[test]
fn test_rustc_precedence() {
    common::rayon_init();
    repo::clone_rust();
    let abort_after = common::abort_after();
    if abort_after == 0 {
        panic!("Skipping all precedence tests");
    }

    let passed = AtomicUsize::new(0);
    let failed = AtomicUsize::new(0);

    // 2018 edition is hard
    let edition_regex = Regex::new(r"\b(async|try)[!(]").unwrap();

    WalkDir::new("tests/rust")
        .sort_by(|a, b| a.file_name().cmp(b.file_name()))
        .into_iter()
        .filter_entry(repo::base_dir_filter)
        .collect::<Result<Vec<DirEntry>, walkdir::Error>>()
        .unwrap()
        .into_par_iter()
        .for_each(|entry| {
            let path = entry.path();
            if path.is_dir() {
                return;
            }

            let content = fs::read_to_string(path).unwrap();
            let content = edition_regex.replace_all(&content, "_$0");

            let (l_passed, l_failed) = match syn::parse_file(&content) {
                Ok(file) => {
                    let edition = repo::edition(path).parse().unwrap();
                    let exprs = collect_exprs(file);
                    test_expressions(edition, exprs)
                }
                Err(msg) => {
                    errorf!("syn failed to parse\n{:?}\n", msg);
                    (0, 1)
                }
            };

            errorf!(
                "=== {}: {} passed | {} failed\n",
                path.display(),
                l_passed,
                l_failed
            );

            passed.fetch_add(l_passed, Ordering::Relaxed);
            let prev_failed = failed.fetch_add(l_failed, Ordering::Relaxed);

            if prev_failed + l_failed >= abort_after {
                process::exit(1);
            }
        });

    let passed = passed.load(Ordering::Relaxed);
    let failed = failed.load(Ordering::Relaxed);

    errorf!("\n===== Precedence Test Results =====\n");
    errorf!("{} passed | {} failed\n", passed, failed);

    if failed > 0 {
        panic!("{} failures", failed);
    }
}

fn test_expressions(edition: Edition, exprs: Vec<syn::Expr>) -> (usize, usize) {
    let mut passed = 0;
    let mut failed = 0;

    rustc_span::create_session_if_not_set_then(edition, |_| {
        for expr in exprs {
            let raw = quote!(#expr).to_string();

            let librustc_ast = if let Some(e) = librustc_parse_and_rewrite(&raw) {
                e
            } else {
                failed += 1;
                errorf!("\nFAIL - librustc failed to parse raw\n");
                continue;
            };

            let syn_expr = syn_brackets(expr);
            let syn_ast = if let Some(e) = parse::librustc_expr(&quote!(#syn_expr).to_string()) {
                e
            } else {
                failed += 1;
                errorf!("\nFAIL - librustc failed to parse bracketed\n");
                continue;
            };

            if SpanlessEq::eq(&syn_ast, &librustc_ast) {
                passed += 1;
            } else {
                failed += 1;
                errorf!("\nFAIL\n{:?}\n!=\n{:?}\n", syn_ast, librustc_ast);
            }
        }
    });

    (passed, failed)
}

fn librustc_parse_and_rewrite(input: &str) -> Option<P<ast::Expr>> {
    parse::librustc_expr(input).and_then(librustc_brackets)
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precedence of the parsed expressions, and produce a stringified
/// form of the resulting expression.
///
/// This method operates on librustc objects.
fn librustc_brackets(mut librustc_expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
    use rustc_ast::ast::{
        Attribute, Block, BorrowKind, Expr, ExprField, ExprKind, GenericArg, Local, LocalKind, Pat,
        Stmt, StmtKind, StructExpr, StructRest, Ty,
    };
    use rustc_ast::mut_visit::{noop_visit_generic_arg, noop_visit_local, MutVisitor};
    use rustc_data_structures::map_in_place::MapInPlace;
    use rustc_data_structures::thin_vec::ThinVec;
    use rustc_span::DUMMY_SP;
    use std::mem;
    use std::ops::DerefMut;

    struct BracketsVisitor {
        failed: bool,
    }

    fn flat_map_field<T: MutVisitor>(mut f: ExprField, vis: &mut T) -> Vec<ExprField> {
        if f.is_shorthand {
            noop_visit_expr(&mut f.expr, vis);
        } else {
            vis.visit_expr(&mut f.expr);
        }
        vec![f]
    }

    fn flat_map_stmt<T: MutVisitor>(stmt: Stmt, vis: &mut T) -> Vec<Stmt> {
        let kind = match stmt.kind {
            // Don't wrap toplevel expressions in statements.
            StmtKind::Expr(mut e) => {
                noop_visit_expr(&mut e, vis);
                StmtKind::Expr(e)
            }
            StmtKind::Semi(mut e) => {
                noop_visit_expr(&mut e, vis);
                StmtKind::Semi(e)
            }
            s => s,
        };

        vec![Stmt { kind, ..stmt }]
    }

    fn noop_visit_expr<T: MutVisitor>(e: &mut Expr, vis: &mut T) {
        use rustc_ast::mut_visit::{noop_visit_expr, visit_attrs};
        match &mut e.kind {
            ExprKind::AddrOf(BorrowKind::Raw, ..) => {}
            ExprKind::Struct(expr) => {
                let StructExpr {
                    qself,
                    path,
                    fields,
                    rest,
                } = expr.deref_mut();
                vis.visit_qself(qself);
                vis.visit_path(path);
                fields.flat_map_in_place(|field| flat_map_field(field, vis));
                if let StructRest::Base(rest) = rest {
                    vis.visit_expr(rest);
                }
                vis.visit_id(&mut e.id);
                vis.visit_span(&mut e.span);
                visit_attrs(&mut e.attrs, vis);
            }
            _ => noop_visit_expr(e, vis),
        }
    }

    impl MutVisitor for BracketsVisitor {
        fn visit_expr(&mut self, e: &mut P<Expr>) {
            match e.kind {
                ExprKind::ConstBlock(..) => {}
                _ => noop_visit_expr(e, self),
            }
            match e.kind {
                ExprKind::If(..) | ExprKind::Block(..) | ExprKind::Let(..) => {}
                _ => {
                    let inner = mem::replace(
                        e,
                        P(Expr {
                            id: ast::DUMMY_NODE_ID,
                            kind: ExprKind::Err,
                            span: DUMMY_SP,
                            attrs: ThinVec::new(),
                            tokens: None,
                        }),
                    );
                    e.kind = ExprKind::Paren(inner);
                }
            }
        }

        fn visit_generic_arg(&mut self, arg: &mut GenericArg) {
            match arg {
                // Don't wrap unbraced const generic arg as that's invalid syntax.
                GenericArg::Const(anon_const) => {
                    if let ExprKind::Block(..) = &mut anon_const.value.kind {
                        noop_visit_expr(&mut anon_const.value, self);
                    }
                }
                _ => noop_visit_generic_arg(arg, self),
            }
        }

        fn visit_block(&mut self, block: &mut P<Block>) {
            self.visit_id(&mut block.id);
            block
                .stmts
                .flat_map_in_place(|stmt| flat_map_stmt(stmt, self));
            self.visit_span(&mut block.span);
        }

        fn visit_local(&mut self, local: &mut P<Local>) {
            match local.kind {
                LocalKind::InitElse(..) => {}
                _ => noop_visit_local(local, self),
            }
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn visit_pat(&mut self, pat: &mut P<Pat>) {
            let _ = pat;
        }

        fn visit_ty(&mut self, ty: &mut P<Ty>) {
            let _ = ty;
        }

        fn visit_attribute(&mut self, attr: &mut Attribute) {
            let _ = attr;
        }
    }

    let mut folder = BracketsVisitor { failed: false };
    folder.visit_expr(&mut librustc_expr);
    if folder.failed {
        None
    } else {
        Some(librustc_expr)
    }
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precedence of the parsed expressions, and produce a stringified
/// form of the resulting expression.
fn syn_brackets(syn_expr: syn::Expr) -> syn::Expr {
    use syn::fold::{fold_expr, fold_generic_argument, fold_generic_method_argument, Fold};
    use syn::{token, Expr, ExprParen, GenericArgument, GenericMethodArgument, Pat, Stmt, Type};

    struct ParenthesizeEveryExpr;
    impl Fold for ParenthesizeEveryExpr {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            match expr {
                Expr::Group(_) => unreachable!(),
                Expr::If(..) | Expr::Unsafe(..) | Expr::Block(..) | Expr::Let(..) => {
                    fold_expr(self, expr)
                }
                _ => Expr::Paren(ExprParen {
                    attrs: Vec::new(),
                    expr: Box::new(fold_expr(self, expr)),
                    paren_token: token::Paren::default(),
                }),
            }
        }

        fn fold_generic_argument(&mut self, arg: GenericArgument) -> GenericArgument {
            match arg {
                GenericArgument::Const(arg) => GenericArgument::Const(match arg {
                    Expr::Block(_) => fold_expr(self, arg),
                    // Don't wrap unbraced const generic arg as that's invalid syntax.
                    _ => arg,
                }),
                _ => fold_generic_argument(self, arg),
            }
        }

        fn fold_generic_method_argument(
            &mut self,
            arg: GenericMethodArgument,
        ) -> GenericMethodArgument {
            match arg {
                GenericMethodArgument::Const(arg) => GenericMethodArgument::Const(match arg {
                    Expr::Block(_) => fold_expr(self, arg),
                    // Don't wrap unbraced const generic arg as that's invalid syntax.
                    _ => arg,
                }),
                _ => fold_generic_method_argument(self, arg),
            }
        }

        fn fold_stmt(&mut self, stmt: Stmt) -> Stmt {
            match stmt {
                // Don't wrap toplevel expressions in statements.
                Stmt::Expr(e) => Stmt::Expr(fold_expr(self, e)),
                Stmt::Semi(e, semi) => {
                    if let Expr::Verbatim(_) = e {
                        Stmt::Semi(e, semi)
                    } else {
                        Stmt::Semi(fold_expr(self, e), semi)
                    }
                }
                s => s,
            }
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn fold_pat(&mut self, pat: Pat) -> Pat {
            pat
        }

        fn fold_type(&mut self, ty: Type) -> Type {
            ty
        }
    }

    let mut folder = ParenthesizeEveryExpr;
    folder.fold_expr(syn_expr)
}

/// Walk through a crate collecting all expressions we can find in it.
fn collect_exprs(file: syn::File) -> Vec<syn::Expr> {
    use syn::fold::Fold;
    use syn::punctuated::Punctuated;
    use syn::{token, Expr, ExprTuple, Path};

    struct CollectExprs(Vec<Expr>);
    impl Fold for CollectExprs {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            match expr {
                Expr::Verbatim(_) => {}
                _ => self.0.push(expr),
            }

            Expr::Tuple(ExprTuple {
                attrs: vec![],
                elems: Punctuated::new(),
                paren_token: token::Paren::default(),
            })
        }

        fn fold_path(&mut self, path: Path) -> Path {
            // Skip traversing into const generic path arguments
            path
        }
    }

    let mut folder = CollectExprs(vec![]);
    folder.fold_file(file);
    folder.0
}
<|endoftext|>


<commit_before>// This file is part of rust-web/twig
//
// For the copyright and license information, please view the LICENSE
// file that was distributed with this source code.

//! Node.

use std::fmt::Debug;
use std::collections::HashMap;
use engine::parser::error::{NodeError, NodeErrorCode};
use engine::parser::token::stream::Position;

pub trait Node : Debug {
    fn tag(&self) -> &str;
    fn position(&self) -> &Position;
    fn children(&self) -> &Vec<Box<Node>>;
    fn children_mut(&mut self) -> &mut Vec<Box<Node>>;
    fn has_attribute(&self, key: &str) -> bool;
    fn attribute(&self, key: &str) -> Result<&str, NodeError>;
    fn set_attribute(&mut self, key: &str, value: &str) -> Option<String>;
    fn rm_attribute(&mut self, key: &str) -> Option<String>;
}

type NodeDataAttibutes = HashMap<String, String>;

#[allow(dead_code)]
#[derive(Debug, Default)]
pub struct GenericNode<T> {
    tag: String,
    position: Position,
    nodes: Vec<Box<Node>>, // ??
    attributes: NodeDataAttibutes,
    data: T,
}

#[allow(dead_code)]
impl<T> Node for GenericNode<T> where
    T: Debug
{
    fn position(&self) -> &Position {
        &self.position
    }

    fn tag(&self) -> &str {
        &self.tag
    }

    fn has_attribute(&self, key: &str) -> bool {
        self.attributes.contains_key(key)
    }

    fn attribute(&self, key: &str) -> Result<&str, NodeError> {
        match self.attributes.get(key) {
            None => {
                err!(NodeErrorCode::AttributeNotFound {
                    key: key.to_string(),
                    node_tag: self.tag.to_string()
                })
            },
            Some(value) => Ok(value)
        }
    }

    fn set_attribute(&mut self, key: &str, value: &str) -> Option<String> {
        self.attributes.insert(key.to_string(), value.to_string())
    }

    fn rm_attribute(&mut self, key: &str) -> Option<String> {
        self.attributes.remove(key)
    }

    fn children(&self) -> &Vec<Box<Node>> {
        &self.nodes
    }

    fn children_mut(&mut self) -> &mut Vec<Box<Node>> {
        &mut self.nodes
    }
}
<commit_msg>remove GenericNode<commit_after>// This file is part of rust-web/twig
//
// For the copyright and license information, please view the LICENSE
// file that was distributed with this source code.

//! Node.

use std::fmt::Debug;
use engine::parser::token::stream::Position;

pub trait Node : Debug {
    fn tag(&self) -> &str;
    fn position(&self) -> &Position;
    fn children(&self) -> &Vec<Box<Node>>;
    fn children_mut(&mut self) -> &mut Vec<Box<Node>>;
}
<|endoftext|>


<commit_before>/// Iterator returned for the error case of `IterTools::exactly_one()`
/// This iterator yields exactly the same elements as the input iterator.
///
/// During the execution of exactly_one the iterator must be mutated.  This wrapper
/// effectively "restores" the state of the input iterator when it's handed back.
///
/// This is very similar to PutBackN except this iterator only supports 0-2 elements and does not
/// use a `Vec`.
#[derive(Debug, Clone)]
pub struct ExactlyOneErr<T, I>
where
    I: Iterator<Item = T>,
{
    first_two: (Option<T>, Option<T>),
    inner: I,
}

impl<T, I> ExactlyOneErr<T, I>
where
    I: Iterator<Item = T>,
{
    /// Creates a new `ExactlyOneErr` iterator.
    pub fn new(first_two: (Option<T>, Option<T>), inner: I) -> Self {
        Self { first_two, inner }
    }
}

impl<T, I> Iterator for ExactlyOneErr<T, I>
where
    I: Iterator<Item = T>,
{
    type Item = T;

    fn next(&mut self) -> Option<T> {
        self.first_two
            .0
            .take()
            .or_else(|| self.first_two.1.take())
            .or_else(|| self.inner.next())
    }
}
<commit_msg>Add size_hint<commit_after>use size_hint;

/// Iterator returned for the error case of `IterTools::exactly_one()`
/// This iterator yields exactly the same elements as the input iterator.
///
/// During the execution of exactly_one the iterator must be mutated.  This wrapper
/// effectively "restores" the state of the input iterator when it's handed back.
///
/// This is very similar to PutBackN except this iterator only supports 0-2 elements and does not
/// use a `Vec`.
#[derive(Debug, Clone)]
pub struct ExactlyOneErr<T, I>
where
    I: Iterator<Item = T>,
{
    first_two: (Option<T>, Option<T>),
    inner: I,
}

impl<T, I> ExactlyOneErr<T, I>
where
    I: Iterator<Item = T>,
{
    /// Creates a new `ExactlyOneErr` iterator.
    pub fn new(first_two: (Option<T>, Option<T>), inner: I) -> Self {
        Self { first_two, inner }
    }
}

impl<T, I> Iterator for ExactlyOneErr<T, I>
where
    I: Iterator<Item = T>,
{
    type Item = T;

    fn next(&mut self) -> Option<T> {
        self.first_two
            .0
            .take()
            .or_else(|| self.first_two.1.take())
            .or_else(|| self.inner.next())
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let mut additional_len = 0;
        if self.first_two.0.is_some() {
            additional_len += 1;
        }
        if self.first_two.1.is_some() {
            additional_len += 1;
        }
        size_hint::add_scalar(self.inner.size_hint(), additional_len)
    }
}
<|endoftext|>


<commit_before>// CITA
// Copyright 2016-2018 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use cita_types::{Address, H160, U256};
use contracts::native::factory::Factory as NativeFactory;
use contracts::tools::method as method_tools;
use engines::NullEngine;
use evm::action_params::{ActionParams, ActionValue};
use evm::call_type::CallType;
use evm::env_info::EnvInfo;
use evm::{Factory, Finalize, VMType};
use externalities::{Externalities, OriginInfo, OutputPolicy};
use libexecutor::economical_model::EconomicalModel;
use state::State;
use state::Substate;
use state_db::StateDB;
use std::str::FromStr;
use trace::Tracer;
use trace::{NoopTracer, NoopVMTracer};
use types::reserved_addresses;
use util::BytesRef;

const AUTO_EXEC: &[u8] = &*b"autoExec()";

lazy_static! {
    static ref AUTO_EXEC_ADDR: H160 = H160::from_str(reserved_addresses::AUTO_EXEC).unwrap();
    static ref AUTO_EXEC_HASH: Vec<u8> = method_tools::encode_to_vec(AUTO_EXEC);
}

pub fn auto_exec(
    state: &mut State<StateDB>,
    auto_exec_quota_limit: u64,
    economical_model: EconomicalModel,
    // TODO: UPGRADE PROTOC0L VERSION
    env_info: EnvInfo,
) {
    let hash = &*AUTO_EXEC_HASH;
    let params = ActionParams {
        code_address: *AUTO_EXEC_ADDR,
        address: *AUTO_EXEC_ADDR,
        sender: Address::from(0x0),
        origin: Address::from(0x0),
        gas: U256::from(auto_exec_quota_limit),
        gas_price: U256::from(1),
        value: ActionValue::Transfer(U256::from(0)),
        code: state.code(&*AUTO_EXEC_ADDR).unwrap(),
        code_hash: state.code_hash(&*AUTO_EXEC_ADDR).unwrap(),
        data: Some(hash.to_vec()),
        call_type: CallType::Call,
    };

    let mut substate = Substate::new();
    let mut tracer = NoopTracer;
    let mut out = vec![];
    let mut trace_output = tracer.prepare_trace_output();
    let output = OutputPolicy::Return(BytesRef::Flexible(&mut out), trace_output.as_mut());
    let factory = Factory::new(VMType::Interpreter, 1024 * 32);

    let engine = NullEngine::default();
    let native_factory = NativeFactory::default();
    let origin_info = OriginInfo::from(&params);
    let mut vm_tracer = NoopVMTracer;
    let mut ext = Externalities::new(
        state,
        &env_info,
        &engine,
        &factory,
        &native_factory,
        0,
        origin_info,
        &mut substate,
        output,
        &mut tracer,
        &mut vm_tracer,
        false,
        economical_model,
    );
    let res = {
        factory
            .create(params.gas)
            .exec(&params, &mut ext)
            .finalize(ext)
    };

    match res {
        Ok(res) => trace!("Auto exec succeed: {:?}", res),
        Err(e) => info!("Auto exec failed: {}", e),
    }
}
<commit_msg>Remove useless comment.<commit_after>// CITA
// Copyright 2016-2018 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use cita_types::{Address, H160, U256};
use contracts::native::factory::Factory as NativeFactory;
use contracts::tools::method as method_tools;
use engines::NullEngine;
use evm::action_params::{ActionParams, ActionValue};
use evm::call_type::CallType;
use evm::env_info::EnvInfo;
use evm::{Factory, Finalize, VMType};
use externalities::{Externalities, OriginInfo, OutputPolicy};
use libexecutor::economical_model::EconomicalModel;
use state::State;
use state::Substate;
use state_db::StateDB;
use std::str::FromStr;
use trace::Tracer;
use trace::{NoopTracer, NoopVMTracer};
use types::reserved_addresses;
use util::BytesRef;

const AUTO_EXEC: &[u8] = &*b"autoExec()";

lazy_static! {
    static ref AUTO_EXEC_ADDR: H160 = H160::from_str(reserved_addresses::AUTO_EXEC).unwrap();
    static ref AUTO_EXEC_HASH: Vec<u8> = method_tools::encode_to_vec(AUTO_EXEC);
}

pub fn auto_exec(
    state: &mut State<StateDB>,
    auto_exec_quota_limit: u64,
    economical_model: EconomicalModel,
    env_info: EnvInfo,
) {
    let hash = &*AUTO_EXEC_HASH;
    let params = ActionParams {
        code_address: *AUTO_EXEC_ADDR,
        address: *AUTO_EXEC_ADDR,
        sender: Address::from(0x0),
        origin: Address::from(0x0),
        gas: U256::from(auto_exec_quota_limit),
        gas_price: U256::from(1),
        value: ActionValue::Transfer(U256::from(0)),
        code: state.code(&*AUTO_EXEC_ADDR).unwrap(),
        code_hash: state.code_hash(&*AUTO_EXEC_ADDR).unwrap(),
        data: Some(hash.to_vec()),
        call_type: CallType::Call,
    };

    let mut substate = Substate::new();
    let mut tracer = NoopTracer;
    let mut out = vec![];
    let mut trace_output = tracer.prepare_trace_output();
    let output = OutputPolicy::Return(BytesRef::Flexible(&mut out), trace_output.as_mut());
    let factory = Factory::new(VMType::Interpreter, 1024 * 32);

    let engine = NullEngine::default();
    let native_factory = NativeFactory::default();
    let origin_info = OriginInfo::from(&params);
    let mut vm_tracer = NoopVMTracer;
    let mut ext = Externalities::new(
        state,
        &env_info,
        &engine,
        &factory,
        &native_factory,
        0,
        origin_info,
        &mut substate,
        output,
        &mut tracer,
        &mut vm_tracer,
        false,
        economical_model,
    );
    let res = {
        factory
            .create(params.gas)
            .exec(&params, &mut ext)
            .finalize(ext)
    };

    match res {
        Ok(res) => trace!("Auto exec succeed: {:?}", res),
        Err(e) => info!("Auto exec failed: {}", e),
    }
}
<|endoftext|>