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

use hyper::Client;

use select::dom::Dom;
use select::predicate::*;

#[derive(Debug)]
pub struct DictDef {
    pub word: String,
    pub def: String,
    pub example: Option<String>,
    pub upvote: i32,
    pub downvote: i32,
    pub contributor: String,
    pub date: String,
    pub id: String,
    pub sounds: Option<Vec<String>>,
    pub similars: Option<Vec<String>>
}

impl DictDef {
}

fn urban_dict_url (word: &str) -> String {
    let mut s = String::new();
    s.push_str("http://www.urbandictionary.com/define.php?term=");
    s.push_str(word);
    s
}

fn json_list_to_strings(json: &str) -> Vec<String> {
    json[1..json.len()-1].split(", ").map(|s| s[1..s.len()-1].to_owned()).collect()
}

fn get_def_from_doc (doc: &Dom) -> Option<DictDef> {
    if let Some(panel) = doc.find(Class("def-panel")).first() {
        if let Some(word) = panel.find(Class("word")).first() {
            let word = word.text();

            let def = panel.find(Class("meaning")).first().unwrap().text();
            let defid = panel.attr("data-defid").unwrap_or("").to_owned();

            let example = panel.find(Class("example")).first().and_then(|e| Some(e.text()));
            let author = panel.find(Class("author")).first().and_then(|e| Some(e.text())).unwrap_or("".to_owned());
            let date = panel.find(Class("author")).first().and_then(|e| e.next()).and_then(|e| Some(e.text().trim().to_owned())).unwrap_or("".to_owned());

            let sounds = panel.find(Class("play-sound")).first().and_then(|e| e.attr("data-urls").and_then(|s| Some(s.to_owned()))).and_then(|l| Some(json_list_to_strings(&l)));

            let similars = Some(doc.find(Name("ul").and(Class("alphabetical"))).find(Name("li")).find(Name("a")).iter().map(|e| e.text()).collect());

            Some(DictDef {
                word: word.trim().to_owned(),
                def: def.trim().to_owned(),
                example: example,
                upvote: 0,
                downvote: 0,
                contributor: author,
                date: date,
                id: defid,
                sounds: sounds,
                similars: similars
            })
        } else {
            None
        }
    } else {
        None
    }
}

fn find_from_url(url: &str) -> Option<DictDef> {
    let client = Client::new();

    let mut resp = client.get(url).send().unwrap();
    let mut body = String::new();
    {
        resp.read_to_string(&mut body).unwrap();
    }

    let dom = Dom::from_str(&body);
    get_def_from_doc(&dom)
}

pub fn find_word_of_the_day() -> Option<DictDef> {
    find_from_url("http://www.urbandictionary.com/")
}

pub fn find_on_urban_dict (word: &str) -> Option<DictDef> {
    let url = urban_dict_url(word);
    find_from_url(&url)
}
<commit_msg>Use https<commit_after>use std::io::Read;

use hyper::Client;

use select::dom::Dom;
use select::predicate::*;

#[derive(Debug)]
pub struct DictDef {
    pub word: String,
    pub def: String,
    pub example: Option<String>,
    pub upvote: i32,
    pub downvote: i32,
    pub contributor: String,
    pub date: String,
    pub id: String,
    pub sounds: Option<Vec<String>>,
    pub similars: Option<Vec<String>>
}

impl DictDef {
}

fn urban_dict_url (word: &str) -> String {
    let mut s = String::new();
    s.push_str("https://www.urbandictionary.com/define.php?term=");
    s.push_str(word);
    s
}

fn json_list_to_strings(json: &str) -> Vec<String> {
    json[1..json.len()-1].split(", ").map(|s| s[1..s.len()-1].to_owned()).collect()
}

fn get_def_from_doc (doc: &Dom) -> Option<DictDef> {
    if let Some(panel) = doc.find(Class("def-panel")).first() {
        if let Some(word) = panel.find(Class("word")).first() {
            let word = word.text();

            let def = panel.find(Class("meaning")).first().unwrap().text();
            let defid = panel.attr("data-defid").unwrap_or("").to_owned();

            let example = panel.find(Class("example")).first().and_then(|e| Some(e.text()));
            let author = panel.find(Class("author")).first().and_then(|e| Some(e.text())).unwrap_or("".to_owned());
            let date = panel.find(Class("author")).first().and_then(|e| e.next()).and_then(|e| Some(e.text().trim().to_owned())).unwrap_or("".to_owned());

            let sounds = panel.find(Class("play-sound")).first().and_then(|e| e.attr("data-urls").and_then(|s| Some(s.to_owned()))).and_then(|l| Some(json_list_to_strings(&l)));

            let similars = Some(doc.find(Name("ul").and(Class("alphabetical"))).find(Name("li")).find(Name("a")).iter().map(|e| e.text()).collect());

            Some(DictDef {
                word: word.trim().to_owned(),
                def: def.trim().to_owned(),
                example: example,
                upvote: 0,
                downvote: 0,
                contributor: author,
                date: date,
                id: defid,
                sounds: sounds,
                similars: similars
            })
        } else {
            None
        }
    } else {
        None
    }
}

fn find_from_url(url: &str) -> Option<DictDef> {
    let client = Client::new();

    let mut resp = client.get(url).send().unwrap();
    let mut body = String::new();
    {
        resp.read_to_string(&mut body).unwrap();
    }

    let dom = Dom::from_str(&body);
    get_def_from_doc(&dom)
}

pub fn find_word_of_the_day() -> Option<DictDef> {
    find_from_url("https://www.urbandictionary.com/")
}

pub fn find_on_urban_dict (word: &str) -> Option<DictDef> {
    let url = urban_dict_url(word);
    find_from_url(&url)
}
<|endoftext|>


<commit_before>//! [Church pair](https://en.wikipedia.org/wiki/Church_encoding#Church_pairs)

use term::*;
use term::Term::*;
use term::Error::*;
use booleans::*;

/// Produces a Church-encoded pair; applying it to two other terms puts them inside it.
///
/// PAIR := λxyz.z x y = λ λ λ 1 3 2
///
/// # Example
/// ```
/// use lambda_calculus::pair::pair;
/// use lambda_calculus::arithmetic::{zero, one};
/// let pair01 = pair().app(zero()).app(one());
///
/// assert_eq!(pair01.fst_ref(), Ok(&zero()));
/// assert_eq!(pair01.snd_ref(), Ok(&one()));
/// ```
pub fn pair() -> Term {
    abs(abs(abs(
        Var(1)
        .app(Var(3))
        .app(Var(2))
    )))
}

/// Applied to a Church-encoded pair (a, b) it yields a.
///
/// FIRST := λp.p TRUE = λ 1 TRUE
///
/// # Example
/// ```
/// use lambda_calculus::pair::{pair, first};
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::normalize;
///
/// let pair_0_1 = pair().app(zero()).app(one());
///
/// assert_eq!(normalize(first().app(pair_0_1)), zero());
/// ```
pub fn first() -> Term { abs(Var(1).app(tru())) }

/// Applied to a Church-encoded pair (a, b) it yields b.
///
/// SECOND := λp.p FALSE = λ 1 FALSE
///
/// # Example
/// ```
/// use lambda_calculus::pair::{pair, second};
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::normalize;
///
/// let pair_0_1 = pair().app(zero()).app(one());
///
/// assert_eq!(normalize(second().app(pair_0_1)), one());
/// ```
pub fn second() -> Term { abs(Var(1).app(fls())) }

impl Term {
    /// Checks whether `self` is a Church-encoded pair.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = pair().app(zero()).app(one());
    ///
    /// assert!(pair01.is_pair());
    /// ```
    pub fn is_pair(&self) -> bool {
        self.fst_ref().is_ok() && self.snd_ref().is_ok()
    }

    /// Splits a Church-encoded pair into a pair of terms, consuming `self`.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = pair().app(zero()).app(one());
    ///
    /// assert_eq!(pair01.unpair(), Ok((zero(), one())));
    /// ```
    pub fn unpair(self) -> Result<(Term, Term), Error> {
        if let Abs(_) = self {
            if let Ok((wrapped_a, b)) = self.unabs().and_then(|t| t.unapp()) {
                Ok((try!(wrapped_a.rhs()), b))
            } else {
                Err(NotAPair)
            }
        } else {
            if let Ok((wrapped_a, b)) = self.unapp() {
                Ok((try!(wrapped_a.rhs()), b))
            } else {
                Err(NotAPair)
            }
        }
    }

    /// Splits a Church-encoded pair into a pair of references to its underlying terms.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = pair().app(zero()).app(one());
    ///
    /// assert_eq!(pair01.unpair_ref(), Ok((&zero(), &one())));
    /// ```
    pub fn unpair_ref(&self) -> Result<(&Term, &Term), Error> {
        if let Abs(_) = *self {
            if let Ok((wrapped_a, b)) = self.unabs_ref().and_then(|t| t.unapp_ref()) {
                Ok((try!(wrapped_a.rhs_ref()), b))
            } else {
                Err(NotAPair)
            }
        } else {
            if let Ok((wrapped_a, b)) = self.unapp_ref() {
                Ok((try!(wrapped_a.rhs_ref()), b))
            } else {
                Err(NotAPair)
            }
        }
    }

    /// Splits a Church-encoded pair into a pair of mutable references to its underlying terms.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let mut pair01 = pair().app(zero()).app(one());
    ///
    /// assert_eq!(pair01.unpair_ref_mut(), Ok((&mut zero(), &mut one())));
    /// ```
    pub fn unpair_ref_mut(&mut self) -> Result<(&mut Term, &mut Term), Error> {
        if let Abs(_) = *self {
            if let Ok((wrapped_a, b)) = self.unabs_ref_mut().and_then(|t| t.unapp_ref_mut()) {
                Ok((try!(wrapped_a.rhs_ref_mut()), b))
            } else {
                Err(NotAPair)
            }
        } else {
            if let Ok((wrapped_a, b)) = self.unapp_ref_mut() {
                Ok((try!(wrapped_a.rhs_ref_mut()), b))
            } else {
                Err(NotAPair)
            }
        }
    }

    /// Returns the first term from a Church-encoded pair, consuming `self`.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = pair().app(zero()).app(one());
    ///
    /// assert_eq!(pair01.fst(), Ok(zero()));
    /// ```
    pub fn fst(self) -> Result<Term, Error> {
        Ok(try!(self.unpair()).0)
    }

    /// Returns a reference to the first term of a Church-encoded pair.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = pair().app(zero()).app(one());
    ///
    /// assert_eq!(pair01.fst_ref(), Ok(&zero()));
    /// ```
    pub fn fst_ref(&self) -> Result<&Term, Error> {
        Ok(try!(self.unpair_ref()).0)
    }

    /// Returns a mutable reference to the first term of a Church-encoded pair.
    /// Returns a reference to the first term of a Church-encoded pair.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let mut pair01 = pair().app(zero()).app(one());
    ///
    /// assert_eq!(pair01.fst_ref_mut(), Ok(&mut zero()));
    /// ```
    pub fn fst_ref_mut(&mut self) -> Result<&mut Term, Error> {
        Ok(try!(self.unpair_ref_mut()).0)
    }

    /// Returns the second term from a Church-encoded pair, consuming `self`.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = pair().app(zero()).app(one());
    ///
    /// assert_eq!(pair01.snd(), Ok(one()));
    /// ```
    pub fn snd(self) -> Result<Term, Error> {
        Ok(try!(self.unpair()).1)
    }

    /// Returns a reference to the second term of a Church-encoded pair.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = pair().app(zero()).app(one());
    ///
    /// assert_eq!(pair01.snd_ref(), Ok(&one()));
    /// ```
    pub fn snd_ref(&self) -> Result<&Term, Error> {
        Ok(try!(self.unpair_ref()).1)
    }

