<commit_before>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::HashSet;

use itertools::Itertools;
use syn::{
    punctuated::Punctuated, Binding, Expr, ExprAssign, ExprAssignOp, ExprAwait, ExprBinary,
    ExprBox, ExprBreak, ExprCast, ExprField, ExprGroup, ExprLet, ExprParen, ExprReference, ExprTry,
    ExprType, ExprUnary, ImplItem, Item, Pat, PatBox, PatReference, PatSlice, PatTuple, Path,
    ReturnType, Stmt, TraitItem, Type, TypeArray, TypeGroup, TypeParamBound, TypeParen, TypePtr,
    TypeReference, TypeSlice,
};

#[derive(Default)]
pub(super) struct CppList(pub(super) HashSet<String>);

impl CppList {
    pub(super) fn search_item(&mut self, item: &Item) {
        match item {
            Item::Fn(fun) => {
                for stmt in &fun.block.stmts {
                    self.search_stmt(stmt)
                }
                self.search_return_type(&fun.sig.output);
                for i in &fun.sig.inputs {
                    match i {
                        syn::FnArg::Receiver(_) => {}
                        syn::FnArg::Typed(pt) => {
                            self.search_pat(&pt.pat);
                            self.search_type(&pt.ty);
                        }
                    }
                }
            }
            Item::Impl(imp) => {
                for item in &imp.items {
                    self.search_impl_item(item)
                }
            }
            Item::Mod(md) => {
                if let Some((_, items)) = &md.content {
                    for item in items {
                        self.search_item(item)
                    }
                }
            }
            Item::Trait(tr) => {
                for item in &tr.items {
                    self.search_trait_item(item)
                }
            }
            _ => {}
        }
    }

    fn search_path(&mut self, path: &Path) {
        let mut seg_iter = path.segments.iter();
        if let Some(first_seg) = seg_iter.next() {
            if first_seg.ident == "ffi" {
                self.0
                    .insert(seg_iter.map(|seg| seg.ident.to_string()).join("::"));
            }
        }
        for seg in path.segments.iter() {
            self.search_path_arguments(&seg.arguments);
        }
    }

    fn search_trait_item(&mut self, itm: &TraitItem) {
        if let TraitItem::Method(itm) = itm {
            if let Some(block) = &itm.default {
                self.search_stmts(block.stmts.iter())
            }
        }
    }

