<commit_before>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use CodeSuggestion;
use SubstitutionPart;
use Substitution;
use Applicability;
use Level;
use std::fmt;
use syntax_pos::{MultiSpan, Span};
use snippet::Style;

#[must_use]
#[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
pub struct Diagnostic {
    pub level: Level,
    pub message: Vec<(String, Style)>,
    pub code: Option<DiagnosticId>,
    pub span: MultiSpan,
    pub children: Vec<SubDiagnostic>,
    pub suggestions: Vec<CodeSuggestion>,
}

#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum DiagnosticId {
    Error(String),
    Lint(String),
}

/// For example a note attached to an error.
#[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
pub struct SubDiagnostic {
    pub level: Level,
    pub message: Vec<(String, Style)>,
    pub span: MultiSpan,
    pub render_span: Option<MultiSpan>,
}

#[derive(PartialEq, Eq)]
pub struct DiagnosticStyledString(pub Vec<StringPart>);

impl DiagnosticStyledString {
    pub fn new() -> DiagnosticStyledString {
        DiagnosticStyledString(vec![])
    }
    pub fn push_normal<S: Into<String>>(&mut self, t: S) {
        self.0.push(StringPart::Normal(t.into()));
    }
    pub fn push_highlighted<S: Into<String>>(&mut self, t: S) {
        self.0.push(StringPart::Highlighted(t.into()));
    }
    pub fn normal<S: Into<String>>(t: S) -> DiagnosticStyledString {
        DiagnosticStyledString(vec![StringPart::Normal(t.into())])
    }

    pub fn highlighted<S: Into<String>>(t: S) -> DiagnosticStyledString {
        DiagnosticStyledString(vec![StringPart::Highlighted(t.into())])
    }

    pub fn content(&self) -> String {
        self.0.iter().map(|x| x.content()).collect::<String>()
    }
}

#[derive(PartialEq, Eq)]
pub enum StringPart {
    Normal(String),
    Highlighted(String),
}

impl StringPart {
    pub fn content(&self) -> String {
        match self {
            &StringPart::Normal(ref s) | & StringPart::Highlighted(ref s) => s.to_owned()
        }
    }
}

impl Diagnostic {
    pub fn new(level: Level, message: &str) -> Self {
        Diagnostic::new_with_code(level, None, message)
    }

    pub fn new_with_code(level: Level, code: Option<DiagnosticId>, message: &str) -> Self {
        Diagnostic {
            level,
            message: vec![(message.to_owned(), Style::NoStyle)],
            code,
            span: MultiSpan::new(),
            children: vec![],
            suggestions: vec![],
        }
    }

    pub fn is_error(&self) -> bool {
        match self.level {
            Level::Bug |
            Level::Fatal |
            Level::PhaseFatal |
            Level::Error |
            Level::FailureNote => {
                true
            }

            Level::Warning |
            Level::Note |
            Level::Help |
            Level::Cancelled => {
                false
            }
        }
    }

    /// Cancel the diagnostic (a structured diagnostic must either be emitted or
    /// canceled or it will panic when dropped).
    pub fn cancel(&mut self) {
        self.level = Level::Cancelled;
    }

    pub fn cancelled(&self) -> bool {
        self.level == Level::Cancelled
    }

    /// Add a span/label to be included in the resulting snippet.
    /// This is pushed onto the `MultiSpan` that was created when the
    /// diagnostic was first built. If you don't call this function at
    /// all, and you just supplied a `Span` to create the diagnostic,
    /// then the snippet will just include that `Span`, which is
    /// called the primary span.
    pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self {
        self.span.push_span_label(span, label.into());
        self
    }

    pub fn note_expected_found(&mut self,
                               label: &dyn fmt::Display,
                               expected: DiagnosticStyledString,
                               found: DiagnosticStyledString)
                               -> &mut Self
    {
        self.note_expected_found_extra(label, expected, found, &"", &"")
    }

    pub fn note_expected_found_extra(&mut self,
                                     label: &dyn fmt::Display,
                                     expected: DiagnosticStyledString,
                                     found: DiagnosticStyledString,
                                     expected_extra: &dyn fmt::Display,
                                     found_extra: &dyn fmt::Display)
                                     -> &mut Self
    {
        let mut msg: Vec<_> = vec![(format!("expected {} `", label), Style::NoStyle)];
        msg.extend(expected.0.iter()
                   .map(|x| match *x {
                       StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
                       StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
                   }));
        msg.push((format!("`{}\n", expected_extra), Style::NoStyle));
        msg.push((format!("   found {} `", label), Style::NoStyle));
        msg.extend(found.0.iter()
                   .map(|x| match *x {
                       StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
                       StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
                   }));
        msg.push((format!("`{}", found_extra), Style::NoStyle));

        // For now, just attach these as notes
        self.highlighted_note(msg);
        self
    }

    pub fn note_trait_signature(&mut self, name: String, signature: String) -> &mut Self {
        self.highlighted_note(vec![
            (format!("`{}` from trait: `", name), Style::NoStyle),
            (signature, Style::Highlight),
            ("`".to_string(), Style::NoStyle)]);
        self
    }

    pub fn note(&mut self, msg: &str) -> &mut Self {
        self.sub(Level::Note, msg, MultiSpan::new(), None);
        self
    }

    pub fn highlighted_note(&mut self, msg: Vec<(String, Style)>) -> &mut Self {
        self.sub_with_highlights(Level::Note, msg, MultiSpan::new(), None);
        self
    }

    pub fn span_note<S: Into<MultiSpan>>(&mut self,
                                         sp: S,
                                         msg: &str)
                                         -> &mut Self {
        self.sub(Level::Note, msg, sp.into(), None);
        self
    }

    pub fn warn(&mut self, msg: &str) -> &mut Self {
        self.sub(Level::Warning, msg, MultiSpan::new(), None);
        self
    }

    pub fn span_warn<S: Into<MultiSpan>>(&mut self,
                                         sp: S,
                                         msg: &str)
                                         -> &mut Self {
        self.sub(Level::Warning, msg, sp.into(), None);
        self
    }

    pub fn help(&mut self , msg: &str) -> &mut Self {
        self.sub(Level::Help, msg, MultiSpan::new(), None);
        self
    }

    pub fn span_help<S: Into<MultiSpan>>(&mut self,
                                         sp: S,
                                         msg: &str)
                                         -> &mut Self {
        self.sub(Level::Help, msg, sp.into(), None);
        self
    }