    /// Returns a mutable reference to the second term of a Church-encoded pair.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let mut pair01 = pair().app(zero()).app(one());
    ///
    /// assert_eq!(pair01.snd_ref_mut(), Ok(&mut one()));
    /// ```
    pub fn snd_ref_mut(&mut self) -> Result<&mut Term, Error> {
        Ok(try!(self.unpair_ref_mut()).1)
    }
}

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

    #[test]
    fn pair_operations() {
        let pair_four_three = normalize(pair().app(4.into()).app(3.into()));

        assert!(pair_four_three.is_pair());

        assert_eq!(pair_four_three.fst_ref(), Ok(&4.into()));
        assert_eq!(pair_four_three.snd_ref(), Ok(&3.into()));

        let unpaired = pair_four_three.unpair();
        assert_eq!(unpaired, Ok((4.into(), 3.into())));
    }
}
<commit_msg>impl From<(Term, Term)> for Term<commit_after>//! [Church pair](https://en.wikipedia.org/wiki/Church_encoding#Church_pairs)

use term::*;
use term::Term::*;
use term::Error::*;
use booleans::*;

/// Produces a Church-encoded pair; applying it to two other terms puts them inside it.
///
/// PAIR := λxyz.z x y = λ λ λ 1 3 2
///
/// # Example
/// ```
/// use lambda_calculus::pair::pair;
/// use lambda_calculus::arithmetic::{zero, one};
/// let pair01 = pair().app(zero()).app(one());
///
/// assert_eq!(pair01.fst_ref(), Ok(&zero()));
/// assert_eq!(pair01.snd_ref(), Ok(&one()));
/// ```
pub fn pair() -> Term {
    abs(abs(abs(
        Var(1)
        .app(Var(3))
        .app(Var(2))
    )))
}

/// Applied to a Church-encoded pair (a, b) it yields a.
///
/// FIRST := λp.p TRUE = λ 1 TRUE
///
/// # Example
/// ```
/// use lambda_calculus::pair::{pair, first};
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::normalize;
///
/// let pair_0_1 = pair().app(zero()).app(one());
///
/// assert_eq!(normalize(first().app(pair_0_1)), zero());
/// ```
pub fn first() -> Term { abs(Var(1).app(tru())) }

/// Applied to a Church-encoded pair (a, b) it yields b.
///
/// SECOND := λp.p FALSE = λ 1 FALSE
///
/// # Example
/// ```
/// use lambda_calculus::pair::{pair, second};
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::normalize;
///
/// let pair_0_1 = pair().app(zero()).app(one());
///
/// assert_eq!(normalize(second().app(pair_0_1)), one());
/// ```
pub fn second() -> Term { abs(Var(1).app(fls())) }

impl Term {
    /// Checks whether `self` is a Church-encoded pair.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = pair().app(zero()).app(one());
    ///
    /// assert!(pair01.is_pair());
    /// ```
    pub fn is_pair(&self) -> bool {
        self.fst_ref().is_ok() && self.snd_ref().is_ok()
    }

    /// Splits a Church-encoded pair into a pair of terms, consuming `self`.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = pair().app(zero()).app(one());
    ///
    /// assert_eq!(pair01.unpair(), Ok((zero(), one())));
    /// ```
    pub fn unpair(self) -> Result<(Term, Term), Error> {
        if let Abs(_) = self {
            if let Ok((wrapped_a, b)) = self.unabs().and_then(|t| t.unapp()) {
                Ok((try!(wrapped_a.rhs()), b))
            } else {
                Err(NotAPair)
            }
        } else {
            if let Ok((wrapped_a, b)) = self.unapp() {
                Ok((try!(wrapped_a.rhs()), b))
            } else {
                Err(NotAPair)
            }
        }
    }

    /// Splits a Church-encoded pair into a pair of references to its underlying terms.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = pair().app(zero()).app(one());
    ///
    /// assert_eq!(pair01.unpair_ref(), Ok((&zero(), &one())));
    /// ```
    pub fn unpair_ref(&self) -> Result<(&Term, &Term), Error> {
        if let Abs(_) = *self {
            if let Ok((wrapped_a, b)) = self.unabs_ref().and_then(|t| t.unapp_ref()) {
                Ok((try!(wrapped_a.rhs_ref()), b))
            } else {
                Err(NotAPair)
            }
        } else {
            if let Ok((wrapped_a, b)) = self.unapp_ref() {
                Ok((try!(wrapped_a.rhs_ref()), b))
            } else {
                Err(NotAPair)
            }
        }
    }

    /// Splits a Church-encoded pair into a pair of mutable references to its underlying terms.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let mut pair01 = pair().app(zero()).app(one());
    ///
    /// assert_eq!(pair01.unpair_ref_mut(), Ok((&mut zero(), &mut one())));
    /// ```
    pub fn unpair_ref_mut(&mut self) -> Result<(&mut Term, &mut Term), Error> {
        if let Abs(_) = *self {
            if let Ok((wrapped_a, b)) = self.unabs_ref_mut().and_then(|t| t.unapp_ref_mut()) {
                Ok((try!(wrapped_a.rhs_ref_mut()), b))
            } else {
                Err(NotAPair)
            }
        } else {
            if let Ok((wrapped_a, b)) = self.unapp_ref_mut() {
                Ok((try!(wrapped_a.rhs_ref_mut()), b))
            } else {
                Err(NotAPair)
            }
        }
    }

    /// Returns the first term from a Church-encoded pair, consuming `self`.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = pair().app(zero()).app(one());
    ///
    /// assert_eq!(pair01.fst(), Ok(zero()));
    /// ```
    pub fn fst(self) -> Result<Term, Error> {
        Ok(try!(self.unpair()).0)
    }

    /// Returns a reference to the first term of a Church-encoded pair.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = pair().app(zero()).app(one());
    ///
    /// assert_eq!(pair01.fst_ref(), Ok(&zero()));
    /// ```
    pub fn fst_ref(&self) -> Result<&Term, Error> {
        Ok(try!(self.unpair_ref()).0)
    }

    /// Returns a mutable reference to the first term of a Church-encoded pair.
    /// Returns a reference to the first term of a Church-encoded pair.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let mut pair01 = pair().app(zero()).app(one());
    ///
    /// assert_eq!(pair01.fst_ref_mut(), Ok(&mut zero()));
    /// ```
    pub fn fst_ref_mut(&mut self) -> Result<&mut Term, Error> {
        Ok(try!(self.unpair_ref_mut()).0)
    }

    /// Returns the second term from a Church-encoded pair, consuming `self`.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = pair().app(zero()).app(one());
    ///
    /// assert_eq!(pair01.snd(), Ok(one()));
    /// ```
    pub fn snd(self) -> Result<Term, Error> {
        Ok(try!(self.unpair()).1)
    }

    /// Returns a reference to the second term of a Church-encoded pair.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = pair().app(zero()).app(one());
    ///
    /// assert_eq!(pair01.snd_ref(), Ok(&one()));
    /// ```
    pub fn snd_ref(&self) -> Result<&Term, Error> {
        Ok(try!(self.unpair_ref()).1)
    }

    /// Returns a mutable reference to the second term of a Church-encoded pair.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let mut pair01 = pair().app(zero()).app(one());
    ///
    /// assert_eq!(pair01.snd_ref_mut(), Ok(&mut one()));
    /// ```
    pub fn snd_ref_mut(&mut self) -> Result<&mut Term, Error> {
        Ok(try!(self.unpair_ref_mut()).1)
    }
}

impl From<(Term, Term)> for Term {
    fn from((t1, t2): (Term, Term)) -> Self {
        abs(
            Var(1)
            .app(t1)
            .app(t2)
        )
    }
}

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

    #[test]
    fn pair_from_pair() {
        assert_eq!(Term::from((0.into(), 1.into())), normalize(pair().app(0.into()).app(1.into())));
    }

    #[test]
    fn pair_operations() {
        let pair_four_three = normalize(pair().app(4.into()).app(3.into()));

        assert!(pair_four_three.is_pair());

        assert_eq!(pair_four_three.fst_ref(), Ok(&4.into()));
        assert_eq!(pair_four_three.snd_ref(), Ok(&3.into()));

        let unpaired = pair_four_three.unpair();
        assert_eq!(unpaired, Ok((4.into(), 3.into())));
    }
}
<|endoftext|>


<commit_before>//! Clippy wrappers around rustc's diagnostic functions.

use rustc_errors::{Applicability, CodeSuggestion, DiagnosticBuilder, Substitution, SubstitutionPart, SuggestionStyle};
use rustc_hir::HirId;
use rustc_lint::{LateContext, Lint, LintContext};
use rustc_span::source_map::{MultiSpan, Span};
use std::env;

/// Wrapper around `DiagnosticBuilder` that adds a link to Clippy documentation for the emitted lint
struct DiagnosticWrapper<'a>(DiagnosticBuilder<'a>);

impl<'a> Drop for DiagnosticWrapper<'a> {
    fn drop(&mut self) {
        self.0.emit();
    }
}

impl<'a> DiagnosticWrapper<'a> {
    fn docs_link(&mut self, lint: &'static Lint) {
        if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() {
            self.0.help(&format!(
                "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{}",
                &option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| {
                    // extract just major + minor version and ignore patch versions
                    format!("rust-{}", n.rsplitn(2, '.').nth(1).unwrap())
                }),
                lint.name_lower().replacen("clippy::", "", 1)
            ));
        }
    }
}

/// Emit a basic lint message with a `msg` and a `span`.
///
/// This is the most primitive of our lint emission methods and can
/// be a good way to get a new lint started.
///
/// Usually it's nicer to provide more context for lint messages.
/// Be sure the output is understandable when you use this method.
///
/// # Example
///
/// ```ignore
/// error: usage of mem::forget on Drop type
///   --> $DIR/mem_forget.rs:17:5
///    |
/// 17 |     std::mem::forget(seven);
///    |     ^^^^^^^^^^^^^^^^^^^^^^^
/// ```
pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<MultiSpan>, msg: &str) {
    DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg)).docs_link(lint);
}

/// Same as `span_lint` but with an extra `help` message.
///
/// Use this if you want to provide some general help but
/// can't provide a specific machine applicable suggestion.
///
/// The `help` message is not attached to any `Span`.
///
/// # Example
///
/// ```ignore
/// error: constant division of 0.0 with 0.0 will always result in NaN
///   --> $DIR/zero_div_zero.rs:6:25
///    |
/// 6  |     let other_f64_nan = 0.0f64 / 0.0;
///    |                         ^^^^^^^^^^^^
///    |
///    = help: Consider using `std::f64::NAN` if you would like a constant representing NaN
/// ```
pub fn span_lint_and_help<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, help: &str) {
    let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg));
    db.0.help(help);
    db.docs_link(lint);
}

/// Like `span_lint` but with a `note` section instead of a `help` message.
///
/// The `note` message is presented separately from the main lint message
/// and is attached to a specific span:
///
/// # Example
///
/// ```ignore
/// error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
///   --> $DIR/drop_forget_ref.rs:10:5
///    |
/// 10 |     forget(&SomeStruct);
///    |     ^^^^^^^^^^^^^^^^^^^
///    |
///    = note: `-D clippy::forget-ref` implied by `-D warnings`
/// note: argument has type &SomeStruct
///   --> $DIR/drop_forget_ref.rs:10:12
///    |
/// 10 |     forget(&SomeStruct);
///    |            ^^^^^^^^^^^
/// ```
pub fn span_lint_and_note<'a, T: LintContext>(
    cx: &'a T,
    lint: &'static Lint,
    span: Span,
    msg: &str,
    note_span: Span,
    note: &str,
) {
    let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg));
    if note_span == span {
        db.0.note(note);
    } else {
        db.0.span_note(note_span, note);
    }
    db.docs_link(lint);
}

pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F)
where
    F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>),
{
    let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg));
    f(&mut db.0);
    db.docs_link(lint);
}