    fn search_stmts<'a>(&mut self, stmts: impl Iterator<Item = &'a Stmt>) {
        for stmt in stmts {
            self.search_stmt(stmt)
        }
    }

    fn search_stmt(&mut self, stmt: &Stmt) {
        match stmt {
            Stmt::Local(lcl) => {
                if let Some((_, expr)) = &lcl.init {
                    self.search_expr(expr)
                }
                self.search_pat(&lcl.pat);
            }
            Stmt::Item(itm) => self.search_item(itm),
            Stmt::Expr(exp) | Stmt::Semi(exp, _) => self.search_expr(exp),
        }
    }

    fn search_expr(&mut self, expr: &Expr) {
        match expr {
            Expr::Path(exp) => {
                self.search_path(&exp.path);
            }
            Expr::Macro(_) => {}
            Expr::Array(array) => self.search_exprs(array.elems.iter()),
            Expr::Assign(ExprAssign { left, right, .. })
            | Expr::AssignOp(ExprAssignOp { left, right, .. })
            | Expr::Binary(ExprBinary { left, right, .. }) => {
                self.search_expr(left);
                self.search_expr(right);
            }
            Expr::Async(ass) => self.search_stmts(ass.block.stmts.iter()),
            Expr::Await(ExprAwait { base, .. }) | Expr::Field(ExprField { base, .. }) => {
                self.search_expr(base)
            }
            Expr::Block(blck) => self.search_stmts(blck.block.stmts.iter()),
            Expr::Box(ExprBox { expr, .. })
            | Expr::Break(ExprBreak {
                expr: Some(expr), ..
            })
            | Expr::Cast(ExprCast { expr, .. })
            | Expr::Group(ExprGroup { expr, .. })
            | Expr::Paren(ExprParen { expr, .. })
            | Expr::Reference(ExprReference { expr, .. })
            | Expr::Try(ExprTry { expr, .. })
            | Expr::Type(ExprType { expr, .. })
            | Expr::Unary(ExprUnary { expr, .. }) => self.search_expr(expr),
            Expr::Call(exc) => {
                self.search_expr(&exc.func);
                self.search_exprs(exc.args.iter());
            }
            Expr::Closure(cls) => self.search_expr(&cls.body),
            Expr::Continue(_)
            | Expr::Lit(_)
            | Expr::Break(ExprBreak { expr: None, .. })
            | Expr::Verbatim(_) => {}
            Expr::ForLoop(fl) => {
                self.search_expr(&fl.expr);
                self.search_stmts(fl.body.stmts.iter());
            }
            Expr::If(exif) => {
                self.search_expr(&exif.cond);
                self.search_stmts(exif.then_branch.stmts.iter());
                if let Some((_, else_branch)) = &exif.else_branch {
                    self.search_expr(else_branch);
                }
            }
            Expr::Index(exidx) => {
                self.search_expr(&exidx.expr);
                self.search_expr(&exidx.index);
            }
            Expr::Let(ExprLet { expr, pat, .. }) => {
                self.search_expr(expr);
                self.search_pat(pat);
            }
            Expr::Loop(exloo) => self.search_stmts(exloo.body.stmts.iter()),
            Expr::Match(exm) => {
                self.search_expr(&exm.expr);
                for a in &exm.arms {
                    self.search_expr(&a.body);
                    if let Some((_, guard)) = &a.guard {
                        self.search_expr(guard);
                    }
                }
            }
            Expr::MethodCall(mtc) => {
                self.search_expr(&mtc.receiver);
                self.search_exprs(mtc.args.iter());
            }
            Expr::Range(exr) => {
                self.search_option_expr(&exr.from);
                self.search_option_expr(&exr.to);
            }
            Expr::Repeat(exr) => {
                self.search_expr(&exr.expr);
                self.search_expr(&exr.len);
            }
            Expr::Return(exret) => {
                if let Some(expr) = &exret.expr {
                    self.search_expr(expr);
                }
            }
            Expr::Struct(exst) => {
                for f in &exst.fields {
                    self.search_expr(&f.expr);
                }
                self.search_option_expr(&exst.rest);
            }
            Expr::TryBlock(extb) => self.search_stmts(extb.block.stmts.iter()),
            Expr::Tuple(ext) => self.search_exprs(ext.elems.iter()),
            Expr::Unsafe(exs) => self.search_stmts(exs.block.stmts.iter()),
            Expr::While(exw) => {
                self.search_expr(&exw.cond);
                self.search_stmts(exw.body.stmts.iter());
            }
            Expr::Yield(exy) => self.search_option_expr(&exy.expr),
            Expr::__TestExhaustive(_) => {}
        }
    }

    fn search_option_expr(&mut self, expr: &Option<Box<Expr>>) {
        if let Some(expr) = &expr {
            self.search_expr(expr);
        }
    }

    fn search_exprs<'a>(&mut self, exprs: impl Iterator<Item = &'a Expr>) {
        for e in exprs {
            self.search_expr(e);
        }
    }

    fn search_impl_item(&mut self, impl_item: &ImplItem) {
        if let ImplItem::Method(itm) = impl_item {
            for stmt in &itm.block.stmts {
                self.search_stmt(stmt)
            }
        }
    }

    fn search_pat(&mut self, pat: &Pat) {
        match pat {
            Pat::Box(PatBox { pat, .. }) | Pat::Reference(PatReference { pat, .. }) => {
                self.search_pat(pat)
            }
            Pat::Ident(_) | Pat::Lit(_) | Pat::Macro(_) | Pat::Range(_) | Pat::Rest(_) => {}
            Pat::Or(pator) => {
                for case in &pator.cases {
                    self.search_pat(case);
                }
            }
            Pat::Path(pp) => self.search_path(&pp.path),
            Pat::Slice(PatSlice { elems, .. }) | Pat::Tuple(PatTuple { elems, .. }) => {
                for case in elems {
                    self.search_pat(case);
                }
            }
            Pat::Struct(ps) => {
                self.search_path(&ps.path);
                for f in &ps.fields {
                    self.search_pat(&f.pat);
                }
            }
            Pat::TupleStruct(tps) => {
                self.search_path(&tps.path);
                for f in &tps.pat.elems {
                    self.search_pat(f);
                }
            }
            Pat::Type(pt) => {
                self.search_pat(&pt.pat);
                self.search_type(&pt.ty);
            }
            _ => {}
        }
    }

    fn search_type(&mut self, ty: &Type) {
        match ty {
            Type::Array(TypeArray { elem, .. })
            | Type::Group(TypeGroup { elem, .. })
            | Type::Paren(TypeParen { elem, .. })
            | Type::Ptr(TypePtr { elem, .. })
            | Type::Reference(TypeReference { elem, .. })
            | Type::Slice(TypeSlice { elem, .. }) => self.search_type(elem),
            Type::BareFn(tf) => {
                for input in &tf.inputs {
                    self.search_type(&input.ty);
                }
                self.search_return_type(&tf.output);
            }
            Type::ImplTrait(tyit) => {
                for b in &tyit.bounds {
                    if let syn::TypeParamBound::Trait(tyt) = b {
                        self.search_path(&tyt.path)
                    }
                }
            }
            Type::Infer(_) | Type::Macro(_) | Type::Never(_) => {}
            Type::Path(typ) => self.search_path(&typ.path),
            Type::TraitObject(tto) => self.search_type_param_bounds(&tto.bounds),
            Type::Tuple(tt) => {
                for e in &tt.elems {
                    self.search_type(e)
                }
            }
            _ => {}
        }
    }

    fn search_type_param_bounds(&mut self, bounds: &Punctuated<TypeParamBound, syn::token::Add>) {
        for b in bounds {
            if let syn::TypeParamBound::Trait(tpbt) = b {
                self.search_path(&tpbt.path)
            }
        }
    }

    fn search_return_type(&mut self, output: &ReturnType) {
        if let ReturnType::Type(_, ty) = &output {
            self.search_type(ty)
        }
    }

    fn search_path_arguments(&mut self, arguments: &syn::PathArguments) {
        match arguments {
            syn::PathArguments::None => {}
            syn::PathArguments::AngleBracketed(paab) => {
                for arg in &paab.args {
                    match arg {
                        syn::GenericArgument::Lifetime(_) => {}
                        syn::GenericArgument::Type(ty)
                        | syn::GenericArgument::Binding(Binding { ty, .. }) => self.search_type(ty),
                        syn::GenericArgument::Constraint(c) => {
                            self.search_type_param_bounds(&c.bounds)
                        }
                        syn::GenericArgument::Const(c) => self.search_expr(c),
                    }
                }
            }
            syn::PathArguments::Parenthesized(pas) => {
                self.search_return_type(&pas.output);
                for t in &pas.inputs {
                    self.search_type(t);
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use syn::{parse_quote, Item};

    use super::CppList;

    fn assert_found(cpp_list: &CppList) {
        assert!(!cpp_list.0.is_empty());
        assert!(cpp_list.0.iter().next().unwrap() == "xxx");
    }

    #[test]
    fn test_mod_plain_call() {
        let mut cpplist = CppList::default();
        let itm = Item::Mod(parse_quote! {
            mod foo {
                fn bar() {
                    ffi::xxx()
                }
            }
        });
        cpplist.search_item(&itm);
        assert_found(&cpplist);
    }

    #[test]
    fn test_plain_call() {
        let mut cpplist = CppList::default();
        let itm = Item::Fn(parse_quote! {
            fn bar() {
                ffi::xxx()
            }
        });
        cpplist.search_item(&itm);
        assert_found(&cpplist);
    }

    #[test]
    fn test_plain_call_with_semi() {
        let mut cpplist = CppList::default();
        let itm = Item::Fn(parse_quote! {
            fn bar() {
                ffi::xxx();
            }
        });
        cpplist.search_item(&itm);
        assert_found(&cpplist);
    }

    #[test]
    fn test_deep_nested_thingy() {
        let mut cpplist = CppList::default();
        let itm = Item::Fn(parse_quote! {
            fn bar() {
                a + 3 * foo(ffi::xxx());
            }
        });
        cpplist.search_item(&itm);
        assert_found(&cpplist);
    }

    #[test]
    fn test_ty_in_let() {
        let mut cpplist = CppList::default();
        let itm = Item::Fn(parse_quote! {
            fn bar() {
                let foo: ffi::xxx = bar();
            }
        });
        cpplist.search_item(&itm);
        assert_found(&cpplist);
    }

    #[test]
    fn test_ty_in_fn() {
        let mut cpplist = CppList::default();
        let itm = Item::Fn(parse_quote! {
            fn bar(a: &mut ffi::xxx) {
            }
        });
        cpplist.search_item(&itm);
        assert_found(&cpplist);
    }

    #[test]
    fn test_ty_in_fn_up() {
        let mut cpplist = CppList::default();
        let itm = Item::Fn(parse_quote! {
            fn bar(a: cxx::UniquePtr<ffi::xxx>) {
            }
        });
        cpplist.search_item(&itm);
        assert_found(&cpplist);
    }
}
<commit_msg>Add namespace test.<commit_after>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::HashSet;

use itertools::Itertools;
use syn::{
    punctuated::Punctuated, Binding, Expr, ExprAssign, ExprAssignOp, ExprAwait, ExprBinary,
    ExprBox, ExprBreak, ExprCast, ExprField, ExprGroup, ExprLet, ExprParen, ExprReference, ExprTry,
    ExprType, ExprUnary, ImplItem, Item, Pat, PatBox, PatReference, PatSlice, PatTuple, Path,
    ReturnType, Stmt, TraitItem, Type, TypeArray, TypeGroup, TypeParamBound, TypeParen, TypePtr,
    TypeReference, TypeSlice,
};

#[derive(Default)]
pub(super) struct CppList(pub(super) HashSet<String>);

impl CppList {
    pub(super) fn search_item(&mut self, item: &Item) {
        match item {
            Item::Fn(fun) => {
                for stmt in &fun.block.stmts {
                    self.search_stmt(stmt)
                }
                self.search_return_type(&fun.sig.output);
                for i in &fun.sig.inputs {
                    match i {
                        syn::FnArg::Receiver(_) => {}
                        syn::FnArg::Typed(pt) => {
                            self.search_pat(&pt.pat);
                            self.search_type(&pt.ty);
                        }
                    }
                }
            }
            Item::Impl(imp) => {
                for item in &imp.items {
                    self.search_impl_item(item)
                }
            }
            Item::Mod(md) => {
                if let Some((_, items)) = &md.content {
                    for item in items {
                        self.search_item(item)
                    }
                }
            }
            Item::Trait(tr) => {
                for item in &tr.items {
                    self.search_trait_item(item)
                }
            }
            _ => {}
        }
    }

    fn search_path(&mut self, path: &Path) {
        let mut seg_iter = path.segments.iter();
        if let Some(first_seg) = seg_iter.next() {
            if first_seg.ident == "ffi" {
                self.0
                    .insert(seg_iter.map(|seg| seg.ident.to_string()).join("::"));
            }
        }
        for seg in path.segments.iter() {
            self.search_path_arguments(&seg.arguments);
        }
    }

    fn search_trait_item(&mut self, itm: &TraitItem) {
        if let TraitItem::Method(itm) = itm {
            if let Some(block) = &itm.default {
                self.search_stmts(block.stmts.iter())
            }
        }
    }

    fn search_stmts<'a>(&mut self, stmts: impl Iterator<Item = &'a Stmt>) {
        for stmt in stmts {
            self.search_stmt(stmt)
        }
    }

    fn search_stmt(&mut self, stmt: &Stmt) {
        match stmt {
            Stmt::Local(lcl) => {
                if let Some((_, expr)) = &lcl.init {
                    self.search_expr(expr)
                }
                self.search_pat(&lcl.pat);
            }
            Stmt::Item(itm) => self.search_item(itm),
            Stmt::Expr(exp) | Stmt::Semi(exp, _) => self.search_expr(exp),
        }
    }

    fn search_expr(&mut self, expr: &Expr) {
        match expr {
            Expr::Path(exp) => {
                self.search_path(&exp.path);
            }
            Expr::Macro(_) => {}
            Expr::Array(array) => self.search_exprs(array.elems.iter()),
            Expr::Assign(ExprAssign { left, right, .. })
            | Expr::AssignOp(ExprAssignOp { left, right, .. })
            | Expr::Binary(ExprBinary { left, right, .. }) => {
                self.search_expr(left);
                self.search_expr(right);
            }
            Expr::Async(ass) => self.search_stmts(ass.block.stmts.iter()),
            Expr::Await(ExprAwait { base, .. }) | Expr::Field(ExprField { base, .. }) => {
                self.search_expr(base)
            }
            Expr::Block(blck) => self.search_stmts(blck.block.stmts.iter()),
            Expr::Box(ExprBox { expr, .. })
            | Expr::Break(ExprBreak {
                expr: Some(expr), ..
            })
            | Expr::Cast(ExprCast { expr, .. })
            | Expr::Group(ExprGroup { expr, .. })
            | Expr::Paren(ExprParen { expr, .. })
            | Expr::Reference(ExprReference { expr, .. })
            | Expr::Try(ExprTry { expr, .. })
            | Expr::Type(ExprType { expr, .. })
            | Expr::Unary(ExprUnary { expr, .. }) => self.search_expr(expr),
            Expr::Call(exc) => {
                self.search_expr(&exc.func);
                self.search_exprs(exc.args.iter());
            }
            Expr::Closure(cls) => self.search_expr(&cls.body),
            Expr::Continue(_)
            | Expr::Lit(_)
            | Expr::Break(ExprBreak { expr: None, .. })
            | Expr::Verbatim(_) => {}
            Expr::ForLoop(fl) => {
                self.search_expr(&fl.expr);
                self.search_stmts(fl.body.stmts.iter());
            }
            Expr::If(exif) => {
                self.search_expr(&exif.cond);
                self.search_stmts(exif.then_branch.stmts.iter());
                if let Some((_, else_branch)) = &exif.else_branch {
                    self.search_expr(else_branch);
                }
            }
            Expr::Index(exidx) => {
                self.search_expr(&exidx.expr);
                self.search_expr(&exidx.index);
            }
            Expr::Let(ExprLet { expr, pat, .. }) => {
                self.search_expr(expr);
                self.search_pat(pat);
            }
            Expr::Loop(exloo) => self.search_stmts(exloo.body.stmts.iter()),
            Expr::Match(exm) => {
                self.search_expr(&exm.expr);
                for a in &exm.arms {
                    self.search_expr(&a.body);
                    if let Some((_, guard)) = &a.guard {
                        self.search_expr(guard);
                    }
                }
            }
            Expr::MethodCall(mtc) => {
                self.search_expr(&mtc.receiver);
                self.search_exprs(mtc.args.iter());
            }
            Expr::Range(exr) => {
                self.search_option_expr(&exr.from);
                self.search_option_expr(&exr.to);
            }
            Expr::Repeat(exr) => {
                self.search_expr(&exr.expr);
                self.search_expr(&exr.len);
            }
            Expr::Return(exret) => {
                if let Some(expr) = &exret.expr {
                    self.search_expr(expr);
                }
            }
            Expr::Struct(exst) => {
                for f in &exst.fields {
                    self.search_expr(&f.expr);
                }
                self.search_option_expr(&exst.rest);
            }
            Expr::TryBlock(extb) => self.search_stmts(extb.block.stmts.iter()),
            Expr::Tuple(ext) => self.search_exprs(ext.elems.iter()),
            Expr::Unsafe(exs) => self.search_stmts(exs.block.stmts.iter()),
            Expr::While(exw) => {
                self.search_expr(&exw.cond);
                self.search_stmts(exw.body.stmts.iter());
            }
            Expr::Yield(exy) => self.search_option_expr(&exy.expr),
            Expr::__TestExhaustive(_) => {}
        }
    }

    fn search_option_expr(&mut self, expr: &Option<Box<Expr>>) {
        if let Some(expr) = &expr {
            self.search_expr(expr);
        }
    }

    fn search_exprs<'a>(&mut self, exprs: impl Iterator<Item = &'a Expr>) {
        for e in exprs {
            self.search_expr(e);
        }
    }

    fn search_impl_item(&mut self, impl_item: &ImplItem) {
        if let ImplItem::Method(itm) = impl_item {
            for stmt in &itm.block.stmts {
                self.search_stmt(stmt)
            }
        }
    }

    fn search_pat(&mut self, pat: &Pat) {
        match pat {
            Pat::Box(PatBox { pat, .. }) | Pat::Reference(PatReference { pat, .. }) => {
                self.search_pat(pat)
            }
            Pat::Ident(_) | Pat::Lit(_) | Pat::Macro(_) | Pat::Range(_) | Pat::Rest(_) => {}
            Pat::Or(pator) => {
                for case in &pator.cases {
                    self.search_pat(case);
                }
            }
            Pat::Path(pp) => self.search_path(&pp.path),
            Pat::Slice(PatSlice { elems, .. }) | Pat::Tuple(PatTuple { elems, .. }) => {
                for case in elems {
                    self.search_pat(case);
                }
            }
            Pat::Struct(ps) => {
                self.search_path(&ps.path);
                for f in &ps.fields {
                    self.search_pat(&f.pat);
                }
            }
            Pat::TupleStruct(tps) => {
                self.search_path(&tps.path);
                for f in &tps.pat.elems {
                    self.search_pat(f);
                }
            }
            Pat::Type(pt) => {
                self.search_pat(&pt.pat);
                self.search_type(&pt.ty);
            }
            _ => {}
        }
    }

    fn search_type(&mut self, ty: &Type) {
        match ty {
            Type::Array(TypeArray { elem, .. })
            | Type::Group(TypeGroup { elem, .. })
            | Type::Paren(TypeParen { elem, .. })
            | Type::Ptr(TypePtr { elem, .. })
            | Type::Reference(TypeReference { elem, .. })
            | Type::Slice(TypeSlice { elem, .. }) => self.search_type(elem),
            Type::BareFn(tf) => {
                for input in &tf.inputs {
                    self.search_type(&input.ty);
                }
                self.search_return_type(&tf.output);
            }
            Type::ImplTrait(tyit) => {
                for b in &tyit.bounds {
                    if let syn::TypeParamBound::Trait(tyt) = b {
                        self.search_path(&tyt.path)
                    }
                }
            }
            Type::Infer(_) | Type::Macro(_) | Type::Never(_) => {}
            Type::Path(typ) => self.search_path(&typ.path),
            Type::TraitObject(tto) => self.search_type_param_bounds(&tto.bounds),
            Type::Tuple(tt) => {
                for e in &tt.elems {
                    self.search_type(e)
                }
            }
            _ => {}
        }
    }

    fn search_type_param_bounds(&mut self, bounds: &Punctuated<TypeParamBound, syn::token::Add>) {
        for b in bounds {
            if let syn::TypeParamBound::Trait(tpbt) = b {
                self.search_path(&tpbt.path)
            }
        }
    }

    fn search_return_type(&mut self, output: &ReturnType) {
        if let ReturnType::Type(_, ty) = &output {
            self.search_type(ty)
        }
    }

    fn search_path_arguments(&mut self, arguments: &syn::PathArguments) {
        match arguments {
            syn::PathArguments::None => {}
            syn::PathArguments::AngleBracketed(paab) => {
                for arg in &paab.args {
                    match arg {
                        syn::GenericArgument::Lifetime(_) => {}
                        syn::GenericArgument::Type(ty)
                        | syn::GenericArgument::Binding(Binding { ty, .. }) => self.search_type(ty),
                        syn::GenericArgument::Constraint(c) => {
                            self.search_type_param_bounds(&c.bounds)
                        }
                        syn::GenericArgument::Const(c) => self.search_expr(c),
                    }
                }
            }
            syn::PathArguments::Parenthesized(pas) => {
                self.search_return_type(&pas.output);
                for t in &pas.inputs {
                    self.search_type(t);
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use syn::{parse_quote, Item};

    use super::CppList;

    fn assert_found(cpp_list: &CppList) {
        assert!(!cpp_list.0.is_empty());
        assert!(cpp_list.0.iter().next().unwrap() == "xxx");
    }

    #[test]
    fn test_mod_plain_call() {
        let mut cpplist = CppList::default();
        let itm = Item::Mod(parse_quote! {
            mod foo {
                fn bar() {
                    ffi::xxx()
                }
            }
        });
        cpplist.search_item(&itm);
        assert_found(&cpplist);
    }

    #[test]
    fn test_plain_call() {
        let mut cpplist = CppList::default();
        let itm = Item::Fn(parse_quote! {
            fn bar() {
                ffi::xxx()
            }
        });
        cpplist.search_item(&itm);
        assert_found(&cpplist);
    }

    #[test]
    fn test_plain_call_with_semi() {
        let mut cpplist = CppList::default();
        let itm = Item::Fn(parse_quote! {
            fn bar() {
                ffi::xxx();
            }
        });
        cpplist.search_item(&itm);
        assert_found(&cpplist);
    }

    #[test]
    fn test_in_ns() {
        let mut cpplist = CppList::default();
        let itm = Item::Fn(parse_quote! {
            fn bar() {
                ffi::a::b::xxx();
            }
        });
        cpplist.search_item(&itm);
        assert!(!cpplist.0.is_empty());
        assert!(cpplist.0.iter().next().unwrap() == "a::b::xxx");
    }

    #[test]
    fn test_deep_nested_thingy() {
        let mut cpplist = CppList::default();
        let itm = Item::Fn(parse_quote! {
            fn bar() {
                a + 3 * foo(ffi::xxx());
            }
        });
        cpplist.search_item(&itm);
        assert_found(&cpplist);
    }

    #[test]
    fn test_ty_in_let() {
        let mut cpplist = CppList::default();
        let itm = Item::Fn(parse_quote! {
            fn bar() {
                let foo: ffi::xxx = bar();
            }
        });
        cpplist.search_item(&itm);
        assert_found(&cpplist);
    }

    #[test]
    fn test_ty_in_fn() {
        let mut cpplist = CppList::default();
        let itm = Item::Fn(parse_quote! {
            fn bar(a: &mut ffi::xxx) {
            }
        });
        cpplist.search_item(&itm);
        assert_found(&cpplist);
    }

    #[test]
    fn test_ty_in_fn_up() {
        let mut cpplist = CppList::default();
        let itm = Item::Fn(parse_quote! {
            fn bar(a: cxx::UniquePtr<ffi::xxx>) {
            }
        });
        cpplist.search_item(&itm);
        assert_found(&cpplist);
    }
}
<|endoftext|>


<commit_before>//! A simplified version of quote-crate like quasi quote macro

// A helper macro quote macro
// FIXME:
// 1. Not all puncts are handled
// 2. #()* pattern repetition not supported now
//    * But we can do it manually, see `test_quote_derive_copy_hack`
#[doc(hidden)]
#[macro_export]
macro_rules! __quote {
    () => {
        Vec::<tt::TokenTree>::new()
    };

    ( @SUBTREE $delim:ident $($tt:tt)* ) => {
        {
            let children = $crate::__quote!($($tt)*);
            let subtree = tt::Subtree {
                delimiter: tt::Delimiter::$delim,
                token_trees: $crate::quote::IntoTt::to_tokens(children),
            };
            subtree
        }
    };

    ( @PUNCT $first:literal ) => {
        {
            vec![
                tt::Leaf::Punct(tt::Punct {
                    char: $first,
                    spacing: tt::Spacing::Alone,
                }).into()
            ]
        }
    };

    ( @PUNCT $first:literal, $sec:literal ) => {
        {
            vec![
                tt::Leaf::Punct(tt::Punct {
                    char: $first,
                    spacing: tt::Spacing::Joint,
                }).into(),
                tt::Leaf::Punct(tt::Punct {
                    char: $sec,
                    spacing: tt::Spacing::Alone,
                }).into()
            ]
        }
    };

    // hash variable
    ( # $first:ident $($tail:tt)* ) => {
        {
            let token = $crate::quote::ToTokenTree::to_token($first);
            let mut tokens = vec![token.into()];
            let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*));
            tokens.append(&mut tail_tokens);
            tokens
        }
    };

    // Brace
    ( { $($tt:tt)* } ) => { $crate::__quote!(@SUBTREE Brace $($tt)*) };
    // Bracket
    ( [ $($tt:tt)* ] ) => { $crate::__quote!(@SUBTREE Bracket $($tt)*) };
    // Parenthesis
    ( ( $($tt:tt)* ) ) => { $crate::__quote!(@SUBTREE Parenthesis $($tt)*) };

    // Literal
    ( $tt:literal ) => { vec![$crate::quote::ToTokenTree::to_token($tt).into()] };
    // Ident
    ( $tt:ident ) => {
        vec![ {
            tt::Leaf::Ident(tt::Ident {
                text: stringify!($tt).into(),
                id: tt::TokenId::unspecified(),
            }).into()
        }]
    };

    // Puncts
    // FIXME: Not all puncts are handled
    ( -> ) => {$crate::__quote!(@PUNCT '-', '>')};
    ( & ) => {$crate::__quote!(@PUNCT '&')};
    ( , ) => {$crate::__quote!(@PUNCT ',')};
    ( : ) => {$crate::__quote!(@PUNCT ':')};
    ( . ) => {$crate::__quote!(@PUNCT '.')};

    ( $first:tt $($tail:tt)+ ) => {
        {
            let mut tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($first));
            let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*));

            tokens.append(&mut tail_tokens);
            tokens
        }
    };
}