    /// Prints out a message with a suggested edit of the code. If the suggestion is presented
    /// inline it will only show the text message and not the text.
    ///
    /// See `CodeSuggestion` for more information.
    #[deprecated(note = "Use `span_suggestion_short_with_applicability`")]
    pub fn span_suggestion_short(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self {
        self.suggestions.push(CodeSuggestion {
            substitutions: vec![Substitution {
                parts: vec![SubstitutionPart {
                    snippet: suggestion,
                    span: sp,
                }],
            }],
            msg: msg.to_owned(),
            show_code_when_inline: false,
            applicability: Applicability::Unspecified,
        });
        self
    }

    /// Prints out a message with a suggested edit of the code.
    ///
    /// In case of short messages and a simple suggestion,
    /// rustc displays it as a label like
    ///
    /// "try adding parentheses: `(tup.0).1`"
    ///
    /// The message
    ///
    /// * should not end in any punctuation (a `:` is added automatically)
    /// * should not be a question
    /// * should not contain any parts like "the following", "as shown"
    /// * may look like "to do xyz, use" or "to do xyz, use abc"
    /// * may contain a name of a function, variable or type, but not whole expressions
    ///
    /// See `CodeSuggestion` for more information.
    #[deprecated(note = "Use `span_suggestion_with_applicability`")]
    pub fn span_suggestion(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self {
        self.suggestions.push(CodeSuggestion {
            substitutions: vec![Substitution {
                parts: vec![SubstitutionPart {
                    snippet: suggestion,
                    span: sp,
                }],
            }],
            msg: msg.to_owned(),
            show_code_when_inline: true,
            applicability: Applicability::Unspecified,
        });
        self
    }

    pub fn multipart_suggestion_with_applicability(
        &mut self,
        msg: &str,
        suggestion: Vec<(Span, String)>,
        applicability: Applicability,
    ) -> &mut Self {
        self.suggestions.push(CodeSuggestion {
            substitutions: vec![Substitution {
                parts: suggestion
                    .into_iter()
                    .map(|(span, snippet)| SubstitutionPart { snippet, span })
                    .collect(),
            }],
            msg: msg.to_owned(),
            show_code_when_inline: true,
            applicability,
        });
        self
    }

    #[deprecated(note = "Use `multipart_suggestion_with_applicability`")]
    pub fn multipart_suggestion(
        &mut self,
        msg: &str,
        suggestion: Vec<(Span, String)>,
    ) -> &mut Self {
        self.multipart_suggestion_with_applicability(
                                                     msg,
                                                     suggestion,
                                                     Applicability::Unspecified
                                                    )
    }

    /// Prints out a message with multiple suggested edits of the code.
    #[deprecated(note = "Use `span_suggestions_with_applicability`")]
    pub fn span_suggestions(&mut self, sp: Span, msg: &str, suggestions: Vec<String>) -> &mut Self {
        self.suggestions.push(CodeSuggestion {
            substitutions: suggestions.into_iter().map(|snippet| Substitution {
                parts: vec![SubstitutionPart {
                    snippet,
                    span: sp,
                }],
            }).collect(),
            msg: msg.to_owned(),
            show_code_when_inline: true,
            applicability: Applicability::Unspecified,
        });
        self
    }

    /// This is a suggestion that may contain mistakes or fillers and should
    /// be read and understood by a human.
    pub fn span_suggestion_with_applicability(&mut self, sp: Span, msg: &str,
                                       suggestion: String,
                                       applicability: Applicability) -> &mut Self {
        self.suggestions.push(CodeSuggestion {
            substitutions: vec![Substitution {
                parts: vec![SubstitutionPart {
                    snippet: suggestion,
                    span: sp,
                }],
            }],
            msg: msg.to_owned(),
            show_code_when_inline: true,
            applicability,
        });
        self
    }

    pub fn span_suggestions_with_applicability(&mut self, sp: Span, msg: &str,
                                        suggestions: Vec<String>,
                                        applicability: Applicability) -> &mut Self {
        self.suggestions.push(CodeSuggestion {
            substitutions: suggestions.into_iter().map(|snippet| Substitution {
                parts: vec![SubstitutionPart {
                    snippet,
                    span: sp,
                }],
            }).collect(),
            msg: msg.to_owned(),
            show_code_when_inline: true,
            applicability,
        });
        self
    }

    pub fn span_suggestion_short_with_applicability(
        &mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability
    ) -> &mut Self {
        self.suggestions.push(CodeSuggestion {
            substitutions: vec![Substitution {
                parts: vec![SubstitutionPart {
                    snippet: suggestion,
                    span: sp,
                }],
            }],
            msg: msg.to_owned(),
            show_code_when_inline: false,
            applicability: applicability,
        });
        self
    }

    pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
        self.span = sp.into();
        self
    }

    pub fn code(&mut self, s: DiagnosticId) -> &mut Self {
        self.code = Some(s);
        self
    }

    pub fn get_code(&self) -> Option<DiagnosticId> {
        self.code.clone()
    }

    pub fn message(&self) -> String {
        self.message.iter().map(|i| i.0.to_owned()).collect::<String>()
    }

    pub fn styled_message(&self) -> &Vec<(String, Style)> {
        &self.message
    }

    /// Used by a lint. Copies over all details *but* the "main
    /// message".
    pub fn copy_details_not_message(&mut self, from: &Diagnostic) {
        self.span = from.span.clone();
        self.code = from.code.clone();
        self.children.extend(from.children.iter().cloned())
    }

    /// Convenience function for internal use, clients should use one of the
    /// public methods above.
    pub fn sub(&mut self,
           level: Level,
           message: &str,
           span: MultiSpan,
           render_span: Option<MultiSpan>) {
        let sub = SubDiagnostic {
            level,
            message: vec![(message.to_owned(), Style::NoStyle)],
            span,
            render_span,
        };
        self.children.push(sub);
    }

    /// Convenience function for internal use, clients should use one of the
    /// public methods above.
    fn sub_with_highlights(&mut self,
                           level: Level,
                           message: Vec<(String, Style)>,
                           span: MultiSpan,
                           render_span: Option<MultiSpan>) {
        let sub = SubDiagnostic {
            level,
            message,
            span,
            render_span,
        };
        self.children.push(sub);
    }
}

impl SubDiagnostic {
    pub fn message(&self) -> String {
        self.message.iter().map(|i| i.0.to_owned()).collect::<String>()
    }

    pub fn styled_message(&self) -> &Vec<(String, Style)> {
        &self.message
    }
}
<commit_msg>trailing whitespace fix<commit_after>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use CodeSuggestion;
use SubstitutionPart;
use Substitution;
use Applicability;
use Level;
use std::fmt;
use syntax_pos::{MultiSpan, Span};
use snippet::Style;

#[must_use]
#[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
pub struct Diagnostic {
    pub level: Level,
    pub message: Vec<(String, Style)>,
    pub code: Option<DiagnosticId>,
    pub span: MultiSpan,
    pub children: Vec<SubDiagnostic>,
    pub suggestions: Vec<CodeSuggestion>,
}

#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum DiagnosticId {
    Error(String),
    Lint(String),
}

/// For example a note attached to an error.
#[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
pub struct SubDiagnostic {
    pub level: Level,
    pub message: Vec<(String, Style)>,
    pub span: MultiSpan,
    pub render_span: Option<MultiSpan>,
}

#[derive(PartialEq, Eq)]
pub struct DiagnosticStyledString(pub Vec<StringPart>);

impl DiagnosticStyledString {
    pub fn new() -> DiagnosticStyledString {
        DiagnosticStyledString(vec![])
    }
    pub fn push_normal<S: Into<String>>(&mut self, t: S) {
        self.0.push(StringPart::Normal(t.into()));
    }
    pub fn push_highlighted<S: Into<String>>(&mut self, t: S) {
        self.0.push(StringPart::Highlighted(t.into()));
    }
    pub fn normal<S: Into<String>>(t: S) -> DiagnosticStyledString {
        DiagnosticStyledString(vec![StringPart::Normal(t.into())])
    }

    pub fn highlighted<S: Into<String>>(t: S) -> DiagnosticStyledString {
        DiagnosticStyledString(vec![StringPart::Highlighted(t.into())])
    }

    pub fn content(&self) -> String {
        self.0.iter().map(|x| x.content()).collect::<String>()
    }
}

#[derive(PartialEq, Eq)]
pub enum StringPart {
    Normal(String),
    Highlighted(String),
}

impl StringPart {
    pub fn content(&self) -> String {
        match self {
            &StringPart::Normal(ref s) | & StringPart::Highlighted(ref s) => s.to_owned()
        }
    }
}

impl Diagnostic {
    pub fn new(level: Level, message: &str) -> Self {
        Diagnostic::new_with_code(level, None, message)
    }

    pub fn new_with_code(level: Level, code: Option<DiagnosticId>, message: &str) -> Self {
        Diagnostic {
            level,
            message: vec![(message.to_owned(), Style::NoStyle)],
            code,
            span: MultiSpan::new(),
            children: vec![],
            suggestions: vec![],
        }
    }

    pub fn is_error(&self) -> bool {
        match self.level {
            Level::Bug |
            Level::Fatal |
            Level::PhaseFatal |
            Level::Error |
            Level::FailureNote => {
                true
            }

            Level::Warning |
            Level::Note |
            Level::Help |
            Level::Cancelled => {
                false
            }
        }
    }

    /// Cancel the diagnostic (a structured diagnostic must either be emitted or
    /// canceled or it will panic when dropped).
    pub fn cancel(&mut self) {
        self.level = Level::Cancelled;
    }

    pub fn cancelled(&self) -> bool {
        self.level == Level::Cancelled
    }

    /// Add a span/label to be included in the resulting snippet.
    /// This is pushed onto the `MultiSpan` that was created when the
    /// diagnostic was first built. If you don't call this function at
    /// all, and you just supplied a `Span` to create the diagnostic,
    /// then the snippet will just include that `Span`, which is
    /// called the primary span.
    pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self {
        self.span.push_span_label(span, label.into());
        self
    }

    pub fn note_expected_found(&mut self,
                               label: &dyn fmt::Display,
                               expected: DiagnosticStyledString,
                               found: DiagnosticStyledString)
                               -> &mut Self
    {
        self.note_expected_found_extra(label, expected, found, &"", &"")
    }

    pub fn note_expected_found_extra(&mut self,
                                     label: &dyn fmt::Display,
                                     expected: DiagnosticStyledString,
                                     found: DiagnosticStyledString,
                                     expected_extra: &dyn fmt::Display,
                                     found_extra: &dyn fmt::Display)
                                     -> &mut Self
    {
        let mut msg: Vec<_> = vec![(format!("expected {} `", label), Style::NoStyle)];
        msg.extend(expected.0.iter()
                   .map(|x| match *x {
                       StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
                       StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
                   }));
        msg.push((format!("`{}\n", expected_extra), Style::NoStyle));
        msg.push((format!("   found {} `", label), Style::NoStyle));
        msg.extend(found.0.iter()
                   .map(|x| match *x {
                       StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
                       StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
                   }));
        msg.push((format!("`{}", found_extra), Style::NoStyle));

        // For now, just attach these as notes
        self.highlighted_note(msg);
        self
    }