pub fn span_lint_hir(cx: &LateContext<'_, '_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) {
    DiagnosticWrapper(cx.tcx.struct_span_lint_hir(lint, hir_id, sp, msg)).docs_link(lint);
}

pub fn span_lint_hir_and_then(
    cx: &LateContext<'_, '_>,
    lint: &'static Lint,
    hir_id: HirId,
    sp: Span,
    msg: &str,
    f: impl FnOnce(&mut DiagnosticBuilder<'_>),
) {
    let mut db = DiagnosticWrapper(cx.tcx.struct_span_lint_hir(lint, hir_id, sp, msg));
    f(&mut db.0);
    db.docs_link(lint);
}

/// Add a span lint with a suggestion on how to fix it.
///
/// These suggestions can be parsed by rustfix to allow it to automatically fix your code.
/// In the example below, `help` is `"try"` and `sugg` is the suggested replacement `".any(|x| x >
/// 2)"`.
///
/// ```ignore
/// error: This `.fold` can be more succinctly expressed as `.any`
/// --> $DIR/methods.rs:390:13
///     |
/// 390 |     let _ = (0..3).fold(false, |acc, x| acc || x > 2);
///     |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)`
///     |
///     = note: `-D fold-any` implied by `-D warnings`
/// ```
pub fn span_lint_and_sugg<'a, T: LintContext>(
    cx: &'a T,
    lint: &'static Lint,
    sp: Span,
    msg: &str,
    help: &str,
    sugg: String,
    applicability: Applicability,
) {
    span_lint_and_then(cx, lint, sp, msg, |db| {
        db.span_suggestion(sp, help, sugg, applicability);
    });
}

/// Create a suggestion made from several `span → replacement`.
///
/// Note: in the JSON format (used by `compiletest_rs`), the help message will
/// appear once per
/// replacement. In human-readable format though, it only appears once before
/// the whole suggestion.
pub fn multispan_sugg<I>(db: &mut DiagnosticBuilder<'_>, help_msg: String, sugg: I)
where
    I: IntoIterator<Item = (Span, String)>,
{
    let sugg = CodeSuggestion {
        substitutions: vec![Substitution {
            parts: sugg
                .into_iter()
                .map(|(span, snippet)| SubstitutionPart { snippet, span })
                .collect(),
        }],
        msg: help_msg,
        style: SuggestionStyle::ShowCode,
        applicability: Applicability::Unspecified,
    };
    db.suggestions.push(sugg);
}
<commit_msg>Rustup to rust-lang/rust#68725<commit_after>//! Clippy wrappers around rustc's diagnostic functions.

use rustc_errors::{Applicability, CodeSuggestion, DiagnosticBuilder, Substitution, SubstitutionPart, SuggestionStyle};
use rustc_hir::HirId;
use rustc_lint::{LateContext, Lint, LintContext};
use rustc_span::source_map::{MultiSpan, Span};
use std::env;

fn docs_link(db: &mut DiagnosticBuilder<'_>, lint: &'static Lint) {
    if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() {
        db.help(&format!(
            "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{}",
            &option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| {
                // extract just major + minor version and ignore patch versions
                format!("rust-{}", n.rsplitn(2, '.').nth(1).unwrap())
            }),
            lint.name_lower().replacen("clippy::", "", 1)
        ));
    }
}

/// Emit a basic lint message with a `msg` and a `span`.
///
/// This is the most primitive of our lint emission methods and can
/// be a good way to get a new lint started.
///
/// Usually it's nicer to provide more context for lint messages.
/// Be sure the output is understandable when you use this method.
///
/// # Example
///
/// ```ignore
/// error: usage of mem::forget on Drop type
///   --> $DIR/mem_forget.rs:17:5
///    |
/// 17 |     std::mem::forget(seven);
///    |     ^^^^^^^^^^^^^^^^^^^^^^^
/// ```
pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<MultiSpan>, msg: &str) {
    cx.struct_span_lint(lint, sp, |ldb| {
        let mut db = ldb.build(msg);
        docs_link(&mut db, lint);
        db.emit();
    });
}

/// Same as `span_lint` but with an extra `help` message.
///
/// Use this if you want to provide some general help but
/// can't provide a specific machine applicable suggestion.
///
/// The `help` message is not attached to any `Span`.
///
/// # Example
///
/// ```ignore
/// error: constant division of 0.0 with 0.0 will always result in NaN
///   --> $DIR/zero_div_zero.rs:6:25
///    |
/// 6  |     let other_f64_nan = 0.0f64 / 0.0;
///    |                         ^^^^^^^^^^^^
///    |
///    = help: Consider using `std::f64::NAN` if you would like a constant representing NaN
/// ```
pub fn span_lint_and_help<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, help: &str) {
    cx.struct_span_lint(lint, span, |ldb| {
        let mut db = ldb.build(msg);
        db.help(help);
        docs_link(&mut db, lint);
        db.emit();
    });
}

/// Like `span_lint` but with a `note` section instead of a `help` message.
///
/// The `note` message is presented separately from the main lint message
/// and is attached to a specific span:
///
/// # Example
///
/// ```ignore
/// error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
///   --> $DIR/drop_forget_ref.rs:10:5
///    |
/// 10 |     forget(&SomeStruct);
///    |     ^^^^^^^^^^^^^^^^^^^
///    |
///    = note: `-D clippy::forget-ref` implied by `-D warnings`
/// note: argument has type &SomeStruct
///   --> $DIR/drop_forget_ref.rs:10:12
///    |
/// 10 |     forget(&SomeStruct);
///    |            ^^^^^^^^^^^
/// ```
pub fn span_lint_and_note<'a, T: LintContext>(
    cx: &'a T,
    lint: &'static Lint,
    span: Span,
    msg: &str,
    note_span: Span,
    note: &str,
) {
    cx.struct_span_lint(lint, span, |ldb| {
        let mut db = ldb.build(msg);
        if note_span == span {
            db.note(note);
        } else {
            db.span_note(note_span, note);
        }
        docs_link(&mut db, lint);
        db.emit();
    });
}

pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F)
where
    F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>),
{
    cx.struct_span_lint(lint, sp, |ldb| {
        let mut db = ldb.build(msg);
        f(&mut db);
        docs_link(&mut db, lint);
        db.emit();
    });
}

pub fn span_lint_hir(cx: &LateContext<'_, '_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) {
    cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |ldb| {
        let mut db = ldb.build(msg);
        docs_link(&mut db, lint);
        db.emit();
    });
}

pub fn span_lint_hir_and_then(
    cx: &LateContext<'_, '_>,
    lint: &'static Lint,
    hir_id: HirId,
    sp: Span,
    msg: &str,
    f: impl FnOnce(&mut DiagnosticBuilder<'_>),
) {
    cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |ldb| {
        let mut db = ldb.build(msg);
        f(&mut db);
        docs_link(&mut db, lint);
        db.emit();
    });
}

/// Add a span lint with a suggestion on how to fix it.
///
/// These suggestions can be parsed by rustfix to allow it to automatically fix your code.
/// In the example below, `help` is `"try"` and `sugg` is the suggested replacement `".any(|x| x >
/// 2)"`.
///
/// ```ignore
/// error: This `.fold` can be more succinctly expressed as `.any`
/// --> $DIR/methods.rs:390:13
///     |
/// 390 |     let _ = (0..3).fold(false, |acc, x| acc || x > 2);
///     |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)`
///     |
///     = note: `-D fold-any` implied by `-D warnings`
/// ```
pub fn span_lint_and_sugg<'a, T: LintContext>(
    cx: &'a T,
    lint: &'static Lint,
    sp: Span,
    msg: &str,
    help: &str,
    sugg: String,
    applicability: Applicability,
) {
    span_lint_and_then(cx, lint, sp, msg, |db| {
        db.span_suggestion(sp, help, sugg, applicability);
    });
}

/// Create a suggestion made from several `span → replacement`.
///
/// Note: in the JSON format (used by `compiletest_rs`), the help message will
/// appear once per
/// replacement. In human-readable format though, it only appears once before
/// the whole suggestion.
pub fn multispan_sugg<I>(db: &mut DiagnosticBuilder<'_>, help_msg: String, sugg: I)
where
    I: IntoIterator<Item = (Span, String)>,
{
    let sugg = CodeSuggestion {
        substitutions: vec![Substitution {
            parts: sugg
                .into_iter()
                .map(|(span, snippet)| SubstitutionPart { snippet, span })
                .collect(),
        }],
        msg: help_msg,
        style: SuggestionStyle::ShowCode,
        applicability: Applicability::Unspecified,
    };
    db.suggestions.push(sugg);
}
<|endoftext|>


<commit_before>/// A macro for extracting the successful type of a `Poll<T, E>`.
///
/// This macro bakes propagation of both errors and `NotReady` signals by
/// returning early.
#[macro_export]
macro_rules! try_ready {
    ($e:expr) => (match $e {
        Ok($crate::Async::Ready(t)) => t,
        Ok($crate::Async::NotReady) => return Ok($crate::Async::NotReady),
        Err(e) => return Err(From::from(e)),
    })
}

/// Return type of the `Future::poll` method, indicates whether a future's value
/// is ready or not.
///
/// * `Ok(Async::Ready(t))` means that a future has successfully resolved
/// * `Ok(Async::NotReady)` means that a future is not ready to complete yet
/// * `Err(e)` means that a future has completed with the given failure
pub type Poll<T, E> = Result<Async<T>, E>;

/// Return type of future, indicating whether a value is ready or not.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Async<T> {
    /// Represents that a value is immediately ready.
    Ready(T),

    /// Represents that a value is not ready yet, but may be so later.
    NotReady,
}

impl<T> Async<T> {
    /// Change the success value of this `Async` with the closure provided
    pub fn map<F, U>(self, f: F) -> Async<U>
        where F: FnOnce(T) -> U
    {
        match self {
            Async::Ready(t) => Async::Ready(f(t)),
            Async::NotReady => Async::NotReady,
        }
    }

    /// Returns whether this is `Async::Ready`
    pub fn is_ready(&self) -> bool {
        match *self {
            Async::Ready(_) => true,
            Async::NotReady => false,
        }
    }

    /// Returns whether this is `Async::NotReady`
    pub fn is_not_ready(&self) -> bool {
        !self.is_ready()
    }
}

impl<T> From<T> for Async<T> {
    fn from(t: T) -> Async<T> {
        Async::Ready(t)
    }
}

/// The result of an asynchronous attempt to send a value to a sink.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AsyncSink<T> {
    /// The `start_send` attempt succeeded, so the sending process has
    /// *started*; you must use `Sink::poll_complete` to drive the send
    /// to completion.
    Ready,

    /// The `start_send` attempt failed due to the sink being full. The value
    /// being sent is returned, and the current `Task` will be automatically
    /// notified again once the sink has room.
    NotReady(T),
}

impl<T> AsyncSink<T> {
    /// Returns whether this is `AsyncSink::Ready`
    pub fn is_ready(&self) -> bool {
        match *self {
            AsyncSink::Ready => true,
            AsyncSink::NotReady(_) => false,
        }
    }

    /// Returns whether this is `AsyncSink::NotReady`
    pub fn is_not_ready(&self) -> bool {
        !self.is_ready()
    }
}

/// Return type of the `Sink::start_send` method, indicating the outcome of a
/// send attempt. See `AsyncSink` for more details.
pub type StartSend<T, E> = Result<AsyncSink<T>, E>;
<commit_msg>Add `AsyncSink::map` method<commit_after>/// A macro for extracting the successful type of a `Poll<T, E>`.
///
/// This macro bakes propagation of both errors and `NotReady` signals by
/// returning early.
#[macro_export]
macro_rules! try_ready {
    ($e:expr) => (match $e {
        Ok($crate::Async::Ready(t)) => t,
        Ok($crate::Async::NotReady) => return Ok($crate::Async::NotReady),
        Err(e) => return Err(From::from(e)),
    })
}