/// FIXME:
/// It probably should implement in proc-macro
#[macro_export]
macro_rules! quote {
    ( $($tt:tt)* ) => {
        $crate::quote::IntoTt::to_subtree($crate::__quote!($($tt)*))
    }
}

pub(crate) trait IntoTt {
    fn to_subtree(self) -> tt::Subtree;
    fn to_tokens(self) -> Vec<tt::TokenTree>;
}

impl IntoTt for Vec<tt::TokenTree> {
    fn to_subtree(self) -> tt::Subtree {
        tt::Subtree { delimiter: tt::Delimiter::None, token_trees: self }
    }

    fn to_tokens(self) -> Vec<tt::TokenTree> {
        self
    }
}

impl IntoTt for tt::Subtree {
    fn to_subtree(self) -> tt::Subtree {
        self
    }

    fn to_tokens(self) -> Vec<tt::TokenTree> {
        vec![tt::TokenTree::Subtree(self)]
    }
}

pub(crate) trait ToTokenTree {
    fn to_token(self) -> tt::TokenTree;
}

impl ToTokenTree for tt::TokenTree {
    fn to_token(self) -> tt::TokenTree {
        self
    }
}

impl ToTokenTree for tt::Subtree {
    fn to_token(self) -> tt::TokenTree {
        self.into()
    }
}

macro_rules! impl_to_to_tokentrees {
    ($($ty:ty => $this:ident $im:block);*) => {
        $(
            impl ToTokenTree for $ty {
                fn to_token($this) -> tt::TokenTree {
                    let leaf: tt::Leaf = $im.into();
                    leaf.into()
                }
            }

            impl ToTokenTree for &$ty {
                fn to_token($this) -> tt::TokenTree {
                    let leaf: tt::Leaf = $im.clone().into();
                    leaf.into()
                }
            }
        )*
    }
}