    pub fn note_trait_signature(&mut self, name: String, signature: String) -> &mut Self {
        self.highlighted_note(vec![
            (format!("`{}` from trait: `", name), Style::NoStyle),
            (signature, Style::Highlight),
            ("`".to_string(), Style::NoStyle)]);
        self
    }

    pub fn note(&mut self, msg: &str) -> &mut Self {
        self.sub(Level::Note, msg, MultiSpan::new(), None);
        self
    }

    pub fn highlighted_note(&mut self, msg: Vec<(String, Style)>) -> &mut Self {
        self.sub_with_highlights(Level::Note, msg, MultiSpan::new(), None);
        self
    }

    pub fn span_note<S: Into<MultiSpan>>(&mut self,
                                         sp: S,
                                         msg: &str)
                                         -> &mut Self {
        self.sub(Level::Note, msg, sp.into(), None);
        self
    }

    pub fn warn(&mut self, msg: &str) -> &mut Self {
        self.sub(Level::Warning, msg, MultiSpan::new(), None);
        self
    }

    pub fn span_warn<S: Into<MultiSpan>>(&mut self,
                                         sp: S,
                                         msg: &str)
                                         -> &mut Self {
        self.sub(Level::Warning, msg, sp.into(), None);
        self
    }

    pub fn help(&mut self , msg: &str) -> &mut Self {
        self.sub(Level::Help, msg, MultiSpan::new(), None);
        self
    }

    pub fn span_help<S: Into<MultiSpan>>(&mut self,
                                         sp: S,
                                         msg: &str)
                                         -> &mut Self {
        self.sub(Level::Help, msg, sp.into(), None);
        self
    }

    /// Prints out a message with a suggested edit of the code. If the suggestion is presented
    /// inline it will only show the text message and not the text.
    ///
    /// See `CodeSuggestion` for more information.
    #[deprecated(note = "Use `span_suggestion_short_with_applicability`")]
    pub fn span_suggestion_short(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self {
        self.suggestions.push(CodeSuggestion {
            substitutions: vec![Substitution {
                parts: vec![SubstitutionPart {
                    snippet: suggestion,
                    span: sp,
                }],
            }],
            msg: msg.to_owned(),
            show_code_when_inline: false,
            applicability: Applicability::Unspecified,
        });
        self
    }

    /// Prints out a message with a suggested edit of the code.
    ///
    /// In case of short messages and a simple suggestion,
    /// rustc displays it as a label like
    ///
    /// "try adding parentheses: `(tup.0).1`"
    ///
    /// The message
    ///
    /// * should not end in any punctuation (a `:` is added automatically)
    /// * should not be a question
    /// * should not contain any parts like "the following", "as shown"
    /// * may look like "to do xyz, use" or "to do xyz, use abc"
    /// * may contain a name of a function, variable or type, but not whole expressions
    ///
    /// See `CodeSuggestion` for more information.
    #[deprecated(note = "Use `span_suggestion_with_applicability`")]
    pub fn span_suggestion(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self {
        self.suggestions.push(CodeSuggestion {
            substitutions: vec![Substitution {
                parts: vec![SubstitutionPart {
                    snippet: suggestion,
                    span: sp,
                }],
            }],
            msg: msg.to_owned(),
            show_code_when_inline: true,
            applicability: Applicability::Unspecified,
        });
        self
    }

    pub fn multipart_suggestion_with_applicability(
        &mut self,
        msg: &str,
        suggestion: Vec<(Span, String)>,
        applicability: Applicability,
    ) -> &mut Self {
        self.suggestions.push(CodeSuggestion {
            substitutions: vec![Substitution {
                parts: suggestion
                    .into_iter()
                    .map(|(span, snippet)| SubstitutionPart { snippet, span })
                    .collect(),
            }],
            msg: msg.to_owned(),
            show_code_when_inline: true,
            applicability,
        });
        self
    }

    #[deprecated(note = "Use `multipart_suggestion_with_applicability`")]
    pub fn multipart_suggestion(
        &mut self,
        msg: &str,
        suggestion: Vec<(Span, String)>,
    ) -> &mut Self {
        self.multipart_suggestion_with_applicability(
                                                     msg,
                                                     suggestion,
                                                     Applicability::Unspecified
                                                    )
    }

    /// Prints out a message with multiple suggested edits of the code.
    #[deprecated(note = "Use `span_suggestions_with_applicability`")]
    pub fn span_suggestions(&mut self, sp: Span, msg: &str, suggestions: Vec<String>) -> &mut Self {
        self.suggestions.push(CodeSuggestion {
            substitutions: suggestions.into_iter().map(|snippet| Substitution {
                parts: vec![SubstitutionPart {
                    snippet,
                    span: sp,
                }],
            }).collect(),
            msg: msg.to_owned(),
            show_code_when_inline: true,
            applicability: Applicability::Unspecified,
        });
        self
    }

    /// This is a suggestion that may contain mistakes or fillers and should
    /// be read and understood by a human.
    pub fn span_suggestion_with_applicability(&mut self, sp: Span, msg: &str,
                                       suggestion: String,
                                       applicability: Applicability) -> &mut Self {
        self.suggestions.push(CodeSuggestion {
            substitutions: vec![Substitution {
                parts: vec![SubstitutionPart {
                    snippet: suggestion,
                    span: sp,
                }],
            }],
            msg: msg.to_owned(),
            show_code_when_inline: true,
            applicability,
        });
        self
    }

    pub fn span_suggestions_with_applicability(&mut self, sp: Span, msg: &str,
                                        suggestions: Vec<String>,
                                        applicability: Applicability) -> &mut Self {
        self.suggestions.push(CodeSuggestion {
            substitutions: suggestions.into_iter().map(|snippet| Substitution {
                parts: vec![SubstitutionPart {
                    snippet,
                    span: sp,
                }],
            }).collect(),
            msg: msg.to_owned(),
            show_code_when_inline: true,
            applicability,
        });
        self
    }

    pub fn span_suggestion_short_with_applicability(
        &mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability
    ) -> &mut Self {
        self.suggestions.push(CodeSuggestion {
            substitutions: vec![Substitution {
                parts: vec![SubstitutionPart {
                    snippet: suggestion,
                    span: sp,
                }],
            }],
            msg: msg.to_owned(),
            show_code_when_inline: false,
            applicability: applicability,
        });
        self
    }

    pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
        self.span = sp.into();
        self
    }

    pub fn code(&mut self, s: DiagnosticId) -> &mut Self {
        self.code = Some(s);
        self
    }

    pub fn get_code(&self) -> Option<DiagnosticId> {
        self.code.clone()
    }

    pub fn message(&self) -> String {
        self.message.iter().map(|i| i.0.to_owned()).collect::<String>()
    }

    pub fn styled_message(&self) -> &Vec<(String, Style)> {
        &self.message
    }

    /// Used by a lint. Copies over all details *but* the "main
    /// message".
    pub fn copy_details_not_message(&mut self, from: &Diagnostic) {
        self.span = from.span.clone();
        self.code = from.code.clone();
        self.children.extend(from.children.iter().cloned())
    }

    /// Convenience function for internal use, clients should use one of the
    /// public methods above.
    pub fn sub(&mut self,
           level: Level,
           message: &str,
           span: MultiSpan,
           render_span: Option<MultiSpan>) {
        let sub = SubDiagnostic {
            level,
            message: vec![(message.to_owned(), Style::NoStyle)],
            span,
            render_span,
        };
        self.children.push(sub);
    }

    /// Convenience function for internal use, clients should use one of the
    /// public methods above.
    fn sub_with_highlights(&mut self,
                           level: Level,
                           message: Vec<(String, Style)>,
                           span: MultiSpan,
                           render_span: Option<MultiSpan>) {
        let sub = SubDiagnostic {
            level,
            message,
            span,
            render_span,
        };
        self.children.push(sub);
    }
}

impl SubDiagnostic {
    pub fn message(&self) -> String {
        self.message.iter().map(|i| i.0.to_owned()).collect::<String>()
    }