/// Return type of the `Future::poll` method, indicates whether a future's value
/// is ready or not.
///
/// * `Ok(Async::Ready(t))` means that a future has successfully resolved
/// * `Ok(Async::NotReady)` means that a future is not ready to complete yet
/// * `Err(e)` means that a future has completed with the given failure
pub type Poll<T, E> = Result<Async<T>, E>;

/// Return type of future, indicating whether a value is ready or not.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Async<T> {
    /// Represents that a value is immediately ready.
    Ready(T),

    /// Represents that a value is not ready yet, but may be so later.
    NotReady,
}

impl<T> Async<T> {
    /// Change the success value of this `Async` with the closure provided
    pub fn map<F, U>(self, f: F) -> Async<U>
        where F: FnOnce(T) -> U
    {
        match self {
            Async::Ready(t) => Async::Ready(f(t)),
            Async::NotReady => Async::NotReady,
        }
    }

    /// Returns whether this is `Async::Ready`
    pub fn is_ready(&self) -> bool {
        match *self {
            Async::Ready(_) => true,
            Async::NotReady => false,
        }
    }

    /// Returns whether this is `Async::NotReady`
    pub fn is_not_ready(&self) -> bool {
        !self.is_ready()
    }
}

impl<T> From<T> for Async<T> {
    fn from(t: T) -> Async<T> {
        Async::Ready(t)
    }
}

/// The result of an asynchronous attempt to send a value to a sink.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AsyncSink<T> {
    /// The `start_send` attempt succeeded, so the sending process has
    /// *started*; you must use `Sink::poll_complete` to drive the send
    /// to completion.
    Ready,

    /// The `start_send` attempt failed due to the sink being full. The value
    /// being sent is returned, and the current `Task` will be automatically
    /// notified again once the sink has room.
    NotReady(T),
}

impl<T> AsyncSink<T> {
    /// Change the NotReady value of this `AsyncSink` with the closure provided
    pub fn map<F, U>(self, f: F) -> AsyncSink<U>
        where F: FnOnce(T) -> U,
    {
        match self {
            AsyncSink::Ready => AsyncSink::Ready,
            AsyncSink::NotReady(t) => AsyncSink::NotReady(f(t)),
        }
    }

    /// Returns whether this is `AsyncSink::Ready`
    pub fn is_ready(&self) -> bool {
        match *self {
            AsyncSink::Ready => true,
            AsyncSink::NotReady(_) => false,
        }
    }

    /// Returns whether this is `AsyncSink::NotReady`
    pub fn is_not_ready(&self) -> bool {
        !self.is_ready()
    }
}

/// Return type of the `Sink::start_send` method, indicating the outcome of a
/// send attempt. See `AsyncSink` for more details.
pub type StartSend<T, E> = Result<AsyncSink<T>, E>;
<|endoftext|>


<commit_before>use std::boxed::Box;
use std::ops::Deref;
use std::fmt;

use rustc_serialize::{Encodable, Encoder};
use rustc_serialize::{Decodable, Decoder};

/// A struct for encoding nested reference types.
///
/// Encoding large objects by reference is really handy.  For example,
/// `encode(&large_hashmap, ...)` encodes the large structure without having to
/// own the hashmap.  However, it is impossible to serialize a reference if that
/// reference is inside of a struct.
///
/// ```ignore rust
/// // Not possible, rustc can not decode the reference.
/// #[derive(RustcEncoding, RustcDecoding)]
/// struct Message<'a>  {
///   big_map: &'a HashMap<u32, u32>,
///   message_type: String,
/// }
/// ```
///
/// This is because on the decoding side, you can't create the Message struct
/// because it needs to have a reference to a HashMap, which is impossible because
/// during deserialization, all members need to be owned by the deserialized
/// object.
///
/// This is where RefBox comes in.  During serialization, it serializs a reference,
/// but during deserialization, it puts that sub-object into a box!
///
/// ```ignore rust
/// // This works!
/// #[derive(RustcEncoding, RustcDecoding)]
/// struct Message<'a> {
///     big_map: RefBox<'a, HashMap<u32, u32>>,
///     message_type: String
/// }
/// ```
///
/// Now we can write
///
/// ```ignore rust
/// let my_map = HashMap::new();
/// let my_msg = Message {
///     big_map: RefBox::new(&my_map),
///     message_type: "foo".to_string()
/// };
///
/// let encoded = encode(&my_msg, ...).unwrap();
/// let decoded: Message<'static> = decode(&encoded[]).unwrap();
/// ```
///
/// Notice that we managed to encode and decode a struct with a nested reference
/// and that the decoded message has the lifetime `'static` which shows us
/// that the message owns everything inside it completely.
///
/// Please don't stick RefBox inside deep data structures.  It is much better
/// suited in the outermost layer of whatever it is that you are encoding.
pub struct RefBox<'a, T: 'a> {
    inner:  RefBoxInner<'a, T, Box<T>>
}

/// Like a RefBox, but encoding from a `str` and decoedes to a `String`.
pub struct StrBox<'a> {
    inner: RefBoxInner<'a, str, String>
}

/// Like a RefBox, but encodes from a `[T]` and encodes to a `Vec<T>`.
pub struct SliceBox<'a, T: 'a> {
    inner: RefBoxInner<'a, [T], Vec<T>>
}

#[derive(Debug, Hash)]
enum RefBoxInner<'a, A: 'a + ?Sized, B> {
    Ref(&'a A),
    Box(B)
}

impl <'a, T> RefBox<'a, T> {
    /// Creates a new RefBox that looks at a borrowed value.
    pub fn new(v: &'a T) -> RefBox<'a, T> {
        RefBox {
            inner: RefBoxInner::Ref(v)
        }
    }
}

impl <T> RefBox<'static, T>  {
    /// Takes the value out of this refbox.
    ///
    /// Fails if this refbox was not created out of a deserialization.
    ///
    /// Unless you are doing some really weird things with static references,
    /// this function will never fail.
    pub fn take(self) -> Box<T> {
        match self.inner {
            RefBoxInner::Box(b) => b,
            _ => unreachable!()
        }
    }

    /// Tries to take the value out of this refbox.
    pub fn try_take(self) -> Result<Box<T>, RefBox<'static, T>> {
        match self.inner {
            RefBoxInner::Box(b) => Ok(b),
            o => Err(RefBox{ inner: o})
        }
    }
}

impl <'a, T: Encodable> Encodable for RefBox<'a, T> {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        self.inner.encode(s)
    }
}

impl <T: Decodable> Decodable for RefBox<'static, T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<RefBox<'static, T>, D::Error> {
        let inner = try!(Decodable::decode(d));
        Ok(RefBox{inner: inner})
    }
}

impl <'a> StrBox<'a> {
    /// Creates a new RefBox that looks at a borrowed value.
    pub fn new(s: &'a str) -> StrBox<'a> {
        StrBox {
            inner: RefBoxInner::Ref(s)
        }
    }
}

impl StrBox<'static>  {
    /// Takes the value out of this refbox.
    ///
    /// Fails if this refbox was not created out of a deserialization.
    ///
    /// Unless you are doing some really weird things with static references,
    /// this function will never fail.
    pub fn take(self) -> String {
        match self.inner {
            RefBoxInner::Box(b) => b,
            _ => unreachable!()
        }
    }

    /// Tries to take the value out of this refbox.
    pub fn try_take(self) -> Result<String, StrBox<'static>> {
        match self.inner {
            RefBoxInner::Box(b) => Ok(b),
            o => Err(StrBox{ inner: o})
        }
    }
}

impl <'a> Encodable for StrBox<'a> {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        self.inner.encode(s)
    }
}

impl Decodable for StrBox<'static> {
    fn decode<D: Decoder>(d: &mut D) -> Result<StrBox<'static>, D::Error> {
        let inner: RefBoxInner<'static, str, String> = try!(Decodable::decode(d));
        Ok(StrBox{inner: inner})
    }
}

//
// SliceBox
//

impl <'a, T> SliceBox<'a, T> {
    /// Creates a new RefBox that looks at a borrowed value.
    pub fn new(v: &'a [T]) -> SliceBox<'a, T> {
        SliceBox {
            inner: RefBoxInner::Ref(v)
        }
    }
}

impl <T> SliceBox<'static, T>  {
    /// Takes the value out of this refbox.
    ///
    /// Fails if this refbox was not created out of a deserialization.
    ///
    /// Unless you are doing some really weird things with static references,
    /// this function will never fail.
    pub fn take(self) -> Vec<T> {
        match self.inner {
            RefBoxInner::Box(b) => b,
            _ => unreachable!()
        }
    }

    /// Tries to take the value out of this refbox.
    pub fn try_take(self) -> Result<Vec<T>, SliceBox<'static, T>> {
        match self.inner {
            RefBoxInner::Box(b) => Ok(b),
            o => Err(SliceBox{ inner: o})
        }
    }
}

impl <'a, T: Encodable> Encodable for SliceBox<'a, T> {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        self.inner.encode(s)
    }
}

impl <T: Decodable> Decodable for SliceBox<'static, T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<SliceBox<'static, T>, D::Error> {
        let inner: RefBoxInner<'static, [T], Vec<T>> = try!(Decodable::decode(d));
        Ok(SliceBox{inner: inner})
    }
}

impl <'a, A: Encodable + ?Sized, B: Encodable> Encodable for RefBoxInner<'a, A, B> {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        match self {
            &RefBoxInner::Ref(ref r) => r.encode(s),
            &RefBoxInner::Box(ref b) => b.encode(s)
        }
    }
}

impl <A: ?Sized, B: Decodable> Decodable for RefBoxInner<'static, A, B> {
    fn decode<D: Decoder>(d: &mut D) -> Result<RefBoxInner<'static, A, B>, D::Error> {
        let decoded = try!(Decodable::decode(d));
        Ok(RefBoxInner::Box(decoded))
    }
}

impl <'a, T> Deref for RefBox<'a, T> {
    type Target = T;

    fn deref(&self) -> &T {
        match &self.inner {
            &RefBoxInner::Ref(ref t) => t,
            &RefBoxInner::Box(ref b) => b.deref()
        }
    }
}

impl <'a, T: fmt::Debug> fmt::Debug for RefBox<'a, T> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "RefBox({:?})", *self)
    }
}
<commit_msg>derive debug for refbox and friends<commit_after>use std::boxed::Box;
use std::ops::Deref;

use rustc_serialize::{Encodable, Encoder};
use rustc_serialize::{Decodable, Decoder};

/// A struct for encoding nested reference types.
///
/// Encoding large objects by reference is really handy.  For example,
/// `encode(&large_hashmap, ...)` encodes the large structure without having to
/// own the hashmap.  However, it is impossible to serialize a reference if that
/// reference is inside of a struct.
///
/// ```ignore rust
/// // Not possible, rustc can not decode the reference.
/// #[derive(RustcEncoding, RustcDecoding)]
/// struct Message<'a>  {
///   big_map: &'a HashMap<u32, u32>,
///   message_type: String,
/// }
/// ```
///
/// This is because on the decoding side, you can't create the Message struct
/// because it needs to have a reference to a HashMap, which is impossible because
/// during deserialization, all members need to be owned by the deserialized
/// object.
///
/// This is where RefBox comes in.  During serialization, it serializs a reference,
/// but during deserialization, it puts that sub-object into a box!
///
/// ```ignore rust
/// // This works!
/// #[derive(RustcEncoding, RustcDecoding)]
/// struct Message<'a> {
///     big_map: RefBox<'a, HashMap<u32, u32>>,
///     message_type: String
/// }
/// ```
///
/// Now we can write
///
/// ```ignore rust
/// let my_map = HashMap::new();
/// let my_msg = Message {
///     big_map: RefBox::new(&my_map),
///     message_type: "foo".to_string()
/// };
///
/// let encoded = encode(&my_msg, ...).unwrap();
/// let decoded: Message<'static> = decode(&encoded[]).unwrap();
/// ```
///
/// Notice that we managed to encode and decode a struct with a nested reference
/// and that the decoded message has the lifetime `'static` which shows us
/// that the message owns everything inside it completely.
///
/// Please don't stick RefBox inside deep data structures.  It is much better
/// suited in the outermost layer of whatever it is that you are encoding.
#[derive(Debug)]
pub struct RefBox<'a, T: 'a> {
    inner:  RefBoxInner<'a, T, Box<T>>
}