impl_to_to_tokentrees! {
    u32 => self { tt::Literal{text: self.to_string().into()} };
    usize => self { tt::Literal{text: self.to_string().into()}};
    i32 => self { tt::Literal{text: self.to_string().into()}};
    &str => self { tt::Literal{text: self.to_string().into()}};
    String => self { tt::Literal{text: self.into()}};
    tt::Leaf => self { self };
    tt::Literal => self { self };
    tt::Ident => self { self };
    tt::Punct => self { self }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_quote_delimiters() {
        assert_eq!(quote!({}).to_string(), "{}");
        assert_eq!(quote!(()).to_string(), "()");
        assert_eq!(quote!([]).to_string(), "[]");
    }

    #[test]
    fn test_quote_idents() {
        assert_eq!(quote!(32).to_string(), "32");
        assert_eq!(quote!(struct).to_string(), "struct");
    }

    #[test]
    fn test_quote_hash_simple_literal() {
        let a = 20;
        assert_eq!(quote!(#a).to_string(), "20");
        let s: String = "hello".into();
        assert_eq!(quote!(#s).to_string(), "hello");
    }

    fn mk_ident(name: &str) -> tt::Ident {
        tt::Ident { text: name.into(), id: tt::TokenId::unspecified() }
    }

    #[test]
    fn test_quote_hash_token_tree() {
        let a = mk_ident("hello");

        let quoted = quote!(#a);
        assert_eq!(quoted.to_string(), "hello");
        let t = format!("{:?}", quoted);
        assert_eq!(t, "Subtree { delimiter: None, token_trees: [Leaf(Ident(Ident { text: \"hello\", id: TokenId(4294967295) }))] }");
    }

    #[test]
    fn test_quote_simple_derive_copy() {
        let name = mk_ident("Foo");

        let quoted = quote! {
            impl Clone for #name {
                fn clone(&self) -> Self {
                    Self {}
                }
            }
        };

        assert_eq!(quoted.to_string(), "impl Clone for Foo {fn clone (& self) -> Self {Self {}}}");
    }

    #[test]
    fn test_quote_derive_copy_hack() {
        // Assume the given struct is:
        // struct Foo {
        //  name: String,
        //  id: u32,
        // }
        let struct_name = mk_ident("Foo");
        let fields = [mk_ident("name"), mk_ident("id")];
        let fields =
            fields.iter().map(|it| quote!(#it: self.#it.clone(), ).token_trees.clone()).flatten();

        let list = tt::Subtree { delimiter: tt::Delimiter::Brace, token_trees: fields.collect() };

        let quoted = quote! {
            impl Clone for #struct_name {
                fn clone(&self) -> Self {
                    Self #list
                }
            }
        };

        assert_eq!(quoted.to_string(), "impl Clone for Foo {fn clone (& self) -> Self {Self {name : self . name . clone () , id : self . id . clone () ,}}}");
    }
}
<commit_msg>Fixed a bug for string lit in quote<commit_after>//! A simplified version of quote-crate like quasi quote macro

// A helper macro quote macro
// FIXME:
// 1. Not all puncts are handled
// 2. #()* pattern repetition not supported now
//    * But we can do it manually, see `test_quote_derive_copy_hack`
#[doc(hidden)]
#[macro_export]
macro_rules! __quote {
    () => {
        Vec::<tt::TokenTree>::new()
    };

    ( @SUBTREE $delim:ident $($tt:tt)* ) => {
        {
            let children = $crate::__quote!($($tt)*);
            let subtree = tt::Subtree {
                delimiter: tt::Delimiter::$delim,
                token_trees: $crate::quote::IntoTt::to_tokens(children),
            };
            subtree
        }
    };

    ( @PUNCT $first:literal ) => {
        {
            vec![
                tt::Leaf::Punct(tt::Punct {
                    char: $first,
                    spacing: tt::Spacing::Alone,
                }).into()
            ]
        }
    };

    ( @PUNCT $first:literal, $sec:literal ) => {
        {
            vec![
                tt::Leaf::Punct(tt::Punct {
                    char: $first,
                    spacing: tt::Spacing::Joint,
                }).into(),
                tt::Leaf::Punct(tt::Punct {
                    char: $sec,
                    spacing: tt::Spacing::Alone,
                }).into()
            ]
        }
    };

    // hash variable
    ( # $first:ident $($tail:tt)* ) => {
        {
            let token = $crate::quote::ToTokenTree::to_token($first);
            let mut tokens = vec![token.into()];
            let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*));
            tokens.append(&mut tail_tokens);
            tokens
        }
    };

    // Brace
    ( { $($tt:tt)* } ) => { $crate::__quote!(@SUBTREE Brace $($tt)*) };
    // Bracket
    ( [ $($tt:tt)* ] ) => { $crate::__quote!(@SUBTREE Bracket $($tt)*) };
    // Parenthesis
    ( ( $($tt:tt)* ) ) => { $crate::__quote!(@SUBTREE Parenthesis $($tt)*) };

    // Literal
    ( $tt:literal ) => { vec![$crate::quote::ToTokenTree::to_token($tt).into()] };
    // Ident
    ( $tt:ident ) => {
        vec![ {
            tt::Leaf::Ident(tt::Ident {
                text: stringify!($tt).into(),
                id: tt::TokenId::unspecified(),
            }).into()
        }]
    };

    // Puncts
    // FIXME: Not all puncts are handled
    ( -> ) => {$crate::__quote!(@PUNCT '-', '>')};
    ( & ) => {$crate::__quote!(@PUNCT '&')};
    ( , ) => {$crate::__quote!(@PUNCT ',')};
    ( : ) => {$crate::__quote!(@PUNCT ':')};
    ( . ) => {$crate::__quote!(@PUNCT '.')};

    ( $first:tt $($tail:tt)+ ) => {
        {
            let mut tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($first));
            let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*));

            tokens.append(&mut tail_tokens);
            tokens
        }
    };
}

/// FIXME:
/// It probably should implement in proc-macro
#[macro_export]
macro_rules! quote {
    ( $($tt:tt)* ) => {
        $crate::quote::IntoTt::to_subtree($crate::__quote!($($tt)*))
    }
}

pub(crate) trait IntoTt {
    fn to_subtree(self) -> tt::Subtree;
    fn to_tokens(self) -> Vec<tt::TokenTree>;
}

impl IntoTt for Vec<tt::TokenTree> {
    fn to_subtree(self) -> tt::Subtree {
        tt::Subtree { delimiter: tt::Delimiter::None, token_trees: self }
    }

    fn to_tokens(self) -> Vec<tt::TokenTree> {
        self
    }
}

impl IntoTt for tt::Subtree {
    fn to_subtree(self) -> tt::Subtree {
        self
    }

    fn to_tokens(self) -> Vec<tt::TokenTree> {
        vec![tt::TokenTree::Subtree(self)]
    }
}

pub(crate) trait ToTokenTree {
    fn to_token(self) -> tt::TokenTree;
}

impl ToTokenTree for tt::TokenTree {
    fn to_token(self) -> tt::TokenTree {
        self
    }
}

impl ToTokenTree for tt::Subtree {
    fn to_token(self) -> tt::TokenTree {
        self.into()
    }
}

macro_rules! impl_to_to_tokentrees {
    ($($ty:ty => $this:ident $im:block);*) => {
        $(
            impl ToTokenTree for $ty {
                fn to_token($this) -> tt::TokenTree {
                    let leaf: tt::Leaf = $im.into();
                    leaf.into()
                }
            }

            impl ToTokenTree for &$ty {
                fn to_token($this) -> tt::TokenTree {
                    let leaf: tt::Leaf = $im.clone().into();
                    leaf.into()
                }
            }
        )*
    }
}