    pub fn styled_message(&self) -> &Vec<(String, Style)> {
        &self.message
    }
}
<|endoftext|>


<commit_before>//! An asynchronous `Mutex`-like type.
//!
//! This module provides [`Mutex`], a type that acts similarly to an asynchronous `Mutex`, with one
//! major difference: the [`MutexGuard`] returned by `lock` is not tied to the lifetime of the
//! `Mutex`. This enables you to acquire a lock, and then pass that guard into a future, and then
//! release it at some later point in time.
//!
//! This allows you to do something along the lines of:
//!
//! ```rust,no_run
//! use tokio::sync::Mutex;
//! use std::sync::Arc;
//!
//! #[tokio::main]
//! async fn main() {
//!     let data1 = Arc::new(Mutex::new(0));
//!     let data2 = Arc::clone(&data1);
//!
//!     tokio::spawn(async move {
//!         let mut lock = data2.lock().await;
//!         *lock += 1;
//!     });
//!
//!     let mut lock = data1.lock().await;
//!     *lock += 1;
//! }
//! ```
//!
//! Note that in contrast to `std::sync::Mutex`, this implementation does not
//! poison the mutex when a thread holding the `MutexGuard` panics. In such a
//! case, the mutex will be unlocked. If the panic is caught, this might leave
//! the data protected by the mutes in an inconsistent state.
//!
//! [`Mutex`]: struct.Mutex.html
//! [`MutexGuard`]: struct.MutexGuard.html

use crate::future::poll_fn;
use crate::sync::semaphore;

use std::cell::UnsafeCell;
use std::fmt;
use std::ops::{Deref, DerefMut};

/// An asynchronous mutual exclusion primitive useful for protecting shared data
///
/// Each mutex has a type parameter (`T`) which represents the data that it is protecting. The data
/// can only be accessed through the RAII guards returned from `lock`, which
/// guarantees that the data is only ever accessed when the mutex is locked.
#[derive(Debug)]
pub struct Mutex<T> {
    c: UnsafeCell<T>,
    s: semaphore::Semaphore,
}

/// A handle to a held `Mutex`.
///
/// As long as you have this guard, you have exclusive access to the underlying `T`. The guard
/// internally keeps a reference-couned pointer to the original `Mutex`, so even if the lock goes
/// away, the guard remains valid.
///
/// The lock is automatically released whenever the guard is dropped, at which point `lock`
/// will succeed yet again.
#[derive(Debug)]
pub struct MutexGuard<'a, T> {
    lock: &'a Mutex<T>,
    permit: semaphore::Permit,
}

// As long as T: Send, it's fine to send and share Mutex<T> between threads.
// If T was not Send, sending and sharing a Mutex<T> would be bad, since you can access T through
// Mutex<T>.
unsafe impl<T> Send for Mutex<T> where T: Send {}
unsafe impl<T> Sync for Mutex<T> where T: Send {}
unsafe impl<'a, T> Sync for MutexGuard<'a, T> where T: Send + Sync {}

#[test]
#[cfg(not(loom))]
fn bounds() {
    fn check<T: Send>() {}
    check::<MutexGuard<'_, u32>>();
}

impl<T> Mutex<T> {
    /// Creates a new lock in an unlocked state ready for use.
    pub fn new(t: T) -> Self {
        Self {
            c: UnsafeCell::new(t),
            s: semaphore::Semaphore::new(1),
        }
    }

    /// A future that resolves on acquiring the lock and returns the `MutexGuard`.
    pub async fn lock(&self) -> MutexGuard<'_, T> {
        let mut guard = MutexGuard {
            lock: self,
            permit: semaphore::Permit::new(),
        };
        poll_fn(|cx| guard.permit.poll_acquire(cx, &self.s))
            .await
            .unwrap_or_else(|_| {
                // The semaphore was closed. but, we never explicitly close it, and we have a
                // handle to it through the Arc, which means that this can never happen.
                unreachable!()
            });
        guard
    }
}

impl<'a, T> Drop for MutexGuard<'a, T> {
    fn drop(&mut self) {
        self.permit.release(&self.lock.s);
    }
}

impl<T> From<T> for Mutex<T> {
    fn from(s: T) -> Self {
        Self::new(s)
    }
}

impl<T> Default for Mutex<T>
where
    T: Default,
{
    fn default() -> Self {
        Self::new(T::default())
    }
}

impl<'a, T> Deref for MutexGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        assert!(self.permit.is_acquired());
        unsafe { &*self.lock.c.get() }
    }
}

impl<'a, T> DerefMut for MutexGuard<'a, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        assert!(self.permit.is_acquired());
        unsafe { &mut *self.lock.c.get() }
    }
}

impl<'a, T: fmt::Display> fmt::Display for MutexGuard<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&**self, f)
    }
}
<commit_msg>sync::Mutex: Fix typo in documentation (#1934)<commit_after>//! An asynchronous `Mutex`-like type.
//!
//! This module provides [`Mutex`], a type that acts similarly to an asynchronous `Mutex`, with one
//! major difference: the [`MutexGuard`] returned by `lock` is not tied to the lifetime of the
//! `Mutex`. This enables you to acquire a lock, and then pass that guard into a future, and then
//! release it at some later point in time.
//!
//! This allows you to do something along the lines of:
//!
//! ```rust,no_run
//! use tokio::sync::Mutex;
//! use std::sync::Arc;
//!
//! #[tokio::main]
//! async fn main() {
//!     let data1 = Arc::new(Mutex::new(0));
//!     let data2 = Arc::clone(&data1);
//!
//!     tokio::spawn(async move {
//!         let mut lock = data2.lock().await;
//!         *lock += 1;
//!     });
//!
//!     let mut lock = data1.lock().await;
//!     *lock += 1;
//! }
//! ```
//!
//! Note that in contrast to `std::sync::Mutex`, this implementation does not
//! poison the mutex when a thread holding the `MutexGuard` panics. In such a
//! case, the mutex will be unlocked. If the panic is caught, this might leave
//! the data protected by the mutex in an inconsistent state.
//!
//! [`Mutex`]: struct.Mutex.html
//! [`MutexGuard`]: struct.MutexGuard.html

use crate::future::poll_fn;
use crate::sync::semaphore;

use std::cell::UnsafeCell;
use std::fmt;
use std::ops::{Deref, DerefMut};

/// An asynchronous mutual exclusion primitive useful for protecting shared data
///
/// Each mutex has a type parameter (`T`) which represents the data that it is protecting. The data
/// can only be accessed through the RAII guards returned from `lock`, which
/// guarantees that the data is only ever accessed when the mutex is locked.
#[derive(Debug)]
pub struct Mutex<T> {
    c: UnsafeCell<T>,
    s: semaphore::Semaphore,
}

/// A handle to a held `Mutex`.
///
/// As long as you have this guard, you have exclusive access to the underlying `T`. The guard
/// internally keeps a reference-couned pointer to the original `Mutex`, so even if the lock goes
/// away, the guard remains valid.
///
/// The lock is automatically released whenever the guard is dropped, at which point `lock`
/// will succeed yet again.
#[derive(Debug)]
pub struct MutexGuard<'a, T> {
    lock: &'a Mutex<T>,
    permit: semaphore::Permit,
}

// As long as T: Send, it's fine to send and share Mutex<T> between threads.
// If T was not Send, sending and sharing a Mutex<T> would be bad, since you can access T through
// Mutex<T>.
unsafe impl<T> Send for Mutex<T> where T: Send {}
unsafe impl<T> Sync for Mutex<T> where T: Send {}
unsafe impl<'a, T> Sync for MutexGuard<'a, T> where T: Send + Sync {}

#[test]
#[cfg(not(loom))]
fn bounds() {
    fn check<T: Send>() {}
    check::<MutexGuard<'_, u32>>();
}

impl<T> Mutex<T> {
    /// Creates a new lock in an unlocked state ready for use.
    pub fn new(t: T) -> Self {
        Self {
            c: UnsafeCell::new(t),
            s: semaphore::Semaphore::new(1),
        }
    }

    /// A future that resolves on acquiring the lock and returns the `MutexGuard`.
    pub async fn lock(&self) -> MutexGuard<'_, T> {
        let mut guard = MutexGuard {
            lock: self,
            permit: semaphore::Permit::new(),
        };
        poll_fn(|cx| guard.permit.poll_acquire(cx, &self.s))
            .await
            .unwrap_or_else(|_| {
                // The semaphore was closed. but, we never explicitly close it, and we have a
                // handle to it through the Arc, which means that this can never happen.
                unreachable!()
            });
        guard
    }
}

impl<'a, T> Drop for MutexGuard<'a, T> {
    fn drop(&mut self) {
        self.permit.release(&self.lock.s);
    }
}

impl<T> From<T> for Mutex<T> {
    fn from(s: T) -> Self {
        Self::new(s)
    }
}

impl<T> Default for Mutex<T>
where
    T: Default,
{
    fn default() -> Self {
        Self::new(T::default())
    }
}

impl<'a, T> Deref for MutexGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        assert!(self.permit.is_acquired());
        unsafe { &*self.lock.c.get() }
    }
}

impl<'a, T> DerefMut for MutexGuard<'a, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        assert!(self.permit.is_acquired());
        unsafe { &mut *self.lock.c.get() }
    }
}