/// Like a RefBox, but encoding from a `str` and decoedes to a `String`.
#[derive(Debug)]
pub struct StrBox<'a> {
    inner: RefBoxInner<'a, str, String>
}

/// Like a RefBox, but encodes from a `[T]` and encodes to a `Vec<T>`.
#[derive(Debug)]
pub struct SliceBox<'a, T: 'a> {
    inner: RefBoxInner<'a, [T], Vec<T>>
}

#[derive(Debug, Hash)]
enum RefBoxInner<'a, A: 'a + ?Sized, B> {
    Ref(&'a A),
    Box(B)
}

impl <'a, T> RefBox<'a, T> {
    /// Creates a new RefBox that looks at a borrowed value.
    pub fn new(v: &'a T) -> RefBox<'a, T> {
        RefBox {
            inner: RefBoxInner::Ref(v)
        }
    }
}

impl <T> RefBox<'static, T>  {
    /// Takes the value out of this refbox.
    ///
    /// Fails if this refbox was not created out of a deserialization.
    ///
    /// Unless you are doing some really weird things with static references,
    /// this function will never fail.
    pub fn take(self) -> Box<T> {
        match self.inner {
            RefBoxInner::Box(b) => b,
            _ => unreachable!()
        }
    }

    /// Tries to take the value out of this refbox.
    pub fn try_take(self) -> Result<Box<T>, RefBox<'static, T>> {
        match self.inner {
            RefBoxInner::Box(b) => Ok(b),
            o => Err(RefBox{ inner: o})
        }
    }
}

impl <'a, T: Encodable> Encodable for RefBox<'a, T> {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        self.inner.encode(s)
    }
}

impl <T: Decodable> Decodable for RefBox<'static, T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<RefBox<'static, T>, D::Error> {
        let inner = try!(Decodable::decode(d));
        Ok(RefBox{inner: inner})
    }
}

impl <'a> StrBox<'a> {
    /// Creates a new RefBox that looks at a borrowed value.
    pub fn new(s: &'a str) -> StrBox<'a> {
        StrBox {
            inner: RefBoxInner::Ref(s)
        }
    }
}

impl StrBox<'static>  {
    /// Takes the value out of this refbox.
    ///
    /// Fails if this refbox was not created out of a deserialization.
    ///
    /// Unless you are doing some really weird things with static references,
    /// this function will never fail.
    pub fn take(self) -> String {
        match self.inner {
            RefBoxInner::Box(b) => b,
            _ => unreachable!()
        }
    }

    /// Tries to take the value out of this refbox.
    pub fn try_take(self) -> Result<String, StrBox<'static>> {
        match self.inner {
            RefBoxInner::Box(b) => Ok(b),
            o => Err(StrBox{ inner: o})
        }
    }
}

impl <'a> Encodable for StrBox<'a> {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        self.inner.encode(s)
    }
}

impl Decodable for StrBox<'static> {
    fn decode<D: Decoder>(d: &mut D) -> Result<StrBox<'static>, D::Error> {
        let inner: RefBoxInner<'static, str, String> = try!(Decodable::decode(d));
        Ok(StrBox{inner: inner})
    }
}

//
// SliceBox
//

impl <'a, T> SliceBox<'a, T> {
    /// Creates a new RefBox that looks at a borrowed value.
    pub fn new(v: &'a [T]) -> SliceBox<'a, T> {
        SliceBox {
            inner: RefBoxInner::Ref(v)
        }
    }
}

impl <T> SliceBox<'static, T>  {
    /// Takes the value out of this refbox.
    ///
    /// Fails if this refbox was not created out of a deserialization.
    ///
    /// Unless you are doing some really weird things with static references,
    /// this function will never fail.
    pub fn take(self) -> Vec<T> {
        match self.inner {
            RefBoxInner::Box(b) => b,
            _ => unreachable!()
        }
    }

    /// Tries to take the value out of this refbox.
    pub fn try_take(self) -> Result<Vec<T>, SliceBox<'static, T>> {
        match self.inner {
            RefBoxInner::Box(b) => Ok(b),
            o => Err(SliceBox{ inner: o})
        }
    }
}

impl <'a, T: Encodable> Encodable for SliceBox<'a, T> {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        self.inner.encode(s)
    }
}

impl <T: Decodable> Decodable for SliceBox<'static, T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<SliceBox<'static, T>, D::Error> {
        let inner: RefBoxInner<'static, [T], Vec<T>> = try!(Decodable::decode(d));
        Ok(SliceBox{inner: inner})
    }
}

impl <'a, A: Encodable + ?Sized, B: Encodable> Encodable for RefBoxInner<'a, A, B> {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        match self {
            &RefBoxInner::Ref(ref r) => r.encode(s),
            &RefBoxInner::Box(ref b) => b.encode(s)
        }
    }
}

impl <A: ?Sized, B: Decodable> Decodable for RefBoxInner<'static, A, B> {
    fn decode<D: Decoder>(d: &mut D) -> Result<RefBoxInner<'static, A, B>, D::Error> {
        let decoded = try!(Decodable::decode(d));
        Ok(RefBoxInner::Box(decoded))
    }
}

impl <'a, T> Deref for RefBox<'a, T> {
    type Target = T;

    fn deref(&self) -> &T {
        match &self.inner {
            &RefBoxInner::Ref(ref t) => t,
            &RefBoxInner::Box(ref b) => b.deref()
        }
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::collections::HashMap;

use cookie;
use iron;
use iron::prelude::*;

use Session;
use SessionBackend;

enum CookieOrString {
    Cookie(cookie::Cookie),
    String(String)
}

pub struct SignedCookieSession {
    values: HashMap<String, CookieOrString>,
    signing_key: Arc<Vec<u8>>,
}

impl Session for SignedCookieSession {
    fn get(&self, key: &str) -> Option<&str> {
        match self.values.get(key) {
            Some(&CookieOrString::Cookie(ref x)) => Some(&x.value),
            Some(&CookieOrString::String(ref x)) => Some(x),
            None => None
        }
    }

    fn set(&mut self, key: &str, value: String) {
        self.values.insert(
            key.to_owned(),
            CookieOrString::String(value)
        );
    }

    fn write_cookies(&self, res: &mut Response) {
        debug_assert!(!res.headers.has::<iron::headers::SetCookie>());

        let cookiejar = cookie::CookieJar::new(&self.signing_key);
        for (key, value) in self.values.iter() {
            cookiejar.signed().add(match value {
                &CookieOrString::Cookie(ref x) => x.clone(),
                &CookieOrString::String(ref x) => {
                    let mut c = cookie::Cookie::new(
                        key.to_owned(),
                        x.to_owned()
                    );
                    c.httponly = true;
                    c.path = Some("/".to_owned());
                    c
                }
            });
        }
        res.headers.set(iron::headers::SetCookie(cookiejar.delta()));
    }
}

#[derive(Clone, Debug)]
pub struct SignedCookieBackend {
    signing_key: Arc<Vec<u8>>,
}

impl SignedCookieBackend {
    pub fn new(signing_key: Vec<u8>) -> Self {
        SignedCookieBackend {
            signing_key: Arc::new(signing_key)
        }
    }
}

impl SessionBackend for SignedCookieBackend {
    type S = SignedCookieSession;

    fn from_request(&self, req: &mut Request) -> Self::S {
        let jar = match req.headers.get::<iron::headers::Cookie>() {
            Some(cookies) => cookies.to_cookie_jar(&self.signing_key),
            None => cookie::CookieJar::new(&self.signing_key)
        };

        SignedCookieSession {
            values: jar.signed().iter()
                .map(|c| (c.name.clone(), CookieOrString::Cookie(c)))
                .collect(),
            signing_key: self.signing_key.clone(),
        }
    }

}
<commit_msg>Add cookie-modifier<commit_after>use std::sync::Arc;
use std::collections::HashMap;

use cookie;
use iron;
use iron::prelude::*;

use Session;
use SessionBackend;

enum CookieOrString {
    Cookie(cookie::Cookie),
    String(String)
}

pub struct SignedCookieSession {
    values: HashMap<String, CookieOrString>,
    signing_key: Arc<Vec<u8>>,
    cookie_modifier: Option<Arc<Box<Fn(&mut cookie::Cookie) + Send + Sync>>>
}

impl Session for SignedCookieSession {
    fn get(&self, key: &str) -> Option<&str> {
        match self.values.get(key) {
            Some(&CookieOrString::Cookie(ref x)) => Some(&x.value),
            Some(&CookieOrString::String(ref x)) => Some(x),
            None => None
        }
    }

    fn set(&mut self, key: &str, value: String) {
        self.values.insert(
            key.to_owned(),
            CookieOrString::String(value)
        );
    }

    fn write_cookies(&self, res: &mut Response) {
        debug_assert!(!res.headers.has::<iron::headers::SetCookie>());

        let cookiejar = cookie::CookieJar::new(&self.signing_key);
        for (key, value) in self.values.iter() {
            cookiejar.signed().add(match value {
                &CookieOrString::Cookie(ref x) => x.clone(),
                &CookieOrString::String(ref x) => {
                    let mut c = cookie::Cookie::new(
                        key.to_owned(),
                        x.to_owned()
                    );
                    c.httponly = true;
                    c.path = Some("/".to_owned());
                    if let Some(ref modifier) = self.cookie_modifier {
                        modifier(&mut c);
                    }
                    c
                }
            });
        }
        res.headers.set(iron::headers::SetCookie(cookiejar.delta()));
    }
}

#[derive(Clone)]
pub struct SignedCookieBackend {
    signing_key: Arc<Vec<u8>>,
    cookie_modifier: Option<Arc<Box<Fn(&mut cookie::Cookie) + Send + Sync + 'static>>>
}

impl SignedCookieBackend {
    pub fn new(signing_key: Vec<u8>) -> Self {
        SignedCookieBackend {
            signing_key: Arc::new(signing_key),
            cookie_modifier: None,
        }
    }

    pub fn set_cookie_modifier<F: Fn(&mut cookie::Cookie) + Send + Sync + 'static>(&mut self, f: F) {
        self.cookie_modifier = Some(Arc::new(Box::new(f)));
    }
}

impl SessionBackend for SignedCookieBackend {
    type S = SignedCookieSession;

    fn from_request(&self, req: &mut Request) -> Self::S {
        let jar = match req.headers.get::<iron::headers::Cookie>() {
            Some(cookies) => cookies.to_cookie_jar(&self.signing_key),
            None => cookie::CookieJar::new(&self.signing_key)
        };

        SignedCookieSession {
            values: jar.signed().iter()
                .map(|c| (c.name.clone(), CookieOrString::Cookie(c)))
                .collect(),
            signing_key: self.signing_key.clone(),
            cookie_modifier: self.cookie_modifier.clone(),
        }
    }

}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::collections::HashMap;
use std::str::FromStr;

use syn;

// A system for specifying properties on items. Annotations are
// given through document comments and parsed by this code.
//
// An annotation is in the form cbindgen:PROPERTY=VALUE
// Where PROPERTY depends on the item
// Where VALUE can be
//  * list - [Item1, Item2, Item3, ...]
//  * atom - Foo
//  * bool - true,false
// Examples:
//  * cbindgen:field-names=[mHandle, mNamespace]
//  * cbindgen:function-postfix=WR_DESTRUCTOR_SAFE

/// A value specified by an annotation.
#[derive(Debug, Clone)]
pub enum AnnotationValue {
    List(Vec<String>),
    Atom(Option<String>),
    Bool(bool),
}

/// A set of annotations specified by a document comment.
#[derive(Debug, Clone)]
pub struct AnnotationSet {
    annotations: HashMap<String, AnnotationValue>
}

impl AnnotationSet {
    pub fn new() -> AnnotationSet {
        AnnotationSet {
            annotations: HashMap::new(),
        }
    }

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