impl_to_to_tokentrees! {
    u32 => self { tt::Literal{text: self.to_string().into()} };
    usize => self { tt::Literal{text: self.to_string().into()}};
    i32 => self { tt::Literal{text: self.to_string().into()}};
    tt::Leaf => self { self };
    tt::Literal => self { self };
    tt::Ident => self { self };
    tt::Punct => self { self };
    &str => self { tt::Literal{text: format!("{:?}", self.escape_default().to_string()).into()}};
    String => self { tt::Literal{text: format!("{:?}", self.escape_default().to_string()).into()}}
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_quote_delimiters() {
        assert_eq!(quote!({}).to_string(), "{}");
        assert_eq!(quote!(()).to_string(), "()");
        assert_eq!(quote!([]).to_string(), "[]");
    }

    #[test]
    fn test_quote_idents() {
        assert_eq!(quote!(32).to_string(), "32");
        assert_eq!(quote!(struct).to_string(), "struct");
    }

    #[test]
    fn test_quote_hash_simple_literal() {
        let a = 20;
        assert_eq!(quote!(#a).to_string(), "20");
        let s: String = "hello".into();
        assert_eq!(quote!(#s).to_string(), "\"hello\"");
    }

    fn mk_ident(name: &str) -> tt::Ident {
        tt::Ident { text: name.into(), id: tt::TokenId::unspecified() }
    }

    #[test]
    fn test_quote_hash_token_tree() {
        let a = mk_ident("hello");

        let quoted = quote!(#a);
        assert_eq!(quoted.to_string(), "hello");
        let t = format!("{:?}", quoted);
        assert_eq!(t, "Subtree { delimiter: None, token_trees: [Leaf(Ident(Ident { text: \"hello\", id: TokenId(4294967295) }))] }");
    }

    #[test]
    fn test_quote_simple_derive_copy() {
        let name = mk_ident("Foo");

        let quoted = quote! {
            impl Clone for #name {
                fn clone(&self) -> Self {
                    Self {}
                }
            }
        };

        assert_eq!(quoted.to_string(), "impl Clone for Foo {fn clone (& self) -> Self {Self {}}}");
    }

    #[test]
    fn test_quote_derive_copy_hack() {
        // Assume the given struct is:
        // struct Foo {
        //  name: String,
        //  id: u32,
        // }
        let struct_name = mk_ident("Foo");
        let fields = [mk_ident("name"), mk_ident("id")];
        let fields =
            fields.iter().map(|it| quote!(#it: self.#it.clone(), ).token_trees.clone()).flatten();

        let list = tt::Subtree { delimiter: tt::Delimiter::Brace, token_trees: fields.collect() };

        let quoted = quote! {
            impl Clone for #struct_name {
                fn clone(&self) -> Self {
                    Self #list
                }
            }
        };

        assert_eq!(quoted.to_string(), "impl Clone for Foo {fn clone (& self) -> Self {Self {name : self . name . clone () , id : self . id . clone () ,}}}");
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2016-2017 Sebastian Dröge <sebastian@centricular.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[macro_export]
macro_rules! plugin_define(
    ($name:expr, $description:expr, $plugin_init:ident,
     $version:expr, $license:expr, $source:expr,
     $package:expr, $origin:expr, $release_datetime:expr) => {
        pub mod plugin_desc {
            use $crate::glib::translate::{from_glib_borrow, ToGlib};

            // Not using c_char here because it requires the libc crate
            #[allow(non_camel_case_types)]
            type c_char = i8;

            #[repr(C)]
            pub struct GstPluginDesc($crate::gst_ffi::GstPluginDesc);
            unsafe impl Sync for GstPluginDesc {}

            #[no_mangle]
            #[allow(non_upper_case_globals)]
            pub static gst_plugin_desc: GstPluginDesc = GstPluginDesc($crate::gst_ffi::GstPluginDesc {
                major_version: 1,
                minor_version: 10,
                name: $name as *const u8 as *const c_char,
                description: $description as *const u8 as *const c_char,
                plugin_init: Some(plugin_init_trampoline),
                version: $version as *const u8 as *const c_char,
                license: $license as *const u8 as *const c_char,
                source: $source as *const u8 as *const c_char,
                package: $package as *const u8 as *const c_char,
                origin: $origin as *const u8 as *const c_char,
                release_datetime: $release_datetime as *const u8 as *const c_char,
                _gst_reserved: [0 as $crate::glib_ffi::gpointer; 4],
            });

            unsafe extern "C" fn plugin_init_trampoline(plugin: *mut $crate::gst_ffi::GstPlugin) -> $crate::glib_ffi::gboolean {
                super::$plugin_init(&from_glib_borrow(plugin)).to_glib()
            }
        }
    };
);
<commit_msg>Also update version in the plugin metadata to 1.8<commit_after>// Copyright (C) 2016-2017 Sebastian Dröge <sebastian@centricular.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[macro_export]
macro_rules! plugin_define(
    ($name:expr, $description:expr, $plugin_init:ident,
     $version:expr, $license:expr, $source:expr,
     $package:expr, $origin:expr, $release_datetime:expr) => {
        pub mod plugin_desc {
            use $crate::glib::translate::{from_glib_borrow, ToGlib};

            // Not using c_char here because it requires the libc crate
            #[allow(non_camel_case_types)]
            type c_char = i8;

            #[repr(C)]
            pub struct GstPluginDesc($crate::gst_ffi::GstPluginDesc);
            unsafe impl Sync for GstPluginDesc {}

            #[no_mangle]
            #[allow(non_upper_case_globals)]
            pub static gst_plugin_desc: GstPluginDesc = GstPluginDesc($crate::gst_ffi::GstPluginDesc {
                major_version: 1,
                minor_version: 8,
                name: $name as *const u8 as *const c_char,
                description: $description as *const u8 as *const c_char,
                plugin_init: Some(plugin_init_trampoline),
                version: $version as *const u8 as *const c_char,
                license: $license as *const u8 as *const c_char,
                source: $source as *const u8 as *const c_char,
                package: $package as *const u8 as *const c_char,
                origin: $origin as *const u8 as *const c_char,
                release_datetime: $release_datetime as *const u8 as *const c_char,
                _gst_reserved: [0 as $crate::glib_ffi::gpointer; 4],
            });

            unsafe extern "C" fn plugin_init_trampoline(plugin: *mut $crate::gst_ffi::GstPlugin) -> $crate::glib_ffi::gboolean {
                super::$plugin_init(&from_glib_borrow(plugin)).to_glib()
            }
        }
    };
);
<|endoftext|>


<commit_before>//! Detecting language items.
//!
//! Language items are items that represent concepts intrinsic to the language
//! itself. Examples are:
//!
//! * Traits that specify "kinds"; e.g., `Sync`, `Send`.
//! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`.
//! * Functions called by the compiler itself.

use crate::check_attr::target_from_impl_item;
use crate::weak_lang_items;

use rustc_middle::middle::cstore::ExternCrate;
use rustc_middle::ty::TyCtxt;

use rustc_ast::Attribute;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::lang_items::{extract, ITEM_REFS};
use rustc_hir::{HirId, LangItem, LanguageItems, Target};

use rustc_middle::ty::query::Providers;

struct LanguageItemCollector<'tcx> {
    items: LanguageItems,
    tcx: TyCtxt<'tcx>,
}

impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> {
    fn visit_item(&mut self, item: &hir::Item<'_>) {
        self.check_for_lang(Target::from_item(item), item.hir_id(), item.attrs);

        if let hir::ItemKind::Enum(def, ..) = &item.kind {
            for variant in def.variants {
                self.check_for_lang(Target::Variant, variant.id, variant.attrs);
            }
        }
    }

    fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
        self.check_for_lang(
            Target::from_trait_item(trait_item),
            trait_item.hir_id(),
            trait_item.attrs,
        )
    }

    fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) {
        self.check_for_lang(
            target_from_impl_item(self.tcx, impl_item),
            impl_item.hir_id(),
            impl_item.attrs,
        )
    }

    fn visit_foreign_item(&mut self, _: &hir::ForeignItem<'_>) {}
}

impl LanguageItemCollector<'tcx> {
    fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> {
        LanguageItemCollector { tcx, items: LanguageItems::new() }
    }

    fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId, attrs: &[Attribute]) {
        let check_name = |attr, sym| self.tcx.sess.check_name(attr, sym);
        if let Some((value, span)) = extract(check_name, &attrs) {
            match ITEM_REFS.get(&value).cloned() {
                // Known lang item with attribute on correct target.
                Some((item_index, expected_target)) if actual_target == expected_target => {
                    let def_id = self.tcx.hir().local_def_id(hir_id);
                    self.collect_item(item_index, def_id.to_def_id());
                }
                // Known lang item with attribute on incorrect target.
                Some((_, expected_target)) => {
                    struct_span_err!(
                        self.tcx.sess,
                        span,
                        E0718,
                        "`{}` language item must be applied to a {}",
                        value,
                        expected_target,
                    )
                    .span_label(
                        span,
                        format!(
                            "attribute should be applied to a {}, not a {}",
                            expected_target, actual_target,
                        ),
                    )
                    .emit();
                }
                // Unknown lang item.
                _ => {
                    struct_span_err!(
                        self.tcx.sess,
                        span,
                        E0522,
                        "definition of an unknown language item: `{}`",
                        value
                    )
                    .span_label(span, format!("definition of unknown language item `{}`", value))
                    .emit();
                }
            }
        }
    }

    fn collect_item(&mut self, item_index: usize, item_def_id: DefId) {
        // Check for duplicates.
        if let Some(original_def_id) = self.items.items[item_index] {
            if original_def_id != item_def_id {
                let lang_item = LangItem::from_u32(item_index as u32).unwrap();
                let name = lang_item.name();
                let mut err = match self.tcx.hir().span_if_local(item_def_id) {
                    Some(span) => struct_span_err!(
                        self.tcx.sess,
                        span,
                        E0152,
                        "found duplicate lang item `{}`",
                        name
                    ),
                    None => match self.tcx.extern_crate(item_def_id) {
                        Some(ExternCrate { dependency_of, .. }) => {
                            self.tcx.sess.struct_err(&format!(
                                "duplicate lang item in crate `{}` (which `{}` depends on): `{}`.",
                                self.tcx.crate_name(item_def_id.krate),
                                self.tcx.crate_name(*dependency_of),
                                name
                            ))
                        }
                        _ => self.tcx.sess.struct_err(&format!(
                            "duplicate lang item in crate `{}`: `{}`.",
                            self.tcx.crate_name(item_def_id.krate),
                            name
                        )),
                    },
                };
                if let Some(span) = self.tcx.hir().span_if_local(original_def_id) {
                    err.span_note(span, "the lang item is first defined here");
                } else {
                    match self.tcx.extern_crate(original_def_id) {
                        Some(ExternCrate { dependency_of, .. }) => {
                            err.note(&format!(
                                "the lang item is first defined in crate `{}` (which `{}` depends on)",
                                self.tcx.crate_name(original_def_id.krate),
                                self.tcx.crate_name(*dependency_of)
                            ));
                        }
                        _ => {
                            err.note(&format!(
                                "the lang item is first defined in crate `{}`.",
                                self.tcx.crate_name(original_def_id.krate)
                            ));
                        }
                    }
                    let mut note_def = |which, def_id: DefId| {
                        let crate_name = self.tcx.crate_name(def_id.krate);
                        let note = if def_id.is_local() {
                            format!("{} definition in the local crate (`{}`)", which, crate_name)
                        } else {
                            let paths: Vec<_> = self
                                .tcx
                                .crate_extern_paths(def_id.krate)
                                .iter()
                                .map(|p| p.display().to_string())
                                .collect();
                            format!(
                                "{} definition in `{}` loaded from {}",
                                which,
                                crate_name,
                                paths.join(", ")
                            )
                        };
                        err.note(&note);
                    };
                    note_def("first", original_def_id);
                    note_def("second", item_def_id);
                }
                err.emit();
            }
        }

        // Matched.
        self.items.items[item_index] = Some(item_def_id);
        if let Some(group) = LangItem::from_u32(item_index as u32).unwrap().group() {
            self.items.groups[group as usize].push(item_def_id);
        }
    }
}

/// Traverses and collects all the lang items in all crates.
fn collect(tcx: TyCtxt<'_>) -> LanguageItems {
    // Initialize the collector.
    let mut collector = LanguageItemCollector::new(tcx);

    // Collect lang items in other crates.
    for &cnum in tcx.crates().iter() {
        for &(def_id, item_index) in tcx.defined_lang_items(cnum).iter() {
            collector.collect_item(item_index, def_id);
        }
    }

    // Collect lang items in this crate.
    tcx.hir().krate().visit_all_item_likes(&mut collector);

    // Extract out the found lang items.
    let LanguageItemCollector { mut items, .. } = collector;

    // Find all required but not-yet-defined lang items.
    weak_lang_items::check_crate(tcx, &mut items);

    items
}

pub fn provide(providers: &mut Providers) {
    providers.get_lang_items = |tcx, id| {
        assert_eq!(id, LOCAL_CRATE);
        collect(tcx)
    };
}
<commit_msg>Access attrs directly from HirId in rustc_passes::lang_items.<commit_after>//! Detecting language items.
//!
//! Language items are items that represent concepts intrinsic to the language
//! itself. Examples are:
//!
//! * Traits that specify "kinds"; e.g., `Sync`, `Send`.
//! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`.
//! * Functions called by the compiler itself.

use crate::check_attr::target_from_impl_item;
use crate::weak_lang_items;

use rustc_middle::middle::cstore::ExternCrate;
use rustc_middle::ty::TyCtxt;

use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::lang_items::{extract, ITEM_REFS};
use rustc_hir::{HirId, LangItem, LanguageItems, Target};

use rustc_middle::ty::query::Providers;

struct LanguageItemCollector<'tcx> {
    items: LanguageItems,
    tcx: TyCtxt<'tcx>,
}

impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> {
    fn visit_item(&mut self, item: &hir::Item<'_>) {
        self.check_for_lang(Target::from_item(item), item.hir_id());

        if let hir::ItemKind::Enum(def, ..) = &item.kind {
            for variant in def.variants {
                self.check_for_lang(Target::Variant, variant.id);
            }
        }
    }

    fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
        self.check_for_lang(Target::from_trait_item(trait_item), trait_item.hir_id())
    }

    fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) {
        self.check_for_lang(target_from_impl_item(self.tcx, impl_item), impl_item.hir_id())
    }

    fn visit_foreign_item(&mut self, _: &hir::ForeignItem<'_>) {}
}

impl LanguageItemCollector<'tcx> {
    fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> {
        LanguageItemCollector { tcx, items: LanguageItems::new() }
    }

    fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId) {
        let attrs = self.tcx.hir().attrs(hir_id);
        let check_name = |attr, sym| self.tcx.sess.check_name(attr, sym);
        if let Some((value, span)) = extract(check_name, &attrs) {
            match ITEM_REFS.get(&value).cloned() {
                // Known lang item with attribute on correct target.
                Some((item_index, expected_target)) if actual_target == expected_target => {
                    let def_id = self.tcx.hir().local_def_id(hir_id);
                    self.collect_item(item_index, def_id.to_def_id());
                }
                // Known lang item with attribute on incorrect target.
                Some((_, expected_target)) => {
                    struct_span_err!(
                        self.tcx.sess,
                        span,
                        E0718,
                        "`{}` language item must be applied to a {}",
                        value,
                        expected_target,
                    )
                    .span_label(
                        span,
                        format!(
                            "attribute should be applied to a {}, not a {}",
                            expected_target, actual_target,
                        ),
                    )
                    .emit();
                }
                // Unknown lang item.
                _ => {
                    struct_span_err!(
                        self.tcx.sess,
                        span,
                        E0522,
                        "definition of an unknown language item: `{}`",
                        value
                    )
                    .span_label(span, format!("definition of unknown language item `{}`", value))
                    .emit();
                }
            }
        }
    }

    fn collect_item(&mut self, item_index: usize, item_def_id: DefId) {
        // Check for duplicates.
        if let Some(original_def_id) = self.items.items[item_index] {
            if original_def_id != item_def_id {
                let lang_item = LangItem::from_u32(item_index as u32).unwrap();
                let name = lang_item.name();
                let mut err = match self.tcx.hir().span_if_local(item_def_id) {
                    Some(span) => struct_span_err!(
                        self.tcx.sess,
                        span,
                        E0152,
                        "found duplicate lang item `{}`",
                        name
                    ),
                    None => match self.tcx.extern_crate(item_def_id) {
                        Some(ExternCrate { dependency_of, .. }) => {
                            self.tcx.sess.struct_err(&format!(
                                "duplicate lang item in crate `{}` (which `{}` depends on): `{}`.",
                                self.tcx.crate_name(item_def_id.krate),
                                self.tcx.crate_name(*dependency_of),
                                name
                            ))
                        }
                        _ => self.tcx.sess.struct_err(&format!(
                            "duplicate lang item in crate `{}`: `{}`.",
                            self.tcx.crate_name(item_def_id.krate),
                            name
                        )),
                    },
                };
                if let Some(span) = self.tcx.hir().span_if_local(original_def_id) {
                    err.span_note(span, "the lang item is first defined here");
                } else {
                    match self.tcx.extern_crate(original_def_id) {
                        Some(ExternCrate { dependency_of, .. }) => {
                            err.note(&format!(
                                "the lang item is first defined in crate `{}` (which `{}` depends on)",
                                self.tcx.crate_name(original_def_id.krate),
                                self.tcx.crate_name(*dependency_of)
                            ));
                        }
                        _ => {
                            err.note(&format!(
                                "the lang item is first defined in crate `{}`.",
                                self.tcx.crate_name(original_def_id.krate)
                            ));
                        }
                    }
                    let mut note_def = |which, def_id: DefId| {
                        let crate_name = self.tcx.crate_name(def_id.krate);
                        let note = if def_id.is_local() {
                            format!("{} definition in the local crate (`{}`)", which, crate_name)
                        } else {
                            let paths: Vec<_> = self
                                .tcx
                                .crate_extern_paths(def_id.krate)
                                .iter()
                                .map(|p| p.display().to_string())
                                .collect();
                            format!(
                                "{} definition in `{}` loaded from {}",
                                which,
                                crate_name,
                                paths.join(", ")
                            )
                        };
                        err.note(&note);
                    };
                    note_def("first", original_def_id);
                    note_def("second", item_def_id);
                }
                err.emit();
            }
        }

        // Matched.
        self.items.items[item_index] = Some(item_def_id);
        if let Some(group) = LangItem::from_u32(item_index as u32).unwrap().group() {
            self.items.groups[group as usize].push(item_def_id);
        }
    }
}