impl<'a, T: fmt::Display> fmt::Display for MutexGuard<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&**self, f)
    }
}
<|endoftext|>


<commit_before>//! The global state.

use std::sync::Mutex; // TODO: Use custom option-like thing.
use std::collections::HashSet;
use std::mem;
use {rand, hazard, mpsc};
use garbage::Garbage;

lazy_static! {
    /// The global state.
    ///
    /// This state is shared between all the threads.
    static ref STATE: State = State::new();
}

/// Create a new hazard.
///
/// This creates a new hazard and registers it in the global state. It's secondary, writer part is
/// returned.
pub fn create_hazard() -> hazard::Writer {
    // Create the hazard.
    let (writer, reader) = hazard::create();
    // Communicate the new hazard to the global state through the channel.
    STATE.chan.send(Message::NewHazard(reader));
    // Return the other half of the hazard.
    writer
}

/// Export garbage into the global state.
///
/// This adds the garbage, which will eventually be destroyed, to the global state. Note that this
/// does not tick, and thus cannot cause garbage collection.
pub fn export_garbage(garbage: Vec<Garbage>) {
    // Send the garbage to the message-passing channel of the state.
    STATE.chan.send(Message::Garbage(garbage));
}

/// Attempt to garbage collect.
///
/// If another garbage collection is currently running, the thread will do nothing, and `Err(())`
/// will be returned. Otherwise, it returns `Ok(())`.
pub fn try_gc() -> Result<(), ()> {
    STATE.try_gc()
}

/// Tick the clock.
///
/// This shall be called when new garbage is added, as it will trigger a GC by some probability.
pub fn tick() {
    /// The probability of triggering a GC.
    ///
    /// This probability is given such that `0` corresponds to 0 and `!0` corresponds to `1`.
    const GC_PROBABILITY: usize = (!0) / 64;

    // Generate a random number and compare it against the probability.
    if rand::random::<usize>() <= GC_PROBABILITY {
        // The outfall was to (attempt at) GC.
        let _ = try_gc();
    }
}

/// A message to the global state.
enum Message {
    /// Add new garbage.
    Garbage(Vec<Garbage>),
    /// Add a new hazard.
    NewHazard(hazard::Reader),
}

/// The global state.
///
/// The global state is shared between all threads and keeps track of the garbage and the active
/// hazards.
///
/// It is divided into two parts: The channel and the garbo. The channel buffers messages, which
/// will eventually be executed at garbo, which holds all the data structures and is protected by a
/// mutex. The garbo holds the other end to the channel.
struct State {
    /// The message-passing channel.
    chan: mpsc::Sender<Message>,
    /// The garbo part of the state.
    garbo: Mutex<Garbo>,
}

impl State {
    /// Initialize a new state.
    fn new() -> State {
        // Create the message-passing channel.
        let (send, recv) = mpsc::channel();

        // Construct the state from the two halfs of the channel.
        State {
            chan: send,
            garbo: Mutex::new(Garbo {
                chan: recv,
                garbage: Vec::new(),
                hazards: Vec::new(),
            })
        }
    }

    /// Try to collect the garbage.
    ///
    /// This will handle all of the messages in the channel and then attempt at collect the
    /// garbage. If another thread is currently collecting garbage, `Err(())` is returned,
    /// otherwise it returns `Ok(())`.
    ///
    /// Garbage collection works by scanning the hazards and dropping all the garbage which is not
    /// currently active in the hazards.
    fn try_gc(&self) -> Result<(), ()> {
        // Lock the "garbo" (the part of the state needed to GC).
        if let Ok(mut garbo) = self.garbo.try_lock() {
            // Handle all the messages sent.
            garbo.handle_all();
            // Collect the garbage.
            garbo.gc();

            Ok(())
        } else {
            // Another thread is collecting.
            Err(())
        }
    }
}

/// The garbo part of the state.
///
/// This part is supposed to act like the garbage collecting part. It handles hazards, garbage, and
/// the receiving point of the message-passing channel.
struct Garbo {
    /// The channel of messages.
    chan: mpsc::Receiver<Message>,
    /// The to-be-destroyed garbage.
    garbage: Vec<Garbage>,
    /// The current hazards.
    hazards: Vec<hazard::Reader>,
}

impl Garbo {
    /// Handle a given message.
    ///
    /// "Handle" in this case refers to applying the operation defined by the message to the state,
    /// effectually executing the instruction of the message.
    fn handle(&mut self, msg: Message) {
        match msg {
            // Append the garbage bulk to the garbage list.
            Message::Garbage(mut garbage) => self.garbage.append(&mut garbage),
            // Register the new hazard into the state.
            Message::NewHazard(hazard) => self.hazards.push(hazard),
        }
    }

    /// Receive and handle all the messages.
    fn handle_all(&mut self) {
        // Go over every message.
        for msg in self.chan.recv_all() {
            self.handle(msg);
        }
    }

    /// Garbage collect all unused garbage.
    fn gc(&mut self) {
        // Create the set which will keep the _active_ hazards.
        let mut active = HashSet::with_capacity(self.hazards.len());

        // Take out the hazards and go over them one-by-one.
        let len = self.hazards.len(); // TODO: This should be substituted into next line.
        for hazard in mem::replace(&mut self.hazards, Vec::with_capacity(len)) {
            match hazard.get() {
                // The hazard is dead, so the other end (the writer) is not available anymore,
                // hence we can safely destroy it.
                hazard::State::Dead => unsafe { hazard.destroy() },
                // The hazard is free and must thus be put back to the hazard list.
                hazard::State::Free => self.hazards.push(hazard),
                hazard::State::Protect(ptr) => {
                    // This hazard is active, hence we insert the pointer it contains in our
                    // "active" set.
                    active.insert(ptr);
                    // Since the hazard is still alive, we must put it back to the hazard list for
                    // future use.
                    self.hazards.push(hazard);
                },
            }
        }

        // Take the garbage and scan it for unused garbage.
        for garbage in mem::replace(&mut self.garbage, Vec::new()) {
            if active.contains(&garbage.ptr()) {
                // If the garbage is in the set of active pointers, it will be put back to the
                // garbage list.
                self.garbage.push(garbage);
            } else {
                // The garbage is unused and not referenced by any hazard, hence we can safely
                // destroy it.
                garbage.destroy();
            }
        }
    }
}

impl Drop for Garbo {
    fn drop(&mut self) {
        // Do a final GC.
        self.gc();
    }
}
<commit_msg>Test that the destructor actually runs in `conc::global`.<commit_after>//! The global state.

use std::sync::Mutex; // TODO: Use custom option-like thing.
use std::collections::HashSet;
use std::mem;
use {rand, hazard, mpsc};
use garbage::Garbage;

lazy_static! {
    /// The global state.
    ///
    /// This state is shared between all the threads.
    static ref STATE: State = State::new();
}

/// Create a new hazard.
///
/// This creates a new hazard and registers it in the global state. It's secondary, writer part is
/// returned.
pub fn create_hazard() -> hazard::Writer {
    // Create the hazard.
    let (writer, reader) = hazard::create();
    // Communicate the new hazard to the global state through the channel.
    STATE.chan.send(Message::NewHazard(reader));
    // Return the other half of the hazard.
    writer
}

/// Export garbage into the global state.
///
/// This adds the garbage, which will eventually be destroyed, to the global state. Note that this
/// does not tick, and thus cannot cause garbage collection.
pub fn export_garbage(garbage: Vec<Garbage>) {
    // Send the garbage to the message-passing channel of the state.
    STATE.chan.send(Message::Garbage(garbage));
}

/// Attempt to garbage collect.
///
/// If another garbage collection is currently running, the thread will do nothing, and `Err(())`
/// will be returned. Otherwise, it returns `Ok(())`.
pub fn try_gc() -> Result<(), ()> {
    STATE.try_gc()
}

/// Tick the clock.
///
/// This shall be called when new garbage is added, as it will trigger a GC by some probability.
pub fn tick() {
    /// The probability of triggering a GC.
    ///
    /// This probability is given such that `0` corresponds to 0 and `!0` corresponds to `1`.
    const GC_PROBABILITY: usize = (!0) / 64;

    // Generate a random number and compare it against the probability.
    if rand::random::<usize>() <= GC_PROBABILITY {
        // The outfall was to (attempt at) GC.
        let _ = try_gc();
    }
}

/// A message to the global state.
enum Message {
    /// Add new garbage.
    Garbage(Vec<Garbage>),
    /// Add a new hazard.
    NewHazard(hazard::Reader),
}

/// The global state.
///
/// The global state is shared between all threads and keeps track of the garbage and the active
/// hazards.
///
/// It is divided into two parts: The channel and the garbo. The channel buffers messages, which
/// will eventually be executed at garbo, which holds all the data structures and is protected by a
/// mutex. The garbo holds the other end to the channel.
struct State {
    /// The message-passing channel.
    chan: mpsc::Sender<Message>,
    /// The garbo part of the state.
    garbo: Mutex<Garbo>,
}