    pub fn load(attrs: &Vec<syn::Attribute>) -> Result<AnnotationSet, String> {
        let mut lines = Vec::new();

        for attr in attrs {
            if attr.style == syn::AttrStyle::Outer &&
               attr.is_sugared_doc {
                if let syn::MetaItem::NameValue(_, syn::Lit::Str(ref comment, _)) = attr.value {
                    let line = comment.trim_left_matches("///").trim();

                    if line.starts_with("cbindgen:") {
                        lines.push(line.to_owned());
                    }
                }
            }
        }

        let mut annotations = HashMap::new();

        // Look at each line for an annotation
        for line in lines {
            // Skip lines that don't start with cbindgen
            if !line.starts_with("cbindgen:") {
                continue;
            }

            // Remove the "cbingen:" prefix
            let annotation = &line[9..];

            // Split the annotation in two
            let parts: Vec<&str> = annotation.split("=")
                                            .map(|x| x.trim())
                                            .collect();

            if parts.len() > 2 {
                return Err(format!("couldn't parse {}", line));
            }

            // Grab the name that this annotation is modifying
            let name = parts[0];

            // If the annotation only has a name, assume it's setting a bool flag
            if parts.len() == 1 {
                annotations.insert(name.to_string(), AnnotationValue::Bool(true));
                continue;
            }

            // Parse the value we're setting the name to
            let value = parts[1];

            if let Some(x) = parse_list(value) {
                annotations.insert(name.to_string(), AnnotationValue::List(x));
                continue;
            }
            if let Ok(x) = value.parse::<bool>() {
                annotations.insert(name.to_string(), AnnotationValue::Bool(x));
                continue;
            }
            annotations.insert(name.to_string(), if value.len() == 0 {
                AnnotationValue::Atom(None)
            } else {
                AnnotationValue::Atom(Some(value.to_string()))
            });
        }

        Ok(AnnotationSet {
            annotations: annotations
        })
    }

    pub fn list(&self, name: &str) -> Option<Vec<String>> {
        match self.annotations.get(name) {
            Some(&AnnotationValue::List(ref x)) => Some(x.clone()),
            _ => None,
        }
    }
    pub fn atom(&self, name: &str) -> Option<Option<String>> {
        match self.annotations.get(name) {
            Some(&AnnotationValue::Atom(ref x)) => Some(x.clone()),
            _ => None,
        }
    }
    pub fn bool(&self, name: &str) -> Option<bool> {
        match self.annotations.get(name) {
            Some(&AnnotationValue::Bool(ref x)) => Some(*x),
            _ => None,
        }
    }

    pub fn parse_atom<T>(&self, name: &str) -> Option<T>
        where T: Default + FromStr
    {
        match self.annotations.get(name) {
            Some(&AnnotationValue::Atom(ref x)) => {
                Some(x.as_ref().map_or(T::default(), |y| { y.parse::<T>().ok().unwrap() }))
            }
            _ => None,
        }
    }
}

/// Parse lists like "[x, y, z]". This is not implemented efficiently or well.
fn parse_list(list: &str) -> Option<Vec<String>> {
    if list.len() < 2 {
        return None;
    }

    match (list.chars().next(), list.chars().last()) {
        (Some('['), Some(']')) => {
            Some(list[1..list.len() - 1].split(',')
                                        .map(|x| x.trim().to_string())
                                        .collect())
        }
        _ => None
    }
}
<commit_msg>Also handle doc strings better in annotations<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::collections::HashMap;
use std::str::FromStr;

use syn;

// A system for specifying properties on items. Annotations are
// given through document comments and parsed by this code.
//
// An annotation is in the form cbindgen:PROPERTY=VALUE
// Where PROPERTY depends on the item
// Where VALUE can be
//  * list - [Item1, Item2, Item3, ...]
//  * atom - Foo
//  * bool - true,false
// Examples:
//  * cbindgen:field-names=[mHandle, mNamespace]
//  * cbindgen:function-postfix=WR_DESTRUCTOR_SAFE

/// A value specified by an annotation.
#[derive(Debug, Clone)]
pub enum AnnotationValue {
    List(Vec<String>),
    Atom(Option<String>),
    Bool(bool),
}

/// A set of annotations specified by a document comment.
#[derive(Debug, Clone)]
pub struct AnnotationSet {
    annotations: HashMap<String, AnnotationValue>
}

impl AnnotationSet {
    pub fn new() -> AnnotationSet {
        AnnotationSet {
            annotations: HashMap::new(),
        }
    }

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

    pub fn load(attrs: &Vec<syn::Attribute>) -> Result<AnnotationSet, String> {
        let mut lines = Vec::new();

        for attr in attrs {
            if attr.style == syn::AttrStyle::Outer {
                if let syn::MetaItem::NameValue(
                    ref name, syn::Lit::Str(ref comment, _)) = attr.value
                {
                    if &*name == "doc" {
                        let line = comment.trim_left_matches("///").trim();
                        if line.starts_with("cbindgen:") {
                            lines.push(line.to_owned());
                        }
                    }
                }
            }
        }

        let mut annotations = HashMap::new();

        // Look at each line for an annotation
        for line in lines {
            // Skip lines that don't start with cbindgen
            if !line.starts_with("cbindgen:") {
                continue;
            }

            // Remove the "cbingen:" prefix
            let annotation = &line[9..];

            // Split the annotation in two
            let parts: Vec<&str> = annotation.split("=")
                                            .map(|x| x.trim())
                                            .collect();

            if parts.len() > 2 {
                return Err(format!("couldn't parse {}", line));
            }

            // Grab the name that this annotation is modifying
            let name = parts[0];

            // If the annotation only has a name, assume it's setting a bool flag
            if parts.len() == 1 {
                annotations.insert(name.to_string(), AnnotationValue::Bool(true));
                continue;
            }

            // Parse the value we're setting the name to
            let value = parts[1];

            if let Some(x) = parse_list(value) {
                annotations.insert(name.to_string(), AnnotationValue::List(x));
                continue;
            }
            if let Ok(x) = value.parse::<bool>() {
                annotations.insert(name.to_string(), AnnotationValue::Bool(x));
                continue;
            }
            annotations.insert(name.to_string(), if value.len() == 0 {
                AnnotationValue::Atom(None)
            } else {
                AnnotationValue::Atom(Some(value.to_string()))
            });
        }

        Ok(AnnotationSet {
            annotations: annotations
        })
    }

    pub fn list(&self, name: &str) -> Option<Vec<String>> {
        match self.annotations.get(name) {
            Some(&AnnotationValue::List(ref x)) => Some(x.clone()),
            _ => None,
        }
    }
    pub fn atom(&self, name: &str) -> Option<Option<String>> {
        match self.annotations.get(name) {
            Some(&AnnotationValue::Atom(ref x)) => Some(x.clone()),
            _ => None,
        }
    }
    pub fn bool(&self, name: &str) -> Option<bool> {
        match self.annotations.get(name) {
            Some(&AnnotationValue::Bool(ref x)) => Some(*x),
            _ => None,
        }
    }

    pub fn parse_atom<T>(&self, name: &str) -> Option<T>
        where T: Default + FromStr
    {
        match self.annotations.get(name) {
            Some(&AnnotationValue::Atom(ref x)) => {
                Some(x.as_ref().map_or(T::default(), |y| { y.parse::<T>().ok().unwrap() }))
            }
            _ => None,
        }
    }
}

/// Parse lists like "[x, y, z]". This is not implemented efficiently or well.
fn parse_list(list: &str) -> Option<Vec<String>> {
    if list.len() < 2 {
        return None;
    }

    match (list.chars().next(), list.chars().last()) {
        (Some('['), Some(']')) => {
            Some(list[1..list.len() - 1].split(',')
                                        .map(|x| x.trim().to_string())
                                        .collect())
        }
        _ => None
    }
}
<|endoftext|>


<commit_before>//! A solver for dataflow problems.

use std::borrow::BorrowMut;
use std::ffi::OsString;
use std::path::PathBuf;

use rustc_ast as ast;
use rustc_data_structures::work_queue::WorkQueue;
use rustc_graphviz as dot;
use rustc_hir::def_id::DefId;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::mir::{self, traversal, BasicBlock};
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::{sym, Symbol};

use super::fmt::DebugWithContext;
use super::graphviz;
use super::{
    visit_results, Analysis, Direction, GenKill, GenKillAnalysis, GenKillSet, JoinSemiLattice,
    ResultsCursor, ResultsVisitor,
};
use crate::util::pretty::{create_dump_file, dump_enabled};

/// A dataflow analysis that has converged to fixpoint.
pub struct Results<'tcx, A>
where
    A: Analysis<'tcx>,
{
    pub analysis: A,
    pub(super) entry_sets: IndexVec<BasicBlock, A::Domain>,
}

impl<A> Results<'tcx, A>
where
    A: Analysis<'tcx>,
{
    /// Creates a `ResultsCursor` that can inspect these `Results`.
    pub fn into_results_cursor(self, body: &'mir mir::Body<'tcx>) -> ResultsCursor<'mir, 'tcx, A> {
        ResultsCursor::new(body, self)
    }

    /// Gets the dataflow state for the given block.
    pub fn entry_set_for_block(&self, block: BasicBlock) -> &A::Domain {
        &self.entry_sets[block]
    }

    pub fn visit_with(
        &self,
        body: &'mir mir::Body<'tcx>,
        blocks: impl IntoIterator<Item = BasicBlock>,
        vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>,
    ) {
        visit_results(body, blocks, self, vis)
    }

    pub fn visit_reachable_with(
        &self,
        body: &'mir mir::Body<'tcx>,
        vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>,
    ) {
        let blocks = mir::traversal::reachable(body);
        visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
    }

    pub fn visit_in_rpo_with(
        &self,
        body: &'mir mir::Body<'tcx>,
        vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>,
    ) {
        let blocks = mir::traversal::reverse_postorder(body);
        visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
    }
}

/// A solver for dataflow problems.
pub struct Engine<'a, 'tcx, A>
where
    A: Analysis<'tcx>,
{
    tcx: TyCtxt<'tcx>,
    body: &'a mir::Body<'tcx>,
    dead_unwinds: Option<&'a BitSet<BasicBlock>>,
    entry_sets: IndexVec<BasicBlock, A::Domain>,
    pass_name: Option<&'static str>,
    analysis: A,

    /// Cached, cumulative transfer functions for each block.
    //
    // FIXME(ecstaticmorse): This boxed `Fn` trait object is invoked inside a tight loop for
    // gen/kill problems on cyclic CFGs. This is not ideal, but it doesn't seem to degrade
    // performance in practice. I've tried a few ways to avoid this, but they have downsides. See
    // the message for the commit that added this FIXME for more information.
    apply_trans_for_block: Option<Box<dyn Fn(BasicBlock, &mut A::Domain)>>,
}

impl<A, D, T> Engine<'a, 'tcx, A>
where
    A: GenKillAnalysis<'tcx, Idx = T, Domain = D>,
    D: Clone + JoinSemiLattice + GenKill<T> + BorrowMut<BitSet<T>>,
    T: Idx,
{
    /// Creates a new `Engine` to solve a gen-kill dataflow problem.
    pub fn new_gen_kill(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, analysis: A) -> Self {
        // If there are no back-edges in the control-flow graph, we only ever need to apply the
        // transfer function for each block exactly once (assuming that we process blocks in RPO).
        //
        // In this case, there's no need to compute the block transfer functions ahead of time.
        if !body.is_cfg_cyclic() {
            return Self::new(tcx, body, analysis, None);
        }

        // Otherwise, compute and store the cumulative transfer function for each block.

        let identity = GenKillSet::identity(analysis.bottom_value(body).borrow().domain_size());
        let mut trans_for_block = IndexVec::from_elem(identity, body.basic_blocks());

        for (block, block_data) in body.basic_blocks().iter_enumerated() {
            let trans = &mut trans_for_block[block];
            A::Direction::gen_kill_effects_in_block(&analysis, trans, block, block_data);
        }

        let apply_trans = Box::new(move |bb: BasicBlock, state: &mut A::Domain| {
            trans_for_block[bb].apply(state.borrow_mut());
        });

        Self::new(tcx, body, analysis, Some(apply_trans as Box<_>))
    }
}

impl<A, D> Engine<'a, 'tcx, A>
where
    A: Analysis<'tcx, Domain = D>,
    D: Clone + JoinSemiLattice,
{
    /// Creates a new `Engine` to solve a dataflow problem with an arbitrary transfer
    /// function.
    ///
    /// Gen-kill problems should use `new_gen_kill`, which will coalesce transfer functions for
    /// better performance.
    pub fn new_generic(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, analysis: A) -> Self {
        Self::new(tcx, body, analysis, None)
    }

    fn new(
        tcx: TyCtxt<'tcx>,
        body: &'a mir::Body<'tcx>,
        analysis: A,
        apply_trans_for_block: Option<Box<dyn Fn(BasicBlock, &mut A::Domain)>>,
    ) -> Self {
        let bottom_value = analysis.bottom_value(body);
        let mut entry_sets = IndexVec::from_elem(bottom_value.clone(), body.basic_blocks());
        analysis.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]);