/// Traverses and collects all the lang items in all crates.
fn collect(tcx: TyCtxt<'_>) -> LanguageItems {
    // Initialize the collector.
    let mut collector = LanguageItemCollector::new(tcx);

    // Collect lang items in other crates.
    for &cnum in tcx.crates().iter() {
        for &(def_id, item_index) in tcx.defined_lang_items(cnum).iter() {
            collector.collect_item(item_index, def_id);
        }
    }

    // Collect lang items in this crate.
    tcx.hir().krate().visit_all_item_likes(&mut collector);

    // Extract out the found lang items.
    let LanguageItemCollector { mut items, .. } = collector;

    // Find all required but not-yet-defined lang items.
    weak_lang_items::check_crate(tcx, &mut items);

    items
}

pub fn provide(providers: &mut Providers) {
    providers.get_lang_items = |tcx, id| {
        assert_eq!(id, LOCAL_CRATE);
        collect(tcx)
    };
}
<|endoftext|>


<commit_before>use super::assert_future;
use crate::future::FutureExt;
use core::iter::FromIterator;
use core::mem;
use core::pin::Pin;
use alloc::vec::Vec;
use futures_core::future::Future;
use futures_core::task::{Context, Poll};

/// Future for the [`select_all`] function.
#[derive(Debug)]
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct SelectAll<Fut> {
    inner: Vec<Fut>,
}

impl<Fut: Unpin> Unpin for SelectAll<Fut> {}

/// Creates a new future which will select over a list of futures.
///
/// The returned future will wait for any future within `iter` to be ready. Upon
/// completion the item resolved will be returned, along with the index of the
/// future that was ready and the list of all the remaining futures.
///
/// There are no guarantees provided on the order of the list with the remaining
/// futures. They might be swapped around, reversed, or completely random.
///
/// This function is only available when the `std` or `alloc` feature of this
/// library is activated, and it is activated by default.
///
/// # Panics
///
/// This function will panic if the iterator specified contains no items.
pub fn select_all<I>(iter: I) -> SelectAll<I::Item>
    where I: IntoIterator,
          I::Item: Future + Unpin,
{
    let ret = SelectAll {
        inner: iter.into_iter().collect()
    };
    assert!(!ret.inner.is_empty());
    assert_future::<(<I::Item as Future>::Output, usize, Vec<I::Item>), _>(ret)
}

impl<Fut: Future + Unpin> Future for SelectAll<Fut> {
    type Output = (Fut::Output, usize, Vec<Fut>);

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let item = self.inner.iter_mut().enumerate().find_map(|(i, f)| {
            match f.poll_unpin(cx) {
                Poll::Pending => None,
                Poll::Ready(e) => Some((i, e)),
            }
        });
        match item {
            Some((idx, res)) => {
                let _ = self.inner.swap_remove(idx);
                let rest = mem::replace(&mut self.inner, Vec::new());
                Poll::Ready((res, idx, rest))
            }
            None => Poll::Pending,
        }
    }
}

impl<Fut: Future + Unpin> FromIterator<Fut> for SelectAll<Fut> {
    fn from_iter<T: IntoIterator<Item = Fut>>(iter: T) -> Self {
        select_all(iter)
    }
}
<commit_msg>Add future::SelectAll::into_inner (#2363)<commit_after>use super::assert_future;
use crate::future::FutureExt;
use core::iter::FromIterator;
use core::mem;
use core::pin::Pin;
use alloc::vec::Vec;
use futures_core::future::Future;
use futures_core::task::{Context, Poll};

/// Future for the [`select_all`] function.
#[derive(Debug)]
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct SelectAll<Fut> {
    inner: Vec<Fut>,
}

impl<Fut: Unpin> Unpin for SelectAll<Fut> {}

/// Creates a new future which will select over a list of futures.
///
/// The returned future will wait for any future within `iter` to be ready. Upon
/// completion the item resolved will be returned, along with the index of the
/// future that was ready and the list of all the remaining futures.
///
/// There are no guarantees provided on the order of the list with the remaining
/// futures. They might be swapped around, reversed, or completely random.
///
/// This function is only available when the `std` or `alloc` feature of this
/// library is activated, and it is activated by default.
///
/// # Panics
///
/// This function will panic if the iterator specified contains no items.
pub fn select_all<I>(iter: I) -> SelectAll<I::Item>
    where I: IntoIterator,
          I::Item: Future + Unpin,
{
    let ret = SelectAll {
        inner: iter.into_iter().collect()
    };
    assert!(!ret.inner.is_empty());
    assert_future::<(<I::Item as Future>::Output, usize, Vec<I::Item>), _>(ret)
}

impl<Fut> SelectAll<Fut> {
    /// Consumes this combinator, returning the underlying futures.
    pub fn into_inner(self) -> Vec<Fut> {
        self.inner
    }
}

impl<Fut: Future + Unpin> Future for SelectAll<Fut> {
    type Output = (Fut::Output, usize, Vec<Fut>);

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let item = self.inner.iter_mut().enumerate().find_map(|(i, f)| {
            match f.poll_unpin(cx) {
                Poll::Pending => None,
                Poll::Ready(e) => Some((i, e)),
            }
        });
        match item {
            Some((idx, res)) => {
                let _ = self.inner.swap_remove(idx);
                let rest = mem::replace(&mut self.inner, Vec::new());
                Poll::Ready((res, idx, rest))
            }
            None => Poll::Pending,
        }
    }
}

impl<Fut: Future + Unpin> FromIterator<Fut> for SelectAll<Fut> {
    fn from_iter<T: IntoIterator<Item = Fut>>(iter: T) -> Self {
        select_all(iter)
    }
}
<|endoftext|>


<commit_before>use super::utils::types::{ Sha256Digest, Bitfield };
use super::rlp::{ RlpStream, Encodable };

pub struct PartialCrosslinkRecord {
    pub shard_id: u16,
    pub shard_block_hash: Sha256Digest,
    pub voter_bitfield: Bitfield
}

impl PartialCrosslinkRecord {
    pub fn new_for_shard(shard_id: u16,
               shard_block_hash: Sha256Digest) -> PartialCrosslinkRecord {
        PartialCrosslinkRecord {
            shard_id: shard_id,
            shard_block_hash: shard_block_hash,
            voter_bitfield: Bitfield::new()
        }
    }
}

/*
 * RLP Encoding
 */
impl Encodable for PartialCrosslinkRecord {
    fn rlp_append(&self, s: &mut RlpStream) {
        s.append(&self.shard_id);
        s.append(&self.shard_block_hash);
        s.append(&self.voter_bitfield);
    }
}

#[cfg(test)]
mod tests {
    use super::super::rlp;
    use super::*;

    #[test]
    fn test_new_for_shard() {
        let id = 1;
        let hash = Sha256Digest::random();
        let p = PartialCrosslinkRecord::new_for_shard(id, hash);
        assert_eq!(p.shard_id, id);
        assert_eq!(p.shard_block_hash, hash);
    }

    #[test]
    fn test_rlp_serialization() {
        let p = PartialCrosslinkRecord {
            shard_id: 1,
            shard_block_hash: Sha256Digest::zero(),
            voter_bitfield: Bitfield::new()
        };
        let e = rlp::encode(&p);
        assert_eq!(e.len(), 35);
        assert_eq!(e[0], 1);
        assert_eq!(e[1], 160);
        assert_eq!(e[2..34], [0; 32]);
        assert_eq!(e[34], 128);
    }
}
<commit_msg>Add zero() to PartialCrosslinkRecord<commit_after>use super::utils::types::{ Sha256Digest, Bitfield };
use super::rlp::{ RlpStream, Encodable };

pub struct PartialCrosslinkRecord {
    pub shard_id: u16,
    pub shard_block_hash: Sha256Digest,
    pub voter_bitfield: Bitfield
}

impl PartialCrosslinkRecord {
    pub fn zero() -> Self {
        Self {
            shard_id: 0,
            shard_block_hash: Sha256Digest::zero(),
            voter_bitfield: Bitfield::new()
        }
    }
}

/*
 * RLP Encoding
 */
impl Encodable for PartialCrosslinkRecord {
    fn rlp_append(&self, s: &mut RlpStream) {
        s.append(&self.shard_id);
        s.append(&self.shard_block_hash);
        s.append(&self.voter_bitfield);
    }
}

#[cfg(test)]
mod tests {
    use super::super::rlp;
    use super::*;

    #[test]
    fn test_zero() {
        let p = PartialCrosslinkRecord::zero();
        assert_eq!(p.shard_id, 0);
        assert_eq!(p.shard_block_hash.is_zero(), true);
        assert_eq!(p.voter_bitfield.num_true_bits(), 0);
    }