impl State {
    /// Initialize a new state.
    fn new() -> State {
        // Create the message-passing channel.
        let (send, recv) = mpsc::channel();

        // Construct the state from the two halfs of the channel.
        State {
            chan: send,
            garbo: Mutex::new(Garbo {
                chan: recv,
                garbage: Vec::new(),
                hazards: Vec::new(),
            })
        }
    }

    /// Try to collect the garbage.
    ///
    /// This will handle all of the messages in the channel and then attempt at collect the
    /// garbage. If another thread is currently collecting garbage, `Err(())` is returned,
    /// otherwise it returns `Ok(())`.
    ///
    /// Garbage collection works by scanning the hazards and dropping all the garbage which is not
    /// currently active in the hazards.
    fn try_gc(&self) -> Result<(), ()> {
        // Lock the "garbo" (the part of the state needed to GC).
        if let Ok(mut garbo) = self.garbo.try_lock() {
            // Handle all the messages sent.
            garbo.handle_all();
            // Collect the garbage.
            garbo.gc();

            Ok(())
        } else {
            // Another thread is collecting.
            Err(())
        }
    }
}

/// The garbo part of the state.
///
/// This part is supposed to act like the garbage collecting part. It handles hazards, garbage, and
/// the receiving point of the message-passing channel.
struct Garbo {
    /// The channel of messages.
    chan: mpsc::Receiver<Message>,
    /// The to-be-destroyed garbage.
    garbage: Vec<Garbage>,
    /// The current hazards.
    hazards: Vec<hazard::Reader>,
}

impl Garbo {
    /// Handle a given message.
    ///
    /// "Handle" in this case refers to applying the operation defined by the message to the state,
    /// effectually executing the instruction of the message.
    fn handle(&mut self, msg: Message) {
        match msg {
            // Append the garbage bulk to the garbage list.
            Message::Garbage(mut garbage) => self.garbage.append(&mut garbage),
            // Register the new hazard into the state.
            Message::NewHazard(hazard) => self.hazards.push(hazard),
        }
    }

    /// Receive and handle all the messages.
    fn handle_all(&mut self) {
        // Go over every message.
        for msg in self.chan.recv_all() {
            self.handle(msg);
        }
    }

    /// Garbage collect all unused garbage.
    fn gc(&mut self) {
        // Create the set which will keep the _active_ hazards.
        let mut active = HashSet::with_capacity(self.hazards.len());

        // Take out the hazards and go over them one-by-one.
        let len = self.hazards.len(); // TODO: This should be substituted into next line.
        for hazard in mem::replace(&mut self.hazards, Vec::with_capacity(len)) {
            match hazard.get() {
                // The hazard is dead, so the other end (the writer) is not available anymore,
                // hence we can safely destroy it.
                hazard::State::Dead => unsafe { hazard.destroy() },
                // The hazard is free and must thus be put back to the hazard list.
                hazard::State::Free => self.hazards.push(hazard),
                hazard::State::Protect(ptr) => {
                    // This hazard is active, hence we insert the pointer it contains in our
                    // "active" set.
                    active.insert(ptr);
                    // Since the hazard is still alive, we must put it back to the hazard list for
                    // future use.
                    self.hazards.push(hazard);
                },
            }
        }

        // Take the garbage and scan it for unused garbage.
        for garbage in mem::replace(&mut self.garbage, Vec::new()) {
            if active.contains(&garbage.ptr()) {
                // If the garbage is in the set of active pointers, it will be put back to the
                // garbage list.
                self.garbage.push(garbage);
            } else {
                // The garbage is unused and not referenced by any hazard, hence we can safely
                // destroy it.
                garbage.destroy();
            }
        }
    }
}