        if A::Direction::is_backward() && entry_sets[mir::START_BLOCK] != bottom_value {
            bug!("`initialize_start_block` is not yet supported for backward dataflow analyses");
        }

        Engine {
            analysis,
            tcx,
            body,
            dead_unwinds: None,
            pass_name: None,
            entry_sets,
            apply_trans_for_block,
        }
    }

    /// Signals that we do not want dataflow state to propagate across unwind edges for these
    /// `BasicBlock`s.
    ///
    /// You must take care that `dead_unwinds` does not contain a `BasicBlock` that *can* actually
    /// unwind during execution. Otherwise, your dataflow results will not be correct.
    pub fn dead_unwinds(mut self, dead_unwinds: &'a BitSet<BasicBlock>) -> Self {
        self.dead_unwinds = Some(dead_unwinds);
        self
    }

    /// Adds an identifier to the graphviz output for this particular run of a dataflow analysis.
    ///
    /// Some analyses are run multiple times in the compilation pipeline. Give them a `pass_name`
    /// to differentiate them. Otherwise, only the results for the latest run will be saved.
    pub fn pass_name(mut self, name: &'static str) -> Self {
        self.pass_name = Some(name);
        self
    }

    /// Computes the fixpoint for this dataflow problem and returns it.
    pub fn iterate_to_fixpoint(self) -> Results<'tcx, A>
    where
        A::Domain: DebugWithContext<A>,
    {
        let Engine {
            analysis,
            body,
            dead_unwinds,
            mut entry_sets,
            tcx,
            apply_trans_for_block,
            pass_name,
            ..
        } = self;

        let mut dirty_queue: WorkQueue<BasicBlock> =
            WorkQueue::with_none(body.basic_blocks().len());

        if A::Direction::is_forward() {
            for (bb, _) in traversal::reverse_postorder(body) {
                dirty_queue.insert(bb);
            }
        } else {
            // Reverse post-order on the reverse CFG may generate a better iteration order for
            // backward dataflow analyses, but probably not enough to matter.
            for (bb, _) in traversal::postorder(body) {
                dirty_queue.insert(bb);
            }
        }

        let mut state = analysis.bottom_value(body);
        while let Some(bb) = dirty_queue.pop() {
            let bb_data = &body[bb];

            // Apply the block transfer function, using the cached one if it exists.
            state.clone_from(&entry_sets[bb]);
            match &apply_trans_for_block {
                Some(apply) => apply(bb, &mut state),
                None => A::Direction::apply_effects_in_block(&analysis, &mut state, bb, bb_data),
            }

            A::Direction::join_state_into_successors_of(
                &analysis,
                tcx,
                body,
                dead_unwinds,
                &mut state,
                (bb, bb_data),
                |target: BasicBlock, state: &A::Domain| {
                    let set_changed = entry_sets[target].join(state);
                    if set_changed {
                        dirty_queue.insert(target);
                    }
                },
            );
        }

        let results = Results { analysis, entry_sets };

        let res = write_graphviz_results(tcx, &body, &results, pass_name);
        if let Err(e) = res {
            warn!("Failed to write graphviz dataflow results: {}", e);
        }

        results
    }
}

// Graphviz

/// Writes a DOT file containing the results of a dataflow analysis if the user requested it via
/// `rustc_mir` attributes.
fn write_graphviz_results<A>(
    tcx: TyCtxt<'tcx>,
    body: &mir::Body<'tcx>,
    results: &Results<'tcx, A>,
    pass_name: Option<&'static str>,
) -> std::io::Result<()>
where
    A: Analysis<'tcx>,
    A::Domain: DebugWithContext<A>,
{
    use std::fs;
    use std::io::{self, Write};

    let def_id = body.source.def_id();
    let attrs = match RustcMirAttrs::parse(tcx, def_id) {
        Ok(attrs) => attrs,

        // Invalid `rustc_mir` attrs are reported in `RustcMirAttrs::parse`
        Err(()) => return Ok(()),
    };

    let mut file = match attrs.output_path(A::NAME) {
        Some(path) => {
            debug!("printing dataflow results for {:?} to {}", def_id, path.display());
            if let Some(parent) = path.parent() {
                fs::create_dir_all(parent)?;
            }
            io::BufWriter::new(fs::File::create(&path)?)
        }

        None if tcx.sess.opts.debugging_opts.dump_mir_dataflow
            && dump_enabled(tcx, A::NAME, def_id) =>
        {
            create_dump_file(
                tcx,
                ".dot",
                None,
                A::NAME,
                &pass_name.unwrap_or("-----"),
                body.source,
            )?
        }

        _ => return Ok(()),
    };

    let style = match attrs.formatter {
        Some(sym::two_phase) => graphviz::OutputStyle::BeforeAndAfter,
        _ => graphviz::OutputStyle::AfterOnly,
    };

    let mut buf = Vec::new();

    let graphviz = graphviz::Formatter::new(body, results, style);
    let mut render_opts =
        vec![dot::RenderOption::Fontname(tcx.sess.opts.debugging_opts.graphviz_font.clone())];
    if tcx.sess.opts.debugging_opts.graphviz_dark_mode {
        render_opts.push(dot::RenderOption::DarkTheme);
    }
    dot::render_opts(&graphviz, &mut buf, &render_opts)?;

    file.write_all(&buf)?;

    Ok(())
}

#[derive(Default)]
struct RustcMirAttrs {
    basename_and_suffix: Option<PathBuf>,
    formatter: Option<Symbol>,
}

impl RustcMirAttrs {
    fn parse(tcx: TyCtxt<'tcx>, def_id: DefId) -> Result<Self, ()> {
        let attrs = tcx.get_attrs(def_id);

        let mut result = Ok(());
        let mut ret = RustcMirAttrs::default();

        let rustc_mir_attrs = attrs
            .iter()
            .filter(|attr| tcx.sess.check_name(attr, sym::rustc_mir))
            .flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter()));

        for attr in rustc_mir_attrs {
            let attr_result = if attr.has_name(sym::borrowck_graphviz_postflow) {
                Self::set_field(&mut ret.basename_and_suffix, tcx, &attr, |s| {
                    let path = PathBuf::from(s.to_string());
                    match path.file_name() {
                        Some(_) => Ok(path),
                        None => {
                            tcx.sess.span_err(attr.span(), "path must end in a filename");
                            Err(())
                        }
                    }
                })
            } else if attr.has_name(sym::borrowck_graphviz_format) {
                Self::set_field(&mut ret.formatter, tcx, &attr, |s| match s {
                    sym::gen_kill | sym::two_phase => Ok(s),
                    _ => {
                        tcx.sess.span_err(attr.span(), "unknown formatter");
                        Err(())
                    }
                })
            } else {
                Ok(())
            };

            result = result.and(attr_result);
        }

        result.map(|()| ret)
    }

    fn set_field<T>(
        field: &mut Option<T>,
        tcx: TyCtxt<'tcx>,
        attr: &ast::NestedMetaItem,
        mapper: impl FnOnce(Symbol) -> Result<T, ()>,
    ) -> Result<(), ()> {
        if field.is_some() {
            tcx.sess
                .span_err(attr.span(), &format!("duplicate values for `{}`", attr.name_or_empty()));

            return Err(());
        }

        if let Some(s) = attr.value_str() {
            *field = Some(mapper(s)?);
            Ok(())
        } else {
            tcx.sess
                .span_err(attr.span(), &format!("`{}` requires an argument", attr.name_or_empty()));
            Err(())
        }
    }

    /// Returns the path where dataflow results should be written, or `None`
    /// `borrowck_graphviz_postflow` was not specified.
    ///
    /// This performs the following transformation to the argument of `borrowck_graphviz_postflow`:
    ///
    /// "path/suffix.dot" -> "path/analysis_name_suffix.dot"
    fn output_path(&self, analysis_name: &str) -> Option<PathBuf> {
        let mut ret = self.basename_and_suffix.as_ref().cloned()?;
        let suffix = ret.file_name().unwrap(); // Checked when parsing attrs

        let mut file_name: OsString = analysis_name.into();
        file_name.push("_");
        file_name.push(suffix);
        ret.set_file_name(file_name);

        Some(ret)
    }
}
<commit_msg>Print to `stderr` when a graphviz file can't be written<commit_after>//! A solver for dataflow problems.

use std::borrow::BorrowMut;
use std::ffi::OsString;
use std::path::PathBuf;

use rustc_ast as ast;
use rustc_data_structures::work_queue::WorkQueue;
use rustc_graphviz as dot;
use rustc_hir::def_id::DefId;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::mir::{self, traversal, BasicBlock};
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::{sym, Symbol};

use super::fmt::DebugWithContext;
use super::graphviz;
use super::{
    visit_results, Analysis, Direction, GenKill, GenKillAnalysis, GenKillSet, JoinSemiLattice,
    ResultsCursor, ResultsVisitor,
};
use crate::util::pretty::{create_dump_file, dump_enabled};

/// A dataflow analysis that has converged to fixpoint.
pub struct Results<'tcx, A>
where
    A: Analysis<'tcx>,
{
    pub analysis: A,
    pub(super) entry_sets: IndexVec<BasicBlock, A::Domain>,
}

impl<A> Results<'tcx, A>
where
    A: Analysis<'tcx>,
{
    /// Creates a `ResultsCursor` that can inspect these `Results`.
    pub fn into_results_cursor(self, body: &'mir mir::Body<'tcx>) -> ResultsCursor<'mir, 'tcx, A> {
        ResultsCursor::new(body, self)
    }

    /// Gets the dataflow state for the given block.
    pub fn entry_set_for_block(&self, block: BasicBlock) -> &A::Domain {
        &self.entry_sets[block]
    }

    pub fn visit_with(
        &self,
        body: &'mir mir::Body<'tcx>,
        blocks: impl IntoIterator<Item = BasicBlock>,
        vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>,
    ) {
        visit_results(body, blocks, self, vis)
    }

    pub fn visit_reachable_with(
        &self,
        body: &'mir mir::Body<'tcx>,
        vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>,
    ) {
        let blocks = mir::traversal::reachable(body);
        visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
    }

    pub fn visit_in_rpo_with(
        &self,
        body: &'mir mir::Body<'tcx>,
        vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>,
    ) {
        let blocks = mir::traversal::reverse_postorder(body);
        visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
    }
}