    #[test]
    fn test_rlp_serialization() {
        let mut p = PartialCrosslinkRecord::zero();
        p.shard_id = 1;
        let e = rlp::encode(&p);
        assert_eq!(e.len(), 35);
        assert_eq!(e[0], 1);
        assert_eq!(e[1], 160);
        assert_eq!(e[2..34], [0; 32]);
        assert_eq!(e[34], 128);
    }
}
<|endoftext|>


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

struct boxedFn { theFn: &'self fn() -> uint }

fn createClosure (closedUint: uint) -> boxedFn {
    boxedFn {theFn: @fn () -> uint { closedUint }} //~ ERROR illegal borrow
}

fn main () {
    let aFn: boxedFn = createClosure(10);

    let myInt: uint = (aFn.theFn)();

    assert myInt == 10;
}
<commit_msg>fix test to not use fn expr<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

struct boxedFn { theFn: &'self fn() -> uint }

fn createClosure (closedUint: uint) -> boxedFn {
    let theFn: @fn() -> uint = || closedUint;
    boxedFn {theFn: theFn} //~ ERROR illegal borrow
}

fn main () {
    let aFn: boxedFn = createClosure(10);

    let myInt: uint = (aFn.theFn)();

    assert myInt == 10;
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate apache2;

use apache2::{Request, Status};

apache2_module!(coming_soon_handler, c_coming_soon_handler, coming_soon_module, b"mod_coming_soon\0");

macro_rules! html_template {() => ("<!doctype html>

      <meta charset=\"utf-8\">
      <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\">
      <title>PolyDraw – Coming Soon</title>
      <meta name=\"description\" content=\"PolyDraw website is coming soon\">
      <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">

      <link href=\"https://fonts.googleapis.com/css?family=Fira+Sans:300,500\" rel=\"stylesheet\" type=\"text/css\">
      <link href=\"https://fonts.googleapis.com/css?family=Roboto+Condensed:400\" rel=\"stylesheet\" type=\"text/css\">
      <link href=\"https://fonts.googleapis.com/css?family=Khand:400\" rel=\"stylesheet\" type=\"text/css\">

PolyDraw

Open source software development

COMING SOON

in

000

days

                  In the meantime, please sign the international petition against

ORGAN HARVESTING

from Falun Gong practitioners in China!

                  JOIN THE PETITION!

")}

fn coming_soon_handler(r: &mut Request) -> Status {
   if r.handler().unwrap() != "coming-soon" || r.uri().unwrap() != "/" {
      return Status::DECLINED
   }

   r.set_content_type("text/html");

   r.write(format!(
      html_template!(),
      STYLESHEET
   ));

   Status::OK
}

const STYLESHEET: &'static str = "
   html, body {
      height: 100%;
      width: 100%;
      margin: 0;
   }

   body {
      display: block;
      font-family: 'Roboto Condensed', sans-serif;
      background-image: url(https://www.polydraw.com/img/mountain-mist.jpg);
      background-size: cover;
      background-repeat: no-repeat;
      background-attachment: fixed;
      background-position: right bottom;
   }

   main {
      display: block;
      position: relative;
      top: 50%;
      margin: 0 auto;
      -webkit-transform: translateY(-50%);
      -ms-transform: translateY(-50%);
      transform: translateY(-50%);
   }

   h1 {
      display: block;
      width: 60%;
      margin: 0 auto;
      font-family: 'Fira Sans', sans-serif;
      font-weight: 500;
      font-size: 3.5em;
      color: white;
      text-align: center;
   }

   h2 {
      display: block;
      width: 70%;
      margin: -0.2em auto 0;
      font-family: 'Fira Sans', sans-serif;
      font-weight: 300;
      font-size: 1.2em;
      color: #5b5b5b;
      text-align: center;
   }

   .coming-soon {
      display: block;
      width: 40%;
      margin: 2.5em auto .1em;
      font-size: 1.5em;
      color: white;
      text-align: center;
   }

   .in {
      display: block;
      font-family: 'Fira Sans', sans-serif;
      font-weight: 300;
      font-size: .8em;
      font-style: italic;
      color: white;
      text-align: center;
   }

   .timer {
      display: block;
      width: 7em;
      text-align: center;
      border-style: solid none solid none;
      border-color: #e6e6e6;
      border-width: 1px;
      margin: 0 auto 1em;
   }

   .timer .number {
      display: block;
      font-family: 'Khand', sans-serif;
      font-size: 4em;
      font-weight: bold;
      color: white;
      text-align: center;
   }

   .timer .days {
      display: block;
      font-family: 'Khand', sans-serif;
      font-size: 1.5em;
      color: white;
      text-align: center;
      margin: -1em auto 0;
   }

   .urgent-call {
      margin: 3% auto 0;
   }

   .urgent-call .description {
      display: block;
      width: 100%;
      padding-top: 1em;
      padding-bottom: 1em;
      background: -webkit-linear-gradient(left, rgba(86,86,107,0), rgba(86,86,107,.25), rgba(86,86,107,0));
      background: linear-gradient(to right,rgba(86,86,107,0),rgba(86,86,107,.25),rgba(86,86,107,0));
   }

   .urgent-call .first, .urgent-call .second, .urgent-call .third {
      margin: 0 auto;
      width: 90%;
      color: white;
      font-size: 1em;
      text-align: center;
   }

   .urgent-call .first {
      margin-bottom: 0.25em;
   }

   .urgent-call .second {
      width: 100%;
      color: #9c292e;
      font-family: 'Khand', sans-serif;
      font-weight: bold;
      font-size: 1.2em;
   }

   .petition .button {
      display: block;
      width: 120px;
      margin: 1em auto 0;
      padding: 3px 6px;
      background: #829776;
      color: #ffffff;
      font-family: 'Fira Sans', sans-serif;
      font-size: .85em;
      font-weight: 300;
      text-align: center;
      text-decoration: none;
      border: solid #ffffff 1px;
      border-radius: 3px;
   }

   .petition .button:hover {
      background: #4d6b3c;
   }

   footer {
      display: table;
      position: fixed;
      width: 96%;
      bottom: 0;
      padding-left: 2%;
      padding-right: 2%;
   }

   .social {
      display: block;
      vertical-align: middle;
      float: right;
   }

   .social a {
      display: inline-block;
      width: 28px;
      height: 28px;
      background-repeat: no-repeat;
      opacity: .5;
      margin-left: .5em;
   }

   .social a:hover {
      opacity: .9;
   }

   .social a.facebook {
      background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAMAAABF0y+mAAAAG1BMVEUAAADY2NjY2NjY2NjY2NhGRkZqamqFhYWtra1jMrL/AAAACXRSTlMAPGaw//////9HdVBWAAAAp0lEQVQoz42TQRLDIAwDVyb/f3GxegAGmJC0PhkWge0RYoYQxuvGSGKkTu9wohW3vQj2yAQoR4Zwh3fWaYAODEJwQWNltqAKEJXShSV71dVWGJCJLuy6+MxFEKwN8uGSPGraml+uaG9s9RuqvVX8FLvSgqJ5PPysdPASP5SP1AS5O2IuEkHRcfCuCFSOt1Y3J5wGkW5O8IFmDg/daTPYH9Z8N/X5O3wBpdI+PxtA6DIAAAAASUVORK5CYII=);
   }

   .social a.twitter {
      background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAMAAABF0y+mAAAAJFBMVEUAAADY2NjV1dXY2NjY2NjY2NjY2NhHR0empqaQkJBtbW3Dw8PQfCyMAAAADHRSTlMAPPVmwKD////////J66Z0AAAA5UlEQVQoz32T0ZKFIAxDT1qc/f+/3VFo9wFQXL23D+oQGpJQxVXCCHJdmB+lFQCq17yDclsoonXYx9NZ+dPy7PQbBEBro/MFw0gwUPJSKRAUewOJiqEbZu5QAUyITQBbVgAPwHUA5OHQO6N4zOMsAFpKW89lAw8FgLW+6XB1Hz9KcuY6XuEjt12XqBKn2bGwgMcpfe7a/XFRYQ+uUzRY9wdE7/DfCdX0cZp5l2jt5FI46QC5F5M4Fl31e/AOmW9oDbB+c89S9klI7POYkIvf4aJd05do5Y6IZTQhYjqsqvE/yLff4Q+6BFspw2Tr1AAAAABJRU5ErkJggg==);
   }

   .social a.github {
      background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAMAAABF0y+mAAAAJFBMVEUAAADY2NjY2NjY2NjY2NjY2NhHR0ebm5u3t7dYWFh3d3dqampwrbVmAAAADHRSTlMAPGbxsP////////80TrKnAAAA4UlEQVQoz32TwW7DMAxDH+ns/z94tbhDpDRBi+lkSCBN0bR4lxAh98YcVgxAaec51NKNIj1eANjmyR+AA8CLZxmqkR8zwAQMEl9KAsExQy+RXaPqxXEBl9gidnZDowGu0olxvBvqcUTSOgmGKlhudeU6JJWLbmmWXwXs04Ga1UaqVK/z9LsuT9+2/XxxovWkFwB2pjfI7ZaB8L6Q53aFdw44UqZb8dyek0R4WMUa5iybIEvNuv83XqBnDLqqgiH59p7JmYTwCd0TE3KLaHPWO315ZiV1jyZUFLUdl2D99x3+AND/ZE+Y11fiAAAAAElFTkSuQmCC);
   }

   @media all and (max-width: 319px) {
      main {
         margin: auto 0;
      }

      h1 {
         margin: -7% auto 0;
         font-size: 1.6em;
      }

      h2 {
         margin: 0 auto;
         font-size: .8em;
      }

      .coming-soon {
         margin: .7em auto 0;
         font-size: .8em;
      }

      .in {
         font-size: .7em;
      }

      .timer {
         width: 3em;
         margin: 0 auto .2em;
      }

      .timer .number {
         font-size: 2em;
      }

      .timer .days {
         font-size: .75em;
      }

      .urgent-call {
         margin: 0 auto;
      }

      .urgent-call .description {
         font-size: 0.7em;
      }

      .petition .button {
         width: 120px;
         margin: 1em auto 0;
         padding: 3px;
         font-size: .6em;
      }
   }

   @media all and (min-width: 320px) and (max-width: 460px) {
      h1 {
         margin: 0 auto;
         font-size: 2.5em;
      }

      h2 {
         margin: 0 auto 2em;
         font-size: .9em;
      }

      .coming-soon {
         margin: 0 auto;
         font-size: 1.3em;
      }

      .timer {
         width: 5em;
         margin: 0 auto 1em;
      }

      .timer .number {
         font-size: 2.8em;
      }

      .timer .days {
         font-size: 1.1em;
      }

      .urgent-call .description {
         font-size: .85em;
      }

      .petition .button {
         width: 100px;
         margin: 1em auto 0;
         font-size: .6em;
      }
   }

   @media all and (min-width: 1600px) {
      h1 {
         font-size: 5.25em;
      }

      h2 {
         font-size: 1.8em;
      }

      .coming-soon {
         font-size: 2.25em;
      }

      .in {
         font-size: 1.2em;
      }

      .timer {
         width: 10em;
         margin: 0.5em auto 2em;
      }

      .timer .number {
         font-size: 6em;
      }

      .timer .days {
         font-size: 2.25em;
      }

      .urgent-call .description {
      }

      .urgent-call .first, .urgent-call .third {
         font-size: 1.5em;
      }

      .urgent-call .second {
         font-size: 1.8em;
      }

      .petition .button {
         width: 180px;
         margin: .8em auto 0;
         padding: 5px;
         font-size: 1.2em;
      }
   }
";
<commit_msg>Improving font sizes on large desktops.<commit_after>#[macro_use]
extern crate apache2;

use apache2::{Request, Status};

apache2_module!(coming_soon_handler, c_coming_soon_handler, coming_soon_module, b"mod_coming_soon\0");

macro_rules! html_template {() => ("<!doctype html>

      <meta charset=\"utf-8\">
      <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\">
      <title>PolyDraw – Coming Soon</title>
      <meta name=\"description\" content=\"PolyDraw website is coming soon\">
      <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">

      <link href=\"https://fonts.googleapis.com/css?family=Fira+Sans:300,500\" rel=\"stylesheet\" type=\"text/css\">
      <link href=\"https://fonts.googleapis.com/css?family=Roboto+Condensed:400\" rel=\"stylesheet\" type=\"text/css\">
      <link href=\"https://fonts.googleapis.com/css?family=Khand:400\" rel=\"stylesheet\" type=\"text/css\">

PolyDraw

Open source software development

COMING SOON

in

000

days

                  In the meantime, please sign the international petition against

ORGAN HARVESTING

from Falun Gong practitioners in China!

                  JOIN THE PETITION!

")}

fn coming_soon_handler(r: &mut Request) -> Status {
   if r.handler().unwrap() != "coming-soon" || r.uri().unwrap() != "/" {
      return Status::DECLINED
   }

   r.set_content_type("text/html");

   r.write(format!(
      html_template!(),
      STYLESHEET
   ));

   Status::OK
}

const STYLESHEET: &'static str = "
   html, body {
      height: 100%;
      width: 100%;
      margin: 0;
   }

   body {
      display: block;
      font-family: 'Roboto Condensed', sans-serif;
      background-image: url(https://www.polydraw.com/img/mountain-mist.jpg);
      background-size: cover;
      background-repeat: no-repeat;
      background-attachment: fixed;
      background-position: right bottom;
   }

   main {
      display: block;
      position: relative;
      top: 50%;
      margin: 0 auto;
      -webkit-transform: translateY(-50%);
      -ms-transform: translateY(-50%);
      transform: translateY(-50%);
   }

   h1 {
      display: block;
      width: 60%;
      margin: 0 auto;
      font-family: 'Fira Sans', sans-serif;
      font-weight: 500;
      font-size: 3.5em;
      color: white;
      text-align: center;
   }

   h2 {
      display: block;
      width: 70%;
      margin: -0.2em auto 0;
      font-family: 'Fira Sans', sans-serif;
      font-weight: 300;
      font-size: 1.2em;
      color: #5b5b5b;
      text-align: center;
   }

   .coming-soon {
      display: block;
      width: 40%;
      margin: 2.5em auto .1em;
      font-size: 1.5em;
      color: white;
      text-align: center;
   }

   .in {
      display: block;
      font-family: 'Fira Sans', sans-serif;
      font-weight: 300;
      font-size: .8em;
      font-style: italic;
      color: white;
      text-align: center;
   }

   .timer {
      display: block;
      width: 7em;
      text-align: center;
      border-style: solid none solid none;
      border-color: #e6e6e6;
      border-width: 1px;
      margin: 0 auto 1em;
   }

   .timer .number {
      display: block;
      font-family: 'Khand', sans-serif;
      font-size: 4em;
      font-weight: bold;
      color: white;
      text-align: center;
   }

   .timer .days {
      display: block;
      font-family: 'Khand', sans-serif;
      font-size: 1.5em;
      color: white;
      text-align: center;
      margin: -1em auto 0;
   }

   .urgent-call {
      margin: 3% auto 0;
   }

   .urgent-call .description {
      display: block;
      width: 100%;
      padding-top: 1em;
      padding-bottom: 1em;
      background: -webkit-linear-gradient(left, rgba(86,86,107,0), rgba(86,86,107,.25), rgba(86,86,107,0));
      background: linear-gradient(to right,rgba(86,86,107,0),rgba(86,86,107,.25),rgba(86,86,107,0));
   }

   .urgent-call .first, .urgent-call .second, .urgent-call .third {
      margin: 0 auto;
      width: 90%;
      color: white;
      font-size: 1em;
      text-align: center;
   }

   .urgent-call .first {
      margin-bottom: 0.25em;
   }

   .urgent-call .second {
      width: 100%;
      color: #9c292e;
      font-family: 'Khand', sans-serif;
      font-weight: bold;
      font-size: 1.2em;
   }

   .petition .button {
      display: block;
      width: 120px;
      margin: 1em auto 0;
      padding: 3px 6px;
      background: #829776;
      color: #ffffff;
      font-family: 'Fira Sans', sans-serif;
      font-size: .85em;
      font-weight: 300;
      text-align: center;
      text-decoration: none;
      border: solid #ffffff 1px;
      border-radius: 3px;
   }

   .petition .button:hover {
      background: #4d6b3c;
   }

   footer {
      display: table;
      position: fixed;
      width: 96%;
      bottom: 0;
      padding-left: 2%;
      padding-right: 2%;
   }

   .social {
      display: block;
      vertical-align: middle;
      float: right;
   }

   .social a {
      display: inline-block;
      width: 28px;
      height: 28px;
      background-repeat: no-repeat;
      opacity: .5;
      margin-left: .5em;
   }

   .social a:hover {
      opacity: .9;
   }

   .social a.facebook {
      background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAMAAABF0y+mAAAAG1BMVEUAAADY2NjY2NjY2NjY2NhGRkZqamqFhYWtra1jMrL/AAAACXRSTlMAPGaw//////9HdVBWAAAAp0lEQVQoz42TQRLDIAwDVyb/f3GxegAGmJC0PhkWge0RYoYQxuvGSGKkTu9wohW3vQj2yAQoR4Zwh3fWaYAODEJwQWNltqAKEJXShSV71dVWGJCJLuy6+MxFEKwN8uGSPGraml+uaG9s9RuqvVX8FLvSgqJ5PPysdPASP5SP1AS5O2IuEkHRcfCuCFSOt1Y3J5wGkW5O8IFmDg/daTPYH9Z8N/X5O3wBpdI+PxtA6DIAAAAASUVORK5CYII=);
   }

   .social a.twitter {
      background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAMAAABF0y+mAAAAJFBMVEUAAADY2NjV1dXY2NjY2NjY2NjY2NhHR0empqaQkJBtbW3Dw8PQfCyMAAAADHRSTlMAPPVmwKD////////J66Z0AAAA5UlEQVQoz32T0ZKFIAxDT1qc/f+/3VFo9wFQXL23D+oQGpJQxVXCCHJdmB+lFQCq17yDclsoonXYx9NZ+dPy7PQbBEBro/MFw0gwUPJSKRAUewOJiqEbZu5QAUyITQBbVgAPwHUA5OHQO6N4zOMsAFpKW89lAw8FgLW+6XB1Hz9KcuY6XuEjt12XqBKn2bGwgMcpfe7a/XFRYQ+uUzRY9wdE7/DfCdX0cZp5l2jt5FI46QC5F5M4Fl31e/AOmW9oDbB+c89S9klI7POYkIvf4aJd05do5Y6IZTQhYjqsqvE/yLff4Q+6BFspw2Tr1AAAAABJRU5ErkJggg==);
   }

   .social a.github {
      background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAMAAABF0y+mAAAAJFBMVEUAAADY2NjY2NjY2NjY2NjY2NhHR0ebm5u3t7dYWFh3d3dqampwrbVmAAAADHRSTlMAPGbxsP////////80TrKnAAAA4UlEQVQoz32TwW7DMAxDH+ns/z94tbhDpDRBi+lkSCBN0bR4lxAh98YcVgxAaec51NKNIj1eANjmyR+AA8CLZxmqkR8zwAQMEl9KAsExQy+RXaPqxXEBl9gidnZDowGu0olxvBvqcUTSOgmGKlhudeU6JJWLbmmWXwXs04Ga1UaqVK/z9LsuT9+2/XxxovWkFwB2pjfI7ZaB8L6Q53aFdw44UqZb8dyek0R4WMUa5iybIEvNuv83XqBnDLqqgiH59p7JmYTwCd0TE3KLaHPWO315ZiV1jyZUFLUdl2D99x3+AND/ZE+Y11fiAAAAAElFTkSuQmCC);
   }

   @media all and (max-width: 319px) {
      main {
         margin: auto 0;
      }

      h1 {
         margin: -7% auto 0;
         font-size: 1.6em;
      }

      h2 {
         margin: 0 auto;
         font-size: .8em;
      }

      .coming-soon {
         margin: .7em auto 0;
         font-size: .8em;
      }

      .in {
         font-size: .7em;
      }

      .timer {
         width: 3em;
         margin: 0 auto .2em;
      }

      .timer .number {
         font-size: 2em;
      }

      .timer .days {
         font-size: .75em;
      }

      .urgent-call {
         margin: 0 auto;
      }

      .urgent-call .description {
         font-size: 0.7em;
      }

      .petition .button {
         width: 120px;
         margin: 1em auto 0;
         padding: 3px;
         font-size: .6em;
      }
   }

   @media all and (min-width: 320px) and (max-width: 460px) {
      h1 {
         margin: 0 auto;
         font-size: 2.5em;
      }

      h2 {
         margin: 0 auto 2em;
         font-size: .9em;
      }

      .coming-soon {
         margin: 0 auto;
         font-size: 1.3em;
      }

      .timer {
         width: 5em;
         margin: 0 auto 1em;
      }

      .timer .number {
         font-size: 2.8em;
      }

      .timer .days {
         font-size: 1.1em;
      }

      .urgent-call .description {
         font-size: .85em;
      }

      .petition .button {
         width: 100px;
         margin: 1em auto 0;
         font-size: .6em;
      }
   }

   @media all and (min-width: 1600px) {
      h1 {
         font-size: 5em;
      }

      h2 {
         font-size: 1.7em;
      }

      .coming-soon {
         font-size: 2.25em;
      }

      .in {
         font-size: 1.2em;
      }

      .timer {
         width: 10em;
         margin: 0.5em auto 2em;
      }

      .timer .number {
         font-size: 5em;
      }

      .timer .days {
         font-size: 2.25em;
      }

      .urgent-call .description {
      }

      .urgent-call .first, .urgent-call .third {
         font-size: 1.5em;
      }

      .urgent-call .second {
         font-size: 1.8em;
      }

      .petition .button {
         width: 180px;
         margin: .8em auto 0;
         padding: 5px;
         font-size: 1.2em;
      }
   }
";
<|endoftext|>