impl Drop for Garbo {
    fn drop(&mut self) {
        // Do a final GC.
        self.gc();
    }
}

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

    #[test]
    fn dtor_runs() {
        fn dtor(x: *const u8) {
            unsafe {
                *(x as *mut u8) = 1;
            }
        }

        for _ in 0..1000 {
            let b = Box::new(0);
            let h = create_hazard();
            h.set(hazard::State::Protect(&*b));
            export_garbage(vec![Garbage::new(&*b, dtor)]);
            while try_gc().is_err() {}
            assert_eq!(*b, 0);
            while try_gc().is_err() {}
            h.set(hazard::State::Free);
            while try_gc().is_err() {}
            assert_eq!(*b, 1);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

Dynamic library facilities.

A simple wrapper over the platform's dynamic library facilities

*/

use c_str::ToCStr;
use iter::Iterator;
use mem;
use ops::*;
use option::*;
use os;
use path::GenericPath;
use path;
use result::*;
use slice::{Vector,OwnedVector};
use str;
use vec::Vec;

pub struct DynamicLibrary { handle: *u8}

impl Drop for DynamicLibrary {
    fn drop(&mut self) {
        match dl::check_for_errors_in(|| {
            unsafe {
                dl::close(self.handle)
            }
        }) {
            Ok(()) => {},
            Err(str) => fail!("{}", str)
        }
    }
}

impl DynamicLibrary {
    /// Lazily open a dynamic library. When passed None it gives a
    /// handle to the calling process
    pub fn open(filename: Option<&path::Path>) -> Result<DynamicLibrary, ~str> {
        unsafe {
            let maybe_library = dl::check_for_errors_in(|| {
                match filename {
                    Some(name) => dl::open_external(name),
                    None => dl::open_internal()
                }
            });

            // The dynamic library must not be constructed if there is
            // an error opening the library so the destructor does not
            // run.
            match maybe_library {
                Err(err) => Err(err),
                Ok(handle) => Ok(DynamicLibrary { handle: handle })
            }
        }
    }

    /// Appends a path to the system search path for dynamic libraries
    pub fn add_search_path(path: &path::Path) {
        let (envvar, sep) = if cfg!(windows) {
            ("PATH", ';' as u8)
        } else if cfg!(target_os = "macos") {
            ("DYLD_LIBRARY_PATH", ':' as u8)
        } else {
            ("LD_LIBRARY_PATH", ':' as u8)
        };
        let newenv = os::getenv_as_bytes(envvar).unwrap_or(box []);
        let mut newenv = newenv.move_iter().collect::<Vec<_>>();
        newenv.push_all(&[sep]);
        newenv.push_all(path.as_vec());
        os::setenv(envvar, str::from_utf8(newenv.as_slice()).unwrap());
    }

    /// Access the value at the symbol of the dynamic library
    pub unsafe fn symbol<T>(&self, symbol: &str) -> Result<T, ~str> {
        // This function should have a lifetime constraint of 'a on
        // T but that feature is still unimplemented

        let maybe_symbol_value = dl::check_for_errors_in(|| {
            symbol.with_c_str(|raw_string| {
                dl::symbol(self.handle, raw_string)
            })
        });

        // The value must not be constructed if there is an error so
        // the destructor does not run.
        match maybe_symbol_value {
            Err(err) => Err(err),
            Ok(symbol_value) => Ok(mem::transmute(symbol_value))
        }
    }
}

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

    #[test]
    #[ignore(cfg(windows))] // FIXME #8818
    #[ignore(cfg(target_os="android"))] // FIXME(#10379)
    fn test_loading_cosine() {
        // The math library does not need to be loaded since it is already
        // statically linked in
        let libm = match DynamicLibrary::open(None) {
            Err(error) => fail!("Could not load self as module: {}", error),
            Ok(libm) => libm
        };

        let cosine: extern fn(libc::c_double) -> libc::c_double = unsafe {
            match libm.symbol("cos") {
                Err(error) => fail!("Could not load function cos: {}", error),
                Ok(cosine) => cosine
            }
        };

        let argument = 0.0;
        let expected_result = 1.0;
        let result = cosine(argument);
        if result != expected_result {
            fail!("cos({:?}) != {:?} but equaled {:?} instead", argument,
                   expected_result, result)
        }
    }

    #[test]
    #[cfg(target_os = "linux")]
    #[cfg(target_os = "macos")]
    #[cfg(target_os = "freebsd")]
    fn test_errors_do_not_crash() {
        // Open /dev/null as a library to get an error, and make sure
        // that only causes an error, and not a crash.
        let path = GenericPath::new("/dev/null");
        match DynamicLibrary::open(Some(&path)) {
            Err(_) => {}
            Ok(_) => fail!("Successfully opened the empty library.")
        }
    }
}

#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
#[cfg(target_os = "macos")]
#[cfg(target_os = "freebsd")]
pub mod dl {
    use c_str::ToCStr;
    use libc;
    use path;
    use ptr;
    use str;
    use result::*;

    pub unsafe fn open_external(filename: &path::Path) -> *u8 {
        filename.with_c_str(|raw_name| {
            dlopen(raw_name, Lazy as libc::c_int) as *u8
        })
    }

    pub unsafe fn open_internal() -> *u8 {
        dlopen(ptr::null(), Lazy as libc::c_int) as *u8
    }

    pub fn check_for_errors_in<T>(f: || -> T) -> Result<T, ~str> {
        use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
        static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;
        unsafe {
            // dlerror isn't thread safe, so we need to lock around this entire
            // sequence
            let _guard = lock.lock();
            let _old_error = dlerror();

            let result = f();

            let last_error = dlerror();
            let ret = if ptr::null() == last_error {
                Ok(result)
            } else {
                Err(str::raw::from_c_str(last_error))
            };

            ret
        }
    }

    pub unsafe fn symbol(handle: *u8, symbol: *libc::c_char) -> *u8 {
        dlsym(handle as *libc::c_void, symbol) as *u8
    }
    pub unsafe fn close(handle: *u8) {
        dlclose(handle as *libc::c_void); ()
    }

    pub enum RTLD {
        Lazy = 1,
        Now = 2,
        Global = 256,
        Local = 0,
    }

    #[link_name = "dl"]
    extern {
        fn dlopen(filename: *libc::c_char, flag: libc::c_int) -> *libc::c_void;
        fn dlerror() -> *libc::c_char;
        fn dlsym(handle: *libc::c_void, symbol: *libc::c_char) -> *libc::c_void;
        fn dlclose(handle: *libc::c_void) -> libc::c_int;
    }
}

#[cfg(target_os = "win32")]
pub mod dl {
    use libc;
    use os;
    use path::GenericPath;
    use path;
    use ptr;
    use result::{Ok, Err, Result};

    pub unsafe fn open_external(filename: &path::Path) -> *u8 {
        os::win32::as_utf16_p(filename.as_str().unwrap(), |raw_name| {
            LoadLibraryW(raw_name as *libc::c_void) as *u8
        })
    }

    pub unsafe fn open_internal() -> *u8 {
        let handle = ptr::null();
        GetModuleHandleExW(0 as libc::DWORD, ptr::null(), &handle as **libc::c_void);
        handle as *u8
    }

    pub fn check_for_errors_in<T>(f: || -> T) -> Result<T, ~str> {
        unsafe {
            SetLastError(0);

            let result = f();

            let error = os::errno();
            if 0 == error {
                Ok(result)
            } else {
                Err(format!("Error code {}", error))
            }
        }
    }

    pub unsafe fn symbol(handle: *u8, symbol: *libc::c_char) -> *u8 {
        GetProcAddress(handle as *libc::c_void, symbol) as *u8
    }
    pub unsafe fn close(handle: *u8) {
        FreeLibrary(handle as *libc::c_void); ()
    }

    extern "system" {
        fn SetLastError(error: libc::size_t);
        fn LoadLibraryW(name: *libc::c_void) -> *libc::c_void;
        fn GetModuleHandleExW(dwFlags: libc::DWORD, name: *u16,
                              handle: **libc::c_void) -> *libc::c_void;
        fn GetProcAddress(handle: *libc::c_void, name: *libc::c_char) -> *libc::c_void;
        fn FreeLibrary(handle: *libc::c_void);
    }
}
<commit_msg>std:: switch the order in which dynamic_lib adds search paths.<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

Dynamic library facilities.

A simple wrapper over the platform's dynamic library facilities

*/

use c_str::ToCStr;
use mem;
use ops::*;
use option::*;
use os;
use path::GenericPath;
use path;
use result::*;
use slice::Vector;
use str;
use vec::Vec;

pub struct DynamicLibrary { handle: *u8}

impl Drop for DynamicLibrary {
    fn drop(&mut self) {
        match dl::check_for_errors_in(|| {
            unsafe {
                dl::close(self.handle)
            }
        }) {
            Ok(()) => {},
            Err(str) => fail!("{}", str)
        }
    }
}

impl DynamicLibrary {
    /// Lazily open a dynamic library. When passed None it gives a
    /// handle to the calling process
    pub fn open(filename: Option<&path::Path>) -> Result<DynamicLibrary, ~str> {
        unsafe {
            let maybe_library = dl::check_for_errors_in(|| {
                match filename {
                    Some(name) => dl::open_external(name),
                    None => dl::open_internal()
                }
            });

            // The dynamic library must not be constructed if there is
            // an error opening the library so the destructor does not
            // run.
            match maybe_library {
                Err(err) => Err(err),
                Ok(handle) => Ok(DynamicLibrary { handle: handle })
            }
        }
    }

    /// Appends a path to the system search path for dynamic libraries
    pub fn add_search_path(path: &path::Path) {
        let (envvar, sep) = if cfg!(windows) {
            ("PATH", ';' as u8)
        } else if cfg!(target_os = "macos") {
            ("DYLD_LIBRARY_PATH", ':' as u8)
        } else {
            ("LD_LIBRARY_PATH", ':' as u8)
        };
        let mut newenv = Vec::from_slice(path.as_vec());
        newenv.push(sep);
        match os::getenv_as_bytes(envvar) {
            Some(bytes) => newenv.push_all(bytes),
            None => {}
        }
        os::setenv(envvar, str::from_utf8(newenv.as_slice()).unwrap());
    }

    /// Access the value at the symbol of the dynamic library
    pub unsafe fn symbol<T>(&self, symbol: &str) -> Result<T, ~str> {
        // This function should have a lifetime constraint of 'a on
        // T but that feature is still unimplemented

        let maybe_symbol_value = dl::check_for_errors_in(|| {
            symbol.with_c_str(|raw_string| {
                dl::symbol(self.handle, raw_string)
            })
        });

        // The value must not be constructed if there is an error so
        // the destructor does not run.
        match maybe_symbol_value {
            Err(err) => Err(err),
            Ok(symbol_value) => Ok(mem::transmute(symbol_value))
        }
    }
}

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

    #[test]
    #[ignore(cfg(windows))] // FIXME #8818
    #[ignore(cfg(target_os="android"))] // FIXME(#10379)
    fn test_loading_cosine() {
        // The math library does not need to be loaded since it is already
        // statically linked in
        let libm = match DynamicLibrary::open(None) {
            Err(error) => fail!("Could not load self as module: {}", error),
            Ok(libm) => libm
        };

        let cosine: extern fn(libc::c_double) -> libc::c_double = unsafe {
            match libm.symbol("cos") {
                Err(error) => fail!("Could not load function cos: {}", error),
                Ok(cosine) => cosine
            }
        };

        let argument = 0.0;
        let expected_result = 1.0;
        let result = cosine(argument);
        if result != expected_result {
            fail!("cos({:?}) != {:?} but equaled {:?} instead", argument,
                   expected_result, result)
        }
    }

    #[test]
    #[cfg(target_os = "linux")]
    #[cfg(target_os = "macos")]
    #[cfg(target_os = "freebsd")]
    fn test_errors_do_not_crash() {
        // Open /dev/null as a library to get an error, and make sure
        // that only causes an error, and not a crash.
        let path = GenericPath::new("/dev/null");
        match DynamicLibrary::open(Some(&path)) {
            Err(_) => {}
            Ok(_) => fail!("Successfully opened the empty library.")
        }
    }
}

#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
#[cfg(target_os = "macos")]
#[cfg(target_os = "freebsd")]
pub mod dl {
    use c_str::ToCStr;
    use libc;
    use path;
    use ptr;
    use str;
    use result::*;

    pub unsafe fn open_external(filename: &path::Path) -> *u8 {
        filename.with_c_str(|raw_name| {
            dlopen(raw_name, Lazy as libc::c_int) as *u8
        })
    }

    pub unsafe fn open_internal() -> *u8 {
        dlopen(ptr::null(), Lazy as libc::c_int) as *u8
    }

    pub fn check_for_errors_in<T>(f: || -> T) -> Result<T, ~str> {
        use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
        static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;
        unsafe {
            // dlerror isn't thread safe, so we need to lock around this entire
            // sequence
            let _guard = lock.lock();
            let _old_error = dlerror();

            let result = f();

            let last_error = dlerror();
            let ret = if ptr::null() == last_error {
                Ok(result)
            } else {
                Err(str::raw::from_c_str(last_error))
            };

            ret
        }
    }

    pub unsafe fn symbol(handle: *u8, symbol: *libc::c_char) -> *u8 {
        dlsym(handle as *libc::c_void, symbol) as *u8
    }
    pub unsafe fn close(handle: *u8) {
        dlclose(handle as *libc::c_void); ()
    }

    pub enum RTLD {
        Lazy = 1,
        Now = 2,
        Global = 256,
        Local = 0,
    }