/// A solver for dataflow problems.
pub struct Engine<'a, 'tcx, A>
where
    A: Analysis<'tcx>,
{
    tcx: TyCtxt<'tcx>,
    body: &'a mir::Body<'tcx>,
    dead_unwinds: Option<&'a BitSet<BasicBlock>>,
    entry_sets: IndexVec<BasicBlock, A::Domain>,
    pass_name: Option<&'static str>,
    analysis: A,

    /// Cached, cumulative transfer functions for each block.
    //
    // FIXME(ecstaticmorse): This boxed `Fn` trait object is invoked inside a tight loop for
    // gen/kill problems on cyclic CFGs. This is not ideal, but it doesn't seem to degrade
    // performance in practice. I've tried a few ways to avoid this, but they have downsides. See
    // the message for the commit that added this FIXME for more information.
    apply_trans_for_block: Option<Box<dyn Fn(BasicBlock, &mut A::Domain)>>,
}

impl<A, D, T> Engine<'a, 'tcx, A>
where
    A: GenKillAnalysis<'tcx, Idx = T, Domain = D>,
    D: Clone + JoinSemiLattice + GenKill<T> + BorrowMut<BitSet<T>>,
    T: Idx,
{
    /// Creates a new `Engine` to solve a gen-kill dataflow problem.
    pub fn new_gen_kill(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, analysis: A) -> Self {
        // If there are no back-edges in the control-flow graph, we only ever need to apply the
        // transfer function for each block exactly once (assuming that we process blocks in RPO).
        //
        // In this case, there's no need to compute the block transfer functions ahead of time.
        if !body.is_cfg_cyclic() {
            return Self::new(tcx, body, analysis, None);
        }

        // Otherwise, compute and store the cumulative transfer function for each block.

        let identity = GenKillSet::identity(analysis.bottom_value(body).borrow().domain_size());
        let mut trans_for_block = IndexVec::from_elem(identity, body.basic_blocks());

        for (block, block_data) in body.basic_blocks().iter_enumerated() {
            let trans = &mut trans_for_block[block];
            A::Direction::gen_kill_effects_in_block(&analysis, trans, block, block_data);
        }

        let apply_trans = Box::new(move |bb: BasicBlock, state: &mut A::Domain| {
            trans_for_block[bb].apply(state.borrow_mut());
        });

        Self::new(tcx, body, analysis, Some(apply_trans as Box<_>))
    }
}

impl<A, D> Engine<'a, 'tcx, A>
where
    A: Analysis<'tcx, Domain = D>,
    D: Clone + JoinSemiLattice,
{
    /// Creates a new `Engine` to solve a dataflow problem with an arbitrary transfer
    /// function.
    ///
    /// Gen-kill problems should use `new_gen_kill`, which will coalesce transfer functions for
    /// better performance.
    pub fn new_generic(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, analysis: A) -> Self {
        Self::new(tcx, body, analysis, None)
    }

    fn new(
        tcx: TyCtxt<'tcx>,
        body: &'a mir::Body<'tcx>,
        analysis: A,
        apply_trans_for_block: Option<Box<dyn Fn(BasicBlock, &mut A::Domain)>>,
    ) -> Self {
        let bottom_value = analysis.bottom_value(body);
        let mut entry_sets = IndexVec::from_elem(bottom_value.clone(), body.basic_blocks());
        analysis.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]);

        if A::Direction::is_backward() && entry_sets[mir::START_BLOCK] != bottom_value {
            bug!("`initialize_start_block` is not yet supported for backward dataflow analyses");
        }

        Engine {
            analysis,
            tcx,
            body,
            dead_unwinds: None,
            pass_name: None,
            entry_sets,
            apply_trans_for_block,
        }
    }

    /// Signals that we do not want dataflow state to propagate across unwind edges for these
    /// `BasicBlock`s.
    ///
    /// You must take care that `dead_unwinds` does not contain a `BasicBlock` that *can* actually
    /// unwind during execution. Otherwise, your dataflow results will not be correct.
    pub fn dead_unwinds(mut self, dead_unwinds: &'a BitSet<BasicBlock>) -> Self {
        self.dead_unwinds = Some(dead_unwinds);
        self
    }

    /// Adds an identifier to the graphviz output for this particular run of a dataflow analysis.
    ///
    /// Some analyses are run multiple times in the compilation pipeline. Give them a `pass_name`
    /// to differentiate them. Otherwise, only the results for the latest run will be saved.
    pub fn pass_name(mut self, name: &'static str) -> Self {
        self.pass_name = Some(name);
        self
    }

    /// Computes the fixpoint for this dataflow problem and returns it.
    pub fn iterate_to_fixpoint(self) -> Results<'tcx, A>
    where
        A::Domain: DebugWithContext<A>,
    {
        let Engine {
            analysis,
            body,
            dead_unwinds,
            mut entry_sets,
            tcx,
            apply_trans_for_block,
            pass_name,
            ..
        } = self;

        let mut dirty_queue: WorkQueue<BasicBlock> =
            WorkQueue::with_none(body.basic_blocks().len());

        if A::Direction::is_forward() {
            for (bb, _) in traversal::reverse_postorder(body) {
                dirty_queue.insert(bb);
            }
        } else {
            // Reverse post-order on the reverse CFG may generate a better iteration order for
            // backward dataflow analyses, but probably not enough to matter.
            for (bb, _) in traversal::postorder(body) {
                dirty_queue.insert(bb);
            }
        }

        let mut state = analysis.bottom_value(body);
        while let Some(bb) = dirty_queue.pop() {
            let bb_data = &body[bb];

            // Apply the block transfer function, using the cached one if it exists.
            state.clone_from(&entry_sets[bb]);
            match &apply_trans_for_block {
                Some(apply) => apply(bb, &mut state),
                None => A::Direction::apply_effects_in_block(&analysis, &mut state, bb, bb_data),
            }

            A::Direction::join_state_into_successors_of(
                &analysis,
                tcx,
                body,
                dead_unwinds,
                &mut state,
                (bb, bb_data),
                |target: BasicBlock, state: &A::Domain| {
                    let set_changed = entry_sets[target].join(state);
                    if set_changed {
                        dirty_queue.insert(target);
                    }
                },
            );
        }

        let results = Results { analysis, entry_sets };

        let res = write_graphviz_results(tcx, &body, &results, pass_name);
        if let Err(e) = res {
            error!("Failed to write graphviz dataflow results: {}", e);
        }

        results
    }
}

// Graphviz

/// Writes a DOT file containing the results of a dataflow analysis if the user requested it via
/// `rustc_mir` attributes.
fn write_graphviz_results<A>(
    tcx: TyCtxt<'tcx>,
    body: &mir::Body<'tcx>,
    results: &Results<'tcx, A>,
    pass_name: Option<&'static str>,
) -> std::io::Result<()>
where
    A: Analysis<'tcx>,
    A::Domain: DebugWithContext<A>,
{
    use std::fs;
    use std::io::{self, Write};

    let def_id = body.source.def_id();
    let attrs = match RustcMirAttrs::parse(tcx, def_id) {
        Ok(attrs) => attrs,

        // Invalid `rustc_mir` attrs are reported in `RustcMirAttrs::parse`
        Err(()) => return Ok(()),
    };

    let mut file = match attrs.output_path(A::NAME) {
        Some(path) => {
            debug!("printing dataflow results for {:?} to {}", def_id, path.display());
            if let Some(parent) = path.parent() {
                fs::create_dir_all(parent)?;
            }
            io::BufWriter::new(fs::File::create(&path)?)
        }

        None if tcx.sess.opts.debugging_opts.dump_mir_dataflow
            && dump_enabled(tcx, A::NAME, def_id) =>
        {
            create_dump_file(
                tcx,
                ".dot",
                None,
                A::NAME,
                &pass_name.unwrap_or("-----"),
                body.source,
            )?
        }

        _ => return Ok(()),
    };

    let style = match attrs.formatter {
        Some(sym::two_phase) => graphviz::OutputStyle::BeforeAndAfter,
        _ => graphviz::OutputStyle::AfterOnly,
    };

    let mut buf = Vec::new();

    let graphviz = graphviz::Formatter::new(body, results, style);
    let mut render_opts =
        vec![dot::RenderOption::Fontname(tcx.sess.opts.debugging_opts.graphviz_font.clone())];
    if tcx.sess.opts.debugging_opts.graphviz_dark_mode {
        render_opts.push(dot::RenderOption::DarkTheme);
    }
    dot::render_opts(&graphviz, &mut buf, &render_opts)?;

    file.write_all(&buf)?;

    Ok(())
}

#[derive(Default)]
struct RustcMirAttrs {
    basename_and_suffix: Option<PathBuf>,
    formatter: Option<Symbol>,
}

impl RustcMirAttrs {
    fn parse(tcx: TyCtxt<'tcx>, def_id: DefId) -> Result<Self, ()> {
        let attrs = tcx.get_attrs(def_id);

        let mut result = Ok(());
        let mut ret = RustcMirAttrs::default();

        let rustc_mir_attrs = attrs
            .iter()
            .filter(|attr| tcx.sess.check_name(attr, sym::rustc_mir))
            .flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter()));

        for attr in rustc_mir_attrs {
            let attr_result = if attr.has_name(sym::borrowck_graphviz_postflow) {
                Self::set_field(&mut ret.basename_and_suffix, tcx, &attr, |s| {
                    let path = PathBuf::from(s.to_string());
                    match path.file_name() {
                        Some(_) => Ok(path),
                        None => {
                            tcx.sess.span_err(attr.span(), "path must end in a filename");
                            Err(())
                        }
                    }
                })
            } else if attr.has_name(sym::borrowck_graphviz_format) {
                Self::set_field(&mut ret.formatter, tcx, &attr, |s| match s {
                    sym::gen_kill | sym::two_phase => Ok(s),
                    _ => {
                        tcx.sess.span_err(attr.span(), "unknown formatter");
                        Err(())
                    }
                })
            } else {
                Ok(())
            };

            result = result.and(attr_result);
        }

        result.map(|()| ret)
    }

    fn set_field<T>(
        field: &mut Option<T>,
        tcx: TyCtxt<'tcx>,
        attr: &ast::NestedMetaItem,
        mapper: impl FnOnce(Symbol) -> Result<T, ()>,
    ) -> Result<(), ()> {
        if field.is_some() {
            tcx.sess
                .span_err(attr.span(), &format!("duplicate values for `{}`", attr.name_or_empty()));

            return Err(());
        }

        if let Some(s) = attr.value_str() {
            *field = Some(mapper(s)?);
            Ok(())
        } else {
            tcx.sess
                .span_err(attr.span(), &format!("`{}` requires an argument", attr.name_or_empty()));
            Err(())
        }
    }

    /// Returns the path where dataflow results should be written, or `None`
    /// `borrowck_graphviz_postflow` was not specified.
    ///
    /// This performs the following transformation to the argument of `borrowck_graphviz_postflow`:
    ///
    /// "path/suffix.dot" -> "path/analysis_name_suffix.dot"
    fn output_path(&self, analysis_name: &str) -> Option<PathBuf> {
        let mut ret = self.basename_and_suffix.as_ref().cloned()?;
        let suffix = ret.file_name().unwrap(); // Checked when parsing attrs

        let mut file_name: OsString = analysis_name.into();
        file_name.push("_");
        file_name.push(suffix);
        ret.set_file_name(file_name);

        Some(ret)
    }
}
<|endoftext|>