    #[link_name = "dl"]
    extern {
        fn dlopen(filename: *libc::c_char, flag: libc::c_int) -> *libc::c_void;
        fn dlerror() -> *libc::c_char;
        fn dlsym(handle: *libc::c_void, symbol: *libc::c_char) -> *libc::c_void;
        fn dlclose(handle: *libc::c_void) -> libc::c_int;
    }
}

#[cfg(target_os = "win32")]
pub mod dl {
    use libc;
    use os;
    use path::GenericPath;
    use path;
    use ptr;
    use result::{Ok, Err, Result};

    pub unsafe fn open_external(filename: &path::Path) -> *u8 {
        os::win32::as_utf16_p(filename.as_str().unwrap(), |raw_name| {
            LoadLibraryW(raw_name as *libc::c_void) as *u8
        })
    }

    pub unsafe fn open_internal() -> *u8 {
        let handle = ptr::null();
        GetModuleHandleExW(0 as libc::DWORD, ptr::null(), &handle as **libc::c_void);
        handle as *u8
    }

    pub fn check_for_errors_in<T>(f: || -> T) -> Result<T, ~str> {
        unsafe {
            SetLastError(0);

            let result = f();

            let error = os::errno();
            if 0 == error {
                Ok(result)
            } else {
                Err(format!("Error code {}", error))
            }
        }
    }

    pub unsafe fn symbol(handle: *u8, symbol: *libc::c_char) -> *u8 {
        GetProcAddress(handle as *libc::c_void, symbol) as *u8
    }
    pub unsafe fn close(handle: *u8) {
        FreeLibrary(handle as *libc::c_void); ()
    }

    extern "system" {
        fn SetLastError(error: libc::size_t);
        fn LoadLibraryW(name: *libc::c_void) -> *libc::c_void;
        fn GetModuleHandleExW(dwFlags: libc::DWORD, name: *u16,
                              handle: **libc::c_void) -> *libc::c_void;
        fn GetProcAddress(handle: *libc::c_void, name: *libc::c_char) -> *libc::c_void;
        fn FreeLibrary(handle: *libc::c_void);
    }
}
<|endoftext|>


<commit_before>use core::pin::Pin;
use futures::io::{AsyncRead, AsyncBufRead};
use futures::stream::{self, TryStreamExt};
use futures::task::Poll;
use futures_test::{task::noop_context, stream::StreamTestExt};

macro_rules! assert_read {
    ($reader:expr, $buf:expr, $item:expr) => {
        let mut cx = noop_context();
        loop {
            match Pin::new(&mut $reader).poll_read(&mut cx, $buf) {
                Poll::Ready(Ok(x)) => {
                    assert_eq!(x, $item);
                    break;
                }
                Poll::Ready(Err(err)) => {
                    panic!("assertion failed: expected value but got {}", err);
                }
                Poll::Pending => {
                    continue;
                }
            }
        }
    };
}

macro_rules! assert_fill_buf {
    ($reader:expr, $buf:expr) => {
        let mut cx = noop_context();
        loop {
            match Pin::new(&mut $reader).poll_fill_buf(&mut cx) {
                Poll::Ready(Ok(x)) => {
                    assert_eq!(x, $buf);
                    break;
                }
                Poll::Ready(Err(err)) => {
                    panic!("assertion failed: expected value but got {}", err);
                }
                Poll::Pending => {
                    continue;
                }
            }
        }
    };
}

#[test]
fn test_into_async_read() {
    let stream = stream::iter((1..=3).flat_map(|_| vec![Ok(vec![]), Ok(vec![1, 2, 3, 4, 5])]));
    let mut reader = stream.interleave_pending().into_async_read();
    let mut buf = vec![0; 3];

    assert_read!(reader, &mut buf, 3);
    assert_eq!(&buf, &[1, 2, 3]);

    assert_read!(reader, &mut buf, 2);
    assert_eq!(&buf[..2], &[4, 5]);

    assert_read!(reader, &mut buf, 3);
    assert_eq!(&buf, &[1, 2, 3]);

    assert_read!(reader, &mut buf, 2);
    assert_eq!(&buf[..2], &[4, 5]);

    assert_read!(reader, &mut buf, 3);
    assert_eq!(&buf, &[1, 2, 3]);

    assert_read!(reader, &mut buf, 2);
    assert_eq!(&buf[..2], &[4, 5]);

    assert_read!(reader, &mut buf, 0);
}

#[test]
fn test_into_async_bufread() -> std::io::Result<()> {
    let stream = stream::iter((1..=2).flat_map(|_| vec![Ok(vec![]), Ok(vec![1, 2, 3, 4, 5])]));
    let mut reader = stream.interleave_pending().into_async_read();

    let mut reader = Pin::new(&mut reader);

    assert_fill_buf!(reader, &[1, 2, 3, 4, 5][..]);
    reader.as_mut().consume(3);

    assert_fill_buf!(reader, &[4, 5][..]);
    reader.as_mut().consume(2);

    assert_fill_buf!(reader, &[1, 2, 3, 4, 5][..]);
    reader.as_mut().consume(2);

    assert_fill_buf!(reader, &[3, 4, 5][..]);
    reader.as_mut().consume(3);

    assert_fill_buf!(reader, &[][..]);

    Ok(())
}
<commit_msg>futures: tests/stream_into_async_read.rs: Don't break w/o "std"<commit_after>#[cfg(feature = "std")] // io::
#[test]
fn test_into_async_read() {
    use core::pin::Pin;
    use futures::io::AsyncRead;
    use futures::stream::{self, TryStreamExt};
    use futures::task::Poll;
    use futures_test::{task::noop_context, stream::StreamTestExt};

    macro_rules! assert_read {
        ($reader:expr, $buf:expr, $item:expr) => {
            let mut cx = noop_context();
            loop {
                match Pin::new(&mut $reader).poll_read(&mut cx, $buf) {
                    Poll::Ready(Ok(x)) => {
                        assert_eq!(x, $item);
                        break;
                    }
                    Poll::Ready(Err(err)) => {
                        panic!("assertion failed: expected value but got {}", err);
                    }
                    Poll::Pending => {
                        continue;
                    }
                }
            }
        };
    }

    let stream = stream::iter((1..=3).flat_map(|_| vec![Ok(vec![]), Ok(vec![1, 2, 3, 4, 5])]));
    let mut reader = stream.interleave_pending().into_async_read();
    let mut buf = vec![0; 3];

    assert_read!(reader, &mut buf, 3);
    assert_eq!(&buf, &[1, 2, 3]);

    assert_read!(reader, &mut buf, 2);
    assert_eq!(&buf[..2], &[4, 5]);

    assert_read!(reader, &mut buf, 3);
    assert_eq!(&buf, &[1, 2, 3]);

    assert_read!(reader, &mut buf, 2);
    assert_eq!(&buf[..2], &[4, 5]);

    assert_read!(reader, &mut buf, 3);
    assert_eq!(&buf, &[1, 2, 3]);

    assert_read!(reader, &mut buf, 2);
    assert_eq!(&buf[..2], &[4, 5]);

    assert_read!(reader, &mut buf, 0);
}

#[cfg(feature = "std")] // io::
#[test]
fn test_into_async_bufread() -> std::io::Result<()> {
    use core::pin::Pin;
    use futures::io::AsyncBufRead;
    use futures::stream::{self, TryStreamExt};
    use futures::task::Poll;
    use futures_test::{task::noop_context, stream::StreamTestExt};

    macro_rules! assert_fill_buf {
        ($reader:expr, $buf:expr) => {
            let mut cx = noop_context();
            loop {
                match Pin::new(&mut $reader).poll_fill_buf(&mut cx) {
                    Poll::Ready(Ok(x)) => {
                        assert_eq!(x, $buf);
                        break;
                    }
                    Poll::Ready(Err(err)) => {
                        panic!("assertion failed: expected value but got {}", err);
                    }
                    Poll::Pending => {
                        continue;
                    }
                }
            }
        };
    }

    let stream = stream::iter((1..=2).flat_map(|_| vec![Ok(vec![]), Ok(vec![1, 2, 3, 4, 5])]));
    let mut reader = stream.interleave_pending().into_async_read();

    let mut reader = Pin::new(&mut reader);

    assert_fill_buf!(reader, &[1, 2, 3, 4, 5][..]);
    reader.as_mut().consume(3);

    assert_fill_buf!(reader, &[4, 5][..]);
    reader.as_mut().consume(2);

    assert_fill_buf!(reader, &[1, 2, 3, 4, 5][..]);
    reader.as_mut().consume(2);

    assert_fill_buf!(reader, &[3, 4, 5][..]);
    reader.as_mut().consume(3);

    assert_fill_buf!(reader, &[][..]);

    Ok(())
}
<|endoftext|>